diff options
Diffstat (limited to 'target/openrisc/translate.c')
-rw-r--r-- | target/openrisc/translate.c | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index 82b8bec150..ce9672e7b7 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -362,6 +362,56 @@ static void gen_divu(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb) gen_ove_cy(dc); } +static void gen_muld(DisasContext *dc, TCGv srca, TCGv srcb) +{ + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i64 t2 = tcg_temp_new_i64(); + + tcg_gen_ext_tl_i64(t1, srca); + tcg_gen_ext_tl_i64(t2, srcb); + if (TARGET_LONG_BITS == 32) { + tcg_gen_mul_i64(cpu_mac, t1, t2); + tcg_gen_movi_tl(cpu_sr_ov, 0); + } else { + TCGv_i64 high = tcg_temp_new_i64(); + + tcg_gen_muls2_i64(cpu_mac, high, t1, t2); + tcg_gen_sari_i64(t1, cpu_mac, 63); + tcg_gen_setcond_i64(TCG_COND_NE, t1, t1, high); + tcg_temp_free_i64(high); + tcg_gen_trunc_i64_tl(cpu_sr_ov, t1); + tcg_gen_neg_tl(cpu_sr_ov, cpu_sr_ov); + + gen_ove_ov(dc); + } + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t2); +} + +static void gen_muldu(DisasContext *dc, TCGv srca, TCGv srcb) +{ + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i64 t2 = tcg_temp_new_i64(); + + tcg_gen_extu_tl_i64(t1, srca); + tcg_gen_extu_tl_i64(t2, srcb); + if (TARGET_LONG_BITS == 32) { + tcg_gen_mul_i64(cpu_mac, t1, t2); + tcg_gen_movi_tl(cpu_sr_cy, 0); + } else { + TCGv_i64 high = tcg_temp_new_i64(); + + tcg_gen_mulu2_i64(cpu_mac, high, t1, t2); + tcg_gen_setcondi_i64(TCG_COND_NE, high, high, 0); + tcg_gen_trunc_i64_tl(cpu_sr_cy, high); + tcg_temp_free_i64(high); + + gen_ove_cy(dc); + } + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t2); +} + static void gen_mac(DisasContext *dc, TCGv srca, TCGv srcb) { TCGv_i64 t1 = tcg_temp_new_i64(); @@ -388,6 +438,25 @@ static void gen_mac(DisasContext *dc, TCGv srca, TCGv srcb) gen_ove_ov(dc); } +static void gen_macu(DisasContext *dc, TCGv srca, TCGv srcb) +{ + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i64 t2 = tcg_temp_new_i64(); + + tcg_gen_extu_tl_i64(t1, srca); + tcg_gen_extu_tl_i64(t2, srcb); + tcg_gen_mul_i64(t1, t1, t2); + tcg_temp_free_i64(t2); + + /* Note that overflow is only computed during addition stage. */ + tcg_gen_add_i64(cpu_mac, cpu_mac, t1); + tcg_gen_setcond_i64(TCG_COND_LTU, t1, cpu_mac, t1); + tcg_gen_trunc_i64_tl(cpu_sr_cy, t1); + tcg_temp_free_i64(t1); + + gen_ove_cy(dc); +} + static void gen_msb(DisasContext *dc, TCGv srca, TCGv srcb) { TCGv_i64 t1 = tcg_temp_new_i64(); @@ -414,6 +483,25 @@ static void gen_msb(DisasContext *dc, TCGv srca, TCGv srcb) gen_ove_ov(dc); } +static void gen_msbu(DisasContext *dc, TCGv srca, TCGv srcb) +{ + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i64 t2 = tcg_temp_new_i64(); + + tcg_gen_extu_tl_i64(t1, srca); + tcg_gen_extu_tl_i64(t2, srcb); + tcg_gen_mul_i64(t1, t1, t2); + + /* Note that overflow is only computed during subtraction stage. */ + tcg_gen_setcond_i64(TCG_COND_LTU, t2, cpu_mac, t1); + tcg_gen_sub_i64(cpu_mac, cpu_mac, t1); + tcg_gen_trunc_i64_tl(cpu_sr_cy, t2); + tcg_temp_free_i64(t2); + tcg_temp_free_i64(t1); + + gen_ove_cy(dc); +} + static void gen_lwa(DisasContext *dc, TCGv rd, TCGv ra, int32_t ofs) { TCGv ea = tcg_temp_new(); @@ -590,6 +678,11 @@ static void dec_calc(DisasContext *dc, uint32_t insn) gen_mul(dc, cpu_R[rd], cpu_R[ra], cpu_R[rb]); return; + case 0x7: /* l.muld */ + LOG_DIS("l.muld r%d, r%d\n", ra, rb); + gen_muld(dc, cpu_R[ra], cpu_R[rb]); + break; + case 0x9: /* l.div */ LOG_DIS("l.div r%d, r%d, r%d\n", rd, ra, rb); gen_div(dc, cpu_R[rd], cpu_R[ra], cpu_R[rb]); @@ -604,6 +697,11 @@ static void dec_calc(DisasContext *dc, uint32_t insn) LOG_DIS("l.mulu r%d, r%d, r%d\n", rd, ra, rb); gen_mulu(dc, cpu_R[rd], cpu_R[ra], cpu_R[rb]); return; + + case 0xc: /* l.muldu */ + LOG_DIS("l.muldu r%d, r%d\n", ra, rb); + gen_muldu(dc, cpu_R[ra], cpu_R[rb]); + return; } break; } @@ -916,6 +1014,16 @@ static void dec_mac(DisasContext *dc, uint32_t insn) gen_msb(dc, cpu_R[ra], cpu_R[rb]); break; + case 0x0003: /* l.macu */ + LOG_DIS("l.macu r%d, r%d\n", ra, rb); + gen_macu(dc, cpu_R[ra], cpu_R[rb]); + break; + + case 0x0004: /* l.msbu */ + LOG_DIS("l.msbu r%d, r%d\n", ra, rb); + gen_msbu(dc, cpu_R[ra], cpu_R[rb]); + break; + default: gen_illegal_exception(dc); break; |