static void dec_calc(DisasContext *dc, uint32_t insn) { uint32_t op0, op1, op2; uint32_t ra, rb, rd; op0 = extract32(insn, 0, 4); op1 = extract32(insn, 8, 2); op2 = extract32(insn, 6, 2); ra = extract32(insn, 16, 5); rb = extract32(insn, 11, 5); rd = extract32(insn, 21, 5); switch (op0) { case 0x0000: switch (op1) { case 0x00: /* l.add */ LOG_DIS("l.add r%d, r%d, r%d\n", rd, ra, rb); { int lab = gen_new_label(); TCGv_i64 ta = tcg_temp_new_i64(); TCGv_i64 tb = tcg_temp_new_i64(); TCGv_i64 td = tcg_temp_local_new_i64(); TCGv_i32 res = tcg_temp_local_new_i32(); TCGv_i32 sr_ove = tcg_temp_local_new_i32(); tcg_gen_extu_i32_i64(ta, cpu_R[ra]); tcg_gen_extu_i32_i64(tb, cpu_R[rb]); tcg_gen_add_i64(td, ta, tb); tcg_gen_trunc_i64_i32(res, td); tcg_gen_shri_i64(td, td, 31); tcg_gen_andi_i64(td, td, 0x3); /* Jump to lab when no overflow. */ tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x0, lab); tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x3, lab); tcg_gen_ori_i32(cpu_sr, cpu_sr, (SR_OV | SR_CY)); tcg_gen_andi_i32(sr_ove, cpu_sr, SR_OVE); tcg_gen_brcondi_i32(TCG_COND_NE, sr_ove, SR_OVE, lab); gen_exception(dc, EXCP_RANGE); gen_set_label(lab); tcg_gen_mov_i32(cpu_R[rd], res); tcg_temp_free_i64(ta); tcg_temp_free_i64(tb); tcg_temp_free_i64(td); tcg_temp_free_i32(res); tcg_temp_free_i32(sr_ove); } break; default: gen_illegal_exception(dc); break; } break; case 0x0001: /* l.addc */ switch (op1) { case 0x00: LOG_DIS("l.addc r%d, r%d, r%d\n", rd, ra, rb); { int lab = gen_new_label(); TCGv_i64 ta = tcg_temp_new_i64(); TCGv_i64 tb = tcg_temp_new_i64(); TCGv_i64 tcy = tcg_temp_local_new_i64(); TCGv_i64 td = tcg_temp_local_new_i64(); TCGv_i32 res = tcg_temp_local_new_i32(); TCGv_i32 sr_cy = tcg_temp_local_new_i32(); TCGv_i32 sr_ove = tcg_temp_local_new_i32(); tcg_gen_extu_i32_i64(ta, cpu_R[ra]); tcg_gen_extu_i32_i64(tb, cpu_R[rb]); tcg_gen_andi_i32(sr_cy, cpu_sr, SR_CY); tcg_gen_extu_i32_i64(tcy, sr_cy); tcg_gen_shri_i64(tcy, tcy, 10); tcg_gen_add_i64(td, ta, tb); tcg_gen_add_i64(td, td, tcy); tcg_gen_trunc_i64_i32(res, td); tcg_gen_shri_i64(td, td, 32); tcg_gen_andi_i64(td, td, 0x3); /* Jump to lab when no overflow. */ tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x0, lab); tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x3, lab); tcg_gen_ori_i32(cpu_sr, cpu_sr, (SR_OV | SR_CY)); tcg_gen_andi_i32(sr_ove, cpu_sr, SR_OVE); tcg_gen_brcondi_i32(TCG_COND_NE, sr_ove, SR_OVE, lab); gen_exception(dc, EXCP_RANGE); gen_set_label(lab); tcg_gen_mov_i32(cpu_R[rd], res); tcg_temp_free_i64(ta); tcg_temp_free_i64(tb); tcg_temp_free_i64(tcy); tcg_temp_free_i64(td); tcg_temp_free_i32(res); tcg_temp_free_i32(sr_cy); tcg_temp_free_i32(sr_ove); } break; default: gen_illegal_exception(dc); break; } break; case 0x0002: /* l.sub */ switch (op1) { case 0x00: LOG_DIS("l.sub r%d, r%d, r%d\n", rd, ra, rb); { int lab = gen_new_label(); TCGv_i64 ta = tcg_temp_new_i64(); TCGv_i64 tb = tcg_temp_new_i64(); TCGv_i64 td = tcg_temp_local_new_i64(); TCGv_i32 res = tcg_temp_local_new_i32(); TCGv_i32 sr_ove = tcg_temp_local_new_i32(); tcg_gen_extu_i32_i64(ta, cpu_R[ra]); tcg_gen_extu_i32_i64(tb, cpu_R[rb]); tcg_gen_sub_i64(td, ta, tb); tcg_gen_trunc_i64_i32(res, td); tcg_gen_shri_i64(td, td, 31); tcg_gen_andi_i64(td, td, 0x3); /* Jump to lab when no overflow. */ tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x0, lab); tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x3, lab); tcg_gen_ori_i32(cpu_sr, cpu_sr, (SR_OV | SR_CY)); tcg_gen_andi_i32(sr_ove, cpu_sr, SR_OVE); tcg_gen_brcondi_i32(TCG_COND_NE, sr_ove, SR_OVE, lab); gen_exception(dc, EXCP_RANGE); gen_set_label(lab); tcg_gen_mov_i32(cpu_R[rd], res); tcg_temp_free_i64(ta); tcg_temp_free_i64(tb); tcg_temp_free_i64(td); tcg_temp_free_i32(res); tcg_temp_free_i32(sr_ove); } break; default: gen_illegal_exception(dc); break; } break; case 0x0003: /* l.and */ switch (op1) { case 0x00: LOG_DIS("l.and r%d, r%d, r%d\n", rd, ra, rb); tcg_gen_and_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]); break; default: gen_illegal_exception(dc); break; } break; case 0x0004: /* l.or */ switch (op1) { case 0x00: LOG_DIS("l.or r%d, r%d, r%d\n", rd, ra, rb); tcg_gen_or_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]); break; default: gen_illegal_exception(dc); break; } break; case 0x0005: switch (op1) { case 0x00: /* l.xor */ LOG_DIS("l.xor r%d, r%d, r%d\n", rd, ra, rb); tcg_gen_xor_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]); break; default: gen_illegal_exception(dc); break; } break; case 0x0006: switch (op1) { case 0x03: /* l.mul */ LOG_DIS("l.mul r%d, r%d, r%d\n", rd, ra, rb); if (ra != 0 && rb != 0) { gen_helper_mul32(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]); } else { tcg_gen_movi_tl(cpu_R[rd], 0x0); } break; default: gen_illegal_exception(dc); break; } break; case 0x0009: switch (op1) { case 0x03: /* l.div */ LOG_DIS("l.div r%d, r%d, r%d\n", rd, ra, rb); { int lab0 = gen_new_label(); int lab1 = gen_new_label(); int lab2 = gen_new_label(); int lab3 = gen_new_label(); TCGv_i32 sr_ove = tcg_temp_local_new_i32(); if (rb == 0) { tcg_gen_ori_tl(cpu_sr, cpu_sr, (SR_OV | SR_CY)); tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE); tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab0); gen_exception(dc, EXCP_RANGE); gen_set_label(lab0); } else { tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_R[rb], 0x00000000, lab1); tcg_gen_brcondi_tl(TCG_COND_NE, cpu_R[ra], 0x80000000, lab2); tcg_gen_brcondi_tl(TCG_COND_NE, cpu_R[rb], 0xffffffff, lab2); gen_set_label(lab1); tcg_gen_ori_tl(cpu_sr, cpu_sr, (SR_OV | SR_CY)); tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE); tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab3); gen_exception(dc, EXCP_RANGE); gen_set_label(lab2); tcg_gen_div_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]); gen_set_label(lab3); } tcg_temp_free_i32(sr_ove); } break; default: gen_illegal_exception(dc); break; } break; case 0x000a: switch (op1) { case 0x03: /* l.divu */ LOG_DIS("l.divu r%d, r%d, r%d\n", rd, ra, rb); { int lab0 = gen_new_label(); int lab1 = gen_new_label(); int lab2 = gen_new_label(); TCGv_i32 sr_ove = tcg_temp_local_new_i32(); if (rb == 0) { tcg_gen_ori_tl(cpu_sr, cpu_sr, (SR_OV | SR_CY)); tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE); tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab0); gen_exception(dc, EXCP_RANGE); gen_set_label(lab0); } else { tcg_gen_brcondi_tl(TCG_COND_NE, cpu_R[rb], 0x00000000, lab1); tcg_gen_ori_tl(cpu_sr, cpu_sr, (SR_OV | SR_CY)); tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE); tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab2); gen_exception(dc, EXCP_RANGE); gen_set_label(lab1); tcg_gen_divu_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]); gen_set_label(lab2); } tcg_temp_free_i32(sr_ove); } break; default: gen_illegal_exception(dc); break; } break; case 0x000b: switch (op1) { case 0x03: /* l.mulu */ LOG_DIS("l.mulu r%d, r%d, r%d\n", rd, ra, rb); if (rb != 0 && ra != 0) { TCGv_i64 result = tcg_temp_local_new_i64(); TCGv_i64 tra = tcg_temp_local_new_i64(); TCGv_i64 trb = tcg_temp_local_new_i64(); TCGv_i64 high = tcg_temp_new_i64(); TCGv_i32 sr_ove = tcg_temp_local_new_i32(); int lab = gen_new_label(); /* Calculate each result. */ tcg_gen_extu_i32_i64(tra, cpu_R[ra]); tcg_gen_extu_i32_i64(trb, cpu_R[rb]); tcg_gen_mul_i64(result, tra, trb); tcg_temp_free_i64(tra); tcg_temp_free_i64(trb); tcg_gen_shri_i64(high, result, TARGET_LONG_BITS); /* Overflow or not. */ tcg_gen_brcondi_i64(TCG_COND_EQ, high, 0x00000000, lab); tcg_gen_ori_tl(cpu_sr, cpu_sr, (SR_OV | SR_CY)); tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE); tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab); gen_exception(dc, EXCP_RANGE); gen_set_label(lab); tcg_temp_free_i64(high); tcg_gen_trunc_i64_tl(cpu_R[rd], result); tcg_temp_free_i64(result); tcg_temp_free_i32(sr_ove); } else { tcg_gen_movi_tl(cpu_R[rd], 0); } break; default: gen_illegal_exception(dc); break; } break; case 0x000e: switch (op1) { case 0x00: /* l.cmov */ LOG_DIS("l.cmov r%d, r%d, r%d\n", rd, ra, rb); { int lab = gen_new_label(); TCGv res = tcg_temp_local_new(); TCGv sr_f = tcg_temp_new(); tcg_gen_andi_tl(sr_f, cpu_sr, SR_F); tcg_gen_mov_tl(res, cpu_R[rb]); tcg_gen_brcondi_tl(TCG_COND_NE, sr_f, SR_F, lab); tcg_gen_mov_tl(res, cpu_R[ra]); gen_set_label(lab); tcg_gen_mov_tl(cpu_R[rd], res); tcg_temp_free(sr_f); tcg_temp_free(res); } break; default: gen_illegal_exception(dc); break; } break; case 0x000f: switch (op1) { case 0x00: /* l.ff1 */ LOG_DIS("l.ff1 r%d, r%d, r%d\n", rd, ra, rb); gen_helper_ff1(cpu_R[rd], cpu_R[ra]); break; case 0x01: /* l.fl1 */ LOG_DIS("l.fl1 r%d, r%d, r%d\n", rd, ra, rb); gen_helper_fl1(cpu_R[rd], cpu_R[ra]); break; default: gen_illegal_exception(dc); break; } break; case 0x0008: switch (op1) { case 0x00: switch (op2) { case 0x00: /* l.sll */ LOG_DIS("l.sll r%d, r%d, r%d\n", rd, ra, rb); tcg_gen_shl_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]); break; case 0x01: /* l.srl */ LOG_DIS("l.srl r%d, r%d, r%d\n", rd, ra, rb); tcg_gen_shr_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]); break; case 0x02: /* l.sra */ LOG_DIS("l.sra r%d, r%d, r%d\n", rd, ra, rb); tcg_gen_sar_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]); break; case 0x03: /* l.ror */ LOG_DIS("l.ror r%d, r%d, r%d\n", rd, ra, rb); tcg_gen_rotr_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]); break; default: gen_illegal_exception(dc); break; } break; default: gen_illegal_exception(dc); break; } break; case 0x000c: switch (op1) { case 0x00: switch (op2) { case 0x00: /* l.exths */ LOG_DIS("l.exths r%d, r%d\n", rd, ra); tcg_gen_ext16s_tl(cpu_R[rd], cpu_R[ra]); break; case 0x01: /* l.extbs */ LOG_DIS("l.extbs r%d, r%d\n", rd, ra); tcg_gen_ext8s_tl(cpu_R[rd], cpu_R[ra]); break; case 0x02: /* l.exthz */ LOG_DIS("l.exthz r%d, r%d\n", rd, ra); tcg_gen_ext16u_tl(cpu_R[rd], cpu_R[ra]); break; case 0x03: /* l.extbz */ LOG_DIS("l.extbz r%d, r%d\n", rd, ra); tcg_gen_ext8u_tl(cpu_R[rd], cpu_R[ra]); break; default: gen_illegal_exception(dc); break; } break; default: gen_illegal_exception(dc); break; } break; case 0x000d: switch (op1) { case 0x00: switch (op2) { case 0x00: /* l.extws */ LOG_DIS("l.extws r%d, r%d\n", rd, ra); tcg_gen_ext32s_tl(cpu_R[rd], cpu_R[ra]); break; case 0x01: /* l.extwz */ LOG_DIS("l.extwz r%d, r%d\n", rd, ra); tcg_gen_ext32u_tl(cpu_R[rd], cpu_R[ra]); break; default: gen_illegal_exception(dc); break; } break; default: gen_illegal_exception(dc); break; } break; default: gen_illegal_exception(dc); break; } }