All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/18] target/riscv: Add support for RISC-V P
@ 2026-07-17 10:06 Molly Chen
  2026-07-17 10:06 ` [PATCH v2 01/18] target/riscv: Add packed SIMD extension state Molly Chen
                   ` (19 more replies)
  0 siblings, 20 replies; 34+ messages in thread
From: Molly Chen @ 2026-07-17 10:06 UTC (permalink / raw)
  To: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
	chao.liu.zevorn
  Cc: xiaoou, qemu-riscv, qemu-devel

This series adds support for the RISC-V Packed SIMD (P) extension.

The P extension defines packed-SIMD fixed-point operations intended
for DSP-style workloads such as multimedia and signal processing.
These instructions operate on packed subword elements within
general-purpose registers (GPRs).

The implementation follows the current development draft of the
specification (v0.20):

  https://github.com/riscv/riscv-p-spec/
  or
  https://www.jhauser.us/RISCV/ext-P/

Compared with v1, this version reduces implementation boilerplate by
defining and reusing helper macros for common patterns in
trans_rvp.c.inc and psimd_helper.c. It also consolidates the P
extension prerequisite validation in riscv_cpu_validate_p().

The Zbkb dependency has been removed to align the implementation with
the current specification. This version also implements the
specification-defined control of vxsat, which was missing from v1.

All instructions have been functionally tested using the following
test suite:

  https://github.com/mollybuild/qemu-riscv-test-uart

The implementation focuses on functional correctness and ISA
coverage. Performance optimizations were not considered at this
stage.

Feedback on the implementation details would be highly appreciated.

Tested with:

  - ninja -C build test
  - make -C build check-qtest-riscv32
  - make -C build check-qtest-riscv64
  - Functional tests for all P extension instructions using
    qemu-riscv-test-uart

No regressions or test failures were observed.

---
Changes in v2:

  - Refactored trans_rvp.c.inc and psimd_helper.c by defining and
    reusing helper macros for common implementation patterns, reducing
    boilerplate and overall code size.
  - Moved the P extension prerequisite checks into
    riscv_cpu_validate_p().
  - Removed the Zbkb dependency to align with the current
    specification.
  - Added the specification-defined vxsat control mechanism, which was
    missing from v1.

v1:
  https://lists.nongnu.org/archive/html/qemu-riscv/2026-04/msg00301.html

Molly Chen (18):
  target/riscv: Add packed SIMD extension state
  target/riscv: Add packed SIMD helper framework
  target/riscv: Add packed SIMD arithmetic instructions
  target/riscv: Add packed SIMD averaging and rounding instructions
  target/riscv: Add packed SIMD absolute, difference, compare and mask
    instructions
  target/riscv: Add packed SIMD shift instructions
  target/riscv: Add packed SIMD exchange instructions
  target/riscv: Add packed SIMD horizontal reduction instructions
  target/riscv: Add packed SIMD pack, merge and count-leading
    instructions
  target/riscv: Add packed SIMD multiplication instructions
  target/riscv: Add packed SIMD multiply-accumulate instructions
  target/riscv: Add packed SIMD Q-format multiplication instructions
  target/riscv: Add packed SIMD Q-format MAC instructions
  target/riscv: Add packed SIMD two-way MAC instructions
  target/riscv: Add packed SIMD four-way MAC instructions
  target/riscv: Add packed SIMD load-replicate instructions
  target/riscv: Add packed SIMD RV32 only instructions
  target/riscv: Remove Zbkb dependency from P extension to align with
    the spec

 target/riscv/cpu.c                          |    5 +-
 target/riscv/cpu.h                          |    8 +
 target/riscv/cpu_bits.h                     |    2 +
 target/riscv/helper.h                       |  529 ++++
 target/riscv/insn32.decode                  |  829 +++++
 target/riscv/machine.c                      |   19 +
 target/riscv/tcg/csr.c                      |   39 +-
 target/riscv/tcg/insn_trans/trans_rvb.c.inc |    4 +-
 target/riscv/tcg/insn_trans/trans_rvp.c.inc | 1389 ++++++++
 target/riscv/tcg/meson.build                |    3 +-
 target/riscv/tcg/psimd_helper.c             | 3165 +++++++++++++++++++
 target/riscv/tcg/tcg-cpu.c                  |   46 +
 target/riscv/tcg/translate.c                |    6 +
 13 files changed, 6038 insertions(+), 6 deletions(-)
 create mode 100644 target/riscv/tcg/insn_trans/trans_rvp.c.inc
 create mode 100644 target/riscv/tcg/psimd_helper.c


base-commit: 8fb307591625731060d399aca42373c02c7cb040
-- 
2.34.1



^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH v2 01/18] target/riscv: Add packed SIMD extension state
  2026-07-17 10:06 [PATCH v2 00/18] target/riscv: Add support for RISC-V P Molly Chen
@ 2026-07-17 10:06 ` Molly Chen
  2026-07-26 19:32   ` Daniel Henrique Barboza
                     ` (2 more replies)
  2026-07-17 10:06 ` [PATCH v2 02/18] target/riscv: Add packed SIMD helper framework Molly Chen
                   ` (18 subsequent siblings)
  19 siblings, 3 replies; 34+ messages in thread
From: Molly Chen @ 2026-07-17 10:06 UTC (permalink / raw)
  To: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
	chao.liu.zevorn, Chao Liu
  Cc: xiaoou, qemu-riscv, qemu-devel, Yin Zhang, Dajun Huang,
	Zhiyuan Yang

Model vxsat with separate Vector/Zve and P-only control paths.  When
Zve* is present, vxsat follows mstatus.VS/vsstatus.VS; when P is
implemented without Zve*, stateen0.VXSAT controls access instead.

Record the P-only stateen result in TB flags so cached translations
preserve both instruction legality and the illegal-vs-virtual exception
class.

Co-authored-by: Yin Zhang <zhangyin2018@iscas.ac.cn>
Co-authored-by: Dajun Huang <djhuang_1@std.uestc.edu.cn>
Co-authored-by: Zhiyuan Yang <zhiyuan.plct@isrc.iscas.ac.cn>

Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
---
 target/riscv/cpu.c         |  5 ++--
 target/riscv/cpu.h         |  8 +++++++
 target/riscv/cpu_bits.h    |  2 ++
 target/riscv/machine.c     | 19 +++++++++++++++
 target/riscv/tcg/csr.c     | 39 +++++++++++++++++++++++++++++--
 target/riscv/tcg/tcg-cpu.c | 48 ++++++++++++++++++++++++++++++++++++++
 6 files changed, 117 insertions(+), 4 deletions(-)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 5a82e6563bf..c9e6c83a491 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -46,7 +46,7 @@
 /* RISC-V CPU definitions */
 static const char riscv_single_letter_exts[] = "IEMAFDQCBPVH";
 const uint32_t misa_bits[] = {RVI, RVE, RVM, RVA, RVF, RVD, RVV,
-                              RVC, RVS, RVU, RVH, RVG, RVB, 0};
+                              RVC, RVS, RVU, RVH, RVG, RVB, RVP, 0};
 #define RISCV_CPU_MVENDORID 0
 #define RISCV_CPU_MIMPID 0
 /*
@@ -1489,7 +1489,8 @@ static const MISAExtInfo misa_ext_info_arr[] = {
     MISA_EXT_INFO(RVH, "h", "Hypervisor"),
     MISA_EXT_INFO(RVV, "v", "Vector operations"),
     MISA_EXT_INFO(RVG, "g", "General purpose (IMAFD_Zicsr_Zifencei)"),
-    MISA_EXT_INFO(RVB, "b", "Bit manipulation (Zba_Zbb_Zbs)")
+    MISA_EXT_INFO(RVB, "b", "Bit manipulation (Zba_Zbb_Zbs)"),
+    MISA_EXT_INFO(RVP, "x-p", "Packed-SIMD instructions")
 };
 
 static void riscv_cpu_validate_misa_mxl(RISCVCPUClass *mcc)
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index c9dfa7daff2..75cfb16d846 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -70,6 +70,7 @@ typedef struct CPUArchState CPURISCVState;
 #define RVG RV('G')
 #define RVB RV('B')
 #define RVX RV('X')
+#define RVP RV('P')
 
 extern const uint32_t misa_bits[];
 const char *riscv_get_misa_ext_name(uint32_t bit);
@@ -742,6 +743,13 @@ FIELD(TB_FLAGS, PM_SIGNEXTEND, 31, 1)
 FIELD(EXT_TB_FLAGS, MISA_EXT, 0, 32)
 FIELD(EXT_TB_FLAGS, ALTFMT, 32, 1)
 FIELD(EXT_TB_FLAGS, BIG_ENDIAN, 33, 1)
+FIELD(EXT_TB_FLAGS, P_VXSAT_EXCP, 34, 2)
+
+enum {
+    P_VXSAT_EXCP_NONE,
+    P_VXSAT_EXCP_ILLEGAL,
+    P_VXSAT_EXCP_VIRTUAL,
+};
 
 #ifdef TARGET_RISCV32
 #define riscv_cpu_mxl(env)  ((void)(env), MXL_RV32)
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index 3f146a43fe4..fa7bf60f4fc 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -355,6 +355,8 @@
 #define SMSTATEEN0_CS       (1ULL << 0)
 #define SMSTATEEN0_FCSR     (1ULL << 1)
 #define SMSTATEEN0_JVT      (1ULL << 2)
+/* Packed-SIMD draft: enable access to vxsat when misa.V = 0. */
+#define SMSTATEEN0_VXSAT    (1ULL << 3)
 #define SMSTATEEN0_CTR      (1ULL << 54)
 #define SMSTATEEN0_P1P13    (1ULL << 56)
 #define SMSTATEEN0_HSCONTXT (1ULL << 57)
diff --git a/target/riscv/machine.c b/target/riscv/machine.c
index 0ab613a2980..a9cd7e4c1cc 100644
--- a/target/riscv/machine.c
+++ b/target/riscv/machine.c
@@ -158,6 +158,24 @@ static const VMStateDescription vmstate_vector = {
     }
 };
 
+static bool p_vxsat_needed(void *opaque)
+{
+    RISCVCPU *cpu = opaque;
+
+    return riscv_has_ext(&cpu->env, RVP) && !cpu->cfg.ext_zve32x;
+}
+
+static const VMStateDescription vmstate_p_vxsat = {
+    .name = "cpu/p-vxsat",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .needed = p_vxsat_needed,
+    .fields = (const VMStateField[]) {
+        VMSTATE_UINT8(env.vxsat, RISCVCPU),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 static bool pointermasking_needed(void *opaque)
 {
     return false;
@@ -518,6 +536,7 @@ const VMStateDescription vmstate_riscv_cpu = {
         &vmstate_pmp,
         &vmstate_hyper,
         &vmstate_vector,
+        &vmstate_p_vxsat,
         &vmstate_pointermasking,
         &vmstate_rv128,
 #ifdef CONFIG_KVM
diff --git a/target/riscv/tcg/csr.c b/target/riscv/tcg/csr.c
index 36f2004bc56..e809997f52e 100644
--- a/target/riscv/tcg/csr.c
+++ b/target/riscv/tcg/csr.c
@@ -109,6 +109,24 @@ static RISCVException vs(CPURISCVState *env, int csrno)
     return RISCV_EXCP_ILLEGAL_INST;
 }
 
+/* vxsat is also architectural state when P is implemented without Zve*. */
+static RISCVException vxsat(CPURISCVState *env, int csrno)
+{
+    if (riscv_cpu_cfg(env)->ext_zve32x) {
+        return vs(env, csrno);
+    }
+
+    if (riscv_has_ext(env, RVP)) {
+#if !defined(CONFIG_USER_ONLY)
+        return smstateen_acc_ok(env, 0, SMSTATEEN0_VXSAT);
+#else
+        return RISCV_EXCP_NONE;
+#endif
+    }
+
+    return RISCV_EXCP_ILLEGAL_INST;
+}
+
 static RISCVException ctr(CPURISCVState *env, int csrno)
 {
 #if !defined(CONFIG_USER_ONLY)
@@ -1013,7 +1031,12 @@ static RISCVException write_vxsat(CPURISCVState *env, int csrno,
                                   target_ulong val, uintptr_t ra)
 {
 #if !defined(CONFIG_USER_ONLY)
-    env->mstatus |= MSTATUS_VS;
+    if (riscv_cpu_cfg(env)->ext_zve32x) {
+        env->mstatus |= MSTATUS_VS;
+        if (env->virt_enabled) {
+            env->mstatus_hs |= MSTATUS_VS;
+        }
+    }
 #endif
     env->vxsat = val & BIT(0);
     return RISCV_EXCP_NONE;
@@ -3494,6 +3517,10 @@ static RISCVException write_mstateen0(CPURISCVState *env, int csrno,
                                       target_ulong new_val, uintptr_t ra)
 {
     uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG;
+
+    if (riscv_has_ext(env, RVP) && !riscv_cpu_cfg(env)->ext_zve32x) {
+        wr_mask |= SMSTATEEN0_VXSAT;
+    }
     if (!riscv_has_ext(env, RVF)) {
         wr_mask |= SMSTATEEN0_FCSR;
     }
@@ -3617,6 +3644,10 @@ static RISCVException write_hstateen0(CPURISCVState *env, int csrno,
 {
     uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG;
 
+    if (riscv_has_ext(env, RVP) && !riscv_cpu_cfg(env)->ext_zve32x) {
+        wr_mask |= SMSTATEEN0_VXSAT;
+    }
+
     if (!riscv_has_ext(env, RVF)) {
         wr_mask |= SMSTATEEN0_FCSR;
     }
@@ -3746,6 +3777,10 @@ static RISCVException write_sstateen0(CPURISCVState *env, int csrno,
 {
     uint64_t wr_mask = 0;
 
+    if (riscv_has_ext(env, RVP) && !riscv_cpu_cfg(env)->ext_zve32x) {
+        wr_mask |= SMSTATEEN0_VXSAT;
+    }
+
     if (!riscv_has_ext(env, RVF)) {
         wr_mask |= SMSTATEEN0_FCSR;
     }
@@ -5916,7 +5951,7 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
     [CSR_FCSR]     = { "fcsr",     fs,     read_fcsr,    write_fcsr   },
     /* Vector CSRs */
     [CSR_VSTART]   = { "vstart",   vs,     read_vstart,  write_vstart },
-    [CSR_VXSAT]    = { "vxsat",    vs,     read_vxsat,   write_vxsat  },
+    [CSR_VXSAT]    = { "vxsat",    vxsat,  read_vxsat,   write_vxsat  },
     [CSR_VXRM]     = { "vxrm",     vs,     read_vxrm,    write_vxrm   },
     [CSR_VCSR]     = { "vcsr",     vs,     read_vcsr,    write_vcsr   },
     [CSR_VL]       = { "vl",       vs,     read_vl                    },
diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
index 4af5cd9c731..1665583accf 100644
--- a/target/riscv/tcg/tcg-cpu.c
+++ b/target/riscv/tcg/tcg-cpu.c
@@ -160,6 +160,8 @@ static TCGTBCPUState riscv_get_tb_cpu_state(CPUState *cs)
     fs = EXT_STATUS_DIRTY;
     vs = EXT_STATUS_DIRTY;
 #else
+    RISCVException p_vxsat_excp;
+
     flags = FIELD_DP32(flags, TB_FLAGS, PRIV, env->priv);
 
     flags |= riscv_env_mmu_index(env, 0);
@@ -182,6 +184,23 @@ static TCGTBCPUState riscv_get_tb_cpu_state(CPUState *cs)
              ? EXT_STATUS_DIRTY : EXT_STATUS_DISABLED;
     }
 
+    /*
+     * Without Zve*, all P instructions in the OP-32 and OP-IMM-32
+     * spaces are controlled by stateen0.VXSAT.  Preserve the exception
+     * class in the TB flags so translated code can distinguish an illegal
+     * instruction from a virtual-instruction exception.
+     */
+    p_vxsat_excp = smstateen_acc_ok(env, 0, SMSTATEEN0_VXSAT);
+    if (riscv_has_ext(env, RVP) && !riscv_cpu_cfg(env)->ext_zve32x) {
+        if (p_vxsat_excp == RISCV_EXCP_VIRT_INSTRUCTION_FAULT) {
+            ext_flags = FIELD_DP64(ext_flags, EXT_TB_FLAGS, P_VXSAT_EXCP,
+                                   P_VXSAT_EXCP_VIRTUAL);
+        } else if (p_vxsat_excp != RISCV_EXCP_NONE) {
+            ext_flags = FIELD_DP64(ext_flags, EXT_TB_FLAGS, P_VXSAT_EXCP,
+                                   P_VXSAT_EXCP_ILLEGAL);
+        }
+    }
+
     if (cpu->cfg.debug && !icount_enabled()) {
         flags = FIELD_DP32(flags, TB_FLAGS, ITRIGGER, env->itrigger_enabled);
     }
@@ -530,6 +549,28 @@ static void riscv_cpu_validate_b(RISCVCPU *cpu)
     }
 }
 
+static void riscv_cpu_validate_p(RISCVCPU *cpu, Error **errp)
+{
+    CPURISCVState *env = &cpu->env;
+
+    if (!riscv_has_ext(env, RVP)) {
+        return;
+    }
+
+    if (riscv_cpu_mxl(env) != MXL_RV32 &&
+        riscv_cpu_mxl(env) != MXL_RV64) {
+        error_setg(errp, "P extension requires RV32 or RV64");
+        return;
+    }
+
+    if (!(cpu->cfg.ext_zmmul && cpu->cfg.ext_zba && cpu->cfg.ext_zbb &&
+          cpu->cfg.ext_zbkb)) {
+        error_setg(errp, "P extension requires zmmul, zba, zbb and zbkb "
+                         "extensions");
+        return;
+    }
+}
+
 /*
  * Check consistency between chosen extensions while setting
  * cpu->cfg accordingly.
@@ -612,6 +653,12 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp)
         return;
     }
 
+    riscv_cpu_validate_p(cpu, &local_err);
+    if (local_err != NULL) {
+        error_propagate(errp, local_err);
+        return;
+    }
+
     riscv_cpu_validate_v(env, &cpu->cfg, &local_err);
     if (local_err != NULL) {
         error_propagate(errp, local_err);
@@ -1414,6 +1461,7 @@ static const RISCVCPUMisaExtConfig misa_ext_cfgs[] = {
     MISA_CFG(RVV, false),
     MISA_CFG(RVG, false),
     MISA_CFG(RVB, false),
+    MISA_CFG(RVP, false),
 };
 
 /*
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH v2 02/18] target/riscv: Add packed SIMD helper framework
  2026-07-17 10:06 [PATCH v2 00/18] target/riscv: Add support for RISC-V P Molly Chen
  2026-07-17 10:06 ` [PATCH v2 01/18] target/riscv: Add packed SIMD extension state Molly Chen
@ 2026-07-17 10:06 ` Molly Chen
  2026-07-26 19:53   ` Daniel Henrique Barboza
                     ` (2 more replies)
  2026-07-17 10:06 ` [PATCH v2 03/18] target/riscv: Add packed SIMD arithmetic instructions Molly Chen
                   ` (17 subsequent siblings)
  19 siblings, 3 replies; 34+ messages in thread
From: Molly Chen @ 2026-07-17 10:06 UTC (permalink / raw)
  To: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
	chao.liu.zevorn, Chao Liu
  Cc: xiaoou, qemu-riscv, qemu-devel

Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
---
 target/riscv/tcg/meson.build    |    3 +-
 target/riscv/tcg/psimd_helper.c | 1656 +++++++++++++++++++++++++++++++
 2 files changed, 1658 insertions(+), 1 deletion(-)
 create mode 100644 target/riscv/tcg/psimd_helper.c

diff --git a/target/riscv/tcg/meson.build b/target/riscv/tcg/meson.build
index a05ab642f41..cc438d7c0d2 100644
--- a/target/riscv/tcg/meson.build
+++ b/target/riscv/tcg/meson.build
@@ -15,7 +15,8 @@ riscv_ss.add(files(
   'vcrypto_helper.c',
   'vector_helper.c',
   'vector_internals.c',
-  'zce_helper.c'))
+  'zce_helper.c',
+  'psimd_helper.c'))
 
 
 riscv_system_ss.add(files(
diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
new file mode 100644
index 00000000000..2948bbb2a86
--- /dev/null
+++ b/target/riscv/tcg/psimd_helper.c
@@ -0,0 +1,1656 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* RISC-V Packed SIMD Extension Helpers for QEMU. */
+/* Copyright (C) 2026 ISRC ISCAS. */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "qemu/host-utils.h"
+#include "exec/helper-proto.h"
+#include "fpu/softfloat.h"
+#include "internals.h"
+
+
+/* Helper macros */
+
+/* Element count calculations */
+#define ELEMS_B(target) (sizeof(target) * 8 / 8)    /* byte elements count */
+#define ELEMS_H(target) (sizeof(target) * 8 / 16)
+#define ELEMS_W(target) (sizeof(target) * 8 / 32)   /* word elements count */
+#define ELEMS_D(target) (sizeof(target) * 8 / 64)
+
+/* Element extraction macros - unsigned to avoid sign extension */
+#define EXTRACT8(val, idx)  (((val) >> ((idx) * 8)) & 0xFF)
+#define EXTRACT16(val, idx) (((val) >> ((idx) * 16)) & 0xFFFF)
+#define EXTRACT32(val, idx) (((val) >> ((idx) * 32)) & 0xFFFFFFFF)
+#define EXTRACT64(val, idx) (((val) >> ((idx) * 64)) & 0xFFFFFFFFFFFFFFFFULL)
+
+/* Element insertion macros */
+#define INSERT8(val, res, idx) \
+    ((val) | ((target_ulong)(uint8_t)(res) << ((idx) * 8)))
+#define INSERT16(val, res, idx) \
+    ((val) | ((target_ulong)(uint16_t)(res) << ((idx) * 16)))
+#define INSERT32(val, res, idx) \
+    ((val) | ((target_ulong)(uint32_t)(res) << ((idx) * 32)))
+#define INSERT32_64(val, res, idx) \
+    ((val) | ((uint64_t)(uint32_t)(res) << ((idx) * 32)))
+#define INSERT64(val, res, idx) \
+    ((val) | ((uint64_t)(res) << ((idx) * 64)))
+
+/* Saturation constants */
+static const int8_t   SAT_MAX_B = 127;
+static const int8_t   SAT_MIN_B = -128;
+static const int16_t  SAT_MAX_H = 32767;
+static const int16_t  SAT_MIN_H = -32768;
+static const int32_t  SAT_MAX_W = 2147483647;
+static const int32_t  SAT_MIN_W = -2147483648LL;
+static const uint8_t  USAT_MAX_B = 255;
+static const uint16_t USAT_MAX_H = 65535;
+static const uint32_t USAT_MAX_W = 4294967295U;
+
+
+/* Saturation helper functions */
+
+/**
+ * Signed saturation for 8-bit elements
+ * Returns saturated value and sets *sat if saturation occurred
+ */
+static inline int8_t signed_saturate_b(int32_t val, int *sat)
+{
+    if (val > SAT_MAX_B) {
+        *sat = 1;
+        return SAT_MAX_B;
+    }
+    if (val < SAT_MIN_B) {
+        *sat = 1;
+        return SAT_MIN_B;
+    }
+    return (int8_t)val;
+}
+
+/**
+ * Signed saturation for 16-bit elements
+ */
+static inline int16_t signed_saturate_h(int32_t val, int *sat)
+{
+    if (val > SAT_MAX_H) {
+        *sat = 1;
+        return SAT_MAX_H;
+    }
+    if (val < SAT_MIN_H) {
+        *sat = 1;
+        return SAT_MIN_H;
+    }
+    return (int16_t)val;
+}
+
+/**
+ * Signed saturation for 32-bit elements
+ */
+static inline int32_t signed_saturate_w(int64_t val, int *sat)
+{
+    if (val > SAT_MAX_W) {
+        *sat = 1;
+        return SAT_MAX_W;
+    }
+    if (val < SAT_MIN_W) {
+        *sat = 1;
+        return SAT_MIN_W;
+    }
+    return (int32_t)val;
+}
+
+/**
+ * Unsigned saturation for 8-bit elements
+ */
+static inline uint8_t unsigned_saturate_b(uint32_t val, int *sat)
+{
+    if (val > USAT_MAX_B) {
+        *sat = 1;
+        return USAT_MAX_B;
+    }
+    return (uint8_t)val;
+}
+
+/**
+ * Unsigned saturation for 16-bit elements
+ */
+static inline uint16_t unsigned_saturate_h(uint32_t val, int *sat)
+{
+    if (val > USAT_MAX_H) {
+        *sat = 1;
+        return USAT_MAX_H;
+    }
+    return (uint16_t)val;
+}
+
+/**
+ * Unsigned saturation for 32-bit elements
+ */
+static inline uint32_t unsigned_saturate_w(uint64_t val, int *sat)
+{
+    if (val > USAT_MAX_W) {
+        *sat = 1;
+        return USAT_MAX_W;
+    }
+    return (uint32_t)val;
+}
+
+static inline target_ulong psimd_abdsumu_b(target_ulong rs1,
+                                           target_ulong rs2,
+                                           target_ulong sum)
+{
+    int elems = ELEMS_B(rs1);
+
+    for (int i = 0; i < elems; i++) {
+        uint8_t e1 = EXTRACT8(rs1, i);
+        uint8_t e2 = EXTRACT8(rs2, i);
+        uint8_t diff = (e1 > e2) ? (e1 - e2) : (e2 - e1);
+        sum += diff;
+    }
+
+    return sum;
+}
+
+#define PSIMD_DO_ADD(N, M) ((N) + (M))
+#define PSIMD_DO_SUB(N, M) ((N) - (M))
+#define PSIMD_DO_ABD(N, M) ((N) >= (M) ? (N) - (M) : (M) - (N))
+#define PSIMD_DO_EQ_MASK(N, M) ((N) == (M) ? -1 : 0)
+#define PSIMD_DO_LT_MASK(N, M) ((N) < (M) ? -1 : 0)
+#define PSIMD_DO_MIN(N, M) ((N) < (M) ? (N) : (M))
+#define PSIMD_DO_MAX(N, M) ((N) > (M) ? (N) : (M))
+#define PSIMD_DO_SLL(N, M) ((N) << (M))
+#define PSIMD_DO_SRL(N, M) ((N) >> (M))
+#define PSIMD_DO_SRA(N, M) ((N) >> (M))
+
+#define GEN_PSIMD_BINOP(NAME, RTYPE, STYPE, DTYPE, EXTRACT, INSERT,       \
+                        ELEMS, OP)                                        \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
+{                                                                         \
+    RTYPE rd = 0;                                                         \
+    int elems = ELEMS(rd);                                                \
+                                                                          \
+    for (int i = 0; i < elems; i++) {                                     \
+        STYPE e1 = (STYPE)EXTRACT(rs1, i);                                \
+        STYPE e2 = (STYPE)EXTRACT(rs2, i);                                \
+        DTYPE res = (DTYPE)OP(e1, e2);                                    \
+        rd = INSERT(rd, res, i);                                          \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_BINOP_SCALAR(NAME, RTYPE, ETYPE, EXTRACT, INSERT,       \
+                               ELEMS, OP)                                 \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
+{                                                                         \
+    RTYPE rd = 0;                                                         \
+    int elems = ELEMS(rd);                                                \
+    ETYPE e2 = (ETYPE)EXTRACT(rs2, 0);                                    \
+                                                                          \
+    for (int i = 0; i < elems; i++) {                                     \
+        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
+        ETYPE res = OP(e1, e2);                                           \
+        rd = INSERT(rd, res, i);                                          \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_SHIFTOP(NAME, RTYPE, STYPE, DTYPE, EXTRACT, INSERT,     \
+                          ELEMS, SHMASK, OP)                              \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
+{                                                                         \
+    RTYPE rd = 0;                                                         \
+    int elems = ELEMS(rd);                                                \
+    uint8_t shamt = rs2 & (SHMASK);                                       \
+                                                                          \
+    for (int i = 0; i < elems; i++) {                                     \
+        STYPE e1 = (STYPE)EXTRACT(rs1, i);                                \
+        DTYPE res = (DTYPE)OP(e1, shamt);                                 \
+        rd = INSERT(rd, res, i);                                          \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_SAT_SHIFTOP(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT, \
+                              ELEMS, SHMASK, SAT_FN)                      \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
+{                                                                         \
+    RTYPE rd = 0;                                                         \
+    int elems = ELEMS(rd);                                                \
+    int sat = 0;                                                          \
+    uint8_t shamt = rs2 & (SHMASK);                                       \
+                                                                          \
+    for (int i = 0; i < elems; i++) {                                     \
+        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
+        WTYPE shifted = (WTYPE)e1 << shamt;                               \
+        ETYPE res = SAT_FN(shifted, &sat);                                \
+        rd = INSERT(rd, res, i);                                          \
+    }                                                                     \
+                                                                          \
+    if (sat) {                                                            \
+        env->vxsat = 1;                                                   \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_ROUND_SRAI(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT,  \
+                             ELEMS, SHMASK)                               \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
+{                                                                         \
+    RTYPE rd = 0;                                                         \
+    int elems = ELEMS(rd);                                                \
+    uint8_t shamt = rs2 & (SHMASK);                                       \
+                                                                          \
+    if (shamt == 0) {                                                     \
+        return rs1;                                                       \
+    }                                                                     \
+                                                                          \
+    for (int i = 0; i < elems; i++) {                                     \
+        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
+        WTYPE rounded = (((WTYPE)e1 >> (shamt - 1)) + 1) >> 1;            \
+        rd = INSERT(rd, (ETYPE)rounded, i);                               \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_SAT_BINOP(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT,   \
+                            ELEMS, OP, SAT_FN)                            \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
+{                                                                         \
+    RTYPE rd = 0;                                                         \
+    int elems = ELEMS(rd);                                                \
+    int sat = 0;                                                          \
+                                                                          \
+    for (int i = 0; i < elems; i++) {                                     \
+        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
+        ETYPE e2 = (ETYPE)EXTRACT(rs2, i);                                \
+        WTYPE val = OP((WTYPE)e1, (WTYPE)e2);                             \
+        ETYPE res = SAT_FN(val, &sat);                                    \
+        rd = INSERT(rd, res, i);                                          \
+    }                                                                     \
+                                                                          \
+    if (sat) {                                                            \
+        env->vxsat = 1;                                                   \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_USUB_SAT(NAME, RTYPE, ETYPE, EXTRACT, INSERT, ELEMS)    \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
+{                                                                         \
+    RTYPE rd = 0;                                                         \
+    int elems = ELEMS(rd);                                                \
+    int sat = 0;                                                          \
+                                                                          \
+    for (int i = 0; i < elems; i++) {                                     \
+        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
+        ETYPE e2 = (ETYPE)EXTRACT(rs2, i);                                \
+        ETYPE res = (e1 >= e2) ? (e1 - e2) : 0;                           \
+        if (e1 < e2) {                                                    \
+            sat = 1;                                                      \
+        }                                                                 \
+        rd = INSERT(rd, res, i);                                          \
+    }                                                                     \
+                                                                          \
+    if (sat) {                                                            \
+        env->vxsat = 1;                                                   \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_AVG_BINOP(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT,   \
+                            ELEMS, OP)                                    \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
+{                                                                         \
+    RTYPE rd = 0;                                                         \
+    int elems = ELEMS(rd);                                                \
+                                                                          \
+    for (int i = 0; i < elems; i++) {                                     \
+        WTYPE e1 = (WTYPE)(ETYPE)EXTRACT(rs1, i);                         \
+        WTYPE e2 = (WTYPE)(ETYPE)EXTRACT(rs2, i);                         \
+        ETYPE res = (ETYPE)(OP(e1, e2) >> 1);                             \
+        rd = INSERT(rd, res, i);                                          \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_SHADD(NAME, RTYPE, ETYPE, EXTRACT, INSERT, ELEMS,       \
+                        SHAMT)                                            \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
+{                                                                         \
+    RTYPE rd = 0;                                                         \
+    int elems = ELEMS(rd);                                                \
+                                                                          \
+    for (int i = 0; i < elems; i++) {                                     \
+        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
+        ETYPE e2 = (ETYPE)EXTRACT(rs2, i);                                \
+        ETYPE res = (e1 << (SHAMT)) + e2;                                 \
+        rd = INSERT(rd, res, i);                                          \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_SAT_SHADD(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT,   \
+                            ELEMS, SHAMT, SH_MIN, SH_MAX, SAT_MIN,        \
+                            SAT_MAX, SAT_FN)                              \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
+{                                                                         \
+    RTYPE rd = 0;                                                         \
+    int elems = ELEMS(rd);                                                \
+    int sat = 0;                                                          \
+                                                                          \
+    for (int i = 0; i < elems; i++) {                                     \
+        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
+        ETYPE e2 = (ETYPE)EXTRACT(rs2, i);                                \
+        WTYPE shifted;                                                    \
+                                                                          \
+        if (e1 > (SH_MAX) || e1 < (SH_MIN)) {                             \
+            shifted = (e1 < 0) ? (SAT_MIN) : (SAT_MAX);                   \
+            sat = 1;                                                      \
+        } else {                                                          \
+            shifted = (WTYPE)e1 << (SHAMT);                               \
+        }                                                                 \
+                                                                          \
+        WTYPE sum = shifted + e2;                                         \
+        ETYPE res = SAT_FN(sum, &sat);                                    \
+        rd = INSERT(rd, res, i);                                          \
+    }                                                                     \
+                                                                          \
+    if (sat) {                                                            \
+        env->vxsat = 1;                                                   \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_SATI(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT,        \
+                       ELEMS, IMMMASK)                                    \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE imm)              \
+{                                                                         \
+    RTYPE rd = 0;                                                         \
+    int elems = ELEMS(rd);                                                \
+    int range = (imm & (IMMMASK)) + 1;                                    \
+    WTYPE max = ((WTYPE)1 << (range - 1)) - 1;                            \
+    WTYPE min = -((WTYPE)1 << (range - 1));                               \
+    int sat = 0;                                                          \
+                                                                          \
+    for (int i = 0; i < elems; i++) {                                     \
+        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
+        ETYPE res;                                                        \
+                                                                          \
+        if (e1 > max) {                                                   \
+            res = max;                                                    \
+            sat = 1;                                                      \
+        } else if (e1 < min) {                                            \
+            res = min;                                                    \
+            sat = 1;                                                      \
+        } else {                                                          \
+            res = e1;                                                     \
+        }                                                                 \
+                                                                          \
+        rd = INSERT(rd, res, i);                                          \
+    }                                                                     \
+                                                                          \
+    if (sat) {                                                            \
+        env->vxsat = 1;                                                   \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_USATI(NAME, RTYPE, ETYPE, UTYPE, WTYPE, EXTRACT,        \
+                        INSERT, ELEMS, ONE)                               \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE imm)              \
+{                                                                         \
+    RTYPE rd = 0;                                                         \
+    int elems = ELEMS(rd);                                                \
+    WTYPE max = ((WTYPE)(ONE) << imm) - 1;                                \
+    int sat = 0;                                                          \
+                                                                          \
+    for (int i = 0; i < elems; i++) {                                     \
+        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
+        ETYPE res;                                                        \
+                                                                          \
+        if (e1 < 0) {                                                     \
+            res = 0;                                                      \
+            sat = 1;                                                      \
+        } else if ((UTYPE)e1 > max) {                                     \
+            res = max;                                                    \
+            sat = 1;                                                      \
+        } else {                                                          \
+            res = e1;                                                     \
+        }                                                                 \
+                                                                          \
+        rd = INSERT(rd, res, i);                                          \
+    }                                                                     \
+                                                                          \
+    if (sat) {                                                            \
+        env->vxsat = 1;                                                   \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_ABS(NAME, RTYPE, ETYPE, EXTRACT, INSERT, ELEMS,         \
+                      MINVAL, MAXVAL)                                     \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1)                         \
+{                                                                         \
+    RTYPE rd = 0;                                                         \
+    int elems = ELEMS(rd);                                                \
+    int sat = 0;                                                          \
+                                                                          \
+    for (int i = 0; i < elems; i++) {                                     \
+        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
+        ETYPE res;                                                        \
+                                                                          \
+        if (e1 == (MINVAL)) {                                             \
+            res = (MAXVAL);                                               \
+            sat = 1;                                                      \
+        } else if (e1 < 0) {                                              \
+            res = -e1;                                                    \
+        } else {                                                          \
+            res = e1;                                                     \
+        }                                                                 \
+                                                                          \
+        rd = INSERT(rd, res, i);                                          \
+    }                                                                     \
+                                                                          \
+    if (sat) {                                                            \
+        env->vxsat = 1;                                                   \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_SCALAR_ABS(NAME, RTYPE, STYPE, UTYPE)                   \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1)                         \
+{                                                                         \
+    STYPE value = (STYPE)rs1;                                            \
+    UTYPE result = (UTYPE)value;                                         \
+                                                                          \
+    if (value < 0) {                                                      \
+        result = (UTYPE)0 - result;                                      \
+    }                                                                     \
+    return (RTYPE)(STYPE)result;                                         \
+}
+
+#define GEN_PSIMD_VAR_SSHA(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT,    \
+                           ELEMS, BITS, SAT_FN)                           \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
+{                                                                         \
+    RTYPE rd = 0;                                                         \
+    int elems = ELEMS(rd);                                                \
+    int sat = 0;                                                          \
+    int8_t shamt = (int8_t)(rs2 & 0xff);                                  \
+                                                                          \
+    for (int i = 0; i < elems; i++) {                                     \
+        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
+        ETYPE res;                                                        \
+                                                                          \
+        if (shamt >= 0) {                                                 \
+            WTYPE shifted = (WTYPE)e1 << shamt;                           \
+            res = SAT_FN(shifted, &sat);                                  \
+        } else {                                                          \
+            int right = -shamt;                                           \
+            if (right >= (BITS)) {                                        \
+                res = (e1 < 0) ? -1 : 0;                                  \
+            } else {                                                      \
+                res = e1 >> right;                                        \
+            }                                                             \
+        }                                                                 \
+                                                                          \
+        rd = INSERT(rd, res, i);                                          \
+    }                                                                     \
+                                                                          \
+    if (sat) {                                                            \
+        env->vxsat = 1;                                                   \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_VAR_SSHAR(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT,   \
+                            ELEMS, BITS, SAT_MIN, SAT_MAX, SAT_FN)        \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
+{                                                                         \
+    RTYPE rd = 0;                                                         \
+    int elems = ELEMS(rd);                                                \
+    int sat = 0;                                                          \
+    int8_t shamt = (int8_t)(rs2 & 0xff);                                  \
+                                                                          \
+    for (int i = 0; i < elems; i++) {                                     \
+        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
+        ETYPE res;                                                        \
+                                                                          \
+        if (shamt >= 0) {                                                 \
+            if (shamt >= (BITS)) {                                        \
+                if (e1 == 0) {                                            \
+                    res = 0;                                              \
+                } else if (e1 > 0) {                                      \
+                    res = (SAT_MAX);                                      \
+                    sat = 1;                                              \
+                } else {                                                  \
+                    res = (SAT_MIN);                                      \
+                    sat = 1;                                              \
+                }                                                         \
+            } else {                                                      \
+                WTYPE shifted = (WTYPE)e1 * ((WTYPE)1 << shamt);          \
+                res = SAT_FN(shifted, &sat);                              \
+            }                                                             \
+        } else {                                                          \
+            int right = -shamt;                                           \
+            if (right >= (BITS)) {                                        \
+                res = 0;                                                  \
+            } else {                                                      \
+                WTYPE rounded = ((e1 >> (right - 1)) + 1) >> 1;           \
+                res = (ETYPE)rounded;                                     \
+            }                                                             \
+        }                                                                 \
+                                                                          \
+        rd = INSERT(rd, res, i);                                          \
+    }                                                                     \
+                                                                          \
+    if (sat) {                                                            \
+        env->vxsat = 1;                                                   \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_VAR_USHL(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT,    \
+                           ELEMS, BITS, SAT_FN)                           \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
+{                                                                         \
+    RTYPE rd = 0;                                                         \
+    int elems = ELEMS(rd);                                                \
+    int sat = 0;                                                          \
+    int8_t shamt = (int8_t)(rs2 & 0xff);                                  \
+                                                                          \
+    for (int i = 0; i < elems; i++) {                                     \
+        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
+        ETYPE res;                                                        \
+                                                                          \
+        if (shamt >= 0) {                                                 \
+            WTYPE shifted = (shamt >= (BITS)) ?                           \
+                            ((WTYPE)e1 << (BITS)) :                       \
+                            ((WTYPE)e1 << shamt);                         \
+            res = SAT_FN(shifted, &sat);                                  \
+        } else {                                                          \
+            int right = -shamt;                                           \
+            if (right >= (BITS)) {                                        \
+                res = 0;                                                  \
+            } else {                                                      \
+                res = e1 >> right;                                        \
+            }                                                             \
+        }                                                                 \
+                                                                          \
+        rd = INSERT(rd, res, i);                                          \
+    }                                                                     \
+                                                                          \
+    if (sat) {                                                            \
+        env->vxsat = 1;                                                   \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_VAR_USHLR(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT,   \
+                            ELEMS, BITS, SAT_FN)                          \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
+{                                                                         \
+    RTYPE rd = 0;                                                         \
+    int elems = ELEMS(rd);                                                \
+    int sat = 0;                                                          \
+    int8_t shamt = (int8_t)(rs2 & 0xff);                                  \
+                                                                          \
+    for (int i = 0; i < elems; i++) {                                     \
+        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
+        ETYPE res;                                                        \
+                                                                          \
+        if (shamt >= 0) {                                                 \
+            WTYPE shifted = (shamt >= (BITS)) ?                           \
+                            ((WTYPE)e1 << (BITS)) :                       \
+                            ((WTYPE)e1 << shamt);                         \
+            res = SAT_FN(shifted, &sat);                                  \
+        } else {                                                          \
+            int right = -shamt;                                           \
+            if (right > (BITS)) {                                         \
+                res = 0;                                                  \
+            } else {                                                      \
+                WTYPE rounded = ((WTYPE)e1 >> (right - 1)) + 1;           \
+                res = (ETYPE)(rounded >> 1);                              \
+            }                                                             \
+        }                                                                 \
+                                                                          \
+        rd = INSERT(rd, res, i);                                          \
+    }                                                                     \
+                                                                          \
+    if (sat) {                                                            \
+        env->vxsat = 1;                                                   \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define PSIMD_DO_SRA64(A, B) ((A) >> (B))
+#define PSIMD_DO_RNDSRA64(A, B)                                          \
+    ((int64_t)((((__int128_t)(A) >> ((B) - 1)) + 1) >> 1))
+
+#define GEN_PSIMD_VAR_SRA64(NAME, RIGHT_OP)                               \
+uint64_t HELPER(NAME)(CPURISCVState *env, uint64_t rs1, uint64_t rs2)     \
+{                                                                         \
+    int64_t a = (int64_t)rs1;                                            \
+    int8_t shamt = (int8_t)(rs2 & 0xff);                                 \
+                                                                          \
+    if (shamt >= 0) {                                                     \
+        return (uint64_t)(a << shamt);                                    \
+    }                                                                     \
+                                                                          \
+    int right = -shamt;                                                   \
+    if (right >= 64) {                                                    \
+        return (a < 0) ? (uint64_t)-1 : 0;                               \
+    }                                                                     \
+    return (uint64_t)RIGHT_OP(a, right);                                  \
+}
+
+#define PSIMD_DO_SRL64(A, B) (((B) >= 64) ? 0 : ((A) >> (B)))
+#define PSIMD_DO_RNDSRL64(A, B)                                          \
+    (((B) > 64) ? 0 : ((((A) >> ((B) - 1)) + 1) >> 1))
+
+#define GEN_PSIMD_VAR_SRL64(NAME, RIGHT_OP)                               \
+uint64_t HELPER(NAME)(CPURISCVState *env, uint64_t rs1, uint64_t rs2)     \
+{                                                                         \
+    int8_t shamt = (int8_t)(rs2 & 0xff);                                 \
+                                                                          \
+    if (shamt < 0) {                                                      \
+        return RIGHT_OP(rs1, -shamt);                                     \
+    }                                                                     \
+    return (shamt >= 64) ? 0 : (rs1 << shamt);                           \
+}
+
+#define GEN_PSIMD_XPAIR_BINOP(NAME, RTYPE, ETYPE, EXTRACT, INSERT,        \
+                              ELEMS, OP_LO, OP_HI)                        \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
+{                                                                         \
+    RTYPE rd = 0;                                                         \
+    int elems = ELEMS(rd);                                                \
+                                                                          \
+    for (int i = 0; i < elems; i += 2) {                                  \
+        ETYPE s1_lo = (ETYPE)EXTRACT(rs1, i);                             \
+        ETYPE s1_hi = (ETYPE)EXTRACT(rs1, i + 1);                         \
+        ETYPE s2_lo = (ETYPE)EXTRACT(rs2, i);                             \
+        ETYPE s2_hi = (ETYPE)EXTRACT(rs2, i + 1);                         \
+        ETYPE res_lo = OP_LO(s1_lo, s2_hi);                               \
+        ETYPE res_hi = OP_HI(s1_hi, s2_lo);                               \
+        rd = INSERT(rd, res_lo, i);                                       \
+        rd = INSERT(rd, res_hi, i + 1);                                   \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_XPAIR_SAT_BINOP(NAME, RTYPE, ETYPE, WTYPE, EXTRACT,     \
+                                  INSERT, ELEMS, OP_LO, OP_HI, SAT_FN)    \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
+{                                                                         \
+    RTYPE rd = 0;                                                         \
+    int elems = ELEMS(rd);                                                \
+    int sat = 0;                                                          \
+                                                                          \
+    for (int i = 0; i < elems; i += 2) {                                  \
+        ETYPE s1_lo = (ETYPE)EXTRACT(rs1, i);                             \
+        ETYPE s1_hi = (ETYPE)EXTRACT(rs1, i + 1);                         \
+        ETYPE s2_lo = (ETYPE)EXTRACT(rs2, i);                             \
+        ETYPE s2_hi = (ETYPE)EXTRACT(rs2, i + 1);                         \
+        WTYPE val_lo = OP_LO((WTYPE)s1_lo, (WTYPE)s2_hi);                 \
+        WTYPE val_hi = OP_HI((WTYPE)s1_hi, (WTYPE)s2_lo);                 \
+        ETYPE res_lo = SAT_FN(val_lo, &sat);                              \
+        ETYPE res_hi = SAT_FN(val_hi, &sat);                              \
+        rd = INSERT(rd, res_lo, i);                                       \
+        rd = INSERT(rd, res_hi, i + 1);                                   \
+    }                                                                     \
+                                                                          \
+    if (sat) {                                                            \
+        env->vxsat = 1;                                                   \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_XPAIR_AVG_BINOP(NAME, RTYPE, ETYPE, WTYPE, EXTRACT,     \
+                                  INSERT, ELEMS, OP_LO, OP_HI)            \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
+{                                                                         \
+    RTYPE rd = 0;                                                         \
+    int elems = ELEMS(rd);                                                \
+                                                                          \
+    for (int i = 0; i < elems; i += 2) {                                  \
+        ETYPE s1_lo = (ETYPE)EXTRACT(rs1, i);                             \
+        ETYPE s1_hi = (ETYPE)EXTRACT(rs1, i + 1);                         \
+        ETYPE s2_lo = (ETYPE)EXTRACT(rs2, i);                             \
+        ETYPE s2_hi = (ETYPE)EXTRACT(rs2, i + 1);                         \
+        ETYPE res_lo = (ETYPE)(OP_LO((WTYPE)s1_lo, (WTYPE)s2_hi) >> 1);   \
+        ETYPE res_hi = (ETYPE)(OP_HI((WTYPE)s1_hi, (WTYPE)s2_lo) >> 1);   \
+        rd = INSERT(rd, res_lo, i);                                       \
+        rd = INSERT(rd, res_hi, i + 1);                                   \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_REDSUM(NAME, RTYPE, SUMTYPE, ETYPE, EXTRACT, ELEMS,     \
+                         INIT)                                            \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
+{                                                                         \
+    SUMTYPE sum = (INIT);                                                 \
+    int elems = ELEMS(rs1);                                               \
+                                                                          \
+    for (int i = 0; i < elems; i++) {                                     \
+        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
+        sum += e1;                                                        \
+    }                                                                     \
+                                                                          \
+    return (RTYPE)sum;                                                    \
+}
+
+#define PSIMD_PAIR_LO(V, MASK, SHIFT) ((V) & (MASK))
+#define PSIMD_PAIR_HI(V, MASK, SHIFT) (((V) >> (SHIFT)) & (MASK))
+
+#define GEN_PSIMD_PAIR_PACK(NAME, RTYPE, ETYPE, EXTRACT, INSERT, ELEMS,   \
+                            MASK, SHIFT, HI_SEL, LO_SEL)                 \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
+{                                                                         \
+    RTYPE rd = 0;                                                         \
+    int elems = ELEMS(rd);                                                \
+                                                                          \
+    for (int i = 0; i < elems; i++) {                                     \
+        ETYPE e1 = EXTRACT(rs1, i);                                       \
+        ETYPE e2 = EXTRACT(rs2, i);                                       \
+        ETYPE res = (HI_SEL(e2, MASK, SHIFT) << (SHIFT)) |                \
+                    LO_SEL(e1, MASK, SHIFT);                              \
+        rd = INSERT(rd, res, i);                                          \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_PAIR_WORD(NAME, RS1_IDX, RS2_IDX)                       \
+uint64_t HELPER(NAME)(CPURISCVState *env, uint64_t rs1, uint64_t rs2)     \
+{                                                                         \
+    uint32_t e1 = EXTRACT32(rs1, RS1_IDX);                                \
+    uint32_t e2 = EXTRACT32(rs2, RS2_IDX);                                \
+                                                                          \
+    return ((uint64_t)e2 << 32) | e1;                                     \
+}
+
+#define GEN_PSIMD_SIGN_EXTEND(NAME, RTYPE, STYPE, DTYPE, EXTRACT, INSERT, \
+                              ELEMS, SCALE)                               \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1)                         \
+{                                                                         \
+    RTYPE rd = 0;                                                         \
+    int elems = ELEMS(rd);                                                \
+                                                                          \
+    for (int i = 0; i < elems; i++) {                                     \
+        STYPE e1 = (STYPE)EXTRACT(rs1, i * (SCALE));                      \
+        rd = INSERT(rd, (DTYPE)e1, i);                                    \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_ZIP(NAME, ETYPE, EXTRACT, ELEMS, BITS, START)           \
+uint64_t HELPER(NAME)(CPURISCVState *env, uint64_t rs1, uint64_t rs2)     \
+{                                                                         \
+    uint64_t rd = 0;                                                      \
+                                                                          \
+    for (int i = 0; i < (ELEMS); i++) {                                   \
+        ETYPE e1 = EXTRACT(rs1, (START) - i);                             \
+        ETYPE e2 = EXTRACT(rs2, (START) - i);                             \
+        rd = (rd << (2 * (BITS))) | ((uint64_t)e2 << (BITS)) | e1;        \
+    }                                                                     \
+                                                                          \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_UNZIP(NAME, EXTRACT, ELEMS, BITS, OFFSET)               \
+uint64_t HELPER(NAME)(CPURISCVState *env, uint64_t rs1, uint64_t rs2)     \
+{                                                                         \
+    uint64_t rd = 0;                                                      \
+                                                                          \
+    for (int i = 0; i < (ELEMS); i++) {                                   \
+        uint64_t e1 = (uint64_t)EXTRACT(rs1, 2 * i + (OFFSET)) <<         \
+                      ((BITS) * i);                                       \
+        uint64_t e2 = (uint64_t)EXTRACT(rs2, 2 * i + (OFFSET)) <<         \
+                      (32 + (BITS) * i);                                  \
+        rd = rd | e2 | e1;                                                \
+    }                                                                     \
+                                                                          \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_BIT_SELECT(NAME, MASK, TRUE_VAL, FALSE_VAL)             \
+target_ulong HELPER(NAME)(CPURISCVState *env, target_ulong rs1,           \
+                          target_ulong rs2, target_ulong rd)              \
+{                                                                         \
+    return (~(MASK) & (FALSE_VAL)) | ((MASK) & (TRUE_VAL));               \
+}
+
+#define GEN_PSIMD_NCLIP_PACK(NAME, ITYPE, OTYPE, EXTRACT, INSERT, ELEMS,  \
+                             SAT_FN)                                      \
+uint64_t HELPER(NAME)(CPURISCVState *env, uint64_t rs1, uint64_t rs2)     \
+{                                                                         \
+    uint64_t rd = 0;                                                      \
+    int sat = 0;                                                          \
+                                                                          \
+    for (int i = 0; i < (ELEMS); i++) {                                   \
+        ITYPE lo = (ITYPE)EXTRACT(rs1, i);                                \
+        ITYPE hi = (ITYPE)EXTRACT(rs2, i);                                \
+        OTYPE res_lo = SAT_FN(lo, &sat);                                  \
+        OTYPE res_hi = SAT_FN(hi, &sat);                                  \
+                                                                          \
+        rd = (uint64_t)INSERT(rd, res_lo, i);                             \
+        rd = (uint64_t)INSERT(rd, res_hi, i + (ELEMS));                   \
+    }                                                                     \
+                                                                          \
+    if (sat) {                                                            \
+        env->vxsat = 1;                                                   \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_CLS(NAME, RTYPE, UTYPE, CLRSB)                          \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1)                         \
+{                                                                         \
+    return CLRSB((UTYPE)rs1);                                             \
+}
+
+#define PSIMD_MUL_S32(A, B)  ((int32_t)(A) * (int32_t)(B))
+#define PSIMD_MUL_SU16(A, B) ((int16_t)(A) * (uint16_t)(B))
+#define PSIMD_MUL_SU32(A, B) ((int32_t)(A) * (uint32_t)(B))
+#define PSIMD_MUL_U32(A, B)  ((uint32_t)(A) * (uint32_t)(B))
+#define PSIMD_MUL_S64(A, B)  ((int64_t)(A) * (int64_t)(B))
+#define PSIMD_MUL_SU64(A, B) ((int64_t)(A) * (uint64_t)(B))
+#define PSIMD_MUL_U64(A, B)  ((uint64_t)(A) * (uint64_t)(B))
+
+#define GEN_PSIMD_MUL_HIGH(NAME, RTYPE, E1TYPE, E2TYPE, PTYPE, HTYPE,     \
+                           EXTRACT, INSERT, ELEMS, SHIFT, ROUND, OP)     \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
+{                                                                         \
+    RTYPE rd = 0;                                                         \
+    int elems = ELEMS(rd);                                                \
+                                                                          \
+    for (int i = 0; i < elems; i++) {                                     \
+        E1TYPE e1 = (E1TYPE)EXTRACT(rs1, i);                              \
+        E2TYPE e2 = (E2TYPE)EXTRACT(rs2, i);                              \
+        PTYPE prod = OP(e1, e2) + (ROUND);                                \
+        HTYPE high = (HTYPE)(prod >> (SHIFT));                            \
+        rd = INSERT(rd, high, i);                                         \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_MUL_HIGH_SEL(NAME, RTYPE, E1TYPE, E2TYPE, PTYPE,        \
+                               HTYPE, EXTRACT1, EXTRACT2, INSERT, ELEMS, \
+                               SCALE, OFFSET, SHIFT, OP)                 \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
+{                                                                         \
+    RTYPE rd = 0;                                                         \
+    int elems = ELEMS(rd);                                                \
+                                                                          \
+    for (int i = 0; i < elems; i++) {                                     \
+        E1TYPE e1 = (E1TYPE)EXTRACT1(rs1, i);                             \
+        E2TYPE e2 = (E2TYPE)EXTRACT2(rs2, i * (SCALE) + (OFFSET));        \
+        PTYPE prod = OP(e1, e2);                                          \
+        HTYPE high = (HTYPE)(prod >> (SHIFT));                            \
+        rd = INSERT(rd, high, i);                                         \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_MUL_ELEM_INDEXED(NAME, RTYPE, E1TYPE, E2TYPE, PTYPE,    \
+                                   OTYPE, EXTRACT, INSERT, ELEMS, SCALE, \
+                                   OFFSET1, OFFSET2, OP)                 \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
+{                                                                         \
+    RTYPE rd = 0;                                                         \
+    int elems = ELEMS(rd);                                                \
+                                                                          \
+    for (int i = 0; i < elems; i++) {                                     \
+        E1TYPE e1 = (E1TYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET1));        \
+        E2TYPE e2 = (E2TYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET2));        \
+        PTYPE mul = OP(e1, e2);                                           \
+        rd = INSERT(rd, (OTYPE)mul, i);                                   \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_MUL_ELEM_SCALAR(NAME, RTYPE, E1TYPE, E2TYPE, PTYPE,     \
+                                  EXTRACT, OFFSET1, OFFSET2, OP)         \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
+{                                                                         \
+    E1TYPE e1 = (E1TYPE)EXTRACT(rs1, OFFSET1);                            \
+    E2TYPE e2 = (E2TYPE)EXTRACT(rs2, OFFSET2);                            \
+    PTYPE mul = OP(e1, e2);                                               \
+                                                                          \
+    return (RTYPE)mul;                                                    \
+}
+
+#define GEN_PSIMD_MUL_HIGH_ACC(NAME, RTYPE, E1TYPE, E2TYPE, DTYPE, PTYPE, \
+                               HTYPE, OTYPE, EXTRACT, INSERT, ELEMS,     \
+                               SHIFT, ROUND, OP)                         \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2, RTYPE dest)  \
+{                                                                         \
+    RTYPE rd = 0;                                                         \
+    int elems = ELEMS(rd);                                                \
+                                                                          \
+    for (int i = 0; i < elems; i++) {                                     \
+        E1TYPE e1 = (E1TYPE)EXTRACT(rs1, i);                              \
+        E2TYPE e2 = (E2TYPE)EXTRACT(rs2, i);                              \
+        DTYPE d = (DTYPE)EXTRACT(dest, i);                                \
+        PTYPE prod = OP(e1, e2) + (ROUND);                                \
+        HTYPE high = (HTYPE)(prod >> (SHIFT));                            \
+        OTYPE res = (OTYPE)(high + d);                                    \
+        rd = INSERT(rd, res, i);                                          \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_MUL_HIGH_ACC_SEL(NAME, RTYPE, E1TYPE, E2TYPE, DTYPE,    \
+                                   PTYPE, HTYPE, OTYPE, EXTRACT1,        \
+                                   EXTRACT2, INSERT, ELEMS, SCALE,       \
+                                   OFFSET, SHIFT, OP)                    \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2, RTYPE dest)  \
+{                                                                         \
+    RTYPE rd = 0;                                                         \
+    int elems = ELEMS(rd);                                                \
+                                                                          \
+    for (int i = 0; i < elems; i++) {                                     \
+        E1TYPE e1 = (E1TYPE)EXTRACT1(rs1, i);                             \
+        E2TYPE e2 = (E2TYPE)EXTRACT2(rs2, i * (SCALE) + (OFFSET));        \
+        DTYPE d = (DTYPE)EXTRACT1(dest, i);                               \
+        PTYPE prod = OP(e1, e2);                                          \
+        HTYPE high = (HTYPE)(prod >> (SHIFT));                            \
+        OTYPE res = (OTYPE)(high + d);                                    \
+        rd = INSERT(rd, res, i);                                          \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_MUL_ACC_INDEXED(NAME, RTYPE, E1TYPE, E2TYPE, DTYPE,     \
+                                  PTYPE, OTYPE, EXTRACT, EXTRACTD,       \
+                                  INSERT, ELEMS, SCALE, OFFSET1,         \
+                                  OFFSET2, OP)                           \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2, RTYPE dest)  \
+{                                                                         \
+    RTYPE rd = 0;                                                         \
+    int elems = ELEMS(rd);                                                \
+                                                                          \
+    for (int i = 0; i < elems; i++) {                                     \
+        E1TYPE e1 = (E1TYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET1));        \
+        E2TYPE e2 = (E2TYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET2));        \
+        DTYPE d = (DTYPE)EXTRACTD(dest, i);                               \
+        PTYPE mul = OP(e1, e2);                                           \
+        rd = INSERT(rd, (OTYPE)(d + mul), i);                             \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_QMUL(NAME, RTYPE, ETYPE, PTYPE, OTYPE, EXTRACT, INSERT, \
+                       ELEMS, SHIFT, ROUND, MINVAL, MAXVAL)              \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
+{                                                                         \
+    RTYPE rd = 0;                                                         \
+    int elems = ELEMS(rd);                                                \
+    int sat = 0;                                                          \
+                                                                          \
+    for (int i = 0; i < elems; i++) {                                     \
+        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
+        ETYPE e2 = (ETYPE)EXTRACT(rs2, i);                                \
+        OTYPE result;                                                     \
+                                                                          \
+        if ((e1 == (ETYPE)(MINVAL)) && (e2 == (ETYPE)(MINVAL))) {         \
+            sat = 1;                                                      \
+            result = (OTYPE)(MAXVAL);                                     \
+        } else {                                                          \
+            PTYPE prod = (PTYPE)e1 * (PTYPE)e2 + (ROUND);                 \
+            result = (OTYPE)(prod >> (SHIFT));                            \
+        }                                                                 \
+        rd = INSERT(rd, result, i);                                       \
+    }                                                                     \
+                                                                          \
+    if (sat) {                                                            \
+        env->vxsat = 1;                                                   \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_QMUL_ACC_INDEXED(NAME, RTYPE, E1TYPE, E2TYPE, DTYPE,    \
+                                   PTYPE, STYPE, OTYPE, EXTRACT,         \
+                                   EXTRACTD, INSERT, ELEMS, SCALE,       \
+                                   OFFSET1, OFFSET2, SHIFT, ROUND, OP)   \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2, RTYPE dest)  \
+{                                                                         \
+    RTYPE rd = 0;                                                         \
+    int elems = ELEMS(rd);                                                \
+                                                                          \
+    for (int i = 0; i < elems; i++) {                                     \
+        E1TYPE e1 = (E1TYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET1));        \
+        E2TYPE e2 = (E2TYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET2));        \
+        DTYPE d = (DTYPE)EXTRACTD(dest, i);                               \
+        PTYPE prod = OP(e1, e2) + (ROUND);                                \
+        STYPE scaled = (STYPE)(((__int128_t)prod) >> (SHIFT));            \
+        rd = INSERT(rd, (OTYPE)(d + scaled), i);                          \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_Q2ADD(NAME, RTYPE, ETYPE, PTYPE, STYPE, OTYPE, EXTRACT, \
+                        INSERT, ELEMS, SCALE, SHIFT, ROUND, OP)          \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
+{                                                                         \
+    RTYPE rd = 0;                                                         \
+    int elems = ELEMS(rd);                                                \
+                                                                          \
+    for (int i = 0; i < elems; i++) {                                     \
+        ETYPE s1_0 = (ETYPE)EXTRACT(rs1, i * (SCALE));                   \
+        ETYPE s1_1 = (ETYPE)EXTRACT(rs1, i * (SCALE) + 1);               \
+        ETYPE s2_0 = (ETYPE)EXTRACT(rs2, i * (SCALE));                   \
+        ETYPE s2_1 = (ETYPE)EXTRACT(rs2, i * (SCALE) + 1);               \
+        PTYPE prod0 = OP(s1_0, s2_0) + (ROUND);                          \
+        PTYPE prod1 = OP(s1_1, s2_1) + (ROUND);                          \
+        STYPE scaled0 = (STYPE)(((__int128_t)prod0) >> (SHIFT));          \
+        STYPE scaled1 = (STYPE)(((__int128_t)prod1) >> (SHIFT));          \
+        rd = INSERT(rd, (OTYPE)(scaled0 + scaled1), i);                   \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_Q2ADDA(NAME, RTYPE, ETYPE, DTYPE, PTYPE, STYPE, OTYPE,  \
+                         EXTRACT, EXTRACTD, INSERT, ELEMS, SCALE,        \
+                         SHIFT, ROUND, OP)                               \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2, RTYPE dest)  \
+{                                                                         \
+    RTYPE rd = 0;                                                         \
+    int elems = ELEMS(rd);                                                \
+                                                                          \
+    for (int i = 0; i < elems; i++) {                                     \
+        ETYPE s1_0 = (ETYPE)EXTRACT(rs1, i * (SCALE));                   \
+        ETYPE s1_1 = (ETYPE)EXTRACT(rs1, i * (SCALE) + 1);               \
+        ETYPE s2_0 = (ETYPE)EXTRACT(rs2, i * (SCALE));                   \
+        ETYPE s2_1 = (ETYPE)EXTRACT(rs2, i * (SCALE) + 1);               \
+        DTYPE d = (DTYPE)EXTRACTD(dest, i);                               \
+        PTYPE prod0 = OP(s1_0, s2_0) + (ROUND);                          \
+        PTYPE prod1 = OP(s1_1, s2_1) + (ROUND);                          \
+        STYPE scaled0 = (STYPE)(((__int128_t)prod0) >> (SHIFT));          \
+        STYPE scaled1 = (STYPE)(((__int128_t)prod1) >> (SHIFT));          \
+        rd = INSERT(rd, (OTYPE)(d + scaled0 + scaled1), i);               \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define PSIMD_COMB_ADD(D, A, B) ((D) + (A) + (B))
+#define PSIMD_COMB_SUB(D, A, B) ((D) + (A) - (B))
+
+#define GEN_PSIMD_2WAY_MUL(NAME, RTYPE, E1TYPE, E2TYPE, PTYPE, OTYPE,     \
+                           EXTRACT, INSERT, ELEMS, SCALE, OFFSET10,      \
+                           OFFSET11, OFFSET20, OFFSET21, OP, COMBINE)   \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
+{                                                                         \
+    RTYPE rd = 0;                                                         \
+    int elems = ELEMS(rd);                                                \
+                                                                          \
+    for (int i = 0; i < elems; i++) {                                     \
+        E1TYPE s1_0 = (E1TYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET10));     \
+        E1TYPE s1_1 = (E1TYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET11));     \
+        E2TYPE s2_0 = (E2TYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET20));     \
+        E2TYPE s2_1 = (E2TYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET21));     \
+        PTYPE prod0 = OP(s1_0, s2_0);                                     \
+        PTYPE prod1 = OP(s1_1, s2_1);                                     \
+        rd = INSERT(rd, (OTYPE)COMBINE(0, prod0, prod1), i);              \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_2WAY_SAT_MUL(NAME, OFFSET10, OFFSET11, OFFSET20,        \
+                               OFFSET21)                                 \
+target_ulong HELPER(NAME)(CPURISCVState *env, target_ulong rs1,           \
+                           target_ulong rs2)                              \
+{                                                                         \
+    target_ulong rd = 0;                                                  \
+    int sat = 0;                                                          \
+                                                                          \
+    for (int i = 0; i < ELEMS_W(rd); i++) {                               \
+        int16_t s1_0 = (int16_t)EXTRACT16(rs1, i * 2 + (OFFSET10));       \
+        int16_t s1_1 = (int16_t)EXTRACT16(rs1, i * 2 + (OFFSET11));       \
+        int16_t s2_0 = (int16_t)EXTRACT16(rs2, i * 2 + (OFFSET20));       \
+        int16_t s2_1 = (int16_t)EXTRACT16(rs2, i * 2 + (OFFSET21));       \
+        uint32_t result;                                                  \
+                                                                          \
+        if (s1_0 == INT16_MIN && s1_1 == INT16_MIN &&                    \
+            s2_0 == INT16_MIN && s2_1 == INT16_MIN) {                    \
+            result = INT32_MAX;                                          \
+            sat = 1;                                                      \
+        } else {                                                          \
+            int32_t prod0 = (int32_t)s1_0 * s2_0;                        \
+            int32_t prod1 = (int32_t)s1_1 * s2_1;                        \
+            result = (uint32_t)(prod0 + prod1);                           \
+        }                                                                 \
+        rd = INSERT32(rd, result, i);                                     \
+    }                                                                     \
+                                                                          \
+    if (sat) {                                                            \
+        env->vxsat = 1;                                                   \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_2WAY_MUL_ACC(NAME, RTYPE, E1TYPE, E2TYPE, DTYPE, PTYPE, \
+                               OTYPE, EXTRACT, EXTRACTD, INSERT, ELEMS,  \
+                               SCALE, OFFSET10, OFFSET11, OFFSET20,      \
+                               OFFSET21, OP, COMBINE)                   \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2, RTYPE dest)  \
+{                                                                         \
+    RTYPE rd = 0;                                                         \
+    int elems = ELEMS(rd);                                                \
+                                                                          \
+    for (int i = 0; i < elems; i++) {                                     \
+        E1TYPE s1_0 = (E1TYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET10));     \
+        E1TYPE s1_1 = (E1TYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET11));     \
+        E2TYPE s2_0 = (E2TYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET20));     \
+        E2TYPE s2_1 = (E2TYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET21));     \
+        DTYPE d = (DTYPE)EXTRACTD(dest, i);                               \
+        PTYPE prod0 = OP(s1_0, s2_0);                                     \
+        PTYPE prod1 = OP(s1_1, s2_1);                                     \
+        rd = INSERT(rd, (OTYPE)COMBINE(d, prod0, prod1), i);              \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_4WAY_MUL(NAME, RTYPE, E1TYPE, E2TYPE, PTYPE, OTYPE,     \
+                           EXTRACT, INSERT, ELEMS, SCALE, OP)            \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
+{                                                                         \
+    RTYPE rd = 0;                                                         \
+    int elems = ELEMS(rd);                                                \
+                                                                          \
+    for (int i = 0; i < elems; i++) {                                     \
+        PTYPE prod0 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE)),              \
+                         (E2TYPE)EXTRACT(rs2, i * (SCALE)));             \
+        PTYPE prod1 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE) + 1),          \
+                         (E2TYPE)EXTRACT(rs2, i * (SCALE) + 1));         \
+        PTYPE prod2 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE) + 2),          \
+                         (E2TYPE)EXTRACT(rs2, i * (SCALE) + 2));         \
+        PTYPE prod3 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE) + 3),          \
+                         (E2TYPE)EXTRACT(rs2, i * (SCALE) + 3));         \
+        rd = INSERT(rd, (OTYPE)(prod0 + prod1 + prod2 + prod3), i);       \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_4WAY_MUL_ACC(NAME, RTYPE, E1TYPE, E2TYPE, DTYPE, PTYPE, \
+                               OTYPE, EXTRACT, EXTRACTD, INSERT, ELEMS,  \
+                               SCALE, OP)                                \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2, RTYPE dest)  \
+{                                                                         \
+    RTYPE rd = 0;                                                         \
+    int elems = ELEMS(rd);                                                \
+                                                                          \
+    for (int i = 0; i < elems; i++) {                                     \
+        DTYPE d = (DTYPE)EXTRACTD(dest, i);                               \
+        PTYPE prod0 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE)),              \
+                         (E2TYPE)EXTRACT(rs2, i * (SCALE)));             \
+        PTYPE prod1 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE) + 1),          \
+                         (E2TYPE)EXTRACT(rs2, i * (SCALE) + 1));         \
+        PTYPE prod2 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE) + 2),          \
+                         (E2TYPE)EXTRACT(rs2, i * (SCALE) + 2));         \
+        PTYPE prod3 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE) + 3),          \
+                         (E2TYPE)EXTRACT(rs2, i * (SCALE) + 3));         \
+        rd = INSERT(rd, (OTYPE)(d + prod0 + prod1 + prod2 + prod3), i);   \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_WIDEN_BINOP(NAME, ETYPE, WTYPE, OTYPE, ELEMS, IBITS,    \
+                              OBITS, IMASK, OP)                          \
+uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2)     \
+{                                                                         \
+    uint64_t rd = 0;                                                      \
+                                                                          \
+    for (int i = 0; i < (ELEMS); i++) {                                   \
+        ETYPE e1 = (ETYPE)((rs1 >> (i * (IBITS))) & (IMASK));             \
+        ETYPE e2 = (ETYPE)((rs2 >> (i * (IBITS))) & (IMASK));             \
+        WTYPE res = OP((WTYPE)0, (WTYPE)e1, (WTYPE)e2);                   \
+        rd |= ((uint64_t)(OTYPE)res) << (i * (OBITS));                    \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_WIDEN_BINOP_ACC(NAME, ETYPE, WTYPE, OTYPE, ELEMS,       \
+                                  IBITS, OBITS, IMASK, OMASK, OP)        \
+uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2,     \
+                      uint64_t dest)                                      \
+{                                                                         \
+    uint64_t rd = 0;                                                      \
+                                                                          \
+    for (int i = 0; i < (ELEMS); i++) {                                   \
+        ETYPE e1 = (ETYPE)((rs1 >> (i * (IBITS))) & (IMASK));             \
+        ETYPE e2 = (ETYPE)((rs2 >> (i * (IBITS))) & (IMASK));             \
+        WTYPE acc = (WTYPE)((dest >> (i * (OBITS))) & (OMASK));           \
+        WTYPE res = OP(acc, (WTYPE)e1, (WTYPE)e2);                        \
+        rd |= ((uint64_t)(OTYPE)res) << (i * (OBITS));                    \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_WIDEN_MUL(NAME, E1TYPE, E2TYPE, PTYPE, OTYPE, ELEMS,    \
+                            EXTRACT, OBITS, OP)                          \
+uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2)     \
+{                                                                         \
+    uint64_t rd = 0;                                                      \
+                                                                          \
+    for (int i = 0; i < (ELEMS); i++) {                                   \
+        E1TYPE e1 = (E1TYPE)EXTRACT(rs1, i);                              \
+        E2TYPE e2 = (E2TYPE)EXTRACT(rs2, i);                              \
+        PTYPE prod = OP(e1, e2);                                          \
+        rd |= ((uint64_t)(OTYPE)prod) << (i * (OBITS));                   \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_WIDEN_MUL_ACC(NAME, E1TYPE, E2TYPE, DTYPE, PTYPE,       \
+                                OTYPE, ELEMS, EXTRACT, EXTRACTD, OBITS,  \
+                                OP)                                      \
+uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2,     \
+                      uint64_t dest)                                      \
+{                                                                         \
+    uint64_t rd = 0;                                                      \
+                                                                          \
+    for (int i = 0; i < (ELEMS); i++) {                                   \
+        E1TYPE e1 = (E1TYPE)EXTRACT(rs1, i);                              \
+        E2TYPE e2 = (E2TYPE)EXTRACT(rs2, i);                              \
+        DTYPE d = (DTYPE)EXTRACTD(dest, i);                               \
+        PTYPE prod = OP(e1, e2);                                          \
+        rd |= ((uint64_t)(OTYPE)(d + prod)) << (i * (OBITS));             \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_WIDEN_QMUL_ACC(NAME, ETYPE, DTYPE, PTYPE, STYPE,        \
+                                 OTYPE, ELEMS, EXTRACT, EXTRACTD, SCALE, \
+                                 OFFSET, SHIFT, ROUND, OBITS, OP)        \
+uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2,     \
+                      uint64_t dest)                                      \
+{                                                                         \
+    uint64_t rd = 0;                                                      \
+                                                                          \
+    for (int i = 0; i < (ELEMS); i++) {                                   \
+        ETYPE e1 = (ETYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET));           \
+        ETYPE e2 = (ETYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET));           \
+        DTYPE d = (DTYPE)EXTRACTD(dest, i);                               \
+        PTYPE prod = OP(e1, e2) + (ROUND);                                \
+        STYPE scaled = (STYPE)(((__int128_t)prod) >> (SHIFT));            \
+        rd |= ((uint64_t)(OTYPE)(d + scaled)) << (i * (OBITS));           \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_DW_2WAY_MUL(NAME, E1TYPE, E2TYPE, PTYPE, EXTRACT,       \
+                              OFFSET10, OFFSET11, OFFSET20, OFFSET21,    \
+                              OP, COMBINE)                               \
+uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2)     \
+{                                                                         \
+    E1TYPE s1_0 = (E1TYPE)EXTRACT(rs1, OFFSET10);                         \
+    E1TYPE s1_1 = (E1TYPE)EXTRACT(rs1, OFFSET11);                         \
+    E2TYPE s2_0 = (E2TYPE)EXTRACT(rs2, OFFSET20);                         \
+    E2TYPE s2_1 = (E2TYPE)EXTRACT(rs2, OFFSET21);                         \
+    PTYPE prod0 = OP(s1_0, s2_0);                                        \
+    PTYPE prod1 = OP(s1_1, s2_1);                                        \
+                                                                          \
+    return (uint64_t)COMBINE(0, prod0, prod1);                            \
+}
+
+#define GEN_PSIMD_DW_2WAY_MUL_ACC(NAME, E1TYPE, E2TYPE, DTYPE, PTYPE,     \
+                                  EXTRACT, OFFSET10, OFFSET11, OFFSET20, \
+                                  OFFSET21, OP, COMBINE)                \
+uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2,     \
+                      uint64_t dest)                                      \
+{                                                                         \
+    E1TYPE s1_0 = (E1TYPE)EXTRACT(rs1, OFFSET10);                         \
+    E1TYPE s1_1 = (E1TYPE)EXTRACT(rs1, OFFSET11);                         \
+    E2TYPE s2_0 = (E2TYPE)EXTRACT(rs2, OFFSET20);                         \
+    E2TYPE s2_1 = (E2TYPE)EXTRACT(rs2, OFFSET21);                         \
+    DTYPE d = (DTYPE)dest;                                                \
+    PTYPE prod0 = OP(s1_0, s2_0);                                        \
+    PTYPE prod1 = OP(s1_1, s2_1);                                        \
+                                                                          \
+    return (uint64_t)COMBINE(d, prod0, prod1);                            \
+}
+
+#define GEN_PSIMD_WIDEN_SHIFT(NAME, ETYPE, WTYPE, OTYPE, ELEMS, IBITS,    \
+                              OBITS, IMASK, SHMASK)                      \
+uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2)     \
+{                                                                         \
+    uint64_t rd = 0;                                                      \
+    uint8_t shamt = rs2 & (SHMASK);                                       \
+                                                                          \
+    for (int i = 0; i < (ELEMS); i++) {                                   \
+        ETYPE e1 = (ETYPE)((rs1 >> (i * (IBITS))) & (IMASK));             \
+        WTYPE res = (WTYPE)e1 << shamt;                                   \
+        rd |= ((uint64_t)(OTYPE)res) << (i * (OBITS));                    \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_DW_ZIP(NAME, EXTRACT, ELEMS, STRIDE, BITS)              \
+uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2)     \
+{                                                                         \
+    uint64_t rd = 0;                                                      \
+                                                                          \
+    for (int i = 0; i < (ELEMS); i++) {                                   \
+        uint64_t e1 = (uint64_t)EXTRACT(rs1, i) << ((STRIDE) * i);        \
+        uint64_t e2 = (uint64_t)EXTRACT(rs2, i)                           \
+                      << ((STRIDE) * i + (BITS));                         \
+        rd |= e2 | e1;                                                    \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_DW_REDSUM(NAME, SUMTYPE, INITTYPE, ETYPE, EXTRACT,      \
+                            ELEMS)                                        \
+uint32_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1_lo,                \
+                      uint32_t rs1_hi, uint32_t rs2)                      \
+{                                                                         \
+    SUMTYPE sum = (INITTYPE)rs2;                                          \
+    uint64_t s1 = ((uint64_t)rs1_hi << 32) | rs1_lo;                      \
+                                                                          \
+    for (int i = 0; i < (ELEMS); i++) {                                   \
+        sum += (ETYPE)EXTRACT(s1, i);                                     \
+    }                                                                     \
+    return (uint32_t)sum;                                                 \
+}
+
+#define GEN_PSIMD_NARROW_SRL(NAME, ETYPE, OTYPE, ELEMS, IBITS, OBITS,     \
+                             IMASK, SHMASK)                               \
+uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
+{                                                                         \
+    uint32_t rd = 0;                                                      \
+    uint8_t shift = shamt & (SHMASK);                                     \
+                                                                          \
+    for (int i = 0; i < (ELEMS); i++) {                                   \
+        ETYPE e1 = (ETYPE)((s1 >> (i * (IBITS))) & (IMASK));              \
+        OTYPE result = (OTYPE)(e1 >> shift);                              \
+        rd |= ((uint32_t)result) << (i * (OBITS));                        \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_NARROW_SRA_PACK(NAME, ETYPE, STYPE, OTYPE, ELEMS,       \
+                                  IBITS, OBITS, IMASK, SHMASK)            \
+uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
+{                                                                         \
+    uint32_t rd = 0;                                                      \
+    uint8_t shift = shamt & (SHMASK);                                     \
+                                                                          \
+    for (int i = 0; i < (ELEMS); i++) {                                   \
+        ETYPE e1 = (ETYPE)((s1 >> (i * (IBITS))) & (IMASK));              \
+        STYPE shx = (STYPE)e1 >> shift;                                   \
+        OTYPE result = (OTYPE)shx;                                        \
+        rd |= ((uint32_t)result) << (i * (OBITS));                        \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_NARROW_RNDSRA_PACK(NAME, ETYPE, STYPE, OTYPE, ELEMS,    \
+                                     IBITS, OBITS, IMASK, SHMASK, RMASK)  \
+uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
+{                                                                         \
+    uint32_t rd = 0;                                                      \
+    uint8_t shift = shamt & (SHMASK);                                     \
+                                                                          \
+    for (int i = 0; i < (ELEMS); i++) {                                   \
+        ETYPE e1 = (ETYPE)((s1 >> (i * (IBITS))) & (IMASK));              \
+        STYPE e1_s = (STYPE)e1;                                           \
+        uint64_t shx = (((uint64_t)e1_s << 1) >> shift) & (RMASK);        \
+        OTYPE result = (OTYPE)((shx + 1) >> 1);                           \
+        rd |= ((uint32_t)result) << (i * (OBITS));                        \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_NCLIP_SIGNED_PACK(NAME, ETYPE, STYPE, CTYPE, OTYPE,     \
+                                    ELEMS, IBITS, OBITS, IMASK, SHMASK,   \
+                                    MIN, MAX, MIN_RES, MAX_RES)           \
+uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
+{                                                                         \
+    uint32_t rd = 0;                                                      \
+    uint8_t shift = shamt & (SHMASK);                                     \
+    int sat = 0;                                                          \
+                                                                          \
+    for (int i = 0; i < (ELEMS); i++) {                                   \
+        ETYPE e1 = (ETYPE)((s1 >> (i * (IBITS))) & (IMASK));              \
+        CTYPE shx = (CTYPE)((STYPE)e1 >> shift);                          \
+        OTYPE result;                                                     \
+                                                                          \
+        if (shx < (MIN)) {                                                \
+            sat = 1;                                                      \
+            result = (MIN_RES);                                           \
+        } else if (shx > (MAX)) {                                         \
+            sat = 1;                                                      \
+            result = (MAX_RES);                                           \
+        } else {                                                          \
+            result = (OTYPE)shx;                                          \
+        }                                                                 \
+        rd |= ((uint32_t)result) << (i * (OBITS));                        \
+    }                                                                     \
+                                                                          \
+    if (sat) {                                                            \
+        env->vxsat = 1;                                                   \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_NCLIPR_SIGNED_PACK(NAME, ETYPE, STYPE, CTYPE, OTYPE,    \
+                                     ELEMS, IBITS, OBITS, IMASK, SHMASK,  \
+                                     RMASK, MIN, MAX, MIN_RES, MAX_RES)   \
+uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
+{                                                                         \
+    uint32_t rd = 0;                                                      \
+    uint8_t shift = shamt & (SHMASK);                                     \
+    int sat = 0;                                                          \
+                                                                          \
+    for (int i = 0; i < (ELEMS); i++) {                                   \
+        ETYPE e1 = (ETYPE)((s1 >> (i * (IBITS))) & (IMASK));              \
+        STYPE e1_s = (STYPE)e1;                                           \
+        uint64_t shx = (((uint64_t)e1_s << 1) >> shift) & (RMASK);        \
+        CTYPE round_shx = (CTYPE)((shx + 1) >> 1);                        \
+        OTYPE result;                                                     \
+                                                                          \
+        if (round_shx < (MIN)) {                                          \
+            sat = 1;                                                      \
+            result = (MIN_RES);                                           \
+        } else if (round_shx > (MAX)) {                                   \
+            sat = 1;                                                      \
+            result = (MAX_RES);                                           \
+        } else {                                                          \
+            result = (OTYPE)round_shx;                                    \
+        }                                                                 \
+        rd |= ((uint32_t)result) << (i * (OBITS));                        \
+    }                                                                     \
+                                                                          \
+    if (sat) {                                                            \
+        env->vxsat = 1;                                                   \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_NCLIP_UNSIGNED_PACK(NAME, ETYPE, WTYPE, OTYPE, ELEMS,   \
+                                      IBITS, OBITS, IMASK, SHMASK, MAX)   \
+uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
+{                                                                         \
+    uint32_t rd = 0;                                                      \
+    uint8_t shift = shamt & (SHMASK);                                     \
+    int sat = 0;                                                          \
+                                                                          \
+    for (int i = 0; i < (ELEMS); i++) {                                   \
+        ETYPE e1 = (ETYPE)((s1 >> (i * (IBITS))) & (IMASK));              \
+        WTYPE shx = (WTYPE)e1 >> shift;                                   \
+        OTYPE result;                                                     \
+                                                                          \
+        if (shx > (MAX)) {                                                \
+            sat = 1;                                                      \
+            result = (OTYPE)(MAX);                                        \
+        } else {                                                          \
+            result = (OTYPE)shx;                                          \
+        }                                                                 \
+        rd |= ((uint32_t)result) << (i * (OBITS));                        \
+    }                                                                     \
+                                                                          \
+    if (sat) {                                                            \
+        env->vxsat = 1;                                                   \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_NCLIPR_UNSIGNED_PACK(NAME, ETYPE, WTYPE, OTYPE, ELEMS,  \
+                                       IBITS, OBITS, IMASK, SHMASK, MAX)  \
+uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
+{                                                                         \
+    uint32_t rd = 0;                                                      \
+    uint8_t shift = shamt & (SHMASK);                                     \
+    int sat = 0;                                                          \
+                                                                          \
+    for (int i = 0; i < (ELEMS); i++) {                                   \
+        ETYPE e1 = (ETYPE)((s1 >> (i * (IBITS))) & (IMASK));              \
+        WTYPE shx = ((WTYPE)e1 << 1) >> shift;                            \
+        WTYPE round_shx = (shx + 1) >> 1;                                 \
+        OTYPE result;                                                     \
+                                                                          \
+        if (round_shx > (MAX)) {                                          \
+            sat = 1;                                                      \
+            result = (OTYPE)(MAX);                                        \
+        } else {                                                          \
+            result = (OTYPE)round_shx;                                    \
+        }                                                                 \
+        rd |= ((uint32_t)result) << (i * (OBITS));                        \
+    }                                                                     \
+                                                                          \
+    if (sat) {                                                            \
+        env->vxsat = 1;                                                   \
+    }                                                                     \
+    return rd;                                                            \
+}
+
+#define GEN_PSIMD_NARROW_SRA(NAME)                                        \
+uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
+{                                                                         \
+    __int128_t s1_s128 = (__int128_t)((int64_t)s1);                       \
+    __int128_t s1_s96 = (s1_s128 << 32) >> 32;                            \
+                                                                          \
+    return (uint32_t)(s1_s96 >> (shamt & 0x3F)) & 0xFFFFFFFF;             \
+}
+
+#define GEN_PSIMD_NARROW_RNDSRA(NAME)                                     \
+uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
+{                                                                         \
+    __int128_t s1_s128 = (__int128_t)((int64_t)s1);                       \
+    __int128_t s1_s96 = (s1_s128 << 32) >> 32;                            \
+    __uint128_t shx_97bit = ((__uint128_t)s1_s96 << 1);                   \
+    uint64_t shx = (uint64_t)(shx_97bit >> (shamt & 0x3F)) & 0x1FFFFFFFF; \
+                                                                          \
+    return (uint32_t)((shx + 1) >> 1);                                    \
+}
+
+#define GEN_PSIMD_NARROW_ALIAS(NAME, TARGET)                              \
+uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
+{                                                                         \
+    return HELPER(TARGET)(env, s1, shamt);                                \
+}
+
+typedef struct {
+    __uint128_t low;
+    uint8_t high;
+} PsImdUint129;
+
+static inline PsImdUint129 psimd_uint129_lshift1(__int128_t val)
+{
+    PsImdUint129 result;
+    __uint128_t uval = (__uint128_t)val;
+
+    result.low = uval << 1;
+    result.high = (uval >> 127) & 0x1;
+    return result;
+}
+
+static inline PsImdUint129 psimd_uint129_rshift(PsImdUint129 val,
+                                                uint32_t shamt)
+{
+    PsImdUint129 result;
+
+    if (shamt == 0) {
+        return val;
+    } else if (shamt >= 129) {
+        result.low = 0;
+        result.high = 0;
+    } else if (shamt == 128) {
+        result.low = val.high;
+        result.high = 0;
+    } else {
+        result.low = (val.low >> shamt) |
+                     ((__uint128_t)val.high << (128 - shamt));
+        result.high = val.high >> shamt;
+    }
+    return result;
+}
+
+#define GEN_PSIMD_NCLIP(NAME)                                             \
+uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
+{                                                                         \
+    __int128_t s1_s128 = (__int128_t)((int64_t)s1);                       \
+    int64_t shx = (int64_t)(s1_s128 >> (shamt & 0x3F));                  \
+                                                                          \
+    if (shx < -2147483648LL) {                                            \
+        env->vxsat = 1;                                                   \
+        return 0x80000000U;                                               \
+    } else if (shx > 2147483647LL) {                                      \
+        env->vxsat = 1;                                                   \
+        return 0x7FFFFFFFU;                                               \
+    } else {                                                              \
+        return (uint32_t)(shx & 0xFFFFFFFF);                              \
+    }                                                                     \
+}
+
+#define GEN_PSIMD_NCLIPR(NAME)                                            \
+uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
+{                                                                         \
+    __int128_t s1_s128 = (__int128_t)((int64_t)s1);                       \
+    PsImdUint129 shx_129bit = psimd_uint129_lshift1(s1_s128);             \
+    PsImdUint129 shx = psimd_uint129_rshift(shx_129bit, shamt & 0x3F);    \
+    int64_t round_shx = (int64_t)((shx.low + 1) >> 1);                    \
+                                                                          \
+    if (round_shx < -2147483648LL) {                                      \
+        env->vxsat = 1;                                                   \
+        return 0x80000000U;                                               \
+    } else if (round_shx > 2147483647LL) {                                \
+        env->vxsat = 1;                                                   \
+        return 0x7FFFFFFFU;                                               \
+    } else {                                                              \
+        return (uint32_t)round_shx;                                       \
+    }                                                                     \
+}
+
+#define GEN_PSIMD_NCLIPU(NAME)                                            \
+uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
+{                                                                         \
+    uint64_t shx = s1 >> (shamt & 0x3F);                                  \
+                                                                          \
+    if (shx > 4294967295ULL) {                                            \
+        env->vxsat = 1;                                                   \
+        return 0xFFFFFFFFU;                                               \
+    } else {                                                              \
+        return (uint32_t)(shx & 0xFFFFFFFF);                              \
+    }                                                                     \
+}
+
+#define GEN_PSIMD_NCLIPRU(NAME)                                           \
+uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
+{                                                                         \
+    __uint128_t shx_65bit = (__uint128_t)s1 << 1;                         \
+    __uint128_t shx = shx_65bit >> (shamt & 0x3F);                        \
+    uint64_t round_shx = (shx + 1) >> 1;                                  \
+                                                                          \
+    if (round_shx > 4294967295ULL) {                                      \
+        env->vxsat = 1;                                                   \
+        return 0xFFFFFFFFU;                                               \
+    } else {                                                              \
+        return (uint32_t)(round_shx & 0xFFFFFFFF);                        \
+    }                                                                     \
+}
+
+/* Basic addition operations (non-saturating) */
+
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH v2 03/18] target/riscv: Add packed SIMD arithmetic instructions
  2026-07-17 10:06 [PATCH v2 00/18] target/riscv: Add support for RISC-V P Molly Chen
  2026-07-17 10:06 ` [PATCH v2 01/18] target/riscv: Add packed SIMD extension state Molly Chen
  2026-07-17 10:06 ` [PATCH v2 02/18] target/riscv: Add packed SIMD helper framework Molly Chen
@ 2026-07-17 10:06 ` Molly Chen
  2026-07-26 22:05   ` Daniel Henrique Barboza
                     ` (2 more replies)
  2026-07-17 10:06 ` [PATCH v2 04/18] target/riscv: Add packed SIMD averaging and rounding instructions Molly Chen
                   ` (16 subsequent siblings)
  19 siblings, 3 replies; 34+ messages in thread
From: Molly Chen @ 2026-07-17 10:06 UTC (permalink / raw)
  To: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
	chao.liu.zevorn, Chao Liu
  Cc: xiaoou, qemu-riscv, qemu-devel

Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
---
 target/riscv/helper.h                       |  41 ++
 target/riscv/insn32.decode                  |  63 +++
 target/riscv/tcg/insn_trans/trans_rvp.c.inc | 547 ++++++++++++++++++++
 target/riscv/tcg/psimd_helper.c             | 114 ++++
 target/riscv/tcg/translate.c                |   4 +
 5 files changed, 769 insertions(+)
 create mode 100644 target/riscv/tcg/insn_trans/trans_rvp.c.inc

diff --git a/target/riscv/helper.h b/target/riscv/helper.h
index 542b7c264fc..eebb2febd95 100644
--- a/target/riscv/helper.h
+++ b/target/riscv/helper.h
@@ -1358,3 +1358,44 @@ DEF_HELPER_1(ssamoswap_disabled, void, env)
 
 /* Zalrsc SC write probe */
 DEF_HELPER_FLAGS_3(sc_probe_write, TCG_CALL_NO_WG, void, env, tl, tl)
+
+/* Packed SIMD */
+/* Packed SIMD - Arithmetic Operations(Non-Saturating and Saturating) */
+DEF_HELPER_3(padd_b, tl, env, tl, tl)
+DEF_HELPER_3(padd_h, tl, env, tl, tl)
+DEF_HELPER_3(padd_w, i64, env, i64, i64)
+DEF_HELPER_3(padd_bs, tl, env, tl, tl)
+DEF_HELPER_3(padd_hs, tl, env, tl, tl)
+DEF_HELPER_3(padd_ws, i64, env, i64, i64)
+DEF_HELPER_3(psub_b, tl, env, tl, tl)
+DEF_HELPER_3(psub_h, tl, env, tl, tl)
+DEF_HELPER_3(psub_w, i64, env, i64, i64)
+DEF_HELPER_3(psh1add_h, tl, env, tl, tl)
+DEF_HELPER_3(psh1add_w, i64, env, i64, i64)
+DEF_HELPER_3(pssh1sadd_h, tl, env, tl, tl)
+DEF_HELPER_3(pssh1sadd_w, i64, env, i64, i64)
+DEF_HELPER_3(ssh1sadd, i32, env, i32, i32)
+DEF_HELPER_3(psadd_b, tl, env, tl, tl)
+DEF_HELPER_3(psadd_h, tl, env, tl, tl)
+DEF_HELPER_3(psadd_w, i64, env, i64, i64)
+DEF_HELPER_3(psaddu_b, tl, env, tl, tl)
+DEF_HELPER_3(psaddu_h, tl, env, tl, tl)
+DEF_HELPER_3(psaddu_w, i64, env, i64, i64)
+DEF_HELPER_3(sadd, i32, env, i32, i32)
+DEF_HELPER_3(saddu, i32, env, i32, i32)
+DEF_HELPER_3(pssub_b, tl, env, tl, tl)
+DEF_HELPER_3(pssub_h, tl, env, tl, tl)
+DEF_HELPER_3(pssub_w, i64, env, i64, i64)
+DEF_HELPER_3(pssubu_b, tl, env, tl, tl)
+DEF_HELPER_3(pssubu_h, tl, env, tl, tl)
+DEF_HELPER_3(pssubu_w, i64, env, i64, i64)
+DEF_HELPER_3(ssub, i32, env, i32, i32)
+DEF_HELPER_3(ssubu, i32, env, i32, i32)
+DEF_HELPER_3(psati_h, tl, env, tl, tl)
+DEF_HELPER_3(pusati_h, tl, env, tl, tl)
+DEF_HELPER_3(psati_w, i64, env, i64, i64)
+DEF_HELPER_3(pusati_w, i64, env, i64, i64)
+DEF_HELPER_3(sati_32, i32, env, i32, i32)
+DEF_HELPER_3(usati_32, i32, env, i32, i32)
+DEF_HELPER_3(sati_64, i64, env, i64, i64)
+DEF_HELPER_3(usati_64, i64, env, i64, i64)
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index 21272fdb504..8da13669d73 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -40,6 +40,9 @@
 %imm_z6   26:1 15:5
 %imm_mop5 30:1 26:2 20:2
 %imm_mop3 30:1 26:2
+%imm_p_ui16 20:4
+%imm_p_ui32 20:5
+%imm_p_ui64 20:6
 
 # Argument sets:
 &empty
@@ -60,6 +63,7 @@
 &k_aes     shamt rs2 rs1 rd
 &mop5 imm rd rs1
 &mop3 imm rd rs1 rs2
+&p_ui imm rs1 rd
 
 # Formats 32:
 @r       .......   ..... ..... ... ..... ....... &r                %rs2 %rs1 %rd
@@ -105,6 +109,10 @@
 @mop5 . . .. .. .... .. ..... ... ..... ....... &mop5 imm=%imm_mop5 %rd %rs1
 @mop3 . . .. .. . ..... ..... ... ..... ....... &mop3 imm=%imm_mop3 %rd %rs1 %rs2
 
+@p_ui16 ..... .... ... ..... ... ..... ....... &i imm=%imm_p_ui16 %rs1 %rd
+@p_ui32 ..... .... ... ..... ... ..... ....... &i imm=%imm_p_ui32 %rs1 %rd
+@p_ui64 ..... .... ... ..... ... ..... ....... &i imm=%imm_p_ui64 %rs1 %rd
+
 # Formats 64:
 @sh5     .......  ..... .....  ... ..... ....... &shift  shamt=%sh5      %rs1 %rd
 
@@ -1084,3 +1092,58 @@ sb_aqrl  00111 . . ..... ..... 000 ..... 0101111 @atom_st
 sh_aqrl  00111 . . ..... ..... 001 ..... 0101111 @atom_st
 sw_aqrl  00111 . . ..... ..... 010 ..... 0101111 @atom_st
 sd_aqrl  00111 . . ..... ..... 011 ..... 0101111 @atom_st
+
+# *** P Experimental Extension Version v020 ***
+# Packed SIMD - Arithmetic Operations(Non-Saturating and Saturating)
+padd_b     1000010 ..... ..... 000 ..... 0111011 @r
+padd_h     1000000 ..... ..... 000 ..... 0111011 @r
+padd_w     1000001 ..... ..... 000 ..... 0111011 @r
+padd_bs    1001110 ..... ..... 010 ..... 0011011 @r
+padd_hs    1001100 ..... ..... 010 ..... 0011011 @r
+padd_ws    1001101 ..... ..... 010 ..... 0011011 @r
+psub_b     1100010 ..... ..... 000 ..... 0111011 @r
+psub_h     1100000 ..... ..... 000 ..... 0111011 @r
+psub_w     1100001 ..... ..... 000 ..... 0111011 @r
+psh1add_h  1010000 ..... ..... 010 ..... 0111011 @r
+psh1add_w  1010001 ..... ..... 010 ..... 0111011 @r
+pssh1sadd_h   1011000 ..... ..... 010 ..... 0111011 @r
+{
+  ssh1sadd    1011001 ..... ..... 010 ..... 0111011 @r
+  pssh1sadd_w 1011001 ..... ..... 010 ..... 0111011 @r
+}
+psadd_b    1001010 ..... ..... 000 ..... 0111011 @r
+psadd_h    1001000 ..... ..... 000 ..... 0111011 @r
+{
+  sadd     1001001 ..... ..... 000 ..... 0111011 @r
+  psadd_w  1001001 ..... ..... 000 ..... 0111011 @r
+}
+psaddu_b   1011010 ..... ..... 000 ..... 0111011 @r
+psaddu_h   1011000 ..... ..... 000 ..... 0111011 @r
+{
+  saddu    1011001 ..... ..... 000 ..... 0111011 @r
+  psaddu_w 1011001 ..... ..... 000 ..... 0111011 @r
+}
+pssub_b    1101010 ..... ..... 000 ..... 0111011 @r
+pssub_h    1101000 ..... ..... 000 ..... 0111011 @r
+{
+  ssub     1101001 ..... ..... 000 ..... 0111011 @r
+  pssub_w  1101001 ..... ..... 000 ..... 0111011 @r
+}
+pssubu_b   1111010 ..... ..... 000 ..... 0111011 @r
+pssubu_h   1111000 ..... ..... 000 ..... 0111011 @r
+{
+  ssubu      1111001 ..... ..... 000 ..... 0111011 @r
+  pssubu_w   1111001 ..... ..... 000 ..... 0111011 @r
+}
+psati_h    11100 001.... ..... 100 ..... 0011011 @p_ui16
+pusati_h   10100 001.... ..... 100 ..... 0011011 @p_ui16
+{
+  sati_32  11100 01..... ..... 100 ..... 0011011 @p_ui32
+  psati_w  11100 01..... ..... 100 ..... 0011011 @p_ui32
+}
+{
+  usati_32 10100 01..... ..... 100 ..... 0011011 @p_ui32
+  pusati_w 10100 01..... ..... 100 ..... 0011011 @p_ui32
+}
+sati_64    111001 ...... ..... 100 ..... 0011011 @p_ui64
+usati_64   101001 ...... ..... 100 ..... 0011011 @p_ui64
diff --git a/target/riscv/tcg/insn_trans/trans_rvp.c.inc b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
new file mode 100644
index 00000000000..056ccfb486e
--- /dev/null
+++ b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
@@ -0,0 +1,547 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* RISC-V translation routines for the P Standard Extensions. */
+/* Copyright (c) 2026 ISRC ISCAS. */
+
+/* Save a 64 bit data in src to dst and dst + 1 */
+
+static bool require_rvp(DisasContext *ctx)
+{
+    uint32_t opcode = ctx->opcode & 0x7f;
+
+    if (!has_ext(ctx, RVP)) {
+        return false;
+    }
+
+    /*
+     * P_VXSAT_EXCP is encoded in the TB flags only when P is implemented
+     * without Zve*, where stateen0.VXSAT controls the whole OP-32 and
+     * OP-IMM-32 P instruction spaces.  When Zve* is present, this field
+     * remains NONE and vxsat access is checked by the VS path instead.
+     */
+    if ((opcode == 0x3b || opcode == 0x1b) &&
+        ctx->p_vxsat_excp != P_VXSAT_EXCP_NONE) {
+        ctx->virt_inst_excp =
+            ctx->p_vxsat_excp == P_VXSAT_EXCP_VIRTUAL;
+        return false;
+    }
+
+    return true;
+}
+
+static bool prepare_rvp_vxsat(DisasContext *ctx)
+{
+    if (!ctx->cfg_ptr->ext_zve32x) {
+        return true;
+    }
+
+    if (ctx->mstatus_vs == EXT_STATUS_DISABLED) {
+        return false;
+    }
+
+    mark_vs_dirty(ctx);
+    return true;
+}
+
+#define REQUIRE_RVP(ctx) do {             \
+    if (!require_rvp(ctx)) {              \
+        return false;                     \
+    }                                     \
+} while (0)
+
+#define GEN_SIMD_TRANS_BODY(NAME, VXSAT)                    \
+do {                                                        \
+    REQUIRE_RVP(ctx);                                       \
+    if (VXSAT && !prepare_rvp_vxsat(ctx)) {                 \
+        return false;                                       \
+    }                                                       \
+    TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE);             \
+    TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE);             \
+    TCGv dest = dest_gpr(ctx, a->rd);                       \
+    gen_helper_##NAME(dest, tcg_env, src1, src2);           \
+    gen_set_gpr(ctx, a->rd, dest);                          \
+    return true;                                            \
+} while (0)
+
+#define GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)                 \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{                                                           \
+    REQUIRE_32BIT(ctx);                                     \
+    return true;                                           \
+}
+
+#define GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)                 \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{                                                           \
+    REQUIRE_64BIT(ctx);                                     \
+    return true;                                           \
+}
+
+#define GEN_SIMD_TRANS(NAME)                                \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{                                                           \
+    GEN_SIMD_TRANS_BODY(NAME, false);                       \
+}
+
+#define GEN_SIMD_TRANS_VXSAT(NAME)                         \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{                                                           \
+    GEN_SIMD_TRANS_BODY(NAME, true);                        \
+}
+
+#if defined(TARGET_RISCV32)
+#define GEN_SIMD_TRANS_32(NAME)                             \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a)  \
+{                                                           \
+    REQUIRE_32BIT(ctx);                                     \
+    GEN_SIMD_TRANS_BODY(NAME, false);                       \
+}
+#define GEN_SIMD_TRANS_32_VXSAT(NAME)                      \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{                                                           \
+    REQUIRE_32BIT(ctx);                                     \
+    GEN_SIMD_TRANS_BODY(NAME, true);                        \
+}
+#else
+#define GEN_SIMD_TRANS_32(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
+#define GEN_SIMD_TRANS_32_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
+#endif
+
+#if defined(TARGET_RISCV32)
+#define GEN_SIMD_TRANS_64(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
+#define GEN_SIMD_TRANS_64_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
+#else
+#define GEN_SIMD_TRANS_64(NAME)                             \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a)  \
+{                                                           \
+    REQUIRE_64BIT(ctx);                                     \
+    GEN_SIMD_TRANS_BODY(NAME, false);                       \
+}
+#define GEN_SIMD_TRANS_64_VXSAT(NAME)                      \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{                                                           \
+    REQUIRE_64BIT(ctx);                                     \
+    GEN_SIMD_TRANS_BODY(NAME, true);                        \
+}
+#endif
+
+#define GEN_SIMD_TRANS_ACC_BODY(NAME, VXSAT)                \
+do {                                                        \
+    REQUIRE_RVP(ctx);                                       \
+    if (VXSAT && !prepare_rvp_vxsat(ctx)) {                 \
+        return false;                                       \
+    }                                                       \
+    TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE);             \
+    TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE);             \
+    TCGv dest = dest_gpr(ctx, a->rd);                       \
+    TCGv t = tcg_temp_new();                                \
+    gen_helper_##NAME(t, tcg_env, src1, src2, dest);        \
+    gen_set_gpr(ctx, a->rd, t);                             \
+    return true;                                            \
+} while (0)
+
+#define GEN_SIMD_TRANS_ACC(NAME)                            \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{                                                           \
+    GEN_SIMD_TRANS_ACC_BODY(NAME, false);                   \
+}
+
+#define GEN_SIMD_TRANS_ACC_VXSAT(NAME)                     \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{                                                           \
+    GEN_SIMD_TRANS_ACC_BODY(NAME, true);                    \
+}
+
+#if defined(TARGET_RISCV32)
+#define GEN_SIMD_TRANS_ACC_32(NAME)                         \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{                                                           \
+    REQUIRE_32BIT(ctx);                                     \
+    GEN_SIMD_TRANS_ACC_BODY(NAME, false);                   \
+}
+#else
+#define GEN_SIMD_TRANS_ACC_32(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
+#endif
+
+#if defined(TARGET_RISCV32)
+#define GEN_SIMD_TRANS_ACC_64(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
+#else
+#define GEN_SIMD_TRANS_ACC_64(NAME)                         \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{                                                           \
+    REQUIRE_64BIT(ctx);                                     \
+    GEN_SIMD_TRANS_ACC_BODY(NAME, false);                   \
+}
+#endif
+
+#define GEN_SIMD_TRANS_R1_BODY(NAME, VXSAT)                 \
+do {                                                        \
+    REQUIRE_RVP(ctx);                                       \
+    if (VXSAT && !prepare_rvp_vxsat(ctx)) {                 \
+        return false;                                       \
+    }                                                       \
+    TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE);             \
+    TCGv dest = dest_gpr(ctx, a->rd);                       \
+    gen_helper_##NAME(dest, tcg_env, src1);                 \
+    gen_set_gpr(ctx, a->rd, dest);                          \
+    return true;                                            \
+} while (0)
+
+#define GEN_SIMD_TRANS_R1(NAME)                             \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{                                                           \
+    GEN_SIMD_TRANS_R1_BODY(NAME, false);                    \
+}
+
+#define GEN_SIMD_TRANS_R1_VXSAT(NAME)                      \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{                                                           \
+    GEN_SIMD_TRANS_R1_BODY(NAME, true);                     \
+}
+
+#if defined(TARGET_RISCV32)
+#define GEN_SIMD_TRANS_R1_64(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
+#define GEN_SIMD_TRANS_R1_64_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
+#else
+#define GEN_SIMD_TRANS_R1_64(NAME)                          \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{                                                           \
+    REQUIRE_64BIT(ctx);                                     \
+    GEN_SIMD_TRANS_R1_BODY(NAME, false);                    \
+}
+#define GEN_SIMD_TRANS_R1_64_VXSAT(NAME)                   \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{                                                           \
+    REQUIRE_64BIT(ctx);                                     \
+    GEN_SIMD_TRANS_R1_BODY(NAME, true);                     \
+}
+#endif
+
+#define GEN_SIMD_TRANS_IMM_BODY(NAME, VXSAT)                \
+do {                                                        \
+    REQUIRE_RVP(ctx);                                       \
+    if (VXSAT && !prepare_rvp_vxsat(ctx)) {                 \
+        return false;                                       \
+    }                                                       \
+    TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE);             \
+    TCGv imm = tcg_constant_tl(a->imm);                     \
+    TCGv dest = dest_gpr(ctx, a->rd);                       \
+    gen_helper_##NAME(dest, tcg_env, src1, imm);            \
+    gen_set_gpr(ctx, a->rd, dest);                          \
+    return true;                                            \
+} while (0)
+
+#define GEN_SIMD_TRANS_IMM(NAME)                            \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{                                                           \
+    GEN_SIMD_TRANS_IMM_BODY(NAME, false);                   \
+}
+
+#define GEN_SIMD_TRANS_IMM_VXSAT(NAME)                     \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{                                                           \
+    GEN_SIMD_TRANS_IMM_BODY(NAME, true);                    \
+}
+
+#if defined(TARGET_RISCV32)
+#define GEN_SIMD_TRANS_IMM_32(NAME)                         \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{                                                           \
+    REQUIRE_32BIT(ctx);                                     \
+    GEN_SIMD_TRANS_IMM_BODY(NAME, false);                   \
+}
+#define GEN_SIMD_TRANS_IMM_32_VXSAT(NAME)                  \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{                                                           \
+    REQUIRE_32BIT(ctx);                                     \
+    GEN_SIMD_TRANS_IMM_BODY(NAME, true);                    \
+}
+#else
+#define GEN_SIMD_TRANS_IMM_32(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
+#define GEN_SIMD_TRANS_IMM_32_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
+#endif
+
+#if defined(TARGET_RISCV32)
+#define GEN_SIMD_TRANS_IMM_64(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
+#define GEN_SIMD_TRANS_IMM_64_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
+#else
+#define GEN_SIMD_TRANS_IMM_64(NAME)                         \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{                                                           \
+    REQUIRE_64BIT(ctx);                                     \
+    GEN_SIMD_TRANS_IMM_BODY(NAME, false);                   \
+}
+#define GEN_SIMD_TRANS_IMM_64_VXSAT(NAME)                  \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{                                                           \
+    REQUIRE_64BIT(ctx);                                     \
+    GEN_SIMD_TRANS_IMM_BODY(NAME, true);                    \
+}
+#endif
+
+#if defined(TARGET_RISCV32)
+#define GEN_SIMD_TRANS_REG_PAIR_SCALAR_OP(NAME, SRC2)       \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{                                                           \
+    REQUIRE_32BIT(ctx);                                     \
+    REQUIRE_RVP(ctx);                                       \
+    TCGv_i32 src1 = get_gpr(ctx, a->rs1, EXT_NONE);         \
+    TCGv_i32 src2 = SRC2;                                   \
+    TCGv_i64 t = tcg_temp_new_i64();                        \
+    gen_helper_##NAME(t, tcg_env, src1, src2);              \
+    set_pair_regs(ctx, (a->rd) * 2, t);                     \
+    return true;                                            \
+}
+
+#define GEN_SIMD_TRANS_REG_PAIR_SCALAR(NAME) \
+    GEN_SIMD_TRANS_REG_PAIR_SCALAR_OP(NAME, get_gpr(ctx, a->rs2, EXT_NONE))
+
+#define GEN_SIMD_TRANS_REG_PAIR_SCALAR_IMM(NAME) \
+    GEN_SIMD_TRANS_REG_PAIR_SCALAR_OP(NAME, tcg_constant_i32(a->imm))
+#else
+#define GEN_SIMD_TRANS_REG_PAIR_SCALAR(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
+#define GEN_SIMD_TRANS_REG_PAIR_SCALAR_IMM(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
+#endif
+
+#if defined(TARGET_RISCV32)
+#define GEN_SIMD_TRANS_REG_PAIR_OP(INSN, HELPER, SRC2_0, SRC2_1, VXSAT) \
+static bool trans_##INSN(DisasContext *ctx, arg_##INSN * a)       \
+{                                                                 \
+    REQUIRE_32BIT(ctx);                                           \
+    REQUIRE_RVP(ctx);                                             \
+    if (VXSAT && !prepare_rvp_vxsat(ctx)) {                       \
+        return false;                                             \
+    }                                                             \
+    TCGv src1_0 = get_gpr(ctx, (a->rs1) * 2, EXT_NONE);           \
+    TCGv src2_0 = SRC2_0;                                         \
+    TCGv dest_0 = dest_gpr(ctx, (a->rd) * 2);                     \
+    TCGv src1_1 = get_gpr(ctx, (a->rs1) * 2 + 1, EXT_NONE);       \
+    TCGv src2_1 = SRC2_1;                                         \
+    TCGv dest_1 = dest_gpr(ctx, (a->rd) * 2 + 1);                 \
+    gen_helper_##HELPER(dest_0, tcg_env, src1_0, src2_0);         \
+    gen_helper_##HELPER(dest_1, tcg_env, src1_1, src2_1);         \
+    gen_set_gpr(ctx, (a->rd) * 2, dest_0);                        \
+    gen_set_gpr(ctx, (a->rd) * 2 + 1, dest_1);                    \
+    return true;                                                  \
+}
+
+#define GEN_SIMD_TRANS_REG_PAIR_LANE(INSN, HELPER)                   \
+    GEN_SIMD_TRANS_REG_PAIR_OP(INSN, HELPER,                       \
+        get_gpr(ctx, (a->rs2) * 2, EXT_NONE),                     \
+        get_gpr(ctx, (a->rs2) * 2 + 1, EXT_NONE), false)
+
+#define GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(INSN, HELPER)            \
+    GEN_SIMD_TRANS_REG_PAIR_OP(INSN, HELPER,                       \
+        get_gpr(ctx, (a->rs2) * 2, EXT_NONE),                     \
+        get_gpr(ctx, (a->rs2) * 2 + 1, EXT_NONE), true)
+
+#define GEN_SIMD_TRANS_REG_PAIR_LANE_IMM(INSN, HELPER)               \
+    GEN_SIMD_TRANS_REG_PAIR_OP(INSN, HELPER,                       \
+        tcg_constant_tl(a->imm), tcg_constant_tl(a->imm), false)
+
+#define GEN_SIMD_TRANS_REG_PAIR_LANE_IMM_VXSAT(INSN, HELPER)        \
+    GEN_SIMD_TRANS_REG_PAIR_OP(INSN, HELPER,                       \
+        tcg_constant_tl(a->imm), tcg_constant_tl(a->imm), true)
+#else
+#define GEN_SIMD_TRANS_REG_PAIR_LANE(INSN, HELPER) \
+    GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
+#define GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(INSN, HELPER) \
+    GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
+#define GEN_SIMD_TRANS_REG_PAIR_LANE_IMM(INSN, HELPER) \
+    GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
+#define GEN_SIMD_TRANS_REG_PAIR_LANE_IMM_VXSAT(INSN, HELPER) \
+    GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
+#endif
+
+#if defined(TARGET_RISCV32)
+#define GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_OP(INSN, HELPER, VXSAT)     \
+static bool trans_##INSN(DisasContext *ctx, arg_##INSN * a)    \
+{                                                              \
+    REQUIRE_32BIT(ctx);                                        \
+    REQUIRE_RVP(ctx);                                          \
+    if (VXSAT && !prepare_rvp_vxsat(ctx)) {                    \
+        return false;                                          \
+    }                                                          \
+    TCGv src1_0 = get_gpr(ctx, (a->rs1) * 2, EXT_NONE);        \
+    TCGv dest_0 = dest_gpr(ctx, (a->rd) * 2);                    \
+    TCGv src1_1 = get_gpr(ctx, (a->rs1) * 2 + 1, EXT_NONE);        \
+    TCGv dest_1 = dest_gpr(ctx, (a->rd) * 2 + 1);                  \
+    TCGv src2   = get_gpr(ctx, a->rs2, EXT_NONE);              \
+    gen_helper_##HELPER(dest_0, tcg_env, src1_0, src2);        \
+    gen_helper_##HELPER(dest_1, tcg_env, src1_1, src2);        \
+    gen_set_gpr(ctx, (a->rd) * 2, dest_0);                     \
+    gen_set_gpr(ctx, (a->rd) * 2 + 1, dest_1);                 \
+    return true;                                              \
+}
+
+#define GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR(INSN, HELPER)              \
+    GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_OP(INSN, HELPER, false)
+
+#define GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_VXSAT(INSN, HELPER)       \
+    GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_OP(INSN, HELPER, true)
+#else
+#define GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR(INSN, HELPER) \
+    GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
+#define GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_VXSAT(INSN, HELPER) \
+    GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
+#endif
+
+#if defined(TARGET_RISCV32)
+#define GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_OP(INSN, HELPER, VXSAT)     \
+static bool trans_##INSN(DisasContext *ctx, arg_##INSN * a)    \
+{                                                              \
+    REQUIRE_RVP(ctx);                                          \
+    if (VXSAT && !prepare_rvp_vxsat(ctx)) {                    \
+        return false;                                          \
+    }                                                          \
+    TCGv src1_0 = get_gpr(ctx, (a->rs1) * 2, EXT_NONE);        \
+    TCGv dest_0 = dest_gpr(ctx, (a->rd) * 2);                  \
+    TCGv src1_1 = get_gpr(ctx, (a->rs1) * 2 + 1, EXT_NONE);    \
+    TCGv dest_1 = dest_gpr(ctx, (a->rd) * 2 + 1);              \
+    gen_helper_##HELPER(dest_0, tcg_env, src1_0);              \
+    gen_helper_##HELPER(dest_1, tcg_env, src1_1);              \
+    gen_set_gpr(ctx, (a->rd) * 2, dest_0);                     \
+    gen_set_gpr(ctx, (a->rd) * 2 + 1, dest_1);                 \
+    return true;                                               \
+}
+
+#define GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY(INSN, HELPER)               \
+    GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_OP(INSN, HELPER, false)
+
+#define GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_VXSAT(INSN, HELPER)        \
+    GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_OP(INSN, HELPER, true)
+#else
+#define GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY(INSN, HELPER) \
+    GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
+#define GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_VXSAT(INSN, HELPER) \
+    GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
+#endif
+
+#if defined(TARGET_RISCV32)
+#define GEN_SIMD_TRANS_REG_PAIR_ACC(NAME)                   \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{                                                           \
+    REQUIRE_32BIT(ctx);                                     \
+    REQUIRE_RVP(ctx);                                       \
+    TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE);             \
+    TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE);             \
+    TCGv_i64 t = tcg_temp_new_i64();                        \
+    if (a->rd == 0) {                                         \
+        tcg_gen_movi_i64(t, 0);                             \
+    } else {                                                  \
+        get_pair_regs(ctx, t, (a->rd) * 2);                   \
+    }                                                       \
+    gen_helper_##NAME(t, tcg_env, src1, src2, t);           \
+    set_pair_regs(ctx, (a->rd) * 2, t);                       \
+    return true;                                           \
+}
+#else
+#define GEN_SIMD_TRANS_REG_PAIR_ACC(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
+#endif
+
+#if defined(TARGET_RISCV32)
+#define GEN_SIMD_TRANS_REG_PAIR_PREDSUM(NAME)               \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{                                                           \
+    REQUIRE_32BIT(ctx);                                     \
+    REQUIRE_RVP(ctx);                                       \
+    TCGv_i32 src1_l;                                        \
+    TCGv_i32 src1_h;                                        \
+    TCGv_i32 src2 = get_gpr(ctx, a->rs2, EXT_NONE);         \
+    TCGv_i32 dest = dest_gpr(ctx, a->rd);                   \
+    if (a->rs1 == 0) {                                        \
+        src1_l = tcg_temp_new_i32();                        \
+        src1_h = tcg_temp_new_i32();                        \
+        tcg_gen_movi_i32(src1_l, 0);                        \
+        tcg_gen_movi_i32(src1_h, 0);                        \
+    } else {                                                  \
+        src1_l = get_gpr(ctx, (a->rs1) * 2, EXT_NONE);        \
+        src1_h = get_gpr(ctx, (a->rs1) * 2 + 1, EXT_NONE);      \
+    }                                                       \
+    gen_helper_##NAME(dest, tcg_env, src1_l, src1_h, src2); \
+    gen_set_gpr(ctx, a->rd, dest);                          \
+    return true;                                           \
+}
+#else
+#define GEN_SIMD_TRANS_REG_PAIR_PREDSUM(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
+#endif
+
+#if defined(TARGET_RISCV32)
+#define GEN_SIMD_TRANS_PN_OP(NAME, SRC2, VXSAT)            \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{                                                           \
+    REQUIRE_32BIT(ctx);                                     \
+    REQUIRE_RVP(ctx);                                       \
+    if (VXSAT && !prepare_rvp_vxsat(ctx)) {                 \
+        return false;                                       \
+    }                                                       \
+    TCGv_i64 s1 = tcg_temp_new_i64();                       \
+    if (a->rs1 == 0) {                                      \
+        tcg_gen_mov_i64(s1, 0);                             \
+    } else {                                                \
+        get_pair_regs(ctx, s1, a->rs1 * 2);                 \
+    }                                                       \
+    TCGv src2 = SRC2;                                       \
+    TCGv dest = dest_gpr(ctx, a->rd);                       \
+    gen_helper_##NAME(dest, tcg_env, s1, src2);             \
+    gen_set_gpr(ctx, a->rd, dest);                          \
+    return true;                                            \
+}
+
+#define GEN_SIMD_TRANS_PN_OP_IMM(NAME) \
+    GEN_SIMD_TRANS_PN_OP(NAME, tcg_constant_tl(a->imm), false)
+
+#define GEN_SIMD_TRANS_PN_OP_IMM_VXSAT(NAME) \
+    GEN_SIMD_TRANS_PN_OP(NAME, tcg_constant_tl(a->imm), true)
+
+#define GEN_SIMD_TRANS_PN_OP_REG(NAME) \
+    GEN_SIMD_TRANS_PN_OP(NAME, get_gpr(ctx, a->rs2, EXT_NONE), false)
+
+#define GEN_SIMD_TRANS_PN_OP_REG_VXSAT(NAME) \
+    GEN_SIMD_TRANS_PN_OP(NAME, get_gpr(ctx, a->rs2, EXT_NONE), true)
+#else
+#define GEN_SIMD_TRANS_PN_OP_IMM(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
+#define GEN_SIMD_TRANS_PN_OP_IMM_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
+#define GEN_SIMD_TRANS_PN_OP_REG(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
+#define GEN_SIMD_TRANS_PN_OP_REG_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
+#endif
+
+/* Packed SIMD - Arithmetic Operations(Non-Saturating and Saturating) */
+GEN_SIMD_TRANS(padd_b)
+GEN_SIMD_TRANS(padd_h)
+GEN_SIMD_TRANS_64(padd_w)
+GEN_SIMD_TRANS(padd_bs)
+GEN_SIMD_TRANS(padd_hs)
+GEN_SIMD_TRANS_64(padd_ws)
+GEN_SIMD_TRANS(psub_b)
+GEN_SIMD_TRANS(psub_h)
+GEN_SIMD_TRANS_64(psub_w)
+GEN_SIMD_TRANS(psh1add_h)
+GEN_SIMD_TRANS_64(psh1add_w)
+GEN_SIMD_TRANS_VXSAT(pssh1sadd_h)
+GEN_SIMD_TRANS_64_VXSAT(pssh1sadd_w)
+GEN_SIMD_TRANS_32_VXSAT(ssh1sadd)
+GEN_SIMD_TRANS_VXSAT(psadd_b)
+GEN_SIMD_TRANS_VXSAT(psadd_h)
+GEN_SIMD_TRANS_64_VXSAT(psadd_w)
+GEN_SIMD_TRANS_VXSAT(psaddu_b)
+GEN_SIMD_TRANS_VXSAT(psaddu_h)
+GEN_SIMD_TRANS_64_VXSAT(psaddu_w)
+GEN_SIMD_TRANS_32_VXSAT(sadd)
+GEN_SIMD_TRANS_32_VXSAT(saddu)
+GEN_SIMD_TRANS_VXSAT(pssub_b)
+GEN_SIMD_TRANS_VXSAT(pssub_h)
+GEN_SIMD_TRANS_64_VXSAT(pssub_w)
+GEN_SIMD_TRANS_VXSAT(pssubu_b)
+GEN_SIMD_TRANS_VXSAT(pssubu_h)
+GEN_SIMD_TRANS_64_VXSAT(pssubu_w)
+GEN_SIMD_TRANS_32_VXSAT(ssub)
+GEN_SIMD_TRANS_32_VXSAT(ssubu)
+GEN_SIMD_TRANS_IMM_VXSAT(psati_h)
+GEN_SIMD_TRANS_IMM_VXSAT(pusati_h)
+GEN_SIMD_TRANS_IMM_64_VXSAT(psati_w)
+GEN_SIMD_TRANS_IMM_64_VXSAT(pusati_w)
+GEN_SIMD_TRANS_IMM_32_VXSAT(sati_32)
+GEN_SIMD_TRANS_IMM_32_VXSAT(usati_32)
+GEN_SIMD_TRANS_IMM_64_VXSAT(sati_64)
+GEN_SIMD_TRANS_IMM_64_VXSAT(usati_64)
+
diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
index 2948bbb2a86..52c58e0287e 100644
--- a/target/riscv/tcg/psimd_helper.c
+++ b/target/riscv/tcg/psimd_helper.c
@@ -1654,3 +1654,117 @@ uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
 
 /* Basic addition operations (non-saturating) */
 
+GEN_PSIMD_BINOP(padd_b, target_ulong, uint8_t, uint8_t,
+                EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ADD)
+GEN_PSIMD_BINOP(padd_h, target_ulong, uint16_t, uint16_t,
+                EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ADD)
+GEN_PSIMD_BINOP(padd_w, uint64_t, uint32_t, uint32_t,
+                EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD)
+
+GEN_PSIMD_BINOP_SCALAR(padd_bs, target_ulong, uint8_t,
+                       EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ADD)
+GEN_PSIMD_BINOP_SCALAR(padd_hs, target_ulong, uint16_t,
+                       EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ADD)
+GEN_PSIMD_BINOP_SCALAR(padd_ws, uint64_t, uint32_t,
+                       EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD)
+
+/* Basic subtraction operations (non-saturating) */
+
+GEN_PSIMD_BINOP(psub_b, target_ulong, uint8_t, uint8_t,
+                EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_SUB)
+GEN_PSIMD_BINOP(psub_h, target_ulong, uint16_t, uint16_t,
+                EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_SUB)
+GEN_PSIMD_BINOP(psub_w, uint64_t, uint32_t, uint32_t,
+                EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_SUB)
+
+/* Shift-left-by-one and add operations */
+
+GEN_PSIMD_SHADD(psh1add_h, target_ulong, uint16_t,
+                EXTRACT16, INSERT16, ELEMS_H, 1)
+GEN_PSIMD_SHADD(psh1add_w, uint64_t, uint32_t,
+                EXTRACT32, INSERT32, ELEMS_W, 1)
+
+GEN_PSIMD_SAT_SHADD(pssh1sadd_h, target_ulong, int16_t, int32_t,
+                    EXTRACT16, INSERT16, ELEMS_H, 1, -0x4000, 0x3fff,
+                    SAT_MIN_H, SAT_MAX_H, signed_saturate_h)
+GEN_PSIMD_SAT_SHADD(pssh1sadd_w, uint64_t, int32_t, int64_t,
+                    EXTRACT32, INSERT32, ELEMS_W, 1, -0x40000000,
+                    0x3fffffff, SAT_MIN_W, SAT_MAX_W, signed_saturate_w)
+
+GEN_PSIMD_SAT_SHADD(ssh1sadd, uint32_t, int32_t, int64_t,
+                    EXTRACT32, INSERT32, ELEMS_W, 1, -0x40000000,
+                    0x3fffffff, SAT_MIN_W, SAT_MAX_W, signed_saturate_w)
+
+/* Saturating addition operations */
+
+GEN_PSIMD_SAT_BINOP(psadd_b, target_ulong, int8_t, int32_t,
+                    EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ADD,
+                    signed_saturate_b)
+GEN_PSIMD_SAT_BINOP(psadd_h, target_ulong, int16_t, int32_t,
+                    EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ADD,
+                    signed_saturate_h)
+GEN_PSIMD_SAT_BINOP(psadd_w, uint64_t, int32_t, int64_t,
+                    EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD,
+                    signed_saturate_w)
+
+GEN_PSIMD_SAT_BINOP(psaddu_b, target_ulong, uint8_t, uint32_t,
+                    EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ADD,
+                    unsigned_saturate_b)
+GEN_PSIMD_SAT_BINOP(psaddu_h, target_ulong, uint16_t, uint32_t,
+                    EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ADD,
+                    unsigned_saturate_h)
+GEN_PSIMD_SAT_BINOP(psaddu_w, uint64_t, uint32_t, uint64_t,
+                    EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD,
+                    unsigned_saturate_w)
+
+GEN_PSIMD_SAT_BINOP(sadd, uint32_t, int32_t, int64_t,
+                    EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD,
+                    signed_saturate_w)
+GEN_PSIMD_SAT_BINOP(saddu, uint32_t, uint32_t, uint64_t,
+                    EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD,
+                    unsigned_saturate_w)
+
+/* Saturating subtraction operations */
+
+GEN_PSIMD_SAT_BINOP(pssub_b, target_ulong, int8_t, int32_t,
+                    EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_SUB,
+                    signed_saturate_b)
+GEN_PSIMD_SAT_BINOP(pssub_h, target_ulong, int16_t, int32_t,
+                    EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_SUB,
+                    signed_saturate_h)
+GEN_PSIMD_SAT_BINOP(pssub_w, uint64_t, int32_t, int64_t,
+                    EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_SUB,
+                    signed_saturate_w)
+
+GEN_PSIMD_USUB_SAT(pssubu_b, target_ulong, uint8_t,
+                   EXTRACT8, INSERT8, ELEMS_B)
+GEN_PSIMD_USUB_SAT(pssubu_h, target_ulong, uint16_t,
+                   EXTRACT16, INSERT16, ELEMS_H)
+GEN_PSIMD_USUB_SAT(pssubu_w, uint64_t, uint32_t,
+                   EXTRACT32, INSERT32, ELEMS_W)
+
+GEN_PSIMD_SAT_BINOP(ssub, uint32_t, int32_t, int64_t,
+                    EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_SUB,
+                    signed_saturate_w)
+GEN_PSIMD_USUB_SAT(ssubu, uint32_t, uint32_t,
+                   EXTRACT32, INSERT32, ELEMS_W)
+
+/* Saturation instructions (SAT, USAT) */
+
+GEN_PSIMD_SATI(psati_h, target_ulong, int16_t, int64_t,
+               EXTRACT16, INSERT16, ELEMS_H, 0x0f)
+GEN_PSIMD_USATI(pusati_h, target_ulong, int16_t, uint16_t, uint32_t,
+                EXTRACT16, INSERT16, ELEMS_H, 1U)
+GEN_PSIMD_SATI(psati_w, uint64_t, int32_t, int64_t,
+               EXTRACT32, INSERT32, ELEMS_W, 0x1f)
+GEN_PSIMD_USATI(pusati_w, uint64_t, int32_t, uint32_t, uint64_t,
+                EXTRACT32, INSERT32, ELEMS_W, 1ULL)
+GEN_PSIMD_SATI(sati_32, uint32_t, int32_t, int64_t,
+               EXTRACT32, INSERT32, ELEMS_W, 0x1f)
+GEN_PSIMD_USATI(usati_32, uint32_t, int32_t, uint32_t, uint32_t,
+                EXTRACT32, INSERT32, ELEMS_W, 1U)
+GEN_PSIMD_SATI(sati_64, uint64_t, int64_t, int64_t,
+               EXTRACT64, INSERT64, ELEMS_D, 0x3f)
+GEN_PSIMD_USATI(usati_64, uint64_t, int64_t, uint64_t, uint64_t,
+                EXTRACT64, INSERT64, ELEMS_D, 1ULL)
+
diff --git a/target/riscv/tcg/translate.c b/target/riscv/tcg/translate.c
index 9684dbe7528..0df9d4190f1 100644
--- a/target/riscv/tcg/translate.c
+++ b/target/riscv/tcg/translate.c
@@ -103,6 +103,7 @@ typedef struct DisasContext {
     bool vstart_eq_zero;
     bool vl_eq_vlmax;
     bool altfmt;
+    uint8_t p_vxsat_excp;
     CPUState *cs;
     TCGv zero;
     /* actual address width */
@@ -1199,6 +1200,7 @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc)
 #include "insn_trans/trans_rvh.c.inc"
 #include "insn_trans/trans_rvv.c.inc"
 #include "insn_trans/trans_rvb.c.inc"
+#include "insn_trans/trans_rvp.c.inc"
 #include "insn_trans/trans_rvzicond.c.inc"
 #include "insn_trans/trans_rvzacas.c.inc"
 #include "insn_trans/trans_rvzabha.c.inc"
@@ -1333,6 +1335,8 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
     ctx->vstart_eq_zero = FIELD_EX32(tb_flags, TB_FLAGS, VSTART_EQ_ZERO);
     ctx->vl_eq_vlmax = FIELD_EX32(tb_flags, TB_FLAGS, VL_EQ_VLMAX);
     ctx->altfmt = FIELD_EX64(ext_tb_flags, EXT_TB_FLAGS, ALTFMT);
+    ctx->p_vxsat_excp = FIELD_EX64(ext_tb_flags, EXT_TB_FLAGS,
+                                   P_VXSAT_EXCP);
     ctx->misa_mxl_max = mcc->def->misa_mxl_max;
     ctx->xl = FIELD_EX32(tb_flags, TB_FLAGS, XL);
     ctx->address_xl = FIELD_EX32(tb_flags, TB_FLAGS, AXL);
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH v2 04/18] target/riscv: Add packed SIMD averaging and rounding instructions
  2026-07-17 10:06 [PATCH v2 00/18] target/riscv: Add support for RISC-V P Molly Chen
                   ` (2 preceding siblings ...)
  2026-07-17 10:06 ` [PATCH v2 03/18] target/riscv: Add packed SIMD arithmetic instructions Molly Chen
@ 2026-07-17 10:06 ` Molly Chen
  2026-07-27 18:58   ` Daniel Henrique Barboza
  2026-07-17 10:06 ` [PATCH v2 05/18] target/riscv: Add packed SIMD absolute, difference, compare and mask instructions Molly Chen
                   ` (15 subsequent siblings)
  19 siblings, 1 reply; 34+ messages in thread
From: Molly Chen @ 2026-07-17 10:06 UTC (permalink / raw)
  To: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
	chao.liu.zevorn, Chao Liu
  Cc: xiaoou, qemu-riscv, qemu-devel

Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
---
 target/riscv/helper.h                       | 18 ++++++++++
 target/riscv/insn32.decode                  | 26 ++++++++++++++
 target/riscv/tcg/insn_trans/trans_rvp.c.inc | 18 ++++++++++
 target/riscv/tcg/psimd_helper.c             | 40 +++++++++++++++++++++
 4 files changed, 102 insertions(+)

diff --git a/target/riscv/helper.h b/target/riscv/helper.h
index eebb2febd95..7256f776ae6 100644
--- a/target/riscv/helper.h
+++ b/target/riscv/helper.h
@@ -1399,3 +1399,21 @@ DEF_HELPER_3(sati_32, i32, env, i32, i32)
 DEF_HELPER_3(usati_32, i32, env, i32, i32)
 DEF_HELPER_3(sati_64, i64, env, i64, i64)
 DEF_HELPER_3(usati_64, i64, env, i64, i64)
+
+/* Packed SIMD - Averaging and Rounding Operations */
+DEF_HELPER_3(paadd_b, tl, env, tl, tl)
+DEF_HELPER_3(paadd_h, tl, env, tl, tl)
+DEF_HELPER_3(paadd_w, i64, env, i64, i64)
+DEF_HELPER_3(paaddu_b, tl, env, tl, tl)
+DEF_HELPER_3(paaddu_h, tl, env, tl, tl)
+DEF_HELPER_3(paaddu_w, i64, env, i64, i64)
+DEF_HELPER_3(aadd, i32, env, i32, i32)
+DEF_HELPER_3(aaddu, i32, env, i32, i32)
+DEF_HELPER_3(pasub_b, tl, env, tl, tl)
+DEF_HELPER_3(pasub_h, tl, env, tl, tl)
+DEF_HELPER_3(pasub_w, i64, env, i64, i64)
+DEF_HELPER_3(pasubu_b, tl, env, tl, tl)
+DEF_HELPER_3(pasubu_h, tl, env, tl, tl)
+DEF_HELPER_3(pasubu_w, i64, env, i64, i64)
+DEF_HELPER_3(asub, i32, env, i32, i32)
+DEF_HELPER_3(asubu, i32, env, i32, i32)
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index 8da13669d73..005cc055b8a 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -1147,3 +1147,29 @@ pusati_h   10100 001.... ..... 100 ..... 0011011 @p_ui16
 }
 sati_64    111001 ...... ..... 100 ..... 0011011 @p_ui64
 usati_64   101001 ...... ..... 100 ..... 0011011 @p_ui64
+
+# Packed SIMD - Averaging and Rounding Operations
+paadd_b    1001110 ..... ..... 000 ..... 0111011 @r
+paadd_h    1001100 ..... ..... 000 ..... 0111011 @r
+{
+  aadd     1001101 ..... ..... 000 ..... 0111011 @r
+  paadd_w  1001101 ..... ..... 000 ..... 0111011 @r
+}
+paaddu_b   1011110 ..... ..... 000 ..... 0111011 @r
+paaddu_h   1011100 ..... ..... 000 ..... 0111011 @r
+{
+  aaddu    1011101 ..... ..... 000 ..... 0111011 @r
+  paaddu_w 1011101 ..... ..... 000 ..... 0111011 @r
+}
+pasub_b    1101110 ..... ..... 000 ..... 0111011 @r
+pasub_h    1101100 ..... ..... 000 ..... 0111011 @r
+{
+  asub     1101101 ..... ..... 000 ..... 0111011 @r
+  pasub_w  1101101 ..... ..... 000 ..... 0111011 @r
+}
+pasubu_b   1111110 ..... ..... 000 ..... 0111011 @r
+pasubu_h   1111100 ..... ..... 000 ..... 0111011 @r
+{
+  asubu    1111101 ..... ..... 000 ..... 0111011 @r
+  pasubu_w 1111101 ..... ..... 000 ..... 0111011 @r
+}
diff --git a/target/riscv/tcg/insn_trans/trans_rvp.c.inc b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
index 056ccfb486e..43c59aef182 100644
--- a/target/riscv/tcg/insn_trans/trans_rvp.c.inc
+++ b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
@@ -545,3 +545,21 @@ GEN_SIMD_TRANS_IMM_32_VXSAT(usati_32)
 GEN_SIMD_TRANS_IMM_64_VXSAT(sati_64)
 GEN_SIMD_TRANS_IMM_64_VXSAT(usati_64)
 
+/* Packed SIMD - Averaging and Rounding Operations */
+GEN_SIMD_TRANS(paadd_b)
+GEN_SIMD_TRANS(paadd_h)
+GEN_SIMD_TRANS_64(paadd_w)
+GEN_SIMD_TRANS(paaddu_b)
+GEN_SIMD_TRANS(paaddu_h)
+GEN_SIMD_TRANS_64(paaddu_w)
+GEN_SIMD_TRANS_32(aadd)
+GEN_SIMD_TRANS_32(aaddu)
+GEN_SIMD_TRANS(pasub_b)
+GEN_SIMD_TRANS(pasub_h)
+GEN_SIMD_TRANS_64(pasub_w)
+GEN_SIMD_TRANS(pasubu_b)
+GEN_SIMD_TRANS(pasubu_h)
+GEN_SIMD_TRANS_64(pasubu_w)
+GEN_SIMD_TRANS_32(asub)
+GEN_SIMD_TRANS_32(asubu)
+
diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
index 52c58e0287e..162041a8f18 100644
--- a/target/riscv/tcg/psimd_helper.c
+++ b/target/riscv/tcg/psimd_helper.c
@@ -1768,3 +1768,43 @@ GEN_PSIMD_SATI(sati_64, uint64_t, int64_t, int64_t,
 GEN_PSIMD_USATI(usati_64, uint64_t, int64_t, uint64_t, uint64_t,
                 EXTRACT64, INSERT64, ELEMS_D, 1ULL)
 
+/* Averaging Operations (non-saturating) */
+
+GEN_PSIMD_AVG_BINOP(paadd_b, target_ulong, int8_t, int16_t,
+                    EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ADD)
+GEN_PSIMD_AVG_BINOP(paadd_h, target_ulong, int16_t, int32_t,
+                    EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ADD)
+GEN_PSIMD_AVG_BINOP(paadd_w, uint64_t, int32_t, int64_t,
+                    EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD)
+
+GEN_PSIMD_AVG_BINOP(paaddu_b, target_ulong, uint8_t, uint16_t,
+                    EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ADD)
+GEN_PSIMD_AVG_BINOP(paaddu_h, target_ulong, uint16_t, uint32_t,
+                    EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ADD)
+GEN_PSIMD_AVG_BINOP(paaddu_w, uint64_t, uint32_t, uint64_t,
+                    EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD)
+
+GEN_PSIMD_AVG_BINOP(aadd, uint32_t, int32_t, int64_t,
+                    EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD)
+GEN_PSIMD_AVG_BINOP(aaddu, uint32_t, uint32_t, uint64_t,
+                    EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD)
+
+GEN_PSIMD_AVG_BINOP(pasub_b, target_ulong, int8_t, int16_t,
+                    EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_SUB)
+GEN_PSIMD_AVG_BINOP(pasub_h, target_ulong, int16_t, int32_t,
+                    EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_SUB)
+GEN_PSIMD_AVG_BINOP(pasub_w, uint64_t, int32_t, int64_t,
+                    EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_SUB)
+
+GEN_PSIMD_AVG_BINOP(pasubu_b, target_ulong, uint8_t, uint16_t,
+                    EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_SUB)
+GEN_PSIMD_AVG_BINOP(pasubu_h, target_ulong, uint16_t, uint32_t,
+                    EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_SUB)
+GEN_PSIMD_AVG_BINOP(pasubu_w, uint64_t, uint32_t, uint64_t,
+                    EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_SUB)
+
+GEN_PSIMD_AVG_BINOP(asub, uint32_t, int32_t, int64_t,
+                    EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_SUB)
+GEN_PSIMD_AVG_BINOP(asubu, uint32_t, uint32_t, uint64_t,
+                    EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_SUB)
+
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH v2 05/18] target/riscv: Add packed SIMD absolute, difference, compare and mask instructions
  2026-07-17 10:06 [PATCH v2 00/18] target/riscv: Add support for RISC-V P Molly Chen
                   ` (3 preceding siblings ...)
  2026-07-17 10:06 ` [PATCH v2 04/18] target/riscv: Add packed SIMD averaging and rounding instructions Molly Chen
@ 2026-07-17 10:06 ` Molly Chen
  2026-07-17 10:06 ` [PATCH v2 06/18] target/riscv: Add packed SIMD shift instructions Molly Chen
                   ` (14 subsequent siblings)
  19 siblings, 0 replies; 34+ messages in thread
From: Molly Chen @ 2026-07-17 10:06 UTC (permalink / raw)
  To: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
	chao.liu.zevorn, Chao Liu
  Cc: xiaoou, qemu-riscv, qemu-devel

Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
---
 target/riscv/helper.h                       | 38 +++++++++
 target/riscv/insn32.decode                  | 44 ++++++++++
 target/riscv/tcg/insn_trans/trans_rvp.c.inc | 38 +++++++++
 target/riscv/tcg/psimd_helper.c             | 95 +++++++++++++++++++++
 4 files changed, 215 insertions(+)

diff --git a/target/riscv/helper.h b/target/riscv/helper.h
index 7256f776ae6..1628ca119ac 100644
--- a/target/riscv/helper.h
+++ b/target/riscv/helper.h
@@ -1417,3 +1417,41 @@ DEF_HELPER_3(pasubu_h, tl, env, tl, tl)
 DEF_HELPER_3(pasubu_w, i64, env, i64, i64)
 DEF_HELPER_3(asub, i32, env, i32, i32)
 DEF_HELPER_3(asubu, i32, env, i32, i32)
+
+/* Packed SIMD - Absolute Value and Difference Operations */
+DEF_HELPER_2(psabs_b, tl, env, tl)
+DEF_HELPER_2(psabs_h, tl, env, tl)
+DEF_HELPER_2(abs, tl, env, tl)
+DEF_HELPER_2(absw, i64, env, i64)
+DEF_HELPER_3(pabd_b, tl, env, tl, tl)
+DEF_HELPER_3(pabdu_b, tl, env, tl, tl)
+DEF_HELPER_3(pabd_h, tl, env, tl, tl)
+DEF_HELPER_3(pabdu_h, tl, env, tl, tl)
+DEF_HELPER_3(pabdsumu_b, tl, env, tl, tl)
+DEF_HELPER_4(pabdsumau_b, tl, env, tl, tl, tl)
+
+/* Packed SIMD - Comparison and Mask Generation Operations */
+DEF_HELPER_3(pmseq_b, tl, env, tl, tl)
+DEF_HELPER_3(pmslt_b, tl, env, tl, tl)
+DEF_HELPER_3(pmsltu_b, tl, env, tl, tl)
+DEF_HELPER_3(pmin_b, tl, env, tl, tl)
+DEF_HELPER_3(pminu_b, tl, env, tl, tl)
+DEF_HELPER_3(pmax_b, tl, env, tl, tl)
+DEF_HELPER_3(pmaxu_b, tl, env, tl, tl)
+DEF_HELPER_3(pmseq_h, tl, env, tl, tl)
+DEF_HELPER_3(pmslt_h, tl, env, tl, tl)
+DEF_HELPER_3(pmsltu_h, tl, env, tl, tl)
+DEF_HELPER_3(pmin_h, tl, env, tl, tl)
+DEF_HELPER_3(pminu_h, tl, env, tl, tl)
+DEF_HELPER_3(pmax_h, tl, env, tl, tl)
+DEF_HELPER_3(pmaxu_h, tl, env, tl, tl)
+DEF_HELPER_3(pmseq_w, i64, env, i64, i64)
+DEF_HELPER_3(pmslt_w, i64, env, i64, i64)
+DEF_HELPER_3(pmsltu_w, i64, env, i64, i64)
+DEF_HELPER_3(pmin_w, i64, env, i64, i64)
+DEF_HELPER_3(pminu_w, i64, env, i64, i64)
+DEF_HELPER_3(pmax_w, i64, env, i64, i64)
+DEF_HELPER_3(pmaxu_w, i64, env, i64, i64)
+DEF_HELPER_3(mseq, i32, env, i32, i32)
+DEF_HELPER_3(mslt, i32, env, i32, i32)
+DEF_HELPER_3(msltu, i32, env, i32, i32)
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index 005cc055b8a..0c60f2eac7a 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -1173,3 +1173,47 @@ pasubu_h   1111100 ..... ..... 000 ..... 0111011 @r
   asubu    1111101 ..... ..... 000 ..... 0111011 @r
   pasubu_w 1111101 ..... ..... 000 ..... 0111011 @r
 }
+
+# Packed SIMD - Absolute Value and Difference Operations
+psabs_b    1110010 00111 ..... 010 ..... 0011011 @r2
+psabs_h    1110000 00111 ..... 010 ..... 0011011 @r2
+abs        01100 0000111 ..... 001 ..... 0010011 @r2
+absw       01100 0000111 ..... 001 ..... 0011011 @r2
+pabd_b     1100110 ..... ..... 000 ..... 0111011 @r
+pabdu_b    1110110 ..... ..... 000 ..... 0111011 @r
+pabd_h     1100100 ..... ..... 000 ..... 0111011 @r
+pabdu_h    1110100 ..... ..... 000 ..... 0111011 @r
+pabdsumu_b 1011010 ..... ..... 001 ..... 0111011 @r
+pabdsumau_b 1011110 ..... ..... 001 ..... 0111011 @r
+
+# Packed SIMD - Comparison and Mask Generation Operations
+pmseq_b    1100010 ..... ..... 110 ..... 0111011 @r
+pmslt_b    1101010 ..... ..... 110 ..... 0111011 @r
+pmsltu_b   1101110 ..... ..... 110 ..... 0111011 @r
+pmin_b     1110010 ..... ..... 110 ..... 0111011 @r
+pminu_b    1110110 ..... ..... 110 ..... 0111011 @r
+pmax_b     1111010 ..... ..... 110 ..... 0111011 @r
+pmaxu_b    1111110 ..... ..... 110 ..... 0111011 @r
+pmseq_h    1100000 ..... ..... 110 ..... 0111011 @r
+pmslt_h    1101000 ..... ..... 110 ..... 0111011 @r
+pmsltu_h   1101100 ..... ..... 110 ..... 0111011 @r
+pmin_h     1110000 ..... ..... 110 ..... 0111011 @r
+pminu_h    1110100 ..... ..... 110 ..... 0111011 @r
+pmax_h     1111000 ..... ..... 110 ..... 0111011 @r
+pmaxu_h    1111100 ..... ..... 110 ..... 0111011 @r
+{
+  mseq     1100001 ..... ..... 110 ..... 0111011 @r
+  pmseq_w  1100001 ..... ..... 110 ..... 0111011 @r
+}
+{
+  mslt     1101001 ..... ..... 110 ..... 0111011 @r
+  pmslt_w  1101001 ..... ..... 110 ..... 0111011 @r
+}
+{
+  msltu    1101101 ..... ..... 110 ..... 0111011 @r
+  pmsltu_w 1101101 ..... ..... 110 ..... 0111011 @r
+}
+pmin_w     1110001 ..... ..... 110 ..... 0111011 @r
+pminu_w    1110101 ..... ..... 110 ..... 0111011 @r
+pmax_w     1111001 ..... ..... 110 ..... 0111011 @r
+pmaxu_w    1111101 ..... ..... 110 ..... 0111011 @r
diff --git a/target/riscv/tcg/insn_trans/trans_rvp.c.inc b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
index 43c59aef182..2ad8e818ba5 100644
--- a/target/riscv/tcg/insn_trans/trans_rvp.c.inc
+++ b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
@@ -563,3 +563,41 @@ GEN_SIMD_TRANS_64(pasubu_w)
 GEN_SIMD_TRANS_32(asub)
 GEN_SIMD_TRANS_32(asubu)
 
+/* Packed SIMD - Absolute Value and Difference Operations */
+GEN_SIMD_TRANS_R1_VXSAT(psabs_b)
+GEN_SIMD_TRANS_R1_VXSAT(psabs_h)
+GEN_SIMD_TRANS_R1(abs)
+GEN_SIMD_TRANS_R1_64(absw)
+GEN_SIMD_TRANS(pabd_b)
+GEN_SIMD_TRANS(pabdu_b)
+GEN_SIMD_TRANS(pabd_h)
+GEN_SIMD_TRANS(pabdu_h)
+GEN_SIMD_TRANS(pabdsumu_b)
+GEN_SIMD_TRANS_ACC(pabdsumau_b)
+
+/* Packed SIMD - Comparison and Mask Generation Operations */
+GEN_SIMD_TRANS(pmseq_b)
+GEN_SIMD_TRANS(pmslt_b)
+GEN_SIMD_TRANS(pmsltu_b)
+GEN_SIMD_TRANS(pmin_b)
+GEN_SIMD_TRANS(pminu_b)
+GEN_SIMD_TRANS(pmax_b)
+GEN_SIMD_TRANS(pmaxu_b)
+GEN_SIMD_TRANS(pmseq_h)
+GEN_SIMD_TRANS(pmslt_h)
+GEN_SIMD_TRANS(pmsltu_h)
+GEN_SIMD_TRANS(pmin_h)
+GEN_SIMD_TRANS(pminu_h)
+GEN_SIMD_TRANS(pmax_h)
+GEN_SIMD_TRANS(pmaxu_h)
+GEN_SIMD_TRANS_64(pmseq_w)
+GEN_SIMD_TRANS_64(pmslt_w)
+GEN_SIMD_TRANS_64(pmsltu_w)
+GEN_SIMD_TRANS_64(pmin_w)
+GEN_SIMD_TRANS_64(pminu_w)
+GEN_SIMD_TRANS_64(pmax_w)
+GEN_SIMD_TRANS_64(pmaxu_w)
+GEN_SIMD_TRANS_32(mseq)
+GEN_SIMD_TRANS_32(mslt)
+GEN_SIMD_TRANS_32(msltu)
+
diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
index 162041a8f18..034afe5a054 100644
--- a/target/riscv/tcg/psimd_helper.c
+++ b/target/riscv/tcg/psimd_helper.c
@@ -1808,3 +1808,98 @@ GEN_PSIMD_AVG_BINOP(asub, uint32_t, int32_t, int64_t,
 GEN_PSIMD_AVG_BINOP(asubu, uint32_t, uint32_t, uint64_t,
                     EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_SUB)
 
+/* Absolute value operations */
+
+GEN_PSIMD_ABS(psabs_b, target_ulong, int8_t,
+              EXTRACT8, INSERT8, ELEMS_B, INT8_MIN, INT8_MAX)
+GEN_PSIMD_ABS(psabs_h, target_ulong, int16_t,
+              EXTRACT16, INSERT16, ELEMS_H, INT16_MIN, INT16_MAX)
+
+GEN_PSIMD_SCALAR_ABS(abs, target_ulong, target_long, target_ulong)
+GEN_PSIMD_SCALAR_ABS(absw, uint64_t, int32_t, uint32_t)
+
+/* Absolute difference operations */
+
+GEN_PSIMD_BINOP(pabd_b, target_ulong, int8_t, uint8_t,
+                EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ABD)
+GEN_PSIMD_BINOP(pabdu_b, target_ulong, uint8_t, uint8_t,
+                EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ABD)
+GEN_PSIMD_BINOP(pabd_h, target_ulong, int16_t, uint16_t,
+                EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ABD)
+GEN_PSIMD_BINOP(pabdu_h, target_ulong, uint16_t, uint16_t,
+                EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ABD)
+
+/**
+ * PABDSUMU.B - Sum of unsigned absolute differences
+ * Returns sum(|rs1[i] - rs2[i]|) for all bytes
+ */
+target_ulong HELPER(pabdsumu_b)(CPURISCVState *env,
+                                target_ulong rs1, target_ulong rs2)
+{
+    return psimd_abdsumu_b(rs1, rs2, 0);
+}
+
+/**
+ * PABDSUMAU.B - Accumulated sum of unsigned absolute differences
+ * rd = rd + sum(|rs1[i] - rs2[i]|)
+ */
+target_ulong HELPER(pabdsumau_b)(CPURISCVState *env, target_ulong rs1,
+                                 target_ulong rs2, target_ulong rd)
+{
+    return psimd_abdsumu_b(rs1, rs2, rd);
+}
+
+/* Comparison operations (producing masks) */
+
+GEN_PSIMD_BINOP(pmseq_b, target_ulong, uint8_t, uint8_t,
+                EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_EQ_MASK)
+GEN_PSIMD_BINOP(pmslt_b, target_ulong, int8_t, uint8_t,
+                EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_LT_MASK)
+GEN_PSIMD_BINOP(pmsltu_b, target_ulong, uint8_t, uint8_t,
+                EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_LT_MASK)
+GEN_PSIMD_BINOP(pmin_b, target_ulong, int8_t, int8_t,
+                EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_MIN)
+GEN_PSIMD_BINOP(pminu_b, target_ulong, uint8_t, uint8_t,
+                EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_MIN)
+GEN_PSIMD_BINOP(pmax_b, target_ulong, int8_t, int8_t,
+                EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_MAX)
+GEN_PSIMD_BINOP(pmaxu_b, target_ulong, uint8_t, uint8_t,
+                EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_MAX)
+
+GEN_PSIMD_BINOP(pmseq_h, target_ulong, uint16_t, uint16_t,
+                EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_EQ_MASK)
+GEN_PSIMD_BINOP(pmslt_h, target_ulong, int16_t, uint16_t,
+                EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_LT_MASK)
+GEN_PSIMD_BINOP(pmsltu_h, target_ulong, uint16_t, uint16_t,
+                EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_LT_MASK)
+GEN_PSIMD_BINOP(pmin_h, target_ulong, int16_t, int16_t,
+                EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_MIN)
+GEN_PSIMD_BINOP(pminu_h, target_ulong, uint16_t, uint16_t,
+                EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_MIN)
+GEN_PSIMD_BINOP(pmax_h, target_ulong, int16_t, int16_t,
+                EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_MAX)
+GEN_PSIMD_BINOP(pmaxu_h, target_ulong, uint16_t, uint16_t,
+                EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_MAX)
+
+GEN_PSIMD_BINOP(pmseq_w, uint64_t, uint32_t, uint32_t,
+                EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_EQ_MASK)
+GEN_PSIMD_BINOP(pmslt_w, uint64_t, int32_t, uint32_t,
+                EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_LT_MASK)
+GEN_PSIMD_BINOP(pmsltu_w, uint64_t, uint32_t, uint32_t,
+                EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_LT_MASK)
+GEN_PSIMD_BINOP(pmin_w, uint64_t, int32_t, int32_t,
+                EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_MIN)
+GEN_PSIMD_BINOP(pminu_w, uint64_t, uint32_t, uint32_t,
+                EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_MIN)
+GEN_PSIMD_BINOP(pmax_w, uint64_t, int32_t, int32_t,
+                EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_MAX)
+GEN_PSIMD_BINOP(pmaxu_w, uint64_t, uint32_t, uint32_t,
+                EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_MAX)
+
+GEN_PSIMD_BINOP(mseq, uint32_t, uint32_t, uint32_t,
+                EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_EQ_MASK)
+GEN_PSIMD_BINOP(mslt, uint32_t, int32_t, uint32_t,
+                EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_LT_MASK)
+GEN_PSIMD_BINOP(msltu, uint32_t, uint32_t, uint32_t,
+                EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_LT_MASK)
+
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH v2 06/18] target/riscv: Add packed SIMD shift instructions
  2026-07-17 10:06 [PATCH v2 00/18] target/riscv: Add support for RISC-V P Molly Chen
                   ` (4 preceding siblings ...)
  2026-07-17 10:06 ` [PATCH v2 05/18] target/riscv: Add packed SIMD absolute, difference, compare and mask instructions Molly Chen
@ 2026-07-17 10:06 ` Molly Chen
  2026-07-17 10:07 ` [PATCH v2 07/18] target/riscv: Add packed SIMD exchange instructions Molly Chen
                   ` (13 subsequent siblings)
  19 siblings, 0 replies; 34+ messages in thread
From: Molly Chen @ 2026-07-17 10:06 UTC (permalink / raw)
  To: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
	chao.liu.zevorn, Chao Liu
  Cc: xiaoou, qemu-riscv, qemu-devel

Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
---
 target/riscv/helper.h                       |  43 ++++++
 target/riscv/insn32.decode                  |  57 ++++++++
 target/riscv/tcg/insn_trans/trans_rvp.c.inc |  43 ++++++
 target/riscv/tcg/psimd_helper.c             | 149 ++++++++++++++++++++
 4 files changed, 292 insertions(+)

diff --git a/target/riscv/helper.h b/target/riscv/helper.h
index 1628ca119ac..d72323890f6 100644
--- a/target/riscv/helper.h
+++ b/target/riscv/helper.h
@@ -1455,3 +1455,46 @@ DEF_HELPER_3(pmaxu_w, i64, env, i64, i64)
 DEF_HELPER_3(mseq, i32, env, i32, i32)
 DEF_HELPER_3(mslt, i32, env, i32, i32)
 DEF_HELPER_3(msltu, i32, env, i32, i32)
+
+/* Packed SIMD - Shift Operations */
+DEF_HELPER_3(pslli_b, tl, env, tl, tl)
+DEF_HELPER_3(psll_bs, tl, env, tl, tl)
+DEF_HELPER_3(pslli_h, tl, env, tl, tl)
+DEF_HELPER_3(psll_hs, tl, env, tl, tl)
+DEF_HELPER_3(pslli_w, i64, env, i64, i64)
+DEF_HELPER_3(psll_ws, i64, env, i64, i64)
+DEF_HELPER_3(psrli_b, tl, env, tl, tl)
+DEF_HELPER_3(psrl_bs, tl, env, tl, tl)
+DEF_HELPER_3(psrli_h, tl, env, tl, tl)
+DEF_HELPER_3(psrl_hs, tl, env, tl, tl)
+DEF_HELPER_3(psrli_w, i64, env, i64, i64)
+DEF_HELPER_3(psrl_ws, i64, env, i64, i64)
+DEF_HELPER_3(psrai_b, tl, env, tl, tl)
+DEF_HELPER_3(psra_bs, tl, env, tl, tl)
+DEF_HELPER_3(psrai_h, tl, env, tl, tl)
+DEF_HELPER_3(psra_hs, tl, env, tl, tl)
+DEF_HELPER_3(psrai_w, i64, env, i64, i64)
+DEF_HELPER_3(psra_ws, i64, env, i64, i64)
+DEF_HELPER_3(psslai_h, tl, env, tl, tl)
+DEF_HELPER_3(psslai_w, i64, env, i64, i64)
+DEF_HELPER_3(sslai, i32, env, i32, i32)
+DEF_HELPER_3(psrari_h, tl, env, tl, tl)
+DEF_HELPER_3(psrari_w, i64, env, i64, i64)
+DEF_HELPER_3(srari_32, i32, env, i32, i32)
+DEF_HELPER_3(srari_64, i64, env, i64, i64)
+DEF_HELPER_3(pssha_hs, tl, env, tl, tl)
+DEF_HELPER_3(pssha_ws, i64, env, i64, i64)
+DEF_HELPER_3(psshar_hs, tl, env, tl, tl)
+DEF_HELPER_3(psshar_ws, i64, env, i64, i64)
+DEF_HELPER_3(ssha, i32, env, i32, i32)
+DEF_HELPER_3(sshar, i32, env, i32, i32)
+DEF_HELPER_3(sha, i64, env, i64, i64)
+DEF_HELPER_3(shar, i64, env, i64, i64)
+DEF_HELPER_3(psshl_hs, tl, env, tl, tl)
+DEF_HELPER_3(psshlr_hs, tl, env, tl, tl)
+DEF_HELPER_3(psshl_ws, i64, env, i64, i64)
+DEF_HELPER_3(psshlr_ws, i64, env, i64, i64)
+DEF_HELPER_3(sshl, i32, env, i32, i32)
+DEF_HELPER_3(sshlr, i32, env, i32, i32)
+DEF_HELPER_3(shl, i64, env, i64, i64)
+DEF_HELPER_3(shlr, i64, env, i64, i64)
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index 0c60f2eac7a..fb029bb512f 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -40,6 +40,7 @@
 %imm_z6   26:1 15:5
 %imm_mop5 30:1 26:2 20:2
 %imm_mop3 30:1 26:2
+%imm_p_ui8 20:3
 %imm_p_ui16 20:4
 %imm_p_ui32 20:5
 %imm_p_ui64 20:6
@@ -109,6 +110,7 @@
 @mop5 . . .. .. .... .. ..... ... ..... ....... &mop5 imm=%imm_mop5 %rd %rs1
 @mop3 . . .. .. . ..... ..... ... ..... ....... &mop3 imm=%imm_mop3 %rd %rs1 %rs2
 
+@p_ui8  ..... .... ... ..... ... ..... ....... &i imm=%imm_p_ui8  %rs1 %rd
 @p_ui16 ..... .... ... ..... ... ..... ....... &i imm=%imm_p_ui16 %rs1 %rd
 @p_ui32 ..... .... ... ..... ... ..... ....... &i imm=%imm_p_ui32 %rs1 %rd
 @p_ui64 ..... .... ... ..... ... ..... ....... &i imm=%imm_p_ui64 %rs1 %rd
@@ -1217,3 +1219,58 @@ pmin_w     1110001 ..... ..... 110 ..... 0111011 @r
 pminu_w    1110101 ..... ..... 110 ..... 0111011 @r
 pmax_w     1111001 ..... ..... 110 ..... 0111011 @r
 pmaxu_w    1111101 ..... ..... 110 ..... 0111011 @r
+
+# Packed SIMD - Shift Operations
+pslli_b    10000 0001... ..... 010 ..... 0011011 @p_ui8
+psll_bs    1000110 ..... ..... 010 ..... 0011011 @r
+pslli_h    10000 001.... ..... 010 ..... 0011011 @p_ui16
+psll_hs    1000100 ..... ..... 010 ..... 0011011 @r
+pslli_w    10000 01..... ..... 010 ..... 0011011 @p_ui32
+psll_ws    1000101 ..... ..... 010 ..... 0011011 @r
+psrli_b    10000 0001... ..... 100 ..... 0011011 @p_ui8
+psrl_bs    1000110 ..... ..... 100 ..... 0011011 @r
+psrli_h    10000 001.... ..... 100 ..... 0011011 @p_ui16
+psrl_hs    1000100 ..... ..... 100 ..... 0011011 @r
+psrli_w    10000 01..... ..... 100 ..... 0011011 @p_ui32
+psrl_ws    1000101 ..... ..... 100 ..... 0011011 @r
+psrai_b    11000 0001... ..... 100 ..... 0011011 @p_ui8
+psra_bs    1100110 ..... ..... 100 ..... 0011011 @r
+psrai_h    11000 001.... ..... 100 ..... 0011011 @p_ui16
+psra_hs    1100100 ..... ..... 100 ..... 0011011 @r
+psrai_w    11000 01..... ..... 100 ..... 0011011 @p_ui32
+psra_ws    1100101 ..... ..... 100 ..... 0011011 @r
+psslai_h   11010 001.... ..... 010 ..... 0011011 @p_ui16
+{
+  sslai    11010 01..... ..... 010 ..... 0011011 @p_ui32
+  psslai_w 11010 01..... ..... 010 ..... 0011011 @p_ui32
+}
+psrari_h   11010 001.... ..... 100 ..... 0011011 @p_ui16
+{
+  srari_32 11010 01..... ..... 100 ..... 0011011 @p_ui32
+  psrari_w 11010 01..... ..... 100 ..... 0011011 @p_ui32
+}
+srari_64   110101 ...... ..... 100 ..... 0011011 @p_ui64
+pssha_hs   1110100 ..... ..... 010 ..... 0011011 @r
+{
+  ssha     1110101 ..... ..... 010 ..... 0011011 @r
+  pssha_ws 1110101 ..... ..... 010 ..... 0011011 @r
+}
+psshar_hs  1111100 ..... ..... 010 ..... 0011011 @r
+{
+  sshar    1111101 ..... ..... 010 ..... 0011011 @r
+  psshar_ws 1111101 ..... ..... 010 ..... 0011011 @r
+}
+sha        1110111 ..... ..... 010 ..... 0011011 @r
+shar       1111111 ..... ..... 010 ..... 0011011 @r
+psshl_hs   1010100 ..... ..... 010 ..... 0011011 @r
+psshlr_hs  1011100 ..... ..... 010 ..... 0011011 @r
+{
+  psshl_ws 1010101 ..... ..... 010 ..... 0011011 @r
+  sshl     1010101 ..... ..... 010 ..... 0011011 @r
+}
+{
+  psshlr_ws 1011101 ..... ..... 010 ..... 0011011 @r
+  sshlr     1011101 ..... ..... 010 ..... 0011011 @r
+}
+shl        1010111 ..... ..... 010 ..... 0011011 @r
+shlr       1011111 ..... ..... 010 ..... 0011011 @r
diff --git a/target/riscv/tcg/insn_trans/trans_rvp.c.inc b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
index 2ad8e818ba5..fb82760a60c 100644
--- a/target/riscv/tcg/insn_trans/trans_rvp.c.inc
+++ b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
@@ -601,3 +601,46 @@ GEN_SIMD_TRANS_32(mseq)
 GEN_SIMD_TRANS_32(mslt)
 GEN_SIMD_TRANS_32(msltu)
 
+/* Packed SIMD - Shift Operations */
+GEN_SIMD_TRANS_IMM(pslli_b)
+GEN_SIMD_TRANS(psll_bs)
+GEN_SIMD_TRANS_IMM(pslli_h)
+GEN_SIMD_TRANS(psll_hs)
+GEN_SIMD_TRANS_IMM_64(pslli_w)
+GEN_SIMD_TRANS_64(psll_ws)
+GEN_SIMD_TRANS_IMM(psrli_b)
+GEN_SIMD_TRANS(psrl_bs)
+GEN_SIMD_TRANS_IMM(psrli_h)
+GEN_SIMD_TRANS(psrl_hs)
+GEN_SIMD_TRANS_IMM_64(psrli_w)
+GEN_SIMD_TRANS_64(psrl_ws)
+GEN_SIMD_TRANS_IMM(psrai_b)
+GEN_SIMD_TRANS(psra_bs)
+GEN_SIMD_TRANS_IMM(psrai_h)
+GEN_SIMD_TRANS(psra_hs)
+GEN_SIMD_TRANS_IMM_64(psrai_w)
+GEN_SIMD_TRANS_64(psra_ws)
+GEN_SIMD_TRANS_IMM_VXSAT(psslai_h)
+GEN_SIMD_TRANS_IMM_64_VXSAT(psslai_w)
+GEN_SIMD_TRANS_IMM_32_VXSAT(sslai)
+GEN_SIMD_TRANS_IMM(psrari_h)
+GEN_SIMD_TRANS_IMM_64(psrari_w)
+GEN_SIMD_TRANS_IMM_32(srari_32)
+GEN_SIMD_TRANS_IMM_64(srari_64)
+GEN_SIMD_TRANS_VXSAT(pssha_hs)
+GEN_SIMD_TRANS_64_VXSAT(pssha_ws)
+GEN_SIMD_TRANS_VXSAT(psshar_hs)
+GEN_SIMD_TRANS_64_VXSAT(psshar_ws)
+GEN_SIMD_TRANS_32_VXSAT(ssha)
+GEN_SIMD_TRANS_32_VXSAT(sshar)
+GEN_SIMD_TRANS_64(sha)
+GEN_SIMD_TRANS_64(shar)
+GEN_SIMD_TRANS_VXSAT(psshl_hs)
+GEN_SIMD_TRANS_VXSAT(psshlr_hs)
+GEN_SIMD_TRANS_64_VXSAT(psshl_ws)
+GEN_SIMD_TRANS_64_VXSAT(psshlr_ws)
+GEN_SIMD_TRANS_32_VXSAT(sshl)
+GEN_SIMD_TRANS_32_VXSAT(sshlr)
+GEN_SIMD_TRANS_64(shl)
+GEN_SIMD_TRANS_64(shlr)
+
diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
index 034afe5a054..8b106a336f5 100644
--- a/target/riscv/tcg/psimd_helper.c
+++ b/target/riscv/tcg/psimd_helper.c
@@ -1903,3 +1903,152 @@ GEN_PSIMD_BINOP(mslt, uint32_t, int32_t, uint32_t,
 GEN_PSIMD_BINOP(msltu, uint32_t, uint32_t, uint32_t,
                 EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_LT_MASK)
 
+/* Shift operations (immediate and register) */
+
+GEN_PSIMD_SHIFTOP(pslli_b, target_ulong, uint8_t, uint8_t,
+                  EXTRACT8, INSERT8, ELEMS_B, 0x07, PSIMD_DO_SLL)
+GEN_PSIMD_SHIFTOP(psll_bs, target_ulong, uint8_t, uint8_t,
+                  EXTRACT8, INSERT8, ELEMS_B, 0x07, PSIMD_DO_SLL)
+GEN_PSIMD_SHIFTOP(pslli_h, target_ulong, uint16_t, uint16_t,
+                  EXTRACT16, INSERT16, ELEMS_H, 0x0f, PSIMD_DO_SLL)
+GEN_PSIMD_SHIFTOP(psll_hs, target_ulong, uint16_t, uint16_t,
+                  EXTRACT16, INSERT16, ELEMS_H, 0x0f, PSIMD_DO_SLL)
+GEN_PSIMD_SHIFTOP(pslli_w, uint64_t, uint32_t, uint32_t,
+                  EXTRACT32, INSERT32, ELEMS_W, 0x1f, PSIMD_DO_SLL)
+GEN_PSIMD_SHIFTOP(psll_ws, uint64_t, uint32_t, uint32_t,
+                  EXTRACT32, INSERT32, ELEMS_W, 0x1f, PSIMD_DO_SLL)
+
+GEN_PSIMD_SHIFTOP(psrli_b, target_ulong, uint8_t, uint8_t,
+                  EXTRACT8, INSERT8, ELEMS_B, 0x07, PSIMD_DO_SRL)
+GEN_PSIMD_SHIFTOP(psrl_bs, target_ulong, uint8_t, uint8_t,
+                  EXTRACT8, INSERT8, ELEMS_B, 0x07, PSIMD_DO_SRL)
+GEN_PSIMD_SHIFTOP(psrli_h, target_ulong, uint16_t, uint16_t,
+                  EXTRACT16, INSERT16, ELEMS_H, 0x0f, PSIMD_DO_SRL)
+GEN_PSIMD_SHIFTOP(psrl_hs, target_ulong, uint16_t, uint16_t,
+                  EXTRACT16, INSERT16, ELEMS_H, 0x0f, PSIMD_DO_SRL)
+GEN_PSIMD_SHIFTOP(psrli_w, uint64_t, uint32_t, uint32_t,
+                  EXTRACT32, INSERT32, ELEMS_W, 0x1f, PSIMD_DO_SRL)
+GEN_PSIMD_SHIFTOP(psrl_ws, uint64_t, uint32_t, uint32_t,
+                  EXTRACT32, INSERT32, ELEMS_W, 0x1f, PSIMD_DO_SRL)
+
+GEN_PSIMD_SHIFTOP(psrai_b, target_ulong, int8_t, uint8_t,
+                  EXTRACT8, INSERT8, ELEMS_B, 0x07, PSIMD_DO_SRA)
+GEN_PSIMD_SHIFTOP(psra_bs, target_ulong, int8_t, uint8_t,
+                  EXTRACT8, INSERT8, ELEMS_B, 0x07, PSIMD_DO_SRA)
+GEN_PSIMD_SHIFTOP(psrai_h, target_ulong, int16_t, uint16_t,
+                  EXTRACT16, INSERT16, ELEMS_H, 0x0f, PSIMD_DO_SRA)
+GEN_PSIMD_SHIFTOP(psra_hs, target_ulong, int16_t, uint16_t,
+                  EXTRACT16, INSERT16, ELEMS_H, 0x0f, PSIMD_DO_SRA)
+GEN_PSIMD_SHIFTOP(psrai_w, uint64_t, int32_t, uint32_t,
+                  EXTRACT32, INSERT32, ELEMS_W, 0x1f, PSIMD_DO_SRA)
+GEN_PSIMD_SHIFTOP(psra_ws, uint64_t, int32_t, uint32_t,
+                  EXTRACT32, INSERT32, ELEMS_W, 0x1f, PSIMD_DO_SRA)
+
+/* Saturating shift operations */
+
+GEN_PSIMD_SAT_SHIFTOP(psslai_h, target_ulong, int16_t, int32_t,
+                      EXTRACT16, INSERT16, ELEMS_H, 0x0f,
+                      signed_saturate_h)
+GEN_PSIMD_SAT_SHIFTOP(psslai_w, uint64_t, int32_t, int64_t,
+                      EXTRACT32, INSERT32, ELEMS_W, 0x1f,
+                      signed_saturate_w)
+
+GEN_PSIMD_SAT_SHIFTOP(sslai, uint32_t, int32_t, int64_t,
+                      EXTRACT32, INSERT32, ELEMS_W, 0x1f,
+                      signed_saturate_w)
+
+/* Rounding shift operations */
+
+GEN_PSIMD_ROUND_SRAI(psrari_h, target_ulong, int16_t, int32_t,
+                     EXTRACT16, INSERT16, ELEMS_H, 0x0f)
+GEN_PSIMD_ROUND_SRAI(psrari_w, uint64_t, int32_t, int64_t,
+                     EXTRACT32, INSERT32, ELEMS_W, 0x1f)
+
+GEN_PSIMD_ROUND_SRAI(srari_32, uint32_t, int32_t, int64_t,
+                     EXTRACT32, INSERT32, ELEMS_W, 0x1f)
+
+/**
+ * SRARI_64 - 64-bit scalar arithmetic shift right with rounding
+ */
+uint64_t HELPER(srari_64)(CPURISCVState *env, uint64_t rs1, uint64_t imm)
+{
+    int64_t a = (int64_t)rs1;
+    uint8_t shamt = imm & 0x3F;
+
+    if (shamt == 0) {
+        return rs1;
+    }
+
+    return (uint64_t)(((a >> (shamt - 1)) + 1) >> 1);
+}
+
+/* Variable shift operations (with saturation and rounding) */
+
+GEN_PSIMD_VAR_SSHA(pssha_hs, target_ulong, int16_t, int32_t,
+                   EXTRACT16, INSERT16, ELEMS_H, 16, signed_saturate_h)
+GEN_PSIMD_VAR_SSHA(pssha_ws, uint64_t, int32_t, int64_t,
+                   EXTRACT32, INSERT32, ELEMS_W, 32, signed_saturate_w)
+
+GEN_PSIMD_VAR_SSHAR(psshar_hs, target_ulong, int16_t, int32_t,
+                    EXTRACT16, INSERT16, ELEMS_H, 16, SAT_MIN_H, SAT_MAX_H,
+                    signed_saturate_h)
+GEN_PSIMD_VAR_SSHAR(psshar_ws, uint64_t, int32_t, int64_t,
+                    EXTRACT32, INSERT32, ELEMS_W, 32, SAT_MIN_W, SAT_MAX_W,
+                    signed_saturate_w)
+
+GEN_PSIMD_VAR_SSHA(ssha, uint32_t, int32_t, int64_t,
+                   EXTRACT32, INSERT32, ELEMS_W, 32, signed_saturate_w)
+
+/**
+ * SSHAR - 32-bit scalar variable shift with rounding and saturation
+ */
+uint32_t HELPER(sshar)(CPURISCVState *env, uint32_t rs1, uint32_t rs2)
+{
+    int32_t a = (int32_t)rs1;
+    int8_t shamt = (int8_t)(rs2 & 0xFF);
+    int sat = 0;
+    int32_t res;
+
+    if (shamt >= 0) {
+        int64_t shifted = (int64_t)a << shamt;
+        res = signed_saturate_w(shifted, &sat);
+    } else {
+        int right = -shamt;
+        if (right >= 32) {
+            res = (a < 0) ? -1 : 0;
+        } else {
+            int64_t rounded = ((a >> (right - 1)) + 1) >> 1;
+            res = (int32_t)rounded;
+        }
+    }
+
+    if (sat) {
+        env->vxsat = 1;
+    }
+    return (uint32_t)res;
+}
+
+GEN_PSIMD_VAR_SRA64(sha, PSIMD_DO_SRA64)
+GEN_PSIMD_VAR_SRA64(shar, PSIMD_DO_RNDSRA64)
+
+GEN_PSIMD_VAR_USHL(psshl_hs, target_ulong, uint16_t, uint32_t,
+                   EXTRACT16, INSERT16, ELEMS_H, 16, unsigned_saturate_h)
+
+GEN_PSIMD_VAR_USHLR(psshlr_hs, target_ulong, uint16_t, uint32_t,
+                    EXTRACT16, INSERT16, ELEMS_H, 16, unsigned_saturate_h)
+
+GEN_PSIMD_VAR_USHL(psshl_ws, uint64_t, uint32_t, uint64_t,
+                   EXTRACT32, INSERT32, ELEMS_W, 32, unsigned_saturate_w)
+
+GEN_PSIMD_VAR_USHLR(psshlr_ws, uint64_t, uint32_t, uint64_t,
+                    EXTRACT32, INSERT32, ELEMS_W, 32, unsigned_saturate_w)
+
+GEN_PSIMD_VAR_USHL(sshl, uint32_t, uint32_t, uint64_t,
+                   EXTRACT32, INSERT32, ELEMS_W, 32, unsigned_saturate_w)
+
+GEN_PSIMD_VAR_USHLR(sshlr, uint32_t, uint32_t, uint64_t,
+                    EXTRACT32, INSERT32, ELEMS_W, 32, unsigned_saturate_w)
+
+GEN_PSIMD_VAR_SRL64(shl, PSIMD_DO_SRL64)
+GEN_PSIMD_VAR_SRL64(shlr, PSIMD_DO_RNDSRL64)
+
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH v2 07/18] target/riscv: Add packed SIMD exchange instructions
  2026-07-17 10:06 [PATCH v2 00/18] target/riscv: Add support for RISC-V P Molly Chen
                   ` (5 preceding siblings ...)
  2026-07-17 10:06 ` [PATCH v2 06/18] target/riscv: Add packed SIMD shift instructions Molly Chen
@ 2026-07-17 10:07 ` Molly Chen
  2026-07-17 10:07 ` [PATCH v2 08/18] target/riscv: Add packed SIMD horizontal reduction instructions Molly Chen
                   ` (12 subsequent siblings)
  19 siblings, 0 replies; 34+ messages in thread
From: Molly Chen @ 2026-07-17 10:07 UTC (permalink / raw)
  To: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
	chao.liu.zevorn, Chao Liu
  Cc: xiaoou, qemu-riscv, qemu-devel

Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
---
 target/riscv/helper.h                       | 14 +++++++
 target/riscv/insn32.decode                  | 14 +++++++
 target/riscv/tcg/insn_trans/trans_rvp.c.inc | 14 +++++++
 target/riscv/tcg/psimd_helper.c             | 44 +++++++++++++++++++++
 4 files changed, 86 insertions(+)

diff --git a/target/riscv/helper.h b/target/riscv/helper.h
index d72323890f6..d0b13cf3c6a 100644
--- a/target/riscv/helper.h
+++ b/target/riscv/helper.h
@@ -1498,3 +1498,17 @@ DEF_HELPER_3(sshl, i32, env, i32, i32)
 DEF_HELPER_3(sshlr, i32, env, i32, i32)
 DEF_HELPER_3(shl, i64, env, i64, i64)
 DEF_HELPER_3(shlr, i64, env, i64, i64)
+
+/* Packed SIMD - Exchange Operations */
+DEF_HELPER_3(pas_hx, tl, env, tl, tl)
+DEF_HELPER_3(psa_hx, tl, env, tl, tl)
+DEF_HELPER_3(psas_hx, tl, env, tl, tl)
+DEF_HELPER_3(pssa_hx, tl, env, tl, tl)
+DEF_HELPER_3(paas_hx, tl, env, tl, tl)
+DEF_HELPER_3(pasa_hx, tl, env, tl, tl)
+DEF_HELPER_3(pas_wx, i64, env, i64, i64)
+DEF_HELPER_3(psa_wx, i64, env, i64, i64)
+DEF_HELPER_3(psas_wx, i64, env, i64, i64)
+DEF_HELPER_3(pssa_wx, i64, env, i64, i64)
+DEF_HELPER_3(paas_wx, i64, env, i64, i64)
+DEF_HELPER_3(pasa_wx, i64, env, i64, i64)
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index fb029bb512f..e331ba6a38c 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -1274,3 +1274,17 @@ psshlr_hs  1011100 ..... ..... 010 ..... 0011011 @r
 }
 shl        1010111 ..... ..... 010 ..... 0011011 @r
 shlr       1011111 ..... ..... 010 ..... 0011011 @r
+
+# Packed SIMD - Exchange Operations
+pas_hx     1000000 ..... ..... 110 ..... 0111011 @r
+psa_hx     1000010 ..... ..... 110 ..... 0111011 @r
+psas_hx    1001000 ..... ..... 110 ..... 0111011 @r
+pssa_hx    1001010 ..... ..... 110 ..... 0111011 @r
+paas_hx    1001100 ..... ..... 110 ..... 0111011 @r
+pasa_hx    1001110 ..... ..... 110 ..... 0111011 @r
+pas_wx     1000001 ..... ..... 110 ..... 0111011 @r
+psa_wx     1000011 ..... ..... 110 ..... 0111011 @r
+psas_wx    1001001 ..... ..... 110 ..... 0111011 @r
+pssa_wx    1001011 ..... ..... 110 ..... 0111011 @r
+paas_wx    1001101 ..... ..... 110 ..... 0111011 @r
+pasa_wx    1001111 ..... ..... 110 ..... 0111011 @r
diff --git a/target/riscv/tcg/insn_trans/trans_rvp.c.inc b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
index fb82760a60c..61e1fb8d816 100644
--- a/target/riscv/tcg/insn_trans/trans_rvp.c.inc
+++ b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
@@ -644,3 +644,17 @@ GEN_SIMD_TRANS_32_VXSAT(sshlr)
 GEN_SIMD_TRANS_64(shl)
 GEN_SIMD_TRANS_64(shlr)
 
+/* Packed SIMD - Exchange Operations */
+GEN_SIMD_TRANS(pas_hx)
+GEN_SIMD_TRANS(psa_hx)
+GEN_SIMD_TRANS_VXSAT(psas_hx)
+GEN_SIMD_TRANS_VXSAT(pssa_hx)
+GEN_SIMD_TRANS(paas_hx)
+GEN_SIMD_TRANS(pasa_hx)
+GEN_SIMD_TRANS_64(pas_wx)
+GEN_SIMD_TRANS_64(psa_wx)
+GEN_SIMD_TRANS_64_VXSAT(psas_wx)
+GEN_SIMD_TRANS_64_VXSAT(pssa_wx)
+GEN_SIMD_TRANS_64(paas_wx)
+GEN_SIMD_TRANS_64(pasa_wx)
+
diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
index 8b106a336f5..ccc43b2dda0 100644
--- a/target/riscv/tcg/psimd_helper.c
+++ b/target/riscv/tcg/psimd_helper.c
@@ -2052,3 +2052,47 @@ GEN_PSIMD_VAR_USHLR(sshlr, uint32_t, uint32_t, uint64_t,
 GEN_PSIMD_VAR_SRL64(shl, PSIMD_DO_SRL64)
 GEN_PSIMD_VAR_SRL64(shlr, PSIMD_DO_RNDSRL64)
 
+/* Exchange operations (AS/SA/AS/SA with X suffix) */
+
+GEN_PSIMD_XPAIR_BINOP(pas_hx, target_ulong, int16_t,
+                      EXTRACT16, INSERT16, ELEMS_H,
+                      PSIMD_DO_SUB, PSIMD_DO_ADD)
+GEN_PSIMD_XPAIR_BINOP(psa_hx, target_ulong, int16_t,
+                      EXTRACT16, INSERT16, ELEMS_H,
+                      PSIMD_DO_ADD, PSIMD_DO_SUB)
+
+GEN_PSIMD_XPAIR_SAT_BINOP(psas_hx, target_ulong, int16_t, int32_t,
+                          EXTRACT16, INSERT16, ELEMS_H,
+                          PSIMD_DO_SUB, PSIMD_DO_ADD, signed_saturate_h)
+GEN_PSIMD_XPAIR_SAT_BINOP(pssa_hx, target_ulong, int16_t, int32_t,
+                          EXTRACT16, INSERT16, ELEMS_H,
+                          PSIMD_DO_ADD, PSIMD_DO_SUB, signed_saturate_h)
+
+GEN_PSIMD_XPAIR_AVG_BINOP(paas_hx, target_ulong, int16_t, int32_t,
+                          EXTRACT16, INSERT16, ELEMS_H,
+                          PSIMD_DO_SUB, PSIMD_DO_ADD)
+GEN_PSIMD_XPAIR_AVG_BINOP(pasa_hx, target_ulong, int16_t, int32_t,
+                          EXTRACT16, INSERT16, ELEMS_H,
+                          PSIMD_DO_ADD, PSIMD_DO_SUB)
+
+GEN_PSIMD_XPAIR_BINOP(pas_wx, uint64_t, int32_t,
+                      EXTRACT32, INSERT32, ELEMS_W,
+                      PSIMD_DO_SUB, PSIMD_DO_ADD)
+GEN_PSIMD_XPAIR_BINOP(psa_wx, uint64_t, int32_t,
+                      EXTRACT32, INSERT32, ELEMS_W,
+                      PSIMD_DO_ADD, PSIMD_DO_SUB)
+
+GEN_PSIMD_XPAIR_SAT_BINOP(psas_wx, uint64_t, int32_t, int64_t,
+                          EXTRACT32, INSERT32, ELEMS_W,
+                          PSIMD_DO_SUB, PSIMD_DO_ADD, signed_saturate_w)
+GEN_PSIMD_XPAIR_SAT_BINOP(pssa_wx, uint64_t, int32_t, int64_t,
+                          EXTRACT32, INSERT32, ELEMS_W,
+                          PSIMD_DO_ADD, PSIMD_DO_SUB, signed_saturate_w)
+
+GEN_PSIMD_XPAIR_AVG_BINOP(paas_wx, uint64_t, int32_t, int64_t,
+                          EXTRACT32, INSERT32, ELEMS_W,
+                          PSIMD_DO_SUB, PSIMD_DO_ADD)
+GEN_PSIMD_XPAIR_AVG_BINOP(pasa_wx, uint64_t, int32_t, int64_t,
+                          EXTRACT32, INSERT32, ELEMS_W,
+                          PSIMD_DO_ADD, PSIMD_DO_SUB)
+
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH v2 08/18] target/riscv: Add packed SIMD horizontal reduction instructions
  2026-07-17 10:06 [PATCH v2 00/18] target/riscv: Add support for RISC-V P Molly Chen
                   ` (6 preceding siblings ...)
  2026-07-17 10:07 ` [PATCH v2 07/18] target/riscv: Add packed SIMD exchange instructions Molly Chen
@ 2026-07-17 10:07 ` Molly Chen
  2026-07-17 10:07 ` [PATCH v2 09/18] target/riscv: Add packed SIMD pack, merge and count-leading instructions Molly Chen
                   ` (11 subsequent siblings)
  19 siblings, 0 replies; 34+ messages in thread
From: Molly Chen @ 2026-07-17 10:07 UTC (permalink / raw)
  To: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
	chao.liu.zevorn, Chao Liu
  Cc: xiaoou, qemu-riscv, qemu-devel

Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
---
 target/riscv/helper.h                       |  8 ++++++++
 target/riscv/insn32.decode                  |  8 ++++++++
 target/riscv/tcg/insn_trans/trans_rvp.c.inc |  8 ++++++++
 target/riscv/tcg/psimd_helper.c             | 15 +++++++++++++++
 4 files changed, 39 insertions(+)

diff --git a/target/riscv/helper.h b/target/riscv/helper.h
index d0b13cf3c6a..5fe650c5d71 100644
--- a/target/riscv/helper.h
+++ b/target/riscv/helper.h
@@ -1512,3 +1512,11 @@ DEF_HELPER_3(psas_wx, i64, env, i64, i64)
 DEF_HELPER_3(pssa_wx, i64, env, i64, i64)
 DEF_HELPER_3(paas_wx, i64, env, i64, i64)
 DEF_HELPER_3(pasa_wx, i64, env, i64, i64)
+
+/* Packed SIMD - Horizontal Reduction Operations */
+DEF_HELPER_3(predsum_bs, tl, env, tl, tl)
+DEF_HELPER_3(predsumu_bs, tl, env, tl, tl)
+DEF_HELPER_3(predsum_hs, tl, env, tl, tl)
+DEF_HELPER_3(predsumu_hs, tl, env, tl, tl)
+DEF_HELPER_3(predsum_ws, i64, env, i64, i64)
+DEF_HELPER_3(predsumu_ws, i64, env, i64, i64)
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index e331ba6a38c..9d0f5c48b6d 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -1288,3 +1288,11 @@ psas_wx    1001001 ..... ..... 110 ..... 0111011 @r
 pssa_wx    1001011 ..... ..... 110 ..... 0111011 @r
 paas_wx    1001101 ..... ..... 110 ..... 0111011 @r
 pasa_wx    1001111 ..... ..... 110 ..... 0111011 @r
+
+# Packed SIMD - Horizontal Reduction Operations
+predsum_bs   1001110 ..... ..... 100 ..... 0011011 @r
+predsumu_bs  1011110 ..... ..... 100 ..... 0011011 @r
+predsum_hs   1001100 ..... ..... 100 ..... 0011011 @r
+predsumu_hs  1011100 ..... ..... 100 ..... 0011011 @r
+predsum_ws   1001101 ..... ..... 100 ..... 0011011 @r
+predsumu_ws  1011101 ..... ..... 100 ..... 0011011 @r
diff --git a/target/riscv/tcg/insn_trans/trans_rvp.c.inc b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
index 61e1fb8d816..9f2ae9da1d1 100644
--- a/target/riscv/tcg/insn_trans/trans_rvp.c.inc
+++ b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
@@ -658,3 +658,11 @@ GEN_SIMD_TRANS_64_VXSAT(pssa_wx)
 GEN_SIMD_TRANS_64(paas_wx)
 GEN_SIMD_TRANS_64(pasa_wx)
 
+/* Packed SIMD - Horizontal Reduction Operations */
+GEN_SIMD_TRANS(predsum_bs)
+GEN_SIMD_TRANS(predsumu_bs)
+GEN_SIMD_TRANS(predsum_hs)
+GEN_SIMD_TRANS(predsumu_hs)
+GEN_SIMD_TRANS_64(predsum_ws)
+GEN_SIMD_TRANS_64(predsumu_ws)
+
diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
index ccc43b2dda0..0acf0414bf9 100644
--- a/target/riscv/tcg/psimd_helper.c
+++ b/target/riscv/tcg/psimd_helper.c
@@ -2096,3 +2096,18 @@ GEN_PSIMD_XPAIR_AVG_BINOP(pasa_wx, uint64_t, int32_t, int64_t,
                           EXTRACT32, INSERT32, ELEMS_W,
                           PSIMD_DO_ADD, PSIMD_DO_SUB)
 
+/* Horizontal sum operations */
+
+GEN_PSIMD_REDSUM(predsum_bs, target_ulong, int64_t, int8_t,
+                 EXTRACT8, ELEMS_B, (int64_t)(int32_t)rs2)
+GEN_PSIMD_REDSUM(predsumu_bs, target_ulong, uint64_t, uint8_t,
+                 EXTRACT8, ELEMS_B, rs2)
+GEN_PSIMD_REDSUM(predsum_hs, target_ulong, int64_t, int16_t,
+                 EXTRACT16, ELEMS_H, (int64_t)(int32_t)rs2)
+GEN_PSIMD_REDSUM(predsumu_hs, target_ulong, uint64_t, uint16_t,
+                 EXTRACT16, ELEMS_H, rs2)
+GEN_PSIMD_REDSUM(predsum_ws, uint64_t, int64_t, int32_t,
+                 EXTRACT32, ELEMS_W, (int64_t)rs2)
+GEN_PSIMD_REDSUM(predsumu_ws, uint64_t, uint64_t, uint32_t,
+                 EXTRACT32, ELEMS_W, rs2)
+
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH v2 09/18] target/riscv: Add packed SIMD pack, merge and count-leading instructions
  2026-07-17 10:06 [PATCH v2 00/18] target/riscv: Add support for RISC-V P Molly Chen
                   ` (7 preceding siblings ...)
  2026-07-17 10:07 ` [PATCH v2 08/18] target/riscv: Add packed SIMD horizontal reduction instructions Molly Chen
@ 2026-07-17 10:07 ` Molly Chen
  2026-07-17 10:07 ` [PATCH v2 10/18] target/riscv: Add packed SIMD multiplication instructions Molly Chen
                   ` (10 subsequent siblings)
  19 siblings, 0 replies; 34+ messages in thread
From: Molly Chen @ 2026-07-17 10:07 UTC (permalink / raw)
  To: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
	chao.liu.zevorn, Chao Liu
  Cc: xiaoou, qemu-riscv, qemu-devel

Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
---
 target/riscv/helper.h                       |  41 ++++++
 target/riscv/insn32.decode                  |  41 ++++++
 target/riscv/tcg/insn_trans/trans_rvp.c.inc |  41 ++++++
 target/riscv/tcg/psimd_helper.c             | 148 ++++++++++++++++++++
 4 files changed, 271 insertions(+)

diff --git a/target/riscv/helper.h b/target/riscv/helper.h
index 5fe650c5d71..f83af437d40 100644
--- a/target/riscv/helper.h
+++ b/target/riscv/helper.h
@@ -1520,3 +1520,44 @@ DEF_HELPER_3(predsum_hs, tl, env, tl, tl)
 DEF_HELPER_3(predsumu_hs, tl, env, tl, tl)
 DEF_HELPER_3(predsum_ws, i64, env, i64, i64)
 DEF_HELPER_3(predsumu_ws, i64, env, i64, i64)
+
+/* Packed SIMD - Pack, Unpack, and Merge Operations */
+DEF_HELPER_3(ppaire_b, tl, env, tl, tl)
+DEF_HELPER_3(ppaireo_b, tl, env, tl, tl)
+DEF_HELPER_3(ppairoe_b, tl, env, tl, tl)
+DEF_HELPER_3(ppairo_b, tl, env, tl, tl)
+DEF_HELPER_3(ppaire_h, i64, env, i64, i64)
+DEF_HELPER_3(ppaireo_h, tl, env, tl, tl)
+DEF_HELPER_3(ppairoe_h, tl, env, tl, tl)
+DEF_HELPER_3(ppairo_h, tl, env, tl, tl)
+DEF_HELPER_3(ppaireo_w, i64, env, i64, i64)
+DEF_HELPER_3(ppairoe_w, i64, env, i64, i64)
+DEF_HELPER_3(ppairo_w, i64, env, i64, i64)
+DEF_HELPER_2(psext_h_b, tl, env, tl)
+DEF_HELPER_2(psext_w_b, i64, env, i64)
+DEF_HELPER_2(psext_w_h, i64, env, i64)
+DEF_HELPER_2(rev, tl, env, tl)
+DEF_HELPER_2(rev16, i64, env, i64)
+DEF_HELPER_3(zip8p, i64, env, i64, i64)
+DEF_HELPER_3(zip8hp, i64, env, i64, i64)
+DEF_HELPER_3(unzip8p, i64, env, i64, i64)
+DEF_HELPER_3(unzip8hp, i64, env, i64, i64)
+DEF_HELPER_3(zip16p, i64, env, i64, i64)
+DEF_HELPER_3(zip16hp, i64, env, i64, i64)
+DEF_HELPER_3(unzip16p, i64, env, i64, i64)
+DEF_HELPER_3(unzip16hp, i64, env, i64, i64)
+DEF_HELPER_4(slx, tl, env, tl, tl, tl)
+DEF_HELPER_4(srx, tl, env, tl, tl, tl)
+DEF_HELPER_4(mvm, tl, env, tl, tl, tl)
+DEF_HELPER_4(mvmn, tl, env, tl, tl, tl)
+DEF_HELPER_4(merge, tl, env, tl, tl, tl)
+DEF_HELPER_3(pnclipp_b, i64, env, i64, i64)
+DEF_HELPER_3(pnclipup_b, i64, env, i64, i64)
+DEF_HELPER_3(pnclipp_h, i64, env, i64, i64)
+DEF_HELPER_3(pnclipup_h, i64, env, i64, i64)
+DEF_HELPER_3(pnclipp_w, i64, env, i64, i64)
+DEF_HELPER_3(pnclipup_w, i64, env, i64, i64)
+
+/* Packed SIMD - Count Leading Operations */
+DEF_HELPER_2(cls, tl, env, tl)
+DEF_HELPER_2(clsw, i64, env, i64)
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index 9d0f5c48b6d..14dab4cb641 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -1296,3 +1296,44 @@ predsum_hs   1001100 ..... ..... 100 ..... 0011011 @r
 predsumu_hs  1011100 ..... ..... 100 ..... 0011011 @r
 predsum_ws   1001101 ..... ..... 100 ..... 0011011 @r
 predsumu_ws  1011101 ..... ..... 100 ..... 0011011 @r
+
+# Packed SIMD - Pack, Unpack, and Merge Operations
+ppaire_b    1000000 ..... ..... 100 ..... 0111011 @r
+ppaireo_b   1001000 ..... ..... 100 ..... 0111011 @r
+ppairoe_b   1010000 ..... ..... 100 ..... 0111011 @r
+ppairo_b    1011000 ..... ..... 100 ..... 0111011 @r
+ppaireo_h   1001001 ..... ..... 100 ..... 0111011 @r
+ppairoe_h   1010001 ..... ..... 100 ..... 0111011 @r
+ppairo_h    1011001 ..... ..... 100 ..... 0111011 @r
+ppaire_h    1000001 ..... ..... 100 ..... 0111011 @r
+ppaireo_w   1001011 ..... ..... 100 ..... 0111011 @r
+ppairoe_w   1010011 ..... ..... 100 ..... 0111011 @r
+ppairo_w    1011011 ..... ..... 100 ..... 0111011 @r
+psext_h_b   1110000 00100 ..... 010 ..... 0011011 @r2
+psext_w_b   1110001 00100 ..... 010 ..... 0011011 @r2
+psext_w_h   1110001 00101 ..... 010 ..... 0011011 @r2
+rev         01101 0111111 ..... 101 ..... 0010011 @r2
+rev16       01101 0110000 ..... 101 ..... 0010011 @r2
+zip8p       1111000 ..... ..... 010 ..... 0111011 @r
+zip8hp      1111010 ..... ..... 010 ..... 0111011 @r
+unzip8p     1110000 ..... ..... 010 ..... 0111011 @r
+unzip8hp    1110010 ..... ..... 010 ..... 0111011 @r
+zip16p      1111001 ..... ..... 010 ..... 0111011 @r
+zip16hp     1111011 ..... ..... 010 ..... 0111011 @r
+unzip16p    1110001 ..... ..... 010 ..... 0111011 @r
+unzip16hp   1110011 ..... ..... 010 ..... 0111011 @r
+slx         1000111 ..... ..... 001 ..... 0111011 @r
+srx         1010111 ..... ..... 001 ..... 0111011 @r
+mvm         1010100 ..... ..... 001 ..... 0111011 @r
+mvmn        1010101 ..... ..... 001 ..... 0111011 @r
+merge       1010110 ..... ..... 001 ..... 0111011 @r
+pnclipp_b   1100000 ..... ..... 010 ..... 0111011 @r
+pnclipup_b  1000000 ..... ..... 010 ..... 0111011 @r
+pnclipp_h   1100001 ..... ..... 010 ..... 0111011 @r
+pnclipup_h  1000001 ..... ..... 010 ..... 0111011 @r
+pnclipp_w   1100011 ..... ..... 010 ..... 0111011 @r
+pnclipup_w  1000011 ..... ..... 010 ..... 0111011 @r
+
+# Packed SIMD - Count Leading Operations
+cls    01100 0000011 ..... 001 ..... 0010011 @r2
+clsw   01100 0000011 ..... 001 ..... 0011011 @r2
diff --git a/target/riscv/tcg/insn_trans/trans_rvp.c.inc b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
index 9f2ae9da1d1..486184eeaf3 100644
--- a/target/riscv/tcg/insn_trans/trans_rvp.c.inc
+++ b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
@@ -666,3 +666,44 @@ GEN_SIMD_TRANS(predsumu_hs)
 GEN_SIMD_TRANS_64(predsum_ws)
 GEN_SIMD_TRANS_64(predsumu_ws)
 
+/* Packed SIMD - Pack, Unpack, and Merge Operations */
+GEN_SIMD_TRANS(ppaire_b)
+GEN_SIMD_TRANS(ppaireo_b)
+GEN_SIMD_TRANS(ppairoe_b)
+GEN_SIMD_TRANS(ppairo_b)
+GEN_SIMD_TRANS_64(ppaire_h)
+GEN_SIMD_TRANS(ppaireo_h)
+GEN_SIMD_TRANS(ppairoe_h)
+GEN_SIMD_TRANS(ppairo_h)
+GEN_SIMD_TRANS_64(ppaireo_w)
+GEN_SIMD_TRANS_64(ppairoe_w)
+GEN_SIMD_TRANS_64(ppairo_w)
+GEN_SIMD_TRANS_R1(psext_h_b)
+GEN_SIMD_TRANS_R1_64(psext_w_b)
+GEN_SIMD_TRANS_R1_64(psext_w_h)
+GEN_SIMD_TRANS_R1(rev)
+GEN_SIMD_TRANS_R1_64(rev16)
+GEN_SIMD_TRANS_64(zip8p)
+GEN_SIMD_TRANS_64(zip8hp)
+GEN_SIMD_TRANS_64(unzip8p)
+GEN_SIMD_TRANS_64(unzip8hp)
+GEN_SIMD_TRANS_64(zip16p)
+GEN_SIMD_TRANS_64(zip16hp)
+GEN_SIMD_TRANS_64(unzip16p)
+GEN_SIMD_TRANS_64(unzip16hp)
+GEN_SIMD_TRANS_ACC(slx)
+GEN_SIMD_TRANS_ACC(srx)
+GEN_SIMD_TRANS_ACC(mvm)
+GEN_SIMD_TRANS_ACC(mvmn)
+GEN_SIMD_TRANS_ACC(merge)
+GEN_SIMD_TRANS_64_VXSAT(pnclipp_b)
+GEN_SIMD_TRANS_64_VXSAT(pnclipup_b)
+GEN_SIMD_TRANS_64_VXSAT(pnclipp_h)
+GEN_SIMD_TRANS_64_VXSAT(pnclipup_h)
+GEN_SIMD_TRANS_64_VXSAT(pnclipp_w)
+GEN_SIMD_TRANS_64_VXSAT(pnclipup_w)
+
+/* Packed SIMD - Count Leading Operations */
+GEN_SIMD_TRANS_R1(cls)
+GEN_SIMD_TRANS_R1_64(clsw)
+
diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
index 0acf0414bf9..99f11f084f2 100644
--- a/target/riscv/tcg/psimd_helper.c
+++ b/target/riscv/tcg/psimd_helper.c
@@ -2111,3 +2111,151 @@ GEN_PSIMD_REDSUM(predsum_ws, uint64_t, int64_t, int32_t,
 GEN_PSIMD_REDSUM(predsumu_ws, uint64_t, uint64_t, uint32_t,
                  EXTRACT32, ELEMS_W, rs2)
 
+/* Packing/unpacking operations */
+
+GEN_PSIMD_PAIR_PACK(ppaire_b, target_ulong, uint16_t,
+                    EXTRACT16, INSERT16, ELEMS_H, 0x00ff, 8,
+                    PSIMD_PAIR_LO, PSIMD_PAIR_LO)
+GEN_PSIMD_PAIR_PACK(ppaireo_b, target_ulong, uint16_t,
+                    EXTRACT16, INSERT16, ELEMS_H, 0x00ff, 8,
+                    PSIMD_PAIR_HI, PSIMD_PAIR_LO)
+GEN_PSIMD_PAIR_PACK(ppairoe_b, target_ulong, uint16_t,
+                    EXTRACT16, INSERT16, ELEMS_H, 0x00ff, 8,
+                    PSIMD_PAIR_LO, PSIMD_PAIR_HI)
+GEN_PSIMD_PAIR_PACK(ppairo_b, target_ulong, uint16_t,
+                    EXTRACT16, INSERT16, ELEMS_H, 0x00ff, 8,
+                    PSIMD_PAIR_HI, PSIMD_PAIR_HI)
+
+GEN_PSIMD_PAIR_PACK(ppaire_h, uint64_t, uint32_t,
+                    EXTRACT32, INSERT32, ELEMS_W, 0x0000ffff, 16,
+                    PSIMD_PAIR_LO, PSIMD_PAIR_LO)
+GEN_PSIMD_PAIR_PACK(ppaireo_h, target_ulong, uint32_t,
+                    EXTRACT32, INSERT32, ELEMS_W, 0x0000ffff, 16,
+                    PSIMD_PAIR_HI, PSIMD_PAIR_LO)
+GEN_PSIMD_PAIR_PACK(ppairoe_h, target_ulong, uint32_t,
+                    EXTRACT32, INSERT32, ELEMS_W, 0x0000ffff, 16,
+                    PSIMD_PAIR_LO, PSIMD_PAIR_HI)
+GEN_PSIMD_PAIR_PACK(ppairo_h, target_ulong, uint32_t,
+                    EXTRACT32, INSERT32, ELEMS_W, 0x0000ffff, 16,
+                    PSIMD_PAIR_HI, PSIMD_PAIR_HI)
+
+GEN_PSIMD_PAIR_WORD(ppaireo_w, 0, 1)
+GEN_PSIMD_PAIR_WORD(ppairoe_w, 1, 0)
+GEN_PSIMD_PAIR_WORD(ppairo_w, 1, 1)
+
+GEN_PSIMD_SIGN_EXTEND(psext_h_b, target_ulong, int8_t, int16_t,
+                      EXTRACT8, INSERT16, ELEMS_H, 2)
+GEN_PSIMD_SIGN_EXTEND(psext_w_b, uint64_t, int8_t, int32_t,
+                      EXTRACT8, INSERT32, ELEMS_W, 4)
+GEN_PSIMD_SIGN_EXTEND(psext_w_h, uint64_t, int16_t, int32_t,
+                      EXTRACT16, INSERT32, ELEMS_W, 2)
+
+/**
+ * REV - Reverse all bits
+ */
+target_ulong HELPER(rev)(CPURISCVState *env, target_ulong rs1)
+{
+    target_ulong rd = 0;
+
+    for (int i = 0; i < TARGET_LONG_BITS; i++) {
+        rd = (rd << 1) | (rs1 & 1);
+        rs1 >>= 1;
+    }
+
+    return rd;
+}
+
+/**
+ * REV16 - Reverse 16-bit chunks (RV64 only)
+ */
+uint64_t HELPER(rev16)(CPURISCVState *env, uint64_t rs1)
+{
+    uint64_t rd = 0;
+
+    for (int i = 0; i < 4; i++) {
+        uint16_t chunk = EXTRACT16(rs1, i);
+        rd = (rd << 16) | chunk;
+    }
+
+    return rd;
+}
+
+GEN_PSIMD_ZIP(zip8p, uint8_t, EXTRACT8, 4, 8, 3)
+GEN_PSIMD_ZIP(zip8hp, uint8_t, EXTRACT8, 4, 8, 7)
+GEN_PSIMD_UNZIP(unzip8p, EXTRACT8, 4, 8, 0)
+GEN_PSIMD_UNZIP(unzip8hp, EXTRACT8, 4, 8, 1)
+
+GEN_PSIMD_ZIP(zip16p, uint16_t, EXTRACT16, 2, 16, 1)
+GEN_PSIMD_ZIP(zip16hp, uint16_t, EXTRACT16, 2, 16, 3)
+GEN_PSIMD_UNZIP(unzip16p, EXTRACT16, 2, 16, 0)
+GEN_PSIMD_UNZIP(unzip16hp, EXTRACT16, 2, 16, 1)
+
+/* Merge and mask operations */
+
+/**
+ * SLX - Shift left extended (concatenate rd and rs1, shift left, take upper)
+ */
+target_ulong HELPER(slx)(CPURISCVState *env, target_ulong rs1,
+                         target_ulong rs2, target_ulong rd)
+{
+    int shamt = (TARGET_LONG_BITS == 32) ? (rs2 & 0x1F) : (rs2 & 0x3F);
+    target_ulong xrs1 = 0;
+    target_ulong xrd = 0;
+
+    if (shamt <= TARGET_LONG_BITS) {
+        xrs1 = rs1 >> (TARGET_LONG_BITS - shamt);
+        xrd = (rd << shamt) + xrs1;
+    } else {
+        xrd = rs1 << (shamt - TARGET_LONG_BITS);
+    }
+
+    return xrd;
+}
+
+/**
+ * SRX - Shift right extended (concatenate rs1 and rd, shift right, take lower)
+ */
+target_ulong HELPER(srx)(CPURISCVState *env, target_ulong rs1,
+                         target_ulong rs2, target_ulong rd)
+{
+    int shamt = (TARGET_LONG_BITS == 32) ? (rs2 & 0x1F) : (rs2 & 0x3F);
+    target_ulong xrs1 = 0;
+    target_ulong xrd = 0;
+
+    if (shamt <= TARGET_LONG_BITS) {
+        xrs1 = rs1 << (TARGET_LONG_BITS - shamt);
+        xrd = (rd >> shamt) + xrs1;
+    } else {
+        xrd = rs1 >> (shamt - TARGET_LONG_BITS);
+    }
+
+    return xrd;
+}
+
+GEN_PSIMD_BIT_SELECT(mvm, rs2, rs1, rd)
+GEN_PSIMD_BIT_SELECT(mvmn, rs2, rd, rs1)
+GEN_PSIMD_BIT_SELECT(merge, rd, rs2, rs1)
+
+GEN_PSIMD_NCLIP_PACK(pnclipp_b, int16_t, int8_t,
+                     EXTRACT16, INSERT8, 4, signed_saturate_b)
+GEN_PSIMD_NCLIP_PACK(pnclipup_b, uint16_t, uint8_t,
+                     EXTRACT16, INSERT8, 4, unsigned_saturate_b)
+GEN_PSIMD_NCLIP_PACK(pnclipp_h, int32_t, int16_t,
+                     EXTRACT32, INSERT16, 2, signed_saturate_h)
+GEN_PSIMD_NCLIP_PACK(pnclipup_h, uint32_t, uint16_t,
+                     EXTRACT32, INSERT16, 2, unsigned_saturate_h)
+GEN_PSIMD_NCLIP_PACK(pnclipp_w, int64_t, int32_t,
+                     EXTRACT64, INSERT32_64, 1, signed_saturate_w)
+GEN_PSIMD_NCLIP_PACK(pnclipup_w, uint64_t, uint32_t,
+                     EXTRACT64, INSERT32_64, 1, unsigned_saturate_w)
+
+/* Count leading operations */
+
+#if TARGET_LONG_BITS == 64
+GEN_PSIMD_CLS(cls, target_ulong, uint64_t, clrsb64)
+#else
+GEN_PSIMD_CLS(cls, target_ulong, uint32_t, clrsb32)
+#endif
+
+GEN_PSIMD_CLS(clsw, uint64_t, uint32_t, clrsb32)
+
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH v2 10/18] target/riscv: Add packed SIMD multiplication instructions
  2026-07-17 10:06 [PATCH v2 00/18] target/riscv: Add support for RISC-V P Molly Chen
                   ` (8 preceding siblings ...)
  2026-07-17 10:07 ` [PATCH v2 09/18] target/riscv: Add packed SIMD pack, merge and count-leading instructions Molly Chen
@ 2026-07-17 10:07 ` Molly Chen
  2026-07-17 10:07 ` [PATCH v2 11/18] target/riscv: Add packed SIMD multiply-accumulate instructions Molly Chen
                   ` (9 subsequent siblings)
  19 siblings, 0 replies; 34+ messages in thread
From: Molly Chen @ 2026-07-17 10:07 UTC (permalink / raw)
  To: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
	chao.liu.zevorn, Chao Liu
  Cc: xiaoou, qemu-riscv, qemu-devel

Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
---
 target/riscv/helper.h                       |  63 +++++++
 target/riscv/insn32.decode                  |  93 ++++++++++
 target/riscv/tcg/insn_trans/trans_rvp.c.inc |  63 +++++++
 target/riscv/tcg/psimd_helper.c             | 184 ++++++++++++++++++++
 4 files changed, 403 insertions(+)

diff --git a/target/riscv/helper.h b/target/riscv/helper.h
index f83af437d40..f06f40b1284 100644
--- a/target/riscv/helper.h
+++ b/target/riscv/helper.h
@@ -1561,3 +1561,66 @@ DEF_HELPER_3(pnclipup_w, i64, env, i64, i64)
 /* Packed SIMD - Count Leading Operations */
 DEF_HELPER_2(cls, tl, env, tl)
 DEF_HELPER_2(clsw, i64, env, i64)
+
+/* Packed SIMD - Pure Multiplication Operations */
+DEF_HELPER_3(pmulh_h, tl, env, tl, tl)
+DEF_HELPER_3(pmulhsu_h, tl, env, tl, tl)
+DEF_HELPER_3(pmulhu_h, tl, env, tl, tl)
+DEF_HELPER_3(pmulhr_h, tl, env, tl, tl)
+DEF_HELPER_3(pmulhrsu_h, tl, env, tl, tl)
+DEF_HELPER_3(pmulhru_h, tl, env, tl, tl)
+DEF_HELPER_3(pmulh_w, i64, env, i64, i64)
+DEF_HELPER_3(pmulhr_w, i64, env, i64, i64)
+DEF_HELPER_3(pmulhsu_w, i64, env, i64, i64)
+DEF_HELPER_3(pmulhrsu_w, i64, env, i64, i64)
+DEF_HELPER_3(pmulhu_w, i64, env, i64, i64)
+DEF_HELPER_3(pmulhru_w, i64, env, i64, i64)
+DEF_HELPER_3(mulhr, i32, env, i32, i32)
+DEF_HELPER_3(mulhrsu, i32, env, i32, i32)
+DEF_HELPER_3(mulhru, i32, env, i32, i32)
+DEF_HELPER_3(pmulh_h_b0, tl, env, tl, tl)
+DEF_HELPER_3(pmulh_h_b1, tl, env, tl, tl)
+DEF_HELPER_3(pmulhsu_h_b0, tl, env, tl, tl)
+DEF_HELPER_3(pmulhsu_h_b1, tl, env, tl, tl)
+DEF_HELPER_3(mulh_h0, i32, env, i32, i32)
+DEF_HELPER_3(mulh_h1, i32, env, i32, i32)
+DEF_HELPER_3(mulhsu_h0, i32, env, i32, i32)
+DEF_HELPER_3(mulhsu_h1, i32, env, i32, i32)
+DEF_HELPER_3(pmulh_w_h0, i64, env, i64, i64)
+DEF_HELPER_3(pmulh_w_h1, i64, env, i64, i64)
+DEF_HELPER_3(pmulhsu_w_h0, i64, env, i64, i64)
+DEF_HELPER_3(pmulhsu_w_h1, i64, env, i64, i64)
+DEF_HELPER_3(pmul_h_b00, tl, env, tl, tl)
+DEF_HELPER_3(pmul_h_b01, tl, env, tl, tl)
+DEF_HELPER_3(pmul_h_b11, tl, env, tl, tl)
+DEF_HELPER_3(pmulsu_h_b00, tl, env, tl, tl)
+DEF_HELPER_3(pmulsu_h_b11, tl, env, tl, tl)
+DEF_HELPER_3(pmulu_h_b00, tl, env, tl, tl)
+DEF_HELPER_3(pmulu_h_b01, tl, env, tl, tl)
+DEF_HELPER_3(pmulu_h_b11, tl, env, tl, tl)
+DEF_HELPER_3(pmul_w_h00, i64, env, i64, i64)
+DEF_HELPER_3(pmul_w_h01, i64, env, i64, i64)
+DEF_HELPER_3(pmul_w_h11, i64, env, i64, i64)
+DEF_HELPER_3(pmulsu_w_h00, i64, env, i64, i64)
+DEF_HELPER_3(pmulsu_w_h11, i64, env, i64, i64)
+DEF_HELPER_3(pmulu_w_h00, i64, env, i64, i64)
+DEF_HELPER_3(pmulu_w_h01, i64, env, i64, i64)
+DEF_HELPER_3(pmulu_w_h11, i64, env, i64, i64)
+DEF_HELPER_3(pm2sadd_h, tl, env, tl, tl)
+DEF_HELPER_3(pm2sadd_hx, tl, env, tl, tl)
+DEF_HELPER_3(mul_h00, i32, env, i32, i32)
+DEF_HELPER_3(mul_h01, i32, env, i32, i32)
+DEF_HELPER_3(mul_h11, i32, env, i32, i32)
+DEF_HELPER_3(mulsu_h00, i32, env, i32, i32)
+DEF_HELPER_3(mulsu_h11, i32, env, i32, i32)
+DEF_HELPER_3(mulu_h00, i32, env, i32, i32)
+DEF_HELPER_3(mulu_h01, i32, env, i32, i32)
+DEF_HELPER_3(mulu_h11, i32, env, i32, i32)
+DEF_HELPER_3(mul_w00, i64, env, i64, i64)
+DEF_HELPER_3(mul_w01, i64, env, i64, i64)
+DEF_HELPER_3(mul_w11, i64, env, i64, i64)
+DEF_HELPER_3(mulsu_w00, i64, env, i64, i64)
+DEF_HELPER_3(mulsu_w11, i64, env, i64, i64)
+DEF_HELPER_3(mulu_w00, i64, env, i64, i64)
+DEF_HELPER_3(mulu_w01, i64, env, i64, i64)
+DEF_HELPER_3(mulu_w11, i64, env, i64, i64)
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index 14dab4cb641..cc0cc35fe24 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -1337,3 +1337,96 @@ pnclipup_w  1000011 ..... ..... 010 ..... 0111011 @r
 # Packed SIMD - Count Leading Operations
 cls    01100 0000011 ..... 001 ..... 0010011 @r2
 clsw   01100 0000011 ..... 001 ..... 0011011 @r2
+
+# Packed SIMD - Pure Multiplication Operations
+pmulh_h     10000 00 ..... ..... 111 ..... 0111011 @r
+pmulhsu_h   11000 00 ..... ..... 111 ..... 0111011 @r
+pmulhu_h    10010 00 ..... ..... 111 ..... 0111011 @r
+pmulhr_h    10000 10 ..... ..... 111 ..... 0111011 @r
+pmulhrsu_h  11000 10 ..... ..... 111 ..... 0111011 @r
+pmulhru_h   10010 10 ..... ..... 111 ..... 0111011 @r
+pmulh_w     10000 01 ..... ..... 111 ..... 0111011 @r
+{
+  mulhr     10000 11 ..... ..... 111 ..... 0111011 @r
+  pmulhr_w  10000 11 ..... ..... 111 ..... 0111011 @r
+}
+pmulhsu_w   11000 01 ..... ..... 111 ..... 0111011 @r
+{
+  mulhrsu   11000 11 ..... ..... 111 ..... 0111011 @r
+  pmulhrsu_w    11000 11 ..... ..... 111 ..... 0111011 @r
+}
+pmulhu_w    10010 01 ..... ..... 111 ..... 0111011 @r
+{
+  mulhru    10010 11 ..... ..... 111 ..... 0111011 @r
+  pmulhru_w 10010 11 ..... ..... 111 ..... 0111011 @r
+}
+pmulh_h_b0      10100 00 ..... ..... 111 ..... 0111011 @r
+pmulh_h_b1      10110 00 ..... ..... 111 ..... 0111011 @r
+pmulhsu_h_b0    10100 10 ..... ..... 111 ..... 0111011 @r
+pmulhsu_h_b1    10110 10 ..... ..... 111 ..... 0111011 @r
+{
+  mulh_h0       10100 01 ..... ..... 111 ..... 0111011 @r
+  pmulh_w_h0    10100 01 ..... ..... 111 ..... 0111011 @r
+}
+{
+  mulh_h1       10110 01 ..... ..... 111 ..... 0111011 @r
+  pmulh_w_h1    10110 01 ..... ..... 111 ..... 0111011 @r
+}
+{
+  mulhsu_h0     10100 11 ..... ..... 111 ..... 0111011 @r
+  pmulhsu_w_h0  10100 11 ..... ..... 111 ..... 0111011 @r
+}
+{
+  mulhsu_h1     10110 11 ..... ..... 111 ..... 0111011 @r
+  pmulhsu_w_h1  10110 11 ..... ..... 111 ..... 0111011 @r
+}
+pmul_h_b00      10000 00 ..... ..... 011 ..... 0111011 @r
+pmul_h_b01      10010 00 ..... ..... 001 ..... 0111011 @r
+pmul_h_b11      10010 00 ..... ..... 011 ..... 0111011 @r
+pmulsu_h_b00    11100 00 ..... ..... 011 ..... 0111011 @r
+pmulsu_h_b11    11110 00 ..... ..... 011 ..... 0111011 @r
+pmulu_h_b00     10100 00 ..... ..... 011 ..... 0111011 @r
+pmulu_h_b01     10110 00 ..... ..... 001 ..... 0111011 @r
+pmulu_h_b11     10110 00 ..... ..... 011 ..... 0111011 @r
+{
+  mul_h00       10000 01 ..... ..... 011 ..... 0111011 @r
+  pmul_w_h00    10000 01 ..... ..... 011 ..... 0111011 @r
+}
+{
+  mul_h01       10010 01 ..... ..... 001 ..... 0111011 @r
+  pmul_w_h01    10010 01 ..... ..... 001 ..... 0111011 @r
+}
+{
+  mul_h11       10010 01 ..... ..... 011 ..... 0111011 @r
+  pmul_w_h11    10010 01 ..... ..... 011 ..... 0111011 @r
+}
+{
+  mulsu_h00     11100 01 ..... ..... 011 ..... 0111011 @r
+  pmulsu_w_h00  11100 01 ..... ..... 011 ..... 0111011 @r
+}
+{
+  mulsu_h11     11110 01 ..... ..... 011 ..... 0111011 @r
+  pmulsu_w_h11  11110 01 ..... ..... 011 ..... 0111011 @r
+}
+{
+  mulu_h00      10100 01 ..... ..... 011 ..... 0111011 @r
+  pmulu_w_h00   10100 01 ..... ..... 011 ..... 0111011 @r
+}
+{
+  mulu_h01      10110 01 ..... ..... 001 ..... 0111011 @r
+  pmulu_w_h01   10110 01 ..... ..... 001 ..... 0111011 @r
+}
+{
+  mulu_h11      10110 01 ..... ..... 011 ..... 0111011 @r
+  pmulu_w_h11   10110 01 ..... ..... 011 ..... 0111011 @r
+}
+pm2sadd_h       11000 10 ..... ..... 101 ..... 0111011 @r
+pm2sadd_hx      11010 10 ..... ..... 101 ..... 0111011 @r
+mul_w00         10000 11 ..... ..... 011 ..... 0111011 @r
+mul_w01         10010 11 ..... ..... 001 ..... 0111011 @r
+mul_w11         10010 11 ..... ..... 011 ..... 0111011 @r
+mulsu_w00       11100 11 ..... ..... 011 ..... 0111011 @r
+mulsu_w11       11110 11 ..... ..... 011 ..... 0111011 @r
+mulu_w00        10100 11 ..... ..... 011 ..... 0111011 @r
+mulu_w01        10110 11 ..... ..... 001 ..... 0111011 @r
+mulu_w11        10110 11 ..... ..... 011 ..... 0111011 @r
diff --git a/target/riscv/tcg/insn_trans/trans_rvp.c.inc b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
index 486184eeaf3..7edea099d01 100644
--- a/target/riscv/tcg/insn_trans/trans_rvp.c.inc
+++ b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
@@ -707,3 +707,66 @@ GEN_SIMD_TRANS_64_VXSAT(pnclipup_w)
 GEN_SIMD_TRANS_R1(cls)
 GEN_SIMD_TRANS_R1_64(clsw)
 
+/* Packed SIMD - Pure Multiplication Operations */
+GEN_SIMD_TRANS(pmulh_h)
+GEN_SIMD_TRANS(pmulhsu_h)
+GEN_SIMD_TRANS(pmulhu_h)
+GEN_SIMD_TRANS(pmulhr_h)
+GEN_SIMD_TRANS(pmulhrsu_h)
+GEN_SIMD_TRANS(pmulhru_h)
+GEN_SIMD_TRANS_64(pmulh_w)
+GEN_SIMD_TRANS_64(pmulhr_w)
+GEN_SIMD_TRANS_64(pmulhsu_w)
+GEN_SIMD_TRANS_64(pmulhrsu_w)
+GEN_SIMD_TRANS_64(pmulhu_w)
+GEN_SIMD_TRANS_64(pmulhru_w)
+GEN_SIMD_TRANS_32(mulhr)
+GEN_SIMD_TRANS_32(mulhrsu)
+GEN_SIMD_TRANS_32(mulhru)
+GEN_SIMD_TRANS(pmulh_h_b0)
+GEN_SIMD_TRANS(pmulh_h_b1)
+GEN_SIMD_TRANS(pmulhsu_h_b0)
+GEN_SIMD_TRANS(pmulhsu_h_b1)
+GEN_SIMD_TRANS_32(mulh_h0)
+GEN_SIMD_TRANS_32(mulh_h1)
+GEN_SIMD_TRANS_32(mulhsu_h0)
+GEN_SIMD_TRANS_32(mulhsu_h1)
+GEN_SIMD_TRANS_64(pmulh_w_h0)
+GEN_SIMD_TRANS_64(pmulh_w_h1)
+GEN_SIMD_TRANS_64(pmulhsu_w_h0)
+GEN_SIMD_TRANS_64(pmulhsu_w_h1)
+GEN_SIMD_TRANS(pmul_h_b00)
+GEN_SIMD_TRANS(pmul_h_b01)
+GEN_SIMD_TRANS(pmul_h_b11)
+GEN_SIMD_TRANS(pmulsu_h_b00)
+GEN_SIMD_TRANS(pmulsu_h_b11)
+GEN_SIMD_TRANS(pmulu_h_b00)
+GEN_SIMD_TRANS(pmulu_h_b01)
+GEN_SIMD_TRANS(pmulu_h_b11)
+GEN_SIMD_TRANS_64(pmul_w_h00)
+GEN_SIMD_TRANS_64(pmul_w_h01)
+GEN_SIMD_TRANS_64(pmul_w_h11)
+GEN_SIMD_TRANS_64(pmulsu_w_h00)
+GEN_SIMD_TRANS_64(pmulsu_w_h11)
+GEN_SIMD_TRANS_64(pmulu_w_h00)
+GEN_SIMD_TRANS_64(pmulu_w_h01)
+GEN_SIMD_TRANS_64(pmulu_w_h11)
+GEN_SIMD_TRANS_VXSAT(pm2sadd_h)
+GEN_SIMD_TRANS_VXSAT(pm2sadd_hx)
+GEN_SIMD_TRANS_32(mul_h00)
+GEN_SIMD_TRANS_32(mul_h01)
+GEN_SIMD_TRANS_32(mul_h11)
+GEN_SIMD_TRANS_32(mulsu_h00)
+GEN_SIMD_TRANS_32(mulsu_h11)
+GEN_SIMD_TRANS_32(mulu_h00)
+GEN_SIMD_TRANS_32(mulu_h01)
+GEN_SIMD_TRANS_32(mulu_h11)
+GEN_SIMD_TRANS_64(mul_w00)
+GEN_SIMD_TRANS_64(mul_w01)
+GEN_SIMD_TRANS_64(mul_w11)
+GEN_SIMD_TRANS_64(mulsu_w00)
+GEN_SIMD_TRANS_64(mulsu_w11)
+GEN_SIMD_TRANS_64(mulu_w00)
+GEN_SIMD_TRANS_64(mulu_w01)
+GEN_SIMD_TRANS_64(mulu_w11)
+
diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
index 99f11f084f2..5be8fe257f8 100644
--- a/target/riscv/tcg/psimd_helper.c
+++ b/target/riscv/tcg/psimd_helper.c
@@ -2259,3 +2259,187 @@ GEN_PSIMD_CLS(cls, target_ulong, uint32_t, clrsb32)
 
 GEN_PSIMD_CLS(clsw, uint64_t, uint32_t, clrsb32)
 
+/* Pure multiplication operations */
+
+GEN_PSIMD_MUL_HIGH(pmulh_h, target_ulong, int16_t, int16_t, int32_t,
+                   uint16_t, EXTRACT16, INSERT16, ELEMS_H, 16, 0,
+                   PSIMD_MUL_S32)
+GEN_PSIMD_MUL_HIGH(pmulhsu_h, target_ulong, int16_t, uint16_t, int32_t,
+                   uint16_t, EXTRACT16, INSERT16, ELEMS_H, 16, 0,
+                   PSIMD_MUL_SU32)
+GEN_PSIMD_MUL_HIGH(pmulhu_h, target_ulong, uint16_t, uint16_t, uint32_t,
+                   uint16_t, EXTRACT16, INSERT16, ELEMS_H, 16, 0,
+                   PSIMD_MUL_U32)
+GEN_PSIMD_MUL_HIGH(pmulhr_h, target_ulong, int16_t, int16_t, int32_t,
+                   uint16_t, EXTRACT16, INSERT16, ELEMS_H, 16, 1 << 15,
+                   PSIMD_MUL_S32)
+GEN_PSIMD_MUL_HIGH(pmulhrsu_h, target_ulong, int16_t, uint16_t, int32_t,
+                   uint16_t, EXTRACT16, INSERT16, ELEMS_H, 16, 1 << 15,
+                   PSIMD_MUL_SU32)
+GEN_PSIMD_MUL_HIGH(pmulhru_h, target_ulong, uint16_t, uint16_t, uint32_t,
+                   uint16_t, EXTRACT16, INSERT16, ELEMS_H, 16, 1 << 15,
+                   PSIMD_MUL_U32)
+
+GEN_PSIMD_MUL_HIGH(pmulh_w, uint64_t, int32_t, int32_t, int64_t,
+                   uint32_t, EXTRACT32, INSERT32, ELEMS_W, 32, 0,
+                   PSIMD_MUL_S64)
+GEN_PSIMD_MUL_HIGH(pmulhr_w, uint64_t, int32_t, int32_t, int64_t,
+                   uint32_t, EXTRACT32, INSERT32, ELEMS_W, 32, 1LL << 31,
+                   PSIMD_MUL_S64)
+GEN_PSIMD_MUL_HIGH(pmulhsu_w, uint64_t, int32_t, uint32_t, int64_t,
+                   uint32_t, EXTRACT32, INSERT32, ELEMS_W, 32, 0,
+                   PSIMD_MUL_SU64)
+GEN_PSIMD_MUL_HIGH(pmulhrsu_w, uint64_t, int32_t, uint32_t, int64_t,
+                   uint32_t, EXTRACT32, INSERT32, ELEMS_W, 32, 1LL << 31,
+                   PSIMD_MUL_SU64)
+GEN_PSIMD_MUL_HIGH(pmulhu_w, uint64_t, uint32_t, uint32_t, uint64_t,
+                   uint32_t, EXTRACT32, INSERT32, ELEMS_W, 32, 0,
+                   PSIMD_MUL_U64)
+GEN_PSIMD_MUL_HIGH(pmulhru_w, uint64_t, uint32_t, uint32_t, uint64_t,
+                   uint32_t, EXTRACT32, INSERT32, ELEMS_W, 32, 1LL << 31,
+                   PSIMD_MUL_U64)
+
+GEN_PSIMD_MUL_HIGH(mulhr, uint32_t, int32_t, int32_t, int64_t,
+                   uint32_t, EXTRACT32, INSERT32, ELEMS_W, 32, 1LL << 31,
+                   PSIMD_MUL_S64)
+GEN_PSIMD_MUL_HIGH(mulhrsu, uint32_t, int32_t, uint32_t, int64_t,
+                   uint32_t, EXTRACT32, INSERT32, ELEMS_W, 32, 1LL << 31,
+                   PSIMD_MUL_SU64)
+GEN_PSIMD_MUL_HIGH(mulhru, uint32_t, uint32_t, uint32_t, uint64_t,
+                   uint32_t, EXTRACT32, INSERT32, ELEMS_W, 32, 1LL << 31,
+                   PSIMD_MUL_U64)
+
+GEN_PSIMD_MUL_HIGH_SEL(pmulh_h_b0, target_ulong, int16_t, int8_t,
+                       int32_t, uint16_t, EXTRACT16, EXTRACT8, INSERT16,
+                       ELEMS_H, 2, 0, 8, PSIMD_MUL_S32)
+GEN_PSIMD_MUL_HIGH_SEL(pmulh_h_b1, target_ulong, int16_t, int8_t,
+                       int32_t, uint16_t, EXTRACT16, EXTRACT8, INSERT16,
+                       ELEMS_H, 2, 1, 8, PSIMD_MUL_S32)
+GEN_PSIMD_MUL_HIGH_SEL(pmulhsu_h_b0, target_ulong, int16_t, uint8_t,
+                       int32_t, uint16_t, EXTRACT16, EXTRACT8, INSERT16,
+                       ELEMS_H, 2, 0, 8, PSIMD_MUL_SU32)
+GEN_PSIMD_MUL_HIGH_SEL(pmulhsu_h_b1, target_ulong, int16_t, uint8_t,
+                       int32_t, uint16_t, EXTRACT16, EXTRACT8, INSERT16,
+                       ELEMS_H, 2, 1, 8, PSIMD_MUL_SU32)
+
+GEN_PSIMD_MUL_HIGH_SEL(mulh_h0, uint32_t, int32_t, int16_t,
+                       int64_t, uint32_t, EXTRACT32, EXTRACT16, INSERT32,
+                       ELEMS_W, 0, 0, 16, PSIMD_MUL_S64)
+GEN_PSIMD_MUL_HIGH_SEL(mulh_h1, uint32_t, int32_t, int16_t,
+                       int64_t, uint32_t, EXTRACT32, EXTRACT16, INSERT32,
+                       ELEMS_W, 0, 1, 16, PSIMD_MUL_S64)
+GEN_PSIMD_MUL_HIGH_SEL(mulhsu_h0, uint32_t, int32_t, uint16_t,
+                       int64_t, uint32_t, EXTRACT32, EXTRACT16, INSERT32,
+                       ELEMS_W, 0, 0, 16, PSIMD_MUL_SU64)
+GEN_PSIMD_MUL_HIGH_SEL(mulhsu_h1, uint32_t, int32_t, uint16_t,
+                       int64_t, uint32_t, EXTRACT32, EXTRACT16, INSERT32,
+                       ELEMS_W, 0, 1, 16, PSIMD_MUL_SU64)
+
+GEN_PSIMD_MUL_HIGH_SEL(pmulh_w_h0, uint64_t, int32_t, int16_t,
+                       int64_t, uint32_t, EXTRACT32, EXTRACT16, INSERT32,
+                       ELEMS_W, 2, 0, 16, PSIMD_MUL_S64)
+GEN_PSIMD_MUL_HIGH_SEL(pmulh_w_h1, uint64_t, int32_t, int16_t,
+                       int64_t, uint32_t, EXTRACT32, EXTRACT16, INSERT32,
+                       ELEMS_W, 2, 1, 16, PSIMD_MUL_S64)
+GEN_PSIMD_MUL_HIGH_SEL(pmulhsu_w_h0, uint64_t, int32_t, uint16_t,
+                       int64_t, uint32_t, EXTRACT32, EXTRACT16, INSERT32,
+                       ELEMS_W, 2, 0, 16, PSIMD_MUL_SU64)
+GEN_PSIMD_MUL_HIGH_SEL(pmulhsu_w_h1, uint64_t, int32_t, uint16_t,
+                       int64_t, uint32_t, EXTRACT32, EXTRACT16, INSERT32,
+                       ELEMS_W, 2, 1, 16, PSIMD_MUL_SU64)
+
+GEN_PSIMD_MUL_ELEM_INDEXED(pmul_h_b00, target_ulong, int8_t, int8_t,
+                           int16_t, uint16_t, EXTRACT8, INSERT16, ELEMS_H,
+                           2, 0, 0, PSIMD_MUL_S32)
+GEN_PSIMD_MUL_ELEM_INDEXED(pmul_h_b01, target_ulong, int8_t, int8_t,
+                           int16_t, uint16_t, EXTRACT8, INSERT16, ELEMS_H,
+                           2, 0, 1, PSIMD_MUL_S32)
+GEN_PSIMD_MUL_ELEM_INDEXED(pmul_h_b11, target_ulong, int8_t, int8_t,
+                           int16_t, uint16_t, EXTRACT8, INSERT16, ELEMS_H,
+                           2, 1, 1, PSIMD_MUL_S32)
+
+GEN_PSIMD_MUL_ELEM_INDEXED(pmulsu_h_b00, target_ulong, int8_t, uint8_t,
+                           int16_t, uint16_t, EXTRACT8, INSERT16, ELEMS_H,
+                           2, 0, 0, PSIMD_MUL_SU16)
+GEN_PSIMD_MUL_ELEM_INDEXED(pmulsu_h_b11, target_ulong, int8_t, uint8_t,
+                           int16_t, uint16_t, EXTRACT8, INSERT16, ELEMS_H,
+                           2, 1, 1, PSIMD_MUL_SU16)
+
+GEN_PSIMD_MUL_ELEM_INDEXED(pmulu_h_b00, target_ulong, uint8_t, uint8_t,
+                           uint16_t, uint16_t, EXTRACT8, INSERT16, ELEMS_H,
+                           2, 0, 0, PSIMD_MUL_U32)
+GEN_PSIMD_MUL_ELEM_INDEXED(pmulu_h_b01, target_ulong, uint8_t, uint8_t,
+                           uint16_t, uint16_t, EXTRACT8, INSERT16, ELEMS_H,
+                           2, 0, 1, PSIMD_MUL_U32)
+GEN_PSIMD_MUL_ELEM_INDEXED(pmulu_h_b11, target_ulong, uint8_t, uint8_t,
+                           uint16_t, uint16_t, EXTRACT8, INSERT16, ELEMS_H,
+                           2, 1, 1, PSIMD_MUL_U32)
+
+GEN_PSIMD_MUL_ELEM_INDEXED(pmul_w_h00, uint64_t, int16_t, int16_t,
+                           int32_t, uint32_t, EXTRACT16, INSERT32, ELEMS_W,
+                           2, 0, 0, PSIMD_MUL_S32)
+GEN_PSIMD_MUL_ELEM_INDEXED(pmul_w_h01, uint64_t, int16_t, int16_t,
+                           int32_t, uint32_t, EXTRACT16, INSERT32, ELEMS_W,
+                           2, 0, 1, PSIMD_MUL_S32)
+GEN_PSIMD_MUL_ELEM_INDEXED(pmul_w_h11, uint64_t, int16_t, int16_t,
+                           int32_t, uint32_t, EXTRACT16, INSERT32, ELEMS_W,
+                           2, 1, 1, PSIMD_MUL_S32)
+
+GEN_PSIMD_MUL_ELEM_INDEXED(pmulsu_w_h00, uint64_t, int16_t, uint16_t,
+                           int32_t, uint32_t, EXTRACT16, INSERT32, ELEMS_W,
+                           2, 0, 0, PSIMD_MUL_SU32)
+GEN_PSIMD_MUL_ELEM_INDEXED(pmulsu_w_h11, uint64_t, int16_t, uint16_t,
+                           int32_t, uint32_t, EXTRACT16, INSERT32, ELEMS_W,
+                           2, 1, 1, PSIMD_MUL_SU32)
+
+GEN_PSIMD_MUL_ELEM_INDEXED(pmulu_w_h00, uint64_t, uint16_t, uint16_t,
+                           uint32_t, uint32_t, EXTRACT16, INSERT32, ELEMS_W,
+                           2, 0, 0, PSIMD_MUL_U32)
+GEN_PSIMD_MUL_ELEM_INDEXED(pmulu_w_h01, uint64_t, uint16_t, uint16_t,
+                           uint32_t, uint32_t, EXTRACT16, INSERT32, ELEMS_W,
+                           2, 0, 1, PSIMD_MUL_U32)
+GEN_PSIMD_MUL_ELEM_INDEXED(pmulu_w_h11, uint64_t, uint16_t, uint16_t,
+                           uint32_t, uint32_t, EXTRACT16, INSERT32, ELEMS_W,
+                           2, 1, 1, PSIMD_MUL_U32)
+
+GEN_PSIMD_2WAY_SAT_MUL(pm2sadd_h, 0, 1, 0, 1)
+GEN_PSIMD_2WAY_SAT_MUL(pm2sadd_hx, 0, 1, 1, 0)
+
+GEN_PSIMD_MUL_ELEM_SCALAR(mul_h00, uint32_t, int16_t, int16_t,
+                          int32_t, EXTRACT16, 0, 0, PSIMD_MUL_S32)
+GEN_PSIMD_MUL_ELEM_SCALAR(mul_h01, uint32_t, int16_t, int16_t,
+                          int32_t, EXTRACT16, 0, 1, PSIMD_MUL_S32)
+GEN_PSIMD_MUL_ELEM_SCALAR(mul_h11, uint32_t, int16_t, int16_t,
+                          int32_t, EXTRACT16, 1, 1, PSIMD_MUL_S32)
+
+GEN_PSIMD_MUL_ELEM_SCALAR(mulsu_h00, uint32_t, int16_t, uint16_t,
+                          int32_t, EXTRACT16, 0, 0, PSIMD_MUL_SU32)
+GEN_PSIMD_MUL_ELEM_SCALAR(mulsu_h11, uint32_t, int16_t, uint16_t,
+                          int32_t, EXTRACT16, 1, 1, PSIMD_MUL_SU32)
+
+GEN_PSIMD_MUL_ELEM_SCALAR(mulu_h00, uint32_t, uint16_t, uint16_t,
+                          uint32_t, EXTRACT16, 0, 0, PSIMD_MUL_U32)
+GEN_PSIMD_MUL_ELEM_SCALAR(mulu_h01, uint32_t, uint16_t, uint16_t,
+                          uint32_t, EXTRACT16, 0, 1, PSIMD_MUL_U32)
+GEN_PSIMD_MUL_ELEM_SCALAR(mulu_h11, uint32_t, uint16_t, uint16_t,
+                          uint32_t, EXTRACT16, 1, 1, PSIMD_MUL_U32)
+
+GEN_PSIMD_MUL_ELEM_SCALAR(mul_w00, uint64_t, int32_t, int32_t,
+                          int64_t, EXTRACT32, 0, 0, PSIMD_MUL_S64)
+GEN_PSIMD_MUL_ELEM_SCALAR(mul_w01, uint64_t, int32_t, int32_t,
+                          int64_t, EXTRACT32, 0, 1, PSIMD_MUL_S64)
+GEN_PSIMD_MUL_ELEM_SCALAR(mul_w11, uint64_t, int32_t, int32_t,
+                          int64_t, EXTRACT32, 1, 1, PSIMD_MUL_S64)
+
+GEN_PSIMD_MUL_ELEM_SCALAR(mulsu_w00, uint64_t, int32_t, uint32_t,
+                          int64_t, EXTRACT32, 0, 0, PSIMD_MUL_SU64)
+GEN_PSIMD_MUL_ELEM_SCALAR(mulsu_w11, uint64_t, int32_t, uint32_t,
+                          int64_t, EXTRACT32, 1, 1, PSIMD_MUL_SU64)
+
+GEN_PSIMD_MUL_ELEM_SCALAR(mulu_w00, uint64_t, uint32_t, uint32_t,
+                          uint64_t, EXTRACT32, 0, 0, PSIMD_MUL_U64)
+GEN_PSIMD_MUL_ELEM_SCALAR(mulu_w01, uint64_t, uint32_t, uint32_t,
+                          uint64_t, EXTRACT32, 0, 1, PSIMD_MUL_U64)
+GEN_PSIMD_MUL_ELEM_SCALAR(mulu_w11, uint64_t, uint32_t, uint32_t,
+                          uint64_t, EXTRACT32, 1, 1, PSIMD_MUL_U64)
+
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH v2 11/18] target/riscv: Add packed SIMD multiply-accumulate instructions
  2026-07-17 10:06 [PATCH v2 00/18] target/riscv: Add support for RISC-V P Molly Chen
                   ` (9 preceding siblings ...)
  2026-07-17 10:07 ` [PATCH v2 10/18] target/riscv: Add packed SIMD multiplication instructions Molly Chen
@ 2026-07-17 10:07 ` Molly Chen
  2026-07-17 10:07 ` [PATCH v2 12/18] target/riscv: Add packed SIMD Q-format multiplication instructions Molly Chen
                   ` (8 subsequent siblings)
  19 siblings, 0 replies; 34+ messages in thread
From: Molly Chen @ 2026-07-17 10:07 UTC (permalink / raw)
  To: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
	chao.liu.zevorn, Chao Liu
  Cc: xiaoou, qemu-riscv, qemu-devel

Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
---
 target/riscv/helper.h                       |  56 ++++++
 target/riscv/insn32.decode                  |  92 +++++++++
 target/riscv/tcg/insn_trans/trans_rvp.c.inc |  56 ++++++
 target/riscv/tcg/psimd_helper.c             | 195 ++++++++++++++++++++
 4 files changed, 399 insertions(+)

diff --git a/target/riscv/helper.h b/target/riscv/helper.h
index f06f40b1284..48604d91a79 100644
--- a/target/riscv/helper.h
+++ b/target/riscv/helper.h
@@ -1624,3 +1624,59 @@ DEF_HELPER_3(mulsu_w11, i64, env, i64, i64)
 DEF_HELPER_3(mulu_w00, i64, env, i64, i64)
 DEF_HELPER_3(mulu_w01, i64, env, i64, i64)
 DEF_HELPER_3(mulu_w11, i64, env, i64, i64)
+
+/* Packed SIMD - Multiply-Accumulate Operations */
+DEF_HELPER_4(pmhacc_h, tl, env, tl, tl, tl)
+DEF_HELPER_4(pmhaccsu_h, tl, env, tl, tl, tl)
+DEF_HELPER_4(pmhaccu_h, tl, env, tl, tl, tl)
+DEF_HELPER_4(pmhracc_h, tl, env, tl, tl, tl)
+DEF_HELPER_4(pmhraccsu_h, tl, env, tl, tl, tl)
+DEF_HELPER_4(pmhraccu_h, tl, env, tl, tl, tl)
+DEF_HELPER_4(pmhacc_w, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmhracc_w, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmhaccsu_w, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmhraccsu_w, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmhaccu_w, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmhraccu_w, i64, env, i64, i64, i64)
+DEF_HELPER_4(mhacc, i32, env, i32, i32, i32)
+DEF_HELPER_4(mhracc, i32, env, i32, i32, i32)
+DEF_HELPER_4(mhaccsu, i32, env, i32, i32, i32)
+DEF_HELPER_4(mhraccsu, i32, env, i32, i32, i32)
+DEF_HELPER_4(mhaccu, i32, env, i32, i32, i32)
+DEF_HELPER_4(mhraccu, i32, env, i32, i32, i32)
+DEF_HELPER_4(pmhacc_h_b0, tl, env, tl, tl, tl)
+DEF_HELPER_4(pmhacc_h_b1, tl, env, tl, tl, tl)
+DEF_HELPER_4(pmhaccsu_h_b0, tl, env, tl, tl, tl)
+DEF_HELPER_4(pmhaccsu_h_b1, tl, env, tl, tl, tl)
+DEF_HELPER_4(mhacc_h0, i32, env, i32, i32, i32)
+DEF_HELPER_4(mhacc_h1, i32, env, i32, i32, i32)
+DEF_HELPER_4(mhaccsu_h0, i32, env, i32, i32, i32)
+DEF_HELPER_4(mhaccsu_h1, i32, env, i32, i32, i32)
+DEF_HELPER_4(pmhacc_w_h0, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmhacc_w_h1, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmhaccsu_w_h0, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmhaccsu_w_h1, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmacc_w_h00, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmacc_w_h01, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmacc_w_h11, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmaccsu_w_h00, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmaccsu_w_h11, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmaccu_w_h00, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmaccu_w_h01, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmaccu_w_h11, i64, env, i64, i64, i64)
+DEF_HELPER_4(macc_h00, i32, env, i32, i32, i32)
+DEF_HELPER_4(macc_h01, i32, env, i32, i32, i32)
+DEF_HELPER_4(macc_h11, i32, env, i32, i32, i32)
+DEF_HELPER_4(maccsu_h00, i32, env, i32, i32, i32)
+DEF_HELPER_4(maccsu_h11, i32, env, i32, i32, i32)
+DEF_HELPER_4(maccu_h00, i32, env, i32, i32, i32)
+DEF_HELPER_4(maccu_h01, i32, env, i32, i32, i32)
+DEF_HELPER_4(maccu_h11, i32, env, i32, i32, i32)
+DEF_HELPER_4(macc_w00, i64, env, i64, i64, i64)
+DEF_HELPER_4(macc_w01, i64, env, i64, i64, i64)
+DEF_HELPER_4(macc_w11, i64, env, i64, i64, i64)
+DEF_HELPER_4(maccsu_w00, i64, env, i64, i64, i64)
+DEF_HELPER_4(maccsu_w11, i64, env, i64, i64, i64)
+DEF_HELPER_4(maccu_w00, i64, env, i64, i64, i64)
+DEF_HELPER_4(maccu_w01, i64, env, i64, i64, i64)
+DEF_HELPER_4(maccu_w11, i64, env, i64, i64, i64)
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index cc0cc35fe24..a9b407e43e2 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -1430,3 +1430,95 @@ mulsu_w11       11110 11 ..... ..... 011 ..... 0111011 @r
 mulu_w00        10100 11 ..... ..... 011 ..... 0111011 @r
 mulu_w01        10110 11 ..... ..... 001 ..... 0111011 @r
 mulu_w11        10110 11 ..... ..... 011 ..... 0111011 @r
+
+# Packed SIMD - Multiply-Accumulate Operations
+pmhacc_h    10001 00 ..... ..... 111 ..... 0111011 @r
+pmhaccsu_h  11001 00 ..... ..... 111 ..... 0111011 @r
+pmhaccu_h   10011 00 ..... ..... 111 ..... 0111011 @r
+pmhracc_h   10001 10 ..... ..... 111 ..... 0111011 @r
+pmhraccsu_h 11001 10 ..... ..... 111 ..... 0111011 @r
+pmhraccu_h  10011 10 ..... ..... 111 ..... 0111011 @r
+{
+  mhacc     10001 01 ..... ..... 111 ..... 0111011 @r
+  pmhacc_w  10001 01 ..... ..... 111 ..... 0111011 @r
+}
+{
+  mhracc    10001 11 ..... ..... 111 ..... 0111011 @r
+  pmhracc_w 10001 11 ..... ..... 111 ..... 0111011 @r
+}
+{
+  mhaccsu   11001 01 ..... ..... 111 ..... 0111011 @r
+  pmhaccsu_w    11001 01 ..... ..... 111 ..... 0111011 @r
+}
+{
+  mhraccsu  11001 11 ..... ..... 111 ..... 0111011 @r
+  pmhraccsu_w   11001 11 ..... ..... 111 ..... 0111011 @r
+}
+{
+  mhaccu    10011 01 ..... ..... 111 ..... 0111011 @r
+  pmhaccu_w 10011 01 ..... ..... 111 ..... 0111011 @r
+}
+{
+  mhraccu   10011 11 ..... ..... 111 ..... 0111011 @r
+  pmhraccu_w    10011 11 ..... ..... 111 ..... 0111011 @r
+}
+pmhacc_h_b0     10101 00 ..... ..... 111 ..... 0111011 @r
+pmhacc_h_b1     10111 00 ..... ..... 111 ..... 0111011 @r
+pmhaccsu_h_b0   10101 10 ..... ..... 111 ..... 0111011 @r
+pmhaccsu_h_b1   10111 10 ..... ..... 111 ..... 0111011 @r
+{
+  mhacc_h0      10101 01 ..... ..... 111 ..... 0111011 @r
+  pmhacc_w_h0   10101 01 ..... ..... 111 ..... 0111011 @r
+}
+{
+  mhacc_h1      10111 01 ..... ..... 111 ..... 0111011 @r
+  pmhacc_w_h1   10111 01 ..... ..... 111 ..... 0111011 @r
+}
+{
+  mhaccsu_h0    10101 11 ..... ..... 111 ..... 0111011 @r
+  pmhaccsu_w_h0 10101 11 ..... ..... 111 ..... 0111011 @r
+}
+{
+  mhaccsu_h1    10111 11 ..... ..... 111 ..... 0111011 @r
+  pmhaccsu_w_h1 10111 11 ..... ..... 111 ..... 0111011 @r
+}
+{
+  macc_h00      10001 01 ..... ..... 011 ..... 0111011 @r
+  pmacc_w_h00   10001 01 ..... ..... 011 ..... 0111011 @r
+}
+{
+  macc_h01      10011 01 ..... ..... 001 ..... 0111011 @r
+  pmacc_w_h01   10011 01 ..... ..... 001 ..... 0111011 @r
+}
+{
+  macc_h11      10011 01 ..... ..... 011 ..... 0111011 @r
+  pmacc_w_h11   10011 01 ..... ..... 011 ..... 0111011 @r
+}
+{
+  maccsu_h00    11101 01 ..... ..... 011 ..... 0111011 @r
+  pmaccsu_w_h00 11101 01 ..... ..... 011 ..... 0111011 @r
+}
+{
+  maccsu_h11    11111 01 ..... ..... 011 ..... 0111011 @r
+  pmaccsu_w_h11 11111 01 ..... ..... 011 ..... 0111011 @r
+}
+{
+  maccu_h00     10101 01 ..... ..... 011 ..... 0111011 @r
+  pmaccu_w_h00  10101 01 ..... ..... 011 ..... 0111011 @r
+}
+{
+  maccu_h01     10111 01 ..... ..... 001 ..... 0111011 @r
+  pmaccu_w_h01  10111 01 ..... ..... 001 ..... 0111011 @r
+}
+{
+  maccu_h11     10111 01 ..... ..... 011 ..... 0111011 @r
+  pmaccu_w_h11  10111 01 ..... ..... 011 ..... 0111011 @r
+}
+macc_w00        10001 11 ..... ..... 011 ..... 0111011 @r
+macc_w01        10011 11 ..... ..... 001 ..... 0111011 @r
+macc_w11        10011 11 ..... ..... 011 ..... 0111011 @r
+maccsu_w00      11101 11 ..... ..... 011 ..... 0111011 @r
+maccsu_w11      11111 11 ..... ..... 011 ..... 0111011 @r
+maccu_w00       10101 11 ..... ..... 011 ..... 0111011 @r
+maccu_w01       10111 11 ..... ..... 001 ..... 0111011 @r
+maccu_w11       10111 11 ..... ..... 011 ..... 0111011 @r
diff --git a/target/riscv/tcg/insn_trans/trans_rvp.c.inc b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
index 7edea099d01..5a30c49016f 100644
--- a/target/riscv/tcg/insn_trans/trans_rvp.c.inc
+++ b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
@@ -770,3 +770,59 @@ GEN_SIMD_TRANS_64(mulu_w00)
 GEN_SIMD_TRANS_64(mulu_w01)
 GEN_SIMD_TRANS_64(mulu_w11)
 
+/* Packed SIMD - Multiply-Accumulate Operations */
+GEN_SIMD_TRANS_ACC(pmhacc_h)
+GEN_SIMD_TRANS_ACC(pmhaccsu_h)
+GEN_SIMD_TRANS_ACC(pmhaccu_h)
+GEN_SIMD_TRANS_ACC(pmhracc_h)
+GEN_SIMD_TRANS_ACC(pmhraccsu_h)
+GEN_SIMD_TRANS_ACC(pmhraccu_h)
+GEN_SIMD_TRANS_ACC_64(pmhacc_w)
+GEN_SIMD_TRANS_ACC_64(pmhracc_w)
+GEN_SIMD_TRANS_ACC_64(pmhaccsu_w)
+GEN_SIMD_TRANS_ACC_64(pmhraccsu_w)
+GEN_SIMD_TRANS_ACC_64(pmhaccu_w)
+GEN_SIMD_TRANS_ACC_64(pmhraccu_w)
+GEN_SIMD_TRANS_ACC_32(mhacc)
+GEN_SIMD_TRANS_ACC_32(mhracc)
+GEN_SIMD_TRANS_ACC_32(mhaccsu)
+GEN_SIMD_TRANS_ACC_32(mhraccsu)
+GEN_SIMD_TRANS_ACC_32(mhaccu)
+GEN_SIMD_TRANS_ACC_32(mhraccu)
+GEN_SIMD_TRANS_ACC(pmhacc_h_b0)
+GEN_SIMD_TRANS_ACC(pmhacc_h_b1)
+GEN_SIMD_TRANS_ACC(pmhaccsu_h_b0)
+GEN_SIMD_TRANS_ACC(pmhaccsu_h_b1)
+GEN_SIMD_TRANS_ACC_32(mhacc_h0)
+GEN_SIMD_TRANS_ACC_32(mhacc_h1)
+GEN_SIMD_TRANS_ACC_32(mhaccsu_h0)
+GEN_SIMD_TRANS_ACC_32(mhaccsu_h1)
+GEN_SIMD_TRANS_ACC_64(pmhacc_w_h0)
+GEN_SIMD_TRANS_ACC_64(pmhacc_w_h1)
+GEN_SIMD_TRANS_ACC_64(pmhaccsu_w_h0)
+GEN_SIMD_TRANS_ACC_64(pmhaccsu_w_h1)
+GEN_SIMD_TRANS_ACC_64(pmacc_w_h00)
+GEN_SIMD_TRANS_ACC_64(pmacc_w_h01)
+GEN_SIMD_TRANS_ACC_64(pmacc_w_h11)
+GEN_SIMD_TRANS_ACC_64(pmaccsu_w_h00)
+GEN_SIMD_TRANS_ACC_64(pmaccsu_w_h11)
+GEN_SIMD_TRANS_ACC_64(pmaccu_w_h00)
+GEN_SIMD_TRANS_ACC_64(pmaccu_w_h01)
+GEN_SIMD_TRANS_ACC_64(pmaccu_w_h11)
+GEN_SIMD_TRANS_ACC_32(macc_h00)
+GEN_SIMD_TRANS_ACC_32(macc_h01)
+GEN_SIMD_TRANS_ACC_32(macc_h11)
+GEN_SIMD_TRANS_ACC_32(maccsu_h00)
+GEN_SIMD_TRANS_ACC_32(maccsu_h11)
+GEN_SIMD_TRANS_ACC_32(maccu_h00)
+GEN_SIMD_TRANS_ACC_32(maccu_h01)
+GEN_SIMD_TRANS_ACC_32(maccu_h11)
+GEN_SIMD_TRANS_ACC_64(macc_w00)
+GEN_SIMD_TRANS_ACC_64(macc_w01)
+GEN_SIMD_TRANS_ACC_64(macc_w11)
+GEN_SIMD_TRANS_ACC_64(maccsu_w00)
+GEN_SIMD_TRANS_ACC_64(maccsu_w11)
+GEN_SIMD_TRANS_ACC_64(maccu_w00)
+GEN_SIMD_TRANS_ACC_64(maccu_w01)
+GEN_SIMD_TRANS_ACC_64(maccu_w11)
+
diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
index 5be8fe257f8..91a3aac3ebb 100644
--- a/target/riscv/tcg/psimd_helper.c
+++ b/target/riscv/tcg/psimd_helper.c
@@ -2443,3 +2443,198 @@ GEN_PSIMD_MUL_ELEM_SCALAR(mulu_w01, uint64_t, uint32_t, uint32_t,
 GEN_PSIMD_MUL_ELEM_SCALAR(mulu_w11, uint64_t, uint32_t, uint32_t,
                           uint64_t, EXTRACT32, 1, 1, PSIMD_MUL_U64)
 
+/* Multiply-Accumulate Operations */
+
+GEN_PSIMD_MUL_HIGH_ACC(pmhacc_h, target_ulong, int16_t, int16_t, int16_t,
+                       int32_t, int16_t, uint16_t, EXTRACT16, INSERT16,
+                       ELEMS_H, 16, 0, PSIMD_MUL_S32)
+GEN_PSIMD_MUL_HIGH_ACC(pmhaccsu_h, target_ulong, int16_t, uint16_t, int16_t,
+                       int32_t, int16_t, uint16_t, EXTRACT16, INSERT16,
+                       ELEMS_H, 16, 0, PSIMD_MUL_SU32)
+GEN_PSIMD_MUL_HIGH_ACC(pmhaccu_h, target_ulong, uint16_t, uint16_t, uint16_t,
+                       uint32_t, uint16_t, uint16_t, EXTRACT16, INSERT16,
+                       ELEMS_H, 16, 0, PSIMD_MUL_U32)
+GEN_PSIMD_MUL_HIGH_ACC(pmhracc_h, target_ulong, int16_t, int16_t, int16_t,
+                       int32_t, int16_t, uint16_t, EXTRACT16, INSERT16,
+                       ELEMS_H, 16, 1 << 15, PSIMD_MUL_S32)
+GEN_PSIMD_MUL_HIGH_ACC(pmhraccsu_h, target_ulong, int16_t, uint16_t, int16_t,
+                       int32_t, int16_t, uint16_t, EXTRACT16, INSERT16,
+                       ELEMS_H, 16, 1 << 15, PSIMD_MUL_SU32)
+GEN_PSIMD_MUL_HIGH_ACC(pmhraccu_h, target_ulong, uint16_t, uint16_t,
+                       uint16_t, uint32_t, uint16_t, uint16_t,
+                       EXTRACT16, INSERT16, ELEMS_H, 16, 1 << 15,
+                       PSIMD_MUL_U32)
+
+GEN_PSIMD_MUL_HIGH_ACC(pmhacc_w, uint64_t, int32_t, int32_t, int32_t,
+                       int64_t, int32_t, uint32_t, EXTRACT32, INSERT32,
+                       ELEMS_W, 32, 0, PSIMD_MUL_S64)
+GEN_PSIMD_MUL_HIGH_ACC(pmhracc_w, uint64_t, int32_t, int32_t, int32_t,
+                       int64_t, int32_t, uint32_t, EXTRACT32, INSERT32,
+                       ELEMS_W, 32, 1LL << 31, PSIMD_MUL_S64)
+GEN_PSIMD_MUL_HIGH_ACC(pmhaccsu_w, uint64_t, int32_t, uint32_t, int32_t,
+                       int64_t, int32_t, uint32_t, EXTRACT32, INSERT32,
+                       ELEMS_W, 32, 0, PSIMD_MUL_SU64)
+GEN_PSIMD_MUL_HIGH_ACC(pmhraccsu_w, uint64_t, int32_t, uint32_t, int32_t,
+                       int64_t, int32_t, uint32_t, EXTRACT32, INSERT32,
+                       ELEMS_W, 32, 1LL << 31, PSIMD_MUL_SU64)
+GEN_PSIMD_MUL_HIGH_ACC(pmhaccu_w, uint64_t, uint32_t, uint32_t, uint32_t,
+                       uint64_t, uint32_t, uint32_t, EXTRACT32, INSERT32,
+                       ELEMS_W, 32, 0, PSIMD_MUL_U64)
+GEN_PSIMD_MUL_HIGH_ACC(pmhraccu_w, uint64_t, uint32_t, uint32_t, uint32_t,
+                       uint64_t, uint32_t, uint32_t, EXTRACT32, INSERT32,
+                       ELEMS_W, 32, 1LL << 31, PSIMD_MUL_U64)
+
+GEN_PSIMD_MUL_HIGH_ACC(mhacc, uint32_t, int32_t, int32_t, int32_t,
+                       int64_t, int32_t, uint32_t, EXTRACT32, INSERT32,
+                       ELEMS_W, 32, 0, PSIMD_MUL_S64)
+GEN_PSIMD_MUL_HIGH_ACC(mhracc, uint32_t, int32_t, int32_t, int32_t,
+                       int64_t, int32_t, uint32_t, EXTRACT32, INSERT32,
+                       ELEMS_W, 32, 1LL << 31, PSIMD_MUL_S64)
+GEN_PSIMD_MUL_HIGH_ACC(mhaccsu, uint32_t, int32_t, uint32_t, int32_t,
+                       int64_t, int32_t, uint32_t, EXTRACT32, INSERT32,
+                       ELEMS_W, 32, 0, PSIMD_MUL_SU64)
+GEN_PSIMD_MUL_HIGH_ACC(mhraccsu, uint32_t, int32_t, uint32_t, int32_t,
+                       int64_t, int32_t, uint32_t, EXTRACT32, INSERT32,
+                       ELEMS_W, 32, 1LL << 31, PSIMD_MUL_SU64)
+GEN_PSIMD_MUL_HIGH_ACC(mhaccu, uint32_t, uint32_t, uint32_t, uint32_t,
+                       uint64_t, uint32_t, uint32_t, EXTRACT32, INSERT32,
+                       ELEMS_W, 32, 0, PSIMD_MUL_U64)
+GEN_PSIMD_MUL_HIGH_ACC(mhraccu, uint32_t, uint32_t, uint32_t, uint32_t,
+                       uint64_t, uint32_t, uint32_t, EXTRACT32, INSERT32,
+                       ELEMS_W, 32, 1LL << 31, PSIMD_MUL_U64)
+
+GEN_PSIMD_MUL_HIGH_ACC_SEL(pmhacc_h_b0, target_ulong, int16_t, int8_t,
+                           int16_t, int32_t, int16_t, uint16_t, EXTRACT16,
+                           EXTRACT8, INSERT16, ELEMS_H, 2, 0, 8,
+                           PSIMD_MUL_S32)
+GEN_PSIMD_MUL_HIGH_ACC_SEL(pmhacc_h_b1, target_ulong, int16_t, int8_t,
+                           int16_t, int32_t, int16_t, uint16_t, EXTRACT16,
+                           EXTRACT8, INSERT16, ELEMS_H, 2, 1, 8,
+                           PSIMD_MUL_S32)
+GEN_PSIMD_MUL_HIGH_ACC_SEL(pmhaccsu_h_b0, target_ulong, int16_t, uint8_t,
+                           int16_t, int32_t, int16_t, uint16_t, EXTRACT16,
+                           EXTRACT8, INSERT16, ELEMS_H, 2, 0, 8,
+                           PSIMD_MUL_SU32)
+GEN_PSIMD_MUL_HIGH_ACC_SEL(pmhaccsu_h_b1, target_ulong, int16_t, uint8_t,
+                           int16_t, int32_t, int16_t, uint16_t, EXTRACT16,
+                           EXTRACT8, INSERT16, ELEMS_H, 2, 1, 8,
+                           PSIMD_MUL_SU32)
+
+GEN_PSIMD_MUL_HIGH_ACC_SEL(mhacc_h0, uint32_t, int32_t, int16_t, int32_t,
+                           int64_t, int32_t, uint32_t, EXTRACT32,
+                           EXTRACT16, INSERT32, ELEMS_W, 0, 0, 16,
+                           PSIMD_MUL_S64)
+GEN_PSIMD_MUL_HIGH_ACC_SEL(mhacc_h1, uint32_t, int32_t, int16_t, int32_t,
+                           int64_t, int32_t, uint32_t, EXTRACT32,
+                           EXTRACT16, INSERT32, ELEMS_W, 0, 1, 16,
+                           PSIMD_MUL_S64)
+GEN_PSIMD_MUL_HIGH_ACC_SEL(mhaccsu_h0, uint32_t, int32_t, uint16_t, int32_t,
+                           int64_t, int32_t, uint32_t, EXTRACT32,
+                           EXTRACT16, INSERT32, ELEMS_W, 0, 0, 16,
+                           PSIMD_MUL_SU64)
+GEN_PSIMD_MUL_HIGH_ACC_SEL(mhaccsu_h1, uint32_t, int32_t, uint16_t, int32_t,
+                           int64_t, int32_t, uint32_t, EXTRACT32,
+                           EXTRACT16, INSERT32, ELEMS_W, 0, 1, 16,
+                           PSIMD_MUL_SU64)
+
+GEN_PSIMD_MUL_HIGH_ACC_SEL(pmhacc_w_h0, uint64_t, int32_t, int16_t,
+                           int32_t, int64_t, int32_t, uint32_t, EXTRACT32,
+                           EXTRACT16, INSERT32, ELEMS_W, 2, 0, 16,
+                           PSIMD_MUL_S64)
+GEN_PSIMD_MUL_HIGH_ACC_SEL(pmhacc_w_h1, uint64_t, int32_t, int16_t,
+                           int32_t, int64_t, int32_t, uint32_t, EXTRACT32,
+                           EXTRACT16, INSERT32, ELEMS_W, 2, 1, 16,
+                           PSIMD_MUL_S64)
+GEN_PSIMD_MUL_HIGH_ACC_SEL(pmhaccsu_w_h0, uint64_t, int32_t, uint16_t,
+                           int32_t, int64_t, int32_t, uint32_t, EXTRACT32,
+                           EXTRACT16, INSERT32, ELEMS_W, 2, 0, 16,
+                           PSIMD_MUL_SU64)
+GEN_PSIMD_MUL_HIGH_ACC_SEL(pmhaccsu_w_h1, uint64_t, int32_t, uint16_t,
+                           int32_t, int64_t, int32_t, uint32_t, EXTRACT32,
+                           EXTRACT16, INSERT32, ELEMS_W, 2, 1, 16,
+                           PSIMD_MUL_SU64)
+
+GEN_PSIMD_MUL_ACC_INDEXED(pmacc_w_h00, uint64_t, int16_t, int16_t,
+                          int32_t, int32_t, uint32_t, EXTRACT16, EXTRACT32,
+                          INSERT32, ELEMS_W, 2, 0, 0, PSIMD_MUL_S32)
+GEN_PSIMD_MUL_ACC_INDEXED(pmacc_w_h01, uint64_t, int16_t, int16_t,
+                          int32_t, int32_t, uint32_t, EXTRACT16, EXTRACT32,
+                          INSERT32, ELEMS_W, 2, 0, 1, PSIMD_MUL_S32)
+GEN_PSIMD_MUL_ACC_INDEXED(pmacc_w_h11, uint64_t, int16_t, int16_t,
+                          int32_t, int32_t, uint32_t, EXTRACT16, EXTRACT32,
+                          INSERT32, ELEMS_W, 2, 1, 1, PSIMD_MUL_S32)
+GEN_PSIMD_MUL_ACC_INDEXED(pmaccsu_w_h00, uint64_t, int16_t, uint16_t,
+                          int32_t, int32_t, uint32_t, EXTRACT16, EXTRACT32,
+                          INSERT32, ELEMS_W, 2, 0, 0, PSIMD_MUL_SU32)
+GEN_PSIMD_MUL_ACC_INDEXED(pmaccsu_w_h11, uint64_t, int16_t, uint16_t,
+                          int32_t, int32_t, uint32_t, EXTRACT16, EXTRACT32,
+                          INSERT32, ELEMS_W, 2, 1, 1, PSIMD_MUL_SU32)
+GEN_PSIMD_MUL_ACC_INDEXED(pmaccu_w_h00, uint64_t, uint16_t, uint16_t,
+                          uint32_t, uint32_t, uint32_t, EXTRACT16,
+                          EXTRACT32, INSERT32, ELEMS_W, 2, 0, 0,
+                          PSIMD_MUL_U32)
+GEN_PSIMD_MUL_ACC_INDEXED(pmaccu_w_h01, uint64_t, uint16_t, uint16_t,
+                          uint32_t, uint32_t, uint32_t, EXTRACT16,
+                          EXTRACT32, INSERT32, ELEMS_W, 2, 0, 1,
+                          PSIMD_MUL_U32)
+GEN_PSIMD_MUL_ACC_INDEXED(pmaccu_w_h11, uint64_t, uint16_t, uint16_t,
+                          uint32_t, uint32_t, uint32_t, EXTRACT16,
+                          EXTRACT32, INSERT32, ELEMS_W, 2, 1, 1,
+                          PSIMD_MUL_U32)
+
+GEN_PSIMD_MUL_ACC_INDEXED(macc_h00, uint32_t, int16_t, int16_t,
+                          int32_t, int32_t, uint32_t, EXTRACT16, EXTRACT32,
+                          INSERT32, ELEMS_W, 0, 0, 0, PSIMD_MUL_S32)
+GEN_PSIMD_MUL_ACC_INDEXED(macc_h01, uint32_t, int16_t, int16_t,
+                          int32_t, int32_t, uint32_t, EXTRACT16, EXTRACT32,
+                          INSERT32, ELEMS_W, 0, 0, 1, PSIMD_MUL_S32)
+GEN_PSIMD_MUL_ACC_INDEXED(macc_h11, uint32_t, int16_t, int16_t,
+                          int32_t, int32_t, uint32_t, EXTRACT16, EXTRACT32,
+                          INSERT32, ELEMS_W, 0, 1, 1, PSIMD_MUL_S32)
+GEN_PSIMD_MUL_ACC_INDEXED(maccsu_h00, uint32_t, int16_t, uint16_t,
+                          int32_t, int32_t, uint32_t, EXTRACT16, EXTRACT32,
+                          INSERT32, ELEMS_W, 0, 0, 0, PSIMD_MUL_SU32)
+GEN_PSIMD_MUL_ACC_INDEXED(maccsu_h11, uint32_t, int16_t, uint16_t,
+                          int32_t, int32_t, uint32_t, EXTRACT16, EXTRACT32,
+                          INSERT32, ELEMS_W, 0, 1, 1, PSIMD_MUL_SU32)
+GEN_PSIMD_MUL_ACC_INDEXED(maccu_h00, uint32_t, uint16_t, uint16_t,
+                          uint32_t, uint32_t, uint32_t, EXTRACT16,
+                          EXTRACT32, INSERT32, ELEMS_W, 0, 0, 0,
+                          PSIMD_MUL_U32)
+GEN_PSIMD_MUL_ACC_INDEXED(maccu_h01, uint32_t, uint16_t, uint16_t,
+                          uint32_t, uint32_t, uint32_t, EXTRACT16,
+                          EXTRACT32, INSERT32, ELEMS_W, 0, 0, 1,
+                          PSIMD_MUL_U32)
+GEN_PSIMD_MUL_ACC_INDEXED(maccu_h11, uint32_t, uint16_t, uint16_t,
+                          uint32_t, uint32_t, uint32_t, EXTRACT16,
+                          EXTRACT32, INSERT32, ELEMS_W, 0, 1, 1,
+                          PSIMD_MUL_U32)
+
+GEN_PSIMD_MUL_ACC_INDEXED(macc_w00, uint64_t, int32_t, int32_t,
+                          int64_t, int64_t, uint64_t, EXTRACT32, EXTRACT64,
+                          INSERT64, ELEMS_D, 0, 0, 0, PSIMD_MUL_S64)
+GEN_PSIMD_MUL_ACC_INDEXED(macc_w01, uint64_t, int32_t, int32_t,
+                          int64_t, int64_t, uint64_t, EXTRACT32, EXTRACT64,
+                          INSERT64, ELEMS_D, 0, 0, 1, PSIMD_MUL_S64)
+GEN_PSIMD_MUL_ACC_INDEXED(macc_w11, uint64_t, int32_t, int32_t,
+                          int64_t, int64_t, uint64_t, EXTRACT32, EXTRACT64,
+                          INSERT64, ELEMS_D, 0, 1, 1, PSIMD_MUL_S64)
+GEN_PSIMD_MUL_ACC_INDEXED(maccsu_w00, uint64_t, int32_t, uint32_t,
+                          int64_t, int64_t, uint64_t, EXTRACT32, EXTRACT64,
+                          INSERT64, ELEMS_D, 0, 0, 0, PSIMD_MUL_SU64)
+GEN_PSIMD_MUL_ACC_INDEXED(maccsu_w11, uint64_t, int32_t, uint32_t,
+                          int64_t, int64_t, uint64_t, EXTRACT32, EXTRACT64,
+                          INSERT64, ELEMS_D, 0, 1, 1, PSIMD_MUL_SU64)
+GEN_PSIMD_MUL_ACC_INDEXED(maccu_w00, uint64_t, uint32_t, uint32_t,
+                          uint64_t, uint64_t, uint64_t, EXTRACT32,
+                          EXTRACT64, INSERT64, ELEMS_D, 0, 0, 0,
+                          PSIMD_MUL_U64)
+GEN_PSIMD_MUL_ACC_INDEXED(maccu_w01, uint64_t, uint32_t, uint32_t,
+                          uint64_t, uint64_t, uint64_t, EXTRACT32,
+                          EXTRACT64, INSERT64, ELEMS_D, 0, 0, 1,
+                          PSIMD_MUL_U64)
+GEN_PSIMD_MUL_ACC_INDEXED(maccu_w11, uint64_t, uint32_t, uint32_t,
+                          uint64_t, uint64_t, uint64_t, EXTRACT32,
+                          EXTRACT64, INSERT64, ELEMS_D, 0, 1, 1,
+                          PSIMD_MUL_U64)
+
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH v2 12/18] target/riscv: Add packed SIMD Q-format multiplication instructions
  2026-07-17 10:06 [PATCH v2 00/18] target/riscv: Add support for RISC-V P Molly Chen
                   ` (10 preceding siblings ...)
  2026-07-17 10:07 ` [PATCH v2 11/18] target/riscv: Add packed SIMD multiply-accumulate instructions Molly Chen
@ 2026-07-17 10:07 ` Molly Chen
  2026-07-17 10:07 ` [PATCH v2 13/18] target/riscv: Add packed SIMD Q-format MAC instructions Molly Chen
                   ` (7 subsequent siblings)
  19 siblings, 0 replies; 34+ messages in thread
From: Molly Chen @ 2026-07-17 10:07 UTC (permalink / raw)
  To: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
	chao.liu.zevorn, Chao Liu
  Cc: xiaoou, qemu-riscv, qemu-devel

Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
---
 target/riscv/helper.h                       |  8 ++++++++
 target/riscv/insn32.decode                  | 12 ++++++++++++
 target/riscv/tcg/insn_trans/trans_rvp.c.inc |  8 ++++++++
 target/riscv/tcg/psimd_helper.c             | 17 +++++++++++++++++
 4 files changed, 45 insertions(+)

diff --git a/target/riscv/helper.h b/target/riscv/helper.h
index 48604d91a79..638c7b0629d 100644
--- a/target/riscv/helper.h
+++ b/target/riscv/helper.h
@@ -1680,3 +1680,11 @@ DEF_HELPER_4(maccsu_w11, i64, env, i64, i64, i64)
 DEF_HELPER_4(maccu_w00, i64, env, i64, i64, i64)
 DEF_HELPER_4(maccu_w01, i64, env, i64, i64, i64)
 DEF_HELPER_4(maccu_w11, i64, env, i64, i64, i64)
+
+/* Packed SIMD - Q-Format Multiplication Operations */
+DEF_HELPER_3(pmulq_h, tl, env, tl, tl)
+DEF_HELPER_3(pmulqr_h, tl, env, tl, tl)
+DEF_HELPER_3(pmulq_w, i64, env, i64, i64)
+DEF_HELPER_3(pmulqr_w, i64, env, i64, i64)
+DEF_HELPER_3(mulq, i32, env, i32, i32)
+DEF_HELPER_3(mulqr, i32, env, i32, i32)
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index a9b407e43e2..9c50a4dbf52 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -1522,3 +1522,15 @@ maccsu_w11      11111 11 ..... ..... 011 ..... 0111011 @r
 maccu_w00       10101 11 ..... ..... 011 ..... 0111011 @r
 maccu_w01       10111 11 ..... ..... 001 ..... 0111011 @r
 maccu_w11       10111 11 ..... ..... 011 ..... 0111011 @r
+
+# Packed SIMD - Q-Format Multiplication Operations
+pmulq_h     11010 00 ..... ..... 111 ..... 0111011 @r
+pmulqr_h    11010 10 ..... ..... 111 ..... 0111011 @r
+{
+  mulq      11010 01 ..... ..... 111 ..... 0111011 @r
+  pmulq_w   11010 01 ..... ..... 111 ..... 0111011 @r
+}
+{
+  mulqr     11010 11 ..... ..... 111 ..... 0111011 @r
+  pmulqr_w  11010 11 ..... ..... 111 ..... 0111011 @r
+}
diff --git a/target/riscv/tcg/insn_trans/trans_rvp.c.inc b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
index 5a30c49016f..3535f71de88 100644
--- a/target/riscv/tcg/insn_trans/trans_rvp.c.inc
+++ b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
@@ -826,3 +826,11 @@ GEN_SIMD_TRANS_ACC_64(maccu_w00)
 GEN_SIMD_TRANS_ACC_64(maccu_w01)
 GEN_SIMD_TRANS_ACC_64(maccu_w11)
 
+/* Packed SIMD - Q-Format Multiplication Operations */
+GEN_SIMD_TRANS_VXSAT(pmulq_h)
+GEN_SIMD_TRANS_VXSAT(pmulqr_h)
+GEN_SIMD_TRANS_64_VXSAT(pmulq_w)
+GEN_SIMD_TRANS_64_VXSAT(pmulqr_w)
+GEN_SIMD_TRANS_32_VXSAT(mulq)
+GEN_SIMD_TRANS_32_VXSAT(mulqr)
+
diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
index 91a3aac3ebb..11ca17576be 100644
--- a/target/riscv/tcg/psimd_helper.c
+++ b/target/riscv/tcg/psimd_helper.c
@@ -2638,3 +2638,20 @@ GEN_PSIMD_MUL_ACC_INDEXED(maccu_w11, uint64_t, uint32_t, uint32_t,
                           EXTRACT64, INSERT64, ELEMS_D, 0, 1, 1,
                           PSIMD_MUL_U64)
 
+/* Q-Format Multiplication Operations */
+
+GEN_PSIMD_QMUL(pmulq_h, target_ulong, int16_t, int32_t, uint16_t,
+               EXTRACT16, INSERT16, ELEMS_H, 15, 0, INT16_MIN, INT16_MAX)
+GEN_PSIMD_QMUL(pmulqr_h, target_ulong, int16_t, int32_t, uint16_t,
+               EXTRACT16, INSERT16, ELEMS_H, 15, 1 << 14, INT16_MIN,
+               INT16_MAX)
+GEN_PSIMD_QMUL(pmulq_w, uint64_t, int32_t, int64_t, uint32_t,
+               EXTRACT32, INSERT32, ELEMS_W, 31, 0, INT32_MIN, INT32_MAX)
+GEN_PSIMD_QMUL(pmulqr_w, uint64_t, int32_t, int64_t, uint32_t,
+               EXTRACT32, INSERT32, ELEMS_W, 31, 1LL << 30, INT32_MIN,
+               INT32_MAX)
+GEN_PSIMD_QMUL(mulq, uint32_t, int32_t, int64_t, uint32_t,
+               EXTRACT32, INSERT32, ELEMS_W, 31, 0, INT32_MIN, INT32_MAX)
+GEN_PSIMD_QMUL(mulqr, uint32_t, int32_t, int64_t, uint32_t,
+               EXTRACT32, INSERT32, ELEMS_W, 31, 1LL << 30, INT32_MIN,
+               INT32_MAX)
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH v2 13/18] target/riscv: Add packed SIMD Q-format MAC instructions
  2026-07-17 10:06 [PATCH v2 00/18] target/riscv: Add support for RISC-V P Molly Chen
                   ` (11 preceding siblings ...)
  2026-07-17 10:07 ` [PATCH v2 12/18] target/riscv: Add packed SIMD Q-format multiplication instructions Molly Chen
@ 2026-07-17 10:07 ` Molly Chen
  2026-07-17 10:07 ` [PATCH v2 14/18] target/riscv: Add packed SIMD two-way " Molly Chen
                   ` (6 subsequent siblings)
  19 siblings, 0 replies; 34+ messages in thread
From: Molly Chen @ 2026-07-17 10:07 UTC (permalink / raw)
  To: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
	chao.liu.zevorn, Chao Liu
  Cc: xiaoou, qemu-riscv, qemu-devel

Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
---
 target/riscv/helper.h                       | 20 ++++++
 target/riscv/insn32.decode                  | 32 +++++++++
 target/riscv/tcg/insn_trans/trans_rvp.c.inc | 20 ++++++
 target/riscv/tcg/psimd_helper.c             | 78 +++++++++++++++++++++
 4 files changed, 150 insertions(+)

diff --git a/target/riscv/helper.h b/target/riscv/helper.h
index 638c7b0629d..9568a7f91c4 100644
--- a/target/riscv/helper.h
+++ b/target/riscv/helper.h
@@ -1688,3 +1688,23 @@ DEF_HELPER_3(pmulq_w, i64, env, i64, i64)
 DEF_HELPER_3(pmulqr_w, i64, env, i64, i64)
 DEF_HELPER_3(mulq, i32, env, i32, i32)
 DEF_HELPER_3(mulqr, i32, env, i32, i32)
+
+/* Packed SIMD - Q-Format Multiply-Accumulate Operations */
+DEF_HELPER_4(mqacc_h00, i32, env, i32, i32, i32)
+DEF_HELPER_4(mqacc_h01, i32, env, i32, i32, i32)
+DEF_HELPER_4(mqacc_h11, i32, env, i32, i32, i32)
+DEF_HELPER_4(mqracc_h00, i32, env, i32, i32, i32)
+DEF_HELPER_4(mqracc_h01, i32, env, i32, i32, i32)
+DEF_HELPER_4(mqracc_h11, i32, env, i32, i32, i32)
+DEF_HELPER_4(mqacc_w00, i64, env, i64, i64, i64)
+DEF_HELPER_4(mqacc_w01, i64, env, i64, i64, i64)
+DEF_HELPER_4(mqacc_w11, i64, env, i64, i64, i64)
+DEF_HELPER_4(mqracc_w00, i64, env, i64, i64, i64)
+DEF_HELPER_4(mqracc_w01, i64, env, i64, i64, i64)
+DEF_HELPER_4(mqracc_w11, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmqacc_w_h00, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmqacc_w_h01, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmqacc_w_h11, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmqracc_w_h00, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmqracc_w_h01, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmqracc_w_h11, i64, env, i64, i64, i64)
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index 9c50a4dbf52..e2af5f83965 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -1534,3 +1534,35 @@ pmulqr_h    11010 10 ..... ..... 111 ..... 0111011 @r
   mulqr     11010 11 ..... ..... 111 ..... 0111011 @r
   pmulqr_w  11010 11 ..... ..... 111 ..... 0111011 @r
 }
+
+# Packed SIMD - Q-Format Multiply-Accumulate Operations
+{
+  mqacc_h00 11101 00 ..... ..... 111 ..... 0111011 @r
+  pmqacc_w_h00  11101 00 ..... ..... 111 ..... 0111011 @r
+}
+{
+  mqacc_h01 11111 00 ..... ..... 101 ..... 0111011 @r
+  pmqacc_w_h01 11111 00 ..... ..... 101 ..... 0111011 @r
+}
+{
+  mqacc_h11 11111 00 ..... ..... 111 ..... 0111011 @r
+  pmqacc_w_h11 11111 00 ..... ..... 111 ..... 0111011 @r
+}
+{
+  mqracc_h00 11101 10 ..... ..... 111 ..... 0111011 @r
+  pmqracc_w_h00 11101 10 ..... ..... 111 ..... 0111011 @r
+}
+{
+  mqracc_h01 11111 10 ..... ..... 101 ..... 0111011 @r
+  pmqracc_w_h01 11111 10 ..... ..... 101 ..... 0111011 @r
+}
+{
+  mqracc_h11 11111 10 ..... ..... 111 ..... 0111011 @r
+  pmqracc_w_h11 11111 10 ..... ..... 111 ..... 0111011 @r
+}
+mqacc_w00       11101 01 ..... ..... 111 ..... 0111011 @r
+mqacc_w01       11111 01 ..... ..... 101 ..... 0111011 @r
+mqacc_w11       11111 01 ..... ..... 111 ..... 0111011 @r
+mqracc_w00      11101 11 ..... ..... 111 ..... 0111011 @r
+mqracc_w01      11111 11 ..... ..... 101 ..... 0111011 @r
+mqracc_w11      11111 11 ..... ..... 111 ..... 0111011 @r
diff --git a/target/riscv/tcg/insn_trans/trans_rvp.c.inc b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
index 3535f71de88..cec18255a1e 100644
--- a/target/riscv/tcg/insn_trans/trans_rvp.c.inc
+++ b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
@@ -834,3 +834,23 @@ GEN_SIMD_TRANS_64_VXSAT(pmulqr_w)
 GEN_SIMD_TRANS_32_VXSAT(mulq)
 GEN_SIMD_TRANS_32_VXSAT(mulqr)
 
+/* Packed SIMD - Q-Format Multiply-Accumulate Operations */
+GEN_SIMD_TRANS_ACC_32(mqacc_h00)
+GEN_SIMD_TRANS_ACC_32(mqacc_h01)
+GEN_SIMD_TRANS_ACC_32(mqacc_h11)
+GEN_SIMD_TRANS_ACC_32(mqracc_h00)
+GEN_SIMD_TRANS_ACC_32(mqracc_h01)
+GEN_SIMD_TRANS_ACC_32(mqracc_h11)
+GEN_SIMD_TRANS_ACC_64(mqacc_w00)
+GEN_SIMD_TRANS_ACC_64(mqacc_w01)
+GEN_SIMD_TRANS_ACC_64(mqacc_w11)
+GEN_SIMD_TRANS_ACC_64(mqracc_w00)
+GEN_SIMD_TRANS_ACC_64(mqracc_w01)
+GEN_SIMD_TRANS_ACC_64(mqracc_w11)
+GEN_SIMD_TRANS_ACC_64(pmqacc_w_h00)
+GEN_SIMD_TRANS_ACC_64(pmqacc_w_h01)
+GEN_SIMD_TRANS_ACC_64(pmqacc_w_h11)
+GEN_SIMD_TRANS_ACC_64(pmqracc_w_h00)
+GEN_SIMD_TRANS_ACC_64(pmqracc_w_h01)
+GEN_SIMD_TRANS_ACC_64(pmqracc_w_h11)
+
diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
index 11ca17576be..ecdb20bbb58 100644
--- a/target/riscv/tcg/psimd_helper.c
+++ b/target/riscv/tcg/psimd_helper.c
@@ -2655,3 +2655,81 @@ GEN_PSIMD_QMUL(mulq, uint32_t, int32_t, int64_t, uint32_t,
 GEN_PSIMD_QMUL(mulqr, uint32_t, int32_t, int64_t, uint32_t,
                EXTRACT32, INSERT32, ELEMS_W, 31, 1LL << 30, INT32_MIN,
                INT32_MAX)
+
+
+/* Q-Format Multiply-Accumulate Operations */
+
+GEN_PSIMD_QMUL_ACC_INDEXED(mqacc_h00, uint32_t, int16_t, int16_t,
+                           int32_t, int64_t, int32_t, uint32_t, EXTRACT16,
+                           EXTRACT32, INSERT32, ELEMS_W, 0, 0, 0, 15, 0,
+                           PSIMD_MUL_S64)
+GEN_PSIMD_QMUL_ACC_INDEXED(mqacc_h01, uint32_t, int16_t, int16_t,
+                           int32_t, int64_t, int32_t, uint32_t, EXTRACT16,
+                           EXTRACT32, INSERT32, ELEMS_W, 0, 0, 1, 15, 0,
+                           PSIMD_MUL_S64)
+GEN_PSIMD_QMUL_ACC_INDEXED(mqacc_h11, uint32_t, int16_t, int16_t,
+                           int32_t, int64_t, int32_t, uint32_t, EXTRACT16,
+                           EXTRACT32, INSERT32, ELEMS_W, 0, 1, 1, 15, 0,
+                           PSIMD_MUL_S64)
+GEN_PSIMD_QMUL_ACC_INDEXED(mqracc_h00, uint32_t, int16_t, int16_t,
+                           int32_t, int64_t, int32_t, uint32_t, EXTRACT16,
+                           EXTRACT32, INSERT32, ELEMS_W, 0, 0, 0, 15,
+                           1LL << 14, PSIMD_MUL_S64)
+GEN_PSIMD_QMUL_ACC_INDEXED(mqracc_h01, uint32_t, int16_t, int16_t,
+                           int32_t, int64_t, int32_t, uint32_t, EXTRACT16,
+                           EXTRACT32, INSERT32, ELEMS_W, 0, 0, 1, 15,
+                           1LL << 14, PSIMD_MUL_S64)
+GEN_PSIMD_QMUL_ACC_INDEXED(mqracc_h11, uint32_t, int16_t, int16_t,
+                           int32_t, int64_t, int32_t, uint32_t, EXTRACT16,
+                           EXTRACT32, INSERT32, ELEMS_W, 0, 1, 1, 15,
+                           1LL << 14, PSIMD_MUL_S64)
+
+GEN_PSIMD_QMUL_ACC_INDEXED(mqacc_w00, uint64_t, int32_t, int32_t,
+                           int64_t, int64_t, int64_t, uint64_t, EXTRACT32,
+                           EXTRACT64, INSERT64, ELEMS_D, 0, 0, 0, 31, 0,
+                           PSIMD_MUL_S64)
+GEN_PSIMD_QMUL_ACC_INDEXED(mqacc_w01, uint64_t, int32_t, int32_t,
+                           int64_t, int64_t, int64_t, uint64_t, EXTRACT32,
+                           EXTRACT64, INSERT64, ELEMS_D, 0, 0, 1, 31, 0,
+                           PSIMD_MUL_S64)
+GEN_PSIMD_QMUL_ACC_INDEXED(mqacc_w11, uint64_t, int32_t, int32_t,
+                           int64_t, int64_t, int64_t, uint64_t, EXTRACT32,
+                           EXTRACT64, INSERT64, ELEMS_D, 0, 1, 1, 31, 0,
+                           PSIMD_MUL_S64)
+GEN_PSIMD_QMUL_ACC_INDEXED(mqracc_w00, uint64_t, int32_t, int32_t,
+                           int64_t, int64_t, int64_t, uint64_t, EXTRACT32,
+                           EXTRACT64, INSERT64, ELEMS_D, 0, 0, 0, 31,
+                           1LL << 30, PSIMD_MUL_S64)
+GEN_PSIMD_QMUL_ACC_INDEXED(mqracc_w01, uint64_t, int32_t, int32_t,
+                           int64_t, int64_t, int64_t, uint64_t, EXTRACT32,
+                           EXTRACT64, INSERT64, ELEMS_D, 0, 0, 1, 31,
+                           1LL << 30, PSIMD_MUL_S64)
+GEN_PSIMD_QMUL_ACC_INDEXED(mqracc_w11, uint64_t, int32_t, int32_t,
+                           int64_t, int64_t, int64_t, uint64_t, EXTRACT32,
+                           EXTRACT64, INSERT64, ELEMS_D, 0, 1, 1, 31,
+                           1LL << 30, PSIMD_MUL_S64)
+
+GEN_PSIMD_QMUL_ACC_INDEXED(pmqacc_w_h00, uint64_t, int16_t, int16_t,
+                           int32_t, int64_t, int32_t, uint32_t, EXTRACT16,
+                           EXTRACT32, INSERT32, ELEMS_W, 2, 0, 0, 15, 0,
+                           PSIMD_MUL_S64)
+GEN_PSIMD_QMUL_ACC_INDEXED(pmqacc_w_h01, uint64_t, int16_t, int16_t,
+                           int32_t, int64_t, int32_t, uint32_t, EXTRACT16,
+                           EXTRACT32, INSERT32, ELEMS_W, 2, 0, 1, 15, 0,
+                           PSIMD_MUL_S64)
+GEN_PSIMD_QMUL_ACC_INDEXED(pmqacc_w_h11, uint64_t, int16_t, int16_t,
+                           int32_t, int64_t, int32_t, uint32_t, EXTRACT16,
+                           EXTRACT32, INSERT32, ELEMS_W, 2, 1, 1, 15, 0,
+                           PSIMD_MUL_S64)
+GEN_PSIMD_QMUL_ACC_INDEXED(pmqracc_w_h00, uint64_t, int16_t, int16_t,
+                           int32_t, int64_t, int32_t, uint32_t, EXTRACT16,
+                           EXTRACT32, INSERT32, ELEMS_W, 2, 0, 0, 15,
+                           1LL << 14, PSIMD_MUL_S64)
+GEN_PSIMD_QMUL_ACC_INDEXED(pmqracc_w_h01, uint64_t, int16_t, int16_t,
+                           int32_t, int64_t, int32_t, uint32_t, EXTRACT16,
+                           EXTRACT32, INSERT32, ELEMS_W, 2, 0, 1, 15,
+                           1LL << 14, PSIMD_MUL_S64)
+GEN_PSIMD_QMUL_ACC_INDEXED(pmqracc_w_h11, uint64_t, int16_t, int16_t,
+                           int32_t, int64_t, int32_t, uint32_t, EXTRACT16,
+                           EXTRACT32, INSERT32, ELEMS_W, 2, 1, 1, 15,
+                           1LL << 14, PSIMD_MUL_S64)
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH v2 14/18] target/riscv: Add packed SIMD two-way MAC instructions
  2026-07-17 10:06 [PATCH v2 00/18] target/riscv: Add support for RISC-V P Molly Chen
                   ` (12 preceding siblings ...)
  2026-07-17 10:07 ` [PATCH v2 13/18] target/riscv: Add packed SIMD Q-format MAC instructions Molly Chen
@ 2026-07-17 10:07 ` Molly Chen
  2026-07-17 10:07 ` [PATCH v2 15/18] target/riscv: Add packed SIMD four-way " Molly Chen
                   ` (5 subsequent siblings)
  19 siblings, 0 replies; 34+ messages in thread
From: Molly Chen @ 2026-07-17 10:07 UTC (permalink / raw)
  To: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
	chao.liu.zevorn, Chao Liu
  Cc: xiaoou, qemu-riscv, qemu-devel

Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
---
 target/riscv/helper.h                       |  34 ++++++
 target/riscv/insn32.decode                  |  34 ++++++
 target/riscv/tcg/insn_trans/trans_rvp.c.inc |  34 ++++++
 target/riscv/tcg/psimd_helper.c             | 116 ++++++++++++++++++++
 4 files changed, 218 insertions(+)

diff --git a/target/riscv/helper.h b/target/riscv/helper.h
index 9568a7f91c4..b0743d19177 100644
--- a/target/riscv/helper.h
+++ b/target/riscv/helper.h
@@ -1708,3 +1708,37 @@ DEF_HELPER_4(pmqacc_w_h11, i64, env, i64, i64, i64)
 DEF_HELPER_4(pmqracc_w_h00, i64, env, i64, i64, i64)
 DEF_HELPER_4(pmqracc_w_h01, i64, env, i64, i64, i64)
 DEF_HELPER_4(pmqracc_w_h11, i64, env, i64, i64, i64)
+
+/* Packed SIMD - Two-Way Multiply and Accumulate Operations */
+DEF_HELPER_3(pmq2add_h, tl, env, tl, tl)
+DEF_HELPER_3(pmqr2add_h, tl, env, tl, tl)
+DEF_HELPER_4(pmq2adda_h, tl, env, tl, tl, tl)
+DEF_HELPER_4(pmqr2adda_h, tl, env, tl, tl, tl)
+DEF_HELPER_3(pmq2add_w, i64, env, i64, i64)
+DEF_HELPER_3(pmqr2add_w, i64, env, i64, i64)
+DEF_HELPER_4(pmq2adda_w, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmqr2adda_w, i64, env, i64, i64, i64)
+DEF_HELPER_3(pm2add_h, tl, env, tl, tl)
+DEF_HELPER_3(pm2addsu_h, tl, env, tl, tl)
+DEF_HELPER_3(pm2addu_h, tl, env, tl, tl)
+DEF_HELPER_3(pm2add_hx, tl, env, tl, tl)
+DEF_HELPER_3(pm2sub_h, tl, env, tl, tl)
+DEF_HELPER_3(pm2sub_hx, tl, env, tl, tl)
+DEF_HELPER_4(pm2adda_h, tl, env, tl, tl, tl)
+DEF_HELPER_4(pm2addasu_h, tl, env, tl, tl, tl)
+DEF_HELPER_4(pm2addau_h, tl, env, tl, tl, tl)
+DEF_HELPER_4(pm2adda_hx, tl, env, tl, tl, tl)
+DEF_HELPER_4(pm2suba_h, tl, env, tl, tl, tl)
+DEF_HELPER_4(pm2suba_hx, tl, env, tl, tl, tl)
+DEF_HELPER_3(pm2add_w, i64, env, i64, i64)
+DEF_HELPER_3(pm2addsu_w, i64, env, i64, i64)
+DEF_HELPER_3(pm2addu_w, i64, env, i64, i64)
+DEF_HELPER_3(pm2add_wx, i64, env, i64, i64)
+DEF_HELPER_3(pm2sub_w, i64, env, i64, i64)
+DEF_HELPER_3(pm2sub_wx, i64, env, i64, i64)
+DEF_HELPER_4(pm2adda_w, i64, env, i64, i64, i64)
+DEF_HELPER_4(pm2addasu_w, i64, env, i64, i64, i64)
+DEF_HELPER_4(pm2addau_w, i64, env, i64, i64, i64)
+DEF_HELPER_4(pm2adda_wx, i64, env, i64, i64, i64)
+DEF_HELPER_4(pm2suba_w, i64, env, i64, i64, i64)
+DEF_HELPER_4(pm2suba_wx, i64, env, i64, i64, i64)
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index e2af5f83965..1c8bdde25c2 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -1566,3 +1566,37 @@ mqacc_w11       11111 01 ..... ..... 111 ..... 0111011 @r
 mqracc_w00      11101 11 ..... ..... 111 ..... 0111011 @r
 mqracc_w01      11111 11 ..... ..... 101 ..... 0111011 @r
 mqracc_w11      11111 11 ..... ..... 111 ..... 0111011 @r
+
+# Packed SIMD - Two-Way Multiply and Accumulate Operations
+pmq2add_h       10110 00 ..... ..... 101 ..... 0111011 @r
+pmqr2add_h      10110 10 ..... ..... 101 ..... 0111011 @r
+pmq2adda_h      10111 00 ..... ..... 101 ..... 0111011 @r
+pmqr2adda_h     10111 10 ..... ..... 101 ..... 0111011 @r
+pmq2add_w       10110 01 ..... ..... 101 ..... 0111011 @r
+pmqr2add_w      10110 11 ..... ..... 101 ..... 0111011 @r
+pmq2adda_w      10111 01 ..... ..... 101 ..... 0111011 @r
+pmqr2adda_w     10111 11 ..... ..... 101 ..... 0111011 @r
+pm2add_h        10000 00 ..... ..... 101 ..... 0111011 @r
+pm2addsu_h      11100 00 ..... ..... 101 ..... 0111011 @r
+pm2addu_h       10100 00 ..... ..... 101 ..... 0111011 @r
+pm2add_hx       10010 00 ..... ..... 101 ..... 0111011 @r
+pm2sub_h        11000 00 ..... ..... 101 ..... 0111011 @r
+pm2sub_hx       11010 00 ..... ..... 101 ..... 0111011 @r
+pm2adda_h       10001 00 ..... ..... 101 ..... 0111011 @r
+pm2addasu_h     11101 00 ..... ..... 101 ..... 0111011 @r
+pm2addau_h      10101 00 ..... ..... 101 ..... 0111011 @r
+pm2adda_hx      10011 00 ..... ..... 101 ..... 0111011 @r
+pm2suba_h       11001 00 ..... ..... 101 ..... 0111011 @r
+pm2suba_hx      11011 00 ..... ..... 101 ..... 0111011 @r
+pm2add_w        10000 01 ..... ..... 101 ..... 0111011 @r
+pm2addsu_w      11100 01 ..... ..... 101 ..... 0111011 @r
+pm2addu_w       10100 01 ..... ..... 101 ..... 0111011 @r
+pm2add_wx       10010 01 ..... ..... 101 ..... 0111011 @r
+pm2sub_w        11000 01 ..... ..... 101 ..... 0111011 @r
+pm2sub_wx       11010 01 ..... ..... 101 ..... 0111011 @r
+pm2adda_w       10001 01 ..... ..... 101 ..... 0111011 @r
+pm2addasu_w     11101 01 ..... ..... 101 ..... 0111011 @r
+pm2addau_w      10101 01 ..... ..... 101 ..... 0111011 @r
+pm2adda_wx      10011 01 ..... ..... 101 ..... 0111011 @r
+pm2suba_w       11001 01 ..... ..... 101 ..... 0111011 @r
+pm2suba_wx      11011 01 ..... ..... 101 ..... 0111011 @r
diff --git a/target/riscv/tcg/insn_trans/trans_rvp.c.inc b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
index cec18255a1e..cf670b144c3 100644
--- a/target/riscv/tcg/insn_trans/trans_rvp.c.inc
+++ b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
@@ -854,3 +854,37 @@ GEN_SIMD_TRANS_ACC_64(pmqracc_w_h00)
 GEN_SIMD_TRANS_ACC_64(pmqracc_w_h01)
 GEN_SIMD_TRANS_ACC_64(pmqracc_w_h11)
 
+/* Packed SIMD - Two-Way Multiply and Accumulate Operations */
+GEN_SIMD_TRANS(pmq2add_h)
+GEN_SIMD_TRANS(pmqr2add_h)
+GEN_SIMD_TRANS_ACC(pmq2adda_h)
+GEN_SIMD_TRANS_ACC(pmqr2adda_h)
+GEN_SIMD_TRANS_64(pmq2add_w)
+GEN_SIMD_TRANS_64(pmqr2add_w)
+GEN_SIMD_TRANS_ACC_64(pmq2adda_w)
+GEN_SIMD_TRANS_ACC_64(pmqr2adda_w)
+GEN_SIMD_TRANS(pm2add_h)
+GEN_SIMD_TRANS(pm2addsu_h)
+GEN_SIMD_TRANS(pm2addu_h)
+GEN_SIMD_TRANS(pm2add_hx)
+GEN_SIMD_TRANS(pm2sub_h)
+GEN_SIMD_TRANS(pm2sub_hx)
+GEN_SIMD_TRANS_ACC(pm2adda_h)
+GEN_SIMD_TRANS_ACC(pm2addasu_h)
+GEN_SIMD_TRANS_ACC(pm2addau_h)
+GEN_SIMD_TRANS_ACC(pm2adda_hx)
+GEN_SIMD_TRANS_ACC(pm2suba_h)
+GEN_SIMD_TRANS_ACC(pm2suba_hx)
+GEN_SIMD_TRANS_64(pm2add_w)
+GEN_SIMD_TRANS_64(pm2addsu_w)
+GEN_SIMD_TRANS_64(pm2addu_w)
+GEN_SIMD_TRANS_64(pm2add_wx)
+GEN_SIMD_TRANS_64(pm2sub_w)
+GEN_SIMD_TRANS_64(pm2sub_wx)
+GEN_SIMD_TRANS_ACC_64(pm2adda_w)
+GEN_SIMD_TRANS_ACC_64(pm2addasu_w)
+GEN_SIMD_TRANS_ACC_64(pm2addau_w)
+GEN_SIMD_TRANS_ACC_64(pm2adda_wx)
+GEN_SIMD_TRANS_ACC_64(pm2suba_w)
+GEN_SIMD_TRANS_ACC_64(pm2suba_wx)
+
diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
index ecdb20bbb58..bad04937b54 100644
--- a/target/riscv/tcg/psimd_helper.c
+++ b/target/riscv/tcg/psimd_helper.c
@@ -2733,3 +2733,119 @@ GEN_PSIMD_QMUL_ACC_INDEXED(pmqracc_w_h11, uint64_t, int16_t, int16_t,
                            int32_t, int64_t, int32_t, uint32_t, EXTRACT16,
                            EXTRACT32, INSERT32, ELEMS_W, 2, 1, 1, 15,
                            1LL << 14, PSIMD_MUL_S64)
+
+/* Two-Way Multiply and Accumulate Operations */
+
+GEN_PSIMD_Q2ADD(pmq2add_h, target_ulong, int16_t, int32_t, int64_t,
+                uint32_t, EXTRACT16, INSERT32, ELEMS_W, 2, 15, 0,
+                PSIMD_MUL_S32)
+GEN_PSIMD_Q2ADD(pmqr2add_h, target_ulong, int16_t, int32_t, int64_t,
+                uint32_t, EXTRACT16, INSERT32, ELEMS_W, 2, 15, 1LL << 14,
+                PSIMD_MUL_S32)
+GEN_PSIMD_Q2ADDA(pmq2adda_h, target_ulong, int16_t, int32_t, int32_t,
+                 int64_t, uint32_t, EXTRACT16, EXTRACT32, INSERT32,
+                 ELEMS_W, 2, 15, 0, PSIMD_MUL_S32)
+GEN_PSIMD_Q2ADDA(pmqr2adda_h, target_ulong, int16_t, int32_t, int32_t,
+                 int64_t, uint32_t, EXTRACT16, EXTRACT32, INSERT32,
+                 ELEMS_W, 2, 15, 1LL << 14, PSIMD_MUL_S32)
+
+GEN_PSIMD_Q2ADD(pmq2add_w, uint64_t, int32_t, int64_t, int64_t,
+                uint64_t, EXTRACT32, INSERT64, ELEMS_D, 0, 31, 0,
+                PSIMD_MUL_S64)
+GEN_PSIMD_Q2ADD(pmqr2add_w, uint64_t, int32_t, int64_t, int64_t,
+                uint64_t, EXTRACT32, INSERT64, ELEMS_D, 0, 31, 1LL << 30,
+                PSIMD_MUL_S64)
+GEN_PSIMD_Q2ADDA(pmq2adda_w, uint64_t, int32_t, int64_t, int64_t,
+                 int64_t, uint64_t, EXTRACT32, EXTRACT64, INSERT64,
+                 ELEMS_D, 0, 31, 0, PSIMD_MUL_S64)
+GEN_PSIMD_Q2ADDA(pmqr2adda_w, uint64_t, int32_t, int64_t, int64_t,
+                 int64_t, uint64_t, EXTRACT32, EXTRACT64, INSERT64,
+                 ELEMS_D, 0, 31, 1LL << 30, PSIMD_MUL_S64)
+
+GEN_PSIMD_2WAY_MUL(pm2add_h, target_ulong, int16_t, int16_t,
+                   int32_t, uint32_t, EXTRACT16, INSERT32, ELEMS_W, 2,
+                   0, 1, 0, 1, PSIMD_MUL_S32, PSIMD_COMB_ADD)
+GEN_PSIMD_2WAY_MUL(pm2addsu_h, target_ulong, int16_t, uint16_t,
+                   int32_t, uint32_t, EXTRACT16, INSERT32, ELEMS_W, 2,
+                   0, 1, 0, 1, PSIMD_MUL_SU32, PSIMD_COMB_ADD)
+GEN_PSIMD_2WAY_MUL(pm2addu_h, target_ulong, uint16_t, uint16_t,
+                   uint32_t, uint32_t, EXTRACT16, INSERT32, ELEMS_W, 2,
+                   0, 1, 0, 1, PSIMD_MUL_U32, PSIMD_COMB_ADD)
+GEN_PSIMD_2WAY_MUL(pm2add_hx, target_ulong, int16_t, int16_t,
+                   int32_t, uint32_t, EXTRACT16, INSERT32, ELEMS_W, 2,
+                   0, 1, 1, 0, PSIMD_MUL_S32, PSIMD_COMB_ADD)
+GEN_PSIMD_2WAY_MUL(pm2sub_h, target_ulong, int16_t, int16_t,
+                   int32_t, uint32_t, EXTRACT16, INSERT32, ELEMS_W, 2,
+                   0, 1, 0, 1, PSIMD_MUL_S32, PSIMD_COMB_SUB)
+GEN_PSIMD_2WAY_MUL(pm2sub_hx, target_ulong, int16_t, int16_t,
+                   int32_t, uint32_t, EXTRACT16, INSERT32, ELEMS_W, 2,
+                   0, 1, 1, 0, PSIMD_MUL_S32, PSIMD_COMB_SUB)
+
+GEN_PSIMD_2WAY_MUL_ACC(pm2adda_h, target_ulong, int16_t, int16_t,
+                       int32_t, int32_t, uint32_t, EXTRACT16, EXTRACT32,
+                       INSERT32, ELEMS_W, 2, 0, 1, 0, 1, PSIMD_MUL_S32,
+                       PSIMD_COMB_ADD)
+GEN_PSIMD_2WAY_MUL_ACC(pm2addasu_h, target_ulong, int16_t, uint16_t,
+                       int32_t, int32_t, uint32_t, EXTRACT16, EXTRACT32,
+                       INSERT32, ELEMS_W, 2, 0, 1, 0, 1, PSIMD_MUL_SU32,
+                       PSIMD_COMB_ADD)
+GEN_PSIMD_2WAY_MUL_ACC(pm2addau_h, target_ulong, uint16_t, uint16_t,
+                       uint32_t, uint32_t, uint32_t, EXTRACT16, EXTRACT32,
+                       INSERT32, ELEMS_W, 2, 0, 1, 0, 1, PSIMD_MUL_U32,
+                       PSIMD_COMB_ADD)
+GEN_PSIMD_2WAY_MUL_ACC(pm2adda_hx, target_ulong, int16_t, int16_t,
+                       int32_t, int32_t, uint32_t, EXTRACT16, EXTRACT32,
+                       INSERT32, ELEMS_W, 2, 0, 1, 1, 0, PSIMD_MUL_S32,
+                       PSIMD_COMB_ADD)
+GEN_PSIMD_2WAY_MUL_ACC(pm2suba_h, target_ulong, int16_t, int16_t,
+                       int32_t, int32_t, uint32_t, EXTRACT16, EXTRACT32,
+                       INSERT32, ELEMS_W, 2, 0, 1, 0, 1, PSIMD_MUL_S32,
+                       PSIMD_COMB_SUB)
+GEN_PSIMD_2WAY_MUL_ACC(pm2suba_hx, target_ulong, int16_t, int16_t,
+                       int32_t, int32_t, uint32_t, EXTRACT16, EXTRACT32,
+                       INSERT32, ELEMS_W, 2, 0, 1, 1, 0, PSIMD_MUL_S32,
+                       PSIMD_COMB_SUB)
+
+GEN_PSIMD_2WAY_MUL(pm2add_w, uint64_t, int32_t, int32_t,
+                   int64_t, uint64_t, EXTRACT32, INSERT64, ELEMS_D, 0,
+                   0, 1, 0, 1, PSIMD_MUL_S64, PSIMD_COMB_ADD)
+GEN_PSIMD_2WAY_MUL(pm2addsu_w, uint64_t, int32_t, uint32_t,
+                   int64_t, uint64_t, EXTRACT32, INSERT64, ELEMS_D, 0,
+                   0, 1, 0, 1, PSIMD_MUL_SU64, PSIMD_COMB_ADD)
+GEN_PSIMD_2WAY_MUL(pm2addu_w, uint64_t, uint32_t, uint32_t,
+                   uint64_t, uint64_t, EXTRACT32, INSERT64, ELEMS_D, 0,
+                   0, 1, 0, 1, PSIMD_MUL_U64, PSIMD_COMB_ADD)
+GEN_PSIMD_2WAY_MUL(pm2add_wx, uint64_t, int32_t, int32_t,
+                   int64_t, uint64_t, EXTRACT32, INSERT64, ELEMS_D, 0,
+                   0, 1, 1, 0, PSIMD_MUL_S64, PSIMD_COMB_ADD)
+GEN_PSIMD_2WAY_MUL(pm2sub_w, uint64_t, int32_t, int32_t,
+                   int64_t, uint64_t, EXTRACT32, INSERT64, ELEMS_D, 0,
+                   0, 1, 0, 1, PSIMD_MUL_S64, PSIMD_COMB_SUB)
+GEN_PSIMD_2WAY_MUL(pm2sub_wx, uint64_t, int32_t, int32_t,
+                   int64_t, uint64_t, EXTRACT32, INSERT64, ELEMS_D, 0,
+                   0, 1, 1, 0, PSIMD_MUL_S64, PSIMD_COMB_SUB)
+
+GEN_PSIMD_2WAY_MUL_ACC(pm2adda_w, uint64_t, int32_t, int32_t,
+                       int64_t, int64_t, uint64_t, EXTRACT32, EXTRACT64,
+                       INSERT64, ELEMS_D, 0, 0, 1, 0, 1, PSIMD_MUL_S64,
+                       PSIMD_COMB_ADD)
+GEN_PSIMD_2WAY_MUL_ACC(pm2addasu_w, uint64_t, int32_t, uint32_t,
+                       int64_t, int64_t, uint64_t, EXTRACT32, EXTRACT64,
+                       INSERT64, ELEMS_D, 0, 0, 1, 0, 1, PSIMD_MUL_SU64,
+                       PSIMD_COMB_ADD)
+GEN_PSIMD_2WAY_MUL_ACC(pm2addau_w, uint64_t, uint32_t, uint32_t,
+                       uint64_t, uint64_t, uint64_t, EXTRACT32, EXTRACT64,
+                       INSERT64, ELEMS_D, 0, 0, 1, 0, 1, PSIMD_MUL_U64,
+                       PSIMD_COMB_ADD)
+GEN_PSIMD_2WAY_MUL_ACC(pm2adda_wx, uint64_t, int32_t, int32_t,
+                       int64_t, int64_t, uint64_t, EXTRACT32, EXTRACT64,
+                       INSERT64, ELEMS_D, 0, 0, 1, 1, 0, PSIMD_MUL_S64,
+                       PSIMD_COMB_ADD)
+GEN_PSIMD_2WAY_MUL_ACC(pm2suba_w, uint64_t, int32_t, int32_t,
+                       int64_t, int64_t, uint64_t, EXTRACT32, EXTRACT64,
+                       INSERT64, ELEMS_D, 0, 0, 1, 0, 1, PSIMD_MUL_S64,
+                       PSIMD_COMB_SUB)
+GEN_PSIMD_2WAY_MUL_ACC(pm2suba_wx, uint64_t, int32_t, int32_t,
+                       int64_t, int64_t, uint64_t, EXTRACT32, EXTRACT64,
+                       INSERT64, ELEMS_D, 0, 0, 1, 1, 0, PSIMD_MUL_S64,
+                       PSIMD_COMB_SUB)
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH v2 15/18] target/riscv: Add packed SIMD four-way MAC instructions
  2026-07-17 10:06 [PATCH v2 00/18] target/riscv: Add support for RISC-V P Molly Chen
                   ` (13 preceding siblings ...)
  2026-07-17 10:07 ` [PATCH v2 14/18] target/riscv: Add packed SIMD two-way " Molly Chen
@ 2026-07-17 10:07 ` Molly Chen
  2026-07-17 10:07 ` [PATCH v2 16/18] target/riscv: Add packed SIMD load-replicate instructions Molly Chen
                   ` (4 subsequent siblings)
  19 siblings, 0 replies; 34+ messages in thread
From: Molly Chen @ 2026-07-17 10:07 UTC (permalink / raw)
  To: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
	chao.liu.zevorn, Chao Liu
  Cc: xiaoou, qemu-riscv, qemu-devel

Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
---
 target/riscv/helper.h                       | 14 +++++++
 target/riscv/insn32.decode                  | 14 +++++++
 target/riscv/tcg/insn_trans/trans_rvp.c.inc | 14 +++++++
 target/riscv/tcg/psimd_helper.c             | 41 +++++++++++++++++++++
 4 files changed, 83 insertions(+)

diff --git a/target/riscv/helper.h b/target/riscv/helper.h
index b0743d19177..fb95a9f71b5 100644
--- a/target/riscv/helper.h
+++ b/target/riscv/helper.h
@@ -1742,3 +1742,17 @@ DEF_HELPER_4(pm2addau_w, i64, env, i64, i64, i64)
 DEF_HELPER_4(pm2adda_wx, i64, env, i64, i64, i64)
 DEF_HELPER_4(pm2suba_w, i64, env, i64, i64, i64)
 DEF_HELPER_4(pm2suba_wx, i64, env, i64, i64, i64)
+
+/* Packed SIMD - Four-Way Multiply and Accumulate Operations */
+DEF_HELPER_3(pm4add_b, tl, env, tl, tl)
+DEF_HELPER_3(pm4addsu_b, tl, env, tl, tl)
+DEF_HELPER_3(pm4addu_b, tl, env, tl, tl)
+DEF_HELPER_4(pm4adda_b, tl, env, tl, tl, tl)
+DEF_HELPER_4(pm4addasu_b, tl, env, tl, tl, tl)
+DEF_HELPER_4(pm4addau_b, tl, env, tl, tl, tl)
+DEF_HELPER_3(pm4add_h, i64, env, i64, i64)
+DEF_HELPER_3(pm4addsu_h, i64, env, i64, i64)
+DEF_HELPER_3(pm4addu_h, i64, env, i64, i64)
+DEF_HELPER_4(pm4adda_h, i64, env, i64, i64, i64)
+DEF_HELPER_4(pm4addasu_h, i64, env, i64, i64, i64)
+DEF_HELPER_4(pm4addau_h, i64, env, i64, i64, i64)
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index 1c8bdde25c2..8720fedb592 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -1600,3 +1600,17 @@ pm2addau_w      10101 01 ..... ..... 101 ..... 0111011 @r
 pm2adda_wx      10011 01 ..... ..... 101 ..... 0111011 @r
 pm2suba_w       11001 01 ..... ..... 101 ..... 0111011 @r
 pm2suba_wx      11011 01 ..... ..... 101 ..... 0111011 @r
+
+# Packed SIMD - Four-Way Multiply and Accumulate Operations
+pm4add_b        10000 10 ..... ..... 101 ..... 0111011 @r
+pm4addsu_b      11100 10 ..... ..... 101 ..... 0111011 @r
+pm4addu_b       10100 10 ..... ..... 101 ..... 0111011 @r
+pm4adda_b       10001 10 ..... ..... 101 ..... 0111011 @r
+pm4addasu_b     11101 10 ..... ..... 101 ..... 0111011 @r
+pm4addau_b      10101 10 ..... ..... 101 ..... 0111011 @r
+pm4add_h        10000 11 ..... ..... 101 ..... 0111011 @r
+pm4addsu_h      11100 11 ..... ..... 101 ..... 0111011 @r
+pm4addu_h       10100 11 ..... ..... 101 ..... 0111011 @r
+pm4adda_h       10001 11 ..... ..... 101 ..... 0111011 @r
+pm4addasu_h     11101 11 ..... ..... 101 ..... 0111011 @r
+pm4addau_h      10101 11 ..... ..... 101 ..... 0111011 @r
diff --git a/target/riscv/tcg/insn_trans/trans_rvp.c.inc b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
index cf670b144c3..6c344a66dc8 100644
--- a/target/riscv/tcg/insn_trans/trans_rvp.c.inc
+++ b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
@@ -888,3 +888,17 @@ GEN_SIMD_TRANS_ACC_64(pm2adda_wx)
 GEN_SIMD_TRANS_ACC_64(pm2suba_w)
 GEN_SIMD_TRANS_ACC_64(pm2suba_wx)
 
+/* Packed SIMD - Four-Way Multiply and Accumulate Operations */
+GEN_SIMD_TRANS(pm4add_b)
+GEN_SIMD_TRANS(pm4addsu_b)
+GEN_SIMD_TRANS(pm4addu_b)
+GEN_SIMD_TRANS_ACC(pm4adda_b)
+GEN_SIMD_TRANS_ACC(pm4addasu_b)
+GEN_SIMD_TRANS_ACC(pm4addau_b)
+GEN_SIMD_TRANS_64(pm4add_h)
+GEN_SIMD_TRANS_64(pm4addsu_h)
+GEN_SIMD_TRANS_64(pm4addu_h)
+GEN_SIMD_TRANS_ACC_64(pm4adda_h)
+GEN_SIMD_TRANS_ACC_64(pm4addasu_h)
+GEN_SIMD_TRANS_ACC_64(pm4addau_h)
+
diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
index bad04937b54..e7c7e554938 100644
--- a/target/riscv/tcg/psimd_helper.c
+++ b/target/riscv/tcg/psimd_helper.c
@@ -2849,3 +2849,44 @@ GEN_PSIMD_2WAY_MUL_ACC(pm2suba_wx, uint64_t, int32_t, int32_t,
                        int64_t, int64_t, uint64_t, EXTRACT32, EXTRACT64,
                        INSERT64, ELEMS_D, 0, 0, 1, 1, 0, PSIMD_MUL_S64,
                        PSIMD_COMB_SUB)
+
+
+/* Four-Way Multiply and Accumulate Operations */
+
+GEN_PSIMD_4WAY_MUL(pm4add_b, target_ulong, int8_t, int8_t,
+                   int32_t, uint32_t, EXTRACT8, INSERT32, ELEMS_W, 4,
+                   PSIMD_MUL_S32)
+GEN_PSIMD_4WAY_MUL(pm4addsu_b, target_ulong, int8_t, uint8_t,
+                   int32_t, uint32_t, EXTRACT8, INSERT32, ELEMS_W, 4,
+                   PSIMD_MUL_SU32)
+GEN_PSIMD_4WAY_MUL(pm4addu_b, target_ulong, uint8_t, uint8_t,
+                   uint32_t, uint32_t, EXTRACT8, INSERT32, ELEMS_W, 4,
+                   PSIMD_MUL_U32)
+GEN_PSIMD_4WAY_MUL_ACC(pm4adda_b, target_ulong, int8_t, int8_t,
+                       int32_t, int32_t, uint32_t, EXTRACT8, EXTRACT32,
+                       INSERT32, ELEMS_W, 4, PSIMD_MUL_S32)
+GEN_PSIMD_4WAY_MUL_ACC(pm4addasu_b, target_ulong, int8_t, uint8_t,
+                       int32_t, int32_t, uint32_t, EXTRACT8, EXTRACT32,
+                       INSERT32, ELEMS_W, 4, PSIMD_MUL_SU32)
+GEN_PSIMD_4WAY_MUL_ACC(pm4addau_b, target_ulong, uint8_t, uint8_t,
+                       uint32_t, uint32_t, uint32_t, EXTRACT8, EXTRACT32,
+                       INSERT32, ELEMS_W, 4, PSIMD_MUL_U32)
+
+GEN_PSIMD_4WAY_MUL(pm4add_h, uint64_t, int16_t, int16_t,
+                   int64_t, uint64_t, EXTRACT16, INSERT64, ELEMS_D, 0,
+                   PSIMD_MUL_S64)
+GEN_PSIMD_4WAY_MUL(pm4addsu_h, uint64_t, int16_t, uint16_t,
+                   int64_t, uint64_t, EXTRACT16, INSERT64, ELEMS_D, 0,
+                   PSIMD_MUL_SU64)
+GEN_PSIMD_4WAY_MUL(pm4addu_h, uint64_t, uint16_t, uint16_t,
+                   uint64_t, uint64_t, EXTRACT16, INSERT64, ELEMS_D, 0,
+                   PSIMD_MUL_U64)
+GEN_PSIMD_4WAY_MUL_ACC(pm4adda_h, uint64_t, int16_t, int16_t,
+                       int64_t, int64_t, uint64_t, EXTRACT16, EXTRACT64,
+                       INSERT64, ELEMS_D, 0, PSIMD_MUL_S64)
+GEN_PSIMD_4WAY_MUL_ACC(pm4addasu_h, uint64_t, int16_t, uint16_t,
+                       int64_t, int64_t, uint64_t, EXTRACT16, EXTRACT64,
+                       INSERT64, ELEMS_D, 0, PSIMD_MUL_SU64)
+GEN_PSIMD_4WAY_MUL_ACC(pm4addau_h, uint64_t, uint16_t, uint16_t,
+                       uint64_t, uint64_t, uint64_t, EXTRACT16, EXTRACT64,
+                       INSERT64, ELEMS_D, 0, PSIMD_MUL_U64)
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH v2 16/18] target/riscv: Add packed SIMD load-replicate instructions
  2026-07-17 10:06 [PATCH v2 00/18] target/riscv: Add support for RISC-V P Molly Chen
                   ` (14 preceding siblings ...)
  2026-07-17 10:07 ` [PATCH v2 15/18] target/riscv: Add packed SIMD four-way " Molly Chen
@ 2026-07-17 10:07 ` Molly Chen
  2026-07-17 10:07 ` [PATCH v2 17/18] target/riscv: Add packed SIMD RV32 only instructions Molly Chen
                   ` (3 subsequent siblings)
  19 siblings, 0 replies; 34+ messages in thread
From: Molly Chen @ 2026-07-17 10:07 UTC (permalink / raw)
  To: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
	chao.liu.zevorn, Chao Liu
  Cc: xiaoou, qemu-riscv, qemu-devel

Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
---
 target/riscv/insn32.decode                  | 16 ++++++++++++++
 target/riscv/tcg/insn_trans/trans_rvp.c.inc | 24 +++++++++++++++++++++
 target/riscv/tcg/translate.c                |  2 ++
 3 files changed, 42 insertions(+)

diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index 8720fedb592..403e17e439d 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -44,6 +44,10 @@
 %imm_p_ui16 20:4
 %imm_p_ui32 20:5
 %imm_p_ui64 20:6
+%imm_p_l1  16:8
+%imm_p_l2  15:s1 16:9
+%imm_p_l3  15:s9 24:1              !function=ex_shift_6
+%imm_p_l4  15:s9 24:1              !function=ex_shift_22
 
 # Argument sets:
 &empty
@@ -53,6 +57,7 @@
 &r    rd rs1 rs2
 &r2   rd rs1
 &r2_s rs1 rs2
+&p_l  imm rd
 &s    imm rs1 rs2
 &u    imm rd
 &shift     shamt rs1 rd
@@ -114,6 +119,10 @@
 @p_ui16 ..... .... ... ..... ... ..... ....... &i imm=%imm_p_ui16 %rs1 %rd
 @p_ui32 ..... .... ... ..... ... ..... ....... &i imm=%imm_p_ui32 %rs1 %rd
 @p_ui64 ..... .... ... ..... ... ..... ....... &i imm=%imm_p_ui64 %rs1 %rd
+@p_l1  ........ ........ .... ..... ....... &p_l      imm=%imm_p_l1         %rd
+@p_l2  ....... .......... ... ..... ....... &p_l      imm=%imm_p_l2         %rd
+@p_l3  ....... .......... ... ..... ....... &p_l      imm=%imm_p_l3         %rd
+@p_l4  ....... .......... ... ..... ....... &p_l      imm=%imm_p_l4         %rd
 
 # Formats 64:
 @sh5     .......  ..... .....  ... ..... ....... &shift  shamt=%sh5      %rs1 %rd
@@ -1614,3 +1623,10 @@ pm4addu_h       10100 11 ..... ..... 101 ..... 0111011 @r
 pm4adda_h       10001 11 ..... ..... 101 ..... 0111011 @r
 pm4addasu_h     11101 11 ..... ..... 101 ..... 0111011 @r
 pm4addau_h      10101 11 ..... ..... 101 ..... 0111011 @r
+
+# Packed SIMD - Load and Replicate instructions
+pli_b    10110100 ........ 0010 ..... 0011011 @p_l1
+pli_h    1011000 .......... 010 ..... 0011011 @p_l2
+plui_h   1111000 .......... 010 ..... 0011011 @p_l3
+pli_w    1011001 ..... ..... 010 ..... 0011011 @p_l2
+plui_w   1111001 ..... ..... 010 ..... 0011011 @p_l4
diff --git a/target/riscv/tcg/insn_trans/trans_rvp.c.inc b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
index 6c344a66dc8..4d5fc230d2e 100644
--- a/target/riscv/tcg/insn_trans/trans_rvp.c.inc
+++ b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
@@ -902,3 +902,27 @@ GEN_SIMD_TRANS_ACC_64(pm4adda_h)
 GEN_SIMD_TRANS_ACC_64(pm4addasu_h)
 GEN_SIMD_TRANS_ACC_64(pm4addau_h)
 
+#define GEN_PLI(NAME, PRE_REQ, IMM_TYPE, LIMIT, SHIFT, ADDEND) \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a)    \
+{                                                              \
+    PRE_REQ                                                    \
+    REQUIRE_RVP(ctx);                                          \
+    int i = 1;                                                 \
+    IMM_TYPE imm = a->imm;                                     \
+    while (i < (LIMIT)) {                                      \
+        imm = (imm << (SHIFT)) + (ADDEND);                     \
+        i++;                                                   \
+    }                                                          \
+    gen_set_gpri(ctx, a->rd, imm);                             \
+    return true;                                               \
+}
+
+GEN_PLI(pli_b, , target_long, TARGET_LONG_SIZE, 8, a->imm)
+GEN_PLI(pli_h, , target_long, TARGET_LONG_SIZE / 2, 16,
+        a->imm & 0xFFFF)
+GEN_PLI(plui_h, , target_long, TARGET_LONG_SIZE / 2, 16,
+        a->imm & 0xFFFF)
+GEN_PLI(pli_w, REQUIRE_64BIT(ctx); , int64_t, TARGET_LONG_SIZE / 4, 32,
+        a->imm & 0xFFFFFFFF)
+GEN_PLI(plui_w, REQUIRE_64BIT(ctx); , int64_t, TARGET_LONG_SIZE / 4, 32,
+        a->imm & 0xFFFFFFFF)
diff --git a/target/riscv/tcg/translate.c b/target/riscv/tcg/translate.c
index 0df9d4190f1..668ec3120af 100644
--- a/target/riscv/tcg/translate.c
+++ b/target/riscv/tcg/translate.c
@@ -790,7 +790,9 @@ EX_SH(1)
 EX_SH(2)
 EX_SH(3)
 EX_SH(4)
+EX_SH(6)
 EX_SH(12)
+EX_SH(22)
 
 #define REQUIRE_EXT(ctx, ext) do { \
     if (!has_ext(ctx, ext)) {      \
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH v2 17/18] target/riscv: Add packed SIMD RV32 only instructions
  2026-07-17 10:06 [PATCH v2 00/18] target/riscv: Add support for RISC-V P Molly Chen
                   ` (15 preceding siblings ...)
  2026-07-17 10:07 ` [PATCH v2 16/18] target/riscv: Add packed SIMD load-replicate instructions Molly Chen
@ 2026-07-17 10:07 ` Molly Chen
  2026-07-17 10:07 ` [PATCH v2 18/18] target/riscv: Remove Zbkb dependency from P extension to align with the spec Molly Chen
                   ` (2 subsequent siblings)
  19 siblings, 0 replies; 34+ messages in thread
From: Molly Chen @ 2026-07-17 10:07 UTC (permalink / raw)
  To: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
	chao.liu.zevorn, Chao Liu
  Cc: xiaoou, qemu-riscv, qemu-devel

Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
---
 target/riscv/helper.h                       | 131 ++++++
 target/riscv/insn32.decode                  | 285 +++++++++++-
 target/riscv/tcg/insn_trans/trans_rvp.c.inc | 461 ++++++++++++++++++++
 target/riscv/tcg/psimd_helper.c             | 273 ++++++++++++
 4 files changed, 1149 insertions(+), 1 deletion(-)

diff --git a/target/riscv/helper.h b/target/riscv/helper.h
index fb95a9f71b5..78e6f17be82 100644
--- a/target/riscv/helper.h
+++ b/target/riscv/helper.h
@@ -1756,3 +1756,134 @@ DEF_HELPER_3(pm4addu_h, i64, env, i64, i64)
 DEF_HELPER_4(pm4adda_h, i64, env, i64, i64, i64)
 DEF_HELPER_4(pm4addasu_h, i64, env, i64, i64, i64)
 DEF_HELPER_4(pm4addau_h, i64, env, i64, i64, i64)
+
+/* Packed SIMD - Double-Width Operations (RV32 only, register pairs) */
+DEF_HELPER_3(pwadd_b, i64, env, i32, i32)
+DEF_HELPER_4(pwadda_b, i64, env, i32, i32, i64)
+DEF_HELPER_3(pwaddu_b, i64, env, i32, i32)
+DEF_HELPER_4(pwaddau_b, i64, env, i32, i32, i64)
+DEF_HELPER_3(pwsub_b, i64, env, i32, i32)
+DEF_HELPER_4(pwsuba_b, i64, env, i32, i32, i64)
+DEF_HELPER_3(pwsubu_b, i64, env, i32, i32)
+DEF_HELPER_4(pwsubau_b, i64, env, i32, i32, i64)
+DEF_HELPER_3(pwslli_b, i64, env, i32, i32)
+DEF_HELPER_3(pwsll_bs, i64, env, i32, i32)
+DEF_HELPER_3(pwslai_b, i64, env, i32, i32)
+DEF_HELPER_3(pwsla_bs, i64, env, i32, i32)
+
+DEF_HELPER_3(pwadd_h, i64, env, i32, i32)
+DEF_HELPER_4(pwadda_h, i64, env, i32, i32, i64)
+DEF_HELPER_3(pwaddu_h, i64, env, i32, i32)
+DEF_HELPER_4(pwaddau_h, i64, env, i32, i32, i64)
+DEF_HELPER_3(pwsub_h, i64, env, i32, i32)
+DEF_HELPER_4(pwsuba_h, i64, env, i32, i32, i64)
+DEF_HELPER_3(pwsubu_h, i64, env, i32, i32)
+DEF_HELPER_4(pwsubau_h, i64, env, i32, i32, i64)
+DEF_HELPER_3(pwslli_h, i64, env, i32, i32)
+DEF_HELPER_3(pwsll_hs, i64, env, i32, i32)
+DEF_HELPER_3(pwslai_h, i64, env, i32, i32)
+DEF_HELPER_3(pwsla_hs, i64, env, i32, i32)
+
+DEF_HELPER_3(wadd, i64, env, i32, i32)
+DEF_HELPER_4(wadda, i64, env, i32, i32, i64)
+DEF_HELPER_3(waddu, i64, env, i32, i32)
+DEF_HELPER_4(waddau, i64, env, i32, i32, i64)
+DEF_HELPER_3(wsub, i64, env, i32, i32)
+DEF_HELPER_4(wsuba, i64, env, i32, i32, i64)
+DEF_HELPER_3(wsubu, i64, env, i32, i32)
+DEF_HELPER_4(wsubau, i64, env, i32, i32, i64)
+DEF_HELPER_3(wslli, i64, env, i32, i32)
+DEF_HELPER_3(wsll, i64, env, i32, i32)
+DEF_HELPER_3(wslai, i64, env, i32, i32)
+DEF_HELPER_3(wsla, i64, env, i32, i32)
+
+DEF_HELPER_3(wzip8p, i64, env, i32, i32)
+DEF_HELPER_3(wzip16p, i64, env, i32, i32)
+
+DEF_HELPER_4(predsum_dbs, i32, env, i32, i32, i32)
+DEF_HELPER_4(predsumu_dbs, i32, env, i32, i32, i32)
+DEF_HELPER_4(predsum_dhs, i32, env, i32, i32, i32)
+DEF_HELPER_4(predsumu_dhs, i32, env, i32, i32, i32)
+
+DEF_HELPER_3(pnsrli_b, i32, env, i64, i32)
+DEF_HELPER_3(pnsrai_b, i32, env, i64, i32)
+DEF_HELPER_3(pnsrari_b, i32, env, i64, i32)
+DEF_HELPER_3(pnclipi_b, i32, env, i64, i32)
+DEF_HELPER_3(pnclipri_b, i32, env, i64, i32)
+DEF_HELPER_3(pnclipiu_b, i32, env, i64, i32)
+DEF_HELPER_3(pnclipriu_b, i32, env, i64, i32)
+DEF_HELPER_3(pnsrl_bs, i32, env, i64, i32)
+DEF_HELPER_3(pnsra_bs, i32, env, i64, i32)
+DEF_HELPER_3(pnsrar_bs, i32, env, i64, i32)
+DEF_HELPER_3(pnclip_bs, i32, env, i64, i32)
+DEF_HELPER_3(pnclipr_bs, i32, env, i64, i32)
+DEF_HELPER_3(pnclipu_bs, i32, env, i64, i32)
+DEF_HELPER_3(pnclipru_bs, i32, env, i64, i32)
+
+DEF_HELPER_3(pnsrli_h, i32, env, i64, i32)
+DEF_HELPER_3(pnsrai_h, i32, env, i64, i32)
+DEF_HELPER_3(pnsrari_h, i32, env, i64, i32)
+DEF_HELPER_3(pnclipi_h, i32, env, i64, i32)
+DEF_HELPER_3(pnclipri_h, i32, env, i64, i32)
+DEF_HELPER_3(pnclipiu_h, i32, env, i64, i32)
+DEF_HELPER_3(pnclipriu_h, i32, env, i64, i32)
+DEF_HELPER_3(pnsrl_hs, i32, env, i64, i32)
+DEF_HELPER_3(pnsra_hs, i32, env, i64, i32)
+DEF_HELPER_3(pnsrar_hs, i32, env, i64, i32)
+DEF_HELPER_3(pnclip_hs, i32, env, i64, i32)
+DEF_HELPER_3(pnclipr_hs, i32, env, i64, i32)
+DEF_HELPER_3(pnclipu_hs, i32, env, i64, i32)
+DEF_HELPER_3(pnclipru_hs, i32, env, i64, i32)
+
+DEF_HELPER_3(nsrli, i32, env, i64, i32)
+DEF_HELPER_3(nsrai, i32, env, i64, i32)
+DEF_HELPER_3(nsrari, i32, env, i64, i32)
+DEF_HELPER_3(nclipi, i32, env, i64, i32)
+DEF_HELPER_3(nclipri, i32, env, i64, i32)
+DEF_HELPER_3(nclipiu, i32, env, i64, i32)
+DEF_HELPER_3(nclipriu, i32, env, i64, i32)
+DEF_HELPER_3(nsrl, i32, env, i64, i32)
+DEF_HELPER_3(nsra, i32, env, i64, i32)
+DEF_HELPER_3(nsrar, i32, env, i64, i32)
+DEF_HELPER_3(nclip, i32, env, i64, i32)
+DEF_HELPER_3(nclipr, i32, env, i64, i32)
+DEF_HELPER_3(nclipu, i32, env, i64, i32)
+DEF_HELPER_3(nclipru, i32, env, i64, i32)
+
+DEF_HELPER_4(pmqwacc_h, i64, env, i32, i32, i64)
+DEF_HELPER_4(pmqrwacc_h, i64, env, i32, i32, i64)
+DEF_HELPER_4(mqwacc, i64, env, i32, i32, i64)
+DEF_HELPER_4(mqrwacc, i64, env, i32, i32, i64)
+
+DEF_HELPER_3(pwmul_b, i64, env, i32, i32)
+DEF_HELPER_3(pwmulsu_b, i64, env, i32, i32)
+DEF_HELPER_3(pwmulu_b, i64, env, i32, i32)
+DEF_HELPER_3(pwmul_h, i64, env, i32, i32)
+DEF_HELPER_3(pwmulsu_h, i64, env, i32, i32)
+DEF_HELPER_3(pwmulu_h, i64, env, i32, i32)
+
+DEF_HELPER_4(pwmacc_h, i64, env, i32, i32, i64)
+DEF_HELPER_4(pwmaccsu_h, i64, env, i32, i32, i64)
+DEF_HELPER_4(pwmaccu_h, i64, env, i32, i32, i64)
+
+DEF_HELPER_3(wmul, i64, env, i32, i32)
+DEF_HELPER_3(wmulsu, i64, env, i32, i32)
+DEF_HELPER_3(wmulu, i64, env, i32, i32)
+
+DEF_HELPER_4(wmacc, i64, env, i32, i32, i64)
+DEF_HELPER_4(wmaccsu, i64, env, i32, i32, i64)
+DEF_HELPER_4(wmaccu, i64, env, i32, i32, i64)
+
+DEF_HELPER_3(pm2wadd_h, i64, env, i32, i32)
+DEF_HELPER_3(pm2waddsu_h, i64, env, i32, i32)
+DEF_HELPER_3(pm2waddu_h, i64, env, i32, i32)
+DEF_HELPER_3(pm2wadd_hx, i64, env, i32, i32)
+DEF_HELPER_4(pm2wadda_h, i64, env, i32, i32, i64)
+DEF_HELPER_4(pm2waddasu_h, i64, env, i32, i32, i64)
+DEF_HELPER_4(pm2waddau_h, i64, env, i32, i32, i64)
+DEF_HELPER_4(pm2wadda_hx, i64, env, i32, i32, i64)
+
+DEF_HELPER_3(pm2wsub_h, i64, env, i32, i32)
+DEF_HELPER_3(pm2wsub_hx, i64, env, i32, i32)
+DEF_HELPER_4(pm2wsuba_h, i64, env, i32, i32, i64)
+DEF_HELPER_4(pm2wsuba_hx, i64, env, i32, i32, i64)
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index 403e17e439d..a477b812fd6 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -23,6 +23,9 @@
 %rd        7:5
 %sh5       20:5
 %sh6       20:6
+%rs2_p     21:4
+%rs1_p     16:4
+%rd_p      8:4
 
 %sh7    20:7
 %csr    20:12
@@ -57,7 +60,6 @@
 &r    rd rs1 rs2
 &r2   rd rs1
 &r2_s rs1 rs2
-&p_l  imm rd
 &s    imm rs1 rs2
 &u    imm rd
 &shift     shamt rs1 rd
@@ -69,6 +71,7 @@
 &k_aes     shamt rs2 rs1 rd
 &mop5 imm rd rs1
 &mop3 imm rd rs1 rs2
+&p_l  imm rd
 &p_ui imm rs1 rd
 
 # Formats 32:
@@ -102,6 +105,11 @@
 @r2_zimm11 . zimm:11  ..... ... ..... ....... %rs1 %rd
 @r2_zimm10 .. zimm:10  ..... ... ..... ....... %rs1 %rd
 @r2_s    .......   ..... ..... ... ..... ....... %rs2 %rs1
+@r_p_1       .......   ..... ..... ... ..... ....... &r    %rs2 %rs1 rd=%rd_p
+@r_p_2     .......   ..... ..... ... ..... ....... &r    rs2=%rs2_p rs1=%rs1_p rd=%rd_p
+@r_p_3     .......   ..... ..... ... ..... ....... &r    %rs2 rs1=%rs1_p rd=%rd_p
+@r_p_4     .......   ..... ..... ... ..... ....... &r    %rs2 rs1=%rs1_p %rd
+@r2_p      .......   ..... ..... ... ..... ....... &r2   rs1=%rs1_p rd=%rd_p
 
 @hfence_gvma ....... ..... .....   ... ..... ....... %rs2 %rs1
 @hfence_vvma ....... ..... .....   ... ..... ....... %rs2 %rs1
@@ -123,6 +131,18 @@
 @p_l2  ....... .......... ... ..... ....... &p_l      imm=%imm_p_l2         %rd
 @p_l3  ....... .......... ... ..... ....... &p_l      imm=%imm_p_l3         %rd
 @p_l4  ....... .......... ... ..... ....... &p_l      imm=%imm_p_l4         %rd
+@p_l1_p  ........ ........ .... ..... ....... &p_l    imm=%imm_p_l1         rd=%rd_p
+@p_l2_p  ........ ........ .... ..... ....... &p_l    imm=%imm_p_l2         rd=%rd_p
+@p_l3_p  ....... .......... ... ..... ....... &p_l    imm=%imm_p_l3         rd=%rd_p
+@p_ui8_p ..... .... ... ..... ... ..... .......  &i imm=%imm_p_ui8 rs1=%rs1_p rd=%rd_p
+@p_ui16_p ..... .... ... ..... ... ..... ....... &p_ui imm=%imm_p_ui16 %rs1 rd=%rd_p
+@p_ui16_p_2 ..... .... ... ..... ... ..... ....... &p_ui imm=%imm_p_ui16 rs1=%rs1_p rd=%rd_p
+@p_ui16_p_3 ..... .... ... .... .... ..... ....... &p_ui imm=%imm_p_ui16 rs1=%rs1_p %rd
+@p_ui32_p ..... .... ... ..... ... ..... ....... &p_ui imm=%imm_p_ui32 %rs1 rd=%rd_p
+@p_ui32_p_2 ..... .... ... ..... ... ..... ....... &p_ui imm=%imm_p_ui32 rs1=%rs1_p rd=%rd_p
+@p_ui32_p_3 ..... .... ... ..... ... ..... ....... &p_ui imm=%imm_p_ui32 rs1=%rs1_p %rd
+@p_ui64_p ..... .... ... ..... ... ..... ....... &p_ui imm=%imm_p_ui64 %rs1 rd=%rd_p
+@p_ui64_p_2 ..... .... ... ..... ... ..... ....... &p_ui imm=%imm_p_ui64 rs1=%rs1_p %rd
 
 # Formats 64:
 @sh5     .......  ..... .....  ... ..... ....... &shift  shamt=%sh5      %rs1 %rd
@@ -1630,3 +1650,266 @@ pli_h    1011000 .......... 010 ..... 0011011 @p_l2
 plui_h   1111000 .......... 010 ..... 0011011 @p_l3
 pli_w    1011001 ..... ..... 010 ..... 0011011 @p_l2
 plui_w   1111001 ..... ..... 010 ..... 0011011 @p_l4
+
+# Packed SIMD - Double-Width Operations (RV32 only, register pairs)
+# register-pair destination
+pwadd_b    0000010 ..... ..... 010 .... 10011011 @r_p_1
+pwadda_b   0000110 ..... ..... 010 .... 10011011 @r_p_1
+pwaddu_b   0001010 ..... ..... 010 .... 10011011 @r_p_1
+pwaddau_b  0001110 ..... ..... 010 .... 10011011 @r_p_1
+pwsub_b    0100010 ..... ..... 010 .... 10011011 @r_p_1
+pwsuba_b   0100110 ..... ..... 010 .... 10011011 @r_p_1
+pwsubu_b   0101010 ..... ..... 010 .... 10011011 @r_p_1
+pwsubau_b  0101110 ..... ..... 010 .... 10011011 @r_p_1
+pwslli_b   00000 001.... ..... 010 .... 00011011 @p_ui16_p
+pwsll_bs   0000100 ..... ..... 010 .... 00011011 @r_p_1
+pwslai_b   01000 001.... ..... 010 .... 00011011 @p_ui16_p
+pwsla_bs   0100100 ..... ..... 010 .... 00011011 @r_p_1
+
+pwadd_h    0000000 ..... ..... 010 .... 10011011 @r_p_1
+pwadda_h   0000100 ..... ..... 010 .... 10011011 @r_p_1
+pwaddu_h   0001000 ..... ..... 010 .... 10011011 @r_p_1
+pwaddau_h  0001100 ..... ..... 010 .... 10011011 @r_p_1
+pwsub_h    0100000 ..... ..... 010 .... 10011011 @r_p_1
+pwsuba_h   0100100 ..... ..... 010 .... 10011011 @r_p_1
+pwsubu_h   0101000 ..... ..... 010 .... 10011011 @r_p_1
+pwsubau_h  0101100 ..... ..... 010 .... 10011011 @r_p_1
+pwslli_h   00000 01..... ..... 010 .... 00011011 @p_ui32_p
+pwsll_hs   0000101 ..... ..... 010 .... 00011011 @r_p_1
+pwslai_h   01000 01..... ..... 010 .... 00011011 @p_ui32_p
+pwsla_hs   0100101 ..... ..... 010 .... 00011011 @r_p_1
+
+wadd    0000001 ..... ..... 010 .... 10011011 @r_p_1
+wadda   0000101 ..... ..... 010 .... 10011011 @r_p_1
+waddu   0001001 ..... ..... 010 .... 10011011 @r_p_1
+waddau  0001101 ..... ..... 010 .... 10011011 @r_p_1
+wsub    0100001 ..... ..... 010 .... 10011011 @r_p_1
+wsuba   0100101 ..... ..... 010 .... 10011011 @r_p_1
+wsubu   0101001 ..... ..... 010 .... 10011011 @r_p_1
+wsubau  0101101 ..... ..... 010 .... 10011011 @r_p_1
+wslli   00000 1...... ..... 010 .... 00011011 @p_ui64_p
+wsll    0000111 ..... ..... 010 .... 00011011 @r_p_1
+wslai   01000 1...... ..... 010 .... 00011011 @p_ui64_p
+wsla    0100111 ..... ..... 010 .... 00011011 @r_p_1
+
+wzip8p    0111100 ..... ..... 010 .... 00011011 @r_p_1
+wzip16p   0111101 ..... ..... 010 .... 00011011 @r_p_1
+
+#register-pair operands
+pli_db    00110100 ........ 0010 .... 00011011 @p_l1_p
+padd_db   1000010 .... 0 .... 0110 .... 00011011 @r_p_2
+psub_db   1100010 .... 0 .... 0110 .... 00011011 @r_p_2
+psadd_db  1001010 .... 0 .... 0110 .... 00011011 @r_p_2
+psaddu_db    1011010 .... 0 .... 0110 .... 00011011 @r_p_2
+pssub_db     1101010 .... 0 .... 0110 .... 00011011 @r_p_2
+pssubu_db    1111010 .... 0 .... 0110 .... 00011011 @r_p_2
+paadd_db     1001110 .... 0 .... 0110 .... 00011011 @r_p_2
+paaddu_db    1011110 .... 0 .... 0110 .... 00011011 @r_p_2
+pasub_db     1101110 .... 0 .... 0110 .... 00011011 @r_p_2
+pasubu_db    1111110 .... 0 .... 0110 .... 00011011 @r_p_2
+pabd_db      1100110 .... 0 .... 0110 .... 00011011 @r_p_2
+pabdu_db     1110110 .... 0 .... 0110 .... 00011011 @r_p_2
+psabs_db     0110010 00111 .... 0110 .... 00011011 @r2_p
+pli_dh    0011000 .......... 010 .... 00011011 @p_l2_p
+plui_dh   0111000 .......... 010 .... 00011011 @p_l3_p
+padd_dh   1000000 .... 0 .... 0110 .... 00011011 @r_p_2
+psub_dh   1100000 .... 0 .... 0110 .... 00011011 @r_p_2
+psadd_dh  1001000 .... 0 .... 0110 .... 00011011 @r_p_2
+psaddu_dh 1011000 .... 0 .... 0110 .... 00011011 @r_p_2
+pssub_dh  1101000 .... 0 .... 0110 .... 00011011 @r_p_2
+pssubu_dh 1111000 .... 0 .... 0110 .... 00011011 @r_p_2
+paadd_dh  1001100 .... 0 .... 0110 .... 00011011 @r_p_2
+paaddu_dh 1011100 .... 0 .... 0110 .... 00011011 @r_p_2
+pasub_dh  1101100 .... 0 .... 0110 .... 00011011 @r_p_2
+pasubu_dh    1111100 .... 0 .... 0110 .... 00011011 @r_p_2
+psh1add_dh   1010000 .... 1 .... 0110 .... 00011011 @r_p_2
+pssh1sadd_dh 1011000 .... 1 .... 0110 .... 00011011 @r_p_2
+pas_dhx    1000000 .... 1 .... 1110 .... 00011011 @r_p_2
+psa_dhx    1000010 .... 1 .... 1110 .... 00011011 @r_p_2
+psas_dhx   1001000 .... 1 .... 1110 .... 00011011 @r_p_2
+pssa_dhx   1001010 .... 1 .... 1110 .... 00011011 @r_p_2
+paas_dhx   1001100 .... 1 .... 1110 .... 00011011 @r_p_2
+pasa_dhx   1001110 .... 1 .... 1110 .... 00011011 @r_p_2
+pabd_dh    1100100 .... 0 .... 0110 .... 00011011 @r_p_2
+pabdu_dh   1110100 .... 0 .... 0110 .... 00011011 @r_p_2
+psabs_dh   0110000 00111 .... 0110 .... 00011011 @r2_p
+padd_dw    1000001 .... 0 .... 0110 .... 00011011 @r_p_2
+psub_dw    1100001 .... 0 .... 0110 .... 00011011 @r_p_2
+psadd_dw   1001001 .... 0 .... 0110 .... 00011011 @r_p_2
+psaddu_dw  1011001 .... 0 .... 0110 .... 00011011 @r_p_2
+pssub_dw   1101001 .... 0 .... 0110 .... 00011011 @r_p_2
+pssubu_dw  1111001 .... 0 .... 0110 .... 00011011 @r_p_2
+paadd_dw   1001101 .... 0 .... 0110 .... 00011011 @r_p_2
+paaddu_dw  1011101 .... 0 .... 0110 .... 00011011 @r_p_2
+pasub_dw   1101101 .... 0 .... 0110 .... 00011011 @r_p_2
+pasubu_dw  1111101 .... 0 .... 0110 .... 00011011 @r_p_2
+psh1add_dw 1010001 .... 1 .... 0110 .... 00011011 @r_p_2
+pssh1sadd_dw  1011001 .... 1 .... 0110 .... 00011011 @r_p_2
+addd_p    1000011 .... 0 .... 0110 .... 00011011 @r_p_2
+subd_p    1100011 .... 0 .... 0110 .... 00011011 @r_p_2
+
+# register-pair first source only
+predsum_dbs    0001110 ..... .... 0100 ..... 0011011 @r_p_4
+predsumu_dbs   0011110 ..... .... 0100 ..... 0011011 @r_p_4
+predsum_dhs    0001100 ..... .... 0100 ..... 0011011 @r_p_4
+predsumu_dhs   0011100 ..... .... 0100 ..... 0011011 @r_p_4
+
+# register-pair operands
+pslli_db    00000 0001... .... 0110 .... 00011011 @p_ui8_p
+psrli_db    00000 0001... .... 1110 .... 00011011 @p_ui8_p
+psrai_db    01000 0001... .... 1110 .... 00011011 @p_ui8_p
+pmin_db     1110010 .... 1 .... 1110 .... 00011011 @r_p_2
+pminu_db    1110110 .... 1 .... 1110 .... 00011011 @r_p_2
+pmax_db     1111010 .... 1 .... 1110 .... 00011011 @r_p_2
+pmaxu_db    1111110 .... 1 .... 1110 .... 00011011 @r_p_2
+pmseq_db    1100010 .... 1 .... 1110 .... 00011011 @r_p_2
+pmslt_db    1101010 .... 1 .... 1110 .... 00011011 @r_p_2
+pmsltu_db   1101110 .... 1 .... 1110 .... 00011011 @r_p_2
+psext_dh_b  0110000 00100 .... 0110 .... 00011011 @r2_p
+psati_dh    01100 001.... .... 1110 .... 00011011 @p_ui16_p_2
+pusati_dh   00100 001.... .... 1110 .... 00011011 @p_ui16_p_2
+pslli_dh    00000 001.... .... 0110 .... 00011011 @p_ui16_p_2
+psrli_dh    00000 001.... .... 1110 .... 00011011 @p_ui16_p_2
+psrai_dh    01000 001.... .... 1110 .... 00011011 @p_ui16_p_2
+psslai_dh   01010 001.... .... 0110 .... 00011011 @p_ui16_p_2
+psrari_dh   01010 001.... .... 1110 .... 00011011 @p_ui16_p_2
+pmin_dh     1110000 .... 1 .... 1110 .... 00011011 @r_p_2
+pminu_dh    1110100 .... 1 .... 1110 .... 00011011 @r_p_2
+pmax_dh     1111000 .... 1 .... 1110 .... 00011011 @r_p_2
+pmaxu_dh    1111100 .... 1 .... 1110 .... 00011011 @r_p_2
+pmseq_dh    1100000 .... 1 .... 1110 .... 00011011 @r_p_2
+pmslt_dh    1101000 .... 1 .... 1110 .... 00011011 @r_p_2
+pmsltu_dh   1101100 .... 1 .... 1110 .... 00011011 @r_p_2
+psext_dw_b  0110001 00100 .... 0110 .... 00011011 @r2_p
+psext_dw_h  0110001 00101 .... 0110 .... 00011011 @r2_p
+psati_dw    01100 01..... .... 1110 .... 00011011 @p_ui32_p_2
+pusati_dw   00100 01..... .... 1110 .... 00011011 @p_ui32_p_2
+pslli_dw    00000 01..... .... 0110 .... 00011011 @p_ui32_p_2
+psrli_dw    00000 01..... .... 1110 .... 00011011 @p_ui32_p_2
+psrai_dw    01000 01..... .... 1110 .... 00011011 @p_ui32_p_2
+psslai_dw   01010 01..... .... 0110 .... 00011011 @p_ui32_p_2
+psrari_dw   01010 01..... .... 1110 .... 00011011 @p_ui32_p_2
+pmin_dw    1110001 .... 1 .... 1110 .... 00011011 @r_p_2
+pminu_dw   1110101 .... 1 .... 1110 .... 00011011 @r_p_2
+pmax_dw    1111001 .... 1 .... 1110 .... 00011011 @r_p_2
+pmaxu_dw   1111101 .... 1 .... 1110 .... 00011011 @r_p_2
+pmseq_dw    1100001 .... 1 .... 1110 .... 00011011 @r_p_2
+pmslt_dw    1101001 .... 1 .... 1110 .... 00011011 @r_p_2
+pmsltu_dw   1101101 .... 1 .... 1110 .... 00011011 @r_p_2
+
+# register-pair first source and dest
+padd_dbs    0001110 ..... .... 0110 .... 00011011 @r_p_3
+psll_dbs    0000110 ..... .... 0110 .... 00011011 @r_p_3
+psrl_dbs    0000110 ..... .... 1110 .... 00011011 @r_p_3
+psra_dbs    0100110 ..... .... 1110 .... 00011011 @r_p_3
+padd_dhs    0001100 ..... .... 0110 .... 00011011 @r_p_3
+psll_dhs    0000100 ..... .... 0110 .... 00011011 @r_p_3
+psrl_dhs    0000100 ..... .... 1110 .... 00011011 @r_p_3
+psra_dhs    0100100 ..... .... 1110 .... 00011011 @r_p_3
+pssha_dhs   0110100 ..... .... 0110 .... 00011011 @r_p_3
+psshar_dhs  0111100 ..... .... 0110 .... 00011011 @r_p_3
+psshl_dhs   0010100 ..... .... 0110 .... 00011011 @r_p_3
+psshlr_dhs  0011100 ..... .... 0110 .... 00011011 @r_p_3
+padd_dws    0001101 ..... .... 0110 .... 00011011 @r_p_3
+psll_dws    0000101 ..... .... 0110 .... 00011011 @r_p_3
+psrl_dws    0000101 ..... .... 1110 .... 00011011 @r_p_3
+psra_dws    0100101 ..... .... 1110 .... 00011011 @r_p_3
+pssha_dws   0110101 ..... .... 0110 .... 00011011 @r_p_3
+psshar_dws  0111101 ..... .... 0110 .... 00011011 @r_p_3
+psshl_dws   0010101 ..... .... 0110 .... 00011011 @r_p_3
+psshlr_dws  0011101 ..... .... 0110 .... 00011011 @r_p_3
+
+# register-pair operands
+ppaire_db    1000000 .... 0 .... 1110 .... 00011011 @r_p_2
+ppaireo_db  1001000 .... 0 .... 1110 .... 00011011 @r_p_2
+ppairoe_db  1010000 .... 0 .... 1110 .... 00011011 @r_p_2
+ppairo_db   1011000 .... 0 .... 1110 .... 00011011 @r_p_2
+ppaire_dh    1000001 .... 0 .... 1110 .... 00011011 @r_p_2
+ppaireo_dh  1001001 .... 0 .... 1110 .... 00011011 @r_p_2
+ppairoe_dh  1010001 .... 0 .... 1110 .... 00011011 @r_p_2
+ppairo_dh   1011001 .... 0 .... 1110 .... 00011011 @r_p_2
+
+#register-pair first source only
+pnsrli_b    00000 001.... .... 1100 ..... 0011011 @p_ui16_p_3
+pnsrai_b    01000 001.... .... 1100 ..... 0011011 @p_ui16_p_3
+pnsrari_b   01010 001.... .... 1100 ..... 0011011 @p_ui16_p_3
+pnclipi_b   01100 001.... .... 1100 ..... 0011011 @p_ui16_p_3
+pnclipri_b  01110 001.... .... 1100 ..... 0011011 @p_ui16_p_3
+pnclipiu_b  00100 001.... .... 1100 ..... 0011011 @p_ui16_p_3
+pnclipriu_b 00110 001.... .... 1100 ..... 0011011 @p_ui16_p_3
+pnsrl_bs    00001 00 ..... .... 1100 ..... 0011011 @r_p_4
+pnsra_bs    01001 00 ..... .... 1100 ..... 0011011 @r_p_4
+pnsrar_bs   01011 00 ..... .... 1100 ..... 0011011 @r_p_4
+pnclip_bs   01101 00 ..... .... 1100 ..... 0011011 @r_p_4
+pnclipr_bs  01111 00 ..... .... 1100 ..... 0011011 @r_p_4
+pnclipu_bs  00101 00 ..... .... 1100 ..... 0011011 @r_p_4
+pnclipru_bs 00111 00 ..... .... 1100 ..... 0011011 @r_p_4
+
+pnsrli_h    00000 01..... .... 1100 ..... 0011011 @p_ui32_p_3
+pnsrai_h    01000 01..... .... 1100 ..... 0011011 @p_ui32_p_3
+pnsrari_h   01010 01..... .... 1100 ..... 0011011 @p_ui32_p_3
+pnclipi_h   01100 01..... .... 1100 ..... 0011011 @p_ui32_p_3
+pnclipri_h  01110 01..... .... 1100 ..... 0011011 @p_ui32_p_3
+pnclipiu_h  00100 01..... .... 1100 ..... 0011011 @p_ui32_p_3
+pnclipriu_h 00110 01..... .... 1100 ..... 0011011 @p_ui32_p_3
+pnsrl_hs    00001 01 ..... .... 1100 ..... 0011011 @r_p_4
+pnsra_hs    01001 01 ..... .... 1100 ..... 0011011 @r_p_4
+pnsrar_hs   01011 01 ..... .... 1100 ..... 0011011 @r_p_4
+pnclip_hs   01101 01 ..... .... 1100 ..... 0011011 @r_p_4
+pnclipr_hs  01111 01 ..... .... 1100 ..... 0011011 @r_p_4
+pnclipu_hs  00101 01 ..... .... 1100 ..... 0011011 @r_p_4
+pnclipru_hs 00111 01 ..... .... 1100 ..... 0011011 @r_p_4
+
+nsrli       00000 1...... .... 1100 ..... 0011011 @p_ui64_p_2
+nsrai       01000 1...... .... 1100 ..... 0011011 @p_ui64_p_2
+nsrari      01010 1...... .... 1100 ..... 0011011 @p_ui64_p_2
+nclipi      01100 1...... .... 1100 ..... 0011011 @p_ui64_p_2
+nclipri     01110 1...... .... 1100 ..... 0011011 @p_ui64_p_2
+nclipiu     00100 1...... .... 1100 ..... 0011011 @p_ui64_p_2
+nclipriu    00110 1...... .... 1100 ..... 0011011 @p_ui64_p_2
+nsrl        00001 11 ..... .... 1100 ..... 0011011 @r_p_4
+nsra        01001 11 ..... .... 1100 ..... 0011011 @r_p_4
+nsrar       01011 11 ..... .... 1100 ..... 0011011 @r_p_4
+nclip       01101 11 ..... .... 1100 ..... 0011011 @r_p_4
+nclipr      01111 11 ..... .... 1100 ..... 0011011 @r_p_4
+nclipu      00101 11 ..... .... 1100 ..... 0011011 @r_p_4
+nclipru     00111 11 ..... .... 1100 ..... 0011011 @r_p_4
+
+# register-pair multiply
+pmqwacc_h       01111 00 ..... ..... 010 .... 10011011 @r_p_1
+pmqrwacc_h      01111 10 ..... ..... 010 .... 10011011 @r_p_1
+mqwacc          01111 01 ..... ..... 010 .... 10011011 @r_p_1
+mqrwacc         01111 11 ..... ..... 010 .... 10011011 @r_p_1
+
+pwmul_b         00100 10 ..... ..... 010 .... 10011011 @r_p_1
+pwmulsu_b       01100 10 ..... ..... 010 .... 10011011 @r_p_1
+pwmulu_b        00110 10 ..... ..... 010 .... 10011011 @r_p_1
+
+pwmul_h         00100 00 ..... ..... 010 .... 10011011 @r_p_1
+pwmulsu_h       01100 00 ..... ..... 010 .... 10011011 @r_p_1
+pwmulu_h        00110 00 ..... ..... 010 .... 10011011 @r_p_1
+pwmacc_h        00101 00 ..... ..... 010 .... 10011011 @r_p_1
+pwmaccsu_h      01101 00 ..... ..... 010 .... 10011011 @r_p_1
+pwmaccu_h       00111 00 ..... ..... 010 .... 10011011 @r_p_1
+
+wmul            00100 01 ..... ..... 010 .... 10011011 @r_p_1
+wmulsu          01100 01 ..... ..... 010 .... 10011011 @r_p_1
+wmulu           00110 01 ..... ..... 010 .... 10011011 @r_p_1
+wmacc           00101 01 ..... ..... 010 .... 10011011 @r_p_1
+wmaccsu         01101 01 ..... ..... 010 .... 10011011 @r_p_1
+wmaccu          00111 01 ..... ..... 010 .... 10011011 @r_p_1
+
+pm2wadd_h       00000 11 ..... ..... 010 .... 10011011 @r_p_1
+pm2waddsu_h     01100 11 ..... ..... 010 .... 10011011 @r_p_1
+pm2waddu_h      00100 11 ..... ..... 010 .... 10011011 @r_p_1
+pm2wadd_hx      00010 11 ..... ..... 010 .... 10011011 @r_p_1
+
+pm2wadda_h      00001 11 ..... ..... 010 .... 10011011 @r_p_1
+pm2waddasu_h    01101 11 ..... ..... 010 .... 10011011 @r_p_1
+pm2waddau_h     00101 11 ..... ..... 010 .... 10011011 @r_p_1
+pm2wadda_hx     00011 11 ..... ..... 010 .... 10011011 @r_p_1
+
+pm2wsub_h       01000 11 ..... ..... 010 .... 10011011 @r_p_1
+pm2wsub_hx      01010 11 ..... ..... 010 .... 10011011 @r_p_1
+pm2wsuba_h      01001 11 ..... ..... 010 .... 10011011 @r_p_1
+pm2wsuba_hx     01011 11 ..... ..... 010 .... 10011011 @r_p_1
diff --git a/target/riscv/tcg/insn_trans/trans_rvp.c.inc b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
index 4d5fc230d2e..e33e0ec110a 100644
--- a/target/riscv/tcg/insn_trans/trans_rvp.c.inc
+++ b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
@@ -3,6 +3,36 @@
 /* Copyright (c) 2026 ISRC ISCAS. */
 
 /* Save a 64 bit data in src to dst and dst + 1 */
+static void set_pair_regs(DisasContext *ctx, int dst, TCGv_i64 src)
+{
+#if defined(TARGET_RISCV32)
+    TCGv_i64 tl_64 = tcg_temp_new_i64();
+    TCGv_i64 th_64 = tcg_temp_new_i64();
+    TCGv_i32 tl_32 = tcg_temp_new_i32();
+    TCGv_i32 th_32 = tcg_temp_new_i32();
+    tcg_gen_extract_i64(tl_64, src, 0, 32);
+    tcg_gen_extract_i64(th_64, src, 32, 32);
+    tcg_gen_trunc_i64_tl(tl_32, tl_64);
+    tcg_gen_trunc_i64_tl(th_32, th_64);
+    gen_set_gpr(ctx, dst, tl_32);
+    gen_set_gpr(ctx, dst + 1, th_32);
+# else
+    gen_set_gpr(ctx, dst, src);
+#endif
+}
+
+/* Concat two 32 bit data in src and src + 1 to dst */
+static void get_pair_regs(DisasContext *ctx, TCGv_i64 dst, int src)
+{
+#if defined(TARGET_RISCV32)
+    TCGv t1 = get_gpr(ctx, src, EXT_NONE);
+    TCGv t2 = get_gpr(ctx, src + 1, EXT_NONE);
+    tcg_gen_concat_i32_i64(dst, t1, t2);
+#else
+    TCGv t1 = get_gpr(ctx, src, EXT_NONE);
+    tcg_gen_mov_tl(dst, t1);
+#endif
+}
 
 static bool require_rvp(DisasContext *ctx)
 {
@@ -902,6 +932,241 @@ GEN_SIMD_TRANS_ACC_64(pm4adda_h)
 GEN_SIMD_TRANS_ACC_64(pm4addasu_h)
 GEN_SIMD_TRANS_ACC_64(pm4addau_h)
 
+/* Packed SIMD - Double-Width Operations (RV32 only, register pairs) */
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pwadd_b)
+GEN_SIMD_TRANS_REG_PAIR_ACC(pwadda_b)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pwaddu_b)
+GEN_SIMD_TRANS_REG_PAIR_ACC(pwaddau_b)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pwsub_b)
+GEN_SIMD_TRANS_REG_PAIR_ACC(pwsuba_b)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pwsubu_b)
+GEN_SIMD_TRANS_REG_PAIR_ACC(pwsubau_b)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR_IMM(pwslli_b)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pwsll_bs)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR_IMM(pwslai_b)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pwsla_bs)
+
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pwadd_h)
+GEN_SIMD_TRANS_REG_PAIR_ACC(pwadda_h)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pwaddu_h)
+GEN_SIMD_TRANS_REG_PAIR_ACC(pwaddau_h)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pwsub_h)
+GEN_SIMD_TRANS_REG_PAIR_ACC(pwsuba_h)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pwsubu_h)
+GEN_SIMD_TRANS_REG_PAIR_ACC(pwsubau_h)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR_IMM(pwslli_h)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pwsll_hs)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR_IMM(pwslai_h)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pwsla_hs)
+
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(wadd)
+GEN_SIMD_TRANS_REG_PAIR_ACC(wadda)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(waddu)
+GEN_SIMD_TRANS_REG_PAIR_ACC(waddau)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(wsub)
+GEN_SIMD_TRANS_REG_PAIR_ACC(wsuba)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(wsubu)
+GEN_SIMD_TRANS_REG_PAIR_ACC(wsubau)
+
+GEN_SIMD_TRANS_REG_PAIR_SCALAR_IMM(wslli)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(wsll)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR_IMM(wslai)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(wsla)
+
+GEN_SIMD_TRANS_REG_PAIR_LANE(padd_db, padd_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE(psub_db, psub_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(psadd_db, psadd_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(psaddu_db, psaddu_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(pssub_db, pssub_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(pssubu_db, pssubu_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE(paadd_db, paadd_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE(paaddu_db, paaddu_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pasub_db, pasub_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pasubu_db, pasubu_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pabd_db, pabd_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pabdu_db, pabdu_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_VXSAT(psabs_db, psabs_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE(padd_dh, padd_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE(psub_dh, psub_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(psadd_dh, psadd_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(psaddu_dh, psaddu_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(pssub_dh, pssub_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(pssubu_dh, pssubu_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE(paadd_dh, paadd_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE(paaddu_dh, paaddu_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pasub_dh, pasub_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pasubu_dh, pasubu_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE(psh1add_dh, psh1add_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(pssh1sadd_dh, pssh1sadd_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pas_dhx, pas_hx)
+GEN_SIMD_TRANS_REG_PAIR_LANE(psa_dhx, psa_hx)
+GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(psas_dhx, psas_hx)
+GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(pssa_dhx, pssa_hx)
+GEN_SIMD_TRANS_REG_PAIR_LANE(paas_dhx, paas_hx)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pasa_dhx, pasa_hx)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pabd_dh, pabd_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pabdu_dh, pabdu_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_VXSAT(psabs_dh, psabs_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(psadd_dw, sadd)
+GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(psaddu_dw, saddu)
+GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(pssub_dw, ssub)
+GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(pssubu_dw, ssubu)
+GEN_SIMD_TRANS_REG_PAIR_LANE(paadd_dw, aadd)
+GEN_SIMD_TRANS_REG_PAIR_LANE(paaddu_dw, aaddu)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pasub_dw, asub)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pasubu_dw, asubu)
+GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(pssh1sadd_dw, ssh1sadd)
+
+GEN_SIMD_TRANS_REG_PAIR_LANE_IMM(pslli_db, pslli_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE_IMM(psrli_db, psrli_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE_IMM(psrai_db, psrai_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pmin_db, pmin_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pminu_db, pminu_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pmax_db, pmax_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pmaxu_db, pmaxu_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pmseq_db, pmseq_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pmslt_db, pmslt_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pmsltu_db, pmsltu_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY(psext_dh_b, psext_h_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE_IMM_VXSAT(psati_dh, psati_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE_IMM_VXSAT(pusati_dh, pusati_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE_IMM(pslli_dh, pslli_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE_IMM(psrli_dh, psrli_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE_IMM(psrai_dh, psrai_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE_IMM_VXSAT(psslai_dh, psslai_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE_IMM(psrari_dh, psrari_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pmin_dh, pmin_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pminu_dh, pminu_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pmax_dh, pmax_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pmaxu_dh, pmaxu_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pmseq_dh, pmseq_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pmslt_dh, pmslt_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pmsltu_dh, pmsltu_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE_IMM_VXSAT(psati_dw, sati_32)
+GEN_SIMD_TRANS_REG_PAIR_LANE_IMM_VXSAT(pusati_dw, usati_32)
+GEN_SIMD_TRANS_REG_PAIR_LANE_IMM_VXSAT(psslai_dw, sslai)
+GEN_SIMD_TRANS_REG_PAIR_LANE_IMM(psrari_dw, srari_32)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pmseq_dw, mseq)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pmslt_dw, mslt)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pmsltu_dw, msltu)
+
+GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR(padd_dbs, padd_bs)
+GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR(psll_dbs, psll_bs)
+GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR(psrl_dbs, psrl_bs)
+GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR(psra_dbs, psra_bs)
+GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR(padd_dhs, padd_hs)
+GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR(psll_dhs, psll_hs)
+GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR(psrl_dhs, psrl_hs)
+GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR(psra_dhs, psra_hs)
+GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_VXSAT(pssha_dhs, pssha_hs)
+GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_VXSAT(psshar_dhs, psshar_hs)
+GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_VXSAT(psshl_dhs, psshl_hs)
+GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_VXSAT(psshlr_dhs, psshlr_hs)
+GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_VXSAT(pssha_dws, ssha)
+GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_VXSAT(psshar_dws, sshar)
+GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_VXSAT(psshl_dws, sshl)
+GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_VXSAT(psshlr_dws, sshlr)
+
+GEN_SIMD_TRANS_REG_PAIR_LANE(ppairo_db, ppairo_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE(ppairo_dh, ppairo_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE(ppaire_db, ppaire_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE(ppaireo_db, ppaireo_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE(ppaireo_dh, ppaireo_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE(ppairoe_dh, ppairoe_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE(ppairoe_db, ppairoe_b)
+
+GEN_SIMD_TRANS_REG_PAIR_PREDSUM(predsum_dbs)
+GEN_SIMD_TRANS_REG_PAIR_PREDSUM(predsumu_dbs)
+GEN_SIMD_TRANS_REG_PAIR_PREDSUM(predsum_dhs)
+GEN_SIMD_TRANS_REG_PAIR_PREDSUM(predsumu_dhs)
+
+GEN_SIMD_TRANS_PN_OP_IMM(pnsrli_b)
+GEN_SIMD_TRANS_PN_OP_IMM(pnsrai_b)
+GEN_SIMD_TRANS_PN_OP_IMM(pnsrari_b)
+GEN_SIMD_TRANS_PN_OP_IMM_VXSAT(pnclipi_b)
+GEN_SIMD_TRANS_PN_OP_IMM_VXSAT(pnclipri_b)
+GEN_SIMD_TRANS_PN_OP_IMM_VXSAT(pnclipiu_b)
+GEN_SIMD_TRANS_PN_OP_IMM_VXSAT(pnclipriu_b)
+
+GEN_SIMD_TRANS_PN_OP_IMM(pnsrli_h)
+GEN_SIMD_TRANS_PN_OP_IMM(pnsrai_h)
+GEN_SIMD_TRANS_PN_OP_IMM(pnsrari_h)
+GEN_SIMD_TRANS_PN_OP_IMM_VXSAT(pnclipi_h)
+GEN_SIMD_TRANS_PN_OP_IMM_VXSAT(pnclipri_h)
+GEN_SIMD_TRANS_PN_OP_IMM_VXSAT(pnclipiu_h)
+GEN_SIMD_TRANS_PN_OP_IMM_VXSAT(pnclipriu_h)
+
+GEN_SIMD_TRANS_PN_OP_IMM(nsrli)
+GEN_SIMD_TRANS_PN_OP_IMM(nsrai)
+GEN_SIMD_TRANS_PN_OP_IMM(nsrari)
+GEN_SIMD_TRANS_PN_OP_IMM_VXSAT(nclipi)
+GEN_SIMD_TRANS_PN_OP_IMM_VXSAT(nclipri)
+GEN_SIMD_TRANS_PN_OP_IMM_VXSAT(nclipiu)
+GEN_SIMD_TRANS_PN_OP_IMM_VXSAT(nclipriu)
+
+GEN_SIMD_TRANS_PN_OP_REG(pnsrl_bs)
+GEN_SIMD_TRANS_PN_OP_REG(pnsra_bs)
+GEN_SIMD_TRANS_PN_OP_REG(pnsrar_bs)
+GEN_SIMD_TRANS_PN_OP_REG_VXSAT(pnclip_bs)
+GEN_SIMD_TRANS_PN_OP_REG_VXSAT(pnclipr_bs)
+GEN_SIMD_TRANS_PN_OP_REG_VXSAT(pnclipu_bs)
+GEN_SIMD_TRANS_PN_OP_REG_VXSAT(pnclipru_bs)
+
+GEN_SIMD_TRANS_PN_OP_REG(pnsrl_hs)
+GEN_SIMD_TRANS_PN_OP_REG(pnsra_hs)
+GEN_SIMD_TRANS_PN_OP_REG(pnsrar_hs)
+GEN_SIMD_TRANS_PN_OP_REG_VXSAT(pnclip_hs)
+GEN_SIMD_TRANS_PN_OP_REG_VXSAT(pnclipr_hs)
+GEN_SIMD_TRANS_PN_OP_REG_VXSAT(pnclipu_hs)
+GEN_SIMD_TRANS_PN_OP_REG_VXSAT(pnclipru_hs)
+
+GEN_SIMD_TRANS_PN_OP_REG(nsrl)
+GEN_SIMD_TRANS_PN_OP_REG(nsra)
+GEN_SIMD_TRANS_PN_OP_REG(nsrar)
+GEN_SIMD_TRANS_PN_OP_REG_VXSAT(nclip)
+GEN_SIMD_TRANS_PN_OP_REG_VXSAT(nclipr)
+GEN_SIMD_TRANS_PN_OP_REG_VXSAT(nclipu)
+GEN_SIMD_TRANS_PN_OP_REG_VXSAT(nclipru)
+
+GEN_SIMD_TRANS_REG_PAIR_ACC(pmqwacc_h)
+GEN_SIMD_TRANS_REG_PAIR_ACC(pmqrwacc_h)
+GEN_SIMD_TRANS_REG_PAIR_ACC(mqwacc)
+GEN_SIMD_TRANS_REG_PAIR_ACC(mqrwacc)
+
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pwmul_b)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pwmulsu_b)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pwmulu_b)
+
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pwmul_h)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pwmulsu_h)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pwmulu_h)
+GEN_SIMD_TRANS_REG_PAIR_ACC(pwmacc_h)
+GEN_SIMD_TRANS_REG_PAIR_ACC(pwmaccsu_h)
+GEN_SIMD_TRANS_REG_PAIR_ACC(pwmaccu_h)
+
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(wmul)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(wmulsu)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(wmulu)
+
+GEN_SIMD_TRANS_REG_PAIR_ACC(wmacc)
+GEN_SIMD_TRANS_REG_PAIR_ACC(wmaccsu)
+GEN_SIMD_TRANS_REG_PAIR_ACC(wmaccu)
+
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pm2wadd_h)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pm2waddsu_h)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pm2waddu_h)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pm2wadd_hx)
+
+GEN_SIMD_TRANS_REG_PAIR_ACC(pm2wadda_h)
+GEN_SIMD_TRANS_REG_PAIR_ACC(pm2waddasu_h)
+GEN_SIMD_TRANS_REG_PAIR_ACC(pm2waddau_h)
+GEN_SIMD_TRANS_REG_PAIR_ACC(pm2wadda_hx)
+
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pm2wsub_h)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pm2wsub_hx)
+GEN_SIMD_TRANS_REG_PAIR_ACC(pm2wsuba_h)
+GEN_SIMD_TRANS_REG_PAIR_ACC(pm2wsuba_hx)
+
 #define GEN_PLI(NAME, PRE_REQ, IMM_TYPE, LIMIT, SHIFT, ADDEND) \
 static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a)    \
 {                                                              \
@@ -917,6 +1182,21 @@ static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a)    \
     return true;                                               \
 }
 
+#define GEN_PLI_D(NAME, IMM_TYPE, LIMIT, SHIFT, ADDEND)         \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a)    \
+{                                                              \
+    REQUIRE_RVP(ctx);                                          \
+    int i = 1;                                                 \
+    IMM_TYPE imm = a->imm;                                     \
+    while (i < (LIMIT)) {                                      \
+        imm = (imm << (SHIFT)) + (ADDEND);                     \
+        i++;                                                   \
+    }                                                          \
+    gen_set_gpri(ctx, (a->rd) * 2, imm);                       \
+    gen_set_gpri(ctx, (a->rd) * 2 + 1, imm);                   \
+    return true;                                               \
+}
+
 GEN_PLI(pli_b, , target_long, TARGET_LONG_SIZE, 8, a->imm)
 GEN_PLI(pli_h, , target_long, TARGET_LONG_SIZE / 2, 16,
         a->imm & 0xFFFF)
@@ -926,3 +1206,184 @@ GEN_PLI(pli_w, REQUIRE_64BIT(ctx); , int64_t, TARGET_LONG_SIZE / 4, 32,
         a->imm & 0xFFFFFFFF)
 GEN_PLI(plui_w, REQUIRE_64BIT(ctx); , int64_t, TARGET_LONG_SIZE / 4, 32,
         a->imm & 0xFFFFFFFF)
+GEN_PLI_D(pli_db, target_long, TARGET_LONG_SIZE, 8, a->imm)
+GEN_PLI_D(pli_dh, target_long, TARGET_LONG_SIZE / 2, 16,
+          a->imm & 0xFFFF)
+GEN_PLI_D(plui_dh, target_long, TARGET_LONG_SIZE / 2, 16,
+          a->imm & 0xFFFF)
+
+#define GEN_DW_LANE_BINOP(NAME, OP)                         \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{                                                           \
+    REQUIRE_32BIT(ctx);                                     \
+    REQUIRE_RVP(ctx);                                       \
+    TCGv src1_0 = get_gpr(ctx, (a->rs1) * 2, EXT_NONE);     \
+    TCGv src2_0 = get_gpr(ctx, (a->rs2) * 2, EXT_NONE);     \
+    TCGv dest_0 = dest_gpr(ctx, (a->rd) * 2);               \
+    TCGv src1_1 = get_gpr(ctx, (a->rs1) * 2 + 1, EXT_NONE); \
+    TCGv src2_1 = get_gpr(ctx, (a->rs2) * 2 + 1, EXT_NONE); \
+    TCGv dest_1 = dest_gpr(ctx, (a->rd) * 2 + 1);           \
+    OP(dest_0, src1_0, src2_0);                             \
+    OP(dest_1, src1_1, src2_1);                             \
+    gen_set_gpr(ctx, (a->rd) * 2, dest_0);                  \
+    gen_set_gpr(ctx, (a->rd) * 2 + 1, dest_1);              \
+    return true;                                            \
+}
+
+GEN_DW_LANE_BINOP(padd_dw, tcg_gen_add_tl)
+GEN_DW_LANE_BINOP(psub_dw, tcg_gen_sub_tl)
+GEN_DW_LANE_BINOP(psh1add_dw, gen_sh1add)
+
+/* Verify rd is not zero register for wzip8p and wzip16p. */
+#if defined(TARGET_RISCV32)
+#define GEN_WZIP_P(NAME)                                      \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a)  \
+{                                                            \
+    REQUIRE_32BIT(ctx);                                      \
+    REQUIRE_RVP(ctx);                                        \
+    TCGv_i32 src1 = get_gpr(ctx, a->rs1, EXT_NONE);          \
+    TCGv_i32 src2 = get_gpr(ctx, a->rs2, EXT_NONE);          \
+    TCGv_i64 t = tcg_temp_new_i64();                         \
+    if (a->rd == 0) {                                        \
+        return true;                                         \
+    } else {                                                 \
+        get_pair_regs(ctx, t, (a->rd) * 2);                  \
+    }                                                        \
+    gen_helper_##NAME(t, tcg_env, src1, src2);               \
+    set_pair_regs(ctx, (a->rd) * 2, t);                      \
+    return true;                                             \
+}
+#else
+#define GEN_WZIP_P(NAME)                                      \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a)  \
+{                                                            \
+    REQUIRE_32BIT(ctx);                                      \
+    return true;                                             \
+}
+#endif
+
+GEN_WZIP_P(wzip8p)
+GEN_WZIP_P(wzip16p)
+
+#define GEN_PAIR_I64_BINOP(NAME, OP)                         \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a)  \
+{                                                            \
+    REQUIRE_32BIT(ctx);                                      \
+    REQUIRE_RVP(ctx);                                        \
+    TCGv_i64 src1 = tcg_temp_new_i64();                      \
+    TCGv_i64 src2 = tcg_temp_new_i64();                      \
+    TCGv_i64 dest = tcg_temp_new_i64();                      \
+    get_pair_regs(ctx, src1, (a->rs1) * 2);                  \
+    get_pair_regs(ctx, src2, (a->rs2) * 2);                  \
+    get_pair_regs(ctx, dest, (a->rd) * 2);                   \
+    OP(dest, src1, src2);                                    \
+    set_pair_regs(ctx, (a->rd) * 2, dest);                   \
+    return true;                                             \
+}
+
+GEN_PAIR_I64_BINOP(addd_p, tcg_gen_add_i64)
+GEN_PAIR_I64_BINOP(subd_p, tcg_gen_sub_i64)
+
+#define GEN_DW_EXT(NAME, OP)                                \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{                                                           \
+    REQUIRE_32BIT(ctx);                                     \
+    REQUIRE_RVP(ctx);                                       \
+    TCGv dest_0 = dest_gpr(ctx, (a->rd) * 2);               \
+    TCGv src1_0 = get_gpr(ctx, (a->rs1) * 2, EXT_NONE);     \
+    TCGv dest_1 = dest_gpr(ctx, (a->rd) * 2 + 1);           \
+    TCGv src1_1 = get_gpr(ctx, (a->rs1) * 2 + 1, EXT_NONE); \
+    OP(dest_0, src1_0);                                     \
+    gen_set_gpr(ctx, (a->rd) * 2, dest_0);                  \
+    OP(dest_1, src1_1);                                     \
+    gen_set_gpr(ctx, (a->rd) * 2 + 1, dest_1);              \
+    return true;                                            \
+}
+
+GEN_DW_EXT(psext_dw_b, tcg_gen_ext8s_tl)
+GEN_DW_EXT(psext_dw_h, tcg_gen_ext16s_tl)
+
+#define GEN_DW_SHIFT_IMM(NAME, OP)                          \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{                                                           \
+    REQUIRE_32BIT(ctx);                                     \
+    REQUIRE_RVP(ctx);                                       \
+    arg_shift a0, a1;                                       \
+    a0.rd = (a->rd) * 2;                                    \
+    a0.rs1 = (a->rs1) * 2;                                  \
+    a0.shamt = a->imm;                                      \
+    a1.rd = (a->rd) * 2 + 1;                                \
+    a1.rs1 = (a->rs1) * 2 + 1;                              \
+    a1.shamt = a->imm;                                      \
+    gen_shift_imm_fn(ctx, &a0, EXT_NONE, OP, NULL);         \
+    gen_shift_imm_fn(ctx, &a1, EXT_NONE, OP, NULL);         \
+    return true;                                            \
+}
+
+#define GEN_DW_SHIFT_IMM_PER_OL(NAME, OP, OP_OL)                  \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a)       \
+{                                                                 \
+    REQUIRE_32BIT(ctx);                                           \
+    REQUIRE_RVP(ctx);                                             \
+    arg_shift a0, a1;                                             \
+    a0.rd = (a->rd) * 2;                                          \
+    a0.rs1 = (a->rs1) * 2;                                        \
+    a0.shamt = a->imm;                                            \
+    a1.rd = (a->rd) * 2 + 1;                                      \
+    a1.rs1 = (a->rs1) * 2 + 1;                                    \
+    a1.shamt = a->imm;                                            \
+    gen_shift_imm_fn_per_ol(ctx, &a0, EXT_NONE, OP, OP_OL, NULL); \
+    gen_shift_imm_fn_per_ol(ctx, &a1, EXT_NONE, OP, OP_OL, NULL); \
+    return true;                                                  \
+}
+
+GEN_DW_SHIFT_IMM(pslli_dw, tcg_gen_shli_tl)
+GEN_DW_SHIFT_IMM_PER_OL(psrli_dw, tcg_gen_shri_tl, gen_srliw)
+GEN_DW_SHIFT_IMM_PER_OL(psrai_dw, tcg_gen_sari_tl, gen_sraiw)
+
+#define GEN_DW_PAIR_ARITH(NAME, EXTRA_REQ, EXT, OP)         \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{                                                           \
+    REQUIRE_32BIT(ctx);                                     \
+    REQUIRE_RVP(ctx);                                       \
+    EXTRA_REQ                                               \
+    arg_r a0, a1;                                           \
+    a0.rd = (a->rd) * 2;                                    \
+    a0.rs1 = (a->rs1) * 2;                                  \
+    a0.rs2 = (a->rs2) * 2;                                  \
+    a1.rd = (a->rd) * 2 + 1;                                \
+    a1.rs1 = (a->rs1) * 2 + 1;                              \
+    a1.rs2 = (a->rs2) * 2 + 1;                              \
+    gen_arith(ctx, &a0, EXT, OP, NULL);                     \
+    gen_arith(ctx, &a1, EXT, OP, NULL);                     \
+    return true;                                            \
+}
+
+GEN_DW_PAIR_ARITH(pmin_dw, REQUIRE_ZBB(ctx); , EXT_SIGN, tcg_gen_smin_tl)
+GEN_DW_PAIR_ARITH(pminu_dw, REQUIRE_ZBB(ctx); , EXT_SIGN, tcg_gen_umin_tl)
+GEN_DW_PAIR_ARITH(pmax_dw, REQUIRE_ZBB(ctx); , EXT_SIGN, tcg_gen_smax_tl)
+GEN_DW_PAIR_ARITH(pmaxu_dw, REQUIRE_ZBB(ctx); , EXT_SIGN, tcg_gen_umax_tl)
+
+#define GEN_DWS_REG_OP(NAME, GEN, EXT, OP)                  \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{                                                           \
+    REQUIRE_32BIT(ctx);                                     \
+    REQUIRE_RVP(ctx);                                       \
+    arg_r a0, a1;                                           \
+    a0.rd = (a->rd) * 2;                                    \
+    a0.rs1 = (a->rs1) * 2;                                  \
+    a0.rs2 = a->rs2;                                        \
+    a1.rd = (a->rd) * 2 + 1;                                \
+    a1.rs1 = (a->rs1) * 2 + 1;                              \
+    a1.rs2 = a->rs2;                                        \
+    GEN(ctx, &a0, EXT, OP, NULL);                           \
+    GEN(ctx, &a1, EXT, OP, NULL);                           \
+    return true;                                            \
+}
+
+GEN_DWS_REG_OP(padd_dws, gen_arith, EXT_NONE, tcg_gen_add_tl)
+GEN_DWS_REG_OP(psll_dws, gen_shift, EXT_NONE, tcg_gen_shl_tl)
+GEN_DWS_REG_OP(psrl_dws, gen_shift, EXT_ZERO, tcg_gen_shr_tl)
+GEN_DWS_REG_OP(psra_dws, gen_shift, EXT_SIGN, tcg_gen_sar_tl)
+
+GEN_DW_PAIR_ARITH(ppaire_dh, REQUIRE_ZBKB(ctx); , EXT_NONE, gen_pack)
diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
index e7c7e554938..c69adae10cc 100644
--- a/target/riscv/tcg/psimd_helper.c
+++ b/target/riscv/tcg/psimd_helper.c
@@ -2890,3 +2890,276 @@ GEN_PSIMD_4WAY_MUL_ACC(pm4addasu_h, uint64_t, int16_t, uint16_t,
 GEN_PSIMD_4WAY_MUL_ACC(pm4addau_h, uint64_t, uint16_t, uint16_t,
                        uint64_t, uint64_t, uint64_t, EXTRACT16, EXTRACT64,
                        INSERT64, ELEMS_D, 0, PSIMD_MUL_U64)
+
+/* Double-Width Operations (RV32 only, register pairs) */
+
+GEN_PSIMD_WIDEN_BINOP(pwadd_b, int8_t, int16_t, uint16_t,
+                      4, 8, 16, 0xFF, PSIMD_COMB_ADD)
+GEN_PSIMD_WIDEN_BINOP_ACC(pwadda_b, int8_t, int16_t, uint16_t,
+                          4, 8, 16, 0xFF, 0xFFFF, PSIMD_COMB_ADD)
+GEN_PSIMD_WIDEN_BINOP(pwaddu_b, uint8_t, uint16_t, uint16_t,
+                      4, 8, 16, 0xFF, PSIMD_COMB_ADD)
+GEN_PSIMD_WIDEN_BINOP_ACC(pwaddau_b, uint8_t, uint16_t, uint16_t,
+                          4, 8, 16, 0xFF, 0xFFFF, PSIMD_COMB_ADD)
+GEN_PSIMD_WIDEN_BINOP(pwsub_b, int8_t, int16_t, uint16_t,
+                      4, 8, 16, 0xFF, PSIMD_COMB_SUB)
+GEN_PSIMD_WIDEN_BINOP_ACC(pwsuba_b, int8_t, int16_t, uint16_t,
+                          4, 8, 16, 0xFF, 0xFFFF, PSIMD_COMB_SUB)
+GEN_PSIMD_WIDEN_BINOP(pwsubu_b, uint8_t, uint16_t, uint16_t,
+                      4, 8, 16, 0xFF, PSIMD_COMB_SUB)
+GEN_PSIMD_WIDEN_BINOP_ACC(pwsubau_b, uint8_t, uint16_t, uint16_t,
+                          4, 8, 16, 0xFF, 0xFFFF, PSIMD_COMB_SUB)
+
+GEN_PSIMD_WIDEN_SHIFT(pwslli_b, uint8_t, uint16_t, uint16_t,
+                      4, 8, 16, 0xFF, 0x0F)
+GEN_PSIMD_WIDEN_SHIFT(pwsll_bs, uint8_t, uint16_t, uint16_t,
+                      4, 8, 16, 0xFF, 0x1F)
+GEN_PSIMD_WIDEN_SHIFT(pwslai_b, int8_t, int16_t, uint16_t,
+                      4, 8, 16, 0xFF, 0x0F)
+GEN_PSIMD_WIDEN_SHIFT(pwsla_bs, int8_t, int16_t, uint16_t,
+                      4, 8, 16, 0xFF, 0x1F)
+
+GEN_PSIMD_WIDEN_BINOP(pwadd_h, int16_t, int32_t, uint32_t,
+                      2, 16, 32, 0xFFFF, PSIMD_COMB_ADD)
+GEN_PSIMD_WIDEN_BINOP_ACC(pwadda_h, int16_t, int32_t, uint32_t,
+                          2, 16, 32, 0xFFFF, 0xFFFFFFFFULL,
+                          PSIMD_COMB_ADD)
+GEN_PSIMD_WIDEN_BINOP(pwaddu_h, uint16_t, uint32_t, uint32_t,
+                      2, 16, 32, 0xFFFF, PSIMD_COMB_ADD)
+GEN_PSIMD_WIDEN_BINOP_ACC(pwaddau_h, uint16_t, uint32_t, uint32_t,
+                          2, 16, 32, 0xFFFF, 0xFFFFFFFFULL,
+                          PSIMD_COMB_ADD)
+GEN_PSIMD_WIDEN_BINOP(pwsub_h, int16_t, int32_t, uint32_t,
+                      2, 16, 32, 0xFFFF, PSIMD_COMB_SUB)
+GEN_PSIMD_WIDEN_BINOP_ACC(pwsuba_h, int16_t, int32_t, uint32_t,
+                          2, 16, 32, 0xFFFF, 0xFFFFFFFFULL,
+                          PSIMD_COMB_SUB)
+GEN_PSIMD_WIDEN_BINOP(pwsubu_h, uint16_t, uint32_t, uint32_t,
+                      2, 16, 32, 0xFFFF, PSIMD_COMB_SUB)
+GEN_PSIMD_WIDEN_BINOP_ACC(pwsubau_h, uint16_t, uint32_t, uint32_t,
+                          2, 16, 32, 0xFFFF, 0xFFFFFFFFULL,
+                          PSIMD_COMB_SUB)
+
+GEN_PSIMD_WIDEN_SHIFT(pwslli_h, uint16_t, uint32_t, uint32_t,
+                      2, 16, 32, 0xFFFF, 0x1F)
+GEN_PSIMD_WIDEN_SHIFT(pwsll_hs, uint16_t, uint32_t, uint32_t,
+                      2, 16, 32, 0xFFFF, 0x1F)
+GEN_PSIMD_WIDEN_SHIFT(pwslai_h, int16_t, int32_t, uint32_t,
+                      2, 16, 32, 0xFFFF, 0x1F)
+GEN_PSIMD_WIDEN_SHIFT(pwsla_hs, int16_t, int32_t, uint32_t,
+                      2, 16, 32, 0xFFFF, 0x1F)
+
+GEN_PSIMD_WIDEN_BINOP(wadd, int32_t, int64_t, uint64_t,
+                      1, 32, 64, 0xFFFFFFFF, PSIMD_COMB_ADD)
+GEN_PSIMD_WIDEN_BINOP_ACC(wadda, int32_t, int64_t, uint64_t,
+                          1, 32, 64, 0xFFFFFFFF, 0xFFFFFFFFFFFFFFFFULL,
+                          PSIMD_COMB_ADD)
+GEN_PSIMD_WIDEN_BINOP(waddu, uint32_t, uint64_t, uint64_t,
+                      1, 32, 64, 0xFFFFFFFF, PSIMD_COMB_ADD)
+GEN_PSIMD_WIDEN_BINOP_ACC(waddau, uint32_t, uint64_t, uint64_t,
+                          1, 32, 64, 0xFFFFFFFF, 0xFFFFFFFFFFFFFFFFULL,
+                          PSIMD_COMB_ADD)
+GEN_PSIMD_WIDEN_BINOP(wsub, int32_t, int64_t, uint64_t,
+                      1, 32, 64, 0xFFFFFFFF, PSIMD_COMB_SUB)
+GEN_PSIMD_WIDEN_BINOP_ACC(wsuba, int32_t, int64_t, uint64_t,
+                          1, 32, 64, 0xFFFFFFFF, 0xFFFFFFFFFFFFFFFFULL,
+                          PSIMD_COMB_SUB)
+GEN_PSIMD_WIDEN_BINOP(wsubu, uint32_t, uint64_t, uint64_t,
+                      1, 32, 64, 0xFFFFFFFF, PSIMD_COMB_SUB)
+GEN_PSIMD_WIDEN_BINOP_ACC(wsubau, uint32_t, uint64_t, uint64_t,
+                          1, 32, 64, 0xFFFFFFFF, 0xFFFFFFFFFFFFFFFFULL,
+                          PSIMD_COMB_SUB)
+
+GEN_PSIMD_WIDEN_SHIFT(wslli, uint32_t, uint64_t, uint64_t,
+                      1, 32, 64, 0xFFFFFFFF, 0x3F)
+GEN_PSIMD_WIDEN_SHIFT(wsll, uint32_t, uint64_t, uint64_t,
+                      1, 32, 64, 0xFFFFFFFF, 0x3F)
+GEN_PSIMD_WIDEN_SHIFT(wslai, int32_t, int64_t, uint64_t,
+                      1, 32, 64, 0xFFFFFFFF, 0x3F)
+GEN_PSIMD_WIDEN_SHIFT(wsla, int32_t, int64_t, uint64_t,
+                      1, 32, 64, 0xFFFFFFFF, 0x3F)
+
+GEN_PSIMD_DW_ZIP(wzip8p, EXTRACT8, 4, 16, 8)
+GEN_PSIMD_DW_ZIP(wzip16p, EXTRACT16, 2, 32, 16)
+
+GEN_PSIMD_DW_REDSUM(predsum_dbs, int64_t, int32_t, int8_t, EXTRACT8, 8)
+GEN_PSIMD_DW_REDSUM(predsumu_dbs, uint64_t, uint32_t, uint8_t, EXTRACT8, 8)
+GEN_PSIMD_DW_REDSUM(predsum_dhs, int64_t, int32_t, int16_t, EXTRACT16, 4)
+GEN_PSIMD_DW_REDSUM(predsumu_dhs, uint64_t, uint32_t, uint16_t, EXTRACT16, 4)
+
+
+/* Narrowing Operations (RV32 only, register pair sources) */
+
+GEN_PSIMD_NARROW_SRL(pnsrli_b, uint16_t, uint8_t,
+                     4, 16, 8, 0xFFFF, 0x0F)
+GEN_PSIMD_NARROW_SRL(pnsrl_bs, uint16_t, uint8_t,
+                     4, 16, 8, 0xFFFF, 0x1F)
+GEN_PSIMD_NARROW_SRA_PACK(pnsrai_b, int16_t, int32_t, uint8_t,
+                          4, 16, 8, 0xFFFF, 0x0F)
+GEN_PSIMD_NARROW_SRA_PACK(pnsra_bs, int16_t, int32_t, uint8_t,
+                          4, 16, 8, 0xFFFF, 0x1F)
+GEN_PSIMD_NARROW_RNDSRA_PACK(pnsrari_b, int16_t, int32_t, uint8_t,
+                             4, 16, 8, 0xFFFF, 0x0F, 0x1FF)
+GEN_PSIMD_NARROW_RNDSRA_PACK(pnsrar_bs, int16_t, int32_t, uint8_t,
+                             4, 16, 8, 0xFFFF, 0x1F, 0x1FF)
+GEN_PSIMD_NCLIP_SIGNED_PACK(pnclipi_b, int16_t, int32_t, int16_t,
+                            uint8_t, 4, 16, 8, 0xFFFF, 0x0F,
+                            -128, 127, 0x80, 0x7F)
+GEN_PSIMD_NCLIPR_SIGNED_PACK(pnclipri_b, int16_t, int32_t, int16_t,
+                             uint8_t, 4, 16, 8, 0xFFFF, 0x0F, 0x1FFFF,
+                             -128, 127, 0x80, 0x7F)
+GEN_PSIMD_NCLIP_UNSIGNED_PACK(pnclipiu_b, uint16_t, uint16_t, uint8_t,
+                              4, 16, 8, 0xFFFF, 0x0F, 0x00FF)
+GEN_PSIMD_NCLIPR_UNSIGNED_PACK(pnclipriu_b, uint16_t, uint32_t, uint8_t,
+                               4, 16, 8, 0xFFFF, 0x0F, 0x00FF)
+GEN_PSIMD_NCLIP_SIGNED_PACK(pnclip_bs, int16_t, int32_t, int16_t,
+                            uint8_t, 4, 16, 8, 0xFFFF, 0x1F,
+                            -128, 127, 0x80, 0x7F)
+GEN_PSIMD_NCLIPR_SIGNED_PACK(pnclipr_bs, int16_t, int32_t, int16_t,
+                             uint8_t, 4, 16, 8, 0xFFFF, 0x1F, 0x1FFFF,
+                             -128, 127, 0x80, 0x7F)
+GEN_PSIMD_NCLIP_UNSIGNED_PACK(pnclipu_bs, uint16_t, uint32_t, uint8_t,
+                              4, 16, 8, 0xFFFF, 0x1F, 0x00FF)
+GEN_PSIMD_NCLIPR_UNSIGNED_PACK(pnclipru_bs, uint16_t, uint64_t, uint8_t,
+                               4, 16, 8, 0xFFFF, 0x1F, 0x00FF)
+
+GEN_PSIMD_NARROW_SRL(pnsrli_h, uint32_t, uint16_t,
+                     2, 32, 16, 0xFFFFFFFFULL, 0x1F)
+GEN_PSIMD_NARROW_SRA_PACK(pnsrai_h, int32_t, int64_t, uint16_t,
+                          2, 32, 16, 0xFFFFFFFFULL, 0x1F)
+GEN_PSIMD_NARROW_RNDSRA_PACK(pnsrari_h, int32_t, int64_t, uint16_t,
+                             2, 32, 16, 0xFFFFFFFFULL, 0x1F, 0x1FFFF)
+
+GEN_PSIMD_NARROW_SRL(pnsrl_hs, uint32_t, uint16_t,
+                     2, 32, 16, 0xFFFFFFFFULL, 0x1F)
+
+GEN_PSIMD_NARROW_ALIAS(pnsra_hs, pnsrai_h)
+GEN_PSIMD_NARROW_ALIAS(pnsrar_hs, pnsrari_h)
+
+GEN_PSIMD_NCLIP_SIGNED_PACK(pnclip_hs, int32_t, int64_t, int32_t,
+                            uint16_t, 2, 32, 16, 0xFFFFFFFFULL, 0x1F,
+                            -32768, 32767, 0x8000, 0x7FFF)
+GEN_PSIMD_NCLIPR_SIGNED_PACK(pnclipr_hs, int32_t, int64_t, int32_t,
+                             uint16_t, 2, 32, 16, 0xFFFFFFFFULL, 0x1F,
+                             0x1FFFFFFFF, -32768, 32767, 0x8000, 0x7FFF)
+
+GEN_PSIMD_NARROW_ALIAS(pnclipi_h, pnclip_hs)
+GEN_PSIMD_NARROW_ALIAS(pnclipri_h, pnclipr_hs)
+
+GEN_PSIMD_NCLIP_UNSIGNED_PACK(pnclipu_hs, uint32_t, uint32_t, uint16_t,
+                              2, 32, 16, 0xFFFFFFFFULL, 0x1F, 0xFFFF)
+GEN_PSIMD_NCLIPR_UNSIGNED_PACK(pnclipru_hs, uint32_t, uint64_t, uint16_t,
+                               2, 32, 16, 0xFFFFFFFFULL, 0x1F, 0xFFFF)
+
+GEN_PSIMD_NARROW_ALIAS(pnclipiu_h, pnclipu_hs)
+GEN_PSIMD_NARROW_ALIAS(pnclipriu_h, pnclipru_hs)
+
+GEN_PSIMD_NARROW_SRL(nsrli, uint64_t, uint32_t,
+                     1, 64, 32, 0xFFFFFFFFFFFFFFFFULL, 0x3F)
+
+GEN_PSIMD_NARROW_SRA(nsrai)
+GEN_PSIMD_NARROW_RNDSRA(nsrari)
+
+GEN_PSIMD_NARROW_SRL(nsrl, uint64_t, uint32_t,
+                     1, 64, 32, 0xFFFFFFFFFFFFFFFFULL, 0x3F)
+
+GEN_PSIMD_NARROW_SRA(nsra)
+GEN_PSIMD_NARROW_RNDSRA(nsrar)
+
+GEN_PSIMD_NCLIP(nclipi)
+GEN_PSIMD_NCLIPR(nclipri)
+GEN_PSIMD_NCLIPU(nclipiu)
+GEN_PSIMD_NCLIPRU(nclipriu)
+
+GEN_PSIMD_NCLIP(nclip)
+GEN_PSIMD_NCLIPR(nclipr)
+GEN_PSIMD_NCLIPU(nclipu)
+GEN_PSIMD_NCLIPRU(nclipru)
+
+/* Multiplication with Even-Odd Register Pairs as Destination (RV32 only) */
+
+GEN_PSIMD_WIDEN_QMUL_ACC(pmqwacc_h, int16_t, int32_t, int64_t,
+                         int32_t, uint32_t, 2, EXTRACT16, EXTRACT32,
+                         2, 0, 15, 0, 32, PSIMD_MUL_S64)
+GEN_PSIMD_WIDEN_QMUL_ACC(pmqrwacc_h, int16_t, int32_t, int64_t,
+                         int32_t, uint32_t, 2, EXTRACT16, EXTRACT32,
+                         2, 0, 15, 1LL << 14, 32, PSIMD_MUL_S64)
+
+GEN_PSIMD_WIDEN_MUL(pwmul_b, int8_t, int8_t, int16_t, uint16_t,
+                    4, EXTRACT8, 16, PSIMD_MUL_S32)
+GEN_PSIMD_WIDEN_MUL(pwmulsu_b, int8_t, uint8_t, int16_t, uint16_t,
+                    4, EXTRACT8, 16, PSIMD_MUL_SU16)
+GEN_PSIMD_WIDEN_MUL(pwmulu_b, uint8_t, uint8_t, uint16_t, uint16_t,
+                    4, EXTRACT8, 16, PSIMD_MUL_U32)
+GEN_PSIMD_WIDEN_MUL(pwmul_h, int16_t, int16_t, int32_t, uint32_t,
+                    2, EXTRACT16, 32, PSIMD_MUL_S32)
+GEN_PSIMD_WIDEN_MUL(pwmulsu_h, int16_t, uint16_t, int32_t, uint32_t,
+                    2, EXTRACT16, 32, PSIMD_MUL_SU32)
+GEN_PSIMD_WIDEN_MUL(pwmulu_h, uint16_t, uint16_t, uint32_t, uint32_t,
+                    2, EXTRACT16, 32, PSIMD_MUL_U32)
+
+GEN_PSIMD_WIDEN_MUL_ACC(pwmacc_h, int16_t, int16_t, int32_t,
+                        int32_t, uint32_t, 2, EXTRACT16, EXTRACT32, 32,
+                        PSIMD_MUL_S32)
+GEN_PSIMD_WIDEN_MUL_ACC(pwmaccsu_h, int16_t, uint16_t, int32_t,
+                        int32_t, uint32_t, 2, EXTRACT16, EXTRACT32, 32,
+                        PSIMD_MUL_SU32)
+GEN_PSIMD_WIDEN_MUL_ACC(pwmaccu_h, uint16_t, uint16_t, uint32_t,
+                        uint32_t, uint32_t, 2, EXTRACT16, EXTRACT32, 32,
+                        PSIMD_MUL_U32)
+
+GEN_PSIMD_WIDEN_QMUL_ACC(mqwacc, int32_t, int64_t, int64_t,
+                         int64_t, uint64_t, 1, EXTRACT32, EXTRACT64,
+                         0, 0, 31, 0, 64, PSIMD_MUL_S64)
+GEN_PSIMD_WIDEN_QMUL_ACC(mqrwacc, int32_t, int64_t, int64_t,
+                         int64_t, uint64_t, 1, EXTRACT32, EXTRACT64,
+                         0, 0, 31, 1LL << 30, 64, PSIMD_MUL_S64)
+
+GEN_PSIMD_WIDEN_MUL(wmul, int32_t, int32_t, int64_t, uint64_t,
+                    1, EXTRACT32, 64, PSIMD_MUL_S64)
+GEN_PSIMD_WIDEN_MUL(wmulsu, int32_t, uint32_t, int64_t, uint64_t,
+                    1, EXTRACT32, 64, PSIMD_MUL_SU64)
+GEN_PSIMD_WIDEN_MUL(wmulu, uint32_t, uint32_t, uint64_t, uint64_t,
+                    1, EXTRACT32, 64, PSIMD_MUL_U64)
+
+GEN_PSIMD_WIDEN_MUL_ACC(wmacc, int32_t, int32_t, int64_t,
+                        int64_t, uint64_t, 1, EXTRACT32, EXTRACT64, 64,
+                        PSIMD_MUL_S64)
+GEN_PSIMD_WIDEN_MUL_ACC(wmaccsu, int32_t, uint32_t, int64_t,
+                        int64_t, uint64_t, 1, EXTRACT32, EXTRACT64, 64,
+                        PSIMD_MUL_SU64)
+GEN_PSIMD_WIDEN_MUL_ACC(wmaccu, uint32_t, uint32_t, uint64_t,
+                        uint64_t, uint64_t, 1, EXTRACT32, EXTRACT64, 64,
+                        PSIMD_MUL_U64)
+
+GEN_PSIMD_DW_2WAY_MUL(pm2wadd_h, int16_t, int16_t, int64_t,
+                      EXTRACT16, 0, 1, 0, 1, PSIMD_MUL_S64, PSIMD_COMB_ADD)
+GEN_PSIMD_DW_2WAY_MUL(pm2waddsu_h, int16_t, uint16_t, int64_t,
+                      EXTRACT16, 0, 1, 0, 1, PSIMD_MUL_SU64,
+                      PSIMD_COMB_ADD)
+GEN_PSIMD_DW_2WAY_MUL(pm2waddu_h, uint16_t, uint16_t, uint64_t,
+                      EXTRACT16, 0, 1, 0, 1, PSIMD_MUL_U64, PSIMD_COMB_ADD)
+GEN_PSIMD_DW_2WAY_MUL_ACC(pm2wadda_h, int16_t, int16_t, int64_t, int64_t,
+                          EXTRACT16, 0, 1, 0, 1, PSIMD_MUL_S64,
+                          PSIMD_COMB_ADD)
+GEN_PSIMD_DW_2WAY_MUL_ACC(pm2waddasu_h, int16_t, uint16_t, int64_t,
+                          int64_t, EXTRACT16, 0, 1, 0, 1, PSIMD_MUL_SU64,
+                          PSIMD_COMB_ADD)
+GEN_PSIMD_DW_2WAY_MUL_ACC(pm2waddau_h, uint16_t, uint16_t, uint64_t,
+                          uint64_t, EXTRACT16, 0, 1, 0, 1, PSIMD_MUL_U64,
+                          PSIMD_COMB_ADD)
+GEN_PSIMD_DW_2WAY_MUL(pm2wadd_hx, int16_t, int16_t, int64_t,
+                      EXTRACT16, 0, 1, 1, 0, PSIMD_MUL_S64, PSIMD_COMB_ADD)
+GEN_PSIMD_DW_2WAY_MUL_ACC(pm2wadda_hx, int16_t, int16_t, int64_t, int64_t,
+                          EXTRACT16, 0, 1, 1, 0, PSIMD_MUL_S64,
+                          PSIMD_COMB_ADD)
+GEN_PSIMD_DW_2WAY_MUL(pm2wsub_h, int16_t, int16_t, int64_t,
+                      EXTRACT16, 0, 1, 0, 1, PSIMD_MUL_S64, PSIMD_COMB_SUB)
+GEN_PSIMD_DW_2WAY_MUL(pm2wsub_hx, int16_t, int16_t, int64_t,
+                      EXTRACT16, 0, 1, 1, 0, PSIMD_MUL_S64, PSIMD_COMB_SUB)
+GEN_PSIMD_DW_2WAY_MUL_ACC(pm2wsuba_h, int16_t, int16_t, int64_t, int64_t,
+                          EXTRACT16, 0, 1, 0, 1, PSIMD_MUL_S64,
+                          PSIMD_COMB_SUB)
+GEN_PSIMD_DW_2WAY_MUL_ACC(pm2wsuba_hx, int16_t, int16_t, int64_t, int64_t,
+                          EXTRACT16, 0, 1, 1, 0, PSIMD_MUL_S64,
+                          PSIMD_COMB_SUB)
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH v2 18/18] target/riscv: Remove Zbkb dependency from P extension to align with the spec
  2026-07-17 10:06 [PATCH v2 00/18] target/riscv: Add support for RISC-V P Molly Chen
                   ` (16 preceding siblings ...)
  2026-07-17 10:07 ` [PATCH v2 17/18] target/riscv: Add packed SIMD RV32 only instructions Molly Chen
@ 2026-07-17 10:07 ` Molly Chen
  2026-08-03  2:26   ` Chao Liu
  2026-07-29  8:43 ` [PATCH v2 00/18] target/riscv: Add support for RISC-V P Chao Liu
  2026-07-29  9:32 ` Chao Liu
  19 siblings, 1 reply; 34+ messages in thread
From: Molly Chen @ 2026-07-17 10:07 UTC (permalink / raw)
  To: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
	chao.liu.zevorn, Chao Liu
  Cc: xiaoou, qemu-riscv, qemu-devel

Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
---
 target/riscv/tcg/insn_trans/trans_rvb.c.inc | 4 +++-
 target/riscv/tcg/insn_trans/trans_rvp.c.inc | 2 +-
 target/riscv/tcg/tcg-cpu.c                  | 6 ++----
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/target/riscv/tcg/insn_trans/trans_rvb.c.inc b/target/riscv/tcg/insn_trans/trans_rvb.c.inc
index e4dcc7c9913..af53eb4fe4b 100644
--- a/target/riscv/tcg/insn_trans/trans_rvb.c.inc
+++ b/target/riscv/tcg/insn_trans/trans_rvb.c.inc
@@ -527,7 +527,9 @@ static bool trans_brev8(DisasContext *ctx, arg_brev8 *a)
 
 static bool trans_pack(DisasContext *ctx, arg_pack *a)
 {
-    REQUIRE_ZBKB(ctx);
+    if (!has_ext(ctx, RVP) && !ctx->cfg_ptr->ext_zbkb) {
+        return false;
+    }
     return gen_arith(ctx, a, EXT_NONE, gen_pack, NULL);
 }
 
diff --git a/target/riscv/tcg/insn_trans/trans_rvp.c.inc b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
index e33e0ec110a..8c5b52ca970 100644
--- a/target/riscv/tcg/insn_trans/trans_rvp.c.inc
+++ b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
@@ -1386,4 +1386,4 @@ GEN_DWS_REG_OP(psll_dws, gen_shift, EXT_NONE, tcg_gen_shl_tl)
 GEN_DWS_REG_OP(psrl_dws, gen_shift, EXT_ZERO, tcg_gen_shr_tl)
 GEN_DWS_REG_OP(psra_dws, gen_shift, EXT_SIGN, tcg_gen_sar_tl)
 
-GEN_DW_PAIR_ARITH(ppaire_dh, REQUIRE_ZBKB(ctx); , EXT_NONE, gen_pack)
+GEN_DW_PAIR_ARITH(ppaire_dh, , EXT_NONE, gen_pack)
diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
index 1665583accf..36b0196a626 100644
--- a/target/riscv/tcg/tcg-cpu.c
+++ b/target/riscv/tcg/tcg-cpu.c
@@ -563,10 +563,8 @@ static void riscv_cpu_validate_p(RISCVCPU *cpu, Error **errp)
         return;
     }
 
-    if (!(cpu->cfg.ext_zmmul && cpu->cfg.ext_zba && cpu->cfg.ext_zbb &&
-          cpu->cfg.ext_zbkb)) {
-        error_setg(errp, "P extension requires zmmul, zba, zbb and zbkb "
-                         "extensions");
+    if (!(cpu->cfg.ext_zmmul && cpu->cfg.ext_zba && cpu->cfg.ext_zbb)) {
+        error_setg(errp, "P extension requires zmmul, zba and zbb extensions");
         return;
     }
 }
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* Re: [PATCH v2 01/18] target/riscv: Add packed SIMD extension state
  2026-07-17 10:06 ` [PATCH v2 01/18] target/riscv: Add packed SIMD extension state Molly Chen
@ 2026-07-26 19:32   ` Daniel Henrique Barboza
  2026-07-27  6:13   ` Nutty.Liu
  2026-07-29  8:43   ` Chao Liu
  2 siblings, 0 replies; 34+ messages in thread
From: Daniel Henrique Barboza @ 2026-07-26 19:32 UTC (permalink / raw)
  To: Molly Chen, palmer, alistair.francis, liwei1518, zhiwei_liu,
	chao.liu.zevorn, Chao Liu
  Cc: qemu-riscv, qemu-devel, Yin Zhang, Dajun Huang, Zhiyuan Yang



On 7/17/2026 7:06 AM, Molly Chen wrote:
> Model vxsat with separate Vector/Zve and P-only control paths.  When
> Zve* is present, vxsat follows mstatus.VS/vsstatus.VS; when P is
> implemented without Zve*, stateen0.VXSAT controls access instead.
> 
> Record the P-only stateen result in TB flags so cached translations
> preserve both instruction legality and the illegal-vs-virtual exception
> class.
> 
> Co-authored-by: Yin Zhang <zhangyin2018@iscas.ac.cn>
> Co-authored-by: Dajun Huang <djhuang_1@std.uestc.edu.cn>
> Co-authored-by: Zhiyuan Yang <zhiyuan.plct@isrc.iscas.ac.cn>
> 
> Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
> ---

Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>

>   target/riscv/cpu.c         |  5 ++--
>   target/riscv/cpu.h         |  8 +++++++
>   target/riscv/cpu_bits.h    |  2 ++
>   target/riscv/machine.c     | 19 +++++++++++++++
>   target/riscv/tcg/csr.c     | 39 +++++++++++++++++++++++++++++--
>   target/riscv/tcg/tcg-cpu.c | 48 ++++++++++++++++++++++++++++++++++++++
>   6 files changed, 117 insertions(+), 4 deletions(-)
> 
> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> index 5a82e6563bf..c9e6c83a491 100644
> --- a/target/riscv/cpu.c
> +++ b/target/riscv/cpu.c
> @@ -46,7 +46,7 @@
>   /* RISC-V CPU definitions */
>   static const char riscv_single_letter_exts[] = "IEMAFDQCBPVH";
>   const uint32_t misa_bits[] = {RVI, RVE, RVM, RVA, RVF, RVD, RVV,
> -                              RVC, RVS, RVU, RVH, RVG, RVB, 0};
> +                              RVC, RVS, RVU, RVH, RVG, RVB, RVP, 0};
>   #define RISCV_CPU_MVENDORID 0
>   #define RISCV_CPU_MIMPID 0
>   /*
> @@ -1489,7 +1489,8 @@ static const MISAExtInfo misa_ext_info_arr[] = {
>       MISA_EXT_INFO(RVH, "h", "Hypervisor"),
>       MISA_EXT_INFO(RVV, "v", "Vector operations"),
>       MISA_EXT_INFO(RVG, "g", "General purpose (IMAFD_Zicsr_Zifencei)"),
> -    MISA_EXT_INFO(RVB, "b", "Bit manipulation (Zba_Zbb_Zbs)")
> +    MISA_EXT_INFO(RVB, "b", "Bit manipulation (Zba_Zbb_Zbs)"),
> +    MISA_EXT_INFO(RVP, "x-p", "Packed-SIMD instructions")
>   };
>   
>   static void riscv_cpu_validate_misa_mxl(RISCVCPUClass *mcc)
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index c9dfa7daff2..75cfb16d846 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -70,6 +70,7 @@ typedef struct CPUArchState CPURISCVState;
>   #define RVG RV('G')
>   #define RVB RV('B')
>   #define RVX RV('X')
> +#define RVP RV('P')
>   
>   extern const uint32_t misa_bits[];
>   const char *riscv_get_misa_ext_name(uint32_t bit);
> @@ -742,6 +743,13 @@ FIELD(TB_FLAGS, PM_SIGNEXTEND, 31, 1)
>   FIELD(EXT_TB_FLAGS, MISA_EXT, 0, 32)
>   FIELD(EXT_TB_FLAGS, ALTFMT, 32, 1)
>   FIELD(EXT_TB_FLAGS, BIG_ENDIAN, 33, 1)
> +FIELD(EXT_TB_FLAGS, P_VXSAT_EXCP, 34, 2)
> +
> +enum {
> +    P_VXSAT_EXCP_NONE,
> +    P_VXSAT_EXCP_ILLEGAL,
> +    P_VXSAT_EXCP_VIRTUAL,
> +};
>   
>   #ifdef TARGET_RISCV32
>   #define riscv_cpu_mxl(env)  ((void)(env), MXL_RV32)
> diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
> index 3f146a43fe4..fa7bf60f4fc 100644
> --- a/target/riscv/cpu_bits.h
> +++ b/target/riscv/cpu_bits.h
> @@ -355,6 +355,8 @@
>   #define SMSTATEEN0_CS       (1ULL << 0)
>   #define SMSTATEEN0_FCSR     (1ULL << 1)
>   #define SMSTATEEN0_JVT      (1ULL << 2)
> +/* Packed-SIMD draft: enable access to vxsat when misa.V = 0. */
> +#define SMSTATEEN0_VXSAT    (1ULL << 3)
>   #define SMSTATEEN0_CTR      (1ULL << 54)
>   #define SMSTATEEN0_P1P13    (1ULL << 56)
>   #define SMSTATEEN0_HSCONTXT (1ULL << 57)
> diff --git a/target/riscv/machine.c b/target/riscv/machine.c
> index 0ab613a2980..a9cd7e4c1cc 100644
> --- a/target/riscv/machine.c
> +++ b/target/riscv/machine.c
> @@ -158,6 +158,24 @@ static const VMStateDescription vmstate_vector = {
>       }
>   };
>   
> +static bool p_vxsat_needed(void *opaque)
> +{
> +    RISCVCPU *cpu = opaque;
> +
> +    return riscv_has_ext(&cpu->env, RVP) && !cpu->cfg.ext_zve32x;
> +}
> +
> +static const VMStateDescription vmstate_p_vxsat = {
> +    .name = "cpu/p-vxsat",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .needed = p_vxsat_needed,
> +    .fields = (const VMStateField[]) {
> +        VMSTATE_UINT8(env.vxsat, RISCVCPU),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
>   static bool pointermasking_needed(void *opaque)
>   {
>       return false;
> @@ -518,6 +536,7 @@ const VMStateDescription vmstate_riscv_cpu = {
>           &vmstate_pmp,
>           &vmstate_hyper,
>           &vmstate_vector,
> +        &vmstate_p_vxsat,
>           &vmstate_pointermasking,
>           &vmstate_rv128,
>   #ifdef CONFIG_KVM
> diff --git a/target/riscv/tcg/csr.c b/target/riscv/tcg/csr.c
> index 36f2004bc56..e809997f52e 100644
> --- a/target/riscv/tcg/csr.c
> +++ b/target/riscv/tcg/csr.c
> @@ -109,6 +109,24 @@ static RISCVException vs(CPURISCVState *env, int csrno)
>       return RISCV_EXCP_ILLEGAL_INST;
>   }
>   
> +/* vxsat is also architectural state when P is implemented without Zve*. */
> +static RISCVException vxsat(CPURISCVState *env, int csrno)
> +{
> +    if (riscv_cpu_cfg(env)->ext_zve32x) {
> +        return vs(env, csrno);
> +    }
> +
> +    if (riscv_has_ext(env, RVP)) {
> +#if !defined(CONFIG_USER_ONLY)
> +        return smstateen_acc_ok(env, 0, SMSTATEEN0_VXSAT);
> +#else
> +        return RISCV_EXCP_NONE;
> +#endif
> +    }
> +
> +    return RISCV_EXCP_ILLEGAL_INST;
> +}
> +
>   static RISCVException ctr(CPURISCVState *env, int csrno)
>   {
>   #if !defined(CONFIG_USER_ONLY)
> @@ -1013,7 +1031,12 @@ static RISCVException write_vxsat(CPURISCVState *env, int csrno,
>                                     target_ulong val, uintptr_t ra)
>   {
>   #if !defined(CONFIG_USER_ONLY)
> -    env->mstatus |= MSTATUS_VS;
> +    if (riscv_cpu_cfg(env)->ext_zve32x) {
> +        env->mstatus |= MSTATUS_VS;
> +        if (env->virt_enabled) {
> +            env->mstatus_hs |= MSTATUS_VS;
> +        }
> +    }
>   #endif
>       env->vxsat = val & BIT(0);
>       return RISCV_EXCP_NONE;
> @@ -3494,6 +3517,10 @@ static RISCVException write_mstateen0(CPURISCVState *env, int csrno,
>                                         target_ulong new_val, uintptr_t ra)
>   {
>       uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG;
> +
> +    if (riscv_has_ext(env, RVP) && !riscv_cpu_cfg(env)->ext_zve32x) {
> +        wr_mask |= SMSTATEEN0_VXSAT;
> +    }
>       if (!riscv_has_ext(env, RVF)) {
>           wr_mask |= SMSTATEEN0_FCSR;
>       }
> @@ -3617,6 +3644,10 @@ static RISCVException write_hstateen0(CPURISCVState *env, int csrno,
>   {
>       uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG;
>   
> +    if (riscv_has_ext(env, RVP) && !riscv_cpu_cfg(env)->ext_zve32x) {
> +        wr_mask |= SMSTATEEN0_VXSAT;
> +    }
> +
>       if (!riscv_has_ext(env, RVF)) {
>           wr_mask |= SMSTATEEN0_FCSR;
>       }
> @@ -3746,6 +3777,10 @@ static RISCVException write_sstateen0(CPURISCVState *env, int csrno,
>   {
>       uint64_t wr_mask = 0;
>   
> +    if (riscv_has_ext(env, RVP) && !riscv_cpu_cfg(env)->ext_zve32x) {
> +        wr_mask |= SMSTATEEN0_VXSAT;
> +    }
> +
>       if (!riscv_has_ext(env, RVF)) {
>           wr_mask |= SMSTATEEN0_FCSR;
>       }
> @@ -5916,7 +5951,7 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
>       [CSR_FCSR]     = { "fcsr",     fs,     read_fcsr,    write_fcsr   },
>       /* Vector CSRs */
>       [CSR_VSTART]   = { "vstart",   vs,     read_vstart,  write_vstart },
> -    [CSR_VXSAT]    = { "vxsat",    vs,     read_vxsat,   write_vxsat  },
> +    [CSR_VXSAT]    = { "vxsat",    vxsat,  read_vxsat,   write_vxsat  },
>       [CSR_VXRM]     = { "vxrm",     vs,     read_vxrm,    write_vxrm   },
>       [CSR_VCSR]     = { "vcsr",     vs,     read_vcsr,    write_vcsr   },
>       [CSR_VL]       = { "vl",       vs,     read_vl                    },
> diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
> index 4af5cd9c731..1665583accf 100644
> --- a/target/riscv/tcg/tcg-cpu.c
> +++ b/target/riscv/tcg/tcg-cpu.c
> @@ -160,6 +160,8 @@ static TCGTBCPUState riscv_get_tb_cpu_state(CPUState *cs)
>       fs = EXT_STATUS_DIRTY;
>       vs = EXT_STATUS_DIRTY;
>   #else
> +    RISCVException p_vxsat_excp;
> +
>       flags = FIELD_DP32(flags, TB_FLAGS, PRIV, env->priv);
>   
>       flags |= riscv_env_mmu_index(env, 0);
> @@ -182,6 +184,23 @@ static TCGTBCPUState riscv_get_tb_cpu_state(CPUState *cs)
>                ? EXT_STATUS_DIRTY : EXT_STATUS_DISABLED;
>       }
>   
> +    /*
> +     * Without Zve*, all P instructions in the OP-32 and OP-IMM-32
> +     * spaces are controlled by stateen0.VXSAT.  Preserve the exception
> +     * class in the TB flags so translated code can distinguish an illegal
> +     * instruction from a virtual-instruction exception.
> +     */
> +    p_vxsat_excp = smstateen_acc_ok(env, 0, SMSTATEEN0_VXSAT);
> +    if (riscv_has_ext(env, RVP) && !riscv_cpu_cfg(env)->ext_zve32x) {
> +        if (p_vxsat_excp == RISCV_EXCP_VIRT_INSTRUCTION_FAULT) {
> +            ext_flags = FIELD_DP64(ext_flags, EXT_TB_FLAGS, P_VXSAT_EXCP,
> +                                   P_VXSAT_EXCP_VIRTUAL);
> +        } else if (p_vxsat_excp != RISCV_EXCP_NONE) {
> +            ext_flags = FIELD_DP64(ext_flags, EXT_TB_FLAGS, P_VXSAT_EXCP,
> +                                   P_VXSAT_EXCP_ILLEGAL);
> +        }
> +    }
> +
>       if (cpu->cfg.debug && !icount_enabled()) {
>           flags = FIELD_DP32(flags, TB_FLAGS, ITRIGGER, env->itrigger_enabled);
>       }
> @@ -530,6 +549,28 @@ static void riscv_cpu_validate_b(RISCVCPU *cpu)
>       }
>   }
>   
> +static void riscv_cpu_validate_p(RISCVCPU *cpu, Error **errp)
> +{
> +    CPURISCVState *env = &cpu->env;
> +
> +    if (!riscv_has_ext(env, RVP)) {
> +        return;
> +    }
> +
> +    if (riscv_cpu_mxl(env) != MXL_RV32 &&
> +        riscv_cpu_mxl(env) != MXL_RV64) {
> +        error_setg(errp, "P extension requires RV32 or RV64");
> +        return;
> +    }
> +
> +    if (!(cpu->cfg.ext_zmmul && cpu->cfg.ext_zba && cpu->cfg.ext_zbb &&
> +          cpu->cfg.ext_zbkb)) {
> +        error_setg(errp, "P extension requires zmmul, zba, zbb and zbkb "
> +                         "extensions");
> +        return;
> +    }
> +}
> +
>   /*
>    * Check consistency between chosen extensions while setting
>    * cpu->cfg accordingly.
> @@ -612,6 +653,12 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp)
>           return;
>       }
>   
> +    riscv_cpu_validate_p(cpu, &local_err);
> +    if (local_err != NULL) {
> +        error_propagate(errp, local_err);
> +        return;
> +    }
> +
>       riscv_cpu_validate_v(env, &cpu->cfg, &local_err);
>       if (local_err != NULL) {
>           error_propagate(errp, local_err);
> @@ -1414,6 +1461,7 @@ static const RISCVCPUMisaExtConfig misa_ext_cfgs[] = {
>       MISA_CFG(RVV, false),
>       MISA_CFG(RVG, false),
>       MISA_CFG(RVB, false),
> +    MISA_CFG(RVP, false),
>   };
>   
>   /*



^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH v2 02/18] target/riscv: Add packed SIMD helper framework
  2026-07-17 10:06 ` [PATCH v2 02/18] target/riscv: Add packed SIMD helper framework Molly Chen
@ 2026-07-26 19:53   ` Daniel Henrique Barboza
  2026-07-27  6:16   ` Nutty.Liu
  2026-07-29  9:01   ` Chao Liu
  2 siblings, 0 replies; 34+ messages in thread
From: Daniel Henrique Barboza @ 2026-07-26 19:53 UTC (permalink / raw)
  To: Molly Chen, palmer, alistair.francis, liwei1518, zhiwei_liu,
	chao.liu.zevorn, Chao Liu
  Cc: qemu-riscv, qemu-devel



On 7/17/2026 7:06 AM, Molly Chen wrote:
> Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
> ---

There might be some code reduction opportunities in these helpers but
I'm afraid it'll come at a cost of readability.  I think this is fine
for now.


Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>


>   target/riscv/tcg/meson.build    |    3 +-
>   target/riscv/tcg/psimd_helper.c | 1656 +++++++++++++++++++++++++++++++
>   2 files changed, 1658 insertions(+), 1 deletion(-)
>   create mode 100644 target/riscv/tcg/psimd_helper.c
> 
> diff --git a/target/riscv/tcg/meson.build b/target/riscv/tcg/meson.build
> index a05ab642f41..cc438d7c0d2 100644
> --- a/target/riscv/tcg/meson.build
> +++ b/target/riscv/tcg/meson.build
> @@ -15,7 +15,8 @@ riscv_ss.add(files(
>     'vcrypto_helper.c',
>     'vector_helper.c',
>     'vector_internals.c',
> -  'zce_helper.c'))
> +  'zce_helper.c',
> +  'psimd_helper.c'))
>   
>   
>   riscv_system_ss.add(files(
> diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
> new file mode 100644
> index 00000000000..2948bbb2a86
> --- /dev/null
> +++ b/target/riscv/tcg/psimd_helper.c
> @@ -0,0 +1,1656 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/* RISC-V Packed SIMD Extension Helpers for QEMU. */
> +/* Copyright (C) 2026 ISRC ISCAS. */
> +
> +#include "qemu/osdep.h"
> +#include "cpu.h"
> +#include "qemu/host-utils.h"
> +#include "exec/helper-proto.h"
> +#include "fpu/softfloat.h"
> +#include "internals.h"
> +
> +
> +/* Helper macros */
> +
> +/* Element count calculations */
> +#define ELEMS_B(target) (sizeof(target) * 8 / 8)    /* byte elements count */
> +#define ELEMS_H(target) (sizeof(target) * 8 / 16)
> +#define ELEMS_W(target) (sizeof(target) * 8 / 32)   /* word elements count */
> +#define ELEMS_D(target) (sizeof(target) * 8 / 64)
> +
> +/* Element extraction macros - unsigned to avoid sign extension */
> +#define EXTRACT8(val, idx)  (((val) >> ((idx) * 8)) & 0xFF)
> +#define EXTRACT16(val, idx) (((val) >> ((idx) * 16)) & 0xFFFF)
> +#define EXTRACT32(val, idx) (((val) >> ((idx) * 32)) & 0xFFFFFFFF)
> +#define EXTRACT64(val, idx) (((val) >> ((idx) * 64)) & 0xFFFFFFFFFFFFFFFFULL)
> +
> +/* Element insertion macros */
> +#define INSERT8(val, res, idx) \
> +    ((val) | ((target_ulong)(uint8_t)(res) << ((idx) * 8)))
> +#define INSERT16(val, res, idx) \
> +    ((val) | ((target_ulong)(uint16_t)(res) << ((idx) * 16)))
> +#define INSERT32(val, res, idx) \
> +    ((val) | ((target_ulong)(uint32_t)(res) << ((idx) * 32)))
> +#define INSERT32_64(val, res, idx) \
> +    ((val) | ((uint64_t)(uint32_t)(res) << ((idx) * 32)))
> +#define INSERT64(val, res, idx) \
> +    ((val) | ((uint64_t)(res) << ((idx) * 64)))
> +
> +/* Saturation constants */
> +static const int8_t   SAT_MAX_B = 127;
> +static const int8_t   SAT_MIN_B = -128;
> +static const int16_t  SAT_MAX_H = 32767;
> +static const int16_t  SAT_MIN_H = -32768;
> +static const int32_t  SAT_MAX_W = 2147483647;
> +static const int32_t  SAT_MIN_W = -2147483648LL;
> +static const uint8_t  USAT_MAX_B = 255;
> +static const uint16_t USAT_MAX_H = 65535;
> +static const uint32_t USAT_MAX_W = 4294967295U;
> +
> +
> +/* Saturation helper functions */
> +
> +/**
> + * Signed saturation for 8-bit elements
> + * Returns saturated value and sets *sat if saturation occurred
> + */
> +static inline int8_t signed_saturate_b(int32_t val, int *sat)
> +{
> +    if (val > SAT_MAX_B) {
> +        *sat = 1;
> +        return SAT_MAX_B;
> +    }
> +    if (val < SAT_MIN_B) {
> +        *sat = 1;
> +        return SAT_MIN_B;
> +    }
> +    return (int8_t)val;
> +}
> +
> +/**
> + * Signed saturation for 16-bit elements
> + */
> +static inline int16_t signed_saturate_h(int32_t val, int *sat)
> +{
> +    if (val > SAT_MAX_H) {
> +        *sat = 1;
> +        return SAT_MAX_H;
> +    }
> +    if (val < SAT_MIN_H) {
> +        *sat = 1;
> +        return SAT_MIN_H;
> +    }
> +    return (int16_t)val;
> +}
> +
> +/**
> + * Signed saturation for 32-bit elements
> + */
> +static inline int32_t signed_saturate_w(int64_t val, int *sat)
> +{
> +    if (val > SAT_MAX_W) {
> +        *sat = 1;
> +        return SAT_MAX_W;
> +    }
> +    if (val < SAT_MIN_W) {
> +        *sat = 1;
> +        return SAT_MIN_W;
> +    }
> +    return (int32_t)val;
> +}
> +
> +/**
> + * Unsigned saturation for 8-bit elements
> + */
> +static inline uint8_t unsigned_saturate_b(uint32_t val, int *sat)
> +{
> +    if (val > USAT_MAX_B) {
> +        *sat = 1;
> +        return USAT_MAX_B;
> +    }
> +    return (uint8_t)val;
> +}
> +
> +/**
> + * Unsigned saturation for 16-bit elements
> + */
> +static inline uint16_t unsigned_saturate_h(uint32_t val, int *sat)
> +{
> +    if (val > USAT_MAX_H) {
> +        *sat = 1;
> +        return USAT_MAX_H;
> +    }
> +    return (uint16_t)val;
> +}
> +
> +/**
> + * Unsigned saturation for 32-bit elements
> + */
> +static inline uint32_t unsigned_saturate_w(uint64_t val, int *sat)
> +{
> +    if (val > USAT_MAX_W) {
> +        *sat = 1;
> +        return USAT_MAX_W;
> +    }
> +    return (uint32_t)val;
> +}
> +
> +static inline target_ulong psimd_abdsumu_b(target_ulong rs1,
> +                                           target_ulong rs2,
> +                                           target_ulong sum)
> +{
> +    int elems = ELEMS_B(rs1);
> +
> +    for (int i = 0; i < elems; i++) {
> +        uint8_t e1 = EXTRACT8(rs1, i);
> +        uint8_t e2 = EXTRACT8(rs2, i);
> +        uint8_t diff = (e1 > e2) ? (e1 - e2) : (e2 - e1);
> +        sum += diff;
> +    }
> +
> +    return sum;
> +}
> +
> +#define PSIMD_DO_ADD(N, M) ((N) + (M))
> +#define PSIMD_DO_SUB(N, M) ((N) - (M))
> +#define PSIMD_DO_ABD(N, M) ((N) >= (M) ? (N) - (M) : (M) - (N))
> +#define PSIMD_DO_EQ_MASK(N, M) ((N) == (M) ? -1 : 0)
> +#define PSIMD_DO_LT_MASK(N, M) ((N) < (M) ? -1 : 0)
> +#define PSIMD_DO_MIN(N, M) ((N) < (M) ? (N) : (M))
> +#define PSIMD_DO_MAX(N, M) ((N) > (M) ? (N) : (M))
> +#define PSIMD_DO_SLL(N, M) ((N) << (M))
> +#define PSIMD_DO_SRL(N, M) ((N) >> (M))
> +#define PSIMD_DO_SRA(N, M) ((N) >> (M))
> +
> +#define GEN_PSIMD_BINOP(NAME, RTYPE, STYPE, DTYPE, EXTRACT, INSERT,       \
> +                        ELEMS, OP)                                        \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        STYPE e1 = (STYPE)EXTRACT(rs1, i);                                \
> +        STYPE e2 = (STYPE)EXTRACT(rs2, i);                                \
> +        DTYPE res = (DTYPE)OP(e1, e2);                                    \
> +        rd = INSERT(rd, res, i);                                          \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_BINOP_SCALAR(NAME, RTYPE, ETYPE, EXTRACT, INSERT,       \
> +                               ELEMS, OP)                                 \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +    ETYPE e2 = (ETYPE)EXTRACT(rs2, 0);                                    \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
> +        ETYPE res = OP(e1, e2);                                           \
> +        rd = INSERT(rd, res, i);                                          \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_SHIFTOP(NAME, RTYPE, STYPE, DTYPE, EXTRACT, INSERT,     \
> +                          ELEMS, SHMASK, OP)                              \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +    uint8_t shamt = rs2 & (SHMASK);                                       \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        STYPE e1 = (STYPE)EXTRACT(rs1, i);                                \
> +        DTYPE res = (DTYPE)OP(e1, shamt);                                 \
> +        rd = INSERT(rd, res, i);                                          \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_SAT_SHIFTOP(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT, \
> +                              ELEMS, SHMASK, SAT_FN)                      \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +    int sat = 0;                                                          \
> +    uint8_t shamt = rs2 & (SHMASK);                                       \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
> +        WTYPE shifted = (WTYPE)e1 << shamt;                               \
> +        ETYPE res = SAT_FN(shifted, &sat);                                \
> +        rd = INSERT(rd, res, i);                                          \
> +    }                                                                     \
> +                                                                          \
> +    if (sat) {                                                            \
> +        env->vxsat = 1;                                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_ROUND_SRAI(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT,  \
> +                             ELEMS, SHMASK)                               \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +    uint8_t shamt = rs2 & (SHMASK);                                       \
> +                                                                          \
> +    if (shamt == 0) {                                                     \
> +        return rs1;                                                       \
> +    }                                                                     \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
> +        WTYPE rounded = (((WTYPE)e1 >> (shamt - 1)) + 1) >> 1;            \
> +        rd = INSERT(rd, (ETYPE)rounded, i);                               \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_SAT_BINOP(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT,   \
> +                            ELEMS, OP, SAT_FN)                            \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +    int sat = 0;                                                          \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
> +        ETYPE e2 = (ETYPE)EXTRACT(rs2, i);                                \
> +        WTYPE val = OP((WTYPE)e1, (WTYPE)e2);                             \
> +        ETYPE res = SAT_FN(val, &sat);                                    \
> +        rd = INSERT(rd, res, i);                                          \
> +    }                                                                     \
> +                                                                          \
> +    if (sat) {                                                            \
> +        env->vxsat = 1;                                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_USUB_SAT(NAME, RTYPE, ETYPE, EXTRACT, INSERT, ELEMS)    \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +    int sat = 0;                                                          \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
> +        ETYPE e2 = (ETYPE)EXTRACT(rs2, i);                                \
> +        ETYPE res = (e1 >= e2) ? (e1 - e2) : 0;                           \
> +        if (e1 < e2) {                                                    \
> +            sat = 1;                                                      \
> +        }                                                                 \
> +        rd = INSERT(rd, res, i);                                          \
> +    }                                                                     \
> +                                                                          \
> +    if (sat) {                                                            \
> +        env->vxsat = 1;                                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_AVG_BINOP(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT,   \
> +                            ELEMS, OP)                                    \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        WTYPE e1 = (WTYPE)(ETYPE)EXTRACT(rs1, i);                         \
> +        WTYPE e2 = (WTYPE)(ETYPE)EXTRACT(rs2, i);                         \
> +        ETYPE res = (ETYPE)(OP(e1, e2) >> 1);                             \
> +        rd = INSERT(rd, res, i);                                          \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_SHADD(NAME, RTYPE, ETYPE, EXTRACT, INSERT, ELEMS,       \
> +                        SHAMT)                                            \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
> +        ETYPE e2 = (ETYPE)EXTRACT(rs2, i);                                \
> +        ETYPE res = (e1 << (SHAMT)) + e2;                                 \
> +        rd = INSERT(rd, res, i);                                          \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_SAT_SHADD(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT,   \
> +                            ELEMS, SHAMT, SH_MIN, SH_MAX, SAT_MIN,        \
> +                            SAT_MAX, SAT_FN)                              \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +    int sat = 0;                                                          \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
> +        ETYPE e2 = (ETYPE)EXTRACT(rs2, i);                                \
> +        WTYPE shifted;                                                    \
> +                                                                          \
> +        if (e1 > (SH_MAX) || e1 < (SH_MIN)) {                             \
> +            shifted = (e1 < 0) ? (SAT_MIN) : (SAT_MAX);                   \
> +            sat = 1;                                                      \
> +        } else {                                                          \
> +            shifted = (WTYPE)e1 << (SHAMT);                               \
> +        }                                                                 \
> +                                                                          \
> +        WTYPE sum = shifted + e2;                                         \
> +        ETYPE res = SAT_FN(sum, &sat);                                    \
> +        rd = INSERT(rd, res, i);                                          \
> +    }                                                                     \
> +                                                                          \
> +    if (sat) {                                                            \
> +        env->vxsat = 1;                                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_SATI(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT,        \
> +                       ELEMS, IMMMASK)                                    \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE imm)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +    int range = (imm & (IMMMASK)) + 1;                                    \
> +    WTYPE max = ((WTYPE)1 << (range - 1)) - 1;                            \
> +    WTYPE min = -((WTYPE)1 << (range - 1));                               \
> +    int sat = 0;                                                          \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
> +        ETYPE res;                                                        \
> +                                                                          \
> +        if (e1 > max) {                                                   \
> +            res = max;                                                    \
> +            sat = 1;                                                      \
> +        } else if (e1 < min) {                                            \
> +            res = min;                                                    \
> +            sat = 1;                                                      \
> +        } else {                                                          \
> +            res = e1;                                                     \
> +        }                                                                 \
> +                                                                          \
> +        rd = INSERT(rd, res, i);                                          \
> +    }                                                                     \
> +                                                                          \
> +    if (sat) {                                                            \
> +        env->vxsat = 1;                                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_USATI(NAME, RTYPE, ETYPE, UTYPE, WTYPE, EXTRACT,        \
> +                        INSERT, ELEMS, ONE)                               \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE imm)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +    WTYPE max = ((WTYPE)(ONE) << imm) - 1;                                \
> +    int sat = 0;                                                          \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
> +        ETYPE res;                                                        \
> +                                                                          \
> +        if (e1 < 0) {                                                     \
> +            res = 0;                                                      \
> +            sat = 1;                                                      \
> +        } else if ((UTYPE)e1 > max) {                                     \
> +            res = max;                                                    \
> +            sat = 1;                                                      \
> +        } else {                                                          \
> +            res = e1;                                                     \
> +        }                                                                 \
> +                                                                          \
> +        rd = INSERT(rd, res, i);                                          \
> +    }                                                                     \
> +                                                                          \
> +    if (sat) {                                                            \
> +        env->vxsat = 1;                                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_ABS(NAME, RTYPE, ETYPE, EXTRACT, INSERT, ELEMS,         \
> +                      MINVAL, MAXVAL)                                     \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1)                         \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +    int sat = 0;                                                          \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
> +        ETYPE res;                                                        \
> +                                                                          \
> +        if (e1 == (MINVAL)) {                                             \
> +            res = (MAXVAL);                                               \
> +            sat = 1;                                                      \
> +        } else if (e1 < 0) {                                              \
> +            res = -e1;                                                    \
> +        } else {                                                          \
> +            res = e1;                                                     \
> +        }                                                                 \
> +                                                                          \
> +        rd = INSERT(rd, res, i);                                          \
> +    }                                                                     \
> +                                                                          \
> +    if (sat) {                                                            \
> +        env->vxsat = 1;                                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_SCALAR_ABS(NAME, RTYPE, STYPE, UTYPE)                   \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1)                         \
> +{                                                                         \
> +    STYPE value = (STYPE)rs1;                                            \
> +    UTYPE result = (UTYPE)value;                                         \
> +                                                                          \
> +    if (value < 0) {                                                      \
> +        result = (UTYPE)0 - result;                                      \
> +    }                                                                     \
> +    return (RTYPE)(STYPE)result;                                         \
> +}
> +
> +#define GEN_PSIMD_VAR_SSHA(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT,    \
> +                           ELEMS, BITS, SAT_FN)                           \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +    int sat = 0;                                                          \
> +    int8_t shamt = (int8_t)(rs2 & 0xff);                                  \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
> +        ETYPE res;                                                        \
> +                                                                          \
> +        if (shamt >= 0) {                                                 \
> +            WTYPE shifted = (WTYPE)e1 << shamt;                           \
> +            res = SAT_FN(shifted, &sat);                                  \
> +        } else {                                                          \
> +            int right = -shamt;                                           \
> +            if (right >= (BITS)) {                                        \
> +                res = (e1 < 0) ? -1 : 0;                                  \
> +            } else {                                                      \
> +                res = e1 >> right;                                        \
> +            }                                                             \
> +        }                                                                 \
> +                                                                          \
> +        rd = INSERT(rd, res, i);                                          \
> +    }                                                                     \
> +                                                                          \
> +    if (sat) {                                                            \
> +        env->vxsat = 1;                                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_VAR_SSHAR(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT,   \
> +                            ELEMS, BITS, SAT_MIN, SAT_MAX, SAT_FN)        \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +    int sat = 0;                                                          \
> +    int8_t shamt = (int8_t)(rs2 & 0xff);                                  \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
> +        ETYPE res;                                                        \
> +                                                                          \
> +        if (shamt >= 0) {                                                 \
> +            if (shamt >= (BITS)) {                                        \
> +                if (e1 == 0) {                                            \
> +                    res = 0;                                              \
> +                } else if (e1 > 0) {                                      \
> +                    res = (SAT_MAX);                                      \
> +                    sat = 1;                                              \
> +                } else {                                                  \
> +                    res = (SAT_MIN);                                      \
> +                    sat = 1;                                              \
> +                }                                                         \
> +            } else {                                                      \
> +                WTYPE shifted = (WTYPE)e1 * ((WTYPE)1 << shamt);          \
> +                res = SAT_FN(shifted, &sat);                              \
> +            }                                                             \
> +        } else {                                                          \
> +            int right = -shamt;                                           \
> +            if (right >= (BITS)) {                                        \
> +                res = 0;                                                  \
> +            } else {                                                      \
> +                WTYPE rounded = ((e1 >> (right - 1)) + 1) >> 1;           \
> +                res = (ETYPE)rounded;                                     \
> +            }                                                             \
> +        }                                                                 \
> +                                                                          \
> +        rd = INSERT(rd, res, i);                                          \
> +    }                                                                     \
> +                                                                          \
> +    if (sat) {                                                            \
> +        env->vxsat = 1;                                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_VAR_USHL(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT,    \
> +                           ELEMS, BITS, SAT_FN)                           \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +    int sat = 0;                                                          \
> +    int8_t shamt = (int8_t)(rs2 & 0xff);                                  \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
> +        ETYPE res;                                                        \
> +                                                                          \
> +        if (shamt >= 0) {                                                 \
> +            WTYPE shifted = (shamt >= (BITS)) ?                           \
> +                            ((WTYPE)e1 << (BITS)) :                       \
> +                            ((WTYPE)e1 << shamt);                         \
> +            res = SAT_FN(shifted, &sat);                                  \
> +        } else {                                                          \
> +            int right = -shamt;                                           \
> +            if (right >= (BITS)) {                                        \
> +                res = 0;                                                  \
> +            } else {                                                      \
> +                res = e1 >> right;                                        \
> +            }                                                             \
> +        }                                                                 \
> +                                                                          \
> +        rd = INSERT(rd, res, i);                                          \
> +    }                                                                     \
> +                                                                          \
> +    if (sat) {                                                            \
> +        env->vxsat = 1;                                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_VAR_USHLR(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT,   \
> +                            ELEMS, BITS, SAT_FN)                          \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +    int sat = 0;                                                          \
> +    int8_t shamt = (int8_t)(rs2 & 0xff);                                  \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
> +        ETYPE res;                                                        \
> +                                                                          \
> +        if (shamt >= 0) {                                                 \
> +            WTYPE shifted = (shamt >= (BITS)) ?                           \
> +                            ((WTYPE)e1 << (BITS)) :                       \
> +                            ((WTYPE)e1 << shamt);                         \
> +            res = SAT_FN(shifted, &sat);                                  \
> +        } else {                                                          \
> +            int right = -shamt;                                           \
> +            if (right > (BITS)) {                                         \
> +                res = 0;                                                  \
> +            } else {                                                      \
> +                WTYPE rounded = ((WTYPE)e1 >> (right - 1)) + 1;           \
> +                res = (ETYPE)(rounded >> 1);                              \
> +            }                                                             \
> +        }                                                                 \
> +                                                                          \
> +        rd = INSERT(rd, res, i);                                          \
> +    }                                                                     \
> +                                                                          \
> +    if (sat) {                                                            \
> +        env->vxsat = 1;                                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define PSIMD_DO_SRA64(A, B) ((A) >> (B))
> +#define PSIMD_DO_RNDSRA64(A, B)                                          \
> +    ((int64_t)((((__int128_t)(A) >> ((B) - 1)) + 1) >> 1))
> +
> +#define GEN_PSIMD_VAR_SRA64(NAME, RIGHT_OP)                               \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint64_t rs1, uint64_t rs2)     \
> +{                                                                         \
> +    int64_t a = (int64_t)rs1;                                            \
> +    int8_t shamt = (int8_t)(rs2 & 0xff);                                 \
> +                                                                          \
> +    if (shamt >= 0) {                                                     \
> +        return (uint64_t)(a << shamt);                                    \
> +    }                                                                     \
> +                                                                          \
> +    int right = -shamt;                                                   \
> +    if (right >= 64) {                                                    \
> +        return (a < 0) ? (uint64_t)-1 : 0;                               \
> +    }                                                                     \
> +    return (uint64_t)RIGHT_OP(a, right);                                  \
> +}
> +
> +#define PSIMD_DO_SRL64(A, B) (((B) >= 64) ? 0 : ((A) >> (B)))
> +#define PSIMD_DO_RNDSRL64(A, B)                                          \
> +    (((B) > 64) ? 0 : ((((A) >> ((B) - 1)) + 1) >> 1))
> +
> +#define GEN_PSIMD_VAR_SRL64(NAME, RIGHT_OP)                               \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint64_t rs1, uint64_t rs2)     \
> +{                                                                         \
> +    int8_t shamt = (int8_t)(rs2 & 0xff);                                 \
> +                                                                          \
> +    if (shamt < 0) {                                                      \
> +        return RIGHT_OP(rs1, -shamt);                                     \
> +    }                                                                     \
> +    return (shamt >= 64) ? 0 : (rs1 << shamt);                           \
> +}
> +
> +#define GEN_PSIMD_XPAIR_BINOP(NAME, RTYPE, ETYPE, EXTRACT, INSERT,        \
> +                              ELEMS, OP_LO, OP_HI)                        \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +                                                                          \
> +    for (int i = 0; i < elems; i += 2) {                                  \
> +        ETYPE s1_lo = (ETYPE)EXTRACT(rs1, i);                             \
> +        ETYPE s1_hi = (ETYPE)EXTRACT(rs1, i + 1);                         \
> +        ETYPE s2_lo = (ETYPE)EXTRACT(rs2, i);                             \
> +        ETYPE s2_hi = (ETYPE)EXTRACT(rs2, i + 1);                         \
> +        ETYPE res_lo = OP_LO(s1_lo, s2_hi);                               \
> +        ETYPE res_hi = OP_HI(s1_hi, s2_lo);                               \
> +        rd = INSERT(rd, res_lo, i);                                       \
> +        rd = INSERT(rd, res_hi, i + 1);                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_XPAIR_SAT_BINOP(NAME, RTYPE, ETYPE, WTYPE, EXTRACT,     \
> +                                  INSERT, ELEMS, OP_LO, OP_HI, SAT_FN)    \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +    int sat = 0;                                                          \
> +                                                                          \
> +    for (int i = 0; i < elems; i += 2) {                                  \
> +        ETYPE s1_lo = (ETYPE)EXTRACT(rs1, i);                             \
> +        ETYPE s1_hi = (ETYPE)EXTRACT(rs1, i + 1);                         \
> +        ETYPE s2_lo = (ETYPE)EXTRACT(rs2, i);                             \
> +        ETYPE s2_hi = (ETYPE)EXTRACT(rs2, i + 1);                         \
> +        WTYPE val_lo = OP_LO((WTYPE)s1_lo, (WTYPE)s2_hi);                 \
> +        WTYPE val_hi = OP_HI((WTYPE)s1_hi, (WTYPE)s2_lo);                 \
> +        ETYPE res_lo = SAT_FN(val_lo, &sat);                              \
> +        ETYPE res_hi = SAT_FN(val_hi, &sat);                              \
> +        rd = INSERT(rd, res_lo, i);                                       \
> +        rd = INSERT(rd, res_hi, i + 1);                                   \
> +    }                                                                     \
> +                                                                          \
> +    if (sat) {                                                            \
> +        env->vxsat = 1;                                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_XPAIR_AVG_BINOP(NAME, RTYPE, ETYPE, WTYPE, EXTRACT,     \
> +                                  INSERT, ELEMS, OP_LO, OP_HI)            \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +                                                                          \
> +    for (int i = 0; i < elems; i += 2) {                                  \
> +        ETYPE s1_lo = (ETYPE)EXTRACT(rs1, i);                             \
> +        ETYPE s1_hi = (ETYPE)EXTRACT(rs1, i + 1);                         \
> +        ETYPE s2_lo = (ETYPE)EXTRACT(rs2, i);                             \
> +        ETYPE s2_hi = (ETYPE)EXTRACT(rs2, i + 1);                         \
> +        ETYPE res_lo = (ETYPE)(OP_LO((WTYPE)s1_lo, (WTYPE)s2_hi) >> 1);   \
> +        ETYPE res_hi = (ETYPE)(OP_HI((WTYPE)s1_hi, (WTYPE)s2_lo) >> 1);   \
> +        rd = INSERT(rd, res_lo, i);                                       \
> +        rd = INSERT(rd, res_hi, i + 1);                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_REDSUM(NAME, RTYPE, SUMTYPE, ETYPE, EXTRACT, ELEMS,     \
> +                         INIT)                                            \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    SUMTYPE sum = (INIT);                                                 \
> +    int elems = ELEMS(rs1);                                               \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
> +        sum += e1;                                                        \
> +    }                                                                     \
> +                                                                          \
> +    return (RTYPE)sum;                                                    \
> +}
> +
> +#define PSIMD_PAIR_LO(V, MASK, SHIFT) ((V) & (MASK))
> +#define PSIMD_PAIR_HI(V, MASK, SHIFT) (((V) >> (SHIFT)) & (MASK))
> +
> +#define GEN_PSIMD_PAIR_PACK(NAME, RTYPE, ETYPE, EXTRACT, INSERT, ELEMS,   \
> +                            MASK, SHIFT, HI_SEL, LO_SEL)                 \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        ETYPE e1 = EXTRACT(rs1, i);                                       \
> +        ETYPE e2 = EXTRACT(rs2, i);                                       \
> +        ETYPE res = (HI_SEL(e2, MASK, SHIFT) << (SHIFT)) |                \
> +                    LO_SEL(e1, MASK, SHIFT);                              \
> +        rd = INSERT(rd, res, i);                                          \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_PAIR_WORD(NAME, RS1_IDX, RS2_IDX)                       \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint64_t rs1, uint64_t rs2)     \
> +{                                                                         \
> +    uint32_t e1 = EXTRACT32(rs1, RS1_IDX);                                \
> +    uint32_t e2 = EXTRACT32(rs2, RS2_IDX);                                \
> +                                                                          \
> +    return ((uint64_t)e2 << 32) | e1;                                     \
> +}
> +
> +#define GEN_PSIMD_SIGN_EXTEND(NAME, RTYPE, STYPE, DTYPE, EXTRACT, INSERT, \
> +                              ELEMS, SCALE)                               \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1)                         \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        STYPE e1 = (STYPE)EXTRACT(rs1, i * (SCALE));                      \
> +        rd = INSERT(rd, (DTYPE)e1, i);                                    \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_ZIP(NAME, ETYPE, EXTRACT, ELEMS, BITS, START)           \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint64_t rs1, uint64_t rs2)     \
> +{                                                                         \
> +    uint64_t rd = 0;                                                      \
> +                                                                          \
> +    for (int i = 0; i < (ELEMS); i++) {                                   \
> +        ETYPE e1 = EXTRACT(rs1, (START) - i);                             \
> +        ETYPE e2 = EXTRACT(rs2, (START) - i);                             \
> +        rd = (rd << (2 * (BITS))) | ((uint64_t)e2 << (BITS)) | e1;        \
> +    }                                                                     \
> +                                                                          \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_UNZIP(NAME, EXTRACT, ELEMS, BITS, OFFSET)               \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint64_t rs1, uint64_t rs2)     \
> +{                                                                         \
> +    uint64_t rd = 0;                                                      \
> +                                                                          \
> +    for (int i = 0; i < (ELEMS); i++) {                                   \
> +        uint64_t e1 = (uint64_t)EXTRACT(rs1, 2 * i + (OFFSET)) <<         \
> +                      ((BITS) * i);                                       \
> +        uint64_t e2 = (uint64_t)EXTRACT(rs2, 2 * i + (OFFSET)) <<         \
> +                      (32 + (BITS) * i);                                  \
> +        rd = rd | e2 | e1;                                                \
> +    }                                                                     \
> +                                                                          \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_BIT_SELECT(NAME, MASK, TRUE_VAL, FALSE_VAL)             \
> +target_ulong HELPER(NAME)(CPURISCVState *env, target_ulong rs1,           \
> +                          target_ulong rs2, target_ulong rd)              \
> +{                                                                         \
> +    return (~(MASK) & (FALSE_VAL)) | ((MASK) & (TRUE_VAL));               \
> +}
> +
> +#define GEN_PSIMD_NCLIP_PACK(NAME, ITYPE, OTYPE, EXTRACT, INSERT, ELEMS,  \
> +                             SAT_FN)                                      \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint64_t rs1, uint64_t rs2)     \
> +{                                                                         \
> +    uint64_t rd = 0;                                                      \
> +    int sat = 0;                                                          \
> +                                                                          \
> +    for (int i = 0; i < (ELEMS); i++) {                                   \
> +        ITYPE lo = (ITYPE)EXTRACT(rs1, i);                                \
> +        ITYPE hi = (ITYPE)EXTRACT(rs2, i);                                \
> +        OTYPE res_lo = SAT_FN(lo, &sat);                                  \
> +        OTYPE res_hi = SAT_FN(hi, &sat);                                  \
> +                                                                          \
> +        rd = (uint64_t)INSERT(rd, res_lo, i);                             \
> +        rd = (uint64_t)INSERT(rd, res_hi, i + (ELEMS));                   \
> +    }                                                                     \
> +                                                                          \
> +    if (sat) {                                                            \
> +        env->vxsat = 1;                                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_CLS(NAME, RTYPE, UTYPE, CLRSB)                          \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1)                         \
> +{                                                                         \
> +    return CLRSB((UTYPE)rs1);                                             \
> +}
> +
> +#define PSIMD_MUL_S32(A, B)  ((int32_t)(A) * (int32_t)(B))
> +#define PSIMD_MUL_SU16(A, B) ((int16_t)(A) * (uint16_t)(B))
> +#define PSIMD_MUL_SU32(A, B) ((int32_t)(A) * (uint32_t)(B))
> +#define PSIMD_MUL_U32(A, B)  ((uint32_t)(A) * (uint32_t)(B))
> +#define PSIMD_MUL_S64(A, B)  ((int64_t)(A) * (int64_t)(B))
> +#define PSIMD_MUL_SU64(A, B) ((int64_t)(A) * (uint64_t)(B))
> +#define PSIMD_MUL_U64(A, B)  ((uint64_t)(A) * (uint64_t)(B))
> +
> +#define GEN_PSIMD_MUL_HIGH(NAME, RTYPE, E1TYPE, E2TYPE, PTYPE, HTYPE,     \
> +                           EXTRACT, INSERT, ELEMS, SHIFT, ROUND, OP)     \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        E1TYPE e1 = (E1TYPE)EXTRACT(rs1, i);                              \
> +        E2TYPE e2 = (E2TYPE)EXTRACT(rs2, i);                              \
> +        PTYPE prod = OP(e1, e2) + (ROUND);                                \
> +        HTYPE high = (HTYPE)(prod >> (SHIFT));                            \
> +        rd = INSERT(rd, high, i);                                         \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_MUL_HIGH_SEL(NAME, RTYPE, E1TYPE, E2TYPE, PTYPE,        \
> +                               HTYPE, EXTRACT1, EXTRACT2, INSERT, ELEMS, \
> +                               SCALE, OFFSET, SHIFT, OP)                 \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        E1TYPE e1 = (E1TYPE)EXTRACT1(rs1, i);                             \
> +        E2TYPE e2 = (E2TYPE)EXTRACT2(rs2, i * (SCALE) + (OFFSET));        \
> +        PTYPE prod = OP(e1, e2);                                          \
> +        HTYPE high = (HTYPE)(prod >> (SHIFT));                            \
> +        rd = INSERT(rd, high, i);                                         \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_MUL_ELEM_INDEXED(NAME, RTYPE, E1TYPE, E2TYPE, PTYPE,    \
> +                                   OTYPE, EXTRACT, INSERT, ELEMS, SCALE, \
> +                                   OFFSET1, OFFSET2, OP)                 \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        E1TYPE e1 = (E1TYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET1));        \
> +        E2TYPE e2 = (E2TYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET2));        \
> +        PTYPE mul = OP(e1, e2);                                           \
> +        rd = INSERT(rd, (OTYPE)mul, i);                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_MUL_ELEM_SCALAR(NAME, RTYPE, E1TYPE, E2TYPE, PTYPE,     \
> +                                  EXTRACT, OFFSET1, OFFSET2, OP)         \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    E1TYPE e1 = (E1TYPE)EXTRACT(rs1, OFFSET1);                            \
> +    E2TYPE e2 = (E2TYPE)EXTRACT(rs2, OFFSET2);                            \
> +    PTYPE mul = OP(e1, e2);                                               \
> +                                                                          \
> +    return (RTYPE)mul;                                                    \
> +}
> +
> +#define GEN_PSIMD_MUL_HIGH_ACC(NAME, RTYPE, E1TYPE, E2TYPE, DTYPE, PTYPE, \
> +                               HTYPE, OTYPE, EXTRACT, INSERT, ELEMS,     \
> +                               SHIFT, ROUND, OP)                         \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2, RTYPE dest)  \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        E1TYPE e1 = (E1TYPE)EXTRACT(rs1, i);                              \
> +        E2TYPE e2 = (E2TYPE)EXTRACT(rs2, i);                              \
> +        DTYPE d = (DTYPE)EXTRACT(dest, i);                                \
> +        PTYPE prod = OP(e1, e2) + (ROUND);                                \
> +        HTYPE high = (HTYPE)(prod >> (SHIFT));                            \
> +        OTYPE res = (OTYPE)(high + d);                                    \
> +        rd = INSERT(rd, res, i);                                          \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_MUL_HIGH_ACC_SEL(NAME, RTYPE, E1TYPE, E2TYPE, DTYPE,    \
> +                                   PTYPE, HTYPE, OTYPE, EXTRACT1,        \
> +                                   EXTRACT2, INSERT, ELEMS, SCALE,       \
> +                                   OFFSET, SHIFT, OP)                    \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2, RTYPE dest)  \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        E1TYPE e1 = (E1TYPE)EXTRACT1(rs1, i);                             \
> +        E2TYPE e2 = (E2TYPE)EXTRACT2(rs2, i * (SCALE) + (OFFSET));        \
> +        DTYPE d = (DTYPE)EXTRACT1(dest, i);                               \
> +        PTYPE prod = OP(e1, e2);                                          \
> +        HTYPE high = (HTYPE)(prod >> (SHIFT));                            \
> +        OTYPE res = (OTYPE)(high + d);                                    \
> +        rd = INSERT(rd, res, i);                                          \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_MUL_ACC_INDEXED(NAME, RTYPE, E1TYPE, E2TYPE, DTYPE,     \
> +                                  PTYPE, OTYPE, EXTRACT, EXTRACTD,       \
> +                                  INSERT, ELEMS, SCALE, OFFSET1,         \
> +                                  OFFSET2, OP)                           \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2, RTYPE dest)  \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        E1TYPE e1 = (E1TYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET1));        \
> +        E2TYPE e2 = (E2TYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET2));        \
> +        DTYPE d = (DTYPE)EXTRACTD(dest, i);                               \
> +        PTYPE mul = OP(e1, e2);                                           \
> +        rd = INSERT(rd, (OTYPE)(d + mul), i);                             \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_QMUL(NAME, RTYPE, ETYPE, PTYPE, OTYPE, EXTRACT, INSERT, \
> +                       ELEMS, SHIFT, ROUND, MINVAL, MAXVAL)              \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +    int sat = 0;                                                          \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
> +        ETYPE e2 = (ETYPE)EXTRACT(rs2, i);                                \
> +        OTYPE result;                                                     \
> +                                                                          \
> +        if ((e1 == (ETYPE)(MINVAL)) && (e2 == (ETYPE)(MINVAL))) {         \
> +            sat = 1;                                                      \
> +            result = (OTYPE)(MAXVAL);                                     \
> +        } else {                                                          \
> +            PTYPE prod = (PTYPE)e1 * (PTYPE)e2 + (ROUND);                 \
> +            result = (OTYPE)(prod >> (SHIFT));                            \
> +        }                                                                 \
> +        rd = INSERT(rd, result, i);                                       \
> +    }                                                                     \
> +                                                                          \
> +    if (sat) {                                                            \
> +        env->vxsat = 1;                                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_QMUL_ACC_INDEXED(NAME, RTYPE, E1TYPE, E2TYPE, DTYPE,    \
> +                                   PTYPE, STYPE, OTYPE, EXTRACT,         \
> +                                   EXTRACTD, INSERT, ELEMS, SCALE,       \
> +                                   OFFSET1, OFFSET2, SHIFT, ROUND, OP)   \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2, RTYPE dest)  \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        E1TYPE e1 = (E1TYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET1));        \
> +        E2TYPE e2 = (E2TYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET2));        \
> +        DTYPE d = (DTYPE)EXTRACTD(dest, i);                               \
> +        PTYPE prod = OP(e1, e2) + (ROUND);                                \
> +        STYPE scaled = (STYPE)(((__int128_t)prod) >> (SHIFT));            \
> +        rd = INSERT(rd, (OTYPE)(d + scaled), i);                          \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_Q2ADD(NAME, RTYPE, ETYPE, PTYPE, STYPE, OTYPE, EXTRACT, \
> +                        INSERT, ELEMS, SCALE, SHIFT, ROUND, OP)          \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        ETYPE s1_0 = (ETYPE)EXTRACT(rs1, i * (SCALE));                   \
> +        ETYPE s1_1 = (ETYPE)EXTRACT(rs1, i * (SCALE) + 1);               \
> +        ETYPE s2_0 = (ETYPE)EXTRACT(rs2, i * (SCALE));                   \
> +        ETYPE s2_1 = (ETYPE)EXTRACT(rs2, i * (SCALE) + 1);               \
> +        PTYPE prod0 = OP(s1_0, s2_0) + (ROUND);                          \
> +        PTYPE prod1 = OP(s1_1, s2_1) + (ROUND);                          \
> +        STYPE scaled0 = (STYPE)(((__int128_t)prod0) >> (SHIFT));          \
> +        STYPE scaled1 = (STYPE)(((__int128_t)prod1) >> (SHIFT));          \
> +        rd = INSERT(rd, (OTYPE)(scaled0 + scaled1), i);                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_Q2ADDA(NAME, RTYPE, ETYPE, DTYPE, PTYPE, STYPE, OTYPE,  \
> +                         EXTRACT, EXTRACTD, INSERT, ELEMS, SCALE,        \
> +                         SHIFT, ROUND, OP)                               \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2, RTYPE dest)  \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        ETYPE s1_0 = (ETYPE)EXTRACT(rs1, i * (SCALE));                   \
> +        ETYPE s1_1 = (ETYPE)EXTRACT(rs1, i * (SCALE) + 1);               \
> +        ETYPE s2_0 = (ETYPE)EXTRACT(rs2, i * (SCALE));                   \
> +        ETYPE s2_1 = (ETYPE)EXTRACT(rs2, i * (SCALE) + 1);               \
> +        DTYPE d = (DTYPE)EXTRACTD(dest, i);                               \
> +        PTYPE prod0 = OP(s1_0, s2_0) + (ROUND);                          \
> +        PTYPE prod1 = OP(s1_1, s2_1) + (ROUND);                          \
> +        STYPE scaled0 = (STYPE)(((__int128_t)prod0) >> (SHIFT));          \
> +        STYPE scaled1 = (STYPE)(((__int128_t)prod1) >> (SHIFT));          \
> +        rd = INSERT(rd, (OTYPE)(d + scaled0 + scaled1), i);               \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define PSIMD_COMB_ADD(D, A, B) ((D) + (A) + (B))
> +#define PSIMD_COMB_SUB(D, A, B) ((D) + (A) - (B))
> +
> +#define GEN_PSIMD_2WAY_MUL(NAME, RTYPE, E1TYPE, E2TYPE, PTYPE, OTYPE,     \
> +                           EXTRACT, INSERT, ELEMS, SCALE, OFFSET10,      \
> +                           OFFSET11, OFFSET20, OFFSET21, OP, COMBINE)   \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        E1TYPE s1_0 = (E1TYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET10));     \
> +        E1TYPE s1_1 = (E1TYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET11));     \
> +        E2TYPE s2_0 = (E2TYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET20));     \
> +        E2TYPE s2_1 = (E2TYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET21));     \
> +        PTYPE prod0 = OP(s1_0, s2_0);                                     \
> +        PTYPE prod1 = OP(s1_1, s2_1);                                     \
> +        rd = INSERT(rd, (OTYPE)COMBINE(0, prod0, prod1), i);              \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_2WAY_SAT_MUL(NAME, OFFSET10, OFFSET11, OFFSET20,        \
> +                               OFFSET21)                                 \
> +target_ulong HELPER(NAME)(CPURISCVState *env, target_ulong rs1,           \
> +                           target_ulong rs2)                              \
> +{                                                                         \
> +    target_ulong rd = 0;                                                  \
> +    int sat = 0;                                                          \
> +                                                                          \
> +    for (int i = 0; i < ELEMS_W(rd); i++) {                               \
> +        int16_t s1_0 = (int16_t)EXTRACT16(rs1, i * 2 + (OFFSET10));       \
> +        int16_t s1_1 = (int16_t)EXTRACT16(rs1, i * 2 + (OFFSET11));       \
> +        int16_t s2_0 = (int16_t)EXTRACT16(rs2, i * 2 + (OFFSET20));       \
> +        int16_t s2_1 = (int16_t)EXTRACT16(rs2, i * 2 + (OFFSET21));       \
> +        uint32_t result;                                                  \
> +                                                                          \
> +        if (s1_0 == INT16_MIN && s1_1 == INT16_MIN &&                    \
> +            s2_0 == INT16_MIN && s2_1 == INT16_MIN) {                    \
> +            result = INT32_MAX;                                          \
> +            sat = 1;                                                      \
> +        } else {                                                          \
> +            int32_t prod0 = (int32_t)s1_0 * s2_0;                        \
> +            int32_t prod1 = (int32_t)s1_1 * s2_1;                        \
> +            result = (uint32_t)(prod0 + prod1);                           \
> +        }                                                                 \
> +        rd = INSERT32(rd, result, i);                                     \
> +    }                                                                     \
> +                                                                          \
> +    if (sat) {                                                            \
> +        env->vxsat = 1;                                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_2WAY_MUL_ACC(NAME, RTYPE, E1TYPE, E2TYPE, DTYPE, PTYPE, \
> +                               OTYPE, EXTRACT, EXTRACTD, INSERT, ELEMS,  \
> +                               SCALE, OFFSET10, OFFSET11, OFFSET20,      \
> +                               OFFSET21, OP, COMBINE)                   \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2, RTYPE dest)  \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        E1TYPE s1_0 = (E1TYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET10));     \
> +        E1TYPE s1_1 = (E1TYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET11));     \
> +        E2TYPE s2_0 = (E2TYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET20));     \
> +        E2TYPE s2_1 = (E2TYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET21));     \
> +        DTYPE d = (DTYPE)EXTRACTD(dest, i);                               \
> +        PTYPE prod0 = OP(s1_0, s2_0);                                     \
> +        PTYPE prod1 = OP(s1_1, s2_1);                                     \
> +        rd = INSERT(rd, (OTYPE)COMBINE(d, prod0, prod1), i);              \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_4WAY_MUL(NAME, RTYPE, E1TYPE, E2TYPE, PTYPE, OTYPE,     \
> +                           EXTRACT, INSERT, ELEMS, SCALE, OP)            \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        PTYPE prod0 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE)),              \
> +                         (E2TYPE)EXTRACT(rs2, i * (SCALE)));             \
> +        PTYPE prod1 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE) + 1),          \
> +                         (E2TYPE)EXTRACT(rs2, i * (SCALE) + 1));         \
> +        PTYPE prod2 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE) + 2),          \
> +                         (E2TYPE)EXTRACT(rs2, i * (SCALE) + 2));         \
> +        PTYPE prod3 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE) + 3),          \
> +                         (E2TYPE)EXTRACT(rs2, i * (SCALE) + 3));         \
> +        rd = INSERT(rd, (OTYPE)(prod0 + prod1 + prod2 + prod3), i);       \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_4WAY_MUL_ACC(NAME, RTYPE, E1TYPE, E2TYPE, DTYPE, PTYPE, \
> +                               OTYPE, EXTRACT, EXTRACTD, INSERT, ELEMS,  \
> +                               SCALE, OP)                                \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2, RTYPE dest)  \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        DTYPE d = (DTYPE)EXTRACTD(dest, i);                               \
> +        PTYPE prod0 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE)),              \
> +                         (E2TYPE)EXTRACT(rs2, i * (SCALE)));             \
> +        PTYPE prod1 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE) + 1),          \
> +                         (E2TYPE)EXTRACT(rs2, i * (SCALE) + 1));         \
> +        PTYPE prod2 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE) + 2),          \
> +                         (E2TYPE)EXTRACT(rs2, i * (SCALE) + 2));         \
> +        PTYPE prod3 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE) + 3),          \
> +                         (E2TYPE)EXTRACT(rs2, i * (SCALE) + 3));         \
> +        rd = INSERT(rd, (OTYPE)(d + prod0 + prod1 + prod2 + prod3), i);   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_WIDEN_BINOP(NAME, ETYPE, WTYPE, OTYPE, ELEMS, IBITS,    \
> +                              OBITS, IMASK, OP)                          \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2)     \
> +{                                                                         \
> +    uint64_t rd = 0;                                                      \
> +                                                                          \
> +    for (int i = 0; i < (ELEMS); i++) {                                   \
> +        ETYPE e1 = (ETYPE)((rs1 >> (i * (IBITS))) & (IMASK));             \
> +        ETYPE e2 = (ETYPE)((rs2 >> (i * (IBITS))) & (IMASK));             \
> +        WTYPE res = OP((WTYPE)0, (WTYPE)e1, (WTYPE)e2);                   \
> +        rd |= ((uint64_t)(OTYPE)res) << (i * (OBITS));                    \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_WIDEN_BINOP_ACC(NAME, ETYPE, WTYPE, OTYPE, ELEMS,       \
> +                                  IBITS, OBITS, IMASK, OMASK, OP)        \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2,     \
> +                      uint64_t dest)                                      \
> +{                                                                         \
> +    uint64_t rd = 0;                                                      \
> +                                                                          \
> +    for (int i = 0; i < (ELEMS); i++) {                                   \
> +        ETYPE e1 = (ETYPE)((rs1 >> (i * (IBITS))) & (IMASK));             \
> +        ETYPE e2 = (ETYPE)((rs2 >> (i * (IBITS))) & (IMASK));             \
> +        WTYPE acc = (WTYPE)((dest >> (i * (OBITS))) & (OMASK));           \
> +        WTYPE res = OP(acc, (WTYPE)e1, (WTYPE)e2);                        \
> +        rd |= ((uint64_t)(OTYPE)res) << (i * (OBITS));                    \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_WIDEN_MUL(NAME, E1TYPE, E2TYPE, PTYPE, OTYPE, ELEMS,    \
> +                            EXTRACT, OBITS, OP)                          \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2)     \
> +{                                                                         \
> +    uint64_t rd = 0;                                                      \
> +                                                                          \
> +    for (int i = 0; i < (ELEMS); i++) {                                   \
> +        E1TYPE e1 = (E1TYPE)EXTRACT(rs1, i);                              \
> +        E2TYPE e2 = (E2TYPE)EXTRACT(rs2, i);                              \
> +        PTYPE prod = OP(e1, e2);                                          \
> +        rd |= ((uint64_t)(OTYPE)prod) << (i * (OBITS));                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_WIDEN_MUL_ACC(NAME, E1TYPE, E2TYPE, DTYPE, PTYPE,       \
> +                                OTYPE, ELEMS, EXTRACT, EXTRACTD, OBITS,  \
> +                                OP)                                      \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2,     \
> +                      uint64_t dest)                                      \
> +{                                                                         \
> +    uint64_t rd = 0;                                                      \
> +                                                                          \
> +    for (int i = 0; i < (ELEMS); i++) {                                   \
> +        E1TYPE e1 = (E1TYPE)EXTRACT(rs1, i);                              \
> +        E2TYPE e2 = (E2TYPE)EXTRACT(rs2, i);                              \
> +        DTYPE d = (DTYPE)EXTRACTD(dest, i);                               \
> +        PTYPE prod = OP(e1, e2);                                          \
> +        rd |= ((uint64_t)(OTYPE)(d + prod)) << (i * (OBITS));             \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_WIDEN_QMUL_ACC(NAME, ETYPE, DTYPE, PTYPE, STYPE,        \
> +                                 OTYPE, ELEMS, EXTRACT, EXTRACTD, SCALE, \
> +                                 OFFSET, SHIFT, ROUND, OBITS, OP)        \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2,     \
> +                      uint64_t dest)                                      \
> +{                                                                         \
> +    uint64_t rd = 0;                                                      \
> +                                                                          \
> +    for (int i = 0; i < (ELEMS); i++) {                                   \
> +        ETYPE e1 = (ETYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET));           \
> +        ETYPE e2 = (ETYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET));           \
> +        DTYPE d = (DTYPE)EXTRACTD(dest, i);                               \
> +        PTYPE prod = OP(e1, e2) + (ROUND);                                \
> +        STYPE scaled = (STYPE)(((__int128_t)prod) >> (SHIFT));            \
> +        rd |= ((uint64_t)(OTYPE)(d + scaled)) << (i * (OBITS));           \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_DW_2WAY_MUL(NAME, E1TYPE, E2TYPE, PTYPE, EXTRACT,       \
> +                              OFFSET10, OFFSET11, OFFSET20, OFFSET21,    \
> +                              OP, COMBINE)                               \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2)     \
> +{                                                                         \
> +    E1TYPE s1_0 = (E1TYPE)EXTRACT(rs1, OFFSET10);                         \
> +    E1TYPE s1_1 = (E1TYPE)EXTRACT(rs1, OFFSET11);                         \
> +    E2TYPE s2_0 = (E2TYPE)EXTRACT(rs2, OFFSET20);                         \
> +    E2TYPE s2_1 = (E2TYPE)EXTRACT(rs2, OFFSET21);                         \
> +    PTYPE prod0 = OP(s1_0, s2_0);                                        \
> +    PTYPE prod1 = OP(s1_1, s2_1);                                        \
> +                                                                          \
> +    return (uint64_t)COMBINE(0, prod0, prod1);                            \
> +}
> +
> +#define GEN_PSIMD_DW_2WAY_MUL_ACC(NAME, E1TYPE, E2TYPE, DTYPE, PTYPE,     \
> +                                  EXTRACT, OFFSET10, OFFSET11, OFFSET20, \
> +                                  OFFSET21, OP, COMBINE)                \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2,     \
> +                      uint64_t dest)                                      \
> +{                                                                         \
> +    E1TYPE s1_0 = (E1TYPE)EXTRACT(rs1, OFFSET10);                         \
> +    E1TYPE s1_1 = (E1TYPE)EXTRACT(rs1, OFFSET11);                         \
> +    E2TYPE s2_0 = (E2TYPE)EXTRACT(rs2, OFFSET20);                         \
> +    E2TYPE s2_1 = (E2TYPE)EXTRACT(rs2, OFFSET21);                         \
> +    DTYPE d = (DTYPE)dest;                                                \
> +    PTYPE prod0 = OP(s1_0, s2_0);                                        \
> +    PTYPE prod1 = OP(s1_1, s2_1);                                        \
> +                                                                          \
> +    return (uint64_t)COMBINE(d, prod0, prod1);                            \
> +}
> +
> +#define GEN_PSIMD_WIDEN_SHIFT(NAME, ETYPE, WTYPE, OTYPE, ELEMS, IBITS,    \
> +                              OBITS, IMASK, SHMASK)                      \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2)     \
> +{                                                                         \
> +    uint64_t rd = 0;                                                      \
> +    uint8_t shamt = rs2 & (SHMASK);                                       \
> +                                                                          \
> +    for (int i = 0; i < (ELEMS); i++) {                                   \
> +        ETYPE e1 = (ETYPE)((rs1 >> (i * (IBITS))) & (IMASK));             \
> +        WTYPE res = (WTYPE)e1 << shamt;                                   \
> +        rd |= ((uint64_t)(OTYPE)res) << (i * (OBITS));                    \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_DW_ZIP(NAME, EXTRACT, ELEMS, STRIDE, BITS)              \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2)     \
> +{                                                                         \
> +    uint64_t rd = 0;                                                      \
> +                                                                          \
> +    for (int i = 0; i < (ELEMS); i++) {                                   \
> +        uint64_t e1 = (uint64_t)EXTRACT(rs1, i) << ((STRIDE) * i);        \
> +        uint64_t e2 = (uint64_t)EXTRACT(rs2, i)                           \
> +                      << ((STRIDE) * i + (BITS));                         \
> +        rd |= e2 | e1;                                                    \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_DW_REDSUM(NAME, SUMTYPE, INITTYPE, ETYPE, EXTRACT,      \
> +                            ELEMS)                                        \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1_lo,                \
> +                      uint32_t rs1_hi, uint32_t rs2)                      \
> +{                                                                         \
> +    SUMTYPE sum = (INITTYPE)rs2;                                          \
> +    uint64_t s1 = ((uint64_t)rs1_hi << 32) | rs1_lo;                      \
> +                                                                          \
> +    for (int i = 0; i < (ELEMS); i++) {                                   \
> +        sum += (ETYPE)EXTRACT(s1, i);                                     \
> +    }                                                                     \
> +    return (uint32_t)sum;                                                 \
> +}
> +
> +#define GEN_PSIMD_NARROW_SRL(NAME, ETYPE, OTYPE, ELEMS, IBITS, OBITS,     \
> +                             IMASK, SHMASK)                               \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
> +{                                                                         \
> +    uint32_t rd = 0;                                                      \
> +    uint8_t shift = shamt & (SHMASK);                                     \
> +                                                                          \
> +    for (int i = 0; i < (ELEMS); i++) {                                   \
> +        ETYPE e1 = (ETYPE)((s1 >> (i * (IBITS))) & (IMASK));              \
> +        OTYPE result = (OTYPE)(e1 >> shift);                              \
> +        rd |= ((uint32_t)result) << (i * (OBITS));                        \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_NARROW_SRA_PACK(NAME, ETYPE, STYPE, OTYPE, ELEMS,       \
> +                                  IBITS, OBITS, IMASK, SHMASK)            \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
> +{                                                                         \
> +    uint32_t rd = 0;                                                      \
> +    uint8_t shift = shamt & (SHMASK);                                     \
> +                                                                          \
> +    for (int i = 0; i < (ELEMS); i++) {                                   \
> +        ETYPE e1 = (ETYPE)((s1 >> (i * (IBITS))) & (IMASK));              \
> +        STYPE shx = (STYPE)e1 >> shift;                                   \
> +        OTYPE result = (OTYPE)shx;                                        \
> +        rd |= ((uint32_t)result) << (i * (OBITS));                        \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_NARROW_RNDSRA_PACK(NAME, ETYPE, STYPE, OTYPE, ELEMS,    \
> +                                     IBITS, OBITS, IMASK, SHMASK, RMASK)  \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
> +{                                                                         \
> +    uint32_t rd = 0;                                                      \
> +    uint8_t shift = shamt & (SHMASK);                                     \
> +                                                                          \
> +    for (int i = 0; i < (ELEMS); i++) {                                   \
> +        ETYPE e1 = (ETYPE)((s1 >> (i * (IBITS))) & (IMASK));              \
> +        STYPE e1_s = (STYPE)e1;                                           \
> +        uint64_t shx = (((uint64_t)e1_s << 1) >> shift) & (RMASK);        \
> +        OTYPE result = (OTYPE)((shx + 1) >> 1);                           \
> +        rd |= ((uint32_t)result) << (i * (OBITS));                        \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_NCLIP_SIGNED_PACK(NAME, ETYPE, STYPE, CTYPE, OTYPE,     \
> +                                    ELEMS, IBITS, OBITS, IMASK, SHMASK,   \
> +                                    MIN, MAX, MIN_RES, MAX_RES)           \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
> +{                                                                         \
> +    uint32_t rd = 0;                                                      \
> +    uint8_t shift = shamt & (SHMASK);                                     \
> +    int sat = 0;                                                          \
> +                                                                          \
> +    for (int i = 0; i < (ELEMS); i++) {                                   \
> +        ETYPE e1 = (ETYPE)((s1 >> (i * (IBITS))) & (IMASK));              \
> +        CTYPE shx = (CTYPE)((STYPE)e1 >> shift);                          \
> +        OTYPE result;                                                     \
> +                                                                          \
> +        if (shx < (MIN)) {                                                \
> +            sat = 1;                                                      \
> +            result = (MIN_RES);                                           \
> +        } else if (shx > (MAX)) {                                         \
> +            sat = 1;                                                      \
> +            result = (MAX_RES);                                           \
> +        } else {                                                          \
> +            result = (OTYPE)shx;                                          \
> +        }                                                                 \
> +        rd |= ((uint32_t)result) << (i * (OBITS));                        \
> +    }                                                                     \
> +                                                                          \
> +    if (sat) {                                                            \
> +        env->vxsat = 1;                                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_NCLIPR_SIGNED_PACK(NAME, ETYPE, STYPE, CTYPE, OTYPE,    \
> +                                     ELEMS, IBITS, OBITS, IMASK, SHMASK,  \
> +                                     RMASK, MIN, MAX, MIN_RES, MAX_RES)   \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
> +{                                                                         \
> +    uint32_t rd = 0;                                                      \
> +    uint8_t shift = shamt & (SHMASK);                                     \
> +    int sat = 0;                                                          \
> +                                                                          \
> +    for (int i = 0; i < (ELEMS); i++) {                                   \
> +        ETYPE e1 = (ETYPE)((s1 >> (i * (IBITS))) & (IMASK));              \
> +        STYPE e1_s = (STYPE)e1;                                           \
> +        uint64_t shx = (((uint64_t)e1_s << 1) >> shift) & (RMASK);        \
> +        CTYPE round_shx = (CTYPE)((shx + 1) >> 1);                        \
> +        OTYPE result;                                                     \
> +                                                                          \
> +        if (round_shx < (MIN)) {                                          \
> +            sat = 1;                                                      \
> +            result = (MIN_RES);                                           \
> +        } else if (round_shx > (MAX)) {                                   \
> +            sat = 1;                                                      \
> +            result = (MAX_RES);                                           \
> +        } else {                                                          \
> +            result = (OTYPE)round_shx;                                    \
> +        }                                                                 \
> +        rd |= ((uint32_t)result) << (i * (OBITS));                        \
> +    }                                                                     \
> +                                                                          \
> +    if (sat) {                                                            \
> +        env->vxsat = 1;                                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_NCLIP_UNSIGNED_PACK(NAME, ETYPE, WTYPE, OTYPE, ELEMS,   \
> +                                      IBITS, OBITS, IMASK, SHMASK, MAX)   \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
> +{                                                                         \
> +    uint32_t rd = 0;                                                      \
> +    uint8_t shift = shamt & (SHMASK);                                     \
> +    int sat = 0;                                                          \
> +                                                                          \
> +    for (int i = 0; i < (ELEMS); i++) {                                   \
> +        ETYPE e1 = (ETYPE)((s1 >> (i * (IBITS))) & (IMASK));              \
> +        WTYPE shx = (WTYPE)e1 >> shift;                                   \
> +        OTYPE result;                                                     \
> +                                                                          \
> +        if (shx > (MAX)) {                                                \
> +            sat = 1;                                                      \
> +            result = (OTYPE)(MAX);                                        \
> +        } else {                                                          \
> +            result = (OTYPE)shx;                                          \
> +        }                                                                 \
> +        rd |= ((uint32_t)result) << (i * (OBITS));                        \
> +    }                                                                     \
> +                                                                          \
> +    if (sat) {                                                            \
> +        env->vxsat = 1;                                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_NCLIPR_UNSIGNED_PACK(NAME, ETYPE, WTYPE, OTYPE, ELEMS,  \
> +                                       IBITS, OBITS, IMASK, SHMASK, MAX)  \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
> +{                                                                         \
> +    uint32_t rd = 0;                                                      \
> +    uint8_t shift = shamt & (SHMASK);                                     \
> +    int sat = 0;                                                          \
> +                                                                          \
> +    for (int i = 0; i < (ELEMS); i++) {                                   \
> +        ETYPE e1 = (ETYPE)((s1 >> (i * (IBITS))) & (IMASK));              \
> +        WTYPE shx = ((WTYPE)e1 << 1) >> shift;                            \
> +        WTYPE round_shx = (shx + 1) >> 1;                                 \
> +        OTYPE result;                                                     \
> +                                                                          \
> +        if (round_shx > (MAX)) {                                          \
> +            sat = 1;                                                      \
> +            result = (OTYPE)(MAX);                                        \
> +        } else {                                                          \
> +            result = (OTYPE)round_shx;                                    \
> +        }                                                                 \
> +        rd |= ((uint32_t)result) << (i * (OBITS));                        \
> +    }                                                                     \
> +                                                                          \
> +    if (sat) {                                                            \
> +        env->vxsat = 1;                                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_NARROW_SRA(NAME)                                        \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
> +{                                                                         \
> +    __int128_t s1_s128 = (__int128_t)((int64_t)s1);                       \
> +    __int128_t s1_s96 = (s1_s128 << 32) >> 32;                            \
> +                                                                          \
> +    return (uint32_t)(s1_s96 >> (shamt & 0x3F)) & 0xFFFFFFFF;             \
> +}
> +
> +#define GEN_PSIMD_NARROW_RNDSRA(NAME)                                     \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
> +{                                                                         \
> +    __int128_t s1_s128 = (__int128_t)((int64_t)s1);                       \
> +    __int128_t s1_s96 = (s1_s128 << 32) >> 32;                            \
> +    __uint128_t shx_97bit = ((__uint128_t)s1_s96 << 1);                   \
> +    uint64_t shx = (uint64_t)(shx_97bit >> (shamt & 0x3F)) & 0x1FFFFFFFF; \
> +                                                                          \
> +    return (uint32_t)((shx + 1) >> 1);                                    \
> +}
> +
> +#define GEN_PSIMD_NARROW_ALIAS(NAME, TARGET)                              \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
> +{                                                                         \
> +    return HELPER(TARGET)(env, s1, shamt);                                \
> +}
> +
> +typedef struct {
> +    __uint128_t low;
> +    uint8_t high;
> +} PsImdUint129;
> +
> +static inline PsImdUint129 psimd_uint129_lshift1(__int128_t val)
> +{
> +    PsImdUint129 result;
> +    __uint128_t uval = (__uint128_t)val;
> +
> +    result.low = uval << 1;
> +    result.high = (uval >> 127) & 0x1;
> +    return result;
> +}
> +
> +static inline PsImdUint129 psimd_uint129_rshift(PsImdUint129 val,
> +                                                uint32_t shamt)
> +{
> +    PsImdUint129 result;
> +
> +    if (shamt == 0) {
> +        return val;
> +    } else if (shamt >= 129) {
> +        result.low = 0;
> +        result.high = 0;
> +    } else if (shamt == 128) {
> +        result.low = val.high;
> +        result.high = 0;
> +    } else {
> +        result.low = (val.low >> shamt) |
> +                     ((__uint128_t)val.high << (128 - shamt));
> +        result.high = val.high >> shamt;
> +    }
> +    return result;
> +}
> +
> +#define GEN_PSIMD_NCLIP(NAME)                                             \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
> +{                                                                         \
> +    __int128_t s1_s128 = (__int128_t)((int64_t)s1);                       \
> +    int64_t shx = (int64_t)(s1_s128 >> (shamt & 0x3F));                  \
> +                                                                          \
> +    if (shx < -2147483648LL) {                                            \
> +        env->vxsat = 1;                                                   \
> +        return 0x80000000U;                                               \
> +    } else if (shx > 2147483647LL) {                                      \
> +        env->vxsat = 1;                                                   \
> +        return 0x7FFFFFFFU;                                               \
> +    } else {                                                              \
> +        return (uint32_t)(shx & 0xFFFFFFFF);                              \
> +    }                                                                     \
> +}
> +
> +#define GEN_PSIMD_NCLIPR(NAME)                                            \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
> +{                                                                         \
> +    __int128_t s1_s128 = (__int128_t)((int64_t)s1);                       \
> +    PsImdUint129 shx_129bit = psimd_uint129_lshift1(s1_s128);             \
> +    PsImdUint129 shx = psimd_uint129_rshift(shx_129bit, shamt & 0x3F);    \
> +    int64_t round_shx = (int64_t)((shx.low + 1) >> 1);                    \
> +                                                                          \
> +    if (round_shx < -2147483648LL) {                                      \
> +        env->vxsat = 1;                                                   \
> +        return 0x80000000U;                                               \
> +    } else if (round_shx > 2147483647LL) {                                \
> +        env->vxsat = 1;                                                   \
> +        return 0x7FFFFFFFU;                                               \
> +    } else {                                                              \
> +        return (uint32_t)round_shx;                                       \
> +    }                                                                     \
> +}
> +
> +#define GEN_PSIMD_NCLIPU(NAME)                                            \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
> +{                                                                         \
> +    uint64_t shx = s1 >> (shamt & 0x3F);                                  \
> +                                                                          \
> +    if (shx > 4294967295ULL) {                                            \
> +        env->vxsat = 1;                                                   \
> +        return 0xFFFFFFFFU;                                               \
> +    } else {                                                              \
> +        return (uint32_t)(shx & 0xFFFFFFFF);                              \
> +    }                                                                     \
> +}
> +
> +#define GEN_PSIMD_NCLIPRU(NAME)                                           \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
> +{                                                                         \
> +    __uint128_t shx_65bit = (__uint128_t)s1 << 1;                         \
> +    __uint128_t shx = shx_65bit >> (shamt & 0x3F);                        \
> +    uint64_t round_shx = (shx + 1) >> 1;                                  \
> +                                                                          \
> +    if (round_shx > 4294967295ULL) {                                      \
> +        env->vxsat = 1;                                                   \
> +        return 0xFFFFFFFFU;                                               \
> +    } else {                                                              \
> +        return (uint32_t)(round_shx & 0xFFFFFFFF);                        \
> +    }                                                                     \
> +}
> +
> +/* Basic addition operations (non-saturating) */
> +



^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH v2 03/18] target/riscv: Add packed SIMD arithmetic instructions
  2026-07-17 10:06 ` [PATCH v2 03/18] target/riscv: Add packed SIMD arithmetic instructions Molly Chen
@ 2026-07-26 22:05   ` Daniel Henrique Barboza
  2026-07-29  6:17   ` Nutty.Liu
  2026-07-29  9:27   ` Chao Liu
  2 siblings, 0 replies; 34+ messages in thread
From: Daniel Henrique Barboza @ 2026-07-26 22:05 UTC (permalink / raw)
  To: Molly Chen, palmer, alistair.francis, liwei1518, zhiwei_liu,
	chao.liu.zevorn, Chao Liu
  Cc: qemu-riscv, qemu-devel



On 7/17/2026 7:06 AM, Molly Chen wrote:
> Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
> ---

Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>

>   target/riscv/helper.h                       |  41 ++
>   target/riscv/insn32.decode                  |  63 +++
>   target/riscv/tcg/insn_trans/trans_rvp.c.inc | 547 ++++++++++++++++++++
>   target/riscv/tcg/psimd_helper.c             | 114 ++++
>   target/riscv/tcg/translate.c                |   4 +
>   5 files changed, 769 insertions(+)
>   create mode 100644 target/riscv/tcg/insn_trans/trans_rvp.c.inc
> 
> diff --git a/target/riscv/helper.h b/target/riscv/helper.h
> index 542b7c264fc..eebb2febd95 100644
> --- a/target/riscv/helper.h
> +++ b/target/riscv/helper.h
> @@ -1358,3 +1358,44 @@ DEF_HELPER_1(ssamoswap_disabled, void, env)
>   
>   /* Zalrsc SC write probe */
>   DEF_HELPER_FLAGS_3(sc_probe_write, TCG_CALL_NO_WG, void, env, tl, tl)
> +
> +/* Packed SIMD */
> +/* Packed SIMD - Arithmetic Operations(Non-Saturating and Saturating) */
> +DEF_HELPER_3(padd_b, tl, env, tl, tl)
> +DEF_HELPER_3(padd_h, tl, env, tl, tl)
> +DEF_HELPER_3(padd_w, i64, env, i64, i64)
> +DEF_HELPER_3(padd_bs, tl, env, tl, tl)
> +DEF_HELPER_3(padd_hs, tl, env, tl, tl)
> +DEF_HELPER_3(padd_ws, i64, env, i64, i64)
> +DEF_HELPER_3(psub_b, tl, env, tl, tl)
> +DEF_HELPER_3(psub_h, tl, env, tl, tl)
> +DEF_HELPER_3(psub_w, i64, env, i64, i64)
> +DEF_HELPER_3(psh1add_h, tl, env, tl, tl)
> +DEF_HELPER_3(psh1add_w, i64, env, i64, i64)
> +DEF_HELPER_3(pssh1sadd_h, tl, env, tl, tl)
> +DEF_HELPER_3(pssh1sadd_w, i64, env, i64, i64)
> +DEF_HELPER_3(ssh1sadd, i32, env, i32, i32)
> +DEF_HELPER_3(psadd_b, tl, env, tl, tl)
> +DEF_HELPER_3(psadd_h, tl, env, tl, tl)
> +DEF_HELPER_3(psadd_w, i64, env, i64, i64)
> +DEF_HELPER_3(psaddu_b, tl, env, tl, tl)
> +DEF_HELPER_3(psaddu_h, tl, env, tl, tl)
> +DEF_HELPER_3(psaddu_w, i64, env, i64, i64)
> +DEF_HELPER_3(sadd, i32, env, i32, i32)
> +DEF_HELPER_3(saddu, i32, env, i32, i32)
> +DEF_HELPER_3(pssub_b, tl, env, tl, tl)
> +DEF_HELPER_3(pssub_h, tl, env, tl, tl)
> +DEF_HELPER_3(pssub_w, i64, env, i64, i64)
> +DEF_HELPER_3(pssubu_b, tl, env, tl, tl)
> +DEF_HELPER_3(pssubu_h, tl, env, tl, tl)
> +DEF_HELPER_3(pssubu_w, i64, env, i64, i64)
> +DEF_HELPER_3(ssub, i32, env, i32, i32)
> +DEF_HELPER_3(ssubu, i32, env, i32, i32)
> +DEF_HELPER_3(psati_h, tl, env, tl, tl)
> +DEF_HELPER_3(pusati_h, tl, env, tl, tl)
> +DEF_HELPER_3(psati_w, i64, env, i64, i64)
> +DEF_HELPER_3(pusati_w, i64, env, i64, i64)
> +DEF_HELPER_3(sati_32, i32, env, i32, i32)
> +DEF_HELPER_3(usati_32, i32, env, i32, i32)
> +DEF_HELPER_3(sati_64, i64, env, i64, i64)
> +DEF_HELPER_3(usati_64, i64, env, i64, i64)
> diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
> index 21272fdb504..8da13669d73 100644
> --- a/target/riscv/insn32.decode
> +++ b/target/riscv/insn32.decode
> @@ -40,6 +40,9 @@
>   %imm_z6   26:1 15:5
>   %imm_mop5 30:1 26:2 20:2
>   %imm_mop3 30:1 26:2
> +%imm_p_ui16 20:4
> +%imm_p_ui32 20:5
> +%imm_p_ui64 20:6
>   
>   # Argument sets:
>   &empty
> @@ -60,6 +63,7 @@
>   &k_aes     shamt rs2 rs1 rd
>   &mop5 imm rd rs1
>   &mop3 imm rd rs1 rs2
> +&p_ui imm rs1 rd
>   
>   # Formats 32:
>   @r       .......   ..... ..... ... ..... ....... &r                %rs2 %rs1 %rd
> @@ -105,6 +109,10 @@
>   @mop5 . . .. .. .... .. ..... ... ..... ....... &mop5 imm=%imm_mop5 %rd %rs1
>   @mop3 . . .. .. . ..... ..... ... ..... ....... &mop3 imm=%imm_mop3 %rd %rs1 %rs2
>   
> +@p_ui16 ..... .... ... ..... ... ..... ....... &i imm=%imm_p_ui16 %rs1 %rd
> +@p_ui32 ..... .... ... ..... ... ..... ....... &i imm=%imm_p_ui32 %rs1 %rd
> +@p_ui64 ..... .... ... ..... ... ..... ....... &i imm=%imm_p_ui64 %rs1 %rd
> +
>   # Formats 64:
>   @sh5     .......  ..... .....  ... ..... ....... &shift  shamt=%sh5      %rs1 %rd
>   
> @@ -1084,3 +1092,58 @@ sb_aqrl  00111 . . ..... ..... 000 ..... 0101111 @atom_st
>   sh_aqrl  00111 . . ..... ..... 001 ..... 0101111 @atom_st
>   sw_aqrl  00111 . . ..... ..... 010 ..... 0101111 @atom_st
>   sd_aqrl  00111 . . ..... ..... 011 ..... 0101111 @atom_st
> +
> +# *** P Experimental Extension Version v020 ***
> +# Packed SIMD - Arithmetic Operations(Non-Saturating and Saturating)
> +padd_b     1000010 ..... ..... 000 ..... 0111011 @r
> +padd_h     1000000 ..... ..... 000 ..... 0111011 @r
> +padd_w     1000001 ..... ..... 000 ..... 0111011 @r
> +padd_bs    1001110 ..... ..... 010 ..... 0011011 @r
> +padd_hs    1001100 ..... ..... 010 ..... 0011011 @r
> +padd_ws    1001101 ..... ..... 010 ..... 0011011 @r
> +psub_b     1100010 ..... ..... 000 ..... 0111011 @r
> +psub_h     1100000 ..... ..... 000 ..... 0111011 @r
> +psub_w     1100001 ..... ..... 000 ..... 0111011 @r
> +psh1add_h  1010000 ..... ..... 010 ..... 0111011 @r
> +psh1add_w  1010001 ..... ..... 010 ..... 0111011 @r
> +pssh1sadd_h   1011000 ..... ..... 010 ..... 0111011 @r
> +{
> +  ssh1sadd    1011001 ..... ..... 010 ..... 0111011 @r
> +  pssh1sadd_w 1011001 ..... ..... 010 ..... 0111011 @r
> +}
> +psadd_b    1001010 ..... ..... 000 ..... 0111011 @r
> +psadd_h    1001000 ..... ..... 000 ..... 0111011 @r
> +{
> +  sadd     1001001 ..... ..... 000 ..... 0111011 @r
> +  psadd_w  1001001 ..... ..... 000 ..... 0111011 @r
> +}
> +psaddu_b   1011010 ..... ..... 000 ..... 0111011 @r
> +psaddu_h   1011000 ..... ..... 000 ..... 0111011 @r
> +{
> +  saddu    1011001 ..... ..... 000 ..... 0111011 @r
> +  psaddu_w 1011001 ..... ..... 000 ..... 0111011 @r
> +}
> +pssub_b    1101010 ..... ..... 000 ..... 0111011 @r
> +pssub_h    1101000 ..... ..... 000 ..... 0111011 @r
> +{
> +  ssub     1101001 ..... ..... 000 ..... 0111011 @r
> +  pssub_w  1101001 ..... ..... 000 ..... 0111011 @r
> +}
> +pssubu_b   1111010 ..... ..... 000 ..... 0111011 @r
> +pssubu_h   1111000 ..... ..... 000 ..... 0111011 @r
> +{
> +  ssubu      1111001 ..... ..... 000 ..... 0111011 @r
> +  pssubu_w   1111001 ..... ..... 000 ..... 0111011 @r
> +}
> +psati_h    11100 001.... ..... 100 ..... 0011011 @p_ui16
> +pusati_h   10100 001.... ..... 100 ..... 0011011 @p_ui16
> +{
> +  sati_32  11100 01..... ..... 100 ..... 0011011 @p_ui32
> +  psati_w  11100 01..... ..... 100 ..... 0011011 @p_ui32
> +}
> +{
> +  usati_32 10100 01..... ..... 100 ..... 0011011 @p_ui32
> +  pusati_w 10100 01..... ..... 100 ..... 0011011 @p_ui32
> +}
> +sati_64    111001 ...... ..... 100 ..... 0011011 @p_ui64
> +usati_64   101001 ...... ..... 100 ..... 0011011 @p_ui64
> diff --git a/target/riscv/tcg/insn_trans/trans_rvp.c.inc b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
> new file mode 100644
> index 00000000000..056ccfb486e
> --- /dev/null
> +++ b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
> @@ -0,0 +1,547 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/* RISC-V translation routines for the P Standard Extensions. */
> +/* Copyright (c) 2026 ISRC ISCAS. */
> +
> +/* Save a 64 bit data in src to dst and dst + 1 */
> +
> +static bool require_rvp(DisasContext *ctx)
> +{
> +    uint32_t opcode = ctx->opcode & 0x7f;
> +
> +    if (!has_ext(ctx, RVP)) {
> +        return false;
> +    }
> +
> +    /*
> +     * P_VXSAT_EXCP is encoded in the TB flags only when P is implemented
> +     * without Zve*, where stateen0.VXSAT controls the whole OP-32 and
> +     * OP-IMM-32 P instruction spaces.  When Zve* is present, this field
> +     * remains NONE and vxsat access is checked by the VS path instead.
> +     */
> +    if ((opcode == 0x3b || opcode == 0x1b) &&
> +        ctx->p_vxsat_excp != P_VXSAT_EXCP_NONE) {
> +        ctx->virt_inst_excp =
> +            ctx->p_vxsat_excp == P_VXSAT_EXCP_VIRTUAL;
> +        return false;
> +    }
> +
> +    return true;
> +}
> +
> +static bool prepare_rvp_vxsat(DisasContext *ctx)
> +{
> +    if (!ctx->cfg_ptr->ext_zve32x) {
> +        return true;
> +    }
> +
> +    if (ctx->mstatus_vs == EXT_STATUS_DISABLED) {
> +        return false;
> +    }
> +
> +    mark_vs_dirty(ctx);
> +    return true;
> +}
> +
> +#define REQUIRE_RVP(ctx) do {             \
> +    if (!require_rvp(ctx)) {              \
> +        return false;                     \
> +    }                                     \
> +} while (0)
> +
> +#define GEN_SIMD_TRANS_BODY(NAME, VXSAT)                    \
> +do {                                                        \
> +    REQUIRE_RVP(ctx);                                       \
> +    if (VXSAT && !prepare_rvp_vxsat(ctx)) {                 \
> +        return false;                                       \
> +    }                                                       \
> +    TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE);             \
> +    TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE);             \
> +    TCGv dest = dest_gpr(ctx, a->rd);                       \
> +    gen_helper_##NAME(dest, tcg_env, src1, src2);           \
> +    gen_set_gpr(ctx, a->rd, dest);                          \
> +    return true;                                            \
> +} while (0)
> +
> +#define GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)                 \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_32BIT(ctx);                                     \
> +    return true;                                           \
> +}
> +
> +#define GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)                 \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_64BIT(ctx);                                     \
> +    return true;                                           \
> +}
> +
> +#define GEN_SIMD_TRANS(NAME)                                \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    GEN_SIMD_TRANS_BODY(NAME, false);                       \
> +}
> +
> +#define GEN_SIMD_TRANS_VXSAT(NAME)                         \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    GEN_SIMD_TRANS_BODY(NAME, true);                        \
> +}
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_32(NAME)                             \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a)  \
> +{                                                           \
> +    REQUIRE_32BIT(ctx);                                     \
> +    GEN_SIMD_TRANS_BODY(NAME, false);                       \
> +}
> +#define GEN_SIMD_TRANS_32_VXSAT(NAME)                      \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_32BIT(ctx);                                     \
> +    GEN_SIMD_TRANS_BODY(NAME, true);                        \
> +}
> +#else
> +#define GEN_SIMD_TRANS_32(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#define GEN_SIMD_TRANS_32_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_64(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
> +#define GEN_SIMD_TRANS_64_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
> +#else
> +#define GEN_SIMD_TRANS_64(NAME)                             \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a)  \
> +{                                                           \
> +    REQUIRE_64BIT(ctx);                                     \
> +    GEN_SIMD_TRANS_BODY(NAME, false);                       \
> +}
> +#define GEN_SIMD_TRANS_64_VXSAT(NAME)                      \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_64BIT(ctx);                                     \
> +    GEN_SIMD_TRANS_BODY(NAME, true);                        \
> +}
> +#endif
> +
> +#define GEN_SIMD_TRANS_ACC_BODY(NAME, VXSAT)                \
> +do {                                                        \
> +    REQUIRE_RVP(ctx);                                       \
> +    if (VXSAT && !prepare_rvp_vxsat(ctx)) {                 \
> +        return false;                                       \
> +    }                                                       \
> +    TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE);             \
> +    TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE);             \
> +    TCGv dest = dest_gpr(ctx, a->rd);                       \
> +    TCGv t = tcg_temp_new();                                \
> +    gen_helper_##NAME(t, tcg_env, src1, src2, dest);        \
> +    gen_set_gpr(ctx, a->rd, t);                             \
> +    return true;                                            \
> +} while (0)
> +
> +#define GEN_SIMD_TRANS_ACC(NAME)                            \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    GEN_SIMD_TRANS_ACC_BODY(NAME, false);                   \
> +}
> +
> +#define GEN_SIMD_TRANS_ACC_VXSAT(NAME)                     \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    GEN_SIMD_TRANS_ACC_BODY(NAME, true);                    \
> +}
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_ACC_32(NAME)                         \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_32BIT(ctx);                                     \
> +    GEN_SIMD_TRANS_ACC_BODY(NAME, false);                   \
> +}
> +#else
> +#define GEN_SIMD_TRANS_ACC_32(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_ACC_64(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
> +#else
> +#define GEN_SIMD_TRANS_ACC_64(NAME)                         \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_64BIT(ctx);                                     \
> +    GEN_SIMD_TRANS_ACC_BODY(NAME, false);                   \
> +}
> +#endif
> +
> +#define GEN_SIMD_TRANS_R1_BODY(NAME, VXSAT)                 \
> +do {                                                        \
> +    REQUIRE_RVP(ctx);                                       \
> +    if (VXSAT && !prepare_rvp_vxsat(ctx)) {                 \
> +        return false;                                       \
> +    }                                                       \
> +    TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE);             \
> +    TCGv dest = dest_gpr(ctx, a->rd);                       \
> +    gen_helper_##NAME(dest, tcg_env, src1);                 \
> +    gen_set_gpr(ctx, a->rd, dest);                          \
> +    return true;                                            \
> +} while (0)
> +
> +#define GEN_SIMD_TRANS_R1(NAME)                             \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    GEN_SIMD_TRANS_R1_BODY(NAME, false);                    \
> +}
> +
> +#define GEN_SIMD_TRANS_R1_VXSAT(NAME)                      \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    GEN_SIMD_TRANS_R1_BODY(NAME, true);                     \
> +}
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_R1_64(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
> +#define GEN_SIMD_TRANS_R1_64_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
> +#else
> +#define GEN_SIMD_TRANS_R1_64(NAME)                          \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_64BIT(ctx);                                     \
> +    GEN_SIMD_TRANS_R1_BODY(NAME, false);                    \
> +}
> +#define GEN_SIMD_TRANS_R1_64_VXSAT(NAME)                   \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_64BIT(ctx);                                     \
> +    GEN_SIMD_TRANS_R1_BODY(NAME, true);                     \
> +}
> +#endif
> +
> +#define GEN_SIMD_TRANS_IMM_BODY(NAME, VXSAT)                \
> +do {                                                        \
> +    REQUIRE_RVP(ctx);                                       \
> +    if (VXSAT && !prepare_rvp_vxsat(ctx)) {                 \
> +        return false;                                       \
> +    }                                                       \
> +    TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE);             \
> +    TCGv imm = tcg_constant_tl(a->imm);                     \
> +    TCGv dest = dest_gpr(ctx, a->rd);                       \
> +    gen_helper_##NAME(dest, tcg_env, src1, imm);            \
> +    gen_set_gpr(ctx, a->rd, dest);                          \
> +    return true;                                            \
> +} while (0)
> +
> +#define GEN_SIMD_TRANS_IMM(NAME)                            \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    GEN_SIMD_TRANS_IMM_BODY(NAME, false);                   \
> +}
> +
> +#define GEN_SIMD_TRANS_IMM_VXSAT(NAME)                     \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    GEN_SIMD_TRANS_IMM_BODY(NAME, true);                    \
> +}
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_IMM_32(NAME)                         \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_32BIT(ctx);                                     \
> +    GEN_SIMD_TRANS_IMM_BODY(NAME, false);                   \
> +}
> +#define GEN_SIMD_TRANS_IMM_32_VXSAT(NAME)                  \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_32BIT(ctx);                                     \
> +    GEN_SIMD_TRANS_IMM_BODY(NAME, true);                    \
> +}
> +#else
> +#define GEN_SIMD_TRANS_IMM_32(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#define GEN_SIMD_TRANS_IMM_32_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_IMM_64(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
> +#define GEN_SIMD_TRANS_IMM_64_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
> +#else
> +#define GEN_SIMD_TRANS_IMM_64(NAME)                         \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_64BIT(ctx);                                     \
> +    GEN_SIMD_TRANS_IMM_BODY(NAME, false);                   \
> +}
> +#define GEN_SIMD_TRANS_IMM_64_VXSAT(NAME)                  \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_64BIT(ctx);                                     \
> +    GEN_SIMD_TRANS_IMM_BODY(NAME, true);                    \
> +}
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_REG_PAIR_SCALAR_OP(NAME, SRC2)       \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_32BIT(ctx);                                     \
> +    REQUIRE_RVP(ctx);                                       \
> +    TCGv_i32 src1 = get_gpr(ctx, a->rs1, EXT_NONE);         \
> +    TCGv_i32 src2 = SRC2;                                   \
> +    TCGv_i64 t = tcg_temp_new_i64();                        \
> +    gen_helper_##NAME(t, tcg_env, src1, src2);              \
> +    set_pair_regs(ctx, (a->rd) * 2, t);                     \
> +    return true;                                            \
> +}
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_SCALAR(NAME) \
> +    GEN_SIMD_TRANS_REG_PAIR_SCALAR_OP(NAME, get_gpr(ctx, a->rs2, EXT_NONE))
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_SCALAR_IMM(NAME) \
> +    GEN_SIMD_TRANS_REG_PAIR_SCALAR_OP(NAME, tcg_constant_i32(a->imm))
> +#else
> +#define GEN_SIMD_TRANS_REG_PAIR_SCALAR(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#define GEN_SIMD_TRANS_REG_PAIR_SCALAR_IMM(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_REG_PAIR_OP(INSN, HELPER, SRC2_0, SRC2_1, VXSAT) \
> +static bool trans_##INSN(DisasContext *ctx, arg_##INSN * a)       \
> +{                                                                 \
> +    REQUIRE_32BIT(ctx);                                           \
> +    REQUIRE_RVP(ctx);                                             \
> +    if (VXSAT && !prepare_rvp_vxsat(ctx)) {                       \
> +        return false;                                             \
> +    }                                                             \
> +    TCGv src1_0 = get_gpr(ctx, (a->rs1) * 2, EXT_NONE);           \
> +    TCGv src2_0 = SRC2_0;                                         \
> +    TCGv dest_0 = dest_gpr(ctx, (a->rd) * 2);                     \
> +    TCGv src1_1 = get_gpr(ctx, (a->rs1) * 2 + 1, EXT_NONE);       \
> +    TCGv src2_1 = SRC2_1;                                         \
> +    TCGv dest_1 = dest_gpr(ctx, (a->rd) * 2 + 1);                 \
> +    gen_helper_##HELPER(dest_0, tcg_env, src1_0, src2_0);         \
> +    gen_helper_##HELPER(dest_1, tcg_env, src1_1, src2_1);         \
> +    gen_set_gpr(ctx, (a->rd) * 2, dest_0);                        \
> +    gen_set_gpr(ctx, (a->rd) * 2 + 1, dest_1);                    \
> +    return true;                                                  \
> +}
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE(INSN, HELPER)                   \
> +    GEN_SIMD_TRANS_REG_PAIR_OP(INSN, HELPER,                       \
> +        get_gpr(ctx, (a->rs2) * 2, EXT_NONE),                     \
> +        get_gpr(ctx, (a->rs2) * 2 + 1, EXT_NONE), false)
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(INSN, HELPER)            \
> +    GEN_SIMD_TRANS_REG_PAIR_OP(INSN, HELPER,                       \
> +        get_gpr(ctx, (a->rs2) * 2, EXT_NONE),                     \
> +        get_gpr(ctx, (a->rs2) * 2 + 1, EXT_NONE), true)
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_IMM(INSN, HELPER)               \
> +    GEN_SIMD_TRANS_REG_PAIR_OP(INSN, HELPER,                       \
> +        tcg_constant_tl(a->imm), tcg_constant_tl(a->imm), false)
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_IMM_VXSAT(INSN, HELPER)        \
> +    GEN_SIMD_TRANS_REG_PAIR_OP(INSN, HELPER,                       \
> +        tcg_constant_tl(a->imm), tcg_constant_tl(a->imm), true)
> +#else
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE(INSN, HELPER) \
> +    GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(INSN, HELPER) \
> +    GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_IMM(INSN, HELPER) \
> +    GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_IMM_VXSAT(INSN, HELPER) \
> +    GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_OP(INSN, HELPER, VXSAT)     \
> +static bool trans_##INSN(DisasContext *ctx, arg_##INSN * a)    \
> +{                                                              \
> +    REQUIRE_32BIT(ctx);                                        \
> +    REQUIRE_RVP(ctx);                                          \
> +    if (VXSAT && !prepare_rvp_vxsat(ctx)) {                    \
> +        return false;                                          \
> +    }                                                          \
> +    TCGv src1_0 = get_gpr(ctx, (a->rs1) * 2, EXT_NONE);        \
> +    TCGv dest_0 = dest_gpr(ctx, (a->rd) * 2);                    \
> +    TCGv src1_1 = get_gpr(ctx, (a->rs1) * 2 + 1, EXT_NONE);        \
> +    TCGv dest_1 = dest_gpr(ctx, (a->rd) * 2 + 1);                  \
> +    TCGv src2   = get_gpr(ctx, a->rs2, EXT_NONE);              \
> +    gen_helper_##HELPER(dest_0, tcg_env, src1_0, src2);        \
> +    gen_helper_##HELPER(dest_1, tcg_env, src1_1, src2);        \
> +    gen_set_gpr(ctx, (a->rd) * 2, dest_0);                     \
> +    gen_set_gpr(ctx, (a->rd) * 2 + 1, dest_1);                 \
> +    return true;                                              \
> +}
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR(INSN, HELPER)              \
> +    GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_OP(INSN, HELPER, false)
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_VXSAT(INSN, HELPER)       \
> +    GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_OP(INSN, HELPER, true)
> +#else
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR(INSN, HELPER) \
> +    GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_VXSAT(INSN, HELPER) \
> +    GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_OP(INSN, HELPER, VXSAT)     \
> +static bool trans_##INSN(DisasContext *ctx, arg_##INSN * a)    \
> +{                                                              \
> +    REQUIRE_RVP(ctx);                                          \
> +    if (VXSAT && !prepare_rvp_vxsat(ctx)) {                    \
> +        return false;                                          \
> +    }                                                          \
> +    TCGv src1_0 = get_gpr(ctx, (a->rs1) * 2, EXT_NONE);        \
> +    TCGv dest_0 = dest_gpr(ctx, (a->rd) * 2);                  \
> +    TCGv src1_1 = get_gpr(ctx, (a->rs1) * 2 + 1, EXT_NONE);    \
> +    TCGv dest_1 = dest_gpr(ctx, (a->rd) * 2 + 1);              \
> +    gen_helper_##HELPER(dest_0, tcg_env, src1_0);              \
> +    gen_helper_##HELPER(dest_1, tcg_env, src1_1);              \
> +    gen_set_gpr(ctx, (a->rd) * 2, dest_0);                     \
> +    gen_set_gpr(ctx, (a->rd) * 2 + 1, dest_1);                 \
> +    return true;                                               \
> +}
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY(INSN, HELPER)               \
> +    GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_OP(INSN, HELPER, false)
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_VXSAT(INSN, HELPER)        \
> +    GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_OP(INSN, HELPER, true)
> +#else
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY(INSN, HELPER) \
> +    GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_VXSAT(INSN, HELPER) \
> +    GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_REG_PAIR_ACC(NAME)                   \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_32BIT(ctx);                                     \
> +    REQUIRE_RVP(ctx);                                       \
> +    TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE);             \
> +    TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE);             \
> +    TCGv_i64 t = tcg_temp_new_i64();                        \
> +    if (a->rd == 0) {                                         \
> +        tcg_gen_movi_i64(t, 0);                             \
> +    } else {                                                  \
> +        get_pair_regs(ctx, t, (a->rd) * 2);                   \
> +    }                                                       \
> +    gen_helper_##NAME(t, tcg_env, src1, src2, t);           \
> +    set_pair_regs(ctx, (a->rd) * 2, t);                       \
> +    return true;                                           \
> +}
> +#else
> +#define GEN_SIMD_TRANS_REG_PAIR_ACC(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_REG_PAIR_PREDSUM(NAME)               \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_32BIT(ctx);                                     \
> +    REQUIRE_RVP(ctx);                                       \
> +    TCGv_i32 src1_l;                                        \
> +    TCGv_i32 src1_h;                                        \
> +    TCGv_i32 src2 = get_gpr(ctx, a->rs2, EXT_NONE);         \
> +    TCGv_i32 dest = dest_gpr(ctx, a->rd);                   \
> +    if (a->rs1 == 0) {                                        \
> +        src1_l = tcg_temp_new_i32();                        \
> +        src1_h = tcg_temp_new_i32();                        \
> +        tcg_gen_movi_i32(src1_l, 0);                        \
> +        tcg_gen_movi_i32(src1_h, 0);                        \
> +    } else {                                                  \
> +        src1_l = get_gpr(ctx, (a->rs1) * 2, EXT_NONE);        \
> +        src1_h = get_gpr(ctx, (a->rs1) * 2 + 1, EXT_NONE);      \
> +    }                                                       \
> +    gen_helper_##NAME(dest, tcg_env, src1_l, src1_h, src2); \
> +    gen_set_gpr(ctx, a->rd, dest);                          \
> +    return true;                                           \
> +}
> +#else
> +#define GEN_SIMD_TRANS_REG_PAIR_PREDSUM(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_PN_OP(NAME, SRC2, VXSAT)            \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_32BIT(ctx);                                     \
> +    REQUIRE_RVP(ctx);                                       \
> +    if (VXSAT && !prepare_rvp_vxsat(ctx)) {                 \
> +        return false;                                       \
> +    }                                                       \
> +    TCGv_i64 s1 = tcg_temp_new_i64();                       \
> +    if (a->rs1 == 0) {                                      \
> +        tcg_gen_mov_i64(s1, 0);                             \
> +    } else {                                                \
> +        get_pair_regs(ctx, s1, a->rs1 * 2);                 \
> +    }                                                       \
> +    TCGv src2 = SRC2;                                       \
> +    TCGv dest = dest_gpr(ctx, a->rd);                       \
> +    gen_helper_##NAME(dest, tcg_env, s1, src2);             \
> +    gen_set_gpr(ctx, a->rd, dest);                          \
> +    return true;                                            \
> +}
> +
> +#define GEN_SIMD_TRANS_PN_OP_IMM(NAME) \
> +    GEN_SIMD_TRANS_PN_OP(NAME, tcg_constant_tl(a->imm), false)
> +
> +#define GEN_SIMD_TRANS_PN_OP_IMM_VXSAT(NAME) \
> +    GEN_SIMD_TRANS_PN_OP(NAME, tcg_constant_tl(a->imm), true)
> +
> +#define GEN_SIMD_TRANS_PN_OP_REG(NAME) \
> +    GEN_SIMD_TRANS_PN_OP(NAME, get_gpr(ctx, a->rs2, EXT_NONE), false)
> +
> +#define GEN_SIMD_TRANS_PN_OP_REG_VXSAT(NAME) \
> +    GEN_SIMD_TRANS_PN_OP(NAME, get_gpr(ctx, a->rs2, EXT_NONE), true)
> +#else
> +#define GEN_SIMD_TRANS_PN_OP_IMM(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#define GEN_SIMD_TRANS_PN_OP_IMM_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#define GEN_SIMD_TRANS_PN_OP_REG(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#define GEN_SIMD_TRANS_PN_OP_REG_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#endif
> +
> +/* Packed SIMD - Arithmetic Operations(Non-Saturating and Saturating) */
> +GEN_SIMD_TRANS(padd_b)
> +GEN_SIMD_TRANS(padd_h)
> +GEN_SIMD_TRANS_64(padd_w)
> +GEN_SIMD_TRANS(padd_bs)
> +GEN_SIMD_TRANS(padd_hs)
> +GEN_SIMD_TRANS_64(padd_ws)
> +GEN_SIMD_TRANS(psub_b)
> +GEN_SIMD_TRANS(psub_h)
> +GEN_SIMD_TRANS_64(psub_w)
> +GEN_SIMD_TRANS(psh1add_h)
> +GEN_SIMD_TRANS_64(psh1add_w)
> +GEN_SIMD_TRANS_VXSAT(pssh1sadd_h)
> +GEN_SIMD_TRANS_64_VXSAT(pssh1sadd_w)
> +GEN_SIMD_TRANS_32_VXSAT(ssh1sadd)
> +GEN_SIMD_TRANS_VXSAT(psadd_b)
> +GEN_SIMD_TRANS_VXSAT(psadd_h)
> +GEN_SIMD_TRANS_64_VXSAT(psadd_w)
> +GEN_SIMD_TRANS_VXSAT(psaddu_b)
> +GEN_SIMD_TRANS_VXSAT(psaddu_h)
> +GEN_SIMD_TRANS_64_VXSAT(psaddu_w)
> +GEN_SIMD_TRANS_32_VXSAT(sadd)
> +GEN_SIMD_TRANS_32_VXSAT(saddu)
> +GEN_SIMD_TRANS_VXSAT(pssub_b)
> +GEN_SIMD_TRANS_VXSAT(pssub_h)
> +GEN_SIMD_TRANS_64_VXSAT(pssub_w)
> +GEN_SIMD_TRANS_VXSAT(pssubu_b)
> +GEN_SIMD_TRANS_VXSAT(pssubu_h)
> +GEN_SIMD_TRANS_64_VXSAT(pssubu_w)
> +GEN_SIMD_TRANS_32_VXSAT(ssub)
> +GEN_SIMD_TRANS_32_VXSAT(ssubu)
> +GEN_SIMD_TRANS_IMM_VXSAT(psati_h)
> +GEN_SIMD_TRANS_IMM_VXSAT(pusati_h)
> +GEN_SIMD_TRANS_IMM_64_VXSAT(psati_w)
> +GEN_SIMD_TRANS_IMM_64_VXSAT(pusati_w)
> +GEN_SIMD_TRANS_IMM_32_VXSAT(sati_32)
> +GEN_SIMD_TRANS_IMM_32_VXSAT(usati_32)
> +GEN_SIMD_TRANS_IMM_64_VXSAT(sati_64)
> +GEN_SIMD_TRANS_IMM_64_VXSAT(usati_64)
> +
> diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
> index 2948bbb2a86..52c58e0287e 100644
> --- a/target/riscv/tcg/psimd_helper.c
> +++ b/target/riscv/tcg/psimd_helper.c
> @@ -1654,3 +1654,117 @@ uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
>   
>   /* Basic addition operations (non-saturating) */
>   
> +GEN_PSIMD_BINOP(padd_b, target_ulong, uint8_t, uint8_t,
> +                EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ADD)
> +GEN_PSIMD_BINOP(padd_h, target_ulong, uint16_t, uint16_t,
> +                EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ADD)
> +GEN_PSIMD_BINOP(padd_w, uint64_t, uint32_t, uint32_t,
> +                EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD)
> +
> +GEN_PSIMD_BINOP_SCALAR(padd_bs, target_ulong, uint8_t,
> +                       EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ADD)
> +GEN_PSIMD_BINOP_SCALAR(padd_hs, target_ulong, uint16_t,
> +                       EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ADD)
> +GEN_PSIMD_BINOP_SCALAR(padd_ws, uint64_t, uint32_t,
> +                       EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD)
> +
> +/* Basic subtraction operations (non-saturating) */
> +
> +GEN_PSIMD_BINOP(psub_b, target_ulong, uint8_t, uint8_t,
> +                EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_SUB)
> +GEN_PSIMD_BINOP(psub_h, target_ulong, uint16_t, uint16_t,
> +                EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_SUB)
> +GEN_PSIMD_BINOP(psub_w, uint64_t, uint32_t, uint32_t,
> +                EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_SUB)
> +
> +/* Shift-left-by-one and add operations */
> +
> +GEN_PSIMD_SHADD(psh1add_h, target_ulong, uint16_t,
> +                EXTRACT16, INSERT16, ELEMS_H, 1)
> +GEN_PSIMD_SHADD(psh1add_w, uint64_t, uint32_t,
> +                EXTRACT32, INSERT32, ELEMS_W, 1)
> +
> +GEN_PSIMD_SAT_SHADD(pssh1sadd_h, target_ulong, int16_t, int32_t,
> +                    EXTRACT16, INSERT16, ELEMS_H, 1, -0x4000, 0x3fff,
> +                    SAT_MIN_H, SAT_MAX_H, signed_saturate_h)
> +GEN_PSIMD_SAT_SHADD(pssh1sadd_w, uint64_t, int32_t, int64_t,
> +                    EXTRACT32, INSERT32, ELEMS_W, 1, -0x40000000,
> +                    0x3fffffff, SAT_MIN_W, SAT_MAX_W, signed_saturate_w)
> +
> +GEN_PSIMD_SAT_SHADD(ssh1sadd, uint32_t, int32_t, int64_t,
> +                    EXTRACT32, INSERT32, ELEMS_W, 1, -0x40000000,
> +                    0x3fffffff, SAT_MIN_W, SAT_MAX_W, signed_saturate_w)
> +
> +/* Saturating addition operations */
> +
> +GEN_PSIMD_SAT_BINOP(psadd_b, target_ulong, int8_t, int32_t,
> +                    EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ADD,
> +                    signed_saturate_b)
> +GEN_PSIMD_SAT_BINOP(psadd_h, target_ulong, int16_t, int32_t,
> +                    EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ADD,
> +                    signed_saturate_h)
> +GEN_PSIMD_SAT_BINOP(psadd_w, uint64_t, int32_t, int64_t,
> +                    EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD,
> +                    signed_saturate_w)
> +
> +GEN_PSIMD_SAT_BINOP(psaddu_b, target_ulong, uint8_t, uint32_t,
> +                    EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ADD,
> +                    unsigned_saturate_b)
> +GEN_PSIMD_SAT_BINOP(psaddu_h, target_ulong, uint16_t, uint32_t,
> +                    EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ADD,
> +                    unsigned_saturate_h)
> +GEN_PSIMD_SAT_BINOP(psaddu_w, uint64_t, uint32_t, uint64_t,
> +                    EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD,
> +                    unsigned_saturate_w)
> +
> +GEN_PSIMD_SAT_BINOP(sadd, uint32_t, int32_t, int64_t,
> +                    EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD,
> +                    signed_saturate_w)
> +GEN_PSIMD_SAT_BINOP(saddu, uint32_t, uint32_t, uint64_t,
> +                    EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD,
> +                    unsigned_saturate_w)
> +
> +/* Saturating subtraction operations */
> +
> +GEN_PSIMD_SAT_BINOP(pssub_b, target_ulong, int8_t, int32_t,
> +                    EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_SUB,
> +                    signed_saturate_b)
> +GEN_PSIMD_SAT_BINOP(pssub_h, target_ulong, int16_t, int32_t,
> +                    EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_SUB,
> +                    signed_saturate_h)
> +GEN_PSIMD_SAT_BINOP(pssub_w, uint64_t, int32_t, int64_t,
> +                    EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_SUB,
> +                    signed_saturate_w)
> +
> +GEN_PSIMD_USUB_SAT(pssubu_b, target_ulong, uint8_t,
> +                   EXTRACT8, INSERT8, ELEMS_B)
> +GEN_PSIMD_USUB_SAT(pssubu_h, target_ulong, uint16_t,
> +                   EXTRACT16, INSERT16, ELEMS_H)
> +GEN_PSIMD_USUB_SAT(pssubu_w, uint64_t, uint32_t,
> +                   EXTRACT32, INSERT32, ELEMS_W)
> +
> +GEN_PSIMD_SAT_BINOP(ssub, uint32_t, int32_t, int64_t,
> +                    EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_SUB,
> +                    signed_saturate_w)
> +GEN_PSIMD_USUB_SAT(ssubu, uint32_t, uint32_t,
> +                   EXTRACT32, INSERT32, ELEMS_W)
> +
> +/* Saturation instructions (SAT, USAT) */
> +
> +GEN_PSIMD_SATI(psati_h, target_ulong, int16_t, int64_t,
> +               EXTRACT16, INSERT16, ELEMS_H, 0x0f)
> +GEN_PSIMD_USATI(pusati_h, target_ulong, int16_t, uint16_t, uint32_t,
> +                EXTRACT16, INSERT16, ELEMS_H, 1U)
> +GEN_PSIMD_SATI(psati_w, uint64_t, int32_t, int64_t,
> +               EXTRACT32, INSERT32, ELEMS_W, 0x1f)
> +GEN_PSIMD_USATI(pusati_w, uint64_t, int32_t, uint32_t, uint64_t,
> +                EXTRACT32, INSERT32, ELEMS_W, 1ULL)
> +GEN_PSIMD_SATI(sati_32, uint32_t, int32_t, int64_t,
> +               EXTRACT32, INSERT32, ELEMS_W, 0x1f)
> +GEN_PSIMD_USATI(usati_32, uint32_t, int32_t, uint32_t, uint32_t,
> +                EXTRACT32, INSERT32, ELEMS_W, 1U)
> +GEN_PSIMD_SATI(sati_64, uint64_t, int64_t, int64_t,
> +               EXTRACT64, INSERT64, ELEMS_D, 0x3f)
> +GEN_PSIMD_USATI(usati_64, uint64_t, int64_t, uint64_t, uint64_t,
> +                EXTRACT64, INSERT64, ELEMS_D, 1ULL)
> +
> diff --git a/target/riscv/tcg/translate.c b/target/riscv/tcg/translate.c
> index 9684dbe7528..0df9d4190f1 100644
> --- a/target/riscv/tcg/translate.c
> +++ b/target/riscv/tcg/translate.c
> @@ -103,6 +103,7 @@ typedef struct DisasContext {
>       bool vstart_eq_zero;
>       bool vl_eq_vlmax;
>       bool altfmt;
> +    uint8_t p_vxsat_excp;
>       CPUState *cs;
>       TCGv zero;
>       /* actual address width */
> @@ -1199,6 +1200,7 @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc)
>   #include "insn_trans/trans_rvh.c.inc"
>   #include "insn_trans/trans_rvv.c.inc"
>   #include "insn_trans/trans_rvb.c.inc"
> +#include "insn_trans/trans_rvp.c.inc"
>   #include "insn_trans/trans_rvzicond.c.inc"
>   #include "insn_trans/trans_rvzacas.c.inc"
>   #include "insn_trans/trans_rvzabha.c.inc"
> @@ -1333,6 +1335,8 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
>       ctx->vstart_eq_zero = FIELD_EX32(tb_flags, TB_FLAGS, VSTART_EQ_ZERO);
>       ctx->vl_eq_vlmax = FIELD_EX32(tb_flags, TB_FLAGS, VL_EQ_VLMAX);
>       ctx->altfmt = FIELD_EX64(ext_tb_flags, EXT_TB_FLAGS, ALTFMT);
> +    ctx->p_vxsat_excp = FIELD_EX64(ext_tb_flags, EXT_TB_FLAGS,
> +                                   P_VXSAT_EXCP);
>       ctx->misa_mxl_max = mcc->def->misa_mxl_max;
>       ctx->xl = FIELD_EX32(tb_flags, TB_FLAGS, XL);
>       ctx->address_xl = FIELD_EX32(tb_flags, TB_FLAGS, AXL);



^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH v2 01/18] target/riscv: Add packed SIMD extension state
  2026-07-17 10:06 ` [PATCH v2 01/18] target/riscv: Add packed SIMD extension state Molly Chen
  2026-07-26 19:32   ` Daniel Henrique Barboza
@ 2026-07-27  6:13   ` Nutty.Liu
  2026-07-29  8:43   ` Chao Liu
  2 siblings, 0 replies; 34+ messages in thread
From: Nutty.Liu @ 2026-07-27  6:13 UTC (permalink / raw)
  To: Molly Chen, palmer, alistair.francis, liwei1518, daniel.barboza,
	zhiwei_liu, chao.liu.zevorn, Chao Liu
  Cc: qemu-riscv, qemu-devel, Yin Zhang, Dajun Huang, Zhiyuan Yang


On 7/17/2026 6:06 PM, Molly Chen wrote:
> Model vxsat with separate Vector/Zve and P-only control paths.  When
> Zve* is present, vxsat follows mstatus.VS/vsstatus.VS; when P is
> implemented without Zve*, stateen0.VXSAT controls access instead.
>
> Record the P-only stateen result in TB flags so cached translations
> preserve both instruction legality and the illegal-vs-virtual exception
> class.
>
> Co-authored-by: Yin Zhang <zhangyin2018@iscas.ac.cn>
> Co-authored-by: Dajun Huang <djhuang_1@std.uestc.edu.cn>
> Co-authored-by: Zhiyuan Yang <zhiyuan.plct@isrc.iscas.ac.cn>
>
> Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
Reviewed-by: Nutty Liu <nutty.liu@hotmail.com>

Thanks,
Nutty
> ---
>   target/riscv/cpu.c         |  5 ++--
>   target/riscv/cpu.h         |  8 +++++++
>   target/riscv/cpu_bits.h    |  2 ++
>   target/riscv/machine.c     | 19 +++++++++++++++
>   target/riscv/tcg/csr.c     | 39 +++++++++++++++++++++++++++++--
>   target/riscv/tcg/tcg-cpu.c | 48 ++++++++++++++++++++++++++++++++++++++
>   6 files changed, 117 insertions(+), 4 deletions(-)
>
> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> index 5a82e6563bf..c9e6c83a491 100644
> --- a/target/riscv/cpu.c
> +++ b/target/riscv/cpu.c
> @@ -46,7 +46,7 @@
>   /* RISC-V CPU definitions */
>   static const char riscv_single_letter_exts[] = "IEMAFDQCBPVH";
>   const uint32_t misa_bits[] = {RVI, RVE, RVM, RVA, RVF, RVD, RVV,
> -                              RVC, RVS, RVU, RVH, RVG, RVB, 0};
> +                              RVC, RVS, RVU, RVH, RVG, RVB, RVP, 0};
>   #define RISCV_CPU_MVENDORID 0
>   #define RISCV_CPU_MIMPID 0
>   /*
> @@ -1489,7 +1489,8 @@ static const MISAExtInfo misa_ext_info_arr[] = {
>       MISA_EXT_INFO(RVH, "h", "Hypervisor"),
>       MISA_EXT_INFO(RVV, "v", "Vector operations"),
>       MISA_EXT_INFO(RVG, "g", "General purpose (IMAFD_Zicsr_Zifencei)"),
> -    MISA_EXT_INFO(RVB, "b", "Bit manipulation (Zba_Zbb_Zbs)")
> +    MISA_EXT_INFO(RVB, "b", "Bit manipulation (Zba_Zbb_Zbs)"),
> +    MISA_EXT_INFO(RVP, "x-p", "Packed-SIMD instructions")
>   };
>   
>   static void riscv_cpu_validate_misa_mxl(RISCVCPUClass *mcc)
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index c9dfa7daff2..75cfb16d846 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -70,6 +70,7 @@ typedef struct CPUArchState CPURISCVState;
>   #define RVG RV('G')
>   #define RVB RV('B')
>   #define RVX RV('X')
> +#define RVP RV('P')
>   
>   extern const uint32_t misa_bits[];
>   const char *riscv_get_misa_ext_name(uint32_t bit);
> @@ -742,6 +743,13 @@ FIELD(TB_FLAGS, PM_SIGNEXTEND, 31, 1)
>   FIELD(EXT_TB_FLAGS, MISA_EXT, 0, 32)
>   FIELD(EXT_TB_FLAGS, ALTFMT, 32, 1)
>   FIELD(EXT_TB_FLAGS, BIG_ENDIAN, 33, 1)
> +FIELD(EXT_TB_FLAGS, P_VXSAT_EXCP, 34, 2)
> +
> +enum {
> +    P_VXSAT_EXCP_NONE,
> +    P_VXSAT_EXCP_ILLEGAL,
> +    P_VXSAT_EXCP_VIRTUAL,
> +};
>   
>   #ifdef TARGET_RISCV32
>   #define riscv_cpu_mxl(env)  ((void)(env), MXL_RV32)
> diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
> index 3f146a43fe4..fa7bf60f4fc 100644
> --- a/target/riscv/cpu_bits.h
> +++ b/target/riscv/cpu_bits.h
> @@ -355,6 +355,8 @@
>   #define SMSTATEEN0_CS       (1ULL << 0)
>   #define SMSTATEEN0_FCSR     (1ULL << 1)
>   #define SMSTATEEN0_JVT      (1ULL << 2)
> +/* Packed-SIMD draft: enable access to vxsat when misa.V = 0. */
> +#define SMSTATEEN0_VXSAT    (1ULL << 3)
>   #define SMSTATEEN0_CTR      (1ULL << 54)
>   #define SMSTATEEN0_P1P13    (1ULL << 56)
>   #define SMSTATEEN0_HSCONTXT (1ULL << 57)
> diff --git a/target/riscv/machine.c b/target/riscv/machine.c
> index 0ab613a2980..a9cd7e4c1cc 100644
> --- a/target/riscv/machine.c
> +++ b/target/riscv/machine.c
> @@ -158,6 +158,24 @@ static const VMStateDescription vmstate_vector = {
>       }
>   };
>   
> +static bool p_vxsat_needed(void *opaque)
> +{
> +    RISCVCPU *cpu = opaque;
> +
> +    return riscv_has_ext(&cpu->env, RVP) && !cpu->cfg.ext_zve32x;
> +}
> +
> +static const VMStateDescription vmstate_p_vxsat = {
> +    .name = "cpu/p-vxsat",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .needed = p_vxsat_needed,
> +    .fields = (const VMStateField[]) {
> +        VMSTATE_UINT8(env.vxsat, RISCVCPU),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
>   static bool pointermasking_needed(void *opaque)
>   {
>       return false;
> @@ -518,6 +536,7 @@ const VMStateDescription vmstate_riscv_cpu = {
>           &vmstate_pmp,
>           &vmstate_hyper,
>           &vmstate_vector,
> +        &vmstate_p_vxsat,
>           &vmstate_pointermasking,
>           &vmstate_rv128,
>   #ifdef CONFIG_KVM
> diff --git a/target/riscv/tcg/csr.c b/target/riscv/tcg/csr.c
> index 36f2004bc56..e809997f52e 100644
> --- a/target/riscv/tcg/csr.c
> +++ b/target/riscv/tcg/csr.c
> @@ -109,6 +109,24 @@ static RISCVException vs(CPURISCVState *env, int csrno)
>       return RISCV_EXCP_ILLEGAL_INST;
>   }
>   
> +/* vxsat is also architectural state when P is implemented without Zve*. */
> +static RISCVException vxsat(CPURISCVState *env, int csrno)
> +{
> +    if (riscv_cpu_cfg(env)->ext_zve32x) {
> +        return vs(env, csrno);
> +    }
> +
> +    if (riscv_has_ext(env, RVP)) {
> +#if !defined(CONFIG_USER_ONLY)
> +        return smstateen_acc_ok(env, 0, SMSTATEEN0_VXSAT);
> +#else
> +        return RISCV_EXCP_NONE;
> +#endif
> +    }
> +
> +    return RISCV_EXCP_ILLEGAL_INST;
> +}
> +
>   static RISCVException ctr(CPURISCVState *env, int csrno)
>   {
>   #if !defined(CONFIG_USER_ONLY)
> @@ -1013,7 +1031,12 @@ static RISCVException write_vxsat(CPURISCVState *env, int csrno,
>                                     target_ulong val, uintptr_t ra)
>   {
>   #if !defined(CONFIG_USER_ONLY)
> -    env->mstatus |= MSTATUS_VS;
> +    if (riscv_cpu_cfg(env)->ext_zve32x) {
> +        env->mstatus |= MSTATUS_VS;
> +        if (env->virt_enabled) {
> +            env->mstatus_hs |= MSTATUS_VS;
> +        }
> +    }
>   #endif
>       env->vxsat = val & BIT(0);
>       return RISCV_EXCP_NONE;
> @@ -3494,6 +3517,10 @@ static RISCVException write_mstateen0(CPURISCVState *env, int csrno,
>                                         target_ulong new_val, uintptr_t ra)
>   {
>       uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG;
> +
> +    if (riscv_has_ext(env, RVP) && !riscv_cpu_cfg(env)->ext_zve32x) {
> +        wr_mask |= SMSTATEEN0_VXSAT;
> +    }
>       if (!riscv_has_ext(env, RVF)) {
>           wr_mask |= SMSTATEEN0_FCSR;
>       }
> @@ -3617,6 +3644,10 @@ static RISCVException write_hstateen0(CPURISCVState *env, int csrno,
>   {
>       uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG;
>   
> +    if (riscv_has_ext(env, RVP) && !riscv_cpu_cfg(env)->ext_zve32x) {
> +        wr_mask |= SMSTATEEN0_VXSAT;
> +    }
> +
>       if (!riscv_has_ext(env, RVF)) {
>           wr_mask |= SMSTATEEN0_FCSR;
>       }
> @@ -3746,6 +3777,10 @@ static RISCVException write_sstateen0(CPURISCVState *env, int csrno,
>   {
>       uint64_t wr_mask = 0;
>   
> +    if (riscv_has_ext(env, RVP) && !riscv_cpu_cfg(env)->ext_zve32x) {
> +        wr_mask |= SMSTATEEN0_VXSAT;
> +    }
> +
>       if (!riscv_has_ext(env, RVF)) {
>           wr_mask |= SMSTATEEN0_FCSR;
>       }
> @@ -5916,7 +5951,7 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
>       [CSR_FCSR]     = { "fcsr",     fs,     read_fcsr,    write_fcsr   },
>       /* Vector CSRs */
>       [CSR_VSTART]   = { "vstart",   vs,     read_vstart,  write_vstart },
> -    [CSR_VXSAT]    = { "vxsat",    vs,     read_vxsat,   write_vxsat  },
> +    [CSR_VXSAT]    = { "vxsat",    vxsat,  read_vxsat,   write_vxsat  },
>       [CSR_VXRM]     = { "vxrm",     vs,     read_vxrm,    write_vxrm   },
>       [CSR_VCSR]     = { "vcsr",     vs,     read_vcsr,    write_vcsr   },
>       [CSR_VL]       = { "vl",       vs,     read_vl                    },
> diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
> index 4af5cd9c731..1665583accf 100644
> --- a/target/riscv/tcg/tcg-cpu.c
> +++ b/target/riscv/tcg/tcg-cpu.c
> @@ -160,6 +160,8 @@ static TCGTBCPUState riscv_get_tb_cpu_state(CPUState *cs)
>       fs = EXT_STATUS_DIRTY;
>       vs = EXT_STATUS_DIRTY;
>   #else
> +    RISCVException p_vxsat_excp;
> +
>       flags = FIELD_DP32(flags, TB_FLAGS, PRIV, env->priv);
>   
>       flags |= riscv_env_mmu_index(env, 0);
> @@ -182,6 +184,23 @@ static TCGTBCPUState riscv_get_tb_cpu_state(CPUState *cs)
>                ? EXT_STATUS_DIRTY : EXT_STATUS_DISABLED;
>       }
>   
> +    /*
> +     * Without Zve*, all P instructions in the OP-32 and OP-IMM-32
> +     * spaces are controlled by stateen0.VXSAT.  Preserve the exception
> +     * class in the TB flags so translated code can distinguish an illegal
> +     * instruction from a virtual-instruction exception.
> +     */
> +    p_vxsat_excp = smstateen_acc_ok(env, 0, SMSTATEEN0_VXSAT);
> +    if (riscv_has_ext(env, RVP) && !riscv_cpu_cfg(env)->ext_zve32x) {
> +        if (p_vxsat_excp == RISCV_EXCP_VIRT_INSTRUCTION_FAULT) {
> +            ext_flags = FIELD_DP64(ext_flags, EXT_TB_FLAGS, P_VXSAT_EXCP,
> +                                   P_VXSAT_EXCP_VIRTUAL);
> +        } else if (p_vxsat_excp != RISCV_EXCP_NONE) {
> +            ext_flags = FIELD_DP64(ext_flags, EXT_TB_FLAGS, P_VXSAT_EXCP,
> +                                   P_VXSAT_EXCP_ILLEGAL);
> +        }
> +    }
> +
>       if (cpu->cfg.debug && !icount_enabled()) {
>           flags = FIELD_DP32(flags, TB_FLAGS, ITRIGGER, env->itrigger_enabled);
>       }
> @@ -530,6 +549,28 @@ static void riscv_cpu_validate_b(RISCVCPU *cpu)
>       }
>   }
>   
> +static void riscv_cpu_validate_p(RISCVCPU *cpu, Error **errp)
> +{
> +    CPURISCVState *env = &cpu->env;
> +
> +    if (!riscv_has_ext(env, RVP)) {
> +        return;
> +    }
> +
> +    if (riscv_cpu_mxl(env) != MXL_RV32 &&
> +        riscv_cpu_mxl(env) != MXL_RV64) {
> +        error_setg(errp, "P extension requires RV32 or RV64");
> +        return;
> +    }
> +
> +    if (!(cpu->cfg.ext_zmmul && cpu->cfg.ext_zba && cpu->cfg.ext_zbb &&
> +          cpu->cfg.ext_zbkb)) {
> +        error_setg(errp, "P extension requires zmmul, zba, zbb and zbkb "
> +                         "extensions");
> +        return;
> +    }
> +}
> +
>   /*
>    * Check consistency between chosen extensions while setting
>    * cpu->cfg accordingly.
> @@ -612,6 +653,12 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp)
>           return;
>       }
>   
> +    riscv_cpu_validate_p(cpu, &local_err);
> +    if (local_err != NULL) {
> +        error_propagate(errp, local_err);
> +        return;
> +    }
> +
>       riscv_cpu_validate_v(env, &cpu->cfg, &local_err);
>       if (local_err != NULL) {
>           error_propagate(errp, local_err);
> @@ -1414,6 +1461,7 @@ static const RISCVCPUMisaExtConfig misa_ext_cfgs[] = {
>       MISA_CFG(RVV, false),
>       MISA_CFG(RVG, false),
>       MISA_CFG(RVB, false),
> +    MISA_CFG(RVP, false),
>   };
>   
>   /*


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH v2 02/18] target/riscv: Add packed SIMD helper framework
  2026-07-17 10:06 ` [PATCH v2 02/18] target/riscv: Add packed SIMD helper framework Molly Chen
  2026-07-26 19:53   ` Daniel Henrique Barboza
@ 2026-07-27  6:16   ` Nutty.Liu
  2026-07-29  9:01   ` Chao Liu
  2 siblings, 0 replies; 34+ messages in thread
From: Nutty.Liu @ 2026-07-27  6:16 UTC (permalink / raw)
  To: Molly Chen, palmer, alistair.francis, liwei1518, daniel.barboza,
	zhiwei_liu, chao.liu.zevorn, Chao Liu
  Cc: qemu-riscv, qemu-devel


On 7/17/2026 6:06 PM, Molly Chen wrote:
> Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
It would be better to add some description for this series.
Otherwise,
Reviewed-by: Nutty Liu <nutty.liu@hotmail.com>

Thanks,
Nutty
> ---
>   target/riscv/tcg/meson.build    |    3 +-
>   target/riscv/tcg/psimd_helper.c | 1656 +++++++++++++++++++++++++++++++
>   2 files changed, 1658 insertions(+), 1 deletion(-)
>   create mode 100644 target/riscv/tcg/psimd_helper.c
>
> diff --git a/target/riscv/tcg/meson.build b/target/riscv/tcg/meson.build
> index a05ab642f41..cc438d7c0d2 100644
> --- a/target/riscv/tcg/meson.build
> +++ b/target/riscv/tcg/meson.build
> @@ -15,7 +15,8 @@ riscv_ss.add(files(
>     'vcrypto_helper.c',
>     'vector_helper.c',
>     'vector_internals.c',
> -  'zce_helper.c'))
> +  'zce_helper.c',
> +  'psimd_helper.c'))
>   
>   
>   riscv_system_ss.add(files(
> diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
> new file mode 100644
> index 00000000000..2948bbb2a86
> --- /dev/null
> +++ b/target/riscv/tcg/psimd_helper.c
> @@ -0,0 +1,1656 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/* RISC-V Packed SIMD Extension Helpers for QEMU. */
> +/* Copyright (C) 2026 ISRC ISCAS. */
> +
> +#include "qemu/osdep.h"
> +#include "cpu.h"
> +#include "qemu/host-utils.h"
> +#include "exec/helper-proto.h"
> +#include "fpu/softfloat.h"
> +#include "internals.h"
> +
> +
> +/* Helper macros */
> +
> +/* Element count calculations */
> +#define ELEMS_B(target) (sizeof(target) * 8 / 8)    /* byte elements count */
> +#define ELEMS_H(target) (sizeof(target) * 8 / 16)
> +#define ELEMS_W(target) (sizeof(target) * 8 / 32)   /* word elements count */
> +#define ELEMS_D(target) (sizeof(target) * 8 / 64)
> +
> +/* Element extraction macros - unsigned to avoid sign extension */
> +#define EXTRACT8(val, idx)  (((val) >> ((idx) * 8)) & 0xFF)
> +#define EXTRACT16(val, idx) (((val) >> ((idx) * 16)) & 0xFFFF)
> +#define EXTRACT32(val, idx) (((val) >> ((idx) * 32)) & 0xFFFFFFFF)
> +#define EXTRACT64(val, idx) (((val) >> ((idx) * 64)) & 0xFFFFFFFFFFFFFFFFULL)
> +
> +/* Element insertion macros */
> +#define INSERT8(val, res, idx) \
> +    ((val) | ((target_ulong)(uint8_t)(res) << ((idx) * 8)))
> +#define INSERT16(val, res, idx) \
> +    ((val) | ((target_ulong)(uint16_t)(res) << ((idx) * 16)))
> +#define INSERT32(val, res, idx) \
> +    ((val) | ((target_ulong)(uint32_t)(res) << ((idx) * 32)))
> +#define INSERT32_64(val, res, idx) \
> +    ((val) | ((uint64_t)(uint32_t)(res) << ((idx) * 32)))
> +#define INSERT64(val, res, idx) \
> +    ((val) | ((uint64_t)(res) << ((idx) * 64)))
> +
> +/* Saturation constants */
> +static const int8_t   SAT_MAX_B = 127;
> +static const int8_t   SAT_MIN_B = -128;
> +static const int16_t  SAT_MAX_H = 32767;
> +static const int16_t  SAT_MIN_H = -32768;
> +static const int32_t  SAT_MAX_W = 2147483647;
> +static const int32_t  SAT_MIN_W = -2147483648LL;
> +static const uint8_t  USAT_MAX_B = 255;
> +static const uint16_t USAT_MAX_H = 65535;
> +static const uint32_t USAT_MAX_W = 4294967295U;
> +
> +
> +/* Saturation helper functions */
> +
> +/**
> + * Signed saturation for 8-bit elements
> + * Returns saturated value and sets *sat if saturation occurred
> + */
> +static inline int8_t signed_saturate_b(int32_t val, int *sat)
> +{
> +    if (val > SAT_MAX_B) {
> +        *sat = 1;
> +        return SAT_MAX_B;
> +    }
> +    if (val < SAT_MIN_B) {
> +        *sat = 1;
> +        return SAT_MIN_B;
> +    }
> +    return (int8_t)val;
> +}
> +
> +/**
> + * Signed saturation for 16-bit elements
> + */
> +static inline int16_t signed_saturate_h(int32_t val, int *sat)
> +{
> +    if (val > SAT_MAX_H) {
> +        *sat = 1;
> +        return SAT_MAX_H;
> +    }
> +    if (val < SAT_MIN_H) {
> +        *sat = 1;
> +        return SAT_MIN_H;
> +    }
> +    return (int16_t)val;
> +}
> +
> +/**
> + * Signed saturation for 32-bit elements
> + */
> +static inline int32_t signed_saturate_w(int64_t val, int *sat)
> +{
> +    if (val > SAT_MAX_W) {
> +        *sat = 1;
> +        return SAT_MAX_W;
> +    }
> +    if (val < SAT_MIN_W) {
> +        *sat = 1;
> +        return SAT_MIN_W;
> +    }
> +    return (int32_t)val;
> +}
> +
> +/**
> + * Unsigned saturation for 8-bit elements
> + */
> +static inline uint8_t unsigned_saturate_b(uint32_t val, int *sat)
> +{
> +    if (val > USAT_MAX_B) {
> +        *sat = 1;
> +        return USAT_MAX_B;
> +    }
> +    return (uint8_t)val;
> +}
> +
> +/**
> + * Unsigned saturation for 16-bit elements
> + */
> +static inline uint16_t unsigned_saturate_h(uint32_t val, int *sat)
> +{
> +    if (val > USAT_MAX_H) {
> +        *sat = 1;
> +        return USAT_MAX_H;
> +    }
> +    return (uint16_t)val;
> +}
> +
> +/**
> + * Unsigned saturation for 32-bit elements
> + */
> +static inline uint32_t unsigned_saturate_w(uint64_t val, int *sat)
> +{
> +    if (val > USAT_MAX_W) {
> +        *sat = 1;
> +        return USAT_MAX_W;
> +    }
> +    return (uint32_t)val;
> +}
> +
> +static inline target_ulong psimd_abdsumu_b(target_ulong rs1,
> +                                           target_ulong rs2,
> +                                           target_ulong sum)
> +{
> +    int elems = ELEMS_B(rs1);
> +
> +    for (int i = 0; i < elems; i++) {
> +        uint8_t e1 = EXTRACT8(rs1, i);
> +        uint8_t e2 = EXTRACT8(rs2, i);
> +        uint8_t diff = (e1 > e2) ? (e1 - e2) : (e2 - e1);
> +        sum += diff;
> +    }
> +
> +    return sum;
> +}
> +
> +#define PSIMD_DO_ADD(N, M) ((N) + (M))
> +#define PSIMD_DO_SUB(N, M) ((N) - (M))
> +#define PSIMD_DO_ABD(N, M) ((N) >= (M) ? (N) - (M) : (M) - (N))
> +#define PSIMD_DO_EQ_MASK(N, M) ((N) == (M) ? -1 : 0)
> +#define PSIMD_DO_LT_MASK(N, M) ((N) < (M) ? -1 : 0)
> +#define PSIMD_DO_MIN(N, M) ((N) < (M) ? (N) : (M))
> +#define PSIMD_DO_MAX(N, M) ((N) > (M) ? (N) : (M))
> +#define PSIMD_DO_SLL(N, M) ((N) << (M))
> +#define PSIMD_DO_SRL(N, M) ((N) >> (M))
> +#define PSIMD_DO_SRA(N, M) ((N) >> (M))
> +
> +#define GEN_PSIMD_BINOP(NAME, RTYPE, STYPE, DTYPE, EXTRACT, INSERT,       \
> +                        ELEMS, OP)                                        \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        STYPE e1 = (STYPE)EXTRACT(rs1, i);                                \
> +        STYPE e2 = (STYPE)EXTRACT(rs2, i);                                \
> +        DTYPE res = (DTYPE)OP(e1, e2);                                    \
> +        rd = INSERT(rd, res, i);                                          \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_BINOP_SCALAR(NAME, RTYPE, ETYPE, EXTRACT, INSERT,       \
> +                               ELEMS, OP)                                 \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +    ETYPE e2 = (ETYPE)EXTRACT(rs2, 0);                                    \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
> +        ETYPE res = OP(e1, e2);                                           \
> +        rd = INSERT(rd, res, i);                                          \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_SHIFTOP(NAME, RTYPE, STYPE, DTYPE, EXTRACT, INSERT,     \
> +                          ELEMS, SHMASK, OP)                              \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +    uint8_t shamt = rs2 & (SHMASK);                                       \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        STYPE e1 = (STYPE)EXTRACT(rs1, i);                                \
> +        DTYPE res = (DTYPE)OP(e1, shamt);                                 \
> +        rd = INSERT(rd, res, i);                                          \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_SAT_SHIFTOP(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT, \
> +                              ELEMS, SHMASK, SAT_FN)                      \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +    int sat = 0;                                                          \
> +    uint8_t shamt = rs2 & (SHMASK);                                       \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
> +        WTYPE shifted = (WTYPE)e1 << shamt;                               \
> +        ETYPE res = SAT_FN(shifted, &sat);                                \
> +        rd = INSERT(rd, res, i);                                          \
> +    }                                                                     \
> +                                                                          \
> +    if (sat) {                                                            \
> +        env->vxsat = 1;                                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_ROUND_SRAI(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT,  \
> +                             ELEMS, SHMASK)                               \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +    uint8_t shamt = rs2 & (SHMASK);                                       \
> +                                                                          \
> +    if (shamt == 0) {                                                     \
> +        return rs1;                                                       \
> +    }                                                                     \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
> +        WTYPE rounded = (((WTYPE)e1 >> (shamt - 1)) + 1) >> 1;            \
> +        rd = INSERT(rd, (ETYPE)rounded, i);                               \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_SAT_BINOP(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT,   \
> +                            ELEMS, OP, SAT_FN)                            \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +    int sat = 0;                                                          \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
> +        ETYPE e2 = (ETYPE)EXTRACT(rs2, i);                                \
> +        WTYPE val = OP((WTYPE)e1, (WTYPE)e2);                             \
> +        ETYPE res = SAT_FN(val, &sat);                                    \
> +        rd = INSERT(rd, res, i);                                          \
> +    }                                                                     \
> +                                                                          \
> +    if (sat) {                                                            \
> +        env->vxsat = 1;                                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_USUB_SAT(NAME, RTYPE, ETYPE, EXTRACT, INSERT, ELEMS)    \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +    int sat = 0;                                                          \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
> +        ETYPE e2 = (ETYPE)EXTRACT(rs2, i);                                \
> +        ETYPE res = (e1 >= e2) ? (e1 - e2) : 0;                           \
> +        if (e1 < e2) {                                                    \
> +            sat = 1;                                                      \
> +        }                                                                 \
> +        rd = INSERT(rd, res, i);                                          \
> +    }                                                                     \
> +                                                                          \
> +    if (sat) {                                                            \
> +        env->vxsat = 1;                                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_AVG_BINOP(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT,   \
> +                            ELEMS, OP)                                    \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        WTYPE e1 = (WTYPE)(ETYPE)EXTRACT(rs1, i);                         \
> +        WTYPE e2 = (WTYPE)(ETYPE)EXTRACT(rs2, i);                         \
> +        ETYPE res = (ETYPE)(OP(e1, e2) >> 1);                             \
> +        rd = INSERT(rd, res, i);                                          \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_SHADD(NAME, RTYPE, ETYPE, EXTRACT, INSERT, ELEMS,       \
> +                        SHAMT)                                            \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
> +        ETYPE e2 = (ETYPE)EXTRACT(rs2, i);                                \
> +        ETYPE res = (e1 << (SHAMT)) + e2;                                 \
> +        rd = INSERT(rd, res, i);                                          \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_SAT_SHADD(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT,   \
> +                            ELEMS, SHAMT, SH_MIN, SH_MAX, SAT_MIN,        \
> +                            SAT_MAX, SAT_FN)                              \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +    int sat = 0;                                                          \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
> +        ETYPE e2 = (ETYPE)EXTRACT(rs2, i);                                \
> +        WTYPE shifted;                                                    \
> +                                                                          \
> +        if (e1 > (SH_MAX) || e1 < (SH_MIN)) {                             \
> +            shifted = (e1 < 0) ? (SAT_MIN) : (SAT_MAX);                   \
> +            sat = 1;                                                      \
> +        } else {                                                          \
> +            shifted = (WTYPE)e1 << (SHAMT);                               \
> +        }                                                                 \
> +                                                                          \
> +        WTYPE sum = shifted + e2;                                         \
> +        ETYPE res = SAT_FN(sum, &sat);                                    \
> +        rd = INSERT(rd, res, i);                                          \
> +    }                                                                     \
> +                                                                          \
> +    if (sat) {                                                            \
> +        env->vxsat = 1;                                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_SATI(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT,        \
> +                       ELEMS, IMMMASK)                                    \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE imm)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +    int range = (imm & (IMMMASK)) + 1;                                    \
> +    WTYPE max = ((WTYPE)1 << (range - 1)) - 1;                            \
> +    WTYPE min = -((WTYPE)1 << (range - 1));                               \
> +    int sat = 0;                                                          \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
> +        ETYPE res;                                                        \
> +                                                                          \
> +        if (e1 > max) {                                                   \
> +            res = max;                                                    \
> +            sat = 1;                                                      \
> +        } else if (e1 < min) {                                            \
> +            res = min;                                                    \
> +            sat = 1;                                                      \
> +        } else {                                                          \
> +            res = e1;                                                     \
> +        }                                                                 \
> +                                                                          \
> +        rd = INSERT(rd, res, i);                                          \
> +    }                                                                     \
> +                                                                          \
> +    if (sat) {                                                            \
> +        env->vxsat = 1;                                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_USATI(NAME, RTYPE, ETYPE, UTYPE, WTYPE, EXTRACT,        \
> +                        INSERT, ELEMS, ONE)                               \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE imm)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +    WTYPE max = ((WTYPE)(ONE) << imm) - 1;                                \
> +    int sat = 0;                                                          \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
> +        ETYPE res;                                                        \
> +                                                                          \
> +        if (e1 < 0) {                                                     \
> +            res = 0;                                                      \
> +            sat = 1;                                                      \
> +        } else if ((UTYPE)e1 > max) {                                     \
> +            res = max;                                                    \
> +            sat = 1;                                                      \
> +        } else {                                                          \
> +            res = e1;                                                     \
> +        }                                                                 \
> +                                                                          \
> +        rd = INSERT(rd, res, i);                                          \
> +    }                                                                     \
> +                                                                          \
> +    if (sat) {                                                            \
> +        env->vxsat = 1;                                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_ABS(NAME, RTYPE, ETYPE, EXTRACT, INSERT, ELEMS,         \
> +                      MINVAL, MAXVAL)                                     \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1)                         \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +    int sat = 0;                                                          \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
> +        ETYPE res;                                                        \
> +                                                                          \
> +        if (e1 == (MINVAL)) {                                             \
> +            res = (MAXVAL);                                               \
> +            sat = 1;                                                      \
> +        } else if (e1 < 0) {                                              \
> +            res = -e1;                                                    \
> +        } else {                                                          \
> +            res = e1;                                                     \
> +        }                                                                 \
> +                                                                          \
> +        rd = INSERT(rd, res, i);                                          \
> +    }                                                                     \
> +                                                                          \
> +    if (sat) {                                                            \
> +        env->vxsat = 1;                                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_SCALAR_ABS(NAME, RTYPE, STYPE, UTYPE)                   \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1)                         \
> +{                                                                         \
> +    STYPE value = (STYPE)rs1;                                            \
> +    UTYPE result = (UTYPE)value;                                         \
> +                                                                          \
> +    if (value < 0) {                                                      \
> +        result = (UTYPE)0 - result;                                      \
> +    }                                                                     \
> +    return (RTYPE)(STYPE)result;                                         \
> +}
> +
> +#define GEN_PSIMD_VAR_SSHA(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT,    \
> +                           ELEMS, BITS, SAT_FN)                           \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +    int sat = 0;                                                          \
> +    int8_t shamt = (int8_t)(rs2 & 0xff);                                  \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
> +        ETYPE res;                                                        \
> +                                                                          \
> +        if (shamt >= 0) {                                                 \
> +            WTYPE shifted = (WTYPE)e1 << shamt;                           \
> +            res = SAT_FN(shifted, &sat);                                  \
> +        } else {                                                          \
> +            int right = -shamt;                                           \
> +            if (right >= (BITS)) {                                        \
> +                res = (e1 < 0) ? -1 : 0;                                  \
> +            } else {                                                      \
> +                res = e1 >> right;                                        \
> +            }                                                             \
> +        }                                                                 \
> +                                                                          \
> +        rd = INSERT(rd, res, i);                                          \
> +    }                                                                     \
> +                                                                          \
> +    if (sat) {                                                            \
> +        env->vxsat = 1;                                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_VAR_SSHAR(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT,   \
> +                            ELEMS, BITS, SAT_MIN, SAT_MAX, SAT_FN)        \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +    int sat = 0;                                                          \
> +    int8_t shamt = (int8_t)(rs2 & 0xff);                                  \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
> +        ETYPE res;                                                        \
> +                                                                          \
> +        if (shamt >= 0) {                                                 \
> +            if (shamt >= (BITS)) {                                        \
> +                if (e1 == 0) {                                            \
> +                    res = 0;                                              \
> +                } else if (e1 > 0) {                                      \
> +                    res = (SAT_MAX);                                      \
> +                    sat = 1;                                              \
> +                } else {                                                  \
> +                    res = (SAT_MIN);                                      \
> +                    sat = 1;                                              \
> +                }                                                         \
> +            } else {                                                      \
> +                WTYPE shifted = (WTYPE)e1 * ((WTYPE)1 << shamt);          \
> +                res = SAT_FN(shifted, &sat);                              \
> +            }                                                             \
> +        } else {                                                          \
> +            int right = -shamt;                                           \
> +            if (right >= (BITS)) {                                        \
> +                res = 0;                                                  \
> +            } else {                                                      \
> +                WTYPE rounded = ((e1 >> (right - 1)) + 1) >> 1;           \
> +                res = (ETYPE)rounded;                                     \
> +            }                                                             \
> +        }                                                                 \
> +                                                                          \
> +        rd = INSERT(rd, res, i);                                          \
> +    }                                                                     \
> +                                                                          \
> +    if (sat) {                                                            \
> +        env->vxsat = 1;                                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_VAR_USHL(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT,    \
> +                           ELEMS, BITS, SAT_FN)                           \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +    int sat = 0;                                                          \
> +    int8_t shamt = (int8_t)(rs2 & 0xff);                                  \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
> +        ETYPE res;                                                        \
> +                                                                          \
> +        if (shamt >= 0) {                                                 \
> +            WTYPE shifted = (shamt >= (BITS)) ?                           \
> +                            ((WTYPE)e1 << (BITS)) :                       \
> +                            ((WTYPE)e1 << shamt);                         \
> +            res = SAT_FN(shifted, &sat);                                  \
> +        } else {                                                          \
> +            int right = -shamt;                                           \
> +            if (right >= (BITS)) {                                        \
> +                res = 0;                                                  \
> +            } else {                                                      \
> +                res = e1 >> right;                                        \
> +            }                                                             \
> +        }                                                                 \
> +                                                                          \
> +        rd = INSERT(rd, res, i);                                          \
> +    }                                                                     \
> +                                                                          \
> +    if (sat) {                                                            \
> +        env->vxsat = 1;                                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_VAR_USHLR(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT,   \
> +                            ELEMS, BITS, SAT_FN)                          \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +    int sat = 0;                                                          \
> +    int8_t shamt = (int8_t)(rs2 & 0xff);                                  \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
> +        ETYPE res;                                                        \
> +                                                                          \
> +        if (shamt >= 0) {                                                 \
> +            WTYPE shifted = (shamt >= (BITS)) ?                           \
> +                            ((WTYPE)e1 << (BITS)) :                       \
> +                            ((WTYPE)e1 << shamt);                         \
> +            res = SAT_FN(shifted, &sat);                                  \
> +        } else {                                                          \
> +            int right = -shamt;                                           \
> +            if (right > (BITS)) {                                         \
> +                res = 0;                                                  \
> +            } else {                                                      \
> +                WTYPE rounded = ((WTYPE)e1 >> (right - 1)) + 1;           \
> +                res = (ETYPE)(rounded >> 1);                              \
> +            }                                                             \
> +        }                                                                 \
> +                                                                          \
> +        rd = INSERT(rd, res, i);                                          \
> +    }                                                                     \
> +                                                                          \
> +    if (sat) {                                                            \
> +        env->vxsat = 1;                                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define PSIMD_DO_SRA64(A, B) ((A) >> (B))
> +#define PSIMD_DO_RNDSRA64(A, B)                                          \
> +    ((int64_t)((((__int128_t)(A) >> ((B) - 1)) + 1) >> 1))
> +
> +#define GEN_PSIMD_VAR_SRA64(NAME, RIGHT_OP)                               \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint64_t rs1, uint64_t rs2)     \
> +{                                                                         \
> +    int64_t a = (int64_t)rs1;                                            \
> +    int8_t shamt = (int8_t)(rs2 & 0xff);                                 \
> +                                                                          \
> +    if (shamt >= 0) {                                                     \
> +        return (uint64_t)(a << shamt);                                    \
> +    }                                                                     \
> +                                                                          \
> +    int right = -shamt;                                                   \
> +    if (right >= 64) {                                                    \
> +        return (a < 0) ? (uint64_t)-1 : 0;                               \
> +    }                                                                     \
> +    return (uint64_t)RIGHT_OP(a, right);                                  \
> +}
> +
> +#define PSIMD_DO_SRL64(A, B) (((B) >= 64) ? 0 : ((A) >> (B)))
> +#define PSIMD_DO_RNDSRL64(A, B)                                          \
> +    (((B) > 64) ? 0 : ((((A) >> ((B) - 1)) + 1) >> 1))
> +
> +#define GEN_PSIMD_VAR_SRL64(NAME, RIGHT_OP)                               \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint64_t rs1, uint64_t rs2)     \
> +{                                                                         \
> +    int8_t shamt = (int8_t)(rs2 & 0xff);                                 \
> +                                                                          \
> +    if (shamt < 0) {                                                      \
> +        return RIGHT_OP(rs1, -shamt);                                     \
> +    }                                                                     \
> +    return (shamt >= 64) ? 0 : (rs1 << shamt);                           \
> +}
> +
> +#define GEN_PSIMD_XPAIR_BINOP(NAME, RTYPE, ETYPE, EXTRACT, INSERT,        \
> +                              ELEMS, OP_LO, OP_HI)                        \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +                                                                          \
> +    for (int i = 0; i < elems; i += 2) {                                  \
> +        ETYPE s1_lo = (ETYPE)EXTRACT(rs1, i);                             \
> +        ETYPE s1_hi = (ETYPE)EXTRACT(rs1, i + 1);                         \
> +        ETYPE s2_lo = (ETYPE)EXTRACT(rs2, i);                             \
> +        ETYPE s2_hi = (ETYPE)EXTRACT(rs2, i + 1);                         \
> +        ETYPE res_lo = OP_LO(s1_lo, s2_hi);                               \
> +        ETYPE res_hi = OP_HI(s1_hi, s2_lo);                               \
> +        rd = INSERT(rd, res_lo, i);                                       \
> +        rd = INSERT(rd, res_hi, i + 1);                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_XPAIR_SAT_BINOP(NAME, RTYPE, ETYPE, WTYPE, EXTRACT,     \
> +                                  INSERT, ELEMS, OP_LO, OP_HI, SAT_FN)    \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +    int sat = 0;                                                          \
> +                                                                          \
> +    for (int i = 0; i < elems; i += 2) {                                  \
> +        ETYPE s1_lo = (ETYPE)EXTRACT(rs1, i);                             \
> +        ETYPE s1_hi = (ETYPE)EXTRACT(rs1, i + 1);                         \
> +        ETYPE s2_lo = (ETYPE)EXTRACT(rs2, i);                             \
> +        ETYPE s2_hi = (ETYPE)EXTRACT(rs2, i + 1);                         \
> +        WTYPE val_lo = OP_LO((WTYPE)s1_lo, (WTYPE)s2_hi);                 \
> +        WTYPE val_hi = OP_HI((WTYPE)s1_hi, (WTYPE)s2_lo);                 \
> +        ETYPE res_lo = SAT_FN(val_lo, &sat);                              \
> +        ETYPE res_hi = SAT_FN(val_hi, &sat);                              \
> +        rd = INSERT(rd, res_lo, i);                                       \
> +        rd = INSERT(rd, res_hi, i + 1);                                   \
> +    }                                                                     \
> +                                                                          \
> +    if (sat) {                                                            \
> +        env->vxsat = 1;                                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_XPAIR_AVG_BINOP(NAME, RTYPE, ETYPE, WTYPE, EXTRACT,     \
> +                                  INSERT, ELEMS, OP_LO, OP_HI)            \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +                                                                          \
> +    for (int i = 0; i < elems; i += 2) {                                  \
> +        ETYPE s1_lo = (ETYPE)EXTRACT(rs1, i);                             \
> +        ETYPE s1_hi = (ETYPE)EXTRACT(rs1, i + 1);                         \
> +        ETYPE s2_lo = (ETYPE)EXTRACT(rs2, i);                             \
> +        ETYPE s2_hi = (ETYPE)EXTRACT(rs2, i + 1);                         \
> +        ETYPE res_lo = (ETYPE)(OP_LO((WTYPE)s1_lo, (WTYPE)s2_hi) >> 1);   \
> +        ETYPE res_hi = (ETYPE)(OP_HI((WTYPE)s1_hi, (WTYPE)s2_lo) >> 1);   \
> +        rd = INSERT(rd, res_lo, i);                                       \
> +        rd = INSERT(rd, res_hi, i + 1);                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_REDSUM(NAME, RTYPE, SUMTYPE, ETYPE, EXTRACT, ELEMS,     \
> +                         INIT)                                            \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    SUMTYPE sum = (INIT);                                                 \
> +    int elems = ELEMS(rs1);                                               \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
> +        sum += e1;                                                        \
> +    }                                                                     \
> +                                                                          \
> +    return (RTYPE)sum;                                                    \
> +}
> +
> +#define PSIMD_PAIR_LO(V, MASK, SHIFT) ((V) & (MASK))
> +#define PSIMD_PAIR_HI(V, MASK, SHIFT) (((V) >> (SHIFT)) & (MASK))
> +
> +#define GEN_PSIMD_PAIR_PACK(NAME, RTYPE, ETYPE, EXTRACT, INSERT, ELEMS,   \
> +                            MASK, SHIFT, HI_SEL, LO_SEL)                 \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        ETYPE e1 = EXTRACT(rs1, i);                                       \
> +        ETYPE e2 = EXTRACT(rs2, i);                                       \
> +        ETYPE res = (HI_SEL(e2, MASK, SHIFT) << (SHIFT)) |                \
> +                    LO_SEL(e1, MASK, SHIFT);                              \
> +        rd = INSERT(rd, res, i);                                          \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_PAIR_WORD(NAME, RS1_IDX, RS2_IDX)                       \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint64_t rs1, uint64_t rs2)     \
> +{                                                                         \
> +    uint32_t e1 = EXTRACT32(rs1, RS1_IDX);                                \
> +    uint32_t e2 = EXTRACT32(rs2, RS2_IDX);                                \
> +                                                                          \
> +    return ((uint64_t)e2 << 32) | e1;                                     \
> +}
> +
> +#define GEN_PSIMD_SIGN_EXTEND(NAME, RTYPE, STYPE, DTYPE, EXTRACT, INSERT, \
> +                              ELEMS, SCALE)                               \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1)                         \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        STYPE e1 = (STYPE)EXTRACT(rs1, i * (SCALE));                      \
> +        rd = INSERT(rd, (DTYPE)e1, i);                                    \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_ZIP(NAME, ETYPE, EXTRACT, ELEMS, BITS, START)           \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint64_t rs1, uint64_t rs2)     \
> +{                                                                         \
> +    uint64_t rd = 0;                                                      \
> +                                                                          \
> +    for (int i = 0; i < (ELEMS); i++) {                                   \
> +        ETYPE e1 = EXTRACT(rs1, (START) - i);                             \
> +        ETYPE e2 = EXTRACT(rs2, (START) - i);                             \
> +        rd = (rd << (2 * (BITS))) | ((uint64_t)e2 << (BITS)) | e1;        \
> +    }                                                                     \
> +                                                                          \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_UNZIP(NAME, EXTRACT, ELEMS, BITS, OFFSET)               \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint64_t rs1, uint64_t rs2)     \
> +{                                                                         \
> +    uint64_t rd = 0;                                                      \
> +                                                                          \
> +    for (int i = 0; i < (ELEMS); i++) {                                   \
> +        uint64_t e1 = (uint64_t)EXTRACT(rs1, 2 * i + (OFFSET)) <<         \
> +                      ((BITS) * i);                                       \
> +        uint64_t e2 = (uint64_t)EXTRACT(rs2, 2 * i + (OFFSET)) <<         \
> +                      (32 + (BITS) * i);                                  \
> +        rd = rd | e2 | e1;                                                \
> +    }                                                                     \
> +                                                                          \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_BIT_SELECT(NAME, MASK, TRUE_VAL, FALSE_VAL)             \
> +target_ulong HELPER(NAME)(CPURISCVState *env, target_ulong rs1,           \
> +                          target_ulong rs2, target_ulong rd)              \
> +{                                                                         \
> +    return (~(MASK) & (FALSE_VAL)) | ((MASK) & (TRUE_VAL));               \
> +}
> +
> +#define GEN_PSIMD_NCLIP_PACK(NAME, ITYPE, OTYPE, EXTRACT, INSERT, ELEMS,  \
> +                             SAT_FN)                                      \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint64_t rs1, uint64_t rs2)     \
> +{                                                                         \
> +    uint64_t rd = 0;                                                      \
> +    int sat = 0;                                                          \
> +                                                                          \
> +    for (int i = 0; i < (ELEMS); i++) {                                   \
> +        ITYPE lo = (ITYPE)EXTRACT(rs1, i);                                \
> +        ITYPE hi = (ITYPE)EXTRACT(rs2, i);                                \
> +        OTYPE res_lo = SAT_FN(lo, &sat);                                  \
> +        OTYPE res_hi = SAT_FN(hi, &sat);                                  \
> +                                                                          \
> +        rd = (uint64_t)INSERT(rd, res_lo, i);                             \
> +        rd = (uint64_t)INSERT(rd, res_hi, i + (ELEMS));                   \
> +    }                                                                     \
> +                                                                          \
> +    if (sat) {                                                            \
> +        env->vxsat = 1;                                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_CLS(NAME, RTYPE, UTYPE, CLRSB)                          \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1)                         \
> +{                                                                         \
> +    return CLRSB((UTYPE)rs1);                                             \
> +}
> +
> +#define PSIMD_MUL_S32(A, B)  ((int32_t)(A) * (int32_t)(B))
> +#define PSIMD_MUL_SU16(A, B) ((int16_t)(A) * (uint16_t)(B))
> +#define PSIMD_MUL_SU32(A, B) ((int32_t)(A) * (uint32_t)(B))
> +#define PSIMD_MUL_U32(A, B)  ((uint32_t)(A) * (uint32_t)(B))
> +#define PSIMD_MUL_S64(A, B)  ((int64_t)(A) * (int64_t)(B))
> +#define PSIMD_MUL_SU64(A, B) ((int64_t)(A) * (uint64_t)(B))
> +#define PSIMD_MUL_U64(A, B)  ((uint64_t)(A) * (uint64_t)(B))
> +
> +#define GEN_PSIMD_MUL_HIGH(NAME, RTYPE, E1TYPE, E2TYPE, PTYPE, HTYPE,     \
> +                           EXTRACT, INSERT, ELEMS, SHIFT, ROUND, OP)     \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        E1TYPE e1 = (E1TYPE)EXTRACT(rs1, i);                              \
> +        E2TYPE e2 = (E2TYPE)EXTRACT(rs2, i);                              \
> +        PTYPE prod = OP(e1, e2) + (ROUND);                                \
> +        HTYPE high = (HTYPE)(prod >> (SHIFT));                            \
> +        rd = INSERT(rd, high, i);                                         \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_MUL_HIGH_SEL(NAME, RTYPE, E1TYPE, E2TYPE, PTYPE,        \
> +                               HTYPE, EXTRACT1, EXTRACT2, INSERT, ELEMS, \
> +                               SCALE, OFFSET, SHIFT, OP)                 \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        E1TYPE e1 = (E1TYPE)EXTRACT1(rs1, i);                             \
> +        E2TYPE e2 = (E2TYPE)EXTRACT2(rs2, i * (SCALE) + (OFFSET));        \
> +        PTYPE prod = OP(e1, e2);                                          \
> +        HTYPE high = (HTYPE)(prod >> (SHIFT));                            \
> +        rd = INSERT(rd, high, i);                                         \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_MUL_ELEM_INDEXED(NAME, RTYPE, E1TYPE, E2TYPE, PTYPE,    \
> +                                   OTYPE, EXTRACT, INSERT, ELEMS, SCALE, \
> +                                   OFFSET1, OFFSET2, OP)                 \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        E1TYPE e1 = (E1TYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET1));        \
> +        E2TYPE e2 = (E2TYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET2));        \
> +        PTYPE mul = OP(e1, e2);                                           \
> +        rd = INSERT(rd, (OTYPE)mul, i);                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_MUL_ELEM_SCALAR(NAME, RTYPE, E1TYPE, E2TYPE, PTYPE,     \
> +                                  EXTRACT, OFFSET1, OFFSET2, OP)         \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    E1TYPE e1 = (E1TYPE)EXTRACT(rs1, OFFSET1);                            \
> +    E2TYPE e2 = (E2TYPE)EXTRACT(rs2, OFFSET2);                            \
> +    PTYPE mul = OP(e1, e2);                                               \
> +                                                                          \
> +    return (RTYPE)mul;                                                    \
> +}
> +
> +#define GEN_PSIMD_MUL_HIGH_ACC(NAME, RTYPE, E1TYPE, E2TYPE, DTYPE, PTYPE, \
> +                               HTYPE, OTYPE, EXTRACT, INSERT, ELEMS,     \
> +                               SHIFT, ROUND, OP)                         \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2, RTYPE dest)  \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        E1TYPE e1 = (E1TYPE)EXTRACT(rs1, i);                              \
> +        E2TYPE e2 = (E2TYPE)EXTRACT(rs2, i);                              \
> +        DTYPE d = (DTYPE)EXTRACT(dest, i);                                \
> +        PTYPE prod = OP(e1, e2) + (ROUND);                                \
> +        HTYPE high = (HTYPE)(prod >> (SHIFT));                            \
> +        OTYPE res = (OTYPE)(high + d);                                    \
> +        rd = INSERT(rd, res, i);                                          \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_MUL_HIGH_ACC_SEL(NAME, RTYPE, E1TYPE, E2TYPE, DTYPE,    \
> +                                   PTYPE, HTYPE, OTYPE, EXTRACT1,        \
> +                                   EXTRACT2, INSERT, ELEMS, SCALE,       \
> +                                   OFFSET, SHIFT, OP)                    \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2, RTYPE dest)  \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        E1TYPE e1 = (E1TYPE)EXTRACT1(rs1, i);                             \
> +        E2TYPE e2 = (E2TYPE)EXTRACT2(rs2, i * (SCALE) + (OFFSET));        \
> +        DTYPE d = (DTYPE)EXTRACT1(dest, i);                               \
> +        PTYPE prod = OP(e1, e2);                                          \
> +        HTYPE high = (HTYPE)(prod >> (SHIFT));                            \
> +        OTYPE res = (OTYPE)(high + d);                                    \
> +        rd = INSERT(rd, res, i);                                          \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_MUL_ACC_INDEXED(NAME, RTYPE, E1TYPE, E2TYPE, DTYPE,     \
> +                                  PTYPE, OTYPE, EXTRACT, EXTRACTD,       \
> +                                  INSERT, ELEMS, SCALE, OFFSET1,         \
> +                                  OFFSET2, OP)                           \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2, RTYPE dest)  \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        E1TYPE e1 = (E1TYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET1));        \
> +        E2TYPE e2 = (E2TYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET2));        \
> +        DTYPE d = (DTYPE)EXTRACTD(dest, i);                               \
> +        PTYPE mul = OP(e1, e2);                                           \
> +        rd = INSERT(rd, (OTYPE)(d + mul), i);                             \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_QMUL(NAME, RTYPE, ETYPE, PTYPE, OTYPE, EXTRACT, INSERT, \
> +                       ELEMS, SHIFT, ROUND, MINVAL, MAXVAL)              \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +    int sat = 0;                                                          \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        ETYPE e1 = (ETYPE)EXTRACT(rs1, i);                                \
> +        ETYPE e2 = (ETYPE)EXTRACT(rs2, i);                                \
> +        OTYPE result;                                                     \
> +                                                                          \
> +        if ((e1 == (ETYPE)(MINVAL)) && (e2 == (ETYPE)(MINVAL))) {         \
> +            sat = 1;                                                      \
> +            result = (OTYPE)(MAXVAL);                                     \
> +        } else {                                                          \
> +            PTYPE prod = (PTYPE)e1 * (PTYPE)e2 + (ROUND);                 \
> +            result = (OTYPE)(prod >> (SHIFT));                            \
> +        }                                                                 \
> +        rd = INSERT(rd, result, i);                                       \
> +    }                                                                     \
> +                                                                          \
> +    if (sat) {                                                            \
> +        env->vxsat = 1;                                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_QMUL_ACC_INDEXED(NAME, RTYPE, E1TYPE, E2TYPE, DTYPE,    \
> +                                   PTYPE, STYPE, OTYPE, EXTRACT,         \
> +                                   EXTRACTD, INSERT, ELEMS, SCALE,       \
> +                                   OFFSET1, OFFSET2, SHIFT, ROUND, OP)   \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2, RTYPE dest)  \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        E1TYPE e1 = (E1TYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET1));        \
> +        E2TYPE e2 = (E2TYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET2));        \
> +        DTYPE d = (DTYPE)EXTRACTD(dest, i);                               \
> +        PTYPE prod = OP(e1, e2) + (ROUND);                                \
> +        STYPE scaled = (STYPE)(((__int128_t)prod) >> (SHIFT));            \
> +        rd = INSERT(rd, (OTYPE)(d + scaled), i);                          \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_Q2ADD(NAME, RTYPE, ETYPE, PTYPE, STYPE, OTYPE, EXTRACT, \
> +                        INSERT, ELEMS, SCALE, SHIFT, ROUND, OP)          \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        ETYPE s1_0 = (ETYPE)EXTRACT(rs1, i * (SCALE));                   \
> +        ETYPE s1_1 = (ETYPE)EXTRACT(rs1, i * (SCALE) + 1);               \
> +        ETYPE s2_0 = (ETYPE)EXTRACT(rs2, i * (SCALE));                   \
> +        ETYPE s2_1 = (ETYPE)EXTRACT(rs2, i * (SCALE) + 1);               \
> +        PTYPE prod0 = OP(s1_0, s2_0) + (ROUND);                          \
> +        PTYPE prod1 = OP(s1_1, s2_1) + (ROUND);                          \
> +        STYPE scaled0 = (STYPE)(((__int128_t)prod0) >> (SHIFT));          \
> +        STYPE scaled1 = (STYPE)(((__int128_t)prod1) >> (SHIFT));          \
> +        rd = INSERT(rd, (OTYPE)(scaled0 + scaled1), i);                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_Q2ADDA(NAME, RTYPE, ETYPE, DTYPE, PTYPE, STYPE, OTYPE,  \
> +                         EXTRACT, EXTRACTD, INSERT, ELEMS, SCALE,        \
> +                         SHIFT, ROUND, OP)                               \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2, RTYPE dest)  \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        ETYPE s1_0 = (ETYPE)EXTRACT(rs1, i * (SCALE));                   \
> +        ETYPE s1_1 = (ETYPE)EXTRACT(rs1, i * (SCALE) + 1);               \
> +        ETYPE s2_0 = (ETYPE)EXTRACT(rs2, i * (SCALE));                   \
> +        ETYPE s2_1 = (ETYPE)EXTRACT(rs2, i * (SCALE) + 1);               \
> +        DTYPE d = (DTYPE)EXTRACTD(dest, i);                               \
> +        PTYPE prod0 = OP(s1_0, s2_0) + (ROUND);                          \
> +        PTYPE prod1 = OP(s1_1, s2_1) + (ROUND);                          \
> +        STYPE scaled0 = (STYPE)(((__int128_t)prod0) >> (SHIFT));          \
> +        STYPE scaled1 = (STYPE)(((__int128_t)prod1) >> (SHIFT));          \
> +        rd = INSERT(rd, (OTYPE)(d + scaled0 + scaled1), i);               \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define PSIMD_COMB_ADD(D, A, B) ((D) + (A) + (B))
> +#define PSIMD_COMB_SUB(D, A, B) ((D) + (A) - (B))
> +
> +#define GEN_PSIMD_2WAY_MUL(NAME, RTYPE, E1TYPE, E2TYPE, PTYPE, OTYPE,     \
> +                           EXTRACT, INSERT, ELEMS, SCALE, OFFSET10,      \
> +                           OFFSET11, OFFSET20, OFFSET21, OP, COMBINE)   \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        E1TYPE s1_0 = (E1TYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET10));     \
> +        E1TYPE s1_1 = (E1TYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET11));     \
> +        E2TYPE s2_0 = (E2TYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET20));     \
> +        E2TYPE s2_1 = (E2TYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET21));     \
> +        PTYPE prod0 = OP(s1_0, s2_0);                                     \
> +        PTYPE prod1 = OP(s1_1, s2_1);                                     \
> +        rd = INSERT(rd, (OTYPE)COMBINE(0, prod0, prod1), i);              \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_2WAY_SAT_MUL(NAME, OFFSET10, OFFSET11, OFFSET20,        \
> +                               OFFSET21)                                 \
> +target_ulong HELPER(NAME)(CPURISCVState *env, target_ulong rs1,           \
> +                           target_ulong rs2)                              \
> +{                                                                         \
> +    target_ulong rd = 0;                                                  \
> +    int sat = 0;                                                          \
> +                                                                          \
> +    for (int i = 0; i < ELEMS_W(rd); i++) {                               \
> +        int16_t s1_0 = (int16_t)EXTRACT16(rs1, i * 2 + (OFFSET10));       \
> +        int16_t s1_1 = (int16_t)EXTRACT16(rs1, i * 2 + (OFFSET11));       \
> +        int16_t s2_0 = (int16_t)EXTRACT16(rs2, i * 2 + (OFFSET20));       \
> +        int16_t s2_1 = (int16_t)EXTRACT16(rs2, i * 2 + (OFFSET21));       \
> +        uint32_t result;                                                  \
> +                                                                          \
> +        if (s1_0 == INT16_MIN && s1_1 == INT16_MIN &&                    \
> +            s2_0 == INT16_MIN && s2_1 == INT16_MIN) {                    \
> +            result = INT32_MAX;                                          \
> +            sat = 1;                                                      \
> +        } else {                                                          \
> +            int32_t prod0 = (int32_t)s1_0 * s2_0;                        \
> +            int32_t prod1 = (int32_t)s1_1 * s2_1;                        \
> +            result = (uint32_t)(prod0 + prod1);                           \
> +        }                                                                 \
> +        rd = INSERT32(rd, result, i);                                     \
> +    }                                                                     \
> +                                                                          \
> +    if (sat) {                                                            \
> +        env->vxsat = 1;                                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_2WAY_MUL_ACC(NAME, RTYPE, E1TYPE, E2TYPE, DTYPE, PTYPE, \
> +                               OTYPE, EXTRACT, EXTRACTD, INSERT, ELEMS,  \
> +                               SCALE, OFFSET10, OFFSET11, OFFSET20,      \
> +                               OFFSET21, OP, COMBINE)                   \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2, RTYPE dest)  \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        E1TYPE s1_0 = (E1TYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET10));     \
> +        E1TYPE s1_1 = (E1TYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET11));     \
> +        E2TYPE s2_0 = (E2TYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET20));     \
> +        E2TYPE s2_1 = (E2TYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET21));     \
> +        DTYPE d = (DTYPE)EXTRACTD(dest, i);                               \
> +        PTYPE prod0 = OP(s1_0, s2_0);                                     \
> +        PTYPE prod1 = OP(s1_1, s2_1);                                     \
> +        rd = INSERT(rd, (OTYPE)COMBINE(d, prod0, prod1), i);              \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_4WAY_MUL(NAME, RTYPE, E1TYPE, E2TYPE, PTYPE, OTYPE,     \
> +                           EXTRACT, INSERT, ELEMS, SCALE, OP)            \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2)              \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        PTYPE prod0 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE)),              \
> +                         (E2TYPE)EXTRACT(rs2, i * (SCALE)));             \
> +        PTYPE prod1 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE) + 1),          \
> +                         (E2TYPE)EXTRACT(rs2, i * (SCALE) + 1));         \
> +        PTYPE prod2 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE) + 2),          \
> +                         (E2TYPE)EXTRACT(rs2, i * (SCALE) + 2));         \
> +        PTYPE prod3 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE) + 3),          \
> +                         (E2TYPE)EXTRACT(rs2, i * (SCALE) + 3));         \
> +        rd = INSERT(rd, (OTYPE)(prod0 + prod1 + prod2 + prod3), i);       \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_4WAY_MUL_ACC(NAME, RTYPE, E1TYPE, E2TYPE, DTYPE, PTYPE, \
> +                               OTYPE, EXTRACT, EXTRACTD, INSERT, ELEMS,  \
> +                               SCALE, OP)                                \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2, RTYPE dest)  \
> +{                                                                         \
> +    RTYPE rd = 0;                                                         \
> +    int elems = ELEMS(rd);                                                \
> +                                                                          \
> +    for (int i = 0; i < elems; i++) {                                     \
> +        DTYPE d = (DTYPE)EXTRACTD(dest, i);                               \
> +        PTYPE prod0 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE)),              \
> +                         (E2TYPE)EXTRACT(rs2, i * (SCALE)));             \
> +        PTYPE prod1 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE) + 1),          \
> +                         (E2TYPE)EXTRACT(rs2, i * (SCALE) + 1));         \
> +        PTYPE prod2 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE) + 2),          \
> +                         (E2TYPE)EXTRACT(rs2, i * (SCALE) + 2));         \
> +        PTYPE prod3 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE) + 3),          \
> +                         (E2TYPE)EXTRACT(rs2, i * (SCALE) + 3));         \
> +        rd = INSERT(rd, (OTYPE)(d + prod0 + prod1 + prod2 + prod3), i);   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_WIDEN_BINOP(NAME, ETYPE, WTYPE, OTYPE, ELEMS, IBITS,    \
> +                              OBITS, IMASK, OP)                          \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2)     \
> +{                                                                         \
> +    uint64_t rd = 0;                                                      \
> +                                                                          \
> +    for (int i = 0; i < (ELEMS); i++) {                                   \
> +        ETYPE e1 = (ETYPE)((rs1 >> (i * (IBITS))) & (IMASK));             \
> +        ETYPE e2 = (ETYPE)((rs2 >> (i * (IBITS))) & (IMASK));             \
> +        WTYPE res = OP((WTYPE)0, (WTYPE)e1, (WTYPE)e2);                   \
> +        rd |= ((uint64_t)(OTYPE)res) << (i * (OBITS));                    \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_WIDEN_BINOP_ACC(NAME, ETYPE, WTYPE, OTYPE, ELEMS,       \
> +                                  IBITS, OBITS, IMASK, OMASK, OP)        \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2,     \
> +                      uint64_t dest)                                      \
> +{                                                                         \
> +    uint64_t rd = 0;                                                      \
> +                                                                          \
> +    for (int i = 0; i < (ELEMS); i++) {                                   \
> +        ETYPE e1 = (ETYPE)((rs1 >> (i * (IBITS))) & (IMASK));             \
> +        ETYPE e2 = (ETYPE)((rs2 >> (i * (IBITS))) & (IMASK));             \
> +        WTYPE acc = (WTYPE)((dest >> (i * (OBITS))) & (OMASK));           \
> +        WTYPE res = OP(acc, (WTYPE)e1, (WTYPE)e2);                        \
> +        rd |= ((uint64_t)(OTYPE)res) << (i * (OBITS));                    \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_WIDEN_MUL(NAME, E1TYPE, E2TYPE, PTYPE, OTYPE, ELEMS,    \
> +                            EXTRACT, OBITS, OP)                          \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2)     \
> +{                                                                         \
> +    uint64_t rd = 0;                                                      \
> +                                                                          \
> +    for (int i = 0; i < (ELEMS); i++) {                                   \
> +        E1TYPE e1 = (E1TYPE)EXTRACT(rs1, i);                              \
> +        E2TYPE e2 = (E2TYPE)EXTRACT(rs2, i);                              \
> +        PTYPE prod = OP(e1, e2);                                          \
> +        rd |= ((uint64_t)(OTYPE)prod) << (i * (OBITS));                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_WIDEN_MUL_ACC(NAME, E1TYPE, E2TYPE, DTYPE, PTYPE,       \
> +                                OTYPE, ELEMS, EXTRACT, EXTRACTD, OBITS,  \
> +                                OP)                                      \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2,     \
> +                      uint64_t dest)                                      \
> +{                                                                         \
> +    uint64_t rd = 0;                                                      \
> +                                                                          \
> +    for (int i = 0; i < (ELEMS); i++) {                                   \
> +        E1TYPE e1 = (E1TYPE)EXTRACT(rs1, i);                              \
> +        E2TYPE e2 = (E2TYPE)EXTRACT(rs2, i);                              \
> +        DTYPE d = (DTYPE)EXTRACTD(dest, i);                               \
> +        PTYPE prod = OP(e1, e2);                                          \
> +        rd |= ((uint64_t)(OTYPE)(d + prod)) << (i * (OBITS));             \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_WIDEN_QMUL_ACC(NAME, ETYPE, DTYPE, PTYPE, STYPE,        \
> +                                 OTYPE, ELEMS, EXTRACT, EXTRACTD, SCALE, \
> +                                 OFFSET, SHIFT, ROUND, OBITS, OP)        \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2,     \
> +                      uint64_t dest)                                      \
> +{                                                                         \
> +    uint64_t rd = 0;                                                      \
> +                                                                          \
> +    for (int i = 0; i < (ELEMS); i++) {                                   \
> +        ETYPE e1 = (ETYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET));           \
> +        ETYPE e2 = (ETYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET));           \
> +        DTYPE d = (DTYPE)EXTRACTD(dest, i);                               \
> +        PTYPE prod = OP(e1, e2) + (ROUND);                                \
> +        STYPE scaled = (STYPE)(((__int128_t)prod) >> (SHIFT));            \
> +        rd |= ((uint64_t)(OTYPE)(d + scaled)) << (i * (OBITS));           \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_DW_2WAY_MUL(NAME, E1TYPE, E2TYPE, PTYPE, EXTRACT,       \
> +                              OFFSET10, OFFSET11, OFFSET20, OFFSET21,    \
> +                              OP, COMBINE)                               \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2)     \
> +{                                                                         \
> +    E1TYPE s1_0 = (E1TYPE)EXTRACT(rs1, OFFSET10);                         \
> +    E1TYPE s1_1 = (E1TYPE)EXTRACT(rs1, OFFSET11);                         \
> +    E2TYPE s2_0 = (E2TYPE)EXTRACT(rs2, OFFSET20);                         \
> +    E2TYPE s2_1 = (E2TYPE)EXTRACT(rs2, OFFSET21);                         \
> +    PTYPE prod0 = OP(s1_0, s2_0);                                        \
> +    PTYPE prod1 = OP(s1_1, s2_1);                                        \
> +                                                                          \
> +    return (uint64_t)COMBINE(0, prod0, prod1);                            \
> +}
> +
> +#define GEN_PSIMD_DW_2WAY_MUL_ACC(NAME, E1TYPE, E2TYPE, DTYPE, PTYPE,     \
> +                                  EXTRACT, OFFSET10, OFFSET11, OFFSET20, \
> +                                  OFFSET21, OP, COMBINE)                \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2,     \
> +                      uint64_t dest)                                      \
> +{                                                                         \
> +    E1TYPE s1_0 = (E1TYPE)EXTRACT(rs1, OFFSET10);                         \
> +    E1TYPE s1_1 = (E1TYPE)EXTRACT(rs1, OFFSET11);                         \
> +    E2TYPE s2_0 = (E2TYPE)EXTRACT(rs2, OFFSET20);                         \
> +    E2TYPE s2_1 = (E2TYPE)EXTRACT(rs2, OFFSET21);                         \
> +    DTYPE d = (DTYPE)dest;                                                \
> +    PTYPE prod0 = OP(s1_0, s2_0);                                        \
> +    PTYPE prod1 = OP(s1_1, s2_1);                                        \
> +                                                                          \
> +    return (uint64_t)COMBINE(d, prod0, prod1);                            \
> +}
> +
> +#define GEN_PSIMD_WIDEN_SHIFT(NAME, ETYPE, WTYPE, OTYPE, ELEMS, IBITS,    \
> +                              OBITS, IMASK, SHMASK)                      \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2)     \
> +{                                                                         \
> +    uint64_t rd = 0;                                                      \
> +    uint8_t shamt = rs2 & (SHMASK);                                       \
> +                                                                          \
> +    for (int i = 0; i < (ELEMS); i++) {                                   \
> +        ETYPE e1 = (ETYPE)((rs1 >> (i * (IBITS))) & (IMASK));             \
> +        WTYPE res = (WTYPE)e1 << shamt;                                   \
> +        rd |= ((uint64_t)(OTYPE)res) << (i * (OBITS));                    \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_DW_ZIP(NAME, EXTRACT, ELEMS, STRIDE, BITS)              \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2)     \
> +{                                                                         \
> +    uint64_t rd = 0;                                                      \
> +                                                                          \
> +    for (int i = 0; i < (ELEMS); i++) {                                   \
> +        uint64_t e1 = (uint64_t)EXTRACT(rs1, i) << ((STRIDE) * i);        \
> +        uint64_t e2 = (uint64_t)EXTRACT(rs2, i)                           \
> +                      << ((STRIDE) * i + (BITS));                         \
> +        rd |= e2 | e1;                                                    \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_DW_REDSUM(NAME, SUMTYPE, INITTYPE, ETYPE, EXTRACT,      \
> +                            ELEMS)                                        \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1_lo,                \
> +                      uint32_t rs1_hi, uint32_t rs2)                      \
> +{                                                                         \
> +    SUMTYPE sum = (INITTYPE)rs2;                                          \
> +    uint64_t s1 = ((uint64_t)rs1_hi << 32) | rs1_lo;                      \
> +                                                                          \
> +    for (int i = 0; i < (ELEMS); i++) {                                   \
> +        sum += (ETYPE)EXTRACT(s1, i);                                     \
> +    }                                                                     \
> +    return (uint32_t)sum;                                                 \
> +}
> +
> +#define GEN_PSIMD_NARROW_SRL(NAME, ETYPE, OTYPE, ELEMS, IBITS, OBITS,     \
> +                             IMASK, SHMASK)                               \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
> +{                                                                         \
> +    uint32_t rd = 0;                                                      \
> +    uint8_t shift = shamt & (SHMASK);                                     \
> +                                                                          \
> +    for (int i = 0; i < (ELEMS); i++) {                                   \
> +        ETYPE e1 = (ETYPE)((s1 >> (i * (IBITS))) & (IMASK));              \
> +        OTYPE result = (OTYPE)(e1 >> shift);                              \
> +        rd |= ((uint32_t)result) << (i * (OBITS));                        \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_NARROW_SRA_PACK(NAME, ETYPE, STYPE, OTYPE, ELEMS,       \
> +                                  IBITS, OBITS, IMASK, SHMASK)            \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
> +{                                                                         \
> +    uint32_t rd = 0;                                                      \
> +    uint8_t shift = shamt & (SHMASK);                                     \
> +                                                                          \
> +    for (int i = 0; i < (ELEMS); i++) {                                   \
> +        ETYPE e1 = (ETYPE)((s1 >> (i * (IBITS))) & (IMASK));              \
> +        STYPE shx = (STYPE)e1 >> shift;                                   \
> +        OTYPE result = (OTYPE)shx;                                        \
> +        rd |= ((uint32_t)result) << (i * (OBITS));                        \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_NARROW_RNDSRA_PACK(NAME, ETYPE, STYPE, OTYPE, ELEMS,    \
> +                                     IBITS, OBITS, IMASK, SHMASK, RMASK)  \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
> +{                                                                         \
> +    uint32_t rd = 0;                                                      \
> +    uint8_t shift = shamt & (SHMASK);                                     \
> +                                                                          \
> +    for (int i = 0; i < (ELEMS); i++) {                                   \
> +        ETYPE e1 = (ETYPE)((s1 >> (i * (IBITS))) & (IMASK));              \
> +        STYPE e1_s = (STYPE)e1;                                           \
> +        uint64_t shx = (((uint64_t)e1_s << 1) >> shift) & (RMASK);        \
> +        OTYPE result = (OTYPE)((shx + 1) >> 1);                           \
> +        rd |= ((uint32_t)result) << (i * (OBITS));                        \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_NCLIP_SIGNED_PACK(NAME, ETYPE, STYPE, CTYPE, OTYPE,     \
> +                                    ELEMS, IBITS, OBITS, IMASK, SHMASK,   \
> +                                    MIN, MAX, MIN_RES, MAX_RES)           \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
> +{                                                                         \
> +    uint32_t rd = 0;                                                      \
> +    uint8_t shift = shamt & (SHMASK);                                     \
> +    int sat = 0;                                                          \
> +                                                                          \
> +    for (int i = 0; i < (ELEMS); i++) {                                   \
> +        ETYPE e1 = (ETYPE)((s1 >> (i * (IBITS))) & (IMASK));              \
> +        CTYPE shx = (CTYPE)((STYPE)e1 >> shift);                          \
> +        OTYPE result;                                                     \
> +                                                                          \
> +        if (shx < (MIN)) {                                                \
> +            sat = 1;                                                      \
> +            result = (MIN_RES);                                           \
> +        } else if (shx > (MAX)) {                                         \
> +            sat = 1;                                                      \
> +            result = (MAX_RES);                                           \
> +        } else {                                                          \
> +            result = (OTYPE)shx;                                          \
> +        }                                                                 \
> +        rd |= ((uint32_t)result) << (i * (OBITS));                        \
> +    }                                                                     \
> +                                                                          \
> +    if (sat) {                                                            \
> +        env->vxsat = 1;                                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_NCLIPR_SIGNED_PACK(NAME, ETYPE, STYPE, CTYPE, OTYPE,    \
> +                                     ELEMS, IBITS, OBITS, IMASK, SHMASK,  \
> +                                     RMASK, MIN, MAX, MIN_RES, MAX_RES)   \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
> +{                                                                         \
> +    uint32_t rd = 0;                                                      \
> +    uint8_t shift = shamt & (SHMASK);                                     \
> +    int sat = 0;                                                          \
> +                                                                          \
> +    for (int i = 0; i < (ELEMS); i++) {                                   \
> +        ETYPE e1 = (ETYPE)((s1 >> (i * (IBITS))) & (IMASK));              \
> +        STYPE e1_s = (STYPE)e1;                                           \
> +        uint64_t shx = (((uint64_t)e1_s << 1) >> shift) & (RMASK);        \
> +        CTYPE round_shx = (CTYPE)((shx + 1) >> 1);                        \
> +        OTYPE result;                                                     \
> +                                                                          \
> +        if (round_shx < (MIN)) {                                          \
> +            sat = 1;                                                      \
> +            result = (MIN_RES);                                           \
> +        } else if (round_shx > (MAX)) {                                   \
> +            sat = 1;                                                      \
> +            result = (MAX_RES);                                           \
> +        } else {                                                          \
> +            result = (OTYPE)round_shx;                                    \
> +        }                                                                 \
> +        rd |= ((uint32_t)result) << (i * (OBITS));                        \
> +    }                                                                     \
> +                                                                          \
> +    if (sat) {                                                            \
> +        env->vxsat = 1;                                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_NCLIP_UNSIGNED_PACK(NAME, ETYPE, WTYPE, OTYPE, ELEMS,   \
> +                                      IBITS, OBITS, IMASK, SHMASK, MAX)   \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
> +{                                                                         \
> +    uint32_t rd = 0;                                                      \
> +    uint8_t shift = shamt & (SHMASK);                                     \
> +    int sat = 0;                                                          \
> +                                                                          \
> +    for (int i = 0; i < (ELEMS); i++) {                                   \
> +        ETYPE e1 = (ETYPE)((s1 >> (i * (IBITS))) & (IMASK));              \
> +        WTYPE shx = (WTYPE)e1 >> shift;                                   \
> +        OTYPE result;                                                     \
> +                                                                          \
> +        if (shx > (MAX)) {                                                \
> +            sat = 1;                                                      \
> +            result = (OTYPE)(MAX);                                        \
> +        } else {                                                          \
> +            result = (OTYPE)shx;                                          \
> +        }                                                                 \
> +        rd |= ((uint32_t)result) << (i * (OBITS));                        \
> +    }                                                                     \
> +                                                                          \
> +    if (sat) {                                                            \
> +        env->vxsat = 1;                                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_NCLIPR_UNSIGNED_PACK(NAME, ETYPE, WTYPE, OTYPE, ELEMS,  \
> +                                       IBITS, OBITS, IMASK, SHMASK, MAX)  \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
> +{                                                                         \
> +    uint32_t rd = 0;                                                      \
> +    uint8_t shift = shamt & (SHMASK);                                     \
> +    int sat = 0;                                                          \
> +                                                                          \
> +    for (int i = 0; i < (ELEMS); i++) {                                   \
> +        ETYPE e1 = (ETYPE)((s1 >> (i * (IBITS))) & (IMASK));              \
> +        WTYPE shx = ((WTYPE)e1 << 1) >> shift;                            \
> +        WTYPE round_shx = (shx + 1) >> 1;                                 \
> +        OTYPE result;                                                     \
> +                                                                          \
> +        if (round_shx > (MAX)) {                                          \
> +            sat = 1;                                                      \
> +            result = (OTYPE)(MAX);                                        \
> +        } else {                                                          \
> +            result = (OTYPE)round_shx;                                    \
> +        }                                                                 \
> +        rd |= ((uint32_t)result) << (i * (OBITS));                        \
> +    }                                                                     \
> +                                                                          \
> +    if (sat) {                                                            \
> +        env->vxsat = 1;                                                   \
> +    }                                                                     \
> +    return rd;                                                            \
> +}
> +
> +#define GEN_PSIMD_NARROW_SRA(NAME)                                        \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
> +{                                                                         \
> +    __int128_t s1_s128 = (__int128_t)((int64_t)s1);                       \
> +    __int128_t s1_s96 = (s1_s128 << 32) >> 32;                            \
> +                                                                          \
> +    return (uint32_t)(s1_s96 >> (shamt & 0x3F)) & 0xFFFFFFFF;             \
> +}
> +
> +#define GEN_PSIMD_NARROW_RNDSRA(NAME)                                     \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
> +{                                                                         \
> +    __int128_t s1_s128 = (__int128_t)((int64_t)s1);                       \
> +    __int128_t s1_s96 = (s1_s128 << 32) >> 32;                            \
> +    __uint128_t shx_97bit = ((__uint128_t)s1_s96 << 1);                   \
> +    uint64_t shx = (uint64_t)(shx_97bit >> (shamt & 0x3F)) & 0x1FFFFFFFF; \
> +                                                                          \
> +    return (uint32_t)((shx + 1) >> 1);                                    \
> +}
> +
> +#define GEN_PSIMD_NARROW_ALIAS(NAME, TARGET)                              \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
> +{                                                                         \
> +    return HELPER(TARGET)(env, s1, shamt);                                \
> +}
> +
> +typedef struct {
> +    __uint128_t low;
> +    uint8_t high;
> +} PsImdUint129;
> +
> +static inline PsImdUint129 psimd_uint129_lshift1(__int128_t val)
> +{
> +    PsImdUint129 result;
> +    __uint128_t uval = (__uint128_t)val;
> +
> +    result.low = uval << 1;
> +    result.high = (uval >> 127) & 0x1;
> +    return result;
> +}
> +
> +static inline PsImdUint129 psimd_uint129_rshift(PsImdUint129 val,
> +                                                uint32_t shamt)
> +{
> +    PsImdUint129 result;
> +
> +    if (shamt == 0) {
> +        return val;
> +    } else if (shamt >= 129) {
> +        result.low = 0;
> +        result.high = 0;
> +    } else if (shamt == 128) {
> +        result.low = val.high;
> +        result.high = 0;
> +    } else {
> +        result.low = (val.low >> shamt) |
> +                     ((__uint128_t)val.high << (128 - shamt));
> +        result.high = val.high >> shamt;
> +    }
> +    return result;
> +}
> +
> +#define GEN_PSIMD_NCLIP(NAME)                                             \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
> +{                                                                         \
> +    __int128_t s1_s128 = (__int128_t)((int64_t)s1);                       \
> +    int64_t shx = (int64_t)(s1_s128 >> (shamt & 0x3F));                  \
> +                                                                          \
> +    if (shx < -2147483648LL) {                                            \
> +        env->vxsat = 1;                                                   \
> +        return 0x80000000U;                                               \
> +    } else if (shx > 2147483647LL) {                                      \
> +        env->vxsat = 1;                                                   \
> +        return 0x7FFFFFFFU;                                               \
> +    } else {                                                              \
> +        return (uint32_t)(shx & 0xFFFFFFFF);                              \
> +    }                                                                     \
> +}
> +
> +#define GEN_PSIMD_NCLIPR(NAME)                                            \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
> +{                                                                         \
> +    __int128_t s1_s128 = (__int128_t)((int64_t)s1);                       \
> +    PsImdUint129 shx_129bit = psimd_uint129_lshift1(s1_s128);             \
> +    PsImdUint129 shx = psimd_uint129_rshift(shx_129bit, shamt & 0x3F);    \
> +    int64_t round_shx = (int64_t)((shx.low + 1) >> 1);                    \
> +                                                                          \
> +    if (round_shx < -2147483648LL) {                                      \
> +        env->vxsat = 1;                                                   \
> +        return 0x80000000U;                                               \
> +    } else if (round_shx > 2147483647LL) {                                \
> +        env->vxsat = 1;                                                   \
> +        return 0x7FFFFFFFU;                                               \
> +    } else {                                                              \
> +        return (uint32_t)round_shx;                                       \
> +    }                                                                     \
> +}
> +
> +#define GEN_PSIMD_NCLIPU(NAME)                                            \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
> +{                                                                         \
> +    uint64_t shx = s1 >> (shamt & 0x3F);                                  \
> +                                                                          \
> +    if (shx > 4294967295ULL) {                                            \
> +        env->vxsat = 1;                                                   \
> +        return 0xFFFFFFFFU;                                               \
> +    } else {                                                              \
> +        return (uint32_t)(shx & 0xFFFFFFFF);                              \
> +    }                                                                     \
> +}
> +
> +#define GEN_PSIMD_NCLIPRU(NAME)                                           \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
> +{                                                                         \
> +    __uint128_t shx_65bit = (__uint128_t)s1 << 1;                         \
> +    __uint128_t shx = shx_65bit >> (shamt & 0x3F);                        \
> +    uint64_t round_shx = (shx + 1) >> 1;                                  \
> +                                                                          \
> +    if (round_shx > 4294967295ULL) {                                      \
> +        env->vxsat = 1;                                                   \
> +        return 0xFFFFFFFFU;                                               \
> +    } else {                                                              \
> +        return (uint32_t)(round_shx & 0xFFFFFFFF);                        \
> +    }                                                                     \
> +}
> +
> +/* Basic addition operations (non-saturating) */
> +


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH v2 04/18] target/riscv: Add packed SIMD averaging and rounding instructions
  2026-07-17 10:06 ` [PATCH v2 04/18] target/riscv: Add packed SIMD averaging and rounding instructions Molly Chen
@ 2026-07-27 18:58   ` Daniel Henrique Barboza
  0 siblings, 0 replies; 34+ messages in thread
From: Daniel Henrique Barboza @ 2026-07-27 18:58 UTC (permalink / raw)
  To: Molly Chen, palmer, alistair.francis, liwei1518, zhiwei_liu,
	chao.liu.zevorn, Chao Liu
  Cc: qemu-riscv, qemu-devel



On 7/17/2026 7:06 AM, Molly Chen wrote:
> Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
> ---

Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>

>   target/riscv/helper.h                       | 18 ++++++++++
>   target/riscv/insn32.decode                  | 26 ++++++++++++++
>   target/riscv/tcg/insn_trans/trans_rvp.c.inc | 18 ++++++++++
>   target/riscv/tcg/psimd_helper.c             | 40 +++++++++++++++++++++
>   4 files changed, 102 insertions(+)
> 
> diff --git a/target/riscv/helper.h b/target/riscv/helper.h
> index eebb2febd95..7256f776ae6 100644
> --- a/target/riscv/helper.h
> +++ b/target/riscv/helper.h
> @@ -1399,3 +1399,21 @@ DEF_HELPER_3(sati_32, i32, env, i32, i32)
>   DEF_HELPER_3(usati_32, i32, env, i32, i32)
>   DEF_HELPER_3(sati_64, i64, env, i64, i64)
>   DEF_HELPER_3(usati_64, i64, env, i64, i64)
> +
> +/* Packed SIMD - Averaging and Rounding Operations */
> +DEF_HELPER_3(paadd_b, tl, env, tl, tl)
> +DEF_HELPER_3(paadd_h, tl, env, tl, tl)
> +DEF_HELPER_3(paadd_w, i64, env, i64, i64)
> +DEF_HELPER_3(paaddu_b, tl, env, tl, tl)
> +DEF_HELPER_3(paaddu_h, tl, env, tl, tl)
> +DEF_HELPER_3(paaddu_w, i64, env, i64, i64)
> +DEF_HELPER_3(aadd, i32, env, i32, i32)
> +DEF_HELPER_3(aaddu, i32, env, i32, i32)
> +DEF_HELPER_3(pasub_b, tl, env, tl, tl)
> +DEF_HELPER_3(pasub_h, tl, env, tl, tl)
> +DEF_HELPER_3(pasub_w, i64, env, i64, i64)
> +DEF_HELPER_3(pasubu_b, tl, env, tl, tl)
> +DEF_HELPER_3(pasubu_h, tl, env, tl, tl)
> +DEF_HELPER_3(pasubu_w, i64, env, i64, i64)
> +DEF_HELPER_3(asub, i32, env, i32, i32)
> +DEF_HELPER_3(asubu, i32, env, i32, i32)
> diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
> index 8da13669d73..005cc055b8a 100644
> --- a/target/riscv/insn32.decode
> +++ b/target/riscv/insn32.decode
> @@ -1147,3 +1147,29 @@ pusati_h   10100 001.... ..... 100 ..... 0011011 @p_ui16
>   }
>   sati_64    111001 ...... ..... 100 ..... 0011011 @p_ui64
>   usati_64   101001 ...... ..... 100 ..... 0011011 @p_ui64
> +
> +# Packed SIMD - Averaging and Rounding Operations
> +paadd_b    1001110 ..... ..... 000 ..... 0111011 @r
> +paadd_h    1001100 ..... ..... 000 ..... 0111011 @r
> +{
> +  aadd     1001101 ..... ..... 000 ..... 0111011 @r
> +  paadd_w  1001101 ..... ..... 000 ..... 0111011 @r
> +}
> +paaddu_b   1011110 ..... ..... 000 ..... 0111011 @r
> +paaddu_h   1011100 ..... ..... 000 ..... 0111011 @r
> +{
> +  aaddu    1011101 ..... ..... 000 ..... 0111011 @r
> +  paaddu_w 1011101 ..... ..... 000 ..... 0111011 @r
> +}
> +pasub_b    1101110 ..... ..... 000 ..... 0111011 @r
> +pasub_h    1101100 ..... ..... 000 ..... 0111011 @r
> +{
> +  asub     1101101 ..... ..... 000 ..... 0111011 @r
> +  pasub_w  1101101 ..... ..... 000 ..... 0111011 @r
> +}
> +pasubu_b   1111110 ..... ..... 000 ..... 0111011 @r
> +pasubu_h   1111100 ..... ..... 000 ..... 0111011 @r
> +{
> +  asubu    1111101 ..... ..... 000 ..... 0111011 @r
> +  pasubu_w 1111101 ..... ..... 000 ..... 0111011 @r
> +}
> diff --git a/target/riscv/tcg/insn_trans/trans_rvp.c.inc b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
> index 056ccfb486e..43c59aef182 100644
> --- a/target/riscv/tcg/insn_trans/trans_rvp.c.inc
> +++ b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
> @@ -545,3 +545,21 @@ GEN_SIMD_TRANS_IMM_32_VXSAT(usati_32)
>   GEN_SIMD_TRANS_IMM_64_VXSAT(sati_64)
>   GEN_SIMD_TRANS_IMM_64_VXSAT(usati_64)
>   
> +/* Packed SIMD - Averaging and Rounding Operations */
> +GEN_SIMD_TRANS(paadd_b)
> +GEN_SIMD_TRANS(paadd_h)
> +GEN_SIMD_TRANS_64(paadd_w)
> +GEN_SIMD_TRANS(paaddu_b)
> +GEN_SIMD_TRANS(paaddu_h)
> +GEN_SIMD_TRANS_64(paaddu_w)
> +GEN_SIMD_TRANS_32(aadd)
> +GEN_SIMD_TRANS_32(aaddu)
> +GEN_SIMD_TRANS(pasub_b)
> +GEN_SIMD_TRANS(pasub_h)
> +GEN_SIMD_TRANS_64(pasub_w)
> +GEN_SIMD_TRANS(pasubu_b)
> +GEN_SIMD_TRANS(pasubu_h)
> +GEN_SIMD_TRANS_64(pasubu_w)
> +GEN_SIMD_TRANS_32(asub)
> +GEN_SIMD_TRANS_32(asubu)
> +
> diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
> index 52c58e0287e..162041a8f18 100644
> --- a/target/riscv/tcg/psimd_helper.c
> +++ b/target/riscv/tcg/psimd_helper.c
> @@ -1768,3 +1768,43 @@ GEN_PSIMD_SATI(sati_64, uint64_t, int64_t, int64_t,
>   GEN_PSIMD_USATI(usati_64, uint64_t, int64_t, uint64_t, uint64_t,
>                   EXTRACT64, INSERT64, ELEMS_D, 1ULL)
>   
> +/* Averaging Operations (non-saturating) */
> +
> +GEN_PSIMD_AVG_BINOP(paadd_b, target_ulong, int8_t, int16_t,
> +                    EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ADD)
> +GEN_PSIMD_AVG_BINOP(paadd_h, target_ulong, int16_t, int32_t,
> +                    EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ADD)
> +GEN_PSIMD_AVG_BINOP(paadd_w, uint64_t, int32_t, int64_t,
> +                    EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD)
> +
> +GEN_PSIMD_AVG_BINOP(paaddu_b, target_ulong, uint8_t, uint16_t,
> +                    EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ADD)
> +GEN_PSIMD_AVG_BINOP(paaddu_h, target_ulong, uint16_t, uint32_t,
> +                    EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ADD)
> +GEN_PSIMD_AVG_BINOP(paaddu_w, uint64_t, uint32_t, uint64_t,
> +                    EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD)
> +
> +GEN_PSIMD_AVG_BINOP(aadd, uint32_t, int32_t, int64_t,
> +                    EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD)
> +GEN_PSIMD_AVG_BINOP(aaddu, uint32_t, uint32_t, uint64_t,
> +                    EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD)
> +
> +GEN_PSIMD_AVG_BINOP(pasub_b, target_ulong, int8_t, int16_t,
> +                    EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_SUB)
> +GEN_PSIMD_AVG_BINOP(pasub_h, target_ulong, int16_t, int32_t,
> +                    EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_SUB)
> +GEN_PSIMD_AVG_BINOP(pasub_w, uint64_t, int32_t, int64_t,
> +                    EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_SUB)
> +
> +GEN_PSIMD_AVG_BINOP(pasubu_b, target_ulong, uint8_t, uint16_t,
> +                    EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_SUB)
> +GEN_PSIMD_AVG_BINOP(pasubu_h, target_ulong, uint16_t, uint32_t,
> +                    EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_SUB)
> +GEN_PSIMD_AVG_BINOP(pasubu_w, uint64_t, uint32_t, uint64_t,
> +                    EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_SUB)
> +
> +GEN_PSIMD_AVG_BINOP(asub, uint32_t, int32_t, int64_t,
> +                    EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_SUB)
> +GEN_PSIMD_AVG_BINOP(asubu, uint32_t, uint32_t, uint64_t,
> +                    EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_SUB)
> +



^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH v2 03/18] target/riscv: Add packed SIMD arithmetic instructions
  2026-07-17 10:06 ` [PATCH v2 03/18] target/riscv: Add packed SIMD arithmetic instructions Molly Chen
  2026-07-26 22:05   ` Daniel Henrique Barboza
@ 2026-07-29  6:17   ` Nutty.Liu
  2026-07-29  9:27   ` Chao Liu
  2 siblings, 0 replies; 34+ messages in thread
From: Nutty.Liu @ 2026-07-29  6:17 UTC (permalink / raw)
  To: Molly Chen, palmer, alistair.francis, liwei1518, daniel.barboza,
	zhiwei_liu, chao.liu.zevorn, Chao Liu
  Cc: qemu-riscv, qemu-devel


On 7/17/2026 6:06 PM, Molly Chen wrote:
> Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
Reviewed-by: Nutty Liu <nutty.liu@hotmail.com>

Thanks,
Nutty
> ---
>   target/riscv/helper.h                       |  41 ++
>   target/riscv/insn32.decode                  |  63 +++
>   target/riscv/tcg/insn_trans/trans_rvp.c.inc | 547 ++++++++++++++++++++
>   target/riscv/tcg/psimd_helper.c             | 114 ++++
>   target/riscv/tcg/translate.c                |   4 +
>   5 files changed, 769 insertions(+)
>   create mode 100644 target/riscv/tcg/insn_trans/trans_rvp.c.inc
>
> diff --git a/target/riscv/helper.h b/target/riscv/helper.h
> index 542b7c264fc..eebb2febd95 100644
> --- a/target/riscv/helper.h
> +++ b/target/riscv/helper.h
> @@ -1358,3 +1358,44 @@ DEF_HELPER_1(ssamoswap_disabled, void, env)
>   
>   /* Zalrsc SC write probe */
>   DEF_HELPER_FLAGS_3(sc_probe_write, TCG_CALL_NO_WG, void, env, tl, tl)
> +
> +/* Packed SIMD */
> +/* Packed SIMD - Arithmetic Operations(Non-Saturating and Saturating) */
> +DEF_HELPER_3(padd_b, tl, env, tl, tl)
> +DEF_HELPER_3(padd_h, tl, env, tl, tl)
> +DEF_HELPER_3(padd_w, i64, env, i64, i64)
> +DEF_HELPER_3(padd_bs, tl, env, tl, tl)
> +DEF_HELPER_3(padd_hs, tl, env, tl, tl)
> +DEF_HELPER_3(padd_ws, i64, env, i64, i64)
> +DEF_HELPER_3(psub_b, tl, env, tl, tl)
> +DEF_HELPER_3(psub_h, tl, env, tl, tl)
> +DEF_HELPER_3(psub_w, i64, env, i64, i64)
> +DEF_HELPER_3(psh1add_h, tl, env, tl, tl)
> +DEF_HELPER_3(psh1add_w, i64, env, i64, i64)
> +DEF_HELPER_3(pssh1sadd_h, tl, env, tl, tl)
> +DEF_HELPER_3(pssh1sadd_w, i64, env, i64, i64)
> +DEF_HELPER_3(ssh1sadd, i32, env, i32, i32)
> +DEF_HELPER_3(psadd_b, tl, env, tl, tl)
> +DEF_HELPER_3(psadd_h, tl, env, tl, tl)
> +DEF_HELPER_3(psadd_w, i64, env, i64, i64)
> +DEF_HELPER_3(psaddu_b, tl, env, tl, tl)
> +DEF_HELPER_3(psaddu_h, tl, env, tl, tl)
> +DEF_HELPER_3(psaddu_w, i64, env, i64, i64)
> +DEF_HELPER_3(sadd, i32, env, i32, i32)
> +DEF_HELPER_3(saddu, i32, env, i32, i32)
> +DEF_HELPER_3(pssub_b, tl, env, tl, tl)
> +DEF_HELPER_3(pssub_h, tl, env, tl, tl)
> +DEF_HELPER_3(pssub_w, i64, env, i64, i64)
> +DEF_HELPER_3(pssubu_b, tl, env, tl, tl)
> +DEF_HELPER_3(pssubu_h, tl, env, tl, tl)
> +DEF_HELPER_3(pssubu_w, i64, env, i64, i64)
> +DEF_HELPER_3(ssub, i32, env, i32, i32)
> +DEF_HELPER_3(ssubu, i32, env, i32, i32)
> +DEF_HELPER_3(psati_h, tl, env, tl, tl)
> +DEF_HELPER_3(pusati_h, tl, env, tl, tl)
> +DEF_HELPER_3(psati_w, i64, env, i64, i64)
> +DEF_HELPER_3(pusati_w, i64, env, i64, i64)
> +DEF_HELPER_3(sati_32, i32, env, i32, i32)
> +DEF_HELPER_3(usati_32, i32, env, i32, i32)
> +DEF_HELPER_3(sati_64, i64, env, i64, i64)
> +DEF_HELPER_3(usati_64, i64, env, i64, i64)
> diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
> index 21272fdb504..8da13669d73 100644
> --- a/target/riscv/insn32.decode
> +++ b/target/riscv/insn32.decode
> @@ -40,6 +40,9 @@
>   %imm_z6   26:1 15:5
>   %imm_mop5 30:1 26:2 20:2
>   %imm_mop3 30:1 26:2
> +%imm_p_ui16 20:4
> +%imm_p_ui32 20:5
> +%imm_p_ui64 20:6
>   
>   # Argument sets:
>   &empty
> @@ -60,6 +63,7 @@
>   &k_aes     shamt rs2 rs1 rd
>   &mop5 imm rd rs1
>   &mop3 imm rd rs1 rs2
> +&p_ui imm rs1 rd
>   
>   # Formats 32:
>   @r       .......   ..... ..... ... ..... ....... &r                %rs2 %rs1 %rd
> @@ -105,6 +109,10 @@
>   @mop5 . . .. .. .... .. ..... ... ..... ....... &mop5 imm=%imm_mop5 %rd %rs1
>   @mop3 . . .. .. . ..... ..... ... ..... ....... &mop3 imm=%imm_mop3 %rd %rs1 %rs2
>   
> +@p_ui16 ..... .... ... ..... ... ..... ....... &i imm=%imm_p_ui16 %rs1 %rd
> +@p_ui32 ..... .... ... ..... ... ..... ....... &i imm=%imm_p_ui32 %rs1 %rd
> +@p_ui64 ..... .... ... ..... ... ..... ....... &i imm=%imm_p_ui64 %rs1 %rd
> +
>   # Formats 64:
>   @sh5     .......  ..... .....  ... ..... ....... &shift  shamt=%sh5      %rs1 %rd
>   
> @@ -1084,3 +1092,58 @@ sb_aqrl  00111 . . ..... ..... 000 ..... 0101111 @atom_st
>   sh_aqrl  00111 . . ..... ..... 001 ..... 0101111 @atom_st
>   sw_aqrl  00111 . . ..... ..... 010 ..... 0101111 @atom_st
>   sd_aqrl  00111 . . ..... ..... 011 ..... 0101111 @atom_st
> +
> +# *** P Experimental Extension Version v020 ***
> +# Packed SIMD - Arithmetic Operations(Non-Saturating and Saturating)
> +padd_b     1000010 ..... ..... 000 ..... 0111011 @r
> +padd_h     1000000 ..... ..... 000 ..... 0111011 @r
> +padd_w     1000001 ..... ..... 000 ..... 0111011 @r
> +padd_bs    1001110 ..... ..... 010 ..... 0011011 @r
> +padd_hs    1001100 ..... ..... 010 ..... 0011011 @r
> +padd_ws    1001101 ..... ..... 010 ..... 0011011 @r
> +psub_b     1100010 ..... ..... 000 ..... 0111011 @r
> +psub_h     1100000 ..... ..... 000 ..... 0111011 @r
> +psub_w     1100001 ..... ..... 000 ..... 0111011 @r
> +psh1add_h  1010000 ..... ..... 010 ..... 0111011 @r
> +psh1add_w  1010001 ..... ..... 010 ..... 0111011 @r
> +pssh1sadd_h   1011000 ..... ..... 010 ..... 0111011 @r
> +{
> +  ssh1sadd    1011001 ..... ..... 010 ..... 0111011 @r
> +  pssh1sadd_w 1011001 ..... ..... 010 ..... 0111011 @r
> +}
> +psadd_b    1001010 ..... ..... 000 ..... 0111011 @r
> +psadd_h    1001000 ..... ..... 000 ..... 0111011 @r
> +{
> +  sadd     1001001 ..... ..... 000 ..... 0111011 @r
> +  psadd_w  1001001 ..... ..... 000 ..... 0111011 @r
> +}
> +psaddu_b   1011010 ..... ..... 000 ..... 0111011 @r
> +psaddu_h   1011000 ..... ..... 000 ..... 0111011 @r
> +{
> +  saddu    1011001 ..... ..... 000 ..... 0111011 @r
> +  psaddu_w 1011001 ..... ..... 000 ..... 0111011 @r
> +}
> +pssub_b    1101010 ..... ..... 000 ..... 0111011 @r
> +pssub_h    1101000 ..... ..... 000 ..... 0111011 @r
> +{
> +  ssub     1101001 ..... ..... 000 ..... 0111011 @r
> +  pssub_w  1101001 ..... ..... 000 ..... 0111011 @r
> +}
> +pssubu_b   1111010 ..... ..... 000 ..... 0111011 @r
> +pssubu_h   1111000 ..... ..... 000 ..... 0111011 @r
> +{
> +  ssubu      1111001 ..... ..... 000 ..... 0111011 @r
> +  pssubu_w   1111001 ..... ..... 000 ..... 0111011 @r
> +}
> +psati_h    11100 001.... ..... 100 ..... 0011011 @p_ui16
> +pusati_h   10100 001.... ..... 100 ..... 0011011 @p_ui16
> +{
> +  sati_32  11100 01..... ..... 100 ..... 0011011 @p_ui32
> +  psati_w  11100 01..... ..... 100 ..... 0011011 @p_ui32
> +}
> +{
> +  usati_32 10100 01..... ..... 100 ..... 0011011 @p_ui32
> +  pusati_w 10100 01..... ..... 100 ..... 0011011 @p_ui32
> +}
> +sati_64    111001 ...... ..... 100 ..... 0011011 @p_ui64
> +usati_64   101001 ...... ..... 100 ..... 0011011 @p_ui64
> diff --git a/target/riscv/tcg/insn_trans/trans_rvp.c.inc b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
> new file mode 100644
> index 00000000000..056ccfb486e
> --- /dev/null
> +++ b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
> @@ -0,0 +1,547 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/* RISC-V translation routines for the P Standard Extensions. */
> +/* Copyright (c) 2026 ISRC ISCAS. */
> +
> +/* Save a 64 bit data in src to dst and dst + 1 */
> +
> +static bool require_rvp(DisasContext *ctx)
> +{
> +    uint32_t opcode = ctx->opcode & 0x7f;
> +
> +    if (!has_ext(ctx, RVP)) {
> +        return false;
> +    }
> +
> +    /*
> +     * P_VXSAT_EXCP is encoded in the TB flags only when P is implemented
> +     * without Zve*, where stateen0.VXSAT controls the whole OP-32 and
> +     * OP-IMM-32 P instruction spaces.  When Zve* is present, this field
> +     * remains NONE and vxsat access is checked by the VS path instead.
> +     */
> +    if ((opcode == 0x3b || opcode == 0x1b) &&
> +        ctx->p_vxsat_excp != P_VXSAT_EXCP_NONE) {
> +        ctx->virt_inst_excp =
> +            ctx->p_vxsat_excp == P_VXSAT_EXCP_VIRTUAL;
> +        return false;
> +    }
> +
> +    return true;
> +}
> +
> +static bool prepare_rvp_vxsat(DisasContext *ctx)
> +{
> +    if (!ctx->cfg_ptr->ext_zve32x) {
> +        return true;
> +    }
> +
> +    if (ctx->mstatus_vs == EXT_STATUS_DISABLED) {
> +        return false;
> +    }
> +
> +    mark_vs_dirty(ctx);
> +    return true;
> +}
> +
> +#define REQUIRE_RVP(ctx) do {             \
> +    if (!require_rvp(ctx)) {              \
> +        return false;                     \
> +    }                                     \
> +} while (0)
> +
> +#define GEN_SIMD_TRANS_BODY(NAME, VXSAT)                    \
> +do {                                                        \
> +    REQUIRE_RVP(ctx);                                       \
> +    if (VXSAT && !prepare_rvp_vxsat(ctx)) {                 \
> +        return false;                                       \
> +    }                                                       \
> +    TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE);             \
> +    TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE);             \
> +    TCGv dest = dest_gpr(ctx, a->rd);                       \
> +    gen_helper_##NAME(dest, tcg_env, src1, src2);           \
> +    gen_set_gpr(ctx, a->rd, dest);                          \
> +    return true;                                            \
> +} while (0)
> +
> +#define GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)                 \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_32BIT(ctx);                                     \
> +    return true;                                           \
> +}
> +
> +#define GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)                 \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_64BIT(ctx);                                     \
> +    return true;                                           \
> +}
> +
> +#define GEN_SIMD_TRANS(NAME)                                \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    GEN_SIMD_TRANS_BODY(NAME, false);                       \
> +}
> +
> +#define GEN_SIMD_TRANS_VXSAT(NAME)                         \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    GEN_SIMD_TRANS_BODY(NAME, true);                        \
> +}
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_32(NAME)                             \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a)  \
> +{                                                           \
> +    REQUIRE_32BIT(ctx);                                     \
> +    GEN_SIMD_TRANS_BODY(NAME, false);                       \
> +}
> +#define GEN_SIMD_TRANS_32_VXSAT(NAME)                      \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_32BIT(ctx);                                     \
> +    GEN_SIMD_TRANS_BODY(NAME, true);                        \
> +}
> +#else
> +#define GEN_SIMD_TRANS_32(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#define GEN_SIMD_TRANS_32_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_64(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
> +#define GEN_SIMD_TRANS_64_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
> +#else
> +#define GEN_SIMD_TRANS_64(NAME)                             \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a)  \
> +{                                                           \
> +    REQUIRE_64BIT(ctx);                                     \
> +    GEN_SIMD_TRANS_BODY(NAME, false);                       \
> +}
> +#define GEN_SIMD_TRANS_64_VXSAT(NAME)                      \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_64BIT(ctx);                                     \
> +    GEN_SIMD_TRANS_BODY(NAME, true);                        \
> +}
> +#endif
> +
> +#define GEN_SIMD_TRANS_ACC_BODY(NAME, VXSAT)                \
> +do {                                                        \
> +    REQUIRE_RVP(ctx);                                       \
> +    if (VXSAT && !prepare_rvp_vxsat(ctx)) {                 \
> +        return false;                                       \
> +    }                                                       \
> +    TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE);             \
> +    TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE);             \
> +    TCGv dest = dest_gpr(ctx, a->rd);                       \
> +    TCGv t = tcg_temp_new();                                \
> +    gen_helper_##NAME(t, tcg_env, src1, src2, dest);        \
> +    gen_set_gpr(ctx, a->rd, t);                             \
> +    return true;                                            \
> +} while (0)
> +
> +#define GEN_SIMD_TRANS_ACC(NAME)                            \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    GEN_SIMD_TRANS_ACC_BODY(NAME, false);                   \
> +}
> +
> +#define GEN_SIMD_TRANS_ACC_VXSAT(NAME)                     \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    GEN_SIMD_TRANS_ACC_BODY(NAME, true);                    \
> +}
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_ACC_32(NAME)                         \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_32BIT(ctx);                                     \
> +    GEN_SIMD_TRANS_ACC_BODY(NAME, false);                   \
> +}
> +#else
> +#define GEN_SIMD_TRANS_ACC_32(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_ACC_64(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
> +#else
> +#define GEN_SIMD_TRANS_ACC_64(NAME)                         \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_64BIT(ctx);                                     \
> +    GEN_SIMD_TRANS_ACC_BODY(NAME, false);                   \
> +}
> +#endif
> +
> +#define GEN_SIMD_TRANS_R1_BODY(NAME, VXSAT)                 \
> +do {                                                        \
> +    REQUIRE_RVP(ctx);                                       \
> +    if (VXSAT && !prepare_rvp_vxsat(ctx)) {                 \
> +        return false;                                       \
> +    }                                                       \
> +    TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE);             \
> +    TCGv dest = dest_gpr(ctx, a->rd);                       \
> +    gen_helper_##NAME(dest, tcg_env, src1);                 \
> +    gen_set_gpr(ctx, a->rd, dest);                          \
> +    return true;                                            \
> +} while (0)
> +
> +#define GEN_SIMD_TRANS_R1(NAME)                             \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    GEN_SIMD_TRANS_R1_BODY(NAME, false);                    \
> +}
> +
> +#define GEN_SIMD_TRANS_R1_VXSAT(NAME)                      \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    GEN_SIMD_TRANS_R1_BODY(NAME, true);                     \
> +}
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_R1_64(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
> +#define GEN_SIMD_TRANS_R1_64_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
> +#else
> +#define GEN_SIMD_TRANS_R1_64(NAME)                          \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_64BIT(ctx);                                     \
> +    GEN_SIMD_TRANS_R1_BODY(NAME, false);                    \
> +}
> +#define GEN_SIMD_TRANS_R1_64_VXSAT(NAME)                   \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_64BIT(ctx);                                     \
> +    GEN_SIMD_TRANS_R1_BODY(NAME, true);                     \
> +}
> +#endif
> +
> +#define GEN_SIMD_TRANS_IMM_BODY(NAME, VXSAT)                \
> +do {                                                        \
> +    REQUIRE_RVP(ctx);                                       \
> +    if (VXSAT && !prepare_rvp_vxsat(ctx)) {                 \
> +        return false;                                       \
> +    }                                                       \
> +    TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE);             \
> +    TCGv imm = tcg_constant_tl(a->imm);                     \
> +    TCGv dest = dest_gpr(ctx, a->rd);                       \
> +    gen_helper_##NAME(dest, tcg_env, src1, imm);            \
> +    gen_set_gpr(ctx, a->rd, dest);                          \
> +    return true;                                            \
> +} while (0)
> +
> +#define GEN_SIMD_TRANS_IMM(NAME)                            \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    GEN_SIMD_TRANS_IMM_BODY(NAME, false);                   \
> +}
> +
> +#define GEN_SIMD_TRANS_IMM_VXSAT(NAME)                     \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    GEN_SIMD_TRANS_IMM_BODY(NAME, true);                    \
> +}
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_IMM_32(NAME)                         \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_32BIT(ctx);                                     \
> +    GEN_SIMD_TRANS_IMM_BODY(NAME, false);                   \
> +}
> +#define GEN_SIMD_TRANS_IMM_32_VXSAT(NAME)                  \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_32BIT(ctx);                                     \
> +    GEN_SIMD_TRANS_IMM_BODY(NAME, true);                    \
> +}
> +#else
> +#define GEN_SIMD_TRANS_IMM_32(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#define GEN_SIMD_TRANS_IMM_32_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_IMM_64(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
> +#define GEN_SIMD_TRANS_IMM_64_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
> +#else
> +#define GEN_SIMD_TRANS_IMM_64(NAME)                         \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_64BIT(ctx);                                     \
> +    GEN_SIMD_TRANS_IMM_BODY(NAME, false);                   \
> +}
> +#define GEN_SIMD_TRANS_IMM_64_VXSAT(NAME)                  \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_64BIT(ctx);                                     \
> +    GEN_SIMD_TRANS_IMM_BODY(NAME, true);                    \
> +}
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_REG_PAIR_SCALAR_OP(NAME, SRC2)       \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_32BIT(ctx);                                     \
> +    REQUIRE_RVP(ctx);                                       \
> +    TCGv_i32 src1 = get_gpr(ctx, a->rs1, EXT_NONE);         \
> +    TCGv_i32 src2 = SRC2;                                   \
> +    TCGv_i64 t = tcg_temp_new_i64();                        \
> +    gen_helper_##NAME(t, tcg_env, src1, src2);              \
> +    set_pair_regs(ctx, (a->rd) * 2, t);                     \
> +    return true;                                            \
> +}
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_SCALAR(NAME) \
> +    GEN_SIMD_TRANS_REG_PAIR_SCALAR_OP(NAME, get_gpr(ctx, a->rs2, EXT_NONE))
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_SCALAR_IMM(NAME) \
> +    GEN_SIMD_TRANS_REG_PAIR_SCALAR_OP(NAME, tcg_constant_i32(a->imm))
> +#else
> +#define GEN_SIMD_TRANS_REG_PAIR_SCALAR(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#define GEN_SIMD_TRANS_REG_PAIR_SCALAR_IMM(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_REG_PAIR_OP(INSN, HELPER, SRC2_0, SRC2_1, VXSAT) \
> +static bool trans_##INSN(DisasContext *ctx, arg_##INSN * a)       \
> +{                                                                 \
> +    REQUIRE_32BIT(ctx);                                           \
> +    REQUIRE_RVP(ctx);                                             \
> +    if (VXSAT && !prepare_rvp_vxsat(ctx)) {                       \
> +        return false;                                             \
> +    }                                                             \
> +    TCGv src1_0 = get_gpr(ctx, (a->rs1) * 2, EXT_NONE);           \
> +    TCGv src2_0 = SRC2_0;                                         \
> +    TCGv dest_0 = dest_gpr(ctx, (a->rd) * 2);                     \
> +    TCGv src1_1 = get_gpr(ctx, (a->rs1) * 2 + 1, EXT_NONE);       \
> +    TCGv src2_1 = SRC2_1;                                         \
> +    TCGv dest_1 = dest_gpr(ctx, (a->rd) * 2 + 1);                 \
> +    gen_helper_##HELPER(dest_0, tcg_env, src1_0, src2_0);         \
> +    gen_helper_##HELPER(dest_1, tcg_env, src1_1, src2_1);         \
> +    gen_set_gpr(ctx, (a->rd) * 2, dest_0);                        \
> +    gen_set_gpr(ctx, (a->rd) * 2 + 1, dest_1);                    \
> +    return true;                                                  \
> +}
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE(INSN, HELPER)                   \
> +    GEN_SIMD_TRANS_REG_PAIR_OP(INSN, HELPER,                       \
> +        get_gpr(ctx, (a->rs2) * 2, EXT_NONE),                     \
> +        get_gpr(ctx, (a->rs2) * 2 + 1, EXT_NONE), false)
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(INSN, HELPER)            \
> +    GEN_SIMD_TRANS_REG_PAIR_OP(INSN, HELPER,                       \
> +        get_gpr(ctx, (a->rs2) * 2, EXT_NONE),                     \
> +        get_gpr(ctx, (a->rs2) * 2 + 1, EXT_NONE), true)
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_IMM(INSN, HELPER)               \
> +    GEN_SIMD_TRANS_REG_PAIR_OP(INSN, HELPER,                       \
> +        tcg_constant_tl(a->imm), tcg_constant_tl(a->imm), false)
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_IMM_VXSAT(INSN, HELPER)        \
> +    GEN_SIMD_TRANS_REG_PAIR_OP(INSN, HELPER,                       \
> +        tcg_constant_tl(a->imm), tcg_constant_tl(a->imm), true)
> +#else
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE(INSN, HELPER) \
> +    GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(INSN, HELPER) \
> +    GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_IMM(INSN, HELPER) \
> +    GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_IMM_VXSAT(INSN, HELPER) \
> +    GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_OP(INSN, HELPER, VXSAT)     \
> +static bool trans_##INSN(DisasContext *ctx, arg_##INSN * a)    \
> +{                                                              \
> +    REQUIRE_32BIT(ctx);                                        \
> +    REQUIRE_RVP(ctx);                                          \
> +    if (VXSAT && !prepare_rvp_vxsat(ctx)) {                    \
> +        return false;                                          \
> +    }                                                          \
> +    TCGv src1_0 = get_gpr(ctx, (a->rs1) * 2, EXT_NONE);        \
> +    TCGv dest_0 = dest_gpr(ctx, (a->rd) * 2);                    \
> +    TCGv src1_1 = get_gpr(ctx, (a->rs1) * 2 + 1, EXT_NONE);        \
> +    TCGv dest_1 = dest_gpr(ctx, (a->rd) * 2 + 1);                  \
> +    TCGv src2   = get_gpr(ctx, a->rs2, EXT_NONE);              \
> +    gen_helper_##HELPER(dest_0, tcg_env, src1_0, src2);        \
> +    gen_helper_##HELPER(dest_1, tcg_env, src1_1, src2);        \
> +    gen_set_gpr(ctx, (a->rd) * 2, dest_0);                     \
> +    gen_set_gpr(ctx, (a->rd) * 2 + 1, dest_1);                 \
> +    return true;                                              \
> +}
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR(INSN, HELPER)              \
> +    GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_OP(INSN, HELPER, false)
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_VXSAT(INSN, HELPER)       \
> +    GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_OP(INSN, HELPER, true)
> +#else
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR(INSN, HELPER) \
> +    GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_VXSAT(INSN, HELPER) \
> +    GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_OP(INSN, HELPER, VXSAT)     \
> +static bool trans_##INSN(DisasContext *ctx, arg_##INSN * a)    \
> +{                                                              \
> +    REQUIRE_RVP(ctx);                                          \
> +    if (VXSAT && !prepare_rvp_vxsat(ctx)) {                    \
> +        return false;                                          \
> +    }                                                          \
> +    TCGv src1_0 = get_gpr(ctx, (a->rs1) * 2, EXT_NONE);        \
> +    TCGv dest_0 = dest_gpr(ctx, (a->rd) * 2);                  \
> +    TCGv src1_1 = get_gpr(ctx, (a->rs1) * 2 + 1, EXT_NONE);    \
> +    TCGv dest_1 = dest_gpr(ctx, (a->rd) * 2 + 1);              \
> +    gen_helper_##HELPER(dest_0, tcg_env, src1_0);              \
> +    gen_helper_##HELPER(dest_1, tcg_env, src1_1);              \
> +    gen_set_gpr(ctx, (a->rd) * 2, dest_0);                     \
> +    gen_set_gpr(ctx, (a->rd) * 2 + 1, dest_1);                 \
> +    return true;                                               \
> +}
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY(INSN, HELPER)               \
> +    GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_OP(INSN, HELPER, false)
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_VXSAT(INSN, HELPER)        \
> +    GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_OP(INSN, HELPER, true)
> +#else
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY(INSN, HELPER) \
> +    GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_VXSAT(INSN, HELPER) \
> +    GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_REG_PAIR_ACC(NAME)                   \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_32BIT(ctx);                                     \
> +    REQUIRE_RVP(ctx);                                       \
> +    TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE);             \
> +    TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE);             \
> +    TCGv_i64 t = tcg_temp_new_i64();                        \
> +    if (a->rd == 0) {                                         \
> +        tcg_gen_movi_i64(t, 0);                             \
> +    } else {                                                  \
> +        get_pair_regs(ctx, t, (a->rd) * 2);                   \
> +    }                                                       \
> +    gen_helper_##NAME(t, tcg_env, src1, src2, t);           \
> +    set_pair_regs(ctx, (a->rd) * 2, t);                       \
> +    return true;                                           \
> +}
> +#else
> +#define GEN_SIMD_TRANS_REG_PAIR_ACC(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_REG_PAIR_PREDSUM(NAME)               \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_32BIT(ctx);                                     \
> +    REQUIRE_RVP(ctx);                                       \
> +    TCGv_i32 src1_l;                                        \
> +    TCGv_i32 src1_h;                                        \
> +    TCGv_i32 src2 = get_gpr(ctx, a->rs2, EXT_NONE);         \
> +    TCGv_i32 dest = dest_gpr(ctx, a->rd);                   \
> +    if (a->rs1 == 0) {                                        \
> +        src1_l = tcg_temp_new_i32();                        \
> +        src1_h = tcg_temp_new_i32();                        \
> +        tcg_gen_movi_i32(src1_l, 0);                        \
> +        tcg_gen_movi_i32(src1_h, 0);                        \
> +    } else {                                                  \
> +        src1_l = get_gpr(ctx, (a->rs1) * 2, EXT_NONE);        \
> +        src1_h = get_gpr(ctx, (a->rs1) * 2 + 1, EXT_NONE);      \
> +    }                                                       \
> +    gen_helper_##NAME(dest, tcg_env, src1_l, src1_h, src2); \
> +    gen_set_gpr(ctx, a->rd, dest);                          \
> +    return true;                                           \
> +}
> +#else
> +#define GEN_SIMD_TRANS_REG_PAIR_PREDSUM(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_PN_OP(NAME, SRC2, VXSAT)            \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_32BIT(ctx);                                     \
> +    REQUIRE_RVP(ctx);                                       \
> +    if (VXSAT && !prepare_rvp_vxsat(ctx)) {                 \
> +        return false;                                       \
> +    }                                                       \
> +    TCGv_i64 s1 = tcg_temp_new_i64();                       \
> +    if (a->rs1 == 0) {                                      \
> +        tcg_gen_mov_i64(s1, 0);                             \
> +    } else {                                                \
> +        get_pair_regs(ctx, s1, a->rs1 * 2);                 \
> +    }                                                       \
> +    TCGv src2 = SRC2;                                       \
> +    TCGv dest = dest_gpr(ctx, a->rd);                       \
> +    gen_helper_##NAME(dest, tcg_env, s1, src2);             \
> +    gen_set_gpr(ctx, a->rd, dest);                          \
> +    return true;                                            \
> +}
> +
> +#define GEN_SIMD_TRANS_PN_OP_IMM(NAME) \
> +    GEN_SIMD_TRANS_PN_OP(NAME, tcg_constant_tl(a->imm), false)
> +
> +#define GEN_SIMD_TRANS_PN_OP_IMM_VXSAT(NAME) \
> +    GEN_SIMD_TRANS_PN_OP(NAME, tcg_constant_tl(a->imm), true)
> +
> +#define GEN_SIMD_TRANS_PN_OP_REG(NAME) \
> +    GEN_SIMD_TRANS_PN_OP(NAME, get_gpr(ctx, a->rs2, EXT_NONE), false)
> +
> +#define GEN_SIMD_TRANS_PN_OP_REG_VXSAT(NAME) \
> +    GEN_SIMD_TRANS_PN_OP(NAME, get_gpr(ctx, a->rs2, EXT_NONE), true)
> +#else
> +#define GEN_SIMD_TRANS_PN_OP_IMM(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#define GEN_SIMD_TRANS_PN_OP_IMM_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#define GEN_SIMD_TRANS_PN_OP_REG(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#define GEN_SIMD_TRANS_PN_OP_REG_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#endif
> +
> +/* Packed SIMD - Arithmetic Operations(Non-Saturating and Saturating) */
> +GEN_SIMD_TRANS(padd_b)
> +GEN_SIMD_TRANS(padd_h)
> +GEN_SIMD_TRANS_64(padd_w)
> +GEN_SIMD_TRANS(padd_bs)
> +GEN_SIMD_TRANS(padd_hs)
> +GEN_SIMD_TRANS_64(padd_ws)
> +GEN_SIMD_TRANS(psub_b)
> +GEN_SIMD_TRANS(psub_h)
> +GEN_SIMD_TRANS_64(psub_w)
> +GEN_SIMD_TRANS(psh1add_h)
> +GEN_SIMD_TRANS_64(psh1add_w)
> +GEN_SIMD_TRANS_VXSAT(pssh1sadd_h)
> +GEN_SIMD_TRANS_64_VXSAT(pssh1sadd_w)
> +GEN_SIMD_TRANS_32_VXSAT(ssh1sadd)
> +GEN_SIMD_TRANS_VXSAT(psadd_b)
> +GEN_SIMD_TRANS_VXSAT(psadd_h)
> +GEN_SIMD_TRANS_64_VXSAT(psadd_w)
> +GEN_SIMD_TRANS_VXSAT(psaddu_b)
> +GEN_SIMD_TRANS_VXSAT(psaddu_h)
> +GEN_SIMD_TRANS_64_VXSAT(psaddu_w)
> +GEN_SIMD_TRANS_32_VXSAT(sadd)
> +GEN_SIMD_TRANS_32_VXSAT(saddu)
> +GEN_SIMD_TRANS_VXSAT(pssub_b)
> +GEN_SIMD_TRANS_VXSAT(pssub_h)
> +GEN_SIMD_TRANS_64_VXSAT(pssub_w)
> +GEN_SIMD_TRANS_VXSAT(pssubu_b)
> +GEN_SIMD_TRANS_VXSAT(pssubu_h)
> +GEN_SIMD_TRANS_64_VXSAT(pssubu_w)
> +GEN_SIMD_TRANS_32_VXSAT(ssub)
> +GEN_SIMD_TRANS_32_VXSAT(ssubu)
> +GEN_SIMD_TRANS_IMM_VXSAT(psati_h)
> +GEN_SIMD_TRANS_IMM_VXSAT(pusati_h)
> +GEN_SIMD_TRANS_IMM_64_VXSAT(psati_w)
> +GEN_SIMD_TRANS_IMM_64_VXSAT(pusati_w)
> +GEN_SIMD_TRANS_IMM_32_VXSAT(sati_32)
> +GEN_SIMD_TRANS_IMM_32_VXSAT(usati_32)
> +GEN_SIMD_TRANS_IMM_64_VXSAT(sati_64)
> +GEN_SIMD_TRANS_IMM_64_VXSAT(usati_64)
> +
> diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
> index 2948bbb2a86..52c58e0287e 100644
> --- a/target/riscv/tcg/psimd_helper.c
> +++ b/target/riscv/tcg/psimd_helper.c
> @@ -1654,3 +1654,117 @@ uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
>   
>   /* Basic addition operations (non-saturating) */
>   
> +GEN_PSIMD_BINOP(padd_b, target_ulong, uint8_t, uint8_t,
> +                EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ADD)
> +GEN_PSIMD_BINOP(padd_h, target_ulong, uint16_t, uint16_t,
> +                EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ADD)
> +GEN_PSIMD_BINOP(padd_w, uint64_t, uint32_t, uint32_t,
> +                EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD)
> +
> +GEN_PSIMD_BINOP_SCALAR(padd_bs, target_ulong, uint8_t,
> +                       EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ADD)
> +GEN_PSIMD_BINOP_SCALAR(padd_hs, target_ulong, uint16_t,
> +                       EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ADD)
> +GEN_PSIMD_BINOP_SCALAR(padd_ws, uint64_t, uint32_t,
> +                       EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD)
> +
> +/* Basic subtraction operations (non-saturating) */
> +
> +GEN_PSIMD_BINOP(psub_b, target_ulong, uint8_t, uint8_t,
> +                EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_SUB)
> +GEN_PSIMD_BINOP(psub_h, target_ulong, uint16_t, uint16_t,
> +                EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_SUB)
> +GEN_PSIMD_BINOP(psub_w, uint64_t, uint32_t, uint32_t,
> +                EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_SUB)
> +
> +/* Shift-left-by-one and add operations */
> +
> +GEN_PSIMD_SHADD(psh1add_h, target_ulong, uint16_t,
> +                EXTRACT16, INSERT16, ELEMS_H, 1)
> +GEN_PSIMD_SHADD(psh1add_w, uint64_t, uint32_t,
> +                EXTRACT32, INSERT32, ELEMS_W, 1)
> +
> +GEN_PSIMD_SAT_SHADD(pssh1sadd_h, target_ulong, int16_t, int32_t,
> +                    EXTRACT16, INSERT16, ELEMS_H, 1, -0x4000, 0x3fff,
> +                    SAT_MIN_H, SAT_MAX_H, signed_saturate_h)
> +GEN_PSIMD_SAT_SHADD(pssh1sadd_w, uint64_t, int32_t, int64_t,
> +                    EXTRACT32, INSERT32, ELEMS_W, 1, -0x40000000,
> +                    0x3fffffff, SAT_MIN_W, SAT_MAX_W, signed_saturate_w)
> +
> +GEN_PSIMD_SAT_SHADD(ssh1sadd, uint32_t, int32_t, int64_t,
> +                    EXTRACT32, INSERT32, ELEMS_W, 1, -0x40000000,
> +                    0x3fffffff, SAT_MIN_W, SAT_MAX_W, signed_saturate_w)
> +
> +/* Saturating addition operations */
> +
> +GEN_PSIMD_SAT_BINOP(psadd_b, target_ulong, int8_t, int32_t,
> +                    EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ADD,
> +                    signed_saturate_b)
> +GEN_PSIMD_SAT_BINOP(psadd_h, target_ulong, int16_t, int32_t,
> +                    EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ADD,
> +                    signed_saturate_h)
> +GEN_PSIMD_SAT_BINOP(psadd_w, uint64_t, int32_t, int64_t,
> +                    EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD,
> +                    signed_saturate_w)
> +
> +GEN_PSIMD_SAT_BINOP(psaddu_b, target_ulong, uint8_t, uint32_t,
> +                    EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ADD,
> +                    unsigned_saturate_b)
> +GEN_PSIMD_SAT_BINOP(psaddu_h, target_ulong, uint16_t, uint32_t,
> +                    EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ADD,
> +                    unsigned_saturate_h)
> +GEN_PSIMD_SAT_BINOP(psaddu_w, uint64_t, uint32_t, uint64_t,
> +                    EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD,
> +                    unsigned_saturate_w)
> +
> +GEN_PSIMD_SAT_BINOP(sadd, uint32_t, int32_t, int64_t,
> +                    EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD,
> +                    signed_saturate_w)
> +GEN_PSIMD_SAT_BINOP(saddu, uint32_t, uint32_t, uint64_t,
> +                    EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD,
> +                    unsigned_saturate_w)
> +
> +/* Saturating subtraction operations */
> +
> +GEN_PSIMD_SAT_BINOP(pssub_b, target_ulong, int8_t, int32_t,
> +                    EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_SUB,
> +                    signed_saturate_b)
> +GEN_PSIMD_SAT_BINOP(pssub_h, target_ulong, int16_t, int32_t,
> +                    EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_SUB,
> +                    signed_saturate_h)
> +GEN_PSIMD_SAT_BINOP(pssub_w, uint64_t, int32_t, int64_t,
> +                    EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_SUB,
> +                    signed_saturate_w)
> +
> +GEN_PSIMD_USUB_SAT(pssubu_b, target_ulong, uint8_t,
> +                   EXTRACT8, INSERT8, ELEMS_B)
> +GEN_PSIMD_USUB_SAT(pssubu_h, target_ulong, uint16_t,
> +                   EXTRACT16, INSERT16, ELEMS_H)
> +GEN_PSIMD_USUB_SAT(pssubu_w, uint64_t, uint32_t,
> +                   EXTRACT32, INSERT32, ELEMS_W)
> +
> +GEN_PSIMD_SAT_BINOP(ssub, uint32_t, int32_t, int64_t,
> +                    EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_SUB,
> +                    signed_saturate_w)
> +GEN_PSIMD_USUB_SAT(ssubu, uint32_t, uint32_t,
> +                   EXTRACT32, INSERT32, ELEMS_W)
> +
> +/* Saturation instructions (SAT, USAT) */
> +
> +GEN_PSIMD_SATI(psati_h, target_ulong, int16_t, int64_t,
> +               EXTRACT16, INSERT16, ELEMS_H, 0x0f)
> +GEN_PSIMD_USATI(pusati_h, target_ulong, int16_t, uint16_t, uint32_t,
> +                EXTRACT16, INSERT16, ELEMS_H, 1U)
> +GEN_PSIMD_SATI(psati_w, uint64_t, int32_t, int64_t,
> +               EXTRACT32, INSERT32, ELEMS_W, 0x1f)
> +GEN_PSIMD_USATI(pusati_w, uint64_t, int32_t, uint32_t, uint64_t,
> +                EXTRACT32, INSERT32, ELEMS_W, 1ULL)
> +GEN_PSIMD_SATI(sati_32, uint32_t, int32_t, int64_t,
> +               EXTRACT32, INSERT32, ELEMS_W, 0x1f)
> +GEN_PSIMD_USATI(usati_32, uint32_t, int32_t, uint32_t, uint32_t,
> +                EXTRACT32, INSERT32, ELEMS_W, 1U)
> +GEN_PSIMD_SATI(sati_64, uint64_t, int64_t, int64_t,
> +               EXTRACT64, INSERT64, ELEMS_D, 0x3f)
> +GEN_PSIMD_USATI(usati_64, uint64_t, int64_t, uint64_t, uint64_t,
> +                EXTRACT64, INSERT64, ELEMS_D, 1ULL)
> +
> diff --git a/target/riscv/tcg/translate.c b/target/riscv/tcg/translate.c
> index 9684dbe7528..0df9d4190f1 100644
> --- a/target/riscv/tcg/translate.c
> +++ b/target/riscv/tcg/translate.c
> @@ -103,6 +103,7 @@ typedef struct DisasContext {
>       bool vstart_eq_zero;
>       bool vl_eq_vlmax;
>       bool altfmt;
> +    uint8_t p_vxsat_excp;
>       CPUState *cs;
>       TCGv zero;
>       /* actual address width */
> @@ -1199,6 +1200,7 @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc)
>   #include "insn_trans/trans_rvh.c.inc"
>   #include "insn_trans/trans_rvv.c.inc"
>   #include "insn_trans/trans_rvb.c.inc"
> +#include "insn_trans/trans_rvp.c.inc"
>   #include "insn_trans/trans_rvzicond.c.inc"
>   #include "insn_trans/trans_rvzacas.c.inc"
>   #include "insn_trans/trans_rvzabha.c.inc"
> @@ -1333,6 +1335,8 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
>       ctx->vstart_eq_zero = FIELD_EX32(tb_flags, TB_FLAGS, VSTART_EQ_ZERO);
>       ctx->vl_eq_vlmax = FIELD_EX32(tb_flags, TB_FLAGS, VL_EQ_VLMAX);
>       ctx->altfmt = FIELD_EX64(ext_tb_flags, EXT_TB_FLAGS, ALTFMT);
> +    ctx->p_vxsat_excp = FIELD_EX64(ext_tb_flags, EXT_TB_FLAGS,
> +                                   P_VXSAT_EXCP);
>       ctx->misa_mxl_max = mcc->def->misa_mxl_max;
>       ctx->xl = FIELD_EX32(tb_flags, TB_FLAGS, XL);
>       ctx->address_xl = FIELD_EX32(tb_flags, TB_FLAGS, AXL);


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH v2 00/18] target/riscv: Add support for RISC-V P
  2026-07-17 10:06 [PATCH v2 00/18] target/riscv: Add support for RISC-V P Molly Chen
                   ` (17 preceding siblings ...)
  2026-07-17 10:07 ` [PATCH v2 18/18] target/riscv: Remove Zbkb dependency from P extension to align with the spec Molly Chen
@ 2026-07-29  8:43 ` Chao Liu
  2026-07-29  9:32 ` Chao Liu
  19 siblings, 0 replies; 34+ messages in thread
From: Chao Liu @ 2026-07-29  8:43 UTC (permalink / raw)
  To: Molly Chen
  Cc: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
	qemu-riscv, qemu-devel

Hi Molly,

On Fri, Jul 17, 2026 at 10:06:53AM +0800, Molly Chen wrote:
> This series adds support for the RISC-V Packed SIMD (P) extension.
> 
> The P extension defines packed-SIMD fixed-point operations intended
> for DSP-style workloads such as multimedia and signal processing.
> These instructions operate on packed subword elements within
> general-purpose registers (GPRs).
> 
> The implementation follows the current development draft of the
> specification (v0.20):
> 
>   https://github.com/riscv/riscv-p-spec/
>   or
>   https://www.jhauser.us/RISCV/ext-P/
> 
> Compared with v1, this version reduces implementation boilerplate by
> defining and reusing helper macros for common patterns in
> trans_rvp.c.inc and psimd_helper.c. It also consolidates the P
> extension prerequisite validation in riscv_cpu_validate_p().
> 
> The Zbkb dependency has been removed to align the implementation with
> the current specification. This version also implements the
> specification-defined control of vxsat, which was missing from v1.
> 
> All instructions have been functionally tested using the following
> test suite:
> 
>   https://github.com/mollybuild/qemu-riscv-test-uart
I believe we need to add some TCG test cases for the patches if
the latest compiler supports the P extension, we can add some cases
similar to your repo.


Thanks,
Chao

> 
> The implementation focuses on functional correctness and ISA
> coverage. Performance optimizations were not considered at this
> stage.
> 
> Feedback on the implementation details would be highly appreciated.
> 
> Tested with:
> 
>   - ninja -C build test
>   - make -C build check-qtest-riscv32
>   - make -C build check-qtest-riscv64
>   - Functional tests for all P extension instructions using
>     qemu-riscv-test-uart
> 
> No regressions or test failures were observed.
> 
> ---
> Changes in v2:
> 
>   - Refactored trans_rvp.c.inc and psimd_helper.c by defining and
>     reusing helper macros for common implementation patterns, reducing
>     boilerplate and overall code size.
>   - Moved the P extension prerequisite checks into
>     riscv_cpu_validate_p().
>   - Removed the Zbkb dependency to align with the current
>     specification.
>   - Added the specification-defined vxsat control mechanism, which was
>     missing from v1.
> 
> v1:
>   https://lists.nongnu.org/archive/html/qemu-riscv/2026-04/msg00301.html
> 
> Molly Chen (18):
>   target/riscv: Add packed SIMD extension state
>   target/riscv: Add packed SIMD helper framework
>   target/riscv: Add packed SIMD arithmetic instructions
>   target/riscv: Add packed SIMD averaging and rounding instructions
>   target/riscv: Add packed SIMD absolute, difference, compare and mask
>     instructions
>   target/riscv: Add packed SIMD shift instructions
>   target/riscv: Add packed SIMD exchange instructions
>   target/riscv: Add packed SIMD horizontal reduction instructions
>   target/riscv: Add packed SIMD pack, merge and count-leading
>     instructions
>   target/riscv: Add packed SIMD multiplication instructions
>   target/riscv: Add packed SIMD multiply-accumulate instructions
>   target/riscv: Add packed SIMD Q-format multiplication instructions
>   target/riscv: Add packed SIMD Q-format MAC instructions
>   target/riscv: Add packed SIMD two-way MAC instructions
>   target/riscv: Add packed SIMD four-way MAC instructions
>   target/riscv: Add packed SIMD load-replicate instructions
>   target/riscv: Add packed SIMD RV32 only instructions
>   target/riscv: Remove Zbkb dependency from P extension to align with
>     the spec
> 
>  target/riscv/cpu.c                          |    5 +-
>  target/riscv/cpu.h                          |    8 +
>  target/riscv/cpu_bits.h                     |    2 +
>  target/riscv/helper.h                       |  529 ++++
>  target/riscv/insn32.decode                  |  829 +++++
>  target/riscv/machine.c                      |   19 +
>  target/riscv/tcg/csr.c                      |   39 +-
>  target/riscv/tcg/insn_trans/trans_rvb.c.inc |    4 +-
>  target/riscv/tcg/insn_trans/trans_rvp.c.inc | 1389 ++++++++
>  target/riscv/tcg/meson.build                |    3 +-
>  target/riscv/tcg/psimd_helper.c             | 3165 +++++++++++++++++++
>  target/riscv/tcg/tcg-cpu.c                  |   46 +
>  target/riscv/tcg/translate.c                |    6 +
>  13 files changed, 6038 insertions(+), 6 deletions(-)
>  create mode 100644 target/riscv/tcg/insn_trans/trans_rvp.c.inc
>  create mode 100644 target/riscv/tcg/psimd_helper.c
> 
> 
> base-commit: 8fb307591625731060d399aca42373c02c7cb040
> -- 
> 2.34.1
> 


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH v2 01/18] target/riscv: Add packed SIMD extension state
  2026-07-17 10:06 ` [PATCH v2 01/18] target/riscv: Add packed SIMD extension state Molly Chen
  2026-07-26 19:32   ` Daniel Henrique Barboza
  2026-07-27  6:13   ` Nutty.Liu
@ 2026-07-29  8:43   ` Chao Liu
  2 siblings, 0 replies; 34+ messages in thread
From: Chao Liu @ 2026-07-29  8:43 UTC (permalink / raw)
  To: Molly Chen
  Cc: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
	Chao Liu, qemu-riscv, qemu-devel, Yin Zhang, Dajun Huang,
	Zhiyuan Yang

On Fri, Jul 17, 2026 at 10:06:54AM +0800, Molly Chen wrote:
> Model vxsat with separate Vector/Zve and P-only control paths.  When
> Zve* is present, vxsat follows mstatus.VS/vsstatus.VS; when P is
> implemented without Zve*, stateen0.VXSAT controls access instead.
> 
> Record the P-only stateen result in TB flags so cached translations
> preserve both instruction legality and the illegal-vs-virtual exception
> class.
> 
> Co-authored-by: Yin Zhang <zhangyin2018@iscas.ac.cn>
> Co-authored-by: Dajun Huang <djhuang_1@std.uestc.edu.cn>
> Co-authored-by: Zhiyuan Yang <zhiyuan.plct@isrc.iscas.ac.cn>
> 
> Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
Reviewed-by: Chao Liu <chao.liu@processmission.com>

Thanks,
Chao

> ---
>  target/riscv/cpu.c         |  5 ++--
>  target/riscv/cpu.h         |  8 +++++++
>  target/riscv/cpu_bits.h    |  2 ++
>  target/riscv/machine.c     | 19 +++++++++++++++
>  target/riscv/tcg/csr.c     | 39 +++++++++++++++++++++++++++++--
>  target/riscv/tcg/tcg-cpu.c | 48 ++++++++++++++++++++++++++++++++++++++
>  6 files changed, 117 insertions(+), 4 deletions(-)
> 
> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> index 5a82e6563bf..c9e6c83a491 100644
> --- a/target/riscv/cpu.c
> +++ b/target/riscv/cpu.c
> @@ -46,7 +46,7 @@
>  /* RISC-V CPU definitions */
>  static const char riscv_single_letter_exts[] = "IEMAFDQCBPVH";
>  const uint32_t misa_bits[] = {RVI, RVE, RVM, RVA, RVF, RVD, RVV,
> -                              RVC, RVS, RVU, RVH, RVG, RVB, 0};
> +                              RVC, RVS, RVU, RVH, RVG, RVB, RVP, 0};
>  #define RISCV_CPU_MVENDORID 0
>  #define RISCV_CPU_MIMPID 0
>  /*
> @@ -1489,7 +1489,8 @@ static const MISAExtInfo misa_ext_info_arr[] = {
>      MISA_EXT_INFO(RVH, "h", "Hypervisor"),
>      MISA_EXT_INFO(RVV, "v", "Vector operations"),
>      MISA_EXT_INFO(RVG, "g", "General purpose (IMAFD_Zicsr_Zifencei)"),
> -    MISA_EXT_INFO(RVB, "b", "Bit manipulation (Zba_Zbb_Zbs)")
> +    MISA_EXT_INFO(RVB, "b", "Bit manipulation (Zba_Zbb_Zbs)"),
> +    MISA_EXT_INFO(RVP, "x-p", "Packed-SIMD instructions")
>  };
>  
>  static void riscv_cpu_validate_misa_mxl(RISCVCPUClass *mcc)
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index c9dfa7daff2..75cfb16d846 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -70,6 +70,7 @@ typedef struct CPUArchState CPURISCVState;
>  #define RVG RV('G')
>  #define RVB RV('B')
>  #define RVX RV('X')
> +#define RVP RV('P')
>  
>  extern const uint32_t misa_bits[];
>  const char *riscv_get_misa_ext_name(uint32_t bit);
> @@ -742,6 +743,13 @@ FIELD(TB_FLAGS, PM_SIGNEXTEND, 31, 1)
>  FIELD(EXT_TB_FLAGS, MISA_EXT, 0, 32)
>  FIELD(EXT_TB_FLAGS, ALTFMT, 32, 1)
>  FIELD(EXT_TB_FLAGS, BIG_ENDIAN, 33, 1)
> +FIELD(EXT_TB_FLAGS, P_VXSAT_EXCP, 34, 2)
> +
> +enum {
> +    P_VXSAT_EXCP_NONE,
> +    P_VXSAT_EXCP_ILLEGAL,
> +    P_VXSAT_EXCP_VIRTUAL,
> +};
>  
>  #ifdef TARGET_RISCV32
>  #define riscv_cpu_mxl(env)  ((void)(env), MXL_RV32)
> diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
> index 3f146a43fe4..fa7bf60f4fc 100644
> --- a/target/riscv/cpu_bits.h
> +++ b/target/riscv/cpu_bits.h
> @@ -355,6 +355,8 @@
>  #define SMSTATEEN0_CS       (1ULL << 0)
>  #define SMSTATEEN0_FCSR     (1ULL << 1)
>  #define SMSTATEEN0_JVT      (1ULL << 2)
> +/* Packed-SIMD draft: enable access to vxsat when misa.V = 0. */
> +#define SMSTATEEN0_VXSAT    (1ULL << 3)
>  #define SMSTATEEN0_CTR      (1ULL << 54)
>  #define SMSTATEEN0_P1P13    (1ULL << 56)
>  #define SMSTATEEN0_HSCONTXT (1ULL << 57)
> diff --git a/target/riscv/machine.c b/target/riscv/machine.c
> index 0ab613a2980..a9cd7e4c1cc 100644
> --- a/target/riscv/machine.c
> +++ b/target/riscv/machine.c
> @@ -158,6 +158,24 @@ static const VMStateDescription vmstate_vector = {
>      }
>  };
>  
> +static bool p_vxsat_needed(void *opaque)
> +{
> +    RISCVCPU *cpu = opaque;
> +
> +    return riscv_has_ext(&cpu->env, RVP) && !cpu->cfg.ext_zve32x;
> +}
> +
> +static const VMStateDescription vmstate_p_vxsat = {
> +    .name = "cpu/p-vxsat",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .needed = p_vxsat_needed,
> +    .fields = (const VMStateField[]) {
> +        VMSTATE_UINT8(env.vxsat, RISCVCPU),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
>  static bool pointermasking_needed(void *opaque)
>  {
>      return false;
> @@ -518,6 +536,7 @@ const VMStateDescription vmstate_riscv_cpu = {
>          &vmstate_pmp,
>          &vmstate_hyper,
>          &vmstate_vector,
> +        &vmstate_p_vxsat,
>          &vmstate_pointermasking,
>          &vmstate_rv128,
>  #ifdef CONFIG_KVM
> diff --git a/target/riscv/tcg/csr.c b/target/riscv/tcg/csr.c
> index 36f2004bc56..e809997f52e 100644
> --- a/target/riscv/tcg/csr.c
> +++ b/target/riscv/tcg/csr.c
> @@ -109,6 +109,24 @@ static RISCVException vs(CPURISCVState *env, int csrno)
>      return RISCV_EXCP_ILLEGAL_INST;
>  }
>  
> +/* vxsat is also architectural state when P is implemented without Zve*. */
> +static RISCVException vxsat(CPURISCVState *env, int csrno)
> +{
> +    if (riscv_cpu_cfg(env)->ext_zve32x) {
> +        return vs(env, csrno);
> +    }
> +
> +    if (riscv_has_ext(env, RVP)) {
> +#if !defined(CONFIG_USER_ONLY)
> +        return smstateen_acc_ok(env, 0, SMSTATEEN0_VXSAT);
> +#else
> +        return RISCV_EXCP_NONE;
> +#endif
> +    }
> +
> +    return RISCV_EXCP_ILLEGAL_INST;
> +}
> +
>  static RISCVException ctr(CPURISCVState *env, int csrno)
>  {
>  #if !defined(CONFIG_USER_ONLY)
> @@ -1013,7 +1031,12 @@ static RISCVException write_vxsat(CPURISCVState *env, int csrno,
>                                    target_ulong val, uintptr_t ra)
>  {
>  #if !defined(CONFIG_USER_ONLY)
> -    env->mstatus |= MSTATUS_VS;
> +    if (riscv_cpu_cfg(env)->ext_zve32x) {
> +        env->mstatus |= MSTATUS_VS;
> +        if (env->virt_enabled) {
> +            env->mstatus_hs |= MSTATUS_VS;
> +        }
> +    }
>  #endif
>      env->vxsat = val & BIT(0);
>      return RISCV_EXCP_NONE;
> @@ -3494,6 +3517,10 @@ static RISCVException write_mstateen0(CPURISCVState *env, int csrno,
>                                        target_ulong new_val, uintptr_t ra)
>  {
>      uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG;
> +
> +    if (riscv_has_ext(env, RVP) && !riscv_cpu_cfg(env)->ext_zve32x) {
> +        wr_mask |= SMSTATEEN0_VXSAT;
> +    }
>      if (!riscv_has_ext(env, RVF)) {
>          wr_mask |= SMSTATEEN0_FCSR;
>      }
> @@ -3617,6 +3644,10 @@ static RISCVException write_hstateen0(CPURISCVState *env, int csrno,
>  {
>      uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG;
>  
> +    if (riscv_has_ext(env, RVP) && !riscv_cpu_cfg(env)->ext_zve32x) {
> +        wr_mask |= SMSTATEEN0_VXSAT;
> +    }
> +
>      if (!riscv_has_ext(env, RVF)) {
>          wr_mask |= SMSTATEEN0_FCSR;
>      }
> @@ -3746,6 +3777,10 @@ static RISCVException write_sstateen0(CPURISCVState *env, int csrno,
>  {
>      uint64_t wr_mask = 0;
>  
> +    if (riscv_has_ext(env, RVP) && !riscv_cpu_cfg(env)->ext_zve32x) {
> +        wr_mask |= SMSTATEEN0_VXSAT;
> +    }
> +
>      if (!riscv_has_ext(env, RVF)) {
>          wr_mask |= SMSTATEEN0_FCSR;
>      }
> @@ -5916,7 +5951,7 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
>      [CSR_FCSR]     = { "fcsr",     fs,     read_fcsr,    write_fcsr   },
>      /* Vector CSRs */
>      [CSR_VSTART]   = { "vstart",   vs,     read_vstart,  write_vstart },
> -    [CSR_VXSAT]    = { "vxsat",    vs,     read_vxsat,   write_vxsat  },
> +    [CSR_VXSAT]    = { "vxsat",    vxsat,  read_vxsat,   write_vxsat  },
>      [CSR_VXRM]     = { "vxrm",     vs,     read_vxrm,    write_vxrm   },
>      [CSR_VCSR]     = { "vcsr",     vs,     read_vcsr,    write_vcsr   },
>      [CSR_VL]       = { "vl",       vs,     read_vl                    },
> diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
> index 4af5cd9c731..1665583accf 100644
> --- a/target/riscv/tcg/tcg-cpu.c
> +++ b/target/riscv/tcg/tcg-cpu.c
> @@ -160,6 +160,8 @@ static TCGTBCPUState riscv_get_tb_cpu_state(CPUState *cs)
>      fs = EXT_STATUS_DIRTY;
>      vs = EXT_STATUS_DIRTY;
>  #else
> +    RISCVException p_vxsat_excp;
> +
>      flags = FIELD_DP32(flags, TB_FLAGS, PRIV, env->priv);
>  
>      flags |= riscv_env_mmu_index(env, 0);
> @@ -182,6 +184,23 @@ static TCGTBCPUState riscv_get_tb_cpu_state(CPUState *cs)
>               ? EXT_STATUS_DIRTY : EXT_STATUS_DISABLED;
>      }
>  
> +    /*
> +     * Without Zve*, all P instructions in the OP-32 and OP-IMM-32
> +     * spaces are controlled by stateen0.VXSAT.  Preserve the exception
> +     * class in the TB flags so translated code can distinguish an illegal
> +     * instruction from a virtual-instruction exception.
> +     */
> +    p_vxsat_excp = smstateen_acc_ok(env, 0, SMSTATEEN0_VXSAT);
> +    if (riscv_has_ext(env, RVP) && !riscv_cpu_cfg(env)->ext_zve32x) {
> +        if (p_vxsat_excp == RISCV_EXCP_VIRT_INSTRUCTION_FAULT) {
> +            ext_flags = FIELD_DP64(ext_flags, EXT_TB_FLAGS, P_VXSAT_EXCP,
> +                                   P_VXSAT_EXCP_VIRTUAL);
> +        } else if (p_vxsat_excp != RISCV_EXCP_NONE) {
> +            ext_flags = FIELD_DP64(ext_flags, EXT_TB_FLAGS, P_VXSAT_EXCP,
> +                                   P_VXSAT_EXCP_ILLEGAL);
> +        }
> +    }
> +
>      if (cpu->cfg.debug && !icount_enabled()) {
>          flags = FIELD_DP32(flags, TB_FLAGS, ITRIGGER, env->itrigger_enabled);
>      }
> @@ -530,6 +549,28 @@ static void riscv_cpu_validate_b(RISCVCPU *cpu)
>      }
>  }
>  
> +static void riscv_cpu_validate_p(RISCVCPU *cpu, Error **errp)
> +{
> +    CPURISCVState *env = &cpu->env;
> +
> +    if (!riscv_has_ext(env, RVP)) {
> +        return;
> +    }
> +
> +    if (riscv_cpu_mxl(env) != MXL_RV32 &&
> +        riscv_cpu_mxl(env) != MXL_RV64) {
> +        error_setg(errp, "P extension requires RV32 or RV64");
> +        return;
> +    }
> +
> +    if (!(cpu->cfg.ext_zmmul && cpu->cfg.ext_zba && cpu->cfg.ext_zbb &&
> +          cpu->cfg.ext_zbkb)) {
> +        error_setg(errp, "P extension requires zmmul, zba, zbb and zbkb "
> +                         "extensions");
> +        return;
> +    }
> +}
> +
>  /*
>   * Check consistency between chosen extensions while setting
>   * cpu->cfg accordingly.
> @@ -612,6 +653,12 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp)
>          return;
>      }
>  
> +    riscv_cpu_validate_p(cpu, &local_err);
> +    if (local_err != NULL) {
> +        error_propagate(errp, local_err);
> +        return;
> +    }
> +
>      riscv_cpu_validate_v(env, &cpu->cfg, &local_err);
>      if (local_err != NULL) {
>          error_propagate(errp, local_err);
> @@ -1414,6 +1461,7 @@ static const RISCVCPUMisaExtConfig misa_ext_cfgs[] = {
>      MISA_CFG(RVV, false),
>      MISA_CFG(RVG, false),
>      MISA_CFG(RVB, false),
> +    MISA_CFG(RVP, false),
>  };
>  
>  /*
> -- 
> 2.34.1
> 


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH v2 02/18] target/riscv: Add packed SIMD helper framework
  2026-07-17 10:06 ` [PATCH v2 02/18] target/riscv: Add packed SIMD helper framework Molly Chen
  2026-07-26 19:53   ` Daniel Henrique Barboza
  2026-07-27  6:16   ` Nutty.Liu
@ 2026-07-29  9:01   ` Chao Liu
  2 siblings, 0 replies; 34+ messages in thread
From: Chao Liu @ 2026-07-29  9:01 UTC (permalink / raw)
  To: Molly Chen
  Cc: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
	Chao Liu, qemu-riscv, qemu-devel

On Fri, Jul 17, 2026 at 10:06:55AM +0800, Molly Chen wrote:
> Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
> ---
>  target/riscv/tcg/meson.build    |    3 +-
>  target/riscv/tcg/psimd_helper.c | 1656 +++++++++++++++++++++++++++++++
>  2 files changed, 1658 insertions(+), 1 deletion(-)
>  create mode 100644 target/riscv/tcg/psimd_helper.c
> 
> diff --git a/target/riscv/tcg/meson.build b/target/riscv/tcg/meson.build
> index a05ab642f41..cc438d7c0d2 100644
> --- a/target/riscv/tcg/meson.build
> +++ b/target/riscv/tcg/meson.build
> @@ -15,7 +15,8 @@ riscv_ss.add(files(
>    'vcrypto_helper.c',
>    'vector_helper.c',
>    'vector_internals.c',
> -  'zce_helper.c'))
> +  'zce_helper.c',
> +  'psimd_helper.c'))
>  
>  
>  riscv_system_ss.add(files(
> diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
> new file mode 100644
> index 00000000000..2948bbb2a86
> --- /dev/null
> +++ b/target/riscv/tcg/psimd_helper.c
> @@ -0,0 +1,1656 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/* RISC-V Packed SIMD Extension Helpers for QEMU. */
> +/* Copyright (C) 2026 ISRC ISCAS. */
> +
> +#include "qemu/osdep.h"
> +#include "cpu.h"
> +#include "qemu/host-utils.h"
> +#include "exec/helper-proto.h"
> +#include "fpu/softfloat.h"
> +#include "internals.h"
> +
> +
> +/* Helper macros */
> +
> +/* Element count calculations */
> +#define ELEMS_B(target) (sizeof(target) * 8 / 8)    /* byte elements count */
> +#define ELEMS_H(target) (sizeof(target) * 8 / 16)
> +#define ELEMS_W(target) (sizeof(target) * 8 / 32)   /* word elements count */
> +#define ELEMS_D(target) (sizeof(target) * 8 / 64)
> +
> +/* Element extraction macros - unsigned to avoid sign extension */
> +#define EXTRACT8(val, idx)  (((val) >> ((idx) * 8)) & 0xFF)
> +#define EXTRACT16(val, idx) (((val) >> ((idx) * 16)) & 0xFFFF)
> +#define EXTRACT32(val, idx) (((val) >> ((idx) * 32)) & 0xFFFFFFFF)
> +#define EXTRACT64(val, idx) (((val) >> ((idx) * 64)) & 0xFFFFFFFFFFFFFFFFULL)
> +
QEMU has the generator bit-operation helper macros. I believe you don't need to
define them again, so you can just follow this header file path.

path: include/qemu/bitops.h

```
  extract8(value, start, length)
  extract16(value, start, length)
  extract32(value, start, length)
  extract64(value, start, length)

  sextract32(value, start, length)
  sextract64(value, start, length)
```

So we can redefine these helper macros like this:

```
  #define EXTRACT_B(val, idx) extract64((val), (idx) * 8, 8)
  #define EXTRACT_H(val, idx) extract64((val), (idx) * 16, 16)
  #define EXTRACT_W(val, idx) extract64((val), (idx) * 32, 32)
  #define EXTRACT_D(val, idx) extract64((val), (idx) * 64, 64)
```

> +/* Element insertion macros */
> +#define INSERT8(val, res, idx) \
> +    ((val) | ((target_ulong)(uint8_t)(res) << ((idx) * 8)))
> +#define INSERT16(val, res, idx) \
> +    ((val) | ((target_ulong)(uint16_t)(res) << ((idx) * 16)))
> +#define INSERT32(val, res, idx) \
> +    ((val) | ((target_ulong)(uint32_t)(res) << ((idx) * 32)))
> +#define INSERT32_64(val, res, idx) \
> +    ((val) | ((uint64_t)(uint32_t)(res) << ((idx) * 32)))
> +#define INSERT64(val, res, idx) \
> +    ((val) | ((uint64_t)(res) << ((idx) * 64)))
> +
> +/* Saturation constants */
> +static const int8_t   SAT_MAX_B = 127;
> +static const int8_t   SAT_MIN_B = -128;
> +static const int16_t  SAT_MAX_H = 32767;
> +static const int16_t  SAT_MIN_H = -32768;
> +static const int32_t  SAT_MAX_W = 2147483647;
> +static const int32_t  SAT_MIN_W = -2147483648LL;
> +static const uint8_t  USAT_MAX_B = 255;
> +static const uint16_t USAT_MAX_H = 65535;
> +static const uint32_t USAT_MAX_W = 4294967295U;
> +
> +
> +/* Saturation helper functions */
> +
> +/**
> + * Signed saturation for 8-bit elements
> + * Returns saturated value and sets *sat if saturation occurred
> + */
This helper function has some comments that explain what it does.
I believe we don't need these explanations if the function name is
already clear.

The other helper functions below are similar. I think we only need
to add comments when it's necessary to explain the reasoning behind
why we're doing something.

d> +static inline int8_t signed_saturate_b(int32_t val, int *sat)
> +{
> +    if (val > SAT_MAX_B) {
> +        *sat = 1;
> +        return SAT_MAX_B;
> +    }
> +    if (val < SAT_MIN_B) {
> +        *sat = 1;
> +        return SAT_MIN_B;
> +    }
> +    return (int8_t)val;
> +}
> +
> +/**
> + * Signed saturation for 16-bit elements
> + */
> +static inline int16_t signed_saturate_h(int32_t val, int *sat)
> +{
> +    if (val > SAT_MAX_H) {
> +        *sat = 1;
> +        return SAT_MAX_H;
> +    }
> +    if (val < SAT_MIN_H) {
> +        *sat = 1;
> +        return SAT_MIN_H;
> +    }
> +    return (int16_t)val;
> +}
> +
> +/**
> + * Signed saturation for 32-bit elements
> + */
> +static inline int32_t signed_saturate_w(int64_t val, int *sat)
> +{
> +    if (val > SAT_MAX_W) {
> +        *sat = 1;
> +        return SAT_MAX_W;
> +    }
> +    if (val < SAT_MIN_W) {
> +        *sat = 1;
> +        return SAT_MIN_W;
> +    }
> +    return (int32_t)val;
> +}
> +
> +/**
> + * Unsigned saturation for 8-bit elements
> + */
> +static inline uint8_t unsigned_saturate_b(uint32_t val, int *sat)
> +{
> +    if (val > USAT_MAX_B) {
> +        *sat = 1;
> +        return USAT_MAX_B;
> +    }
> +    return (uint8_t)val;
> +}
> +
> +/**
> + * Unsigned saturation for 16-bit elements
> + */
> +static inline uint16_t unsigned_saturate_h(uint32_t val, int *sat)
> +{
> +    if (val > USAT_MAX_H) {
> +        *sat = 1;
> +        return USAT_MAX_H;
> +    }
> +    return (uint16_t)val;
> +}
> +
> +/**
> + * Unsigned saturation for 32-bit elements
> + */
> +static inline uint32_t unsigned_saturate_w(uint64_t val, int *sat)
> +{
> +    if (val > USAT_MAX_W) {
> +        *sat = 1;
> +        return USAT_MAX_W;
> +    }
> +    return (uint32_t)val;
> +}
> +
> +static inline target_ulong psimd_abdsumu_b(target_ulong rs1,
> +                                           target_ulong rs2,
> +                                           target_ulong sum)
> +{
> +    int elems = ELEMS_B(rs1);
> +
> +    for (int i = 0; i < elems; i++) {
> +        uint8_t e1 = EXTRACT8(rs1, i);
> +        uint8_t e2 = EXTRACT8(rs2, i);
> +        uint8_t diff = (e1 > e2) ? (e1 - e2) : (e2 - e1);
> +        sum += diff;
> +    }
> +
> +    return sum;
> +}
> +
> +#define PSIMD_DO_ADD(N, M) ((N) + (M))
> +#define PSIMD_DO_SUB(N, M) ((N) - (M))
> +#define PSIMD_DO_ABD(N, M) ((N) >= (M) ? (N) - (M) : (M) - (N))
> +#define PSIMD_DO_EQ_MASK(N, M) ((N) == (M) ? -1 : 0)
> +#define PSIMD_DO_LT_MASK(N, M) ((N) < (M) ? -1 : 0)
> +#define PSIMD_DO_MIN(N, M) ((N) < (M) ? (N) : (M))
> +#define PSIMD_DO_MAX(N, M) ((N) > (M) ? (N) : (M))
> +#define PSIMD_DO_SLL(N, M) ((N) << (M))
> +#define PSIMD_DO_SRL(N, M) ((N) >> (M))
> +#define PSIMD_DO_SRA(N, M) ((N) >> (M))
> +

[...]

> +
> +#define GEN_PSIMD_SCALAR_ABS(NAME, RTYPE, STYPE, UTYPE)                   \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1)                         \
> +{                                                                         \
> +    STYPE value = (STYPE)rs1;                                            \
> +    UTYPE result = (UTYPE)value;                                         \
> +                                                                          \
> +    if (value < 0) {                                                      \
> +        result = (UTYPE)0 - result;                                      \
> +    }                                                                     \
> +    return (RTYPE)(STYPE)result;                                         \
> +}
The '\' for the column widths aren't aligned here. It would
look much better if we could align them consistently throughout.

[...]

> +uint64_t HELPER(NAME)(CPURISCVState *env, uint64_t rs1, uint64_t rs2)     \
> +{                                                                         \
> +    int64_t a = (int64_t)rs1;                                            \
> +    int8_t shamt = (int8_t)(rs2 & 0xff);                                 \
> +                                                                          \
> +    if (shamt >= 0) {                                                     \
> +        return (uint64_t)(a << shamt);                                    \
> +    }                                                                     \
> +                                                                          \
> +    int right = -shamt;                                                   \
> +    if (right >= 64) {                                                    \
> +        return (a < 0) ? (uint64_t)-1 : 0;                               \
> +    }                                                                     \
> +    return (uint64_t)RIGHT_OP(a, right);                                  \
> +}
There are similar alignment issues here.

> +
> +#define PSIMD_DO_SRL64(A, B) (((B) >= 64) ? 0 : ((A) >> (B)))
> +#define PSIMD_DO_RNDSRL64(A, B)                                          \
> +    (((B) > 64) ? 0 : ((((A) >> ((B) - 1)) + 1) >> 1))
> +
> +#define GEN_PSIMD_VAR_SRL64(NAME, RIGHT_OP)                               \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint64_t rs1, uint64_t rs2)     \
> +{                                                                         \
> +    int8_t shamt = (int8_t)(rs2 & 0xff);                                 \
> +                                                                          \
> +    if (shamt < 0) {                                                      \
> +        return RIGHT_OP(rs1, -shamt);                                     \
> +    }                                                                     \
> +    return (shamt >= 64) ? 0 : (rs1 << shamt);                           \
> +}
> +
Same here.You can check again for the patches.

Thanks,
Chao


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH v2 03/18] target/riscv: Add packed SIMD arithmetic instructions
  2026-07-17 10:06 ` [PATCH v2 03/18] target/riscv: Add packed SIMD arithmetic instructions Molly Chen
  2026-07-26 22:05   ` Daniel Henrique Barboza
  2026-07-29  6:17   ` Nutty.Liu
@ 2026-07-29  9:27   ` Chao Liu
  2 siblings, 0 replies; 34+ messages in thread
From: Chao Liu @ 2026-07-29  9:27 UTC (permalink / raw)
  To: Molly Chen
  Cc: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
	Chao Liu, qemu-riscv, qemu-devel

On Fri, Jul 17, 2026 at 10:06:56AM +0800, Molly Chen wrote:
> Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
I think we need to add a commit body to explain what the patch does.

Thanks,
Chao
> ---
>  target/riscv/helper.h                       |  41 ++
>  target/riscv/insn32.decode                  |  63 +++
>  target/riscv/tcg/insn_trans/trans_rvp.c.inc | 547 ++++++++++++++++++++
>  target/riscv/tcg/psimd_helper.c             | 114 ++++
>  target/riscv/tcg/translate.c                |   4 +
>  5 files changed, 769 insertions(+)
>  create mode 100644 target/riscv/tcg/insn_trans/trans_rvp.c.inc
> 
> diff --git a/target/riscv/helper.h b/target/riscv/helper.h
> index 542b7c264fc..eebb2febd95 100644
> --- a/target/riscv/helper.h
> +++ b/target/riscv/helper.h
> @@ -1358,3 +1358,44 @@ DEF_HELPER_1(ssamoswap_disabled, void, env)
>  
>  /* Zalrsc SC write probe */
>  DEF_HELPER_FLAGS_3(sc_probe_write, TCG_CALL_NO_WG, void, env, tl, tl)
> +
> +/* Packed SIMD */
> +/* Packed SIMD - Arithmetic Operations(Non-Saturating and Saturating) */
> +DEF_HELPER_3(padd_b, tl, env, tl, tl)
> +DEF_HELPER_3(padd_h, tl, env, tl, tl)
> +DEF_HELPER_3(padd_w, i64, env, i64, i64)
> +DEF_HELPER_3(padd_bs, tl, env, tl, tl)
> +DEF_HELPER_3(padd_hs, tl, env, tl, tl)
> +DEF_HELPER_3(padd_ws, i64, env, i64, i64)
> +DEF_HELPER_3(psub_b, tl, env, tl, tl)
> +DEF_HELPER_3(psub_h, tl, env, tl, tl)
> +DEF_HELPER_3(psub_w, i64, env, i64, i64)
> +DEF_HELPER_3(psh1add_h, tl, env, tl, tl)
> +DEF_HELPER_3(psh1add_w, i64, env, i64, i64)
> +DEF_HELPER_3(pssh1sadd_h, tl, env, tl, tl)
> +DEF_HELPER_3(pssh1sadd_w, i64, env, i64, i64)
> +DEF_HELPER_3(ssh1sadd, i32, env, i32, i32)
> +DEF_HELPER_3(psadd_b, tl, env, tl, tl)
> +DEF_HELPER_3(psadd_h, tl, env, tl, tl)
> +DEF_HELPER_3(psadd_w, i64, env, i64, i64)
> +DEF_HELPER_3(psaddu_b, tl, env, tl, tl)
> +DEF_HELPER_3(psaddu_h, tl, env, tl, tl)
> +DEF_HELPER_3(psaddu_w, i64, env, i64, i64)
> +DEF_HELPER_3(sadd, i32, env, i32, i32)
> +DEF_HELPER_3(saddu, i32, env, i32, i32)
> +DEF_HELPER_3(pssub_b, tl, env, tl, tl)
> +DEF_HELPER_3(pssub_h, tl, env, tl, tl)
> +DEF_HELPER_3(pssub_w, i64, env, i64, i64)
> +DEF_HELPER_3(pssubu_b, tl, env, tl, tl)
> +DEF_HELPER_3(pssubu_h, tl, env, tl, tl)
> +DEF_HELPER_3(pssubu_w, i64, env, i64, i64)
> +DEF_HELPER_3(ssub, i32, env, i32, i32)
> +DEF_HELPER_3(ssubu, i32, env, i32, i32)
> +DEF_HELPER_3(psati_h, tl, env, tl, tl)
> +DEF_HELPER_3(pusati_h, tl, env, tl, tl)
> +DEF_HELPER_3(psati_w, i64, env, i64, i64)
> +DEF_HELPER_3(pusati_w, i64, env, i64, i64)
> +DEF_HELPER_3(sati_32, i32, env, i32, i32)
> +DEF_HELPER_3(usati_32, i32, env, i32, i32)
> +DEF_HELPER_3(sati_64, i64, env, i64, i64)
> +DEF_HELPER_3(usati_64, i64, env, i64, i64)
> diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
> index 21272fdb504..8da13669d73 100644
> --- a/target/riscv/insn32.decode
> +++ b/target/riscv/insn32.decode
> @@ -40,6 +40,9 @@
>  %imm_z6   26:1 15:5
>  %imm_mop5 30:1 26:2 20:2
>  %imm_mop3 30:1 26:2
> +%imm_p_ui16 20:4
> +%imm_p_ui32 20:5
> +%imm_p_ui64 20:6
>  
>  # Argument sets:
>  &empty
> @@ -60,6 +63,7 @@
>  &k_aes     shamt rs2 rs1 rd
>  &mop5 imm rd rs1
>  &mop3 imm rd rs1 rs2
> +&p_ui imm rs1 rd
>  
>  # Formats 32:
>  @r       .......   ..... ..... ... ..... ....... &r                %rs2 %rs1 %rd
> @@ -105,6 +109,10 @@
>  @mop5 . . .. .. .... .. ..... ... ..... ....... &mop5 imm=%imm_mop5 %rd %rs1
>  @mop3 . . .. .. . ..... ..... ... ..... ....... &mop3 imm=%imm_mop3 %rd %rs1 %rs2
>  
> +@p_ui16 ..... .... ... ..... ... ..... ....... &i imm=%imm_p_ui16 %rs1 %rd
> +@p_ui32 ..... .... ... ..... ... ..... ....... &i imm=%imm_p_ui32 %rs1 %rd
> +@p_ui64 ..... .... ... ..... ... ..... ....... &i imm=%imm_p_ui64 %rs1 %rd
> +
>  # Formats 64:
>  @sh5     .......  ..... .....  ... ..... ....... &shift  shamt=%sh5      %rs1 %rd
>  
> @@ -1084,3 +1092,58 @@ sb_aqrl  00111 . . ..... ..... 000 ..... 0101111 @atom_st
>  sh_aqrl  00111 . . ..... ..... 001 ..... 0101111 @atom_st
>  sw_aqrl  00111 . . ..... ..... 010 ..... 0101111 @atom_st
>  sd_aqrl  00111 . . ..... ..... 011 ..... 0101111 @atom_st
> +
> +# *** P Experimental Extension Version v020 ***
> +# Packed SIMD - Arithmetic Operations(Non-Saturating and Saturating)
> +padd_b     1000010 ..... ..... 000 ..... 0111011 @r
> +padd_h     1000000 ..... ..... 000 ..... 0111011 @r
> +padd_w     1000001 ..... ..... 000 ..... 0111011 @r
> +padd_bs    1001110 ..... ..... 010 ..... 0011011 @r
> +padd_hs    1001100 ..... ..... 010 ..... 0011011 @r
> +padd_ws    1001101 ..... ..... 010 ..... 0011011 @r
> +psub_b     1100010 ..... ..... 000 ..... 0111011 @r
> +psub_h     1100000 ..... ..... 000 ..... 0111011 @r
> +psub_w     1100001 ..... ..... 000 ..... 0111011 @r
> +psh1add_h  1010000 ..... ..... 010 ..... 0111011 @r
> +psh1add_w  1010001 ..... ..... 010 ..... 0111011 @r
> +pssh1sadd_h   1011000 ..... ..... 010 ..... 0111011 @r
> +{
> +  ssh1sadd    1011001 ..... ..... 010 ..... 0111011 @r
> +  pssh1sadd_w 1011001 ..... ..... 010 ..... 0111011 @r
> +}
> +psadd_b    1001010 ..... ..... 000 ..... 0111011 @r
> +psadd_h    1001000 ..... ..... 000 ..... 0111011 @r
> +{
> +  sadd     1001001 ..... ..... 000 ..... 0111011 @r
> +  psadd_w  1001001 ..... ..... 000 ..... 0111011 @r
> +}
> +psaddu_b   1011010 ..... ..... 000 ..... 0111011 @r
> +psaddu_h   1011000 ..... ..... 000 ..... 0111011 @r
> +{
> +  saddu    1011001 ..... ..... 000 ..... 0111011 @r
> +  psaddu_w 1011001 ..... ..... 000 ..... 0111011 @r
> +}
> +pssub_b    1101010 ..... ..... 000 ..... 0111011 @r
> +pssub_h    1101000 ..... ..... 000 ..... 0111011 @r
> +{
> +  ssub     1101001 ..... ..... 000 ..... 0111011 @r
> +  pssub_w  1101001 ..... ..... 000 ..... 0111011 @r
> +}
> +pssubu_b   1111010 ..... ..... 000 ..... 0111011 @r
> +pssubu_h   1111000 ..... ..... 000 ..... 0111011 @r
> +{
> +  ssubu      1111001 ..... ..... 000 ..... 0111011 @r
> +  pssubu_w   1111001 ..... ..... 000 ..... 0111011 @r
> +}
> +psati_h    11100 001.... ..... 100 ..... 0011011 @p_ui16
> +pusati_h   10100 001.... ..... 100 ..... 0011011 @p_ui16
> +{
> +  sati_32  11100 01..... ..... 100 ..... 0011011 @p_ui32
> +  psati_w  11100 01..... ..... 100 ..... 0011011 @p_ui32
> +}
> +{
> +  usati_32 10100 01..... ..... 100 ..... 0011011 @p_ui32
> +  pusati_w 10100 01..... ..... 100 ..... 0011011 @p_ui32
> +}
> +sati_64    111001 ...... ..... 100 ..... 0011011 @p_ui64
> +usati_64   101001 ...... ..... 100 ..... 0011011 @p_ui64
> diff --git a/target/riscv/tcg/insn_trans/trans_rvp.c.inc b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
> new file mode 100644
> index 00000000000..056ccfb486e
> --- /dev/null
> +++ b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
> @@ -0,0 +1,547 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/* RISC-V translation routines for the P Standard Extensions. */
> +/* Copyright (c) 2026 ISRC ISCAS. */
> +
> +/* Save a 64 bit data in src to dst and dst + 1 */
> +
> +static bool require_rvp(DisasContext *ctx)
> +{
> +    uint32_t opcode = ctx->opcode & 0x7f;
> +
> +    if (!has_ext(ctx, RVP)) {
> +        return false;
> +    }
> +
> +    /*
> +     * P_VXSAT_EXCP is encoded in the TB flags only when P is implemented
> +     * without Zve*, where stateen0.VXSAT controls the whole OP-32 and
> +     * OP-IMM-32 P instruction spaces.  When Zve* is present, this field
> +     * remains NONE and vxsat access is checked by the VS path instead.
> +     */
> +    if ((opcode == 0x3b || opcode == 0x1b) &&
> +        ctx->p_vxsat_excp != P_VXSAT_EXCP_NONE) {
> +        ctx->virt_inst_excp =
> +            ctx->p_vxsat_excp == P_VXSAT_EXCP_VIRTUAL;
> +        return false;
> +    }
> +
> +    return true;
> +}
> +
> +static bool prepare_rvp_vxsat(DisasContext *ctx)
> +{
> +    if (!ctx->cfg_ptr->ext_zve32x) {
> +        return true;
> +    }
> +
> +    if (ctx->mstatus_vs == EXT_STATUS_DISABLED) {
> +        return false;
> +    }
> +
> +    mark_vs_dirty(ctx);
> +    return true;
> +}
> +
> +#define REQUIRE_RVP(ctx) do {             \
> +    if (!require_rvp(ctx)) {              \
> +        return false;                     \
> +    }                                     \
> +} while (0)
> +
> +#define GEN_SIMD_TRANS_BODY(NAME, VXSAT)                    \
> +do {                                                        \
> +    REQUIRE_RVP(ctx);                                       \
> +    if (VXSAT && !prepare_rvp_vxsat(ctx)) {                 \
> +        return false;                                       \
> +    }                                                       \
> +    TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE);             \
> +    TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE);             \
> +    TCGv dest = dest_gpr(ctx, a->rd);                       \
> +    gen_helper_##NAME(dest, tcg_env, src1, src2);           \
> +    gen_set_gpr(ctx, a->rd, dest);                          \
> +    return true;                                            \
> +} while (0)
> +
> +#define GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)                 \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_32BIT(ctx);                                     \
> +    return true;                                           \
> +}
> +
> +#define GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)                 \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_64BIT(ctx);                                     \
> +    return true;                                           \
> +}
> +
> +#define GEN_SIMD_TRANS(NAME)                                \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    GEN_SIMD_TRANS_BODY(NAME, false);                       \
> +}
> +
> +#define GEN_SIMD_TRANS_VXSAT(NAME)                         \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    GEN_SIMD_TRANS_BODY(NAME, true);                        \
> +}
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_32(NAME)                             \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a)  \
> +{                                                           \
> +    REQUIRE_32BIT(ctx);                                     \
> +    GEN_SIMD_TRANS_BODY(NAME, false);                       \
> +}
> +#define GEN_SIMD_TRANS_32_VXSAT(NAME)                      \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_32BIT(ctx);                                     \
> +    GEN_SIMD_TRANS_BODY(NAME, true);                        \
> +}
> +#else
> +#define GEN_SIMD_TRANS_32(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#define GEN_SIMD_TRANS_32_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_64(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
> +#define GEN_SIMD_TRANS_64_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
> +#else
> +#define GEN_SIMD_TRANS_64(NAME)                             \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a)  \
> +{                                                           \
> +    REQUIRE_64BIT(ctx);                                     \
> +    GEN_SIMD_TRANS_BODY(NAME, false);                       \
> +}
> +#define GEN_SIMD_TRANS_64_VXSAT(NAME)                      \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_64BIT(ctx);                                     \
> +    GEN_SIMD_TRANS_BODY(NAME, true);                        \
> +}
> +#endif
> +
> +#define GEN_SIMD_TRANS_ACC_BODY(NAME, VXSAT)                \
> +do {                                                        \
> +    REQUIRE_RVP(ctx);                                       \
> +    if (VXSAT && !prepare_rvp_vxsat(ctx)) {                 \
> +        return false;                                       \
> +    }                                                       \
> +    TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE);             \
> +    TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE);             \
> +    TCGv dest = dest_gpr(ctx, a->rd);                       \
> +    TCGv t = tcg_temp_new();                                \
> +    gen_helper_##NAME(t, tcg_env, src1, src2, dest);        \
> +    gen_set_gpr(ctx, a->rd, t);                             \
> +    return true;                                            \
> +} while (0)
> +
> +#define GEN_SIMD_TRANS_ACC(NAME)                            \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    GEN_SIMD_TRANS_ACC_BODY(NAME, false);                   \
> +}
> +
> +#define GEN_SIMD_TRANS_ACC_VXSAT(NAME)                     \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    GEN_SIMD_TRANS_ACC_BODY(NAME, true);                    \
> +}
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_ACC_32(NAME)                         \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_32BIT(ctx);                                     \
> +    GEN_SIMD_TRANS_ACC_BODY(NAME, false);                   \
> +}
> +#else
> +#define GEN_SIMD_TRANS_ACC_32(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_ACC_64(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
> +#else
> +#define GEN_SIMD_TRANS_ACC_64(NAME)                         \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_64BIT(ctx);                                     \
> +    GEN_SIMD_TRANS_ACC_BODY(NAME, false);                   \
> +}
> +#endif
> +
> +#define GEN_SIMD_TRANS_R1_BODY(NAME, VXSAT)                 \
> +do {                                                        \
> +    REQUIRE_RVP(ctx);                                       \
> +    if (VXSAT && !prepare_rvp_vxsat(ctx)) {                 \
> +        return false;                                       \
> +    }                                                       \
> +    TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE);             \
> +    TCGv dest = dest_gpr(ctx, a->rd);                       \
> +    gen_helper_##NAME(dest, tcg_env, src1);                 \
> +    gen_set_gpr(ctx, a->rd, dest);                          \
> +    return true;                                            \
> +} while (0)
> +
> +#define GEN_SIMD_TRANS_R1(NAME)                             \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    GEN_SIMD_TRANS_R1_BODY(NAME, false);                    \
> +}
> +
> +#define GEN_SIMD_TRANS_R1_VXSAT(NAME)                      \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    GEN_SIMD_TRANS_R1_BODY(NAME, true);                     \
> +}
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_R1_64(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
> +#define GEN_SIMD_TRANS_R1_64_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
> +#else
> +#define GEN_SIMD_TRANS_R1_64(NAME)                          \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_64BIT(ctx);                                     \
> +    GEN_SIMD_TRANS_R1_BODY(NAME, false);                    \
> +}
> +#define GEN_SIMD_TRANS_R1_64_VXSAT(NAME)                   \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_64BIT(ctx);                                     \
> +    GEN_SIMD_TRANS_R1_BODY(NAME, true);                     \
> +}
> +#endif
> +
> +#define GEN_SIMD_TRANS_IMM_BODY(NAME, VXSAT)                \
> +do {                                                        \
> +    REQUIRE_RVP(ctx);                                       \
> +    if (VXSAT && !prepare_rvp_vxsat(ctx)) {                 \
> +        return false;                                       \
> +    }                                                       \
> +    TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE);             \
> +    TCGv imm = tcg_constant_tl(a->imm);                     \
> +    TCGv dest = dest_gpr(ctx, a->rd);                       \
> +    gen_helper_##NAME(dest, tcg_env, src1, imm);            \
> +    gen_set_gpr(ctx, a->rd, dest);                          \
> +    return true;                                            \
> +} while (0)
> +
> +#define GEN_SIMD_TRANS_IMM(NAME)                            \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    GEN_SIMD_TRANS_IMM_BODY(NAME, false);                   \
> +}
> +
> +#define GEN_SIMD_TRANS_IMM_VXSAT(NAME)                     \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    GEN_SIMD_TRANS_IMM_BODY(NAME, true);                    \
> +}
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_IMM_32(NAME)                         \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_32BIT(ctx);                                     \
> +    GEN_SIMD_TRANS_IMM_BODY(NAME, false);                   \
> +}
> +#define GEN_SIMD_TRANS_IMM_32_VXSAT(NAME)                  \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_32BIT(ctx);                                     \
> +    GEN_SIMD_TRANS_IMM_BODY(NAME, true);                    \
> +}
> +#else
> +#define GEN_SIMD_TRANS_IMM_32(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#define GEN_SIMD_TRANS_IMM_32_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_IMM_64(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
> +#define GEN_SIMD_TRANS_IMM_64_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
> +#else
> +#define GEN_SIMD_TRANS_IMM_64(NAME)                         \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_64BIT(ctx);                                     \
> +    GEN_SIMD_TRANS_IMM_BODY(NAME, false);                   \
> +}
> +#define GEN_SIMD_TRANS_IMM_64_VXSAT(NAME)                  \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_64BIT(ctx);                                     \
> +    GEN_SIMD_TRANS_IMM_BODY(NAME, true);                    \
> +}
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_REG_PAIR_SCALAR_OP(NAME, SRC2)       \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_32BIT(ctx);                                     \
> +    REQUIRE_RVP(ctx);                                       \
> +    TCGv_i32 src1 = get_gpr(ctx, a->rs1, EXT_NONE);         \
> +    TCGv_i32 src2 = SRC2;                                   \
> +    TCGv_i64 t = tcg_temp_new_i64();                        \
> +    gen_helper_##NAME(t, tcg_env, src1, src2);              \
> +    set_pair_regs(ctx, (a->rd) * 2, t);                     \
> +    return true;                                            \
> +}
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_SCALAR(NAME) \
> +    GEN_SIMD_TRANS_REG_PAIR_SCALAR_OP(NAME, get_gpr(ctx, a->rs2, EXT_NONE))
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_SCALAR_IMM(NAME) \
> +    GEN_SIMD_TRANS_REG_PAIR_SCALAR_OP(NAME, tcg_constant_i32(a->imm))
> +#else
> +#define GEN_SIMD_TRANS_REG_PAIR_SCALAR(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#define GEN_SIMD_TRANS_REG_PAIR_SCALAR_IMM(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_REG_PAIR_OP(INSN, HELPER, SRC2_0, SRC2_1, VXSAT) \
> +static bool trans_##INSN(DisasContext *ctx, arg_##INSN * a)       \
> +{                                                                 \
> +    REQUIRE_32BIT(ctx);                                           \
> +    REQUIRE_RVP(ctx);                                             \
> +    if (VXSAT && !prepare_rvp_vxsat(ctx)) {                       \
> +        return false;                                             \
> +    }                                                             \
> +    TCGv src1_0 = get_gpr(ctx, (a->rs1) * 2, EXT_NONE);           \
> +    TCGv src2_0 = SRC2_0;                                         \
> +    TCGv dest_0 = dest_gpr(ctx, (a->rd) * 2);                     \
> +    TCGv src1_1 = get_gpr(ctx, (a->rs1) * 2 + 1, EXT_NONE);       \
> +    TCGv src2_1 = SRC2_1;                                         \
> +    TCGv dest_1 = dest_gpr(ctx, (a->rd) * 2 + 1);                 \
> +    gen_helper_##HELPER(dest_0, tcg_env, src1_0, src2_0);         \
> +    gen_helper_##HELPER(dest_1, tcg_env, src1_1, src2_1);         \
> +    gen_set_gpr(ctx, (a->rd) * 2, dest_0);                        \
> +    gen_set_gpr(ctx, (a->rd) * 2 + 1, dest_1);                    \
> +    return true;                                                  \
> +}
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE(INSN, HELPER)                   \
> +    GEN_SIMD_TRANS_REG_PAIR_OP(INSN, HELPER,                       \
> +        get_gpr(ctx, (a->rs2) * 2, EXT_NONE),                     \
> +        get_gpr(ctx, (a->rs2) * 2 + 1, EXT_NONE), false)
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(INSN, HELPER)            \
> +    GEN_SIMD_TRANS_REG_PAIR_OP(INSN, HELPER,                       \
> +        get_gpr(ctx, (a->rs2) * 2, EXT_NONE),                     \
> +        get_gpr(ctx, (a->rs2) * 2 + 1, EXT_NONE), true)
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_IMM(INSN, HELPER)               \
> +    GEN_SIMD_TRANS_REG_PAIR_OP(INSN, HELPER,                       \
> +        tcg_constant_tl(a->imm), tcg_constant_tl(a->imm), false)
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_IMM_VXSAT(INSN, HELPER)        \
> +    GEN_SIMD_TRANS_REG_PAIR_OP(INSN, HELPER,                       \
> +        tcg_constant_tl(a->imm), tcg_constant_tl(a->imm), true)
> +#else
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE(INSN, HELPER) \
> +    GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(INSN, HELPER) \
> +    GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_IMM(INSN, HELPER) \
> +    GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_IMM_VXSAT(INSN, HELPER) \
> +    GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_OP(INSN, HELPER, VXSAT)     \
> +static bool trans_##INSN(DisasContext *ctx, arg_##INSN * a)    \
> +{                                                              \
> +    REQUIRE_32BIT(ctx);                                        \
> +    REQUIRE_RVP(ctx);                                          \
> +    if (VXSAT && !prepare_rvp_vxsat(ctx)) {                    \
> +        return false;                                          \
> +    }                                                          \
> +    TCGv src1_0 = get_gpr(ctx, (a->rs1) * 2, EXT_NONE);        \
> +    TCGv dest_0 = dest_gpr(ctx, (a->rd) * 2);                    \
> +    TCGv src1_1 = get_gpr(ctx, (a->rs1) * 2 + 1, EXT_NONE);        \
> +    TCGv dest_1 = dest_gpr(ctx, (a->rd) * 2 + 1);                  \
> +    TCGv src2   = get_gpr(ctx, a->rs2, EXT_NONE);              \
> +    gen_helper_##HELPER(dest_0, tcg_env, src1_0, src2);        \
> +    gen_helper_##HELPER(dest_1, tcg_env, src1_1, src2);        \
> +    gen_set_gpr(ctx, (a->rd) * 2, dest_0);                     \
> +    gen_set_gpr(ctx, (a->rd) * 2 + 1, dest_1);                 \
> +    return true;                                              \
> +}
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR(INSN, HELPER)              \
> +    GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_OP(INSN, HELPER, false)
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_VXSAT(INSN, HELPER)       \
> +    GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_OP(INSN, HELPER, true)
> +#else
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR(INSN, HELPER) \
> +    GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_VXSAT(INSN, HELPER) \
> +    GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_OP(INSN, HELPER, VXSAT)     \
> +static bool trans_##INSN(DisasContext *ctx, arg_##INSN * a)    \
> +{                                                              \
> +    REQUIRE_RVP(ctx);                                          \
> +    if (VXSAT && !prepare_rvp_vxsat(ctx)) {                    \
> +        return false;                                          \
> +    }                                                          \
> +    TCGv src1_0 = get_gpr(ctx, (a->rs1) * 2, EXT_NONE);        \
> +    TCGv dest_0 = dest_gpr(ctx, (a->rd) * 2);                  \
> +    TCGv src1_1 = get_gpr(ctx, (a->rs1) * 2 + 1, EXT_NONE);    \
> +    TCGv dest_1 = dest_gpr(ctx, (a->rd) * 2 + 1);              \
> +    gen_helper_##HELPER(dest_0, tcg_env, src1_0);              \
> +    gen_helper_##HELPER(dest_1, tcg_env, src1_1);              \
> +    gen_set_gpr(ctx, (a->rd) * 2, dest_0);                     \
> +    gen_set_gpr(ctx, (a->rd) * 2 + 1, dest_1);                 \
> +    return true;                                               \
> +}
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY(INSN, HELPER)               \
> +    GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_OP(INSN, HELPER, false)
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_VXSAT(INSN, HELPER)        \
> +    GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_OP(INSN, HELPER, true)
> +#else
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY(INSN, HELPER) \
> +    GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_VXSAT(INSN, HELPER) \
> +    GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_REG_PAIR_ACC(NAME)                   \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_32BIT(ctx);                                     \
> +    REQUIRE_RVP(ctx);                                       \
> +    TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE);             \
> +    TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE);             \
> +    TCGv_i64 t = tcg_temp_new_i64();                        \
> +    if (a->rd == 0) {                                         \
> +        tcg_gen_movi_i64(t, 0);                             \
> +    } else {                                                  \
> +        get_pair_regs(ctx, t, (a->rd) * 2);                   \
> +    }                                                       \
> +    gen_helper_##NAME(t, tcg_env, src1, src2, t);           \
> +    set_pair_regs(ctx, (a->rd) * 2, t);                       \
> +    return true;                                           \
> +}
> +#else
> +#define GEN_SIMD_TRANS_REG_PAIR_ACC(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_REG_PAIR_PREDSUM(NAME)               \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_32BIT(ctx);                                     \
> +    REQUIRE_RVP(ctx);                                       \
> +    TCGv_i32 src1_l;                                        \
> +    TCGv_i32 src1_h;                                        \
> +    TCGv_i32 src2 = get_gpr(ctx, a->rs2, EXT_NONE);         \
> +    TCGv_i32 dest = dest_gpr(ctx, a->rd);                   \
> +    if (a->rs1 == 0) {                                        \
> +        src1_l = tcg_temp_new_i32();                        \
> +        src1_h = tcg_temp_new_i32();                        \
> +        tcg_gen_movi_i32(src1_l, 0);                        \
> +        tcg_gen_movi_i32(src1_h, 0);                        \
> +    } else {                                                  \
> +        src1_l = get_gpr(ctx, (a->rs1) * 2, EXT_NONE);        \
> +        src1_h = get_gpr(ctx, (a->rs1) * 2 + 1, EXT_NONE);      \
> +    }                                                       \
> +    gen_helper_##NAME(dest, tcg_env, src1_l, src1_h, src2); \
> +    gen_set_gpr(ctx, a->rd, dest);                          \
> +    return true;                                           \
> +}
> +#else
> +#define GEN_SIMD_TRANS_REG_PAIR_PREDSUM(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_PN_OP(NAME, SRC2, VXSAT)            \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{                                                           \
> +    REQUIRE_32BIT(ctx);                                     \
> +    REQUIRE_RVP(ctx);                                       \
> +    if (VXSAT && !prepare_rvp_vxsat(ctx)) {                 \
> +        return false;                                       \
> +    }                                                       \
> +    TCGv_i64 s1 = tcg_temp_new_i64();                       \
> +    if (a->rs1 == 0) {                                      \
> +        tcg_gen_mov_i64(s1, 0);                             \
> +    } else {                                                \
> +        get_pair_regs(ctx, s1, a->rs1 * 2);                 \
> +    }                                                       \
> +    TCGv src2 = SRC2;                                       \
> +    TCGv dest = dest_gpr(ctx, a->rd);                       \
> +    gen_helper_##NAME(dest, tcg_env, s1, src2);             \
> +    gen_set_gpr(ctx, a->rd, dest);                          \
> +    return true;                                            \
> +}
> +
> +#define GEN_SIMD_TRANS_PN_OP_IMM(NAME) \
> +    GEN_SIMD_TRANS_PN_OP(NAME, tcg_constant_tl(a->imm), false)
> +
> +#define GEN_SIMD_TRANS_PN_OP_IMM_VXSAT(NAME) \
> +    GEN_SIMD_TRANS_PN_OP(NAME, tcg_constant_tl(a->imm), true)
> +
> +#define GEN_SIMD_TRANS_PN_OP_REG(NAME) \
> +    GEN_SIMD_TRANS_PN_OP(NAME, get_gpr(ctx, a->rs2, EXT_NONE), false)
> +
> +#define GEN_SIMD_TRANS_PN_OP_REG_VXSAT(NAME) \
> +    GEN_SIMD_TRANS_PN_OP(NAME, get_gpr(ctx, a->rs2, EXT_NONE), true)
> +#else
> +#define GEN_SIMD_TRANS_PN_OP_IMM(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#define GEN_SIMD_TRANS_PN_OP_IMM_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#define GEN_SIMD_TRANS_PN_OP_REG(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#define GEN_SIMD_TRANS_PN_OP_REG_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#endif
> +
> +/* Packed SIMD - Arithmetic Operations(Non-Saturating and Saturating) */
> +GEN_SIMD_TRANS(padd_b)
> +GEN_SIMD_TRANS(padd_h)
> +GEN_SIMD_TRANS_64(padd_w)
> +GEN_SIMD_TRANS(padd_bs)
> +GEN_SIMD_TRANS(padd_hs)
> +GEN_SIMD_TRANS_64(padd_ws)
> +GEN_SIMD_TRANS(psub_b)
> +GEN_SIMD_TRANS(psub_h)
> +GEN_SIMD_TRANS_64(psub_w)
> +GEN_SIMD_TRANS(psh1add_h)
> +GEN_SIMD_TRANS_64(psh1add_w)
> +GEN_SIMD_TRANS_VXSAT(pssh1sadd_h)
> +GEN_SIMD_TRANS_64_VXSAT(pssh1sadd_w)
> +GEN_SIMD_TRANS_32_VXSAT(ssh1sadd)
> +GEN_SIMD_TRANS_VXSAT(psadd_b)
> +GEN_SIMD_TRANS_VXSAT(psadd_h)
> +GEN_SIMD_TRANS_64_VXSAT(psadd_w)
> +GEN_SIMD_TRANS_VXSAT(psaddu_b)
> +GEN_SIMD_TRANS_VXSAT(psaddu_h)
> +GEN_SIMD_TRANS_64_VXSAT(psaddu_w)
> +GEN_SIMD_TRANS_32_VXSAT(sadd)
> +GEN_SIMD_TRANS_32_VXSAT(saddu)
> +GEN_SIMD_TRANS_VXSAT(pssub_b)
> +GEN_SIMD_TRANS_VXSAT(pssub_h)
> +GEN_SIMD_TRANS_64_VXSAT(pssub_w)
> +GEN_SIMD_TRANS_VXSAT(pssubu_b)
> +GEN_SIMD_TRANS_VXSAT(pssubu_h)
> +GEN_SIMD_TRANS_64_VXSAT(pssubu_w)
> +GEN_SIMD_TRANS_32_VXSAT(ssub)
> +GEN_SIMD_TRANS_32_VXSAT(ssubu)
> +GEN_SIMD_TRANS_IMM_VXSAT(psati_h)
> +GEN_SIMD_TRANS_IMM_VXSAT(pusati_h)
> +GEN_SIMD_TRANS_IMM_64_VXSAT(psati_w)
> +GEN_SIMD_TRANS_IMM_64_VXSAT(pusati_w)
> +GEN_SIMD_TRANS_IMM_32_VXSAT(sati_32)
> +GEN_SIMD_TRANS_IMM_32_VXSAT(usati_32)
> +GEN_SIMD_TRANS_IMM_64_VXSAT(sati_64)
> +GEN_SIMD_TRANS_IMM_64_VXSAT(usati_64)
> +
> diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
> index 2948bbb2a86..52c58e0287e 100644
> --- a/target/riscv/tcg/psimd_helper.c
> +++ b/target/riscv/tcg/psimd_helper.c
> @@ -1654,3 +1654,117 @@ uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt)    \
>  
>  /* Basic addition operations (non-saturating) */
>  
> +GEN_PSIMD_BINOP(padd_b, target_ulong, uint8_t, uint8_t,
> +                EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ADD)
> +GEN_PSIMD_BINOP(padd_h, target_ulong, uint16_t, uint16_t,
> +                EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ADD)
> +GEN_PSIMD_BINOP(padd_w, uint64_t, uint32_t, uint32_t,
> +                EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD)
> +
> +GEN_PSIMD_BINOP_SCALAR(padd_bs, target_ulong, uint8_t,
> +                       EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ADD)
> +GEN_PSIMD_BINOP_SCALAR(padd_hs, target_ulong, uint16_t,
> +                       EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ADD)
> +GEN_PSIMD_BINOP_SCALAR(padd_ws, uint64_t, uint32_t,
> +                       EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD)
> +
> +/* Basic subtraction operations (non-saturating) */
> +
> +GEN_PSIMD_BINOP(psub_b, target_ulong, uint8_t, uint8_t,
> +                EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_SUB)
> +GEN_PSIMD_BINOP(psub_h, target_ulong, uint16_t, uint16_t,
> +                EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_SUB)
> +GEN_PSIMD_BINOP(psub_w, uint64_t, uint32_t, uint32_t,
> +                EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_SUB)
> +
> +/* Shift-left-by-one and add operations */
> +
> +GEN_PSIMD_SHADD(psh1add_h, target_ulong, uint16_t,
> +                EXTRACT16, INSERT16, ELEMS_H, 1)
> +GEN_PSIMD_SHADD(psh1add_w, uint64_t, uint32_t,
> +                EXTRACT32, INSERT32, ELEMS_W, 1)
> +
> +GEN_PSIMD_SAT_SHADD(pssh1sadd_h, target_ulong, int16_t, int32_t,
> +                    EXTRACT16, INSERT16, ELEMS_H, 1, -0x4000, 0x3fff,
> +                    SAT_MIN_H, SAT_MAX_H, signed_saturate_h)
> +GEN_PSIMD_SAT_SHADD(pssh1sadd_w, uint64_t, int32_t, int64_t,
> +                    EXTRACT32, INSERT32, ELEMS_W, 1, -0x40000000,
> +                    0x3fffffff, SAT_MIN_W, SAT_MAX_W, signed_saturate_w)
> +
> +GEN_PSIMD_SAT_SHADD(ssh1sadd, uint32_t, int32_t, int64_t,
> +                    EXTRACT32, INSERT32, ELEMS_W, 1, -0x40000000,
> +                    0x3fffffff, SAT_MIN_W, SAT_MAX_W, signed_saturate_w)
> +
> +/* Saturating addition operations */
> +
> +GEN_PSIMD_SAT_BINOP(psadd_b, target_ulong, int8_t, int32_t,
> +                    EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ADD,
> +                    signed_saturate_b)
> +GEN_PSIMD_SAT_BINOP(psadd_h, target_ulong, int16_t, int32_t,
> +                    EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ADD,
> +                    signed_saturate_h)
> +GEN_PSIMD_SAT_BINOP(psadd_w, uint64_t, int32_t, int64_t,
> +                    EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD,
> +                    signed_saturate_w)
> +
> +GEN_PSIMD_SAT_BINOP(psaddu_b, target_ulong, uint8_t, uint32_t,
> +                    EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ADD,
> +                    unsigned_saturate_b)
> +GEN_PSIMD_SAT_BINOP(psaddu_h, target_ulong, uint16_t, uint32_t,
> +                    EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ADD,
> +                    unsigned_saturate_h)
> +GEN_PSIMD_SAT_BINOP(psaddu_w, uint64_t, uint32_t, uint64_t,
> +                    EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD,
> +                    unsigned_saturate_w)
> +
> +GEN_PSIMD_SAT_BINOP(sadd, uint32_t, int32_t, int64_t,
> +                    EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD,
> +                    signed_saturate_w)
> +GEN_PSIMD_SAT_BINOP(saddu, uint32_t, uint32_t, uint64_t,
> +                    EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD,
> +                    unsigned_saturate_w)
> +
> +/* Saturating subtraction operations */
> +
> +GEN_PSIMD_SAT_BINOP(pssub_b, target_ulong, int8_t, int32_t,
> +                    EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_SUB,
> +                    signed_saturate_b)
> +GEN_PSIMD_SAT_BINOP(pssub_h, target_ulong, int16_t, int32_t,
> +                    EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_SUB,
> +                    signed_saturate_h)
> +GEN_PSIMD_SAT_BINOP(pssub_w, uint64_t, int32_t, int64_t,
> +                    EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_SUB,
> +                    signed_saturate_w)
> +
> +GEN_PSIMD_USUB_SAT(pssubu_b, target_ulong, uint8_t,
> +                   EXTRACT8, INSERT8, ELEMS_B)
> +GEN_PSIMD_USUB_SAT(pssubu_h, target_ulong, uint16_t,
> +                   EXTRACT16, INSERT16, ELEMS_H)
> +GEN_PSIMD_USUB_SAT(pssubu_w, uint64_t, uint32_t,
> +                   EXTRACT32, INSERT32, ELEMS_W)
> +
> +GEN_PSIMD_SAT_BINOP(ssub, uint32_t, int32_t, int64_t,
> +                    EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_SUB,
> +                    signed_saturate_w)
> +GEN_PSIMD_USUB_SAT(ssubu, uint32_t, uint32_t,
> +                   EXTRACT32, INSERT32, ELEMS_W)
> +
> +/* Saturation instructions (SAT, USAT) */
> +
> +GEN_PSIMD_SATI(psati_h, target_ulong, int16_t, int64_t,
> +               EXTRACT16, INSERT16, ELEMS_H, 0x0f)
> +GEN_PSIMD_USATI(pusati_h, target_ulong, int16_t, uint16_t, uint32_t,
> +                EXTRACT16, INSERT16, ELEMS_H, 1U)
> +GEN_PSIMD_SATI(psati_w, uint64_t, int32_t, int64_t,
> +               EXTRACT32, INSERT32, ELEMS_W, 0x1f)
> +GEN_PSIMD_USATI(pusati_w, uint64_t, int32_t, uint32_t, uint64_t,
> +                EXTRACT32, INSERT32, ELEMS_W, 1ULL)
> +GEN_PSIMD_SATI(sati_32, uint32_t, int32_t, int64_t,
> +               EXTRACT32, INSERT32, ELEMS_W, 0x1f)
> +GEN_PSIMD_USATI(usati_32, uint32_t, int32_t, uint32_t, uint32_t,
> +                EXTRACT32, INSERT32, ELEMS_W, 1U)
> +GEN_PSIMD_SATI(sati_64, uint64_t, int64_t, int64_t,
> +               EXTRACT64, INSERT64, ELEMS_D, 0x3f)
> +GEN_PSIMD_USATI(usati_64, uint64_t, int64_t, uint64_t, uint64_t,
> +                EXTRACT64, INSERT64, ELEMS_D, 1ULL)
> +
> diff --git a/target/riscv/tcg/translate.c b/target/riscv/tcg/translate.c
> index 9684dbe7528..0df9d4190f1 100644
> --- a/target/riscv/tcg/translate.c
> +++ b/target/riscv/tcg/translate.c
> @@ -103,6 +103,7 @@ typedef struct DisasContext {
>      bool vstart_eq_zero;
>      bool vl_eq_vlmax;
>      bool altfmt;
> +    uint8_t p_vxsat_excp;
>      CPUState *cs;
>      TCGv zero;
>      /* actual address width */
> @@ -1199,6 +1200,7 @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc)
>  #include "insn_trans/trans_rvh.c.inc"
>  #include "insn_trans/trans_rvv.c.inc"
>  #include "insn_trans/trans_rvb.c.inc"
> +#include "insn_trans/trans_rvp.c.inc"
>  #include "insn_trans/trans_rvzicond.c.inc"
>  #include "insn_trans/trans_rvzacas.c.inc"
>  #include "insn_trans/trans_rvzabha.c.inc"
> @@ -1333,6 +1335,8 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
>      ctx->vstart_eq_zero = FIELD_EX32(tb_flags, TB_FLAGS, VSTART_EQ_ZERO);
>      ctx->vl_eq_vlmax = FIELD_EX32(tb_flags, TB_FLAGS, VL_EQ_VLMAX);
>      ctx->altfmt = FIELD_EX64(ext_tb_flags, EXT_TB_FLAGS, ALTFMT);
> +    ctx->p_vxsat_excp = FIELD_EX64(ext_tb_flags, EXT_TB_FLAGS,
> +                                   P_VXSAT_EXCP);
>      ctx->misa_mxl_max = mcc->def->misa_mxl_max;
>      ctx->xl = FIELD_EX32(tb_flags, TB_FLAGS, XL);
>      ctx->address_xl = FIELD_EX32(tb_flags, TB_FLAGS, AXL);
> -- 
> 2.34.1
> 


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH v2 00/18] target/riscv: Add support for RISC-V P
  2026-07-17 10:06 [PATCH v2 00/18] target/riscv: Add support for RISC-V P Molly Chen
                   ` (18 preceding siblings ...)
  2026-07-29  8:43 ` [PATCH v2 00/18] target/riscv: Add support for RISC-V P Chao Liu
@ 2026-07-29  9:32 ` Chao Liu
  2026-08-05 18:36   ` Daniel Henrique Barboza
  19 siblings, 1 reply; 34+ messages in thread
From: Chao Liu @ 2026-07-29  9:32 UTC (permalink / raw)
  To: Molly Chen
  Cc: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
	qemu-riscv, qemu-devel

On Fri, Jul 17, 2026 at 10:06:53AM +0800, Molly Chen wrote:
> This series adds support for the RISC-V Packed SIMD (P) extension.
> 
> The P extension defines packed-SIMD fixed-point operations intended
> for DSP-style workloads such as multimedia and signal processing.
> These instructions operate on packed subword elements within
> general-purpose registers (GPRs).
> 
> The implementation follows the current development draft of the
> specification (v0.20):
> 
>   https://github.com/riscv/riscv-p-spec/
>   or
>   https://www.jhauser.us/RISCV/ext-P/
> 
> Compared with v1, this version reduces implementation boilerplate by
> defining and reusing helper macros for common patterns in
> trans_rvp.c.inc and psimd_helper.c. It also consolidates the P
> extension prerequisite validation in riscv_cpu_validate_p().
> 
> The Zbkb dependency has been removed to align the implementation with
> the current specification. This version also implements the
> specification-defined control of vxsat, which was missing from v1.
> 
> All instructions have been functionally tested using the following
> test suite:
> 
>   https://github.com/mollybuild/qemu-riscv-test-uart
> 
> The implementation focuses on functional correctness and ISA
> coverage. Performance optimizations were not considered at this
> stage.
> 
> Feedback on the implementation details would be highly appreciated.
> 
> Tested with:
> 
>   - ninja -C build test
>   - make -C build check-qtest-riscv32
>   - make -C build check-qtest-riscv64
>   - Functional tests for all P extension instructions using
>     qemu-riscv-test-uart
> 
> No regressions or test failures were observed.
> 
> ---
> Changes in v2:
> 
>   - Refactored trans_rvp.c.inc and psimd_helper.c by defining and
>     reusing helper macros for common implementation patterns, reducing
>     boilerplate and overall code size.
>   - Moved the P extension prerequisite checks into
>     riscv_cpu_validate_p().
>   - Removed the Zbkb dependency to align with the current
>     specification.
>   - Added the specification-defined vxsat control mechanism, which was
>     missing from v1.
> 
This patch set is a significant improvement over v1. I think there are still
a few common issues we can address together:

1. The line break characters '\' in the helper macros we defined need to be space-aligned.
2. Every patch is currently missing a commit body. 

I think these changes are quite necessary.

Thanks,
Chao
> v1:
>   https://lists.nongnu.org/archive/html/qemu-riscv/2026-04/msg00301.html
> 
> Molly Chen (18):
>   target/riscv: Add packed SIMD extension state
>   target/riscv: Add packed SIMD helper framework
>   target/riscv: Add packed SIMD arithmetic instructions
>   target/riscv: Add packed SIMD averaging and rounding instructions
>   target/riscv: Add packed SIMD absolute, difference, compare and mask
>     instructions
>   target/riscv: Add packed SIMD shift instructions
>   target/riscv: Add packed SIMD exchange instructions
>   target/riscv: Add packed SIMD horizontal reduction instructions
>   target/riscv: Add packed SIMD pack, merge and count-leading
>     instructions
>   target/riscv: Add packed SIMD multiplication instructions
>   target/riscv: Add packed SIMD multiply-accumulate instructions
>   target/riscv: Add packed SIMD Q-format multiplication instructions
>   target/riscv: Add packed SIMD Q-format MAC instructions
>   target/riscv: Add packed SIMD two-way MAC instructions
>   target/riscv: Add packed SIMD four-way MAC instructions
>   target/riscv: Add packed SIMD load-replicate instructions
>   target/riscv: Add packed SIMD RV32 only instructions
>   target/riscv: Remove Zbkb dependency from P extension to align with
>     the spec
> 
>  target/riscv/cpu.c                          |    5 +-
>  target/riscv/cpu.h                          |    8 +
>  target/riscv/cpu_bits.h                     |    2 +
>  target/riscv/helper.h                       |  529 ++++
>  target/riscv/insn32.decode                  |  829 +++++
>  target/riscv/machine.c                      |   19 +
>  target/riscv/tcg/csr.c                      |   39 +-
>  target/riscv/tcg/insn_trans/trans_rvb.c.inc |    4 +-
>  target/riscv/tcg/insn_trans/trans_rvp.c.inc | 1389 ++++++++
>  target/riscv/tcg/meson.build                |    3 +-
>  target/riscv/tcg/psimd_helper.c             | 3165 +++++++++++++++++++
>  target/riscv/tcg/tcg-cpu.c                  |   46 +
>  target/riscv/tcg/translate.c                |    6 +
>  13 files changed, 6038 insertions(+), 6 deletions(-)
>  create mode 100644 target/riscv/tcg/insn_trans/trans_rvp.c.inc
>  create mode 100644 target/riscv/tcg/psimd_helper.c
> 
> 
> base-commit: 8fb307591625731060d399aca42373c02c7cb040
> -- 
> 2.34.1
> 


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH v2 18/18] target/riscv: Remove Zbkb dependency from P extension to align with the spec
  2026-07-17 10:07 ` [PATCH v2 18/18] target/riscv: Remove Zbkb dependency from P extension to align with the spec Molly Chen
@ 2026-08-03  2:26   ` Chao Liu
  0 siblings, 0 replies; 34+ messages in thread
From: Chao Liu @ 2026-08-03  2:26 UTC (permalink / raw)
  To: Molly Chen
  Cc: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
	chao.liu.zevorn, qemu-riscv, qemu-devel

On Fri, Jul 17, 2026 at 10:07:11AM +0800, Molly Chen wrote:
> Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
Reviewed-by: Chao Liu <chao.liu@processmission.com>

Thanks,
Chao

> ---
>  target/riscv/tcg/insn_trans/trans_rvb.c.inc | 4 +++-
>  target/riscv/tcg/insn_trans/trans_rvp.c.inc | 2 +-
>  target/riscv/tcg/tcg-cpu.c                  | 6 ++----
>  3 files changed, 6 insertions(+), 6 deletions(-)
> 
> diff --git a/target/riscv/tcg/insn_trans/trans_rvb.c.inc b/target/riscv/tcg/insn_trans/trans_rvb.c.inc
> index e4dcc7c9913..af53eb4fe4b 100644
> --- a/target/riscv/tcg/insn_trans/trans_rvb.c.inc
> +++ b/target/riscv/tcg/insn_trans/trans_rvb.c.inc
> @@ -527,7 +527,9 @@ static bool trans_brev8(DisasContext *ctx, arg_brev8 *a)
>  
>  static bool trans_pack(DisasContext *ctx, arg_pack *a)
>  {
> -    REQUIRE_ZBKB(ctx);
> +    if (!has_ext(ctx, RVP) && !ctx->cfg_ptr->ext_zbkb) {
> +        return false;
> +    }
>      return gen_arith(ctx, a, EXT_NONE, gen_pack, NULL);
>  }
>  
> diff --git a/target/riscv/tcg/insn_trans/trans_rvp.c.inc b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
> index e33e0ec110a..8c5b52ca970 100644
> --- a/target/riscv/tcg/insn_trans/trans_rvp.c.inc
> +++ b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
> @@ -1386,4 +1386,4 @@ GEN_DWS_REG_OP(psll_dws, gen_shift, EXT_NONE, tcg_gen_shl_tl)
>  GEN_DWS_REG_OP(psrl_dws, gen_shift, EXT_ZERO, tcg_gen_shr_tl)
>  GEN_DWS_REG_OP(psra_dws, gen_shift, EXT_SIGN, tcg_gen_sar_tl)
>  
> -GEN_DW_PAIR_ARITH(ppaire_dh, REQUIRE_ZBKB(ctx); , EXT_NONE, gen_pack)
> +GEN_DW_PAIR_ARITH(ppaire_dh, , EXT_NONE, gen_pack)
> diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
> index 1665583accf..36b0196a626 100644
> --- a/target/riscv/tcg/tcg-cpu.c
> +++ b/target/riscv/tcg/tcg-cpu.c
> @@ -563,10 +563,8 @@ static void riscv_cpu_validate_p(RISCVCPU *cpu, Error **errp)
>          return;
>      }
>  
> -    if (!(cpu->cfg.ext_zmmul && cpu->cfg.ext_zba && cpu->cfg.ext_zbb &&
> -          cpu->cfg.ext_zbkb)) {
> -        error_setg(errp, "P extension requires zmmul, zba, zbb and zbkb "
> -                         "extensions");
> +    if (!(cpu->cfg.ext_zmmul && cpu->cfg.ext_zba && cpu->cfg.ext_zbb)) {
> +        error_setg(errp, "P extension requires zmmul, zba and zbb extensions");
>          return;
>      }
>  }
> -- 
> 2.34.1
> 


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH v2 00/18] target/riscv: Add support for RISC-V P
  2026-07-29  9:32 ` Chao Liu
@ 2026-08-05 18:36   ` Daniel Henrique Barboza
  2026-08-11  7:54     ` MOLLY CHEN
  0 siblings, 1 reply; 34+ messages in thread
From: Daniel Henrique Barboza @ 2026-08-05 18:36 UTC (permalink / raw)
  To: Chao Liu, Molly Chen
  Cc: palmer, alistair.francis, liwei1518, zhiwei_liu, qemu-riscv,
	qemu-devel



On 7/29/2026 6:32 AM, Chao Liu wrote:
> On Fri, Jul 17, 2026 at 10:06:53AM +0800, Molly Chen wrote:
>> This series adds support for the RISC-V Packed SIMD (P) extension.
>>
>> The P extension defines packed-SIMD fixed-point operations intended
>> for DSP-style workloads such as multimedia and signal processing.
>> These instructions operate on packed subword elements within
>> general-purpose registers (GPRs).
>>
>> The implementation follows the current development draft of the
>> specification (v0.20):
>>
>>    https://github.com/riscv/riscv-p-spec/
>>    or
>>    https://www.jhauser.us/RISCV/ext-P/
>>
>> Compared with v1, this version reduces implementation boilerplate by
>> defining and reusing helper macros for common patterns in
>> trans_rvp.c.inc and psimd_helper.c. It also consolidates the P
>> extension prerequisite validation in riscv_cpu_validate_p().
>>
>> The Zbkb dependency has been removed to align the implementation with
>> the current specification. This version also implements the
>> specification-defined control of vxsat, which was missing from v1.
>>
>> All instructions have been functionally tested using the following
>> test suite:
>>
>>    https://github.com/mollybuild/qemu-riscv-test-uart
>>
>> The implementation focuses on functional correctness and ISA
>> coverage. Performance optimizations were not considered at this
>> stage.
>>
>> Feedback on the implementation details would be highly appreciated.
>>
>> Tested with:
>>
>>    - ninja -C build test
>>    - make -C build check-qtest-riscv32
>>    - make -C build check-qtest-riscv64
>>    - Functional tests for all P extension instructions using
>>      qemu-riscv-test-uart
>>
>> No regressions or test failures were observed.
>>
>> ---
>> Changes in v2:
>>
>>    - Refactored trans_rvp.c.inc and psimd_helper.c by defining and
>>      reusing helper macros for common implementation patterns, reducing
>>      boilerplate and overall code size.
>>    - Moved the P extension prerequisite checks into
>>      riscv_cpu_validate_p().
>>    - Removed the Zbkb dependency to align with the current
>>      specification.
>>    - Added the specification-defined vxsat control mechanism, which was
>>      missing from v1.
>>
> This patch set is a significant improvement over v1. I think there are still
> a few common issues we can address together:

v2 is a huge improvement indeed.  v1 had 11k lines, v2 cut those by half due to
the smart use of helpers.

> 
> 1. The line break characters '\' in the helper macros we defined need to be space-aligned.
> 2. Every patch is currently missing a commit body.
> 
> I think these changes are quite necessary.

Yeah, having a commit message allows us to make fewer guesses when reviewing code.
E.g. the usage of __int128t__ macros and the choice of some rounding formulas.  We
can make review  assumptions and hope all is fine, but it's not ideal.

And, as Chao mentioned in his other reply, having test cases will be helpful to
assert that everything being added here is sane.  In particular with the amount
of lines we're adding here.


Cheers,
Daniel

> 
> Thanks,
> Chao
>> v1:
>>    https://lists.nongnu.org/archive/html/qemu-riscv/2026-04/msg00301.html
>>
>> Molly Chen (18):
>>    target/riscv: Add packed SIMD extension state
>>    target/riscv: Add packed SIMD helper framework
>>    target/riscv: Add packed SIMD arithmetic instructions
>>    target/riscv: Add packed SIMD averaging and rounding instructions
>>    target/riscv: Add packed SIMD absolute, difference, compare and mask
>>      instructions
>>    target/riscv: Add packed SIMD shift instructions
>>    target/riscv: Add packed SIMD exchange instructions
>>    target/riscv: Add packed SIMD horizontal reduction instructions
>>    target/riscv: Add packed SIMD pack, merge and count-leading
>>      instructions
>>    target/riscv: Add packed SIMD multiplication instructions
>>    target/riscv: Add packed SIMD multiply-accumulate instructions
>>    target/riscv: Add packed SIMD Q-format multiplication instructions
>>    target/riscv: Add packed SIMD Q-format MAC instructions
>>    target/riscv: Add packed SIMD two-way MAC instructions
>>    target/riscv: Add packed SIMD four-way MAC instructions
>>    target/riscv: Add packed SIMD load-replicate instructions
>>    target/riscv: Add packed SIMD RV32 only instructions
>>    target/riscv: Remove Zbkb dependency from P extension to align with
>>      the spec
>>
>>   target/riscv/cpu.c                          |    5 +-
>>   target/riscv/cpu.h                          |    8 +
>>   target/riscv/cpu_bits.h                     |    2 +
>>   target/riscv/helper.h                       |  529 ++++
>>   target/riscv/insn32.decode                  |  829 +++++
>>   target/riscv/machine.c                      |   19 +
>>   target/riscv/tcg/csr.c                      |   39 +-
>>   target/riscv/tcg/insn_trans/trans_rvb.c.inc |    4 +-
>>   target/riscv/tcg/insn_trans/trans_rvp.c.inc | 1389 ++++++++
>>   target/riscv/tcg/meson.build                |    3 +-
>>   target/riscv/tcg/psimd_helper.c             | 3165 +++++++++++++++++++
>>   target/riscv/tcg/tcg-cpu.c                  |   46 +
>>   target/riscv/tcg/translate.c                |    6 +
>>   13 files changed, 6038 insertions(+), 6 deletions(-)
>>   create mode 100644 target/riscv/tcg/insn_trans/trans_rvp.c.inc
>>   create mode 100644 target/riscv/tcg/psimd_helper.c
>>
>>
>> base-commit: 8fb307591625731060d399aca42373c02c7cb040
>> -- 
>> 2.34.1
>>



^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH v2 00/18] target/riscv: Add support for RISC-V P
  2026-08-05 18:36   ` Daniel Henrique Barboza
@ 2026-08-11  7:54     ` MOLLY CHEN
  0 siblings, 0 replies; 34+ messages in thread
From: MOLLY CHEN @ 2026-08-11  7:54 UTC (permalink / raw)
  To: Daniel Henrique Barboza, Chao Liu, nutty.liu
  Cc: palmer, alistair.francis, liwei1518, zhiwei_liu, qemu-riscv,
	qemu-devel

[-- Attachment #1: Type: text/plain, Size: 6650 bytes --]

Thanks Daniel,Chao and Nutty for the review.

I’ll address these issues in v3 by:

  * adding a descriptive commit body to each patch and comments
    for functions that need further explanation;
  * aligning the continuation backslashes in the helper macros;
  * reusing the existing |EXTRACT*|definitions in patch 02/18 instead of
    introducing duplicate definitions; and
  * investigating the addition of P-extension test cases to the QEMU TCG
    test suite, depending on the available toolchain support.

I’ll also document these changes in the v3 cover letter.

Best regards,
Molly

在 2026/8/6 2:36, Daniel Henrique Barboza 写道:
>
>
> On 7/29/2026 6:32 AM, Chao Liu wrote:
>> On Fri, Jul 17, 2026 at 10:06:53AM +0800, Molly Chen wrote:
>>> This series adds support for the RISC-V Packed SIMD (P) extension.
>>>
>>> The P extension defines packed-SIMD fixed-point operations intended
>>> for DSP-style workloads such as multimedia and signal processing.
>>> These instructions operate on packed subword elements within
>>> general-purpose registers (GPRs).
>>>
>>> The implementation follows the current development draft of the
>>> specification (v0.20):
>>>
>>> https://github.com/riscv/riscv-p-spec/
>>>    or
>>> https://www.jhauser.us/RISCV/ext-P/
>>>
>>> Compared with v1, this version reduces implementation boilerplate by
>>> defining and reusing helper macros for common patterns in
>>> trans_rvp.c.inc and psimd_helper.c. It also consolidates the P
>>> extension prerequisite validation in riscv_cpu_validate_p().
>>>
>>> The Zbkb dependency has been removed to align the implementation with
>>> the current specification. This version also implements the
>>> specification-defined control of vxsat, which was missing from v1.
>>>
>>> All instructions have been functionally tested using the following
>>> test suite:
>>>
>>> https://github.com/mollybuild/qemu-riscv-test-uart
>>>
>>> The implementation focuses on functional correctness and ISA
>>> coverage. Performance optimizations were not considered at this
>>> stage.
>>>
>>> Feedback on the implementation details would be highly appreciated.
>>>
>>> Tested with:
>>>
>>>    - ninja -C build test
>>>    - make -C build check-qtest-riscv32
>>>    - make -C build check-qtest-riscv64
>>>    - Functional tests for all P extension instructions using
>>>      qemu-riscv-test-uart
>>>
>>> No regressions or test failures were observed.
>>>
>>> ---
>>> Changes in v2:
>>>
>>>    - Refactored trans_rvp.c.inc and psimd_helper.c by defining and
>>>      reusing helper macros for common implementation patterns, reducing
>>>      boilerplate and overall code size.
>>>    - Moved the P extension prerequisite checks into
>>>      riscv_cpu_validate_p().
>>>    - Removed the Zbkb dependency to align with the current
>>>      specification.
>>>    - Added the specification-defined vxsat control mechanism, which was
>>>      missing from v1.
>>>
>> This patch set is a significant improvement over v1. I think there 
>> are still
>> a few common issues we can address together:
>
> v2 is a huge improvement indeed.  v1 had 11k lines, v2 cut those by 
> half due to
> the smart use of helpers.
>
>>
>> 1. The line break characters '\' in the helper macros we defined need 
>> to be space-aligned.
>> 2. Every patch is currently missing a commit body.
>>
>> I think these changes are quite necessary.
>
> Yeah, having a commit message allows us to make fewer guesses when 
> reviewing code.
> E.g. the usage of __int128t__ macros and the choice of some rounding 
> formulas.  We
> can make review  assumptions and hope all is fine, but it's not ideal.
>
> And, as Chao mentioned in his other reply, having test cases will be 
> helpful to
> assert that everything being added here is sane.  In particular with 
> the amount
> of lines we're adding here.
>
>
> Cheers,
> Daniel
>
>>
>> Thanks,
>> Chao
>>> v1:
>>> https://lists.nongnu.org/archive/html/qemu-riscv/2026-04/msg00301.html
>>>
>>> Molly Chen (18):
>>>    target/riscv: Add packed SIMD extension state
>>>    target/riscv: Add packed SIMD helper framework
>>>    target/riscv: Add packed SIMD arithmetic instructions
>>>    target/riscv: Add packed SIMD averaging and rounding instructions
>>>    target/riscv: Add packed SIMD absolute, difference, compare and mask
>>>      instructions
>>>    target/riscv: Add packed SIMD shift instructions
>>>    target/riscv: Add packed SIMD exchange instructions
>>>    target/riscv: Add packed SIMD horizontal reduction instructions
>>>    target/riscv: Add packed SIMD pack, merge and count-leading
>>>      instructions
>>>    target/riscv: Add packed SIMD multiplication instructions
>>>    target/riscv: Add packed SIMD multiply-accumulate instructions
>>>    target/riscv: Add packed SIMD Q-format multiplication instructions
>>>    target/riscv: Add packed SIMD Q-format MAC instructions
>>>    target/riscv: Add packed SIMD two-way MAC instructions
>>>    target/riscv: Add packed SIMD four-way MAC instructions
>>>    target/riscv: Add packed SIMD load-replicate instructions
>>>    target/riscv: Add packed SIMD RV32 only instructions
>>>    target/riscv: Remove Zbkb dependency from P extension to align with
>>>      the spec
>>>
>>>   target/riscv/cpu.c                          |    5 +-
>>>   target/riscv/cpu.h                          |    8 +
>>>   target/riscv/cpu_bits.h                     |    2 +
>>>   target/riscv/helper.h                       |  529 ++++
>>>   target/riscv/insn32.decode                  |  829 +++++
>>>   target/riscv/machine.c                      |   19 +
>>>   target/riscv/tcg/csr.c                      |   39 +-
>>>   target/riscv/tcg/insn_trans/trans_rvb.c.inc |    4 +-
>>>   target/riscv/tcg/insn_trans/trans_rvp.c.inc | 1389 ++++++++
>>>   target/riscv/tcg/meson.build                |    3 +-
>>>   target/riscv/tcg/psimd_helper.c             | 3165 
>>> +++++++++++++++++++
>>>   target/riscv/tcg/tcg-cpu.c                  |   46 +
>>>   target/riscv/tcg/translate.c                |    6 +
>>>   13 files changed, 6038 insertions(+), 6 deletions(-)
>>>   create mode 100644 target/riscv/tcg/insn_trans/trans_rvp.c.inc
>>>   create mode 100644 target/riscv/tcg/psimd_helper.c
>>>
>>>
>>> base-commit: 8fb307591625731060d399aca42373c02c7cb040
>>> -- 
>>> 2.34.1
>>>

[-- Attachment #2: Type: text/html, Size: 10969 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

end of thread, other threads:[~2026-08-11  7:54 UTC | newest]

Thread overview: 34+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-17 10:06 [PATCH v2 00/18] target/riscv: Add support for RISC-V P Molly Chen
2026-07-17 10:06 ` [PATCH v2 01/18] target/riscv: Add packed SIMD extension state Molly Chen
2026-07-26 19:32   ` Daniel Henrique Barboza
2026-07-27  6:13   ` Nutty.Liu
2026-07-29  8:43   ` Chao Liu
2026-07-17 10:06 ` [PATCH v2 02/18] target/riscv: Add packed SIMD helper framework Molly Chen
2026-07-26 19:53   ` Daniel Henrique Barboza
2026-07-27  6:16   ` Nutty.Liu
2026-07-29  9:01   ` Chao Liu
2026-07-17 10:06 ` [PATCH v2 03/18] target/riscv: Add packed SIMD arithmetic instructions Molly Chen
2026-07-26 22:05   ` Daniel Henrique Barboza
2026-07-29  6:17   ` Nutty.Liu
2026-07-29  9:27   ` Chao Liu
2026-07-17 10:06 ` [PATCH v2 04/18] target/riscv: Add packed SIMD averaging and rounding instructions Molly Chen
2026-07-27 18:58   ` Daniel Henrique Barboza
2026-07-17 10:06 ` [PATCH v2 05/18] target/riscv: Add packed SIMD absolute, difference, compare and mask instructions Molly Chen
2026-07-17 10:06 ` [PATCH v2 06/18] target/riscv: Add packed SIMD shift instructions Molly Chen
2026-07-17 10:07 ` [PATCH v2 07/18] target/riscv: Add packed SIMD exchange instructions Molly Chen
2026-07-17 10:07 ` [PATCH v2 08/18] target/riscv: Add packed SIMD horizontal reduction instructions Molly Chen
2026-07-17 10:07 ` [PATCH v2 09/18] target/riscv: Add packed SIMD pack, merge and count-leading instructions Molly Chen
2026-07-17 10:07 ` [PATCH v2 10/18] target/riscv: Add packed SIMD multiplication instructions Molly Chen
2026-07-17 10:07 ` [PATCH v2 11/18] target/riscv: Add packed SIMD multiply-accumulate instructions Molly Chen
2026-07-17 10:07 ` [PATCH v2 12/18] target/riscv: Add packed SIMD Q-format multiplication instructions Molly Chen
2026-07-17 10:07 ` [PATCH v2 13/18] target/riscv: Add packed SIMD Q-format MAC instructions Molly Chen
2026-07-17 10:07 ` [PATCH v2 14/18] target/riscv: Add packed SIMD two-way " Molly Chen
2026-07-17 10:07 ` [PATCH v2 15/18] target/riscv: Add packed SIMD four-way " Molly Chen
2026-07-17 10:07 ` [PATCH v2 16/18] target/riscv: Add packed SIMD load-replicate instructions Molly Chen
2026-07-17 10:07 ` [PATCH v2 17/18] target/riscv: Add packed SIMD RV32 only instructions Molly Chen
2026-07-17 10:07 ` [PATCH v2 18/18] target/riscv: Remove Zbkb dependency from P extension to align with the spec Molly Chen
2026-08-03  2:26   ` Chao Liu
2026-07-29  8:43 ` [PATCH v2 00/18] target/riscv: Add support for RISC-V P Chao Liu
2026-07-29  9:32 ` Chao Liu
2026-08-05 18:36   ` Daniel Henrique Barboza
2026-08-11  7:54     ` MOLLY CHEN

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.