diff mbox series

[v5,7/9] target/riscv: add support for Zcmt extension

Message ID 20221118123728.49319-8-liweiwei@iscas.ac.cn (mailing list archive)
State New, archived
Headers show
Series support subsets of code size reduction extension | expand

Commit Message

Weiwei Li Nov. 18, 2022, 12:37 p.m. UTC
Add encode, trans* functions and helper functions support for Zcmt
instrutions
Add support for jvt csr

Signed-off-by: Weiwei Li <liweiwei@iscas.ac.cn>
Signed-off-by: Junqiang Wang <wangjunqiang@iscas.ac.cn>
---
 target/riscv/cpu.h                        |  4 ++
 target/riscv/cpu_bits.h                   |  7 +++
 target/riscv/csr.c                        | 38 +++++++++++++++-
 target/riscv/helper.h                     |  3 ++
 target/riscv/insn16.decode                |  7 ++-
 target/riscv/insn_trans/trans_rvzce.c.inc | 28 +++++++++++-
 target/riscv/machine.c                    | 19 ++++++++
 target/riscv/meson.build                  |  3 +-
 target/riscv/zce_helper.c                 | 55 +++++++++++++++++++++++
 9 files changed, 159 insertions(+), 5 deletions(-)
 create mode 100644 target/riscv/zce_helper.c

Comments

