Signed-off-by: Sagar Karandikar <sag...@eecs.berkeley.edu> --- target-riscv/translate.c | 154 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+)
diff --git a/target-riscv/translate.c b/target-riscv/translate.c index 767cdbe..af82eab 100644 --- a/target-riscv/translate.c +++ b/target-riscv/translate.c @@ -641,6 +641,157 @@ static inline void gen_fp_store(DisasContext *ctx, uint32_t opc, int rs1, tcg_temp_free(t1); } +static inline void gen_atomic(DisasContext *ctx, uint32_t opc, + int rd, int rs1, int rs2) +{ + /* TODO: handle aq, rl bits? - for now just get rid of them: */ + opc = MASK_OP_ATOMIC_NO_AQ_RL(opc); + TCGv source1, source2, dat; + TCGLabel *j = gen_new_label(); + TCGLabel *done = gen_new_label(); + source1 = tcg_temp_local_new(); + source2 = tcg_temp_local_new(); + dat = tcg_temp_local_new(); + gen_get_gpr(source1, rs1); + gen_get_gpr(source2, rs2); + + switch (opc) { + /* all currently implemented as non-atomics */ + case OPC_RISC_LR_W: + /* put addr in load_res */ + tcg_gen_mov_tl(load_res, source1); + tcg_gen_qemu_ld_tl(dat, source1, ctx->mem_idx, MO_TESL | MO_ALIGN); + break; + case OPC_RISC_SC_W: + tcg_gen_brcond_tl(TCG_COND_NE, load_res, source1, j); + tcg_gen_qemu_st_tl(source2, source1, ctx->mem_idx, MO_TEUL | MO_ALIGN); + tcg_gen_movi_tl(dat, 0); /*success */ + tcg_gen_br(done); + gen_set_label(j); + tcg_gen_movi_tl(dat, 1); /*fail */ + gen_set_label(done); + break; + case OPC_RISC_AMOSWAP_W: + tcg_gen_qemu_ld_tl(dat, source1, ctx->mem_idx, MO_TESL | MO_ALIGN); + tcg_gen_qemu_st_tl(source2, source1, ctx->mem_idx, MO_TEUL | MO_ALIGN); + break; + case OPC_RISC_AMOADD_W: + tcg_gen_qemu_ld_tl(dat, source1, ctx->mem_idx, MO_TESL | MO_ALIGN); + tcg_gen_add_tl(source2, dat, source2); + tcg_gen_qemu_st_tl(source2, source1, ctx->mem_idx, MO_TEUL | MO_ALIGN); + break; + case OPC_RISC_AMOXOR_W: + tcg_gen_qemu_ld_tl(dat, source1, ctx->mem_idx, MO_TESL | MO_ALIGN); + tcg_gen_xor_tl(source2, dat, source2); + tcg_gen_qemu_st_tl(source2, source1, ctx->mem_idx, MO_TEUL | MO_ALIGN); + break; + case OPC_RISC_AMOAND_W: + tcg_gen_qemu_ld_tl(dat, source1, ctx->mem_idx, MO_TESL | MO_ALIGN); + tcg_gen_and_tl(source2, dat, source2); + tcg_gen_qemu_st_tl(source2, source1, ctx->mem_idx, MO_TEUL | MO_ALIGN); + break; + case OPC_RISC_AMOOR_W: + tcg_gen_qemu_ld_tl(dat, source1, ctx->mem_idx, MO_TESL | MO_ALIGN); + tcg_gen_or_tl(source2, dat, source2); + tcg_gen_qemu_st_tl(source2, source1, ctx->mem_idx, MO_TEUL | MO_ALIGN); + break; + case OPC_RISC_AMOMIN_W: + tcg_gen_ext32s_tl(source2, source2); /* since comparing */ + tcg_gen_qemu_ld_tl(dat, source1, ctx->mem_idx, MO_TESL | MO_ALIGN); + tcg_gen_movcond_tl(TCG_COND_LT, source2, dat, source2, dat, source2); + tcg_gen_qemu_st_tl(source2, source1, ctx->mem_idx, MO_TEUL | MO_ALIGN); + break; + case OPC_RISC_AMOMAX_W: + tcg_gen_ext32s_tl(source2, source2); /* since comparing */ + tcg_gen_qemu_ld_tl(dat, source1, ctx->mem_idx, MO_TESL | MO_ALIGN); + tcg_gen_movcond_tl(TCG_COND_GT, source2, dat, source2, dat, source2); + tcg_gen_qemu_st_tl(source2, source1, ctx->mem_idx, MO_TEUL | MO_ALIGN); + break; + case OPC_RISC_AMOMINU_W: + tcg_gen_ext32u_tl(source2, source2); /* since comparing */ + tcg_gen_qemu_ld_tl(dat, source1, ctx->mem_idx, MO_TEUL | MO_ALIGN); + tcg_gen_movcond_tl(TCG_COND_LTU, source2, dat, source2, dat, source2); + tcg_gen_qemu_st_tl(source2, source1, ctx->mem_idx, MO_TEUL | MO_ALIGN); + tcg_gen_ext32s_tl(dat, dat); /* since load was TEUL */ + break; + case OPC_RISC_AMOMAXU_W: + tcg_gen_ext32u_tl(source2, source2); /* since comparing */ + tcg_gen_qemu_ld_tl(dat, source1, ctx->mem_idx, MO_TEUL | MO_ALIGN); + tcg_gen_movcond_tl(TCG_COND_GTU, source2, dat, source2, dat, source2); + tcg_gen_qemu_st_tl(source2, source1, ctx->mem_idx, MO_TEUL | MO_ALIGN); + tcg_gen_ext32s_tl(dat, dat); /* since load was TEUL */ + break; +#if defined(TARGET_RISCV64) + case OPC_RISC_LR_D: + /* put addr in load_res */ + tcg_gen_mov_tl(load_res, source1); + tcg_gen_qemu_ld_tl(dat, source1, ctx->mem_idx, MO_TEQ | MO_ALIGN); + break; + case OPC_RISC_SC_D: + tcg_gen_brcond_tl(TCG_COND_NE, load_res, source1, j); + tcg_gen_qemu_st_tl(source2, source1, ctx->mem_idx, MO_TEQ | MO_ALIGN); + tcg_gen_movi_tl(dat, 0); /* success */ + tcg_gen_br(done); + gen_set_label(j); + tcg_gen_movi_tl(dat, 1); /* fail */ + gen_set_label(done); + break; + case OPC_RISC_AMOSWAP_D: + tcg_gen_qemu_ld_tl(dat, source1, ctx->mem_idx, MO_TEQ | MO_ALIGN); + tcg_gen_qemu_st_tl(source2, source1, ctx->mem_idx, MO_TEQ | MO_ALIGN); + break; + case OPC_RISC_AMOADD_D: + tcg_gen_qemu_ld_tl(dat, source1, ctx->mem_idx, MO_TEQ | MO_ALIGN); + tcg_gen_add_tl(source2, dat, source2); + tcg_gen_qemu_st_tl(source2, source1, ctx->mem_idx, MO_TEQ | MO_ALIGN); + break; + case OPC_RISC_AMOXOR_D: + tcg_gen_qemu_ld_tl(dat, source1, ctx->mem_idx, MO_TEQ | MO_ALIGN); + tcg_gen_xor_tl(source2, dat, source2); + tcg_gen_qemu_st_tl(source2, source1, ctx->mem_idx, MO_TEQ | MO_ALIGN); + break; + case OPC_RISC_AMOAND_D: + tcg_gen_qemu_ld_tl(dat, source1, ctx->mem_idx, MO_TEQ | MO_ALIGN); + tcg_gen_and_tl(source2, dat, source2); + tcg_gen_qemu_st_tl(source2, source1, ctx->mem_idx, MO_TEQ | MO_ALIGN); + break; + case OPC_RISC_AMOOR_D: + tcg_gen_qemu_ld_tl(dat, source1, ctx->mem_idx, MO_TEQ | MO_ALIGN); + tcg_gen_or_tl(source2, dat, source2); + tcg_gen_qemu_st_tl(source2, source1, ctx->mem_idx, MO_TEQ | MO_ALIGN); + break; + case OPC_RISC_AMOMIN_D: + tcg_gen_qemu_ld_tl(dat, source1, ctx->mem_idx, MO_TEQ | MO_ALIGN); + tcg_gen_movcond_tl(TCG_COND_LT, source2, dat, source2, dat, source2); + tcg_gen_qemu_st_tl(source2, source1, ctx->mem_idx, MO_TEQ | MO_ALIGN); + break; + case OPC_RISC_AMOMAX_D: + tcg_gen_qemu_ld_tl(dat, source1, ctx->mem_idx, MO_TEQ | MO_ALIGN); + tcg_gen_movcond_tl(TCG_COND_GT, source2, dat, source2, dat, source2); + tcg_gen_qemu_st_tl(source2, source1, ctx->mem_idx, MO_TEQ | MO_ALIGN); + break; + case OPC_RISC_AMOMINU_D: + tcg_gen_qemu_ld_tl(dat, source1, ctx->mem_idx, MO_TEQ | MO_ALIGN); + tcg_gen_movcond_tl(TCG_COND_LTU, source2, dat, source2, dat, source2); + tcg_gen_qemu_st_tl(source2, source1, ctx->mem_idx, MO_TEQ | MO_ALIGN); + break; + case OPC_RISC_AMOMAXU_D: + tcg_gen_qemu_ld_tl(dat, source1, ctx->mem_idx, MO_TEQ | MO_ALIGN); + tcg_gen_movcond_tl(TCG_COND_GTU, source2, dat, source2, dat, source2); + tcg_gen_qemu_st_tl(source2, source1, ctx->mem_idx, MO_TEQ | MO_ALIGN); + break; +#endif + default: + kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST); + break; + } + + gen_set_gpr(rd, dat); + tcg_temp_free(source1); + tcg_temp_free(source2); + tcg_temp_free(dat); +} + static void decode_opc(CPURISCVState *env, DisasContext *ctx) { int rs1; @@ -746,6 +897,9 @@ static void decode_opc(CPURISCVState *env, DisasContext *ctx) gen_fp_store(ctx, MASK_OP_FP_STORE(ctx->opcode), rs1, rs2, GET_STORE_IMM(ctx->opcode)); break; + case OPC_RISC_ATOMIC: + gen_atomic(ctx, MASK_OP_ATOMIC(ctx->opcode), rd, rs1, rs2); + break; default: kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST); break; -- 2.9.3