/* * AArch32 translation, common definitions. * * Copyright (c) 2021 Linaro, Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see . */ #ifndef TARGET_ARM_TRANSLATE_A32_H #define TARGET_ARM_TRANSLATE_A32_H /* Prototypes for autogenerated disassembler functions */ bool disas_m_nocp(DisasContext *dc, uint32_t insn); bool disas_mve(DisasContext *dc, uint32_t insn); bool disas_vfp(DisasContext *s, uint32_t insn); bool disas_vfp_uncond(DisasContext *s, uint32_t insn); bool disas_neon_dp(DisasContext *s, uint32_t insn); bool disas_neon_ls(DisasContext *s, uint32_t insn); bool disas_neon_shared(DisasContext *s, uint32_t insn); void load_reg_var(DisasContext *s, TCGv_i32 var, int reg); void arm_gen_condlabel(DisasContext *s); bool vfp_access_check(DisasContext *s); bool vfp_access_check_m(DisasContext *s, bool skip_context_update); void read_neon_element32(TCGv_i32 dest, int reg, int ele, MemOp memop); void read_neon_element64(TCGv_i64 dest, int reg, int ele, MemOp memop); void write_neon_element32(TCGv_i32 src, int reg, int ele, MemOp memop); void write_neon_element64(TCGv_i64 src, int reg, int ele, MemOp memop); TCGv_i32 add_reg_for_lit(DisasContext *s, int reg, int ofs); void gen_set_cpsr(TCGv_i32 var, uint32_t mask); void gen_set_condexec(DisasContext *s); void gen_update_pc(DisasContext *s, target_long diff); void gen_lookup_tb(DisasContext *s); long vfp_reg_offset(bool dp, unsigned reg); long neon_full_reg_offset(unsigned reg); long neon_element_offset(int reg, int element, MemOp memop); void gen_rev16(TCGv_i32 dest, TCGv_i32 var); void clear_eci_state(DisasContext *s); bool mve_eci_check(DisasContext *s); void mve_update_eci(DisasContext *s); void mve_update_and_store_eci(DisasContext *s); bool mve_skip_vmov(DisasContext *s, int vn, int index, int size); static inline TCGv_i32 load_cpu_offset(int offset) { TCGv_i32 tmp = tcg_temp_new_i32(); tcg_gen_ld_i32(tmp, tcg_env, offset); return tmp; } /* Load from a 32-bit field to a TCGv_i32 */ #define load_cpu_field(name) \ ({ \ QEMU_BUILD_BUG_ON(sizeof_field(CPUARMState, name) != 4); \ load_cpu_offset(offsetof(CPUARMState, name)); \ }) /* Load from the low half of a 64-bit field to a TCGv_i32 */ #define load_cpu_field_low32(name) \ ({ \ QEMU_BUILD_BUG_ON(sizeof_field(CPUARMState, name) != 8); \ load_cpu_offset(offsetoflow32(CPUARMState, name)); \ }) void store_cpu_offset(TCGv_i32 var, int offset, int size); #define store_cpu_field(val, name) \ ({ \ QEMU_BUILD_BUG_ON(sizeof_field(CPUARMState, name) != 4 \ && sizeof_field(CPUARMState, name) != 1); \ store_cpu_offset(val, offsetof(CPUARMState, name), \ sizeof_field(CPUARMState, name)); \ }) /* Store to the low half of a 64-bit field from a TCGv_i32 */ #define store_cpu_field_low32(val, name) \ ({ \ QEMU_BUILD_BUG_ON(sizeof_field(CPUARMState, name) != 8); \ store_cpu_offset(val, offsetoflow32(CPUARMState, name), 4); \ }) #define store_cpu_field_constant(val, name) \ store_cpu_field(tcg_constant_i32(val), name) /* Create a new temporary and set it to the value of a CPU register. */ static inline TCGv_i32 load_reg(DisasContext *s, int reg) { TCGv_i32 tmp = tcg_temp_new_i32(); load_reg_var(s, tmp, reg); return tmp; } void store_reg(DisasContext *s, int reg, TCGv_i32 var); void gen_aa32_ld_internal_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32, int index, MemOp opc); void gen_aa32_st_internal_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32, int index, MemOp opc); void gen_aa32_ld_internal_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32, int index, MemOp opc); void gen_aa32_st_internal_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32, int index, MemOp opc); void gen_aa32_ld_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32, int index, MemOp opc); void gen_aa32_st_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32, int index, MemOp opc); void gen_aa32_ld_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32, int index, MemOp opc); void gen_aa32_st_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32, int index, MemOp opc); #define DO_GEN_LD(SUFF, OPC) \ static inline void gen_aa32_ld##SUFF(DisasContext *s, TCGv_i32 val, \ TCGv_i32 a32, int index) \ { \ gen_aa32_ld_i32(s, val, a32, index, OPC); \ } #define DO_GEN_ST(SUFF, OPC) \ static inline void gen_aa32_st##SUFF(DisasContext *s, TCGv_i32 val, \ TCGv_i32 a32, int index) \ { \ gen_aa32_st_i32(s, val, a32, index, OPC); \ } static inline void gen_aa32_ld64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32, int index) { gen_aa32_ld_i64(s, val, a32, index, MO_UQ); } static inline void gen_aa32_st64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32, int index) { gen_aa32_st_i64(s, val, a32, index, MO_UQ); } DO_GEN_LD(8u, MO_UB) DO_GEN_LD(16u, MO_UW) DO_GEN_LD(32u, MO_UL) DO_GEN_ST(8, MO_UB) DO_GEN_ST(16, MO_UW) DO_GEN_ST(32, MO_UL) #undef DO_GEN_LD #undef DO_GEN_ST #if defined(CONFIG_USER_ONLY) #define IS_USER(s) 1 #else #define IS_USER(s) (s->user) #endif /* Set NZCV flags from the high 4 bits of var. */ #define gen_set_nzcv(var) gen_set_cpsr(var, CPSR_NZCV) /* Swap low and high halfwords. */ static inline void gen_swap_half(TCGv_i32 dest, TCGv_i32 var) { tcg_gen_rotri_i32(dest, var, 16); } #endif