Richard Henderson Nov. 18, 2022, 6:15 p.m. UTC | #1
On 11/18/22 04:37, Weiwei Li wrote:
> Add encode, trans* functions and helper functions support for Zcmt
> instrutions
> Add support for jvt csr
> 
> Signed-off-by: Weiwei Li<liweiwei@iscas.ac.cn>
> Signed-off-by: Junqiang Wang<wangjunqiang@iscas.ac.cn>
> ---
>   target/riscv/cpu.h                        |  4 ++
>   target/riscv/cpu_bits.h                   |  7 +++
>   target/riscv/csr.c                        | 38 +++++++++++++++-
>   target/riscv/helper.h                     |  3 ++
>   target/riscv/insn16.decode                |  7 ++-
>   target/riscv/insn_trans/trans_rvzce.c.inc | 28 +++++++++++-
>   target/riscv/machine.c                    | 19 ++++++++
>   target/riscv/meson.build                  |  3 +-
>   target/riscv/zce_helper.c                 | 55 +++++++++++++++++++++++
>   9 files changed, 159 insertions(+), 5 deletions(-)
>   create mode 100644 target/riscv/zce_helper.c

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~
Alistair Francis Nov. 22, 2022, 6:41 a.m. UTC | #2
On Fri, Nov 18, 2022 at 10:46 PM Weiwei Li <liweiwei@iscas.ac.cn> wrote:
>
> Add encode, trans* functions and helper functions support for Zcmt
> instrutions
> Add support for jvt csr
>
> Signed-off-by: Weiwei Li <liweiwei@iscas.ac.cn>
> Signed-off-by: Junqiang Wang <wangjunqiang@iscas.ac.cn>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  target/riscv/cpu.h                        |  4 ++
>  target/riscv/cpu_bits.h                   |  7 +++
>  target/riscv/csr.c                        | 38 +++++++++++++++-
>  target/riscv/helper.h                     |  3 ++
>  target/riscv/insn16.decode                |  7 ++-
>  target/riscv/insn_trans/trans_rvzce.c.inc | 28 +++++++++++-
>  target/riscv/machine.c                    | 19 ++++++++
>  target/riscv/meson.build                  |  3 +-
>  target/riscv/zce_helper.c                 | 55 +++++++++++++++++++++++
>  9 files changed, 159 insertions(+), 5 deletions(-)
>  create mode 100644 target/riscv/zce_helper.c
>
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index 6e915b6937..7bcedc7467 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -181,6 +181,8 @@ struct CPUArchState {
>
>      uint32_t features;
>
> +    target_ulong jvt;
> +
>  #ifdef CONFIG_USER_ONLY
>      uint32_t elf_flags;
>  #endif
> @@ -600,6 +602,8 @@ void riscv_cpu_set_aia_ireg_rmw_fn(CPURISCVState *env, uint32_t priv,
>                                                   target_ulong new_val,
>                                                   target_ulong write_mask),
>                                     void *rmw_fn_arg);
> +
> +RISCVException smstateen_acc_ok(CPURISCVState *env, int index, uint64_t bit);
>  #endif
>  void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv);
>
> diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
> index 8b0d7e20ea..ce347e5575 100644
> --- a/target/riscv/cpu_bits.h
> +++ b/target/riscv/cpu_bits.h
> @@ -319,6 +319,7 @@
>  #define SMSTATEEN_MAX_COUNT 4
>  #define SMSTATEEN0_CS       (1ULL << 0)
>  #define SMSTATEEN0_FCSR     (1ULL << 1)
> +#define SMSTATEEN0_JVT      (1ULL << 2)
>  #define SMSTATEEN0_HSCONTXT (1ULL << 57)
>  #define SMSTATEEN0_IMSIC    (1ULL << 58)
>  #define SMSTATEEN0_AIA      (1ULL << 59)
> @@ -523,6 +524,9 @@
>  /* Crypto Extension */
>  #define CSR_SEED            0x015
>
> +/* Zcmt Extension */
> +#define CSR_JVT             0x017
> +
>  /* mstatus CSR bits */
>  #define MSTATUS_UIE         0x00000001
>  #define MSTATUS_SIE         0x00000002
> @@ -894,4 +898,7 @@ typedef enum RISCVException {
>  #define MHPMEVENT_IDX_MASK                 0xFFFFF
>  #define MHPMEVENT_SSCOF_RESVD              16
>
> +/* JVT CSR bits */
> +#define JVT_MODE                           0x3F
> +#define JVT_BASE                           (~0x3F)
>  #endif
> diff --git a/target/riscv/csr.c b/target/riscv/csr.c
> index 8b25f885ec..5115dc882d 100644
> --- a/target/riscv/csr.c
> +++ b/target/riscv/csr.c
> @@ -42,8 +42,7 @@ void riscv_set_csr_ops(int csrno, riscv_csr_operations *ops)
>
>  /* Predicates */
>  #if !defined(CONFIG_USER_ONLY)
> -static RISCVException smstateen_acc_ok(CPURISCVState *env, int index,
> -                                       uint64_t bit)
> +RISCVException smstateen_acc_ok(CPURISCVState *env, int index, uint64_t bit)
>  {
>      bool virt = riscv_cpu_virt_enabled(env);
>      CPUState *cs = env_cpu(env);
> @@ -167,6 +166,24 @@ static RISCVException ctr32(CPURISCVState *env, int csrno)
>      return ctr(env, csrno);
>  }
>
> +static RISCVException zcmt(CPURISCVState *env, int csrno)
> +{
> +    RISCVCPU *cpu = env_archcpu(env);
> +
> +    if (!cpu->cfg.ext_zcmt) {
> +        return RISCV_EXCP_ILLEGAL_INST;
> +    }
> +
> +#if !defined(CONFIG_USER_ONLY)
> +    RISCVException ret = smstateen_acc_ok(env, 0, SMSTATEEN0_JVT);
> +    if (ret != RISCV_EXCP_NONE) {
> +        return ret;
> +    }
> +#endif
> +
> +    return RISCV_EXCP_NONE;
> +}
> +
>  #if !defined(CONFIG_USER_ONLY)
>  static RISCVException mctr(CPURISCVState *env, int csrno)
>  {
> @@ -3987,6 +4004,20 @@ RISCVException riscv_csrrw_debug(CPURISCVState *env, int csrno,
>      return ret;
>  }
>
> +static RISCVException read_jvt(CPURISCVState *env, int csrno,
> +                               target_ulong *val)
> +{
> +    *val = env->jvt;
> +    return RISCV_EXCP_NONE;
> +}
> +
> +static RISCVException write_jvt(CPURISCVState *env, int csrno,
> +                                target_ulong val)
> +{
> +    env->jvt = val;
> +    return RISCV_EXCP_NONE;
> +}
> +
>  /* Control and Status Register function table */
>  riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
>      /* User Floating-Point CSRs */
> @@ -4024,6 +4055,9 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
>      /* Crypto Extension */
>      [CSR_SEED] = { "seed", seed, NULL, NULL, rmw_seed },
>
> +    /* Zcmt Extension */
> +    [CSR_JVT] = {"jvt", zcmt, read_jvt, write_jvt},
> +
>  #if !defined(CONFIG_USER_ONLY)
>      /* Machine Timers and Counters */
>      [CSR_MCYCLE]    = { "mcycle",    any,   read_hpmcounter,
> diff --git a/target/riscv/helper.h b/target/riscv/helper.h
> index 227c7122ef..d979f0bfc4 100644
> --- a/target/riscv/helper.h
> +++ b/target/riscv/helper.h
> @@ -1136,3 +1136,6 @@ DEF_HELPER_FLAGS_1(aes64im, TCG_CALL_NO_RWG_SE, tl, tl)
>
>  DEF_HELPER_FLAGS_3(sm4ed, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl)
>  DEF_HELPER_FLAGS_3(sm4ks, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl)
> +
> +/* Zce helper */
> +DEF_HELPER_FLAGS_2(cm_jalt, TCG_CALL_NO_WG, tl, env, i32)
> diff --git a/target/riscv/insn16.decode b/target/riscv/insn16.decode
> index 4654c23052..c359c574ab 100644
> --- a/target/riscv/insn16.decode
> +++ b/target/riscv/insn16.decode
> @@ -49,6 +49,7 @@
>  %zcb_h_uimm  5:1                     !function=ex_shift_1
>  %zcmp_spimm  2:2                     !function=ex_shift_4
>  %zcmp_rlist  4:4
> +%zcmt_index  2:8
>
>  # Argument sets imported from insn32.decode:
>  &empty                  !extern
> @@ -63,6 +64,7 @@
>  &r2_s      rs1 rs2      !extern
>
>  &zcmp      zcmp_rlist zcmp_spimm
> +&zcmt      zcmt_index
>
>  # Formats 16:
>  @cr        ....  ..... .....  .. &r      rs2=%rs2_5       rs1=%rd     %rd
> @@ -106,6 +108,7 @@
>  @zcb_sh       ... . .. ... .. ... ..  &s  imm=%zcb_h_uimm  rs1=%rs1_3 rs2=%rs2_3
>  @zcmp         ... ...  ........   ..  &zcmp  %zcmp_rlist   %zcmp_spimm
>  @cm_mv        ... ...  ... .. ... ..  &r2_s  rs2=%sreg2    rs1=%sreg1
> +@zcmt_jt      ... ...  ........   ..  &zcmt  %zcmt_index
>
>  # *** RV32/64C Standard Extension (Quadrant 0) ***
>  {
> @@ -186,7 +189,7 @@ slli              000 .  .....  ..... 10 @c_shift2
>    sq              101  ... ... .. ... 10 @c_sqsp
>    c_fsd           101   ......  ..... 10 @c_sdsp
>
> -  # *** RV64 and RV32 Zcmp Extension ***
> +  # *** RV64 and RV32 Zcmp/Zcmt Extension ***
>    [
>      cm_push         101  11000  .... .. 10 @zcmp
>      cm_pop          101  11010  .... .. 10 @zcmp
> @@ -194,6 +197,8 @@ slli              000 .  .....  ..... 10 @c_shift2
>      cm_popretz      101  11100  .... .. 10 @zcmp
>      cm_mva01s       101  011 ... 11 ... 10 @cm_mv
>      cm_mvsa01       101  011 ... 01 ... 10 @cm_mv
> +
> +    cm_jalt         101  000   ........ 10 @zcmt_jt
>    ]
>  }
>  sw                110 .  .....  ..... 10 @c_swsp
> diff --git a/target/riscv/insn_trans/trans_rvzce.c.inc b/target/riscv/insn_trans/trans_rvzce.c.inc
> index f647b6ed15..43cbd822c5 100644
> --- a/target/riscv/insn_trans/trans_rvzce.c.inc
> +++ b/target/riscv/insn_trans/trans_rvzce.c.inc
> @@ -1,5 +1,5 @@
>  /*
> - * RISC-V translation routines for the Zc[b,mp] Standard Extension.
> + * RISC-V translation routines for the Zc[b,mp,mt] Standard Extension.
>   *
>   * Copyright (c) 2021-2022 PLCT Lab
>   *
> @@ -26,6 +26,11 @@
>          return false;            \
>  } while (0)
>
> +#define REQUIRE_ZCMT(ctx) do {   \
> +    if (!ctx->cfg_ptr->ext_zcmt) \
> +        return false;            \
> +} while (0)
> +
>  static bool trans_c_zext_b(DisasContext *ctx, arg_c_zext_b *a)
>  {
>      REQUIRE_ZCB(ctx);
> @@ -285,3 +290,24 @@ static bool trans_cm_mvsa01(DisasContext *ctx, arg_cm_mvsa01 *a)
>
>      return true;
>  }
> +
> +static bool trans_cm_jalt(DisasContext *ctx, arg_cm_jalt *a)
> +{
> +    REQUIRE_ZCMT(ctx);
> +
> +    /*
> +     * Update pc to current for the non-unwinding exception
> +     * that might come from cpu_ld*_code() in the helper.
> +     */
> +    tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next);
> +    gen_helper_cm_jalt(cpu_pc, cpu_env, tcg_constant_i32(a->zcmt_index));
> +
> +    /* c.jt vs c.jalt depends on the index. */
> +    if (a->zcmt_index >= 32) {
> +        gen_set_gpri(ctx, xRA, ctx->pc_succ_insn);
> +    }
> +
> +    tcg_gen_lookup_and_goto_ptr();
> +    ctx->base.is_jmp = DISAS_NORETURN;
> +    return true;
> +}
> diff --git a/target/riscv/machine.c b/target/riscv/machine.c
> index 65a8549ec2..ee3a2deab6 100644
> --- a/target/riscv/machine.c
> +++ b/target/riscv/machine.c
> @@ -331,6 +331,24 @@ static const VMStateDescription vmstate_pmu_ctr_state = {
>      }
>  };
>
> +static bool jvt_needed(void *opaque)
> +{
> +    RISCVCPU *cpu = opaque;
> +
> +    return cpu->cfg.ext_zcmt;
> +}
> +
> +static const VMStateDescription vmstate_jvt = {
> +    .name = "cpu/jvt",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .needed = jvt_needed,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINTTL(env.jvt, RISCVCPU),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
>  const VMStateDescription vmstate_riscv_cpu = {
>      .name = "cpu",
>      .version_id = 5,
> @@ -400,6 +418,7 @@ const VMStateDescription vmstate_riscv_cpu = {
>          &vmstate_envcfg,
>          &vmstate_debug,
>          &vmstate_smstateen,
> +        &vmstate_jvt,
>          NULL
>      }
>  };
> diff --git a/target/riscv/meson.build b/target/riscv/meson.build
> index ba25164d74..4bf9c9e632 100644
> --- a/target/riscv/meson.build
> +++ b/target/riscv/meson.build
> @@ -18,7 +18,8 @@ riscv_ss.add(files(
>    'bitmanip_helper.c',
>    'translate.c',
>    'm128_helper.c',
> -  'crypto_helper.c'
> +  'crypto_helper.c',
> +  'zce_helper.c'
>  ))
>  riscv_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c'), if_false: files('kvm-stub.c'))
>
> diff --git a/target/riscv/zce_helper.c b/target/riscv/zce_helper.c
> new file mode 100644
> index 0000000000..9cec8c19d6
> --- /dev/null
> +++ b/target/riscv/zce_helper.c
> @@ -0,0 +1,55 @@
> +/*
> + * RISC-V Zc* extension Helpers for QEMU.
> + *
> + * Copyright (c) 2021-2022 PLCT Lab
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2 or later, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "cpu.h"
> +#include "exec/exec-all.h"
> +#include "exec/helper-proto.h"
> +#include "exec/cpu_ldst.h"
> +
> +target_ulong HELPER(cm_jalt)(CPURISCVState *env, uint32_t index)
> +{
> +
> +#if !defined(CONFIG_USER_ONLY)
> +    RISCVException ret = smstateen_acc_ok(env, 0, SMSTATEEN0_JVT);
> +    if (ret != RISCV_EXCP_NONE) {
> +        riscv_raise_exception(env, ret, 0);
> +    }
> +#endif
> +
> +    target_ulong target;
> +    target_ulong val = env->jvt;
> +    int xlen = riscv_cpu_xlen(env);
> +    uint8_t mode = get_field(val, JVT_MODE);
> +    target_ulong base = get_field(val, JVT_BASE);
> +    target_ulong t0;
> +
> +    if (mode != 0) {
> +        riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, 0);
> +    }
> +
> +    if (xlen == 32) {
> +        t0 = base + (index << 2);
> +        target = cpu_ldl_code(env, t0);
> +    } else {
> +        t0 = base + (index << 3);
> +        target = cpu_ldq_code(env, t0);
> +    }
> +
> +    return target & ~0x1;
> +}
> --
> 2.25.1
>
>
diff mbox series

Patch

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 6e915b6937..7bcedc7467 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -181,6 +181,8 @@  struct CPUArchState {
 
     uint32_t features;
 
+    target_ulong jvt;
+
 #ifdef CONFIG_USER_ONLY
     uint32_t elf_flags;
 #endif
@@ -600,6 +602,8 @@  void riscv_cpu_set_aia_ireg_rmw_fn(CPURISCVState *env, uint32_t priv,
                                                  target_ulong new_val,
                                                  target_ulong write_mask),
                                    void *rmw_fn_arg);
+
+RISCVException smstateen_acc_ok(CPURISCVState *env, int index, uint64_t bit);
 #endif
 void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv);
 
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index 8b0d7e20ea..ce347e5575 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -319,6 +319,7 @@ 
 #define SMSTATEEN_MAX_COUNT 4
 #define SMSTATEEN0_CS       (1ULL << 0)
 #define SMSTATEEN0_FCSR     (1ULL << 1)
+#define SMSTATEEN0_JVT      (1ULL << 2)
 #define SMSTATEEN0_HSCONTXT (1ULL << 57)
 #define SMSTATEEN0_IMSIC    (1ULL << 58)
 #define SMSTATEEN0_AIA      (1ULL << 59)
@@ -523,6 +524,9 @@ 
 /* Crypto Extension */
 #define CSR_SEED            0x015
 
+/* Zcmt Extension */
+#define CSR_JVT             0x017
+
 /* mstatus CSR bits */
 #define MSTATUS_UIE         0x00000001
 #define MSTATUS_SIE         0x00000002
@@ -894,4 +898,7 @@  typedef enum RISCVException {
 #define MHPMEVENT_IDX_MASK                 0xFFFFF
 #define MHPMEVENT_SSCOF_RESVD              16
 
+/* JVT CSR bits */
+#define JVT_MODE                           0x3F
+#define JVT_BASE                           (~0x3F)
 #endif
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 8b25f885ec..5115dc882d 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -42,8 +42,7 @@  void riscv_set_csr_ops(int csrno, riscv_csr_operations *ops)
 
 /* Predicates */
 #if !defined(CONFIG_USER_ONLY)
-static RISCVException smstateen_acc_ok(CPURISCVState *env, int index,
-                                       uint64_t bit)
+RISCVException smstateen_acc_ok(CPURISCVState *env, int index, uint64_t bit)
 {
     bool virt = riscv_cpu_virt_enabled(env);
     CPUState *cs = env_cpu(env);
@@ -167,6 +166,24 @@  static RISCVException ctr32(CPURISCVState *env, int csrno)
     return ctr(env, csrno);
 }
 
+static RISCVException zcmt(CPURISCVState *env, int csrno)
+{
+    RISCVCPU *cpu = env_archcpu(env);
+
+    if (!cpu->cfg.ext_zcmt) {
+        return RISCV_EXCP_ILLEGAL_INST;
+    }
+
+#if !defined(CONFIG_USER_ONLY)
+    RISCVException ret = smstateen_acc_ok(env, 0, SMSTATEEN0_JVT);
+    if (ret != RISCV_EXCP_NONE) {
+        return ret;
+    }
+#endif
+
+    return RISCV_EXCP_NONE;
+}
+
 #if !defined(CONFIG_USER_ONLY)
 static RISCVException mctr(CPURISCVState *env, int csrno)
 {
@@ -3987,6 +4004,20 @@  RISCVException riscv_csrrw_debug(CPURISCVState *env, int csrno,
     return ret;
 }
 
+static RISCVException read_jvt(CPURISCVState *env, int csrno,
+                               target_ulong *val)
+{
+    *val = env->jvt;
+    return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_jvt(CPURISCVState *env, int csrno,
+                                target_ulong val)
+{
+    env->jvt = val;
+    return RISCV_EXCP_NONE;
+}
+
 /* Control and Status Register function table */
 riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
     /* User Floating-Point CSRs */
@@ -4024,6 +4055,9 @@  riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
     /* Crypto Extension */
     [CSR_SEED] = { "seed", seed, NULL, NULL, rmw_seed },
 
+    /* Zcmt Extension */
+    [CSR_JVT] = {"jvt", zcmt, read_jvt, write_jvt},
+
 #if !defined(CONFIG_USER_ONLY)
     /* Machine Timers and Counters */
     [CSR_MCYCLE]    = { "mcycle",    any,   read_hpmcounter,
diff --git a/target/riscv/helper.h b/target/riscv/helper.h
index 227c7122ef..d979f0bfc4 100644
--- a/target/riscv/helper.h
+++ b/target/riscv/helper.h
@@ -1136,3 +1136,6 @@  DEF_HELPER_FLAGS_1(aes64im, TCG_CALL_NO_RWG_SE, tl, tl)
 
 DEF_HELPER_FLAGS_3(sm4ed, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl)
 DEF_HELPER_FLAGS_3(sm4ks, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl)
+
+/* Zce helper */
+DEF_HELPER_FLAGS_2(cm_jalt, TCG_CALL_NO_WG, tl, env, i32)
diff --git a/target/riscv/insn16.decode b/target/riscv/insn16.decode
index 4654c23052..c359c574ab 100644
--- a/target/riscv/insn16.decode
+++ b/target/riscv/insn16.decode
@@ -49,6 +49,7 @@ 
 %zcb_h_uimm  5:1                     !function=ex_shift_1
 %zcmp_spimm  2:2                     !function=ex_shift_4
 %zcmp_rlist  4:4
+%zcmt_index  2:8
 
 # Argument sets imported from insn32.decode:
 &empty                  !extern
@@ -63,6 +64,7 @@ 
 &r2_s      rs1 rs2      !extern
 
 &zcmp      zcmp_rlist zcmp_spimm
+&zcmt      zcmt_index
 
 # Formats 16:
 @cr        ....  ..... .....  .. &r      rs2=%rs2_5       rs1=%rd     %rd
@@ -106,6 +108,7 @@ 
 @zcb_sh       ... . .. ... .. ... ..  &s  imm=%zcb_h_uimm  rs1=%rs1_3 rs2=%rs2_3
 @zcmp         ... ...  ........   ..  &zcmp  %zcmp_rlist   %zcmp_spimm
 @cm_mv        ... ...  ... .. ... ..  &r2_s  rs2=%sreg2    rs1=%sreg1
+@zcmt_jt      ... ...  ........   ..  &zcmt  %zcmt_index
 
 # *** RV32/64C Standard Extension (Quadrant 0) ***
 {
@@ -186,7 +189,7 @@  slli              000 .  .....  ..... 10 @c_shift2
   sq              101  ... ... .. ... 10 @c_sqsp
   c_fsd           101   ......  ..... 10 @c_sdsp
 
-  # *** RV64 and RV32 Zcmp Extension ***
+  # *** RV64 and RV32 Zcmp/Zcmt Extension ***
   [
     cm_push         101  11000  .... .. 10 @zcmp
     cm_pop          101  11010  .... .. 10 @zcmp
@@ -194,6 +197,8 @@  slli              000 .  .....  ..... 10 @c_shift2
     cm_popretz      101  11100  .... .. 10 @zcmp
     cm_mva01s       101  011 ... 11 ... 10 @cm_mv
     cm_mvsa01       101  011 ... 01 ... 10 @cm_mv
+
+    cm_jalt         101  000   ........ 10 @zcmt_jt
   ]
 }
 sw                110 .  .....  ..... 10 @c_swsp
diff --git a/target/riscv/insn_trans/trans_rvzce.c.inc b/target/riscv/insn_trans/trans_rvzce.c.inc
index f647b6ed15..43cbd822c5 100644
--- a/target/riscv/insn_trans/trans_rvzce.c.inc
+++ b/target/riscv/insn_trans/trans_rvzce.c.inc
@@ -1,5 +1,5 @@ 
 /*
- * RISC-V translation routines for the Zc[b,mp] Standard Extension.
+ * RISC-V translation routines for the Zc[b,mp,mt] Standard Extension.
  *
  * Copyright (c) 2021-2022 PLCT Lab
  *
@@ -26,6 +26,11 @@ 
         return false;            \
 } while (0)
 
+#define REQUIRE_ZCMT(ctx) do {   \
+    if (!ctx->cfg_ptr->ext_zcmt) \
+        return false;            \
+} while (0)
+
 static bool trans_c_zext_b(DisasContext *ctx, arg_c_zext_b *a)
 {
     REQUIRE_ZCB(ctx);
@@ -285,3 +290,24 @@  static bool trans_cm_mvsa01(DisasContext *ctx, arg_cm_mvsa01 *a)
 
     return true;
 }
+
+static bool trans_cm_jalt(DisasContext *ctx, arg_cm_jalt *a)
+{
+    REQUIRE_ZCMT(ctx);
+
+    /*
+     * Update pc to current for the non-unwinding exception
+     * that might come from cpu_ld*_code() in the helper.
+     */
+    tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next);
+    gen_helper_cm_jalt(cpu_pc, cpu_env, tcg_constant_i32(a->zcmt_index));
+
+    /* c.jt vs c.jalt depends on the index. */
+    if (a->zcmt_index >= 32) {
+        gen_set_gpri(ctx, xRA, ctx->pc_succ_insn);
+    }
+
+    tcg_gen_lookup_and_goto_ptr();
+    ctx->base.is_jmp = DISAS_NORETURN;
+    return true;
+}
diff --git a/target/riscv/machine.c b/target/riscv/machine.c
index 65a8549ec2..ee3a2deab6 100644
--- a/target/riscv/machine.c
+++ b/target/riscv/machine.c
@@ -331,6 +331,24 @@  static const VMStateDescription vmstate_pmu_ctr_state = {
     }
 };
 
+static bool jvt_needed(void *opaque)
+{
+    RISCVCPU *cpu = opaque;
+
+    return cpu->cfg.ext_zcmt;
+}
+
+static const VMStateDescription vmstate_jvt = {
+    .name = "cpu/jvt",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .needed = jvt_needed,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINTTL(env.jvt, RISCVCPU),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 const VMStateDescription vmstate_riscv_cpu = {
     .name = "cpu",
     .version_id = 5,
@@ -400,6 +418,7 @@  const VMStateDescription vmstate_riscv_cpu = {
         &vmstate_envcfg,
         &vmstate_debug,
         &vmstate_smstateen,
+        &vmstate_jvt,
         NULL
     }
 };
diff --git a/target/riscv/meson.build b/target/riscv/meson.build
index ba25164d74..4bf9c9e632 100644
--- a/target/riscv/meson.build
+++ b/target/riscv/meson.build
@@ -18,7 +18,8 @@  riscv_ss.add(files(
   'bitmanip_helper.c',
   'translate.c',
   'm128_helper.c',
-  'crypto_helper.c'
+  'crypto_helper.c',
+  'zce_helper.c'
 ))
 riscv_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c'), if_false: files('kvm-stub.c'))
 
diff --git a/target/riscv/zce_helper.c b/target/riscv/zce_helper.c
new file mode 100644
index 0000000000..9cec8c19d6
--- /dev/null
+++ b/target/riscv/zce_helper.c
@@ -0,0 +1,55 @@ 
+/*
+ * RISC-V Zc* extension Helpers for QEMU.
+ *
+ * Copyright (c) 2021-2022 PLCT Lab
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "exec/exec-all.h"
+#include "exec/helper-proto.h"
+#include "exec/cpu_ldst.h"
+
+target_ulong HELPER(cm_jalt)(CPURISCVState *env, uint32_t index)
+{
+
+#if !defined(CONFIG_USER_ONLY)
+    RISCVException ret = smstateen_acc_ok(env, 0, SMSTATEEN0_JVT);
+    if (ret != RISCV_EXCP_NONE) {
+        riscv_raise_exception(env, ret, 0);
+    }
+#endif
+
+    target_ulong target;
+    target_ulong val = env->jvt;
+    int xlen = riscv_cpu_xlen(env);
+    uint8_t mode = get_field(val, JVT_MODE);
+    target_ulong base = get_field(val, JVT_BASE);
+    target_ulong t0;
+
+    if (mode != 0) {
+        riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, 0);
+    }
+
+    if (xlen == 32) {
+        t0 = base + (index << 2);
+        target = cpu_ldl_code(env, t0);
+    } else {
+        t0 = base + (index << 3);
+        target = cpu_ldq_code(env, t0);
+    }
+
+    return target & ~0x1;
+}