import Unicorn2
This commit is contained in:
133
qemu/target/riscv/insn_trans/trans_privileged.inc.c
Normal file
133
qemu/target/riscv/insn_trans/trans_privileged.inc.c
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* RISC-V translation routines for the RISC-V privileged instructions.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
static bool trans_ecall(DisasContext *ctx, arg_ecall *a)
|
||||
{
|
||||
/* always generates U-level ECALL, fixed in do_interrupt handler */
|
||||
generate_exception(ctx, RISCV_EXCP_U_ECALL);
|
||||
exit_tb(ctx); /* no chaining */
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_ebreak(DisasContext *ctx, arg_ebreak *a)
|
||||
{
|
||||
// ignore this instruction
|
||||
generate_exception(ctx, RISCV_EXCP_BREAKPOINT);
|
||||
exit_tb(ctx); /* no chaining */
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_uret(DisasContext *ctx, arg_uret *a)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool trans_sret(DisasContext *ctx, arg_sret *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
tcg_gen_movi_tl(tcg_ctx, tcg_ctx->cpu_pc, ctx->base.pc_next);
|
||||
|
||||
if (has_ext(ctx, RVS)) {
|
||||
gen_helper_sret(tcg_ctx, tcg_ctx->cpu_pc, tcg_ctx->cpu_env, tcg_ctx->cpu_pc);
|
||||
exit_tb(ctx); /* no chaining */
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_mret(DisasContext *ctx, arg_mret *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
tcg_gen_movi_tl(tcg_ctx, tcg_ctx->cpu_pc, ctx->base.pc_next);
|
||||
gen_helper_mret(tcg_ctx, tcg_ctx->cpu_pc, tcg_ctx->cpu_env, tcg_ctx->cpu_pc);
|
||||
exit_tb(ctx); /* no chaining */
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_wfi(DisasContext *ctx, arg_wfi *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
tcg_gen_movi_tl(tcg_ctx, tcg_ctx->cpu_pc, ctx->pc_succ_insn);
|
||||
gen_helper_wfi(tcg_ctx, tcg_ctx->cpu_env);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_sfence_vma(DisasContext *ctx, arg_sfence_vma *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
if (ctx->priv_ver >= PRIV_VERSION_1_10_0) {
|
||||
gen_helper_tlb_flush(tcg_ctx, tcg_ctx->cpu_env);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool trans_sfence_vm(DisasContext *ctx, arg_sfence_vm *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
if (ctx->priv_ver <= PRIV_VERSION_1_09_1) {
|
||||
gen_helper_tlb_flush(tcg_ctx, tcg_ctx->cpu_env);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool trans_hfence_gvma(DisasContext *ctx, arg_sfence_vma *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
if (ctx->priv_ver >= PRIV_VERSION_1_10_0 &&
|
||||
has_ext(ctx, RVH)) {
|
||||
/* Hpervisor extensions exist */
|
||||
/*
|
||||
* if (env->priv == PRV_M ||
|
||||
* (env->priv == PRV_S &&
|
||||
* !riscv_cpu_virt_enabled(env) &&
|
||||
* get_field(ctx->mstatus_fs, MSTATUS_TVM))) {
|
||||
*/
|
||||
gen_helper_tlb_flush(tcg_ctx, tcg_ctx->cpu_env);
|
||||
return true;
|
||||
/* } */
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool trans_hfence_bvma(DisasContext *ctx, arg_sfence_vma *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
if (ctx->priv_ver >= PRIV_VERSION_1_10_0 &&
|
||||
has_ext(ctx, RVH)) {
|
||||
/* Hpervisor extensions exist */
|
||||
/*
|
||||
* if (env->priv == PRV_M ||
|
||||
* (env->priv == PRV_S &&
|
||||
* !riscv_cpu_virt_enabled(env) &&
|
||||
* get_field(ctx->mstatus_fs, MSTATUS_TVM))) {
|
||||
*/
|
||||
gen_helper_tlb_flush(tcg_ctx, tcg_ctx->cpu_env);
|
||||
return true;
|
||||
/* } */
|
||||
}
|
||||
return false;
|
||||
}
|
||||
227
qemu/target/riscv/insn_trans/trans_rva.inc.c
Normal file
227
qemu/target/riscv/insn_trans/trans_rva.inc.c
Normal file
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
static inline bool gen_lr(DisasContext *ctx, arg_atomic *a, MemOp 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(tcg_ctx, src1, a->rs1);
|
||||
if (a->rl) {
|
||||
tcg_gen_mb(tcg_ctx, TCG_MO_ALL | TCG_BAR_STRL);
|
||||
}
|
||||
tcg_gen_qemu_ld_tl(tcg_ctx, tcg_ctx->load_val, 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, src1);
|
||||
gen_set_gpr(tcg_ctx, a->rd, tcg_ctx->load_val);
|
||||
|
||||
tcg_temp_free(tcg_ctx, src1);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool gen_sc(DisasContext *ctx, arg_atomic *a, MemOp 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(tcg_ctx, src1, a->rs1);
|
||||
tcg_gen_brcond_tl(tcg_ctx, TCG_COND_NE, tcg_ctx->load_res, src1, l1);
|
||||
|
||||
gen_get_gpr(tcg_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, tcg_ctx->load_val, src2,
|
||||
ctx->mem_idx, mop);
|
||||
tcg_gen_setcond_tl(tcg_ctx, TCG_COND_NE, dat, src1, tcg_ctx->load_val);
|
||||
gen_set_gpr(tcg_ctx, a->rd, dat);
|
||||
tcg_gen_br(tcg_ctx, l2);
|
||||
|
||||
gen_set_label(tcg_ctx, l1);
|
||||
/*
|
||||
* Address comparison 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(tcg_ctx, a->rd, dat);
|
||||
|
||||
gen_set_label(tcg_ctx, l2);
|
||||
/*
|
||||
* Clear the load reservation, since an SC must fail if there is
|
||||
* an SC to any address, in between an LR and SC pair.
|
||||
*/
|
||||
tcg_gen_movi_tl(tcg_ctx, tcg_ctx->load_res, -1);
|
||||
|
||||
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, MemOp),
|
||||
MemOp 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(tcg_ctx, src1, a->rs1);
|
||||
gen_get_gpr(tcg_ctx, src2, a->rs2);
|
||||
|
||||
(*func)(tcg_ctx, src2, src1, src2, ctx->mem_idx, mop);
|
||||
|
||||
gen_set_gpr(tcg_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));
|
||||
}
|
||||
|
||||
#ifdef TARGET_RISCV64
|
||||
|
||||
static bool trans_lr_d(DisasContext *ctx, arg_lr_d *a)
|
||||
{
|
||||
return gen_lr(ctx, a, MO_ALIGN | MO_TEQ);
|
||||
}
|
||||
|
||||
static bool trans_sc_d(DisasContext *ctx, arg_sc_d *a)
|
||||
{
|
||||
return gen_sc(ctx, a, (MO_ALIGN | MO_TEQ));
|
||||
}
|
||||
|
||||
static bool trans_amoswap_d(DisasContext *ctx, arg_amoswap_d *a)
|
||||
{
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_xchg_tl, (MO_ALIGN | MO_TEQ));
|
||||
}
|
||||
|
||||
static bool trans_amoadd_d(DisasContext *ctx, arg_amoadd_d *a)
|
||||
{
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_add_tl, (MO_ALIGN | MO_TEQ));
|
||||
}
|
||||
|
||||
static bool trans_amoxor_d(DisasContext *ctx, arg_amoxor_d *a)
|
||||
{
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_xor_tl, (MO_ALIGN | MO_TEQ));
|
||||
}
|
||||
|
||||
static bool trans_amoand_d(DisasContext *ctx, arg_amoand_d *a)
|
||||
{
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_and_tl, (MO_ALIGN | MO_TEQ));
|
||||
}
|
||||
|
||||
static bool trans_amoor_d(DisasContext *ctx, arg_amoor_d *a)
|
||||
{
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_or_tl, (MO_ALIGN | MO_TEQ));
|
||||
}
|
||||
|
||||
static bool trans_amomin_d(DisasContext *ctx, arg_amomin_d *a)
|
||||
{
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smin_tl, (MO_ALIGN | MO_TEQ));
|
||||
}
|
||||
|
||||
static bool trans_amomax_d(DisasContext *ctx, arg_amomax_d *a)
|
||||
{
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smax_tl, (MO_ALIGN | MO_TEQ));
|
||||
}
|
||||
|
||||
static bool trans_amominu_d(DisasContext *ctx, arg_amominu_d *a)
|
||||
{
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umin_tl, (MO_ALIGN | MO_TEQ));
|
||||
}
|
||||
|
||||
static bool trans_amomaxu_d(DisasContext *ctx, arg_amomaxu_d *a)
|
||||
{
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umax_tl, (MO_ALIGN | MO_TEQ));
|
||||
}
|
||||
#endif
|
||||
473
qemu/target/riscv/insn_trans/trans_rvd.inc.c
Normal file
473
qemu/target/riscv/insn_trans/trans_rvd.inc.c
Normal file
@@ -0,0 +1,473 @@
|
||||
/*
|
||||
* RISC-V translation routines for the RV64D 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
static bool trans_fld(DisasContext *ctx, arg_fld *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
TCGv t0 = tcg_temp_new(tcg_ctx);
|
||||
gen_get_gpr(tcg_ctx, t0, a->rs1);
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
tcg_gen_addi_tl(tcg_ctx, t0, t0, a->imm);
|
||||
|
||||
tcg_gen_qemu_ld_i64(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], t0, ctx->mem_idx, MO_TEQ);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
tcg_temp_free(tcg_ctx, t0);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fsd(DisasContext *ctx, arg_fsd *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
TCGv t0 = tcg_temp_new(tcg_ctx);
|
||||
gen_get_gpr(tcg_ctx, t0, a->rs1);
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
tcg_gen_addi_tl(tcg_ctx, t0, t0, a->imm);
|
||||
|
||||
tcg_gen_qemu_st_i64(tcg_ctx, tcg_ctx->cpu_fpr[a->rs2], t0, ctx->mem_idx, MO_TEQ);
|
||||
|
||||
tcg_temp_free(tcg_ctx, t0);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fmadd_d(DisasContext *ctx, arg_fmadd_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fmadd_d(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], tcg_ctx->cpu_env, tcg_ctx->cpu_fpr[a->rs1],
|
||||
tcg_ctx->cpu_fpr[a->rs2], tcg_ctx->cpu_fpr[a->rs3]);
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fmsub_d(DisasContext *ctx, arg_fmsub_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fmsub_d(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], tcg_ctx->cpu_env, tcg_ctx->cpu_fpr[a->rs1],
|
||||
tcg_ctx->cpu_fpr[a->rs2], tcg_ctx->cpu_fpr[a->rs3]);
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fnmsub_d(DisasContext *ctx, arg_fnmsub_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fnmsub_d(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], tcg_ctx->cpu_env, tcg_ctx->cpu_fpr[a->rs1],
|
||||
tcg_ctx->cpu_fpr[a->rs2], tcg_ctx->cpu_fpr[a->rs3]);
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fnmadd_d(DisasContext *ctx, arg_fnmadd_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fnmadd_d(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], tcg_ctx->cpu_env, tcg_ctx->cpu_fpr[a->rs1],
|
||||
tcg_ctx->cpu_fpr[a->rs2], tcg_ctx->cpu_fpr[a->rs3]);
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fadd_d(DisasContext *ctx, arg_fadd_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fadd_d(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], tcg_ctx->cpu_env,
|
||||
tcg_ctx->cpu_fpr[a->rs1], tcg_ctx->cpu_fpr[a->rs2]);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fsub_d(DisasContext *ctx, arg_fsub_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fsub_d(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], tcg_ctx->cpu_env,
|
||||
tcg_ctx->cpu_fpr[a->rs1], tcg_ctx->cpu_fpr[a->rs2]);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fmul_d(DisasContext *ctx, arg_fmul_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fmul_d(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], tcg_ctx->cpu_env,
|
||||
tcg_ctx->cpu_fpr[a->rs1], tcg_ctx->cpu_fpr[a->rs2]);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fdiv_d(DisasContext *ctx, arg_fdiv_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fdiv_d(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], tcg_ctx->cpu_env,
|
||||
tcg_ctx->cpu_fpr[a->rs1], tcg_ctx->cpu_fpr[a->rs2]);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fsqrt_d(DisasContext *ctx, arg_fsqrt_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fsqrt_d(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], tcg_ctx->cpu_env, tcg_ctx->cpu_fpr[a->rs1]);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fsgnj_d(DisasContext *ctx, arg_fsgnj_d *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
if (a->rs1 == a->rs2) { /* FMOV */
|
||||
tcg_gen_mov_i64(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], tcg_ctx->cpu_fpr[a->rs1]);
|
||||
} else {
|
||||
tcg_gen_deposit_i64(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], tcg_ctx->cpu_fpr[a->rs2],
|
||||
tcg_ctx->cpu_fpr[a->rs1], 0, 63);
|
||||
}
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fsgnjn_d(DisasContext *ctx, arg_fsgnjn_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
if (a->rs1 == a->rs2) { /* FNEG */
|
||||
tcg_gen_xori_i64(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], tcg_ctx->cpu_fpr[a->rs1], INT64_MIN);
|
||||
} else {
|
||||
TCGv_i64 t0 = tcg_temp_new_i64(tcg_ctx);
|
||||
tcg_gen_not_i64(tcg_ctx, t0, tcg_ctx->cpu_fpr[a->rs2]);
|
||||
tcg_gen_deposit_i64(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], t0, tcg_ctx->cpu_fpr[a->rs1], 0, 63);
|
||||
tcg_temp_free_i64(tcg_ctx, t0);
|
||||
}
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fsgnjx_d(DisasContext *ctx, arg_fsgnjx_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
if (a->rs1 == a->rs2) { /* FABS */
|
||||
tcg_gen_andi_i64(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], tcg_ctx->cpu_fpr[a->rs1], ~INT64_MIN);
|
||||
} else {
|
||||
TCGv_i64 t0 = tcg_temp_new_i64(tcg_ctx);
|
||||
tcg_gen_andi_i64(tcg_ctx, t0, tcg_ctx->cpu_fpr[a->rs2], INT64_MIN);
|
||||
tcg_gen_xor_i64(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], tcg_ctx->cpu_fpr[a->rs1], t0);
|
||||
tcg_temp_free_i64(tcg_ctx, t0);
|
||||
}
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fmin_d(DisasContext *ctx, arg_fmin_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
gen_helper_fmin_d(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], tcg_ctx->cpu_env,
|
||||
tcg_ctx->cpu_fpr[a->rs1], tcg_ctx->cpu_fpr[a->rs2]);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fmax_d(DisasContext *ctx, arg_fmax_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
gen_helper_fmax_d(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], tcg_ctx->cpu_env,
|
||||
tcg_ctx->cpu_fpr[a->rs1], tcg_ctx->cpu_fpr[a->rs2]);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fcvt_s_d(DisasContext *ctx, arg_fcvt_s_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_s_d(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], tcg_ctx->cpu_env, tcg_ctx->cpu_fpr[a->rs1]);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fcvt_d_s(DisasContext *ctx, arg_fcvt_d_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_d_s(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], tcg_ctx->cpu_env, tcg_ctx->cpu_fpr[a->rs1]);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_feq_d(DisasContext *ctx, arg_feq_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
TCGv t0 = tcg_temp_new(tcg_ctx);
|
||||
gen_helper_feq_d(tcg_ctx, t0, tcg_ctx->cpu_env, tcg_ctx->cpu_fpr[a->rs1], tcg_ctx->cpu_fpr[a->rs2]);
|
||||
gen_set_gpr(tcg_ctx, a->rd, t0);
|
||||
tcg_temp_free(tcg_ctx, t0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_flt_d(DisasContext *ctx, arg_flt_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
TCGv t0 = tcg_temp_new(tcg_ctx);
|
||||
gen_helper_flt_d(tcg_ctx, t0, tcg_ctx->cpu_env, tcg_ctx->cpu_fpr[a->rs1], tcg_ctx->cpu_fpr[a->rs2]);
|
||||
gen_set_gpr(tcg_ctx, a->rd, t0);
|
||||
tcg_temp_free(tcg_ctx, t0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fle_d(DisasContext *ctx, arg_fle_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
TCGv t0 = tcg_temp_new(tcg_ctx);
|
||||
gen_helper_fle_d(tcg_ctx, t0, tcg_ctx->cpu_env, tcg_ctx->cpu_fpr[a->rs1], tcg_ctx->cpu_fpr[a->rs2]);
|
||||
gen_set_gpr(tcg_ctx, a->rd, t0);
|
||||
tcg_temp_free(tcg_ctx, t0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fclass_d(DisasContext *ctx, arg_fclass_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
TCGv t0 = tcg_temp_new(tcg_ctx);
|
||||
gen_helper_fclass_d(tcg_ctx, t0, tcg_ctx->cpu_fpr[a->rs1]);
|
||||
gen_set_gpr(tcg_ctx, a->rd, t0);
|
||||
tcg_temp_free(tcg_ctx, t0);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fcvt_w_d(DisasContext *ctx, arg_fcvt_w_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
TCGv t0 = tcg_temp_new(tcg_ctx);
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_w_d(tcg_ctx, t0, tcg_ctx->cpu_env, tcg_ctx->cpu_fpr[a->rs1]);
|
||||
gen_set_gpr(tcg_ctx, a->rd, t0);
|
||||
tcg_temp_free(tcg_ctx, t0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fcvt_wu_d(DisasContext *ctx, arg_fcvt_wu_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
TCGv t0 = tcg_temp_new(tcg_ctx);
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_wu_d(tcg_ctx, t0, tcg_ctx->cpu_env, tcg_ctx->cpu_fpr[a->rs1]);
|
||||
gen_set_gpr(tcg_ctx, a->rd, t0);
|
||||
tcg_temp_free(tcg_ctx, t0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fcvt_d_w(DisasContext *ctx, arg_fcvt_d_w *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
TCGv t0 = tcg_temp_new(tcg_ctx);
|
||||
gen_get_gpr(tcg_ctx, t0, a->rs1);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_d_w(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], tcg_ctx->cpu_env, t0);
|
||||
tcg_temp_free(tcg_ctx, t0);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fcvt_d_wu(DisasContext *ctx, arg_fcvt_d_wu *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
TCGv t0 = tcg_temp_new(tcg_ctx);
|
||||
gen_get_gpr(tcg_ctx, t0, a->rs1);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_d_wu(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], tcg_ctx->cpu_env, t0);
|
||||
tcg_temp_free(tcg_ctx, t0);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef TARGET_RISCV64
|
||||
|
||||
static bool trans_fcvt_l_d(DisasContext *ctx, arg_fcvt_l_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
TCGv t0 = tcg_temp_new(tcg_ctx);
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_l_d(tcg_ctx, t0, tcg_ctx->cpu_env, tcg_ctx->cpu_fpr[a->rs1]);
|
||||
gen_set_gpr(tcg_ctx, a->rd, t0);
|
||||
tcg_temp_free(tcg_ctx, t0);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fcvt_lu_d(DisasContext *ctx, arg_fcvt_lu_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
TCGv t0 = tcg_temp_new(tcg_ctx);
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_lu_d(tcg_ctx, t0, tcg_ctx->cpu_env, tcg_ctx->cpu_fpr[a->rs1]);
|
||||
gen_set_gpr(tcg_ctx, a->rd, t0);
|
||||
tcg_temp_free(tcg_ctx, t0);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fmv_x_d(DisasContext *ctx, arg_fmv_x_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
gen_set_gpr(tcg_ctx, a->rd, tcg_ctx->cpu_fpr[a->rs1]);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fcvt_d_l(DisasContext *ctx, arg_fcvt_d_l *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
TCGv t0 = tcg_temp_new(tcg_ctx);
|
||||
gen_get_gpr(tcg_ctx, t0, a->rs1);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_d_l(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], tcg_ctx->cpu_env, t0);
|
||||
tcg_temp_free(tcg_ctx, t0);
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fcvt_d_lu(DisasContext *ctx, arg_fcvt_d_lu *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
TCGv t0 = tcg_temp_new(tcg_ctx);
|
||||
gen_get_gpr(tcg_ctx, t0, a->rs1);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_d_lu(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], tcg_ctx->cpu_env, t0);
|
||||
tcg_temp_free(tcg_ctx, t0);
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fmv_d_x(DisasContext *ctx, arg_fmv_d_x *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
TCGv t0 = tcg_temp_new(tcg_ctx);
|
||||
gen_get_gpr(tcg_ctx, t0, a->rs1);
|
||||
|
||||
tcg_gen_mov_tl(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], t0);
|
||||
tcg_temp_free(tcg_ctx, t0);
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
474
qemu/target/riscv/insn_trans/trans_rvf.inc.c
Normal file
474
qemu/target/riscv/insn_trans/trans_rvf.inc.c
Normal file
@@ -0,0 +1,474 @@
|
||||
/*
|
||||
* RISC-V translation routines for the RV64F 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define REQUIRE_FPU do {\
|
||||
if (ctx->mstatus_fs == 0) \
|
||||
return false; \
|
||||
} while (0)
|
||||
|
||||
static bool trans_flw(DisasContext *ctx, arg_flw *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
TCGv t0 = tcg_temp_new(tcg_ctx);
|
||||
gen_get_gpr(tcg_ctx, t0, a->rs1);
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
tcg_gen_addi_tl(tcg_ctx, t0, t0, a->imm);
|
||||
|
||||
tcg_gen_qemu_ld_i64(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], t0, ctx->mem_idx, MO_TEUL);
|
||||
/* RISC-V requires NaN-boxing of narrower width floating point values */
|
||||
tcg_gen_ori_i64(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], tcg_ctx->cpu_fpr[a->rd], 0xffffffff00000000ULL);
|
||||
|
||||
tcg_temp_free(tcg_ctx, t0);
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fsw(DisasContext *ctx, arg_fsw *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
TCGv t0 = tcg_temp_new(tcg_ctx);
|
||||
gen_get_gpr(tcg_ctx, t0, a->rs1);
|
||||
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
tcg_gen_addi_tl(tcg_ctx, t0, t0, a->imm);
|
||||
|
||||
tcg_gen_qemu_st_i64(tcg_ctx, tcg_ctx->cpu_fpr[a->rs2], t0, ctx->mem_idx, MO_TEUL);
|
||||
|
||||
tcg_temp_free(tcg_ctx, t0);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fmadd_s(DisasContext *ctx, arg_fmadd_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fmadd_s(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], tcg_ctx->cpu_env, tcg_ctx->cpu_fpr[a->rs1],
|
||||
tcg_ctx->cpu_fpr[a->rs2], tcg_ctx->cpu_fpr[a->rs3]);
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fmsub_s(DisasContext *ctx, arg_fmsub_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fmsub_s(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], tcg_ctx->cpu_env, tcg_ctx->cpu_fpr[a->rs1],
|
||||
tcg_ctx->cpu_fpr[a->rs2], tcg_ctx->cpu_fpr[a->rs3]);
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fnmsub_s(DisasContext *ctx, arg_fnmsub_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fnmsub_s(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], tcg_ctx->cpu_env, tcg_ctx->cpu_fpr[a->rs1],
|
||||
tcg_ctx->cpu_fpr[a->rs2], tcg_ctx->cpu_fpr[a->rs3]);
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fnmadd_s(DisasContext *ctx, arg_fnmadd_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fnmadd_s(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], tcg_ctx->cpu_env, tcg_ctx->cpu_fpr[a->rs1],
|
||||
tcg_ctx->cpu_fpr[a->rs2], tcg_ctx->cpu_fpr[a->rs3]);
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fadd_s(DisasContext *ctx, arg_fadd_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fadd_s(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], tcg_ctx->cpu_env,
|
||||
tcg_ctx->cpu_fpr[a->rs1], tcg_ctx->cpu_fpr[a->rs2]);
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fsub_s(DisasContext *ctx, arg_fsub_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fsub_s(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], tcg_ctx->cpu_env,
|
||||
tcg_ctx->cpu_fpr[a->rs1], tcg_ctx->cpu_fpr[a->rs2]);
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fmul_s(DisasContext *ctx, arg_fmul_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fmul_s(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], tcg_ctx->cpu_env,
|
||||
tcg_ctx->cpu_fpr[a->rs1], tcg_ctx->cpu_fpr[a->rs2]);
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fdiv_s(DisasContext *ctx, arg_fdiv_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fdiv_s(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], tcg_ctx->cpu_env,
|
||||
tcg_ctx->cpu_fpr[a->rs1], tcg_ctx->cpu_fpr[a->rs2]);
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fsqrt_s(DisasContext *ctx, arg_fsqrt_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fsqrt_s(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], tcg_ctx->cpu_env, tcg_ctx->cpu_fpr[a->rs1]);
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fsgnj_s(DisasContext *ctx, arg_fsgnj_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
if (a->rs1 == a->rs2) { /* FMOV */
|
||||
tcg_gen_mov_i64(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], tcg_ctx->cpu_fpr[a->rs1]);
|
||||
} else { /* FSGNJ */
|
||||
tcg_gen_deposit_i64(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], tcg_ctx->cpu_fpr[a->rs2], tcg_ctx->cpu_fpr[a->rs1],
|
||||
0, 31);
|
||||
}
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fsgnjn_s(DisasContext *ctx, arg_fsgnjn_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
if (a->rs1 == a->rs2) { /* FNEG */
|
||||
tcg_gen_xori_i64(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], tcg_ctx->cpu_fpr[a->rs1], INT32_MIN);
|
||||
} else {
|
||||
TCGv_i64 t0 = tcg_temp_new_i64(tcg_ctx);
|
||||
tcg_gen_not_i64(tcg_ctx, t0, tcg_ctx->cpu_fpr[a->rs2]);
|
||||
tcg_gen_deposit_i64(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], t0, tcg_ctx->cpu_fpr[a->rs1], 0, 31);
|
||||
tcg_temp_free_i64(tcg_ctx, t0);
|
||||
}
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fsgnjx_s(DisasContext *ctx, arg_fsgnjx_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
if (a->rs1 == a->rs2) { /* FABS */
|
||||
tcg_gen_andi_i64(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], tcg_ctx->cpu_fpr[a->rs1], ~INT32_MIN);
|
||||
} else {
|
||||
TCGv_i64 t0 = tcg_temp_new_i64(tcg_ctx);
|
||||
tcg_gen_andi_i64(tcg_ctx, t0, tcg_ctx->cpu_fpr[a->rs2], INT32_MIN);
|
||||
tcg_gen_xor_i64(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], tcg_ctx->cpu_fpr[a->rs1], t0);
|
||||
tcg_temp_free_i64(tcg_ctx, t0);
|
||||
}
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fmin_s(DisasContext *ctx, arg_fmin_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
gen_helper_fmin_s(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], tcg_ctx->cpu_env, tcg_ctx->cpu_fpr[a->rs1],
|
||||
tcg_ctx->cpu_fpr[a->rs2]);
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fmax_s(DisasContext *ctx, arg_fmax_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
gen_helper_fmax_s(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], tcg_ctx->cpu_env, tcg_ctx->cpu_fpr[a->rs1],
|
||||
tcg_ctx->cpu_fpr[a->rs2]);
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fcvt_w_s(DisasContext *ctx, arg_fcvt_w_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
TCGv t0 = tcg_temp_new(tcg_ctx);
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_w_s(tcg_ctx, t0, tcg_ctx->cpu_env, tcg_ctx->cpu_fpr[a->rs1]);
|
||||
gen_set_gpr(tcg_ctx, a->rd, t0);
|
||||
tcg_temp_free(tcg_ctx, t0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fcvt_wu_s(DisasContext *ctx, arg_fcvt_wu_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
TCGv t0 = tcg_temp_new(tcg_ctx);
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_wu_s(tcg_ctx, t0, tcg_ctx->cpu_env, tcg_ctx->cpu_fpr[a->rs1]);
|
||||
gen_set_gpr(tcg_ctx, a->rd, t0);
|
||||
tcg_temp_free(tcg_ctx, t0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fmv_x_w(DisasContext *ctx, arg_fmv_x_w *a)
|
||||
{
|
||||
/* NOTE: This was FMV.X.S in an earlier version of the ISA spec! */
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
TCGv t0 = tcg_temp_new(tcg_ctx);
|
||||
|
||||
#if defined(TARGET_RISCV64)
|
||||
tcg_gen_ext32s_tl(tcg_ctx, t0, tcg_ctx->cpu_fpr[a->rs1]);
|
||||
#else
|
||||
tcg_gen_extrl_i64_i32(tcg_ctx, t0, tcg_ctx->cpu_fpr[a->rs1]);
|
||||
#endif
|
||||
|
||||
gen_set_gpr(tcg_ctx, a->rd, t0);
|
||||
tcg_temp_free(tcg_ctx, t0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_feq_s(DisasContext *ctx, arg_feq_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
TCGv t0 = tcg_temp_new(tcg_ctx);
|
||||
gen_helper_feq_s(tcg_ctx, t0, tcg_ctx->cpu_env, tcg_ctx->cpu_fpr[a->rs1], tcg_ctx->cpu_fpr[a->rs2]);
|
||||
gen_set_gpr(tcg_ctx, a->rd, t0);
|
||||
tcg_temp_free(tcg_ctx, t0);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_flt_s(DisasContext *ctx, arg_flt_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
TCGv t0 = tcg_temp_new(tcg_ctx);
|
||||
gen_helper_flt_s(tcg_ctx, t0, tcg_ctx->cpu_env, tcg_ctx->cpu_fpr[a->rs1], tcg_ctx->cpu_fpr[a->rs2]);
|
||||
gen_set_gpr(tcg_ctx, a->rd, t0);
|
||||
tcg_temp_free(tcg_ctx, t0);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fle_s(DisasContext *ctx, arg_fle_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
TCGv t0 = tcg_temp_new(tcg_ctx);
|
||||
gen_helper_fle_s(tcg_ctx, t0, tcg_ctx->cpu_env, tcg_ctx->cpu_fpr[a->rs1], tcg_ctx->cpu_fpr[a->rs2]);
|
||||
gen_set_gpr(tcg_ctx, a->rd, t0);
|
||||
tcg_temp_free(tcg_ctx, t0);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fclass_s(DisasContext *ctx, arg_fclass_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
TCGv t0 = tcg_temp_new(tcg_ctx);
|
||||
|
||||
gen_helper_fclass_s(tcg_ctx, t0, tcg_ctx->cpu_fpr[a->rs1]);
|
||||
|
||||
gen_set_gpr(tcg_ctx, a->rd, t0);
|
||||
tcg_temp_free(tcg_ctx, t0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fcvt_s_w(DisasContext *ctx, arg_fcvt_s_w *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
TCGv t0 = tcg_temp_new(tcg_ctx);
|
||||
gen_get_gpr(tcg_ctx, t0, a->rs1);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_s_w(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], tcg_ctx->cpu_env, t0);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
tcg_temp_free(tcg_ctx, t0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fcvt_s_wu(DisasContext *ctx, arg_fcvt_s_wu *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
TCGv t0 = tcg_temp_new(tcg_ctx);
|
||||
gen_get_gpr(tcg_ctx, t0, a->rs1);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_s_wu(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], tcg_ctx->cpu_env, t0);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
tcg_temp_free(tcg_ctx, t0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fmv_w_x(DisasContext *ctx, arg_fmv_w_x *a)
|
||||
{
|
||||
/* NOTE: This was FMV.S.X in an earlier version of the ISA spec! */
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
TCGv t0 = tcg_temp_new(tcg_ctx);
|
||||
gen_get_gpr(tcg_ctx, t0, a->rs1);
|
||||
|
||||
#if defined(TARGET_RISCV64)
|
||||
tcg_gen_mov_i64(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], t0);
|
||||
#else
|
||||
tcg_gen_extu_i32_i64(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], t0);
|
||||
#endif
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
tcg_temp_free(tcg_ctx, t0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef TARGET_RISCV64
|
||||
static bool trans_fcvt_l_s(DisasContext *ctx, arg_fcvt_l_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
TCGv t0 = tcg_temp_new(tcg_ctx);
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_l_s(tcg_ctx, t0, tcg_ctx->cpu_env, tcg_ctx->cpu_fpr[a->rs1]);
|
||||
gen_set_gpr(tcg_ctx, a->rd, t0);
|
||||
tcg_temp_free(tcg_ctx, t0);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fcvt_lu_s(DisasContext *ctx, arg_fcvt_lu_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
TCGv t0 = tcg_temp_new(tcg_ctx);
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_lu_s(tcg_ctx, t0, tcg_ctx->cpu_env, tcg_ctx->cpu_fpr[a->rs1]);
|
||||
gen_set_gpr(tcg_ctx, a->rd, t0);
|
||||
tcg_temp_free(tcg_ctx, t0);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fcvt_s_l(DisasContext *ctx, arg_fcvt_s_l *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
TCGv t0 = tcg_temp_new(tcg_ctx);
|
||||
gen_get_gpr(tcg_ctx, t0, a->rs1);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_s_l(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], tcg_ctx->cpu_env, t0);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
tcg_temp_free(tcg_ctx, t0);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fcvt_s_lu(DisasContext *ctx, arg_fcvt_s_lu *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
TCGv t0 = tcg_temp_new(tcg_ctx);
|
||||
gen_get_gpr(tcg_ctx, t0, a->rs1);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_s_lu(tcg_ctx, tcg_ctx->cpu_fpr[a->rd], tcg_ctx->cpu_env, t0);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
tcg_temp_free(tcg_ctx, t0);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
613
qemu/target/riscv/insn_trans/trans_rvi.inc.c
Normal file
613
qemu/target/riscv/insn_trans/trans_rvi.inc.c
Normal file
@@ -0,0 +1,613 @@
|
||||
/*
|
||||
* RISC-V translation routines for the RVXI Base Integer Instruction Set.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
static bool trans_illegal(DisasContext *ctx, arg_empty *a)
|
||||
{
|
||||
gen_exception_illegal(ctx);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_lui(DisasContext *ctx, arg_lui *a)
|
||||
{
|
||||
if (a->rd != 0) {
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
tcg_gen_movi_tl(tcg_ctx, tcg_ctx->cpu_gpr[a->rd], a->imm);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_auipc(DisasContext *ctx, arg_auipc *a)
|
||||
{
|
||||
if (a->rd != 0) {
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
tcg_gen_movi_tl(tcg_ctx, tcg_ctx->cpu_gpr[a->rd], a->imm + ctx->base.pc_next);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_jal(DisasContext *ctx, arg_jal *a)
|
||||
{
|
||||
gen_jal(ctx, a->rd, a->imm);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_jalr(DisasContext *ctx, arg_jalr *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
/* no chaining with JALR */
|
||||
TCGLabel *misaligned = NULL;
|
||||
TCGv t0 = tcg_temp_new(tcg_ctx);
|
||||
|
||||
gen_get_gpr(tcg_ctx, tcg_ctx->cpu_pc, a->rs1);
|
||||
tcg_gen_addi_tl(tcg_ctx, tcg_ctx->cpu_pc, tcg_ctx->cpu_pc, a->imm);
|
||||
tcg_gen_andi_tl(tcg_ctx, tcg_ctx->cpu_pc, tcg_ctx->cpu_pc, (target_ulong)-2);
|
||||
|
||||
if (!has_ext(ctx, RVC)) {
|
||||
misaligned = gen_new_label(tcg_ctx);
|
||||
tcg_gen_andi_tl(tcg_ctx, t0, tcg_ctx->cpu_pc, 0x2);
|
||||
tcg_gen_brcondi_tl(tcg_ctx, TCG_COND_NE, t0, 0x0, misaligned);
|
||||
}
|
||||
|
||||
if (a->rd != 0) {
|
||||
tcg_gen_movi_tl(tcg_ctx, tcg_ctx->cpu_gpr[a->rd], ctx->pc_succ_insn);
|
||||
}
|
||||
lookup_and_goto_ptr(ctx);
|
||||
|
||||
if (misaligned) {
|
||||
gen_set_label(tcg_ctx, misaligned);
|
||||
gen_exception_inst_addr_mis(ctx);
|
||||
}
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
|
||||
tcg_temp_free(tcg_ctx, t0);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool gen_branch(DisasContext *ctx, arg_b *a, TCGCond cond)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
TCGLabel *l = gen_new_label(tcg_ctx);
|
||||
TCGv source1, source2;
|
||||
source1 = tcg_temp_new(tcg_ctx);
|
||||
source2 = tcg_temp_new(tcg_ctx);
|
||||
gen_get_gpr(tcg_ctx, source1, a->rs1);
|
||||
gen_get_gpr(tcg_ctx, source2, a->rs2);
|
||||
|
||||
tcg_gen_brcond_tl(tcg_ctx, cond, source1, source2, l);
|
||||
gen_goto_tb(ctx, 1, ctx->pc_succ_insn);
|
||||
gen_set_label(tcg_ctx, l); /* branch taken */
|
||||
|
||||
if (!has_ext(ctx, RVC) && ((ctx->base.pc_next + a->imm) & 0x3)) {
|
||||
/* misaligned */
|
||||
gen_exception_inst_addr_mis(ctx);
|
||||
} else {
|
||||
gen_goto_tb(ctx, 0, ctx->base.pc_next + a->imm);
|
||||
}
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
|
||||
tcg_temp_free(tcg_ctx, source1);
|
||||
tcg_temp_free(tcg_ctx, source2);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_beq(DisasContext *ctx, arg_beq *a)
|
||||
{
|
||||
return gen_branch(ctx, a, TCG_COND_EQ);
|
||||
}
|
||||
|
||||
static bool trans_bne(DisasContext *ctx, arg_bne *a)
|
||||
{
|
||||
return gen_branch(ctx, a, TCG_COND_NE);
|
||||
}
|
||||
|
||||
static bool trans_blt(DisasContext *ctx, arg_blt *a)
|
||||
{
|
||||
return gen_branch(ctx, a, TCG_COND_LT);
|
||||
}
|
||||
|
||||
static bool trans_bge(DisasContext *ctx, arg_bge *a)
|
||||
{
|
||||
return gen_branch(ctx, a, TCG_COND_GE);
|
||||
}
|
||||
|
||||
static bool trans_bltu(DisasContext *ctx, arg_bltu *a)
|
||||
{
|
||||
return gen_branch(ctx, a, TCG_COND_LTU);
|
||||
}
|
||||
|
||||
static bool trans_bgeu(DisasContext *ctx, arg_bgeu *a)
|
||||
{
|
||||
return gen_branch(ctx, a, TCG_COND_GEU);
|
||||
}
|
||||
|
||||
static bool gen_load(DisasContext *ctx, arg_lb *a, MemOp memop)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
TCGv t0 = tcg_temp_new(tcg_ctx);
|
||||
TCGv t1 = tcg_temp_new(tcg_ctx);
|
||||
gen_get_gpr(tcg_ctx, t0, a->rs1);
|
||||
tcg_gen_addi_tl(tcg_ctx, t0, t0, a->imm);
|
||||
|
||||
tcg_gen_qemu_ld_tl(tcg_ctx, t1, t0, ctx->mem_idx, memop);
|
||||
gen_set_gpr(tcg_ctx, a->rd, t1);
|
||||
tcg_temp_free(tcg_ctx, t0);
|
||||
tcg_temp_free(tcg_ctx, t1);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_lb(DisasContext *ctx, arg_lb *a)
|
||||
{
|
||||
return gen_load(ctx, a, MO_SB);
|
||||
}
|
||||
|
||||
static bool trans_lh(DisasContext *ctx, arg_lh *a)
|
||||
{
|
||||
return gen_load(ctx, a, MO_TESW);
|
||||
}
|
||||
|
||||
static bool trans_lw(DisasContext *ctx, arg_lw *a)
|
||||
{
|
||||
return gen_load(ctx, a, MO_TESL);
|
||||
}
|
||||
|
||||
static bool trans_lbu(DisasContext *ctx, arg_lbu *a)
|
||||
{
|
||||
return gen_load(ctx, a, MO_UB);
|
||||
}
|
||||
|
||||
static bool trans_lhu(DisasContext *ctx, arg_lhu *a)
|
||||
{
|
||||
return gen_load(ctx, a, MO_TEUW);
|
||||
}
|
||||
|
||||
static bool gen_store(DisasContext *ctx, arg_sb *a, MemOp memop)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
TCGv t0 = tcg_temp_new(tcg_ctx);
|
||||
TCGv dat = tcg_temp_new(tcg_ctx);
|
||||
gen_get_gpr(tcg_ctx, t0, a->rs1);
|
||||
tcg_gen_addi_tl(tcg_ctx, t0, t0, a->imm);
|
||||
gen_get_gpr(tcg_ctx, dat, a->rs2);
|
||||
|
||||
tcg_gen_qemu_st_tl(tcg_ctx, dat, t0, ctx->mem_idx, memop);
|
||||
tcg_temp_free(tcg_ctx, t0);
|
||||
tcg_temp_free(tcg_ctx, dat);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool trans_sb(DisasContext *ctx, arg_sb *a)
|
||||
{
|
||||
return gen_store(ctx, a, MO_SB);
|
||||
}
|
||||
|
||||
static bool trans_sh(DisasContext *ctx, arg_sh *a)
|
||||
{
|
||||
return gen_store(ctx, a, MO_TESW);
|
||||
}
|
||||
|
||||
static bool trans_sw(DisasContext *ctx, arg_sw *a)
|
||||
{
|
||||
return gen_store(ctx, a, MO_TESL);
|
||||
}
|
||||
|
||||
#ifdef TARGET_RISCV64
|
||||
static bool trans_lwu(DisasContext *ctx, arg_lwu *a)
|
||||
{
|
||||
return gen_load(ctx, a, MO_TEUL);
|
||||
}
|
||||
|
||||
static bool trans_ld(DisasContext *ctx, arg_ld *a)
|
||||
{
|
||||
return gen_load(ctx, a, MO_TEQ);
|
||||
}
|
||||
|
||||
static bool trans_sd(DisasContext *ctx, arg_sd *a)
|
||||
{
|
||||
return gen_store(ctx, a, MO_TEQ);
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool trans_addi(DisasContext *ctx, arg_addi *a)
|
||||
{
|
||||
return gen_arith_imm_fn(ctx, a, &tcg_gen_addi_tl);
|
||||
}
|
||||
|
||||
static void gen_slt(TCGContext *tcg_ctx, TCGv ret, TCGv s1, TCGv s2)
|
||||
{
|
||||
tcg_gen_setcond_tl(tcg_ctx, TCG_COND_LT, ret, s1, s2);
|
||||
}
|
||||
|
||||
static void gen_sltu(TCGContext *tcg_ctx, TCGv ret, TCGv s1, TCGv s2)
|
||||
{
|
||||
tcg_gen_setcond_tl(tcg_ctx, TCG_COND_LTU, ret, s1, s2);
|
||||
}
|
||||
|
||||
|
||||
static bool trans_slti(DisasContext *ctx, arg_slti *a)
|
||||
{
|
||||
return gen_arith_imm_tl(ctx, a, &gen_slt);
|
||||
}
|
||||
|
||||
static bool trans_sltiu(DisasContext *ctx, arg_sltiu *a)
|
||||
{
|
||||
return gen_arith_imm_tl(ctx, a, &gen_sltu);
|
||||
}
|
||||
|
||||
static bool trans_xori(DisasContext *ctx, arg_xori *a)
|
||||
{
|
||||
return gen_arith_imm_fn(ctx, a, &tcg_gen_xori_tl);
|
||||
}
|
||||
static bool trans_ori(DisasContext *ctx, arg_ori *a)
|
||||
{
|
||||
return gen_arith_imm_fn(ctx, a, &tcg_gen_ori_tl);
|
||||
}
|
||||
static bool trans_andi(DisasContext *ctx, arg_andi *a)
|
||||
{
|
||||
return gen_arith_imm_fn(ctx, a, &tcg_gen_andi_tl);
|
||||
}
|
||||
static bool trans_slli(DisasContext *ctx, arg_slli *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
if (a->shamt >= TARGET_LONG_BITS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a->rd != 0) {
|
||||
TCGv t = tcg_temp_new(tcg_ctx);
|
||||
gen_get_gpr(tcg_ctx, t, a->rs1);
|
||||
|
||||
tcg_gen_shli_tl(tcg_ctx, t, t, a->shamt);
|
||||
|
||||
gen_set_gpr(tcg_ctx, a->rd, t);
|
||||
tcg_temp_free(tcg_ctx, t);
|
||||
} /* NOP otherwise */
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_srli(DisasContext *ctx, arg_srli *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
if (a->shamt >= TARGET_LONG_BITS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a->rd != 0) {
|
||||
TCGv t = tcg_temp_new(tcg_ctx);
|
||||
gen_get_gpr(tcg_ctx, t, a->rs1);
|
||||
|
||||
tcg_gen_shri_tl(tcg_ctx, t, t, a->shamt);
|
||||
gen_set_gpr(tcg_ctx, a->rd, t);
|
||||
tcg_temp_free(tcg_ctx, t);
|
||||
} /* NOP otherwise */
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_srai(DisasContext *ctx, arg_srai *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
if (a->shamt >= TARGET_LONG_BITS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a->rd != 0) {
|
||||
TCGv t = tcg_temp_new(tcg_ctx);
|
||||
gen_get_gpr(tcg_ctx, t, a->rs1);
|
||||
|
||||
tcg_gen_sari_tl(tcg_ctx, t, t, a->shamt);
|
||||
gen_set_gpr(tcg_ctx, a->rd, t);
|
||||
tcg_temp_free(tcg_ctx, t);
|
||||
} /* NOP otherwise */
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_add(DisasContext *ctx, arg_add *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
return gen_arith(tcg_ctx, a, &tcg_gen_add_tl);
|
||||
}
|
||||
|
||||
static bool trans_sub(DisasContext *ctx, arg_sub *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
return gen_arith(tcg_ctx, a, &tcg_gen_sub_tl);
|
||||
}
|
||||
|
||||
static bool trans_sll(DisasContext *ctx, arg_sll *a)
|
||||
{
|
||||
return gen_shift(ctx, a, &tcg_gen_shl_tl);
|
||||
}
|
||||
|
||||
static bool trans_slt(DisasContext *ctx, arg_slt *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
return gen_arith(tcg_ctx, a, &gen_slt);
|
||||
}
|
||||
|
||||
static bool trans_sltu(DisasContext *ctx, arg_sltu *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
return gen_arith(tcg_ctx, a, &gen_sltu);
|
||||
}
|
||||
|
||||
static bool trans_xor(DisasContext *ctx, arg_xor *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
return gen_arith(tcg_ctx, a, &tcg_gen_xor_tl);
|
||||
}
|
||||
|
||||
static bool trans_srl(DisasContext *ctx, arg_srl *a)
|
||||
{
|
||||
return gen_shift(ctx, a, &tcg_gen_shr_tl);
|
||||
}
|
||||
|
||||
static bool trans_sra(DisasContext *ctx, arg_sra *a)
|
||||
{
|
||||
return gen_shift(ctx, a, &tcg_gen_sar_tl);
|
||||
}
|
||||
|
||||
static bool trans_or(DisasContext *ctx, arg_or *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
return gen_arith(tcg_ctx, a, &tcg_gen_or_tl);
|
||||
}
|
||||
|
||||
static bool trans_and(DisasContext *ctx, arg_and *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
return gen_arith(tcg_ctx, a, &tcg_gen_and_tl);
|
||||
}
|
||||
|
||||
#ifdef TARGET_RISCV64
|
||||
static bool trans_addiw(DisasContext *ctx, arg_addiw *a)
|
||||
{
|
||||
return gen_arith_imm_tl(ctx, a, &gen_addw);
|
||||
}
|
||||
|
||||
static bool trans_slliw(DisasContext *ctx, arg_slliw *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
TCGv source1;
|
||||
source1 = tcg_temp_new(tcg_ctx);
|
||||
gen_get_gpr(tcg_ctx, source1, a->rs1);
|
||||
|
||||
tcg_gen_shli_tl(tcg_ctx, source1, source1, a->shamt);
|
||||
tcg_gen_ext32s_tl(tcg_ctx, source1, source1);
|
||||
gen_set_gpr(tcg_ctx, a->rd, source1);
|
||||
|
||||
tcg_temp_free(tcg_ctx, source1);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_srliw(DisasContext *ctx, arg_srliw *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
TCGv t = tcg_temp_new(tcg_ctx);
|
||||
gen_get_gpr(tcg_ctx, t, a->rs1);
|
||||
tcg_gen_extract_tl(tcg_ctx, t, t, a->shamt, 32 - a->shamt);
|
||||
/* sign-extend for W instructions */
|
||||
tcg_gen_ext32s_tl(tcg_ctx, t, t);
|
||||
gen_set_gpr(tcg_ctx, a->rd, t);
|
||||
tcg_temp_free(tcg_ctx, t);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_sraiw(DisasContext *ctx, arg_sraiw *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
TCGv t = tcg_temp_new(tcg_ctx);
|
||||
gen_get_gpr(tcg_ctx, t, a->rs1);
|
||||
tcg_gen_sextract_tl(tcg_ctx, t, t, a->shamt, 32 - a->shamt);
|
||||
gen_set_gpr(tcg_ctx, a->rd, t);
|
||||
tcg_temp_free(tcg_ctx, t);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_addw(DisasContext *ctx, arg_addw *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
return gen_arith(tcg_ctx, a, &gen_addw);
|
||||
}
|
||||
|
||||
static bool trans_subw(DisasContext *ctx, arg_subw *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
return gen_arith(tcg_ctx, a, &gen_subw);
|
||||
}
|
||||
|
||||
static bool trans_sllw(DisasContext *ctx, arg_sllw *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
TCGv source1 = tcg_temp_new(tcg_ctx);
|
||||
TCGv source2 = tcg_temp_new(tcg_ctx);
|
||||
|
||||
gen_get_gpr(tcg_ctx, source1, a->rs1);
|
||||
gen_get_gpr(tcg_ctx, source2, a->rs2);
|
||||
|
||||
tcg_gen_andi_tl(tcg_ctx, source2, source2, 0x1F);
|
||||
tcg_gen_shl_tl(tcg_ctx, source1, source1, source2);
|
||||
|
||||
tcg_gen_ext32s_tl(tcg_ctx, source1, source1);
|
||||
gen_set_gpr(tcg_ctx, a->rd, source1);
|
||||
tcg_temp_free(tcg_ctx, source1);
|
||||
tcg_temp_free(tcg_ctx, source2);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_srlw(DisasContext *ctx, arg_srlw *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
TCGv source1 = tcg_temp_new(tcg_ctx);
|
||||
TCGv source2 = tcg_temp_new(tcg_ctx);
|
||||
|
||||
gen_get_gpr(tcg_ctx, source1, a->rs1);
|
||||
gen_get_gpr(tcg_ctx, source2, a->rs2);
|
||||
|
||||
/* clear upper 32 */
|
||||
tcg_gen_ext32u_tl(tcg_ctx, source1, source1);
|
||||
tcg_gen_andi_tl(tcg_ctx, source2, source2, 0x1F);
|
||||
tcg_gen_shr_tl(tcg_ctx, source1, source1, source2);
|
||||
|
||||
tcg_gen_ext32s_tl(tcg_ctx, source1, source1);
|
||||
gen_set_gpr(tcg_ctx, a->rd, source1);
|
||||
tcg_temp_free(tcg_ctx, source1);
|
||||
tcg_temp_free(tcg_ctx, source2);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_sraw(DisasContext *ctx, arg_sraw *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
TCGv source1 = tcg_temp_new(tcg_ctx);
|
||||
TCGv source2 = tcg_temp_new(tcg_ctx);
|
||||
|
||||
gen_get_gpr(tcg_ctx, source1, a->rs1);
|
||||
gen_get_gpr(tcg_ctx, source2, a->rs2);
|
||||
|
||||
/*
|
||||
* first, trick to get it to act like working on 32 bits (get rid of
|
||||
* upper 32, sign extend to fill space)
|
||||
*/
|
||||
tcg_gen_ext32s_tl(tcg_ctx, source1, source1);
|
||||
tcg_gen_andi_tl(tcg_ctx, source2, source2, 0x1F);
|
||||
tcg_gen_sar_tl(tcg_ctx, source1, source1, source2);
|
||||
|
||||
gen_set_gpr(tcg_ctx, a->rd, source1);
|
||||
tcg_temp_free(tcg_ctx, source1);
|
||||
tcg_temp_free(tcg_ctx, source2);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool trans_fence(DisasContext *ctx, arg_fence *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
/* FENCE is a full memory barrier. */
|
||||
tcg_gen_mb(tcg_ctx, TCG_MO_ALL | TCG_BAR_SC);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fence_i(DisasContext *ctx, arg_fence_i *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
|
||||
if (!ctx->ext_ifencei) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* FENCE_I is a no-op in QEMU,
|
||||
* however we need to end the translation block
|
||||
*/
|
||||
tcg_gen_movi_tl(tcg_ctx, tcg_ctx->cpu_pc, ctx->pc_succ_insn);
|
||||
exit_tb(ctx);
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
return true;
|
||||
}
|
||||
|
||||
#define RISCV_OP_CSR_PRE do {\
|
||||
source1 = tcg_temp_new(tcg_ctx); \
|
||||
csr_store = tcg_temp_new(tcg_ctx); \
|
||||
dest = tcg_temp_new(tcg_ctx); \
|
||||
rs1_pass = tcg_temp_new(tcg_ctx); \
|
||||
gen_get_gpr(tcg_ctx, source1, a->rs1); \
|
||||
tcg_gen_movi_tl(tcg_ctx, tcg_ctx->cpu_pc, ctx->base.pc_next); \
|
||||
tcg_gen_movi_tl(tcg_ctx, rs1_pass, a->rs1); \
|
||||
tcg_gen_movi_tl(tcg_ctx, csr_store, a->csr); \
|
||||
gen_io_start(tcg_ctx);\
|
||||
} while (0)
|
||||
|
||||
#define RISCV_OP_CSR_POST do {\
|
||||
gen_set_gpr(tcg_ctx, a->rd, dest); \
|
||||
tcg_gen_movi_tl(tcg_ctx, tcg_ctx->cpu_pc, ctx->pc_succ_insn); \
|
||||
exit_tb(ctx); \
|
||||
ctx->base.is_jmp = DISAS_NORETURN; \
|
||||
tcg_temp_free(tcg_ctx, source1); \
|
||||
tcg_temp_free(tcg_ctx, csr_store); \
|
||||
tcg_temp_free(tcg_ctx, dest); \
|
||||
tcg_temp_free(tcg_ctx, rs1_pass); \
|
||||
} while (0)
|
||||
|
||||
|
||||
static bool trans_csrrw(DisasContext *ctx, arg_csrrw *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
TCGv source1, csr_store, dest, rs1_pass;
|
||||
RISCV_OP_CSR_PRE;
|
||||
gen_helper_csrrw(tcg_ctx, dest, tcg_ctx->cpu_env, source1, csr_store);
|
||||
RISCV_OP_CSR_POST;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_csrrs(DisasContext *ctx, arg_csrrs *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
TCGv source1, csr_store, dest, rs1_pass;
|
||||
RISCV_OP_CSR_PRE;
|
||||
gen_helper_csrrs(tcg_ctx, dest, tcg_ctx->cpu_env, source1, csr_store, rs1_pass);
|
||||
RISCV_OP_CSR_POST;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_csrrc(DisasContext *ctx, arg_csrrc *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
TCGv source1, csr_store, dest, rs1_pass;
|
||||
RISCV_OP_CSR_PRE;
|
||||
gen_helper_csrrc(tcg_ctx, dest, tcg_ctx->cpu_env, source1, csr_store, rs1_pass);
|
||||
RISCV_OP_CSR_POST;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_csrrwi(DisasContext *ctx, arg_csrrwi *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
TCGv source1, csr_store, dest, rs1_pass;
|
||||
RISCV_OP_CSR_PRE;
|
||||
gen_helper_csrrw(tcg_ctx, dest, tcg_ctx->cpu_env, rs1_pass, csr_store);
|
||||
RISCV_OP_CSR_POST;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_csrrsi(DisasContext *ctx, arg_csrrsi *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
TCGv source1, csr_store, dest, rs1_pass;
|
||||
RISCV_OP_CSR_PRE;
|
||||
gen_helper_csrrs(tcg_ctx, dest, tcg_ctx->cpu_env, rs1_pass, csr_store, rs1_pass);
|
||||
RISCV_OP_CSR_POST;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_csrrci(DisasContext *ctx, arg_csrrci *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
TCGv source1, csr_store, dest, rs1_pass;
|
||||
RISCV_OP_CSR_PRE;
|
||||
gen_helper_csrrc(tcg_ctx, dest, tcg_ctx->cpu_env, rs1_pass, csr_store, rs1_pass);
|
||||
RISCV_OP_CSR_POST;
|
||||
return true;
|
||||
}
|
||||
133
qemu/target/riscv/insn_trans/trans_rvm.inc.c
Normal file
133
qemu/target/riscv/insn_trans/trans_rvm.inc.c
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
static bool trans_mul(DisasContext *ctx, arg_mul *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
return gen_arith(tcg_ctx, a, &tcg_gen_mul_tl);
|
||||
}
|
||||
|
||||
static bool trans_mulh(DisasContext *ctx, arg_mulh *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
TCGv source1 = tcg_temp_new(tcg_ctx);
|
||||
TCGv source2 = tcg_temp_new(tcg_ctx);
|
||||
gen_get_gpr(tcg_ctx, source1, a->rs1);
|
||||
gen_get_gpr(tcg_ctx, source2, a->rs2);
|
||||
|
||||
tcg_gen_muls2_tl(tcg_ctx, source2, source1, source1, source2);
|
||||
|
||||
gen_set_gpr(tcg_ctx, a->rd, source1);
|
||||
tcg_temp_free(tcg_ctx, source1);
|
||||
tcg_temp_free(tcg_ctx, source2);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_mulhsu(DisasContext *ctx, arg_mulhsu *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
return gen_arith(tcg_ctx, a, &gen_mulhsu);
|
||||
}
|
||||
|
||||
static bool trans_mulhu(DisasContext *ctx, arg_mulhu *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
TCGv source1 = tcg_temp_new(tcg_ctx);
|
||||
TCGv source2 = tcg_temp_new(tcg_ctx);
|
||||
gen_get_gpr(tcg_ctx, source1, a->rs1);
|
||||
gen_get_gpr(tcg_ctx, source2, a->rs2);
|
||||
|
||||
tcg_gen_mulu2_tl(tcg_ctx, source2, source1, source1, source2);
|
||||
|
||||
gen_set_gpr(tcg_ctx, a->rd, source1);
|
||||
tcg_temp_free(tcg_ctx, source1);
|
||||
tcg_temp_free(tcg_ctx, source2);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_div(DisasContext *ctx, arg_div *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
return gen_arith(tcg_ctx, a, &gen_div);
|
||||
}
|
||||
|
||||
static bool trans_divu(DisasContext *ctx, arg_divu *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
return gen_arith(tcg_ctx, a, &gen_divu);
|
||||
}
|
||||
|
||||
static bool trans_rem(DisasContext *ctx, arg_rem *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
return gen_arith(tcg_ctx, a, &gen_rem);
|
||||
}
|
||||
|
||||
static bool trans_remu(DisasContext *ctx, arg_remu *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
return gen_arith(tcg_ctx, a, &gen_remu);
|
||||
}
|
||||
|
||||
#ifdef TARGET_RISCV64
|
||||
static bool trans_mulw(DisasContext *ctx, arg_mulw *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
return gen_arith(tcg_ctx, a, &gen_mulw);
|
||||
}
|
||||
|
||||
static bool trans_divw(DisasContext *ctx, arg_divw *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
return gen_arith_div_w(tcg_ctx, a, &gen_div);
|
||||
}
|
||||
|
||||
static bool trans_divuw(DisasContext *ctx, arg_divuw *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
return gen_arith_div_uw(tcg_ctx, a, &gen_divu);
|
||||
}
|
||||
|
||||
static bool trans_remw(DisasContext *ctx, arg_remw *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
return gen_arith_div_w(tcg_ctx, a, &gen_rem);
|
||||
}
|
||||
|
||||
static bool trans_remuw(DisasContext *ctx, arg_remuw *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
return gen_arith_div_uw(tcg_ctx, a, &gen_remu);
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user