From 81013f9e2b57dd32fa2f6dfd2f4cc8db8512c4e6 Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Mon, 18 Mar 2019 16:25:46 -0400 Subject: [PATCH] target/riscv: Convert RV32A insns to decodetree Backports commit 3b77c289aef21b33517f2fd7639cce13bed50cc1 from qemu --- qemu/target/riscv/insn32.decode | 17 ++ qemu/target/riscv/insn_trans/trans_rva.inc.c | 163 +++++++++++++++++++ qemu/target/riscv/insn_trans/trans_rvm.inc.c | 113 +++++++++++++ qemu/target/riscv/translate.c | 1 + 4 files changed, 294 insertions(+) create mode 100644 qemu/target/riscv/insn_trans/trans_rva.inc.c create mode 100644 qemu/target/riscv/insn_trans/trans_rvm.inc.c diff --git a/qemu/target/riscv/insn32.decode b/qemu/target/riscv/insn32.decode index e53944bf..00b9e2d9 100644 --- a/qemu/target/riscv/insn32.decode +++ b/qemu/target/riscv/insn32.decode @@ -34,6 +34,7 @@ # Argument sets: &b imm rs2 rs1 &shift shamt rs1 rd +&atomic aq rl rs2 rs1 rd # Formats 32: @r ....... ..... ..... ... ..... ....... %rs2 %rs1 %rd @@ -46,6 +47,9 @@ @sh ...... ...... ..... ... ..... ....... &shift shamt=%sh10 %rs1 %rd @csr ............ ..... ... ..... ....... %csr %rs1 %rd +@atom_ld ..... aq:1 rl:1 ..... ........ ..... ....... &atomic rs2=0 %rs1 %rd +@atom_st ..... aq:1 rl:1 ..... ........ ..... ....... &atomic %rs2 %rs1 %rd + # *** RV32I Base Instruction Set *** lui .................... ..... 0110111 @u auipc .................... ..... 0010111 @u @@ -102,3 +106,16 @@ div 0000001 ..... ..... 100 ..... 0110011 @r divu 0000001 ..... ..... 101 ..... 0110011 @r rem 0000001 ..... ..... 110 ..... 0110011 @r remu 0000001 ..... ..... 111 ..... 0110011 @r + +# *** RV32A Standard Extension *** +lr_w 00010 . . 00000 ..... 010 ..... 0101111 @atom_ld +sc_w 00011 . . ..... ..... 010 ..... 0101111 @atom_st +amoswap_w 00001 . . ..... ..... 010 ..... 0101111 @atom_st +amoadd_w 00000 . . ..... ..... 010 ..... 0101111 @atom_st +amoxor_w 00100 . . ..... ..... 010 ..... 0101111 @atom_st +amoand_w 01100 . . ..... ..... 010 ..... 0101111 @atom_st +amoor_w 01000 . . ..... ..... 010 ..... 0101111 @atom_st +amomin_w 10000 . . ..... ..... 010 ..... 0101111 @atom_st +amomax_w 10100 . . ..... ..... 010 ..... 0101111 @atom_st +amominu_w 11000 . . ..... ..... 010 ..... 0101111 @atom_st +amomaxu_w 11100 . . ..... ..... 010 ..... 0101111 @atom_st diff --git a/qemu/target/riscv/insn_trans/trans_rva.inc.c b/qemu/target/riscv/insn_trans/trans_rva.inc.c new file mode 100644 index 00000000..f72002d9 --- /dev/null +++ b/qemu/target/riscv/insn_trans/trans_rva.inc.c @@ -0,0 +1,163 @@ +/* + * RISC-V translation routines for the RV64A Standard Extension. + * + * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu + * Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de + * Bastian Koppelmann, kbastian@mail.uni-paderborn.de + * + * 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 . + */ + +static inline bool gen_lr(DisasContext *ctx, arg_atomic *a, TCGMemOp mop) +{ + TCGContext *tcg_ctx = ctx->uc->tcg_ctx; + TCGv src1 = tcg_temp_new(tcg_ctx); + /* Put addr in load_res, data in load_val. */ + gen_get_gpr(ctx, src1, a->rs1); + if (a->rl) { + tcg_gen_mb(tcg_ctx, TCG_MO_ALL | TCG_BAR_STRL); + } + tcg_gen_qemu_ld_tl(ctx->uc, tcg_ctx->load_val_risc, src1, ctx->mem_idx, mop); + if (a->aq) { + tcg_gen_mb(tcg_ctx, TCG_MO_ALL | TCG_BAR_LDAQ); + } + tcg_gen_mov_tl(tcg_ctx, tcg_ctx->load_res_risc, src1); + gen_set_gpr(ctx, a->rd, tcg_ctx->load_val_risc); + + tcg_temp_free(tcg_ctx, src1); + return true; +} + +static inline bool gen_sc(DisasContext *ctx, arg_atomic *a, TCGMemOp mop) +{ + TCGContext *tcg_ctx = ctx->uc->tcg_ctx; + TCGv src1 = tcg_temp_new(tcg_ctx); + TCGv src2 = tcg_temp_new(tcg_ctx); + TCGv dat = tcg_temp_new(tcg_ctx); + TCGLabel *l1 = gen_new_label(tcg_ctx); + TCGLabel *l2 = gen_new_label(tcg_ctx); + + gen_get_gpr(ctx, src1, a->rs1); + tcg_gen_brcond_tl(tcg_ctx, TCG_COND_NE, tcg_ctx->load_res_risc, src1, l1); + + gen_get_gpr(ctx, src2, a->rs2); + /* + * Note that the TCG atomic primitives are SC, + * so we can ignore AQ/RL along this path. + */ + tcg_gen_atomic_cmpxchg_tl(tcg_ctx, src1, tcg_ctx->load_res_risc, tcg_ctx->load_val_risc, src2, + ctx->mem_idx, mop); + tcg_gen_setcond_tl(tcg_ctx, TCG_COND_NE, dat, src1, tcg_ctx->load_val_risc); + gen_set_gpr(ctx, a->rd, dat); + tcg_gen_br(tcg_ctx, l2); + + gen_set_label(tcg_ctx, l1); + /* + * Address comparion failure. However, we still need to + * provide the memory barrier implied by AQ/RL. + */ + tcg_gen_mb(tcg_ctx, TCG_MO_ALL + a->aq * TCG_BAR_LDAQ + a->rl * TCG_BAR_STRL); + tcg_gen_movi_tl(tcg_ctx, dat, 1); + gen_set_gpr(ctx, a->rd, dat); + + gen_set_label(tcg_ctx, l2); + tcg_temp_free(tcg_ctx, dat); + tcg_temp_free(tcg_ctx, src1); + tcg_temp_free(tcg_ctx, src2); + return true; +} + +static bool gen_amo(DisasContext *ctx, arg_atomic *a, + void(*func)(TCGContext *, TCGv, TCGv, TCGv, TCGArg, TCGMemOp), + TCGMemOp mop) +{ + TCGContext *tcg_ctx = ctx->uc->tcg_ctx; + TCGv src1 = tcg_temp_new(tcg_ctx); + TCGv src2 = tcg_temp_new(tcg_ctx); + + gen_get_gpr(ctx, src1, a->rs1); + gen_get_gpr(ctx, src2, a->rs2); + + (*func)(tcg_ctx, src2, src1, src2, ctx->mem_idx, mop); + + gen_set_gpr(ctx, a->rd, src2); + tcg_temp_free(tcg_ctx, src1); + tcg_temp_free(tcg_ctx, src2); + return true; +} + +static bool trans_lr_w(DisasContext *ctx, arg_lr_w *a) +{ + REQUIRE_EXT(ctx, RVA); + return gen_lr(ctx, a, (MO_ALIGN | MO_TESL)); +} + +static bool trans_sc_w(DisasContext *ctx, arg_sc_w *a) +{ + REQUIRE_EXT(ctx, RVA); + return gen_sc(ctx, a, (MO_ALIGN | MO_TESL)); +} + +static bool trans_amoswap_w(DisasContext *ctx, arg_amoswap_w *a) +{ + REQUIRE_EXT(ctx, RVA); + return gen_amo(ctx, a, &tcg_gen_atomic_xchg_tl, (MO_ALIGN | MO_TESL)); +} + +static bool trans_amoadd_w(DisasContext *ctx, arg_amoadd_w *a) +{ + REQUIRE_EXT(ctx, RVA); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_add_tl, (MO_ALIGN | MO_TESL)); +} + +static bool trans_amoxor_w(DisasContext *ctx, arg_amoxor_w *a) +{ + REQUIRE_EXT(ctx, RVA); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_xor_tl, (MO_ALIGN | MO_TESL)); +} + +static bool trans_amoand_w(DisasContext *ctx, arg_amoand_w *a) +{ + REQUIRE_EXT(ctx, RVA); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_and_tl, (MO_ALIGN | MO_TESL)); +} + +static bool trans_amoor_w(DisasContext *ctx, arg_amoor_w *a) +{ + REQUIRE_EXT(ctx, RVA); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_or_tl, (MO_ALIGN | MO_TESL)); +} + +static bool trans_amomin_w(DisasContext *ctx, arg_amomin_w *a) +{ + REQUIRE_EXT(ctx, RVA); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smin_tl, (MO_ALIGN | MO_TESL)); +} + +static bool trans_amomax_w(DisasContext *ctx, arg_amomax_w *a) +{ + REQUIRE_EXT(ctx, RVA); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smax_tl, (MO_ALIGN | MO_TESL)); +} + +static bool trans_amominu_w(DisasContext *ctx, arg_amominu_w *a) +{ + REQUIRE_EXT(ctx, RVA); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umin_tl, (MO_ALIGN | MO_TESL)); +} + +static bool trans_amomaxu_w(DisasContext *ctx, arg_amomaxu_w *a) +{ + REQUIRE_EXT(ctx, RVA); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umax_tl, (MO_ALIGN | MO_TESL)); +} diff --git a/qemu/target/riscv/insn_trans/trans_rvm.inc.c b/qemu/target/riscv/insn_trans/trans_rvm.inc.c new file mode 100644 index 00000000..69631c9e --- /dev/null +++ b/qemu/target/riscv/insn_trans/trans_rvm.inc.c @@ -0,0 +1,113 @@ +/* + * RISC-V translation routines for the RV64M Standard Extension. + * + * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu + * Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de + * Bastian Koppelmann, kbastian@mail.uni-paderborn.de + * + * 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 . + */ + + +static bool trans_mul(DisasContext *ctx, arg_mul *a) +{ + REQUIRE_EXT(ctx, RVM); + gen_arith(ctx, OPC_RISC_MUL, a->rd, a->rs1, a->rs2); + return true; +} + +static bool trans_mulh(DisasContext *ctx, arg_mulh *a) +{ + REQUIRE_EXT(ctx, RVM); + gen_arith(ctx, OPC_RISC_MULH, a->rd, a->rs1, a->rs2); + return true; +} + +static bool trans_mulhsu(DisasContext *ctx, arg_mulhsu *a) +{ + REQUIRE_EXT(ctx, RVM); + gen_arith(ctx, OPC_RISC_MULHSU, a->rd, a->rs1, a->rs2); + return true; +} + +static bool trans_mulhu(DisasContext *ctx, arg_mulhu *a) +{ + REQUIRE_EXT(ctx, RVM); + gen_arith(ctx, OPC_RISC_MULHU, a->rd, a->rs1, a->rs2); + return true; +} + +static bool trans_div(DisasContext *ctx, arg_div *a) +{ + REQUIRE_EXT(ctx, RVM); + gen_arith(ctx, OPC_RISC_DIV, a->rd, a->rs1, a->rs2); + return true; +} + +static bool trans_divu(DisasContext *ctx, arg_divu *a) +{ + REQUIRE_EXT(ctx, RVM); + gen_arith(ctx, OPC_RISC_DIVU, a->rd, a->rs1, a->rs2); + return true; +} + +static bool trans_rem(DisasContext *ctx, arg_rem *a) +{ + REQUIRE_EXT(ctx, RVM); + gen_arith(ctx, OPC_RISC_REM, a->rd, a->rs1, a->rs2); + return true; +} + +static bool trans_remu(DisasContext *ctx, arg_remu *a) +{ + REQUIRE_EXT(ctx, RVM); + gen_arith(ctx, OPC_RISC_REMU, a->rd, a->rs1, a->rs2); + return true; +} + +#ifdef TARGET_RISCV64 +static bool trans_mulw(DisasContext *ctx, arg_mulw *a) +{ + REQUIRE_EXT(ctx, RVM); + gen_arith(ctx, OPC_RISC_MULW, a->rd, a->rs1, a->rs2); + return true; +} + +static bool trans_divw(DisasContext *ctx, arg_divw *a) +{ + REQUIRE_EXT(ctx, RVM); + gen_arith(ctx, OPC_RISC_DIVW, a->rd, a->rs1, a->rs2); + return true; +} + +static bool trans_divuw(DisasContext *ctx, arg_divuw *a) +{ + REQUIRE_EXT(ctx, RVM); + gen_arith(ctx, OPC_RISC_DIVUW, a->rd, a->rs1, a->rs2); + return true; +} + +static bool trans_remw(DisasContext *ctx, arg_remw *a) +{ + REQUIRE_EXT(ctx, RVM); + gen_arith(ctx, OPC_RISC_REMW, a->rd, a->rs1, a->rs2); + return true; +} + +static bool trans_remuw(DisasContext *ctx, arg_remuw *a) +{ + REQUIRE_EXT(ctx, RVM); + gen_arith(ctx, OPC_RISC_REMUW, a->rd, a->rs1, a->rs2); + return true; +} +#endif diff --git a/qemu/target/riscv/translate.c b/qemu/target/riscv/translate.c index 0c95076e..361b1b6b 100644 --- a/qemu/target/riscv/translate.c +++ b/qemu/target/riscv/translate.c @@ -1923,6 +1923,7 @@ bool decode_insn32(DisasContext *ctx, uint32_t insn); /* Include insn module translation function */ #include "insn_trans/trans_rvi.inc.c" #include "insn_trans/trans_rvm.inc.c" +#include "insn_trans/trans_rva.inc.c" static void decode_RV32_64G(DisasContext *ctx) {