diff mbox series

[7/8] target/riscv: 128-bit support for some csrs

Message ID 20210830171638.126325-7-frederic.petrot@univ-grenoble-alpes.fr
State New
Headers show
Series [1/8] target/riscv: Settings for 128-bit extension support | expand

Commit Message

Frédéric Pétrot Aug. 30, 2021, 5:16 p.m. UTC
Adding 128-bit support for a minimal subset of the csrs, so that it is
possible to boot and jump to and return from interrupts/exceptions using
the csrrw instruction.
The (partially handled) 128-bit csrs are the following:
csr_mhartid, csr_mstatus, csr_misa, csr_mtvec, csr_mscratch and csr_mepc.
We fallback on the 64-bit version of the csr functions, assuming the relevant
information stands in the lower double-word when no 128-bit support is
implemented.

Signed-off-by: Frédéric Pétrot <frederic.petrot@univ-grenoble-alpes.fr>
Co-authored-by: Fabien Portas <fabien.portas@grenoble-inp.org>
---
 target/riscv/cpu.h                      |  52 +++--
 target/riscv/cpu_bits.h                 |   2 +
 target/riscv/csr.c                      | 264 ++++++++++++++++++++++++
 target/riscv/helper.h                   |   7 +
 target/riscv/insn_trans/trans_rvi.c.inc |  76 +++++++
 target/riscv/op_helper.c                |  60 ++++++
 target/riscv/translate.c                |   4 +
 target/riscv/utils_128.h                | 173 ++++++++++++++++
 8 files changed, 625 insertions(+), 13 deletions(-)
 create mode 100644 target/riscv/utils_128.h

Comments

Richard Henderson Aug. 31, 2021, 3:43 a.m. UTC | #1
On 8/30/21 10:16 AM, Frédéric Pétrot wrote:
>   target/riscv/utils_128.h                | 173 ++++++++++++++++

You should extend include/qemu/int128.h as needed, rather than this.

> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index 4321b03b94..0d18055e08 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -26,6 +26,7 @@
>   #include "fpu/softfloat-types.h"
>   #include "qom/object.h"
>   
> +#include "utils_128.h"

And anyway, it's certainly not needed in cpu.h.

> @@ -60,19 +61,6 @@
>   #define RV64 ((target_ulong)2 << (TARGET_LONG_BITS - 2))
>   /* To be used on misah, the upper part of misa */
>   #define RV128 ((target_ulong)3 << (TARGET_LONG_BITS - 2))
> -/*
> - * Defined to force the use of tcg 128-bit arithmetic
> - * if the compiler does not have a 128-bit built-in type
> - */
> -#define SOFT_128BIT
> -/*
> - * If available and not explicitly disabled,
> - * use compiler's 128-bit integers.
> - */
> -#if defined(__SIZEOF_INT128__) && !defined(SOFT_128BIT)
> -#define HARD_128BIT
> -#endif

You shouldn't have added these earlier and remove them here.  Of course, I don't think 
they're needed at all.


r~
diff mbox series

Patch

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 4321b03b94..0d18055e08 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -26,6 +26,7 @@ 
 #include "fpu/softfloat-types.h"
 #include "qom/object.h"
 
+#include "utils_128.h"
 #define TCG_GUEST_DEFAULT_MO 0
 
 #define TYPE_RISCV_CPU "riscv-cpu"
@@ -60,19 +61,6 @@ 
 #define RV64 ((target_ulong)2 << (TARGET_LONG_BITS - 2))
 /* To be used on misah, the upper part of misa */
 #define RV128 ((target_ulong)3 << (TARGET_LONG_BITS - 2))
-/*
- * Defined to force the use of tcg 128-bit arithmetic
- * if the compiler does not have a 128-bit built-in type
- */
-#define SOFT_128BIT
-/*
- * If available and not explicitly disabled,
- * use compiler's 128-bit integers.
- */
-#if defined(__SIZEOF_INT128__) && !defined(SOFT_128BIT)
-#define HARD_128BIT
-#endif
-
 
 #define RV(x) ((target_ulong)1 << (x - 'A'))
 
@@ -214,6 +202,11 @@  struct CPURISCVState {
     /* Upper 64-bits of 128-bit CSRs */
     uint64_t misah;
     uint64_t misah_mask;
+    uint64_t mtvech;
+    uint64_t mscratchh;
+    uint64_t mepch;
+    uint64_t satph;
+    uint64_t mstatush;
 #endif
 
     /* Virtual CSRs */
@@ -491,9 +484,20 @@  static inline void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc,
     *pflags = flags;
 }
 
