From 115d0540481c8b5ff4577487d7c3f00e1df8c99f Mon Sep 17 00:00:00 2001 From: xiongnandi Date: Mon, 5 Aug 2024 20:09:24 +0800 Subject: [PATCH] cortex-m7: fpu: Implement VMAXNM and VMINNM instructions --- arch/arm/helper.c | 2 ++ arch/arm/helper.h | 4 +++ arch/arm/translate.c | 58 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+) diff --git a/arch/arm/helper.c b/arch/arm/helper.c index 8693e7598..b520df6b3 100644 --- a/arch/arm/helper.c +++ b/arch/arm/helper.c @@ -2364,6 +2364,8 @@ VFP_BINOP(add) VFP_BINOP(sub) VFP_BINOP(mul) VFP_BINOP(div) +VFP_BINOP(minnum) +VFP_BINOP(maxnum) #undef VFP_BINOP float32 VFP_HELPER(neg, s)(float32 a) diff --git a/arch/arm/helper.h b/arch/arm/helper.h index 0f40fb625..377d18e1a 100644 --- a/arch/arm/helper.h +++ b/arch/arm/helper.h @@ -89,6 +89,10 @@ DEF_HELPER_3(vfp_muls, f32, f32, f32, ptr) DEF_HELPER_3(vfp_muld, f64, f64, f64, ptr) DEF_HELPER_3(vfp_divs, f32, f32, f32, ptr) DEF_HELPER_3(vfp_divd, f64, f64, f64, ptr) +DEF_HELPER_3(vfp_maxnums, f32, f32, f32, ptr) +DEF_HELPER_3(vfp_maxnumd, f64, f64, f64, ptr) +DEF_HELPER_3(vfp_minnums, f32, f32, f32, ptr) +DEF_HELPER_3(vfp_minnumd, f64, f64, f64, ptr) DEF_HELPER_1(vfp_negs, f32, f32) DEF_HELPER_1(vfp_negd, f64, f64) DEF_HELPER_1(vfp_abss, f32, f32) diff --git a/arch/arm/translate.c b/arch/arm/translate.c index bdb18ce70..bac06c00f 100644 --- a/arch/arm/translate.c +++ b/arch/arm/translate.c @@ -2789,6 +2789,55 @@ static int generate_vsel_insn(CPUState *env, DisasContext *s, uint32_t insn) return 0; } +/* See ARMv7-M Architecture Reference Manual - A7.7.237 */ +static int handle_vminmaxnm(uint32_t insn, uint32_t rd, uint32_t rn, + uint32_t rm, uint32_t dp) +{ + uint32_t vmin = extract32(insn, 6, 1); + TCGv_ptr fpst = get_fpstatus_ptr(0); + + if (dp) { + TCGv_i64 frn, frm, dest; + + frn = tcg_temp_new_i64(); + frm = tcg_temp_new_i64(); + dest = tcg_temp_new_i64(); + + tcg_gen_ld_f64(frn, cpu_env, vfp_reg_offset(dp, rn)); + tcg_gen_ld_f64(frm, cpu_env, vfp_reg_offset(dp, rm)); + if (vmin) { + gen_helper_vfp_minnumd(dest, frn, frm, fpst); + } else { + gen_helper_vfp_maxnumd(dest, frn, frm, fpst); + } + tcg_gen_st_f64(dest, cpu_env, vfp_reg_offset(dp, rd)); + tcg_temp_free_i64(frn); + tcg_temp_free_i64(frm); + tcg_temp_free_i64(dest); + } else { + TCGv_i32 frn, frm, dest; + + frn = tcg_temp_new_i32(); + frm = tcg_temp_new_i32(); + dest = tcg_temp_new_i32(); + + tcg_gen_ld_f32(frn, cpu_env, vfp_reg_offset(dp, rn)); + tcg_gen_ld_f32(frm, cpu_env, vfp_reg_offset(dp, rm)); + if (vmin) { + gen_helper_vfp_minnums(dest, frn, frm, fpst); + } else { + gen_helper_vfp_maxnums(dest, frn, frm, fpst); + } + tcg_gen_st_f32(dest, cpu_env, vfp_reg_offset(dp, rd)); + tcg_temp_free_i32(frn); + tcg_temp_free_i32(frm); + tcg_temp_free_i32(dest); + } + + tcg_temp_free_ptr(fpst); + return 0; +} + /* Disassemble a VFP instruction. Returns nonzero if an error occurred (ie. an undefined instruction). */ static int disas_vfp_insn(CPUState *env, DisasContext *s, uint32_t insn) @@ -3212,6 +3261,15 @@ static int disas_vfp_insn(CPUState *env, DisasContext *s, uint32_t insn) case 8: /* div: fn / fm */ gen_vfp_div(dp); break; + case 9: /* VMAXNM/VMINNM */ + /* TODO: may need to introduce feature like VFP5 here */ + /* FPv5 FPU add new floating-point maximum and minimum numbers instructions + * See ARMv7-M Architecture Reference Manual - A2.5 */ + if (!arm_feature(env, ARM_FEATURE_VFP4)) { + return 1; + } + handle_vminmaxnm(insn, rd, rn, rm, dp); + break; case 10: /* VFNMA : fd = muladd(-fd, fn, fm) */ case 11: /* VFNMS : fd = muladd(-fd, -fn, fm) */ case 12: /* VFMA : fd = muladd( fd, fn, fm) */