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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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-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, 0 replies; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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
  19 siblings, 0 replies; 31+ 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] 31+ messages in thread

end of thread, other threads:[~2026-07-29  9:32 UTC | newest]

Thread overview: 31+ 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-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

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.