+#if defined(TARGET_RISCV128)
+RISCVException riscv_csrrw_check(CPURISCVState *env,
+                                 int csrno,
+                                 const UINT128 *write_mask,
+                                 RISCVCPU *cpu);
+#endif
 RISCVException riscv_csrrw(CPURISCVState *env, int csrno,
                            target_ulong *ret_value,
                            target_ulong new_value, target_ulong write_mask);
+#if defined(TARGET_RISCV128)
+RISCVException riscv_csrrw_128(CPURISCVState *env, int csrno,
+                                UINT128 *ret_value,
+                                UINT128 new_value, UINT128 write_mask);
+#endif
 RISCVException riscv_csrrw_debug(CPURISCVState *env, int csrno,
                                  target_ulong *ret_value,
                                  target_ulong new_value,
@@ -523,6 +527,17 @@  typedef RISCVException (*riscv_csr_op_fn)(CPURISCVState *env, int csrno,
                                           target_ulong new_value,
                                           target_ulong write_mask);
 
+#if defined(TARGET_RISCV128)
+typedef RISCVException (*riscv_csr_read128_fn)(CPURISCVState *env, int csrno,
+                                               UINT128 *ret_value);
+typedef RISCVException (*riscv_csr_write128_fn)(CPURISCVState *env, int csrno,
+                                             UINT128 new_value);
+typedef RISCVException (*riscv_csr_op128_fn)(CPURISCVState *env, int csrno,
+                                             UINT128 *ret_value,
+                                             UINT128 new_value,
+                                             UINT128 write_mask);
+#endif
+
 typedef struct {
     const char *name;
     riscv_csr_predicate_fn predicate;
@@ -531,6 +546,14 @@  typedef struct {
     riscv_csr_op_fn op;
 } riscv_csr_operations;
 
+#if defined(TARGET_RISCV128)
+typedef struct {
+    riscv_csr_read128_fn read128;
+    riscv_csr_write128_fn write128;
+    riscv_csr_op128_fn op128;
+} riscv_csr_operations128;
+#endif
+
 /* CSR function table constants */
 enum {
     CSR_TABLE_SIZE = 0x1000
@@ -538,6 +561,9 @@  enum {
 
 /* CSR function table */
 extern riscv_csr_operations csr_ops[CSR_TABLE_SIZE];
+#if defined(TARGET_RISCV128)
+extern riscv_csr_operations128 csr_ops_128[CSR_TABLE_SIZE];
+#endif
 
 void riscv_get_csr_ops(int csrno, riscv_csr_operations *ops);
 void riscv_set_csr_ops(int csrno, riscv_csr_operations *ops);
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index 7330ff5a19..901f0e890a 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -361,6 +361,8 @@ 
 #define MSTATUS32_SD        0x80000000
 #define MSTATUS64_SD        0x8000000000000000ULL
 
+#define MSTATUSH128_SD      0x8000000000000000ULL
+
 #define MISA32_MXL          0xC0000000
 #define MISA64_MXL          0xC000000000000000ULL
 
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 9a4ed18ac5..c3471a1365 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -462,6 +462,14 @@  static const char valid_vm_1_10_64[16] = {
 };
 
 /* Machine Information Registers */
+#if defined(TARGET_RISCV128)
+static RISCVException read_zero_128(CPURISCVState *env, int csrno,
+                                    UINT128 *val)
+{
+    *val = u128_zero();
+    return RISCV_EXCP_NONE;
+}
+#endif
 static RISCVException read_zero(CPURISCVState *env, int csrno,
                                 target_ulong *val)
 {
@@ -469,6 +477,14 @@  static RISCVException read_zero(CPURISCVState *env, int csrno,
     return RISCV_EXCP_NONE;
 }
 
+#if defined(TARGET_RISCV128)
+static RISCVException read_mhartid_128(CPURISCVState *env, int csrno,
+                                       UINT128 *val)
+{
+    *val = u128_from64(env->mhartid);
+    return RISCV_EXCP_NONE;
+}
+#endif
 static RISCVException read_mhartid(CPURISCVState *env, int csrno,
                                    target_ulong *val)
 {
@@ -477,6 +493,61 @@  static RISCVException read_mhartid(CPURISCVState *env, int csrno,
 }
 
 /* Machine Trap Setup */
+#if defined(TARGET_RISCV128)
+static RISCVException read_mstatus_128(CPURISCVState *env, int csrno,
+                                   UINT128 *val)
+{
+    *val = u128_from_pair(env->mstatus, env->mstatush);
+    return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_mstatus_128(CPURISCVState *env, int csrno,
+                                        UINT128 val)
+{
+    UINT128 mstatus = u128_from_pair(env->mstatus, env->mstatush);
+    UINT128 mask = u128_zero();
+    int dirty;
+
+    /* flush tlb on mstatus fields that affect VM */
+    if (u128_lo64(u128_xor(mstatus, val))
+            & (MSTATUS_MXR | MSTATUS_MPP | MSTATUS_MPV |
+                           MSTATUS_MPRV | MSTATUS_SUM)) {
+        tlb_flush(env_cpu(env));
+    }
+    mask = u128_from64(MSTATUS_SIE | MSTATUS_SPIE | MSTATUS_MIE | MSTATUS_MPIE |
+                       MSTATUS_SPP | MSTATUS_FS | MSTATUS_MPRV | MSTATUS_SUM |
+                       MSTATUS_MPP | MSTATUS_MXR | MSTATUS_TVM | MSTATUS_TSR |
+                       MSTATUS_TW);
+
+    if (!riscv_cpu_is_32bit(env)) {
+        /*
+         * RV32: MPV and GVA are not in mstatus. The current plan is to
+         * add them to mstatush. For now, we just don't support it.
+         */
+        mask = u128_or(mask, u128_from64(MSTATUS_MPV | MSTATUS_GVA));
+    }
+
+    mstatus = u128_or(u128_and(mstatus, u128_not(mask)), u128_and(val, mask));
+
+    dirty = ((u128_get_lo64(&mstatus) & MSTATUS_FS) == MSTATUS_FS) |
+            ((u128_get_lo64(&mstatus) & MSTATUS_XS) == MSTATUS_XS);
+    if (dirty) {
+        if (riscv_cpu_is_32bit(env)) {
+            mstatus = u128_from64(u128_get_lo64(&mstatus) | MSTATUS32_SD);
+        } else if (riscv_cpu_is_64bit(env)) {
+            mstatus = u128_from64(u128_get_lo64(&mstatus) | MSTATUS64_SD);
+        } else {
+            mstatus = u128_or(mstatus, u128_from_pair(0, MSTATUSH128_SD));
+        }
+    }
+
+    env->mstatus = u128_get_lo64(&mstatus);
+    env->mstatush = u128_get_hi64(&mstatus);
+
+    return RISCV_EXCP_NONE;
+}
+#endif
+
 static RISCVException read_mstatus(CPURISCVState *env, int csrno,
                                    target_ulong *val)
 {
@@ -554,6 +625,15 @@  static RISCVException write_mstatush(CPURISCVState *env, int csrno,
     return RISCV_EXCP_NONE;
 }
 
+#if defined(TARGET_RISCV128)
+static RISCVException read_misa_128(CPURISCVState *env, int csrno,
+                                    UINT128 *val)
+{
+    *val = u128_from_pair(env->misa, env->misah);
+    return RISCV_EXCP_NONE;
+}
+#endif
+
 static RISCVException read_misa(CPURISCVState *env, int csrno,
                                 target_ulong *val)
 {
@@ -663,6 +743,27 @@  static RISCVException write_mie(CPURISCVState *env, int csrno,
     return RISCV_EXCP_NONE;
 }
 
+#if defined(TARGET_RISCV128)
+static RISCVException read_mtvec_128(CPURISCVState *env, int csrno,
+                                     UINT128 *val)
+{
+    *val = u128_from_pair(env->mtvec, env->mtvech);
+    return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_mtvec_128(CPURISCVState *env, int csrno,
+                                      UINT128 val)
+{
+    /* bits [1:0] encode mode; 0 = direct, 1 = vectored, 2 >= reserved */
+    if ((u128_get_lo64(&val) & 3) < 2) {
+        env->mtvec = u128_get_lo64(&val);
+        env->mtvech = u128_get_hi64(&val);
+    } else {
+        qemu_log_mask(LOG_UNIMP, "CSR_MTVEC: reserved mode not supported\n");
+    }
+    return RISCV_EXCP_NONE;
+}
+#endif
 static RISCVException read_mtvec(CPURISCVState *env, int csrno,
                                  target_ulong *val)
 {
@@ -697,6 +798,20 @@  static RISCVException write_mcounteren(CPURISCVState *env, int csrno,
 }
 
 /* Machine Trap Handling */
+#if defined(TARGET_RISCV128)
+static RISCVException read_mscratch_128(CPURISCVState *env, int csrno,
+                                        UINT128 *val)  {
+    *val = u128_from_pair(env->mscratch, env->mscratchh);
+    return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_mscratch_128(CPURISCVState *env, int csrno,
+                                         UINT128 val) {
+    env->mscratch = u128_get_lo64(&val);
+    env->mscratchh = u128_get_hi64(&val);
+    return RISCV_EXCP_NONE;
+}
+#endif
 static RISCVException read_mscratch(CPURISCVState *env, int csrno,
                                     target_ulong *val)
 {
@@ -711,6 +826,23 @@  static RISCVException write_mscratch(CPURISCVState *env, int csrno,
     return RISCV_EXCP_NONE;
 }
 
+#if defined(TARGET_RISCV128)
+static RISCVException read_mepc_128(CPURISCVState *env, int csrno,
+                                    UINT128 *val)
+{
+    *val = u128_from_pair(env->mepc, env->mepch);
+    return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_mepc_128(CPURISCVState *env, int csrno,
+                                     UINT128 val)
+{
+    env->mepc = u128_get_lo64(&val);
+    env->mepch = u128_get_hi64(&val);
+    return RISCV_EXCP_NONE;
+}
+#endif
+
 static RISCVException read_mepc(CPURISCVState *env, int csrno,
                                      target_ulong *val)
 {
@@ -1493,6 +1625,120 @@  RISCVException riscv_csrrw(CPURISCVState *env, int csrno,
     return RISCV_EXCP_NONE;
 }
 
+#if defined(TARGET_RISCV128)
+static inline RISCVException riscv_csrrw_128_check(CPURISCVState *env,
+                                 int csrno,
+                                 const UINT128 *write_mask,
+                                 RISCVCPU *cpu) {
+    /* check privileges and return -1 if check fails */
+#if !defined(CONFIG_USER_ONLY)
+    int effective_priv = env->priv;
+    int read_only = get_field(csrno, 0xC00) == 3;
+
+    if (riscv_has_ext(env, RVH) &&
+        env->priv == PRV_S &&
+        !riscv_cpu_virt_enabled(env)) {
+        /*
+         * We are in S mode without virtualisation, therefore we are in HS Mode.
+         * Add 1 to the effective privledge level to allow us to access the
+         * Hypervisor CSRs.
+         */
+        effective_priv++;
+    }
+
+    if ((u128_is_nonzero(write_mask) && read_only) ||
+        (!env->debugger && (effective_priv < get_field(csrno, 0x300)))) {
+        return RISCV_EXCP_ILLEGAL_INST;
+    }
+#endif
+
+    /* ensure the CSR extension is enabled. */
+    if (!cpu->cfg.ext_icsr) {
+        return RISCV_EXCP_ILLEGAL_INST;
+    }
+
+    /* check predicate */
+    if (!csr_ops[csrno].predicate) {
+        return RISCV_EXCP_ILLEGAL_INST;
+    }
+    RISCVException ret = csr_ops[csrno].predicate(env, csrno);
+    if (ret != RISCV_EXCP_NONE) {
+        return ret;
+    }
+
+    return RISCV_EXCP_NONE;
+}
+
+RISCVException riscv_csrrw_128(CPURISCVState *env, int csrno,
+                               UINT128 *ret_value,
+                               UINT128 new_value, UINT128 write_mask) {
+    RISCVException ret;
+    UINT128 old_value;
+
+    RISCVCPU *cpu = env_archcpu(env);
+
+    if (!csr_ops_128[csrno].read128 && !csr_ops_128[csrno].op128) {
+        /*
+         * FIXME: Fall back to 64-bit version for now, if the 128-bit
+         * alternative isn't defined.
+         * Note, some CSRs don't extend to MXLEN, for those,
+         * this fallback is correctly handling the read/write.
+         */
+        target_ulong ret_64;
+        ret = riscv_csrrw(env, csrno, &ret_64,
+                          u128_get_lo64(&new_value),
+                          u128_get_lo64(&write_mask));
+
+        if (ret_value) {
+            *ret_value = u128_from64(ret_64);
+        }
+
+        return ret;
+    }
+
+    RISCVException check_status =
+        riscv_csrrw_128_check(env, csrno, &write_mask, cpu);
+    if (check_status != RISCV_EXCP_NONE) {
+        return check_status;
+    }
+
+    /* execute combined read/write operation if it exists */
+    if (csr_ops_128[csrno].op128) {
+        return csr_ops_128[csrno].op128(env, csrno, ret_value,
+                                        new_value, write_mask);
+    }
+
+    /* if no accessor exists then return failure */
+    if (!csr_ops_128[csrno].read128) {
+        return RISCV_EXCP_ILLEGAL_INST;
+    }
+    /* read old value */
+    ret = csr_ops_128[csrno].read128(env, csrno, &old_value);
+    if (ret != RISCV_EXCP_NONE) {
+        return ret;
+    }
+
+    /* write value if writable and write mask set, otherwise drop writes */
+    if (u128_is_nonzero(&write_mask)) {
+        new_value = u128_or(u128_and(old_value, u128_not(write_mask)),
+                            u128_and(new_value, write_mask));
+        if (csr_ops_128[csrno].write128) {
+            ret = csr_ops_128[csrno].write128(env, csrno, new_value);
+            if (ret != RISCV_EXCP_NONE) {
+                return ret;
+            }
+        }
+    }
+
+    /* return old value */
+    if (ret_value) {
+        *ret_value = old_value;
+    }
+
+    return RISCV_EXCP_NONE;
+}
+#endif
+
 /*
  * Debugger support.  If not in user mode, set env->debugger before the
  * riscv_csrrw call and clear it after the call.
@@ -1514,6 +1760,24 @@  RISCVException riscv_csrrw_debug(CPURISCVState *env, int csrno,
 }
 
 /* Control and Status Register function table */
+#if defined(TARGET_RISCV128)
+riscv_csr_operations128 csr_ops_128[CSR_TABLE_SIZE] = {
+#if !defined(CONFIG_USER_ONLY)
+    [CSR_MVENDORID]  = { read_zero_128    },
+    [CSR_MARCHID]    = { read_zero_128    },
+    [CSR_MIMPID]     = { read_zero_128    },
+    [CSR_MHARTID]    = { read_mhartid_128 },
+
+    [CSR_MSTATUS]    = { read_mstatus_128,  write_mstatus_128 },
+    [CSR_MISA]       = { read_misa_128    },
+    [CSR_MTVEC]      = { read_mtvec_128,    write_mtvec_128   },
+
+    [CSR_MSCRATCH]   = { read_mscratch_128, write_mscratch_128},
+    [CSR_MEPC]       = { read_mepc_128,     write_mepc_128    },
+#endif
+};
+#endif
+
 riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
     /* User Floating-Point CSRs */
     [CSR_FFLAGS]   = { "fflags",   fs,     read_fflags,  write_fflags },
diff --git a/target/riscv/helper.h b/target/riscv/helper.h
index f3aed608dc..e3eb1dfe59 100644
--- a/target/riscv/helper.h
+++ b/target/riscv/helper.h
@@ -68,6 +68,13 @@  DEF_HELPER_FLAGS_2(gorcw, TCG_CALL_NO_RWG_SE, tl, tl, tl)
 DEF_HELPER_3(csrrw, tl, env, tl, tl)
 DEF_HELPER_4(csrrs, tl, env, tl, tl, tl)
 DEF_HELPER_4(csrrc, tl, env, tl, tl, tl)
+
+#ifdef TARGET_RISCV128
+DEF_HELPER_5(csrrw_128, void, env, tl, tl, tl, tl)
+DEF_HELPER_5(csrrs_128, void, env, tl, tl, tl, tl)
+DEF_HELPER_5(csrrc_128, void, env, tl, tl, tl, tl)
+#endif
+
 #ifndef CONFIG_USER_ONLY
 DEF_HELPER_2(sret, tl, env, tl)
 DEF_HELPER_2(mret, tl, env, tl)
diff --git a/target/riscv/insn_trans/trans_rvi.c.inc b/target/riscv/insn_trans/trans_rvi.c.inc
index 0401ba3d69..2c8041ba15 100644
--- a/target/riscv/insn_trans/trans_rvi.c.inc
+++ b/target/riscv/insn_trans/trans_rvi.c.inc
@@ -1543,6 +1543,29 @@  static bool trans_fence_i(DisasContext *ctx, arg_fence_i *a)
     gen_io_start();\
 } while (0)
 
+#if defined(TARGET_RISCV128)
+#define RISCV_OP_CSR128_PRE do { \
+    source1_lo = tcg_temp_new(); \
+    source1_hi = tcg_temp_new(); \
+    csr_store = tcg_temp_new();  \
+    rd = tcg_const_tl(a->rd); \
+    gen_get_gpr(source1_lo, a->rs1); \
+    gen_get_gprh(source1_hi, a->rs1); \
+    tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next); \
+    tcg_gen_movi_tl(csr_store, a->csr); \
+    gen_io_start(); \
+} while (0)
+
+#define RISCV_OP_CSRI128_PRE do { \
+    source1_lo = tcg_const_tl(a->rs1); \
+    source1_hi = tcg_const_tl(0); \
+    csr_store = tcg_const_tl(a->csr); \
+    rd = tcg_const_tl(a->rd); \
+    tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next); \
+    gen_io_start(); \
+} while (0)
+#endif
+
 #define RISCV_OP_CSR_POST do {\
     gen_set_gpr(a->rd, dest); \
     tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn); \
@@ -1554,57 +1577,110 @@  static bool trans_fence_i(DisasContext *ctx, arg_fence_i *a)
     tcg_temp_free(rs1_pass); \
 } while (0)
 
+#if defined(TARGET_RISCV128)
+#define RISCV_OP_CSR128_POST do {\
+    tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn); \
+    exit_tb(ctx); \
+    ctx->base.is_jmp = DISAS_NORETURN; \
+    tcg_temp_free(source1_hi); \
+    tcg_temp_free(source1_lo); \
+    tcg_temp_free(csr_store); \
+    tcg_temp_free(rd); \
+} while (0)
+#endif
 
 static bool trans_csrrw(DisasContext *ctx, arg_csrrw *a)
 {
+#if !defined(TARGET_RISCV128)
     TCGv source1, csr_store, dest, rs1_pass;
     RISCV_OP_CSR_PRE;
     gen_helper_csrrw(dest, cpu_env, source1, csr_store);
     RISCV_OP_CSR_POST;
+#else
+    TCGv csr_store, source1_lo, source1_hi, rd;
+    RISCV_OP_CSR128_PRE;
+    gen_helper_csrrw_128(cpu_env, rd, csr_store, source1_lo, source1_hi);
+    RISCV_OP_CSR128_POST;
+#endif
     return true;
 }
 
 static bool trans_csrrs(DisasContext *ctx, arg_csrrs *a)
 {
+#if !defined(TARGET_RISCV128)
     TCGv source1, csr_store, dest, rs1_pass;
     RISCV_OP_CSR_PRE;
     gen_helper_csrrs(dest, cpu_env, source1, csr_store, rs1_pass);
     RISCV_OP_CSR_POST;
+#else
+    TCGv csr_store, source1_lo, source1_hi, rd;
+    RISCV_OP_CSR128_PRE;
+    gen_helper_csrrs_128(cpu_env, rd, csr_store, source1_lo, source1_hi);
+    RISCV_OP_CSR128_POST;
+#endif
     return true;
 }
 
 static bool trans_csrrc(DisasContext *ctx, arg_csrrc *a)
 {
+#if !defined(TARGET_RISCV128)
     TCGv source1, csr_store, dest, rs1_pass;
     RISCV_OP_CSR_PRE;
     gen_helper_csrrc(dest, cpu_env, source1, csr_store, rs1_pass);
     RISCV_OP_CSR_POST;
+#else
+    TCGv csr_store, source1_lo, source1_hi, rd;
+    RISCV_OP_CSR128_PRE;
+    gen_helper_csrrc_128(cpu_env, rd, csr_store, source1_lo, source1_hi);
+    RISCV_OP_CSR128_POST;
+#endif
     return true;
 }
 
 static bool trans_csrrwi(DisasContext *ctx, arg_csrrwi *a)
 {
+#if !defined(TARGET_RISCV128)
     TCGv source1, csr_store, dest, rs1_pass;
     RISCV_OP_CSR_PRE;
     gen_helper_csrrw(dest, cpu_env, rs1_pass, csr_store);
     RISCV_OP_CSR_POST;
+#else
+    TCGv csr_store, source1_lo, source1_hi, rd;
+    RISCV_OP_CSRI128_PRE;
+    gen_helper_csrrw_128(cpu_env, rd, csr_store, source1_lo, source1_hi);
+    RISCV_OP_CSR128_POST;
+#endif
     return true;
 }
 
 static bool trans_csrrsi(DisasContext *ctx, arg_csrrsi *a)
 {
+#if !defined(TARGET_RISCV128)
     TCGv source1, csr_store, dest, rs1_pass;
     RISCV_OP_CSR_PRE;
     gen_helper_csrrs(dest, cpu_env, rs1_pass, csr_store, rs1_pass);
     RISCV_OP_CSR_POST;
+#else
+    TCGv csr_store, source1_lo, source1_hi, rd;
+    RISCV_OP_CSRI128_PRE;
+    gen_helper_csrrs_128(cpu_env, rd, csr_store, source1_lo, source1_hi);
+    RISCV_OP_CSR128_POST;
+#endif
     return true;
 }
 
 static bool trans_csrrci(DisasContext *ctx, arg_csrrci *a)
 {
+#if !defined(TARGET_RISCV128)
     TCGv source1, csr_store, dest, rs1_pass;
     RISCV_OP_CSR_PRE;
     gen_helper_csrrc(dest, cpu_env, rs1_pass, csr_store, rs1_pass);
     RISCV_OP_CSR_POST;
+#else
+    TCGv csr_store, source1_lo, source1_hi, rd;
+    RISCV_OP_CSRI128_PRE;
+    gen_helper_csrrc_128(cpu_env, rd, csr_store, source1_lo, source1_hi);
+    RISCV_OP_CSR128_POST;
+#endif
     return true;
 }
diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
index 3c48e739ac..de3f4a2a61 100644
--- a/target/riscv/op_helper.c
+++ b/target/riscv/op_helper.c
@@ -23,6 +23,8 @@ 
 #include "exec/exec-all.h"
 #include "exec/helper-proto.h"
 
+#include "utils_128.h"
+
 /* Exceptions processing helpers */
 void QEMU_NORETURN riscv_raise_exception(CPURISCVState *env,
                                           uint32_t exception, uintptr_t pc)
@@ -73,6 +75,64 @@  target_ulong helper_csrrc(CPURISCVState *env, target_ulong src,
     return val;
 }
 
+#if defined(TARGET_RISCV128)
+void HELPER(csrrw_128)(CPURISCVState *env, target_ulong rd, target_ulong csrno,
+                       target_ulong src_l, target_ulong src_h)
+{
+    UINT128 ret_value = u128_zero();
+    RISCVException ret = riscv_csrrw_128(env, csrno, &ret_value,
+                                         u128_from_pair(src_l, src_h),
+                                         u128_maxval());
+
+    if (ret != RISCV_EXCP_NONE) {
+        riscv_raise_exception(env, ret, GETPC());
+    }
+
+    if (rd != 0) {
+        env->gpr[rd] = u128_get_lo64(&ret_value);
+        if (riscv_cpu_is_128bit(env)) {
+            env->gprh[rd] = u128_get_hi64(&ret_value);
+        }
+    }
+}
+
+void HELPER(csrrs_128)(CPURISCVState *env, target_ulong rd, target_ulong csrno,
+                       target_ulong src_l, target_ulong src_h)
+{
+    UINT128 ret_value = u128_zero();
+    RISCVException ret = riscv_csrrw_128(env, csrno, &ret_value,
+                                         u128_maxval(),
+                                         u128_from_pair(src_l, src_h));
+
+    if (ret != RISCV_EXCP_NONE) {
+        riscv_raise_exception(env, ret, GETPC());
+    }
+
+    if (rd != 0) {
+        env->gpr[rd] = u128_get_lo64(&ret_value);
+        env->gprh[rd] = u128_get_hi64(&ret_value);
+    }
+}
+
+void HELPER(csrrc_128)(CPURISCVState *env, target_ulong rd, target_ulong csrno,
+                       target_ulong src_l, target_ulong src_h)
+{
+    UINT128 ret_value = u128_zero();
+    RISCVException ret = riscv_csrrw_128(env, csrno, &ret_value,
+                                         u128_zero(),
+                                         u128_from_pair(src_l, src_h));
+
+    if (ret != RISCV_EXCP_NONE) {
+        riscv_raise_exception(env, ret, GETPC());
+    }
+
+    if (rd != 0) {
+        env->gpr[rd] = u128_get_lo64(&ret_value);
+        env->gprh[rd] = u128_get_hi64(&ret_value);
+    }
+}
+#endif
+
 #ifndef CONFIG_USER_ONLY
 
 target_ulong helper_sret(CPURISCVState *env, target_ulong cpu_pc_deb)
diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index 7d447bd225..5d0da1ce39 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -31,6 +31,10 @@ 
 
 #include "instmap.h"
 
+#if defined(TARGET_RISCV128)
+#include "utils_128.h"
+#endif
+
 /* global register indices */
 static TCGv cpu_gpr[32], cpu_pc, cpu_vl;
 #if defined(TARGET_RISCV128)
diff --git a/target/riscv/utils_128.h b/target/riscv/utils_128.h
new file mode 100644
index 0000000000..b149597fa1
--- /dev/null
+++ b/target/riscv/utils_128.h
@@ -0,0 +1,173 @@ 
+#ifndef QEMU_128_UTILS_128_H
+#define QEMU_128_UTILS_128_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "qemu/osdep.h"
+
+/*
+ * Defined to force the use of "software" 128-bit arithmetic
+ * (instead of the compiler's built-in type)
+ */
+#define SOFT_128BIT
+/*
+ * If available and not explicitly disabled,
+ * use compiler's 128-bit integers.
+ */
+#if defined(__SIZEOF_INT128__) && !defined(SOFT_128BIT)
+#define HARD_128BIT
+#endif
+
+/*
+ * Define a UINT128 type, that will either be a built-in type,
+ * or a struct packing a pair of 64-bit ints.
+ * of 64-bot values.
+ */
+#if defined(HARD_128BIT)
+#define UINT128 __uint128_t
+#define INT128 __int128_t
+#else
+typedef struct { uint64_t lo; uint64_t hi; } type_uint128;
+#define UINT128 type_uint128
+#endif
+
+/* Assignment operator for UINT128 */
+static inline void u128_assign(UINT128 *target, const UINT128 *val)
+{
+#if defined(HARD_128BIT)
+    *target = *val;
+#else
+    target->lo = val->lo;
+    target->hi = val->hi;
+#endif
+}
+
+static inline bool u128_is_nonzero(const UINT128 *val)
+{
+#if defined(HARD_128BIT)
+    return (*val) != 0;
+#else
+    return val->hi != 0 || val->lo != 0;
+#endif
+}
+
+static inline UINT128 u128_from_pair(uint64_t lo, uint64_t hi)
+{
+#if defined(HARD_128BIT)
+    return (((UINT128) hi) << 64) | lo;
+#else
+    return (UINT128) {lo, hi};
+#endif
+}
+
+/* Zero-extends a 64-bit value to a 128-bit one */
+static inline UINT128 u128_from64(uint64_t val)
+{
+    return u128_from_pair(val, 0);
+}
+
+static inline uint64_t u128_get_lo64(const UINT128 *val)
+{
+#if defined(HARD_128BIT)
+    return (*val) & 0xffffffffffffffff;
+#else
+    return val->lo;
+#endif
+}
+
+static inline uint64_t u128_get_hi64(const UINT128 *val)
+{
+#if defined(HARD_128BIT)
+    return ((*val) >> 64) & 0xffffffffffffffff;
+#else
+    return val->hi;
+#endif
+}
+
+/* Equivalents to u128_get_[lo/hi]64, but taking struct on stack */
+static inline uint64_t u128_lo64(const UINT128 val)
+{
+#if defined(HARD_128BIT)
+    return val & 0xffffffffffffffff;
+#else
+    return val.lo;
+#endif
+}
+
+static inline uint64_t u128_hi64(const UINT128 val)
+{
+#if defined(HARD_128BIT)
+    return (val >> 64) & 0xffffffffffffffff;
+#else
+    return val.hi;
+#endif
+}
+
+/* Bitwise logic operations needed to access csrs */
+static inline UINT128 u128_or(UINT128 a, UINT128 b)
+{
+#if defined(HARD_128BIT)
+    return a | b;
+#else
+    return (UINT128) {a.lo | b.lo, a.hi | b.hi};
+#endif
+}
+
+static inline UINT128 u128_and(UINT128 a, UINT128 b)
+{
+#if defined(HARD_128BIT)
+    return a & b;
+#else
+    return (UINT128) {a.lo & b.lo, a.hi & b.hi};
+#endif
+}
+
+static inline UINT128 u128_xor(UINT128 a, UINT128 b)
+{
+#if defined(HARD_128BIT)
+    return a ^ b;
+#else
+    return (UINT128) {a.lo ^ b.lo, a.hi ^ b.hi};
+#endif
+}
+
+static inline UINT128 u128_not(UINT128 a)
+{
+#if defined(HARD_128BIT)
+    return ~a;
+#else
+    return (UINT128) {~a.lo, ~a.hi};
+#endif
+}
+
+/* Static constants, should be easily inlined by compiler */
+static inline UINT128 u128_zero(void)
+{
+#if defined(HARD_128BIT)
+        return 0;
+#else
+        return (UINT128) {0, 0};
+#endif
+}
+
+static inline UINT128 u128_one(void)
+{
+#if defined(HARD_128BIT)
+    return 1;
+#else
+    return (UINT128) {1, 0};
+#endif
+}
+
+static inline UINT128 u128_maxval(void)
+{
+#if defined(HARD_128BIT)
+    UINT128 val = 0xffffffffffffffff;
+    return (val << 64) | 0xffffffffffffffff;
+#else
+    return (UINT128) {0xffffffffffffffff, 0xffffffffffffffff};
+#endif
+}
+
+#endif