diff --git a/target-tricore/cpu.c b/target-tricore/cpu.c index abe16fa7e6..2ba0cf4c89 100644 --- a/target-tricore/cpu.c +++ b/target-tricore/cpu.c @@ -118,7 +118,7 @@ static void tc1796_initfn(Object *obj) { TriCoreCPU *cpu = TRICORE_CPU(obj); - set_feature(&cpu->env, TRICORE_FEATURE_13); + set_feature(&cpu->env, TRICORE_FEATURE_131); } static void aurix_initfn(Object *obj) diff --git a/target-tricore/cpu.h b/target-tricore/cpu.h index 7555b70a47..e5409e45f3 100644 --- a/target-tricore/cpu.h +++ b/target-tricore/cpu.h @@ -238,6 +238,7 @@ struct CPUTriCoreState { #define MASK_LCX_LCXS 0x000f0000 #define MASK_LCX_LCX0 0x0000ffff +#define TRICORE_HFLAG_KUU 0x3 #define TRICORE_HFLAG_UM0 0x00002 /* user mode-0 flag */ #define TRICORE_HFLAG_UM1 0x00001 /* user mode-1 flag */ #define TRICORE_HFLAG_SM 0x00000 /* kernel mode flag */ diff --git a/target-tricore/helper.h b/target-tricore/helper.h index 068dc7b422..7405feee88 100644 --- a/target-tricore/helper.h +++ b/target-tricore/helper.h @@ -60,10 +60,14 @@ DEF_HELPER_FLAGS_2(max_b, TCG_CALL_NO_RWG_SE, i32, i32, i32) DEF_HELPER_FLAGS_2(max_bu, TCG_CALL_NO_RWG_SE, i32, i32, i32) DEF_HELPER_FLAGS_2(max_h, TCG_CALL_NO_RWG_SE, i32, i32, i32) DEF_HELPER_FLAGS_2(max_hu, TCG_CALL_NO_RWG_SE, i32, i32, i32) +DEF_HELPER_FLAGS_2(ixmax, TCG_CALL_NO_RWG_SE, i64, i64, i32) +DEF_HELPER_FLAGS_2(ixmax_u, TCG_CALL_NO_RWG_SE, i64, i64, i32) DEF_HELPER_FLAGS_2(min_b, TCG_CALL_NO_RWG_SE, i32, i32, i32) DEF_HELPER_FLAGS_2(min_bu, TCG_CALL_NO_RWG_SE, i32, i32, i32) DEF_HELPER_FLAGS_2(min_h, TCG_CALL_NO_RWG_SE, i32, i32, i32) DEF_HELPER_FLAGS_2(min_hu, TCG_CALL_NO_RWG_SE, i32, i32, i32) +DEF_HELPER_FLAGS_2(ixmin, TCG_CALL_NO_RWG_SE, i64, i64, i32) +DEF_HELPER_FLAGS_2(ixmin_u, TCG_CALL_NO_RWG_SE, i64, i64, i32) /* count leading ... */ DEF_HELPER_FLAGS_1(clo, TCG_CALL_NO_RWG_SE, i32, i32) DEF_HELPER_FLAGS_1(clo_h, TCG_CALL_NO_RWG_SE, i32, i32) @@ -81,12 +85,16 @@ DEF_HELPER_FLAGS_2(bmerge, TCG_CALL_NO_RWG_SE, i32, i32, i32) DEF_HELPER_FLAGS_1(bsplit, TCG_CALL_NO_RWG_SE, i64, i32) DEF_HELPER_FLAGS_1(parity, TCG_CALL_NO_RWG_SE, i32, i32) /* float */ +DEF_HELPER_FLAGS_4(pack, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32, i32) DEF_HELPER_1(unpack, i64, i32) /* dvinit */ DEF_HELPER_3(dvinit_b_13, i64, env, i32, i32) DEF_HELPER_3(dvinit_b_131, i64, env, i32, i32) DEF_HELPER_3(dvinit_h_13, i64, env, i32, i32) DEF_HELPER_3(dvinit_h_131, i64, env, i32, i32) +DEF_HELPER_FLAGS_2(dvadj, TCG_CALL_NO_RWG_SE, i64, i64, i32) +DEF_HELPER_FLAGS_2(dvstep, TCG_CALL_NO_RWG_SE, i64, i64, i32) +DEF_HELPER_FLAGS_2(dvstep_u, TCG_CALL_NO_RWG_SE, i64, i64, i32) /* mulh */ DEF_HELPER_FLAGS_5(mul_h, TCG_CALL_NO_RWG_SE, i64, i32, i32, i32, i32, i32) DEF_HELPER_FLAGS_5(mulm_h, TCG_CALL_NO_RWG_SE, i64, i32, i32, i32, i32, i32) diff --git a/target-tricore/op_helper.c b/target-tricore/op_helper.c index 13e27291c1..ed26b302b0 100644 --- a/target-tricore/op_helper.c +++ b/target-tricore/op_helper.c @@ -80,29 +80,40 @@ static uint32_t ssov32(CPUTriCoreState *env, int64_t arg) return ret; } -static uint32_t suov32(CPUTriCoreState *env, int64_t arg) +static uint32_t suov32_pos(CPUTriCoreState *env, uint64_t arg) { uint32_t ret; - int64_t max_pos = UINT32_MAX; + uint64_t max_pos = UINT32_MAX; if (arg > max_pos) { env->PSW_USB_V = (1 << 31); env->PSW_USB_SV = (1 << 31); ret = (target_ulong)max_pos; } else { - if (arg < 0) { - env->PSW_USB_V = (1 << 31); - env->PSW_USB_SV = (1 << 31); - ret = 0; - } else { - env->PSW_USB_V = 0; - ret = (target_ulong)arg; - } + env->PSW_USB_V = 0; + ret = (target_ulong)arg; } env->PSW_USB_AV = arg ^ arg * 2u; env->PSW_USB_SAV |= env->PSW_USB_AV; return ret; } +static uint32_t suov32_neg(CPUTriCoreState *env, int64_t arg) +{ + uint32_t ret; + + if (arg < 0) { + env->PSW_USB_V = (1 << 31); + env->PSW_USB_SV = (1 << 31); + ret = 0; + } else { + env->PSW_USB_V = 0; + ret = (target_ulong)arg; + } + env->PSW_USB_AV = arg ^ arg * 2u; + env->PSW_USB_SAV |= env->PSW_USB_AV; + return ret; +} + static uint32_t ssov16(CPUTriCoreState *env, int32_t hw0, int32_t hw1) { int32_t max_pos = INT16_MAX; @@ -189,7 +200,7 @@ target_ulong helper_add_suov(CPUTriCoreState *env, target_ulong r1, int64_t t1 = extract64(r1, 0, 32); int64_t t2 = extract64(r2, 0, 32); int64_t result = t1 + t2; - return suov32(env, result); + return suov32_pos(env, result); } target_ulong helper_add_h_suov(CPUTriCoreState *env, target_ulong r1, @@ -227,7 +238,7 @@ target_ulong helper_sub_suov(CPUTriCoreState *env, target_ulong r1, int64_t t1 = extract64(r1, 0, 32); int64_t t2 = extract64(r2, 0, 32); int64_t result = t1 - t2; - return suov32(env, result); + return suov32_neg(env, result); } target_ulong helper_sub_h_suov(CPUTriCoreState *env, target_ulong r1, @@ -255,7 +266,8 @@ target_ulong helper_mul_suov(CPUTriCoreState *env, target_ulong r1, int64_t t1 = extract64(r1, 0, 32); int64_t t2 = extract64(r2, 0, 32); int64_t result = t1 * t2; - return suov32(env, result); + + return suov32_pos(env, result); } target_ulong helper_sha_ssov(CPUTriCoreState *env, target_ulong r1, @@ -355,7 +367,7 @@ target_ulong helper_madd32_suov(CPUTriCoreState *env, target_ulong r1, int64_t result; result = t2 + (t1 * t3); - return suov32(env, result); + return suov32_pos(env, result); } uint64_t helper_madd64_ssov(CPUTriCoreState *env, target_ulong r1, @@ -370,6 +382,10 @@ uint64_t helper_madd64_ssov(CPUTriCoreState *env, target_ulong r1, ret = mul + r2; ovf = (ret ^ mul) & ~(mul ^ r2); + t1 = ret >> 32; + env->PSW_USB_AV = t1 ^ t1 * 2u; + env->PSW_USB_SAV |= env->PSW_USB_AV; + if ((int64_t)ovf < 0) { env->PSW_USB_V = (1 << 31); env->PSW_USB_SV = (1 << 31); @@ -383,9 +399,6 @@ uint64_t helper_madd64_ssov(CPUTriCoreState *env, target_ulong r1, } else { env->PSW_USB_V = 0; } - t1 = ret >> 32; - env->PSW_USB_AV = t1 ^ t1 * 2u; - env->PSW_USB_SAV |= env->PSW_USB_AV; return ret; } @@ -400,6 +413,10 @@ uint64_t helper_madd64_suov(CPUTriCoreState *env, target_ulong r1, mul = t1 * t3; ret = mul + r2; + t1 = ret >> 32; + env->PSW_USB_AV = t1 ^ t1 * 2u; + env->PSW_USB_SAV |= env->PSW_USB_AV; + if (ret < r2) { env->PSW_USB_V = (1 << 31); env->PSW_USB_SV = (1 << 31); @@ -408,9 +425,6 @@ uint64_t helper_madd64_suov(CPUTriCoreState *env, target_ulong r1, } else { env->PSW_USB_V = 0; } - t1 = ret >> 32; - env->PSW_USB_AV = t1 ^ t1 * 2u; - env->PSW_USB_SAV |= env->PSW_USB_AV; return ret; } @@ -435,7 +449,7 @@ target_ulong helper_msub32_suov(CPUTriCoreState *env, target_ulong r1, int64_t result; result = t2 - (t1 * t3); - return suov32(env, result); + return suov32_neg(env, result); } uint64_t helper_msub64_ssov(CPUTriCoreState *env, target_ulong r1, @@ -450,6 +464,10 @@ uint64_t helper_msub64_ssov(CPUTriCoreState *env, target_ulong r1, ret = r2 - mul; ovf = (ret ^ r2) & (mul ^ r2); + t1 = ret >> 32; + env->PSW_USB_AV = t1 ^ t1 * 2u; + env->PSW_USB_SAV |= env->PSW_USB_AV; + if ((int64_t)ovf < 0) { env->PSW_USB_V = (1 << 31); env->PSW_USB_SV = (1 << 31); @@ -463,9 +481,6 @@ uint64_t helper_msub64_ssov(CPUTriCoreState *env, target_ulong r1, } else { env->PSW_USB_V = 0; } - t1 = ret >> 32; - env->PSW_USB_AV = t1 ^ t1 * 2u; - env->PSW_USB_SAV |= env->PSW_USB_AV; return ret; } @@ -479,6 +494,10 @@ uint64_t helper_msub64_suov(CPUTriCoreState *env, target_ulong r1, mul = t1 * t3; ret = r2 - mul; + t1 = ret >> 32; + env->PSW_USB_AV = t1 ^ t1 * 2u; + env->PSW_USB_SAV |= env->PSW_USB_AV; + if (ret > r2) { env->PSW_USB_V = (1 << 31); env->PSW_USB_SV = (1 << 31); @@ -487,9 +506,6 @@ uint64_t helper_msub64_suov(CPUTriCoreState *env, target_ulong r1, } else { env->PSW_USB_V = 0; } - t1 = ret >> 32; - env->PSW_USB_AV = t1 ^ t1 * 2u; - env->PSW_USB_SAV |= env->PSW_USB_AV; return ret; } @@ -867,6 +883,50 @@ uint32_t helper_##name ##_hu(target_ulong r1, target_ulong r2)\ \ return ret; \ } \ + \ +uint64_t helper_ix##name(uint64_t r1, uint32_t r2) \ +{ \ + int64_t r2l, r2h, r1hl; \ + uint64_t ret = 0; \ + \ + ret = ((r1 + 2) & 0xffff); \ + r2l = sextract64(r2, 0, 16); \ + r2h = sextract64(r2, 16, 16); \ + r1hl = sextract64(r1, 32, 16); \ + \ + if ((r2l op ## = r2h) && (r2l op r1hl)) { \ + ret |= (r2l & 0xffff) << 32; \ + ret |= extract64(r1, 0, 16) << 16; \ + } else if ((r2h op r2l) && (r2h op r1hl)) { \ + ret |= extract64(r2, 16, 16) << 32; \ + ret |= extract64(r1 + 1, 0, 16) << 16; \ + } else { \ + ret |= r1 & 0xffffffff0000ull; \ + } \ + return ret; \ +} \ + \ +uint64_t helper_ix##name ##_u(uint64_t r1, uint32_t r2) \ +{ \ + int64_t r2l, r2h, r1hl; \ + uint64_t ret = 0; \ + \ + ret = ((r1 + 2) & 0xffff); \ + r2l = extract64(r2, 0, 16); \ + r2h = extract64(r2, 16, 16); \ + r1hl = extract64(r1, 32, 16); \ + \ + if ((r2l op ## = r2h) && (r2l op r1hl)) { \ + ret |= (r2l & 0xffff) << 32; \ + ret |= extract64(r1, 0, 16) << 16; \ + } else if ((r2h op r2l) && (r2h op r1hl)) { \ + ret |= extract64(r2, 16, 16) << 32; \ + ret |= extract64(r1 + 1, 0, 16) << 16; \ + } else { \ + ret |= r1 & 0xffffffff0000ull; \ + } \ + return ret; \ +} EXTREMA_H_B(max, >) EXTREMA_H_B(min, <) @@ -994,7 +1054,7 @@ uint32_t helper_sha(CPUTriCoreState *env, target_ulong r1, target_ulong r2) } else if (shift_count > 0) { result = t1 << shift_count; /* calc carry */ - env->PSW_USB_C = ((result & 0xffffffff00000000) != 0); + env->PSW_USB_C = ((result & 0xffffffff00000000ULL) != 0); /* calc v */ env->PSW_USB_V = (((result > 0x7fffffffLL) || (result < -0x80000000LL)) << 31); @@ -1100,6 +1160,48 @@ uint32_t helper_parity(target_ulong r1) return ret; } +uint32_t helper_pack(uint32_t carry, uint32_t r1_low, uint32_t r1_high, + target_ulong r2) +{ + uint32_t ret; + int32_t fp_exp, fp_frac, temp_exp, fp_exp_frac; + int32_t int_exp = r1_high; + int32_t int_mant = r1_low; + uint32_t flag_rnd = (int_mant & (1 << 7)) && ( + (int_mant & (1 << 8)) || + (int_mant & 0x7f) || + (carry != 0)); + if (((int_mant & (1<<31)) == 0) && (int_exp == 255)) { + fp_exp = 255; + fp_frac = extract32(int_mant, 8, 23); + } else if ((int_mant & (1<<31)) && (int_exp >= 127)) { + fp_exp = 255; + fp_frac = 0; + } else if ((int_mant & (1<<31)) && (int_exp <= -128)) { + fp_exp = 0; + fp_frac = 0; + } else if (int_mant == 0) { + fp_exp = 0; + fp_frac = 0; + } else { + if (((int_mant & (1 << 31)) == 0)) { + temp_exp = 0; + } else { + temp_exp = int_exp + 128; + } + fp_exp_frac = (((temp_exp & 0xff) << 23) | + extract32(int_mant, 8, 23)) + + flag_rnd; + fp_exp = extract32(fp_exp_frac, 23, 8); + fp_frac = extract32(fp_exp_frac, 0, 23); + } + ret = r2 & (1 << 31); + ret = ret + (fp_exp << 23); + ret = ret + (fp_frac & 0x7fffff); + + return ret; +} + uint64_t helper_unpack(target_ulong arg1) { int32_t fp_exp = extract32(arg1, 23, 8); @@ -1228,6 +1330,80 @@ uint64_t helper_dvinit_h_131(CPUTriCoreState *env, uint32_t r1, uint32_t r2) return ret; } +uint64_t helper_dvadj(uint64_t r1, uint32_t r2) +{ + int32_t x_sign = (r1 >> 63); + int32_t q_sign = x_sign ^ (r2 >> 31); + int32_t eq_pos = x_sign & ((r1 >> 32) == r2); + int32_t eq_neg = x_sign & ((r1 >> 32) == -r2); + uint32_t quotient; + uint64_t ret, remainder; + + if ((q_sign & ~eq_neg) | eq_pos) { + quotient = (r1 + 1) & 0xffffffff; + } else { + quotient = r1 & 0xffffffff; + } + + if (eq_pos | eq_neg) { + remainder = 0; + } else { + remainder = (r1 & 0xffffffff00000000ull); + } + ret = remainder|quotient; + return ret; +} + +uint64_t helper_dvstep(uint64_t r1, uint32_t r2) +{ + int32_t dividend_sign = extract64(r1, 63, 1); + int32_t divisor_sign = extract32(r2, 31, 1); + int32_t quotient_sign = (dividend_sign != divisor_sign); + int32_t addend, dividend_quotient, remainder; + int32_t i, temp; + + if (quotient_sign) { + addend = r2; + } else { + addend = -r2; + } + dividend_quotient = (int32_t)r1; + remainder = (int32_t)(r1 >> 32); + + for (i = 0; i < 8; i++) { + remainder = (remainder << 1) | extract32(dividend_quotient, 31, 1); + dividend_quotient <<= 1; + temp = remainder + addend; + if ((temp < 0) == dividend_sign) { + remainder = temp; + } + if (((temp < 0) == dividend_sign)) { + dividend_quotient = dividend_quotient | !quotient_sign; + } else { + dividend_quotient = dividend_quotient | quotient_sign; + } + } + return ((uint64_t)remainder << 32) | (uint32_t)dividend_quotient; +} + +uint64_t helper_dvstep_u(uint64_t r1, uint32_t r2) +{ + int32_t dividend_quotient = extract64(r1, 0, 32); + int64_t remainder = extract64(r1, 32, 32); + int32_t i; + int64_t temp; + for (i = 0; i < 8; i++) { + remainder = (remainder << 1) | extract32(dividend_quotient, 31, 1); + dividend_quotient <<= 1; + temp = (remainder & 0xffffffff) - r2; + if (temp >= 0) { + remainder = temp; + } + dividend_quotient = dividend_quotient | !(temp < 0); + } + return ((uint64_t)remainder << 32) | (uint32_t)dividend_quotient; +} + uint64_t helper_mul_h(uint32_t arg00, uint32_t arg01, uint32_t arg10, uint32_t arg11, uint32_t n) { diff --git a/target-tricore/translate.c b/target-tricore/translate.c index def7f4ad45..a73b7000b4 100644 --- a/target-tricore/translate.c +++ b/target-tricore/translate.c @@ -182,6 +182,18 @@ void tricore_cpu_dump_state(CPUState *cs, FILE *f, tcg_temp_free(arg11); \ } while (0) +#define GEN_HELPER_RRR(name, rl, rh, al1, ah1, arg2) do { \ + TCGv_i64 ret = tcg_temp_new_i64(); \ + TCGv_i64 arg1 = tcg_temp_new_i64(); \ + \ + tcg_gen_concat_i32_i64(arg1, al1, ah1); \ + gen_helper_##name(ret, arg1, arg2); \ + tcg_gen_extr_i64_i32(rl, rh, ret); \ + \ + tcg_temp_free_i64(ret); \ + tcg_temp_free_i64(arg1); \ +} while (0) + #define EA_ABS_FORMAT(con) (((con & 0x3C000) << 14) + (con & 0x3FFF)) #define EA_B_ABSOLUT(con) (((offset & 0xf00000) << 8) | \ ((offset & 0x0fffff) << 1)) @@ -343,7 +355,7 @@ static inline void gen_mfcr(CPUTriCoreState *env, TCGv ret, int32_t offset) static inline void gen_mtcr(CPUTriCoreState *env, DisasContext *ctx, TCGv r1, int32_t offset) { - if (ctx->hflags & TRICORE_HFLAG_SM) { + if ((ctx->hflags & TRICORE_HFLAG_KUU) == TRICORE_HFLAG_SM) { /* since we're caching PSW make this a special case */ if (offset == 0xfe04) { gen_helper_psw_write(cpu_env, r1); @@ -745,7 +757,7 @@ static inline void gen_cond_add(TCGCond cond, TCGv r1, TCGv r2, TCGv r3, tcg_gen_and_tl(temp, temp, mask); tcg_gen_or_tl(cpu_PSW_SAV, temp, cpu_PSW_SAV); /* write back result */ - tcg_gen_movcond_tl(cond, r3, r4, t0, result, r3); + tcg_gen_movcond_tl(cond, r3, r4, t0, result, r1); tcg_temp_free(t0); tcg_temp_free(temp); @@ -820,6 +832,45 @@ static inline void gen_subc_CC(TCGv ret, TCGv r1, TCGv r2) tcg_temp_free(temp); } +static inline void gen_cond_sub(TCGCond cond, TCGv r1, TCGv r2, TCGv r3, + TCGv r4) +{ + TCGv temp = tcg_temp_new(); + TCGv temp2 = tcg_temp_new(); + TCGv result = tcg_temp_new(); + TCGv mask = tcg_temp_new(); + TCGv t0 = tcg_const_i32(0); + + /* create mask for sticky bits */ + tcg_gen_setcond_tl(cond, mask, r4, t0); + tcg_gen_shli_tl(mask, mask, 31); + + tcg_gen_sub_tl(result, r1, r2); + /* Calc PSW_V */ + tcg_gen_xor_tl(temp, result, r1); + tcg_gen_xor_tl(temp2, r1, r2); + tcg_gen_and_tl(temp, temp, temp2); + tcg_gen_movcond_tl(cond, cpu_PSW_V, r4, t0, temp, cpu_PSW_V); + /* Set PSW_SV */ + tcg_gen_and_tl(temp, temp, mask); + tcg_gen_or_tl(cpu_PSW_SV, temp, cpu_PSW_SV); + /* calc AV bit */ + tcg_gen_add_tl(temp, result, result); + tcg_gen_xor_tl(temp, temp, result); + tcg_gen_movcond_tl(cond, cpu_PSW_AV, r4, t0, temp, cpu_PSW_AV); + /* calc SAV bit */ + tcg_gen_and_tl(temp, temp, mask); + tcg_gen_or_tl(cpu_PSW_SAV, temp, cpu_PSW_SAV); + /* write back result */ + tcg_gen_movcond_tl(cond, r3, r4, t0, result, r1); + + tcg_temp_free(t0); + tcg_temp_free(temp); + tcg_temp_free(temp2); + tcg_temp_free(result); + tcg_temp_free(mask); +} + static inline void gen_abs(TCGv ret, TCGv r1) { TCGv temp = tcg_temp_new(); @@ -987,6 +1038,119 @@ static inline void gen_maddsui_32(TCGv ret, TCGv r1, TCGv r2, int32_t con) tcg_temp_free(temp); } +static void +gen_mul_q(TCGv rl, TCGv rh, TCGv arg1, TCGv arg2, uint32_t n, uint32_t up_shift) +{ + TCGv temp = tcg_temp_new(); + TCGv_i64 temp_64 = tcg_temp_new_i64(); + TCGv_i64 temp2_64 = tcg_temp_new_i64(); + + if (n == 0) { + if (up_shift == 32) { + tcg_gen_muls2_tl(rh, rl, arg1, arg2); + } else if (up_shift == 16) { + tcg_gen_ext_i32_i64(temp_64, arg1); + tcg_gen_ext_i32_i64(temp2_64, arg2); + + tcg_gen_mul_i64(temp_64, temp_64, temp2_64); + tcg_gen_shri_i64(temp_64, temp_64, up_shift); + tcg_gen_extr_i64_i32(rl, rh, temp_64); + } else { + tcg_gen_muls2_tl(rl, rh, arg1, arg2); + } + /* reset v bit */ + tcg_gen_movi_tl(cpu_PSW_V, 0); + } else { /* n is exspected to be 1 */ + tcg_gen_ext_i32_i64(temp_64, arg1); + tcg_gen_ext_i32_i64(temp2_64, arg2); + + tcg_gen_mul_i64(temp_64, temp_64, temp2_64); + + if (up_shift == 0) { + tcg_gen_shli_i64(temp_64, temp_64, 1); + } else { + tcg_gen_shri_i64(temp_64, temp_64, up_shift - 1); + } + tcg_gen_extr_i64_i32(rl, rh, temp_64); + /* overflow only occours if r1 = r2 = 0x8000 */ + if (up_shift == 0) {/* result is 64 bit */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_PSW_V, rh, + 0x80000000); + } else { /* result is 32 bit */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_PSW_V, rl, + 0x80000000); + } + tcg_gen_shli_tl(cpu_PSW_V, cpu_PSW_V, 31); + /* calc sv overflow bit */ + tcg_gen_or_tl(cpu_PSW_SV, cpu_PSW_SV, cpu_PSW_V); + } + /* calc av overflow bit */ + if (up_shift == 0) { + tcg_gen_add_tl(cpu_PSW_AV, rh, rh); + tcg_gen_xor_tl(cpu_PSW_AV, rh, cpu_PSW_AV); + } else { + tcg_gen_add_tl(cpu_PSW_AV, rl, rl); + tcg_gen_xor_tl(cpu_PSW_AV, rl, cpu_PSW_AV); + } + /* calc sav overflow bit */ + tcg_gen_or_tl(cpu_PSW_SAV, cpu_PSW_SAV, cpu_PSW_AV); + tcg_temp_free(temp); + tcg_temp_free_i64(temp_64); + tcg_temp_free_i64(temp2_64); +} + +static void +gen_mul_q_16(TCGv ret, TCGv arg1, TCGv arg2, uint32_t n) +{ + TCGv temp = tcg_temp_new(); + if (n == 0) { + tcg_gen_mul_tl(ret, arg1, arg2); + } else { /* n is exspected to be 1 */ + tcg_gen_mul_tl(ret, arg1, arg2); + tcg_gen_shli_tl(ret, ret, 1); + /* catch special case r1 = r2 = 0x8000 */ + tcg_gen_setcondi_tl(TCG_COND_EQ, temp, ret, 0x80000000); + tcg_gen_sub_tl(ret, ret, temp); + } + /* reset v bit */ + tcg_gen_movi_tl(cpu_PSW_V, 0); + /* calc av overflow bit */ + tcg_gen_add_tl(cpu_PSW_AV, ret, ret); + tcg_gen_xor_tl(cpu_PSW_AV, ret, cpu_PSW_AV); + /* calc sav overflow bit */ + tcg_gen_or_tl(cpu_PSW_SAV, cpu_PSW_SAV, cpu_PSW_AV); + + tcg_temp_free(temp); +} + +static void gen_mulr_q(TCGv ret, TCGv arg1, TCGv arg2, uint32_t n) +{ + TCGv temp = tcg_temp_new(); + if (n == 0) { + tcg_gen_mul_tl(ret, arg1, arg2); + tcg_gen_addi_tl(ret, ret, 0x8000); + } else { + tcg_gen_mul_tl(ret, arg1, arg2); + tcg_gen_shli_tl(ret, ret, 1); + tcg_gen_addi_tl(ret, ret, 0x8000); + /* catch special case r1 = r2 = 0x8000 */ + tcg_gen_setcondi_tl(TCG_COND_EQ, temp, ret, 0x80008000); + tcg_gen_muli_tl(temp, temp, 0x8001); + tcg_gen_sub_tl(ret, ret, temp); + } + /* reset v bit */ + tcg_gen_movi_tl(cpu_PSW_V, 0); + /* calc av overflow bit */ + tcg_gen_add_tl(cpu_PSW_AV, ret, ret); + tcg_gen_xor_tl(cpu_PSW_AV, ret, cpu_PSW_AV); + /* calc sav overflow bit */ + tcg_gen_or_tl(cpu_PSW_SAV, cpu_PSW_SAV, cpu_PSW_AV); + /* cut halfword off */ + tcg_gen_andi_tl(ret, ret, 0xffff0000); + + tcg_temp_free(temp); +} + static inline void gen_maddsi_64(TCGv ret_low, TCGv ret_high, TCGv r1, TCGv r2_low, TCGv r2_high, int32_t con) @@ -1647,6 +1811,7 @@ static void gen_compute_branch(DisasContext *ctx, uint32_t opc, int r1, break; case OPC1_32_B_JLA: tcg_gen_movi_tl(cpu_gpr_a[11], ctx->next_pc); + /* fall through */ case OPC1_32_B_JA: gen_goto_tb(ctx, 0, EA_B_ABSOLUT(offset)); break; @@ -3898,7 +4063,7 @@ static void decode_rcr_cond_select(CPUTriCoreState *env, DisasContext *ctx) case OPC2_32_RCR_SEL: temp = tcg_const_i32(0); temp2 = tcg_const_i32(const9); - tcg_gen_movcond_tl(TCG_COND_NE, cpu_gpr_d[r3], cpu_gpr_d[r4], temp, + tcg_gen_movcond_tl(TCG_COND_NE, cpu_gpr_d[r4], cpu_gpr_d[r3], temp, cpu_gpr_d[r1], temp2); tcg_temp_free(temp); tcg_temp_free(temp2); @@ -3906,7 +4071,7 @@ static void decode_rcr_cond_select(CPUTriCoreState *env, DisasContext *ctx) case OPC2_32_RCR_SELN: temp = tcg_const_i32(0); temp2 = tcg_const_i32(const9); - tcg_gen_movcond_tl(TCG_COND_EQ, cpu_gpr_d[r3], cpu_gpr_d[r4], temp, + tcg_gen_movcond_tl(TCG_COND_EQ, cpu_gpr_d[r4], cpu_gpr_d[r3], temp, cpu_gpr_d[r1], temp2); tcg_temp_free(temp); tcg_temp_free(temp2); @@ -4778,6 +4943,249 @@ static void decode_rr1_mul(CPUTriCoreState *env, DisasContext *ctx) tcg_temp_free(n); } +static void decode_rr1_mulq(CPUTriCoreState *env, DisasContext *ctx) +{ + uint32_t op2; + int r1, r2, r3; + uint32_t n; + + TCGv temp, temp2; + + r1 = MASK_OP_RR1_S1(ctx->opcode); + r2 = MASK_OP_RR1_S2(ctx->opcode); + r3 = MASK_OP_RR1_D(ctx->opcode); + n = MASK_OP_RR1_N(ctx->opcode); + op2 = MASK_OP_RR1_OP2(ctx->opcode); + + temp = tcg_temp_new(); + temp2 = tcg_temp_new(); + + switch (op2) { + case OPC2_32_RR1_MUL_Q_32: + gen_mul_q(cpu_gpr_d[r3], temp, cpu_gpr_d[r1], cpu_gpr_d[r2], n, 32); + break; + case OPC2_32_RR1_MUL_Q_64: + gen_mul_q(cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2], + n, 0); + break; + case OPC2_32_RR1_MUL_Q_32_L: + tcg_gen_ext16s_tl(temp, cpu_gpr_d[r2]); + gen_mul_q(cpu_gpr_d[r3], temp, cpu_gpr_d[r1], temp, n, 16); + break; + case OPC2_32_RR1_MUL_Q_64_L: + tcg_gen_ext16s_tl(temp, cpu_gpr_d[r2]); + gen_mul_q(cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1], temp, n, 0); + break; + case OPC2_32_RR1_MUL_Q_32_U: + tcg_gen_sari_tl(temp, cpu_gpr_d[r2], 16); + gen_mul_q(cpu_gpr_d[r3], temp, cpu_gpr_d[r1], temp, n, 16); + break; + case OPC2_32_RR1_MUL_Q_64_U: + tcg_gen_sari_tl(temp, cpu_gpr_d[r2], 16); + gen_mul_q(cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1], temp, n, 0); + break; + case OPC2_32_RR1_MUL_Q_32_LL: + tcg_gen_ext16s_tl(temp, cpu_gpr_d[r1]); + tcg_gen_ext16s_tl(temp2, cpu_gpr_d[r2]); + gen_mul_q_16(cpu_gpr_d[r3], temp, temp2, n); + break; + case OPC2_32_RR1_MUL_Q_32_UU: + tcg_gen_sari_tl(temp, cpu_gpr_d[r1], 16); + tcg_gen_sari_tl(temp2, cpu_gpr_d[r2], 16); + gen_mul_q_16(cpu_gpr_d[r3], temp, temp2, n); + break; + case OPC2_32_RR1_MULR_Q_32_L: + tcg_gen_ext16s_tl(temp, cpu_gpr_d[r1]); + tcg_gen_ext16s_tl(temp2, cpu_gpr_d[r2]); + gen_mulr_q(cpu_gpr_d[r3], temp, temp2, n); + break; + case OPC2_32_RR1_MULR_Q_32_U: + tcg_gen_sari_tl(temp, cpu_gpr_d[r1], 16); + tcg_gen_sari_tl(temp2, cpu_gpr_d[r2], 16); + gen_mulr_q(cpu_gpr_d[r3], temp, temp2, n); + break; + } + tcg_temp_free(temp); + tcg_temp_free(temp2); +} + +/* RR2 format */ +static void decode_rr2_mul(CPUTriCoreState *env, DisasContext *ctx) +{ + uint32_t op2; + int r1, r2, r3; + + op2 = MASK_OP_RR2_OP2(ctx->opcode); + r1 = MASK_OP_RR2_S1(ctx->opcode); + r2 = MASK_OP_RR2_S2(ctx->opcode); + r3 = MASK_OP_RR2_D(ctx->opcode); + switch (op2) { + case OPC2_32_RR2_MUL_32: + gen_mul_i32s(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]); + break; + case OPC2_32_RR2_MUL_64: + gen_mul_i64s(cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1], + cpu_gpr_d[r2]); + break; + case OPC2_32_RR2_MULS_32: + gen_helper_mul_ssov(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1], + cpu_gpr_d[r2]); + break; + case OPC2_32_RR2_MUL_U_64: + gen_mul_i64u(cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1], + cpu_gpr_d[r2]); + break; + case OPC2_32_RR2_MULS_U_32: + gen_helper_mul_suov(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1], + cpu_gpr_d[r2]); + break; + } +} + +/* RRPW format */ +static void decode_rrpw_extract_insert(CPUTriCoreState *env, DisasContext *ctx) +{ + uint32_t op2; + int r1, r2, r3; + int32_t pos, width; + + op2 = MASK_OP_RRPW_OP2(ctx->opcode); + r1 = MASK_OP_RRPW_S1(ctx->opcode); + r2 = MASK_OP_RRPW_S2(ctx->opcode); + r3 = MASK_OP_RRPW_D(ctx->opcode); + pos = MASK_OP_RRPW_POS(ctx->opcode); + width = MASK_OP_RRPW_WIDTH(ctx->opcode); + + switch (op2) { + case OPC2_32_RRPW_EXTR: + if (pos + width <= 31) { + /* optimize special cases */ + if ((pos == 0) && (width == 8)) { + tcg_gen_ext8s_tl(cpu_gpr_d[r3], cpu_gpr_d[r1]); + } else if ((pos == 0) && (width == 16)) { + tcg_gen_ext16s_tl(cpu_gpr_d[r3], cpu_gpr_d[r1]); + } else { + tcg_gen_shli_tl(cpu_gpr_d[r3], cpu_gpr_d[r1], 32 - pos - width); + tcg_gen_sari_tl(cpu_gpr_d[r3], cpu_gpr_d[r3], 32 - width); + } + } + break; + case OPC2_32_RRPW_EXTR_U: + if (width == 0) { + tcg_gen_movi_tl(cpu_gpr_d[r3], 0); + } else { + tcg_gen_shri_tl(cpu_gpr_d[r3], cpu_gpr_d[r1], pos); + tcg_gen_andi_tl(cpu_gpr_d[r3], cpu_gpr_d[r3], ~0u >> (32-width)); + } + break; + case OPC2_32_RRPW_IMASK: + if (pos + width <= 31) { + tcg_gen_movi_tl(cpu_gpr_d[r3+1], ((1u << width) - 1) << pos); + tcg_gen_shli_tl(cpu_gpr_d[r3], cpu_gpr_d[r2], pos); + } + break; + case OPC2_32_RRPW_INSERT: + if (pos + width <= 31) { + tcg_gen_deposit_tl(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2], + width, pos); + } + break; + } +} + +/* RRR format */ +static void decode_rrr_cond_select(CPUTriCoreState *env, DisasContext *ctx) +{ + uint32_t op2; + int r1, r2, r3, r4; + TCGv temp; + + op2 = MASK_OP_RRR_OP2(ctx->opcode); + r1 = MASK_OP_RRR_S1(ctx->opcode); + r2 = MASK_OP_RRR_S2(ctx->opcode); + r3 = MASK_OP_RRR_S3(ctx->opcode); + r4 = MASK_OP_RRR_D(ctx->opcode); + + switch (op2) { + case OPC2_32_RRR_CADD: + gen_cond_add(TCG_COND_NE, cpu_gpr_d[r1], cpu_gpr_d[r2], + cpu_gpr_d[r4], cpu_gpr_d[r3]); + break; + case OPC2_32_RRR_CADDN: + gen_cond_add(TCG_COND_EQ, cpu_gpr_d[r1], cpu_gpr_d[r2], cpu_gpr_d[r4], + cpu_gpr_d[r3]); + break; + case OPC2_32_RRR_CSUB: + gen_cond_sub(TCG_COND_NE, cpu_gpr_d[r1], cpu_gpr_d[r2], cpu_gpr_d[r4], + cpu_gpr_d[r3]); + break; + case OPC2_32_RRR_CSUBN: + gen_cond_sub(TCG_COND_EQ, cpu_gpr_d[r1], cpu_gpr_d[r2], cpu_gpr_d[r4], + cpu_gpr_d[r3]); + break; + case OPC2_32_RRR_SEL: + temp = tcg_const_i32(0); + tcg_gen_movcond_tl(TCG_COND_NE, cpu_gpr_d[r4], cpu_gpr_d[r3], temp, + cpu_gpr_d[r1], cpu_gpr_d[r2]); + tcg_temp_free(temp); + break; + case OPC2_32_RRR_SELN: + temp = tcg_const_i32(0); + tcg_gen_movcond_tl(TCG_COND_EQ, cpu_gpr_d[r4], cpu_gpr_d[r3], temp, + cpu_gpr_d[r1], cpu_gpr_d[r2]); + tcg_temp_free(temp); + break; + } +} + +static void decode_rrr_divide(CPUTriCoreState *env, DisasContext *ctx) +{ + uint32_t op2; + + int r1, r2, r3, r4; + + op2 = MASK_OP_RRR_OP2(ctx->opcode); + r1 = MASK_OP_RRR_S1(ctx->opcode); + r2 = MASK_OP_RRR_S2(ctx->opcode); + r3 = MASK_OP_RRR_S3(ctx->opcode); + r4 = MASK_OP_RRR_D(ctx->opcode); + + switch (op2) { + case OPC2_32_RRR_DVADJ: + GEN_HELPER_RRR(dvadj, cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r2]); + break; + case OPC2_32_RRR_DVSTEP: + GEN_HELPER_RRR(dvstep, cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r2]); + break; + case OPC2_32_RRR_DVSTEP_U: + GEN_HELPER_RRR(dvstep_u, cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r2]); + break; + case OPC2_32_RRR_IXMAX: + GEN_HELPER_RRR(ixmax, cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r2]); + break; + case OPC2_32_RRR_IXMAX_U: + GEN_HELPER_RRR(ixmax_u, cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r2]); + break; + case OPC2_32_RRR_IXMIN: + GEN_HELPER_RRR(ixmin, cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r2]); + break; + case OPC2_32_RRR_IXMIN_U: + GEN_HELPER_RRR(ixmin_u, cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r2]); + break; + case OPC2_32_RRR_PACK: + gen_helper_pack(cpu_gpr_d[r4], cpu_PSW_C, cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r1]); + break; + } +} + static void decode_32Bit_opc(CPUTriCoreState *env, DisasContext *ctx) { int op1; @@ -5035,6 +5443,38 @@ static void decode_32Bit_opc(CPUTriCoreState *env, DisasContext *ctx) case OPCM_32_RR1_MUL: decode_rr1_mul(env, ctx); break; + case OPCM_32_RR1_MULQ: + decode_rr1_mulq(env, ctx); + break; +/* RR2 format */ + case OPCM_32_RR2_MUL: + decode_rr2_mul(env, ctx); + break; +/* RRPW format */ + case OPCM_32_RRPW_EXTRACT_INSERT: + decode_rrpw_extract_insert(env, ctx); + break; + case OPC1_32_RRPW_DEXTR: + r1 = MASK_OP_RRPW_S1(ctx->opcode); + r2 = MASK_OP_RRPW_S2(ctx->opcode); + r3 = MASK_OP_RRPW_D(ctx->opcode); + const16 = MASK_OP_RRPW_POS(ctx->opcode); + if (r1 == r2) { + tcg_gen_rotli_tl(cpu_gpr_d[r3], cpu_gpr_d[r1], const16); + } else { + temp = tcg_temp_new(); + tcg_gen_shli_tl(cpu_gpr_d[r3], cpu_gpr_d[r2], const16); + tcg_gen_shri_tl(temp, cpu_gpr_d[r1], 32 - const16); + tcg_gen_or_tl(cpu_gpr_d[r3], cpu_gpr_d[r3], temp); + tcg_temp_free(temp); + } + break; +/* RRR Format */ + case OPCM_32_RRR_COND_SELECT: + decode_rrr_cond_select(env, ctx); + break; + case OPCM_32_RRR_DIVIDE: + decode_rrr_divide(env, ctx); } } diff --git a/target-tricore/tricore-opcodes.h b/target-tricore/tricore-opcodes.h index 82bd161645..baf537f160 100644 --- a/target-tricore/tricore-opcodes.h +++ b/target-tricore/tricore-opcodes.h @@ -516,7 +516,7 @@ enum { OPC1_32_RRPW_DEXTR = 0x77, /* RRR Format */ OPCM_32_RRR_COND_SELECT = 0x2b, - OPCM_32_RRR_FLOAT = 0x6b, + OPCM_32_RRR_DIVIDE = 0x6b, /* RRR1 Format */ OPCM_32_RRR1_MADD = 0x83, OPCM_32_RRR1_MADDQ_H = 0x43,