:p
atchew
Login
The following changes since commit 14556211bc6d7125a44d5b5df90caba019b0ec0e: Merge tag 'qemu-macppc-20240918' of https://github.com/mcayland/qemu into staging (2024-09-18 20:59:10 +0100) are available in the Git repository at: https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20240919 for you to fetch changes up to 89b30b4921e51bb47313d2d8fdc3d7bce987e4c5: docs/devel: Remove nested-papr.txt (2024-09-19 13:33:15 +0100) ---------------------------------------------------------------- target-arm queue: * target/arm: Correct ID_AA64ISAR1_EL1 value for neoverse-v1 * target/arm: More conversions to decodetree of A64 SIMD insns * hw/char/stm32l4x5_usart.c: Enable USART ACK bit response * tests: update aarch64/sbsa-ref tests * kvm: minor Coverity nit fixes * docs/devel: Remove nested-papr.txt ---------------------------------------------------------------- Jacob Abrams (1): hw/char/stm32l4x5_usart.c: Enable USART ACK bit response Marcin Juszkiewicz (4): tests: use default cpu for aarch64/sbsa-ref tests: add FreeBSD tests for aarch64/sbsa-ref tests: expand timeout information for aarch64/sbsa-ref tests: drop OpenBSD tests for aarch64/sbsa-ref Peter Maydell (4): kvm: Make 'mmap_size' be 'int' in kvm_init_vcpu(), do_kvm_destroy_vcpu() kvm: Remove unreachable code in kvm_dirty_ring_reaper_thread() target/arm: Correct ID_AA64ISAR1_EL1 value for neoverse-v1 docs/devel: Remove nested-papr.txt Richard Henderson (29): target/arm: Replace tcg_gen_dupi_vec with constants in gengvec.c target/arm: Replace tcg_gen_dupi_vec with constants in translate-sve.c target/arm: Use cmpsel in gen_ushl_vec target/arm: Use cmpsel in gen_sshl_vec target/arm: Use tcg_gen_extract2_i64 for EXT target/arm: Convert EXT to decodetree target/arm: Convert TBL, TBX to decodetree target/arm: Convert UZP, TRN, ZIP to decodetree target/arm: Simplify do_reduction_op target/arm: Convert ADDV, *ADDLV, *MAXV, *MINV to decodetree target/arm: Convert FMAXNMV, FMINNMV, FMAXV, FMINV to decodetree target/arm: Convert FMOVI (scalar, immediate) to decodetree target/arm: Convert MOVI, FMOV, ORR, BIC (vector immediate) to decodetree target/arm: Introduce gen_gvec_sshr, gen_gvec_ushr target/arm: Fix whitespace near gen_srshr64_i64 target/arm: Convert handle_vec_simd_shri to decodetree target/arm: Convert handle_vec_simd_shli to decodetree target/arm: Use {, s}extract in handle_vec_simd_wshli target/arm: Convert SSHLL, USHLL to decodetree target/arm: Push tcg_rnd into handle_shri_with_rndacc target/arm: Split out subroutines of handle_shri_with_rndacc target/arm: Convert SHRN, RSHRN to decodetree target/arm: Convert handle_scalar_simd_shri to decodetree target/arm: Convert handle_scalar_simd_shli to decodetree target/arm: Convert VQSHL, VQSHLU to gvec target/arm: Widen NeonGenNarrowEnvFn return to 64 bits target/arm: Convert SQSHL, UQSHL, SQSHLU (immediate) to decodetree target/arm: Convert vector [US]QSHRN, [US]QRSHRN, SQSHRUN to decodetree target/arm: Convert scalar [US]QSHRN, [US]QRSHRN, SQSHRUN to decodetree docs/devel/nested-papr.txt | 119 -- target/arm/helper.h | 34 +- target/arm/tcg/translate.h | 14 +- target/arm/tcg/a64.decode | 257 ++++ target/arm/tcg/neon-dp.decode | 6 +- accel/kvm/kvm-all.c | 10 +- hw/char/stm32l4x5_usart.c | 16 + target/arm/tcg/cpu64.c | 2 +- target/arm/tcg/gengvec.c | 121 +- target/arm/tcg/neon_helper.c | 76 +- target/arm/tcg/translate-a64.c | 2081 +++++++++++++----------------- target/arm/tcg/translate-neon.c | 179 +-- target/arm/tcg/translate-sve.c | 128 +- tests/qtest/stm32l4x5_usart-test.c | 36 +- tests/functional/test_aarch64_sbsaref.py | 58 +- 15 files changed, 1479 insertions(+), 1658 deletions(-) delete mode 100644 docs/devel/nested-papr.txt
From: Richard Henderson <richard.henderson@linaro.org> Instead of copying a constant into a temporary with dupi, use a vector constant directly. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20240912024114.1097832-2-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/gengvec.c | 43 ++++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/target/arm/tcg/gengvec.c b/target/arm/tcg/gengvec.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/gengvec.c +++ b/target/arm/tcg/gengvec.c @@ -XXX,XX +XXX,XX @@ void gen_srshr32_i32(TCGv_i32 d, TCGv_i32 a, int32_t sh) static void gen_srshr_vec(unsigned vece, TCGv_vec d, TCGv_vec a, int64_t sh) { TCGv_vec t = tcg_temp_new_vec_matching(d); - TCGv_vec ones = tcg_temp_new_vec_matching(d); + TCGv_vec ones = tcg_constant_vec_matching(d, vece, 1); tcg_gen_shri_vec(vece, t, a, sh - 1); - tcg_gen_dupi_vec(vece, ones, 1); tcg_gen_and_vec(vece, t, t, ones); tcg_gen_sari_vec(vece, d, a, sh); tcg_gen_add_vec(vece, d, d, t); @@ -XXX,XX +XXX,XX @@ void gen_urshr64_i64(TCGv_i64 d, TCGv_i64 a, int64_t sh) static void gen_urshr_vec(unsigned vece, TCGv_vec d, TCGv_vec a, int64_t shift) { TCGv_vec t = tcg_temp_new_vec_matching(d); - TCGv_vec ones = tcg_temp_new_vec_matching(d); + TCGv_vec ones = tcg_constant_vec_matching(d, vece, 1); tcg_gen_shri_vec(vece, t, a, shift - 1); - tcg_gen_dupi_vec(vece, ones, 1); tcg_gen_and_vec(vece, t, t, ones); tcg_gen_shri_vec(vece, d, a, shift); tcg_gen_add_vec(vece, d, d, t); @@ -XXX,XX +XXX,XX @@ static void gen_shr64_ins_i64(TCGv_i64 d, TCGv_i64 a, int64_t shift) static void gen_shr_ins_vec(unsigned vece, TCGv_vec d, TCGv_vec a, int64_t sh) { TCGv_vec t = tcg_temp_new_vec_matching(d); - TCGv_vec m = tcg_temp_new_vec_matching(d); + int64_t mi = MAKE_64BIT_MASK((8 << vece) - sh, sh); + TCGv_vec m = tcg_constant_vec_matching(d, vece, mi); - tcg_gen_dupi_vec(vece, m, MAKE_64BIT_MASK((8 << vece) - sh, sh)); tcg_gen_shri_vec(vece, t, a, sh); tcg_gen_and_vec(vece, d, d, m); tcg_gen_or_vec(vece, d, d, t); @@ -XXX,XX +XXX,XX @@ static void gen_shl64_ins_i64(TCGv_i64 d, TCGv_i64 a, int64_t shift) static void gen_shl_ins_vec(unsigned vece, TCGv_vec d, TCGv_vec a, int64_t sh) { TCGv_vec t = tcg_temp_new_vec_matching(d); - TCGv_vec m = tcg_temp_new_vec_matching(d); + TCGv_vec m = tcg_constant_vec_matching(d, vece, MAKE_64BIT_MASK(0, sh)); tcg_gen_shli_vec(vece, t, a, sh); - tcg_gen_dupi_vec(vece, m, MAKE_64BIT_MASK(0, sh)); tcg_gen_and_vec(vece, d, d, m); tcg_gen_or_vec(vece, d, d, t); } @@ -XXX,XX +XXX,XX @@ static void gen_ushl_vec(unsigned vece, TCGv_vec dst, TCGv_vec rval = tcg_temp_new_vec_matching(dst); TCGv_vec lsh = tcg_temp_new_vec_matching(dst); TCGv_vec rsh = tcg_temp_new_vec_matching(dst); - TCGv_vec msk, max; + TCGv_vec max; tcg_gen_neg_vec(vece, rsh, shift); if (vece == MO_8) { tcg_gen_mov_vec(lsh, shift); } else { - msk = tcg_temp_new_vec_matching(dst); - tcg_gen_dupi_vec(vece, msk, 0xff); + TCGv_vec msk = tcg_constant_vec_matching(dst, vece, 0xff); tcg_gen_and_vec(vece, lsh, shift, msk); tcg_gen_and_vec(vece, rsh, rsh, msk); } @@ -XXX,XX +XXX,XX @@ static void gen_ushl_vec(unsigned vece, TCGv_vec dst, tcg_gen_shlv_vec(vece, lval, src, lsh); tcg_gen_shrv_vec(vece, rval, src, rsh); - max = tcg_temp_new_vec_matching(dst); - tcg_gen_dupi_vec(vece, max, 8 << vece); - /* * The choice of LT (signed) and GEU (unsigned) are biased toward * the instructions of the x86_64 host. For MO_8, the whole byte @@ -XXX,XX +XXX,XX @@ static void gen_ushl_vec(unsigned vece, TCGv_vec dst, * have already masked to a byte and so a signed compare works. * Other tcg hosts have a full set of comparisons and do not care. */ + max = tcg_constant_vec_matching(dst, vece, 8 << vece); if (vece == MO_8) { tcg_gen_cmp_vec(TCG_COND_GEU, vece, lsh, lsh, max); tcg_gen_cmp_vec(TCG_COND_GEU, vece, rsh, rsh, max); @@ -XXX,XX +XXX,XX @@ static void gen_sshl_vec(unsigned vece, TCGv_vec dst, TCGv_vec lsh = tcg_temp_new_vec_matching(dst); TCGv_vec rsh = tcg_temp_new_vec_matching(dst); TCGv_vec tmp = tcg_temp_new_vec_matching(dst); + TCGv_vec max, zero; /* * Rely on the TCG guarantee that out of range shifts produce @@ -XXX,XX +XXX,XX @@ static void gen_sshl_vec(unsigned vece, TCGv_vec dst, if (vece == MO_8) { tcg_gen_mov_vec(lsh, shift); } else { - tcg_gen_dupi_vec(vece, tmp, 0xff); - tcg_gen_and_vec(vece, lsh, shift, tmp); - tcg_gen_and_vec(vece, rsh, rsh, tmp); + TCGv_vec msk = tcg_constant_vec_matching(dst, vece, 0xff); + tcg_gen_and_vec(vece, lsh, shift, msk); + tcg_gen_and_vec(vece, rsh, rsh, msk); } /* Bound rsh so out of bound right shift gets -1. */ - tcg_gen_dupi_vec(vece, tmp, (8 << vece) - 1); - tcg_gen_umin_vec(vece, rsh, rsh, tmp); - tcg_gen_cmp_vec(TCG_COND_GT, vece, tmp, lsh, tmp); + max = tcg_constant_vec_matching(dst, vece, (8 << vece) - 1); + tcg_gen_umin_vec(vece, rsh, rsh, max); + tcg_gen_cmp_vec(TCG_COND_GT, vece, tmp, lsh, max); tcg_gen_shlv_vec(vece, lval, src, lsh); tcg_gen_sarv_vec(vece, rval, src, rsh); @@ -XXX,XX +XXX,XX @@ static void gen_sshl_vec(unsigned vece, TCGv_vec dst, tcg_gen_andc_vec(vece, lval, lval, tmp); /* Select between left and right shift. */ + zero = tcg_constant_vec_matching(dst, vece, 0); if (vece == MO_8) { - tcg_gen_dupi_vec(vece, tmp, 0); - tcg_gen_cmpsel_vec(TCG_COND_LT, vece, dst, lsh, tmp, rval, lval); + tcg_gen_cmpsel_vec(TCG_COND_LT, vece, dst, lsh, zero, rval, lval); } else { - tcg_gen_dupi_vec(vece, tmp, 0x80); - tcg_gen_cmpsel_vec(TCG_COND_LT, vece, dst, lsh, tmp, lval, rval); + TCGv_vec sgn = tcg_constant_vec_matching(dst, vece, 0x80); + tcg_gen_cmpsel_vec(TCG_COND_LT, vece, dst, lsh, sgn, lval, rval); } } -- 2.34.1
From: Richard Henderson <richard.henderson@linaro.org> Instead of copying a constant into a temporary with dupi, use a vector constant directly. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20240912024114.1097832-3-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/translate-sve.c | 128 +++++++++++++-------------------- 1 file changed, 49 insertions(+), 79 deletions(-) diff --git a/target/arm/tcg/translate-sve.c b/target/arm/tcg/translate-sve.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-sve.c +++ b/target/arm/tcg/translate-sve.c @@ -XXX,XX +XXX,XX @@ static void gen_sshll_vec(unsigned vece, TCGv_vec d, TCGv_vec n, int64_t imm) if (top) { if (shl == halfbits) { - TCGv_vec t = tcg_temp_new_vec_matching(d); - tcg_gen_dupi_vec(vece, t, MAKE_64BIT_MASK(halfbits, halfbits)); - tcg_gen_and_vec(vece, d, n, t); + tcg_gen_and_vec(vece, d, n, + tcg_constant_vec_matching(d, vece, + MAKE_64BIT_MASK(halfbits, halfbits))); } else { tcg_gen_sari_vec(vece, d, n, halfbits); tcg_gen_shli_vec(vece, d, d, shl); @@ -XXX,XX +XXX,XX @@ static void gen_ushll_vec(unsigned vece, TCGv_vec d, TCGv_vec n, int64_t imm) if (top) { if (shl == halfbits) { - TCGv_vec t = tcg_temp_new_vec_matching(d); - tcg_gen_dupi_vec(vece, t, MAKE_64BIT_MASK(halfbits, halfbits)); - tcg_gen_and_vec(vece, d, n, t); + tcg_gen_and_vec(vece, d, n, + tcg_constant_vec_matching(d, vece, + MAKE_64BIT_MASK(halfbits, halfbits))); } else { tcg_gen_shri_vec(vece, d, n, halfbits); tcg_gen_shli_vec(vece, d, d, shl); } } else { if (shl == 0) { - TCGv_vec t = tcg_temp_new_vec_matching(d); - tcg_gen_dupi_vec(vece, t, MAKE_64BIT_MASK(0, halfbits)); - tcg_gen_and_vec(vece, d, n, t); + tcg_gen_and_vec(vece, d, n, + tcg_constant_vec_matching(d, vece, + MAKE_64BIT_MASK(0, halfbits))); } else { tcg_gen_shli_vec(vece, d, n, halfbits); tcg_gen_shri_vec(vece, d, d, halfbits - shl); @@ -XXX,XX +XXX,XX @@ static const TCGOpcode sqxtn_list[] = { static void gen_sqxtnb_vec(unsigned vece, TCGv_vec d, TCGv_vec n) { - TCGv_vec t = tcg_temp_new_vec_matching(d); int halfbits = 4 << vece; int64_t mask = (1ull << halfbits) - 1; int64_t min = -1ull << (halfbits - 1); int64_t max = -min - 1; - tcg_gen_dupi_vec(vece, t, min); - tcg_gen_smax_vec(vece, d, n, t); - tcg_gen_dupi_vec(vece, t, max); - tcg_gen_smin_vec(vece, d, d, t); - tcg_gen_dupi_vec(vece, t, mask); - tcg_gen_and_vec(vece, d, d, t); + tcg_gen_smax_vec(vece, d, n, tcg_constant_vec_matching(d, vece, min)); + tcg_gen_smin_vec(vece, d, d, tcg_constant_vec_matching(d, vece, max)); + tcg_gen_and_vec(vece, d, d, tcg_constant_vec_matching(d, vece, mask)); } static const GVecGen2 sqxtnb_ops[3] = { @@ -XXX,XX +XXX,XX @@ TRANS_FEAT(SQXTNB, aa64_sve2, do_narrow_extract, a, sqxtnb_ops) static void gen_sqxtnt_vec(unsigned vece, TCGv_vec d, TCGv_vec n) { - TCGv_vec t = tcg_temp_new_vec_matching(d); int halfbits = 4 << vece; int64_t mask = (1ull << halfbits) - 1; int64_t min = -1ull << (halfbits - 1); int64_t max = -min - 1; - tcg_gen_dupi_vec(vece, t, min); - tcg_gen_smax_vec(vece, n, n, t); - tcg_gen_dupi_vec(vece, t, max); - tcg_gen_smin_vec(vece, n, n, t); + tcg_gen_smax_vec(vece, n, n, tcg_constant_vec_matching(d, vece, min)); + tcg_gen_smin_vec(vece, n, n, tcg_constant_vec_matching(d, vece, max)); tcg_gen_shli_vec(vece, n, n, halfbits); - tcg_gen_dupi_vec(vece, t, mask); - tcg_gen_bitsel_vec(vece, d, t, d, n); + tcg_gen_bitsel_vec(vece, d, tcg_constant_vec_matching(d, vece, mask), d, n); } static const GVecGen2 sqxtnt_ops[3] = { @@ -XXX,XX +XXX,XX @@ static const TCGOpcode uqxtn_list[] = { static void gen_uqxtnb_vec(unsigned vece, TCGv_vec d, TCGv_vec n) { - TCGv_vec t = tcg_temp_new_vec_matching(d); int halfbits = 4 << vece; int64_t max = (1ull << halfbits) - 1; - tcg_gen_dupi_vec(vece, t, max); - tcg_gen_umin_vec(vece, d, n, t); + tcg_gen_umin_vec(vece, d, n, tcg_constant_vec_matching(d, vece, max)); } static const GVecGen2 uqxtnb_ops[3] = { @@ -XXX,XX +XXX,XX @@ TRANS_FEAT(UQXTNB, aa64_sve2, do_narrow_extract, a, uqxtnb_ops) static void gen_uqxtnt_vec(unsigned vece, TCGv_vec d, TCGv_vec n) { - TCGv_vec t = tcg_temp_new_vec_matching(d); int halfbits = 4 << vece; int64_t max = (1ull << halfbits) - 1; + TCGv_vec maxv = tcg_constant_vec_matching(d, vece, max); - tcg_gen_dupi_vec(vece, t, max); - tcg_gen_umin_vec(vece, n, n, t); + tcg_gen_umin_vec(vece, n, n, maxv); tcg_gen_shli_vec(vece, n, n, halfbits); - tcg_gen_bitsel_vec(vece, d, t, d, n); + tcg_gen_bitsel_vec(vece, d, maxv, d, n); } static const GVecGen2 uqxtnt_ops[3] = { @@ -XXX,XX +XXX,XX @@ static const TCGOpcode sqxtun_list[] = { static void gen_sqxtunb_vec(unsigned vece, TCGv_vec d, TCGv_vec n) { - TCGv_vec t = tcg_temp_new_vec_matching(d); int halfbits = 4 << vece; int64_t max = (1ull << halfbits) - 1; - tcg_gen_dupi_vec(vece, t, 0); - tcg_gen_smax_vec(vece, d, n, t); - tcg_gen_dupi_vec(vece, t, max); - tcg_gen_umin_vec(vece, d, d, t); + tcg_gen_smax_vec(vece, d, n, tcg_constant_vec_matching(d, vece, 0)); + tcg_gen_umin_vec(vece, d, d, tcg_constant_vec_matching(d, vece, max)); } static const GVecGen2 sqxtunb_ops[3] = { @@ -XXX,XX +XXX,XX @@ TRANS_FEAT(SQXTUNB, aa64_sve2, do_narrow_extract, a, sqxtunb_ops) static void gen_sqxtunt_vec(unsigned vece, TCGv_vec d, TCGv_vec n) { - TCGv_vec t = tcg_temp_new_vec_matching(d); int halfbits = 4 << vece; int64_t max = (1ull << halfbits) - 1; + TCGv_vec maxv = tcg_constant_vec_matching(d, vece, max); - tcg_gen_dupi_vec(vece, t, 0); - tcg_gen_smax_vec(vece, n, n, t); - tcg_gen_dupi_vec(vece, t, max); - tcg_gen_umin_vec(vece, n, n, t); + tcg_gen_smax_vec(vece, n, n, tcg_constant_vec_matching(d, vece, 0)); + tcg_gen_umin_vec(vece, n, n, maxv); tcg_gen_shli_vec(vece, n, n, halfbits); - tcg_gen_bitsel_vec(vece, d, t, d, n); + tcg_gen_bitsel_vec(vece, d, maxv, d, n); } static const GVecGen2 sqxtunt_ops[3] = { @@ -XXX,XX +XXX,XX @@ static void gen_shrnb64_i64(TCGv_i64 d, TCGv_i64 n, int64_t shr) static void gen_shrnb_vec(unsigned vece, TCGv_vec d, TCGv_vec n, int64_t shr) { - TCGv_vec t = tcg_temp_new_vec_matching(d); int halfbits = 4 << vece; uint64_t mask = MAKE_64BIT_MASK(0, halfbits); tcg_gen_shri_vec(vece, n, n, shr); - tcg_gen_dupi_vec(vece, t, mask); - tcg_gen_and_vec(vece, d, n, t); + tcg_gen_and_vec(vece, d, n, tcg_constant_vec_matching(d, vece, mask)); } static const TCGOpcode shrnb_vec_list[] = { INDEX_op_shri_vec, 0 }; @@ -XXX,XX +XXX,XX @@ static void gen_shrnt64_i64(TCGv_i64 d, TCGv_i64 n, int64_t shr) static void gen_shrnt_vec(unsigned vece, TCGv_vec d, TCGv_vec n, int64_t shr) { - TCGv_vec t = tcg_temp_new_vec_matching(d); int halfbits = 4 << vece; uint64_t mask = MAKE_64BIT_MASK(0, halfbits); tcg_gen_shli_vec(vece, n, n, halfbits - shr); - tcg_gen_dupi_vec(vece, t, mask); - tcg_gen_bitsel_vec(vece, d, t, d, n); + tcg_gen_bitsel_vec(vece, d, tcg_constant_vec_matching(d, vece, mask), d, n); } static const TCGOpcode shrnt_vec_list[] = { INDEX_op_shli_vec, 0 }; @@ -XXX,XX +XXX,XX @@ TRANS_FEAT(RSHRNT, aa64_sve2, do_shr_narrow, a, rshrnt_ops) static void gen_sqshrunb_vec(unsigned vece, TCGv_vec d, TCGv_vec n, int64_t shr) { - TCGv_vec t = tcg_temp_new_vec_matching(d); int halfbits = 4 << vece; + uint64_t max = MAKE_64BIT_MASK(0, halfbits); tcg_gen_sari_vec(vece, n, n, shr); - tcg_gen_dupi_vec(vece, t, 0); - tcg_gen_smax_vec(vece, n, n, t); - tcg_gen_dupi_vec(vece, t, MAKE_64BIT_MASK(0, halfbits)); - tcg_gen_umin_vec(vece, d, n, t); + tcg_gen_smax_vec(vece, n, n, tcg_constant_vec_matching(d, vece, 0)); + tcg_gen_umin_vec(vece, d, n, tcg_constant_vec_matching(d, vece, max)); } static const TCGOpcode sqshrunb_vec_list[] = { @@ -XXX,XX +XXX,XX @@ TRANS_FEAT(SQSHRUNB, aa64_sve2, do_shr_narrow, a, sqshrunb_ops) static void gen_sqshrunt_vec(unsigned vece, TCGv_vec d, TCGv_vec n, int64_t shr) { - TCGv_vec t = tcg_temp_new_vec_matching(d); int halfbits = 4 << vece; + uint64_t max = MAKE_64BIT_MASK(0, halfbits); + TCGv_vec maxv = tcg_constant_vec_matching(d, vece, max); tcg_gen_sari_vec(vece, n, n, shr); - tcg_gen_dupi_vec(vece, t, 0); - tcg_gen_smax_vec(vece, n, n, t); - tcg_gen_dupi_vec(vece, t, MAKE_64BIT_MASK(0, halfbits)); - tcg_gen_umin_vec(vece, n, n, t); + tcg_gen_smax_vec(vece, n, n, tcg_constant_vec_matching(d, vece, 0)); + tcg_gen_umin_vec(vece, n, n, maxv); tcg_gen_shli_vec(vece, n, n, halfbits); - tcg_gen_bitsel_vec(vece, d, t, d, n); + tcg_gen_bitsel_vec(vece, d, maxv, d, n); } static const TCGOpcode sqshrunt_vec_list[] = { @@ -XXX,XX +XXX,XX @@ TRANS_FEAT(SQRSHRUNT, aa64_sve2, do_shr_narrow, a, sqrshrunt_ops) static void gen_sqshrnb_vec(unsigned vece, TCGv_vec d, TCGv_vec n, int64_t shr) { - TCGv_vec t = tcg_temp_new_vec_matching(d); int halfbits = 4 << vece; int64_t max = MAKE_64BIT_MASK(0, halfbits - 1); int64_t min = -max - 1; + int64_t mask = MAKE_64BIT_MASK(0, halfbits); tcg_gen_sari_vec(vece, n, n, shr); - tcg_gen_dupi_vec(vece, t, min); - tcg_gen_smax_vec(vece, n, n, t); - tcg_gen_dupi_vec(vece, t, max); - tcg_gen_smin_vec(vece, n, n, t); - tcg_gen_dupi_vec(vece, t, MAKE_64BIT_MASK(0, halfbits)); - tcg_gen_and_vec(vece, d, n, t); + tcg_gen_smax_vec(vece, n, n, tcg_constant_vec_matching(d, vece, min)); + tcg_gen_smin_vec(vece, n, n, tcg_constant_vec_matching(d, vece, max)); + tcg_gen_and_vec(vece, d, n, tcg_constant_vec_matching(d, vece, mask)); } static const TCGOpcode sqshrnb_vec_list[] = { @@ -XXX,XX +XXX,XX @@ TRANS_FEAT(SQSHRNB, aa64_sve2, do_shr_narrow, a, sqshrnb_ops) static void gen_sqshrnt_vec(unsigned vece, TCGv_vec d, TCGv_vec n, int64_t shr) { - TCGv_vec t = tcg_temp_new_vec_matching(d); int halfbits = 4 << vece; int64_t max = MAKE_64BIT_MASK(0, halfbits - 1); int64_t min = -max - 1; + int64_t mask = MAKE_64BIT_MASK(0, halfbits); tcg_gen_sari_vec(vece, n, n, shr); - tcg_gen_dupi_vec(vece, t, min); - tcg_gen_smax_vec(vece, n, n, t); - tcg_gen_dupi_vec(vece, t, max); - tcg_gen_smin_vec(vece, n, n, t); + tcg_gen_smax_vec(vece, n, n, tcg_constant_vec_matching(d, vece, min)); + tcg_gen_smin_vec(vece, n, n, tcg_constant_vec_matching(d, vece, max)); tcg_gen_shli_vec(vece, n, n, halfbits); - tcg_gen_dupi_vec(vece, t, MAKE_64BIT_MASK(0, halfbits)); - tcg_gen_bitsel_vec(vece, d, t, d, n); + tcg_gen_bitsel_vec(vece, d, tcg_constant_vec_matching(d, vece, mask), d, n); } static const TCGOpcode sqshrnt_vec_list[] = { @@ -XXX,XX +XXX,XX @@ TRANS_FEAT(SQRSHRNT, aa64_sve2, do_shr_narrow, a, sqrshrnt_ops) static void gen_uqshrnb_vec(unsigned vece, TCGv_vec d, TCGv_vec n, int64_t shr) { - TCGv_vec t = tcg_temp_new_vec_matching(d); int halfbits = 4 << vece; + int64_t max = MAKE_64BIT_MASK(0, halfbits); tcg_gen_shri_vec(vece, n, n, shr); - tcg_gen_dupi_vec(vece, t, MAKE_64BIT_MASK(0, halfbits)); - tcg_gen_umin_vec(vece, d, n, t); + tcg_gen_umin_vec(vece, d, n, tcg_constant_vec_matching(d, vece, max)); } static const TCGOpcode uqshrnb_vec_list[] = { @@ -XXX,XX +XXX,XX @@ TRANS_FEAT(UQSHRNB, aa64_sve2, do_shr_narrow, a, uqshrnb_ops) static void gen_uqshrnt_vec(unsigned vece, TCGv_vec d, TCGv_vec n, int64_t shr) { - TCGv_vec t = tcg_temp_new_vec_matching(d); int halfbits = 4 << vece; + int64_t max = MAKE_64BIT_MASK(0, halfbits); + TCGv_vec maxv = tcg_constant_vec_matching(d, vece, max); tcg_gen_shri_vec(vece, n, n, shr); - tcg_gen_dupi_vec(vece, t, MAKE_64BIT_MASK(0, halfbits)); - tcg_gen_umin_vec(vece, n, n, t); + tcg_gen_umin_vec(vece, n, n, maxv); tcg_gen_shli_vec(vece, n, n, halfbits); - tcg_gen_bitsel_vec(vece, d, t, d, n); + tcg_gen_bitsel_vec(vece, d, maxv, d, n); } static const TCGOpcode uqshrnt_vec_list[] = { -- 2.34.1
From: Richard Henderson <richard.henderson@linaro.org> Instead of cmp+and or cmp+andc, use cmpsel. This will be better for hosts that use predicate registers for cmp. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20240912024114.1097832-4-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/gengvec.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/target/arm/tcg/gengvec.c b/target/arm/tcg/gengvec.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/gengvec.c +++ b/target/arm/tcg/gengvec.c @@ -XXX,XX +XXX,XX @@ static void gen_ushl_vec(unsigned vece, TCGv_vec dst, TCGv_vec rval = tcg_temp_new_vec_matching(dst); TCGv_vec lsh = tcg_temp_new_vec_matching(dst); TCGv_vec rsh = tcg_temp_new_vec_matching(dst); - TCGv_vec max; + TCGv_vec max, zero; tcg_gen_neg_vec(vece, rsh, shift); if (vece == MO_8) { @@ -XXX,XX +XXX,XX @@ static void gen_ushl_vec(unsigned vece, TCGv_vec dst, tcg_gen_shrv_vec(vece, rval, src, rsh); /* - * The choice of LT (signed) and GEU (unsigned) are biased toward + * The choice of GE (signed) and GEU (unsigned) are biased toward * the instructions of the x86_64 host. For MO_8, the whole byte * is significant so we must use an unsigned compare; otherwise we * have already masked to a byte and so a signed compare works. * Other tcg hosts have a full set of comparisons and do not care. */ + zero = tcg_constant_vec_matching(dst, vece, 0); max = tcg_constant_vec_matching(dst, vece, 8 << vece); if (vece == MO_8) { - tcg_gen_cmp_vec(TCG_COND_GEU, vece, lsh, lsh, max); - tcg_gen_cmp_vec(TCG_COND_GEU, vece, rsh, rsh, max); - tcg_gen_andc_vec(vece, lval, lval, lsh); - tcg_gen_andc_vec(vece, rval, rval, rsh); + tcg_gen_cmpsel_vec(TCG_COND_GEU, vece, lval, lsh, max, zero, lval); + tcg_gen_cmpsel_vec(TCG_COND_GEU, vece, rval, rsh, max, zero, rval); } else { - tcg_gen_cmp_vec(TCG_COND_LT, vece, lsh, lsh, max); - tcg_gen_cmp_vec(TCG_COND_LT, vece, rsh, rsh, max); - tcg_gen_and_vec(vece, lval, lval, lsh); - tcg_gen_and_vec(vece, rval, rval, rsh); + tcg_gen_cmpsel_vec(TCG_COND_GE, vece, lval, lsh, max, zero, lval); + tcg_gen_cmpsel_vec(TCG_COND_GE, vece, rval, rsh, max, zero, rval); } tcg_gen_or_vec(vece, dst, lval, rval); } @@ -XXX,XX +XXX,XX @@ void gen_gvec_ushl(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, { static const TCGOpcode vecop_list[] = { INDEX_op_neg_vec, INDEX_op_shlv_vec, - INDEX_op_shrv_vec, INDEX_op_cmp_vec, 0 + INDEX_op_shrv_vec, INDEX_op_cmpsel_vec, 0 }; static const GVecGen3 ops[4] = { { .fniv = gen_ushl_vec, -- 2.34.1
From: Richard Henderson <richard.henderson@linaro.org> Instead of cmp+and or cmp+andc, use cmpsel. This will be better for hosts that use predicate registers for cmp. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20240912024114.1097832-5-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/gengvec.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/target/arm/tcg/gengvec.c b/target/arm/tcg/gengvec.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/gengvec.c +++ b/target/arm/tcg/gengvec.c @@ -XXX,XX +XXX,XX @@ static void gen_sshl_vec(unsigned vece, TCGv_vec dst, TCGv_vec rval = tcg_temp_new_vec_matching(dst); TCGv_vec lsh = tcg_temp_new_vec_matching(dst); TCGv_vec rsh = tcg_temp_new_vec_matching(dst); - TCGv_vec tmp = tcg_temp_new_vec_matching(dst); TCGv_vec max, zero; /* @@ -XXX,XX +XXX,XX @@ static void gen_sshl_vec(unsigned vece, TCGv_vec dst, /* Bound rsh so out of bound right shift gets -1. */ max = tcg_constant_vec_matching(dst, vece, (8 << vece) - 1); tcg_gen_umin_vec(vece, rsh, rsh, max); - tcg_gen_cmp_vec(TCG_COND_GT, vece, tmp, lsh, max); tcg_gen_shlv_vec(vece, lval, src, lsh); tcg_gen_sarv_vec(vece, rval, src, rsh); /* Select in-bound left shift. */ - tcg_gen_andc_vec(vece, lval, lval, tmp); + zero = tcg_constant_vec_matching(dst, vece, 0); + tcg_gen_cmpsel_vec(TCG_COND_GT, vece, lval, lsh, max, zero, lval); /* Select between left and right shift. */ - zero = tcg_constant_vec_matching(dst, vece, 0); if (vece == MO_8) { tcg_gen_cmpsel_vec(TCG_COND_LT, vece, dst, lsh, zero, rval, lval); } else { @@ -XXX,XX +XXX,XX @@ void gen_gvec_sshl(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, { static const TCGOpcode vecop_list[] = { INDEX_op_neg_vec, INDEX_op_umin_vec, INDEX_op_shlv_vec, - INDEX_op_sarv_vec, INDEX_op_cmp_vec, INDEX_op_cmpsel_vec, 0 + INDEX_op_sarv_vec, INDEX_op_cmpsel_vec, 0 }; static const GVecGen3 ops[4] = { { .fniv = gen_sshl_vec, -- 2.34.1
From: Richard Henderson <richard.henderson@linaro.org> The extract2 tcg op performs the same operation as the do_ext64 function. Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20240912024114.1097832-6-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/translate-a64.c | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ static void disas_data_proc_fp(DisasContext *s, uint32_t insn) } } -static void do_ext64(DisasContext *s, TCGv_i64 tcg_left, TCGv_i64 tcg_right, - int pos) -{ - /* Extract 64 bits from the middle of two concatenated 64 bit - * vector register slices left:right. The extracted bits start - * at 'pos' bits into the right (least significant) side. - * We return the result in tcg_right, and guarantee not to - * trash tcg_left. - */ - TCGv_i64 tcg_tmp = tcg_temp_new_i64(); - assert(pos > 0 && pos < 64); - - tcg_gen_shri_i64(tcg_right, tcg_right, pos); - tcg_gen_shli_i64(tcg_tmp, tcg_left, 64 - pos); - tcg_gen_or_i64(tcg_right, tcg_right, tcg_tmp); -} - /* EXT * 31 30 29 24 23 22 21 20 16 15 14 11 10 9 5 4 0 * +---+---+-------------+-----+---+------+---+------+---+------+------+ @@ -XXX,XX +XXX,XX @@ static void disas_simd_ext(DisasContext *s, uint32_t insn) read_vec_element(s, tcg_resl, rn, 0, MO_64); if (pos != 0) { read_vec_element(s, tcg_resh, rm, 0, MO_64); - do_ext64(s, tcg_resh, tcg_resl, pos); + tcg_gen_extract2_i64(tcg_resl, tcg_resl, tcg_resh, pos); } } else { TCGv_i64 tcg_hh; @@ -XXX,XX +XXX,XX @@ static void disas_simd_ext(DisasContext *s, uint32_t insn) read_vec_element(s, tcg_resh, elt->reg, elt->elt, MO_64); elt++; if (pos != 0) { - do_ext64(s, tcg_resh, tcg_resl, pos); + tcg_gen_extract2_i64(tcg_resl, tcg_resl, tcg_resh, pos); tcg_hh = tcg_temp_new_i64(); read_vec_element(s, tcg_hh, elt->reg, elt->elt, MO_64); - do_ext64(s, tcg_hh, tcg_resh, pos); + tcg_gen_extract2_i64(tcg_resh, tcg_resh, tcg_hh, pos); } } -- 2.34.1
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20240912024114.1097832-7-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/a64.decode | 5 ++ target/arm/tcg/translate-a64.c | 121 +++++++++++++-------------------- 2 files changed, 53 insertions(+), 73 deletions(-) diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -XXX,XX +XXX,XX @@ FMADD 0001 1111 .. 0 ..... 0 ..... ..... ..... @rrrr_hsd FMSUB 0001 1111 .. 0 ..... 1 ..... ..... ..... @rrrr_hsd FNMADD 0001 1111 .. 1 ..... 0 ..... ..... ..... @rrrr_hsd FNMSUB 0001 1111 .. 1 ..... 1 ..... ..... ..... @rrrr_hsd + +# Advanced SIMD Extract + +EXT_d 0010 1110 00 0 rm:5 00 imm:3 0 rn:5 rd:5 +EXT_q 0110 1110 00 0 rm:5 0 imm:4 0 rn:5 rd:5 diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ static bool trans_FCSEL(DisasContext *s, arg_FCSEL *a) return true; } +/* + * Advanced SIMD Extract + */ + +static bool trans_EXT_d(DisasContext *s, arg_EXT_d *a) +{ + if (fp_access_check(s)) { + TCGv_i64 lo = read_fp_dreg(s, a->rn); + if (a->imm != 0) { + TCGv_i64 hi = read_fp_dreg(s, a->rm); + tcg_gen_extract2_i64(lo, lo, hi, a->imm * 8); + } + write_fp_dreg(s, a->rd, lo); + } + return true; +} + +static bool trans_EXT_q(DisasContext *s, arg_EXT_q *a) +{ + TCGv_i64 lo, hi; + int pos = (a->imm & 7) * 8; + int elt = a->imm >> 3; + + if (!fp_access_check(s)) { + return true; + } + + lo = tcg_temp_new_i64(); + hi = tcg_temp_new_i64(); + + read_vec_element(s, lo, a->rn, elt, MO_64); + elt++; + read_vec_element(s, hi, elt & 2 ? a->rm : a->rn, elt & 1, MO_64); + elt++; + + if (pos != 0) { + TCGv_i64 hh = tcg_temp_new_i64(); + tcg_gen_extract2_i64(lo, lo, hi, pos); + read_vec_element(s, hh, a->rm, elt & 1, MO_64); + tcg_gen_extract2_i64(hi, hi, hh, pos); + } + + write_vec_element(s, lo, a->rd, 0, MO_64); + write_vec_element(s, hi, a->rd, 1, MO_64); + clear_vec_high(s, true, a->rd); + return true; +} + /* * Floating-point data-processing (3 source) */ @@ -XXX,XX +XXX,XX @@ static void disas_data_proc_fp(DisasContext *s, uint32_t insn) } } -/* EXT - * 31 30 29 24 23 22 21 20 16 15 14 11 10 9 5 4 0 - * +---+---+-------------+-----+---+------+---+------+---+------+------+ - * | 0 | Q | 1 0 1 1 1 0 | op2 | 0 | Rm | 0 | imm4 | 0 | Rn | Rd | - * +---+---+-------------+-----+---+------+---+------+---+------+------+ - */ -static void disas_simd_ext(DisasContext *s, uint32_t insn) -{ - int is_q = extract32(insn, 30, 1); - int op2 = extract32(insn, 22, 2); - int imm4 = extract32(insn, 11, 4); - int rm = extract32(insn, 16, 5); - int rn = extract32(insn, 5, 5); - int rd = extract32(insn, 0, 5); - int pos = imm4 << 3; - TCGv_i64 tcg_resl, tcg_resh; - - if (op2 != 0 || (!is_q && extract32(imm4, 3, 1))) { - unallocated_encoding(s); - return; - } - - if (!fp_access_check(s)) { - return; - } - - tcg_resh = tcg_temp_new_i64(); - tcg_resl = tcg_temp_new_i64(); - - /* Vd gets bits starting at pos bits into Vm:Vn. This is - * either extracting 128 bits from a 128:128 concatenation, or - * extracting 64 bits from a 64:64 concatenation. - */ - if (!is_q) { - read_vec_element(s, tcg_resl, rn, 0, MO_64); - if (pos != 0) { - read_vec_element(s, tcg_resh, rm, 0, MO_64); - tcg_gen_extract2_i64(tcg_resl, tcg_resl, tcg_resh, pos); - } - } else { - TCGv_i64 tcg_hh; - typedef struct { - int reg; - int elt; - } EltPosns; - EltPosns eltposns[] = { {rn, 0}, {rn, 1}, {rm, 0}, {rm, 1} }; - EltPosns *elt = eltposns; - - if (pos >= 64) { - elt++; - pos -= 64; - } - - read_vec_element(s, tcg_resl, elt->reg, elt->elt, MO_64); - elt++; - read_vec_element(s, tcg_resh, elt->reg, elt->elt, MO_64); - elt++; - if (pos != 0) { - tcg_gen_extract2_i64(tcg_resl, tcg_resl, tcg_resh, pos); - tcg_hh = tcg_temp_new_i64(); - read_vec_element(s, tcg_hh, elt->reg, elt->elt, MO_64); - tcg_gen_extract2_i64(tcg_resh, tcg_resh, tcg_hh, pos); - } - } - - write_vec_element(s, tcg_resl, rd, 0, MO_64); - if (is_q) { - write_vec_element(s, tcg_resh, rd, 1, MO_64); - } - clear_vec_high(s, is_q, rd); -} - /* TBL/TBX * 31 30 29 24 23 22 21 20 16 15 14 13 12 11 10 9 5 4 0 * +---+---+-------------+-----+---+------+---+-----+----+-----+------+------+ @@ -XXX,XX +XXX,XX @@ static const AArch64DecodeTable data_proc_simd[] = { { 0x0f000400, 0x9f800400, disas_simd_shift_imm }, { 0x0e000000, 0xbf208c00, disas_simd_tb }, { 0x0e000800, 0xbf208c00, disas_simd_zip_trn }, - { 0x2e000000, 0xbf208400, disas_simd_ext }, { 0x5e200800, 0xdf3e0c00, disas_simd_scalar_two_reg_misc }, { 0x5f000400, 0xdf800400, disas_simd_scalar_shift_imm }, { 0x0e780800, 0x8f7e0c00, disas_simd_two_reg_misc_fp16 }, -- 2.34.1
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20240912024114.1097832-8-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/a64.decode | 4 +++ target/arm/tcg/translate-a64.c | 47 ++++++++++------------------------ 2 files changed, 18 insertions(+), 33 deletions(-) diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -XXX,XX +XXX,XX @@ FNMSUB 0001 1111 .. 1 ..... 1 ..... ..... ..... @rrrr_hsd EXT_d 0010 1110 00 0 rm:5 00 imm:3 0 rn:5 rd:5 EXT_q 0110 1110 00 0 rm:5 0 imm:4 0 rn:5 rd:5 + +# Advanced SIMD Table Lookup + +TBL_TBX 0 q:1 00 1110 000 rm:5 0 len:2 tbx:1 00 rn:5 rd:5 diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ static bool trans_EXTR(DisasContext *s, arg_extract *a) return true; } +static bool trans_TBL_TBX(DisasContext *s, arg_TBL_TBX *a) +{ + if (fp_access_check(s)) { + int len = (a->len + 1) * 16; + + tcg_gen_gvec_2_ptr(vec_full_reg_offset(s, a->rd), + vec_full_reg_offset(s, a->rm), tcg_env, + a->q ? 16 : 8, vec_full_reg_size(s), + (len << 6) | (a->tbx << 5) | a->rn, + gen_helper_simd_tblx); + } + return true; +} + /* * Cryptographic AES, SHA, SHA512 */ @@ -XXX,XX +XXX,XX @@ static void disas_data_proc_fp(DisasContext *s, uint32_t insn) } } -/* TBL/TBX - * 31 30 29 24 23 22 21 20 16 15 14 13 12 11 10 9 5 4 0 - * +---+---+-------------+-----+---+------+---+-----+----+-----+------+------+ - * | 0 | Q | 0 0 1 1 1 0 | op2 | 0 | Rm | 0 | len | op | 0 0 | Rn | Rd | - * +---+---+-------------+-----+---+------+---+-----+----+-----+------+------+ - */ -static void disas_simd_tb(DisasContext *s, uint32_t insn) -{ - int op2 = extract32(insn, 22, 2); - int is_q = extract32(insn, 30, 1); - int rm = extract32(insn, 16, 5); - int rn = extract32(insn, 5, 5); - int rd = extract32(insn, 0, 5); - int is_tbx = extract32(insn, 12, 1); - int len = (extract32(insn, 13, 2) + 1) * 16; - - if (op2 != 0) { - unallocated_encoding(s); - return; - } - - if (!fp_access_check(s)) { - return; - } - - tcg_gen_gvec_2_ptr(vec_full_reg_offset(s, rd), - vec_full_reg_offset(s, rm), tcg_env, - is_q ? 16 : 8, vec_full_reg_size(s), - (len << 6) | (is_tbx << 5) | rn, - gen_helper_simd_tblx); -} - /* ZIP/UZP/TRN * 31 30 29 24 23 22 21 20 16 15 14 12 11 10 9 5 4 0 * +---+---+-------------+------+---+------+---+------------------+------+ @@ -XXX,XX +XXX,XX @@ static const AArch64DecodeTable data_proc_simd[] = { /* simd_mod_imm decode is a subset of simd_shift_imm, so must precede it */ { 0x0f000400, 0x9ff80400, disas_simd_mod_imm }, { 0x0f000400, 0x9f800400, disas_simd_shift_imm }, - { 0x0e000000, 0xbf208c00, disas_simd_tb }, { 0x0e000800, 0xbf208c00, disas_simd_zip_trn }, { 0x5e200800, 0xdf3e0c00, disas_simd_scalar_two_reg_misc }, { 0x5f000400, 0xdf800400, disas_simd_scalar_shift_imm }, -- 2.34.1
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20240912024114.1097832-9-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/a64.decode | 9 ++ target/arm/tcg/translate-a64.c | 158 ++++++++++++++------------------- 2 files changed, 77 insertions(+), 90 deletions(-) diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -XXX,XX +XXX,XX @@ EXT_q 0110 1110 00 0 rm:5 0 imm:4 0 rn:5 rd:5 # Advanced SIMD Table Lookup TBL_TBX 0 q:1 00 1110 000 rm:5 0 len:2 tbx:1 00 rn:5 rd:5 + +# Advanced SIMD Permute + +UZP1 0.00 1110 .. 0 ..... 0 001 10 ..... ..... @qrrr_e +UZP2 0.00 1110 .. 0 ..... 0 101 10 ..... ..... @qrrr_e +TRN1 0.00 1110 .. 0 ..... 0 010 10 ..... ..... @qrrr_e +TRN2 0.00 1110 .. 0 ..... 0 110 10 ..... ..... @qrrr_e +ZIP1 0.00 1110 .. 0 ..... 0 011 10 ..... ..... @qrrr_e +ZIP2 0.00 1110 .. 0 ..... 0 111 10 ..... ..... @qrrr_e diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ static bool trans_TBL_TBX(DisasContext *s, arg_TBL_TBX *a) return true; } +typedef int simd_permute_idx_fn(int i, int part, int elements); + +static bool do_simd_permute(DisasContext *s, arg_qrrr_e *a, + simd_permute_idx_fn *fn, int part) +{ + MemOp esz = a->esz; + int datasize = a->q ? 16 : 8; + int elements = datasize >> esz; + TCGv_i64 tcg_res[2], tcg_ele; + + if (esz == MO_64 && !a->q) { + return false; + } + if (!fp_access_check(s)) { + return true; + } + + tcg_res[0] = tcg_temp_new_i64(); + tcg_res[1] = a->q ? tcg_temp_new_i64() : NULL; + tcg_ele = tcg_temp_new_i64(); + + for (int i = 0; i < elements; i++) { + int o, w, idx; + + idx = fn(i, part, elements); + read_vec_element(s, tcg_ele, (idx & elements ? a->rm : a->rn), + idx & (elements - 1), esz); + + w = (i << (esz + 3)) / 64; + o = (i << (esz + 3)) % 64; + if (o == 0) { + tcg_gen_mov_i64(tcg_res[w], tcg_ele); + } else { + tcg_gen_deposit_i64(tcg_res[w], tcg_res[w], tcg_ele, o, 8 << esz); + } + } + + for (int i = a->q; i >= 0; --i) { + write_vec_element(s, tcg_res[i], a->rd, i, MO_64); + } + clear_vec_high(s, a->q, a->rd); + return true; +} + +static int permute_load_uzp(int i, int part, int elements) +{ + return 2 * i + part; +} + +TRANS(UZP1, do_simd_permute, a, permute_load_uzp, 0) +TRANS(UZP2, do_simd_permute, a, permute_load_uzp, 1) + +static int permute_load_trn(int i, int part, int elements) +{ + return (i & 1) * elements + (i & ~1) + part; +} + +TRANS(TRN1, do_simd_permute, a, permute_load_trn, 0) +TRANS(TRN2, do_simd_permute, a, permute_load_trn, 1) + +static int permute_load_zip(int i, int part, int elements) +{ + return (i & 1) * elements + ((part * elements + i) >> 1); +} + +TRANS(ZIP1, do_simd_permute, a, permute_load_zip, 0) +TRANS(ZIP2, do_simd_permute, a, permute_load_zip, 1) + /* * Cryptographic AES, SHA, SHA512 */ @@ -XXX,XX +XXX,XX @@ static void disas_data_proc_fp(DisasContext *s, uint32_t insn) } } -/* ZIP/UZP/TRN - * 31 30 29 24 23 22 21 20 16 15 14 12 11 10 9 5 4 0 - * +---+---+-------------+------+---+------+---+------------------+------+ - * | 0 | Q | 0 0 1 1 1 0 | size | 0 | Rm | 0 | opc | 1 0 | Rn | Rd | - * +---+---+-------------+------+---+------+---+------------------+------+ - */ -static void disas_simd_zip_trn(DisasContext *s, uint32_t insn) -{ - int rd = extract32(insn, 0, 5); - int rn = extract32(insn, 5, 5); - int rm = extract32(insn, 16, 5); - int size = extract32(insn, 22, 2); - /* opc field bits [1:0] indicate ZIP/UZP/TRN; - * bit 2 indicates 1 vs 2 variant of the insn. - */ - int opcode = extract32(insn, 12, 2); - bool part = extract32(insn, 14, 1); - bool is_q = extract32(insn, 30, 1); - int esize = 8 << size; - int i; - int datasize = is_q ? 128 : 64; - int elements = datasize / esize; - TCGv_i64 tcg_res[2], tcg_ele; - - if (opcode == 0 || (size == 3 && !is_q)) { - unallocated_encoding(s); - return; - } - - if (!fp_access_check(s)) { - return; - } - - tcg_res[0] = tcg_temp_new_i64(); - tcg_res[1] = is_q ? tcg_temp_new_i64() : NULL; - tcg_ele = tcg_temp_new_i64(); - - for (i = 0; i < elements; i++) { - int o, w; - - switch (opcode) { - case 1: /* UZP1/2 */ - { - int midpoint = elements / 2; - if (i < midpoint) { - read_vec_element(s, tcg_ele, rn, 2 * i + part, size); - } else { - read_vec_element(s, tcg_ele, rm, - 2 * (i - midpoint) + part, size); - } - break; - } - case 2: /* TRN1/2 */ - if (i & 1) { - read_vec_element(s, tcg_ele, rm, (i & ~1) + part, size); - } else { - read_vec_element(s, tcg_ele, rn, (i & ~1) + part, size); - } - break; - case 3: /* ZIP1/2 */ - { - int base = part * elements / 2; - if (i & 1) { - read_vec_element(s, tcg_ele, rm, base + (i >> 1), size); - } else { - read_vec_element(s, tcg_ele, rn, base + (i >> 1), size); - } - break; - } - default: - g_assert_not_reached(); - } - - w = (i * esize) / 64; - o = (i * esize) % 64; - if (o == 0) { - tcg_gen_mov_i64(tcg_res[w], tcg_ele); - } else { - tcg_gen_shli_i64(tcg_ele, tcg_ele, o); - tcg_gen_or_i64(tcg_res[w], tcg_res[w], tcg_ele); - } - } - - for (i = 0; i <= is_q; ++i) { - write_vec_element(s, tcg_res[i], rd, i, MO_64); - } - clear_vec_high(s, is_q, rd); -} - /* * do_reduction_op helper * @@ -XXX,XX +XXX,XX @@ static const AArch64DecodeTable data_proc_simd[] = { /* simd_mod_imm decode is a subset of simd_shift_imm, so must precede it */ { 0x0f000400, 0x9ff80400, disas_simd_mod_imm }, { 0x0f000400, 0x9f800400, disas_simd_shift_imm }, - { 0x0e000800, 0xbf208c00, disas_simd_zip_trn }, { 0x5e200800, 0xdf3e0c00, disas_simd_scalar_two_reg_misc }, { 0x5f000400, 0xdf800400, disas_simd_scalar_shift_imm }, { 0x0e780800, 0x8f7e0c00, disas_simd_two_reg_misc_fp16 }, -- 2.34.1
From: Richard Henderson <richard.henderson@linaro.org> Use simple shift and add instead of ctpop, ctz, shift and mask. Unlike SVE, there is no predicate to disable elements. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20240912024114.1097832-10-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/translate-a64.c | 40 +++++++++++----------------------- 1 file changed, 13 insertions(+), 27 deletions(-) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ static void disas_data_proc_fp(DisasContext *s, uint32_t insn) * important for correct NaN propagation that we do these * operations in exactly the order specified by the pseudocode. * - * This is a recursive function, TCG temps should be freed by the - * calling function once it is done with the values. + * This is a recursive function. */ static TCGv_i32 do_reduction_op(DisasContext *s, int fpopcode, int rn, - int esize, int size, int vmap, TCGv_ptr fpst) + MemOp esz, int ebase, int ecount, TCGv_ptr fpst) { - if (esize == size) { - int element; - MemOp msize = esize == 16 ? MO_16 : MO_32; - TCGv_i32 tcg_elem; - - /* We should have one register left here */ - assert(ctpop8(vmap) == 1); - element = ctz32(vmap); - assert(element < 8); - - tcg_elem = tcg_temp_new_i32(); - read_vec_element_i32(s, tcg_elem, rn, element, msize); + if (ecount == 1) { + TCGv_i32 tcg_elem = tcg_temp_new_i32(); + read_vec_element_i32(s, tcg_elem, rn, ebase, esz); return tcg_elem; } else { - int bits = size / 2; - int shift = ctpop8(vmap) / 2; - int vmap_lo = (vmap >> shift) & vmap; - int vmap_hi = (vmap & ~vmap_lo); + int half = ecount >> 1; TCGv_i32 tcg_hi, tcg_lo, tcg_res; - tcg_hi = do_reduction_op(s, fpopcode, rn, esize, bits, vmap_hi, fpst); - tcg_lo = do_reduction_op(s, fpopcode, rn, esize, bits, vmap_lo, fpst); + tcg_hi = do_reduction_op(s, fpopcode, rn, esz, + ebase + half, half, fpst); + tcg_lo = do_reduction_op(s, fpopcode, rn, esz, + ebase, half, fpst); tcg_res = tcg_temp_new_i32(); switch (fpopcode) { @@ -XXX,XX +XXX,XX @@ static void disas_simd_across_lanes(DisasContext *s, uint32_t insn) bool is_u = extract32(insn, 29, 1); bool is_fp = false; bool is_min = false; - int esize; int elements; int i; TCGv_i64 tcg_res, tcg_elt; @@ -XXX,XX +XXX,XX @@ static void disas_simd_across_lanes(DisasContext *s, uint32_t insn) return; } - esize = 8 << size; - elements = (is_q ? 128 : 64) / esize; + elements = (is_q ? 16 : 8) >> size; tcg_res = tcg_temp_new_i64(); tcg_elt = tcg_temp_new_i64(); @@ -XXX,XX +XXX,XX @@ static void disas_simd_across_lanes(DisasContext *s, uint32_t insn) */ TCGv_ptr fpst = fpstatus_ptr(size == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); int fpopcode = opcode | is_min << 4 | is_u << 5; - int vmap = (1 << elements) - 1; - TCGv_i32 tcg_res32 = do_reduction_op(s, fpopcode, rn, esize, - (is_q ? 128 : 64), vmap, fpst); + TCGv_i32 tcg_res32 = do_reduction_op(s, fpopcode, rn, size, + 0, elements, fpst); tcg_gen_extu_i32_i64(tcg_res, tcg_res32); } -- 2.34.1
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20240912024114.1097832-11-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/a64.decode | 12 +++ target/arm/tcg/translate-a64.c | 140 ++++++++++++--------------------- 2 files changed, 61 insertions(+), 91 deletions(-) diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -XXX,XX +XXX,XX @@ @rrr_q1e3 ........ ... rm:5 ...... rn:5 rd:5 &qrrr_e q=1 esz=3 @rrrr_q1e3 ........ ... rm:5 . ra:5 rn:5 rd:5 &qrrrr_e q=1 esz=3 +@qrr_e . q:1 ...... esz:2 ...... ...... rn:5 rd:5 &qrr_e + @qrrr_b . q:1 ...... ... rm:5 ...... rn:5 rd:5 &qrrr_e esz=0 @qrrr_h . q:1 ...... ... rm:5 ...... rn:5 rd:5 &qrrr_e esz=1 @qrrr_s . q:1 ...... ... rm:5 ...... rn:5 rd:5 &qrrr_e esz=2 @@ -XXX,XX +XXX,XX @@ TRN1 0.00 1110 .. 0 ..... 0 010 10 ..... ..... @qrrr_e TRN2 0.00 1110 .. 0 ..... 0 110 10 ..... ..... @qrrr_e ZIP1 0.00 1110 .. 0 ..... 0 011 10 ..... ..... @qrrr_e ZIP2 0.00 1110 .. 0 ..... 0 111 10 ..... ..... @qrrr_e + +# Advanced SIMD Across Lanes + +ADDV 0.00 1110 .. 11000 11011 10 ..... ..... @qrr_e +SADDLV 0.00 1110 .. 11000 00011 10 ..... ..... @qrr_e +UADDLV 0.10 1110 .. 11000 00011 10 ..... ..... @qrr_e +SMAXV 0.00 1110 .. 11000 01010 10 ..... ..... @qrr_e +UMAXV 0.10 1110 .. 11000 01010 10 ..... ..... @qrr_e +SMINV 0.00 1110 .. 11000 11010 10 ..... ..... @qrr_e +UMINV 0.10 1110 .. 11000 11010 10 ..... ..... @qrr_e diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ TRANS(FNMADD, do_fmadd, a, true, true) TRANS(FMSUB, do_fmadd, a, false, true) TRANS(FNMSUB, do_fmadd, a, true, false) +/* + * Advanced SIMD Across Lanes + */ + +static bool do_int_reduction(DisasContext *s, arg_qrr_e *a, bool widen, + MemOp src_sign, NeonGenTwo64OpFn *fn) +{ + TCGv_i64 tcg_res, tcg_elt; + MemOp src_mop = a->esz | src_sign; + int elements = (a->q ? 16 : 8) >> a->esz; + + /* Reject MO_64, and MO_32 without Q: a minimum of 4 elements. */ + if (elements < 4) { + return false; + } + if (!fp_access_check(s)) { + return true; + } + + tcg_res = tcg_temp_new_i64(); + tcg_elt = tcg_temp_new_i64(); + + read_vec_element(s, tcg_res, a->rn, 0, src_mop); + for (int i = 1; i < elements; i++) { + read_vec_element(s, tcg_elt, a->rn, i, src_mop); + fn(tcg_res, tcg_res, tcg_elt); + } + + tcg_gen_ext_i64(tcg_res, tcg_res, a->esz + widen); + write_fp_dreg(s, a->rd, tcg_res); + return true; +} + +TRANS(ADDV, do_int_reduction, a, false, 0, tcg_gen_add_i64) +TRANS(SADDLV, do_int_reduction, a, true, MO_SIGN, tcg_gen_add_i64) +TRANS(UADDLV, do_int_reduction, a, true, 0, tcg_gen_add_i64) +TRANS(SMAXV, do_int_reduction, a, false, MO_SIGN, tcg_gen_smax_i64) +TRANS(UMAXV, do_int_reduction, a, false, 0, tcg_gen_umax_i64) +TRANS(SMINV, do_int_reduction, a, false, MO_SIGN, tcg_gen_smin_i64) +TRANS(UMINV, do_int_reduction, a, false, 0, tcg_gen_umin_i64) + /* Shift a TCGv src by TCGv shift_amount, put result in dst. * Note that it is the caller's responsibility to ensure that the * shift amount is in range (ie 0..31 or 0..63) and provide the ARM @@ -XXX,XX +XXX,XX @@ static void disas_simd_across_lanes(DisasContext *s, uint32_t insn) int opcode = extract32(insn, 12, 5); bool is_q = extract32(insn, 30, 1); bool is_u = extract32(insn, 29, 1); - bool is_fp = false; bool is_min = false; int elements; - int i; - TCGv_i64 tcg_res, tcg_elt; switch (opcode) { - case 0x1b: /* ADDV */ - if (is_u) { - unallocated_encoding(s); - return; - } - /* fall through */ - case 0x3: /* SADDLV, UADDLV */ - case 0xa: /* SMAXV, UMAXV */ - case 0x1a: /* SMINV, UMINV */ - if (size == 3 || (size == 2 && !is_q)) { - unallocated_encoding(s); - return; - } - break; case 0xc: /* FMAXNMV, FMINNMV */ case 0xf: /* FMAXV, FMINV */ /* Bit 1 of size field encodes min vs max and the actual size @@ -XXX,XX +XXX,XX @@ static void disas_simd_across_lanes(DisasContext *s, uint32_t insn) * precision. */ is_min = extract32(size, 1, 1); - is_fp = true; if (!is_u && dc_isar_feature(aa64_fp16, s)) { size = 1; } else if (!is_u || !is_q || extract32(size, 0, 1)) { @@ -XXX,XX +XXX,XX @@ static void disas_simd_across_lanes(DisasContext *s, uint32_t insn) } break; default: + case 0x3: /* SADDLV, UADDLV */ + case 0xa: /* SMAXV, UMAXV */ + case 0x1a: /* SMINV, UMINV */ + case 0x1b: /* ADDV */ unallocated_encoding(s); return; } @@ -XXX,XX +XXX,XX @@ static void disas_simd_across_lanes(DisasContext *s, uint32_t insn) elements = (is_q ? 16 : 8) >> size; - tcg_res = tcg_temp_new_i64(); - tcg_elt = tcg_temp_new_i64(); - - /* These instructions operate across all lanes of a vector - * to produce a single result. We can guarantee that a 64 - * bit intermediate is sufficient: - * + for [US]ADDLV the maximum element size is 32 bits, and - * the result type is 64 bits - * + for FMAX*V, FMIN*V, ADDV the intermediate type is the - * same as the element size, which is 32 bits at most - * For the integer operations we can choose to work at 64 - * or 32 bits and truncate at the end; for simplicity - * we use 64 bits always. The floating point - * ops do require 32 bit intermediates, though. - */ - if (!is_fp) { - read_vec_element(s, tcg_res, rn, 0, size | (is_u ? 0 : MO_SIGN)); - - for (i = 1; i < elements; i++) { - read_vec_element(s, tcg_elt, rn, i, size | (is_u ? 0 : MO_SIGN)); - - switch (opcode) { - case 0x03: /* SADDLV / UADDLV */ - case 0x1b: /* ADDV */ - tcg_gen_add_i64(tcg_res, tcg_res, tcg_elt); - break; - case 0x0a: /* SMAXV / UMAXV */ - if (is_u) { - tcg_gen_umax_i64(tcg_res, tcg_res, tcg_elt); - } else { - tcg_gen_smax_i64(tcg_res, tcg_res, tcg_elt); - } - break; - case 0x1a: /* SMINV / UMINV */ - if (is_u) { - tcg_gen_umin_i64(tcg_res, tcg_res, tcg_elt); - } else { - tcg_gen_smin_i64(tcg_res, tcg_res, tcg_elt); - } - break; - default: - g_assert_not_reached(); - } - - } - } else { + { /* Floating point vector reduction ops which work across 32 * bit (single) or 16 bit (half-precision) intermediates. * Note that correct NaN propagation requires that we do these @@ -XXX,XX +XXX,XX @@ static void disas_simd_across_lanes(DisasContext *s, uint32_t insn) */ TCGv_ptr fpst = fpstatus_ptr(size == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); int fpopcode = opcode | is_min << 4 | is_u << 5; - TCGv_i32 tcg_res32 = do_reduction_op(s, fpopcode, rn, size, - 0, elements, fpst); - tcg_gen_extu_i32_i64(tcg_res, tcg_res32); + TCGv_i32 tcg_res = do_reduction_op(s, fpopcode, rn, size, + 0, elements, fpst); + write_fp_sreg(s, rd, tcg_res); } - - /* Now truncate the result to the width required for the final output */ - if (opcode == 0x03) { - /* SADDLV, UADDLV: result is 2*esize */ - size++; - } - - switch (size) { - case 0: - tcg_gen_ext8u_i64(tcg_res, tcg_res); - break; - case 1: - tcg_gen_ext16u_i64(tcg_res, tcg_res); - break; - case 2: - tcg_gen_ext32u_i64(tcg_res, tcg_res); - break; - case 3: - break; - default: - g_assert_not_reached(); - } - - write_fp_dreg(s, rd, tcg_res); } /* AdvSIMD modified immediate -- 2.34.1
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20240912024114.1097832-12-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/a64.decode | 14 +++ target/arm/tcg/translate-a64.c | 176 ++++++++++----------------------- 2 files changed, 67 insertions(+), 123 deletions(-) diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -XXX,XX +XXX,XX @@ @rrx_d ........ .. . rm:5 .... idx:1 . rn:5 rd:5 &rrx_e esz=3 @rr_q1e0 ........ ........ ...... rn:5 rd:5 &qrr_e q=1 esz=0 +@rr_q1e2 ........ ........ ...... rn:5 rd:5 &qrr_e q=1 esz=2 @r2r_q1e0 ........ ........ ...... rm:5 rd:5 &qrrr_e rn=%rd q=1 esz=0 @rrr_q1e0 ........ ... rm:5 ...... rn:5 rd:5 &qrrr_e q=1 esz=0 @rrr_q1e3 ........ ... rm:5 ...... rn:5 rd:5 &qrrr_e q=1 esz=3 @rrrr_q1e3 ........ ... rm:5 . ra:5 rn:5 rd:5 &qrrrr_e q=1 esz=3 +@qrr_h . q:1 ...... .. ...... ...... rn:5 rd:5 &qrr_e esz=1 @qrr_e . q:1 ...... esz:2 ...... ...... rn:5 rd:5 &qrr_e @qrrr_b . q:1 ...... ... rm:5 ...... rn:5 rd:5 &qrrr_e esz=0 @@ -XXX,XX +XXX,XX @@ SMAXV 0.00 1110 .. 11000 01010 10 ..... ..... @qrr_e UMAXV 0.10 1110 .. 11000 01010 10 ..... ..... @qrr_e SMINV 0.00 1110 .. 11000 11010 10 ..... ..... @qrr_e UMINV 0.10 1110 .. 11000 11010 10 ..... ..... @qrr_e + +FMAXNMV_h 0.00 1110 00 11000 01100 10 ..... ..... @qrr_h +FMAXNMV_s 0110 1110 00 11000 01100 10 ..... ..... @rr_q1e2 + +FMINNMV_h 0.00 1110 10 11000 01100 10 ..... ..... @qrr_h +FMINNMV_s 0110 1110 10 11000 01100 10 ..... ..... @rr_q1e2 + +FMAXV_h 0.00 1110 00 11000 01111 10 ..... ..... @qrr_h +FMAXV_s 0110 1110 00 11000 01111 10 ..... ..... @rr_q1e2 + +FMINV_h 0.00 1110 10 11000 01111 10 ..... ..... @qrr_h +FMINV_s 0110 1110 10 11000 01111 10 ..... ..... @rr_q1e2 diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ TRANS(UMAXV, do_int_reduction, a, false, 0, tcg_gen_umax_i64) TRANS(SMINV, do_int_reduction, a, false, MO_SIGN, tcg_gen_smin_i64) TRANS(UMINV, do_int_reduction, a, false, 0, tcg_gen_umin_i64) +/* + * do_fp_reduction helper + * + * This mirrors the Reduce() pseudocode in the ARM ARM. It is + * important for correct NaN propagation that we do these + * operations in exactly the order specified by the pseudocode. + * + * This is a recursive function. + */ +static TCGv_i32 do_reduction_op(DisasContext *s, int rn, MemOp esz, + int ebase, int ecount, TCGv_ptr fpst, + NeonGenTwoSingleOpFn *fn) +{ + if (ecount == 1) { + TCGv_i32 tcg_elem = tcg_temp_new_i32(); + read_vec_element_i32(s, tcg_elem, rn, ebase, esz); + return tcg_elem; + } else { + int half = ecount >> 1; + TCGv_i32 tcg_hi, tcg_lo, tcg_res; + + tcg_hi = do_reduction_op(s, rn, esz, ebase + half, half, fpst, fn); + tcg_lo = do_reduction_op(s, rn, esz, ebase, half, fpst, fn); + tcg_res = tcg_temp_new_i32(); + + fn(tcg_res, tcg_lo, tcg_hi, fpst); + return tcg_res; + } +} + +static bool do_fp_reduction(DisasContext *s, arg_qrr_e *a, + NeonGenTwoSingleOpFn *fn) +{ + if (fp_access_check(s)) { + MemOp esz = a->esz; + int elts = (a->q ? 16 : 8) >> esz; + TCGv_ptr fpst = fpstatus_ptr(esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); + TCGv_i32 res = do_reduction_op(s, a->rn, esz, 0, elts, fpst, fn); + write_fp_sreg(s, a->rd, res); + } + return true; +} + +TRANS_FEAT(FMAXNMV_h, aa64_fp16, do_fp_reduction, a, gen_helper_advsimd_maxnumh) +TRANS_FEAT(FMINNMV_h, aa64_fp16, do_fp_reduction, a, gen_helper_advsimd_minnumh) +TRANS_FEAT(FMAXV_h, aa64_fp16, do_fp_reduction, a, gen_helper_advsimd_maxh) +TRANS_FEAT(FMINV_h, aa64_fp16, do_fp_reduction, a, gen_helper_advsimd_minh) + +TRANS(FMAXNMV_s, do_fp_reduction, a, gen_helper_vfp_maxnums) +TRANS(FMINNMV_s, do_fp_reduction, a, gen_helper_vfp_minnums) +TRANS(FMAXV_s, do_fp_reduction, a, gen_helper_vfp_maxs) +TRANS(FMINV_s, do_fp_reduction, a, gen_helper_vfp_mins) + /* Shift a TCGv src by TCGv shift_amount, put result in dst. * Note that it is the caller's responsibility to ensure that the * shift amount is in range (ie 0..31 or 0..63) and provide the ARM @@ -XXX,XX +XXX,XX @@ static void disas_data_proc_fp(DisasContext *s, uint32_t insn) } } -/* - * do_reduction_op helper - * - * This mirrors the Reduce() pseudocode in the ARM ARM. It is - * important for correct NaN propagation that we do these - * operations in exactly the order specified by the pseudocode. - * - * This is a recursive function. - */ -static TCGv_i32 do_reduction_op(DisasContext *s, int fpopcode, int rn, - MemOp esz, int ebase, int ecount, TCGv_ptr fpst) -{ - if (ecount == 1) { - TCGv_i32 tcg_elem = tcg_temp_new_i32(); - read_vec_element_i32(s, tcg_elem, rn, ebase, esz); - return tcg_elem; - } else { - int half = ecount >> 1; - TCGv_i32 tcg_hi, tcg_lo, tcg_res; - - tcg_hi = do_reduction_op(s, fpopcode, rn, esz, - ebase + half, half, fpst); - tcg_lo = do_reduction_op(s, fpopcode, rn, esz, - ebase, half, fpst); - tcg_res = tcg_temp_new_i32(); - - switch (fpopcode) { - case 0x0c: /* fmaxnmv half-precision */ - gen_helper_advsimd_maxnumh(tcg_res, tcg_lo, tcg_hi, fpst); - break; - case 0x0f: /* fmaxv half-precision */ - gen_helper_advsimd_maxh(tcg_res, tcg_lo, tcg_hi, fpst); - break; - case 0x1c: /* fminnmv half-precision */ - gen_helper_advsimd_minnumh(tcg_res, tcg_lo, tcg_hi, fpst); - break; - case 0x1f: /* fminv half-precision */ - gen_helper_advsimd_minh(tcg_res, tcg_lo, tcg_hi, fpst); - break; - case 0x2c: /* fmaxnmv */ - gen_helper_vfp_maxnums(tcg_res, tcg_lo, tcg_hi, fpst); - break; - case 0x2f: /* fmaxv */ - gen_helper_vfp_maxs(tcg_res, tcg_lo, tcg_hi, fpst); - break; - case 0x3c: /* fminnmv */ - gen_helper_vfp_minnums(tcg_res, tcg_lo, tcg_hi, fpst); - break; - case 0x3f: /* fminv */ - gen_helper_vfp_mins(tcg_res, tcg_lo, tcg_hi, fpst); - break; - default: - g_assert_not_reached(); - } - return tcg_res; - } -} - -/* AdvSIMD across lanes - * 31 30 29 28 24 23 22 21 17 16 12 11 10 9 5 4 0 - * +---+---+---+-----------+------+-----------+--------+-----+------+------+ - * | 0 | Q | U | 0 1 1 1 0 | size | 1 1 0 0 0 | opcode | 1 0 | Rn | Rd | - * +---+---+---+-----------+------+-----------+--------+-----+------+------+ - */ -static void disas_simd_across_lanes(DisasContext *s, uint32_t insn) -{ - int rd = extract32(insn, 0, 5); - int rn = extract32(insn, 5, 5); - int size = extract32(insn, 22, 2); - int opcode = extract32(insn, 12, 5); - bool is_q = extract32(insn, 30, 1); - bool is_u = extract32(insn, 29, 1); - bool is_min = false; - int elements; - - switch (opcode) { - case 0xc: /* FMAXNMV, FMINNMV */ - case 0xf: /* FMAXV, FMINV */ - /* Bit 1 of size field encodes min vs max and the actual size - * depends on the encoding of the U bit. If not set (and FP16 - * enabled) then we do half-precision float instead of single - * precision. - */ - is_min = extract32(size, 1, 1); - if (!is_u && dc_isar_feature(aa64_fp16, s)) { - size = 1; - } else if (!is_u || !is_q || extract32(size, 0, 1)) { - unallocated_encoding(s); - return; - } else { - size = 2; - } - break; - default: - case 0x3: /* SADDLV, UADDLV */ - case 0xa: /* SMAXV, UMAXV */ - case 0x1a: /* SMINV, UMINV */ - case 0x1b: /* ADDV */ - unallocated_encoding(s); - return; - } - - if (!fp_access_check(s)) { - return; - } - - elements = (is_q ? 16 : 8) >> size; - - { - /* Floating point vector reduction ops which work across 32 - * bit (single) or 16 bit (half-precision) intermediates. - * Note that correct NaN propagation requires that we do these - * operations in exactly the order specified by the pseudocode. - */ - TCGv_ptr fpst = fpstatus_ptr(size == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); - int fpopcode = opcode | is_min << 4 | is_u << 5; - TCGv_i32 tcg_res = do_reduction_op(s, fpopcode, rn, size, - 0, elements, fpst); - write_fp_sreg(s, rd, tcg_res); - } -} - /* AdvSIMD modified immediate * 31 30 29 28 19 18 16 15 12 11 10 9 5 4 0 * +---+---+----+---------------------+-----+-------+----+---+-------+------+ @@ -XXX,XX +XXX,XX @@ static void disas_simd_two_reg_misc_fp16(DisasContext *s, uint32_t insn) static const AArch64DecodeTable data_proc_simd[] = { /* pattern , mask , fn */ { 0x0e200800, 0x9f3e0c00, disas_simd_two_reg_misc }, - { 0x0e300800, 0x9f3e0c00, disas_simd_across_lanes }, /* simd_mod_imm decode is a subset of simd_shift_imm, so must precede it */ { 0x0f000400, 0x9ff80400, disas_simd_mod_imm }, { 0x0f000400, 0x9f800400, disas_simd_shift_imm }, -- 2.34.1
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20240912024114.1097832-13-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/a64.decode | 4 ++ target/arm/tcg/translate-a64.c | 74 ++++++++++++---------------------- 2 files changed, 30 insertions(+), 48 deletions(-) diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -XXX,XX +XXX,XX @@ FMAXV_s 0110 1110 00 11000 01111 10 ..... ..... @rr_q1e2 FMINV_h 0.00 1110 10 11000 01111 10 ..... ..... @qrr_h FMINV_s 0110 1110 10 11000 01111 10 ..... ..... @rr_q1e2 + +# Floating-point Immediate + +FMOVI_s 0001 1110 .. 1 imm:8 100 00000 rd:5 esz=%esz_hsd diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ TRANS(FMINNMV_s, do_fp_reduction, a, gen_helper_vfp_minnums) TRANS(FMAXV_s, do_fp_reduction, a, gen_helper_vfp_maxs) TRANS(FMINV_s, do_fp_reduction, a, gen_helper_vfp_mins) +/* + * Floating-point Immediate + */ + +static bool trans_FMOVI_s(DisasContext *s, arg_FMOVI_s *a) +{ + switch (a->esz) { + case MO_32: + case MO_64: + break; + case MO_16: + if (!dc_isar_feature(aa64_fp16, s)) { + return false; + } + break; + default: + return false; + } + if (fp_access_check(s)) { + uint64_t imm = vfp_expand_imm(a->esz, a->imm); + write_fp_dreg(s, a->rd, tcg_constant_i64(imm)); + } + return true; +} + /* Shift a TCGv src by TCGv shift_amount, put result in dst. * Note that it is the caller's responsibility to ensure that the * shift amount is in range (ie 0..31 or 0..63) and provide the ARM @@ -XXX,XX +XXX,XX @@ static void disas_fp_1src(DisasContext *s, uint32_t insn) } } -/* Floating point immediate - * 31 30 29 28 24 23 22 21 20 13 12 10 9 5 4 0 - * +---+---+---+-----------+------+---+------------+-------+------+------+ - * | M | 0 | S | 1 1 1 1 0 | type | 1 | imm8 | 1 0 0 | imm5 | Rd | - * +---+---+---+-----------+------+---+------------+-------+------+------+ - */ -static void disas_fp_imm(DisasContext *s, uint32_t insn) -{ - int rd = extract32(insn, 0, 5); - int imm5 = extract32(insn, 5, 5); - int imm8 = extract32(insn, 13, 8); - int type = extract32(insn, 22, 2); - int mos = extract32(insn, 29, 3); - uint64_t imm; - MemOp sz; - - if (mos || imm5) { - unallocated_encoding(s); - return; - } - - switch (type) { - case 0: - sz = MO_32; - break; - case 1: - sz = MO_64; - break; - case 3: - sz = MO_16; - if (dc_isar_feature(aa64_fp16, s)) { - break; - } - /* fallthru */ - default: - unallocated_encoding(s); - return; - } - - if (!fp_access_check(s)) { - return; - } - - imm = vfp_expand_imm(sz, imm8); - write_fp_dreg(s, rd, tcg_constant_i64(imm)); -} - /* Handle floating point <=> fixed point conversions. Note that we can * also deal with fp <=> integer conversions as a special case (scale == 64) * OPTME: consider handling that special case specially or at least skipping @@ -XXX,XX +XXX,XX @@ static void disas_data_proc_fp(DisasContext *s, uint32_t insn) switch (ctz32(extract32(insn, 12, 4))) { case 0: /* [15:12] == xxx1 */ /* Floating point immediate */ - disas_fp_imm(s, insn); + unallocated_encoding(s); /* in decodetree */ break; case 1: /* [15:12] == xx10 */ /* Floating point compare */ -- 2.34.1
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20240912024114.1097832-14-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/a64.decode | 9 +++ target/arm/tcg/translate-a64.c | 117 ++++++++++++++------------------- 2 files changed, 59 insertions(+), 67 deletions(-) diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -XXX,XX +XXX,XX @@ FMINV_s 0110 1110 10 11000 01111 10 ..... ..... @rr_q1e2 # Floating-point Immediate FMOVI_s 0001 1110 .. 1 imm:8 100 00000 rd:5 esz=%esz_hsd + +# Advanced SIMD Modified Immediate + +%abcdefgh 16:3 5:5 + +FMOVI_v_h 0 q:1 00 1111 00000 ... 1111 11 ..... rd:5 %abcdefgh + +# MOVI, MVNI, ORR, BIC, FMOV are all intermixed via cmode. +Vimm 0 q:1 op:1 0 1111 00000 ... cmode:4 01 ..... rd:5 %abcdefgh diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ static bool trans_FMOVI_s(DisasContext *s, arg_FMOVI_s *a) return true; } +/* + * Advanced SIMD Modified Immediate + */ + +static bool trans_FMOVI_v_h(DisasContext *s, arg_FMOVI_v_h *a) +{ + if (!dc_isar_feature(aa64_fp16, s)) { + return false; + } + if (fp_access_check(s)) { + tcg_gen_gvec_dup_imm(MO_16, vec_full_reg_offset(s, a->rd), + a->q ? 16 : 8, vec_full_reg_size(s), + vfp_expand_imm(MO_16, a->abcdefgh)); + } + return true; +} + +static void gen_movi(unsigned vece, uint32_t dofs, uint32_t aofs, + int64_t c, uint32_t oprsz, uint32_t maxsz) +{ + tcg_gen_gvec_dup_imm(MO_64, dofs, oprsz, maxsz, c); +} + +static bool trans_Vimm(DisasContext *s, arg_Vimm *a) +{ + GVecGen2iFn *fn; + + /* Handle decode of cmode/op here between ORR/BIC/MOVI */ + if ((a->cmode & 1) && a->cmode < 12) { + /* For op=1, the imm will be inverted, so BIC becomes AND. */ + fn = a->op ? tcg_gen_gvec_andi : tcg_gen_gvec_ori; + } else { + /* There is one unallocated cmode/op combination in this space */ + if (a->cmode == 15 && a->op == 1 && a->q == 0) { + return false; + } + fn = gen_movi; + } + + if (fp_access_check(s)) { + uint64_t imm = asimd_imm_const(a->abcdefgh, a->cmode, a->op); + gen_gvec_fn2i(s, a->q, a->rd, a->rd, imm, fn, MO_64); + } + return true; +} + /* Shift a TCGv src by TCGv shift_amount, put result in dst. * Note that it is the caller's responsibility to ensure that the * shift amount is in range (ie 0..31 or 0..63) and provide the ARM @@ -XXX,XX +XXX,XX @@ static void disas_data_proc_fp(DisasContext *s, uint32_t insn) } } -/* AdvSIMD modified immediate - * 31 30 29 28 19 18 16 15 12 11 10 9 5 4 0 - * +---+---+----+---------------------+-----+-------+----+---+-------+------+ - * | 0 | Q | op | 0 1 1 1 1 0 0 0 0 0 | abc | cmode | o2 | 1 | defgh | Rd | - * +---+---+----+---------------------+-----+-------+----+---+-------+------+ - * - * There are a number of operations that can be carried out here: - * MOVI - move (shifted) imm into register - * MVNI - move inverted (shifted) imm into register - * ORR - bitwise OR of (shifted) imm with register - * BIC - bitwise clear of (shifted) imm with register - * With ARMv8.2 we also have: - * FMOV half-precision - */ -static void disas_simd_mod_imm(DisasContext *s, uint32_t insn) -{ - int rd = extract32(insn, 0, 5); - int cmode = extract32(insn, 12, 4); - int o2 = extract32(insn, 11, 1); - uint64_t abcdefgh = extract32(insn, 5, 5) | (extract32(insn, 16, 3) << 5); - bool is_neg = extract32(insn, 29, 1); - bool is_q = extract32(insn, 30, 1); - uint64_t imm = 0; - - if (o2) { - if (cmode != 0xf || is_neg) { - unallocated_encoding(s); - return; - } - /* FMOV (vector, immediate) - half-precision */ - if (!dc_isar_feature(aa64_fp16, s)) { - unallocated_encoding(s); - return; - } - imm = vfp_expand_imm(MO_16, abcdefgh); - /* now duplicate across the lanes */ - imm = dup_const(MO_16, imm); - } else { - if (cmode == 0xf && is_neg && !is_q) { - unallocated_encoding(s); - return; - } - imm = asimd_imm_const(abcdefgh, cmode, is_neg); - } - - if (!fp_access_check(s)) { - return; - } - - if (!((cmode & 0x9) == 0x1 || (cmode & 0xd) == 0x9)) { - /* MOVI or MVNI, with MVNI negation handled above. */ - tcg_gen_gvec_dup_imm(MO_64, vec_full_reg_offset(s, rd), is_q ? 16 : 8, - vec_full_reg_size(s), imm); - } else { - /* ORR or BIC, with BIC negation to AND handled above. */ - if (is_neg) { - gen_gvec_fn2i(s, is_q, rd, rd, imm, tcg_gen_gvec_andi, MO_64); - } else { - gen_gvec_fn2i(s, is_q, rd, rd, imm, tcg_gen_gvec_ori, MO_64); - } - } -} - /* * Common SSHR[RA]/USHR[RA] - Shift right (optional rounding/accumulate) * @@ -XXX,XX +XXX,XX @@ static void disas_simd_shift_imm(DisasContext *s, uint32_t insn) bool is_u = extract32(insn, 29, 1); bool is_q = extract32(insn, 30, 1); - /* data_proc_simd[] has sent immh == 0 to disas_simd_mod_imm. */ - assert(immh != 0); + if (immh == 0) { + unallocated_encoding(s); + return; + } switch (opcode) { case 0x08: /* SRI */ @@ -XXX,XX +XXX,XX @@ static void disas_simd_two_reg_misc_fp16(DisasContext *s, uint32_t insn) static const AArch64DecodeTable data_proc_simd[] = { /* pattern , mask , fn */ { 0x0e200800, 0x9f3e0c00, disas_simd_two_reg_misc }, - /* simd_mod_imm decode is a subset of simd_shift_imm, so must precede it */ - { 0x0f000400, 0x9ff80400, disas_simd_mod_imm }, { 0x0f000400, 0x9f800400, disas_simd_shift_imm }, { 0x5e200800, 0xdf3e0c00, disas_simd_scalar_two_reg_misc }, { 0x5f000400, 0xdf800400, disas_simd_scalar_shift_imm }, -- 2.34.1
From: Richard Henderson <richard.henderson@linaro.org> Handle the two special cases within these new functions instead of higher in the call stack. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20240912024114.1097832-15-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/translate.h | 5 +++++ target/arm/tcg/gengvec.c | 19 +++++++++++++++++++ target/arm/tcg/translate-a64.c | 16 +--------------- target/arm/tcg/translate-neon.c | 25 ++----------------------- 4 files changed, 27 insertions(+), 38 deletions(-) diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate.h +++ b/target/arm/tcg/translate.h @@ -XXX,XX +XXX,XX @@ void gen_sqsub_d(TCGv_i64 d, TCGv_i64 q, TCGv_i64 a, TCGv_i64 b); void gen_gvec_sqsub_qc(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz); +void gen_gvec_sshr(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, + int64_t shift, uint32_t opr_sz, uint32_t max_sz); +void gen_gvec_ushr(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, + int64_t shift, uint32_t opr_sz, uint32_t max_sz); + void gen_gvec_ssra(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, int64_t shift, uint32_t opr_sz, uint32_t max_sz); void gen_gvec_usra(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, diff --git a/target/arm/tcg/gengvec.c b/target/arm/tcg/gengvec.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/gengvec.c +++ b/target/arm/tcg/gengvec.c @@ -XXX,XX +XXX,XX @@ GEN_CMP0(gen_gvec_cgt0, TCG_COND_GT) #undef GEN_CMP0 +void gen_gvec_sshr(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, + int64_t shift, uint32_t opr_sz, uint32_t max_sz) +{ + /* Signed shift out of range results in all-sign-bits */ + shift = MIN(shift, (8 << vece) - 1); + tcg_gen_gvec_sari(vece, rd_ofs, rm_ofs, shift, opr_sz, max_sz); +} + +void gen_gvec_ushr(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, + int64_t shift, uint32_t opr_sz, uint32_t max_sz) +{ + /* Unsigned shift out of range results in all-zero-bits */ + if (shift >= (8 << vece)) { + tcg_gen_gvec_dup_imm(vece, rd_ofs, opr_sz, max_sz, 0); + } else { + tcg_gen_gvec_shri(vece, rd_ofs, rm_ofs, shift, opr_sz, max_sz); + } +} + static void gen_ssra8_i64(TCGv_i64 d, TCGv_i64 a, int64_t shift) { tcg_gen_vec_sar8i_i64(a, a, shift); diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ static void handle_vec_simd_shri(DisasContext *s, bool is_q, bool is_u, break; case 0x00: /* SSHR / USHR */ - if (is_u) { - if (shift == 8 << size) { - /* Shift count the same size as element size produces zero. */ - tcg_gen_gvec_dup_imm(size, vec_full_reg_offset(s, rd), - is_q ? 16 : 8, vec_full_reg_size(s), 0); - return; - } - gvec_fn = tcg_gen_gvec_shri; - } else { - /* Shift count the same size as element size produces all sign. */ - if (shift == 8 << size) { - shift -= 1; - } - gvec_fn = tcg_gen_gvec_sari; - } + gvec_fn = is_u ? gen_gvec_ushr : gen_gvec_sshr; break; case 0x04: /* SRSHR / URSHR (rounding) */ diff --git a/target/arm/tcg/translate-neon.c b/target/arm/tcg/translate-neon.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-neon.c +++ b/target/arm/tcg/translate-neon.c @@ -XXX,XX +XXX,XX @@ DO_2SH(VRSHR_S, gen_gvec_srshr) DO_2SH(VRSHR_U, gen_gvec_urshr) DO_2SH(VRSRA_S, gen_gvec_srsra) DO_2SH(VRSRA_U, gen_gvec_ursra) - -static bool trans_VSHR_S_2sh(DisasContext *s, arg_2reg_shift *a) -{ - /* Signed shift out of range results in all-sign-bits */ - a->shift = MIN(a->shift, (8 << a->size) - 1); - return do_vector_2sh(s, a, tcg_gen_gvec_sari); -} - -static void gen_zero_rd_2sh(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, - int64_t shift, uint32_t oprsz, uint32_t maxsz) -{ - tcg_gen_gvec_dup_imm(vece, rd_ofs, oprsz, maxsz, 0); -} - -static bool trans_VSHR_U_2sh(DisasContext *s, arg_2reg_shift *a) -{ - /* Shift out of range is architecturally valid and results in zero. */ - if (a->shift >= (8 << a->size)) { - return do_vector_2sh(s, a, gen_zero_rd_2sh); - } else { - return do_vector_2sh(s, a, tcg_gen_gvec_shri); - } -} +DO_2SH(VSHR_S, gen_gvec_sshr) +DO_2SH(VSHR_U, gen_gvec_ushr) static bool do_2shift_env_64(DisasContext *s, arg_2reg_shift *a, NeonGenTwo64OpEnvFn *fn) -- 2.34.1
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20240912024114.1097832-16-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/gengvec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/arm/tcg/gengvec.c b/target/arm/tcg/gengvec.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/gengvec.c +++ b/target/arm/tcg/gengvec.c @@ -XXX,XX +XXX,XX @@ void gen_srshr32_i32(TCGv_i32 d, TCGv_i32 a, int32_t sh) tcg_gen_add_i32(d, d, t); } - void gen_srshr64_i64(TCGv_i64 d, TCGv_i64 a, int64_t sh) +void gen_srshr64_i64(TCGv_i64 d, TCGv_i64 a, int64_t sh) { TCGv_i64 t = tcg_temp_new_i64(); -- 2.34.1
From: Richard Henderson <richard.henderson@linaro.org> This includes SSHR, USHR, SSRA, USRA, SRSHR, URSHR, SRSRA, URSRA, SRI. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20240912024114.1097832-17-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/a64.decode | 63 ++++++++++++++++++++++++- target/arm/tcg/translate-a64.c | 86 +++++++++++----------------------- 2 files changed, 89 insertions(+), 60 deletions(-) diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -XXX,XX +XXX,XX @@ &rrx_e rd rn rm idx esz &rrrr_e rd rn rm ra esz &qrr_e q rd rn esz +&qrri_e q rd rn imm esz &qrrr_e q rd rn rm esz &qrrx_e q rd rn rm idx esz &qrrrr_e q rd rn rm ra esz @@ -XXX,XX +XXX,XX @@ FMINV_s 0110 1110 10 11000 01111 10 ..... ..... @rr_q1e2 FMOVI_s 0001 1110 .. 1 imm:8 100 00000 rd:5 esz=%esz_hsd -# Advanced SIMD Modified Immediate +# Advanced SIMD Modified Immediate / Shift by Immediate %abcdefgh 16:3 5:5 +# Right shifts are encoded as N - shift, where N is the element size in bits. +%neon_rshift_i6 16:6 !function=rsub_64 +%neon_rshift_i5 16:5 !function=rsub_32 +%neon_rshift_i4 16:4 !function=rsub_16 +%neon_rshift_i3 16:3 !function=rsub_8 + +@q_shri_b . q:1 .. ..... 0001 ... ..... . rn:5 rd:5 \ + &qrri_e esz=0 imm=%neon_rshift_i3 +@q_shri_h . q:1 .. ..... 001 .... ..... . rn:5 rd:5 \ + &qrri_e esz=1 imm=%neon_rshift_i4 +@q_shri_s . q:1 .. ..... 01 ..... ..... . rn:5 rd:5 \ + &qrri_e esz=2 imm=%neon_rshift_i5 +@q_shri_d . 1 .. ..... 1 ...... ..... . rn:5 rd:5 \ + &qrri_e esz=3 imm=%neon_rshift_i6 q=1 + FMOVI_v_h 0 q:1 00 1111 00000 ... 1111 11 ..... rd:5 %abcdefgh # MOVI, MVNI, ORR, BIC, FMOV are all intermixed via cmode. Vimm 0 q:1 op:1 0 1111 00000 ... cmode:4 01 ..... rd:5 %abcdefgh + +SSHR_v 0.00 11110 .... ... 00000 1 ..... ..... @q_shri_b +SSHR_v 0.00 11110 .... ... 00000 1 ..... ..... @q_shri_h +SSHR_v 0.00 11110 .... ... 00000 1 ..... ..... @q_shri_s +SSHR_v 0.00 11110 .... ... 00000 1 ..... ..... @q_shri_d + +USHR_v 0.10 11110 .... ... 00000 1 ..... ..... @q_shri_b +USHR_v 0.10 11110 .... ... 00000 1 ..... ..... @q_shri_h +USHR_v 0.10 11110 .... ... 00000 1 ..... ..... @q_shri_s +USHR_v 0.10 11110 .... ... 00000 1 ..... ..... @q_shri_d + +SSRA_v 0.00 11110 .... ... 00010 1 ..... ..... @q_shri_b +SSRA_v 0.00 11110 .... ... 00010 1 ..... ..... @q_shri_h +SSRA_v 0.00 11110 .... ... 00010 1 ..... ..... @q_shri_s +SSRA_v 0.00 11110 .... ... 00010 1 ..... ..... @q_shri_d + +USRA_v 0.10 11110 .... ... 00010 1 ..... ..... @q_shri_b +USRA_v 0.10 11110 .... ... 00010 1 ..... ..... @q_shri_h +USRA_v 0.10 11110 .... ... 00010 1 ..... ..... @q_shri_s +USRA_v 0.10 11110 .... ... 00010 1 ..... ..... @q_shri_d + +SRSHR_v 0.00 11110 .... ... 00100 1 ..... ..... @q_shri_b +SRSHR_v 0.00 11110 .... ... 00100 1 ..... ..... @q_shri_h +SRSHR_v 0.00 11110 .... ... 00100 1 ..... ..... @q_shri_s +SRSHR_v 0.00 11110 .... ... 00100 1 ..... ..... @q_shri_d + +URSHR_v 0.10 11110 .... ... 00100 1 ..... ..... @q_shri_b +URSHR_v 0.10 11110 .... ... 00100 1 ..... ..... @q_shri_h +URSHR_v 0.10 11110 .... ... 00100 1 ..... ..... @q_shri_s +URSHR_v 0.10 11110 .... ... 00100 1 ..... ..... @q_shri_d + +SRSRA_v 0.00 11110 .... ... 00110 1 ..... ..... @q_shri_b +SRSRA_v 0.00 11110 .... ... 00110 1 ..... ..... @q_shri_h +SRSRA_v 0.00 11110 .... ... 00110 1 ..... ..... @q_shri_s +SRSRA_v 0.00 11110 .... ... 00110 1 ..... ..... @q_shri_d + +URSRA_v 0.10 11110 .... ... 00110 1 ..... ..... @q_shri_b +URSRA_v 0.10 11110 .... ... 00110 1 ..... ..... @q_shri_h +URSRA_v 0.10 11110 .... ... 00110 1 ..... ..... @q_shri_s +URSRA_v 0.10 11110 .... ... 00110 1 ..... ..... @q_shri_d + +SRI_v 0.10 11110 .... ... 01000 1 ..... ..... @q_shri_b +SRI_v 0.10 11110 .... ... 01000 1 ..... ..... @q_shri_h +SRI_v 0.10 11110 .... ... 01000 1 ..... ..... @q_shri_s +SRI_v 0.10 11110 .... ... 01000 1 ..... ..... @q_shri_d diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ static bool trans_Vimm(DisasContext *s, arg_Vimm *a) return true; } +/* + * Advanced SIMD Shift by Immediate + */ + +static bool do_vec_shift_imm(DisasContext *s, arg_qrri_e *a, GVecGen2iFn *fn) +{ + if (fp_access_check(s)) { + gen_gvec_fn2i(s, a->q, a->rd, a->rn, a->imm, fn, a->esz); + } + return true; +} + +TRANS(SSHR_v, do_vec_shift_imm, a, gen_gvec_sshr) +TRANS(USHR_v, do_vec_shift_imm, a, gen_gvec_ushr) +TRANS(SSRA_v, do_vec_shift_imm, a, gen_gvec_ssra) +TRANS(USRA_v, do_vec_shift_imm, a, gen_gvec_usra) +TRANS(SRSHR_v, do_vec_shift_imm, a, gen_gvec_srshr) +TRANS(URSHR_v, do_vec_shift_imm, a, gen_gvec_urshr) +TRANS(SRSRA_v, do_vec_shift_imm, a, gen_gvec_srsra) +TRANS(URSRA_v, do_vec_shift_imm, a, gen_gvec_ursra) +TRANS(SRI_v, do_vec_shift_imm, a, gen_gvec_sri) + /* Shift a TCGv src by TCGv shift_amount, put result in dst. * Note that it is the caller's responsibility to ensure that the * shift amount is in range (ie 0..31 or 0..63) and provide the ARM @@ -XXX,XX +XXX,XX @@ static void disas_simd_scalar_two_reg_misc(DisasContext *s, uint32_t insn) } } -/* SSHR[RA]/USHR[RA] - Vector shift right (optional rounding/accumulate) */ -static void handle_vec_simd_shri(DisasContext *s, bool is_q, bool is_u, - int immh, int immb, int opcode, int rn, int rd) -{ - int size = 32 - clz32(immh) - 1; - int immhb = immh << 3 | immb; - int shift = 2 * (8 << size) - immhb; - GVecGen2iFn *gvec_fn; - - if (extract32(immh, 3, 1) && !is_q) { - unallocated_encoding(s); - return; - } - tcg_debug_assert(size <= 3); - - if (!fp_access_check(s)) { - return; - } - - switch (opcode) { - case 0x02: /* SSRA / USRA (accumulate) */ - gvec_fn = is_u ? gen_gvec_usra : gen_gvec_ssra; - break; - - case 0x08: /* SRI */ - gvec_fn = gen_gvec_sri; - break; - - case 0x00: /* SSHR / USHR */ - gvec_fn = is_u ? gen_gvec_ushr : gen_gvec_sshr; - break; - - case 0x04: /* SRSHR / URSHR (rounding) */ - gvec_fn = is_u ? gen_gvec_urshr : gen_gvec_srshr; - break; - - case 0x06: /* SRSRA / URSRA (accum + rounding) */ - gvec_fn = is_u ? gen_gvec_ursra : gen_gvec_srsra; - break; - - default: - g_assert_not_reached(); - } - - gen_gvec_fn2i(s, is_q, rd, rn, shift, gvec_fn, size); -} - /* SHL/SLI - Vector shift left */ static void handle_vec_simd_shli(DisasContext *s, bool is_q, bool insert, int immh, int immb, int opcode, int rn, int rd) @@ -XXX,XX +XXX,XX @@ static void disas_simd_shift_imm(DisasContext *s, uint32_t insn) } switch (opcode) { - case 0x08: /* SRI */ - if (!is_u) { - unallocated_encoding(s); - return; - } - /* fall through */ - case 0x00: /* SSHR / USHR */ - case 0x02: /* SSRA / USRA (accumulate) */ - case 0x04: /* SRSHR / URSHR (rounding) */ - case 0x06: /* SRSRA / URSRA (accum + rounding) */ - handle_vec_simd_shri(s, is_q, is_u, immh, immb, opcode, rn, rd); - break; case 0x0a: /* SHL / SLI */ handle_vec_simd_shli(s, is_q, is_u, immh, immb, opcode, rn, rd); break; @@ -XXX,XX +XXX,XX @@ static void disas_simd_shift_imm(DisasContext *s, uint32_t insn) handle_simd_shift_fpint_conv(s, false, is_q, is_u, immh, immb, rn, rd); return; default: + case 0x00: /* SSHR / USHR */ + case 0x02: /* SSRA / USRA (accumulate) */ + case 0x04: /* SRSHR / URSHR (rounding) */ + case 0x06: /* SRSRA / URSRA (accum + rounding) */ + case 0x08: /* SRI */ unallocated_encoding(s); return; } -- 2.34.1
From: Richard Henderson <richard.henderson@linaro.org> This includes SHL and SLI. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20240912024114.1097832-18-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/a64.decode | 15 +++++++++++++++ target/arm/tcg/translate-a64.c | 33 +++------------------------------ 2 files changed, 18 insertions(+), 30 deletions(-) diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -XXX,XX +XXX,XX @@ FMOVI_s 0001 1110 .. 1 imm:8 100 00000 rd:5 esz=%esz_hsd @q_shri_d . 1 .. ..... 1 ...... ..... . rn:5 rd:5 \ &qrri_e esz=3 imm=%neon_rshift_i6 q=1 +@q_shli_b . q:1 .. ..... 0001 imm:3 ..... . rn:5 rd:5 &qrri_e esz=0 +@q_shli_h . q:1 .. ..... 001 imm:4 ..... . rn:5 rd:5 &qrri_e esz=1 +@q_shli_s . q:1 .. ..... 01 imm:5 ..... . rn:5 rd:5 &qrri_e esz=2 +@q_shli_d . 1 .. ..... 1 imm:6 ..... . rn:5 rd:5 &qrri_e esz=3 q=1 + FMOVI_v_h 0 q:1 00 1111 00000 ... 1111 11 ..... rd:5 %abcdefgh # MOVI, MVNI, ORR, BIC, FMOV are all intermixed via cmode. @@ -XXX,XX +XXX,XX @@ SRI_v 0.10 11110 .... ... 01000 1 ..... ..... @q_shri_b SRI_v 0.10 11110 .... ... 01000 1 ..... ..... @q_shri_h SRI_v 0.10 11110 .... ... 01000 1 ..... ..... @q_shri_s SRI_v 0.10 11110 .... ... 01000 1 ..... ..... @q_shri_d + +SHL_v 0.00 11110 .... ... 01010 1 ..... ..... @q_shli_b +SHL_v 0.00 11110 .... ... 01010 1 ..... ..... @q_shli_h +SHL_v 0.00 11110 .... ... 01010 1 ..... ..... @q_shli_s +SHL_v 0.00 11110 .... ... 01010 1 ..... ..... @q_shli_d + +SLI_v 0.10 11110 .... ... 01010 1 ..... ..... @q_shli_b +SLI_v 0.10 11110 .... ... 01010 1 ..... ..... @q_shli_h +SLI_v 0.10 11110 .... ... 01010 1 ..... ..... @q_shli_s +SLI_v 0.10 11110 .... ... 01010 1 ..... ..... @q_shli_d diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ TRANS(URSHR_v, do_vec_shift_imm, a, gen_gvec_urshr) TRANS(SRSRA_v, do_vec_shift_imm, a, gen_gvec_srsra) TRANS(URSRA_v, do_vec_shift_imm, a, gen_gvec_ursra) TRANS(SRI_v, do_vec_shift_imm, a, gen_gvec_sri) +TRANS(SHL_v, do_vec_shift_imm, a, tcg_gen_gvec_shli) +TRANS(SLI_v, do_vec_shift_imm, a, gen_gvec_sli); /* Shift a TCGv src by TCGv shift_amount, put result in dst. * Note that it is the caller's responsibility to ensure that the @@ -XXX,XX +XXX,XX @@ static void disas_simd_scalar_two_reg_misc(DisasContext *s, uint32_t insn) } } -/* SHL/SLI - Vector shift left */ -static void handle_vec_simd_shli(DisasContext *s, bool is_q, bool insert, - int immh, int immb, int opcode, int rn, int rd) -{ - int size = 32 - clz32(immh) - 1; - int immhb = immh << 3 | immb; - int shift = immhb - (8 << size); - - /* Range of size is limited by decode: immh is a non-zero 4 bit field */ - assert(size >= 0 && size <= 3); - - if (extract32(immh, 3, 1) && !is_q) { - unallocated_encoding(s); - return; - } - - if (!fp_access_check(s)) { - return; - } - - if (insert) { - gen_gvec_fn2i(s, is_q, rd, rn, shift, gen_gvec_sli, size); - } else { - gen_gvec_fn2i(s, is_q, rd, rn, shift, tcg_gen_gvec_shli, size); - } -} - /* USHLL/SHLL - Vector shift left with widening */ static void handle_vec_simd_wshli(DisasContext *s, bool is_q, bool is_u, int immh, int immb, int opcode, int rn, int rd) @@ -XXX,XX +XXX,XX @@ static void disas_simd_shift_imm(DisasContext *s, uint32_t insn) } switch (opcode) { - case 0x0a: /* SHL / SLI */ - handle_vec_simd_shli(s, is_q, is_u, immh, immb, opcode, rn, rd); - break; case 0x10: /* SHRN */ case 0x11: /* RSHRN / SQRSHRUN */ if (is_u) { @@ -XXX,XX +XXX,XX @@ static void disas_simd_shift_imm(DisasContext *s, uint32_t insn) case 0x04: /* SRSHR / URSHR (rounding) */ case 0x06: /* SRSRA / URSRA (accum + rounding) */ case 0x08: /* SRI */ + case 0x0a: /* SHL / SLI */ unallocated_encoding(s); return; } -- 2.34.1
From: Richard Henderson <richard.henderson@linaro.org> Combine the right shift with the extension via the tcg extract operations. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20240912024114.1097832-19-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/translate-a64.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ static void handle_vec_simd_wshli(DisasContext *s, bool is_q, bool is_u, read_vec_element(s, tcg_rn, rn, is_q ? 1 : 0, MO_64); for (i = 0; i < elements; i++) { - tcg_gen_shri_i64(tcg_rd, tcg_rn, i * esize); - ext_and_shift_reg(tcg_rd, tcg_rd, size | (!is_u << 2), 0); + if (is_u) { + tcg_gen_extract_i64(tcg_rd, tcg_rn, i * esize, esize); + } else { + tcg_gen_sextract_i64(tcg_rd, tcg_rn, i * esize, esize); + } tcg_gen_shli_i64(tcg_rd, tcg_rd, shift); write_vec_element(s, tcg_rd, rd, i, size + 1); } -- 2.34.1
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20240912024114.1097832-20-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/a64.decode | 8 ++++ target/arm/tcg/translate-a64.c | 81 ++++++++++++++++------------------ 2 files changed, 45 insertions(+), 44 deletions(-) diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -XXX,XX +XXX,XX @@ SLI_v 0.10 11110 .... ... 01010 1 ..... ..... @q_shli_b SLI_v 0.10 11110 .... ... 01010 1 ..... ..... @q_shli_h SLI_v 0.10 11110 .... ... 01010 1 ..... ..... @q_shli_s SLI_v 0.10 11110 .... ... 01010 1 ..... ..... @q_shli_d + +SSHLL_v 0.00 11110 .... ... 10100 1 ..... ..... @q_shli_b +SSHLL_v 0.00 11110 .... ... 10100 1 ..... ..... @q_shli_h +SSHLL_v 0.00 11110 .... ... 10100 1 ..... ..... @q_shli_s + +USHLL_v 0.10 11110 .... ... 10100 1 ..... ..... @q_shli_b +USHLL_v 0.10 11110 .... ... 10100 1 ..... ..... @q_shli_h +USHLL_v 0.10 11110 .... ... 10100 1 ..... ..... @q_shli_s diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ TRANS(SRI_v, do_vec_shift_imm, a, gen_gvec_sri) TRANS(SHL_v, do_vec_shift_imm, a, tcg_gen_gvec_shli) TRANS(SLI_v, do_vec_shift_imm, a, gen_gvec_sli); +static bool do_vec_shift_imm_wide(DisasContext *s, arg_qrri_e *a, bool is_u) +{ + TCGv_i64 tcg_rn, tcg_rd; + int esz = a->esz; + int esize; + + if (!fp_access_check(s)) { + return true; + } + + /* + * For the LL variants the store is larger than the load, + * so if rd == rn we would overwrite parts of our input. + * So load everything right now and use shifts in the main loop. + */ + tcg_rd = tcg_temp_new_i64(); + tcg_rn = tcg_temp_new_i64(); + read_vec_element(s, tcg_rn, a->rn, a->q, MO_64); + + esize = 8 << esz; + for (int i = 0, elements = 8 >> esz; i < elements; i++) { + if (is_u) { + tcg_gen_extract_i64(tcg_rd, tcg_rn, i * esize, esize); + } else { + tcg_gen_sextract_i64(tcg_rd, tcg_rn, i * esize, esize); + } + tcg_gen_shli_i64(tcg_rd, tcg_rd, a->imm); + write_vec_element(s, tcg_rd, a->rd, i, esz + 1); + } + clear_vec_high(s, true, a->rd); + return true; +} + +TRANS(SSHLL_v, do_vec_shift_imm_wide, a, false) +TRANS(USHLL_v, do_vec_shift_imm_wide, a, true) + /* Shift a TCGv src by TCGv shift_amount, put result in dst. * Note that it is the caller's responsibility to ensure that the * shift amount is in range (ie 0..31 or 0..63) and provide the ARM @@ -XXX,XX +XXX,XX @@ static void disas_simd_scalar_two_reg_misc(DisasContext *s, uint32_t insn) } } -/* USHLL/SHLL - Vector shift left with widening */ -static void handle_vec_simd_wshli(DisasContext *s, bool is_q, bool is_u, - int immh, int immb, int opcode, int rn, int rd) -{ - int size = 32 - clz32(immh) - 1; - int immhb = immh << 3 | immb; - int shift = immhb - (8 << size); - int dsize = 64; - int esize = 8 << size; - int elements = dsize/esize; - TCGv_i64 tcg_rn = tcg_temp_new_i64(); - TCGv_i64 tcg_rd = tcg_temp_new_i64(); - int i; - - if (size >= 3) { - unallocated_encoding(s); - return; - } - - if (!fp_access_check(s)) { - return; - } - - /* For the LL variants the store is larger than the load, - * so if rd == rn we would overwrite parts of our input. - * So load everything right now and use shifts in the main loop. - */ - read_vec_element(s, tcg_rn, rn, is_q ? 1 : 0, MO_64); - - for (i = 0; i < elements; i++) { - if (is_u) { - tcg_gen_extract_i64(tcg_rd, tcg_rn, i * esize, esize); - } else { - tcg_gen_sextract_i64(tcg_rd, tcg_rn, i * esize, esize); - } - tcg_gen_shli_i64(tcg_rd, tcg_rd, shift); - write_vec_element(s, tcg_rd, rd, i, size + 1); - } - clear_vec_high(s, true, rd); -} - /* SHRN/RSHRN - Shift right with narrowing (and potential rounding) */ static void handle_vec_simd_shrn(DisasContext *s, bool is_q, int immh, int immb, int opcode, int rn, int rd) @@ -XXX,XX +XXX,XX @@ static void disas_simd_shift_imm(DisasContext *s, uint32_t insn) handle_vec_simd_sqshrn(s, false, is_q, is_u, is_u, immh, immb, opcode, rn, rd); break; - case 0x14: /* SSHLL / USHLL */ - handle_vec_simd_wshli(s, is_q, is_u, immh, immb, opcode, rn, rd); - break; case 0x1c: /* SCVTF / UCVTF */ handle_simd_shift_intfp_conv(s, false, is_q, is_u, immh, immb, opcode, rn, rd); @@ -XXX,XX +XXX,XX @@ static void disas_simd_shift_imm(DisasContext *s, uint32_t insn) case 0x06: /* SRSRA / URSRA (accum + rounding) */ case 0x08: /* SRI */ case 0x0a: /* SHL / SLI */ + case 0x14: /* SSHLL / USHLL */ unallocated_encoding(s); return; } -- 2.34.1
From: Richard Henderson <richard.henderson@linaro.org> We always pass the same value for round; compute it within common code. Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20240912024114.1097832-21-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/translate-a64.c | 32 ++++++-------------------------- 1 file changed, 6 insertions(+), 26 deletions(-) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ static void disas_data_proc_fp(DisasContext *s, uint32_t insn) * the vector and scalar code. */ static void handle_shri_with_rndacc(TCGv_i64 tcg_res, TCGv_i64 tcg_src, - TCGv_i64 tcg_rnd, bool accumulate, + bool round, bool accumulate, bool is_u, int size, int shift) { bool extended_result = false; - bool round = tcg_rnd != NULL; int ext_lshift = 0; TCGv_i64 tcg_src_hi; @@ -XXX,XX +XXX,XX @@ static void handle_shri_with_rndacc(TCGv_i64 tcg_res, TCGv_i64 tcg_src, /* Deal with the rounding step */ if (round) { + TCGv_i64 tcg_rnd = tcg_constant_i64(1ull << (shift - 1)); if (extended_result) { TCGv_i64 tcg_zero = tcg_constant_i64(0); if (!is_u) { @@ -XXX,XX +XXX,XX @@ static void handle_scalar_simd_shri(DisasContext *s, bool insert = false; TCGv_i64 tcg_rn; TCGv_i64 tcg_rd; - TCGv_i64 tcg_round; if (!extract32(immh, 3, 1)) { unallocated_encoding(s); @@ -XXX,XX +XXX,XX @@ static void handle_scalar_simd_shri(DisasContext *s, break; } - if (round) { - tcg_round = tcg_constant_i64(1ULL << (shift - 1)); - } else { - tcg_round = NULL; - } - tcg_rn = read_fp_dreg(s, rn); tcg_rd = (accumulate || insert) ? read_fp_dreg(s, rd) : tcg_temp_new_i64(); @@ -XXX,XX +XXX,XX @@ static void handle_scalar_simd_shri(DisasContext *s, tcg_gen_deposit_i64(tcg_rd, tcg_rd, tcg_rn, 0, esize - shift); } } else { - handle_shri_with_rndacc(tcg_rd, tcg_rn, tcg_round, + handle_shri_with_rndacc(tcg_rd, tcg_rn, round, accumulate, is_u, size, shift); } @@ -XXX,XX +XXX,XX @@ static void handle_vec_simd_sqshrn(DisasContext *s, bool is_scalar, bool is_q, int elements = is_scalar ? 1 : (64 / esize); bool round = extract32(opcode, 0, 1); MemOp ldop = (size + 1) | (is_u_shift ? 0 : MO_SIGN); - TCGv_i64 tcg_rn, tcg_rd, tcg_round; + TCGv_i64 tcg_rn, tcg_rd; TCGv_i32 tcg_rd_narrowed; TCGv_i64 tcg_final; @@ -XXX,XX +XXX,XX @@ static void handle_vec_simd_sqshrn(DisasContext *s, bool is_scalar, bool is_q, tcg_rd_narrowed = tcg_temp_new_i32(); tcg_final = tcg_temp_new_i64(); - if (round) { - tcg_round = tcg_constant_i64(1ULL << (shift - 1)); - } else { - tcg_round = NULL; - } - for (i = 0; i < elements; i++) { read_vec_element(s, tcg_rn, rn, i, ldop); - handle_shri_with_rndacc(tcg_rd, tcg_rn, tcg_round, + handle_shri_with_rndacc(tcg_rd, tcg_rn, round, false, is_u_shift, size+1, shift); narrowfn(tcg_rd_narrowed, tcg_env, tcg_rd); tcg_gen_extu_i32_i64(tcg_rd, tcg_rd_narrowed); @@ -XXX,XX +XXX,XX @@ static void handle_vec_simd_shrn(DisasContext *s, bool is_q, int shift = (2 * esize) - immhb; bool round = extract32(opcode, 0, 1); TCGv_i64 tcg_rn, tcg_rd, tcg_final; - TCGv_i64 tcg_round; int i; if (extract32(immh, 3, 1)) { @@ -XXX,XX +XXX,XX @@ static void handle_vec_simd_shrn(DisasContext *s, bool is_q, tcg_final = tcg_temp_new_i64(); read_vec_element(s, tcg_final, rd, is_q ? 1 : 0, MO_64); - if (round) { - tcg_round = tcg_constant_i64(1ULL << (shift - 1)); - } else { - tcg_round = NULL; - } - for (i = 0; i < elements; i++) { read_vec_element(s, tcg_rn, rn, i, size+1); - handle_shri_with_rndacc(tcg_rd, tcg_rn, tcg_round, + handle_shri_with_rndacc(tcg_rd, tcg_rn, round, false, true, size+1, shift); tcg_gen_deposit_i64(tcg_final, tcg_final, tcg_rd, esize * i, esize); -- 2.34.1
From: Richard Henderson <richard.henderson@linaro.org> There isn't a lot of commonality along the different paths of handle_shri_with_rndacc. Split them out to separate functions, which will be usable during the decodetree conversion. Simplify 64-bit rounding operations to not require double-word arithmetic. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20240912024114.1097832-22-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/translate-a64.c | 138 ++++++++++++++++++++------------- 1 file changed, 82 insertions(+), 56 deletions(-) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ static bool do_vec_shift_imm_wide(DisasContext *s, arg_qrri_e *a, bool is_u) TRANS(SSHLL_v, do_vec_shift_imm_wide, a, false) TRANS(USHLL_v, do_vec_shift_imm_wide, a, true) +static void gen_sshr_d(TCGv_i64 dst, TCGv_i64 src, int64_t shift) +{ + assert(shift >= 0 && shift <= 64); + tcg_gen_sari_i64(dst, src, MIN(shift, 63)); +} + +static void gen_ushr_d(TCGv_i64 dst, TCGv_i64 src, int64_t shift) +{ + assert(shift >= 0 && shift <= 64); + if (shift == 64) { + tcg_gen_movi_i64(dst, 0); + } else { + tcg_gen_shri_i64(dst, src, shift); + } +} + +static void gen_srshr_bhs(TCGv_i64 dst, TCGv_i64 src, int64_t shift) +{ + assert(shift >= 0 && shift <= 32); + if (shift) { + TCGv_i64 rnd = tcg_constant_i64(1ull << (shift - 1)); + tcg_gen_add_i64(dst, src, rnd); + tcg_gen_sari_i64(dst, dst, shift); + } else { + tcg_gen_mov_i64(dst, src); + } +} + +static void gen_urshr_bhs(TCGv_i64 dst, TCGv_i64 src, int64_t shift) +{ + assert(shift >= 0 && shift <= 32); + if (shift) { + TCGv_i64 rnd = tcg_constant_i64(1ull << (shift - 1)); + tcg_gen_add_i64(dst, src, rnd); + tcg_gen_shri_i64(dst, dst, shift); + } else { + tcg_gen_mov_i64(dst, src); + } +} + +static void gen_srshr_d(TCGv_i64 dst, TCGv_i64 src, int64_t shift) +{ + assert(shift >= 0 && shift <= 64); + if (shift == 0) { + tcg_gen_mov_i64(dst, src); + } else if (shift == 64) { + /* Extension of sign bit (0,-1) plus sign bit (0,1) is zero. */ + tcg_gen_movi_i64(dst, 0); + } else { + TCGv_i64 rnd = tcg_temp_new_i64(); + tcg_gen_extract_i64(rnd, src, shift - 1, 1); + tcg_gen_sari_i64(dst, src, shift); + tcg_gen_add_i64(dst, dst, rnd); + } +} + +static void gen_urshr_d(TCGv_i64 dst, TCGv_i64 src, int64_t shift) +{ + assert(shift >= 0 && shift <= 64); + if (shift == 0) { + tcg_gen_mov_i64(dst, src); + } else if (shift == 64) { + /* Rounding will propagate bit 63 into bit 64. */ + tcg_gen_shri_i64(dst, src, 63); + } else { + TCGv_i64 rnd = tcg_temp_new_i64(); + tcg_gen_extract_i64(rnd, src, shift - 1, 1); + tcg_gen_shri_i64(dst, src, shift); + tcg_gen_add_i64(dst, dst, rnd); + } +} + /* Shift a TCGv src by TCGv shift_amount, put result in dst. * Note that it is the caller's responsibility to ensure that the * shift amount is in range (ie 0..31 or 0..63) and provide the ARM @@ -XXX,XX +XXX,XX @@ static void handle_shri_with_rndacc(TCGv_i64 tcg_res, TCGv_i64 tcg_src, bool round, bool accumulate, bool is_u, int size, int shift) { - bool extended_result = false; - int ext_lshift = 0; - TCGv_i64 tcg_src_hi; - - if (round && size == 3) { - extended_result = true; - ext_lshift = 64 - shift; - tcg_src_hi = tcg_temp_new_i64(); - } else if (shift == 64) { - if (!accumulate && is_u) { - /* result is zero */ - tcg_gen_movi_i64(tcg_res, 0); - return; - } - } - - /* Deal with the rounding step */ - if (round) { - TCGv_i64 tcg_rnd = tcg_constant_i64(1ull << (shift - 1)); - if (extended_result) { - TCGv_i64 tcg_zero = tcg_constant_i64(0); - if (!is_u) { - /* take care of sign extending tcg_res */ - tcg_gen_sari_i64(tcg_src_hi, tcg_src, 63); - tcg_gen_add2_i64(tcg_src, tcg_src_hi, - tcg_src, tcg_src_hi, - tcg_rnd, tcg_zero); - } else { - tcg_gen_add2_i64(tcg_src, tcg_src_hi, - tcg_src, tcg_zero, - tcg_rnd, tcg_zero); - } + if (!round) { + if (is_u) { + gen_ushr_d(tcg_src, tcg_src, shift); } else { - tcg_gen_add_i64(tcg_src, tcg_src, tcg_rnd); + gen_sshr_d(tcg_src, tcg_src, shift); } - } - - /* Now do the shift right */ - if (round && extended_result) { - /* extended case, >64 bit precision required */ - if (ext_lshift == 0) { - /* special case, only high bits matter */ - tcg_gen_mov_i64(tcg_src, tcg_src_hi); + } else if (size == MO_64) { + if (is_u) { + gen_urshr_d(tcg_src, tcg_src, shift); } else { - tcg_gen_shri_i64(tcg_src, tcg_src, shift); - tcg_gen_shli_i64(tcg_src_hi, tcg_src_hi, ext_lshift); - tcg_gen_or_i64(tcg_src, tcg_src, tcg_src_hi); + gen_srshr_d(tcg_src, tcg_src, shift); } } else { if (is_u) { - if (shift == 64) { - /* essentially shifting in 64 zeros */ - tcg_gen_movi_i64(tcg_src, 0); - } else { - tcg_gen_shri_i64(tcg_src, tcg_src, shift); - } + gen_urshr_bhs(tcg_src, tcg_src, shift); } else { - if (shift == 64) { - /* effectively extending the sign-bit */ - tcg_gen_sari_i64(tcg_src, tcg_src, 63); - } else { - tcg_gen_sari_i64(tcg_src, tcg_src, shift); - } + gen_srshr_bhs(tcg_src, tcg_src, shift); } } -- 2.34.1
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20240912024114.1097832-23-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/a64.decode | 8 +++ target/arm/tcg/translate-a64.c | 95 +++++++++++++++++----------------- 2 files changed, 55 insertions(+), 48 deletions(-) diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -XXX,XX +XXX,XX @@ SSHLL_v 0.00 11110 .... ... 10100 1 ..... ..... @q_shli_s USHLL_v 0.10 11110 .... ... 10100 1 ..... ..... @q_shli_b USHLL_v 0.10 11110 .... ... 10100 1 ..... ..... @q_shli_h USHLL_v 0.10 11110 .... ... 10100 1 ..... ..... @q_shli_s + +SHRN_v 0.00 11110 .... ... 10000 1 ..... ..... @q_shri_b +SHRN_v 0.00 11110 .... ... 10000 1 ..... ..... @q_shri_h +SHRN_v 0.00 11110 .... ... 10000 1 ..... ..... @q_shri_s + +RSHRN_v 0.00 11110 .... ... 10001 1 ..... ..... @q_shri_b +RSHRN_v 0.00 11110 .... ... 10001 1 ..... ..... @q_shri_h +RSHRN_v 0.00 11110 .... ... 10001 1 ..... ..... @q_shri_s diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ static void gen_urshr_d(TCGv_i64 dst, TCGv_i64 src, int64_t shift) } } +static bool do_vec_shift_imm_narrow(DisasContext *s, arg_qrri_e *a, + WideShiftImmFn * const fns[3], MemOp sign) +{ + TCGv_i64 tcg_rn, tcg_rd; + int esz = a->esz; + int esize; + WideShiftImmFn *fn; + + tcg_debug_assert(esz >= MO_8 && esz <= MO_32); + + if (!fp_access_check(s)) { + return true; + } + + tcg_rn = tcg_temp_new_i64(); + tcg_rd = tcg_temp_new_i64(); + tcg_gen_movi_i64(tcg_rd, 0); + + fn = fns[esz]; + esize = 8 << esz; + for (int i = 0, elements = 8 >> esz; i < elements; i++) { + read_vec_element(s, tcg_rn, a->rn, i, (esz + 1) | sign); + fn(tcg_rn, tcg_rn, a->imm); + tcg_gen_deposit_i64(tcg_rd, tcg_rd, tcg_rn, esize * i, esize); + } + + write_vec_element(s, tcg_rd, a->rd, a->q, MO_64); + clear_vec_high(s, a->q, a->rd); + return true; +} + +static WideShiftImmFn * const shrn_fns[] = { + tcg_gen_shri_i64, + tcg_gen_shri_i64, + gen_ushr_d, +}; +TRANS(SHRN_v, do_vec_shift_imm_narrow, a, shrn_fns, 0) + +static WideShiftImmFn * const rshrn_fns[] = { + gen_urshr_bhs, + gen_urshr_bhs, + gen_urshr_d, +}; +TRANS(RSHRN_v, do_vec_shift_imm_narrow, a, rshrn_fns, 0) + /* Shift a TCGv src by TCGv shift_amount, put result in dst. * Note that it is the caller's responsibility to ensure that the * shift amount is in range (ie 0..31 or 0..63) and provide the ARM @@ -XXX,XX +XXX,XX @@ static void disas_simd_scalar_two_reg_misc(DisasContext *s, uint32_t insn) } } -/* SHRN/RSHRN - Shift right with narrowing (and potential rounding) */ -static void handle_vec_simd_shrn(DisasContext *s, bool is_q, - int immh, int immb, int opcode, int rn, int rd) -{ - int immhb = immh << 3 | immb; - int size = 32 - clz32(immh) - 1; - int dsize = 64; - int esize = 8 << size; - int elements = dsize/esize; - int shift = (2 * esize) - immhb; - bool round = extract32(opcode, 0, 1); - TCGv_i64 tcg_rn, tcg_rd, tcg_final; - int i; - - if (extract32(immh, 3, 1)) { - unallocated_encoding(s); - return; - } - - if (!fp_access_check(s)) { - return; - } - - tcg_rn = tcg_temp_new_i64(); - tcg_rd = tcg_temp_new_i64(); - tcg_final = tcg_temp_new_i64(); - read_vec_element(s, tcg_final, rd, is_q ? 1 : 0, MO_64); - - for (i = 0; i < elements; i++) { - read_vec_element(s, tcg_rn, rn, i, size+1); - handle_shri_with_rndacc(tcg_rd, tcg_rn, round, - false, true, size+1, shift); - - tcg_gen_deposit_i64(tcg_final, tcg_final, tcg_rd, esize * i, esize); - } - - if (!is_q) { - write_vec_element(s, tcg_final, rd, 0, MO_64); - } else { - write_vec_element(s, tcg_final, rd, 1, MO_64); - } - - clear_vec_high(s, is_q, rd); -} - - /* AdvSIMD shift by immediate * 31 30 29 28 23 22 19 18 16 15 11 10 9 5 4 0 * +---+---+---+-------------+------+------+--------+---+------+------+ @@ -XXX,XX +XXX,XX @@ static void disas_simd_shift_imm(DisasContext *s, uint32_t insn) } switch (opcode) { - case 0x10: /* SHRN */ + case 0x10: /* SHRN / SQSHRUN */ case 0x11: /* RSHRN / SQRSHRUN */ if (is_u) { handle_vec_simd_sqshrn(s, false, is_q, false, true, immh, immb, opcode, rn, rd); } else { - handle_vec_simd_shrn(s, is_q, immh, immb, opcode, rn, rd); + unallocated_encoding(s); } break; case 0x12: /* SQSHRN / UQSHRN */ -- 2.34.1
From: Richard Henderson <richard.henderson@linaro.org> This includes SSHR, USHR, SSRA, USRA, SRSHR, URSHR, SRSRA, URSRA, SRI. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20240912024114.1097832-24-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/a64.decode | 16 ++++ target/arm/tcg/translate-a64.c | 140 ++++++++++++++++----------------- 2 files changed, 86 insertions(+), 70 deletions(-) diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -XXX,XX +XXX,XX @@ &rri_sf rd rn imm sf &i imm &rr_e rd rn esz +&rri_e rd rn imm esz &rrr_e rd rn rm esz &rrx_e rd rn rm idx esz &rrrr_e rd rn rm ra esz @@ -XXX,XX +XXX,XX @@ SHRN_v 0.00 11110 .... ... 10000 1 ..... ..... @q_shri_s RSHRN_v 0.00 11110 .... ... 10001 1 ..... ..... @q_shri_b RSHRN_v 0.00 11110 .... ... 10001 1 ..... ..... @q_shri_h RSHRN_v 0.00 11110 .... ... 10001 1 ..... ..... @q_shri_s + +# Advanced SIMD scalar shift by immediate + +@shri_d .... ..... 1 ...... ..... . rn:5 rd:5 \ + &rri_e esz=3 imm=%neon_rshift_i6 + +SSHR_s 0101 11110 .... ... 00000 1 ..... ..... @shri_d +USHR_s 0111 11110 .... ... 00000 1 ..... ..... @shri_d +SSRA_s 0101 11110 .... ... 00010 1 ..... ..... @shri_d +USRA_s 0111 11110 .... ... 00010 1 ..... ..... @shri_d +SRSHR_s 0101 11110 .... ... 00100 1 ..... ..... @shri_d +URSHR_s 0111 11110 .... ... 00100 1 ..... ..... @shri_d +SRSRA_s 0101 11110 .... ... 00110 1 ..... ..... @shri_d +URSRA_s 0111 11110 .... ... 00110 1 ..... ..... @shri_d +SRI_s 0111 11110 .... ... 01000 1 ..... ..... @shri_d diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ static void gen_ushr_d(TCGv_i64 dst, TCGv_i64 src, int64_t shift) } } +static void gen_ssra_d(TCGv_i64 dst, TCGv_i64 src, int64_t shift) +{ + gen_sshr_d(src, src, shift); + tcg_gen_add_i64(dst, dst, src); +} + +static void gen_usra_d(TCGv_i64 dst, TCGv_i64 src, int64_t shift) +{ + gen_ushr_d(src, src, shift); + tcg_gen_add_i64(dst, dst, src); +} + static void gen_srshr_bhs(TCGv_i64 dst, TCGv_i64 src, int64_t shift) { assert(shift >= 0 && shift <= 32); @@ -XXX,XX +XXX,XX @@ static void gen_urshr_d(TCGv_i64 dst, TCGv_i64 src, int64_t shift) } } +static void gen_srsra_d(TCGv_i64 dst, TCGv_i64 src, int64_t shift) +{ + gen_srshr_d(src, src, shift); + tcg_gen_add_i64(dst, dst, src); +} + +static void gen_ursra_d(TCGv_i64 dst, TCGv_i64 src, int64_t shift) +{ + gen_urshr_d(src, src, shift); + tcg_gen_add_i64(dst, dst, src); +} + +static void gen_sri_d(TCGv_i64 dst, TCGv_i64 src, int64_t shift) +{ + /* If shift is 64, dst is unchanged. */ + if (shift != 64) { + tcg_gen_shri_i64(src, src, shift); + tcg_gen_deposit_i64(dst, dst, src, 0, 64 - shift); + } +} + static bool do_vec_shift_imm_narrow(DisasContext *s, arg_qrri_e *a, WideShiftImmFn * const fns[3], MemOp sign) { @@ -XXX,XX +XXX,XX @@ static WideShiftImmFn * const rshrn_fns[] = { }; TRANS(RSHRN_v, do_vec_shift_imm_narrow, a, rshrn_fns, 0) +/* + * Advanced SIMD Scalar Shift by Immediate + */ + +static bool do_scalar_shift_imm(DisasContext *s, arg_rri_e *a, + WideShiftImmFn *fn, bool accumulate, + MemOp sign) +{ + if (fp_access_check(s)) { + TCGv_i64 rd = tcg_temp_new_i64(); + TCGv_i64 rn = tcg_temp_new_i64(); + + read_vec_element(s, rn, a->rn, 0, a->esz | sign); + if (accumulate) { + read_vec_element(s, rd, a->rd, 0, a->esz | sign); + } + fn(rd, rn, a->imm); + write_fp_dreg(s, a->rd, rd); + } + return true; +} + +TRANS(SSHR_s, do_scalar_shift_imm, a, gen_sshr_d, false, 0) +TRANS(USHR_s, do_scalar_shift_imm, a, gen_ushr_d, false, 0) +TRANS(SSRA_s, do_scalar_shift_imm, a, gen_ssra_d, true, 0) +TRANS(USRA_s, do_scalar_shift_imm, a, gen_usra_d, true, 0) +TRANS(SRSHR_s, do_scalar_shift_imm, a, gen_srshr_d, false, 0) +TRANS(URSHR_s, do_scalar_shift_imm, a, gen_urshr_d, false, 0) +TRANS(SRSRA_s, do_scalar_shift_imm, a, gen_srsra_d, true, 0) +TRANS(URSRA_s, do_scalar_shift_imm, a, gen_ursra_d, true, 0) +TRANS(SRI_s, do_scalar_shift_imm, a, gen_sri_d, true, 0) + /* Shift a TCGv src by TCGv shift_amount, put result in dst. * Note that it is the caller's responsibility to ensure that the * shift amount is in range (ie 0..31 or 0..63) and provide the ARM @@ -XXX,XX +XXX,XX @@ static void handle_shri_with_rndacc(TCGv_i64 tcg_res, TCGv_i64 tcg_src, } } -/* SSHR[RA]/USHR[RA] - Scalar shift right (optional rounding/accumulate) */ -static void handle_scalar_simd_shri(DisasContext *s, - bool is_u, int immh, int immb, - int opcode, int rn, int rd) -{ - const int size = 3; - int immhb = immh << 3 | immb; - int shift = 2 * (8 << size) - immhb; - bool accumulate = false; - bool round = false; - bool insert = false; - TCGv_i64 tcg_rn; - TCGv_i64 tcg_rd; - - if (!extract32(immh, 3, 1)) { - unallocated_encoding(s); - return; - } - - if (!fp_access_check(s)) { - return; - } - - switch (opcode) { - case 0x02: /* SSRA / USRA (accumulate) */ - accumulate = true; - break; - case 0x04: /* SRSHR / URSHR (rounding) */ - round = true; - break; - case 0x06: /* SRSRA / URSRA (accum + rounding) */ - accumulate = round = true; - break; - case 0x08: /* SRI */ - insert = true; - break; - } - - tcg_rn = read_fp_dreg(s, rn); - tcg_rd = (accumulate || insert) ? read_fp_dreg(s, rd) : tcg_temp_new_i64(); - - if (insert) { - /* shift count same as element size is valid but does nothing; - * special case to avoid potential shift by 64. - */ - int esize = 8 << size; - if (shift != esize) { - tcg_gen_shri_i64(tcg_rn, tcg_rn, shift); - tcg_gen_deposit_i64(tcg_rd, tcg_rd, tcg_rn, 0, esize - shift); - } - } else { - handle_shri_with_rndacc(tcg_rd, tcg_rn, round, - accumulate, is_u, size, shift); - } - - write_fp_dreg(s, rd, tcg_rd); -} - /* SHL/SLI - Scalar shift left */ static void handle_scalar_simd_shli(DisasContext *s, bool insert, int immh, int immb, int opcode, @@ -XXX,XX +XXX,XX @@ static void disas_simd_scalar_shift_imm(DisasContext *s, uint32_t insn) } switch (opcode) { - case 0x08: /* SRI */ - if (!is_u) { - unallocated_encoding(s); - return; - } - /* fall through */ - case 0x00: /* SSHR / USHR */ - case 0x02: /* SSRA / USRA */ - case 0x04: /* SRSHR / URSHR */ - case 0x06: /* SRSRA / URSRA */ - handle_scalar_simd_shri(s, is_u, immh, immb, opcode, rn, rd); - break; case 0x0a: /* SHL / SLI */ handle_scalar_simd_shli(s, is_u, immh, immb, opcode, rn, rd); break; @@ -XXX,XX +XXX,XX @@ static void disas_simd_scalar_shift_imm(DisasContext *s, uint32_t insn) handle_simd_shift_fpint_conv(s, true, false, is_u, immh, immb, rn, rd); break; default: + case 0x00: /* SSHR / USHR */ + case 0x02: /* SSRA / USRA */ + case 0x04: /* SRSHR / URSHR */ + case 0x06: /* SRSRA / URSRA */ + case 0x08: /* SRI */ unallocated_encoding(s); break; } -- 2.34.1
From: Richard Henderson <richard.henderson@linaro.org> This includes SHL and SLI. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20240912024114.1097832-25-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/a64.decode | 4 ++++ target/arm/tcg/translate-a64.c | 44 +++++++--------------------------- 2 files changed, 13 insertions(+), 35 deletions(-) diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -XXX,XX +XXX,XX @@ RSHRN_v 0.00 11110 .... ... 10001 1 ..... ..... @q_shri_s @shri_d .... ..... 1 ...... ..... . rn:5 rd:5 \ &rri_e esz=3 imm=%neon_rshift_i6 +@shli_d .... ..... 1 imm:6 ..... . rn:5 rd:5 &rri_e esz=3 SSHR_s 0101 11110 .... ... 00000 1 ..... ..... @shri_d USHR_s 0111 11110 .... ... 00000 1 ..... ..... @shri_d @@ -XXX,XX +XXX,XX @@ URSHR_s 0111 11110 .... ... 00100 1 ..... ..... @shri_d SRSRA_s 0101 11110 .... ... 00110 1 ..... ..... @shri_d URSRA_s 0111 11110 .... ... 00110 1 ..... ..... @shri_d SRI_s 0111 11110 .... ... 01000 1 ..... ..... @shri_d + +SHL_s 0101 11110 .... ... 01010 1 ..... ..... @shli_d +SLI_s 0111 11110 .... ... 01010 1 ..... ..... @shli_d diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ static void gen_sri_d(TCGv_i64 dst, TCGv_i64 src, int64_t shift) } } +static void gen_sli_d(TCGv_i64 dst, TCGv_i64 src, int64_t shift) +{ + tcg_gen_deposit_i64(dst, dst, src, shift, 64 - shift); +} + static bool do_vec_shift_imm_narrow(DisasContext *s, arg_qrri_e *a, WideShiftImmFn * const fns[3], MemOp sign) { @@ -XXX,XX +XXX,XX @@ TRANS(SRSRA_s, do_scalar_shift_imm, a, gen_srsra_d, true, 0) TRANS(URSRA_s, do_scalar_shift_imm, a, gen_ursra_d, true, 0) TRANS(SRI_s, do_scalar_shift_imm, a, gen_sri_d, true, 0) +TRANS(SHL_s, do_scalar_shift_imm, a, tcg_gen_shli_i64, false, 0) +TRANS(SLI_s, do_scalar_shift_imm, a, gen_sli_d, true, 0) + /* Shift a TCGv src by TCGv shift_amount, put result in dst. * Note that it is the caller's responsibility to ensure that the * shift amount is in range (ie 0..31 or 0..63) and provide the ARM @@ -XXX,XX +XXX,XX @@ static void handle_shri_with_rndacc(TCGv_i64 tcg_res, TCGv_i64 tcg_src, } } -/* SHL/SLI - Scalar shift left */ -static void handle_scalar_simd_shli(DisasContext *s, bool insert, - int immh, int immb, int opcode, - int rn, int rd) -{ - int size = 32 - clz32(immh) - 1; - int immhb = immh << 3 | immb; - int shift = immhb - (8 << size); - TCGv_i64 tcg_rn; - TCGv_i64 tcg_rd; - - if (!extract32(immh, 3, 1)) { - unallocated_encoding(s); - return; - } - - if (!fp_access_check(s)) { - return; - } - - tcg_rn = read_fp_dreg(s, rn); - tcg_rd = insert ? read_fp_dreg(s, rd) : tcg_temp_new_i64(); - - if (insert) { - tcg_gen_deposit_i64(tcg_rd, tcg_rd, tcg_rn, shift, 64 - shift); - } else { - tcg_gen_shli_i64(tcg_rd, tcg_rn, shift); - } - - write_fp_dreg(s, rd, tcg_rd); -} - /* SQSHRN/SQSHRUN - Saturating (signed/unsigned) shift right with * (signed/unsigned) narrowing */ static void handle_vec_simd_sqshrn(DisasContext *s, bool is_scalar, bool is_q, @@ -XXX,XX +XXX,XX @@ static void disas_simd_scalar_shift_imm(DisasContext *s, uint32_t insn) } switch (opcode) { - case 0x0a: /* SHL / SLI */ - handle_scalar_simd_shli(s, is_u, immh, immb, opcode, rn, rd); - break; case 0x1c: /* SCVTF, UCVTF */ handle_simd_shift_intfp_conv(s, true, false, is_u, immh, immb, opcode, rn, rd); @@ -XXX,XX +XXX,XX @@ static void disas_simd_scalar_shift_imm(DisasContext *s, uint32_t insn) case 0x04: /* SRSHR / URSHR */ case 0x06: /* SRSRA / URSRA */ case 0x08: /* SRI */ + case 0x0a: /* SHL / SLI */ unallocated_encoding(s); break; } -- 2.34.1
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20240912024114.1097832-26-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/helper.h | 12 ++++ target/arm/tcg/translate.h | 7 ++ target/arm/tcg/neon-dp.decode | 6 +- target/arm/tcg/gengvec.c | 36 +++++++++++ target/arm/tcg/neon_helper.c | 33 ++++++++++ target/arm/tcg/translate-neon.c | 110 +------------------------------- 6 files changed, 94 insertions(+), 110 deletions(-) diff --git a/target/arm/helper.h b/target/arm/helper.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -XXX,XX +XXX,XX @@ DEF_HELPER_FLAGS_5(neon_uqrshl_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32 DEF_HELPER_FLAGS_5(neon_uqrshl_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_5(neon_uqrshl_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_5(neon_uqrshl_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(neon_sqshli_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(neon_sqshli_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(neon_sqshli_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(neon_sqshli_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(neon_uqshli_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(neon_uqshli_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(neon_uqshli_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(neon_uqshli_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(neon_sqshlui_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(neon_sqshlui_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(neon_sqshlui_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(neon_sqshlui_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(gvec_srshl_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(gvec_srshl_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate.h +++ b/target/arm/tcg/translate.h @@ -XXX,XX +XXX,XX @@ void gen_neon_sqrshl(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, void gen_neon_uqrshl(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz); +void gen_neon_sqshli(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + int64_t c, uint32_t opr_sz, uint32_t max_sz); +void gen_neon_uqshli(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + int64_t c, uint32_t opr_sz, uint32_t max_sz); +void gen_neon_sqshlui(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + int64_t c, uint32_t opr_sz, uint32_t max_sz); + void gen_gvec_shadd(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz); void gen_gvec_uhadd(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, diff --git a/target/arm/tcg/neon-dp.decode b/target/arm/tcg/neon-dp.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/neon-dp.decode +++ b/target/arm/tcg/neon-dp.decode @@ -XXX,XX +XXX,XX @@ VSLI_2sh 1111 001 1 1 . ...... .... 0101 . . . 1 .... @2reg_shl_s VSLI_2sh 1111 001 1 1 . ...... .... 0101 . . . 1 .... @2reg_shl_h VSLI_2sh 1111 001 1 1 . ...... .... 0101 . . . 1 .... @2reg_shl_b -VQSHLU_64_2sh 1111 001 1 1 . ...... .... 0110 . . . 1 .... @2reg_shl_d +VQSHLU_2sh 1111 001 1 1 . ...... .... 0110 . . . 1 .... @2reg_shl_d VQSHLU_2sh 1111 001 1 1 . ...... .... 0110 . . . 1 .... @2reg_shl_s VQSHLU_2sh 1111 001 1 1 . ...... .... 0110 . . . 1 .... @2reg_shl_h VQSHLU_2sh 1111 001 1 1 . ...... .... 0110 . . . 1 .... @2reg_shl_b -VQSHL_S_64_2sh 1111 001 0 1 . ...... .... 0111 . . . 1 .... @2reg_shl_d +VQSHL_S_2sh 1111 001 0 1 . ...... .... 0111 . . . 1 .... @2reg_shl_d VQSHL_S_2sh 1111 001 0 1 . ...... .... 0111 . . . 1 .... @2reg_shl_s VQSHL_S_2sh 1111 001 0 1 . ...... .... 0111 . . . 1 .... @2reg_shl_h VQSHL_S_2sh 1111 001 0 1 . ...... .... 0111 . . . 1 .... @2reg_shl_b -VQSHL_U_64_2sh 1111 001 1 1 . ...... .... 0111 . . . 1 .... @2reg_shl_d +VQSHL_U_2sh 1111 001 1 1 . ...... .... 0111 . . . 1 .... @2reg_shl_d VQSHL_U_2sh 1111 001 1 1 . ...... .... 0111 . . . 1 .... @2reg_shl_s VQSHL_U_2sh 1111 001 1 1 . ...... .... 0111 . . . 1 .... @2reg_shl_h VQSHL_U_2sh 1111 001 1 1 . ...... .... 0111 . . . 1 .... @2reg_shl_b diff --git a/target/arm/tcg/gengvec.c b/target/arm/tcg/gengvec.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/gengvec.c +++ b/target/arm/tcg/gengvec.c @@ -XXX,XX +XXX,XX @@ void gen_neon_uqrshl(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, opr_sz, max_sz, 0, fns[vece]); } +void gen_neon_sqshli(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + int64_t c, uint32_t opr_sz, uint32_t max_sz) +{ + static gen_helper_gvec_2_ptr * const fns[] = { + gen_helper_neon_sqshli_b, gen_helper_neon_sqshli_h, + gen_helper_neon_sqshli_s, gen_helper_neon_sqshli_d, + }; + tcg_debug_assert(vece <= MO_64); + tcg_debug_assert(c >= 0 && c <= (8 << vece)); + tcg_gen_gvec_2_ptr(rd_ofs, rn_ofs, tcg_env, opr_sz, max_sz, c, fns[vece]); +} + +void gen_neon_uqshli(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + int64_t c, uint32_t opr_sz, uint32_t max_sz) +{ + static gen_helper_gvec_2_ptr * const fns[] = { + gen_helper_neon_uqshli_b, gen_helper_neon_uqshli_h, + gen_helper_neon_uqshli_s, gen_helper_neon_uqshli_d, + }; + tcg_debug_assert(vece <= MO_64); + tcg_debug_assert(c >= 0 && c <= (8 << vece)); + tcg_gen_gvec_2_ptr(rd_ofs, rn_ofs, tcg_env, opr_sz, max_sz, c, fns[vece]); +} + +void gen_neon_sqshlui(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + int64_t c, uint32_t opr_sz, uint32_t max_sz) +{ + static gen_helper_gvec_2_ptr * const fns[] = { + gen_helper_neon_sqshlui_b, gen_helper_neon_sqshlui_h, + gen_helper_neon_sqshlui_s, gen_helper_neon_sqshlui_d, + }; + tcg_debug_assert(vece <= MO_64); + tcg_debug_assert(c >= 0 && c <= (8 << vece)); + tcg_gen_gvec_2_ptr(rd_ofs, rn_ofs, tcg_env, opr_sz, max_sz, c, fns[vece]); +} + void gen_uqadd_bhs(TCGv_i64 res, TCGv_i64 qc, TCGv_i64 a, TCGv_i64 b, MemOp esz) { uint64_t max = MAKE_64BIT_MASK(0, 8 << esz); diff --git a/target/arm/tcg/neon_helper.c b/target/arm/tcg/neon_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/neon_helper.c +++ b/target/arm/tcg/neon_helper.c @@ -XXX,XX +XXX,XX @@ void HELPER(name)(void *vd, void *vn, void *vm, void *venv, uint32_t desc) \ clear_tail(d, opr_sz, simd_maxsz(desc)); \ } +#define NEON_GVEC_VOP2i_ENV(name, vtype) \ +void HELPER(name)(void *vd, void *vn, void *venv, uint32_t desc) \ +{ \ + intptr_t i, opr_sz = simd_oprsz(desc); \ + int imm = simd_data(desc); \ + vtype *d = vd, *n = vn; \ + CPUARMState *env = venv; \ + for (i = 0; i < opr_sz / sizeof(vtype); i++) { \ + NEON_FN(d[i], n[i], imm); \ + } \ + clear_tail(d, opr_sz, simd_maxsz(desc)); \ +} + /* Pairwise operations. */ /* For 32-bit elements each segment only contains a single element, so the elementwise and pairwise operations are the same. */ @@ -XXX,XX +XXX,XX @@ uint64_t HELPER(neon_rshl_u64)(uint64_t val, uint64_t shift) (dest = do_uqrshl_bhs(src1, (int8_t)src2, 8, false, env->vfp.qc)) NEON_VOP_ENV(qshl_u8, neon_u8, 4) NEON_GVEC_VOP2_ENV(neon_uqshl_b, uint8_t) +NEON_GVEC_VOP2i_ENV(neon_uqshli_b, uint8_t) #undef NEON_FN #define NEON_FN(dest, src1, src2) \ (dest = do_uqrshl_bhs(src1, (int8_t)src2, 16, false, env->vfp.qc)) NEON_VOP_ENV(qshl_u16, neon_u16, 2) NEON_GVEC_VOP2_ENV(neon_uqshl_h, uint16_t) +NEON_GVEC_VOP2i_ENV(neon_uqshli_h, uint16_t) #undef NEON_FN #define NEON_FN(dest, src1, src2) \ (dest = do_uqrshl_bhs(src1, (int8_t)src2, 32, false, env->vfp.qc)) NEON_GVEC_VOP2_ENV(neon_uqshl_s, uint32_t) +NEON_GVEC_VOP2i_ENV(neon_uqshli_s, uint32_t) #undef NEON_FN #define NEON_FN(dest, src1, src2) \ (dest = do_uqrshl_d(src1, (int8_t)src2, false, env->vfp.qc)) NEON_GVEC_VOP2_ENV(neon_uqshl_d, uint64_t) +NEON_GVEC_VOP2i_ENV(neon_uqshli_d, uint64_t) #undef NEON_FN uint32_t HELPER(neon_qshl_u32)(CPUARMState *env, uint32_t val, uint32_t shift) @@ -XXX,XX +XXX,XX @@ uint64_t HELPER(neon_qshl_u64)(CPUARMState *env, uint64_t val, uint64_t shift) (dest = do_sqrshl_bhs(src1, (int8_t)src2, 8, false, env->vfp.qc)) NEON_VOP_ENV(qshl_s8, neon_s8, 4) NEON_GVEC_VOP2_ENV(neon_sqshl_b, int8_t) +NEON_GVEC_VOP2i_ENV(neon_sqshli_b, int8_t) #undef NEON_FN #define NEON_FN(dest, src1, src2) \ (dest = do_sqrshl_bhs(src1, (int8_t)src2, 16, false, env->vfp.qc)) NEON_VOP_ENV(qshl_s16, neon_s16, 2) NEON_GVEC_VOP2_ENV(neon_sqshl_h, int16_t) +NEON_GVEC_VOP2i_ENV(neon_sqshli_h, int16_t) #undef NEON_FN #define NEON_FN(dest, src1, src2) \ (dest = do_sqrshl_bhs(src1, (int8_t)src2, 32, false, env->vfp.qc)) NEON_GVEC_VOP2_ENV(neon_sqshl_s, int32_t) +NEON_GVEC_VOP2i_ENV(neon_sqshli_s, int32_t) #undef NEON_FN #define NEON_FN(dest, src1, src2) \ (dest = do_sqrshl_d(src1, (int8_t)src2, false, env->vfp.qc)) NEON_GVEC_VOP2_ENV(neon_sqshl_d, int64_t) +NEON_GVEC_VOP2i_ENV(neon_sqshli_d, int64_t) #undef NEON_FN uint32_t HELPER(neon_qshl_s32)(CPUARMState *env, uint32_t val, uint32_t shift) @@ -XXX,XX +XXX,XX @@ uint64_t HELPER(neon_qshl_s64)(CPUARMState *env, uint64_t val, uint64_t shift) #define NEON_FN(dest, src1, src2) \ (dest = do_suqrshl_bhs(src1, (int8_t)src2, 8, false, env->vfp.qc)) NEON_VOP_ENV(qshlu_s8, neon_s8, 4) +NEON_GVEC_VOP2i_ENV(neon_sqshlui_b, int8_t) #undef NEON_FN #define NEON_FN(dest, src1, src2) \ (dest = do_suqrshl_bhs(src1, (int8_t)src2, 16, false, env->vfp.qc)) NEON_VOP_ENV(qshlu_s16, neon_s16, 2) +NEON_GVEC_VOP2i_ENV(neon_sqshlui_h, int16_t) #undef NEON_FN uint32_t HELPER(neon_qshlu_s32)(CPUARMState *env, uint32_t val, uint32_t shift) @@ -XXX,XX +XXX,XX @@ uint64_t HELPER(neon_qshlu_s64)(CPUARMState *env, uint64_t val, uint64_t shift) return do_suqrshl_d(val, (int8_t)shift, false, env->vfp.qc); } +#define NEON_FN(dest, src1, src2) \ + (dest = do_suqrshl_bhs(src1, (int8_t)src2, 32, false, env->vfp.qc)) +NEON_GVEC_VOP2i_ENV(neon_sqshlui_s, int32_t) +#undef NEON_FN + +#define NEON_FN(dest, src1, src2) \ + (dest = do_suqrshl_d(src1, (int8_t)src2, false, env->vfp.qc)) +NEON_GVEC_VOP2i_ENV(neon_sqshlui_d, int64_t) +#undef NEON_FN + #define NEON_FN(dest, src1, src2) \ (dest = do_uqrshl_bhs(src1, (int8_t)src2, 8, true, env->vfp.qc)) NEON_VOP_ENV(qrshl_u8, neon_u8, 4) diff --git a/target/arm/tcg/translate-neon.c b/target/arm/tcg/translate-neon.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-neon.c +++ b/target/arm/tcg/translate-neon.c @@ -XXX,XX +XXX,XX @@ DO_2SH(VRSRA_S, gen_gvec_srsra) DO_2SH(VRSRA_U, gen_gvec_ursra) DO_2SH(VSHR_S, gen_gvec_sshr) DO_2SH(VSHR_U, gen_gvec_ushr) - -static bool do_2shift_env_64(DisasContext *s, arg_2reg_shift *a, - NeonGenTwo64OpEnvFn *fn) -{ - /* - * 2-reg-and-shift operations, size == 3 case, where the - * function needs to be passed tcg_env. - */ - TCGv_i64 constimm; - int pass; - - if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { - return false; - } - - /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && - ((a->vd | a->vm) & 0x10)) { - return false; - } - - if ((a->vm | a->vd) & a->q) { - return false; - } - - if (!vfp_access_check(s)) { - return true; - } - - /* - * To avoid excessive duplication of ops we implement shift - * by immediate using the variable shift operations. - */ - constimm = tcg_constant_i64(dup_const(a->size, a->shift)); - - for (pass = 0; pass < a->q + 1; pass++) { - TCGv_i64 tmp = tcg_temp_new_i64(); - - read_neon_element64(tmp, a->vm, pass, MO_64); - fn(tmp, tcg_env, tmp, constimm); - write_neon_element64(tmp, a->vd, pass, MO_64); - } - return true; -} - -static bool do_2shift_env_32(DisasContext *s, arg_2reg_shift *a, - NeonGenTwoOpEnvFn *fn) -{ - /* - * 2-reg-and-shift operations, size < 3 case, where the - * helper needs to be passed tcg_env. - */ - TCGv_i32 constimm, tmp; - int pass; - - if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { - return false; - } - - /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && - ((a->vd | a->vm) & 0x10)) { - return false; - } - - if ((a->vm | a->vd) & a->q) { - return false; - } - - if (!vfp_access_check(s)) { - return true; - } - - /* - * To avoid excessive duplication of ops we implement shift - * by immediate using the variable shift operations. - */ - constimm = tcg_constant_i32(dup_const(a->size, a->shift)); - tmp = tcg_temp_new_i32(); - - for (pass = 0; pass < (a->q ? 4 : 2); pass++) { - read_neon_element32(tmp, a->vm, pass, MO_32); - fn(tmp, tcg_env, tmp, constimm); - write_neon_element32(tmp, a->vd, pass, MO_32); - } - return true; -} - -#define DO_2SHIFT_ENV(INSN, FUNC) \ - static bool trans_##INSN##_64_2sh(DisasContext *s, arg_2reg_shift *a) \ - { \ - return do_2shift_env_64(s, a, gen_helper_neon_##FUNC##64); \ - } \ - static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \ - { \ - static NeonGenTwoOpEnvFn * const fns[] = { \ - gen_helper_neon_##FUNC##8, \ - gen_helper_neon_##FUNC##16, \ - gen_helper_neon_##FUNC##32, \ - }; \ - assert(a->size < ARRAY_SIZE(fns)); \ - return do_2shift_env_32(s, a, fns[a->size]); \ - } - -DO_2SHIFT_ENV(VQSHLU, qshlu_s) -DO_2SHIFT_ENV(VQSHL_U, qshl_u) -DO_2SHIFT_ENV(VQSHL_S, qshl_s) +DO_2SH(VQSHLU, gen_neon_sqshlui) +DO_2SH(VQSHL_U, gen_neon_uqshli) +DO_2SH(VQSHL_S, gen_neon_sqshli) static bool do_2shift_narrow_64(DisasContext *s, arg_2reg_shift *a, NeonGenTwo64OpFn *shiftfn, -- 2.34.1
From: Richard Henderson <richard.henderson@linaro.org> While these functions really do return a 32-bit value, widening the return type means that we need do less marshalling between TCG types. Remove NeonGenNarrowEnvFn typedef; add NeonGenOne64OpEnvFn. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 20240912024114.1097832-27-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/helper.h | 22 ++++++------ target/arm/tcg/translate.h | 2 +- target/arm/tcg/neon_helper.c | 43 ++++++++++++++--------- target/arm/tcg/translate-a64.c | 60 ++++++++++++++++++--------------- target/arm/tcg/translate-neon.c | 44 ++++++++++++------------ 5 files changed, 93 insertions(+), 78 deletions(-) diff --git a/target/arm/helper.h b/target/arm/helper.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -XXX,XX +XXX,XX @@ DEF_HELPER_3(neon_qrdmulh_s32, i32, env, i32, i32) DEF_HELPER_4(neon_qrdmlah_s32, i32, env, s32, s32, s32) DEF_HELPER_4(neon_qrdmlsh_s32, i32, env, s32, s32, s32) -DEF_HELPER_1(neon_narrow_u8, i32, i64) -DEF_HELPER_1(neon_narrow_u16, i32, i64) -DEF_HELPER_2(neon_unarrow_sat8, i32, env, i64) -DEF_HELPER_2(neon_narrow_sat_u8, i32, env, i64) -DEF_HELPER_2(neon_narrow_sat_s8, i32, env, i64) -DEF_HELPER_2(neon_unarrow_sat16, i32, env, i64) -DEF_HELPER_2(neon_narrow_sat_u16, i32, env, i64) -DEF_HELPER_2(neon_narrow_sat_s16, i32, env, i64) -DEF_HELPER_2(neon_unarrow_sat32, i32, env, i64) -DEF_HELPER_2(neon_narrow_sat_u32, i32, env, i64) -DEF_HELPER_2(neon_narrow_sat_s32, i32, env, i64) +DEF_HELPER_1(neon_narrow_u8, i64, i64) +DEF_HELPER_1(neon_narrow_u16, i64, i64) +DEF_HELPER_2(neon_unarrow_sat8, i64, env, i64) +DEF_HELPER_2(neon_narrow_sat_u8, i64, env, i64) +DEF_HELPER_2(neon_narrow_sat_s8, i64, env, i64) +DEF_HELPER_2(neon_unarrow_sat16, i64, env, i64) +DEF_HELPER_2(neon_narrow_sat_u16, i64, env, i64) +DEF_HELPER_2(neon_narrow_sat_s16, i64, env, i64) +DEF_HELPER_2(neon_unarrow_sat32, i64, env, i64) +DEF_HELPER_2(neon_narrow_sat_u32, i64, env, i64) +DEF_HELPER_2(neon_narrow_sat_s32, i64, env, i64) DEF_HELPER_1(neon_narrow_high_u8, i32, i64) DEF_HELPER_1(neon_narrow_high_u16, i32, i64) DEF_HELPER_1(neon_narrow_round_high_u8, i32, i64) diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate.h +++ b/target/arm/tcg/translate.h @@ -XXX,XX +XXX,XX @@ typedef void NeonGenThreeOpEnvFn(TCGv_i32, TCGv_env, TCGv_i32, typedef void NeonGenTwo64OpFn(TCGv_i64, TCGv_i64, TCGv_i64); typedef void NeonGenTwo64OpEnvFn(TCGv_i64, TCGv_ptr, TCGv_i64, TCGv_i64); typedef void NeonGenNarrowFn(TCGv_i32, TCGv_i64); -typedef void NeonGenNarrowEnvFn(TCGv_i32, TCGv_ptr, TCGv_i64); typedef void NeonGenWidenFn(TCGv_i64, TCGv_i32); typedef void NeonGenTwoOpWidenFn(TCGv_i64, TCGv_i32, TCGv_i32); typedef void NeonGenOneSingleOpFn(TCGv_i32, TCGv_i32, TCGv_ptr); typedef void NeonGenTwoSingleOpFn(TCGv_i32, TCGv_i32, TCGv_i32, TCGv_ptr); typedef void NeonGenTwoDoubleOpFn(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_ptr); typedef void NeonGenOne64OpFn(TCGv_i64, TCGv_i64); +typedef void NeonGenOne64OpEnvFn(TCGv_i64, TCGv_env, TCGv_i64); typedef void CryptoTwoOpFn(TCGv_ptr, TCGv_ptr); typedef void CryptoThreeOpIntFn(TCGv_ptr, TCGv_ptr, TCGv_i32); typedef void CryptoThreeOpFn(TCGv_ptr, TCGv_ptr, TCGv_ptr); diff --git a/target/arm/tcg/neon_helper.c b/target/arm/tcg/neon_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/neon_helper.c +++ b/target/arm/tcg/neon_helper.c @@ -XXX,XX +XXX,XX @@ NEON_VOP_ENV(qrdmulh_s32, neon_s32, 1) #undef NEON_FN #undef NEON_QDMULH32 -uint32_t HELPER(neon_narrow_u8)(uint64_t x) +/* Only the low 32-bits of output are significant. */ +uint64_t HELPER(neon_narrow_u8)(uint64_t x) { return (x & 0xffu) | ((x >> 8) & 0xff00u) | ((x >> 16) & 0xff0000u) | ((x >> 24) & 0xff000000u); } -uint32_t HELPER(neon_narrow_u16)(uint64_t x) +/* Only the low 32-bits of output are significant. */ +uint64_t HELPER(neon_narrow_u16)(uint64_t x) { return (x & 0xffffu) | ((x >> 16) & 0xffff0000u); } @@ -XXX,XX +XXX,XX @@ uint32_t HELPER(neon_narrow_round_high_u16)(uint64_t x) return ((x >> 16) & 0xffff) | ((x >> 32) & 0xffff0000); } -uint32_t HELPER(neon_unarrow_sat8)(CPUARMState *env, uint64_t x) +/* Only the low 32-bits of output are significant. */ +uint64_t HELPER(neon_unarrow_sat8)(CPUARMState *env, uint64_t x) { uint16_t s; uint8_t d; @@ -XXX,XX +XXX,XX @@ uint32_t HELPER(neon_unarrow_sat8)(CPUARMState *env, uint64_t x) return res; } -uint32_t HELPER(neon_narrow_sat_u8)(CPUARMState *env, uint64_t x) +/* Only the low 32-bits of output are significant. */ +uint64_t HELPER(neon_narrow_sat_u8)(CPUARMState *env, uint64_t x) { uint16_t s; uint8_t d; @@ -XXX,XX +XXX,XX @@ uint32_t HELPER(neon_narrow_sat_u8)(CPUARMState *env, uint64_t x) return res; } -uint32_t HELPER(neon_narrow_sat_s8)(CPUARMState *env, uint64_t x) +/* Only the low 32-bits of output are significant. */ +uint64_t HELPER(neon_narrow_sat_s8)(CPUARMState *env, uint64_t x) { int16_t s; uint8_t d; @@ -XXX,XX +XXX,XX @@ uint32_t HELPER(neon_narrow_sat_s8)(CPUARMState *env, uint64_t x) return res; } -uint32_t HELPER(neon_unarrow_sat16)(CPUARMState *env, uint64_t x) +/* Only the low 32-bits of output are significant. */ +uint64_t HELPER(neon_unarrow_sat16)(CPUARMState *env, uint64_t x) { uint32_t high; uint32_t low; @@ -XXX,XX +XXX,XX @@ uint32_t HELPER(neon_unarrow_sat16)(CPUARMState *env, uint64_t x) high = 0xffff; SET_QC(); } - return low | (high << 16); + return deposit32(low, 16, 16, high); } -uint32_t HELPER(neon_narrow_sat_u16)(CPUARMState *env, uint64_t x) +/* Only the low 32-bits of output are significant. */ +uint64_t HELPER(neon_narrow_sat_u16)(CPUARMState *env, uint64_t x) { uint32_t high; uint32_t low; @@ -XXX,XX +XXX,XX @@ uint32_t HELPER(neon_narrow_sat_u16)(CPUARMState *env, uint64_t x) high = 0xffff; SET_QC(); } - return low | (high << 16); + return deposit32(low, 16, 16, high); } -uint32_t HELPER(neon_narrow_sat_s16)(CPUARMState *env, uint64_t x) +/* Only the low 32-bits of output are significant. */ +uint64_t HELPER(neon_narrow_sat_s16)(CPUARMState *env, uint64_t x) { int32_t low; int32_t high; @@ -XXX,XX +XXX,XX @@ uint32_t HELPER(neon_narrow_sat_s16)(CPUARMState *env, uint64_t x) high = (high >> 31) ^ 0x7fff; SET_QC(); } - return (uint16_t)low | (high << 16); + return deposit32(low, 16, 16, high); } -uint32_t HELPER(neon_unarrow_sat32)(CPUARMState *env, uint64_t x) +/* Only the low 32-bits of output are significant. */ +uint64_t HELPER(neon_unarrow_sat32)(CPUARMState *env, uint64_t x) { if (x & 0x8000000000000000ull) { SET_QC(); @@ -XXX,XX +XXX,XX @@ uint32_t HELPER(neon_unarrow_sat32)(CPUARMState *env, uint64_t x) return x; } -uint32_t HELPER(neon_narrow_sat_u32)(CPUARMState *env, uint64_t x) +/* Only the low 32-bits of output are significant. */ +uint64_t HELPER(neon_narrow_sat_u32)(CPUARMState *env, uint64_t x) { if (x > 0xffffffffu) { SET_QC(); @@ -XXX,XX +XXX,XX @@ uint32_t HELPER(neon_narrow_sat_u32)(CPUARMState *env, uint64_t x) return x; } -uint32_t HELPER(neon_narrow_sat_s32)(CPUARMState *env, uint64_t x) +/* Only the low 32-bits of output are significant. */ +uint64_t HELPER(neon_narrow_sat_s32)(CPUARMState *env, uint64_t x) { if ((int64_t)x != (int32_t)x) { SET_QC(); - return ((int64_t)x >> 63) ^ 0x7fffffff; + return (uint32_t)((int64_t)x >> 63) ^ 0x7fffffff; } - return x; + return (uint32_t)x; } uint64_t HELPER(neon_widen_u8)(uint32_t x) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ static void handle_vec_simd_sqshrn(DisasContext *s, bool is_scalar, bool is_q, int elements = is_scalar ? 1 : (64 / esize); bool round = extract32(opcode, 0, 1); MemOp ldop = (size + 1) | (is_u_shift ? 0 : MO_SIGN); - TCGv_i64 tcg_rn, tcg_rd; - TCGv_i32 tcg_rd_narrowed; - TCGv_i64 tcg_final; + TCGv_i64 tcg_rn, tcg_rd, tcg_final; - static NeonGenNarrowEnvFn * const signed_narrow_fns[4][2] = { + static NeonGenOne64OpEnvFn * const signed_narrow_fns[4][2] = { { gen_helper_neon_narrow_sat_s8, gen_helper_neon_unarrow_sat8 }, { gen_helper_neon_narrow_sat_s16, @@ -XXX,XX +XXX,XX @@ static void handle_vec_simd_sqshrn(DisasContext *s, bool is_scalar, bool is_q, gen_helper_neon_unarrow_sat32 }, { NULL, NULL }, }; - static NeonGenNarrowEnvFn * const unsigned_narrow_fns[4] = { + static NeonGenOne64OpEnvFn * const unsigned_narrow_fns[4] = { gen_helper_neon_narrow_sat_u8, gen_helper_neon_narrow_sat_u16, gen_helper_neon_narrow_sat_u32, NULL }; - NeonGenNarrowEnvFn *narrowfn; + NeonGenOne64OpEnvFn *narrowfn; int i; @@ -XXX,XX +XXX,XX @@ static void handle_vec_simd_sqshrn(DisasContext *s, bool is_scalar, bool is_q, tcg_rn = tcg_temp_new_i64(); tcg_rd = tcg_temp_new_i64(); - tcg_rd_narrowed = tcg_temp_new_i32(); tcg_final = tcg_temp_new_i64(); for (i = 0; i < elements; i++) { read_vec_element(s, tcg_rn, rn, i, ldop); handle_shri_with_rndacc(tcg_rd, tcg_rn, round, false, is_u_shift, size+1, shift); - narrowfn(tcg_rd_narrowed, tcg_env, tcg_rd); - tcg_gen_extu_i32_i64(tcg_rd, tcg_rd_narrowed); + narrowfn(tcg_rd, tcg_env, tcg_rd); if (i == 0) { tcg_gen_extract_i64(tcg_final, tcg_rd, 0, esize); } else { @@ -XXX,XX +XXX,XX @@ static void handle_2misc_narrow(DisasContext *s, bool scalar, * in the source becomes a size element in the destination). */ int pass; - TCGv_i32 tcg_res[2]; + TCGv_i64 tcg_res[2]; int destelt = is_q ? 2 : 0; int passes = scalar ? 1 : 2; if (scalar) { - tcg_res[1] = tcg_constant_i32(0); + tcg_res[1] = tcg_constant_i64(0); } for (pass = 0; pass < passes; pass++) { TCGv_i64 tcg_op = tcg_temp_new_i64(); - NeonGenNarrowFn *genfn = NULL; - NeonGenNarrowEnvFn *genenvfn = NULL; + NeonGenOne64OpFn *genfn = NULL; + NeonGenOne64OpEnvFn *genenvfn = NULL; if (scalar) { read_vec_element(s, tcg_op, rn, pass, size + 1); } else { read_vec_element(s, tcg_op, rn, pass, MO_64); } - tcg_res[pass] = tcg_temp_new_i32(); + tcg_res[pass] = tcg_temp_new_i64(); switch (opcode) { case 0x12: /* XTN, SQXTUN */ { - static NeonGenNarrowFn * const xtnfns[3] = { + static NeonGenOne64OpFn * const xtnfns[3] = { gen_helper_neon_narrow_u8, gen_helper_neon_narrow_u16, - tcg_gen_extrl_i64_i32, + tcg_gen_ext32u_i64, }; - static NeonGenNarrowEnvFn * const sqxtunfns[3] = { + static NeonGenOne64OpEnvFn * const sqxtunfns[3] = { gen_helper_neon_unarrow_sat8, gen_helper_neon_unarrow_sat16, gen_helper_neon_unarrow_sat32, @@ -XXX,XX +XXX,XX @@ static void handle_2misc_narrow(DisasContext *s, bool scalar, } case 0x14: /* SQXTN, UQXTN */ { - static NeonGenNarrowEnvFn * const fns[3][2] = { + static NeonGenOne64OpEnvFn * const fns[3][2] = { { gen_helper_neon_narrow_sat_s8, gen_helper_neon_narrow_sat_u8 }, { gen_helper_neon_narrow_sat_s16, @@ -XXX,XX +XXX,XX @@ static void handle_2misc_narrow(DisasContext *s, bool scalar, case 0x16: /* FCVTN, FCVTN2 */ /* 32 bit to 16 bit or 64 bit to 32 bit float conversion */ if (size == 2) { - gen_helper_vfp_fcvtsd(tcg_res[pass], tcg_op, tcg_env); + TCGv_i32 tmp = tcg_temp_new_i32(); + gen_helper_vfp_fcvtsd(tmp, tcg_op, tcg_env); + tcg_gen_extu_i32_i64(tcg_res[pass], tmp); } else { TCGv_i32 tcg_lo = tcg_temp_new_i32(); TCGv_i32 tcg_hi = tcg_temp_new_i32(); @@ -XXX,XX +XXX,XX @@ static void handle_2misc_narrow(DisasContext *s, bool scalar, tcg_gen_extr_i64_i32(tcg_lo, tcg_hi, tcg_op); gen_helper_vfp_fcvt_f32_to_f16(tcg_lo, tcg_lo, fpst, ahp); gen_helper_vfp_fcvt_f32_to_f16(tcg_hi, tcg_hi, fpst, ahp); - tcg_gen_deposit_i32(tcg_res[pass], tcg_lo, tcg_hi, 16, 16); + tcg_gen_deposit_i32(tcg_lo, tcg_lo, tcg_hi, 16, 16); + tcg_gen_extu_i32_i64(tcg_res[pass], tcg_lo); } break; case 0x36: /* BFCVTN, BFCVTN2 */ { TCGv_ptr fpst = fpstatus_ptr(FPST_FPCR); - gen_helper_bfcvt_pair(tcg_res[pass], tcg_op, fpst); + TCGv_i32 tmp = tcg_temp_new_i32(); + gen_helper_bfcvt_pair(tmp, tcg_op, fpst); + tcg_gen_extu_i32_i64(tcg_res[pass], tmp); } break; case 0x56: /* FCVTXN, FCVTXN2 */ - /* 64 bit to 32 bit float conversion - * with von Neumann rounding (round to odd) - */ - assert(size == 2); - gen_helper_fcvtx_f64_to_f32(tcg_res[pass], tcg_op, tcg_env); + { + /* + * 64 bit to 32 bit float conversion + * with von Neumann rounding (round to odd) + */ + TCGv_i32 tmp = tcg_temp_new_i32(); + assert(size == 2); + gen_helper_fcvtx_f64_to_f32(tmp, tcg_op, tcg_env); + tcg_gen_extu_i32_i64(tcg_res[pass], tmp); + } break; default: g_assert_not_reached(); @@ -XXX,XX +XXX,XX @@ static void handle_2misc_narrow(DisasContext *s, bool scalar, } for (pass = 0; pass < 2; pass++) { - write_vec_element_i32(s, tcg_res[pass], rd, destelt + pass, MO_32); + write_vec_element(s, tcg_res[pass], rd, destelt + pass, MO_32); } clear_vec_high(s, is_q, rd); } diff --git a/target/arm/tcg/translate-neon.c b/target/arm/tcg/translate-neon.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-neon.c +++ b/target/arm/tcg/translate-neon.c @@ -XXX,XX +XXX,XX @@ DO_2SH(VQSHL_S, gen_neon_sqshli) static bool do_2shift_narrow_64(DisasContext *s, arg_2reg_shift *a, NeonGenTwo64OpFn *shiftfn, - NeonGenNarrowEnvFn *narrowfn) + NeonGenOne64OpEnvFn *narrowfn) { /* 2-reg-and-shift narrowing-shift operations, size == 3 case */ - TCGv_i64 constimm, rm1, rm2; - TCGv_i32 rd; + TCGv_i64 constimm, rm1, rm2, rd; if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { return false; @@ -XXX,XX +XXX,XX @@ static bool do_2shift_narrow_64(DisasContext *s, arg_2reg_shift *a, constimm = tcg_constant_i64(-a->shift); rm1 = tcg_temp_new_i64(); rm2 = tcg_temp_new_i64(); - rd = tcg_temp_new_i32(); + rd = tcg_temp_new_i64(); /* Load both inputs first to avoid potential overwrite if rm == rd */ read_neon_element64(rm1, a->vm, 0, MO_64); @@ -XXX,XX +XXX,XX @@ static bool do_2shift_narrow_64(DisasContext *s, arg_2reg_shift *a, shiftfn(rm1, rm1, constimm); narrowfn(rd, tcg_env, rm1); - write_neon_element32(rd, a->vd, 0, MO_32); + write_neon_element64(rd, a->vd, 0, MO_32); shiftfn(rm2, rm2, constimm); narrowfn(rd, tcg_env, rm2); - write_neon_element32(rd, a->vd, 1, MO_32); + write_neon_element64(rd, a->vd, 1, MO_32); return true; } static bool do_2shift_narrow_32(DisasContext *s, arg_2reg_shift *a, NeonGenTwoOpFn *shiftfn, - NeonGenNarrowEnvFn *narrowfn) + NeonGenOne64OpEnvFn *narrowfn) { /* 2-reg-and-shift narrowing-shift operations, size < 3 case */ TCGv_i32 constimm, rm1, rm2, rm3, rm4; @@ -XXX,XX +XXX,XX @@ static bool do_2shift_narrow_32(DisasContext *s, arg_2reg_shift *a, tcg_gen_concat_i32_i64(rtmp, rm1, rm2); - narrowfn(rm1, tcg_env, rtmp); - write_neon_element32(rm1, a->vd, 0, MO_32); + narrowfn(rtmp, tcg_env, rtmp); + write_neon_element64(rtmp, a->vd, 0, MO_32); shiftfn(rm3, rm3, constimm); shiftfn(rm4, rm4, constimm); tcg_gen_concat_i32_i64(rtmp, rm3, rm4); - narrowfn(rm3, tcg_env, rtmp); - write_neon_element32(rm3, a->vd, 1, MO_32); + narrowfn(rtmp, tcg_env, rtmp); + write_neon_element64(rtmp, a->vd, 1, MO_32); return true; } @@ -XXX,XX +XXX,XX @@ static bool do_2shift_narrow_32(DisasContext *s, arg_2reg_shift *a, return do_2shift_narrow_32(s, a, FUNC, NARROWFUNC); \ } -static void gen_neon_narrow_u32(TCGv_i32 dest, TCGv_ptr env, TCGv_i64 src) +static void gen_neon_narrow_u32(TCGv_i64 dest, TCGv_ptr env, TCGv_i64 src) { - tcg_gen_extrl_i64_i32(dest, src); + tcg_gen_ext32u_i64(dest, src); } -static void gen_neon_narrow_u16(TCGv_i32 dest, TCGv_ptr env, TCGv_i64 src) +static void gen_neon_narrow_u16(TCGv_i64 dest, TCGv_ptr env, TCGv_i64 src) { gen_helper_neon_narrow_u16(dest, src); } -static void gen_neon_narrow_u8(TCGv_i32 dest, TCGv_ptr env, TCGv_i64 src) +static void gen_neon_narrow_u8(TCGv_i64 dest, TCGv_ptr env, TCGv_i64 src) { gen_helper_neon_narrow_u8(dest, src); } @@ -XXX,XX +XXX,XX @@ static bool trans_VZIP(DisasContext *s, arg_2misc *a) } static bool do_vmovn(DisasContext *s, arg_2misc *a, - NeonGenNarrowEnvFn *narrowfn) + NeonGenOne64OpEnvFn *narrowfn) { - TCGv_i64 rm; - TCGv_i32 rd0, rd1; + TCGv_i64 rm, rd0, rd1; if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { return false; @@ -XXX,XX +XXX,XX @@ static bool do_vmovn(DisasContext *s, arg_2misc *a, } rm = tcg_temp_new_i64(); - rd0 = tcg_temp_new_i32(); - rd1 = tcg_temp_new_i32(); + rd0 = tcg_temp_new_i64(); + rd1 = tcg_temp_new_i64(); read_neon_element64(rm, a->vm, 0, MO_64); narrowfn(rd0, tcg_env, rm); read_neon_element64(rm, a->vm, 1, MO_64); narrowfn(rd1, tcg_env, rm); - write_neon_element32(rd0, a->vd, 0, MO_32); - write_neon_element32(rd1, a->vd, 1, MO_32); + write_neon_element64(rd0, a->vd, 0, MO_32); + write_neon_element64(rd1, a->vd, 1, MO_32); return true; } #define DO_VMOVN(INSN, FUNC) \ static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ { \ - static NeonGenNarrowEnvFn * const narrowfn[] = { \ + static NeonGenOne64OpEnvFn * const narrowfn[] = { \ FUNC##8, \ FUNC##16, \ FUNC##32, \ -- 2.34.1
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20240912024114.1097832-28-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/a64.decode | 36 +++++- target/arm/tcg/translate-a64.c | 223 ++++++++++++++------------------- 2 files changed, 128 insertions(+), 131 deletions(-) diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -XXX,XX +XXX,XX @@ RSHRN_v 0.00 11110 .... ... 10001 1 ..... ..... @q_shri_b RSHRN_v 0.00 11110 .... ... 10001 1 ..... ..... @q_shri_h RSHRN_v 0.00 11110 .... ... 10001 1 ..... ..... @q_shri_s +SQSHL_vi 0.00 11110 .... ... 01110 1 ..... ..... @q_shli_b +SQSHL_vi 0.00 11110 .... ... 01110 1 ..... ..... @q_shli_h +SQSHL_vi 0.00 11110 .... ... 01110 1 ..... ..... @q_shli_s +SQSHL_vi 0.00 11110 .... ... 01110 1 ..... ..... @q_shli_d + +UQSHL_vi 0.10 11110 .... ... 01110 1 ..... ..... @q_shli_b +UQSHL_vi 0.10 11110 .... ... 01110 1 ..... ..... @q_shli_h +UQSHL_vi 0.10 11110 .... ... 01110 1 ..... ..... @q_shli_s +UQSHL_vi 0.10 11110 .... ... 01110 1 ..... ..... @q_shli_d + +SQSHLU_vi 0.10 11110 .... ... 01100 1 ..... ..... @q_shli_b +SQSHLU_vi 0.10 11110 .... ... 01100 1 ..... ..... @q_shli_h +SQSHLU_vi 0.10 11110 .... ... 01100 1 ..... ..... @q_shli_s +SQSHLU_vi 0.10 11110 .... ... 01100 1 ..... ..... @q_shli_d + # Advanced SIMD scalar shift by immediate @shri_d .... ..... 1 ...... ..... . rn:5 rd:5 \ &rri_e esz=3 imm=%neon_rshift_i6 -@shli_d .... ..... 1 imm:6 ..... . rn:5 rd:5 &rri_e esz=3 + +@shli_b .... ..... 0001 imm:3 ..... . rn:5 rd:5 &rri_e esz=0 +@shli_h .... ..... 001 imm:4 ..... . rn:5 rd:5 &rri_e esz=1 +@shli_s .... ..... 01 imm:5 ..... . rn:5 rd:5 &rri_e esz=2 +@shli_d .... ..... 1 imm:6 ..... . rn:5 rd:5 &rri_e esz=3 SSHR_s 0101 11110 .... ... 00000 1 ..... ..... @shri_d USHR_s 0111 11110 .... ... 00000 1 ..... ..... @shri_d @@ -XXX,XX +XXX,XX @@ SRI_s 0111 11110 .... ... 01000 1 ..... ..... @shri_d SHL_s 0101 11110 .... ... 01010 1 ..... ..... @shli_d SLI_s 0111 11110 .... ... 01010 1 ..... ..... @shli_d + +SQSHL_si 0101 11110 .... ... 01110 1 ..... ..... @shli_b +SQSHL_si 0101 11110 .... ... 01110 1 ..... ..... @shli_h +SQSHL_si 0101 11110 .... ... 01110 1 ..... ..... @shli_s +SQSHL_si 0101 11110 .... ... 01110 1 ..... ..... @shli_d + +UQSHL_si 0111 11110 .... ... 01110 1 ..... ..... @shli_b +UQSHL_si 0111 11110 .... ... 01110 1 ..... ..... @shli_h +UQSHL_si 0111 11110 .... ... 01110 1 ..... ..... @shli_s +UQSHL_si 0111 11110 .... ... 01110 1 ..... ..... @shli_d + +SQSHLU_si 0111 11110 .... ... 01100 1 ..... ..... @shli_b +SQSHLU_si 0111 11110 .... ... 01100 1 ..... ..... @shli_h +SQSHLU_si 0111 11110 .... ... 01100 1 ..... ..... @shli_s +SQSHLU_si 0111 11110 .... ... 01100 1 ..... ..... @shli_d diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ TRANS(URSRA_v, do_vec_shift_imm, a, gen_gvec_ursra) TRANS(SRI_v, do_vec_shift_imm, a, gen_gvec_sri) TRANS(SHL_v, do_vec_shift_imm, a, tcg_gen_gvec_shli) TRANS(SLI_v, do_vec_shift_imm, a, gen_gvec_sli); +TRANS(SQSHL_vi, do_vec_shift_imm, a, gen_neon_sqshli) +TRANS(UQSHL_vi, do_vec_shift_imm, a, gen_neon_uqshli) +TRANS(SQSHLU_vi, do_vec_shift_imm, a, gen_neon_sqshlui) static bool do_vec_shift_imm_wide(DisasContext *s, arg_qrri_e *a, bool is_u) { @@ -XXX,XX +XXX,XX @@ TRANS(SRI_s, do_scalar_shift_imm, a, gen_sri_d, true, 0) TRANS(SHL_s, do_scalar_shift_imm, a, tcg_gen_shli_i64, false, 0) TRANS(SLI_s, do_scalar_shift_imm, a, gen_sli_d, true, 0) +static void trunc_i64_env_imm(TCGv_i64 d, TCGv_i64 s, int64_t i, + NeonGenTwoOpEnvFn *fn) +{ + TCGv_i32 t = tcg_temp_new_i32(); + tcg_gen_extrl_i64_i32(t, s); + fn(t, tcg_env, t, tcg_constant_i32(i)); + tcg_gen_extu_i32_i64(d, t); +} + +static void gen_sqshli_b(TCGv_i64 d, TCGv_i64 s, int64_t i) +{ + trunc_i64_env_imm(d, s, i, gen_helper_neon_qshl_s8); +} + +static void gen_sqshli_h(TCGv_i64 d, TCGv_i64 s, int64_t i) +{ + trunc_i64_env_imm(d, s, i, gen_helper_neon_qshl_s16); +} + +static void gen_sqshli_s(TCGv_i64 d, TCGv_i64 s, int64_t i) +{ + trunc_i64_env_imm(d, s, i, gen_helper_neon_qshl_s32); +} + +static void gen_sqshli_d(TCGv_i64 d, TCGv_i64 s, int64_t i) +{ + gen_helper_neon_qshl_s64(d, tcg_env, s, tcg_constant_i64(i)); +} + +static void gen_uqshli_b(TCGv_i64 d, TCGv_i64 s, int64_t i) +{ + trunc_i64_env_imm(d, s, i, gen_helper_neon_qshl_u8); +} + +static void gen_uqshli_h(TCGv_i64 d, TCGv_i64 s, int64_t i) +{ + trunc_i64_env_imm(d, s, i, gen_helper_neon_qshl_u16); +} + +static void gen_uqshli_s(TCGv_i64 d, TCGv_i64 s, int64_t i) +{ + trunc_i64_env_imm(d, s, i, gen_helper_neon_qshl_u32); +} + +static void gen_uqshli_d(TCGv_i64 d, TCGv_i64 s, int64_t i) +{ + gen_helper_neon_qshl_u64(d, tcg_env, s, tcg_constant_i64(i)); +} + +static void gen_sqshlui_b(TCGv_i64 d, TCGv_i64 s, int64_t i) +{ + trunc_i64_env_imm(d, s, i, gen_helper_neon_qshlu_s8); +} + +static void gen_sqshlui_h(TCGv_i64 d, TCGv_i64 s, int64_t i) +{ + trunc_i64_env_imm(d, s, i, gen_helper_neon_qshlu_s16); +} + +static void gen_sqshlui_s(TCGv_i64 d, TCGv_i64 s, int64_t i) +{ + trunc_i64_env_imm(d, s, i, gen_helper_neon_qshlu_s32); +} + +static void gen_sqshlui_d(TCGv_i64 d, TCGv_i64 s, int64_t i) +{ + gen_helper_neon_qshlu_s64(d, tcg_env, s, tcg_constant_i64(i)); +} + +static WideShiftImmFn * const f_scalar_sqshli[] = { + gen_sqshli_b, gen_sqshli_h, gen_sqshli_s, gen_sqshli_d +}; + +static WideShiftImmFn * const f_scalar_uqshli[] = { + gen_uqshli_b, gen_uqshli_h, gen_uqshli_s, gen_uqshli_d +}; + +static WideShiftImmFn * const f_scalar_sqshlui[] = { + gen_sqshlui_b, gen_sqshlui_h, gen_sqshlui_s, gen_sqshlui_d +}; + +/* Note that the helpers sign-extend their inputs, so don't do it here. */ +TRANS(SQSHL_si, do_scalar_shift_imm, a, f_scalar_sqshli[a->esz], false, 0) +TRANS(UQSHL_si, do_scalar_shift_imm, a, f_scalar_uqshli[a->esz], false, 0) +TRANS(SQSHLU_si, do_scalar_shift_imm, a, f_scalar_sqshlui[a->esz], false, 0) + /* Shift a TCGv src by TCGv shift_amount, put result in dst. * Note that it is the caller's responsibility to ensure that the * shift amount is in range (ie 0..31 or 0..63) and provide the ARM @@ -XXX,XX +XXX,XX @@ static void handle_vec_simd_sqshrn(DisasContext *s, bool is_scalar, bool is_q, clear_vec_high(s, is_q, rd); } -/* SQSHLU, UQSHL, SQSHL: saturating left shifts */ -static void handle_simd_qshl(DisasContext *s, bool scalar, bool is_q, - bool src_unsigned, bool dst_unsigned, - int immh, int immb, int rn, int rd) -{ - int immhb = immh << 3 | immb; - int size = 32 - clz32(immh) - 1; - int shift = immhb - (8 << size); - int pass; - - assert(immh != 0); - assert(!(scalar && is_q)); - - if (!scalar) { - if (!is_q && extract32(immh, 3, 1)) { - unallocated_encoding(s); - return; - } - - /* Since we use the variable-shift helpers we must - * replicate the shift count into each element of - * the tcg_shift value. - */ - switch (size) { - case 0: - shift |= shift << 8; - /* fall through */ - case 1: - shift |= shift << 16; - break; - case 2: - case 3: - break; - default: - g_assert_not_reached(); - } - } - - if (!fp_access_check(s)) { - return; - } - - if (size == 3) { - TCGv_i64 tcg_shift = tcg_constant_i64(shift); - static NeonGenTwo64OpEnvFn * const fns[2][2] = { - { gen_helper_neon_qshl_s64, gen_helper_neon_qshlu_s64 }, - { NULL, gen_helper_neon_qshl_u64 }, - }; - NeonGenTwo64OpEnvFn *genfn = fns[src_unsigned][dst_unsigned]; - int maxpass = is_q ? 2 : 1; - - for (pass = 0; pass < maxpass; pass++) { - TCGv_i64 tcg_op = tcg_temp_new_i64(); - - read_vec_element(s, tcg_op, rn, pass, MO_64); - genfn(tcg_op, tcg_env, tcg_op, tcg_shift); - write_vec_element(s, tcg_op, rd, pass, MO_64); - } - clear_vec_high(s, is_q, rd); - } else { - TCGv_i32 tcg_shift = tcg_constant_i32(shift); - static NeonGenTwoOpEnvFn * const fns[2][2][3] = { - { - { gen_helper_neon_qshl_s8, - gen_helper_neon_qshl_s16, - gen_helper_neon_qshl_s32 }, - { gen_helper_neon_qshlu_s8, - gen_helper_neon_qshlu_s16, - gen_helper_neon_qshlu_s32 } - }, { - { NULL, NULL, NULL }, - { gen_helper_neon_qshl_u8, - gen_helper_neon_qshl_u16, - gen_helper_neon_qshl_u32 } - } - }; - NeonGenTwoOpEnvFn *genfn = fns[src_unsigned][dst_unsigned][size]; - MemOp memop = scalar ? size : MO_32; - int maxpass = scalar ? 1 : is_q ? 4 : 2; - - for (pass = 0; pass < maxpass; pass++) { - TCGv_i32 tcg_op = tcg_temp_new_i32(); - - read_vec_element_i32(s, tcg_op, rn, pass, memop); - genfn(tcg_op, tcg_env, tcg_op, tcg_shift); - if (scalar) { - switch (size) { - case 0: - tcg_gen_ext8u_i32(tcg_op, tcg_op); - break; - case 1: - tcg_gen_ext16u_i32(tcg_op, tcg_op); - break; - case 2: - break; - default: - g_assert_not_reached(); - } - write_fp_sreg(s, rd, tcg_op); - } else { - write_vec_element_i32(s, tcg_op, rd, pass, MO_32); - } - } - - if (!scalar) { - clear_vec_high(s, is_q, rd); - } - } -} - /* Common vector code for handling integer to FP conversion */ static void handle_simd_intfp_conv(DisasContext *s, int rd, int rn, int elements, int is_signed, @@ -XXX,XX +XXX,XX @@ static void disas_simd_scalar_shift_imm(DisasContext *s, uint32_t insn) handle_vec_simd_sqshrn(s, true, false, is_u, is_u, immh, immb, opcode, rn, rd); break; - case 0xc: /* SQSHLU */ - if (!is_u) { - unallocated_encoding(s); - return; - } - handle_simd_qshl(s, true, false, false, true, immh, immb, rn, rd); - break; - case 0xe: /* SQSHL, UQSHL */ - handle_simd_qshl(s, true, false, is_u, is_u, immh, immb, rn, rd); - break; case 0x1f: /* FCVTZS, FCVTZU */ handle_simd_shift_fpint_conv(s, true, false, is_u, immh, immb, rn, rd); break; @@ -XXX,XX +XXX,XX @@ static void disas_simd_scalar_shift_imm(DisasContext *s, uint32_t insn) case 0x06: /* SRSRA / URSRA */ case 0x08: /* SRI */ case 0x0a: /* SHL / SLI */ + case 0x0c: /* SQSHLU */ + case 0x0e: /* SQSHL, UQSHL */ unallocated_encoding(s); break; } @@ -XXX,XX +XXX,XX @@ static void disas_simd_shift_imm(DisasContext *s, uint32_t insn) handle_simd_shift_intfp_conv(s, false, is_q, is_u, immh, immb, opcode, rn, rd); break; - case 0xc: /* SQSHLU */ - if (!is_u) { - unallocated_encoding(s); - return; - } - handle_simd_qshl(s, false, is_q, false, true, immh, immb, rn, rd); - break; - case 0xe: /* SQSHL, UQSHL */ - handle_simd_qshl(s, false, is_q, is_u, is_u, immh, immb, rn, rd); - break; case 0x1f: /* FCVTZS/ FCVTZU */ handle_simd_shift_fpint_conv(s, false, is_q, is_u, immh, immb, rn, rd); return; @@ -XXX,XX +XXX,XX @@ static void disas_simd_shift_imm(DisasContext *s, uint32_t insn) case 0x06: /* SRSRA / URSRA (accum + rounding) */ case 0x08: /* SRI */ case 0x0a: /* SHL / SLI */ + case 0x0c: /* SQSHLU */ + case 0x0e: /* SQSHL, UQSHL */ case 0x14: /* SSHLL / USHLL */ unallocated_encoding(s); return; -- 2.34.1
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20240912024114.1097832-29-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/a64.decode | 24 +++++ target/arm/tcg/translate-a64.c | 176 ++++++++++++++++++++++++++++++--- 2 files changed, 186 insertions(+), 14 deletions(-) diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -XXX,XX +XXX,XX @@ SQSHLU_vi 0.10 11110 .... ... 01100 1 ..... ..... @q_shli_h SQSHLU_vi 0.10 11110 .... ... 01100 1 ..... ..... @q_shli_s SQSHLU_vi 0.10 11110 .... ... 01100 1 ..... ..... @q_shli_d +SQSHRN_v 0.00 11110 .... ... 10010 1 ..... ..... @q_shri_b +SQSHRN_v 0.00 11110 .... ... 10010 1 ..... ..... @q_shri_h +SQSHRN_v 0.00 11110 .... ... 10010 1 ..... ..... @q_shri_s + +UQSHRN_v 0.10 11110 .... ... 10010 1 ..... ..... @q_shri_b +UQSHRN_v 0.10 11110 .... ... 10010 1 ..... ..... @q_shri_h +UQSHRN_v 0.10 11110 .... ... 10010 1 ..... ..... @q_shri_s + +SQSHRUN_v 0.10 11110 .... ... 10000 1 ..... ..... @q_shri_b +SQSHRUN_v 0.10 11110 .... ... 10000 1 ..... ..... @q_shri_h +SQSHRUN_v 0.10 11110 .... ... 10000 1 ..... ..... @q_shri_s + +SQRSHRN_v 0.00 11110 .... ... 10011 1 ..... ..... @q_shri_b +SQRSHRN_v 0.00 11110 .... ... 10011 1 ..... ..... @q_shri_h +SQRSHRN_v 0.00 11110 .... ... 10011 1 ..... ..... @q_shri_s + +UQRSHRN_v 0.10 11110 .... ... 10011 1 ..... ..... @q_shri_b +UQRSHRN_v 0.10 11110 .... ... 10011 1 ..... ..... @q_shri_h +UQRSHRN_v 0.10 11110 .... ... 10011 1 ..... ..... @q_shri_s + +SQRSHRUN_v 0.10 11110 .... ... 10001 1 ..... ..... @q_shri_b +SQRSHRUN_v 0.10 11110 .... ... 10001 1 ..... ..... @q_shri_h +SQRSHRUN_v 0.10 11110 .... ... 10001 1 ..... ..... @q_shri_s + # Advanced SIMD scalar shift by immediate @shri_d .... ..... 1 ...... ..... . rn:5 rd:5 \ diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ static bool do_vec_shift_imm_narrow(DisasContext *s, arg_qrri_e *a, return true; } +static void gen_sqshrn_b(TCGv_i64 d, TCGv_i64 s, int64_t i) +{ + tcg_gen_sari_i64(d, s, i); + tcg_gen_ext16u_i64(d, d); + gen_helper_neon_narrow_sat_s8(d, tcg_env, d); +} + +static void gen_sqshrn_h(TCGv_i64 d, TCGv_i64 s, int64_t i) +{ + tcg_gen_sari_i64(d, s, i); + tcg_gen_ext32u_i64(d, d); + gen_helper_neon_narrow_sat_s16(d, tcg_env, d); +} + +static void gen_sqshrn_s(TCGv_i64 d, TCGv_i64 s, int64_t i) +{ + gen_sshr_d(d, s, i); + gen_helper_neon_narrow_sat_s32(d, tcg_env, d); +} + +static void gen_uqshrn_b(TCGv_i64 d, TCGv_i64 s, int64_t i) +{ + tcg_gen_shri_i64(d, s, i); + gen_helper_neon_narrow_sat_u8(d, tcg_env, d); +} + +static void gen_uqshrn_h(TCGv_i64 d, TCGv_i64 s, int64_t i) +{ + tcg_gen_shri_i64(d, s, i); + gen_helper_neon_narrow_sat_u16(d, tcg_env, d); +} + +static void gen_uqshrn_s(TCGv_i64 d, TCGv_i64 s, int64_t i) +{ + gen_ushr_d(d, s, i); + gen_helper_neon_narrow_sat_u32(d, tcg_env, d); +} + +static void gen_sqshrun_b(TCGv_i64 d, TCGv_i64 s, int64_t i) +{ + tcg_gen_sari_i64(d, s, i); + tcg_gen_ext16u_i64(d, d); + gen_helper_neon_unarrow_sat8(d, tcg_env, d); +} + +static void gen_sqshrun_h(TCGv_i64 d, TCGv_i64 s, int64_t i) +{ + tcg_gen_sari_i64(d, s, i); + tcg_gen_ext32u_i64(d, d); + gen_helper_neon_unarrow_sat16(d, tcg_env, d); +} + +static void gen_sqshrun_s(TCGv_i64 d, TCGv_i64 s, int64_t i) +{ + gen_sshr_d(d, s, i); + gen_helper_neon_unarrow_sat32(d, tcg_env, d); +} + +static void gen_sqrshrn_b(TCGv_i64 d, TCGv_i64 s, int64_t i) +{ + gen_srshr_bhs(d, s, i); + tcg_gen_ext16u_i64(d, d); + gen_helper_neon_narrow_sat_s8(d, tcg_env, d); +} + +static void gen_sqrshrn_h(TCGv_i64 d, TCGv_i64 s, int64_t i) +{ + gen_srshr_bhs(d, s, i); + tcg_gen_ext32u_i64(d, d); + gen_helper_neon_narrow_sat_s16(d, tcg_env, d); +} + +static void gen_sqrshrn_s(TCGv_i64 d, TCGv_i64 s, int64_t i) +{ + gen_srshr_d(d, s, i); + gen_helper_neon_narrow_sat_s32(d, tcg_env, d); +} + +static void gen_uqrshrn_b(TCGv_i64 d, TCGv_i64 s, int64_t i) +{ + gen_urshr_bhs(d, s, i); + gen_helper_neon_narrow_sat_u8(d, tcg_env, d); +} + +static void gen_uqrshrn_h(TCGv_i64 d, TCGv_i64 s, int64_t i) +{ + gen_urshr_bhs(d, s, i); + gen_helper_neon_narrow_sat_u16(d, tcg_env, d); +} + +static void gen_uqrshrn_s(TCGv_i64 d, TCGv_i64 s, int64_t i) +{ + gen_urshr_d(d, s, i); + gen_helper_neon_narrow_sat_u32(d, tcg_env, d); +} + +static void gen_sqrshrun_b(TCGv_i64 d, TCGv_i64 s, int64_t i) +{ + gen_srshr_bhs(d, s, i); + tcg_gen_ext16u_i64(d, d); + gen_helper_neon_unarrow_sat8(d, tcg_env, d); +} + +static void gen_sqrshrun_h(TCGv_i64 d, TCGv_i64 s, int64_t i) +{ + gen_srshr_bhs(d, s, i); + tcg_gen_ext32u_i64(d, d); + gen_helper_neon_unarrow_sat16(d, tcg_env, d); +} + +static void gen_sqrshrun_s(TCGv_i64 d, TCGv_i64 s, int64_t i) +{ + gen_srshr_d(d, s, i); + gen_helper_neon_unarrow_sat32(d, tcg_env, d); +} + static WideShiftImmFn * const shrn_fns[] = { tcg_gen_shri_i64, tcg_gen_shri_i64, @@ -XXX,XX +XXX,XX @@ static WideShiftImmFn * const rshrn_fns[] = { }; TRANS(RSHRN_v, do_vec_shift_imm_narrow, a, rshrn_fns, 0) +static WideShiftImmFn * const sqshrn_fns[] = { + gen_sqshrn_b, + gen_sqshrn_h, + gen_sqshrn_s, +}; +TRANS(SQSHRN_v, do_vec_shift_imm_narrow, a, sqshrn_fns, MO_SIGN) + +static WideShiftImmFn * const uqshrn_fns[] = { + gen_uqshrn_b, + gen_uqshrn_h, + gen_uqshrn_s, +}; +TRANS(UQSHRN_v, do_vec_shift_imm_narrow, a, uqshrn_fns, 0) + +static WideShiftImmFn * const sqshrun_fns[] = { + gen_sqshrun_b, + gen_sqshrun_h, + gen_sqshrun_s, +}; +TRANS(SQSHRUN_v, do_vec_shift_imm_narrow, a, sqshrun_fns, MO_SIGN) + +static WideShiftImmFn * const sqrshrn_fns[] = { + gen_sqrshrn_b, + gen_sqrshrn_h, + gen_sqrshrn_s, +}; +TRANS(SQRSHRN_v, do_vec_shift_imm_narrow, a, sqrshrn_fns, MO_SIGN) + +static WideShiftImmFn * const uqrshrn_fns[] = { + gen_uqrshrn_b, + gen_uqrshrn_h, + gen_uqrshrn_s, +}; +TRANS(UQRSHRN_v, do_vec_shift_imm_narrow, a, uqrshrn_fns, 0) + +static WideShiftImmFn * const sqrshrun_fns[] = { + gen_sqrshrun_b, + gen_sqrshrun_h, + gen_sqrshrun_s, +}; +TRANS(SQRSHRUN_v, do_vec_shift_imm_narrow, a, sqrshrun_fns, MO_SIGN) + /* * Advanced SIMD Scalar Shift by Immediate */ @@ -XXX,XX +XXX,XX @@ static void disas_simd_shift_imm(DisasContext *s, uint32_t insn) } switch (opcode) { - case 0x10: /* SHRN / SQSHRUN */ - case 0x11: /* RSHRN / SQRSHRUN */ - if (is_u) { - handle_vec_simd_sqshrn(s, false, is_q, false, true, immh, immb, - opcode, rn, rd); - } else { - unallocated_encoding(s); - } - break; - case 0x12: /* SQSHRN / UQSHRN */ - case 0x13: /* SQRSHRN / UQRSHRN */ - handle_vec_simd_sqshrn(s, false, is_q, is_u, is_u, immh, immb, - opcode, rn, rd); - break; case 0x1c: /* SCVTF / UCVTF */ handle_simd_shift_intfp_conv(s, false, is_q, is_u, immh, immb, opcode, rn, rd); @@ -XXX,XX +XXX,XX @@ static void disas_simd_shift_imm(DisasContext *s, uint32_t insn) case 0x0a: /* SHL / SLI */ case 0x0c: /* SQSHLU */ case 0x0e: /* SQSHL, UQSHL */ + case 0x10: /* SHRN / SQSHRUN */ + case 0x11: /* RSHRN / SQRSHRUN */ + case 0x12: /* SQSHRN / UQSHRN */ + case 0x13: /* SQRSHRN / UQRSHRN */ case 0x14: /* SSHLL / USHLL */ unallocated_encoding(s); return; -- 2.34.1
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20240912024114.1097832-30-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/a64.decode | 30 +++++++ target/arm/tcg/translate-a64.c | 160 +++++++-------------------------- 2 files changed, 63 insertions(+), 127 deletions(-) diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -XXX,XX +XXX,XX @@ SQRSHRUN_v 0.10 11110 .... ... 10001 1 ..... ..... @q_shri_s # Advanced SIMD scalar shift by immediate +@shri_b .... ..... 0001 ... ..... . rn:5 rd:5 \ + &rri_e esz=0 imm=%neon_rshift_i3 +@shri_h .... ..... 001 .... ..... . rn:5 rd:5 \ + &rri_e esz=1 imm=%neon_rshift_i4 +@shri_s .... ..... 01 ..... ..... . rn:5 rd:5 \ + &rri_e esz=2 imm=%neon_rshift_i5 @shri_d .... ..... 1 ...... ..... . rn:5 rd:5 \ &rri_e esz=3 imm=%neon_rshift_i6 @@ -XXX,XX +XXX,XX @@ SQSHLU_si 0111 11110 .... ... 01100 1 ..... ..... @shli_b SQSHLU_si 0111 11110 .... ... 01100 1 ..... ..... @shli_h SQSHLU_si 0111 11110 .... ... 01100 1 ..... ..... @shli_s SQSHLU_si 0111 11110 .... ... 01100 1 ..... ..... @shli_d + +SQSHRN_si 0101 11110 .... ... 10010 1 ..... ..... @shri_b +SQSHRN_si 0101 11110 .... ... 10010 1 ..... ..... @shri_h +SQSHRN_si 0101 11110 .... ... 10010 1 ..... ..... @shri_s + +UQSHRN_si 0111 11110 .... ... 10010 1 ..... ..... @shri_b +UQSHRN_si 0111 11110 .... ... 10010 1 ..... ..... @shri_h +UQSHRN_si 0111 11110 .... ... 10010 1 ..... ..... @shri_s + +SQSHRUN_si 0111 11110 .... ... 10000 1 ..... ..... @shri_b +SQSHRUN_si 0111 11110 .... ... 10000 1 ..... ..... @shri_h +SQSHRUN_si 0111 11110 .... ... 10000 1 ..... ..... @shri_s + +SQRSHRN_si 0101 11110 .... ... 10011 1 ..... ..... @shri_b +SQRSHRN_si 0101 11110 .... ... 10011 1 ..... ..... @shri_h +SQRSHRN_si 0101 11110 .... ... 10011 1 ..... ..... @shri_s + +UQRSHRN_si 0111 11110 .... ... 10011 1 ..... ..... @shri_b +UQRSHRN_si 0111 11110 .... ... 10011 1 ..... ..... @shri_h +UQRSHRN_si 0111 11110 .... ... 10011 1 ..... ..... @shri_s + +SQRSHRUN_si 0111 11110 .... ... 10001 1 ..... ..... @shri_b +SQRSHRUN_si 0111 11110 .... ... 10001 1 ..... ..... @shri_h +SQRSHRUN_si 0111 11110 .... ... 10001 1 ..... ..... @shri_s diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ TRANS(SQSHL_si, do_scalar_shift_imm, a, f_scalar_sqshli[a->esz], false, 0) TRANS(UQSHL_si, do_scalar_shift_imm, a, f_scalar_uqshli[a->esz], false, 0) TRANS(SQSHLU_si, do_scalar_shift_imm, a, f_scalar_sqshlui[a->esz], false, 0) +static bool do_scalar_shift_imm_narrow(DisasContext *s, arg_rri_e *a, + WideShiftImmFn * const fns[3], + MemOp sign, bool zext) +{ + MemOp esz = a->esz; + + tcg_debug_assert(esz >= MO_8 && esz <= MO_32); + + if (fp_access_check(s)) { + TCGv_i64 rd = tcg_temp_new_i64(); + TCGv_i64 rn = tcg_temp_new_i64(); + + read_vec_element(s, rn, a->rn, 0, (esz + 1) | sign); + fns[esz](rd, rn, a->imm); + if (zext) { + tcg_gen_ext_i64(rd, rd, esz); + } + write_fp_dreg(s, a->rd, rd); + } + return true; +} + +TRANS(SQSHRN_si, do_scalar_shift_imm_narrow, a, sqshrn_fns, MO_SIGN, true) +TRANS(SQRSHRN_si, do_scalar_shift_imm_narrow, a, sqrshrn_fns, MO_SIGN, true) +TRANS(UQSHRN_si, do_scalar_shift_imm_narrow, a, uqshrn_fns, 0, false) +TRANS(UQRSHRN_si, do_scalar_shift_imm_narrow, a, uqrshrn_fns, 0, false) +TRANS(SQSHRUN_si, do_scalar_shift_imm_narrow, a, sqshrun_fns, MO_SIGN, false) +TRANS(SQRSHRUN_si, do_scalar_shift_imm_narrow, a, sqrshrun_fns, MO_SIGN, false) + /* Shift a TCGv src by TCGv shift_amount, put result in dst. * Note that it is the caller's responsibility to ensure that the * shift amount is in range (ie 0..31 or 0..63) and provide the ARM @@ -XXX,XX +XXX,XX @@ static void disas_data_proc_fp(DisasContext *s, uint32_t insn) } } -/* - * Common SSHR[RA]/USHR[RA] - Shift right (optional rounding/accumulate) - * - * This code is handles the common shifting code and is used by both - * the vector and scalar code. - */ -static void handle_shri_with_rndacc(TCGv_i64 tcg_res, TCGv_i64 tcg_src, - bool round, bool accumulate, - bool is_u, int size, int shift) -{ - if (!round) { - if (is_u) { - gen_ushr_d(tcg_src, tcg_src, shift); - } else { - gen_sshr_d(tcg_src, tcg_src, shift); - } - } else if (size == MO_64) { - if (is_u) { - gen_urshr_d(tcg_src, tcg_src, shift); - } else { - gen_srshr_d(tcg_src, tcg_src, shift); - } - } else { - if (is_u) { - gen_urshr_bhs(tcg_src, tcg_src, shift); - } else { - gen_srshr_bhs(tcg_src, tcg_src, shift); - } - } - - if (accumulate) { - tcg_gen_add_i64(tcg_res, tcg_res, tcg_src); - } else { - tcg_gen_mov_i64(tcg_res, tcg_src); - } -} - -/* SQSHRN/SQSHRUN - Saturating (signed/unsigned) shift right with - * (signed/unsigned) narrowing */ -static void handle_vec_simd_sqshrn(DisasContext *s, bool is_scalar, bool is_q, - bool is_u_shift, bool is_u_narrow, - int immh, int immb, int opcode, - int rn, int rd) -{ - int immhb = immh << 3 | immb; - int size = 32 - clz32(immh) - 1; - int esize = 8 << size; - int shift = (2 * esize) - immhb; - int elements = is_scalar ? 1 : (64 / esize); - bool round = extract32(opcode, 0, 1); - MemOp ldop = (size + 1) | (is_u_shift ? 0 : MO_SIGN); - TCGv_i64 tcg_rn, tcg_rd, tcg_final; - - static NeonGenOne64OpEnvFn * const signed_narrow_fns[4][2] = { - { gen_helper_neon_narrow_sat_s8, - gen_helper_neon_unarrow_sat8 }, - { gen_helper_neon_narrow_sat_s16, - gen_helper_neon_unarrow_sat16 }, - { gen_helper_neon_narrow_sat_s32, - gen_helper_neon_unarrow_sat32 }, - { NULL, NULL }, - }; - static NeonGenOne64OpEnvFn * const unsigned_narrow_fns[4] = { - gen_helper_neon_narrow_sat_u8, - gen_helper_neon_narrow_sat_u16, - gen_helper_neon_narrow_sat_u32, - NULL - }; - NeonGenOne64OpEnvFn *narrowfn; - - int i; - - assert(size < 4); - - if (extract32(immh, 3, 1)) { - unallocated_encoding(s); - return; - } - - if (!fp_access_check(s)) { - return; - } - - if (is_u_shift) { - narrowfn = unsigned_narrow_fns[size]; - } else { - narrowfn = signed_narrow_fns[size][is_u_narrow ? 1 : 0]; - } - - tcg_rn = tcg_temp_new_i64(); - tcg_rd = tcg_temp_new_i64(); - tcg_final = tcg_temp_new_i64(); - - for (i = 0; i < elements; i++) { - read_vec_element(s, tcg_rn, rn, i, ldop); - handle_shri_with_rndacc(tcg_rd, tcg_rn, round, - false, is_u_shift, size+1, shift); - narrowfn(tcg_rd, tcg_env, tcg_rd); - if (i == 0) { - tcg_gen_extract_i64(tcg_final, tcg_rd, 0, esize); - } else { - tcg_gen_deposit_i64(tcg_final, tcg_final, tcg_rd, esize * i, esize); - } - } - - if (!is_q) { - write_vec_element(s, tcg_final, rd, 0, MO_64); - } else { - write_vec_element(s, tcg_final, rd, 1, MO_64); - } - clear_vec_high(s, is_q, rd); -} - /* Common vector code for handling integer to FP conversion */ static void handle_simd_intfp_conv(DisasContext *s, int rd, int rn, int elements, int is_signed, @@ -XXX,XX +XXX,XX @@ static void disas_simd_scalar_shift_imm(DisasContext *s, uint32_t insn) handle_simd_shift_intfp_conv(s, true, false, is_u, immh, immb, opcode, rn, rd); break; - case 0x10: /* SQSHRUN, SQSHRUN2 */ - case 0x11: /* SQRSHRUN, SQRSHRUN2 */ - if (!is_u) { - unallocated_encoding(s); - return; - } - handle_vec_simd_sqshrn(s, true, false, false, true, - immh, immb, opcode, rn, rd); - break; - case 0x12: /* SQSHRN, SQSHRN2, UQSHRN */ - case 0x13: /* SQRSHRN, SQRSHRN2, UQRSHRN, UQRSHRN2 */ - handle_vec_simd_sqshrn(s, true, false, is_u, is_u, - immh, immb, opcode, rn, rd); - break; case 0x1f: /* FCVTZS, FCVTZU */ handle_simd_shift_fpint_conv(s, true, false, is_u, immh, immb, rn, rd); break; @@ -XXX,XX +XXX,XX @@ static void disas_simd_scalar_shift_imm(DisasContext *s, uint32_t insn) case 0x0a: /* SHL / SLI */ case 0x0c: /* SQSHLU */ case 0x0e: /* SQSHL, UQSHL */ + case 0x10: /* SQSHRUN */ + case 0x11: /* SQRSHRUN */ + case 0x12: /* SQSHRN, UQSHRN */ + case 0x13: /* SQRSHRN, UQRSHRN */ unallocated_encoding(s); break; } -- 2.34.1
From: Jacob Abrams <satur9nine@gmail.com> SW modifying USART_CR1 TE bit should cuase HW to respond by altering USART_ISR TEACK bit, and likewise for RE and REACK bit. This resolves some but not all issues necessary for the official STM USART HAL driver to function as is. Fixes: 87b77e6e01ca ("hw/char/stm32l4x5_usart: Enable serial read and write") Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2540 Signed-off-by: Jacob Abrams <satur9nine@gmail.com> Message-id: 20240911043255.51966-1-satur9nine@gmail.com Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/char/stm32l4x5_usart.c | 16 +++++++++++++ tests/qtest/stm32l4x5_usart-test.c | 36 +++++++++++++++++++++++++++++- 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/hw/char/stm32l4x5_usart.c b/hw/char/stm32l4x5_usart.c index XXXXXXX..XXXXXXX 100644 --- a/hw/char/stm32l4x5_usart.c +++ b/hw/char/stm32l4x5_usart.c @@ -XXX,XX +XXX,XX @@ REG32(RDR, 0x24) REG32(TDR, 0x28) FIELD(TDR, TDR, 0, 9) +static void stm32l4x5_update_isr(Stm32l4x5UsartBaseState *s) +{ + if (s->cr1 & R_CR1_TE_MASK) { + s->isr |= R_ISR_TEACK_MASK; + } else { + s->isr &= ~R_ISR_TEACK_MASK; + } + + if (s->cr1 & R_CR1_RE_MASK) { + s->isr |= R_ISR_REACK_MASK; + } else { + s->isr &= ~R_ISR_REACK_MASK; + } +} + static void stm32l4x5_update_irq(Stm32l4x5UsartBaseState *s) { if (((s->isr & R_ISR_WUF_MASK) && (s->cr3 & R_CR3_WUFIE_MASK)) || @@ -XXX,XX +XXX,XX @@ static void stm32l4x5_usart_base_write(void *opaque, hwaddr addr, case A_CR1: s->cr1 = value; stm32l4x5_update_params(s); + stm32l4x5_update_isr(s); stm32l4x5_update_irq(s); return; case A_CR2: diff --git a/tests/qtest/stm32l4x5_usart-test.c b/tests/qtest/stm32l4x5_usart-test.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/stm32l4x5_usart-test.c +++ b/tests/qtest/stm32l4x5_usart-test.c @@ -XXX,XX +XXX,XX @@ REG32(GTPR, 0x10) REG32(RTOR, 0x14) REG32(RQR, 0x18) REG32(ISR, 0x1C) + FIELD(ISR, REACK, 22, 1) + FIELD(ISR, TEACK, 21, 1) FIELD(ISR, TXE, 7, 1) FIELD(ISR, RXNE, 5, 1) FIELD(ISR, ORE, 3, 1) @@ -XXX,XX +XXX,XX @@ static void init_uart(QTestState *qts) /* Enable the transmitter, the receiver and the USART. */ qtest_writel(qts, (USART1_BASE_ADDR + A_CR1), - R_CR1_UE_MASK | R_CR1_RE_MASK | R_CR1_TE_MASK); + cr1 | R_CR1_UE_MASK | R_CR1_RE_MASK | R_CR1_TE_MASK); } static void test_write_read(void) @@ -XXX,XX +XXX,XX @@ static void test_send_str(void) qtest_quit(qts); } +static void test_ack(void) +{ + uint32_t cr1; + uint32_t isr; + QTestState *qts = qtest_init("-M b-l475e-iot01a"); + + init_uart(qts); + + cr1 = qtest_readl(qts, (USART1_BASE_ADDR + A_CR1)); + + /* Disable the transmitter and receiver. */ + qtest_writel(qts, (USART1_BASE_ADDR + A_CR1), + cr1 & ~(R_CR1_RE_MASK | R_CR1_TE_MASK)); + + /* Test ISR ACK for transmitter and receiver disabled */ + isr = qtest_readl(qts, (USART1_BASE_ADDR + A_ISR)); + g_assert_false(isr & R_ISR_TEACK_MASK); + g_assert_false(isr & R_ISR_REACK_MASK); + + /* Enable the transmitter and receiver. */ + qtest_writel(qts, (USART1_BASE_ADDR + A_CR1), + cr1 | (R_CR1_RE_MASK | R_CR1_TE_MASK)); + + /* Test ISR ACK for transmitter and receiver disabled */ + isr = qtest_readl(qts, (USART1_BASE_ADDR + A_ISR)); + g_assert_true(isr & R_ISR_TEACK_MASK); + g_assert_true(isr & R_ISR_REACK_MASK); + + qtest_quit(qts); +} + int main(int argc, char **argv) { int ret; @@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv) qtest_add_func("stm32l4x5/usart/send_char", test_send_char); qtest_add_func("stm32l4x5/usart/receive_str", test_receive_str); qtest_add_func("stm32l4x5/usart/send_str", test_send_str); + qtest_add_func("stm32l4x5/usart/ack", test_ack); ret = g_test_run(); return ret; -- 2.34.1
From: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org> We want to run tests using default cpu without having to remember which Arm core is it. Change Neoverse-N1 (old default) test to use default cpu (Neoverse-N2 at the moment). Signed-off-by: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org> Message-id: 20240910-b4-move-to-freebsd-v5-1-0fb66d803c93@linaro.org Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- tests/functional/test_aarch64_sbsaref.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/tests/functional/test_aarch64_sbsaref.py b/tests/functional/test_aarch64_sbsaref.py index XXXXXXX..XXXXXXX 100755 --- a/tests/functional/test_aarch64_sbsaref.py +++ b/tests/functional/test_aarch64_sbsaref.py @@ -XXX,XX +XXX,XX @@ def test_sbsaref_edk2_firmware(self): # This tests the whole boot chain from EFI to Userspace # We only boot a whole OS for the current top level CPU and GIC # Other test profiles should use more minimal boots - def boot_alpine_linux(self, cpu): + def boot_alpine_linux(self, cpu=None): self.fetch_firmware() iso_path = self.ASSET_ALPINE_ISO.fetch() self.vm.set_console() self.vm.add_args( - "-cpu", cpu, "-drive", f"file={iso_path},media=cdrom,format=raw", ) + if cpu: + self.vm.add_args("-cpu", cpu) self.vm.launch() wait_for_console_pattern(self, "Welcome to Alpine Linux 3.17") @@ -XXX,XX +XXX,XX @@ def boot_alpine_linux(self, cpu): def test_sbsaref_alpine_linux_cortex_a57(self): self.boot_alpine_linux("cortex-a57") - def test_sbsaref_alpine_linux_neoverse_n1(self): - self.boot_alpine_linux("neoverse-n1") + def test_sbsaref_alpine_linux_default_cpu(self): + self.boot_alpine_linux() def test_sbsaref_alpine_linux_max_pauth_off(self): self.boot_alpine_linux("max,pauth=off") @@ -XXX,XX +XXX,XX @@ def test_sbsaref_alpine_linux_max(self): # This tests the whole boot chain from EFI to Userspace # We only boot a whole OS for the current top level CPU and GIC # Other test profiles should use more minimal boots - def boot_openbsd73(self, cpu): + def boot_openbsd73(self, cpu=None): self.fetch_firmware() img_path = self.ASSET_OPENBSD_ISO.fetch() self.vm.set_console() self.vm.add_args( - "-cpu", cpu, "-drive", f"file={img_path},format=raw,snapshot=on", ) + if cpu: + self.vm.add_args("-cpu", cpu) self.vm.launch() wait_for_console_pattern(self, @@ -XXX,XX +XXX,XX @@ def boot_openbsd73(self, cpu): def test_sbsaref_openbsd73_cortex_a57(self): self.boot_openbsd73("cortex-a57") - def test_sbsaref_openbsd73_neoverse_n1(self): - self.boot_openbsd73("neoverse-n1") + def test_sbsaref_openbsd73_default_cpu(self): + self.boot_openbsd73() def test_sbsaref_openbsd73_max_pauth_off(self): self.boot_openbsd73("max,pauth=off") -- 2.34.1
From: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org> FreeBSD has longer support cycle for stable release (14.x EoL in 2028) than OpenBSD (7.3 we use is already EoL). Also bugfixes are backported so we can stay on 14.x for longer. Signed-off-by: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org> Message-id: 20240910-b4-move-to-freebsd-v5-2-0fb66d803c93@linaro.org Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- tests/functional/test_aarch64_sbsaref.py | 43 +++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/tests/functional/test_aarch64_sbsaref.py b/tests/functional/test_aarch64_sbsaref.py index XXXXXXX..XXXXXXX 100755 --- a/tests/functional/test_aarch64_sbsaref.py +++ b/tests/functional/test_aarch64_sbsaref.py @@ -XXX,XX +XXX,XX @@ #!/usr/bin/env python3 # -# Functional test that boots a Linux kernel and checks the console +# Functional test that boots a kernel and checks the console # # SPDX-FileCopyrightText: 2023-2024 Linaro Ltd. # SPDX-FileContributor: Philippe Mathieu-Daudé <philmd@linaro.org> @@ -XXX,XX +XXX,XX @@ def test_sbsaref_openbsd73_max(self): self.boot_openbsd73("max") + ASSET_FREEBSD_ISO = Asset( + ('https://download.freebsd.org/releases/arm64/aarch64/ISO-IMAGES/' + '14.1/FreeBSD-14.1-RELEASE-arm64-aarch64-bootonly.iso'), + '44cdbae275ef1bb6dab1d5fbb59473d4f741e1c8ea8a80fd9e906b531d6ad461') + + # This tests the whole boot chain from EFI to Userspace + # We only boot a whole OS for the current top level CPU and GIC + # Other test profiles should use more minimal boots + def boot_freebsd14(self, cpu=None): + self.fetch_firmware() + + img_path = self.ASSET_FREEBSD_ISO.fetch() + + self.vm.set_console() + self.vm.add_args( + "-drive", f"file={img_path},format=raw,snapshot=on", + ) + if cpu: + self.vm.add_args("-cpu", cpu) + + self.vm.launch() + wait_for_console_pattern(self, 'Welcome to FreeBSD!') + + def test_sbsaref_freebsd14_cortex_a57(self): + self.boot_freebsd14("cortex-a57") + + def test_sbsaref_freebsd14_default_cpu(self): + self.boot_freebsd14() + + def test_sbsaref_freebsd14_max_pauth_off(self): + self.boot_freebsd14("max,pauth=off") + + @skipUnless(os.getenv('QEMU_TEST_TIMEOUT_EXPECTED'), 'Test might timeout') + def test_sbsaref_freebsd14_max_pauth_impdef(self): + self.boot_freebsd14("max,pauth-impdef=on") + + @skipUnless(os.getenv('QEMU_TEST_TIMEOUT_EXPECTED'), 'Test might timeout') + def test_sbsaref_freebsd14_max(self): + self.boot_freebsd14("max") + + if __name__ == '__main__': QemuSystemTest.main() -- 2.34.1
From: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org> 'Test might timeout' means nothing. Replace it with useful information that it is emulation of pointer authentication what makes this test run too long. Signed-off-by: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org> Message-id: 20240910-b4-move-to-freebsd-v5-3-0fb66d803c93@linaro.org Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- tests/functional/test_aarch64_sbsaref.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tests/functional/test_aarch64_sbsaref.py b/tests/functional/test_aarch64_sbsaref.py index XXXXXXX..XXXXXXX 100755 --- a/tests/functional/test_aarch64_sbsaref.py +++ b/tests/functional/test_aarch64_sbsaref.py @@ -XXX,XX +XXX,XX @@ def test_sbsaref_alpine_linux_max_pauth_off(self): def test_sbsaref_alpine_linux_max_pauth_impdef(self): self.boot_alpine_linux("max,pauth-impdef=on") - @skipUnless(os.getenv('QEMU_TEST_TIMEOUT_EXPECTED'), 'Test might timeout') + @skipUnless(os.getenv('QEMU_TEST_TIMEOUT_EXPECTED'), + 'Test might timeout due to PAuth emulation') def test_sbsaref_alpine_linux_max(self): self.boot_alpine_linux("max") @@ -XXX,XX +XXX,XX @@ def test_sbsaref_openbsd73_default_cpu(self): def test_sbsaref_openbsd73_max_pauth_off(self): self.boot_openbsd73("max,pauth=off") - @skipUnless(os.getenv('QEMU_TEST_TIMEOUT_EXPECTED'), 'Test might timeout') + @skipUnless(os.getenv('QEMU_TEST_TIMEOUT_EXPECTED'), + 'Test might timeout due to PAuth emulation') def test_sbsaref_openbsd73_max_pauth_impdef(self): self.boot_openbsd73("max,pauth-impdef=on") - @skipUnless(os.getenv('QEMU_TEST_TIMEOUT_EXPECTED'), 'Test might timeout') + @skipUnless(os.getenv('QEMU_TEST_TIMEOUT_EXPECTED'), + 'Test might timeout due to PAuth emulation') def test_sbsaref_openbsd73_max(self): self.boot_openbsd73("max") @@ -XXX,XX +XXX,XX @@ def test_sbsaref_freebsd14_default_cpu(self): def test_sbsaref_freebsd14_max_pauth_off(self): self.boot_freebsd14("max,pauth=off") - @skipUnless(os.getenv('QEMU_TEST_TIMEOUT_EXPECTED'), 'Test might timeout') + @skipUnless(os.getenv('QEMU_TEST_TIMEOUT_EXPECTED'), + 'Test might timeout due to PAuth emulation') def test_sbsaref_freebsd14_max_pauth_impdef(self): self.boot_freebsd14("max,pauth-impdef=on") - @skipUnless(os.getenv('QEMU_TEST_TIMEOUT_EXPECTED'), 'Test might timeout') + @skipUnless(os.getenv('QEMU_TEST_TIMEOUT_EXPECTED'), + 'Test might timeout due to PAuth emulation') def test_sbsaref_freebsd14_max(self): self.boot_freebsd14("max") -- 2.34.1
From: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org> OpenBSD 7.3 we use is EoL. Both 7.4 and 7.5 releases do not work on anything above Neoverse-N1 due to PAC emulation: https://marc.info/?l=openbsd-arm&m=171050428327850&w=2 OpenBSD 7.6 is not yet released. Signed-off-by: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org> Message-id: 20240910-b4-move-to-freebsd-v5-4-0fb66d803c93@linaro.org Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- tests/functional/test_aarch64_sbsaref.py | 44 ------------------------ 1 file changed, 44 deletions(-) diff --git a/tests/functional/test_aarch64_sbsaref.py b/tests/functional/test_aarch64_sbsaref.py index XXXXXXX..XXXXXXX 100755 --- a/tests/functional/test_aarch64_sbsaref.py +++ b/tests/functional/test_aarch64_sbsaref.py @@ -XXX,XX +XXX,XX @@ def test_sbsaref_alpine_linux_max(self): self.boot_alpine_linux("max") - ASSET_OPENBSD_ISO = Asset( - ('https://cdn.openbsd.org/pub/OpenBSD/7.3/arm64/miniroot73.img'), - '7fc2c75401d6f01fbfa25f4953f72ad7d7c18650056d30755c44b9c129b707e5') - - # This tests the whole boot chain from EFI to Userspace - # We only boot a whole OS for the current top level CPU and GIC - # Other test profiles should use more minimal boots - def boot_openbsd73(self, cpu=None): - self.fetch_firmware() - - img_path = self.ASSET_OPENBSD_ISO.fetch() - - self.vm.set_console() - self.vm.add_args( - "-drive", f"file={img_path},format=raw,snapshot=on", - ) - if cpu: - self.vm.add_args("-cpu", cpu) - - self.vm.launch() - wait_for_console_pattern(self, - "Welcome to the OpenBSD/arm64" - " 7.3 installation program.") - - def test_sbsaref_openbsd73_cortex_a57(self): - self.boot_openbsd73("cortex-a57") - - def test_sbsaref_openbsd73_default_cpu(self): - self.boot_openbsd73() - - def test_sbsaref_openbsd73_max_pauth_off(self): - self.boot_openbsd73("max,pauth=off") - - @skipUnless(os.getenv('QEMU_TEST_TIMEOUT_EXPECTED'), - 'Test might timeout due to PAuth emulation') - def test_sbsaref_openbsd73_max_pauth_impdef(self): - self.boot_openbsd73("max,pauth-impdef=on") - - @skipUnless(os.getenv('QEMU_TEST_TIMEOUT_EXPECTED'), - 'Test might timeout due to PAuth emulation') - def test_sbsaref_openbsd73_max(self): - self.boot_openbsd73("max") - - ASSET_FREEBSD_ISO = Asset( ('https://download.freebsd.org/releases/arm64/aarch64/ISO-IMAGES/' '14.1/FreeBSD-14.1-RELEASE-arm64-aarch64-bootonly.iso'), -- 2.34.1
In kvm_init_vcpu()and do_kvm_destroy_vcpu(), the return value from kvm_ioctl(..., KVM_GET_VCPU_MMAP_SIZE, ...) is an 'int', but we put it into a 'long' logal variable mmap_size. Coverity then complains that there might be a truncation when we copy that value into the 'int ret' which we use for returning a value in an error-exit codepath. This can't ever actually overflow because the value was in an 'int' to start with, but it makes more sense to use 'int' for mmap_size so we don't do the widen-then-narrow sequence in the first place. Resolves: Coverity CID 1547515 Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-id: 20240815131206.3231819-2-peter.maydell@linaro.org --- accel/kvm/kvm-all.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index XXXXXXX..XXXXXXX 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -XXX,XX +XXX,XX @@ int kvm_create_and_park_vcpu(CPUState *cpu) static int do_kvm_destroy_vcpu(CPUState *cpu) { KVMState *s = kvm_state; - long mmap_size; + int mmap_size; int ret = 0; trace_kvm_destroy_vcpu(cpu->cpu_index, kvm_arch_vcpu_id(cpu)); @@ -XXX,XX +XXX,XX @@ void kvm_destroy_vcpu(CPUState *cpu) int kvm_init_vcpu(CPUState *cpu, Error **errp) { KVMState *s = kvm_state; - long mmap_size; + int mmap_size; int ret; trace_kvm_init_vcpu(cpu->cpu_index, kvm_arch_vcpu_id(cpu)); -- 2.34.1
The code at the tail end of the loop in kvm_dirty_ring_reaper_thread() is unreachable, because there is no way for execution to leave the loop. Replace it with a g_assert_not_reached(). (The code has always been unreachable, right from the start when the function was added in commit b4420f198dd8.) Resolves: Coverity CID 1547687 Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 20240815131206.3231819-3-peter.maydell@linaro.org --- accel/kvm/kvm-all.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index XXXXXXX..XXXXXXX 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -XXX,XX +XXX,XX @@ static void *kvm_dirty_ring_reaper_thread(void *data) r->reaper_iteration++; } - trace_kvm_dirty_ring_reaper("exit"); - - rcu_unregister_thread(); - - return NULL; + g_assert_not_reached(); } static void kvm_dirty_ring_reaper_init(KVMState *s) -- 2.34.1
The Neoverse-V1 TRM is a bit confused about the layout of the ID_AA64ISAR1_EL1 register, and so its table 3-6 has the wrong value for this ID register. Trust instead section 3.2.74's list of which fields are set. This means that we stop incorrectly reporting FEAT_XS as present, and now report the presence of FEAT_BF16. Cc: qemu-stable@nongnu.org Reported-by: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20240917161337.3012188-1-peter.maydell@linaro.org --- target/arm/tcg/cpu64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/cpu64.c +++ b/target/arm/tcg/cpu64.c @@ -XXX,XX +XXX,XX @@ static void aarch64_neoverse_v1_initfn(Object *obj) cpu->isar.id_aa64dfr0 = 0x000001f210305519ull; cpu->isar.id_aa64dfr1 = 0x00000000; cpu->isar.id_aa64isar0 = 0x1011111110212120ull; /* with FEAT_RNG */ - cpu->isar.id_aa64isar1 = 0x0111000001211032ull; + cpu->isar.id_aa64isar1 = 0x0011100001211032ull; cpu->isar.id_aa64mmfr0 = 0x0000000000101125ull; cpu->isar.id_aa64mmfr1 = 0x0000000010212122ull; cpu->isar.id_aa64mmfr2 = 0x0220011102101011ull; -- 2.34.1
docs/devel/nested-papr.txt is entirely (apart from the initial paragraph) a partial copy of the kernel documentation https://docs.kernel.org/arch/powerpc/kvm-nested.html There's no benefit to the QEMU docs to converting this to rST, so instead delete it. Anybody needing to know the API and protocol for the guest to communicate with the hypervisor to created nested VMs should refer to the authoratitative documentation in the kernel docs. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Daniel Henrique Barboza <danielhb413@gmail.com> Message-id: 20240816133318.3603114-1-peter.maydell@linaro.org --- docs/devel/nested-papr.txt | 119 ------------------------------------- 1 file changed, 119 deletions(-) delete mode 100644 docs/devel/nested-papr.txt diff --git a/docs/devel/nested-papr.txt b/docs/devel/nested-papr.txt deleted file mode 100644 index XXXXXXX..XXXXXXX --- a/docs/devel/nested-papr.txt +++ /dev/null @@ -XXX,XX +XXX,XX @@ -Nested PAPR API (aka KVM on PowerVM) -==================================== - -This API aims at providing support to enable nested virtualization with -KVM on PowerVM. While the existing support for nested KVM on PowerNV was -introduced with cap-nested-hv option, however, with a slight design change, -to enable this on papr/pseries, a new cap-nested-papr option is added. eg: - - qemu-system-ppc64 -cpu POWER10 -machine pseries,cap-nested-papr=true ... - -Work by: - Michael Neuling <mikey@neuling.org> - Vaibhav Jain <vaibhav@linux.ibm.com> - Jordan Niethe <jniethe5@gmail.com> - Harsh Prateek Bora <harshpb@linux.ibm.com> - Shivaprasad G Bhat <sbhat@linux.ibm.com> - Kautuk Consul <kconsul@linux.vnet.ibm.com> - -Below taken from the kernel documentation: - -Introduction -============ - -This document explains how a guest operating system can act as a -hypervisor and run nested guests through the use of hypercalls, if the -hypervisor has implemented them. The terms L0, L1, and L2 are used to -refer to different software entities. L0 is the hypervisor mode entity -that would normally be called the "host" or "hypervisor". L1 is a -guest virtual machine that is directly run under L0 and is initiated -and controlled by L0. L2 is a guest virtual machine that is initiated -and controlled by L1 acting as a hypervisor. A significant design change -wrt existing API is that now the entire L2 state is maintained within L0. - -Existing Nested-HV API -====================== - -Linux/KVM has had support for Nesting as an L0 or L1 since 2018 - -The L0 code was added:: - - commit 8e3f5fc1045dc49fd175b978c5457f5f51e7a2ce - Author: Paul Mackerras <paulus@ozlabs.org> - Date: Mon Oct 8 16:31:03 2018 +1100 - KVM: PPC: Book3S HV: Framework and hcall stubs for nested virtualization - -The L1 code was added:: - - commit 360cae313702cdd0b90f82c261a8302fecef030a - Author: Paul Mackerras <paulus@ozlabs.org> - Date: Mon Oct 8 16:31:04 2018 +1100 - KVM: PPC: Book3S HV: Nested guest entry via hypercall - -This API works primarily using a signal hcall h_enter_nested(). This -call made by the L1 to tell the L0 to start an L2 vCPU with the given -state. The L0 then starts this L2 and runs until an L2 exit condition -is reached. Once the L2 exits, the state of the L2 is given back to -the L1 by the L0. The full L2 vCPU state is always transferred from -and to L1 when the L2 is run. The L0 doesn't keep any state on the L2 -vCPU (except in the short sequence in the L0 on L1 -> L2 entry and L2 --> L1 exit). - -The only state kept by the L0 is the partition table. The L1 registers -it's partition table using the h_set_partition_table() hcall. All -other state held by the L0 about the L2s is cached state (such as -shadow page tables). - -The L1 may run any L2 or vCPU without first informing the L0. It -simply starts the vCPU using h_enter_nested(). The creation of L2s and -vCPUs is done implicitly whenever h_enter_nested() is called. - -In this document, we call this existing API the v1 API. - -New PAPR API -=============== - -The new PAPR API changes from the v1 API such that the creating L2 and -associated vCPUs is explicit. In this document, we call this the v2 -API. - -h_enter_nested() is replaced with H_GUEST_VCPU_RUN(). Before this can -be called the L1 must explicitly create the L2 using h_guest_create() -and any associated vCPUs() created with h_guest_create_vCPU(). Getting -and setting vCPU state can also be performed using h_guest_{g|s}et -hcall. - -The basic execution flow is for an L1 to create an L2, run it, and -delete it is: - -- L1 and L0 negotiate capabilities with H_GUEST_{G,S}ET_CAPABILITIES() - (normally at L1 boot time). - -- L1 requests the L0 to create an L2 with H_GUEST_CREATE() and receives a token - -- L1 requests the L0 to create an L2 vCPU with H_GUEST_CREATE_VCPU() - -- L1 and L0 communicate the vCPU state using the H_GUEST_{G,S}ET() hcall - -- L1 requests the L0 to run the vCPU using H_GUEST_RUN_VCPU() hcall - -- L1 deletes L2 with H_GUEST_DELETE() - -For more details, please refer: - -[1] Linux Kernel documentation (upstream documentation commit): - -commit 476652297f94a2e5e5ef29e734b0da37ade94110 -Author: Michael Neuling <mikey@neuling.org> -Date: Thu Sep 14 13:06:00 2023 +1000 - - docs: powerpc: Document nested KVM on POWER - - Document support for nested KVM on POWER using the existing API as well - as the new PAPR API. This includes the new HCALL interface and how it - used by KVM. - - Signed-off-by: Michael Neuling <mikey@neuling.org> - Signed-off-by: Jordan Niethe <jniethe5@gmail.com> - Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> - Link: https://msgid.link/20230914030600.16993-12-jniethe5@gmail.com -- 2.34.1
Hi; here's another arm pullreq; main parts here are the new i.MX 8MM EVK board, and a lot of refactoring. thanks -- PMM The following changes since commit aa15257174da180c6a8a9d58f87319cfe61c5520: Merge tag 'pbouvier/pr/plugins-20260424' of https://gitlab.com/p-b-o/qemu into staging (2026-04-25 10:22:04 -0400) are available in the Git repository at: https://gitlab.com/pm215/qemu.git tags/pull-target-arm-20260427 for you to fetch changes up to 4575da5ecb7a27544aa6da1f78e700e8100ceaea: target/arm: report register in WFIT syndromes (2026-04-27 11:46:34 +0100) ---------------------------------------------------------------- target-arm queue: docs/system: add FEAT_AA32 and FEAT_AA64 to emulation list hw/arm: Add the i.MX 8MM EVK(Evaluation Kit) board target/arm: Build M-profile helper code once only hw/arm: Remove hw_error() for the unimplemented CM_LMBUSCNT register hw: Move ARM_SYSCTL_GPIO definitions to arm sysctl specific header target/arm: Allow 'aarch64=off' to be set for TCG CPUs target/arm: Allow some sysregs to not have to be an exact match for migration hw/arm/raspi4b: NOP all DTB nodes when removing unimplemented devices hw/arm/fsl-imx6ul: Implement LCDIF display device target/arm: Refactor syndrome value code to use registerfields target/arm: Report the register in WFxT syndromes ---------------------------------------------------------------- Alex Bennée (24): docs/system: add FEAT_AA32 and FEAT_AA64 to emulation list target/arm: migrate basic syndrome helpers to registerfields target/arm: migrate system/cp trap syndromes to registerfields target/arm: migrate FP/SIMD trap syndromes to registerfields target/arm: migrate eret trap syndromes to registerfields target/arm: migrate SME trap syndromes to registerfields target/arm: migrate PAC trap syndromes to registerfields target/arm: migrate BTI trap syndromes to registerfields target/arm: migrate BXJ trap syndromes to registerfields target/arm: migrate Granule Protection traps to registerfields target/arm: migrate fault syndromes to registerfields target/arm: migrate debug syndromes to registerfields target/arm: migrate wfx syndromes to registerfields target/arm: migrate gcs syndromes to registerfields target/arm: migrate memory op syndromes to registerfields target/arm: migrate check_hcr_el2_trap to use syndrome helper target/arm: use syndrome helpers in arm_cpu_do_interrupt_aarch32_hyp target/arm: use syndrome helpers to set SAME_EL EC bit target/arm: make whpx use syndrome helpers for decode target/arm: make hvf use syndrome helpers for decode target/arm: use syndrome helpers in merge_syn_data_abort target/arm: use syndrome helpers to query VNCR bit target/arm: remove old syndrome defines target/arm: report register in WFIT syndromes Eric Auger (7): target/arm/cpu: Introduce the infrastructure for cpreg migration tolerances target/arm/machine: Handle ToleranceNotOnBothEnds migration tolerances target/arm/machine: Handle ToleranceOnlySrcTestValue migration tolerance target/arm/cpu64: Mitigate migration failures due to spurious TCR_EL1, PIRE0_EL1 and PIR_EL1 target/arm/cpu64: Define cpreg migration tolerance for KVM_REG_ARM_VENDOR_HYP_BMAP_2 target/arm/helper: Define cpreg migration tolerance for DGBDTR_EL0 Revert "target/arm: Reinstate bogus AArch32 DBGDTRTX register for migration compat" Gaurav Sharma (15): hw/arm: Add the i.MX 8MM EVK(Evaluation Kit) board hw/misc/imx8mp_analog: Add property to analog device hw/arm/fsl-imx8mm: Add Analog device IP to iMX8MM SOC hw/arm/fsl-imx8mm: Add Clock Control Module IP to iMX8MM hw/arm/fsl-imx8mm: Implemented support for SNVS hw/arm/fsl-imx8mm: Adding support for USDHC storage controllers hw/arm/fsl-imx8mm: Add PCIe support hw/arm/fsl-imx8mm: Add GPIO controllers hw/arm/fsl-imx8mm: Adding support for I2C emulation hw/arm/fsl-imx8mm: Adding support for SPI controller hw/arm/fsl-imx8mm: Adding support for Watchdog Timers hw/arm/fsl-imx8mm: Adding support for General Purpose Timers hw/arm/fsl-imx8mm: Adding support for ENET ethernet controller hw/arm/fsl-imx8mm: Adding support for USB controller hw/arm/fsl-imx8mm: Adding functional testing of iMX8MM emulation Osama Abdelkader (1): hw/arm/raspi4b: NOP all DTB nodes when removing unimplemented devices Peter Maydell (4): hw: Move ARM_SYSCTL_GPIO definitions to arm sysctl specific header target/arm: Clear AArch64 ID regs from ARMISARegisters if AArch64 disabled target/arm: Allow 'aarch64=off' to be set for TCG CPUs tests/functional/aarch64: Add basic test of TCG aarch64=off Philippe Mathieu-Daudé (9): target/arm: Ignore endianness when setting MTE tags target/arm: Explode MO_TExx -> MO_TE | MO_xx target/arm: Hoist MO_TE into mve_advance_vpt() target/arm: Hoist MO_TE into MVE DO_VSTR() macro target/arm: Introduce mo_endian() helper target/arm: Replace MO_TE -> mo_endian() for MVE helpers target/arm: Compile mve_helper.c once target/arm: Replace MO_TE -> mo_endian() for Cortex-M helpers target/arm: Compile m_helper.c once Thomas Huth (1): hw/arm: Remove hw_error() for the unimplemented CM_LMBUSCNT register Yucai Liu (2): hw/display: Add i.MX6UL LCDIF device model hw/arm/fsl-imx6ul: Wire in the LCDIF device model MAINTAINERS | 16 +- docs/system/arm/cpu-features.rst | 10 +- docs/system/arm/emulation.rst | 2 + docs/system/arm/{imx8mp-evk.rst => imx8m.rst} | 49 +- docs/system/target-arm.rst | 2 +- hw/arm/Kconfig | 25 + hw/arm/fsl-imx6ul.c | 12 +- hw/arm/fsl-imx8mm.c | 704 ++++++++++++++++++++++ hw/arm/imx8mm-evk.c | 130 ++++ hw/arm/integratorcp.c | 3 - hw/arm/meson.build | 2 + hw/arm/raspi4b.c | 10 +- hw/arm/realview.c | 2 +- hw/arm/vexpress.c | 2 +- hw/arm/virt.c | 1 - hw/display/Kconfig | 4 + hw/display/imx6ul_lcdif.c | 453 ++++++++++++++ hw/display/meson.build | 1 + hw/misc/arm_sysctl.c | 2 +- hw/misc/imx8mp_analog.c | 12 +- hw/timer/imx_gpt.c | 26 + hw/vmapple/vmapple.c | 1 - include/hw/arm/fsl-imx6ul.h | 4 +- include/hw/arm/fsl-imx8mm.h | 242 ++++++++ include/hw/arm/primecell.h | 12 - include/hw/display/imx6ul_lcdif.h | 37 ++ include/hw/misc/arm_sysctl.h | 16 + include/hw/misc/imx8mp_analog.h | 3 + include/hw/timer/imx_gpt.h | 2 + target/arm/cpu-features.h | 5 + target/arm/cpu.c | 153 ++++- target/arm/cpu.h | 4 +- target/arm/cpu64.c | 39 ++ target/arm/debug_helper.c | 29 - target/arm/helper.c | 27 +- target/arm/hvf/hvf.c | 14 +- target/arm/internals.h | 60 ++ target/arm/machine.c | 33 +- target/arm/syndrome.h | 595 ++++++++++++++---- target/arm/tcg/debug.c | 2 +- target/arm/tcg/helper-a64.c | 2 +- target/arm/tcg/helper-defs.h | 2 +- target/arm/tcg/m_helper.c | 8 +- target/arm/tcg/meson.build | 6 +- target/arm/tcg/mve_helper.c | 102 ++-- target/arm/tcg/op_helper.c | 7 +- target/arm/tcg/tlb_helper.c | 6 +- target/arm/tcg/translate-a64.c | 2 +- target/arm/tcg/vfp_helper.c | 5 +- target/arm/trace-events | 2 + target/arm/whpx/whpx-all.c | 13 +- tests/functional/aarch64/meson.build | 3 + tests/functional/aarch64/test_imx8mm_evk.py | 69 +++ tests/functional/aarch64/test_virt_aarch64_off.py | 37 ++ tests/qtest/arm-cpu-features.c | 8 +- 55 files changed, 2743 insertions(+), 275 deletions(-) rename docs/system/arm/{imx8mp-evk.rst => imx8m.rst} (58%) create mode 100644 hw/arm/fsl-imx8mm.c create mode 100644 hw/arm/imx8mm-evk.c create mode 100644 hw/display/imx6ul_lcdif.c create mode 100644 include/hw/arm/fsl-imx8mm.h delete mode 100644 include/hw/arm/primecell.h create mode 100644 include/hw/display/imx6ul_lcdif.h create mode 100644 include/hw/misc/arm_sysctl.h create mode 100755 tests/functional/aarch64/test_imx8mm_evk.py create mode 100755 tests/functional/aarch64/test_virt_aarch64_off.py
From: Alex Bennée <alex.bennee@linaro.org> This is just a documentation tweak as we already support both. FEAT_AA32 implies FEAT_AA32EL0. FEAT_AA64 implies FEAT_AA64EL[0123]. This is however useful if you are using emulation.rst as a source of truth of what QEMU emulates and when cross checking with Features.json from Arm. Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260421093506.616307-1-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- docs/system/arm/emulation.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst @@ -XXX,XX +XXX,XX @@ QEMU's TCG emulation includes support for the Armv5, Armv6, Armv7, Armv8 and Armv9 versions of the A-profile architecture. It also has support for the following architecture extensions: +- FEAT_AA32 (PE Support for AArch32) - FEAT_AA32BF16 (AArch32 BFloat16 instructions) - FEAT_AA32EL0 (Support for AArch32 at EL0) - FEAT_AA32EL1 (Support for AArch32 at EL1) @@ -XXX,XX +XXX,XX @@ the following architecture extensions: - FEAT_AA32EL3 (Support for AArch32 at EL3) - FEAT_AA32HPD (AArch32 hierarchical permission disables) - FEAT_AA32I8MM (AArch32 Int8 matrix multiplication instructions) +- FEAT_AA64 (PE uses AArch64 after last reboot) - FEAT_AA64EL0 (Support for AArch64 at EL0) - FEAT_AA64EL1 (Support for AArch64 at EL1) - FEAT_AA64EL2 (Support for AArch64 at EL2) -- 2.43.0
From: Gaurav Sharma <gaurav.sharma_7@nxp.com> Implemented CPUs, RAM, UARTs and Interrupt Controller Other peripherals are represented as TYPE_UNIMPLEMENTED_DEVICE Complete memory map of the SoC is provided. Set default RAM size to 2GB and default CPU count to 4 to match the real i.MX8MM EVK hardware configuration. Documentation is shared with imx8mp-evk to avoid duplication. Signed-off-by: Gaurav Sharma <gaurav.sharma_7@nxp.com> [PMM: fixed over-long lines in doc] Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Bernhard Beschow <shentey@gmail.com> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- MAINTAINERS | 11 +- docs/system/arm/{imx8mp-evk.rst => imx8m.rst} | 49 ++- docs/system/target-arm.rst | 2 +- hw/arm/Kconfig | 12 + hw/arm/fsl-imx8mm.c | 377 ++++++++++++++++++ hw/arm/imx8mm-evk.c | 112 ++++++ hw/arm/meson.build | 2 + include/hw/arm/fsl-imx8mm.h | 158 ++++++++ 8 files changed, 709 insertions(+), 14 deletions(-) rename docs/system/arm/{imx8mp-evk.rst => imx8m.rst} (58%) create mode 100644 hw/arm/fsl-imx8mm.c create mode 100644 hw/arm/imx8mm-evk.c create mode 100644 include/hw/arm/fsl-imx8mm.h diff --git a/MAINTAINERS b/MAINTAINERS index XXXXXXX..XXXXXXX 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -XXX,XX +XXX,XX @@ F: hw/pci-host/designware.c F: include/hw/pci-host/designware.h F: docs/system/arm/mcimx7d-sabre.rst +MCIMX8MM-EVK / iMX8MM +M: Gaurav Sharma <gaurav.sharma_7@nxp.com> +L: qemu-arm@nongnu.org +S: Maintained +F: hw/arm/fsl-imx8mm.c +F: hw/arm/imx8mm-evk.c +F: include/hw/arm/fsl-imx8mm.h +F: docs/system/arm/imx8m.rst + MCIMX8MP-EVK / i.MX8MP M: Bernhard Beschow <shentey@gmail.com> L: qemu-arm@nongnu.org @@ -XXX,XX +XXX,XX @@ F: hw/rtc/rs5c372.c F: include/hw/arm/fsl-imx8mp.h F: include/hw/misc/imx8mp_*.h F: include/hw/pci-host/fsl_imx8m_phy.h -F: docs/system/arm/imx8mp-evk.rst +F: docs/system/arm/imx8m.rst F: tests/functional/aarch64/test_imx8mp_evk.py F: tests/qtest/rs5c372-test.c diff --git a/docs/system/arm/imx8mp-evk.rst b/docs/system/arm/imx8m.rst similarity index 58% rename from docs/system/arm/imx8mp-evk.rst rename to docs/system/arm/imx8m.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/system/arm/imx8mp-evk.rst +++ b/docs/system/arm/imx8m.rst @@ -XXX,XX +XXX,XX @@ -NXP i.MX 8M Plus Evaluation Kit (``imx8mp-evk``) -================================================ +NXP i.MX 8M Plus and i.MX 8M Mini Evaluation Kits (``imx8mp-evk``, ``imx8mm-evk``) +================================================================================== -The ``imx8mp-evk`` machine models the i.MX 8M Plus Evaluation Kit, based on an -i.MX 8M Plus SoC. +The ``imx8mp-evk`` and ``imx8mm-evk`` machine models the i.MX 8M Plus +and i.MX 8M Mini Evaluation Kits, based on i.MX 8M Plus and i.MX8M +Mini SoCs. Supported devices ----------------- -The ``imx8mp-evk`` machine implements the following devices: +The ``imx8mp-evk`` and ``imx8mm-evk`` machines implement the +following devices: * Up to 4 Cortex-A53 cores * Generic Interrupt Controller (GICv3) @@ -XXX,XX +XXX,XX @@ The ``imx8mp-evk`` machine implements the following devices: Boot options ------------ -The ``imx8mp-evk`` machine can start a Linux kernel directly using the standard -``-kernel`` functionality. +The ``imx8mp-evk`` and ``imx8mm-evk`` machines can start a Linux +kernel directly using the standard ``-kernel`` functionality. Direct Linux Kernel Boot '''''''''''''''''''''''' @@ -XXX,XX +XXX,XX @@ is to generate an image with Buildroot. Version 2024.11.1 is tested at the time of writing and involves two steps. First run the following commands in the toplevel directory of the Buildroot source tree: +For i.MX 8M Plus EVK: + .. code-block:: bash $ make freescale_imx8mpevk_defconfig $ make +For i.MX 8M Mini EVK: + +.. code-block:: bash + + $ make freescale_imx8mmevk_defconfig + $ make + Once finished successfully there is an ``output/image`` subfolder. Navigate into it and resize the SD card image to a power of two: @@ -XXX,XX +XXX,XX @@ it and resize the SD card image to a power of two: Now that everything is prepared the machine can be started as follows: +For i.MX 8M Plus EVK: + .. code-block:: bash $ qemu-system-aarch64 -M imx8mp-evk \ @@ -XXX,XX +XXX,XX @@ Now that everything is prepared the machine can be started as follows: -append "root=/dev/mmcblk2p2" \ -drive file=sdcard.img,if=sd,bus=2,format=raw,id=mmcblk2 +For i.MX 8M Mini EVK: + +.. code-block:: bash + + $ qemu-system-aarch64 -M imx8mm-evk -smp 4 -m 2G \ + -display none -serial null -serial stdio \ + -kernel Image \ + -dtb imx8mm-evk.dtb \ + -append "root=/dev/mmcblk2p2" \ + -drive file=sdcard.img,if=sd,bus=2,format=raw,id=mmcblk2 KVM Acceleration ---------------- @@ -XXX,XX +XXX,XX @@ To enable hardware-assisted acceleration via KVM, append ``-accel kvm`` to the command line. While this speeds up performance significantly, be aware of the following limitations: -* The ``imx8mp-evk`` machine is not included under the "virtualization use case" - of :doc:`QEMU's security policy </system/security>`. This means that you - should not trust that it can contain malicious guests, whether it is run - using TCG or KVM. If you don't trust your guests and you're relying on QEMU to - be the security boundary, you want to choose another machine such as ``virt``. +* The ``imx8mp-evk`` and ``imx8mm-evk`` machines are not included + under the "virtualization use case" of :doc:`QEMU's security + policy </system/security>`. This means that you should not trust that + it can contain malicious guests, whether it is run using TCG or KVM. + If you don't trust your guests and you're relying on QEMU to be the + security boundary, you want to choose another machine such as + ``virt``. * Rather than Cortex-A53 CPUs, the same CPU type as the host's will be used. This is a limitation of KVM and may not work with guests with a tight dependency on Cortex-A53. diff --git a/docs/system/target-arm.rst b/docs/system/target-arm.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/system/target-arm.rst +++ b/docs/system/target-arm.rst @@ -XXX,XX +XXX,XX @@ Board-specific documentation arm/imx25-pdk arm/mcimx6ul-evk arm/mcimx7d-sabre - arm/imx8mp-evk + arm/imx8m arm/orangepi arm/raspi arm/collie diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -XXX,XX +XXX,XX @@ config FSL_IMX8MP_EVK depends on TCG select FSL_IMX8MP +config FSL_IMX8MM + bool + select ARM_GIC + select IMX + +config FSL_IMX8MM_EVK + bool + default y + depends on AARCH64 + depends on TCG + select FSL_IMX8MM + config ARM_SMMUV3_ACCEL bool depends on ARM_SMMUV3 diff --git a/hw/arm/fsl-imx8mm.c b/hw/arm/fsl-imx8mm.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/hw/arm/fsl-imx8mm.c @@ -XXX,XX +XXX,XX @@ +/* + * i.MX 8MM SoC Implementation + * + * Based on hw/arm/fsl-imx6.c + * + * Copyright (c) 2025, NXP Semiconductors + * Author: Gaurav Sharma <gaurav.sharma_7@nxp.com> + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * iMX8MM Reference Manual - https://www.nxp.com/products/i.MX8MMINI -> Documentation + */ + +#include "qemu/osdep.h" +#include "system/address-spaces.h" +#include "hw/arm/bsa.h" +#include "hw/arm/fsl-imx8mm.h" +#include "hw/misc/unimp.h" +#include "hw/core/boards.h" +#include "system/kvm.h" +#include "system/system.h" +#include "target/arm/cpu.h" +#include "target/arm/cpu-qom.h" +#include "target/arm/kvm_arm.h" +#include "qapi/error.h" +#include "qobject/qlist.h" + +static const struct { + hwaddr addr; + size_t size; + const char *name; +} fsl_imx8mm_memmap[] = { + [FSL_IMX8MM_RAM] = { FSL_IMX8MM_RAM_START, FSL_IMX8MM_RAM_SIZE_MAX, "ram" }, + [FSL_IMX8MM_DDR_PHY_BROADCAST] = { 0x3dc00000, 4 * MiB, "ddr_phy_broadcast" }, + [FSL_IMX8MM_DDR_PERF_MON] = { 0x3d800000, 4 * MiB, "ddr_perf_mon" }, + [FSL_IMX8MM_DDR_CTL] = { 0x3d400000, 4 * MiB, "ddr_ctl" }, + [FSL_IMX8MM_DDR_PHY] = { 0x3c000000, 16 * MiB, "ddr_phy" }, + [FSL_IMX8MM_GIC_DIST] = { 0x38800000, 512 * KiB, "gic_dist" }, + [FSL_IMX8MM_GIC_REDIST] = { 0x38880000, 512 * KiB, "gic_redist" }, + [FSL_IMX8MM_VPU] = { 0x38340000, 2 * MiB, "vpu" }, + [FSL_IMX8MM_VPU_BLK_CTRL] = { 0x38330000, 2 * MiB, "vpu_blk_ctrl" }, + [FSL_IMX8MM_VPU_G2_DECODER] = { 0x38310000, 1 * MiB, "vpu_g2_decoder" }, + [FSL_IMX8MM_VPU_G1_DECODER] = { 0x38300000, 1 * MiB, "vpu_g1_decoder" }, + [FSL_IMX8MM_USB2_OTG] = { 0x32e50200, 0x200, "usb2_otg" }, + [FSL_IMX8MM_USB2] = { 0x32e50000, 0x200, "usb2" }, + [FSL_IMX8MM_USB1_OTG] = { 0x32e40200, 0x200, "usb1_otg" }, + [FSL_IMX8MM_USB1] = { 0x32e40000, 0x200, "usb1" }, + [FSL_IMX8MM_GPU2D] = { 0x38000000, 64 * KiB, "gpu2d" }, + [FSL_IMX8MM_QSPI1_RX_BUFFER] = { 0x34000000, 32 * MiB, "qspi1_rx_buffer" }, + [FSL_IMX8MM_PCIE1] = { 0x33800000, 4 * MiB, "pcie1" }, + [FSL_IMX8MM_QSPI1_TX_BUFFER] = { 0x33008000, 32 * KiB, "qspi1_tx_buffer" }, + [FSL_IMX8MM_APBH_DMA] = { 0x33000000, 32 * KiB, "apbh_dma" }, + + /* AIPS-4 Begin */ + [FSL_IMX8MM_TZASC] = { 0x32f80000, 64 * KiB, "tzasc" }, + [FSL_IMX8MM_PCIE_PHY1] = { 0x32f00000, 64 * KiB, "pcie_phy1" }, + [FSL_IMX8MM_MEDIA_BLK_CTL] = { 0x32e28000, 256, "media_blk_ctl" }, + [FSL_IMX8MM_LCDIF] = { 0x32e00000, 64 * KiB, "lcdif" }, + [FSL_IMX8MM_MIPI_DSI] = { 0x32e10000, 64 * KiB, "mipi_dsi" }, + [FSL_IMX8MM_MIPI_CSI] = { 0x32e30000, 64 * KiB, "mipi_csi" }, + [FSL_IMX8MM_AIPS4_CONFIGURATION] = { 0x32df0000, 64 * KiB, "aips4_configuration" }, + /* AIPS-4 End */ + + [FSL_IMX8MM_INTERCONNECT] = { 0x32700000, 1 * MiB, "interconnect" }, + + /* AIPS-3 Begin */ + [FSL_IMX8MM_ENET1] = { 0x30be0000, 64 * KiB, "enet1" }, + [FSL_IMX8MM_SDMA1] = { 0x30bd0000, 64 * KiB, "sdma1" }, + [FSL_IMX8MM_QSPI] = { 0x30bb0000, 64 * KiB, "qspi" }, + [FSL_IMX8MM_USDHC3] = { 0x30b60000, 64 * KiB, "usdhc3" }, + [FSL_IMX8MM_USDHC2] = { 0x30b50000, 64 * KiB, "usdhc2" }, + [FSL_IMX8MM_USDHC1] = { 0x30b40000, 64 * KiB, "usdhc1" }, + [FSL_IMX8MM_SEMAPHORE_HS] = { 0x30ac0000, 64 * KiB, "semaphore_hs" }, + [FSL_IMX8MM_MU_B] = { 0x30ab0000, 64 * KiB, "mu_b" }, + [FSL_IMX8MM_MU_A] = { 0x30aa0000, 64 * KiB, "mu_a" }, + [FSL_IMX8MM_UART4] = { 0x30a60000, 64 * KiB, "uart4" }, + [FSL_IMX8MM_I2C4] = { 0x30a50000, 64 * KiB, "i2c4" }, + [FSL_IMX8MM_I2C3] = { 0x30a40000, 64 * KiB, "i2c3" }, + [FSL_IMX8MM_I2C2] = { 0x30a30000, 64 * KiB, "i2c2" }, + [FSL_IMX8MM_I2C1] = { 0x30a20000, 64 * KiB, "i2c1" }, + [FSL_IMX8MM_AIPS3_CONFIGURATION] = { 0x309f0000, 64 * KiB, "aips3_configuration" }, + [FSL_IMX8MM_CAAM] = { 0x30900000, 256 * KiB, "caam" }, + [FSL_IMX8MM_SPBA1] = { 0x308f0000, 64 * KiB, "spba1" }, + [FSL_IMX8MM_UART2] = { 0x30890000, 64 * KiB, "uart2" }, + [FSL_IMX8MM_UART3] = { 0x30880000, 64 * KiB, "uart3" }, + [FSL_IMX8MM_UART1] = { 0x30860000, 64 * KiB, "uart1" }, + [FSL_IMX8MM_ECSPI3] = { 0x30840000, 64 * KiB, "ecspi3" }, + [FSL_IMX8MM_ECSPI2] = { 0x30830000, 64 * KiB, "ecspi2" }, + [FSL_IMX8MM_ECSPI1] = { 0x30820000, 64 * KiB, "ecspi1" }, + /* AIPS-3 End */ + + /* AIPS-2 Begin */ + [FSL_IMX8MM_QOSC] = { 0x307f0000, 64 * KiB, "qosc" }, + [FSL_IMX8MM_PERFMON2] = { 0x307d0000, 64 * KiB, "perfmon2" }, + [FSL_IMX8MM_PERFMON1] = { 0x307c0000, 64 * KiB, "perfmon1" }, + [FSL_IMX8MM_GPT4] = { 0x30700000, 64 * KiB, "gpt4" }, + [FSL_IMX8MM_GPT5] = { 0x306f0000, 64 * KiB, "gpt5" }, + [FSL_IMX8MM_GPT6] = { 0x306e0000, 64 * KiB, "gpt6" }, + [FSL_IMX8MM_SYSCNT_CTRL] = { 0x306c0000, 64 * KiB, "syscnt_ctrl" }, + [FSL_IMX8MM_SYSCNT_CMP] = { 0x306b0000, 64 * KiB, "syscnt_cmp" }, + [FSL_IMX8MM_SYSCNT_RD] = { 0x306a0000, 64 * KiB, "syscnt_rd" }, + [FSL_IMX8MM_PWM4] = { 0x30690000, 64 * KiB, "pwm4" }, + [FSL_IMX8MM_PWM3] = { 0x30680000, 64 * KiB, "pwm3" }, + [FSL_IMX8MM_PWM2] = { 0x30670000, 64 * KiB, "pwm2" }, + [FSL_IMX8MM_PWM1] = { 0x30660000, 64 * KiB, "pwm1" }, + [FSL_IMX8MM_AIPS2_CONFIGURATION] = { 0x305f0000, 64 * KiB, "aips2_configuration" }, + /* AIPS-2 End */ + + /* AIPS-1 Begin */ + [FSL_IMX8MM_CSU] = { 0x303e0000, 64 * KiB, "csu" }, + [FSL_IMX8MM_RDC] = { 0x303d0000, 64 * KiB, "rdc" }, + [FSL_IMX8MM_SEMAPHORE2] = { 0x303c0000, 64 * KiB, "semaphore2" }, + [FSL_IMX8MM_SEMAPHORE1] = { 0x303b0000, 64 * KiB, "semaphore1" }, + [FSL_IMX8MM_GPC] = { 0x303a0000, 64 * KiB, "gpc" }, + [FSL_IMX8MM_SRC] = { 0x30390000, 64 * KiB, "src" }, + [FSL_IMX8MM_CCM] = { 0x30380000, 64 * KiB, "ccm" }, + [FSL_IMX8MM_SNVS_HP] = { 0x30370000, 64 * KiB, "snvs_hp" }, + [FSL_IMX8MM_ANA_PLL] = { 0x30360000, 64 * KiB, "ana_pll" }, + [FSL_IMX8MM_OCOTP_CTRL] = { 0x30350000, 64 * KiB, "ocotp_ctrl" }, + [FSL_IMX8MM_IOMUXC_GPR] = { 0x30340000, 64 * KiB, "iomuxc_gpr" }, + [FSL_IMX8MM_IOMUXC] = { 0x30330000, 64 * KiB, "iomuxc" }, + [FSL_IMX8MM_GPT3] = { 0x302f0000, 64 * KiB, "gpt3" }, + [FSL_IMX8MM_GPT2] = { 0x302e0000, 64 * KiB, "gpt2" }, + [FSL_IMX8MM_GPT1] = { 0x302d0000, 64 * KiB, "gpt1" }, + [FSL_IMX8MM_SDMA2] = { 0x302c0000, 64 * KiB, "sdma2" }, + [FSL_IMX8MM_SDMA3] = { 0x302b0000, 64 * KiB, "sdma3" }, + [FSL_IMX8MM_WDOG3] = { 0x302a0000, 64 * KiB, "wdog3" }, + [FSL_IMX8MM_WDOG2] = { 0x30290000, 64 * KiB, "wdog2" }, + [FSL_IMX8MM_WDOG1] = { 0x30280000, 64 * KiB, "wdog1" }, + [FSL_IMX8MM_ANA_OSC] = { 0x30270000, 64 * KiB, "ana_osc" }, + [FSL_IMX8MM_ANA_TSENSOR] = { 0x30260000, 64 * KiB, "ana_tsensor" }, + [FSL_IMX8MM_GPIO5] = { 0x30240000, 64 * KiB, "gpio5" }, + [FSL_IMX8MM_GPIO4] = { 0x30230000, 64 * KiB, "gpio4" }, + [FSL_IMX8MM_GPIO3] = { 0x30220000, 64 * KiB, "gpio3" }, + [FSL_IMX8MM_GPIO2] = { 0x30210000, 64 * KiB, "gpio2" }, + [FSL_IMX8MM_GPIO1] = { 0x30200000, 64 * KiB, "gpio1" }, + [FSL_IMX8MM_AIPS1_CONFIGURATION] = { 0x301f0000, 64 * KiB, "aips1_configuration" }, + [FSL_IMX8MM_SAI6] = { 0x30060000, 64 * KiB, "sai6" }, + [FSL_IMX8MM_SAI5] = { 0x30050000, 64 * KiB, "sai5" }, + [FSL_IMX8MM_SAI3] = { 0x30030000, 64 * KiB, "sai3" }, + [FSL_IMX8MM_SAI2] = { 0x30020000, 64 * KiB, "sai2" }, + [FSL_IMX8MM_SAI1] = { 0x30010000, 64 * KiB, "sai1" }, + + /* AIPS-1 End */ + + [FSL_IMX8MM_A53_DAP] = { 0x28000000, 16 * MiB, "a53_dap" }, + [FSL_IMX8MM_PCIE1_MEM] = { 0x18000000, 128 * MiB, "pcie1_mem" }, + [FSL_IMX8MM_QSPI_MEM] = { 0x08000000, 256 * MiB, "qspi_mem" }, + [FSL_IMX8MM_OCRAM] = { 0x00900000, 256 * KiB, "ocram" }, + [FSL_IMX8MM_TCM_DTCM] = { 0x00800000, 128 * KiB, "tcm_dtcm" }, + [FSL_IMX8MM_TCM_ITCM] = { 0x007e0000, 128 * KiB, "tcm_itcm" }, + [FSL_IMX8MM_OCRAM_S] = { 0x00180000, 32 * KiB, "ocram_s" }, + [FSL_IMX8MM_CAAM_MEM] = { 0x00100000, 32 * KiB, "caam_mem" }, + [FSL_IMX8MM_BOOT_ROM_PROTECTED] = { 0x0003f000, 4 * KiB, "boot_rom_protected" }, + [FSL_IMX8MM_BOOT_ROM] = { 0x00000000, 252 * KiB, "boot_rom" }, +}; + +static void fsl_imx8mm_init(Object *obj) +{ + MachineState *ms = MACHINE(qdev_get_machine()); + FslImx8mmState *s = FSL_IMX8MM(obj); + const char *cpu_type = ms->cpu_type ?: ARM_CPU_TYPE_NAME("cortex-a53"); + int i; + + for (i = 0; i < MIN(ms->smp.cpus, FSL_IMX8MM_NUM_CPUS); i++) { + g_autofree char *name = g_strdup_printf("cpu%d", i); + object_initialize_child(obj, name, &s->cpu[i], cpu_type); + } + + object_initialize_child(obj, "gic", &s->gic, gicv3_class_name()); + + for (i = 0; i < FSL_IMX8MM_NUM_UARTS; i++) { + g_autofree char *name = g_strdup_printf("uart%d", i + 1); + object_initialize_child(obj, name, &s->uart[i], TYPE_IMX_SERIAL); + } + +} + +static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) +{ + MachineState *ms = MACHINE(qdev_get_machine()); + FslImx8mmState *s = FSL_IMX8MM(dev); + DeviceState *gicdev = DEVICE(&s->gic); + int i; + + if (ms->smp.cpus > FSL_IMX8MM_NUM_CPUS) { + error_setg(errp, "%s: Only %d CPUs are supported (%d requested)", + TYPE_FSL_IMX8MM, FSL_IMX8MM_NUM_CPUS, ms->smp.cpus); + return; + } + + /* CPUs */ + for (i = 0; i < ms->smp.cpus; i++) { + /* On uniprocessor, the CBAR is set to 0 */ + if (ms->smp.cpus > 1 && + object_property_find(OBJECT(&s->cpu[i]), "reset-cbar")) { + object_property_set_int(OBJECT(&s->cpu[i]), "reset-cbar", + fsl_imx8mm_memmap[FSL_IMX8MM_GIC_DIST].addr, + &error_abort); + } + + /* + * CNTFID0 base frequency in Hz of system counter + */ + object_property_set_int(OBJECT(&s->cpu[i]), "cntfrq", 8000000, + &error_abort); + + if (object_property_find(OBJECT(&s->cpu[i]), "has_el2")) { + object_property_set_bool(OBJECT(&s->cpu[i]), "has_el2", + !kvm_enabled(), &error_abort); + } + + if (object_property_find(OBJECT(&s->cpu[i]), "has_el3")) { + object_property_set_bool(OBJECT(&s->cpu[i]), "has_el3", + !kvm_enabled(), &error_abort); + } + + if (i) { + /* + * Secondary CPUs start in powered-down state (and can be + * powered up via the SRC system reset controller) + */ + object_property_set_bool(OBJECT(&s->cpu[i]), "start-powered-off", + true, &error_abort); + } + + if (!qdev_realize(DEVICE(&s->cpu[i]), NULL, errp)) { + return; + } + } + + /* GIC */ + { + SysBusDevice *gicsbd = SYS_BUS_DEVICE(&s->gic); + QList *redist_region_count; + bool pmu = object_property_get_bool(OBJECT(first_cpu), "pmu", NULL); + + qdev_prop_set_uint32(gicdev, "num-cpu", ms->smp.cpus); + qdev_prop_set_uint32(gicdev, "num-irq", + FSL_IMX8MM_NUM_IRQS + GIC_INTERNAL); + redist_region_count = qlist_new(); + qlist_append_int(redist_region_count, ms->smp.cpus); + qdev_prop_set_array(gicdev, "redist-region-count", redist_region_count); + object_property_set_link(OBJECT(&s->gic), "sysmem", + OBJECT(get_system_memory()), &error_fatal); + if (!sysbus_realize(gicsbd, errp)) { + return; + } + sysbus_mmio_map(gicsbd, 0, fsl_imx8mm_memmap[FSL_IMX8MM_GIC_DIST].addr); + sysbus_mmio_map(gicsbd, 1, fsl_imx8mm_memmap[FSL_IMX8MM_GIC_REDIST].addr); + + /* + * Wire the outputs from each CPU's generic timer and the GICv3 + * maintenance interrupt signal to the appropriate GIC PPI inputs, and + * the GIC's IRQ/FIQ interrupt outputs to the CPU's inputs. + */ + for (i = 0; i < ms->smp.cpus; i++) { + DeviceState *cpudev = DEVICE(&s->cpu[i]); + int intidbase = FSL_IMX8MM_NUM_IRQS + i * GIC_INTERNAL; + qemu_irq irq; + + /* + * Mapping from the output timer irq lines from the CPU to the + * GIC PPI inputs. + */ + static const int timer_irqs[] = { + [GTIMER_PHYS] = ARCH_TIMER_NS_EL1_IRQ, + [GTIMER_VIRT] = ARCH_TIMER_VIRT_IRQ, + [GTIMER_HYP] = ARCH_TIMER_NS_EL2_IRQ, + [GTIMER_SEC] = ARCH_TIMER_S_EL1_IRQ, + }; + + for (int j = 0; j < ARRAY_SIZE(timer_irqs); j++) { + irq = qdev_get_gpio_in(gicdev, intidbase + timer_irqs[j]); + qdev_connect_gpio_out(cpudev, j, irq); + } + + irq = qdev_get_gpio_in(gicdev, intidbase + ARCH_GIC_MAINT_IRQ); + qdev_connect_gpio_out_named(cpudev, "gicv3-maintenance-interrupt", + 0, irq); + + irq = qdev_get_gpio_in(gicdev, intidbase + VIRTUAL_PMU_IRQ); + qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0, irq); + + sysbus_connect_irq(gicsbd, i, + qdev_get_gpio_in(cpudev, ARM_CPU_IRQ)); + sysbus_connect_irq(gicsbd, i + ms->smp.cpus, + qdev_get_gpio_in(cpudev, ARM_CPU_FIQ)); + sysbus_connect_irq(gicsbd, i + 2 * ms->smp.cpus, + qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ)); + sysbus_connect_irq(gicsbd, i + 3 * ms->smp.cpus, + qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ)); + + if (kvm_enabled()) { + if (pmu) { + assert(arm_feature(&s->cpu[i].env, ARM_FEATURE_PMU)); + if (kvm_irqchip_in_kernel()) { + kvm_arm_pmu_set_irq(&s->cpu[i], VIRTUAL_PMU_IRQ); + } + kvm_arm_pmu_init(&s->cpu[i]); + } + } + } + } + + /* UARTs */ + for (i = 0; i < FSL_IMX8MM_NUM_UARTS; i++) { + static const struct { + hwaddr addr; + unsigned int irq; + } serial_table[FSL_IMX8MM_NUM_UARTS] = { + { fsl_imx8mm_memmap[FSL_IMX8MM_UART1].addr, FSL_IMX8MM_UART1_IRQ }, + { fsl_imx8mm_memmap[FSL_IMX8MM_UART2].addr, FSL_IMX8MM_UART2_IRQ }, + { fsl_imx8mm_memmap[FSL_IMX8MM_UART3].addr, FSL_IMX8MM_UART3_IRQ }, + { fsl_imx8mm_memmap[FSL_IMX8MM_UART4].addr, FSL_IMX8MM_UART4_IRQ }, + }; + + qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", serial_hd(i)); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->uart[i]), errp)) { + return; + } + + sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart[i]), 0, serial_table[i].addr); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0, + qdev_get_gpio_in(gicdev, serial_table[i].irq)); + } + + /* On-Chip RAM */ + if (!memory_region_init_ram(&s->ocram, OBJECT(dev), "imx8mm.ocram", + fsl_imx8mm_memmap[FSL_IMX8MM_OCRAM].size, + errp)) { + return; + } + memory_region_add_subregion(get_system_memory(), + fsl_imx8mm_memmap[FSL_IMX8MM_OCRAM].addr, + &s->ocram); + + /* Unimplemented devices */ + for (i = 0; i < ARRAY_SIZE(fsl_imx8mm_memmap); i++) { + switch (i) { + case FSL_IMX8MM_GIC_DIST: + case FSL_IMX8MM_GIC_REDIST: + case FSL_IMX8MM_RAM: + case FSL_IMX8MM_OCRAM: + case FSL_IMX8MM_UART1 ... FSL_IMX8MM_UART4: + /* device implemented and treated above */ + break; + + default: + create_unimplemented_device(fsl_imx8mm_memmap[i].name, + fsl_imx8mm_memmap[i].addr, + fsl_imx8mm_memmap[i].size); + break; + } + } +} + +static void fsl_imx8mm_class_init(ObjectClass *oc, const void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = fsl_imx8mm_realize; + + dc->desc = "i.MX 8MM SoC"; +} + +static const TypeInfo fsl_imx8mm_types[] = { + { + .name = TYPE_FSL_IMX8MM, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(FslImx8mmState), + .instance_init = fsl_imx8mm_init, + .class_init = fsl_imx8mm_class_init, + }, +}; + +DEFINE_TYPES(fsl_imx8mm_types) diff --git a/hw/arm/imx8mm-evk.c b/hw/arm/imx8mm-evk.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/hw/arm/imx8mm-evk.c @@ -XXX,XX +XXX,XX @@ +/* + * NXP i.MX 8MM Evaluation Kit System Emulation + * + * Copyright (c) 2025, NXP Semiconductors + * Author: Gaurav Sharma <gaurav.sharma_7@nxp.com> + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "system/address-spaces.h" +#include "hw/arm/boot.h" +#include "hw/arm/fsl-imx8mm.h" +#include "hw/arm/machines-qom.h" +#include "hw/core/boards.h" +#include "hw/core/qdev-properties.h" +#include "system/kvm.h" +#include "system/qtest.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include <libfdt.h> + +static void imx8mm_evk_modify_dtb(const struct arm_boot_info *info, void *fdt) +{ + int i, offset; + + /* Temporarily disable following nodes until they are implemented */ + const char *nodes_to_remove[] = { + "nxp,imx8mm-fspi", + "fsl,imx8mm-mipi-csi", + "fsl,imx8mm-mipi-dsim" + }; + + for (i = 0; i < ARRAY_SIZE(nodes_to_remove); i++) { + const char *dev_str = nodes_to_remove[i]; + + offset = fdt_node_offset_by_compatible(fdt, -1, dev_str); + while (offset >= 0) { + fdt_nop_node(fdt, offset); + offset = fdt_node_offset_by_compatible(fdt, offset, dev_str); + } + } + + /* Remove cpu-idle-states property from CPU nodes */ + offset = fdt_node_offset_by_compatible(fdt, -1, "arm,cortex-a53"); + while (offset >= 0) { + fdt_nop_property(fdt, offset, "cpu-idle-states"); + offset = fdt_node_offset_by_compatible(fdt, offset, "arm,cortex-a53"); + } + + if (kvm_enabled()) { + /* Use system counter frequency from host CPU to fix time in guest */ + offset = fdt_node_offset_by_compatible(fdt, -1, "arm,armv8-timer"); + while (offset >= 0) { + fdt_nop_property(fdt, offset, "clock-frequency"); + offset = fdt_node_offset_by_compatible(fdt, offset, "arm,armv8-timer"); + } + } +} + +static void imx8mm_evk_init(MachineState *machine) +{ + static struct arm_boot_info boot_info; + FslImx8mmState *s; + + if (machine->ram_size > FSL_IMX8MM_RAM_SIZE_MAX) { + error_report("RAM size " RAM_ADDR_FMT " above max supported (%08" PRIx64 ")", + machine->ram_size, FSL_IMX8MM_RAM_SIZE_MAX); + exit(1); + } + + boot_info = (struct arm_boot_info) { + .loader_start = FSL_IMX8MM_RAM_START, + .board_id = -1, + .ram_size = machine->ram_size, + .psci_conduit = QEMU_PSCI_CONDUIT_SMC, + .modify_dtb = imx8mm_evk_modify_dtb, + }; + + s = FSL_IMX8MM(object_new_with_props(TYPE_FSL_IMX8MM, OBJECT(machine), + "soc", &error_fatal, NULL)); + sysbus_realize_and_unref(SYS_BUS_DEVICE(s), &error_fatal); + + memory_region_add_subregion(get_system_memory(), FSL_IMX8MM_RAM_START, + machine->ram); + + if (!qtest_enabled()) { + arm_load_kernel(&s->cpu[0], machine, &boot_info); + } +} + +static const char *imx8mm_evk_get_default_cpu_type(const MachineState *ms) +{ + if (kvm_enabled()) { + return ARM_CPU_TYPE_NAME("host"); + } + + return ARM_CPU_TYPE_NAME("cortex-a53"); +} + +static void imx8mm_evk_machine_init(MachineClass *mc) +{ + mc->desc = "NXP i.MX 8MM EVK Board"; + mc->init = imx8mm_evk_init; + mc->max_cpus = FSL_IMX8MM_NUM_CPUS; + mc->default_cpus = FSL_IMX8MM_NUM_CPUS; + mc->default_ram_size = 2 * GiB; + mc->default_ram_id = "imx8mm-evk.ram"; + mc->get_default_cpu_type = imx8mm_evk_get_default_cpu_type; +} + +DEFINE_MACHINE_AARCH64("imx8mm-evk", imx8mm_evk_machine_init) diff --git a/hw/arm/meson.build b/hw/arm/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/meson.build +++ b/hw/arm/meson.build @@ -XXX,XX +XXX,XX @@ arm_common_ss.add(when: 'CONFIG_ARMSSE', if_true: files('armsse.c')) arm_common_ss.add(when: 'CONFIG_FSL_IMX7', if_true: files('fsl-imx7.c', 'mcimx7d-sabre.c')) arm_common_ss.add(when: 'CONFIG_FSL_IMX8MP', if_true: files('fsl-imx8mp.c')) arm_common_ss.add(when: 'CONFIG_FSL_IMX8MP_EVK', if_true: files('imx8mp-evk.c')) +arm_common_ss.add(when: 'CONFIG_FSL_IMX8MM', if_true: files('fsl-imx8mm.c')) +arm_common_ss.add(when: 'CONFIG_FSL_IMX8MM_EVK', if_true: files('imx8mm-evk.c')) arm_common_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmuv3.c')) arm_common_ss.add(when: 'CONFIG_ARM_SMMUV3_ACCEL', if_true: files('smmuv3-accel.c')) stub_ss.add(files('smmuv3-accel-stubs.c')) diff --git a/include/hw/arm/fsl-imx8mm.h b/include/hw/arm/fsl-imx8mm.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/include/hw/arm/fsl-imx8mm.h @@ -XXX,XX +XXX,XX @@ +/* + * i.MX 8MM SoC Definitions + * + * Copyright (c) 2025, NXP Semiconductors + * Author: Gaurav Sharma <gaurav.sharma_7@nxp.com> + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef FSL_IMX8MM_H +#define FSL_IMX8MM_H + +#include "cpu.h" +#include "hw/char/imx_serial.h" +#include "hw/intc/arm_gicv3_common.h" +#include "qom/object.h" +#include "qemu/units.h" + +#define TYPE_FSL_IMX8MM "fsl-imx8mm" +OBJECT_DECLARE_SIMPLE_TYPE(FslImx8mmState, FSL_IMX8MM) + +#define FSL_IMX8MM_RAM_START 0x40000000 +#define FSL_IMX8MM_RAM_SIZE_MAX (4 * GiB) + +enum FslImx8mmConfiguration { + FSL_IMX8MM_NUM_CPUS = 4, + FSL_IMX8MM_NUM_IRQS = 128, + FSL_IMX8MM_NUM_UARTS = 4, +}; + +struct FslImx8mmState { + SysBusDevice parent_obj; + + ARMCPU cpu[FSL_IMX8MM_NUM_CPUS]; + GICv3State gic; + IMXSerialState uart[FSL_IMX8MM_NUM_UARTS]; + MemoryRegion ocram; +}; + +enum FslImx8mmMemoryRegions { + FSL_IMX8MM_A53_DAP, + FSL_IMX8MM_AIPS1_CONFIGURATION, + FSL_IMX8MM_AIPS2_CONFIGURATION, + FSL_IMX8MM_AIPS3_CONFIGURATION, + FSL_IMX8MM_AIPS4_CONFIGURATION, + FSL_IMX8MM_ANA_OSC, + FSL_IMX8MM_ANA_PLL, + FSL_IMX8MM_ANA_TSENSOR, + FSL_IMX8MM_APBH_DMA, + FSL_IMX8MM_BOOT_ROM, + FSL_IMX8MM_BOOT_ROM_PROTECTED, + FSL_IMX8MM_CAAM, + FSL_IMX8MM_CAAM_MEM, + FSL_IMX8MM_CCM, + FSL_IMX8MM_CSU, + FSL_IMX8MM_DDR_CTL, + FSL_IMX8MM_DDR_PERF_MON, + FSL_IMX8MM_DDR_PHY, + FSL_IMX8MM_DDR_PHY_BROADCAST, + FSL_IMX8MM_ECSPI1, + FSL_IMX8MM_ECSPI2, + FSL_IMX8MM_ECSPI3, + FSL_IMX8MM_ENET1, + FSL_IMX8MM_GIC_DIST, + FSL_IMX8MM_GIC_REDIST, + FSL_IMX8MM_GPC, + FSL_IMX8MM_GPIO1, + FSL_IMX8MM_GPIO2, + FSL_IMX8MM_GPIO3, + FSL_IMX8MM_GPIO4, + FSL_IMX8MM_GPIO5, + FSL_IMX8MM_GPT1, + FSL_IMX8MM_GPT2, + FSL_IMX8MM_GPT3, + FSL_IMX8MM_GPT4, + FSL_IMX8MM_GPT5, + FSL_IMX8MM_GPT6, + FSL_IMX8MM_GPU2D, + FSL_IMX8MM_I2C1, + FSL_IMX8MM_I2C2, + FSL_IMX8MM_I2C3, + FSL_IMX8MM_I2C4, + FSL_IMX8MM_INTERCONNECT, + FSL_IMX8MM_IOMUXC, + FSL_IMX8MM_IOMUXC_GPR, + FSL_IMX8MM_MEDIA_BLK_CTL, + FSL_IMX8MM_LCDIF, + FSL_IMX8MM_MIPI_CSI, + FSL_IMX8MM_MIPI_DSI, + FSL_IMX8MM_MU_A, + FSL_IMX8MM_MU_B, + FSL_IMX8MM_OCOTP_CTRL, + FSL_IMX8MM_OCRAM, + FSL_IMX8MM_OCRAM_S, + FSL_IMX8MM_PCIE1, + FSL_IMX8MM_PCIE1_MEM, + FSL_IMX8MM_PCIE_PHY1, + FSL_IMX8MM_PERFMON1, + FSL_IMX8MM_PERFMON2, + FSL_IMX8MM_PWM1, + FSL_IMX8MM_PWM2, + FSL_IMX8MM_PWM3, + FSL_IMX8MM_PWM4, + FSL_IMX8MM_QOSC, + FSL_IMX8MM_QSPI, + FSL_IMX8MM_QSPI1_RX_BUFFER, + FSL_IMX8MM_QSPI1_TX_BUFFER, + FSL_IMX8MM_QSPI_MEM, + FSL_IMX8MM_RAM, + FSL_IMX8MM_RDC, + FSL_IMX8MM_SAI1, + FSL_IMX8MM_SAI2, + FSL_IMX8MM_SAI3, + FSL_IMX8MM_SAI5, + FSL_IMX8MM_SAI6, + FSL_IMX8MM_SDMA1, + FSL_IMX8MM_SDMA2, + FSL_IMX8MM_SDMA3, + FSL_IMX8MM_SEMAPHORE1, + FSL_IMX8MM_SEMAPHORE2, + FSL_IMX8MM_SEMAPHORE_HS, + FSL_IMX8MM_SNVS_HP, + FSL_IMX8MM_SPBA1, + FSL_IMX8MM_SRC, + FSL_IMX8MM_SYSCNT_CMP, + FSL_IMX8MM_SYSCNT_CTRL, + FSL_IMX8MM_SYSCNT_RD, + FSL_IMX8MM_TCM_DTCM, + FSL_IMX8MM_TCM_ITCM, + FSL_IMX8MM_TZASC, + FSL_IMX8MM_UART1, + FSL_IMX8MM_UART2, + FSL_IMX8MM_UART3, + FSL_IMX8MM_UART4, + FSL_IMX8MM_USB1, + FSL_IMX8MM_USB2, + FSL_IMX8MM_USB1_OTG, + FSL_IMX8MM_USB2_OTG, + FSL_IMX8MM_USDHC1, + FSL_IMX8MM_USDHC2, + FSL_IMX8MM_USDHC3, + FSL_IMX8MM_VPU, + FSL_IMX8MM_VPU_BLK_CTRL, + FSL_IMX8MM_VPU_G1_DECODER, + FSL_IMX8MM_VPU_G2_DECODER, + FSL_IMX8MM_WDOG1, + FSL_IMX8MM_WDOG2, + FSL_IMX8MM_WDOG3, +}; + +enum FslImx8mmIrqs { + FSL_IMX8MM_UART1_IRQ = 26, + FSL_IMX8MM_UART2_IRQ = 27, + FSL_IMX8MM_UART3_IRQ = 28, + FSL_IMX8MM_UART4_IRQ = 29, +}; + +#endif /* FSL_IMX8MM_H */ -- 2.43.0
From: Gaurav Sharma <gaurav.sharma_7@nxp.com> Add configurable properties for register reset values that differ between i.MX 8M variants (Plus, Mini, etc.). This allows the same device implementation to be shared across multiple SoCs. Properties added: - arm-pll-fdiv-ctl0-reset: ARM PLL divider control reset value Default value is set to match i.MX 8MP reset value (0x000FA031). This can be overridden in the variant like iMX8MM with its own reset value. Reviewed-by: Bernhard Beschow <shentey@gmail.com> Signed-off-by: Gaurav Sharma <gaurav.sharma_7@nxp.com> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/misc/imx8mp_analog.c | 12 +++++++++++- include/hw/misc/imx8mp_analog.h | 3 +++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/hw/misc/imx8mp_analog.c b/hw/misc/imx8mp_analog.c index XXXXXXX..XXXXXXX 100644 --- a/hw/misc/imx8mp_analog.c +++ b/hw/misc/imx8mp_analog.c @@ -XXX,XX +XXX,XX @@ #include "qemu/log.h" #include "hw/misc/imx8mp_analog.h" +#include "hw/core/qdev-properties.h" #include "migration/vmstate.h" #define ANALOG_PLL_LOCK BIT(31) @@ -XXX,XX +XXX,XX @@ static void imx8mp_analog_reset(DeviceState *dev) s->analog[ANALOG_VPU_PLL_LOCKD_CTRL] = 0x0010003f; s->analog[ANALOG_VPU_PLL_MNIT_CTRL] = 0x00280081; s->analog[ANALOG_ARM_PLL_GEN_CTRL] = 0x00000810; - s->analog[ANALOG_ARM_PLL_FDIV_CTL0] = 0x000fa031; + + /* Use property value instead of hardcoded */ + s->analog[ANALOG_ARM_PLL_FDIV_CTL0] = s->arm_pll_fdiv_ctl0_reset; + s->analog[ANALOG_ARM_PLL_LOCKD_CTRL] = 0x0010003f; s->analog[ANALOG_ARM_PLL_MNIT_CTRL] = 0x00280081; s->analog[ANALOG_SYS_PLL1_GEN_CTRL] = 0x0aaaa810; @@ -XXX,XX +XXX,XX @@ static const VMStateDescription imx8mp_analog_vmstate = { }, }; +static const Property imx8mp_analog_properties[] = { + DEFINE_PROP_UINT32("arm-pll-fdiv-ctl0-reset", IMX8MPAnalogState, + arm_pll_fdiv_ctl0_reset, 0x000fa031), /* imx8mp default */ +}; + static void imx8mp_analog_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); device_class_set_legacy_reset(dc, imx8mp_analog_reset); + device_class_set_props(dc, imx8mp_analog_properties); dc->vmsd = &imx8mp_analog_vmstate; dc->desc = "i.MX 8M Plus Analog Module"; } diff --git a/include/hw/misc/imx8mp_analog.h b/include/hw/misc/imx8mp_analog.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/misc/imx8mp_analog.h +++ b/include/hw/misc/imx8mp_analog.h @@ -XXX,XX +XXX,XX @@ struct IMX8MPAnalogState { } mmio; uint32_t analog[ANALOG_MAX]; + + /* Property for variant-specific reset values */ + uint32_t arm_pll_fdiv_ctl0_reset; }; #endif /* IMX8MP_ANALOG_H */ -- 2.43.0
From: Gaurav Sharma <gaurav.sharma_7@nxp.com> Add the Analog IP to i.MX8MM SoC. iMX8MM and i.MX8MP uses the same Analog IP so the analog ip source will be shared. The ARM PLL divider control register (arm-pll-fdiv-ctl0) has a different reset value on i.MX8MM (0x000fa030) compared to i.MX8MP (0x000fa031). So iMX8MM will be overriding this property with its own reset-value. Reviewed-by: Bernhard Beschow <shentey@gmail.com> Signed-off-by: Gaurav Sharma <gaurav.sharma_7@nxp.com> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/arm/Kconfig | 1 + hw/arm/fsl-imx8mm.c | 12 ++++++++++++ include/hw/arm/fsl-imx8mm.h | 2 ++ 3 files changed, 15 insertions(+) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -XXX,XX +XXX,XX @@ config FSL_IMX8MP_EVK config FSL_IMX8MM bool select ARM_GIC + select FSL_IMX8MP_ANALOG select IMX config FSL_IMX8MM_EVK diff --git a/hw/arm/fsl-imx8mm.c b/hw/arm/fsl-imx8mm.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/fsl-imx8mm.c +++ b/hw/arm/fsl-imx8mm.c @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_init(Object *obj) object_initialize_child(obj, "gic", &s->gic, gicv3_class_name()); + object_initialize_child(obj, "analog", &s->analog, TYPE_IMX8MP_ANALOG); + for (i = 0; i < FSL_IMX8MM_NUM_UARTS; i++) { g_autofree char *name = g_strdup_printf("uart%d", i + 1); object_initialize_child(obj, name, &s->uart[i], TYPE_IMX_SERIAL); @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) } } + /* Analog */ + object_property_set_uint(OBJECT(&s->analog), "arm-pll-fdiv-ctl0-reset", + 0x000fa030, &error_abort); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->analog), errp)) { + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->analog), 0, + fsl_imx8mm_memmap[FSL_IMX8MM_ANA_PLL].addr); + /* UARTs */ for (i = 0; i < FSL_IMX8MM_NUM_UARTS; i++) { static const struct { @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) /* Unimplemented devices */ for (i = 0; i < ARRAY_SIZE(fsl_imx8mm_memmap); i++) { switch (i) { + case FSL_IMX8MM_ANA_PLL: case FSL_IMX8MM_GIC_DIST: case FSL_IMX8MM_GIC_REDIST: case FSL_IMX8MM_RAM: diff --git a/include/hw/arm/fsl-imx8mm.h b/include/hw/arm/fsl-imx8mm.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/arm/fsl-imx8mm.h +++ b/include/hw/arm/fsl-imx8mm.h @@ -XXX,XX +XXX,XX @@ #include "cpu.h" #include "hw/char/imx_serial.h" #include "hw/intc/arm_gicv3_common.h" +#include "hw/misc/imx8mp_analog.h" #include "qom/object.h" #include "qemu/units.h" @@ -XXX,XX +XXX,XX @@ struct FslImx8mmState { ARMCPU cpu[FSL_IMX8MM_NUM_CPUS]; GICv3State gic; + IMX8MPAnalogState analog; IMXSerialState uart[FSL_IMX8MM_NUM_UARTS]; MemoryRegion ocram; }; -- 2.43.0
From: Gaurav Sharma <gaurav.sharma_7@nxp.com> Add the Clock Control Module (CCM) device to i.MX8MM SoC. The CCM implementation is shared with i.MX8MP as the register layout is identical between the two variants.Hence iMX8MM will be using the source of iMX8MP CCM. Reviewed-by: Bernhard Beschow <shentey@gmail.com> Signed-off-by: Gaurav Sharma <gaurav.sharma_7@nxp.com> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/arm/Kconfig | 1 + hw/arm/fsl-imx8mm.c | 10 ++++++++++ include/hw/arm/fsl-imx8mm.h | 2 ++ 3 files changed, 13 insertions(+) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -XXX,XX +XXX,XX @@ config FSL_IMX8MM bool select ARM_GIC select FSL_IMX8MP_ANALOG + select FSL_IMX8MP_CCM select IMX config FSL_IMX8MM_EVK diff --git a/hw/arm/fsl-imx8mm.c b/hw/arm/fsl-imx8mm.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/fsl-imx8mm.c +++ b/hw/arm/fsl-imx8mm.c @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_init(Object *obj) object_initialize_child(obj, "gic", &s->gic, gicv3_class_name()); + object_initialize_child(obj, "ccm", &s->ccm, TYPE_IMX8MP_CCM); + object_initialize_child(obj, "analog", &s->analog, TYPE_IMX8MP_ANALOG); for (i = 0; i < FSL_IMX8MM_NUM_UARTS; i++) { @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) } } + /* CCM */ + if (!sysbus_realize(SYS_BUS_DEVICE(&s->ccm), errp)) { + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->ccm), 0, + fsl_imx8mm_memmap[FSL_IMX8MM_CCM].addr); + /* Analog */ object_property_set_uint(OBJECT(&s->analog), "arm-pll-fdiv-ctl0-reset", 0x000fa030, &error_abort); @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) for (i = 0; i < ARRAY_SIZE(fsl_imx8mm_memmap); i++) { switch (i) { case FSL_IMX8MM_ANA_PLL: + case FSL_IMX8MM_CCM: case FSL_IMX8MM_GIC_DIST: case FSL_IMX8MM_GIC_REDIST: case FSL_IMX8MM_RAM: diff --git a/include/hw/arm/fsl-imx8mm.h b/include/hw/arm/fsl-imx8mm.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/arm/fsl-imx8mm.h +++ b/include/hw/arm/fsl-imx8mm.h @@ -XXX,XX +XXX,XX @@ #include "hw/char/imx_serial.h" #include "hw/intc/arm_gicv3_common.h" #include "hw/misc/imx8mp_analog.h" +#include "hw/misc/imx8mp_ccm.h" #include "qom/object.h" #include "qemu/units.h" @@ -XXX,XX +XXX,XX @@ struct FslImx8mmState { ARMCPU cpu[FSL_IMX8MM_NUM_CPUS]; GICv3State gic; + IMX8MPCCMState ccm; IMX8MPAnalogState analog; IMXSerialState uart[FSL_IMX8MM_NUM_UARTS]; MemoryRegion ocram; -- 2.43.0
From: Gaurav Sharma <gaurav.sharma_7@nxp.com> SNVS contains an RTC which allows Linux to deal correctly with time Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Bernhard Beschow <shentey@gmail.com> Signed-off-by: Gaurav Sharma <gaurav.sharma_7@nxp.com> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/arm/fsl-imx8mm.c | 10 ++++++++++ include/hw/arm/fsl-imx8mm.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/hw/arm/fsl-imx8mm.c b/hw/arm/fsl-imx8mm.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/fsl-imx8mm.c +++ b/hw/arm/fsl-imx8mm.c @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_init(Object *obj) object_initialize_child(obj, "analog", &s->analog, TYPE_IMX8MP_ANALOG); + object_initialize_child(obj, "snvs", &s->snvs, TYPE_IMX7_SNVS); + for (i = 0; i < FSL_IMX8MM_NUM_UARTS; i++) { g_autofree char *name = g_strdup_printf("uart%d", i + 1); object_initialize_child(obj, name, &s->uart[i], TYPE_IMX_SERIAL); @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) fsl_imx8mm_memmap[FSL_IMX8MM_OCRAM].addr, &s->ocram); + /* SNVS */ + if (!sysbus_realize(SYS_BUS_DEVICE(&s->snvs), errp)) { + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->snvs), 0, + fsl_imx8mm_memmap[FSL_IMX8MM_SNVS_HP].addr); + /* Unimplemented devices */ for (i = 0; i < ARRAY_SIZE(fsl_imx8mm_memmap); i++) { switch (i) { @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) case FSL_IMX8MM_GIC_REDIST: case FSL_IMX8MM_RAM: case FSL_IMX8MM_OCRAM: + case FSL_IMX8MM_SNVS_HP: case FSL_IMX8MM_UART1 ... FSL_IMX8MM_UART4: /* device implemented and treated above */ break; diff --git a/include/hw/arm/fsl-imx8mm.h b/include/hw/arm/fsl-imx8mm.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/arm/fsl-imx8mm.h +++ b/include/hw/arm/fsl-imx8mm.h @@ -XXX,XX +XXX,XX @@ #include "cpu.h" #include "hw/char/imx_serial.h" #include "hw/intc/arm_gicv3_common.h" +#include "hw/misc/imx7_snvs.h" #include "hw/misc/imx8mp_analog.h" #include "hw/misc/imx8mp_ccm.h" #include "qom/object.h" @@ -XXX,XX +XXX,XX @@ struct FslImx8mmState { GICv3State gic; IMX8MPCCMState ccm; IMX8MPAnalogState analog; + IMX7SNVSState snvs; IMXSerialState uart[FSL_IMX8MM_NUM_UARTS]; MemoryRegion ocram; }; -- 2.43.0
From: Gaurav Sharma <gaurav.sharma_7@nxp.com> It enables emulation of SD/MMC cards through a virtual SDHCI interface The emulated SDHCI controller allows guest OS to use emulated storage as a standard block device. This will allow running the images such as those generated by Buildroot. Reviewed-by: Philippe Mathieu-Daude <philmd@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Bernhard Beschow <shentey@gmail.com> Signed-off-by: Gaurav Sharma <gaurav.sharma_7@nxp.com> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/arm/Kconfig | 1 + hw/arm/fsl-imx8mm.c | 25 +++++++++++++++++++++++++ hw/arm/imx8mm-evk.c | 17 +++++++++++++++++ include/hw/arm/fsl-imx8mm.h | 7 +++++++ 4 files changed, 50 insertions(+) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -XXX,XX +XXX,XX @@ config FSL_IMX8MM select FSL_IMX8MP_ANALOG select FSL_IMX8MP_CCM select IMX + select SDHCI config FSL_IMX8MM_EVK bool diff --git a/hw/arm/fsl-imx8mm.c b/hw/arm/fsl-imx8mm.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/fsl-imx8mm.c +++ b/hw/arm/fsl-imx8mm.c @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_init(Object *obj) object_initialize_child(obj, name, &s->uart[i], TYPE_IMX_SERIAL); } + for (i = 0; i < FSL_IMX8MM_NUM_USDHCS; i++) { + g_autofree char *name = g_strdup_printf("usdhc%d", i + 1); + object_initialize_child(obj, name, &s->usdhc[i], TYPE_IMX_USDHC); + } } static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) fsl_imx8mm_memmap[FSL_IMX8MM_OCRAM].addr, &s->ocram); + /* USDHCs */ + for (i = 0; i < FSL_IMX8MM_NUM_USDHCS; i++) { + static const struct { + hwaddr addr; + unsigned int irq; + } usdhc_table[FSL_IMX8MM_NUM_USDHCS] = { + { fsl_imx8mm_memmap[FSL_IMX8MM_USDHC1].addr, FSL_IMX8MM_USDHC1_IRQ }, + { fsl_imx8mm_memmap[FSL_IMX8MM_USDHC2].addr, FSL_IMX8MM_USDHC2_IRQ }, + { fsl_imx8mm_memmap[FSL_IMX8MM_USDHC3].addr, FSL_IMX8MM_USDHC3_IRQ }, + }; + + if (!sysbus_realize(SYS_BUS_DEVICE(&s->usdhc[i]), errp)) { + return; + } + + sysbus_mmio_map(SYS_BUS_DEVICE(&s->usdhc[i]), 0, usdhc_table[i].addr); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->usdhc[i]), 0, + qdev_get_gpio_in(gicdev, usdhc_table[i].irq)); + } + /* SNVS */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->snvs), errp)) { return; @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) case FSL_IMX8MM_OCRAM: case FSL_IMX8MM_SNVS_HP: case FSL_IMX8MM_UART1 ... FSL_IMX8MM_UART4: + case FSL_IMX8MM_USDHC1 ... FSL_IMX8MM_USDHC3: /* device implemented and treated above */ break; diff --git a/hw/arm/imx8mm-evk.c b/hw/arm/imx8mm-evk.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/imx8mm-evk.c +++ b/hw/arm/imx8mm-evk.c @@ -XXX,XX +XXX,XX @@ static void imx8mm_evk_init(MachineState *machine) memory_region_add_subregion(get_system_memory(), FSL_IMX8MM_RAM_START, machine->ram); + for (int i = 0; i < FSL_IMX8MM_NUM_USDHCS; i++) { + BusState *bus; + DeviceState *carddev; + BlockBackend *blk; + DriveInfo *di = drive_get(IF_SD, i, 0); + + if (!di) { + continue; + } + + blk = blk_by_legacy_dinfo(di); + bus = qdev_get_child_bus(DEVICE(&s->usdhc[i]), "sd-bus"); + carddev = qdev_new(TYPE_SD_CARD); + qdev_prop_set_drive_err(carddev, "drive", blk, &error_fatal); + qdev_realize_and_unref(carddev, bus, &error_fatal); + } + if (!qtest_enabled()) { arm_load_kernel(&s->cpu[0], machine, &boot_info); } diff --git a/include/hw/arm/fsl-imx8mm.h b/include/hw/arm/fsl-imx8mm.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/arm/fsl-imx8mm.h +++ b/include/hw/arm/fsl-imx8mm.h @@ -XXX,XX +XXX,XX @@ #include "hw/misc/imx7_snvs.h" #include "hw/misc/imx8mp_analog.h" #include "hw/misc/imx8mp_ccm.h" +#include "hw/sd/sdhci.h" #include "qom/object.h" #include "qemu/units.h" @@ -XXX,XX +XXX,XX @@ enum FslImx8mmConfiguration { FSL_IMX8MM_NUM_CPUS = 4, FSL_IMX8MM_NUM_IRQS = 128, FSL_IMX8MM_NUM_UARTS = 4, + FSL_IMX8MM_NUM_USDHCS = 3, }; struct FslImx8mmState { @@ -XXX,XX +XXX,XX @@ struct FslImx8mmState { IMX7SNVSState snvs; IMXSerialState uart[FSL_IMX8MM_NUM_UARTS]; MemoryRegion ocram; + SDHCIState usdhc[FSL_IMX8MM_NUM_USDHCS]; }; enum FslImx8mmMemoryRegions { @@ -XXX,XX +XXX,XX @@ enum FslImx8mmMemoryRegions { }; enum FslImx8mmIrqs { + FSL_IMX8MM_USDHC1_IRQ = 22, + FSL_IMX8MM_USDHC2_IRQ = 23, + FSL_IMX8MM_USDHC3_IRQ = 24, + FSL_IMX8MM_UART1_IRQ = 26, FSL_IMX8MM_UART2_IRQ = 27, FSL_IMX8MM_UART3_IRQ = 28, -- 2.43.0
From: Gaurav Sharma <gaurav.sharma_7@nxp.com> This enables support for Designware PCI Express Controller emulation It provides a controlled environment to debug the linux pci subsystem Reviewed-by: Philippe Mathieu-Daude <philmd@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Bernhard Beschow <shentey@gmail.com> Signed-off-by: Gaurav Sharma <gaurav.sharma_7@nxp.com> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/arm/Kconfig | 3 +++ hw/arm/fsl-imx8mm.c | 30 ++++++++++++++++++++++++++++++ include/hw/arm/fsl-imx8mm.h | 10 ++++++++++ 3 files changed, 43 insertions(+) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -XXX,XX +XXX,XX @@ config FSL_IMX8MP_EVK config FSL_IMX8MM bool + imply PCI_DEVICES select ARM_GIC select FSL_IMX8MP_ANALOG select FSL_IMX8MP_CCM select IMX select SDHCI + select PCI_EXPRESS_DESIGNWARE + select PCI_EXPRESS_FSL_IMX8M_PHY config FSL_IMX8MM_EVK bool diff --git a/hw/arm/fsl-imx8mm.c b/hw/arm/fsl-imx8mm.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/fsl-imx8mm.c +++ b/hw/arm/fsl-imx8mm.c @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_init(Object *obj) g_autofree char *name = g_strdup_printf("usdhc%d", i + 1); object_initialize_child(obj, name, &s->usdhc[i], TYPE_IMX_USDHC); } + + object_initialize_child(obj, "pcie", &s->pcie, TYPE_DESIGNWARE_PCIE_HOST); + object_initialize_child(obj, "pcie_phy", &s->pcie_phy, + TYPE_FSL_IMX8M_PCIE_PHY); } static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) sysbus_mmio_map(SYS_BUS_DEVICE(&s->snvs), 0, fsl_imx8mm_memmap[FSL_IMX8MM_SNVS_HP].addr); + /* PCIe */ + if (!sysbus_realize(SYS_BUS_DEVICE(&s->pcie), errp)) { + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->pcie), 0, + fsl_imx8mm_memmap[FSL_IMX8MM_PCIE1].addr); + + sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie), 0, + qdev_get_gpio_in(gicdev, FSL_IMX8MM_PCI_INTA_IRQ)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie), 1, + qdev_get_gpio_in(gicdev, FSL_IMX8MM_PCI_INTB_IRQ)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie), 2, + qdev_get_gpio_in(gicdev, FSL_IMX8MM_PCI_INTC_IRQ)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie), 3, + qdev_get_gpio_in(gicdev, FSL_IMX8MM_PCI_INTD_IRQ)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie), 4, + qdev_get_gpio_in(gicdev, FSL_IMX8MM_PCI_MSI_IRQ)); + + if (!sysbus_realize(SYS_BUS_DEVICE(&s->pcie_phy), errp)) { + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->pcie_phy), 0, + fsl_imx8mm_memmap[FSL_IMX8MM_PCIE_PHY1].addr); + /* Unimplemented devices */ for (i = 0; i < ARRAY_SIZE(fsl_imx8mm_memmap); i++) { switch (i) { @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) case FSL_IMX8MM_CCM: case FSL_IMX8MM_GIC_DIST: case FSL_IMX8MM_GIC_REDIST: + case FSL_IMX8MM_PCIE1: + case FSL_IMX8MM_PCIE_PHY1: case FSL_IMX8MM_RAM: case FSL_IMX8MM_OCRAM: case FSL_IMX8MM_SNVS_HP: diff --git a/include/hw/arm/fsl-imx8mm.h b/include/hw/arm/fsl-imx8mm.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/arm/fsl-imx8mm.h +++ b/include/hw/arm/fsl-imx8mm.h @@ -XXX,XX +XXX,XX @@ #include "hw/misc/imx7_snvs.h" #include "hw/misc/imx8mp_analog.h" #include "hw/misc/imx8mp_ccm.h" +#include "hw/pci-host/designware.h" +#include "hw/pci-host/fsl_imx8m_phy.h" #include "hw/sd/sdhci.h" #include "qom/object.h" #include "qemu/units.h" @@ -XXX,XX +XXX,XX @@ struct FslImx8mmState { IMXSerialState uart[FSL_IMX8MM_NUM_UARTS]; MemoryRegion ocram; SDHCIState usdhc[FSL_IMX8MM_NUM_USDHCS]; + DesignwarePCIEHost pcie; + FslImx8mPciePhyState pcie_phy; }; enum FslImx8mmMemoryRegions { @@ -XXX,XX +XXX,XX @@ enum FslImx8mmIrqs { FSL_IMX8MM_UART2_IRQ = 27, FSL_IMX8MM_UART3_IRQ = 28, FSL_IMX8MM_UART4_IRQ = 29, + + FSL_IMX8MM_PCI_INTA_IRQ = 122, + FSL_IMX8MM_PCI_INTB_IRQ = 123, + FSL_IMX8MM_PCI_INTC_IRQ = 124, + FSL_IMX8MM_PCI_INTD_IRQ = 125, + FSL_IMX8MM_PCI_MSI_IRQ = 127, }; #endif /* FSL_IMX8MM_H */ -- 2.43.0
From: Gaurav Sharma <gaurav.sharma_7@nxp.com> Enabled GPIO controller emulation Also updated the GPIO IRQ lines of iMX8MM Reviewed-by: Philippe Mathieu-Daude <philmd@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Bernhard Beschow <shentey@gmail.com> Signed-off-by: Gaurav Sharma <gaurav.sharma_7@nxp.com> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/arm/fsl-imx8mm.c | 54 +++++++++++++++++++++++++++++++++++++ include/hw/arm/fsl-imx8mm.h | 14 ++++++++++ 2 files changed, 68 insertions(+) diff --git a/hw/arm/fsl-imx8mm.c b/hw/arm/fsl-imx8mm.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/fsl-imx8mm.c +++ b/hw/arm/fsl-imx8mm.c @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_init(Object *obj) object_initialize_child(obj, name, &s->uart[i], TYPE_IMX_SERIAL); } + for (i = 0; i < FSL_IMX8MM_NUM_GPIOS; i++) { + g_autofree char *name = g_strdup_printf("gpio%d", i + 1); + object_initialize_child(obj, name, &s->gpio[i], TYPE_IMX_GPIO); + } + for (i = 0; i < FSL_IMX8MM_NUM_USDHCS; i++) { g_autofree char *name = g_strdup_printf("usdhc%d", i + 1); object_initialize_child(obj, name, &s->usdhc[i], TYPE_IMX_USDHC); @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) fsl_imx8mm_memmap[FSL_IMX8MM_OCRAM].addr, &s->ocram); + /* GPIOs */ + for (i = 0; i < FSL_IMX8MM_NUM_GPIOS; i++) { + static const struct { + hwaddr addr; + unsigned int irq_low; + unsigned int irq_high; + } gpio_table[FSL_IMX8MM_NUM_GPIOS] = { + { + fsl_imx8mm_memmap[FSL_IMX8MM_GPIO1].addr, + FSL_IMX8MM_GPIO1_LOW_IRQ, + FSL_IMX8MM_GPIO1_HIGH_IRQ + }, + { + fsl_imx8mm_memmap[FSL_IMX8MM_GPIO2].addr, + FSL_IMX8MM_GPIO2_LOW_IRQ, + FSL_IMX8MM_GPIO2_HIGH_IRQ + }, + { + fsl_imx8mm_memmap[FSL_IMX8MM_GPIO3].addr, + FSL_IMX8MM_GPIO3_LOW_IRQ, + FSL_IMX8MM_GPIO3_HIGH_IRQ + }, + { + fsl_imx8mm_memmap[FSL_IMX8MM_GPIO4].addr, + FSL_IMX8MM_GPIO4_LOW_IRQ, + FSL_IMX8MM_GPIO4_HIGH_IRQ + }, + { + fsl_imx8mm_memmap[FSL_IMX8MM_GPIO5].addr, + FSL_IMX8MM_GPIO5_LOW_IRQ, + FSL_IMX8MM_GPIO5_HIGH_IRQ + }, + }; + object_property_set_bool(OBJECT(&s->gpio[i]), "has-edge-sel", true, + &error_abort); + object_property_set_bool(OBJECT(&s->gpio[i]), "has-upper-pin-irq", + true, &error_abort); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio[i]), errp)) { + return; + } + + sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio[i]), 0, gpio_table[i].addr); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 0, + qdev_get_gpio_in(gicdev, gpio_table[i].irq_low)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 1, + qdev_get_gpio_in(gicdev, gpio_table[i].irq_high)); + } + /* USDHCs */ for (i = 0; i < FSL_IMX8MM_NUM_USDHCS; i++) { static const struct { @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) case FSL_IMX8MM_CCM: case FSL_IMX8MM_GIC_DIST: case FSL_IMX8MM_GIC_REDIST: + case FSL_IMX8MM_GPIO1 ... FSL_IMX8MM_GPIO5: case FSL_IMX8MM_PCIE1: case FSL_IMX8MM_PCIE_PHY1: case FSL_IMX8MM_RAM: diff --git a/include/hw/arm/fsl-imx8mm.h b/include/hw/arm/fsl-imx8mm.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/arm/fsl-imx8mm.h +++ b/include/hw/arm/fsl-imx8mm.h @@ -XXX,XX +XXX,XX @@ #include "cpu.h" #include "hw/char/imx_serial.h" +#include "hw/gpio/imx_gpio.h" #include "hw/intc/arm_gicv3_common.h" #include "hw/misc/imx7_snvs.h" #include "hw/misc/imx8mp_analog.h" @@ -XXX,XX +XXX,XX @@ OBJECT_DECLARE_SIMPLE_TYPE(FslImx8mmState, FSL_IMX8MM) enum FslImx8mmConfiguration { FSL_IMX8MM_NUM_CPUS = 4, + FSL_IMX8MM_NUM_GPIOS = 5, FSL_IMX8MM_NUM_IRQS = 128, FSL_IMX8MM_NUM_UARTS = 4, FSL_IMX8MM_NUM_USDHCS = 3, @@ -XXX,XX +XXX,XX @@ struct FslImx8mmState { ARMCPU cpu[FSL_IMX8MM_NUM_CPUS]; GICv3State gic; + IMXGPIOState gpio[FSL_IMX8MM_NUM_GPIOS]; IMX8MPCCMState ccm; IMX8MPAnalogState analog; IMX7SNVSState snvs; @@ -XXX,XX +XXX,XX @@ enum FslImx8mmIrqs { FSL_IMX8MM_UART3_IRQ = 28, FSL_IMX8MM_UART4_IRQ = 29, + FSL_IMX8MM_GPIO1_LOW_IRQ = 64, + FSL_IMX8MM_GPIO1_HIGH_IRQ = 65, + FSL_IMX8MM_GPIO2_LOW_IRQ = 66, + FSL_IMX8MM_GPIO2_HIGH_IRQ = 67, + FSL_IMX8MM_GPIO3_LOW_IRQ = 68, + FSL_IMX8MM_GPIO3_HIGH_IRQ = 69, + FSL_IMX8MM_GPIO4_LOW_IRQ = 70, + FSL_IMX8MM_GPIO4_HIGH_IRQ = 71, + FSL_IMX8MM_GPIO5_LOW_IRQ = 72, + FSL_IMX8MM_GPIO5_HIGH_IRQ = 73, + FSL_IMX8MM_PCI_INTA_IRQ = 122, FSL_IMX8MM_PCI_INTB_IRQ = 123, FSL_IMX8MM_PCI_INTC_IRQ = 124, -- 2.43.0
From: Gaurav Sharma <gaurav.sharma_7@nxp.com> This can be used to test and debug I2C device drivers. Added I2C interrupts Reviewed-by: Philippe Mathieu-Daude <philmd@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Bernhard Beschow <shentey@gmail.com> Signed-off-by: Gaurav Sharma <gaurav.sharma_7@nxp.com> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/arm/Kconfig | 2 ++ hw/arm/fsl-imx8mm.c | 27 +++++++++++++++++++++++++++ include/hw/arm/fsl-imx8mm.h | 8 ++++++++ 3 files changed, 37 insertions(+) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -XXX,XX +XXX,XX @@ config FSL_IMX8MP_EVK config FSL_IMX8MM bool imply PCI_DEVICES + imply I2C_DEVICES select ARM_GIC select FSL_IMX8MP_ANALOG select FSL_IMX8MP_CCM select IMX + select IMX_I2C select SDHCI select PCI_EXPRESS_DESIGNWARE select PCI_EXPRESS_FSL_IMX8M_PHY diff --git a/hw/arm/fsl-imx8mm.c b/hw/arm/fsl-imx8mm.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/fsl-imx8mm.c +++ b/hw/arm/fsl-imx8mm.c @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_init(Object *obj) object_initialize_child(obj, name, &s->uart[i], TYPE_IMX_SERIAL); } + for (i = 0; i < FSL_IMX8MM_NUM_I2CS; i++) { + g_autofree char *name = g_strdup_printf("i2c%d", i + 1); + object_initialize_child(obj, name, &s->i2c[i], TYPE_IMX_I2C); + } + for (i = 0; i < FSL_IMX8MM_NUM_GPIOS; i++) { g_autofree char *name = g_strdup_printf("gpio%d", i + 1); object_initialize_child(obj, name, &s->gpio[i], TYPE_IMX_GPIO); @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) fsl_imx8mm_memmap[FSL_IMX8MM_OCRAM].addr, &s->ocram); + /* I2Cs */ + for (i = 0; i < FSL_IMX8MM_NUM_I2CS; i++) { + static const struct { + hwaddr addr; + unsigned int irq; + } i2c_table[FSL_IMX8MM_NUM_I2CS] = { + { fsl_imx8mm_memmap[FSL_IMX8MM_I2C1].addr, FSL_IMX8MM_I2C1_IRQ }, + { fsl_imx8mm_memmap[FSL_IMX8MM_I2C2].addr, FSL_IMX8MM_I2C2_IRQ }, + { fsl_imx8mm_memmap[FSL_IMX8MM_I2C3].addr, FSL_IMX8MM_I2C3_IRQ }, + { fsl_imx8mm_memmap[FSL_IMX8MM_I2C4].addr, FSL_IMX8MM_I2C4_IRQ }, + }; + + if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c[i]), errp)) { + return; + } + + sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c[i]), 0, i2c_table[i].addr); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c[i]), 0, + qdev_get_gpio_in(gicdev, i2c_table[i].irq)); + } + /* GPIOs */ for (i = 0; i < FSL_IMX8MM_NUM_GPIOS; i++) { static const struct { @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) case FSL_IMX8MM_GIC_DIST: case FSL_IMX8MM_GIC_REDIST: case FSL_IMX8MM_GPIO1 ... FSL_IMX8MM_GPIO5: + case FSL_IMX8MM_I2C1 ... FSL_IMX8MM_I2C4: case FSL_IMX8MM_PCIE1: case FSL_IMX8MM_PCIE_PHY1: case FSL_IMX8MM_RAM: diff --git a/include/hw/arm/fsl-imx8mm.h b/include/hw/arm/fsl-imx8mm.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/arm/fsl-imx8mm.h +++ b/include/hw/arm/fsl-imx8mm.h @@ -XXX,XX +XXX,XX @@ #include "cpu.h" #include "hw/char/imx_serial.h" #include "hw/gpio/imx_gpio.h" +#include "hw/i2c/imx_i2c.h" #include "hw/intc/arm_gicv3_common.h" #include "hw/misc/imx7_snvs.h" #include "hw/misc/imx8mp_analog.h" @@ -XXX,XX +XXX,XX @@ OBJECT_DECLARE_SIMPLE_TYPE(FslImx8mmState, FSL_IMX8MM) enum FslImx8mmConfiguration { FSL_IMX8MM_NUM_CPUS = 4, FSL_IMX8MM_NUM_GPIOS = 5, + FSL_IMX8MM_NUM_I2CS = 4, FSL_IMX8MM_NUM_IRQS = 128, FSL_IMX8MM_NUM_UARTS = 4, FSL_IMX8MM_NUM_USDHCS = 3, @@ -XXX,XX +XXX,XX @@ struct FslImx8mmState { IMX8MPCCMState ccm; IMX8MPAnalogState analog; IMX7SNVSState snvs; + IMXI2CState i2c[FSL_IMX8MM_NUM_I2CS]; IMXSerialState uart[FSL_IMX8MM_NUM_UARTS]; MemoryRegion ocram; SDHCIState usdhc[FSL_IMX8MM_NUM_USDHCS]; @@ -XXX,XX +XXX,XX @@ enum FslImx8mmIrqs { FSL_IMX8MM_UART3_IRQ = 28, FSL_IMX8MM_UART4_IRQ = 29, + FSL_IMX8MM_I2C1_IRQ = 35, + FSL_IMX8MM_I2C2_IRQ = 36, + FSL_IMX8MM_I2C3_IRQ = 37, + FSL_IMX8MM_I2C4_IRQ = 38, + FSL_IMX8MM_GPIO1_LOW_IRQ = 64, FSL_IMX8MM_GPIO1_HIGH_IRQ = 65, FSL_IMX8MM_GPIO2_LOW_IRQ = 66, -- 2.43.0
From: Gaurav Sharma <gaurav.sharma_7@nxp.com> It enables emulation of ECSPI in iMX8MM Added SPI IRQ lines Reviewed-by: Philippe Mathieu-Daude <philmd@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Bernhard Beschow <shentey@gmail.com> Signed-off-by: Gaurav Sharma <gaurav.sharma_7@nxp.com> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/arm/fsl-imx8mm.c | 26 ++++++++++++++++++++++++++ include/hw/arm/fsl-imx8mm.h | 7 +++++++ 2 files changed, 33 insertions(+) diff --git a/hw/arm/fsl-imx8mm.c b/hw/arm/fsl-imx8mm.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/fsl-imx8mm.c +++ b/hw/arm/fsl-imx8mm.c @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_init(Object *obj) object_initialize_child(obj, name, &s->usdhc[i], TYPE_IMX_USDHC); } + for (i = 0; i < FSL_IMX8MM_NUM_ECSPIS; i++) { + g_autofree char *name = g_strdup_printf("spi%d", i + 1); + object_initialize_child(obj, name, &s->spi[i], TYPE_IMX_SPI); + } + object_initialize_child(obj, "pcie", &s->pcie, TYPE_DESIGNWARE_PCIE_HOST); object_initialize_child(obj, "pcie_phy", &s->pcie_phy, TYPE_FSL_IMX8M_PCIE_PHY); @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) qdev_get_gpio_in(gicdev, usdhc_table[i].irq)); } + /* ECSPIs */ + for (i = 0; i < FSL_IMX8MM_NUM_ECSPIS; i++) { + static const struct { + hwaddr addr; + unsigned int irq; + } spi_table[FSL_IMX8MM_NUM_ECSPIS] = { + { fsl_imx8mm_memmap[FSL_IMX8MM_ECSPI1].addr, FSL_IMX8MM_ECSPI1_IRQ }, + { fsl_imx8mm_memmap[FSL_IMX8MM_ECSPI2].addr, FSL_IMX8MM_ECSPI2_IRQ }, + { fsl_imx8mm_memmap[FSL_IMX8MM_ECSPI3].addr, FSL_IMX8MM_ECSPI3_IRQ }, + }; + + if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), errp)) { + return; + } + + sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0, spi_table[i].addr); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->spi[i]), 0, + qdev_get_gpio_in(gicdev, spi_table[i].irq)); + } + /* SNVS */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->snvs), errp)) { return; @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) case FSL_IMX8MM_GIC_DIST: case FSL_IMX8MM_GIC_REDIST: case FSL_IMX8MM_GPIO1 ... FSL_IMX8MM_GPIO5: + case FSL_IMX8MM_ECSPI1 ... FSL_IMX8MM_ECSPI3: case FSL_IMX8MM_I2C1 ... FSL_IMX8MM_I2C4: case FSL_IMX8MM_PCIE1: case FSL_IMX8MM_PCIE_PHY1: diff --git a/include/hw/arm/fsl-imx8mm.h b/include/hw/arm/fsl-imx8mm.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/arm/fsl-imx8mm.h +++ b/include/hw/arm/fsl-imx8mm.h @@ -XXX,XX +XXX,XX @@ #include "hw/pci-host/designware.h" #include "hw/pci-host/fsl_imx8m_phy.h" #include "hw/sd/sdhci.h" +#include "hw/ssi/imx_spi.h" #include "qom/object.h" #include "qemu/units.h" @@ -XXX,XX +XXX,XX @@ OBJECT_DECLARE_SIMPLE_TYPE(FslImx8mmState, FSL_IMX8MM) enum FslImx8mmConfiguration { FSL_IMX8MM_NUM_CPUS = 4, + FSL_IMX8MM_NUM_ECSPIS = 3, FSL_IMX8MM_NUM_GPIOS = 5, FSL_IMX8MM_NUM_I2CS = 4, FSL_IMX8MM_NUM_IRQS = 128, @@ -XXX,XX +XXX,XX @@ struct FslImx8mmState { IMX8MPCCMState ccm; IMX8MPAnalogState analog; IMX7SNVSState snvs; + IMXSPIState spi[FSL_IMX8MM_NUM_ECSPIS]; IMXI2CState i2c[FSL_IMX8MM_NUM_I2CS]; IMXSerialState uart[FSL_IMX8MM_NUM_UARTS]; MemoryRegion ocram; @@ -XXX,XX +XXX,XX @@ enum FslImx8mmIrqs { FSL_IMX8MM_UART3_IRQ = 28, FSL_IMX8MM_UART4_IRQ = 29, + FSL_IMX8MM_ECSPI1_IRQ = 31, + FSL_IMX8MM_ECSPI2_IRQ = 32, + FSL_IMX8MM_ECSPI3_IRQ = 33, + FSL_IMX8MM_I2C1_IRQ = 35, FSL_IMX8MM_I2C2_IRQ = 36, FSL_IMX8MM_I2C3_IRQ = 37, -- 2.43.0
From: Gaurav Sharma <gaurav.sharma_7@nxp.com> It enables emulation of WDT in iMX8MM Added WDT IRQ lines Reviewed-by: Philippe Mathieu-Daude <philmd@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Bernhard Beschow <shentey@gmail.com> Signed-off-by: Gaurav Sharma <gaurav.sharma_7@nxp.com> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/arm/Kconfig | 1 + hw/arm/fsl-imx8mm.c | 28 ++++++++++++++++++++++++++++ include/hw/arm/fsl-imx8mm.h | 7 +++++++ 3 files changed, 36 insertions(+) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -XXX,XX +XXX,XX @@ config FSL_IMX8MM select SDHCI select PCI_EXPRESS_DESIGNWARE select PCI_EXPRESS_FSL_IMX8M_PHY + select WDT_IMX2 config FSL_IMX8MM_EVK bool diff --git a/hw/arm/fsl-imx8mm.c b/hw/arm/fsl-imx8mm.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/fsl-imx8mm.c +++ b/hw/arm/fsl-imx8mm.c @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_init(Object *obj) object_initialize_child(obj, name, &s->spi[i], TYPE_IMX_SPI); } + for (i = 0; i < FSL_IMX8MM_NUM_WDTS; i++) { + g_autofree char *name = g_strdup_printf("wdt%d", i); + object_initialize_child(obj, name, &s->wdt[i], TYPE_IMX2_WDT); + } + object_initialize_child(obj, "pcie", &s->pcie, TYPE_DESIGNWARE_PCIE_HOST); object_initialize_child(obj, "pcie_phy", &s->pcie_phy, TYPE_FSL_IMX8M_PCIE_PHY); @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) sysbus_mmio_map(SYS_BUS_DEVICE(&s->snvs), 0, fsl_imx8mm_memmap[FSL_IMX8MM_SNVS_HP].addr); + /* Watchdogs */ + for (i = 0; i < FSL_IMX8MM_NUM_WDTS; i++) { + static const struct { + hwaddr addr; + unsigned int irq; + } wdog_table[FSL_IMX8MM_NUM_WDTS] = { + { fsl_imx8mm_memmap[FSL_IMX8MM_WDOG1].addr, FSL_IMX8MM_WDOG1_IRQ }, + { fsl_imx8mm_memmap[FSL_IMX8MM_WDOG2].addr, FSL_IMX8MM_WDOG2_IRQ }, + { fsl_imx8mm_memmap[FSL_IMX8MM_WDOG3].addr, FSL_IMX8MM_WDOG3_IRQ }, + }; + + object_property_set_bool(OBJECT(&s->wdt[i]), "pretimeout-support", + true, &error_abort); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), errp)) { + return; + } + + sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[i]), 0, wdog_table[i].addr); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->wdt[i]), 0, + qdev_get_gpio_in(gicdev, wdog_table[i].irq)); + } + /* PCIe */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->pcie), errp)) { return; @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) case FSL_IMX8MM_SNVS_HP: case FSL_IMX8MM_UART1 ... FSL_IMX8MM_UART4: case FSL_IMX8MM_USDHC1 ... FSL_IMX8MM_USDHC3: + case FSL_IMX8MM_WDOG1 ... FSL_IMX8MM_WDOG3: /* device implemented and treated above */ break; diff --git a/include/hw/arm/fsl-imx8mm.h b/include/hw/arm/fsl-imx8mm.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/arm/fsl-imx8mm.h +++ b/include/hw/arm/fsl-imx8mm.h @@ -XXX,XX +XXX,XX @@ #include "hw/pci-host/fsl_imx8m_phy.h" #include "hw/sd/sdhci.h" #include "hw/ssi/imx_spi.h" +#include "hw/watchdog/wdt_imx2.h" #include "qom/object.h" #include "qemu/units.h" @@ -XXX,XX +XXX,XX @@ enum FslImx8mmConfiguration { FSL_IMX8MM_NUM_IRQS = 128, FSL_IMX8MM_NUM_UARTS = 4, FSL_IMX8MM_NUM_USDHCS = 3, + FSL_IMX8MM_NUM_WDTS = 3, }; struct FslImx8mmState { @@ -XXX,XX +XXX,XX @@ struct FslImx8mmState { IMXSerialState uart[FSL_IMX8MM_NUM_UARTS]; MemoryRegion ocram; SDHCIState usdhc[FSL_IMX8MM_NUM_USDHCS]; + IMX2WdtState wdt[FSL_IMX8MM_NUM_WDTS]; DesignwarePCIEHost pcie; FslImx8mPciePhyState pcie_phy; }; @@ -XXX,XX +XXX,XX @@ enum FslImx8mmIrqs { FSL_IMX8MM_GPIO5_LOW_IRQ = 72, FSL_IMX8MM_GPIO5_HIGH_IRQ = 73, + FSL_IMX8MM_WDOG1_IRQ = 78, + FSL_IMX8MM_WDOG2_IRQ = 79, + FSL_IMX8MM_WDOG3_IRQ = 10, + FSL_IMX8MM_PCI_INTA_IRQ = 122, FSL_IMX8MM_PCI_INTB_IRQ = 123, FSL_IMX8MM_PCI_INTC_IRQ = 124, -- 2.43.0
From: Gaurav Sharma <gaurav.sharma_7@nxp.com> It enables emulation of GPT in iMX8MM Added GPT IRQ lines Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Bernhard Beschow <shentey@gmail.com> Signed-off-by: Gaurav Sharma <gaurav.sharma_7@nxp.com> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/arm/Kconfig | 1 + hw/arm/fsl-imx8mm.c | 54 +++++++++++++++++++++++++++++++++++++ hw/timer/imx_gpt.c | 26 ++++++++++++++++++ include/hw/arm/fsl-imx8mm.h | 11 ++++++++ include/hw/timer/imx_gpt.h | 2 ++ 5 files changed, 94 insertions(+) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -XXX,XX +XXX,XX @@ config FSL_IMX8MM select FSL_IMX8MP_CCM select IMX select IMX_I2C + select OR_IRQ select SDHCI select PCI_EXPRESS_DESIGNWARE select PCI_EXPRESS_FSL_IMX8M_PHY diff --git a/hw/arm/fsl-imx8mm.c b/hw/arm/fsl-imx8mm.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/fsl-imx8mm.c +++ b/hw/arm/fsl-imx8mm.c @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_init(Object *obj) object_initialize_child(obj, name, &s->uart[i], TYPE_IMX_SERIAL); } + for (i = 0; i < FSL_IMX8MM_NUM_GPTS; i++) { + g_autofree char *name = g_strdup_printf("gpt%d", i + 1); + object_initialize_child(obj, name, &s->gpt[i], TYPE_IMX8MM_GPT); + } + object_initialize_child(obj, "gpt5-gpt6-irq", &s->gpt5_gpt6_irq, + TYPE_OR_IRQ); + for (i = 0; i < FSL_IMX8MM_NUM_I2CS; i++) { g_autofree char *name = g_strdup_printf("i2c%d", i + 1); object_initialize_child(obj, name, &s->i2c[i], TYPE_IMX_I2C); @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) fsl_imx8mm_memmap[FSL_IMX8MM_OCRAM].addr, &s->ocram); + /* GPTs */ + object_property_set_int(OBJECT(&s->gpt5_gpt6_irq), "num-lines", 2, + &error_abort); + if (!qdev_realize(DEVICE(&s->gpt5_gpt6_irq), NULL, errp)) { + return; + } + + qdev_connect_gpio_out(DEVICE(&s->gpt5_gpt6_irq), 0, + qdev_get_gpio_in(gicdev, FSL_IMX8MM_GPT5_GPT6_IRQ)); + + for (i = 0; i < FSL_IMX8MM_NUM_GPTS; i++) { + hwaddr gpt_addrs[FSL_IMX8MM_NUM_GPTS] = { + fsl_imx8mm_memmap[FSL_IMX8MM_GPT1].addr, + fsl_imx8mm_memmap[FSL_IMX8MM_GPT2].addr, + fsl_imx8mm_memmap[FSL_IMX8MM_GPT3].addr, + fsl_imx8mm_memmap[FSL_IMX8MM_GPT4].addr, + fsl_imx8mm_memmap[FSL_IMX8MM_GPT5].addr, + fsl_imx8mm_memmap[FSL_IMX8MM_GPT6].addr, + }; + + s->gpt[i].ccm = IMX_CCM(&s->ccm); + + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpt[i]), errp)) { + return; + } + + sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpt[i]), 0, gpt_addrs[i]); + + if (i < FSL_IMX8MM_NUM_GPTS - 2) { + static const unsigned int gpt_irqs[FSL_IMX8MM_NUM_GPTS - 2] = { + FSL_IMX8MM_GPT1_IRQ, + FSL_IMX8MM_GPT2_IRQ, + FSL_IMX8MM_GPT3_IRQ, + FSL_IMX8MM_GPT4_IRQ, + }; + + sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpt[i]), 0, + qdev_get_gpio_in(gicdev, gpt_irqs[i])); + } else { + int irq = i - FSL_IMX8MM_NUM_GPTS + 2; + + sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpt[i]), 0, + qdev_get_gpio_in(DEVICE(&s->gpt5_gpt6_irq), irq)); + } + } + /* I2Cs */ for (i = 0; i < FSL_IMX8MM_NUM_I2CS; i++) { static const struct { @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) case FSL_IMX8MM_GIC_DIST: case FSL_IMX8MM_GIC_REDIST: case FSL_IMX8MM_GPIO1 ... FSL_IMX8MM_GPIO5: + case FSL_IMX8MM_GPT1 ... FSL_IMX8MM_GPT6: case FSL_IMX8MM_ECSPI1 ... FSL_IMX8MM_ECSPI3: case FSL_IMX8MM_I2C1 ... FSL_IMX8MM_I2C4: case FSL_IMX8MM_PCIE1: diff --git a/hw/timer/imx_gpt.c b/hw/timer/imx_gpt.c index XXXXXXX..XXXXXXX 100644 --- a/hw/timer/imx_gpt.c +++ b/hw/timer/imx_gpt.c @@ -XXX,XX +XXX,XX @@ * Originally written by Hans Jiang * Updated by Peter Chubb * Updated by Jean-Christophe Dubois <jcd@tribudubois.net> + * Updated by Gaurav Sharma <gaurav.sharma_7@nxp.com> * * This code is licensed under GPL version 2 or later. See * the COPYING file in the top-level directory. @@ -XXX,XX +XXX,XX @@ static const IMXClk imx8mp_gpt_clocks[] = { CLK_NONE, /* 111 not defined */ }; +static const IMXClk imx8mm_gpt_clocks[] = { + CLK_NONE, /* 000 No clock source */ + CLK_IPG, /* 001 ipg_clk, 532MHz */ + CLK_IPG_HIGH, /* 010 ipg_clk_highfreq */ + CLK_EXT, /* 011 External clock */ + CLK_32k, /* 100 ipg_clk_32k */ + CLK_HIGH, /* 101 ipg_clk_16M */ + CLK_NONE, /* 110 not defined */ + CLK_NONE, /* 111 not defined */ +}; + /* Must be called from within ptimer_transaction_begin/commit block */ static void imx_gpt_set_freq(IMXGPTState *s) { @@ -XXX,XX +XXX,XX @@ static void imx8mp_gpt_init(Object *obj) s->clocks = imx8mp_gpt_clocks; } +static void imx8mm_gpt_init(Object *obj) +{ + IMXGPTState *s = IMX_GPT(obj); + + s->clocks = imx8mm_gpt_clocks; +} + static const TypeInfo imx25_gpt_info = { .name = TYPE_IMX25_GPT, .parent = TYPE_SYS_BUS_DEVICE, @@ -XXX,XX +XXX,XX @@ static const TypeInfo imx8mp_gpt_info = { .instance_init = imx8mp_gpt_init, }; +static const TypeInfo imx8mm_gpt_info = { + .name = TYPE_IMX8MM_GPT, + .parent = TYPE_IMX25_GPT, + .instance_init = imx8mm_gpt_init, +}; + static void imx_gpt_register_types(void) { type_register_static(&imx25_gpt_info); @@ -XXX,XX +XXX,XX @@ static void imx_gpt_register_types(void) type_register_static(&imx6ul_gpt_info); type_register_static(&imx7_gpt_info); type_register_static(&imx8mp_gpt_info); + type_register_static(&imx8mm_gpt_info); } type_init(imx_gpt_register_types) diff --git a/include/hw/arm/fsl-imx8mm.h b/include/hw/arm/fsl-imx8mm.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/arm/fsl-imx8mm.h +++ b/include/hw/arm/fsl-imx8mm.h @@ -XXX,XX +XXX,XX @@ #include "hw/misc/imx7_snvs.h" #include "hw/misc/imx8mp_analog.h" #include "hw/misc/imx8mp_ccm.h" +#include "hw/or-irq.h" #include "hw/pci-host/designware.h" #include "hw/pci-host/fsl_imx8m_phy.h" #include "hw/sd/sdhci.h" #include "hw/ssi/imx_spi.h" +#include "hw/timer/imx_gpt.h" #include "hw/watchdog/wdt_imx2.h" #include "qom/object.h" #include "qemu/units.h" @@ -XXX,XX +XXX,XX @@ enum FslImx8mmConfiguration { FSL_IMX8MM_NUM_CPUS = 4, FSL_IMX8MM_NUM_ECSPIS = 3, FSL_IMX8MM_NUM_GPIOS = 5, + FSL_IMX8MM_NUM_GPTS = 6, FSL_IMX8MM_NUM_I2CS = 4, FSL_IMX8MM_NUM_IRQS = 128, FSL_IMX8MM_NUM_UARTS = 4, @@ -XXX,XX +XXX,XX @@ struct FslImx8mmState { ARMCPU cpu[FSL_IMX8MM_NUM_CPUS]; GICv3State gic; + IMXGPTState gpt[FSL_IMX8MM_NUM_GPTS]; IMXGPIOState gpio[FSL_IMX8MM_NUM_GPIOS]; IMX8MPCCMState ccm; IMX8MPAnalogState analog; @@ -XXX,XX +XXX,XX @@ struct FslImx8mmState { IMX2WdtState wdt[FSL_IMX8MM_NUM_WDTS]; DesignwarePCIEHost pcie; FslImx8mPciePhyState pcie_phy; + OrIRQState gpt5_gpt6_irq; }; enum FslImx8mmMemoryRegions { @@ -XXX,XX +XXX,XX @@ enum FslImx8mmIrqs { FSL_IMX8MM_I2C3_IRQ = 37, FSL_IMX8MM_I2C4_IRQ = 38, + FSL_IMX8MM_GPT1_IRQ = 55, + FSL_IMX8MM_GPT2_IRQ = 54, + FSL_IMX8MM_GPT3_IRQ = 53, + FSL_IMX8MM_GPT4_IRQ = 52, + FSL_IMX8MM_GPT5_GPT6_IRQ = 51, + FSL_IMX8MM_GPIO1_LOW_IRQ = 64, FSL_IMX8MM_GPIO1_HIGH_IRQ = 65, FSL_IMX8MM_GPIO2_LOW_IRQ = 66, diff --git a/include/hw/timer/imx_gpt.h b/include/hw/timer/imx_gpt.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/timer/imx_gpt.h +++ b/include/hw/timer/imx_gpt.h @@ -XXX,XX +XXX,XX @@ * Originally written by Hans Jiang * Updated by Peter Chubb * Updated by Jean-Christophe Dubois <jcd@tribudubois.net> + * Updated by Gaurav Sharma <gaurav.sharma_7@nxp.com> * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -XXX,XX +XXX,XX @@ #define TYPE_IMX6UL_GPT "imx6ul.gpt" #define TYPE_IMX7_GPT "imx7.gpt" #define TYPE_IMX8MP_GPT "imx8mp.gpt" +#define TYPE_IMX8MM_GPT "imx8mm.gpt" #define TYPE_IMX_GPT TYPE_IMX25_GPT -- 2.43.0
From: Gaurav Sharma <gaurav.sharma_7@nxp.com> It enables emulation of ENET ethernet controller in iMX8MM Enables testing and debugging of network dependent drivers Added ENET MAC IRQ lines Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Bernhard Beschow <shentey@gmail.com> Signed-off-by: Gaurav Sharma <gaurav.sharma_7@nxp.com> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/arm/Kconfig | 1 + hw/arm/fsl-imx8mm.c | 24 ++++++++++++++++++++++++ hw/arm/imx8mm-evk.c | 1 + include/hw/arm/fsl-imx8mm.h | 10 +++++++++- 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -XXX,XX +XXX,XX @@ config FSL_IMX8MM select FSL_IMX8MP_ANALOG select FSL_IMX8MP_CCM select IMX + select IMX_FEC select IMX_I2C select OR_IRQ select SDHCI diff --git a/hw/arm/fsl-imx8mm.c b/hw/arm/fsl-imx8mm.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/fsl-imx8mm.c +++ b/hw/arm/fsl-imx8mm.c @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_init(Object *obj) object_initialize_child(obj, name, &s->wdt[i], TYPE_IMX2_WDT); } + object_initialize_child(obj, "eth0", &s->enet, TYPE_IMX_ENET); + object_initialize_child(obj, "pcie", &s->pcie, TYPE_DESIGNWARE_PCIE_HOST); object_initialize_child(obj, "pcie_phy", &s->pcie_phy, TYPE_FSL_IMX8M_PCIE_PHY); @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) qdev_get_gpio_in(gicdev, spi_table[i].irq)); } + /* ENET1 */ + object_property_set_uint(OBJECT(&s->enet), "phy-num", s->phy_num, + &error_abort); + object_property_set_uint(OBJECT(&s->enet), "tx-ring-num", 3, &error_abort); + qemu_configure_nic_device(DEVICE(&s->enet), true, NULL); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->enet), errp)) { + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->enet), 0, + fsl_imx8mm_memmap[FSL_IMX8MM_ENET1].addr); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->enet), 0, + qdev_get_gpio_in(gicdev, FSL_IMX8MM_ENET1_MAC_IRQ)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->enet), 1, + qdev_get_gpio_in(gicdev, FSL_IMX6_ENET1_MAC_1588_IRQ)); + /* SNVS */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->snvs), errp)) { return; @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) case FSL_IMX8MM_GPIO1 ... FSL_IMX8MM_GPIO5: case FSL_IMX8MM_GPT1 ... FSL_IMX8MM_GPT6: case FSL_IMX8MM_ECSPI1 ... FSL_IMX8MM_ECSPI3: + case FSL_IMX8MM_ENET1: case FSL_IMX8MM_I2C1 ... FSL_IMX8MM_I2C4: case FSL_IMX8MM_PCIE1: case FSL_IMX8MM_PCIE_PHY1: @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) } } +static const Property fsl_imx8mm_properties[] = { + DEFINE_PROP_UINT32("fec1-phy-num", FslImx8mmState, phy_num, 0), + DEFINE_PROP_BOOL("fec1-phy-connected", FslImx8mmState, phy_connected, true), +}; + static void fsl_imx8mm_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); + device_class_set_props(dc, fsl_imx8mm_properties); dc->realize = fsl_imx8mm_realize; dc->desc = "i.MX 8MM SoC"; diff --git a/hw/arm/imx8mm-evk.c b/hw/arm/imx8mm-evk.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/imx8mm-evk.c +++ b/hw/arm/imx8mm-evk.c @@ -XXX,XX +XXX,XX @@ static void imx8mm_evk_init(MachineState *machine) s = FSL_IMX8MM(object_new_with_props(TYPE_FSL_IMX8MM, OBJECT(machine), "soc", &error_fatal, NULL)); + object_property_set_uint(OBJECT(s), "fec1-phy-num", 1, &error_fatal); sysbus_realize_and_unref(SYS_BUS_DEVICE(s), &error_fatal); memory_region_add_subregion(get_system_memory(), FSL_IMX8MM_RAM_START, diff --git a/include/hw/arm/fsl-imx8mm.h b/include/hw/arm/fsl-imx8mm.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/arm/fsl-imx8mm.h +++ b/include/hw/arm/fsl-imx8mm.h @@ -XXX,XX +XXX,XX @@ #include "hw/misc/imx7_snvs.h" #include "hw/misc/imx8mp_analog.h" #include "hw/misc/imx8mp_ccm.h" -#include "hw/or-irq.h" +#include "hw/net/imx_fec.h" +#include "hw/core/or-irq.h" #include "hw/pci-host/designware.h" #include "hw/pci-host/fsl_imx8m_phy.h" #include "hw/sd/sdhci.h" @@ -XXX,XX +XXX,XX @@ struct FslImx8mmState { IMXI2CState i2c[FSL_IMX8MM_NUM_I2CS]; IMXSerialState uart[FSL_IMX8MM_NUM_UARTS]; MemoryRegion ocram; + IMXFECState enet; SDHCIState usdhc[FSL_IMX8MM_NUM_USDHCS]; IMX2WdtState wdt[FSL_IMX8MM_NUM_WDTS]; DesignwarePCIEHost pcie; FslImx8mPciePhyState pcie_phy; OrIRQState gpt5_gpt6_irq; + + uint32_t phy_num; + bool phy_connected; }; enum FslImx8mmMemoryRegions { @@ -XXX,XX +XXX,XX @@ enum FslImx8mmIrqs { FSL_IMX8MM_WDOG2_IRQ = 79, FSL_IMX8MM_WDOG3_IRQ = 10, + FSL_IMX8MM_ENET1_MAC_IRQ = 118, + FSL_IMX6_ENET1_MAC_1588_IRQ = 121, + FSL_IMX8MM_PCI_INTA_IRQ = 122, FSL_IMX8MM_PCI_INTB_IRQ = 123, FSL_IMX8MM_PCI_INTC_IRQ = 124, -- 2.43.0
From: Gaurav Sharma <gaurav.sharma_7@nxp.com> It enables emulation of USB on iMX8MM Enables testing and debugging of USB drivers Reviewed-by: Philippe Mathieu-Daude <philmd@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Bernhard Beschow <shentey@gmail.com> Signed-off-by: Gaurav Sharma <gaurav.sharma_7@nxp.com> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/arm/Kconfig | 1 + hw/arm/fsl-imx8mm.c | 27 +++++++++++++++++++++++++++ include/hw/arm/fsl-imx8mm.h | 6 ++++++ 3 files changed, 34 insertions(+) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -XXX,XX +XXX,XX @@ config FSL_IMX8MM select SDHCI select PCI_EXPRESS_DESIGNWARE select PCI_EXPRESS_FSL_IMX8M_PHY + select USB_DWC3 select WDT_IMX2 config FSL_IMX8MM_EVK diff --git a/hw/arm/fsl-imx8mm.c b/hw/arm/fsl-imx8mm.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/fsl-imx8mm.c +++ b/hw/arm/fsl-imx8mm.c @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_init(Object *obj) object_initialize_child(obj, name, &s->usdhc[i], TYPE_IMX_USDHC); } + for (i = 0; i < FSL_IMX8MM_NUM_USBS; i++) { + g_autofree char *name = g_strdup_printf("usb%d", i); + object_initialize_child(obj, name, &s->usb[i], TYPE_USB_DWC3); + } + for (i = 0; i < FSL_IMX8MM_NUM_ECSPIS; i++) { g_autofree char *name = g_strdup_printf("spi%d", i + 1); object_initialize_child(obj, name, &s->spi[i], TYPE_IMX_SPI); @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) qdev_get_gpio_in(gicdev, usdhc_table[i].irq)); } + /* USBs */ + for (i = 0; i < FSL_IMX8MM_NUM_USBS; i++) { + static const struct { + hwaddr addr; + unsigned int irq; + } usb_table[FSL_IMX8MM_NUM_USBS] = { + { fsl_imx8mm_memmap[FSL_IMX8MM_USB1].addr, FSL_IMX8MM_USB1_IRQ }, + { fsl_imx8mm_memmap[FSL_IMX8MM_USB2].addr, FSL_IMX8MM_USB2_IRQ }, + }; + + qdev_prop_set_uint32(DEVICE(&s->usb[i].sysbus_xhci), "p2", 1); + qdev_prop_set_uint32(DEVICE(&s->usb[i].sysbus_xhci), "p3", 1); + qdev_prop_set_uint32(DEVICE(&s->usb[i].sysbus_xhci), "slots", 2); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->usb[i]), errp)) { + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->usb[i]), 0, usb_table[i].addr); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->usb[i].sysbus_xhci), 0, + qdev_get_gpio_in(gicdev, usb_table[i].irq)); + } + /* ECSPIs */ for (i = 0; i < FSL_IMX8MM_NUM_ECSPIS; i++) { static const struct { @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) case FSL_IMX8MM_OCRAM: case FSL_IMX8MM_SNVS_HP: case FSL_IMX8MM_UART1 ... FSL_IMX8MM_UART4: + case FSL_IMX8MM_USB1 ... FSL_IMX8MM_USB2: case FSL_IMX8MM_USDHC1 ... FSL_IMX8MM_USDHC3: case FSL_IMX8MM_WDOG1 ... FSL_IMX8MM_WDOG3: /* device implemented and treated above */ diff --git a/include/hw/arm/fsl-imx8mm.h b/include/hw/arm/fsl-imx8mm.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/arm/fsl-imx8mm.h +++ b/include/hw/arm/fsl-imx8mm.h @@ -XXX,XX +XXX,XX @@ #include "hw/sd/sdhci.h" #include "hw/ssi/imx_spi.h" #include "hw/timer/imx_gpt.h" +#include "hw/usb/hcd-dwc3.h" #include "hw/watchdog/wdt_imx2.h" #include "qom/object.h" #include "qemu/units.h" @@ -XXX,XX +XXX,XX @@ enum FslImx8mmConfiguration { FSL_IMX8MM_NUM_I2CS = 4, FSL_IMX8MM_NUM_IRQS = 128, FSL_IMX8MM_NUM_UARTS = 4, + FSL_IMX8MM_NUM_USBS = 2, FSL_IMX8MM_NUM_USDHCS = 3, FSL_IMX8MM_NUM_WDTS = 3, }; @@ -XXX,XX +XXX,XX @@ struct FslImx8mmState { IMXFECState enet; SDHCIState usdhc[FSL_IMX8MM_NUM_USDHCS]; IMX2WdtState wdt[FSL_IMX8MM_NUM_WDTS]; + USBDWC3 usb[FSL_IMX8MM_NUM_USBS]; DesignwarePCIEHost pcie; FslImx8mPciePhyState pcie_phy; OrIRQState gpt5_gpt6_irq; @@ -XXX,XX +XXX,XX @@ enum FslImx8mmIrqs { FSL_IMX8MM_I2C3_IRQ = 37, FSL_IMX8MM_I2C4_IRQ = 38, + FSL_IMX8MM_USB1_IRQ = 40, + FSL_IMX8MM_USB2_IRQ = 41, + FSL_IMX8MM_GPT1_IRQ = 55, FSL_IMX8MM_GPT2_IRQ = 54, FSL_IMX8MM_GPT3_IRQ = 53, -- 2.43.0
From: Gaurav Sharma <gaurav.sharma_7@nxp.com> Added script that would validate the iMX8MM emulation by checking the linux console log. If it succeeds, it will return:- ok 1 test_imx8mm_evk.Imx8mmEvkMachine.test_aarch64_imx8mm_evk_usdhc Signed-off-by: Gaurav Sharma <gaurav.sharma_7@nxp.com> Reviewed-by: Thomas Huth <thuth@redhat.com> Reviewed-by: Bernhard Beschow <shentey@gmail.com> [PMM: Add missing blank lines that flake8 wants] Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- MAINTAINERS | 1 + tests/functional/aarch64/meson.build | 2 + tests/functional/aarch64/test_imx8mm_evk.py | 69 +++++++++++++++++++++ 3 files changed, 72 insertions(+) create mode 100755 tests/functional/aarch64/test_imx8mm_evk.py diff --git a/MAINTAINERS b/MAINTAINERS index XXXXXXX..XXXXXXX 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -XXX,XX +XXX,XX @@ F: hw/arm/fsl-imx8mm.c F: hw/arm/imx8mm-evk.c F: include/hw/arm/fsl-imx8mm.h F: docs/system/arm/imx8m.rst +F: tests/functional/aarch64/test_imx8mm_evk.py MCIMX8MP-EVK / i.MX8MP M: Bernhard Beschow <shentey@gmail.com> diff --git a/tests/functional/aarch64/meson.build b/tests/functional/aarch64/meson.build index XXXXXXX..XXXXXXX 100644 --- a/tests/functional/aarch64/meson.build +++ b/tests/functional/aarch64/meson.build @@ -XXX,XX +XXX,XX @@ test_aarch64_timeouts = { 'aspeed_ast2700a2' : 600, 'aspeed_ast2700fc' : 600, 'device_passthrough' : 720, + 'imx8mm_evk' : 240, 'imx8mp_evk' : 240, 'raspi4' : 480, 'reverse_debug' : 180, @@ -XXX,XX +XXX,XX @@ tests_aarch64_system_thorough = [ 'aspeed_ast2700fc', 'device_passthrough', 'hotplug_pci', + 'imx8mm_evk', 'imx8mp_evk', 'kvm', 'multiprocess', diff --git a/tests/functional/aarch64/test_imx8mm_evk.py b/tests/functional/aarch64/test_imx8mm_evk.py new file mode 100755 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/functional/aarch64/test_imx8mm_evk.py @@ -XXX,XX +XXX,XX @@ +#!/usr/bin/env python3 +# +# Functional test that boots a Linux kernel and checks the console +# +# SPDX-License-Identifier: GPL-2.0-or-later + +from qemu_test import LinuxKernelTest, Asset + + +class Imx8mmEvkMachine(LinuxKernelTest): + + ASSET_IMAGE = Asset( + ('https://cloud.debian.org/images/cloud/bookworm/20231210-1590/' + 'debian-12-generic-arm64-20231210-1590.tar.xz'), + '7ebf1577b32d5af6204df74b54ca2e4675de9b5a9fa14f3ff70b88eeb7b3b359') + + KERNEL_OFFSET = 0x51000000 + KERNEL_SIZE = 32622528 + INITRD_OFFSET = 0x76000000 + INITRD_SIZE = 30987766 + DTB_OFFSET = 0x64DB5000 + DTB_SIZE = 36812 + + def extract(self, in_path, out_path, offset, size): + try: + with open(in_path, "rb") as source: + source.seek(offset) + data = source.read(size) + with open(out_path, "wb") as target: + target.write(data) + except (IOError, ValueError) as e: + self.log.error(f"Failed to extract {out_path}: {e}") + raise + + def setUp(self): + super().setUp() + + self.image_path = self.scratch_file("disk.raw") + self.kernel_path = self.scratch_file("linux") + self.initrd_path = self.scratch_file("initrd.zstd") + self.dtb_path = self.scratch_file("imx8mm-evk.dtb") + + self.archive_extract(self.ASSET_IMAGE) + self.extract(self.image_path, self.kernel_path, + self.KERNEL_OFFSET, self.KERNEL_SIZE) + self.extract(self.image_path, self.initrd_path, + self.INITRD_OFFSET, self.INITRD_SIZE) + self.extract(self.image_path, self.dtb_path, + self.DTB_OFFSET, self.DTB_SIZE) + + def test_aarch64_imx8mm_evk_usdhc(self): + self.require_accelerator("tcg") + self.set_machine('imx8mm-evk') + self.vm.set_console(console_index=1) + self.vm.add_args('-m', '2G', + '-smp', '4', + '-kernel', self.kernel_path, + '-initrd', self.initrd_path, + '-dtb', self.dtb_path, + '-append', 'root=/dev/mmcblk2p1', + '-drive', f'file={self.image_path},if=sd,bus=2,' + 'format=raw,id=mmcblk2,snapshot=on') + + self.vm.launch() + self.wait_for_console_pattern('Welcome to ') + + +if __name__ == '__main__': + LinuxKernelTest.main() -- 2.43.0
From: Philippe Mathieu-Daudé <philmd@linaro.org> As mentioned by Richard in [*]: We don't actually need any specific endianness here, because every byte has the same value. So we could simply drop MO_TE. That would produce a store in host-endianness, which will be fractionally more efficient on some hosts. [*] https://lore.kernel.org/qemu-devel/d64d3576-9188-4e74-afdc-3492c9feb8e0@linaro.org/ Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-id: 20260414005348.4767-2-philmd@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/helper-a64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/arm/tcg/helper-a64.c b/target/arm/tcg/helper-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/helper-a64.c +++ b/target/arm/tcg/helper-a64.c @@ -XXX,XX +XXX,XX @@ static uint64_t set_step_tags(CPUARMState *env, uint64_t toaddr, * the page dirty and will use the fast path. */ uint64_t repldata = data * 0x0101010101010101ULL; - MemOpIdx oi16 = make_memop_idx(MO_TE | MO_128, memidx); + MemOpIdx oi16 = make_memop_idx(MO_128, memidx); cpu_st16_mmu(env, toaddr, int128_make128(repldata, repldata), oi16, ra); mte_mops_set_tags(env, toaddr, 16, *mtedesc); return 16; -- 2.43.0
From: Philippe Mathieu-Daudé <philmd@linaro.org> Extract the implicit MO_TE definition in order to replace it in the next commit. Mechanical change using: $ for n in UW UL UQ UO SW SL SQ; do \ sed -i -e "s/MO_TE$n/MO_TE | MO_$n/" \ $(git grep -l MO_TE$n target/arm); \ done Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260414005348.4767-3-philmd@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/m_helper.c | 6 +-- target/arm/tcg/mve_helper.c | 79 ++++++++++++++++++++----------------- 2 files changed, 45 insertions(+), 40 deletions(-) diff --git a/target/arm/tcg/m_helper.c b/target/arm/tcg/m_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/m_helper.c +++ b/target/arm/tcg/m_helper.c @@ -XXX,XX +XXX,XX @@ void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest) /* Note that these stores can throw exceptions on MPU faults */ ARMMMUIdx mmu_idx = arm_mmu_idx(env); - MemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, + MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, arm_to_core_mmu_idx(mmu_idx)); cpu_stl_mmu(env, sp, nextinst, oi, GETPC()); cpu_stl_mmu(env, sp + 4, saved_psr, oi, GETPC()); @@ -XXX,XX +XXX,XX @@ void HELPER(v7m_vlstm)(CPUARMState *env, uint32_t fptr) bool lspact = env->v7m.fpccr[s] & R_V7M_FPCCR_LSPACT_MASK; uintptr_t ra = GETPC(); ARMMMUIdx mmu_idx = arm_mmu_idx(env); - MemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, + MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, arm_to_core_mmu_idx(mmu_idx)); assert(env->v7m.secure); @@ -XXX,XX +XXX,XX @@ void HELPER(v7m_vlldm)(CPUARMState *env, uint32_t fptr) ARMCPU *cpu = env_archcpu(env); uintptr_t ra = GETPC(); ARMMMUIdx mmu_idx = arm_mmu_idx(env); - MemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, + MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, arm_to_core_mmu_idx(mmu_idx)); /* fptr is the value of Rn, the frame pointer we load the FP regs from */ diff --git a/target/arm/tcg/mve_helper.c b/target/arm/tcg/mve_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/mve_helper.c +++ b/target/arm/tcg/mve_helper.c @@ -XXX,XX +XXX,XX @@ static void mve_advance_vpt(CPUARMState *env) } DO_VLDR(vldrb, MO_UB, 1, uint8_t, ldb, 1, uint8_t) -DO_VLDR(vldrh, MO_TEUW, 2, uint16_t, ldw, 2, uint16_t) -DO_VLDR(vldrw, MO_TEUL, 4, uint32_t, ldl, 4, uint32_t) +DO_VLDR(vldrh, MO_TE | MO_UW, 2, uint16_t, ldw, 2, uint16_t) +DO_VLDR(vldrw, MO_TE | MO_UL, 4, uint32_t, ldl, 4, uint32_t) DO_VSTR(vstrb, MO_UB, 1, stb, 1, uint8_t) -DO_VSTR(vstrh, MO_TEUW, 2, stw, 2, uint16_t) -DO_VSTR(vstrw, MO_TEUL, 4, stl, 4, uint32_t) +DO_VSTR(vstrh, MO_TE | MO_UW, 2, stw, 2, uint16_t) +DO_VSTR(vstrw, MO_TE | MO_UL, 4, stl, 4, uint32_t) DO_VLDR(vldrb_sh, MO_SB, 1, int8_t, ldb, 2, int16_t) DO_VLDR(vldrb_sw, MO_SB, 1, int8_t, ldb, 4, int32_t) DO_VLDR(vldrb_uh, MO_UB, 1, uint8_t, ldb, 2, uint16_t) DO_VLDR(vldrb_uw, MO_UB, 1, uint8_t, ldb, 4, uint32_t) -DO_VLDR(vldrh_sw, MO_TESW, 2, int16_t, ldw, 4, int32_t) -DO_VLDR(vldrh_uw, MO_TEUW, 2, uint16_t, ldw, 4, uint32_t) +DO_VLDR(vldrh_sw, MO_TE | MO_SW, 2, int16_t, ldw, 4, int32_t) +DO_VLDR(vldrh_uw, MO_TE | MO_UW, 2, uint16_t, ldw, 4, uint32_t) DO_VSTR(vstrb_h, MO_UB, 1, stb, 2, int16_t) DO_VSTR(vstrb_w, MO_UB, 1, stb, 4, int32_t) -DO_VSTR(vstrh_w, MO_TEUW, 2, stw, 4, int32_t) +DO_VSTR(vstrh_w, MO_TE | MO_UW, 2, stw, 4, int32_t) #undef DO_VLDR #undef DO_VSTR @@ -XXX,XX +XXX,XX @@ DO_VSTR(vstrh_w, MO_TEUW, 2, stw, 4, int32_t) unsigned e; \ uint32_t addr; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, mmu_idx); \ + MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ for (e = 0; e < 16 / 4; e++, mask >>= 4, eci_mask >>= 4) { \ if (!(eci_mask & 1)) { \ continue; \ @@ -XXX,XX +XXX,XX @@ DO_VSTR(vstrh_w, MO_TEUW, 2, stw, 4, int32_t) unsigned e; \ uint32_t addr; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, mmu_idx); \ + MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ for (e = 0; e < 16 / 4; e++, mask >>= 4, eci_mask >>= 4) { \ if (!(eci_mask & 1)) { \ continue; \ @@ -XXX,XX +XXX,XX @@ DO_VSTR(vstrh_w, MO_TEUW, 2, stw, 4, int32_t) DO_VLDR_SG(vldrb_sg_sh, MO_SB, int8_t, ldb, 2, int16_t, uint16_t, ADDR_ADD, false) DO_VLDR_SG(vldrb_sg_sw, MO_SB, int8_t, ldb, 4, int32_t, uint32_t, ADDR_ADD, false) -DO_VLDR_SG(vldrh_sg_sw, MO_TESW, int16_t, ldw, 4, int32_t, uint32_t, ADDR_ADD, false) +DO_VLDR_SG(vldrh_sg_sw, MO_TE | MO_SW, int16_t, ldw, 4, + int32_t, uint32_t, ADDR_ADD, false) DO_VLDR_SG(vldrb_sg_ub, MO_UB, uint8_t, ldb, 1, uint8_t, uint8_t, ADDR_ADD, false) DO_VLDR_SG(vldrb_sg_uh, MO_UB, uint8_t, ldb, 2, uint16_t, uint16_t, ADDR_ADD, false) DO_VLDR_SG(vldrb_sg_uw, MO_UB, uint8_t, ldb, 4, uint32_t, uint32_t, ADDR_ADD, false) -DO_VLDR_SG(vldrh_sg_uh, MO_TEUW, uint16_t, ldw, 2, uint16_t, uint16_t, ADDR_ADD, false) -DO_VLDR_SG(vldrh_sg_uw, MO_TEUW, uint16_t, ldw, 4, uint32_t, uint32_t, ADDR_ADD, false) -DO_VLDR_SG(vldrw_sg_uw, MO_TEUL, uint32_t, ldl, 4, uint32_t, uint32_t, ADDR_ADD, false) +DO_VLDR_SG(vldrh_sg_uh, MO_TE | MO_UW, uint16_t, ldw, 2, + uint16_t, uint16_t, ADDR_ADD, false) +DO_VLDR_SG(vldrh_sg_uw, MO_TE | MO_UW, uint16_t, ldw, 4, + uint32_t, uint32_t, ADDR_ADD, false) +DO_VLDR_SG(vldrw_sg_uw, MO_TE | MO_UL, uint32_t, ldl, 4, + uint32_t, uint32_t, ADDR_ADD, false) DO_VLDR64_SG(vldrd_sg_ud, ADDR_ADD, false) -DO_VLDR_SG(vldrh_sg_os_sw, MO_TESW, int16_t, ldw, 4, +DO_VLDR_SG(vldrh_sg_os_sw, MO_TE | MO_SW, int16_t, ldw, 4, int32_t, uint32_t, ADDR_ADD_OSH, false) -DO_VLDR_SG(vldrh_sg_os_uh, MO_TEUW, uint16_t, ldw, 2, +DO_VLDR_SG(vldrh_sg_os_uh, MO_TE | MO_UW, uint16_t, ldw, 2, uint16_t, uint16_t, ADDR_ADD_OSH, false) -DO_VLDR_SG(vldrh_sg_os_uw, MO_TEUW, uint16_t, ldw, 4, +DO_VLDR_SG(vldrh_sg_os_uw, MO_TE | MO_UW, uint16_t, ldw, 4, uint32_t, uint32_t, ADDR_ADD_OSH, false) -DO_VLDR_SG(vldrw_sg_os_uw, MO_TEUL, uint32_t, ldl, 4, +DO_VLDR_SG(vldrw_sg_os_uw, MO_TE | MO_UL, uint32_t, ldl, 4, uint32_t, uint32_t, ADDR_ADD_OSW, false) DO_VLDR64_SG(vldrd_sg_os_ud, ADDR_ADD_OSD, false) DO_VSTR_SG(vstrb_sg_ub, MO_UB, stb, 1, uint8_t, ADDR_ADD, false) DO_VSTR_SG(vstrb_sg_uh, MO_UB, stb, 2, uint16_t, ADDR_ADD, false) DO_VSTR_SG(vstrb_sg_uw, MO_UB, stb, 4, uint32_t, ADDR_ADD, false) -DO_VSTR_SG(vstrh_sg_uh, MO_TEUW, stw, 2, uint16_t, ADDR_ADD, false) -DO_VSTR_SG(vstrh_sg_uw, MO_TEUW, stw, 4, uint32_t, ADDR_ADD, false) -DO_VSTR_SG(vstrw_sg_uw, MO_TEUL, stl, 4, uint32_t, ADDR_ADD, false) +DO_VSTR_SG(vstrh_sg_uh, MO_TE | MO_UW, stw, 2, uint16_t, ADDR_ADD, false) +DO_VSTR_SG(vstrh_sg_uw, MO_TE | MO_UW, stw, 4, uint32_t, ADDR_ADD, false) +DO_VSTR_SG(vstrw_sg_uw, MO_TE | MO_UL, stl, 4, uint32_t, ADDR_ADD, false) DO_VSTR64_SG(vstrd_sg_ud, ADDR_ADD, false) -DO_VSTR_SG(vstrh_sg_os_uh, MO_TEUW, stw, 2, uint16_t, ADDR_ADD_OSH, false) -DO_VSTR_SG(vstrh_sg_os_uw, MO_TEUW, stw, 4, uint32_t, ADDR_ADD_OSH, false) -DO_VSTR_SG(vstrw_sg_os_uw, MO_TEUL, stl, 4, uint32_t, ADDR_ADD_OSW, false) +DO_VSTR_SG(vstrh_sg_os_uh, MO_TE | MO_UW, stw, 2, uint16_t, ADDR_ADD_OSH, false) +DO_VSTR_SG(vstrh_sg_os_uw, MO_TE | MO_UW, stw, 4, uint32_t, ADDR_ADD_OSH, false) +DO_VSTR_SG(vstrw_sg_os_uw, MO_TE | MO_UL, stl, 4, uint32_t, ADDR_ADD_OSW, false) DO_VSTR64_SG(vstrd_sg_os_ud, ADDR_ADD_OSD, false) -DO_VLDR_SG(vldrw_sg_wb_uw, MO_TEUL, uint32_t, ldl, 4, uint32_t, uint32_t, ADDR_ADD, true) +DO_VLDR_SG(vldrw_sg_wb_uw, MO_TE | MO_UL, uint32_t, ldl, 4, + uint32_t, uint32_t, ADDR_ADD, true) DO_VLDR64_SG(vldrd_sg_wb_ud, ADDR_ADD, true) -DO_VSTR_SG(vstrw_sg_wb_uw, MO_TEUL, stl, 4, uint32_t, ADDR_ADD, true) +DO_VSTR_SG(vstrw_sg_wb_uw, MO_TE | MO_UL, stl, 4, uint32_t, ADDR_ADD, true) DO_VSTR64_SG(vstrd_sg_wb_ud, ADDR_ADD, true) /* @@ -XXX,XX +XXX,XX @@ DO_VSTR64_SG(vstrd_sg_wb_ud, ADDR_ADD, true) static const uint8_t off[4] = { O1, O2, O3, O4 }; \ uint32_t addr, data; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, mmu_idx); \ + MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ for (beat = 0; beat < 4; beat++, mask >>= 4) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VSTR64_SG(vstrd_sg_wb_ud, ADDR_ADD, true) int y; /* y counts 0 2 0 2 */ \ uint16_t *qd; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, mmu_idx); \ + MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ for (beat = 0, y = 0; beat < 4; beat++, mask >>= 4, y ^= 2) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VSTR64_SG(vstrd_sg_wb_ud, ADDR_ADD, true) uint32_t *qd; \ int y; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, mmu_idx); \ + MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ for (beat = 0; beat < 4; beat++, mask >>= 4) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VLD4W(vld43w, 6, 7, 8, 9) uint32_t addr, data; \ uint8_t *qd; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, mmu_idx); \ + MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ for (beat = 0; beat < 4; beat++, mask >>= 4) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VLD4W(vld43w, 6, 7, 8, 9) int e; \ uint16_t *qd; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, mmu_idx); \ + MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ for (beat = 0; beat < 4; beat++, mask >>= 4) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VLD4W(vld43w, 6, 7, 8, 9) uint32_t addr, data; \ uint32_t *qd; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, mmu_idx); \ + MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ for (beat = 0; beat < 4; beat++, mask >>= 4) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VLD2W(vld21w, 8, 12, 16, 20) static const uint8_t off[4] = { O1, O2, O3, O4 }; \ uint32_t addr, data; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, mmu_idx); \ + MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ for (beat = 0; beat < 4; beat++, mask >>= 4) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VLD2W(vld21w, 8, 12, 16, 20) int y; /* y counts 0 2 0 2 */ \ uint16_t *qd; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, mmu_idx); \ + MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ for (beat = 0, y = 0; beat < 4; beat++, mask >>= 4, y ^= 2) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VLD2W(vld21w, 8, 12, 16, 20) uint32_t *qd; \ int y; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, mmu_idx); \ + MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ for (beat = 0; beat < 4; beat++, mask >>= 4) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VST4W(vst43w, 6, 7, 8, 9) uint32_t addr, data; \ uint8_t *qd; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, mmu_idx); \ + MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ for (beat = 0; beat < 4; beat++, mask >>= 4) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VST4W(vst43w, 6, 7, 8, 9) int e; \ uint16_t *qd; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, mmu_idx); \ + MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ for (beat = 0; beat < 4; beat++, mask >>= 4) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VST4W(vst43w, 6, 7, 8, 9) uint32_t addr, data; \ uint32_t *qd; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, mmu_idx); \ + MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ for (beat = 0; beat < 4; beat++, mask >>= 4) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ -- 2.43.0
From: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260414005348.4767-4-philmd@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/mve_helper.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/target/arm/tcg/mve_helper.c b/target/arm/tcg/mve_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/mve_helper.c +++ b/target/arm/tcg/mve_helper.c @@ -XXX,XX +XXX,XX @@ static void mve_advance_vpt(CPUARMState *env) uint16_t eci_mask = mve_eci_mask(env); \ unsigned b, e; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MFLAG | MO_ALIGN, mmu_idx); \ + MemOpIdx oi = make_memop_idx(MO_TE | MFLAG | MO_ALIGN, \ + mmu_idx); \ /* \ * R_SXTM allows the dest reg to become UNKNOWN for abandoned \ * beats so we don't care if we update part of the dest and \ @@ -XXX,XX +XXX,XX @@ static void mve_advance_vpt(CPUARMState *env) uint16_t mask = mve_element_mask(env); \ unsigned b, e; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MFLAG | MO_ALIGN, mmu_idx); \ + MemOpIdx oi = make_memop_idx(MO_TE | MFLAG | MO_ALIGN, \ + mmu_idx); \ for (b = 0, e = 0; b < 16; b += ESIZE, e++) { \ if (mask & (1 << b)) { \ cpu_##STTYPE##_mmu(env, addr, d[H##ESIZE(e)], oi, GETPC()); \ @@ -XXX,XX +XXX,XX @@ static void mve_advance_vpt(CPUARMState *env) } DO_VLDR(vldrb, MO_UB, 1, uint8_t, ldb, 1, uint8_t) -DO_VLDR(vldrh, MO_TE | MO_UW, 2, uint16_t, ldw, 2, uint16_t) -DO_VLDR(vldrw, MO_TE | MO_UL, 4, uint32_t, ldl, 4, uint32_t) +DO_VLDR(vldrh, MO_UW, 2, uint16_t, ldw, 2, uint16_t) +DO_VLDR(vldrw, MO_UL, 4, uint32_t, ldl, 4, uint32_t) DO_VSTR(vstrb, MO_UB, 1, stb, 1, uint8_t) -DO_VSTR(vstrh, MO_TE | MO_UW, 2, stw, 2, uint16_t) -DO_VSTR(vstrw, MO_TE | MO_UL, 4, stl, 4, uint32_t) +DO_VSTR(vstrh, MO_UW, 2, stw, 2, uint16_t) +DO_VSTR(vstrw, MO_UL, 4, stl, 4, uint32_t) DO_VLDR(vldrb_sh, MO_SB, 1, int8_t, ldb, 2, int16_t) DO_VLDR(vldrb_sw, MO_SB, 1, int8_t, ldb, 4, int32_t) DO_VLDR(vldrb_uh, MO_UB, 1, uint8_t, ldb, 2, uint16_t) DO_VLDR(vldrb_uw, MO_UB, 1, uint8_t, ldb, 4, uint32_t) -DO_VLDR(vldrh_sw, MO_TE | MO_SW, 2, int16_t, ldw, 4, int32_t) -DO_VLDR(vldrh_uw, MO_TE | MO_UW, 2, uint16_t, ldw, 4, uint32_t) +DO_VLDR(vldrh_sw, MO_SW, 2, int16_t, ldw, 4, int32_t) +DO_VLDR(vldrh_uw, MO_UW, 2, uint16_t, ldw, 4, uint32_t) DO_VSTR(vstrb_h, MO_UB, 1, stb, 2, int16_t) DO_VSTR(vstrb_w, MO_UB, 1, stb, 4, int32_t) -DO_VSTR(vstrh_w, MO_TE | MO_UW, 2, stw, 4, int32_t) +DO_VSTR(vstrh_w, MO_UW, 2, stw, 4, int32_t) #undef DO_VLDR #undef DO_VSTR -- 2.43.0
From: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260414005348.4767-5-philmd@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/mve_helper.c | 43 +++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/target/arm/tcg/mve_helper.c b/target/arm/tcg/mve_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/mve_helper.c +++ b/target/arm/tcg/mve_helper.c @@ -XXX,XX +XXX,XX @@ DO_VSTR(vstrh_w, MO_UW, 2, stw, 4, int32_t) unsigned e; \ uint32_t addr; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MFLAG | MO_ALIGN, mmu_idx); \ + MemOpIdx oi = make_memop_idx(MO_TE | MFLAG | MO_ALIGN, \ + mmu_idx); \ for (e = 0; e < 16 / ESIZE; e++, mask >>= ESIZE, eci_mask >>= ESIZE) { \ if (!(eci_mask & 1)) { \ continue; \ @@ -XXX,XX +XXX,XX @@ DO_VSTR(vstrh_w, MO_UW, 2, stw, 4, int32_t) unsigned e; \ uint32_t addr; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MFLAG | MO_ALIGN, mmu_idx); \ + MemOpIdx oi = make_memop_idx(MO_TE | MFLAG | MO_ALIGN, \ + mmu_idx); \ for (e = 0; e < 16 / ESIZE; e++, mask >>= ESIZE, eci_mask >>= ESIZE) { \ if (!(eci_mask & 1)) { \ continue; \ @@ -XXX,XX +XXX,XX @@ DO_VSTR(vstrh_w, MO_UW, 2, stw, 4, int32_t) DO_VLDR_SG(vldrb_sg_sh, MO_SB, int8_t, ldb, 2, int16_t, uint16_t, ADDR_ADD, false) DO_VLDR_SG(vldrb_sg_sw, MO_SB, int8_t, ldb, 4, int32_t, uint32_t, ADDR_ADD, false) -DO_VLDR_SG(vldrh_sg_sw, MO_TE | MO_SW, int16_t, ldw, 4, - int32_t, uint32_t, ADDR_ADD, false) +DO_VLDR_SG(vldrh_sg_sw, MO_SW, int16_t, ldw, 4, int32_t, uint32_t, ADDR_ADD, false) DO_VLDR_SG(vldrb_sg_ub, MO_UB, uint8_t, ldb, 1, uint8_t, uint8_t, ADDR_ADD, false) DO_VLDR_SG(vldrb_sg_uh, MO_UB, uint8_t, ldb, 2, uint16_t, uint16_t, ADDR_ADD, false) DO_VLDR_SG(vldrb_sg_uw, MO_UB, uint8_t, ldb, 4, uint32_t, uint32_t, ADDR_ADD, false) -DO_VLDR_SG(vldrh_sg_uh, MO_TE | MO_UW, uint16_t, ldw, 2, - uint16_t, uint16_t, ADDR_ADD, false) -DO_VLDR_SG(vldrh_sg_uw, MO_TE | MO_UW, uint16_t, ldw, 4, - uint32_t, uint32_t, ADDR_ADD, false) -DO_VLDR_SG(vldrw_sg_uw, MO_TE | MO_UL, uint32_t, ldl, 4, - uint32_t, uint32_t, ADDR_ADD, false) +DO_VLDR_SG(vldrh_sg_uh, MO_UW, uint16_t, ldw, 2, uint16_t, uint16_t, ADDR_ADD, false) +DO_VLDR_SG(vldrh_sg_uw, MO_UW, uint16_t, ldw, 4, uint32_t, uint32_t, ADDR_ADD, false) +DO_VLDR_SG(vldrw_sg_uw, MO_UL, uint32_t, ldl, 4, uint32_t, uint32_t, ADDR_ADD, false) DO_VLDR64_SG(vldrd_sg_ud, ADDR_ADD, false) -DO_VLDR_SG(vldrh_sg_os_sw, MO_TE | MO_SW, int16_t, ldw, 4, +DO_VLDR_SG(vldrh_sg_os_sw, MO_SW, int16_t, ldw, 4, int32_t, uint32_t, ADDR_ADD_OSH, false) -DO_VLDR_SG(vldrh_sg_os_uh, MO_TE | MO_UW, uint16_t, ldw, 2, +DO_VLDR_SG(vldrh_sg_os_uh, MO_UW, uint16_t, ldw, 2, uint16_t, uint16_t, ADDR_ADD_OSH, false) -DO_VLDR_SG(vldrh_sg_os_uw, MO_TE | MO_UW, uint16_t, ldw, 4, +DO_VLDR_SG(vldrh_sg_os_uw, MO_UW, uint16_t, ldw, 4, uint32_t, uint32_t, ADDR_ADD_OSH, false) -DO_VLDR_SG(vldrw_sg_os_uw, MO_TE | MO_UL, uint32_t, ldl, 4, +DO_VLDR_SG(vldrw_sg_os_uw, MO_UL, uint32_t, ldl, 4, uint32_t, uint32_t, ADDR_ADD_OSW, false) DO_VLDR64_SG(vldrd_sg_os_ud, ADDR_ADD_OSD, false) DO_VSTR_SG(vstrb_sg_ub, MO_UB, stb, 1, uint8_t, ADDR_ADD, false) DO_VSTR_SG(vstrb_sg_uh, MO_UB, stb, 2, uint16_t, ADDR_ADD, false) DO_VSTR_SG(vstrb_sg_uw, MO_UB, stb, 4, uint32_t, ADDR_ADD, false) -DO_VSTR_SG(vstrh_sg_uh, MO_TE | MO_UW, stw, 2, uint16_t, ADDR_ADD, false) -DO_VSTR_SG(vstrh_sg_uw, MO_TE | MO_UW, stw, 4, uint32_t, ADDR_ADD, false) -DO_VSTR_SG(vstrw_sg_uw, MO_TE | MO_UL, stl, 4, uint32_t, ADDR_ADD, false) +DO_VSTR_SG(vstrh_sg_uh, MO_UW, stw, 2, uint16_t, ADDR_ADD, false) +DO_VSTR_SG(vstrh_sg_uw, MO_UW, stw, 4, uint32_t, ADDR_ADD, false) +DO_VSTR_SG(vstrw_sg_uw, MO_UL, stl, 4, uint32_t, ADDR_ADD, false) DO_VSTR64_SG(vstrd_sg_ud, ADDR_ADD, false) -DO_VSTR_SG(vstrh_sg_os_uh, MO_TE | MO_UW, stw, 2, uint16_t, ADDR_ADD_OSH, false) -DO_VSTR_SG(vstrh_sg_os_uw, MO_TE | MO_UW, stw, 4, uint32_t, ADDR_ADD_OSH, false) -DO_VSTR_SG(vstrw_sg_os_uw, MO_TE | MO_UL, stl, 4, uint32_t, ADDR_ADD_OSW, false) +DO_VSTR_SG(vstrh_sg_os_uh, MO_UW, stw, 2, uint16_t, ADDR_ADD_OSH, false) +DO_VSTR_SG(vstrh_sg_os_uw, MO_UW, stw, 4, uint32_t, ADDR_ADD_OSH, false) +DO_VSTR_SG(vstrw_sg_os_uw, MO_UL, stl, 4, uint32_t, ADDR_ADD_OSW, false) DO_VSTR64_SG(vstrd_sg_os_ud, ADDR_ADD_OSD, false) -DO_VLDR_SG(vldrw_sg_wb_uw, MO_TE | MO_UL, uint32_t, ldl, 4, - uint32_t, uint32_t, ADDR_ADD, true) +DO_VLDR_SG(vldrw_sg_wb_uw, MO_UL, uint32_t, ldl, 4, uint32_t, uint32_t, ADDR_ADD, true) DO_VLDR64_SG(vldrd_sg_wb_ud, ADDR_ADD, true) -DO_VSTR_SG(vstrw_sg_wb_uw, MO_TE | MO_UL, stl, 4, uint32_t, ADDR_ADD, true) +DO_VSTR_SG(vstrw_sg_wb_uw, MO_UL, stl, 4, uint32_t, ADDR_ADD, true) DO_VSTR64_SG(vstrd_sg_wb_ud, ADDR_ADD, true) /* -- 2.43.0
From: Philippe Mathieu-Daudé <philmd@linaro.org> Suggested-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260414005348.4767-6-philmd@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/internals.h | 6 ++++++ target/arm/tcg/mve_helper.c | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/target/arm/internals.h b/target/arm/internals.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -XXX,XX +XXX,XX @@ #include "exec/hwaddr.h" #include "exec/vaddr.h" #include "exec/breakpoint.h" +#include "exec/memop.h" #include "accel/tcg/tb-cpu-state.h" #include "hw/core/registerfields.h" #include "tcg/tcg-gvec-desc.h" @@ -XXX,XX +XXX,XX @@ #define BANK_HYP 6 #define BANK_MON 7 +static inline MemOp mo_endian(CPUARMState *env) +{ + return EX_TBFLAG_ANY(env->hflags, BE_DATA) ? MO_BE : MO_LE; +} + static inline int arm_env_mmu_index(CPUARMState *env) { return EX_TBFLAG_ANY(env->hflags, MMUIDX); diff --git a/target/arm/tcg/mve_helper.c b/target/arm/tcg/mve_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/mve_helper.c +++ b/target/arm/tcg/mve_helper.c @@ -XXX,XX +XXX,XX @@ DO_VSTR(vstrh_w, MO_UW, 2, stw, 4, int32_t) unsigned e; \ uint32_t addr; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ + MemOpIdx oi = make_memop_idx(mo_endian(env) | MO_UL | MO_ALIGN, \ + mmu_idx); \ for (e = 0; e < 16 / 4; e++, mask >>= 4, eci_mask >>= 4) { \ if (!(eci_mask & 1)) { \ continue; \ -- 2.43.0
From: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260414005348.4767-7-philmd@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/mve_helper.c | 47 +++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/target/arm/tcg/mve_helper.c b/target/arm/tcg/mve_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/mve_helper.c +++ b/target/arm/tcg/mve_helper.c @@ -XXX,XX +XXX,XX @@ static void mve_advance_vpt(CPUARMState *env) uint16_t eci_mask = mve_eci_mask(env); \ unsigned b, e; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TE | MFLAG | MO_ALIGN, \ + MemOpIdx oi = make_memop_idx(mo_endian(env) | MFLAG | MO_ALIGN, \ mmu_idx); \ /* \ * R_SXTM allows the dest reg to become UNKNOWN for abandoned \ @@ -XXX,XX +XXX,XX @@ static void mve_advance_vpt(CPUARMState *env) uint16_t mask = mve_element_mask(env); \ unsigned b, e; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TE | MFLAG | MO_ALIGN, \ + MemOpIdx oi = make_memop_idx(mo_endian(env) | MFLAG | MO_ALIGN, \ mmu_idx); \ for (b = 0, e = 0; b < 16; b += ESIZE, e++) { \ if (mask & (1 << b)) { \ @@ -XXX,XX +XXX,XX @@ DO_VSTR(vstrh_w, MO_UW, 2, stw, 4, int32_t) unsigned e; \ uint32_t addr; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TE | MFLAG | MO_ALIGN, \ + MemOpIdx oi = make_memop_idx(mo_endian(env) | MFLAG | MO_ALIGN, \ mmu_idx); \ for (e = 0; e < 16 / ESIZE; e++, mask >>= ESIZE, eci_mask >>= ESIZE) { \ if (!(eci_mask & 1)) { \ @@ -XXX,XX +XXX,XX @@ DO_VSTR(vstrh_w, MO_UW, 2, stw, 4, int32_t) unsigned e; \ uint32_t addr; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TE | MFLAG | MO_ALIGN, \ + MemOpIdx oi = make_memop_idx(mo_endian(env) | MFLAG | MO_ALIGN, \ mmu_idx); \ for (e = 0; e < 16 / ESIZE; e++, mask >>= ESIZE, eci_mask >>= ESIZE) { \ if (!(eci_mask & 1)) { \ @@ -XXX,XX +XXX,XX @@ DO_VSTR(vstrh_w, MO_UW, 2, stw, 4, int32_t) unsigned e; \ uint32_t addr; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ + MemOpIdx oi = make_memop_idx(mo_endian(env) | MO_UL | MO_ALIGN, \ + mmu_idx); \ for (e = 0; e < 16 / 4; e++, mask >>= 4, eci_mask >>= 4) { \ if (!(eci_mask & 1)) { \ continue; \ @@ -XXX,XX +XXX,XX @@ DO_VSTR64_SG(vstrd_sg_wb_ud, ADDR_ADD, true) static const uint8_t off[4] = { O1, O2, O3, O4 }; \ uint32_t addr, data; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ + MemOpIdx oi = make_memop_idx(mo_endian(env) | MO_UL | MO_ALIGN, \ + mmu_idx); \ for (beat = 0; beat < 4; beat++, mask >>= 4) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VSTR64_SG(vstrd_sg_wb_ud, ADDR_ADD, true) int y; /* y counts 0 2 0 2 */ \ uint16_t *qd; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ + MemOpIdx oi = make_memop_idx(mo_endian(env) | MO_UL | MO_ALIGN, \ + mmu_idx); \ for (beat = 0, y = 0; beat < 4; beat++, mask >>= 4, y ^= 2) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VSTR64_SG(vstrd_sg_wb_ud, ADDR_ADD, true) uint32_t *qd; \ int y; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ + MemOpIdx oi = make_memop_idx(mo_endian(env) | MO_UL | MO_ALIGN, \ + mmu_idx); \ for (beat = 0; beat < 4; beat++, mask >>= 4) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VLD4W(vld43w, 6, 7, 8, 9) uint32_t addr, data; \ uint8_t *qd; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ + MemOpIdx oi = make_memop_idx(mo_endian(env) | MO_UL | MO_ALIGN, \ + mmu_idx); \ for (beat = 0; beat < 4; beat++, mask >>= 4) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VLD4W(vld43w, 6, 7, 8, 9) int e; \ uint16_t *qd; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ + MemOpIdx oi = make_memop_idx(mo_endian(env) | MO_UL | MO_ALIGN, \ + mmu_idx); \ for (beat = 0; beat < 4; beat++, mask >>= 4) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VLD4W(vld43w, 6, 7, 8, 9) uint32_t addr, data; \ uint32_t *qd; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ + MemOpIdx oi = make_memop_idx(mo_endian(env) | MO_UL | MO_ALIGN, \ + mmu_idx); \ for (beat = 0; beat < 4; beat++, mask >>= 4) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VLD2W(vld21w, 8, 12, 16, 20) static const uint8_t off[4] = { O1, O2, O3, O4 }; \ uint32_t addr, data; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ + MemOpIdx oi = make_memop_idx(mo_endian(env) | MO_UL | MO_ALIGN, \ + mmu_idx); \ for (beat = 0; beat < 4; beat++, mask >>= 4) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VLD2W(vld21w, 8, 12, 16, 20) int y; /* y counts 0 2 0 2 */ \ uint16_t *qd; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ + MemOpIdx oi = make_memop_idx(mo_endian(env) | MO_UL | MO_ALIGN, \ + mmu_idx); \ for (beat = 0, y = 0; beat < 4; beat++, mask >>= 4, y ^= 2) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VLD2W(vld21w, 8, 12, 16, 20) uint32_t *qd; \ int y; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ + MemOpIdx oi = make_memop_idx(mo_endian(env) | MO_UL | MO_ALIGN, \ + mmu_idx); \ for (beat = 0; beat < 4; beat++, mask >>= 4) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VST4W(vst43w, 6, 7, 8, 9) uint32_t addr, data; \ uint8_t *qd; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ + MemOpIdx oi = make_memop_idx(mo_endian(env) | MO_UL | MO_ALIGN, \ + mmu_idx); \ for (beat = 0; beat < 4; beat++, mask >>= 4) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VST4W(vst43w, 6, 7, 8, 9) int e; \ uint16_t *qd; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ + MemOpIdx oi = make_memop_idx(mo_endian(env) | MO_UL | MO_ALIGN, \ + mmu_idx); \ for (beat = 0; beat < 4; beat++, mask >>= 4) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VST4W(vst43w, 6, 7, 8, 9) uint32_t addr, data; \ uint32_t *qd; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ + MemOpIdx oi = make_memop_idx(mo_endian(env) | MO_UL | MO_ALIGN, \ + mmu_idx); \ for (beat = 0; beat < 4; beat++, mask >>= 4) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ -- 2.43.0
From: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260414005348.4767-8-philmd@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/meson.build | 3 ++- target/arm/tcg/mve_helper.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/target/arm/tcg/meson.build b/target/arm/tcg/meson.build index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/meson.build +++ b/target/arm/tcg/meson.build @@ -XXX,XX +XXX,XX @@ arm_ss.add(when: 'TARGET_AARCH64', if_false: files('stubs32.c')) arm_ss.add(files( 'cpu32.c', 'm_helper.c', - 'mve_helper.c', )) arm_ss.add(when: 'TARGET_AARCH64', if_true: files( @@ -XXX,XX +XXX,XX @@ arm_common_system_ss.add( 'debug.c', 'hflags.c', 'gengvec.c', + 'mve_helper.c', 'neon_helper.c', 'op_helper.c', 'psci.c', @@ -XXX,XX +XXX,XX @@ arm_user_ss.add( 'debug.c', 'gengvec.c', 'hflags.c', + 'mve_helper.c', 'neon_helper.c', 'op_helper.c', 'tlb_helper.c', diff --git a/target/arm/tcg/mve_helper.c b/target/arm/tcg/mve_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/mve_helper.c +++ b/target/arm/tcg/mve_helper.c @@ -XXX,XX +XXX,XX @@ #include "helper-mve.h" #include "internals.h" #include "vec_internal.h" -#include "accel/tcg/cpu-ldst.h" +#include "accel/tcg/cpu-ldst-common.h" #include "tcg/tcg.h" #include "fpu/softfloat.h" #include "crypto/clmul.h" -- 2.43.0
From: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260414005348.4767-9-philmd@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/m_helper.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/target/arm/tcg/m_helper.c b/target/arm/tcg/m_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/m_helper.c +++ b/target/arm/tcg/m_helper.c @@ -XXX,XX +XXX,XX @@ void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest) /* Note that these stores can throw exceptions on MPU faults */ ARMMMUIdx mmu_idx = arm_mmu_idx(env); - MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, + MemOpIdx oi = make_memop_idx(mo_endian(env) | MO_UL | MO_ALIGN, arm_to_core_mmu_idx(mmu_idx)); cpu_stl_mmu(env, sp, nextinst, oi, GETPC()); cpu_stl_mmu(env, sp + 4, saved_psr, oi, GETPC()); @@ -XXX,XX +XXX,XX @@ void HELPER(v7m_vlstm)(CPUARMState *env, uint32_t fptr) bool lspact = env->v7m.fpccr[s] & R_V7M_FPCCR_LSPACT_MASK; uintptr_t ra = GETPC(); ARMMMUIdx mmu_idx = arm_mmu_idx(env); - MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, + MemOpIdx oi = make_memop_idx(mo_endian(env) | MO_UL | MO_ALIGN, arm_to_core_mmu_idx(mmu_idx)); assert(env->v7m.secure); @@ -XXX,XX +XXX,XX @@ void HELPER(v7m_vlldm)(CPUARMState *env, uint32_t fptr) ARMCPU *cpu = env_archcpu(env); uintptr_t ra = GETPC(); ARMMMUIdx mmu_idx = arm_mmu_idx(env); - MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, + MemOpIdx oi = make_memop_idx(mo_endian(env) | MO_UL | MO_ALIGN, arm_to_core_mmu_idx(mmu_idx)); /* fptr is the value of Rn, the frame pointer we load the FP regs from */ -- 2.43.0
From: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260414005348.4767-10-philmd@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/m_helper.c | 2 +- target/arm/tcg/meson.build | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/target/arm/tcg/m_helper.c b/target/arm/tcg/m_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/m_helper.c +++ b/target/arm/tcg/m_helper.c @@ -XXX,XX +XXX,XX @@ #include "qemu/log.h" #include "exec/page-protection.h" #ifdef CONFIG_TCG -#include "accel/tcg/cpu-ldst.h" +#include "accel/tcg/cpu-ldst-common.h" #include "semihosting/common-semi.h" #endif #if !defined(CONFIG_USER_ONLY) diff --git a/target/arm/tcg/meson.build b/target/arm/tcg/meson.build index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/meson.build +++ b/target/arm/tcg/meson.build @@ -XXX,XX +XXX,XX @@ arm_ss.add(when: 'TARGET_AARCH64', if_false: files('stubs32.c')) arm_ss.add(files( 'cpu32.c', - 'm_helper.c', )) arm_ss.add(when: 'TARGET_AARCH64', if_true: files( @@ -XXX,XX +XXX,XX @@ arm_common_system_ss.add( 'debug.c', 'hflags.c', 'gengvec.c', + 'm_helper.c', 'mve_helper.c', 'neon_helper.c', 'op_helper.c', @@ -XXX,XX +XXX,XX @@ arm_user_ss.add( 'debug.c', 'gengvec.c', 'hflags.c', + 'm_helper.c', 'mve_helper.c', 'neon_helper.c', 'op_helper.c', -- 2.43.0
From: Thomas Huth <thuth@redhat.com> When writing to this register, QEMU currently aborts: $ echo "readl 0x10000018" | ./qemu-system-arm -audiodev none,id=snd0 \ -M integratorcp,accel=qtest,audiodev=snd0 -display none -qtest stdio [I 0.000000] OPENED [R +0.001907] readl 0x10000018 qemu: hardware error: integratorcm_read: CM_LMBUSCNT [...] Aborted (core dumped) This is bad, a guest should ideally never be able to kill QEMU like this. Now, according to the "Intergrator/CP User Guide" from: https://developer.arm.com/documentation/dui0159/b/porting-integrator-ap-and-im-pd1/registers "The Integrator/AP CM_LMBUSCNT has been removed." That means this register does not seem to be implemented on real CP boards at all, only for older AP boards. Thus it should be fine if we simply ignore this register in QEMU and handle it like all other unimplemented registers in the "default" handler of the case statement. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3407 Signed-off-by: Thomas Huth <thuth@redhat.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-id: 20260420064933.64765-1-thuth@redhat.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/arm/integratorcp.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/integratorcp.c +++ b/hw/arm/integratorcp.c @@ -XXX,XX +XXX,XX @@ static uint64_t integratorcm_read(void *opaque, hwaddr offset, } else { return s->cm_lock; } - case 6: /* CM_LMBUSCNT */ - /* ??? High frequency timer. */ - hw_error("integratorcm_read: CM_LMBUSCNT"); case 7: /* CM_AUXOSC */ return s->cm_auxosc; case 8: /* CM_SDRAM */ -- 2.43.0
include/hw/arm/primecell.h used to be more expansive, but now the only thing it defines is the ARM_SYSCTL_GPIO_* constants for the GPIO lines for the arm-sysctl system-control device used on the Realview, Versatile and Versatile Express boards. Replace it with a header file specific to that device. virt.c and vmapple.c included primecell.h despite not using the constants it defined; there we can simply drop the include entirely. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-id: 20260416172627.690396-1-peter.maydell@linaro.org --- MAINTAINERS | 2 +- hw/arm/realview.c | 2 +- hw/arm/vexpress.c | 2 +- hw/arm/virt.c | 1 - hw/misc/arm_sysctl.c | 2 +- hw/vmapple/vmapple.c | 1 - include/hw/arm/primecell.h | 12 ------------ include/hw/misc/arm_sysctl.h | 16 ++++++++++++++++ 8 files changed, 20 insertions(+), 18 deletions(-) delete mode 100644 include/hw/arm/primecell.h create mode 100644 include/hw/misc/arm_sysctl.h diff --git a/MAINTAINERS b/MAINTAINERS index XXXXXXX..XXXXXXX 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -XXX,XX +XXX,XX @@ F: hw/ssi/pl022.c F: include/hw/ssi/pl022.h F: hw/rtc/pl031.c F: include/hw/rtc/pl031.h -F: include/hw/arm/primecell.h F: hw/timer/cmsdk-apb-timer.c F: include/hw/timer/cmsdk-apb-timer.h F: tests/qtest/cmsdk-apb-timer-test.c @@ -XXX,XX +XXX,XX @@ F: hw/*/versatile* F: hw/i2c/arm_sbcon_i2c.c F: include/hw/i2c/arm_sbcon_i2c.h F: hw/misc/arm_sysctl.c +F: include/hw/misc/arm_sysctl.h F: docs/system/arm/versatile.rst Virt diff --git a/hw/arm/realview.c b/hw/arm/realview.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/realview.c +++ b/hw/arm/realview.c @@ -XXX,XX +XXX,XX @@ #include "target/arm/cpu.h" #include "hw/core/sysbus.h" #include "hw/arm/boot.h" -#include "hw/arm/primecell.h" #include "hw/arm/machines-qom.h" #include "hw/core/split-irq.h" +#include "hw/misc/arm_sysctl.h" #include "hw/net/lan9118.h" #include "hw/net/smc91c111.h" #include "hw/pci/pci.h" diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/vexpress.c +++ b/hw/arm/vexpress.c @@ -XXX,XX +XXX,XX @@ #include "qemu/datadir.h" #include "hw/core/sysbus.h" #include "hw/arm/boot.h" -#include "hw/arm/primecell.h" #include "hw/arm/machines-qom.h" +#include "hw/misc/arm_sysctl.h" #include "hw/net/lan9118.h" #include "hw/i2c/i2c.h" #include "net/net.h" diff --git a/hw/arm/virt.c b/hw/arm/virt.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -XXX,XX +XXX,XX @@ #include "monitor/qdev.h" #include "hw/core/sysbus.h" #include "hw/arm/boot.h" -#include "hw/arm/primecell.h" #include "hw/arm/virt.h" #include "hw/arm/machines-qom.h" #include "hw/block/flash.h" diff --git a/hw/misc/arm_sysctl.c b/hw/misc/arm_sysctl.c index XXXXXXX..XXXXXXX 100644 --- a/hw/misc/arm_sysctl.c +++ b/hw/misc/arm_sysctl.c @@ -XXX,XX +XXX,XX @@ #include "system/runstate.h" #include "qemu/bitops.h" #include "hw/core/sysbus.h" +#include "hw/misc/arm_sysctl.h" #include "migration/vmstate.h" -#include "hw/arm/primecell.h" #include "qemu/log.h" #include "qemu/module.h" #include "qom/object.h" diff --git a/hw/vmapple/vmapple.c b/hw/vmapple/vmapple.c index XXXXXXX..XXXXXXX 100644 --- a/hw/vmapple/vmapple.c +++ b/hw/vmapple/vmapple.c @@ -XXX,XX +XXX,XX @@ #include "hw/core/sysbus.h" #include "hw/usb/usb.h" #include "hw/arm/boot.h" -#include "hw/arm/primecell.h" #include "hw/char/pl011.h" #include "hw/intc/arm_gic.h" #include "hw/intc/arm_gicv3_common.h" diff --git a/include/hw/arm/primecell.h b/include/hw/arm/primecell.h deleted file mode 100644 index XXXXXXX..XXXXXXX --- a/include/hw/arm/primecell.h +++ /dev/null @@ -XXX,XX +XXX,XX @@ -#ifndef PRIMECELL_H -#define PRIMECELL_H - -/* Declarations for ARM PrimeCell based periperals. */ -/* Also includes some devices that are currently only used by the - ARM boards. */ - -/* arm_sysctl GPIO lines */ -#define ARM_SYSCTL_GPIO_MMC_WPROT 0 -#define ARM_SYSCTL_GPIO_MMC_CARDIN 1 - -#endif diff --git a/include/hw/misc/arm_sysctl.h b/include/hw/misc/arm_sysctl.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/include/hw/misc/arm_sysctl.h @@ -XXX,XX +XXX,XX @@ +/* + * Status and system control registers for ARM RealView/Versatile boards. + * + * Copyright (c) Linaro Ltd + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_MISC_ARM_SYSCTL_H +#define HW_MISC_ARM_SYSCTL_H + +/* arm_sysctl inbound GPIO lines */ +#define ARM_SYSCTL_GPIO_MMC_WPROT 0 +#define ARM_SYSCTL_GPIO_MMC_CARDIN 1 + +#endif -- 2.43.0
If we create a normally-AArch64 CPU and configure it with aarch64=off, this will by default leave all the AArch64 ID register values in its ARMISARegisters struct untouched. That in turn means that tests of cpu_isar_feature(aa64_something, cpu) will return true. Until now we have had a design policy that you shouldn't check an aa64_ feature unless you know that the CPU has AArch64; but this is quite fragile as it's easy to forget and only causes a problem in the corner case where AArch64 was turned off. In particular, when we extend the ability to disable AArch64 from only KVM to also TCG there are many more aa64 feature check points which we would otherwise have to audit for whether they needed to be guarded with a check on ARM_FEATURE_AARCH64. Instead, make the CPU realize function zero out all the 64-bit ID registers if a TCG CPU doesn't have AArch64; this will make aa64_ feature tests generally return false. We only do this for TCG because only TCG really needs it, and for KVM it might be confusing to have QEMU's idea of the ID registers be different from KVM's. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260416165353.589569-2-peter.maydell@linaro.org --- target/arm/cpu.c | 35 +++++++++++++++++++++++++++++++++++ target/arm/cpu.h | 3 ++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -XXX,XX +XXX,XX @@ void arm_cpu_finalize_features(ARMCPU *cpu, Error **errp) } } +static void arm_clear_aarch64_idregs(ARMCPU *cpu) +{ + /* Zero out all the AArch64 ID registers in ARMISARegisters */ + SET_IDREG(&cpu->isar, ID_AA64ISAR0, 0); + SET_IDREG(&cpu->isar, ID_AA64ISAR1, 0); + SET_IDREG(&cpu->isar, ID_AA64ISAR2, 0); + SET_IDREG(&cpu->isar, ID_AA64PFR0, 0); + SET_IDREG(&cpu->isar, ID_AA64PFR1, 0); + SET_IDREG(&cpu->isar, ID_AA64PFR2, 0); + SET_IDREG(&cpu->isar, ID_AA64MMFR0, 0); + SET_IDREG(&cpu->isar, ID_AA64MMFR1, 0); + SET_IDREG(&cpu->isar, ID_AA64MMFR2, 0); + SET_IDREG(&cpu->isar, ID_AA64MMFR3, 0); + SET_IDREG(&cpu->isar, ID_AA64DFR0, 0); + SET_IDREG(&cpu->isar, ID_AA64DFR1, 0); + SET_IDREG(&cpu->isar, ID_AA64AFR0, 0); + SET_IDREG(&cpu->isar, ID_AA64AFR1, 0); + SET_IDREG(&cpu->isar, ID_AA64ZFR0, 0); + SET_IDREG(&cpu->isar, ID_AA64SMFR0, 0); +} + static void arm_cpu_realizefn(DeviceState *dev, Error **errp) { CPUState *cs = CPU(dev); @@ -XXX,XX +XXX,XX @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) } #endif + /* + * A TCG aarch64=off CPU has no AArch64 at all, so we clear out the + * ID registers to avoid cpu_isar_feature(aa64_something, cpu) tests + * incorrectly returning true. We don't do this for other accelerators + * (which in practice means "for KVM", since no others have AArch32 + * guest support) because from KVM's point of view the AArch64 ID + * registers still exist and must have their correct values. So we + * avoid clearing them out so that we don't have QEMU and KVM with + * different ideas of the ID registers. + */ + if (tcg_enabled() && !arm_feature(env, ARM_FEATURE_AARCH64)) { + arm_clear_aarch64_idregs(cpu); + } + #ifdef CONFIG_USER_ONLY /* * User mode relies on IC IVAU instructions to catch modification of diff --git a/target/arm/cpu.h b/target/arm/cpu.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -XXX,XX +XXX,XX @@ struct ArchCPU { * Note that if you add an ID register to the ARMISARegisters struct * you need to also update the 32-bit and 64-bit versions of the * kvm_arm_get_host_cpu_features() function to correctly populate the - * field by reading the value from the KVM vCPU. + * field by reading the value from the KVM vCPU. If it is an AArch64 + * ID register then you also must update arm_clear_aarch64_idregs(). */ struct ARMISARegisters { uint32_t mvfr0; -- 2.43.0
Allow the 'aarch64=off' property, which is currently KVM-only, to be set for TCG CPUs also. Note that we don't permit it on the qemu-aarch64 user-mode binary: this makes no sense as that executable can only handle AArch64 syscalls (and it would also assert at startup since it doesn't compile in the A32-specific GDB xml files like arm-neon.xml). Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Tested-by: Clément Chigot <chigot@adacore.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-id: 20260416165353.589569-3-peter.maydell@linaro.org --- docs/system/arm/cpu-features.rst | 10 +++++---- target/arm/cpu-features.h | 5 +++++ target/arm/cpu.c | 36 ++++++++++++++++++++++++++++---- tests/qtest/arm-cpu-features.c | 8 ++----- 4 files changed, 45 insertions(+), 14 deletions(-) diff --git a/docs/system/arm/cpu-features.rst b/docs/system/arm/cpu-features.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/system/arm/cpu-features.rst +++ b/docs/system/arm/cpu-features.rst @@ -XXX,XX +XXX,XX @@ not implement ARMv8-A, will not have the ``aarch64`` CPU property. QEMU's support may be limited for some CPU features, only partially supporting the feature or only supporting the feature under certain configurations. For example, the ``aarch64`` CPU feature, which, when -disabled, enables the optional AArch32 CPU feature, is only supported -when using the KVM accelerator and when running on a host CPU type that -supports the feature. While ``aarch64`` currently only works with KVM, -it could work with TCG. CPU features that are specific to KVM are +disabled, enables the optional AArch32 CPU feature, can only be set to +``off`` on the TCG and KVM accelerators, and it cannot be set to +``off`` under KVM unless running on a host CPU type that supports +running guests in AArch32. + +CPU features that are inherently specific to KVM are prefixed with "kvm-" and are described in "KVM VCPU Features". CPU Feature Probing diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu-features.h +++ b/target/arm/cpu-features.h @@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_aa32_el2(const ARMISARegisters *id) return FIELD_EX64_IDREG(id, ID_AA64PFR0, EL2) >= 2; } +static inline bool isar_feature_aa64_aa32_el3(const ARMISARegisters *id) +{ + return FIELD_EX64_IDREG(id, ID_AA64PFR0, EL3) >= 2; +} + static inline bool isar_feature_aa64_ras(const ARMISARegisters *id) { return FIELD_EX64_IDREG(id, ID_AA64PFR0, RAS) != 0; diff --git a/target/arm/cpu.c b/target/arm/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -XXX,XX +XXX,XX @@ static void aarch64_cpu_set_aarch64(Object *obj, bool value, Error **errp) * uniform execution state like do_interrupt. */ if (value == false) { - if (!kvm_enabled() || !kvm_arm_aarch32_supported()) { - error_setg(errp, "'aarch64' feature cannot be disabled " - "unless KVM is enabled and 32-bit EL1 " - "is supported"); + if (kvm_enabled()) { + if (!kvm_arm_aarch32_supported()) { + error_setg(errp, "'aarch64' feature cannot be disabled for KVM " + "because this host does not support 32-bit EL1"); + return; + } + } else if (tcg_enabled()) { +#ifdef CONFIG_USER_ONLY + error_setg(errp, "'aarch64' feature cannot be disabled for " + "usermode emulator qemu-aarch64; use qemu-arm instead"); + return; +#else + bool aa32_at_highest_el; + if (arm_feature(&cpu->env, ARM_FEATURE_EL3)) { + aa32_at_highest_el = cpu_isar_feature(aa64_aa32_el3, cpu); + } else if (arm_feature(&cpu->env, ARM_FEATURE_EL2)) { + aa32_at_highest_el = cpu_isar_feature(aa64_aa32_el2, cpu); + } else { + aa32_at_highest_el = cpu_isar_feature(aa64_aa32_el1, cpu); + } + + if (!aa32_at_highest_el) { + error_setg(errp, "'aarch64' feature cannot be disabled for " + "this TCG CPU because it does not support 32-bit " + "execution at its highest implemented exception " + "level"); + return; + } +#endif + } else { + error_setg(errp, "'aarch64' feature cannot be disabled for " + "this accelerator"); return; } unset_feature(&cpu->env, ARM_FEATURE_AARCH64); diff --git a/tests/qtest/arm-cpu-features.c b/tests/qtest/arm-cpu-features.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/arm-cpu-features.c +++ b/tests/qtest/arm-cpu-features.c @@ -XXX,XX +XXX,XX @@ static void test_query_cpu_model_expansion(const void *data) sve_tests_default(qts, "max"); pauth_tests_default(qts, "max"); - /* Test that features that depend on KVM generate errors without. */ - assert_error(qts, "max", - "'aarch64' feature cannot be disabled " - "unless KVM is enabled and 32-bit EL1 " - "is supported", - "{ 'aarch64': false }"); + /* TCG allows us to turn off AArch64 on the 'max' CPU type */ + assert_set_feature(qts, "max", "aarch64", false); } qtest_quit(qts); -- 2.43.0
Add a basic test of the TCG 'aarch64=off' functionality; this is the same as our existing arm/test_virt test, but it runs the AArch32 guest kernel on qemu-system-aarch64 with -cpu max,aarch64=off. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-id: 20260416165353.589569-4-peter.maydell@linaro.org --- tests/functional/aarch64/meson.build | 1 + .../aarch64/test_virt_aarch64_off.py | 37 +++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100755 tests/functional/aarch64/test_virt_aarch64_off.py diff --git a/tests/functional/aarch64/meson.build b/tests/functional/aarch64/meson.build index XXXXXXX..XXXXXXX 100644 --- a/tests/functional/aarch64/meson.build +++ b/tests/functional/aarch64/meson.build @@ -XXX,XX +XXX,XX @@ tests_aarch64_system_thorough = [ 'tcg_plugins', 'tuxrun', 'virt', + 'virt_aarch64_off', 'virt_gpu', 'virt_vbsa', 'xen', diff --git a/tests/functional/aarch64/test_virt_aarch64_off.py b/tests/functional/aarch64/test_virt_aarch64_off.py new file mode 100755 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/functional/aarch64/test_virt_aarch64_off.py @@ -XXX,XX +XXX,XX @@ +#!/usr/bin/env python3 +# +# Functional test that boots an AArch32 Linux kernel and checks the console +# on a TCG aarch64 CPU with aarch64=off. This is the same image etc +# as we use in tests/functional/arm/test_virt.py. +# +# SPDX-License-Identifier: GPL-2.0-or-later + +from qemu_test import LinuxKernelTest, Asset + +class ArmVirtMachine(LinuxKernelTest): + + ASSET_KERNEL = Asset( + ('https://archives.fedoraproject.org/pub/archive/fedora/linux/' + 'releases/29/Everything/armhfp/os/images/pxeboot/vmlinuz'), + '18dd5f1a9a28bd539f9d047f7c0677211bae528e8712b40ca5a229a4ad8e2591') + + def test_arm_virt(self): + self.set_machine('virt') + # KVM aarch64=off requires a host CPU that supports it, so + # restrict the test to TCG only + self.require_accelerator('tcg') + self.vm.add_args('-cpu', 'max,aarch64=off') + + kernel_path = self.ASSET_KERNEL.fetch() + + self.vm.set_console() + kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + + 'console=ttyAMA0') + self.vm.add_args('-kernel', kernel_path, + '-append', kernel_command_line) + self.vm.launch() + console_pattern = 'Kernel command line: %s' % kernel_command_line + self.wait_for_console_pattern(console_pattern) + +if __name__ == '__main__': + LinuxKernelTest.main() -- 2.43.0
From: Eric Auger <eric.auger@redhat.com> We introduce a datatype for a tolerance with respect to a given cpreg migration issue. The tolerance applies to a given cpreg kvm index, and can be of different types: a) mismatch in cpreg indexes - ToleranceNotOnBothEnds (cpreg index is allowed to be only present on one end) - ToleranceOnlySrcTestValue (cpreg index is allowed to be only present in source if its value @mask field matches @value) b) mismatch in cpreg values - ToleranceDiffInMask (value differences are allowed only within a mask) - ToleranceFieldLT (incoming field value must be less than a given value) - ToleranceFieldGT (incoming field value must be greater than a given value) A QLIST of such tolerances can be populated using a new helper: arm_register_cpreg_mig_tolerance() and arm_cpu_match_cpreg_mig_tolerance() allows to check whether a tolerance exists for a given kvm index and its criterion is matched. callers for those helpers will be introduced in subsequent patches. Only registration of migration tolerances related to cpreg index mismatch is currently allowed. Signed-off-by: Eric Auger <eric.auger@redhat.com> Message-id: 20260420140552.104369-2-eric.auger@redhat.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/cpu.c | 82 ++++++++++++++++++++++++++++++++++++++++++ target/arm/cpu.h | 1 + target/arm/internals.h | 54 ++++++++++++++++++++++++++++ 3 files changed, 137 insertions(+) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -XXX,XX +XXX,XX @@ void arm_register_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook, QLIST_INSERT_HEAD(&cpu->el_change_hooks, entry, node); } +static ARMCPRegMigTolerance *find_mig_tolerance(ARMCPU *cpu, uint64_t kvmidx) +{ + ARMCPRegMigTolerance *t; + QLIST_FOREACH(t, &cpu->cpreg_mig_tolerances, node) { + if (t->kvmidx == kvmidx) { + return t; + } + } + return NULL; +} + +void arm_register_cpreg_mig_tolerance(ARMCPU *cpu, uint64_t kvmidx, + uint64_t mask, uint64_t value, + ARMCPRegMigToleranceType type) +{ + ARMCPRegMigTolerance *entry; + + /* make sure the kvmidx has not tolerance already registered */ + assert(!find_mig_tolerance(cpu, kvmidx)); + + assert(type == ToleranceNotOnBothEnds || + type == ToleranceOnlySrcTestValue); + + entry = g_new0(ARMCPRegMigTolerance, 1); + + entry->kvmidx = kvmidx; + entry->mask = mask; + entry->value = value; + entry->type = type; + + QLIST_INSERT_HEAD(&cpu->cpreg_mig_tolerances, entry, node); +} + +bool arm_cpu_match_cpreg_mig_tolerance(ARMCPU *cpu, uint64_t kvmidx, + uint64_t vmstate_value, uint64_t local_value, + ARMCPRegMigToleranceType type) +{ + ARMCPRegMigTolerance *t = find_mig_tolerance(cpu, kvmidx); + uint64_t diff, diff_outside_mask, field; + + if (!t || t->type != type) { + return false; + } + + if (type == ToleranceNotOnBothEnds) { + return true; + } + + if (type == ToleranceOnlySrcTestValue && + ((vmstate_value & t->mask) == t->value)) { + return true; + } + + /* Need to check the mask */ + diff = vmstate_value ^ local_value; + diff_outside_mask = diff & ~t->mask; + + if (diff_outside_mask) { + /* there are differences outside of the mask */ + return false; + } + if (type == ToleranceDiffInMask) { + /* differences only in the field, tolerance matched */ + return true; + } + /* need to compare field value against authorized ones */ + field = vmstate_value & t->mask; + if (type == ToleranceFieldLT && (field < t->value)) { + return true; + } + if (type == ToleranceFieldGT && (field > t->value)) { + return true; + } + return false; +} + static void cp_reg_reset(gpointer key, gpointer value, gpointer opaque) { /* Reset a single ARMCPRegInfo register */ @@ -XXX,XX +XXX,XX @@ static void arm_cpu_initfn(Object *obj) QLIST_INIT(&cpu->pre_el_change_hooks); QLIST_INIT(&cpu->el_change_hooks); + QLIST_INIT(&cpu->cpreg_mig_tolerances); #ifdef CONFIG_USER_ONLY # ifdef TARGET_AARCH64 @@ -XXX,XX +XXX,XX @@ static void arm_cpu_finalizefn(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); ARMELChangeHook *hook, *next; + ARMCPRegMigTolerance *t, *n; g_hash_table_destroy(cpu->cp_regs); @@ -XXX,XX +XXX,XX @@ static void arm_cpu_finalizefn(Object *obj) QLIST_REMOVE(hook, node); g_free(hook); } + QLIST_FOREACH_SAFE(t, &cpu->cpreg_mig_tolerances, node, n) { + QLIST_REMOVE(t, node); + g_free(t); + } #ifndef CONFIG_USER_ONLY if (cpu->pmu_timer) { timer_free(cpu->pmu_timer); diff --git a/target/arm/cpu.h b/target/arm/cpu.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -XXX,XX +XXX,XX @@ struct ArchCPU { QLIST_HEAD(, ARMELChangeHook) pre_el_change_hooks; QLIST_HEAD(, ARMELChangeHook) el_change_hooks; + QLIST_HEAD(, ARMCPRegMigTolerance) cpreg_mig_tolerances; int32_t node_id; /* NUMA node this CPU belongs to */ diff --git a/target/arm/internals.h b/target/arm/internals.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -XXX,XX +XXX,XX @@ int compare_u64(const void *a, const void *b); /* Used in FEAT_MEC to set the MECIDWidthm1 field in the MECIDR_EL2 register. */ #define MECID_WIDTH 16 +typedef enum { + ToleranceNotOnBothEnds, + ToleranceOnlySrcTestValue, + ToleranceDiffInMask, + ToleranceFieldLT, + ToleranceFieldGT, +} ARMCPRegMigToleranceType; + +typedef struct ARMCPRegMigTolerance { + uint64_t kvmidx; + uint64_t mask; + uint64_t value; + ARMCPRegMigToleranceType type; + QLIST_ENTRY(ARMCPRegMigTolerance) node; +} ARMCPRegMigTolerance; + +/** + * arm_register_cpreg_mig_tolerance: + * Register a migration tolerance wrt one given cpreg identified by its + * @kvmidx. Calling this function twice for the same @kvmidx is a + * programming error and will cause an assertion failure. + * + * @cpu: vcpu to apply the migration tolerance on + * @kvmidx: kvm index of the cpreg the tolerance applies to + * @mask: bitmask where a difference is tolerated + * (relevant with ToleranceDiffInMask) + * @value: value the bitmask field is compared with + * (relevant with ToleranceFieldLT and ToleranceFieldGT) + * @type: type of the migration tolerance: + * - ToleranceNotOnBothEnds (cpreg index is allowed to be only present + * on one end) + * - ToleranceOnlySrcTestValue (cpreg index is allowed to be only + * present in source if its value @mask field matches @value) + * - ToleranceDiffInMask (mismatch in cpreg values are only tolerated + * if differences are within @mask) + * - ToleranceFieldLT (mismatch in cpreg values are only tolerated + * if incoming @bitmask field value is less than @value) + * - ToleranceFieldGT (mismatch in cpreg values are only tolerated + * if incoming @bitmask field value is greater than @value) + */ +void arm_register_cpreg_mig_tolerance(ARMCPU *cpu, uint64_t kvmidx, + uint64_t mask, uint64_t value, + ARMCPRegMigToleranceType type); + +/** + * arm_cpu_match_cpreg_mig_tolerance: + * Check whether a tolerance of type @type exists for a given @kvmidx + * and the tolerance criterion is satisfied + */ +bool arm_cpu_match_cpreg_mig_tolerance(ARMCPU *cpu, uint64_t kvmidx, + uint64_t vmstate_value, uint64_t local_value, + ARMCPRegMigToleranceType type); + + #endif -- 2.43.0
From: Eric Auger <eric.auger@redhat.com> If there is a mismatch between the cpreg indexes found on both ends, check whether a tolerance was registered for the given kvmidx. If any, silence warning/errors. Signed-off-by: Eric Auger <eric.auger@redhat.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 20260420140552.104369-3-eric.auger@redhat.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/machine.c | 21 +++++++++++++++------ target/arm/trace-events | 2 ++ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/target/arm/machine.c b/target/arm/machine.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/machine.c +++ b/target/arm/machine.c @@ -XXX,XX +XXX,XX @@ static void handle_cpreg_missing_in_incoming_stream(ARMCPU *cpu, uint64_t kvmidx { g_autofree gchar *name = print_register_name(kvmidx); + if (arm_cpu_match_cpreg_mig_tolerance(cpu, kvmidx, + 0, 0, ToleranceNotOnBothEnds)) { + trace_tolerate_cpreg_missing_in_incoming_stream(name); + return; + } warn_report("%s: %s " "expected by the destination but not in the incoming stream: " "skip it", __func__, name); } /* - * Handle the situation where @kvmidx is in the incoming stream - * but not on destination. This currently fails the migration but - * we plan to accomodate some exceptions, hence the boolean returned value. + * Handle the situation where @kvmidx is in the incoming + * stream but not on destination. This fails the migration if + * no cpreg mig tolerance is matched for this @kvmidx + * Return true if the migration should eventually fail */ static bool handle_cpreg_only_in_incoming_stream(ARMCPU *cpu, uint64_t kvmidx) { g_autofree gchar *name = print_register_name(kvmidx); - bool fail = true; + if (arm_cpu_match_cpreg_mig_tolerance(cpu, kvmidx, + 0, 0, ToleranceNotOnBothEnds)) { + trace_tolerate_cpreg_only_in_incoming_stream(name); + return false; + } error_report("%s: %s in the incoming stream but unknown on the " "destination: fail migration", __func__, name); - - return fail; + return true; } static int cpu_post_load(void *opaque, int version_id) diff --git a/target/arm/trace-events b/target/arm/trace-events index XXXXXXX..XXXXXXX 100644 --- a/target/arm/trace-events +++ b/target/arm/trace-events @@ -XXX,XX +XXX,XX @@ arm_psci_call(uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3, uint32_t cpuid # machine.c cpu_post_load(uint32_t cpreg_vmstate_array_len, uint32_t cpreg_array_len) "cpreg_vmstate_array_len=%d cpreg_array_len=%d" +tolerate_cpreg_missing_in_incoming_stream(char *name) "%s is missing in incoming stream but this is explicitly tolerated" +tolerate_cpreg_only_in_incoming_stream(char *name) "%s is in incoming stream but not on destination but this is explicitly tolerated" -- 2.43.0
From: Eric Auger <eric.auger@redhat.com> Pass the value of the incoming register to handle_cpreg_only_in_incoming_stream and check whether there is a matching ToleranceOnlySrcTestValue tolerance. Signed-off-by: Eric Auger <eric.auger@redhat.com> Message-id: 20260420140552.104369-4-eric.auger@redhat.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/machine.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/target/arm/machine.c b/target/arm/machine.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/machine.c +++ b/target/arm/machine.c @@ -XXX,XX +XXX,XX @@ static void handle_cpreg_missing_in_incoming_stream(ARMCPU *cpu, uint64_t kvmidx * no cpreg mig tolerance is matched for this @kvmidx * Return true if the migration should eventually fail */ -static bool handle_cpreg_only_in_incoming_stream(ARMCPU *cpu, uint64_t kvmidx) +static bool +handle_cpreg_only_in_incoming_stream(ARMCPU *cpu, uint64_t kvmidx, uint64_t value) { g_autofree gchar *name = print_register_name(kvmidx); if (arm_cpu_match_cpreg_mig_tolerance(cpu, kvmidx, - 0, 0, ToleranceNotOnBothEnds)) { + 0, 0, ToleranceNotOnBothEnds) || + arm_cpu_match_cpreg_mig_tolerance(cpu, kvmidx, + value, 0, ToleranceOnlySrcTestValue)) { trace_tolerate_cpreg_only_in_incoming_stream(name); return false; } @@ -XXX,XX +XXX,XX @@ static int cpu_post_load(void *opaque, int version_id) } if (cpu->cpreg_vmstate_indexes[v] < cpu->cpreg_indexes[i]) { fail = handle_cpreg_only_in_incoming_stream(cpu, - cpu->cpreg_vmstate_indexes[v++]); + cpu->cpreg_vmstate_indexes[v], + cpu->cpreg_vmstate_values[v]); + v++; continue; } /* matching register, copy the value over */ @@ -XXX,XX +XXX,XX @@ static int cpu_post_load(void *opaque, int version_id) */ for ( ; v < cpu->cpreg_vmstate_array_len; v++) { fail = handle_cpreg_only_in_incoming_stream(cpu, - cpu->cpreg_vmstate_indexes[v]); + cpu->cpreg_vmstate_indexes[v], + cpu->cpreg_vmstate_values[v]); } if (fail) { return -1; -- 2.43.0
From: Eric Auger <eric.auger@redhat.com> Before linux v6.13 those registers were erroneously unconditionally exposed and this was fixed by commits: - 0fcb4eea5345 ("KVM: arm64: Hide TCR2_EL1 from userspace when disabled for guests") - a68cddbe47ef ("KVM: arm64: Hide S1PIE registers from userspace when disabled for guests") in v6.13. This means if we migrate from an old kernel host to a >= 6.13 kernel host, migration currently fails. Declare cpreg migration tolerance for those registers. Signed-off-by: Eric Auger <eric.auger@redhat.com> Reviewed-by: Sebastian Ott <sebott@redhat.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 20260420140552.104369-5-eric.auger@redhat.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/cpu64.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -XXX,XX +XXX,XX @@ static void aarch64_a53_initfn(Object *obj) define_cortex_a72_a57_a53_cp_reginfo(cpu); } +#if defined(CONFIG_KVM) +static void kvm_arm_set_cpreg_mig_tolerances(ARMCPU *cpu) +{ + /* + * Registers that may be in the incoming stream and not exposed + * on the destination + */ + + /* + * TCR_EL1 was erroneously unconditionnally exposed before linux v6.13. + * See commit 0fcb4eea5345 ("KVM: arm64: Hide TCR2_EL1 from userspace + * when disabled for guests") + */ + arm_register_cpreg_mig_tolerance(cpu, ARM64_SYS_REG(3, 0, 2, 0, 3), + 0, 0, ToleranceNotOnBothEnds); + /* + * PIRE0_EL1 and PIR_EL1 were erroneously unconditionnally exposed + * before linux v6.13. See commit a68cddbe47ef ("KVM: arm64: Hide + * S1PIE registers from userspace when disabled for guests") + */ + arm_register_cpreg_mig_tolerance(cpu, ARM64_SYS_REG(3, 0, 10, 2, 2), + 0, 0, ToleranceNotOnBothEnds); + arm_register_cpreg_mig_tolerance(cpu, ARM64_SYS_REG(3, 0, 10, 2, 3), + 0, 0, ToleranceNotOnBothEnds); +} +#endif + static void aarch64_host_initfn(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); @@ -XXX,XX +XXX,XX @@ static void aarch64_host_initfn(Object *obj) #endif #if defined(CONFIG_KVM) + kvm_arm_set_cpreg_mig_tolerances(cpu); kvm_arm_set_cpu_features_from_host(cpu); aarch64_add_sve_properties(obj); #elif defined(CONFIG_HVF) -- 2.43.0
From: Eric Auger <eric.auger@redhat.com> KVM_REG_ARM_VENDOR_HYP_BMAP_2 pseudo FW register is exposed from v6.15 onwards. Backward migration from a >= v6.15 to an older kernel would fail without cpreg migration tolerance definition for this register. If the register is present on source but not on destination, its value must be checked to make sure it matches the reset value, ie. 0, meaning no service is exposed to the guest, hence the choice of a ToleranceOnlySrcTestValue migration tolerance. Signed-off-by: Eric Auger <eric.auger@redhat.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 20260420140552.104369-6-eric.auger@redhat.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/cpu64.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -XXX,XX +XXX,XX @@ static void kvm_arm_set_cpreg_mig_tolerances(ARMCPU *cpu) 0, 0, ToleranceNotOnBothEnds); arm_register_cpreg_mig_tolerance(cpu, ARM64_SYS_REG(3, 0, 10, 2, 3), 0, 0, ToleranceNotOnBothEnds); + + /* + * KVM_REG_ARM_VENDOR_HYP_BMAP_2 pseudo FW register is exposed + * from v6.15 onwards. Backward migration from a >= v6.15 to an older + * kernel would fail without cpreg migration tolerance definition. + * If the register is present on source but not on destination, make + * sure it has its reset value, ie. 0, meaning no service is exposed + * to the guest. + */ + arm_register_cpreg_mig_tolerance(cpu, KVM_REG_ARM_FW_FEAT_BMAP_REG(3), + UINT64_MAX, 0, ToleranceOnlySrcTestValue); } #endif -- 2.43.0
From: Eric Auger <eric.auger@redhat.com> We want to remove AArch32 DBGDTRTX which was erroneously exposed. This was attempted by 655659a74a36b ("target/arm: Correct encoding of Debug Communications Channel registers") but it was discovered that the removal of this debug register broke forward migration on TCG. Now we have the cpreg migration tolerance infrastructure, we can declare one for the DBGDTRTX. This allow to revert the reinstate patch. Signed-off-by: Eric Auger <eric.auger@redhat.com> Reviewed-by: Sebastian Ott <sebott@redhat.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 20260420140552.104369-7-eric.auger@redhat.com [PMM: revised comment, included note about when we can drop the workaround] Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/helper.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/target/arm/helper.c b/target/arm/helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu) .fgt = FGT_CLIDR_EL1, .resetvalue = GET_IDREG(isar, CLIDR) }; + uint64_t dbgtr_el0_kvmidx = + cpreg_to_kvm_id(ENCODE_CP_REG(14, 0, 1, 0, 5, 3, 0)); + define_one_arm_cp_reg(cpu, &clidr); define_arm_cp_regs(cpu, v7_cp_reginfo); define_debug_regs(cpu); + /* + * We used to incorrectly expose a non-existent AArch32 "DBGDTRTX" + * register with this encoding. This has been fixed by commit + * 655659a74a36 ("target/arm: Correct encoding of Debug + * Communications Channel registers") by the introduction of correct + * separate cpreg definitions for AA64 and AA32 versions. However, + * the old cpreg definition couldn't be removed without breaking + * migration, so commit 4f2b82f604 reinstated the bogus encoding + * for migration data only. + * + * Now that we have migration tolerance infrastructure, we can use + * this to allow forward migration from the buggy QEMU versions, + * accepting and ignoring the bogus register if it is in the + * source data. QEMU 11.0 was the last version that sent the + * bogus encoding, so this workaround can be removed at the point + * where we no longer care about migration from that version + * (i.e. when we remove the "virt-11.0" machine type). + */ + arm_register_cpreg_mig_tolerance(cpu, dbgtr_el0_kvmidx, + 0, 0, ToleranceNotOnBothEnds); } else { define_arm_cp_regs(cpu, not_v7_cp_reginfo); } -- 2.43.0
From: Eric Auger <eric.auger@redhat.com> This reverts commit 4f2b82f60431 ("target/arm: Reinstate bogus AArch32 DBGDTRTX register for migration compat). We don't need that commit anymore as the AArch32 DBGDTRTX register is declared to be safe to ignore in the incoming migration stream. Signed-off-by: Eric Auger <eric.auger@redhat.com> Reviewed-by: Sebastian Ott <sebott@redhat.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 20260420140552.104369-8-eric.auger@redhat.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/debug_helper.c | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/target/arm/debug_helper.c b/target/arm/debug_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/debug_helper.c +++ b/target/arm/debug_helper.c @@ -XXX,XX +XXX,XX @@ static void dbgclaimclr_write(CPUARMState *env, const ARMCPRegInfo *ri, env->cp15.dbgclaim &= ~(value & 0xFF); } -static CPAccessResult access_bogus(CPUARMState *env, const ARMCPRegInfo *ri, - bool isread) -{ - /* Always UNDEF, as if this cpreg didn't exist */ - return CP_ACCESS_UNDEFINED; -} - static const ARMCPRegInfo debug_cp_reginfo[] = { /* * DBGDRAR, DBGDSAR: always RAZ since we don't implement memory mapped @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo debug_cp_reginfo[] = { .opc0 = 2, .opc1 = 3, .crn = 0, .crm = 4, .opc2 = 0, .access = PL0_RW, .accessfn = access_tdcc, .type = ARM_CP_CONST, .resetvalue = 0 }, - /* - * This is not a real AArch32 register. We used to incorrectly expose - * this due to a QEMU bug; to avoid breaking migration compatibility we - * need to continue to provide it so that we don't fail the inbound - * migration when it tells us about a sysreg that we don't have. - * We set an always-fails .accessfn, which means that the guest doesn't - * actually see this register (it will always UNDEF, identically to if - * there were no cpreg definition for it other than that we won't print - * a LOG_UNIMP message about it), and we set the ARM_CP_NO_GDB flag so the - * gdbstub won't see it either. - * (We can't just set .access = 0, because add_cpreg_to_hashtable() - * helpfully ignores cpregs which aren't accessible to the highest - * implemented EL.) - * - * TODO: implement a system for being able to describe "this register - * can be ignored if it appears in the inbound stream"; then we can - * remove this temporary hack. - */ - { .name = "BOGUS_DBGDTR_EL0", .state = ARM_CP_STATE_AA32, - .cp = 14, .opc1 = 3, .crn = 0, .crm = 5, .opc2 = 0, - .access = PL0_RW, .accessfn = access_bogus, - .type = ARM_CP_CONST | ARM_CP_NO_GDB, .resetvalue = 0 }, /* * OSECCR_EL1 provides a mechanism for an operating system * to access the contents of EDECCR. EDECCR is not implemented though, -- 2.43.0
From: Osama Abdelkader <osama.abdelkader@gmail.com> fdt_node_offset_by_compatible(fdt, -1, compat) only finds the first match. If the blob has more than one node with the same compatible string, extra nodes will remain active. Remove all the matching nodes, using the same loop as imx8mp-evk.c does for this purpose. Signed-off-by: Osama Abdelkader <osama.abdelkader@gmail.com> Message-id: 20260420162114.308519-1-osama.abdelkader@gmail.com Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/arm/raspi4b.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/hw/arm/raspi4b.c b/hw/arm/raspi4b.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/raspi4b.c +++ b/hw/arm/raspi4b.c @@ -XXX,XX +XXX,XX @@ static void raspi4_modify_dtb(const struct arm_boot_info *info, void *fdt) for (int i = 0; i < ARRAY_SIZE(nodes_to_remove); i++) { const char *dev_str = nodes_to_remove[i]; + int offset; - int offset = fdt_node_offset_by_compatible(fdt, -1, dev_str); - if (offset >= 0) { - if (!fdt_nop_node(fdt, offset)) { - warn_report("bcm2711 dtc: %s has been disabled!", dev_str); + offset = fdt_node_offset_by_compatible(fdt, -1, dev_str); + while (offset >= 0) { + if (fdt_nop_node(fdt, offset) == 0) { + warn_report("bcm2711 dtb: %s has been disabled!", dev_str); } + offset = fdt_node_offset_by_compatible(fdt, offset, dev_str); } } -- 2.43.0
From: Yucai Liu <1486344514@qq.com> Implement a basic i.MX6UL LCDIF controller model with MMIO registers, frame-done interrupt behavior, and framebuffer-backed display updates for RGB565 and XRGB8888 input formats. Place the LCDIF device under hw/display and build it via a dedicated CONFIG_IMX6UL_LCDIF symbol. Model register fields with registerfields.h helpers and provide migration support via vmstate. Signed-off-by: Yucai Liu <1486344514@qq.com> Message-id: 20260412110240.93116-2-yangyanglan718@gmail.com Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- MAINTAINERS | 2 + hw/display/Kconfig | 4 + hw/display/imx6ul_lcdif.c | 453 ++++++++++++++++++++++++++++++ hw/display/meson.build | 1 + include/hw/display/imx6ul_lcdif.h | 37 +++ 5 files changed, 497 insertions(+) create mode 100644 hw/display/imx6ul_lcdif.c create mode 100644 include/hw/display/imx6ul_lcdif.h diff --git a/MAINTAINERS b/MAINTAINERS index XXXXXXX..XXXXXXX 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -XXX,XX +XXX,XX @@ L: qemu-arm@nongnu.org S: Odd Fixes F: hw/arm/mcimx6ul-evk.c F: hw/arm/fsl-imx6ul.c +F: hw/display/imx6ul_lcdif.c F: hw/misc/imx6ul_ccm.c F: include/hw/arm/fsl-imx6ul.h +F: include/hw/display/imx6ul_lcdif.h F: include/hw/misc/imx6ul_ccm.h F: docs/system/arm/mcimx6ul-evk.rst diff --git a/hw/display/Kconfig b/hw/display/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/display/Kconfig +++ b/hw/display/Kconfig @@ -XXX,XX +XXX,XX @@ config PL110 bool select FRAMEBUFFER +config IMX6UL_LCDIF + bool + select FRAMEBUFFER + config SII9022 bool depends on I2C diff --git a/hw/display/imx6ul_lcdif.c b/hw/display/imx6ul_lcdif.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/hw/display/imx6ul_lcdif.c @@ -XXX,XX +XXX,XX @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * i.MX6UL LCDIF controller + * + * Copyright (c) 2026 Yucai Liu <1486344514@qq.com> + */ + +#include "qemu/osdep.h" +#include "hw/display/imx6ul_lcdif.h" +#include "hw/core/irq.h" +#include "hw/core/registerfields.h" +#include "hw/display/framebuffer.h" +#include "migration/vmstate.h" +#include "system/address-spaces.h" +#include "qemu/module.h" +#include "qemu/units.h" +#include "ui/pixel_ops.h" + +#define LCDIF_MMIO_SIZE (16 * KiB) +#define LCDIF_RESET_CTRL1 0x000f0000 + +REG32(CTRL, 0x00) + FIELD(CTRL, RUN, 0, 1) + FIELD(CTRL, WORD_LENGTH, 8, 2) +REG32(CTRL1, 0x10) + FIELD(CTRL1, CUR_FRAME_DONE_IRQ, 9, 1) + FIELD(CTRL1, CUR_FRAME_DONE_IRQ_EN, 13, 1) + FIELD(CTRL1, BYTE_PACKING_FORMAT, 16, 4) +REG32(V4_TRANSFER_COUNT, 0x30) + FIELD(V4_TRANSFER_COUNT, H_COUNT, 0, 16) + FIELD(V4_TRANSFER_COUNT, V_COUNT, 16, 16) +REG32(V4_CUR_BUF, 0x40) +REG32(V4_NEXT_BUF, 0x50) +REG32(AS_NEXT_BUF, 0x230) + +#define REG_SET 0x4 +#define REG_CLR 0x8 +#define REG_TOG 0xc + +#define CTRL_WORD_LENGTH_16 0 +#define CTRL_WORD_LENGTH_24 3 + +#define FRAME_PERIOD_NS (16 * 1000 * 1000ULL) + +enum IMX6ULLCDIFReg { + IMX6UL_LCDIF_REG_CTRL = A_CTRL >> 4, + IMX6UL_LCDIF_REG_CTRL1 = A_CTRL1 >> 4, + IMX6UL_LCDIF_REG_V4_TRANSFER_COUNT = A_V4_TRANSFER_COUNT >> 4, + IMX6UL_LCDIF_REG_V4_CUR_BUF = A_V4_CUR_BUF >> 4, + IMX6UL_LCDIF_REG_V4_NEXT_BUF = A_V4_NEXT_BUF >> 4, + IMX6UL_LCDIF_REG_AS_NEXT_BUF = A_AS_NEXT_BUF >> 4, +}; + +static inline bool imx6ul_lcdif_reg_exists(hwaddr reg) +{ + return (reg >> 4) < IMX6UL_LCDIF_REGS_NUM; +} + +static inline bool imx6ul_lcdif_reg_has_setclr(hwaddr reg) +{ + switch (reg) { + case A_CTRL: + case A_CTRL1: + return true; + default: + return false; + } +} + +static inline bool imx6ul_lcdif_is_running(IMX6ULLCDIFState *s) +{ + uint32_t ctrl = s->regs[IMX6UL_LCDIF_REG_CTRL]; + + return FIELD_EX32(ctrl, CTRL, RUN); +} + +static inline bool imx6ul_lcdif_frame_done_pending(IMX6ULLCDIFState *s) +{ + uint32_t ctrl1 = s->regs[IMX6UL_LCDIF_REG_CTRL1]; + + return FIELD_EX32(ctrl1, CTRL1, CUR_FRAME_DONE_IRQ); +} + +static void imx6ul_lcdif_schedule_frame(IMX6ULLCDIFState *s) +{ + int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + + timer_mod(s->frame_timer, now + FRAME_PERIOD_NS); +} + +static void imx6ul_lcdif_maybe_schedule_frame(IMX6ULLCDIFState *s) +{ + if (imx6ul_lcdif_is_running(s) && !imx6ul_lcdif_frame_done_pending(s)) { + imx6ul_lcdif_schedule_frame(s); + } else { + timer_del(s->frame_timer); + } +} + +static void imx6ul_lcdif_update_irq(IMX6ULLCDIFState *s) +{ + uint32_t ctrl1 = s->regs[IMX6UL_LCDIF_REG_CTRL1]; + bool level = FIELD_EX32(ctrl1, CTRL1, CUR_FRAME_DONE_IRQ_EN) && + FIELD_EX32(ctrl1, CTRL1, CUR_FRAME_DONE_IRQ); + + qemu_set_irq(s->irq, level); +} + +static void imx6ul_lcdif_frame_done(IMX6ULLCDIFState *s) +{ + uint32_t ctrl1 = s->regs[IMX6UL_LCDIF_REG_CTRL1]; + + ctrl1 = FIELD_DP32(ctrl1, CTRL1, CUR_FRAME_DONE_IRQ, 1); + s->regs[IMX6UL_LCDIF_REG_CTRL1] = ctrl1; + imx6ul_lcdif_update_irq(s); +} + +static void imx6ul_lcdif_draw_line_rgb565(void *opaque, uint8_t *dst, + const uint8_t *src, int width, + int dststep) +{ + uint32_t *dst32 = (uint32_t *)dst; + int i; + + for (i = 0; i < width; i++) { + uint16_t pixel = lduw_le_p(src); + uint8_t r = ((pixel >> 11) & 0x1f) << 3; + uint8_t g = ((pixel >> 5) & 0x3f) << 2; + uint8_t b = (pixel & 0x1f) << 3; + + *dst32++ = rgb_to_pixel32(r, g, b); + src += 2; + } +} + +static void imx6ul_lcdif_draw_line_xrgb8888(void *opaque, uint8_t *dst, + const uint8_t *src, int width, + int dststep) +{ + uint32_t *dst32 = (uint32_t *)dst; + int i; + + for (i = 0; i < width; i++) { + uint32_t pixel = ldl_le_p(src); + uint8_t r = (pixel >> 16) & 0xff; + uint8_t g = (pixel >> 8) & 0xff; + uint8_t b = pixel & 0xff; + + *dst32++ = rgb_to_pixel32(r, g, b); + src += 4; + } +} + +static void imx6ul_lcdif_update_display(void *opaque) +{ + IMX6ULLCDIFState *s = opaque; + DisplaySurface *surface = qemu_console_surface(s->con); + uint32_t transfer_count = s->regs[IMX6UL_LCDIF_REG_V4_TRANSFER_COUNT]; + uint32_t width = FIELD_EX32(transfer_count, V4_TRANSFER_COUNT, H_COUNT); + uint32_t height = FIELD_EX32(transfer_count, V4_TRANSFER_COUNT, V_COUNT); + uint32_t ctrl = s->regs[IMX6UL_LCDIF_REG_CTRL]; + uint32_t frame_base = s->regs[IMX6UL_LCDIF_REG_V4_CUR_BUF]; + drawfn fn; + int first = 0; + int last = 0; + int src_width; + + if (!imx6ul_lcdif_is_running(s) || width == 0 || height == 0) { + return; + } + + switch (FIELD_EX32(ctrl, CTRL, WORD_LENGTH)) { + case CTRL_WORD_LENGTH_16: + s->src_bpp = 2; + fn = imx6ul_lcdif_draw_line_rgb565; + break; + case CTRL_WORD_LENGTH_24: + s->src_bpp = 4; + fn = imx6ul_lcdif_draw_line_xrgb8888; + break; + default: + return; + } + + if (surface_width(surface) != width || surface_height(surface) != height) { + qemu_console_resize(s->con, width, height); + surface = qemu_console_surface(s->con); + s->invalidate = true; + } + + src_width = width * s->src_bpp; + if (s->invalidate || s->fb_base != frame_base || + s->src_width != src_width || s->rows != height) { + framebuffer_update_memory_section(&s->fbsection, get_system_memory(), + frame_base, height, src_width); + s->fb_base = frame_base; + s->src_width = src_width; + s->rows = height; + } + + framebuffer_update_display(surface, &s->fbsection, width, height, + src_width, surface_stride(surface), 0, + s->invalidate, fn, s, &first, &last); + if (first >= 0) { + dpy_gfx_update(s->con, 0, first, width, last - first + 1); + } + + s->invalidate = false; +} + +static void imx6ul_lcdif_invalidate_display(void *opaque) +{ + IMX6ULLCDIFState *s = opaque; + + s->invalidate = true; +} + +static const GraphicHwOps imx6ul_lcdif_graphic_ops = { + .invalidate = imx6ul_lcdif_invalidate_display, + .gfx_update = imx6ul_lcdif_update_display, +}; + +static void imx6ul_lcdif_frame_timer_cb(void *opaque) +{ + IMX6ULLCDIFState *s = opaque; + + if (!imx6ul_lcdif_is_running(s) || imx6ul_lcdif_frame_done_pending(s)) { + return; + } + + imx6ul_lcdif_frame_done(s); +} + +static uint64_t imx6ul_lcdif_read(void *opaque, hwaddr offset, unsigned size) +{ + IMX6ULLCDIFState *s = opaque; + hwaddr reg = offset & ~0xf; + uint32_t idx; + + assert(size == 4); + assert(!(offset & 0x3)); + assert(offset < LCDIF_MMIO_SIZE); + + idx = reg >> 4; + if (idx >= ARRAY_SIZE(s->regs)) { + return 0; + } + + return s->regs[idx]; +} + +static void imx6ul_lcdif_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + IMX6ULLCDIFState *s = opaque; + hwaddr reg = offset & ~0xf; + uint32_t idx; + uint32_t oldv; + + assert(size == 4); + assert(!(offset & 0x3)); + assert(offset < LCDIF_MMIO_SIZE); + + if (!imx6ul_lcdif_reg_exists(reg)) { + return; + } + + idx = reg >> 4; + oldv = s->regs[idx]; + + switch (offset & 0xf) { + case 0: + s->regs[idx] = (uint32_t)value; + break; + case REG_SET: + if (!imx6ul_lcdif_reg_has_setclr(reg)) { + return; + } + s->regs[idx] = oldv | (uint32_t)value; + break; + case REG_CLR: + if (!imx6ul_lcdif_reg_has_setclr(reg)) { + return; + } + s->regs[idx] = oldv & ~(uint32_t)value; + break; + case REG_TOG: + if (!imx6ul_lcdif_reg_has_setclr(reg)) { + return; + } + s->regs[idx] = oldv ^ (uint32_t)value; + break; + default: + g_assert_not_reached(); + } + + switch (reg) { + case A_CTRL: + if (!FIELD_EX32(oldv, CTRL, RUN) && + FIELD_EX32(s->regs[idx], CTRL, RUN)) { + s->invalidate = true; + graphic_hw_invalidate(s->con); + imx6ul_lcdif_maybe_schedule_frame(s); + break; + } + if (FIELD_EX32(oldv, CTRL, RUN) && + !FIELD_EX32(s->regs[idx], CTRL, RUN)) { + timer_del(s->frame_timer); + } + break; + case A_CTRL1: + if (FIELD_EX32(oldv, CTRL1, CUR_FRAME_DONE_IRQ) && + !FIELD_EX32(s->regs[idx], CTRL1, CUR_FRAME_DONE_IRQ)) { + imx6ul_lcdif_maybe_schedule_frame(s); + } + break; + case A_V4_TRANSFER_COUNT: + s->invalidate = true; + graphic_hw_invalidate(s->con); + break; + case A_V4_CUR_BUF: + s->invalidate = true; + graphic_hw_invalidate(s->con); + break; + case A_V4_NEXT_BUF: + s->regs[IMX6UL_LCDIF_REG_V4_CUR_BUF] = s->regs[idx]; + imx6ul_lcdif_frame_done(s); + s->invalidate = true; + graphic_hw_invalidate(s->con); + imx6ul_lcdif_maybe_schedule_frame(s); + return; + case A_AS_NEXT_BUF: + imx6ul_lcdif_frame_done(s); + imx6ul_lcdif_maybe_schedule_frame(s); + return; + default: + break; + } + + imx6ul_lcdif_update_irq(s); +} + +static const MemoryRegionOps imx6ul_lcdif_ops = { + .read = imx6ul_lcdif_read, + .write = imx6ul_lcdif_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + .unaligned = false, + }, +}; + +static void imx6ul_lcdif_reset(DeviceState *dev) +{ + IMX6ULLCDIFState *s = IMX6UL_LCDIF(dev); + + memset(s->regs, 0, sizeof(s->regs)); + s->regs[IMX6UL_LCDIF_REG_CTRL1] = LCDIF_RESET_CTRL1; + s->fb_base = 0; + s->src_width = 0; + s->rows = 0; + s->src_bpp = 0; + s->invalidate = true; + timer_del(s->frame_timer); + imx6ul_lcdif_update_irq(s); +} + +static int imx6ul_lcdif_post_load(void *opaque, int version_id) +{ + IMX6ULLCDIFState *s = opaque; + + s->fb_base = 0; + s->src_width = 0; + s->rows = 0; + s->src_bpp = 0; + s->invalidate = true; + + imx6ul_lcdif_update_irq(s); + if (imx6ul_lcdif_is_running(s) && + !imx6ul_lcdif_frame_done_pending(s) && + !timer_pending(s->frame_timer)) { + imx6ul_lcdif_schedule_frame(s); + } + + return 0; +} + +static const VMStateDescription vmstate_imx6ul_lcdif = { + .name = TYPE_IMX6UL_LCDIF, + .version_id = 1, + .minimum_version_id = 1, + .post_load = imx6ul_lcdif_post_load, + .fields = (const VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, IMX6ULLCDIFState, IMX6UL_LCDIF_REGS_NUM), + VMSTATE_TIMER_PTR(frame_timer, IMX6ULLCDIFState), + VMSTATE_END_OF_LIST() + }, +}; + +static void imx6ul_lcdif_realize(DeviceState *dev, Error **errp) +{ + IMX6ULLCDIFState *s = IMX6UL_LCDIF(dev); + + s->frame_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, + imx6ul_lcdif_frame_timer_cb, s); + s->invalidate = true; + memory_region_init_io(&s->iomem, OBJECT(dev), &imx6ul_lcdif_ops, s, + TYPE_IMX6UL_LCDIF, LCDIF_MMIO_SIZE); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); + sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq); + s->con = graphic_console_init(dev, 0, &imx6ul_lcdif_graphic_ops, s); +} + +static void imx6ul_lcdif_unrealize(DeviceState *dev) +{ + IMX6ULLCDIFState *s = IMX6UL_LCDIF(dev); + + timer_del(s->frame_timer); + timer_free(s->frame_timer); + s->frame_timer = NULL; + + if (s->con) { + graphic_console_close(s->con); + s->con = NULL; + } +} + +static void imx6ul_lcdif_class_init(ObjectClass *klass, const void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = imx6ul_lcdif_realize; + dc->unrealize = imx6ul_lcdif_unrealize; + dc->vmsd = &vmstate_imx6ul_lcdif; + device_class_set_legacy_reset(dc, imx6ul_lcdif_reset); + dc->desc = "i.MX6UL LCDIF"; +} + +static const TypeInfo imx6ul_lcdif_info = { + .name = TYPE_IMX6UL_LCDIF, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IMX6ULLCDIFState), + .class_init = imx6ul_lcdif_class_init, +}; + +static void imx6ul_lcdif_register_types(void) +{ + type_register_static(&imx6ul_lcdif_info); +} + +type_init(imx6ul_lcdif_register_types) diff --git a/hw/display/meson.build b/hw/display/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/display/meson.build +++ b/hw/display/meson.build @@ -XXX,XX +XXX,XX @@ system_ss.add(when: ['CONFIG_VGA_CIRRUS', 'CONFIG_VGA_ISA'], if_true: files('cir system_ss.add(when: 'CONFIG_G364FB', if_true: files('g364fb.c')) system_ss.add(when: 'CONFIG_JAZZ_LED', if_true: files('jazz_led.c')) system_ss.add(when: 'CONFIG_PL110', if_true: files('pl110.c')) +system_ss.add(when: 'CONFIG_IMX6UL_LCDIF', if_true: files('imx6ul_lcdif.c')) system_ss.add(when: 'CONFIG_SII9022', if_true: files('sii9022.c')) system_ss.add(when: 'CONFIG_SSD0303', if_true: files('ssd0303.c')) system_ss.add(when: 'CONFIG_SSD0323', if_true: files('ssd0323.c')) diff --git a/include/hw/display/imx6ul_lcdif.h b/include/hw/display/imx6ul_lcdif.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/include/hw/display/imx6ul_lcdif.h @@ -XXX,XX +XXX,XX @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * i.MX6UL LCDIF controller + * + * Copyright (c) 2026 Yucai Liu <1486344514@qq.com> + */ + +#ifndef IMX6UL_LCDIF_H +#define IMX6UL_LCDIF_H + +#include "hw/core/sysbus.h" +#include "qom/object.h" +#include "qemu/timer.h" +#include "ui/console.h" + +#define TYPE_IMX6UL_LCDIF "imx6ul-lcdif" +#define IMX6UL_LCDIF_REGS_NUM ((0x230 >> 4) + 1) +OBJECT_DECLARE_SIMPLE_TYPE(IMX6ULLCDIFState, IMX6UL_LCDIF) + +struct IMX6ULLCDIFState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + MemoryRegionSection fbsection; + qemu_irq irq; + QemuConsole *con; + QEMUTimer *frame_timer; + uint32_t fb_base; + uint32_t src_width; + uint32_t rows; + uint8_t src_bpp; + bool invalidate; + uint32_t regs[IMX6UL_LCDIF_REGS_NUM]; +}; + +#endif /* IMX6UL_LCDIF_H */ -- 2.43.0
From: Yucai Liu <1486344514@qq.com> Instantiate LCDIF as a child object of the i.MX6UL SoC in init and realize it in the SoC realize path before MMIO/IRQ hookup. Also make FSL_IMX6UL select CONFIG_IMX6UL_LCDIF and map the LCDIF region with a 16 KiB size to match the SoC memory map. Signed-off-by: Yucai Liu <1486344514@qq.com> Message-id: 20260412110240.93116-3-yangyanglan718@gmail.com Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/arm/Kconfig | 1 + hw/arm/fsl-imx6ul.c | 12 ++++++++++-- include/hw/arm/fsl-imx6ul.h | 4 +++- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -XXX,XX +XXX,XX @@ config FSL_IMX6UL imply I2C_DEVICES select A15MPCORE select IMX + select IMX6UL_LCDIF select IMX_FEC select IMX_I2C select IMX_USBPHY diff --git a/hw/arm/fsl-imx6ul.c b/hw/arm/fsl-imx6ul.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/fsl-imx6ul.c +++ b/hw/arm/fsl-imx6ul.c @@ -XXX,XX +XXX,XX @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "hw/arm/fsl-imx6ul.h" +#include "hw/display/imx6ul_lcdif.h" #include "hw/misc/unimp.h" #include "hw/usb/imx-usb-phy.h" #include "hw/core/boards.h" @@ -XXX,XX +XXX,XX @@ static void fsl_imx6ul_init(Object *obj) object_initialize_child(obj, name, &s->usb[i], TYPE_CHIPIDEA); } + /* + * LCDIF + */ + object_initialize_child(obj, "lcdif", &s->lcdif, TYPE_IMX6UL_LCDIF); + /* * SDHCIs */ @@ -XXX,XX +XXX,XX @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp) /* * LCD */ - create_unimplemented_device("lcdif", FSL_IMX6UL_LCDIF_ADDR, - FSL_IMX6UL_LCDIF_SIZE); + sysbus_realize(SYS_BUS_DEVICE(&s->lcdif), &error_abort); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->lcdif), 0, FSL_IMX6UL_LCDIF_ADDR); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->lcdif), 0, + qdev_get_gpio_in(gic, FSL_IMX6UL_LCDIF_IRQ)); /* * CSU diff --git a/include/hw/arm/fsl-imx6ul.h b/include/hw/arm/fsl-imx6ul.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/arm/fsl-imx6ul.h +++ b/include/hw/arm/fsl-imx6ul.h @@ -XXX,XX +XXX,XX @@ #include "hw/net/imx_fec.h" #include "hw/usb/chipidea.h" #include "hw/usb/imx-usb-phy.h" +#include "hw/display/imx6ul_lcdif.h" #include "system/memory.h" #include "target/arm/cpu.h" #include "qom/object.h" @@ -XXX,XX +XXX,XX @@ struct FslIMX6ULState { IMX2WdtState wdt[FSL_IMX6UL_NUM_WDTS]; IMXUSBPHYState usbphy[FSL_IMX6UL_NUM_USB_PHYS]; ChipideaState usb[FSL_IMX6UL_NUM_USBS]; + IMX6ULLCDIFState lcdif; MemoryRegion rom; MemoryRegion caam; MemoryRegion ocram; @@ -XXX,XX +XXX,XX @@ enum FslIMX6ULMemoryMap { FSL_IMX6UL_PXP_SIZE = (16 * KiB), FSL_IMX6UL_LCDIF_ADDR = 0x021C8000, - FSL_IMX6UL_LCDIF_SIZE = 0x100, + FSL_IMX6UL_LCDIF_SIZE = (16 * KiB), FSL_IMX6UL_CSI_ADDR = 0x021C4000, FSL_IMX6UL_CSI_SIZE = 0x100, -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> We have a registerfields interface which we can use for defining fields alongside helpers to access them. Define the basic syndrome layout and convert the helpers that take the imm16 data directly. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260422125250.1303100-2-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/syndrome.h | 75 ++++++++++++++++++++++++++++++++----------- 1 file changed, 57 insertions(+), 18 deletions(-) diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/syndrome.h +++ b/target/arm/syndrome.h @@ -XXX,XX +XXX,XX @@ #ifndef TARGET_ARM_SYNDROME_H #define TARGET_ARM_SYNDROME_H -#include "qemu/bitops.h" +#include "hw/core/registerfields.h" /* Valid Syndrome Register EC field values */ enum arm_exception_class { @@ -XXX,XX +XXX,XX @@ enum arm_exception_class { EC_AA64_BKPT = 0x3c, }; +/* Generic syndrome encoding layout for HSR and lower 32 bits of ESR_EL2 */ +FIELD(SYNDROME, EC, 26, 6) +FIELD(SYNDROME, IL, 25, 1) +FIELD(SYNDROME, ISS, 0, 25) + typedef enum { SME_ET_AccessTrap, SME_ET_Streaming, @@ -XXX,XX +XXX,XX @@ typedef enum { static inline uint32_t syn_get_ec(uint32_t syn) { - return syn >> ARM_EL_EC_SHIFT; + return FIELD_EX32(syn, SYNDROME, EC); } static inline uint32_t syn_set_ec(uint32_t syn, uint32_t ec) { - return deposit32(syn, ARM_EL_EC_SHIFT, ARM_EL_EC_LENGTH, ec); + return FIELD_DP32(syn, SYNDROME, EC, ec); } /* @@ -XXX,XX +XXX,XX @@ static inline uint32_t syn_set_ec(uint32_t syn, uint32_t ec) */ static inline uint32_t syn_uncategorized(void) { - return (EC_UNCATEGORIZED << ARM_EL_EC_SHIFT) | ARM_EL_IL; + uint32_t res = syn_set_ec(0, EC_UNCATEGORIZED); + res = FIELD_DP32(res, SYNDROME, IL, 1); + return res; } +FIELD(ISS_IMM16, IMM16, 0, 16) + static inline uint32_t syn_aa64_svc(uint32_t imm16) { - return (EC_AA64_SVC << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff); + uint32_t res = syn_set_ec(0, EC_AA64_SVC); + res = FIELD_DP32(res, SYNDROME, IL, 1); + res = FIELD_DP32(res, ISS_IMM16, IMM16, imm16); + return res; } static inline uint32_t syn_aa64_hvc(uint32_t imm16) { - return (EC_AA64_HVC << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff); + uint32_t res = syn_set_ec(0, EC_AA64_HVC); + res = FIELD_DP32(res, SYNDROME, IL, 1); + res = FIELD_DP32(res, ISS_IMM16, IMM16, imm16); + return res; } static inline uint32_t syn_aa64_smc(uint32_t imm16) { - return (EC_AA64_SMC << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff); + uint32_t res = syn_set_ec(0, EC_AA64_SMC); + res = FIELD_DP32(res, SYNDROME, IL, 1); + res = FIELD_DP32(res, ISS_IMM16, IMM16, imm16); + return res; } static inline uint32_t syn_aa32_svc(uint32_t imm16, bool is_16bit) { - return (EC_AA32_SVC << ARM_EL_EC_SHIFT) | (imm16 & 0xffff) - | (is_16bit ? 0 : ARM_EL_IL); + uint32_t res = syn_set_ec(0, EC_AA32_SVC); + res = FIELD_DP32(res, SYNDROME, IL, is_16bit ? 0 : 1); + res = FIELD_DP32(res, ISS_IMM16, IMM16, imm16); + return res; } static inline uint32_t syn_aa32_hvc(uint32_t imm16) { - return (EC_AA32_HVC << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff); + uint32_t res = syn_set_ec(0, EC_AA32_HVC); + res = FIELD_DP32(res, SYNDROME, IL, 1); + res = FIELD_DP32(res, ISS_IMM16, IMM16, imm16); + return res; } static inline uint32_t syn_aa32_smc(void) { - return (EC_AA32_SMC << ARM_EL_EC_SHIFT) | ARM_EL_IL; + uint32_t res = syn_set_ec(0, EC_AA32_SMC); + res = FIELD_DP32(res, SYNDROME, IL, 1); + return res; } static inline uint32_t syn_aa64_bkpt(uint32_t imm16) { - return (EC_AA64_BKPT << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff); + uint32_t res = syn_set_ec(0, EC_AA64_BKPT); + res = FIELD_DP32(res, SYNDROME, IL, 1); + res = FIELD_DP32(res, ISS_IMM16, IMM16, imm16); + return res; } static inline uint32_t syn_aa32_bkpt(uint32_t imm16, bool is_16bit) { - return (EC_AA32_BKPT << ARM_EL_EC_SHIFT) | (imm16 & 0xffff) - | (is_16bit ? 0 : ARM_EL_IL); + uint32_t res = syn_set_ec(0, EC_AA32_BKPT); + res = FIELD_DP32(res, SYNDROME, IL, is_16bit ? 0 : 1); + res = FIELD_DP32(res, ISS_IMM16, IMM16, imm16); + return res; } static inline uint32_t syn_aa64_sysregtrap(int op0, int op1, int op2, @@ -XXX,XX +XXX,XX @@ static inline uint32_t syn_simd_access_trap(int cv, int cond, bool is_16bit) static inline uint32_t syn_sve_access_trap(void) { - return (EC_SVEACCESSTRAP << ARM_EL_EC_SHIFT) | ARM_EL_IL; + uint32_t res = syn_set_ec(0, EC_SVEACCESSTRAP); + res = FIELD_DP32(res, SYNDROME, IL, 1); + return res; } /* @@ -XXX,XX +XXX,XX @@ static inline uint32_t syn_wfx(int cv, int cond, int ti, bool is_16bit) static inline uint32_t syn_illegalstate(void) { - return (EC_ILLEGALSTATE << ARM_EL_EC_SHIFT) | ARM_EL_IL; + uint32_t res = syn_set_ec(0, EC_ILLEGALSTATE); + res = FIELD_DP32(res, SYNDROME, IL, 1); + return res; } static inline uint32_t syn_pcalignment(void) { - return (EC_PCALIGNMENT << ARM_EL_EC_SHIFT) | ARM_EL_IL; + uint32_t res = syn_set_ec(0, EC_PCALIGNMENT); + res = FIELD_DP32(res, SYNDROME, IL, 1); + return res; } static inline uint32_t syn_gcs_data_check(GCSInstructionType it, int rn) @@ -XXX,XX +XXX,XX @@ static inline uint32_t syn_gcs_gcsstr(int ra, int rn) static inline uint32_t syn_serror(uint32_t extra) { - return (EC_SERROR << ARM_EL_EC_SHIFT) | ARM_EL_IL | extra; + uint32_t res = syn_set_ec(0, EC_SERROR); + res = FIELD_DP32(res, SYNDROME, IL, 1); + res = FIELD_DP32(res, SYNDROME, ISS, extra); + return res; } static inline uint32_t syn_mop(bool is_set, bool is_setg, int options, -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> Migrate syn_aa64_sysregtrap and co-processor register trap syndromes to the registerfields API. The co-processor syndromes are split between single and duel register moves. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260422125250.1303100-3-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/syndrome.h | 124 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 102 insertions(+), 22 deletions(-) diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/syndrome.h +++ b/target/arm/syndrome.h @@ -XXX,XX +XXX,XX @@ enum arm_exception_class { /* Generic syndrome encoding layout for HSR and lower 32 bits of ESR_EL2 */ FIELD(SYNDROME, EC, 26, 6) -FIELD(SYNDROME, IL, 25, 1) +FIELD(SYNDROME, IL, 25, 1) /* IL=1 for 32 bit instructions */ FIELD(SYNDROME, ISS, 0, 25) typedef enum { @@ -XXX,XX +XXX,XX @@ static inline uint32_t syn_aa64_smc(uint32_t imm16) static inline uint32_t syn_aa32_svc(uint32_t imm16, bool is_16bit) { uint32_t res = syn_set_ec(0, EC_AA32_SVC); - res = FIELD_DP32(res, SYNDROME, IL, is_16bit ? 0 : 1); + res = FIELD_DP32(res, SYNDROME, IL, !is_16bit); res = FIELD_DP32(res, ISS_IMM16, IMM16, imm16); return res; } @@ -XXX,XX +XXX,XX @@ static inline uint32_t syn_aa64_bkpt(uint32_t imm16) static inline uint32_t syn_aa32_bkpt(uint32_t imm16, bool is_16bit) { uint32_t res = syn_set_ec(0, EC_AA32_BKPT); - res = FIELD_DP32(res, SYNDROME, IL, is_16bit ? 0 : 1); + res = FIELD_DP32(res, SYNDROME, IL, !is_16bit); res = FIELD_DP32(res, ISS_IMM16, IMM16, imm16); return res; } +/* + * ISS encoding for an exception from MSR, MRS, or System instruction + * in AArch64 state. + */ +FIELD(SYSREG_ISS, ISREAD, 0, 1) /* Direction, 1 is read */ +FIELD(SYSREG_ISS, CRM, 1, 4) +FIELD(SYSREG_ISS, RT, 5, 5) +FIELD(SYSREG_ISS, CRN, 10, 4) +FIELD(SYSREG_ISS, OP1, 14, 3) +FIELD(SYSREG_ISS, OP2, 17, 3) +FIELD(SYSREG_ISS, OP0, 20, 2) + static inline uint32_t syn_aa64_sysregtrap(int op0, int op1, int op2, int crn, int crm, int rt, int isread) { - return (EC_SYSTEMREGISTERTRAP << ARM_EL_EC_SHIFT) | ARM_EL_IL - | (op0 << 20) | (op2 << 17) | (op1 << 14) | (crn << 10) | (rt << 5) - | (crm << 1) | isread; + uint32_t res = syn_set_ec(0, EC_SYSTEMREGISTERTRAP); + res = FIELD_DP32(res, SYNDROME, IL, 1); + + res = FIELD_DP32(res, SYSREG_ISS, OP0, op0); + res = FIELD_DP32(res, SYSREG_ISS, OP2, op2); + res = FIELD_DP32(res, SYSREG_ISS, OP1, op1); + res = FIELD_DP32(res, SYSREG_ISS, CRN, crn); + res = FIELD_DP32(res, SYSREG_ISS, RT, rt); + res = FIELD_DP32(res, SYSREG_ISS, CRM, crm); + res = FIELD_DP32(res, SYSREG_ISS, ISREAD, isread); + + return res; } +/* + * ISS encoding for an exception from an MCR or MRC access + * (move to/from co-processor) + */ +FIELD(COPROC_ISS, ISREAD, 0, 1) +FIELD(COPROC_ISS, CRM, 1, 4) +FIELD(COPROC_ISS, RT, 5, 5) +FIELD(COPROC_ISS, CRN, 10, 4) +FIELD(COPROC_ISS, OP1, 14, 3) +FIELD(COPROC_ISS, OP2, 17, 3) +FIELD(COPROC_ISS, COND, 20, 4) +FIELD(COPROC_ISS, CV, 24, 1) + static inline uint32_t syn_cp14_rt_trap(int cv, int cond, int opc1, int opc2, int crn, int crm, int rt, int isread, bool is_16bit) { - return (EC_CP14RTTRAP << ARM_EL_EC_SHIFT) - | (is_16bit ? 0 : ARM_EL_IL) - | (cv << 24) | (cond << 20) | (opc2 << 17) | (opc1 << 14) - | (crn << 10) | (rt << 5) | (crm << 1) | isread; + uint32_t res = syn_set_ec(0, EC_CP14RTTRAP); + res = FIELD_DP32(res, SYNDROME, IL, !is_16bit); + + res = FIELD_DP32(res, COPROC_ISS, CV, cv); + res = FIELD_DP32(res, COPROC_ISS, COND, cond); + res = FIELD_DP32(res, COPROC_ISS, OP2, opc2); + res = FIELD_DP32(res, COPROC_ISS, OP1, opc1); + res = FIELD_DP32(res, COPROC_ISS, CRN, crn); + res = FIELD_DP32(res, COPROC_ISS, RT, rt); + res = FIELD_DP32(res, COPROC_ISS, CRM, crm); + res = FIELD_DP32(res, COPROC_ISS, ISREAD, isread); + + return res; } static inline uint32_t syn_cp15_rt_trap(int cv, int cond, int opc1, int opc2, int crn, int crm, int rt, int isread, bool is_16bit) { - return (EC_CP15RTTRAP << ARM_EL_EC_SHIFT) - | (is_16bit ? 0 : ARM_EL_IL) - | (cv << 24) | (cond << 20) | (opc2 << 17) | (opc1 << 14) - | (crn << 10) | (rt << 5) | (crm << 1) | isread; + uint32_t res = syn_set_ec(0, EC_CP15RTTRAP); + res = FIELD_DP32(res, SYNDROME, IL, !is_16bit); + + res = FIELD_DP32(res, COPROC_ISS, CV, cv); + res = FIELD_DP32(res, COPROC_ISS, COND, cond); + res = FIELD_DP32(res, COPROC_ISS, OP2, opc2); + res = FIELD_DP32(res, COPROC_ISS, OP1, opc1); + res = FIELD_DP32(res, COPROC_ISS, CRN, crn); + res = FIELD_DP32(res, COPROC_ISS, RT, rt); + res = FIELD_DP32(res, COPROC_ISS, CRM, crm); + res = FIELD_DP32(res, COPROC_ISS, ISREAD, isread); + + return res; } +/* + * ISS encoding for an exception from an MCRR or MRRC access + * (move to/from co-processor with 2 regs) + */ +FIELD(COPROC_R2_ISS, ISREAD, 0, 1) +FIELD(COPROC_R2_ISS, CRM, 1, 4) +FIELD(COPROC_R2_ISS, RT, 5, 5) +FIELD(COPROC_R2_ISS, RT2, 10, 5) +FIELD(COPROC_R2_ISS, OP1, 16, 4) +FIELD(COPROC_R2_ISS, COND, 20, 4) +FIELD(COPROC_R2_ISS, CV, 24, 1) + static inline uint32_t syn_cp14_rrt_trap(int cv, int cond, int opc1, int crm, int rt, int rt2, int isread, bool is_16bit) { - return (EC_CP14RRTTRAP << ARM_EL_EC_SHIFT) - | (is_16bit ? 0 : ARM_EL_IL) - | (cv << 24) | (cond << 20) | (opc1 << 16) - | (rt2 << 10) | (rt << 5) | (crm << 1) | isread; + uint32_t res = syn_set_ec(0, EC_CP14RRTTRAP); + res = FIELD_DP32(res, SYNDROME, IL, !is_16bit); + + res = FIELD_DP32(res, COPROC_R2_ISS, CV, cv); + res = FIELD_DP32(res, COPROC_R2_ISS, COND, cond); + res = FIELD_DP32(res, COPROC_R2_ISS, OP1, opc1); + res = FIELD_DP32(res, COPROC_R2_ISS, RT2, rt2); + res = FIELD_DP32(res, COPROC_R2_ISS, RT, rt); + res = FIELD_DP32(res, COPROC_R2_ISS, CRM, crm); + res = FIELD_DP32(res, COPROC_R2_ISS, ISREAD, isread); + + return res; } static inline uint32_t syn_cp15_rrt_trap(int cv, int cond, int opc1, int crm, int rt, int rt2, int isread, bool is_16bit) { - return (EC_CP15RRTTRAP << ARM_EL_EC_SHIFT) - | (is_16bit ? 0 : ARM_EL_IL) - | (cv << 24) | (cond << 20) | (opc1 << 16) - | (rt2 << 10) | (rt << 5) | (crm << 1) | isread; + uint32_t res = syn_set_ec(0, EC_CP15RRTTRAP); + res = FIELD_DP32(res, SYNDROME, IL, !is_16bit); + + res = FIELD_DP32(res, COPROC_R2_ISS, CV, cv); + res = FIELD_DP32(res, COPROC_R2_ISS, COND, cond); + res = FIELD_DP32(res, COPROC_R2_ISS, OP1, opc1); + res = FIELD_DP32(res, COPROC_R2_ISS, RT2, rt2); + res = FIELD_DP32(res, COPROC_R2_ISS, RT, rt); + res = FIELD_DP32(res, COPROC_R2_ISS, CRM, crm); + res = FIELD_DP32(res, COPROC_R2_ISS, ISREAD, isread); + + return res; } static inline uint32_t syn_fp_access_trap(int cv, int cond, bool is_16bit, -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> The syn_simd_access trap was never used so remove it. We should only see the COPROC encoding on v7 architectures. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260422125250.1303100-4-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/syndrome.h | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/syndrome.h +++ b/target/arm/syndrome.h @@ -XXX,XX +XXX,XX @@ static inline uint32_t syn_cp15_rrt_trap(int cv, int cond, int opc1, int crm, return res; } +/* + * ISS encoding for an exception from an access to a register of + * instruction resulting from the FPEN or TFP traps. + */ +FIELD(FP_ISS, COPROC, 0, 4) /* ARMv7 only */ +FIELD(FP_ISS, COND, 20, 4) +FIELD(FP_ISS, CV, 24, 1) + static inline uint32_t syn_fp_access_trap(int cv, int cond, bool is_16bit, int coproc) { /* AArch32 FP trap or any AArch64 FP/SIMD trap: TA == 0 */ - return (EC_ADVSIMDFPACCESSTRAP << ARM_EL_EC_SHIFT) - | (is_16bit ? 0 : ARM_EL_IL) - | (cv << 24) | (cond << 20) | coproc; -} + uint32_t res = syn_set_ec(0, EC_ADVSIMDFPACCESSTRAP); + res = FIELD_DP32(res, SYNDROME, IL, !is_16bit); -static inline uint32_t syn_simd_access_trap(int cv, int cond, bool is_16bit) -{ - /* AArch32 SIMD trap: TA == 1 coproc == 0 */ - return (EC_ADVSIMDFPACCESSTRAP << ARM_EL_EC_SHIFT) - | (is_16bit ? 0 : ARM_EL_IL) - | (cv << 24) | (cond << 20) | (1 << 5); + res = FIELD_DP32(res, FP_ISS, CV, cv); + res = FIELD_DP32(res, FP_ISS, COND, cond); + res = FIELD_DP32(res, FP_ISS, COPROC, coproc); + + return res; } static inline uint32_t syn_sve_access_trap(void) -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> For simplicity keep the OP as a two bit field rather than the two interlinked fields in the docs (ERET/ERETA). Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260422125250.1303100-5-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/syndrome.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/syndrome.h +++ b/target/arm/syndrome.h @@ -XXX,XX +XXX,XX @@ static inline uint32_t syn_sve_access_trap(void) } /* + * ISS encoding for an exception from an ERET, ERETAA or ERETAB + * instructions. + * * eret_op is bits [1:0] of the ERET instruction, so: * 0 for ERET, 2 for ERETAA, 3 for ERETAB. */ +FIELD(ERET_ISS, OP, 0, 2) + static inline uint32_t syn_erettrap(int eret_op) { - return (EC_ERETTRAP << ARM_EL_EC_SHIFT) | ARM_EL_IL | eret_op; + uint32_t res = syn_set_ec(0, EC_ERETTRAP); + res = FIELD_DP32(res, SYNDROME, IL, 1); + res = FIELD_DP32(res, ERET_ISS, OP, eret_op); + + return res; } static inline uint32_t syn_smetrap(SMEExceptionType etype, bool is_16bit) -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260422125250.1303100-6-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/syndrome.h | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/syndrome.h +++ b/target/arm/syndrome.h @@ -XXX,XX +XXX,XX @@ static inline uint32_t syn_erettrap(int eret_op) return res; } +/* + * ISS encoding for an exception due to SME functionality + */ +FIELD(SME_ISS, SMTC, 0, 2) + static inline uint32_t syn_smetrap(SMEExceptionType etype, bool is_16bit) { - return (EC_SMETRAP << ARM_EL_EC_SHIFT) - | (is_16bit ? 0 : ARM_EL_IL) | etype; + uint32_t res = syn_set_ec(0, EC_SMETRAP); + res = FIELD_DP32(res, SYNDROME, IL, !is_16bit); + res = FIELD_DP32(res, SME_ISS, SMTC, etype); + + return res; } static inline uint32_t syn_pacfail(bool data, int keynumber) -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> syn_pactrap is fairly simple as the ISS is all RES0. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260422125250.1303100-7-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/syndrome.h | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/syndrome.h +++ b/target/arm/syndrome.h @@ -XXX,XX +XXX,XX @@ static inline uint32_t syn_smetrap(SMEExceptionType etype, bool is_16bit) return res; } +/* + * ISS encoding for a PAC Fail exceptions + */ +FIELD(PACFAIL_ISS, BnA, 0, 1) /* B key or A key */ +FIELD(PACFAIL_ISS, DnI, 1, 1) /* Data or Instruction */ + static inline uint32_t syn_pacfail(bool data, int keynumber) { - int error_code = (data << 1) | keynumber; - return (EC_PACFAIL << ARM_EL_EC_SHIFT) | ARM_EL_IL | error_code; + uint32_t res = syn_set_ec(0, EC_PACFAIL); + res = FIELD_DP32(res, SYNDROME, IL, 1); + + res = FIELD_DP32(res, PACFAIL_ISS, DnI, data); + res = FIELD_DP32(res, PACFAIL_ISS, BnA, keynumber); + + return res; } +/* + * ISS encoding for an exception from a trapped Pointer + * Authentication instruction is RES0 + */ static inline uint32_t syn_pactrap(void) { - return (EC_PACTRAP << ARM_EL_EC_SHIFT) | ARM_EL_IL; + uint32_t res = syn_set_ec(0, EC_PACTRAP); + res = FIELD_DP32(res, SYNDROME, IL, 1); + return res; } static inline uint32_t syn_btitrap(int btype) -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260422125250.1303100-8-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/syndrome.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/syndrome.h +++ b/target/arm/syndrome.h @@ -XXX,XX +XXX,XX @@ static inline uint32_t syn_pactrap(void) return res; } +/* + * ISS encoding for an exception from a Branch Target Identification + * instruction. + */ +FIELD(BTI_ISS, BTYPE, 0, 2) + static inline uint32_t syn_btitrap(int btype) { - return (EC_BTITRAP << ARM_EL_EC_SHIFT) | ARM_EL_IL | btype; + uint32_t res = syn_set_ec(0, EC_BTITRAP); + res = FIELD_DP32(res, SYNDROME, IL, 1); + res = FIELD_DP32(res, BTI_ISS, BTYPE, btype); + return res; } static inline uint32_t syn_bxjtrap(int cv, int cond, int rm) -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> This is an Armv7 specific syndrome for chips with Jazelle functionality. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260422125250.1303100-9-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/syndrome.h | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/syndrome.h +++ b/target/arm/syndrome.h @@ -XXX,XX +XXX,XX @@ static inline uint32_t syn_btitrap(int btype) return res; } +/* + * ISS encoding for trapped BXJ execution + * + * This is an Armv7 encoding. + */ +FIELD(BXJ_ISS, RM, 0, 4) +/* bits 4:19 are Reserved, UNK/SBZP */ +FIELD(BXJ_ISS, COND, 20, 4) +FIELD(BXJ_ISS, CV, 24, 1) + static inline uint32_t syn_bxjtrap(int cv, int cond, int rm) { - return (EC_BXJTRAP << ARM_EL_EC_SHIFT) | ARM_EL_IL | - (cv << 24) | (cond << 20) | rm; + uint32_t res = syn_set_ec(0, EC_BXJTRAP); + res = FIELD_DP32(res, SYNDROME, IL, 1); + + res = FIELD_DP32(res, BXJ_ISS, CV, cv); + res = FIELD_DP32(res, BXJ_ISS, COND, cond); + res = FIELD_DP32(res, BXJ_ISS, RM, rm); + + return res; } static inline uint32_t syn_gpc(int s2ptw, int ind, int gpcsc, int vncr, -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260422125250.1303100-10-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/syndrome.h | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/syndrome.h +++ b/target/arm/syndrome.h @@ -XXX,XX +XXX,XX @@ static inline uint32_t syn_bxjtrap(int cv, int cond, int rm) return res; } +/* + * ISS encoding for a Granule Protection Check exception + * + * These are only reported to EL3 + */ +FIELD(GPC_ISS, xFSC, 0, 6) +FIELD(GPC_ISS, WnR, 6, 1) /* Write not Read */ +FIELD(GPC_ISS, S1PTW, 7, 1) +FIELD(GPC_ISS, CM, 8, 1) +FIELD(GPC_ISS, VNCR, 13, 1) +FIELD(GPC_ISS, GPCSC, 14, 6) +FIELD(GPC_ISS, InD, 20, 1) /* Instruction not Data access */ +FIELD(GPC_ISS, S2PTW, 21, 1) + static inline uint32_t syn_gpc(int s2ptw, int ind, int gpcsc, int vncr, int cm, int s1ptw, int wnr, int fsc) { - return (EC_GPC << ARM_EL_EC_SHIFT) | ARM_EL_IL | (s2ptw << 21) - | (ind << 20) | (gpcsc << 14) | (vncr << 13) | (cm << 8) - | (s1ptw << 7) | (wnr << 6) | fsc; + uint32_t res = syn_set_ec(0, EC_GPC); + res = FIELD_DP32(res, SYNDROME, IL, 1); + + res = FIELD_DP32(res, GPC_ISS, S2PTW, s2ptw); + res = FIELD_DP32(res, GPC_ISS, InD, ind); + res = FIELD_DP32(res, GPC_ISS, GPCSC, gpcsc); + res = FIELD_DP32(res, GPC_ISS, VNCR, vncr); + res = FIELD_DP32(res, GPC_ISS, CM, cm); + res = FIELD_DP32(res, GPC_ISS, S1PTW, s1ptw); + res = FIELD_DP32(res, GPC_ISS, WnR, wnr); + res = FIELD_DP32(res, GPC_ISS, xFSC, fsc); + + return res; } static inline uint32_t syn_insn_abort(int same_el, int ea, int s1ptw, int fsc) -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> Migrate syn_insn_abort and syn_data_abort_* to the registerfields API. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-id: 20260422125250.1303100-11-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/syndrome.h | 87 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 74 insertions(+), 13 deletions(-) diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/syndrome.h +++ b/target/arm/syndrome.h @@ -XXX,XX +XXX,XX @@ static inline uint32_t syn_gpc(int s2ptw, int ind, int gpcsc, int vncr, return res; } +/* + * ISS encoding for an exception from an Instruction Abort + * + * (aka instruction abort) + */ +FIELD(IABORT_ISS, IFSC, 0, 6) +FIELD(IABORT_ISS, S1PTW, 7, 1) +FIELD(IABORT_ISS, EA, 9, 1) +FIELD(IABORT_ISS, FnV, 10, 1) /* FAR not Valid */ +FIELD(IABORT_ISS, SET, 11, 2) +FIELD(IABORT_ISS, PFV, 14, 1) +FIELD(IABORT_ISS, TopLevel, 21, 1) /* FEAT_THE */ + static inline uint32_t syn_insn_abort(int same_el, int ea, int s1ptw, int fsc) { - return (EC_INSNABORT << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT) - | ARM_EL_IL | (ea << 9) | (s1ptw << 7) | fsc; + uint32_t res = syn_set_ec(0, EC_INSNABORT + same_el); + res = FIELD_DP32(res, SYNDROME, IL, 1); + + res = FIELD_DP32(res, IABORT_ISS, EA, ea); + res = FIELD_DP32(res, IABORT_ISS, S1PTW, s1ptw); + res = FIELD_DP32(res, IABORT_ISS, IFSC, fsc); + + return res; } +/* + * ISS encoding for an exception from a Data Abort + */ +FIELD(DABORT_ISS, DFSC, 0, 6) +FIELD(DABORT_ISS, WNR, 6, 1) +FIELD(DABORT_ISS, S1PTW, 7, 1) +FIELD(DABORT_ISS, CM, 8, 1) +FIELD(DABORT_ISS, EA, 9, 1) +FIELD(DABORT_ISS, FnV, 10, 1) +FIELD(DABORT_ISS, LST, 11, 2) +FIELD(DABORT_ISS, VNCR, 13, 1) +FIELD(DABORT_ISS, AR, 14, 1) +FIELD(DABORT_ISS, SF, 15, 1) +FIELD(DABORT_ISS, SRT, 16, 5) +FIELD(DABORT_ISS, SSE, 21, 1) +FIELD(DABORT_ISS, SAS, 22, 2) +FIELD(DABORT_ISS, ISV, 24, 1) + static inline uint32_t syn_data_abort_no_iss(int same_el, int fnv, int ea, int cm, int s1ptw, int wnr, int fsc) { - return (EC_DATAABORT << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT) - | ARM_EL_IL - | (fnv << 10) | (ea << 9) | (cm << 8) | (s1ptw << 7) - | (wnr << 6) | fsc; + uint32_t res = syn_set_ec(0, EC_DATAABORT + same_el); + res = FIELD_DP32(res, SYNDROME, IL, 1); + + res = FIELD_DP32(res, DABORT_ISS, FnV, fnv); + res = FIELD_DP32(res, DABORT_ISS, EA, ea); + res = FIELD_DP32(res, DABORT_ISS, CM, cm); + res = FIELD_DP32(res, DABORT_ISS, S1PTW, s1ptw); + res = FIELD_DP32(res, DABORT_ISS, WNR, wnr); + res = FIELD_DP32(res, DABORT_ISS, DFSC, fsc); + + return res; } static inline uint32_t syn_data_abort_with_iss(int same_el, @@ -XXX,XX +XXX,XX @@ static inline uint32_t syn_data_abort_with_iss(int same_el, int wnr, int fsc, bool is_16bit) { - return (EC_DATAABORT << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT) - | (is_16bit ? 0 : ARM_EL_IL) - | ARM_EL_ISV | (sas << 22) | (sse << 21) | (srt << 16) - | (sf << 15) | (ar << 14) - | (ea << 9) | (cm << 8) | (s1ptw << 7) | (wnr << 6) | fsc; + uint32_t res = syn_set_ec(0, EC_DATAABORT + same_el); + res = FIELD_DP32(res, SYNDROME, IL, !is_16bit); + + res = FIELD_DP32(res, DABORT_ISS, ISV, 1); + res = FIELD_DP32(res, DABORT_ISS, SAS, sas); + res = FIELD_DP32(res, DABORT_ISS, SSE, sse); + res = FIELD_DP32(res, DABORT_ISS, SRT, srt); + res = FIELD_DP32(res, DABORT_ISS, SF, sf); + res = FIELD_DP32(res, DABORT_ISS, AR, ar); + res = FIELD_DP32(res, DABORT_ISS, EA, ea); + res = FIELD_DP32(res, DABORT_ISS, CM, cm); + res = FIELD_DP32(res, DABORT_ISS, S1PTW, s1ptw); + res = FIELD_DP32(res, DABORT_ISS, WNR, wnr); + res = FIELD_DP32(res, DABORT_ISS, DFSC, fsc); + + return res; } /* @@ -XXX,XX +XXX,XX @@ static inline uint32_t syn_data_abort_with_iss(int same_el, */ static inline uint32_t syn_data_abort_vncr(int ea, int wnr, int fsc) { - return (EC_DATAABORT << ARM_EL_EC_SHIFT) | (1 << ARM_EL_EC_SHIFT) - | ARM_EL_IL | ARM_EL_VNCR | (wnr << 6) | fsc; + uint32_t res = syn_set_ec(0, EC_DATAABORT_SAME_EL); + res = FIELD_DP32(res, SYNDROME, IL, 1); + + res = FIELD_DP32(res, DABORT_ISS, VNCR, 1); + res = FIELD_DP32(res, DABORT_ISS, WNR, wnr); + res = FIELD_DP32(res, DABORT_ISS, DFSC, fsc); + + return res; } static inline uint32_t syn_swstep(int same_el, int isv, int ex) -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> Migrate syn_swstep, syn_watchpoint and syn_breakpoint to the registerfields API. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260422125250.1303100-12-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/syndrome.h | 54 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 6 deletions(-) diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/syndrome.h +++ b/target/arm/syndrome.h @@ -XXX,XX +XXX,XX @@ static inline uint32_t syn_data_abort_vncr(int ea, int wnr, int fsc) return res; } +/* + * ISS encoding for an exception from a Software Step exception. + */ +FIELD(SOFTSTEP_ISS, IFSC, 0, 6) +FIELD(SOFTSTEP_ISS, EX, 6, 1) +FIELD(SOFTSTEP_ISS, ISV, 24, 1) + static inline uint32_t syn_swstep(int same_el, int isv, int ex) { - return (EC_SOFTWARESTEP << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT) - | ARM_EL_IL | (isv << 24) | (ex << 6) | 0x22; + uint32_t res = syn_set_ec(0, EC_SOFTWARESTEP + same_el); + res = FIELD_DP32(res, SYNDROME, IL, 1); + + res = FIELD_DP32(res, SOFTSTEP_ISS, ISV, isv); + res = FIELD_DP32(res, SOFTSTEP_ISS, EX, ex); + res = FIELD_DP32(res, SOFTSTEP_ISS, IFSC, 0x22); + + return res; } +/* + * ISS encoding for an exception from a Watchpoint exception + */ +FIELD(WATCHPOINT_ISS, DFSC, 0, 6) +FIELD(WATCHPOINT_ISS, WNR, 6, 1) +FIELD(WATCHPOINT_ISS, CM, 8, 1) +FIELD(WATCHPOINT_ISS, FnV, 10, 1) +FIELD(WATCHPOINT_ISS, VNCR, 13, 1) /* FEAT_NV2 */ +FIELD(WATCHPOINT_ISS, FnP, 15, 1) +FIELD(WATCHPOINT_ISS, WPF, 16, 1) +/* bellow mandatory from FEAT_Debugv8p9 */ +FIELD(WATCHPOINT_ISS, WPTV, 17, 1) /* FEAT_Debugv8p2 - WPT valid */ +FIELD(WATCHPOINT_ISS, WPT, 18, 6) /* FEAT_Debugv8p2 - missing WP number */ + static inline uint32_t syn_watchpoint(int same_el, int cm, int wnr) { - return (EC_WATCHPOINT << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT) - | ARM_EL_IL | (cm << 8) | (wnr << 6) | 0x22; + uint32_t res = syn_set_ec(0, EC_WATCHPOINT + same_el); + res = FIELD_DP32(res, SYNDROME, IL, 1); + + res = FIELD_DP32(res, WATCHPOINT_ISS, CM, cm); + res = FIELD_DP32(res, WATCHPOINT_ISS, WNR, wnr); + res = FIELD_DP32(res, WATCHPOINT_ISS, DFSC, 0x22); + + return res; } +/* + * ISS encoding for an exception from a Breakpoint or a Vector Catch + * debug exception. + */ +FIELD(BREAKPOINT_ISS, IFSC, 0, 6) + static inline uint32_t syn_breakpoint(int same_el) { - return (EC_BREAKPOINT << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT) - | ARM_EL_IL | 0x22; + uint32_t res = syn_set_ec(0, EC_BREAKPOINT + same_el); + res = FIELD_DP32(res, SYNDROME, IL, 1); + res = FIELD_DP32(res, BREAKPOINT_ISS, IFSC, 0x22); + + return res; } static inline uint32_t syn_wfx(int cv, int cond, int ti, bool is_16bit) -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> This will help later when we expand the fields we report. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260422125250.1303100-13-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/syndrome.h | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/syndrome.h +++ b/target/arm/syndrome.h @@ -XXX,XX +XXX,XX @@ static inline uint32_t syn_breakpoint(int same_el) return res; } +/* + * ISS encoding for an exception from a WF* instruction + */ +FIELD(WFX_ISS, TI, 0, 2) +FIELD(WFX_ISS, RV, 2, 1) +FIELD(WFX_ISS, RN, 5, 5) +FIELD(WFX_ISS, COND, 20, 4) +FIELD(WFX_ISS, CV, 24, 1) + static inline uint32_t syn_wfx(int cv, int cond, int ti, bool is_16bit) { - return (EC_WFX_TRAP << ARM_EL_EC_SHIFT) | - (is_16bit ? 0 : (1 << ARM_EL_IL_SHIFT)) | - (cv << 24) | (cond << 20) | ti; + uint32_t res = syn_set_ec(0, EC_WFX_TRAP); + res = FIELD_DP32(res, SYNDROME, IL, !is_16bit); + + res = FIELD_DP32(res, WFX_ISS, CV, cv); + res = FIELD_DP32(res, WFX_ISS, COND, cond); + res = FIELD_DP32(res, WFX_ISS, TI, ti); + + return res; } static inline uint32_t syn_illegalstate(void) -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> Tweak arg names to make it clear raddr is the data address register number. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260422125250.1303100-14-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/syndrome.h | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/syndrome.h +++ b/target/arm/syndrome.h @@ -XXX,XX +XXX,XX @@ static inline uint32_t syn_pcalignment(void) return res; } +/* + * ISS encoding for a GCS exception + * + * Field validity depends on EXTYPE + */ +FIELD(GCS_ISS, IT, 0, 5) +FIELD(GCS_ISS, RN, 5, 5) /* only for non EXLOCK exceptions */ +FIELD(GCS_ISS, RADDR, 10, 5) /* only for GCSSTR/GCSSTTR traps */ +FIELD(GCS_ISS, EXTYPE, 20, 4) + static inline uint32_t syn_gcs_data_check(GCSInstructionType it, int rn) { - return ((EC_GCS << ARM_EL_EC_SHIFT) | ARM_EL_IL | - (GCS_ET_DataCheck << 20) | (rn << 5) | it); + uint32_t res = syn_set_ec(0, EC_GCS); + res = FIELD_DP32(res, SYNDROME, IL, 1); + + res = FIELD_DP32(res, GCS_ISS, EXTYPE, GCS_ET_DataCheck); + res = FIELD_DP32(res, GCS_ISS, RN, rn); + res = FIELD_DP32(res, GCS_ISS, IT, it); + + return res; } static inline uint32_t syn_gcs_exlock(void) { - return (EC_GCS << ARM_EL_EC_SHIFT) | ARM_EL_IL | (GCS_ET_EXLOCK << 20); + uint32_t res = syn_set_ec(0, EC_GCS); + res = FIELD_DP32(res, SYNDROME, IL, 1); + + res = FIELD_DP32(res, GCS_ISS, EXTYPE, GCS_ET_EXLOCK); + + return res; } -static inline uint32_t syn_gcs_gcsstr(int ra, int rn) +static inline uint32_t syn_gcs_gcsstr(int raddr, int rn) { - return ((EC_GCS << ARM_EL_EC_SHIFT) | ARM_EL_IL | - (GCS_ET_GCSSTR_GCSSTTR << 20) | (ra << 10) | (rn << 5)); + uint32_t res = syn_set_ec(0, EC_GCS); + res = FIELD_DP32(res, SYNDROME, IL, 1); + + res = FIELD_DP32(res, GCS_ISS, EXTYPE, GCS_ET_GCSSTR_GCSSTTR); + res = FIELD_DP32(res, GCS_ISS, RADDR, raddr); + res = FIELD_DP32(res, GCS_ISS, RN, rn); + + return res; } static inline uint32_t syn_serror(uint32_t extra) -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260422125250.1303100-15-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/syndrome.h | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/syndrome.h +++ b/target/arm/syndrome.h @@ -XXX,XX +XXX,XX @@ static inline uint32_t syn_serror(uint32_t extra) return res; } +/* + * ISS encoding for an exception from the Memory Copy and Memory Set + * instructions. + */ +FIELD(MOP_ISS, SIZEREG, 0, 5) +FIELD(MOP_ISS, SRCREG, 5, 5) +FIELD(MOP_ISS, DESTREG, 10, 5) +FIELD(MOP_ISS, FORMATOPT, 16, 2) +FIELD(MOP_ISS, OPT_A, 16, 1) +FIELD(MOP_ISS, WRONG_OPT, 17, 1) +FIELD(MOP_ISS, EPILOGUE, 18, 1) +FIELD(MOP_ISS, OPTIONS, 19, 4) +FIELD(MOP_ISS, IS_SETG, 23, 1) +FIELD(MOP_ISS, MEMINST, 24, 1) + static inline uint32_t syn_mop(bool is_set, bool is_setg, int options, bool epilogue, bool wrong_option, bool option_a, int destreg, int srcreg, int sizereg) { - return (EC_MOP << ARM_EL_EC_SHIFT) | ARM_EL_IL | - (is_set << 24) | (is_setg << 23) | (options << 19) | - (epilogue << 18) | (wrong_option << 17) | (option_a << 16) | - (destreg << 10) | (srcreg << 5) | sizereg; + uint32_t res = syn_set_ec(0, EC_MOP); + res = FIELD_DP32(res, SYNDROME, IL, 1); + + res = FIELD_DP32(res, MOP_ISS, MEMINST, is_set); + res = FIELD_DP32(res, MOP_ISS, IS_SETG, is_setg); + res = FIELD_DP32(res, MOP_ISS, OPTIONS, options); + res = FIELD_DP32(res, MOP_ISS, EPILOGUE, epilogue); + res = FIELD_DP32(res, MOP_ISS, WRONG_OPT, wrong_option); + res = FIELD_DP32(res, MOP_ISS, OPT_A, option_a); + res = FIELD_DP32(res, MOP_ISS, DESTREG, destreg); + res = FIELD_DP32(res, MOP_ISS, SRCREG, srcreg); + res = FIELD_DP32(res, MOP_ISS, SIZEREG, sizereg); + + return res; } -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> It shares the same COPROC_ISS encoding as the other CP traps although not all the fields are used. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260422125250.1303100-16-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/syndrome.h | 16 ++++++++++++++++ target/arm/tcg/vfp_helper.c | 5 +---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/syndrome.h +++ b/target/arm/syndrome.h @@ -XXX,XX +XXX,XX @@ FIELD(COPROC_ISS, OP2, 17, 3) FIELD(COPROC_ISS, COND, 20, 4) FIELD(COPROC_ISS, CV, 24, 1) +static inline uint32_t syn_cp10_rt_trap(int cv, int cond, int opc1, + int crn, int rt, int isread) +{ + uint32_t res = syn_set_ec(0, EC_FPIDTRAP); + res = FIELD_DP32(res, SYNDROME, IL, 1); + + res = FIELD_DP32(res, COPROC_ISS, CV, cv); + res = FIELD_DP32(res, COPROC_ISS, COND, cond); + res = FIELD_DP32(res, COPROC_ISS, OP1, opc1); + res = FIELD_DP32(res, COPROC_ISS, CRN, crn); + res = FIELD_DP32(res, COPROC_ISS, RT, rt); + res = FIELD_DP32(res, COPROC_ISS, ISREAD, isread); + + return res; +} + static inline uint32_t syn_cp14_rt_trap(int cv, int cond, int opc1, int opc2, int crn, int crm, int rt, int isread, bool is_16bit) diff --git a/target/arm/tcg/vfp_helper.c b/target/arm/tcg/vfp_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/vfp_helper.c +++ b/target/arm/tcg/vfp_helper.c @@ -XXX,XX +XXX,XX @@ void HELPER(check_hcr_el2_trap)(CPUARMState *env, uint32_t rt, uint32_t reg) g_assert_not_reached(); } - syndrome = ((EC_FPIDTRAP << ARM_EL_EC_SHIFT) - | ARM_EL_IL - | (1 << 24) | (0xe << 20) | (7 << 14) - | (reg << 10) | (rt << 5) | 1); + syndrome = syn_cp10_rt_trap(1, 0xe, 7, reg, rt, 1); raise_exception(env, EXCP_HYP_TRAP, syndrome, 2); } -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> One more step towards dropping the old #defines. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260422125250.1303100-17-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -XXX,XX +XXX,XX @@ static void arm_cpu_do_interrupt_aarch32_hyp(CPUState *cs) */ if (cs->exception_index == EXCP_PREFETCH_ABORT || (cs->exception_index == EXCP_DATA_ABORT && - !(env->exception.syndrome & ARM_EL_ISV)) || + !FIELD_EX32(env->exception.syndrome, SYNDROME, IL)) || syn_get_ec(env->exception.syndrome) == EC_UNCATEGORIZED) { - env->exception.syndrome &= ~ARM_EL_IL; + env->exception.syndrome = FIELD_DP32(env->exception.syndrome, SYNDROME, IL, 0); } } env->cp15.esr_el[2] = env->exception.syndrome; -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> This removes the last use of ARM_EL_EC_SHIFT. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260422125250.1303100-18-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/syndrome.h | 1 - target/arm/tcg/debug.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/syndrome.h +++ b/target/arm/syndrome.h @@ -XXX,XX +XXX,XX @@ typedef enum { } GCSInstructionType; #define ARM_EL_EC_LENGTH 6 -#define ARM_EL_EC_SHIFT 26 #define ARM_EL_IL_SHIFT 25 #define ARM_EL_ISV_SHIFT 24 #define ARM_EL_IL (1 << ARM_EL_IL_SHIFT) diff --git a/target/arm/tcg/debug.c b/target/arm/tcg/debug.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/debug.c +++ b/target/arm/tcg/debug.c @@ -XXX,XX +XXX,XX @@ raise_exception_debug(CPUARMState *env, uint32_t excp, uint32_t syndrome) * Similarly for watchpoint and breakpoint matches. */ assert(debug_el >= cur_el); - syndrome |= (debug_el == cur_el) << ARM_EL_EC_SHIFT; + syndrome |= (debug_el == cur_el) << R_SYNDROME_EC_SHIFT; raise_exception(env, excp, syndrome, debug_el); } -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> Rather than open coding a bunch of shifts and masks we can use the syndrome definitions. While we are at it assert it really is a EC_DATAABORT. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260422125250.1303100-19-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/whpx/whpx-all.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/target/arm/whpx/whpx-all.c b/target/arm/whpx/whpx-all.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/whpx/whpx-all.c +++ b/target/arm/whpx/whpx-all.c @@ -XXX,XX +XXX,XX @@ static int whpx_handle_mmio(CPUState *cpu, WHV_MEMORY_ACCESS_CONTEXT *ctx) { uint64_t syndrome = ctx->Syndrome; - bool isv = syndrome & ARM_EL_ISV; - bool iswrite = (syndrome >> 6) & 1; - bool sse = (syndrome >> 21) & 1; - uint32_t sas = (syndrome >> 22) & 3; + bool isv = FIELD_EX32(syndrome, DABORT_ISS, ISV); + bool iswrite = FIELD_EX32(syndrome, DABORT_ISS, WNR); + bool sse = FIELD_EX32(syndrome, DABORT_ISS, SSE); + uint32_t sas = FIELD_EX32(syndrome, DABORT_ISS, SAS); uint32_t len = 1 << sas; - uint32_t srt = (syndrome >> 16) & 0x1f; - uint32_t cm = (syndrome >> 8) & 0x1; + uint32_t srt = FIELD_EX32(syndrome, DABORT_ISS, SRT); + uint32_t cm = FIELD_EX32(syndrome, DABORT_ISS, CM); uint64_t val = 0; + assert(syn_get_ec(syndrome) == EC_DATAABORT); assert(!cm); assert(isv); -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> Rather than open coding a bunch of shifts and masks we can use the syndrome definitions. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-id: 20260422125250.1303100-20-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/hvf/hvf.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -XXX,XX +XXX,XX @@ static int hvf_handle_exception(CPUState *cpu, hv_vcpu_exit_exception_t *excp) break; } case EC_DATAABORT: { - bool isv = syndrome & ARM_EL_ISV; - bool iswrite = (syndrome >> 6) & 1; - bool s1ptw = (syndrome >> 7) & 1; - bool sse = (syndrome >> 21) & 1; - uint32_t sas = (syndrome >> 22) & 3; + bool isv = FIELD_EX32(syndrome, DABORT_ISS, ISV); + bool iswrite = FIELD_EX32(syndrome, DABORT_ISS, WNR); + bool s1ptw = FIELD_EX32(syndrome, DABORT_ISS, S1PTW); + bool sse = FIELD_EX32(syndrome, DABORT_ISS, SSE); + uint32_t sas = FIELD_EX32(syndrome, DABORT_ISS, SAS); uint32_t len = 1 << sas; - uint32_t srt = (syndrome >> 16) & 0x1f; - uint32_t cm = (syndrome >> 8) & 0x1; + uint32_t srt = FIELD_EX32(syndrome, DABORT_ISS, SRT); + uint32_t cm = FIELD_EX32(syndrome, DABORT_ISS, CM); uint64_t val = 0; uint64_t ipa = excp->physical_address; AddressSpace *as = cpu_get_address_space(cpu, ARMASIdx_NS); -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> One more step to removing the old defines. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260422125250.1303100-21-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/tlb_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/arm/tcg/tlb_helper.c b/target/arm/tcg/tlb_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/tlb_helper.c +++ b/target/arm/tcg/tlb_helper.c @@ -XXX,XX +XXX,XX @@ static inline uint64_t merge_syn_data_abort(uint32_t template_syn, */ assert(!fi->stage2); syn = syn_data_abort_vncr(fi->ea, is_write, fsc); - } else if (!(template_syn & ARM_EL_ISV) || target_el != 2 + } else if (!FIELD_EX32(template_syn, DABORT_ISS, ISV) || target_el != 2 || fi->s1ptw || !fi->stage2) { syn = syn_data_abort_no_iss(same_el, 0, fi->ea, 0, fi->s1ptw, is_write, fsc); -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> These are only valid for data abort syndromes. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260422125250.1303100-22-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/tlb_helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/arm/tcg/tlb_helper.c b/target/arm/tcg/tlb_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/tlb_helper.c +++ b/target/arm/tcg/tlb_helper.c @@ -XXX,XX +XXX,XX @@ static inline uint64_t merge_syn_data_abort(uint32_t template_syn, * ST64BV, or ST64BV0 insns report syndrome info even for stage-1 * faults and regardless of the target EL. */ - if (template_syn & ARM_EL_VNCR) { + if (FIELD_EX32(template_syn, DABORT_ISS, VNCR)) { /* * FEAT_NV2 faults on accesses via VNCR_EL2 are a special case: * they are always reported as "same EL", even though we are going @@ -XXX,XX +XXX,XX @@ void arm_deliver_fault(ARMCPU *cpu, vaddr addr, * because we masked that out in disas_set_insn_syndrome()) */ bool is_vncr = (access_type != MMU_INST_FETCH) && - (env->exception.syndrome & ARM_EL_VNCR); + FIELD_EX32(env->exception.syndrome, DABORT_ISS, VNCR); if (is_vncr) { /* FEAT_NV2 faults on accesses via VNCR_EL2 go to EL2 */ -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> Now everything is defined with registerfields we can drop the old defines. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260422125250.1303100-23-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/syndrome.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/syndrome.h +++ b/target/arm/syndrome.h @@ -XXX,XX +XXX,XX @@ typedef enum { GCS_IT_GCSPOPX = 9, } GCSInstructionType; -#define ARM_EL_EC_LENGTH 6 -#define ARM_EL_IL_SHIFT 25 -#define ARM_EL_ISV_SHIFT 24 -#define ARM_EL_IL (1 << ARM_EL_IL_SHIFT) -#define ARM_EL_ISV (1 << ARM_EL_ISV_SHIFT) - -/* In the Data Abort syndrome */ -#define ARM_EL_VNCR (1 << 13) - static inline uint32_t syn_get_ec(uint32_t syn) { return FIELD_EX32(syn, SYNDROME, EC); -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> Pass the register number (rd) to the wfit helper and report it in the syndrome ISS. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260422125250.1303100-24-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/syndrome.h | 11 ++++++++++- target/arm/tcg/helper-defs.h | 2 +- target/arm/tcg/op_helper.c | 7 ++++--- target/arm/tcg/translate-a64.c | 2 +- 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/syndrome.h +++ b/target/arm/syndrome.h @@ -XXX,XX +XXX,XX @@ FIELD(WFX_ISS, RN, 5, 5) FIELD(WFX_ISS, COND, 20, 4) FIELD(WFX_ISS, CV, 24, 1) -static inline uint32_t syn_wfx(int cv, int cond, int ti, bool is_16bit) +typedef enum { + WFI = 0b00, + WFE = 0b01, + WFIT = 0b10, + WFET = 0xb11 +} wfx_ti; + +static inline uint32_t syn_wfx(int cv, int cond, int rn, bool rv, wfx_ti ti, bool is_16bit) { uint32_t res = syn_set_ec(0, EC_WFX_TRAP); res = FIELD_DP32(res, SYNDROME, IL, !is_16bit); @@ -XXX,XX +XXX,XX @@ static inline uint32_t syn_wfx(int cv, int cond, int ti, bool is_16bit) res = FIELD_DP32(res, WFX_ISS, CV, cv); res = FIELD_DP32(res, WFX_ISS, COND, cond); res = FIELD_DP32(res, WFX_ISS, TI, ti); + res = FIELD_DP32(res, WFX_ISS, RN, rn); + res = FIELD_DP32(res, WFX_ISS, RV, rv); return res; } diff --git a/target/arm/tcg/helper-defs.h b/target/arm/tcg/helper-defs.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/helper-defs.h +++ b/target/arm/tcg/helper-defs.h @@ -XXX,XX +XXX,XX @@ DEF_HELPER_2(exception_pc_alignment, noreturn, env, vaddr) DEF_HELPER_1(setend, void, env) DEF_HELPER_2(wfi, void, env, i32) DEF_HELPER_1(wfe, void, env) -DEF_HELPER_2(wfit, void, env, i64) +DEF_HELPER_2(wfit, void, env, i32) DEF_HELPER_1(yield, void, env) DEF_HELPER_1(pre_hvc, void, env) DEF_HELPER_2(pre_smc, void, env, i32) diff --git a/target/arm/tcg/op_helper.c b/target/arm/tcg/op_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/op_helper.c +++ b/target/arm/tcg/op_helper.c @@ -XXX,XX +XXX,XX @@ void HELPER(wfi)(CPUARMState *env, uint32_t insn_len) env->regs[15] -= insn_len; } - raise_exception(env, excp, syn_wfx(1, 0xe, 0, insn_len == 2), + raise_exception(env, excp, syn_wfx(1, 0xe, 0, false, WFI, insn_len == 2), target_el); } @@ -XXX,XX +XXX,XX @@ void HELPER(wfi)(CPUARMState *env, uint32_t insn_len) #endif } -void HELPER(wfit)(CPUARMState *env, uint64_t timeout) +void HELPER(wfit)(CPUARMState *env, uint32_t rd) { #ifdef CONFIG_USER_ONLY /* @@ -XXX,XX +XXX,XX @@ void HELPER(wfit)(CPUARMState *env, uint64_t timeout) int target_el = check_wfx_trap(env, false, &excp); /* The WFIT should time out when CNTVCT_EL0 >= the specified value. */ uint64_t cntval = gt_get_countervalue(env); + uint64_t timeout = env->xregs[rd]; /* * We want the value that we would get if we read CNTVCT_EL0 from * the current exception level, so the direct_access offset, not @@ -XXX,XX +XXX,XX @@ void HELPER(wfit)(CPUARMState *env, uint64_t timeout) if (target_el) { env->pc -= 4; - raise_exception(env, excp, syn_wfx(1, 0xe, 2, false), target_el); + raise_exception(env, excp, syn_wfx(1, 0xe, rd, true, WFIT, false), target_el); } if (uadd64_overflow(timeout, offset, &nexttick)) { diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ static bool trans_WFIT(DisasContext *s, arg_WFIT *a) } gen_a64_update_pc(s, 4); - gen_helper_wfit(tcg_env, cpu_reg(s, a->rd)); + gen_helper_wfit(tcg_env, tcg_constant_i32(a->rd)); /* Go back to the main loop to check for interrupts */ s->base.is_jmp = DISAS_EXIT; return true; -- 2.43.0