@@ -926,6 +926,7 @@ static Property riscv_cpu_extensions[] = {
DEFINE_PROP_BOOL("xtheadcmo", RISCVCPU, cfg.ext_xtheadcmo, false),
DEFINE_PROP_BOOL("xtheadcondmov", RISCVCPU, cfg.ext_xtheadcondmov, false),
DEFINE_PROP_BOOL("xtheadmac", RISCVCPU, cfg.ext_xtheadmac, false),
+ DEFINE_PROP_BOOL("xtheadmempair", RISCVCPU, cfg.ext_xtheadmempair, false),
DEFINE_PROP_BOOL("xtheadsync", RISCVCPU, cfg.ext_xtheadsync, false),
DEFINE_PROP_BOOL("xtheadxmae", RISCVCPU, cfg.ext_xtheadxmae, false),
DEFINE_PROP_BOOL("xventanacondops", RISCVCPU, cfg.ext_XVentanaCondOps, false),
@@ -446,6 +446,7 @@ struct RISCVCPUConfig {
bool ext_xtheadcmo;
bool ext_xtheadcondmov;
bool ext_xtheadmac;
+ bool ext_xtheadmempair;
bool ext_xtheadsync;
bool ext_xtheadxmae;
bool ext_XVentanaCondOps;
@@ -284,3 +284,93 @@ static bool trans_th_mulsw(DisasContext *ctx, arg_th_mulsw *a)
ctx->ol = MXL_RV32;
return gen_th_mac(ctx, a, tcg_gen_sub_tl, NULL);
}
+
+static bool gen_loadpair_tl(DisasContext *ctx, arg_th_pair *a, MemOp memop,
+ int shamt)
+{
+ TCGv rd1 = dest_gpr(ctx, a->rd1);
+ TCGv rd2 = dest_gpr(ctx, a->rd2);
+ TCGv rs = get_gpr(ctx, a->rs, EXT_NONE);
+ TCGv addr1 = tcg_temp_new();
+ TCGv addr2 = tcg_temp_new();
+
+ tcg_gen_movi_tl(addr1, a->sh2);
+ tcg_gen_shli_tl(addr1, addr1, shamt);
+ tcg_gen_add_tl(addr1, rs, addr1);
+ if ((memop & MO_SIZE) == MO_64) {
+ tcg_gen_addi_tl(addr2, addr1, 8);
+ } else {
+ tcg_gen_addi_tl(addr2, addr1, 4);
+ }
+
+ if (get_xl(ctx) == MXL_RV32) {
+ tcg_gen_ext32u_tl(addr1, addr1);
+ tcg_gen_ext32u_tl(addr2, addr2);
+ }
+
+ tcg_gen_qemu_ld_tl(rd1, addr1, ctx->mem_idx, memop);
+ tcg_gen_qemu_ld_tl(rd2, addr2, ctx->mem_idx, memop);
+ gen_set_gpr(ctx, a->rd1, rd1);
+ gen_set_gpr(ctx, a->rd2, rd2);
+
+ tcg_temp_free(addr1);
+ tcg_temp_free(addr2);
+ return true;
+}
+
+static bool trans_th_ldd(DisasContext *ctx, arg_th_pair *a)
+{
+ REQUIRE_64BIT(ctx);
+ return gen_loadpair_tl(ctx, a, MO_TESQ, 4);
+}
+
+static bool trans_th_lwd(DisasContext *ctx, arg_th_pair *a)
+{
+ return gen_loadpair_tl(ctx, a, MO_TESL, 3);
+}
+
+static bool trans_th_lwud(DisasContext *ctx, arg_th_pair *a)
+{
+ return gen_loadpair_tl(ctx, a, MO_TEUL, 3);
+}
+
+static bool gen_storepair_tl(DisasContext *ctx, arg_th_pair *a, MemOp memop,
+ int shamt)
+{
+ TCGv data1 = get_gpr(ctx, a->rd1, EXT_NONE);
+ TCGv data2 = get_gpr(ctx, a->rd2, EXT_NONE);
+ TCGv rs = get_gpr(ctx, a->rs, EXT_NONE);
+ TCGv addr1 = tcg_temp_new();
+ TCGv addr2 = tcg_temp_new();
+
+ tcg_gen_movi_tl(addr1, a->sh2);
+ tcg_gen_shli_tl(addr1, addr1, shamt);
+ tcg_gen_add_tl(addr1, rs, addr1);
+ if ((memop & MO_SIZE) == MO_64) {
+ tcg_gen_addi_tl(addr2, addr1, 8);
+ } else {
+ tcg_gen_addi_tl(addr2, addr1, 4);
+ }
+
+ if (get_xl(ctx) == MXL_RV32) {
+ tcg_gen_ext32u_tl(addr1, addr1);
+ tcg_gen_ext32u_tl(addr2, addr2);
+ }
+
+ tcg_gen_qemu_st_tl(data1, addr1, ctx->mem_idx, memop);
+ tcg_gen_qemu_st_tl(data2, addr2, ctx->mem_idx, memop);
+
+ tcg_temp_free(addr1);
+ tcg_temp_free(addr2);
+ return true;
+}
+
+static bool trans_th_sdd(DisasContext *ctx, arg_th_pair *a)
+{
+ return gen_storepair_tl(ctx, a, MO_TESQ, 4);
+}
+
+static bool trans_th_swd(DisasContext *ctx, arg_th_pair *a)
+{
+ return gen_storepair_tl(ctx, a, MO_TESL, 3);
+}
@@ -8,6 +8,7 @@ gen = [
decodetree.process('xtheadcmo.decode', extra_args: '--static-decode=decode_xtheadcmo'),
decodetree.process('xtheadcondmov.decode', extra_args: '--static-decode=decode_xtheadcondmov'),
decodetree.process('xtheadmac.decode', extra_args: '--static-decode=decode_xtheadmac'),
+ decodetree.process('xtheadmempair.decode', extra_args: '--static-decode=decode_xtheadmempair'),
decodetree.process('xtheadsync.decode', extra_args: '--static-decode=decode_xtheadsync'),
decodetree.process('XVentanaCondOps.decode', extra_args: '--static-decode=decode_XVentanaCodeOps'),
]
@@ -138,6 +138,7 @@ MATERIALISE_EXT_PREDICATE(xtheadbs)
MATERIALISE_EXT_PREDICATE(xtheadcmo)
MATERIALISE_EXT_PREDICATE(xtheadcondmov);
MATERIALISE_EXT_PREDICATE(xtheadmac);
+MATERIALISE_EXT_PREDICATE(xtheadmempair);
MATERIALISE_EXT_PREDICATE(xtheadsync)
MATERIALISE_EXT_PREDICATE(XVentanaCondOps)
@@ -731,6 +732,7 @@ static int ex_rvc_shifti(DisasContext *ctx, int imm)
#include "decode-xtheadcmo.c.inc"
#include "decode-xtheadcondmov.c.inc"
#include "decode-xtheadmac.c.inc"
+#include "decode-xtheadmempair.c.inc"
#include "decode-xtheadsync.c.inc"
#include "decode-XVentanaCondOps.c.inc"
@@ -1058,6 +1060,7 @@ static void decode_opc(CPURISCVState *env, DisasContext *ctx, uint16_t opcode)
{ has_xtheadcmo_p, decode_xtheadcmo },
{ has_xtheadcondmov_p, decode_xtheadcondmov },
{ has_xtheadmac_p, decode_xtheadmac },
+ { has_xtheadmempair_p, decode_xtheadmempair },
{ has_xtheadsync_p, decode_xtheadsync },
{ has_XVentanaCondOps_p, decode_XVentanaCodeOps },
};
new file mode 100644
@@ -0,0 +1,29 @@
+#
+# RISC-V instruction decode for the XTheadMemPair extension
+#
+# Copyright (c) 2022 Christoph Muellner, christoph.muellner@vrull.eu
+#
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+# The XTheadMemPair extension provides two-GP-register operations.
+#
+# It is documented in
+# https://github.com/T-head-Semi/thead-extension-spec/releases/download/2.0.0/xthead-2022-09-05-2.0.0.pdf
+
+# Fields
+%sh2 25:2
+%rd2 20:5
+%rs 15:5
+%rd1 7:5
+
+# Argument sets
+&th_pair rd1 rs rd2 sh2
+
+# Formats:
+@th_pair ..... .. ..... ..... ... ..... ....... &th_pair %rd1 %rs %rd2 %sh2
+
+th_ldd 11111 .. ..... ..... 100 ..... 0001011 @th_pair
+th_lwd 11100 .. ..... ..... 100 ..... 0001011 @th_pair
+th_lwud 11110 .. ..... ..... 100 ..... 0001011 @th_pair
+th_sdd 11111 .. ..... ..... 101 ..... 0001011 @th_pair
+th_swd 11100 .. ..... ..... 101 ..... 0001011 @th_pair