mirror of
https://github.com/xemu-project/xemu.git
synced 2025-02-12 15:38:21 +00:00
target/riscv: Remove manual decoding of RV32/64M insn
Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Bastian Koppelmann <kbastian@mail.uni-paderborn.de> Signed-off-by: Peer Adelt <peer.adelt@hni.uni-paderborn.de>
This commit is contained in:
parent
34446e8458
commit
1288701682
@ -22,92 +22,99 @@
|
||||
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;
|
||||
return trans_arith(ctx, a, &tcg_gen_mul_tl);
|
||||
}
|
||||
|
||||
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);
|
||||
TCGv source1 = tcg_temp_new();
|
||||
TCGv source2 = tcg_temp_new();
|
||||
gen_get_gpr(source1, a->rs1);
|
||||
gen_get_gpr(source2, a->rs2);
|
||||
|
||||
tcg_gen_muls2_tl(source2, source1, source1, source2);
|
||||
|
||||
gen_set_gpr(a->rd, source1);
|
||||
tcg_temp_free(source1);
|
||||
tcg_temp_free(source2);
|
||||
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;
|
||||
return trans_arith(ctx, a, &gen_mulhsu);
|
||||
}
|
||||
|
||||
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);
|
||||
TCGv source1 = tcg_temp_new();
|
||||
TCGv source2 = tcg_temp_new();
|
||||
gen_get_gpr(source1, a->rs1);
|
||||
gen_get_gpr(source2, a->rs2);
|
||||
|
||||
tcg_gen_mulu2_tl(source2, source1, source1, source2);
|
||||
|
||||
gen_set_gpr(a->rd, source1);
|
||||
tcg_temp_free(source1);
|
||||
tcg_temp_free(source2);
|
||||
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;
|
||||
return trans_arith(ctx, a, &gen_div);
|
||||
}
|
||||
|
||||
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;
|
||||
return trans_arith(ctx, a, &gen_divu);
|
||||
}
|
||||
|
||||
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;
|
||||
return trans_arith(ctx, a, &gen_rem);
|
||||
}
|
||||
|
||||
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;
|
||||
return trans_arith(ctx, a, &gen_remu);
|
||||
}
|
||||
|
||||
#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;
|
||||
return trans_arith(ctx, a, &gen_mulw);
|
||||
}
|
||||
|
||||
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;
|
||||
return gen_arith_div_w(ctx, a, &gen_div);
|
||||
}
|
||||
|
||||
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;
|
||||
return gen_arith_div_w(ctx, a, &gen_divu);
|
||||
}
|
||||
|
||||
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;
|
||||
return gen_arith_div_w(ctx, a, &gen_rem);
|
||||
}
|
||||
|
||||
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;
|
||||
return gen_arith_div_w(ctx, a, &gen_remu);
|
||||
}
|
||||
#endif
|
||||
|
@ -188,193 +188,112 @@ static void gen_mulhsu(TCGv ret, TCGv arg1, TCGv arg2)
|
||||
tcg_temp_free(rh);
|
||||
}
|
||||
|
||||
static void gen_arith(DisasContext *ctx, uint32_t opc, int rd, int rs1,
|
||||
int rs2)
|
||||
static void gen_div(TCGv ret, TCGv source1, TCGv source2)
|
||||
{
|
||||
TCGv source1, source2, cond1, cond2, zeroreg, resultopt1;
|
||||
source1 = tcg_temp_new();
|
||||
source2 = tcg_temp_new();
|
||||
gen_get_gpr(source1, rs1);
|
||||
gen_get_gpr(source2, rs2);
|
||||
TCGv cond1, cond2, zeroreg, resultopt1;
|
||||
/*
|
||||
* Handle by altering args to tcg_gen_div to produce req'd results:
|
||||
* For overflow: want source1 in source1 and 1 in source2
|
||||
* For div by zero: want -1 in source1 and 1 in source2 -> -1 result
|
||||
*/
|
||||
cond1 = tcg_temp_new();
|
||||
cond2 = tcg_temp_new();
|
||||
zeroreg = tcg_const_tl(0);
|
||||
resultopt1 = tcg_temp_new();
|
||||
|
||||
switch (opc) {
|
||||
CASE_OP_32_64(OPC_RISC_MUL):
|
||||
if (!has_ext(ctx, RVM)) {
|
||||
goto do_illegal;
|
||||
}
|
||||
tcg_gen_mul_tl(source1, source1, source2);
|
||||
break;
|
||||
case OPC_RISC_MULH:
|
||||
if (!has_ext(ctx, RVM)) {
|
||||
goto do_illegal;
|
||||
}
|
||||
tcg_gen_muls2_tl(source2, source1, source1, source2);
|
||||
break;
|
||||
case OPC_RISC_MULHSU:
|
||||
if (!has_ext(ctx, RVM)) {
|
||||
goto do_illegal;
|
||||
}
|
||||
gen_mulhsu(source1, source1, source2);
|
||||
break;
|
||||
case OPC_RISC_MULHU:
|
||||
if (!has_ext(ctx, RVM)) {
|
||||
goto do_illegal;
|
||||
}
|
||||
tcg_gen_mulu2_tl(source2, source1, source1, source2);
|
||||
break;
|
||||
#if defined(TARGET_RISCV64)
|
||||
case OPC_RISC_DIVW:
|
||||
if (!has_ext(ctx, RVM)) {
|
||||
goto do_illegal;
|
||||
}
|
||||
tcg_gen_ext32s_tl(source1, source1);
|
||||
tcg_gen_ext32s_tl(source2, source2);
|
||||
/* fall through to DIV */
|
||||
#endif
|
||||
case OPC_RISC_DIV:
|
||||
if (!has_ext(ctx, RVM)) {
|
||||
goto do_illegal;
|
||||
}
|
||||
/* Handle by altering args to tcg_gen_div to produce req'd results:
|
||||
* For overflow: want source1 in source1 and 1 in source2
|
||||
* For div by zero: want -1 in source1 and 1 in source2 -> -1 result */
|
||||
cond1 = tcg_temp_new();
|
||||
cond2 = tcg_temp_new();
|
||||
zeroreg = tcg_const_tl(0);
|
||||
resultopt1 = tcg_temp_new();
|
||||
tcg_gen_movi_tl(resultopt1, (target_ulong)-1);
|
||||
tcg_gen_setcondi_tl(TCG_COND_EQ, cond2, source2, (target_ulong)(~0L));
|
||||
tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source1,
|
||||
((target_ulong)1) << (TARGET_LONG_BITS - 1));
|
||||
tcg_gen_and_tl(cond1, cond1, cond2); /* cond1 = overflow */
|
||||
tcg_gen_setcondi_tl(TCG_COND_EQ, cond2, source2, 0); /* cond2 = div 0 */
|
||||
/* if div by zero, set source1 to -1, otherwise don't change */
|
||||
tcg_gen_movcond_tl(TCG_COND_EQ, source1, cond2, zeroreg, source1,
|
||||
resultopt1);
|
||||
/* if overflow or div by zero, set source2 to 1, else don't change */
|
||||
tcg_gen_or_tl(cond1, cond1, cond2);
|
||||
tcg_gen_movi_tl(resultopt1, (target_ulong)1);
|
||||
tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond1, zeroreg, source2,
|
||||
resultopt1);
|
||||
tcg_gen_div_tl(ret, source1, source2);
|
||||
|
||||
tcg_gen_movi_tl(resultopt1, (target_ulong)-1);
|
||||
tcg_gen_setcondi_tl(TCG_COND_EQ, cond2, source2, (target_ulong)(~0L));
|
||||
tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source1,
|
||||
((target_ulong)1) << (TARGET_LONG_BITS - 1));
|
||||
tcg_gen_and_tl(cond1, cond1, cond2); /* cond1 = overflow */
|
||||
tcg_gen_setcondi_tl(TCG_COND_EQ, cond2, source2, 0); /* cond2 = div 0 */
|
||||
/* if div by zero, set source1 to -1, otherwise don't change */
|
||||
tcg_gen_movcond_tl(TCG_COND_EQ, source1, cond2, zeroreg, source1,
|
||||
resultopt1);
|
||||
/* if overflow or div by zero, set source2 to 1, else don't change */
|
||||
tcg_gen_or_tl(cond1, cond1, cond2);
|
||||
tcg_gen_movi_tl(resultopt1, (target_ulong)1);
|
||||
tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond1, zeroreg, source2,
|
||||
resultopt1);
|
||||
tcg_gen_div_tl(source1, source1, source2);
|
||||
tcg_temp_free(cond1);
|
||||
tcg_temp_free(cond2);
|
||||
tcg_temp_free(zeroreg);
|
||||
tcg_temp_free(resultopt1);
|
||||
}
|
||||
|
||||
tcg_temp_free(cond1);
|
||||
tcg_temp_free(cond2);
|
||||
tcg_temp_free(zeroreg);
|
||||
tcg_temp_free(resultopt1);
|
||||
break;
|
||||
#if defined(TARGET_RISCV64)
|
||||
case OPC_RISC_DIVUW:
|
||||
if (!has_ext(ctx, RVM)) {
|
||||
goto do_illegal;
|
||||
}
|
||||
tcg_gen_ext32u_tl(source1, source1);
|
||||
tcg_gen_ext32u_tl(source2, source2);
|
||||
/* fall through to DIVU */
|
||||
#endif
|
||||
case OPC_RISC_DIVU:
|
||||
if (!has_ext(ctx, RVM)) {
|
||||
goto do_illegal;
|
||||
}
|
||||
cond1 = tcg_temp_new();
|
||||
zeroreg = tcg_const_tl(0);
|
||||
resultopt1 = tcg_temp_new();
|
||||
static void gen_divu(TCGv ret, TCGv source1, TCGv source2)
|
||||
{
|
||||
TCGv cond1, zeroreg, resultopt1;
|
||||
cond1 = tcg_temp_new();
|
||||
|
||||
tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source2, 0);
|
||||
tcg_gen_movi_tl(resultopt1, (target_ulong)-1);
|
||||
tcg_gen_movcond_tl(TCG_COND_EQ, source1, cond1, zeroreg, source1,
|
||||
resultopt1);
|
||||
tcg_gen_movi_tl(resultopt1, (target_ulong)1);
|
||||
tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond1, zeroreg, source2,
|
||||
resultopt1);
|
||||
tcg_gen_divu_tl(source1, source1, source2);
|
||||
zeroreg = tcg_const_tl(0);
|
||||
resultopt1 = tcg_temp_new();
|
||||
|
||||
tcg_temp_free(cond1);
|
||||
tcg_temp_free(zeroreg);
|
||||
tcg_temp_free(resultopt1);
|
||||
break;
|
||||
#if defined(TARGET_RISCV64)
|
||||
case OPC_RISC_REMW:
|
||||
if (!has_ext(ctx, RVM)) {
|
||||
goto do_illegal;
|
||||
}
|
||||
tcg_gen_ext32s_tl(source1, source1);
|
||||
tcg_gen_ext32s_tl(source2, source2);
|
||||
/* fall through to REM */
|
||||
#endif
|
||||
case OPC_RISC_REM:
|
||||
if (!has_ext(ctx, RVM)) {
|
||||
goto do_illegal;
|
||||
}
|
||||
cond1 = tcg_temp_new();
|
||||
cond2 = tcg_temp_new();
|
||||
zeroreg = tcg_const_tl(0);
|
||||
resultopt1 = tcg_temp_new();
|
||||
tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source2, 0);
|
||||
tcg_gen_movi_tl(resultopt1, (target_ulong)-1);
|
||||
tcg_gen_movcond_tl(TCG_COND_EQ, source1, cond1, zeroreg, source1,
|
||||
resultopt1);
|
||||
tcg_gen_movi_tl(resultopt1, (target_ulong)1);
|
||||
tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond1, zeroreg, source2,
|
||||
resultopt1);
|
||||
tcg_gen_divu_tl(ret, source1, source2);
|
||||
|
||||
tcg_gen_movi_tl(resultopt1, 1L);
|
||||
tcg_gen_setcondi_tl(TCG_COND_EQ, cond2, source2, (target_ulong)-1);
|
||||
tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source1,
|
||||
(target_ulong)1 << (TARGET_LONG_BITS - 1));
|
||||
tcg_gen_and_tl(cond2, cond1, cond2); /* cond1 = overflow */
|
||||
tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source2, 0); /* cond2 = div 0 */
|
||||
/* if overflow or div by zero, set source2 to 1, else don't change */
|
||||
tcg_gen_or_tl(cond2, cond1, cond2);
|
||||
tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond2, zeroreg, source2,
|
||||
resultopt1);
|
||||
tcg_gen_rem_tl(resultopt1, source1, source2);
|
||||
/* if div by zero, just return the original dividend */
|
||||
tcg_gen_movcond_tl(TCG_COND_EQ, source1, cond1, zeroreg, resultopt1,
|
||||
source1);
|
||||
tcg_temp_free(cond1);
|
||||
tcg_temp_free(zeroreg);
|
||||
tcg_temp_free(resultopt1);
|
||||
}
|
||||
|
||||
tcg_temp_free(cond1);
|
||||
tcg_temp_free(cond2);
|
||||
tcg_temp_free(zeroreg);
|
||||
tcg_temp_free(resultopt1);
|
||||
break;
|
||||
#if defined(TARGET_RISCV64)
|
||||
case OPC_RISC_REMUW:
|
||||
if (!has_ext(ctx, RVM)) {
|
||||
goto do_illegal;
|
||||
}
|
||||
tcg_gen_ext32u_tl(source1, source1);
|
||||
tcg_gen_ext32u_tl(source2, source2);
|
||||
/* fall through to REMU */
|
||||
#endif
|
||||
case OPC_RISC_REMU:
|
||||
if (!has_ext(ctx, RVM)) {
|
||||
goto do_illegal;
|
||||
}
|
||||
cond1 = tcg_temp_new();
|
||||
zeroreg = tcg_const_tl(0);
|
||||
resultopt1 = tcg_temp_new();
|
||||
static void gen_rem(TCGv ret, TCGv source1, TCGv source2)
|
||||
{
|
||||
TCGv cond1, cond2, zeroreg, resultopt1;
|
||||
|
||||
tcg_gen_movi_tl(resultopt1, (target_ulong)1);
|
||||
tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source2, 0);
|
||||
tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond1, zeroreg, source2,
|
||||
resultopt1);
|
||||
tcg_gen_remu_tl(resultopt1, source1, source2);
|
||||
/* if div by zero, just return the original dividend */
|
||||
tcg_gen_movcond_tl(TCG_COND_EQ, source1, cond1, zeroreg, resultopt1,
|
||||
source1);
|
||||
cond1 = tcg_temp_new();
|
||||
cond2 = tcg_temp_new();
|
||||
zeroreg = tcg_const_tl(0);
|
||||
resultopt1 = tcg_temp_new();
|
||||
|
||||
tcg_temp_free(cond1);
|
||||
tcg_temp_free(zeroreg);
|
||||
tcg_temp_free(resultopt1);
|
||||
break;
|
||||
do_illegal:
|
||||
default:
|
||||
gen_exception_illegal(ctx);
|
||||
return;
|
||||
}
|
||||
tcg_gen_movi_tl(resultopt1, 1L);
|
||||
tcg_gen_setcondi_tl(TCG_COND_EQ, cond2, source2, (target_ulong)-1);
|
||||
tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source1,
|
||||
(target_ulong)1 << (TARGET_LONG_BITS - 1));
|
||||
tcg_gen_and_tl(cond2, cond1, cond2); /* cond1 = overflow */
|
||||
tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source2, 0); /* cond2 = div 0 */
|
||||
/* if overflow or div by zero, set source2 to 1, else don't change */
|
||||
tcg_gen_or_tl(cond2, cond1, cond2);
|
||||
tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond2, zeroreg, source2,
|
||||
resultopt1);
|
||||
tcg_gen_rem_tl(resultopt1, source1, source2);
|
||||
/* if div by zero, just return the original dividend */
|
||||
tcg_gen_movcond_tl(TCG_COND_EQ, ret, cond1, zeroreg, resultopt1,
|
||||
source1);
|
||||
|
||||
if (opc & 0x8) { /* sign extend for W instructions */
|
||||
tcg_gen_ext32s_tl(source1, source1);
|
||||
}
|
||||
tcg_temp_free(cond1);
|
||||
tcg_temp_free(cond2);
|
||||
tcg_temp_free(zeroreg);
|
||||
tcg_temp_free(resultopt1);
|
||||
}
|
||||
|
||||
gen_set_gpr(rd, source1);
|
||||
tcg_temp_free(source1);
|
||||
tcg_temp_free(source2);
|
||||
static void gen_remu(TCGv ret, TCGv source1, TCGv source2)
|
||||
{
|
||||
TCGv cond1, zeroreg, resultopt1;
|
||||
cond1 = tcg_temp_new();
|
||||
zeroreg = tcg_const_tl(0);
|
||||
resultopt1 = tcg_temp_new();
|
||||
|
||||
tcg_gen_movi_tl(resultopt1, (target_ulong)1);
|
||||
tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source2, 0);
|
||||
tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond1, zeroreg, source2,
|
||||
resultopt1);
|
||||
tcg_gen_remu_tl(resultopt1, source1, source2);
|
||||
/* if div by zero, just return the original dividend */
|
||||
tcg_gen_movcond_tl(TCG_COND_EQ, ret, cond1, zeroreg, resultopt1,
|
||||
source1);
|
||||
|
||||
tcg_temp_free(cond1);
|
||||
tcg_temp_free(zeroreg);
|
||||
tcg_temp_free(resultopt1);
|
||||
}
|
||||
|
||||
static void gen_jal(DisasContext *ctx, int rd, target_ulong imm)
|
||||
@ -681,6 +600,33 @@ static void gen_subw(TCGv ret, TCGv arg1, TCGv arg2)
|
||||
tcg_gen_ext32s_tl(ret, ret);
|
||||
}
|
||||
|
||||
static void gen_mulw(TCGv ret, TCGv arg1, TCGv arg2)
|
||||
{
|
||||
tcg_gen_mul_tl(ret, arg1, arg2);
|
||||
tcg_gen_ext32s_tl(ret, ret);
|
||||
}
|
||||
|
||||
static bool gen_arith_div_w(DisasContext *ctx, arg_r *a,
|
||||
void(*func)(TCGv, TCGv, TCGv))
|
||||
{
|
||||
TCGv source1, source2;
|
||||
source1 = tcg_temp_new();
|
||||
source2 = tcg_temp_new();
|
||||
|
||||
gen_get_gpr(source1, a->rs1);
|
||||
gen_get_gpr(source2, a->rs2);
|
||||
tcg_gen_ext32s_tl(source1, source1);
|
||||
tcg_gen_ext32s_tl(source2, source2);
|
||||
|
||||
(*func)(source1, source1, source2);
|
||||
|
||||
tcg_gen_ext32s_tl(source1, source1);
|
||||
gen_set_gpr(a->rd, source1);
|
||||
tcg_temp_free(source1);
|
||||
tcg_temp_free(source2);
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static bool trans_arith(DisasContext *ctx, arg_r *a,
|
||||
|
Loading…
x
Reference in New Issue
Block a user