mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2025-02-25 20:36:56 +00:00
target/arm: Introduce translate-a64.h
Move some stuff that will be common to both translate-a64.c and translate-sve.c. Backports commit 8c71baedb8055beaa681823206ee3a74f9f8649a from qemu
This commit is contained in:
parent
11149ba82b
commit
d2d8e2fc33
|
@ -3214,6 +3214,8 @@
|
||||||
#define arm_reset_cpu arm_reset_cpu_aarch64
|
#define arm_reset_cpu arm_reset_cpu_aarch64
|
||||||
#define arm_set_cpu_off arm_set_cpu_off_aarch64
|
#define arm_set_cpu_off arm_set_cpu_off_aarch64
|
||||||
#define arm_set_cpu_on arm_set_cpu_on_aarch64
|
#define arm_set_cpu_on arm_set_cpu_on_aarch64
|
||||||
|
#define cpu_reg cpu_reg_aarch64
|
||||||
|
#define cpu_reg_sp cpu_reg_sp_aarch64
|
||||||
#define gen_a64_set_pc_im gen_a64_set_pc_im_aarch64
|
#define gen_a64_set_pc_im gen_a64_set_pc_im_aarch64
|
||||||
#define helper_advsimd_acge_f16 helper_advsimd_acge_f16_aarch64
|
#define helper_advsimd_acge_f16 helper_advsimd_acge_f16_aarch64
|
||||||
#define helper_advsimd_acgt_f16 helper_advsimd_acgt_f16_aarch64
|
#define helper_advsimd_acgt_f16 helper_advsimd_acgt_f16_aarch64
|
||||||
|
@ -3278,4 +3280,13 @@
|
||||||
#define helper_vfp_cmps_a64 helper_vfp_cmps_a64_aarch64
|
#define helper_vfp_cmps_a64 helper_vfp_cmps_a64_aarch64
|
||||||
#define helper_vfp_mulxd helper_vfp_mulxd_aarch64
|
#define helper_vfp_mulxd helper_vfp_mulxd_aarch64
|
||||||
#define helper_vfp_mulxs helper_vfp_mulxs_aarch64
|
#define helper_vfp_mulxs helper_vfp_mulxs_aarch64
|
||||||
|
#define logic_imm_decode_wmask logic_imm_decode_wmask_aarch64
|
||||||
|
#define new_tmp_a64 new_tmp_a64_aarch64
|
||||||
|
#define new_tmp_a64_zero new_tmp_a64_zero_aarch64
|
||||||
|
#define read_cpu_reg read_cpu_reg_aarch64
|
||||||
|
#define read_cpu_reg_sp read_cpu_reg_sp_aarch64
|
||||||
|
#define sve_access_check sve_access_check_aarch64
|
||||||
|
#define unallocated_encoding unallocated_encoding_aarch64
|
||||||
|
#define vfp_expand_imm vfp_expand_imm_aarch64
|
||||||
|
#define write_fp_dreg write_fp_dreg_aarch64
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -3214,6 +3214,8 @@
|
||||||
#define arm_reset_cpu arm_reset_cpu_aarch64eb
|
#define arm_reset_cpu arm_reset_cpu_aarch64eb
|
||||||
#define arm_set_cpu_off arm_set_cpu_off_aarch64eb
|
#define arm_set_cpu_off arm_set_cpu_off_aarch64eb
|
||||||
#define arm_set_cpu_on arm_set_cpu_on_aarch64eb
|
#define arm_set_cpu_on arm_set_cpu_on_aarch64eb
|
||||||
|
#define cpu_reg cpu_reg_aarch64eb
|
||||||
|
#define cpu_reg_sp cpu_reg_sp_aarch64eb
|
||||||
#define gen_a64_set_pc_im gen_a64_set_pc_im_aarch64eb
|
#define gen_a64_set_pc_im gen_a64_set_pc_im_aarch64eb
|
||||||
#define helper_advsimd_acge_f16 helper_advsimd_acge_f16_aarch64eb
|
#define helper_advsimd_acge_f16 helper_advsimd_acge_f16_aarch64eb
|
||||||
#define helper_advsimd_acgt_f16 helper_advsimd_acgt_f16_aarch64eb
|
#define helper_advsimd_acgt_f16 helper_advsimd_acgt_f16_aarch64eb
|
||||||
|
@ -3278,4 +3280,13 @@
|
||||||
#define helper_vfp_cmps_a64 helper_vfp_cmps_a64_aarch64eb
|
#define helper_vfp_cmps_a64 helper_vfp_cmps_a64_aarch64eb
|
||||||
#define helper_vfp_mulxd helper_vfp_mulxd_aarch64eb
|
#define helper_vfp_mulxd helper_vfp_mulxd_aarch64eb
|
||||||
#define helper_vfp_mulxs helper_vfp_mulxs_aarch64eb
|
#define helper_vfp_mulxs helper_vfp_mulxs_aarch64eb
|
||||||
|
#define logic_imm_decode_wmask logic_imm_decode_wmask_aarch64eb
|
||||||
|
#define new_tmp_a64 new_tmp_a64_aarch64eb
|
||||||
|
#define new_tmp_a64_zero new_tmp_a64_zero_aarch64eb
|
||||||
|
#define read_cpu_reg read_cpu_reg_aarch64eb
|
||||||
|
#define read_cpu_reg_sp read_cpu_reg_sp_aarch64eb
|
||||||
|
#define sve_access_check sve_access_check_aarch64eb
|
||||||
|
#define unallocated_encoding unallocated_encoding_aarch64eb
|
||||||
|
#define vfp_expand_imm vfp_expand_imm_aarch64eb
|
||||||
|
#define write_fp_dreg write_fp_dreg_aarch64eb
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -3235,6 +3235,8 @@ aarch64_symbols = (
|
||||||
'arm_reset_cpu',
|
'arm_reset_cpu',
|
||||||
'arm_set_cpu_off',
|
'arm_set_cpu_off',
|
||||||
'arm_set_cpu_on',
|
'arm_set_cpu_on',
|
||||||
|
'cpu_reg',
|
||||||
|
'cpu_reg_sp',
|
||||||
'gen_a64_set_pc_im',
|
'gen_a64_set_pc_im',
|
||||||
'helper_advsimd_acge_f16',
|
'helper_advsimd_acge_f16',
|
||||||
'helper_advsimd_acgt_f16',
|
'helper_advsimd_acgt_f16',
|
||||||
|
@ -3298,7 +3300,16 @@ aarch64_symbols = (
|
||||||
'helper_vfp_cmpes_a64',
|
'helper_vfp_cmpes_a64',
|
||||||
'helper_vfp_cmps_a64',
|
'helper_vfp_cmps_a64',
|
||||||
'helper_vfp_mulxd',
|
'helper_vfp_mulxd',
|
||||||
'helper_vfp_mulxs'
|
'helper_vfp_mulxs',
|
||||||
|
'logic_imm_decode_wmask',
|
||||||
|
'new_tmp_a64',
|
||||||
|
'new_tmp_a64_zero',
|
||||||
|
'read_cpu_reg',
|
||||||
|
'read_cpu_reg_sp',
|
||||||
|
'sve_access_check',
|
||||||
|
'unallocated_encoding',
|
||||||
|
'vfp_expand_imm',
|
||||||
|
'write_fp_dreg',
|
||||||
)
|
)
|
||||||
|
|
||||||
mips_symbols = (
|
mips_symbols = (
|
||||||
|
|
|
@ -34,13 +34,13 @@
|
||||||
#include "exec/semihost.h"
|
#include "exec/semihost.h"
|
||||||
#include "exec/gen-icount.h"
|
#include "exec/gen-icount.h"
|
||||||
|
|
||||||
|
#include "translate-a64.h"
|
||||||
|
|
||||||
#ifdef CONFIG_USER_ONLY
|
#ifdef CONFIG_USER_ONLY
|
||||||
static TCGv_i64 cpu_exclusive_test;
|
static TCGv_i64 cpu_exclusive_test;
|
||||||
static TCGv_i32 cpu_exclusive_info;
|
static TCGv_i32 cpu_exclusive_info;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static TCGv_i64 cpu_reg(DisasContext *s, int reg);
|
|
||||||
|
|
||||||
static const char *regnames[] = {
|
static const char *regnames[] = {
|
||||||
"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
|
"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
|
||||||
"x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
|
"x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
|
||||||
|
@ -83,13 +83,6 @@ typedef void CryptoThreeOpIntFn(TCGContext *, TCGv_ptr, TCGv_ptr, TCGv_i32);
|
||||||
typedef void CryptoThreeOpFn(TCGContext *, TCGv_ptr, TCGv_ptr, TCGv_ptr);
|
typedef void CryptoThreeOpFn(TCGContext *, TCGv_ptr, TCGv_ptr, TCGv_ptr);
|
||||||
typedef void AtomicThreeOpFn(TCGContext *, TCGv_i64, TCGv_i64, TCGv_i64, TCGArg, TCGMemOp);
|
typedef void AtomicThreeOpFn(TCGContext *, TCGv_i64, TCGv_i64, TCGv_i64, TCGArg, TCGMemOp);
|
||||||
|
|
||||||
/* Note that the gvec expanders operate on offsets + sizes. */
|
|
||||||
typedef void GVecGen2Fn(TCGContext *, unsigned, uint32_t, uint32_t, uint32_t, uint32_t);
|
|
||||||
typedef void GVecGen2iFn(TCGContext *, unsigned, uint32_t, uint32_t, int64_t,
|
|
||||||
uint32_t, uint32_t);
|
|
||||||
typedef void GVecGen3Fn(TCGContext *, unsigned, uint32_t, uint32_t,
|
|
||||||
uint32_t, uint32_t, uint32_t);
|
|
||||||
|
|
||||||
/* initialize TCG globals. */
|
/* initialize TCG globals. */
|
||||||
void a64_translate_init(struct uc_struct *uc)
|
void a64_translate_init(struct uc_struct *uc)
|
||||||
{
|
{
|
||||||
|
@ -426,22 +419,13 @@ static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void unallocated_encoding(DisasContext *s)
|
void unallocated_encoding(DisasContext *s)
|
||||||
{
|
{
|
||||||
/* Unallocated and reserved encodings are uncategorized */
|
/* Unallocated and reserved encodings are uncategorized */
|
||||||
gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized(),
|
gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized(),
|
||||||
default_exception_el(s));
|
default_exception_el(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
#define unsupported_encoding(s, insn) \
|
|
||||||
do { \
|
|
||||||
qemu_log_mask(LOG_UNIMP, \
|
|
||||||
"%s:%d: unsupported instruction encoding 0x%08x " \
|
|
||||||
"at pc=%016" PRIx64 "\n", \
|
|
||||||
__FILE__, __LINE__, insn, s->pc - 4); \
|
|
||||||
unallocated_encoding(s); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
static void init_tmp_a64_array(DisasContext *s)
|
static void init_tmp_a64_array(DisasContext *s)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_DEBUG_TCG
|
#ifdef CONFIG_DEBUG_TCG
|
||||||
|
@ -460,14 +444,14 @@ static void free_tmp_a64(DisasContext *s)
|
||||||
init_tmp_a64_array(s);
|
init_tmp_a64_array(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static TCGv_i64 new_tmp_a64(DisasContext *s)
|
TCGv_i64 new_tmp_a64(DisasContext *s)
|
||||||
{
|
{
|
||||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||||
assert(s->tmp_a64_count < TMP_A64_MAX);
|
assert(s->tmp_a64_count < TMP_A64_MAX);
|
||||||
return s->tmp_a64[s->tmp_a64_count++] = tcg_temp_new_i64(tcg_ctx);
|
return s->tmp_a64[s->tmp_a64_count++] = tcg_temp_new_i64(tcg_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static TCGv_i64 new_tmp_a64_zero(DisasContext *s)
|
TCGv_i64 new_tmp_a64_zero(DisasContext *s)
|
||||||
{
|
{
|
||||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||||
TCGv_i64 t = new_tmp_a64(s);
|
TCGv_i64 t = new_tmp_a64(s);
|
||||||
|
@ -490,7 +474,7 @@ static TCGv_i64 new_tmp_a64_zero(DisasContext *s)
|
||||||
* to tcg_ctx->cpu_X[31] and ZR accesses to a temporary which can be discarded.
|
* to tcg_ctx->cpu_X[31] and ZR accesses to a temporary which can be discarded.
|
||||||
* This is the point of the _sp forms.
|
* This is the point of the _sp forms.
|
||||||
*/
|
*/
|
||||||
static TCGv_i64 cpu_reg(DisasContext *s, int reg)
|
TCGv_i64 cpu_reg(DisasContext *s, int reg)
|
||||||
{
|
{
|
||||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||||
if (reg == 31) {
|
if (reg == 31) {
|
||||||
|
@ -501,7 +485,7 @@ static TCGv_i64 cpu_reg(DisasContext *s, int reg)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* register access for when 31 == SP */
|
/* register access for when 31 == SP */
|
||||||
static TCGv_i64 cpu_reg_sp(DisasContext *s, int reg)
|
TCGv_i64 cpu_reg_sp(DisasContext *s, int reg)
|
||||||
{
|
{
|
||||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||||
return tcg_ctx->cpu_X[reg];
|
return tcg_ctx->cpu_X[reg];
|
||||||
|
@ -511,7 +495,7 @@ static TCGv_i64 cpu_reg_sp(DisasContext *s, int reg)
|
||||||
* representing the register contents. This TCGv is an auto-freed
|
* representing the register contents. This TCGv is an auto-freed
|
||||||
* temporary so it need not be explicitly freed, and may be modified.
|
* temporary so it need not be explicitly freed, and may be modified.
|
||||||
*/
|
*/
|
||||||
static TCGv_i64 read_cpu_reg(DisasContext *s, int reg, int sf)
|
TCGv_i64 read_cpu_reg(DisasContext *s, int reg, int sf)
|
||||||
{
|
{
|
||||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||||
TCGv_i64 v = new_tmp_a64(s);
|
TCGv_i64 v = new_tmp_a64(s);
|
||||||
|
@ -527,7 +511,7 @@ static TCGv_i64 read_cpu_reg(DisasContext *s, int reg, int sf)
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
static TCGv_i64 read_cpu_reg_sp(DisasContext *s, int reg, int sf)
|
TCGv_i64 read_cpu_reg_sp(DisasContext *s, int reg, int sf)
|
||||||
{
|
{
|
||||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||||
TCGv_i64 v = new_tmp_a64(s);
|
TCGv_i64 v = new_tmp_a64(s);
|
||||||
|
@ -539,74 +523,6 @@ static TCGv_i64 read_cpu_reg_sp(DisasContext *s, int reg, int sf)
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We should have at some point before trying to access an FP register
|
|
||||||
* done the necessary access check, so assert that
|
|
||||||
* (a) we did the check and
|
|
||||||
* (b) we didn't then just plough ahead anyway if it failed.
|
|
||||||
* Print the instruction pattern in the abort message so we can figure
|
|
||||||
* out what we need to fix if a user encounters this problem in the wild.
|
|
||||||
*/
|
|
||||||
static inline void assert_fp_access_checked(DisasContext *s)
|
|
||||||
{
|
|
||||||
#ifdef CONFIG_DEBUG_TCG
|
|
||||||
if (unlikely(!s->fp_access_checked || s->fp_excp_el)) {
|
|
||||||
fprintf(stderr, "target-arm: FP access check missing for "
|
|
||||||
"instruction 0x%08x\n", s->insn);
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return the offset into CPUARMState of an element of specified
|
|
||||||
* size, 'element' places in from the least significant end of
|
|
||||||
* the FP/vector register Qn.
|
|
||||||
*/
|
|
||||||
static inline int vec_reg_offset(DisasContext *s, int regno,
|
|
||||||
int element, TCGMemOp size)
|
|
||||||
{
|
|
||||||
int offs = 0;
|
|
||||||
#ifdef HOST_WORDS_BIGENDIAN
|
|
||||||
/* This is complicated slightly because vfp.zregs[n].d[0] is
|
|
||||||
* still the low half and vfp.zregs[n].d[1] the high half
|
|
||||||
* of the 128 bit vector, even on big endian systems.
|
|
||||||
* Calculate the offset assuming a fully bigendian 128 bits,
|
|
||||||
* then XOR to account for the order of the two 64 bit halves.
|
|
||||||
*/
|
|
||||||
offs += (16 - ((element + 1) * (1 << size)));
|
|
||||||
offs ^= 8;
|
|
||||||
#else
|
|
||||||
offs += element * (1 << size);
|
|
||||||
#endif
|
|
||||||
offs += offsetof(CPUARMState, vfp.zregs[regno]);
|
|
||||||
assert_fp_access_checked(s);
|
|
||||||
return offs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return the offset info CPUARMState of the "whole" vector register Qn. */
|
|
||||||
static inline int vec_full_reg_offset(DisasContext *s, int regno)
|
|
||||||
{
|
|
||||||
assert_fp_access_checked(s);
|
|
||||||
return offsetof(CPUARMState, vfp.zregs[regno]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return a newly allocated pointer to the vector register. */
|
|
||||||
static TCGv_ptr vec_full_reg_ptr(DisasContext *s, int regno)
|
|
||||||
{
|
|
||||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
|
||||||
|
|
||||||
TCGv_ptr ret = tcg_temp_new_ptr(tcg_ctx);
|
|
||||||
tcg_gen_addi_ptr(tcg_ctx, ret, tcg_ctx->cpu_env, vec_full_reg_offset(s, regno));
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return the byte size of the "whole" vector register, VL / 8. */
|
|
||||||
static inline int vec_full_reg_size(DisasContext *s)
|
|
||||||
{
|
|
||||||
/* FIXME SVE: We should put the composite ZCR_EL* value into tb->flags.
|
|
||||||
In the meantime this is just the AdvSIMD length of 128. */
|
|
||||||
return 128 / 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return the offset into CPUARMState of a slice (from
|
/* Return the offset into CPUARMState of a slice (from
|
||||||
* the least significant end) of FP register Qn (ie
|
* the least significant end) of FP register Qn (ie
|
||||||
* Dn, Sn, Hn or Bn).
|
* Dn, Sn, Hn or Bn).
|
||||||
|
@ -675,7 +591,7 @@ static void clear_vec_high(DisasContext *s, bool is_q, int rd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void write_fp_dreg(DisasContext *s, int reg, TCGv_i64 v)
|
void write_fp_dreg(DisasContext *s, int reg, TCGv_i64 v)
|
||||||
{
|
{
|
||||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||||
unsigned ofs = fp_reg_offset(s, reg, MO_64);
|
unsigned ofs = fp_reg_offset(s, reg, MO_64);
|
||||||
|
@ -694,7 +610,7 @@ static void write_fp_sreg(DisasContext *s, int reg, TCGv_i32 v)
|
||||||
tcg_temp_free_i64(tcg_ctx, tmp);
|
tcg_temp_free_i64(tcg_ctx, tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static TCGv_ptr get_fpstatus_ptr(TCGContext *tcg_ctx, bool is_f16)
|
TCGv_ptr get_fpstatus_ptr(TCGContext *tcg_ctx, bool is_f16)
|
||||||
{
|
{
|
||||||
TCGv_ptr statusptr = tcg_temp_new_ptr(tcg_ctx);
|
TCGv_ptr statusptr = tcg_temp_new_ptr(tcg_ctx);
|
||||||
int offset;
|
int offset;
|
||||||
|
@ -1308,14 +1224,14 @@ static inline bool fp_access_check(DisasContext *s)
|
||||||
/* Check that SVE access is enabled. If it is, return true.
|
/* Check that SVE access is enabled. If it is, return true.
|
||||||
* If not, emit code to generate an appropriate exception and return false.
|
* If not, emit code to generate an appropriate exception and return false.
|
||||||
*/
|
*/
|
||||||
static inline bool sve_access_check(DisasContext *s)
|
bool sve_access_check(DisasContext *s)
|
||||||
{
|
{
|
||||||
if (s->sve_excp_el) {
|
if (s->sve_excp_el) {
|
||||||
gen_exception_insn(s, 4, EXCP_UDEF, syn_sve_access_trap(),
|
gen_exception_insn(s, 4, EXCP_UDEF, syn_sve_access_trap(),
|
||||||
s->sve_excp_el);
|
s->sve_excp_el);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return fp_access_check(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -3487,8 +3403,8 @@ static inline uint64_t bitmask64(unsigned int length)
|
||||||
* value (ie should cause a guest UNDEF exception), and true if they are
|
* value (ie should cause a guest UNDEF exception), and true if they are
|
||||||
* valid, in which case the decoded bit pattern is written to result.
|
* valid, in which case the decoded bit pattern is written to result.
|
||||||
*/
|
*/
|
||||||
static bool logic_imm_decode_wmask(uint64_t *result, unsigned int immn,
|
bool logic_imm_decode_wmask(uint64_t *result, unsigned int immn,
|
||||||
unsigned int imms, unsigned int immr)
|
unsigned int imms, unsigned int immr)
|
||||||
{
|
{
|
||||||
uint64_t mask;
|
uint64_t mask;
|
||||||
unsigned e, levels, s, r;
|
unsigned e, levels, s, r;
|
||||||
|
@ -5754,7 +5670,7 @@ static void disas_fp_3src(DisasContext *s, uint32_t insn)
|
||||||
* the range 01....1xx to 10....0xx, and the most significant 4 bits of
|
* the range 01....1xx to 10....0xx, and the most significant 4 bits of
|
||||||
* the mantissa; see VFPExpandImm() in the v8 ARM ARM.
|
* the mantissa; see VFPExpandImm() in the v8 ARM ARM.
|
||||||
*/
|
*/
|
||||||
static uint64_t vfp_expand_imm(int size, uint8_t imm8)
|
uint64_t vfp_expand_imm(int size, uint8_t imm8)
|
||||||
{
|
{
|
||||||
uint64_t imm;
|
uint64_t imm;
|
||||||
|
|
||||||
|
|
119
qemu/target/arm/translate-a64.h
Normal file
119
qemu/target/arm/translate-a64.h
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
/*
|
||||||
|
* AArch64 translation, common definitions.
|
||||||
|
*
|
||||||
|
* 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 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TARGET_ARM_TRANSLATE_A64_H
|
||||||
|
#define TARGET_ARM_TRANSLATE_A64_H
|
||||||
|
|
||||||
|
void unallocated_encoding(DisasContext *s);
|
||||||
|
|
||||||
|
#define unsupported_encoding(s, insn) \
|
||||||
|
do { \
|
||||||
|
qemu_log_mask(LOG_UNIMP, \
|
||||||
|
"%s:%d: unsupported instruction encoding 0x%08x " \
|
||||||
|
"at pc=%016" PRIx64 "\n", \
|
||||||
|
__FILE__, __LINE__, insn, s->pc - 4); \
|
||||||
|
unallocated_encoding(s); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
TCGv_i64 new_tmp_a64(DisasContext *s);
|
||||||
|
TCGv_i64 new_tmp_a64_zero(DisasContext *s);
|
||||||
|
TCGv_i64 cpu_reg(DisasContext *s, int reg);
|
||||||
|
TCGv_i64 cpu_reg_sp(DisasContext *s, int reg);
|
||||||
|
TCGv_i64 read_cpu_reg(DisasContext *s, int reg, int sf);
|
||||||
|
TCGv_i64 read_cpu_reg_sp(DisasContext *s, int reg, int sf);
|
||||||
|
void write_fp_dreg(DisasContext *s, int reg, TCGv_i64 v);
|
||||||
|
TCGv_ptr get_fpstatus_ptr(TCGContext *, bool);
|
||||||
|
bool logic_imm_decode_wmask(uint64_t *result, unsigned int immn,
|
||||||
|
unsigned int imms, unsigned int immr);
|
||||||
|
uint64_t vfp_expand_imm(int size, uint8_t imm8);
|
||||||
|
bool sve_access_check(DisasContext *s);
|
||||||
|
|
||||||
|
/* We should have at some point before trying to access an FP register
|
||||||
|
* done the necessary access check, so assert that
|
||||||
|
* (a) we did the check and
|
||||||
|
* (b) we didn't then just plough ahead anyway if it failed.
|
||||||
|
* Print the instruction pattern in the abort message so we can figure
|
||||||
|
* out what we need to fix if a user encounters this problem in the wild.
|
||||||
|
*/
|
||||||
|
static inline void assert_fp_access_checked(DisasContext *s)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_DEBUG_TCG
|
||||||
|
if (unlikely(!s->fp_access_checked || s->fp_excp_el)) {
|
||||||
|
fprintf(stderr, "target-arm: FP access check missing for "
|
||||||
|
"instruction 0x%08x\n", s->insn);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the offset into CPUARMState of an element of specified
|
||||||
|
* size, 'element' places in from the least significant end of
|
||||||
|
* the FP/vector register Qn.
|
||||||
|
*/
|
||||||
|
static inline int vec_reg_offset(DisasContext *s, int regno,
|
||||||
|
int element, TCGMemOp size)
|
||||||
|
{
|
||||||
|
int offs = 0;
|
||||||
|
#ifdef HOST_WORDS_BIGENDIAN
|
||||||
|
/* This is complicated slightly because vfp.zregs[n].d[0] is
|
||||||
|
* still the low half and vfp.zregs[n].d[1] the high half
|
||||||
|
* of the 128 bit vector, even on big endian systems.
|
||||||
|
* Calculate the offset assuming a fully bigendian 128 bits,
|
||||||
|
* then XOR to account for the order of the two 64 bit halves.
|
||||||
|
*/
|
||||||
|
offs += (16 - ((element + 1) * (1 << size)));
|
||||||
|
offs ^= 8;
|
||||||
|
#else
|
||||||
|
offs += element * (1 << size);
|
||||||
|
#endif
|
||||||
|
offs += offsetof(CPUARMState, vfp.zregs[regno]);
|
||||||
|
assert_fp_access_checked(s);
|
||||||
|
return offs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the offset info CPUARMState of the "whole" vector register Qn. */
|
||||||
|
static inline int vec_full_reg_offset(DisasContext *s, int regno)
|
||||||
|
{
|
||||||
|
assert_fp_access_checked(s);
|
||||||
|
return offsetof(CPUARMState, vfp.zregs[regno]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return a newly allocated pointer to the vector register. */
|
||||||
|
static inline TCGv_ptr vec_full_reg_ptr(DisasContext *s, int regno)
|
||||||
|
{
|
||||||
|
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||||
|
TCGv_ptr ret = tcg_temp_new_ptr(tcg_ctx);
|
||||||
|
tcg_gen_addi_ptr(tcg_ctx, ret, tcg_ctx->cpu_env, vec_full_reg_offset(s, regno));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the byte size of the "whole" vector register, VL / 8. */
|
||||||
|
static inline int vec_full_reg_size(DisasContext *s)
|
||||||
|
{
|
||||||
|
return s->sve_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool disas_sve(DisasContext *, uint32_t);
|
||||||
|
|
||||||
|
/* Note that the gvec expanders operate on offsets + sizes. */
|
||||||
|
typedef void GVecGen2Fn(TCGContext *, unsigned, uint32_t, uint32_t, uint32_t, uint32_t);
|
||||||
|
typedef void GVecGen2iFn(TCGContext *, unsigned, uint32_t, uint32_t, int64_t,
|
||||||
|
uint32_t, uint32_t);
|
||||||
|
typedef void GVecGen3Fn(TCGContext *, unsigned, uint32_t, uint32_t,
|
||||||
|
uint32_t, uint32_t, uint32_t);
|
||||||
|
|
||||||
|
#endif /* TARGET_ARM_TRANSLATE_A64_H */
|
Loading…
Reference in a new issue