mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2025-03-06 14:39:49 +00:00
target/arm: Sychronize with qemu
Synchronizes with bits and pieces that were missed due to merging incorrectly (sorry :<)
This commit is contained in:
parent
753b6601c5
commit
3521e72580
|
@ -7,7 +7,7 @@
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
* as published by the Free Software Foundation; either version 2
|
* as published by the Free Software Foundation; either version 2
|
||||||
* of the License, or (at your option) any later version.
|
* of the License, or (at your option) any later version.
|
||||||
*f
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
@ -156,8 +156,10 @@ static void arm_cpu_reset(CPUState *s)
|
||||||
acc->parent_reset(s);
|
acc->parent_reset(s);
|
||||||
|
|
||||||
memset(env, 0, offsetof(CPUARMState, end_reset_fields));
|
memset(env, 0, offsetof(CPUARMState, end_reset_fields));
|
||||||
|
|
||||||
g_hash_table_foreach(cpu->cp_regs, cp_reg_reset, cpu);
|
g_hash_table_foreach(cpu->cp_regs, cp_reg_reset, cpu);
|
||||||
g_hash_table_foreach(cpu->cp_regs, cp_reg_check_reset, cpu);
|
g_hash_table_foreach(cpu->cp_regs, cp_reg_check_reset, cpu);
|
||||||
|
|
||||||
env->vfp.xregs[ARM_VFP_FPSID] = cpu->reset_fpsid;
|
env->vfp.xregs[ARM_VFP_FPSID] = cpu->reset_fpsid;
|
||||||
env->vfp.xregs[ARM_VFP_MVFR0] = cpu->isar.mvfr0;
|
env->vfp.xregs[ARM_VFP_MVFR0] = cpu->isar.mvfr0;
|
||||||
env->vfp.xregs[ARM_VFP_MVFR1] = cpu->isar.mvfr1;
|
env->vfp.xregs[ARM_VFP_MVFR1] = cpu->isar.mvfr1;
|
||||||
|
@ -239,7 +241,6 @@ static void arm_cpu_reset(CPUState *s)
|
||||||
} else {
|
} else {
|
||||||
env->uncached_cpsr = ARM_CPU_MODE_SVC;
|
env->uncached_cpsr = ARM_CPU_MODE_SVC;
|
||||||
}
|
}
|
||||||
|
|
||||||
env->daif = PSTATE_D | PSTATE_A | PSTATE_I | PSTATE_F;
|
env->daif = PSTATE_D | PSTATE_A | PSTATE_I | PSTATE_F;
|
||||||
|
|
||||||
if (arm_feature(env, ARM_FEATURE_M)) {
|
if (arm_feature(env, ARM_FEATURE_M)) {
|
||||||
|
@ -795,7 +796,6 @@ static int arm_cpu_realizefn(struct uc_struct *uc, DeviceState *dev, Error **err
|
||||||
if (!cpu->has_pmu) {
|
if (!cpu->has_pmu) {
|
||||||
unset_feature(env, ARM_FEATURE_PMU);
|
unset_feature(env, ARM_FEATURE_PMU);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arm_feature(env, ARM_FEATURE_PMU)) {
|
if (arm_feature(env, ARM_FEATURE_PMU)) {
|
||||||
pmu_init(cpu);
|
pmu_init(cpu);
|
||||||
|
|
||||||
|
@ -874,6 +874,8 @@ static int arm_cpu_realizefn(struct uc_struct *uc, DeviceState *dev, Error **err
|
||||||
register_cp_regs_for_features(cpu);
|
register_cp_regs_for_features(cpu);
|
||||||
arm_cpu_register_gdb_regs_for_features(cpu);
|
arm_cpu_register_gdb_regs_for_features(cpu);
|
||||||
|
|
||||||
|
init_cpreg_list(cpu);
|
||||||
|
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
if (cpu->has_el3 || arm_feature(env, ARM_FEATURE_M_SECURITY)) {
|
if (cpu->has_el3 || arm_feature(env, ARM_FEATURE_M_SECURITY)) {
|
||||||
cs->num_ases = 2;
|
cs->num_ases = 2;
|
||||||
|
@ -894,8 +896,6 @@ static int arm_cpu_realizefn(struct uc_struct *uc, DeviceState *dev, Error **err
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
init_cpreg_list(cpu);
|
|
||||||
|
|
||||||
qemu_init_vcpu(cs);
|
qemu_init_vcpu(cs);
|
||||||
cpu_reset(cs);
|
cpu_reset(cs);
|
||||||
|
|
||||||
|
@ -1245,9 +1245,12 @@ static void arm_v7m_class_init(struct uc_struct *uc, ObjectClass *oc, void *data
|
||||||
|
|
||||||
static const ARMCPRegInfo cortexr5_cp_reginfo[] = {
|
static const ARMCPRegInfo cortexr5_cp_reginfo[] = {
|
||||||
/* Dummy the TCM region regs for the moment */
|
/* Dummy the TCM region regs for the moment */
|
||||||
{ "ATCM", 15,9,1, 0,0,0, 0,ARM_CP_CONST, PL1_RW },
|
{ .name = "ATCM", .cp = 15, .opc1 = 0, .crn = 9, .crm = 1, .opc2 = 0,
|
||||||
{ "BTCM", 15,9,1, 0,0,1, 0,ARM_CP_CONST, PL1_RW },
|
.access = PL1_RW, .type = ARM_CP_CONST },
|
||||||
{ "DCACHE_INVAL", 15,15,5, 0,0,0, 0, ARM_CP_NOP, PL1_W },
|
{ .name = "BTCM", .cp = 15, .opc1 = 0, .crn = 9, .crm = 1, .opc2 = 1,
|
||||||
|
.access = PL1_RW, .type = ARM_CP_CONST },
|
||||||
|
{ .name = "DCACHE_INVAL", .cp = 15, .opc1 = 0, .crn = 15, .crm = 5,
|
||||||
|
.opc2 = 0, .access = PL1_W, .type = ARM_CP_NOP },
|
||||||
REGINFO_SENTINEL
|
REGINFO_SENTINEL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1275,6 +1278,7 @@ static void cortex_r5_initfn(struct uc_struct *uc, Object *obj, void *opaque)
|
||||||
cpu->isar.id_isar5 = 0x0;
|
cpu->isar.id_isar5 = 0x0;
|
||||||
cpu->isar.id_isar6 = 0x0;
|
cpu->isar.id_isar6 = 0x0;
|
||||||
cpu->mp_is_up = true;
|
cpu->mp_is_up = true;
|
||||||
|
cpu->pmsav7_dregion = 16;
|
||||||
define_arm_cp_regs(cpu, cortexr5_cp_reginfo);
|
define_arm_cp_regs(cpu, cortexr5_cp_reginfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1287,10 +1291,10 @@ static void cortex_r5f_initfn(struct uc_struct *uc, Object *obj, void *opaque)
|
||||||
}
|
}
|
||||||
|
|
||||||
static const ARMCPRegInfo cortexa8_cp_reginfo[] = {
|
static const ARMCPRegInfo cortexa8_cp_reginfo[] = {
|
||||||
{ "L2LOCKDOWN", 15,9,0, 0,1,0, 0,
|
{ .name = "L2LOCKDOWN", .cp = 15, .crn = 9, .crm = 0, .opc1 = 1, .opc2 = 0,
|
||||||
ARM_CP_CONST, PL1_RW, 0, NULL, 0, },
|
.access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
|
||||||
{ "L2AUXCR", 15,9,0, 0,1,2, 0,
|
{ .name = "L2AUXCR", .cp = 15, .crn = 9, .crm = 0, .opc1 = 1, .opc2 = 2,
|
||||||
ARM_CP_CONST, PL1_RW, 0, NULL, 0, },
|
.access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
|
||||||
REGINFO_SENTINEL
|
REGINFO_SENTINEL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1337,25 +1341,28 @@ static const ARMCPRegInfo cortexa9_cp_reginfo[] = {
|
||||||
/* power_control should be set to maximum latency. Again,
|
/* power_control should be set to maximum latency. Again,
|
||||||
* default to 0 and set by private hook
|
* default to 0 and set by private hook
|
||||||
*/
|
*/
|
||||||
{ "A9_PWRCTL", 15,15,0, 0,0,0, 0,
|
{ .name = "A9_PWRCTL", .cp = 15, .crn = 15, .crm = 0, .opc1 = 0, .opc2 = 0,
|
||||||
0, PL1_RW, 0, NULL, 0, offsetof(CPUARMState, cp15.c15_power_control) },
|
.access = PL1_RW, .resetvalue = 0,
|
||||||
{ "A9_DIAG", 15,15,0, 0,0,1, 0,
|
.fieldoffset = offsetof(CPUARMState, cp15.c15_power_control) },
|
||||||
0, PL1_RW, 0, NULL, 0, offsetof(CPUARMState, cp15.c15_diagnostic) },
|
{ .name = "A9_DIAG", .cp = 15, .crn = 15, .crm = 0, .opc1 = 0, .opc2 = 1,
|
||||||
{ "A9_PWRDIAG",15,15,0, 0,0,2, 0,
|
.access = PL1_RW, .resetvalue = 0,
|
||||||
0, PL1_RW, 0, NULL, 0, offsetof(CPUARMState, cp15.c15_power_diagnostic) },
|
.fieldoffset = offsetof(CPUARMState, cp15.c15_diagnostic) },
|
||||||
{ "NEONBUSY", 15,15,1, 0,0,0, 0,
|
{ .name = "A9_PWRDIAG", .cp = 15, .crn = 15, .crm = 0, .opc1 = 0, .opc2 = 2,
|
||||||
ARM_CP_CONST, PL1_RW, 0, NULL, 0, },
|
.access = PL1_RW, .resetvalue = 0,
|
||||||
|
.fieldoffset = offsetof(CPUARMState, cp15.c15_power_diagnostic) },
|
||||||
|
{ .name = "NEONBUSY", .cp = 15, .crn = 15, .crm = 1, .opc1 = 0, .opc2 = 0,
|
||||||
|
.access = PL1_RW, .resetvalue = 0, .type = ARM_CP_CONST },
|
||||||
/* TLB lockdown control */
|
/* TLB lockdown control */
|
||||||
{ "TLB_LOCKR", 15,15,4, 0,5,2, 0,
|
{ .name = "TLB_LOCKR", .cp = 15, .crn = 15, .crm = 4, .opc1 = 5, .opc2 = 2,
|
||||||
ARM_CP_NOP, PL1_W, 0, NULL, 0 },
|
.access = PL1_W, .resetvalue = 0, .type = ARM_CP_NOP },
|
||||||
{ "TLB_LOCKW", 15,15,4, 0,5,4, 0,
|
{ .name = "TLB_LOCKW", .cp = 15, .crn = 15, .crm = 4, .opc1 = 5, .opc2 = 4,
|
||||||
ARM_CP_NOP, PL1_W, 0, NULL, 0, },
|
.access = PL1_W, .resetvalue = 0, .type = ARM_CP_NOP },
|
||||||
{ "TLB_VA", 15,15,5, 0,5,2, 0,
|
{ .name = "TLB_VA", .cp = 15, .crn = 15, .crm = 5, .opc1 = 5, .opc2 = 2,
|
||||||
ARM_CP_CONST, PL1_RW, 0, NULL, 0, },
|
.access = PL1_RW, .resetvalue = 0, .type = ARM_CP_CONST },
|
||||||
{ "TLB_PA", 15,15,6, 0,5,2, 0,
|
{ .name = "TLB_PA", .cp = 15, .crn = 15, .crm = 6, .opc1 = 5, .opc2 = 2,
|
||||||
ARM_CP_CONST, PL1_RW, 0, NULL, 0 },
|
.access = PL1_RW, .resetvalue = 0, .type = ARM_CP_CONST },
|
||||||
{ "TLB_ATTR", 15,15,7, 0,5,2, 0,
|
{ .name = "TLB_ATTR", .cp = 15, .crn = 15, .crm = 7, .opc1 = 5, .opc2 = 2,
|
||||||
ARM_CP_CONST, PL1_RW, 0, NULL, 0, },
|
.access = PL1_RW, .resetvalue = 0, .type = ARM_CP_CONST },
|
||||||
REGINFO_SENTINEL
|
REGINFO_SENTINEL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1413,12 +1420,12 @@ static uint64_t a15_l2ctlr_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||||
|
|
||||||
static const ARMCPRegInfo cortexa15_cp_reginfo[] = {
|
static const ARMCPRegInfo cortexa15_cp_reginfo[] = {
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
{ "L2CTLR", 15,9,0, 0,1,2, 0,
|
{ .name = "L2CTLR", .cp = 15, .crn = 9, .crm = 0, .opc1 = 1, .opc2 = 2,
|
||||||
0, PL1_RW, 0, NULL, 0, 0, {0, 0},
|
.access = PL1_RW, .resetvalue = 0, .readfn = a15_l2ctlr_read,
|
||||||
NULL, a15_l2ctlr_read, arm_cp_write_ignore, },
|
.writefn = arm_cp_write_ignore, },
|
||||||
#endif
|
#endif
|
||||||
{ "L2ECTLR", 15,9,0, 0,1,3, 0,
|
{ .name = "L2ECTLR", .cp = 15, .crn = 9, .crm = 0, .opc1 = 1, .opc2 = 3,
|
||||||
ARM_CP_CONST, PL1_RW, 0, NULL, 0 },
|
.access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
|
||||||
REGINFO_SENTINEL
|
REGINFO_SENTINEL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1742,51 +1749,55 @@ typedef struct ARMCPUInfo {
|
||||||
|
|
||||||
static const ARMCPUInfo arm_cpus[] = {
|
static const ARMCPUInfo arm_cpus[] = {
|
||||||
#if !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64)
|
#if !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64)
|
||||||
{ "arm926", arm926_initfn },
|
{ .name = "arm926", .initfn = arm926_initfn },
|
||||||
{ "arm946", arm946_initfn },
|
{ .name = "arm946", .initfn = arm946_initfn },
|
||||||
{ "arm1026", arm1026_initfn },
|
{ .name = "arm1026", .initfn = arm1026_initfn },
|
||||||
/* What QEMU calls "arm1136-r2" is actually the 1136 r0p2, i.e. an
|
/* What QEMU calls "arm1136-r2" is actually the 1136 r0p2, i.e. an
|
||||||
* older core than plain "arm1136". In particular this does not
|
* older core than plain "arm1136". In particular this does not
|
||||||
* have the v6K features.
|
* have the v6K features.
|
||||||
*/
|
*/
|
||||||
{ "arm1136-r2", arm1136_r2_initfn },
|
{ .name = "arm1136-r2", .initfn = arm1136_r2_initfn },
|
||||||
{ "arm1136", arm1136_initfn },
|
{ .name = "arm1136", .initfn = arm1136_initfn },
|
||||||
{ "arm1176", arm1176_initfn },
|
{ .name = "arm1176", .initfn = arm1176_initfn },
|
||||||
{ "arm11mpcore", arm11mpcore_initfn },
|
{ .name = "arm11mpcore", .initfn = arm11mpcore_initfn },
|
||||||
{ "cortex-m0", cortex_m0_initfn, arm_v7m_class_init },
|
{ .name = "cortex-m0", .initfn = cortex_m0_initfn,
|
||||||
{ "cortex-m3", cortex_m3_initfn, arm_v7m_class_init },
|
.class_init = arm_v7m_class_init },
|
||||||
{ "cortex-m4", cortex_m4_initfn, arm_v7m_class_init },
|
{ .name = "cortex-m3", .initfn = cortex_m3_initfn,
|
||||||
{ "cortex-m33", cortex_m33_initfn, arm_v7m_class_init },
|
.class_init = arm_v7m_class_init },
|
||||||
{ "cortex-r5", cortex_r5_initfn },
|
{ .name = "cortex-m4", .initfn = cortex_m4_initfn,
|
||||||
{ "cortex-r5f", cortex_r5f_initfn },
|
.class_init = arm_v7m_class_init },
|
||||||
{ "cortex-a7", cortex_a7_initfn },
|
{ .name = "cortex-m33", .initfn = cortex_m33_initfn,
|
||||||
{ "cortex-a8", cortex_a8_initfn },
|
.class_init = arm_v7m_class_init },
|
||||||
{ "cortex-a9", cortex_a9_initfn },
|
{ .name = "cortex-r5", .initfn = cortex_r5_initfn },
|
||||||
{ "cortex-a15", cortex_a15_initfn },
|
{ .name = "cortex-r5f", .initfn = cortex_r5f_initfn },
|
||||||
{ "ti925t", ti925t_initfn },
|
{ .name = "cortex-a7", .initfn = cortex_a7_initfn },
|
||||||
{ "sa1100", sa1100_initfn },
|
{ .name = "cortex-a8", .initfn = cortex_a8_initfn },
|
||||||
{ "sa1110", sa1110_initfn },
|
{ .name = "cortex-a9", .initfn = cortex_a9_initfn },
|
||||||
{ "pxa250", pxa250_initfn },
|
{ .name = "cortex-a15", .initfn = cortex_a15_initfn },
|
||||||
{ "pxa255", pxa255_initfn },
|
{ .name = "ti925t", .initfn = ti925t_initfn },
|
||||||
{ "pxa260", pxa260_initfn },
|
{ .name = "sa1100", .initfn = sa1100_initfn },
|
||||||
{ "pxa261", pxa261_initfn },
|
{ .name = "sa1110", .initfn = sa1110_initfn },
|
||||||
{ "pxa262", pxa262_initfn },
|
{ .name = "pxa250", .initfn = pxa250_initfn },
|
||||||
|
{ .name = "pxa255", .initfn = pxa255_initfn },
|
||||||
|
{ .name = "pxa260", .initfn = pxa260_initfn },
|
||||||
|
{ .name = "pxa261", .initfn = pxa261_initfn },
|
||||||
|
{ .name = "pxa262", .initfn = pxa262_initfn },
|
||||||
/* "pxa270" is an alias for "pxa270-a0" */
|
/* "pxa270" is an alias for "pxa270-a0" */
|
||||||
{ "pxa270", pxa270a0_initfn },
|
{ .name = "pxa270", .initfn = pxa270a0_initfn },
|
||||||
{ "pxa270-a0", pxa270a0_initfn },
|
{ .name = "pxa270-a0", .initfn = pxa270a0_initfn },
|
||||||
{ "pxa270-a1", pxa270a1_initfn },
|
{ .name = "pxa270-a1", .initfn = pxa270a1_initfn },
|
||||||
{ "pxa270-b0", pxa270b0_initfn },
|
{ .name = "pxa270-b0", .initfn = pxa270b0_initfn },
|
||||||
{ "pxa270-b1", pxa270b1_initfn },
|
{ .name = "pxa270-b1", .initfn = pxa270b1_initfn },
|
||||||
{ "pxa270-c0", pxa270c0_initfn },
|
{ .name = "pxa270-c0", .initfn = pxa270c0_initfn },
|
||||||
{ "pxa270-c5", pxa270c5_initfn },
|
{ .name = "pxa270-c5", .initfn = pxa270c5_initfn },
|
||||||
#ifndef TARGET_AARCH64
|
#ifndef TARGET_AARCH64
|
||||||
{ "max", arm_max_initfn },
|
{ .name = "max", .initfn = arm_max_initfn },
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_USER_ONLY
|
#ifdef CONFIG_USER_ONLY
|
||||||
{ "any", arm_max_initfn },
|
{ .name = "any", .initfn = arm_max_initfn },
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
{ NULL }
|
{ .name = NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_USER_ONLY
|
#ifdef CONFIG_USER_ONLY
|
||||||
|
@ -1818,7 +1829,6 @@ static void arm_cpu_class_init(struct uc_struct *uc, ObjectClass *oc, void *data
|
||||||
|
|
||||||
acc->parent_reset = cc->reset;
|
acc->parent_reset = cc->reset;
|
||||||
cc->reset = arm_cpu_reset;
|
cc->reset = arm_cpu_reset;
|
||||||
cc->class_by_name = arm_cpu_class_by_name;
|
|
||||||
|
|
||||||
cc->class_by_name = arm_cpu_class_by_name;
|
cc->class_by_name = arm_cpu_class_by_name;
|
||||||
cc->has_work = arm_cpu_has_work;
|
cc->has_work = arm_cpu_has_work;
|
||||||
|
|
|
@ -32,8 +32,6 @@
|
||||||
# define TARGET_LONG_BITS 32
|
# define TARGET_LONG_BITS 32
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define TARGET_IS_BIENDIAN 1
|
|
||||||
|
|
||||||
/* ARM processors have a weak memory model */
|
/* ARM processors have a weak memory model */
|
||||||
#define TCG_GUEST_DEFAULT_MO (0)
|
#define TCG_GUEST_DEFAULT_MO (0)
|
||||||
|
|
||||||
|
@ -943,6 +941,7 @@ int cpu_arm_signal_handler(int host_signum, void *pinfo,
|
||||||
/**
|
/**
|
||||||
* pmu_op_start/finish
|
* pmu_op_start/finish
|
||||||
* @env: CPUARMState
|
* @env: CPUARMState
|
||||||
|
*
|
||||||
* Convert all PMU counters between their delta form (the typical mode when
|
* Convert all PMU counters between their delta form (the typical mode when
|
||||||
* they are enabled) and the guest-visible values. These two calls must
|
* they are enabled) and the guest-visible values. These two calls must
|
||||||
* surround any action which might affect the counters.
|
* surround any action which might affect the counters.
|
||||||
|
@ -2403,7 +2402,7 @@ struct ARMCPRegInfo {
|
||||||
#define CPREG_FIELD64(env, ri) \
|
#define CPREG_FIELD64(env, ri) \
|
||||||
(*(uint64_t *)((char *)(env) + (ri)->fieldoffset))
|
(*(uint64_t *)((char *)(env) + (ri)->fieldoffset))
|
||||||
|
|
||||||
#define REGINFO_SENTINEL { NULL, 0,0,0,0,0,0, 0, ARM_CP_SENTINEL, 0, 0, NULL, 0,0, {0, 0}, 0,0,0,0,0,0, }
|
#define REGINFO_SENTINEL { .type = ARM_CP_SENTINEL }
|
||||||
|
|
||||||
void define_arm_cp_regs_with_opaque(ARMCPU *cpu,
|
void define_arm_cp_regs_with_opaque(ARMCPU *cpu,
|
||||||
const ARMCPRegInfo *regs, void *opaque);
|
const ARMCPRegInfo *regs, void *opaque);
|
||||||
|
@ -2523,54 +2522,6 @@ bool write_cpustate_to_list(ARMCPU *cpu);
|
||||||
# define TARGET_VIRT_ADDR_SPACE_BITS 32
|
# define TARGET_VIRT_ADDR_SPACE_BITS 32
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
|
||||||
* arm_hcr_el2_imo(): Return the effective value of HCR_EL2.IMO.
|
|
||||||
* Depending on the values of HCR_EL2.E2H and TGE, this may be
|
|
||||||
* "behaves as 1 for all purposes other than direct read/write" or
|
|
||||||
* "behaves as 0 for all purposes other than direct read/write"
|
|
||||||
*/
|
|
||||||
static inline bool arm_hcr_el2_imo(CPUARMState *env)
|
|
||||||
{
|
|
||||||
switch (env->cp15.hcr_el2 & (HCR_TGE | HCR_E2H)) {
|
|
||||||
case HCR_TGE:
|
|
||||||
return true;
|
|
||||||
case HCR_TGE | HCR_E2H:
|
|
||||||
return false;
|
|
||||||
default:
|
|
||||||
return env->cp15.hcr_el2 & HCR_IMO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* arm_hcr_el2_fmo(): Return the effective value of HCR_EL2.FMO.
|
|
||||||
*/
|
|
||||||
static inline bool arm_hcr_el2_fmo(CPUARMState *env)
|
|
||||||
{
|
|
||||||
switch (env->cp15.hcr_el2 & (HCR_TGE | HCR_E2H)) {
|
|
||||||
case HCR_TGE:
|
|
||||||
return true;
|
|
||||||
case HCR_TGE | HCR_E2H:
|
|
||||||
return false;
|
|
||||||
default:
|
|
||||||
return env->cp15.hcr_el2 & HCR_FMO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* arm_hcr_el2_amo(): Return the effective value of HCR_EL2.AMO.
|
|
||||||
*/
|
|
||||||
static inline bool arm_hcr_el2_amo(CPUARMState *env)
|
|
||||||
{
|
|
||||||
switch (env->cp15.hcr_el2 & (HCR_TGE | HCR_E2H)) {
|
|
||||||
case HCR_TGE:
|
|
||||||
return true;
|
|
||||||
case HCR_TGE | HCR_E2H:
|
|
||||||
return false;
|
|
||||||
default:
|
|
||||||
return env->cp15.hcr_el2 & HCR_AMO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx,
|
static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx,
|
||||||
unsigned int target_el)
|
unsigned int target_el)
|
||||||
{
|
{
|
||||||
|
@ -2579,6 +2530,7 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx,
|
||||||
bool secure = arm_is_secure(env);
|
bool secure = arm_is_secure(env);
|
||||||
bool pstate_unmasked;
|
bool pstate_unmasked;
|
||||||
int8_t unmasked = 0;
|
int8_t unmasked = 0;
|
||||||
|
uint64_t hcr_el2;
|
||||||
|
|
||||||
/* Don't take exceptions if they target a lower EL.
|
/* Don't take exceptions if they target a lower EL.
|
||||||
* This check should catch any exceptions that would not be taken but left
|
* This check should catch any exceptions that would not be taken but left
|
||||||
|
@ -2588,6 +2540,8 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hcr_el2 = arm_hcr_el2_eff(env);
|
||||||
|
|
||||||
switch (excp_idx) {
|
switch (excp_idx) {
|
||||||
case EXCP_FIQ:
|
case EXCP_FIQ:
|
||||||
pstate_unmasked = !(env->daif & PSTATE_F);
|
pstate_unmasked = !(env->daif & PSTATE_F);
|
||||||
|
@ -2598,13 +2552,13 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXCP_VFIQ:
|
case EXCP_VFIQ:
|
||||||
if (secure || !arm_hcr_el2_fmo(env) || (env->cp15.hcr_el2 & HCR_TGE)) {
|
if (secure || !(hcr_el2 & HCR_FMO) || (hcr_el2 & HCR_TGE)) {
|
||||||
/* VFIQs are only taken when hypervized and non-secure. */
|
/* VFIQs are only taken when hypervized and non-secure. */
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return !(env->daif & PSTATE_F);
|
return !(env->daif & PSTATE_F);
|
||||||
case EXCP_VIRQ:
|
case EXCP_VIRQ:
|
||||||
if (secure || !arm_hcr_el2_imo(env) || (env->cp15.hcr_el2 & HCR_TGE)) {
|
if (secure || !(hcr_el2 & HCR_IMO) || (hcr_el2 & HCR_TGE)) {
|
||||||
/* VIRQs are only taken when hypervized and non-secure. */
|
/* VIRQs are only taken when hypervized and non-secure. */
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -2644,7 +2598,7 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx,
|
||||||
* to the CPSR.F setting otherwise we further assess the state
|
* to the CPSR.F setting otherwise we further assess the state
|
||||||
* below.
|
* below.
|
||||||
*/
|
*/
|
||||||
hcr = arm_hcr_el2_fmo(env);
|
hcr = hcr_el2 & HCR_FMO;
|
||||||
scr = (env->cp15.scr_el3 & SCR_FIQ);
|
scr = (env->cp15.scr_el3 & SCR_FIQ);
|
||||||
|
|
||||||
/* When EL3 is 32-bit, the SCR.FW bit controls whether the
|
/* When EL3 is 32-bit, the SCR.FW bit controls whether the
|
||||||
|
@ -2661,7 +2615,7 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx,
|
||||||
* when setting the target EL, so it does not have a further
|
* when setting the target EL, so it does not have a further
|
||||||
* affect here.
|
* affect here.
|
||||||
*/
|
*/
|
||||||
hcr = arm_hcr_el2_imo(env);
|
hcr = hcr_el2 & HCR_IMO;
|
||||||
scr = false;
|
scr = false;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -2988,9 +2942,6 @@ static inline bool aa32_generate_debug_exceptions(CPUARMState *env)
|
||||||
* since the pseudocode has it at all callsites except for the one in
|
* since the pseudocode has it at all callsites except for the one in
|
||||||
* CheckSoftwareStep(), where it is elided because both branches would
|
* CheckSoftwareStep(), where it is elided because both branches would
|
||||||
* always return the same value.
|
* always return the same value.
|
||||||
*
|
|
||||||
* Parts of the pseudocode relating to EL2 and EL3 are omitted because we
|
|
||||||
* don't yet implement those exception levels or their associated trap bits.
|
|
||||||
*/
|
*/
|
||||||
static inline bool arm_generate_debug_exceptions(CPUARMState *env)
|
static inline bool arm_generate_debug_exceptions(CPUARMState *env)
|
||||||
{
|
{
|
||||||
|
@ -3011,6 +2962,59 @@ static inline bool arm_singlestep_active(CPUARMState *env)
|
||||||
&& arm_generate_debug_exceptions(env);
|
&& arm_generate_debug_exceptions(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool arm_sctlr_b(CPUARMState *env)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
/* We need not implement SCTLR.ITD in user-mode emulation, so
|
||||||
|
* let linux-user ignore the fact that it conflicts with SCTLR_B.
|
||||||
|
* This lets people run BE32 binaries with "-cpu any".
|
||||||
|
*/
|
||||||
|
#ifndef CONFIG_USER_ONLY
|
||||||
|
!arm_feature(env, ARM_FEATURE_V7) &&
|
||||||
|
#endif
|
||||||
|
(env->cp15.sctlr_el[1] & SCTLR_B) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint64_t arm_sctlr(CPUARMState *env, int el)
|
||||||
|
{
|
||||||
|
if (el == 0) {
|
||||||
|
/* FIXME: ARMv8.1-VHE S2 translation regime. */
|
||||||
|
return env->cp15.sctlr_el[1];
|
||||||
|
} else {
|
||||||
|
return env->cp15.sctlr_el[el];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return true if the processor is in big-endian mode. */
|
||||||
|
static inline bool arm_cpu_data_is_big_endian(CPUARMState *env)
|
||||||
|
{
|
||||||
|
/* In 32bit endianness is determined by looking at CPSR's E bit */
|
||||||
|
if (!is_a64(env)) {
|
||||||
|
return
|
||||||
|
#ifdef CONFIG_USER_ONLY
|
||||||
|
/* In system mode, BE32 is modelled in line with the
|
||||||
|
* architecture (as word-invariant big-endianness), where loads
|
||||||
|
* and stores are done little endian but from addresses which
|
||||||
|
* are adjusted by XORing with the appropriate constant. So the
|
||||||
|
* endianness to use for the raw data access is not affected by
|
||||||
|
* SCTLR.B.
|
||||||
|
* In user mode, however, we model BE32 as byte-invariant
|
||||||
|
* big-endianness (because user-only code cannot tell the
|
||||||
|
* difference), and so we need to use a data access endianness
|
||||||
|
* that depends on SCTLR.B.
|
||||||
|
*/
|
||||||
|
arm_sctlr_b(env) ||
|
||||||
|
#endif
|
||||||
|
((env->uncached_cpsr & CPSR_E) ? 1 : 0);
|
||||||
|
} else {
|
||||||
|
int cur_el = arm_current_el(env);
|
||||||
|
uint64_t sctlr = arm_sctlr(env, cur_el);
|
||||||
|
|
||||||
|
return (sctlr & (cur_el ? SCTLR_EE : SCTLR_E0E)) != 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#include "exec/cpu-all.h"
|
#include "exec/cpu-all.h"
|
||||||
|
|
||||||
/* Bit usage in the TB flags field: bit 31 indicates whether we are
|
/* Bit usage in the TB flags field: bit 31 indicates whether we are
|
||||||
|
@ -3076,57 +3080,16 @@ static inline bool bswap_code(bool sctlr_b)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool arm_sctlr_b(CPUARMState *env)
|
#ifdef CONFIG_USER_ONLY
|
||||||
|
static inline bool arm_cpu_bswap_data(CPUARMState *env)
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
/* We need not implement SCTLR.ITD in user-mode emulation, so
|
#ifdef TARGET_WORDS_BIGENDIAN
|
||||||
* let linux-user ignore the fact that it conflicts with SCTLR_B.
|
1 ^
|
||||||
* This lets people run BE32 binaries with "-cpu any".
|
|
||||||
*/
|
|
||||||
#ifndef CONFIG_USER_ONLY
|
|
||||||
!arm_feature(env, ARM_FEATURE_V7) &&
|
|
||||||
#endif
|
#endif
|
||||||
(env->cp15.sctlr_el[1] & SCTLR_B) != 0;
|
arm_cpu_data_is_big_endian(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint64_t arm_sctlr(CPUARMState *env, int el)
|
|
||||||
{
|
|
||||||
if (el == 0) {
|
|
||||||
/* FIXME: ARMv8.1-VHE S2 translation regime. */
|
|
||||||
return env->cp15.sctlr_el[1];
|
|
||||||
} else {
|
|
||||||
return env->cp15.sctlr_el[el];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return true if the processor is in big-endian mode. */
|
|
||||||
static inline bool arm_cpu_data_is_big_endian(CPUARMState *env)
|
|
||||||
{
|
|
||||||
/* In 32bit endianness is determined by looking at CPSR's E bit */
|
|
||||||
if (!is_a64(env)) {
|
|
||||||
return
|
|
||||||
#ifdef CONFIG_USER_ONLY
|
|
||||||
/* In system mode, BE32 is modelled in line with the
|
|
||||||
* architecture (as word-invariant big-endianness), where loads
|
|
||||||
* and stores are done little endian but from addresses which
|
|
||||||
* are adjusted by XORing with the appropriate constant. So the
|
|
||||||
* endianness to use for the raw data access is not affected by
|
|
||||||
* SCTLR.B.
|
|
||||||
* In user mode, however, we model BE32 as byte-invariant
|
|
||||||
* big-endianness (because user-only code cannot tell the
|
|
||||||
* difference), and so we need to use a data access endianness
|
|
||||||
* that depends on SCTLR.B.
|
|
||||||
*/
|
|
||||||
arm_sctlr_b(env) ||
|
|
||||||
#endif
|
#endif
|
||||||
((env->uncached_cpsr & CPSR_E) ? 1 : 0);
|
|
||||||
} else {
|
|
||||||
int cur_el = arm_current_el(env);
|
|
||||||
uint64_t sctlr = arm_sctlr(env, cur_el);
|
|
||||||
|
|
||||||
return (sctlr & (cur_el ? SCTLR_EE : SCTLR_E0E)) != 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
|
void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
|
||||||
target_ulong *cs_base, uint32_t *flags);
|
target_ulong *cs_base, uint32_t *flags);
|
||||||
|
|
|
@ -342,11 +342,11 @@ typedef struct ARMCPUInfo {
|
||||||
} ARMCPUInfo;
|
} ARMCPUInfo;
|
||||||
|
|
||||||
static const ARMCPUInfo aarch64_cpus[] = {
|
static const ARMCPUInfo aarch64_cpus[] = {
|
||||||
{ "cortex-a57", aarch64_a57_initfn },
|
{ .name = "cortex-a57", .initfn = aarch64_a57_initfn },
|
||||||
{ "cortex-a53", aarch64_a53_initfn },
|
{ .name = "cortex-a53", .initfn = aarch64_a53_initfn },
|
||||||
{ "cortex-a72", aarch64_a72_initfn },
|
{ .name = "cortex-a72", .initfn = aarch64_a72_initfn },
|
||||||
{ "max", aarch64_max_initfn },
|
{ .name = "max", .initfn = aarch64_max_initfn },
|
||||||
{ NULL }
|
{ .name = NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
static QEMU_UNUSED_FUNC bool aarch64_cpu_get_aarch64(Object *obj, Error **errp)
|
static QEMU_UNUSED_FUNC bool aarch64_cpu_get_aarch64(Object *obj, Error **errp)
|
||||||
|
|
|
@ -614,7 +614,6 @@ uint64_t HELPER(crc32c_64)(uint64_t acc, uint64_t val, uint32_t bytes)
|
||||||
return crc32c(acc, buf, bytes) ^ 0xffffffff;
|
return crc32c(acc, buf, bytes) ^ 0xffffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns 0 on success; 1 otherwise. */
|
|
||||||
uint64_t HELPER(paired_cmpxchg64_le)(CPUARMState *env, uint64_t addr,
|
uint64_t HELPER(paired_cmpxchg64_le)(CPUARMState *env, uint64_t addr,
|
||||||
uint64_t new_lo, uint64_t new_hi)
|
uint64_t new_lo, uint64_t new_hi)
|
||||||
{
|
{
|
||||||
|
@ -723,7 +722,6 @@ void HELPER(casp_le_parallel)(CPUARMState *env, uint32_t rs, uint64_t addr,
|
||||||
|
|
||||||
cmpv = int128_make128(env->xregs[rs], env->xregs[rs + 1]);
|
cmpv = int128_make128(env->xregs[rs], env->xregs[rs + 1]);
|
||||||
newv = int128_make128(new_lo, new_hi);
|
newv = int128_make128(new_lo, new_hi);
|
||||||
|
|
||||||
oldv = helper_atomic_cmpxchgo_le_mmu(env, addr, cmpv, newv, oi, ra);
|
oldv = helper_atomic_cmpxchgo_le_mmu(env, addr, cmpv, newv, oi, ra);
|
||||||
|
|
||||||
env->xregs[rs] = int128_getlo(oldv);
|
env->xregs[rs] = int128_getlo(oldv);
|
||||||
|
@ -745,7 +743,6 @@ void HELPER(casp_be_parallel)(CPUARMState *env, uint32_t rs, uint64_t addr,
|
||||||
|
|
||||||
cmpv = int128_make128(env->xregs[rs + 1], env->xregs[rs]);
|
cmpv = int128_make128(env->xregs[rs + 1], env->xregs[rs]);
|
||||||
newv = int128_make128(new_lo, new_hi);
|
newv = int128_make128(new_lo, new_hi);
|
||||||
|
|
||||||
oldv = helper_atomic_cmpxchgo_be_mmu(env, addr, cmpv, newv, oi, ra);
|
oldv = helper_atomic_cmpxchgo_be_mmu(env, addr, cmpv, newv, oi, ra);
|
||||||
|
|
||||||
env->xregs[rs + 1] = int128_getlo(oldv);
|
env->xregs[rs + 1] = int128_getlo(oldv);
|
||||||
|
@ -1113,3 +1110,5 @@ uint32_t HELPER(sqrt_f16)(uint32_t a, void *fpstp)
|
||||||
|
|
||||||
return float16_sqrt(a, s);
|
return float16_sqrt(a, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1230,12 +1230,10 @@ static void pmccntr_op_finish(CPUARMState *env)
|
||||||
{
|
{
|
||||||
if (pmu_counter_enabled(env, 31)) {
|
if (pmu_counter_enabled(env, 31)) {
|
||||||
uint64_t prev_cycles = env->cp15.c15_ccnt_delta;
|
uint64_t prev_cycles = env->cp15.c15_ccnt_delta;
|
||||||
|
|
||||||
if (env->cp15.c9_pmcr & PMCRD) {
|
if (env->cp15.c9_pmcr & PMCRD) {
|
||||||
/* Increment once every 64 processor clock cycles */
|
/* Increment once every 64 processor clock cycles */
|
||||||
prev_cycles /= 64;
|
prev_cycles /= 64;
|
||||||
}
|
}
|
||||||
|
|
||||||
env->cp15.c15_ccnt_delta = prev_cycles - env->cp15.c15_ccnt;
|
env->cp15.c15_ccnt_delta = prev_cycles - env->cp15.c15_ccnt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1472,7 +1470,6 @@ static void pmevtyper_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||||
env->cp15.c14_pmevtyper[counter] = value & PMXEVTYPER_MASK;
|
env->cp15.c14_pmevtyper[counter] = value & PMXEVTYPER_MASK;
|
||||||
pmevcntr_op_finish(env, counter);
|
pmevcntr_op_finish(env, counter);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Attempts to access PMXEVTYPER are CONSTRAINED UNPREDICTABLE when
|
/* Attempts to access PMXEVTYPER are CONSTRAINED UNPREDICTABLE when
|
||||||
* PMSELR value is equal to or greater than the number of implemented
|
* PMSELR value is equal to or greater than the number of implemented
|
||||||
* counters, but not equal to 0x1f. We opt to behave as a RAZ/WI.
|
* counters, but not equal to 0x1f. We opt to behave as a RAZ/WI.
|
||||||
|
@ -2652,6 +2649,7 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
/* In user-mode most of the generic timer registers are inaccessible
|
/* In user-mode most of the generic timer registers are inaccessible
|
||||||
* however modern kernels (4.12+) allow access to cntvct_el0
|
* however modern kernels (4.12+) allow access to cntvct_el0
|
||||||
*/
|
*/
|
||||||
|
@ -2926,15 +2924,16 @@ static void ats_write64(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static const ARMCPRegInfo vapa_cp_reginfo[] = {
|
static const ARMCPRegInfo vapa_cp_reginfo[] = {
|
||||||
{ "PAR", 15,7,4, 0,0,0, 0,
|
{ .name = "PAR", .cp = 15, .crn = 7, .crm = 4, .opc1 = 0, .opc2 = 0,
|
||||||
0, PL1_RW, 0, NULL, 0, 0,
|
.access = PL1_RW, .resetvalue = 0,
|
||||||
{ offsetoflow32(CPUARMState, cp15.par_s), offsetoflow32(CPUARMState, cp15.par_ns) },
|
.bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.par_s),
|
||||||
NULL, NULL, par_write },
|
offsetoflow32(CPUARMState, cp15.par_ns) },
|
||||||
|
.writefn = par_write },
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
/* This underdecoding is safe because the reginfo is NO_RAW. */
|
/* This underdecoding is safe because the reginfo is NO_RAW. */
|
||||||
{ "ATS", 15,7,8, 0,0,CP_ANY, 0,
|
{ .name = "ATS", .cp = 15, .crn = 7, .crm = 8, .opc1 = 0, .opc2 = CP_ANY,
|
||||||
ARM_CP_NO_RAW, PL1_W, 0, NULL, 0, 0, {0, 0},
|
.access = PL1_W, .accessfn = ats_access,
|
||||||
ats_access, NULL, ats_write },
|
.writefn = ats_write, .type = ARM_CP_NO_RAW },
|
||||||
#endif
|
#endif
|
||||||
REGINFO_SENTINEL
|
REGINFO_SENTINEL
|
||||||
};
|
};
|
||||||
|
@ -3565,7 +3564,7 @@ static CPAccessResult aa64_cacheop_access(CPUARMState *env,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void tlbi_aa64_vmalle1is_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
static void tlbi_aa64_vmalle1is_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||||
uint64_t value)
|
uint64_t value)
|
||||||
{
|
{
|
||||||
// UNICORN: TODO: issue #642
|
// UNICORN: TODO: issue #642
|
||||||
#if 0
|
#if 0
|
||||||
|
@ -6008,9 +6007,9 @@ void register_cp_regs_for_features(ARMCPU *cpu)
|
||||||
{ .name = "ID_AA64ZFR0_EL1" },
|
{ .name = "ID_AA64ZFR0_EL1" },
|
||||||
{ .name = "ID_AA64MMFR0_EL1",
|
{ .name = "ID_AA64MMFR0_EL1",
|
||||||
.fixed_bits = 0x00000000ff000000 },
|
.fixed_bits = 0x00000000ff000000 },
|
||||||
|
{ .name = "ID_AA64MMFR1_EL1" },
|
||||||
{ .name = "ID_AA64MMFR*_EL1_RESERVED",
|
{ .name = "ID_AA64MMFR*_EL1_RESERVED",
|
||||||
.is_glob = true },
|
.is_glob = true },
|
||||||
{ .name = "ID_AA64MMFR1_EL1" },
|
|
||||||
{ .name = "ID_AA64DFR0_EL1",
|
{ .name = "ID_AA64DFR0_EL1",
|
||||||
.fixed_bits = 0x0000000000000006 },
|
.fixed_bits = 0x0000000000000006 },
|
||||||
{ .name = "ID_AA64DFR1_EL1" },
|
{ .name = "ID_AA64DFR1_EL1" },
|
||||||
|
@ -7101,11 +7100,11 @@ void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask,
|
||||||
arm_feature(env, ARM_FEATURE_V8)) {
|
arm_feature(env, ARM_FEATURE_V8)) {
|
||||||
mask |= CPSR_IL;
|
mask |= CPSR_IL;
|
||||||
val |= CPSR_IL;
|
val |= CPSR_IL;
|
||||||
|
}
|
||||||
qemu_log_mask(LOG_GUEST_ERROR,
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
"Illegal AArch32 mode switch attempt from %s to %s\n",
|
"Illegal AArch32 mode switch attempt from %s to %s\n",
|
||||||
aarch32_mode_name(env->uncached_cpsr),
|
aarch32_mode_name(env->uncached_cpsr),
|
||||||
aarch32_mode_name(val));
|
aarch32_mode_name(val));
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
qemu_log_mask(CPU_LOG_INT, "%s %s to %s PC 0x%" PRIx32 "\n",
|
qemu_log_mask(CPU_LOG_INT, "%s %s to %s PC 0x%" PRIx32 "\n",
|
||||||
write_type == CPSRWriteExceptionReturn ?
|
write_type == CPSRWriteExceptionReturn ?
|
||||||
|
@ -7937,12 +7936,15 @@ static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain,
|
||||||
* we might now want to take a different exception which
|
* we might now want to take a different exception which
|
||||||
* targets a different security state, so try again from the top.
|
* targets a different security state, so try again from the top.
|
||||||
*/
|
*/
|
||||||
|
qemu_log_mask(CPU_LOG_INT,
|
||||||
|
"...derived exception on callee-saves register stacking");
|
||||||
v7m_exception_taken(cpu, lr, true, true);
|
v7m_exception_taken(cpu, lr, true, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!arm_v7m_load_vector(cpu, exc, targets_secure, &addr)) {
|
if (!arm_v7m_load_vector(cpu, exc, targets_secure, &addr)) {
|
||||||
/* Vector load failed: derived exception */
|
/* Vector load failed: derived exception */
|
||||||
|
qemu_log_mask(CPU_LOG_INT, "...derived exception on vector table load");
|
||||||
v7m_exception_taken(cpu, lr, true, true);
|
v7m_exception_taken(cpu, lr, true, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -8042,12 +8044,19 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
|
||||||
bool exc_secure = false;
|
bool exc_secure = false;
|
||||||
bool return_to_secure;
|
bool return_to_secure;
|
||||||
|
|
||||||
/* We can only get here from an EXCP_EXCEPTION_EXIT, and
|
/* If we're not in Handler mode then jumps to magic exception-exit
|
||||||
* gen_bx_excret() enforces the architectural rule
|
* addresses don't have magic behaviour. However for the v8M
|
||||||
* that jumps to magic addresses don't have magic behaviour unless
|
* security extensions the magic secure-function-return has to
|
||||||
* we're in Handler mode (compare pseudocode BXWritePC()).
|
* work in thread mode too, so to avoid doing an extra check in
|
||||||
|
* the generated code we allow exception-exit magic to also cause the
|
||||||
|
* internal exception and bring us here in thread mode. Correct code
|
||||||
|
* will never try to do this (the following insn fetch will always
|
||||||
|
* fault) so we the overhead of having taken an unnecessary exception
|
||||||
|
* doesn't matter.
|
||||||
*/
|
*/
|
||||||
assert(arm_v7m_is_handler_mode(env));
|
if (!arm_v7m_is_handler_mode(env)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* In the spec pseudocode ExceptionReturn() is called directly
|
/* In the spec pseudocode ExceptionReturn() is called directly
|
||||||
* from BXWritePC() and gets the full target PC value including
|
* from BXWritePC() and gets the full target PC value including
|
||||||
|
@ -8095,7 +8104,7 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
|
||||||
if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
|
if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
|
||||||
// Unicorn: commented out
|
// Unicorn: commented out
|
||||||
//if (armv7m_nvic_raw_execution_priority(env->nvic) >= 0) {
|
//if (armv7m_nvic_raw_execution_priority(env->nvic) >= 0) {
|
||||||
// env->v7m.faultmask[es] = 0;
|
// env->v7m.faultmask[exc_secure] = 0;
|
||||||
//}
|
//}
|
||||||
} else {
|
} else {
|
||||||
env->v7m.faultmask[M_REG_NS] = 0;
|
env->v7m.faultmask[M_REG_NS] = 0;
|
||||||
|
@ -8104,7 +8113,8 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
|
||||||
|
|
||||||
// Unicorn: if'd out
|
// Unicorn: if'd out
|
||||||
#if 0
|
#if 0
|
||||||
switch (armv7m_nvic_complete_irq(env->nvic, env->v7m.exception)) {
|
switch (armv7m_nvic_complete_irq(env->nvic, env->v7m.exception,
|
||||||
|
exc_secure)) {
|
||||||
case -1:
|
case -1:
|
||||||
/* attempt to exit an exception that isn't active */
|
/* attempt to exit an exception that isn't active */
|
||||||
ufault = true;
|
ufault = true;
|
||||||
|
@ -8178,9 +8188,9 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
|
||||||
env->v7m.sfsr |= R_V7M_SFSR_INVER_MASK;
|
env->v7m.sfsr |= R_V7M_SFSR_INVER_MASK;
|
||||||
// Unicorn: commented out
|
// Unicorn: commented out
|
||||||
//armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
|
//armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
|
||||||
v7m_exception_taken(cpu, excret, true, false);
|
|
||||||
qemu_log_mask(CPU_LOG_INT, "...taking SecureFault on existing "
|
qemu_log_mask(CPU_LOG_INT, "...taking SecureFault on existing "
|
||||||
"stackframe: failed EXC_RETURN.ES validity check\n");
|
"stackframe: failed EXC_RETURN.ES validity check\n");
|
||||||
|
v7m_exception_taken(cpu, excret, true, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8191,9 +8201,9 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
|
||||||
env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK;
|
env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK;
|
||||||
// Unicorn: commented out
|
// Unicorn: commented out
|
||||||
//armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE);
|
//armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE);
|
||||||
v7m_exception_taken(cpu, excret, true, false);
|
|
||||||
qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on existing "
|
qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on existing "
|
||||||
"stackframe: failed exception return integrity check\n");
|
"stackframe: failed exception return integrity check\n");
|
||||||
|
v7m_exception_taken(cpu, excret, true, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8260,10 +8270,10 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
|
||||||
env->v7m.sfsr |= R_V7M_SFSR_INVIS_MASK;
|
env->v7m.sfsr |= R_V7M_SFSR_INVIS_MASK;
|
||||||
// Unicorn: commented out
|
// Unicorn: commented out
|
||||||
//armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
|
//armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
|
||||||
v7m_exception_taken(cpu, excret, true, false);
|
|
||||||
qemu_log_mask(CPU_LOG_INT, "...taking SecureFault on existing "
|
qemu_log_mask(CPU_LOG_INT, "...taking SecureFault on existing "
|
||||||
"stackframe: failed exception return integrity "
|
"stackframe: failed exception return integrity "
|
||||||
"signature check\n");
|
"signature check\n");
|
||||||
|
v7m_exception_taken(cpu, excret, true, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8295,6 +8305,7 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
|
||||||
/* v7m_stack_read() pended a fault, so take it (as a tail
|
/* v7m_stack_read() pended a fault, so take it (as a tail
|
||||||
* chained exception on the same stack frame)
|
* chained exception on the same stack frame)
|
||||||
*/
|
*/
|
||||||
|
qemu_log_mask(CPU_LOG_INT, "...derived exception on unstacking\n");
|
||||||
v7m_exception_taken(cpu, excret, true, false);
|
v7m_exception_taken(cpu, excret, true, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -8332,10 +8343,10 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
|
||||||
//armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,
|
//armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,
|
||||||
// env->v7m.secure);
|
// env->v7m.secure);
|
||||||
env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK;
|
env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK;
|
||||||
v7m_exception_taken(cpu, excret, true, false);
|
|
||||||
qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on existing "
|
qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on existing "
|
||||||
"stackframe: failed exception return integrity "
|
"stackframe: failed exception return integrity "
|
||||||
"check\n");
|
"check\n");
|
||||||
|
v7m_exception_taken(cpu, excret, true, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8372,9 +8383,9 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
|
||||||
//armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE);
|
//armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE);
|
||||||
env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK;
|
env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK;
|
||||||
ignore_stackfaults = v7m_push_stack(cpu);
|
ignore_stackfaults = v7m_push_stack(cpu);
|
||||||
v7m_exception_taken(cpu, excret, false, ignore_stackfaults);
|
|
||||||
qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on new stackframe: "
|
qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on new stackframe: "
|
||||||
"failed exception return integrity check\n");
|
"failed exception return integrity check\n");
|
||||||
|
v7m_exception_taken(cpu, excret, false, ignore_stackfaults);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8461,26 +8472,24 @@ static void arm_log_exception(int idx)
|
||||||
if (qemu_loglevel_mask(CPU_LOG_INT)) {
|
if (qemu_loglevel_mask(CPU_LOG_INT)) {
|
||||||
const char *exc = NULL;
|
const char *exc = NULL;
|
||||||
static const char * const excnames[] = {
|
static const char * const excnames[] = {
|
||||||
NULL,
|
[EXCP_UDEF] = "Undefined Instruction",
|
||||||
"Undefined Instruction",
|
[EXCP_SWI] = "SVC",
|
||||||
"SVC",
|
[EXCP_PREFETCH_ABORT] = "Prefetch Abort",
|
||||||
"Prefetch Abort",
|
[EXCP_DATA_ABORT] = "Data Abort",
|
||||||
"Data Abort",
|
[EXCP_IRQ] = "IRQ",
|
||||||
"IRQ",
|
[EXCP_FIQ] = "FIQ",
|
||||||
"FIQ",
|
[EXCP_BKPT] = "Breakpoint",
|
||||||
"Breakpoint",
|
[EXCP_EXCEPTION_EXIT] = "QEMU v7M exception exit",
|
||||||
"QEMU v7M exception exit",
|
[EXCP_KERNEL_TRAP] = "QEMU intercept of kernel commpage",
|
||||||
"QEMU intercept of kernel commpage",
|
[EXCP_HVC] = "Hypervisor Call",
|
||||||
NULL,
|
[EXCP_HYP_TRAP] = "Hypervisor Trap",
|
||||||
"Hypervisor Call",
|
[EXCP_SMC] = "Secure Monitor Call",
|
||||||
"Hypervisor Trap",
|
[EXCP_VIRQ] = "Virtual IRQ",
|
||||||
"Secure Monitor Call",
|
[EXCP_VFIQ] = "Virtual FIQ",
|
||||||
"Virtual IRQ",
|
[EXCP_SEMIHOST] = "Semihosting call",
|
||||||
"Virtual FIQ",
|
[EXCP_NOCP] = "v7M NOCP UsageFault",
|
||||||
"Semihosting call",
|
[EXCP_INVSTATE] = "v7M INVSTATE UsageFault",
|
||||||
"v7M NOCP UsageFault",
|
[EXCP_STKOF] = "v8M STKOF UsageFault",
|
||||||
"v7M INVSTATE UsageFault",
|
|
||||||
"v8M STKOF UsageFault",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (idx >= 0 && idx < ARRAY_SIZE(excnames)) {
|
if (idx >= 0 && idx < ARRAY_SIZE(excnames)) {
|
||||||
|
@ -8629,15 +8638,15 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
|
||||||
handle it. */
|
handle it. */
|
||||||
switch (cs->exception_index) {
|
switch (cs->exception_index) {
|
||||||
case EXCP_UDEF:
|
case EXCP_UDEF:
|
||||||
//armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE);
|
//armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
|
||||||
env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_UNDEFINSTR_MASK;
|
env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_UNDEFINSTR_MASK;
|
||||||
break;
|
break;
|
||||||
case EXCP_NOCP:
|
case EXCP_NOCP:
|
||||||
//armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE);
|
//armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
|
||||||
env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_NOCP_MASK;
|
env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_NOCP_MASK;
|
||||||
break;
|
break;
|
||||||
case EXCP_INVSTATE:
|
case EXCP_INVSTATE:
|
||||||
//armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE);
|
//armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
|
||||||
env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVSTATE_MASK;
|
env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVSTATE_MASK;
|
||||||
break;
|
break;
|
||||||
case EXCP_STKOF:
|
case EXCP_STKOF:
|
||||||
|
@ -8646,7 +8655,7 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
|
||||||
break;
|
break;
|
||||||
case EXCP_SWI:
|
case EXCP_SWI:
|
||||||
/* The PC already points to the next instruction. */
|
/* The PC already points to the next instruction. */
|
||||||
//armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SVC);
|
//armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SVC, env->v7m.secure);
|
||||||
break;
|
break;
|
||||||
case EXCP_PREFETCH_ABORT:
|
case EXCP_PREFETCH_ABORT:
|
||||||
case EXCP_DATA_ABORT:
|
case EXCP_DATA_ABORT:
|
||||||
|
@ -8710,7 +8719,7 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Unicorn: commented out
|
// Unicorn: commented out
|
||||||
//armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_BUS);
|
//armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_BUS, false);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* All other FSR values are either MPU faults or "can't happen
|
/* All other FSR values are either MPU faults or "can't happen
|
||||||
|
@ -8731,7 +8740,8 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Unicorn: commented out
|
// Unicorn: commented out
|
||||||
//armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM);
|
//armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM,
|
||||||
|
// env->v7m.secure);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -8750,7 +8760,7 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
//armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_DEBUG);
|
//armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_DEBUG, false);
|
||||||
break;
|
break;
|
||||||
case EXCP_IRQ:
|
case EXCP_IRQ:
|
||||||
break;
|
break;
|
||||||
|
@ -8806,7 +8816,6 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
|
||||||
|
|
||||||
ignore_stackfaults = v7m_push_stack(cpu);
|
ignore_stackfaults = v7m_push_stack(cpu);
|
||||||
v7m_exception_taken(cpu, lr, false, ignore_stackfaults);
|
v7m_exception_taken(cpu, lr, false, ignore_stackfaults);
|
||||||
qemu_log_mask(CPU_LOG_INT, "... as %d\n", env->v7m.exception);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Function used to synchronize QEMU's AArch64 register set with AArch32
|
/* Function used to synchronize QEMU's AArch64 register set with AArch32
|
||||||
|
@ -10580,7 +10589,6 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address,
|
||||||
param = aa64_va_parameters(env, address, mmu_idx,
|
param = aa64_va_parameters(env, address, mmu_idx,
|
||||||
access_type != MMU_INST_FETCH);
|
access_type != MMU_INST_FETCH);
|
||||||
level = 0;
|
level = 0;
|
||||||
|
|
||||||
/* If we are in 64-bit EL2 or EL3 then there is no TTBR1, so mark it
|
/* If we are in 64-bit EL2 or EL3 then there is no TTBR1, so mark it
|
||||||
* invalid.
|
* invalid.
|
||||||
*/
|
*/
|
||||||
|
@ -12223,7 +12231,6 @@ void HELPER(dc_zva)(CPUARMState *env, uint64_t vaddr_in)
|
||||||
* 1K as an artefact of legacy v5 subpage support being present in the
|
* 1K as an artefact of legacy v5 subpage support being present in the
|
||||||
* same QEMU executable.
|
* same QEMU executable.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int maxidx = DIV_ROUND_UP(blocklen, TARGET_PAGE_SIZE);
|
int maxidx = DIV_ROUND_UP(blocklen, TARGET_PAGE_SIZE);
|
||||||
// msvc doesnt allow non-constant array sizes, so we work out the size it would be
|
// msvc doesnt allow non-constant array sizes, so we work out the size it would be
|
||||||
// TARGET_PAGE_SIZE is 1024
|
// TARGET_PAGE_SIZE is 1024
|
||||||
|
@ -12694,7 +12701,7 @@ ARMMMUIdx arm_stage1_mmu_idx(CPUARMState *env)
|
||||||
void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
|
void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
|
||||||
target_ulong *cs_base, uint32_t *pflags)
|
target_ulong *cs_base, uint32_t *pflags)
|
||||||
{
|
{
|
||||||
ARMMMUIdx mmu_idx = core_to_arm_mmu_idx(env, cpu_mmu_index(env, false));
|
ARMMMUIdx mmu_idx = arm_mmu_idx(env);
|
||||||
int current_el = arm_current_el(env);
|
int current_el = arm_current_el(env);
|
||||||
int fp_el = fp_exception_el(env, current_el);
|
int fp_el = fp_exception_el(env, current_el);
|
||||||
uint32_t flags = 0;
|
uint32_t flags = 0;
|
||||||
|
|
|
@ -92,15 +92,15 @@
|
||||||
|
|
||||||
# Two operand with unused vector element size
|
# Two operand with unused vector element size
|
||||||
@pd_pn_e0 ........ ........ ....... rn:4 . rd:4 &rr_esz esz=0
|
@pd_pn_e0 ........ ........ ....... rn:4 . rd:4 &rr_esz esz=0
|
||||||
|
|
||||||
|
# Two operand
|
||||||
|
@pd_pn ........ esz:2 .. .... ....... rn:4 . rd:4 &rr_esz
|
||||||
@rd_rn ........ esz:2 ...... ...... rn:5 rd:5 &rr_esz
|
@rd_rn ........ esz:2 ...... ...... rn:5 rd:5 &rr_esz
|
||||||
|
|
||||||
# Two operand with governing predicate, flags setting
|
# Two operand with governing predicate, flags setting
|
||||||
@pd_pg_pn_s ........ . s:1 ...... .. pg:4 . rn:4 . rd:4 &rpr_s
|
@pd_pg_pn_s ........ . s:1 ...... .. pg:4 . rn:4 . rd:4 &rpr_s
|
||||||
@pd_pg_pn_s0 ........ . . ...... .. pg:4 . rn:4 . rd:4 &rpr_s s=0
|
@pd_pg_pn_s0 ........ . . ...... .. pg:4 . rn:4 . rd:4 &rpr_s s=0
|
||||||
|
|
||||||
# Two operand
|
|
||||||
@pd_pn ........ esz:2 .. .... ....... rn:4 . rd:4 &rr_esz
|
|
||||||
|
|
||||||
# Three operand with unused vector element size
|
# Three operand with unused vector element size
|
||||||
@rd_rn_rm_e0 ........ ... rm:5 ... ... rn:5 rd:5 &rrr_esz esz=0
|
@rd_rn_rm_e0 ........ ... rm:5 ... ... rn:5 rd:5 &rrr_esz esz=0
|
||||||
|
|
||||||
|
@ -130,14 +130,6 @@
|
||||||
@rd_pg4_rn_rm ........ esz:2 . rm:5 .. pg:4 rn:5 rd:5 &rprr_esz
|
@rd_pg4_rn_rm ........ esz:2 . rm:5 .. pg:4 rn:5 rd:5 &rprr_esz
|
||||||
@pd_pg_rn_rm ........ esz:2 . rm:5 ... pg:3 rn:5 . rd:4 &rprr_esz
|
@pd_pg_rn_rm ........ esz:2 . rm:5 ... pg:3 rn:5 . rd:4 &rprr_esz
|
||||||
|
|
||||||
# One register operand, with governing predicate, vector element size
|
|
||||||
@rd_pg_rn ........ esz:2 ... ... ... pg:3 rn:5 rd:5 &rpr_esz
|
|
||||||
@rd_pg4_pn ........ esz:2 ... ... .. pg:4 . rn:4 rd:5 &rpr_esz
|
|
||||||
@pd_pg_rn ........ esz:2 ... ... ... pg:3 rn:5 . rd:4 &rpr_esz
|
|
||||||
|
|
||||||
# One register operand, with governing predicate, no vector element size
|
|
||||||
@rd_pg_rn_e0 ........ .. ... ... ... pg:3 rn:5 rd:5 &rpr_esz esz=0
|
|
||||||
|
|
||||||
# Three register operand, with governing predicate, vector element size
|
# Three register operand, with governing predicate, vector element size
|
||||||
@rda_pg_rn_rm ........ esz:2 . rm:5 ... pg:3 rn:5 rd:5 \
|
@rda_pg_rn_rm ........ esz:2 . rm:5 ... pg:3 rn:5 rd:5 \
|
||||||
&rprrr_esz ra=%reg_movprfx
|
&rprrr_esz ra=%reg_movprfx
|
||||||
|
@ -146,6 +138,14 @@
|
||||||
@rdn_pg_rm_ra ........ esz:2 . ra:5 ... pg:3 rm:5 rd:5 \
|
@rdn_pg_rm_ra ........ esz:2 . ra:5 ... pg:3 rm:5 rd:5 \
|
||||||
&rprrr_esz rn=%reg_movprfx
|
&rprrr_esz rn=%reg_movprfx
|
||||||
|
|
||||||
|
# One register operand, with governing predicate, vector element size
|
||||||
|
@rd_pg_rn ........ esz:2 ... ... ... pg:3 rn:5 rd:5 &rpr_esz
|
||||||
|
@rd_pg4_pn ........ esz:2 ... ... .. pg:4 . rn:4 rd:5 &rpr_esz
|
||||||
|
@pd_pg_rn ........ esz:2 ... ... ... pg:3 rn:5 . rd:4 &rpr_esz
|
||||||
|
|
||||||
|
# One register operand, with governing predicate, no vector element size
|
||||||
|
@rd_pg_rn_e0 ........ .. ... ... ... pg:3 rn:5 rd:5 &rpr_esz esz=0
|
||||||
|
|
||||||
# Two register operands with a 6-bit signed immediate.
|
# Two register operands with a 6-bit signed immediate.
|
||||||
@rd_rn_i6 ........ ... rn:5 ..... imm:s6 rd:5 &rri
|
@rd_rn_i6 ........ ... rn:5 ..... imm:s6 rd:5 &rri
|
||||||
|
|
||||||
|
@ -346,16 +346,6 @@ FCMUO_ppzz 01100101 .. 0 ..... 110 ... ..... 0 .... @pd_pg_rn_rm
|
||||||
FACGE_ppzz 01100101 .. 0 ..... 110 ... ..... 1 .... @pd_pg_rn_rm
|
FACGE_ppzz 01100101 .. 0 ..... 110 ... ..... 1 .... @pd_pg_rn_rm
|
||||||
FACGT_ppzz 01100101 .. 0 ..... 111 ... ..... 1 .... @pd_pg_rn_rm
|
FACGT_ppzz 01100101 .. 0 ..... 111 ... ..... 1 .... @pd_pg_rn_rm
|
||||||
|
|
||||||
# SVE floating-point arithmetic with immediate (predicated)
|
|
||||||
FADD_zpzi 01100101 .. 011 000 100 ... 0000 . ..... @rdn_i1
|
|
||||||
FSUB_zpzi 01100101 .. 011 001 100 ... 0000 . ..... @rdn_i1
|
|
||||||
FMUL_zpzi 01100101 .. 011 010 100 ... 0000 . ..... @rdn_i1
|
|
||||||
FSUBR_zpzi 01100101 .. 011 011 100 ... 0000 . ..... @rdn_i1
|
|
||||||
FMAXNM_zpzi 01100101 .. 011 100 100 ... 0000 . ..... @rdn_i1
|
|
||||||
FMINNM_zpzi 01100101 .. 011 101 100 ... 0000 . ..... @rdn_i1
|
|
||||||
FMAX_zpzi 01100101 .. 011 110 100 ... 0000 . ..... @rdn_i1
|
|
||||||
FMIN_zpzi 01100101 .. 011 111 100 ... 0000 . ..... @rdn_i1
|
|
||||||
|
|
||||||
### SVE Integer Multiply-Add Group
|
### SVE Integer Multiply-Add Group
|
||||||
|
|
||||||
# SVE integer multiply-add writing addend (predicated)
|
# SVE integer multiply-add writing addend (predicated)
|
||||||
|
@ -831,6 +821,16 @@ FMULX 01100101 .. 00 1010 100 ... ..... ..... @rdn_pg_rm
|
||||||
FDIV 01100101 .. 00 1100 100 ... ..... ..... @rdm_pg_rn # FDIVR
|
FDIV 01100101 .. 00 1100 100 ... ..... ..... @rdm_pg_rn # FDIVR
|
||||||
FDIV 01100101 .. 00 1101 100 ... ..... ..... @rdn_pg_rm
|
FDIV 01100101 .. 00 1101 100 ... ..... ..... @rdn_pg_rm
|
||||||
|
|
||||||
|
# SVE floating-point arithmetic with immediate (predicated)
|
||||||
|
FADD_zpzi 01100101 .. 011 000 100 ... 0000 . ..... @rdn_i1
|
||||||
|
FSUB_zpzi 01100101 .. 011 001 100 ... 0000 . ..... @rdn_i1
|
||||||
|
FMUL_zpzi 01100101 .. 011 010 100 ... 0000 . ..... @rdn_i1
|
||||||
|
FSUBR_zpzi 01100101 .. 011 011 100 ... 0000 . ..... @rdn_i1
|
||||||
|
FMAXNM_zpzi 01100101 .. 011 100 100 ... 0000 . ..... @rdn_i1
|
||||||
|
FMINNM_zpzi 01100101 .. 011 101 100 ... 0000 . ..... @rdn_i1
|
||||||
|
FMAX_zpzi 01100101 .. 011 110 100 ... 0000 . ..... @rdn_i1
|
||||||
|
FMIN_zpzi 01100101 .. 011 111 100 ... 0000 . ..... @rdn_i1
|
||||||
|
|
||||||
# SVE floating-point trig multiply-add coefficient
|
# SVE floating-point trig multiply-add coefficient
|
||||||
FTMAD 01100101 esz:2 010 imm:3 100000 rm:5 rd:5 rn=%reg_movprfx
|
FTMAD 01100101 esz:2 010 imm:3 100000 rm:5 rd:5 rn=%reg_movprfx
|
||||||
|
|
||||||
|
@ -1017,17 +1017,17 @@ PRF 1100010 -- 00 ----- 111 --- ----- 0 ----
|
||||||
|
|
||||||
### SVE Memory Store Group
|
### SVE Memory Store Group
|
||||||
|
|
||||||
# SVE contiguous store (scalar plus immediate)
|
|
||||||
# ST1B, ST1H, ST1W, ST1D; require msz <= esz
|
|
||||||
ST_zpri 1110010 .. esz:2 0.... 111 ... ..... ..... \
|
|
||||||
@rpri_store_msz nreg=0
|
|
||||||
|
|
||||||
# SVE store predicate register
|
# SVE store predicate register
|
||||||
STR_pri 1110010 11 0. ..... 000 ... ..... 0 .... @pd_rn_i9
|
STR_pri 1110010 11 0. ..... 000 ... ..... 0 .... @pd_rn_i9
|
||||||
|
|
||||||
# SVE store vector register
|
# SVE store vector register
|
||||||
STR_zri 1110010 11 0. ..... 010 ... ..... ..... @rd_rn_i9
|
STR_zri 1110010 11 0. ..... 010 ... ..... ..... @rd_rn_i9
|
||||||
|
|
||||||
|
# SVE contiguous store (scalar plus immediate)
|
||||||
|
# ST1B, ST1H, ST1W, ST1D; require msz <= esz
|
||||||
|
ST_zpri 1110010 .. esz:2 0.... 111 ... ..... ..... \
|
||||||
|
@rpri_store_msz nreg=0
|
||||||
|
|
||||||
# SVE contiguous store (scalar plus scalar)
|
# SVE contiguous store (scalar plus scalar)
|
||||||
# ST1B, ST1H, ST1W, ST1D; require msz <= esz
|
# ST1B, ST1H, ST1W, ST1D; require msz <= esz
|
||||||
# Enumerate msz lest we conflict with STR_zri.
|
# Enumerate msz lest we conflict with STR_zri.
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -36,11 +36,6 @@
|
||||||
|
|
||||||
#include "translate-a64.h"
|
#include "translate-a64.h"
|
||||||
|
|
||||||
#ifdef CONFIG_USER_ONLY
|
|
||||||
static TCGv_i64 cpu_exclusive_test;
|
|
||||||
static TCGv_i32 cpu_exclusive_info;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
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",
|
||||||
|
@ -109,12 +104,6 @@ void a64_translate_init(struct uc_struct *uc)
|
||||||
offsetof(CPUARMState, exclusive_val), "exclusive_val");
|
offsetof(CPUARMState, exclusive_val), "exclusive_val");
|
||||||
tcg_ctx->cpu_exclusive_high = tcg_global_mem_new_i64(uc->tcg_ctx, tcg_ctx->cpu_env,
|
tcg_ctx->cpu_exclusive_high = tcg_global_mem_new_i64(uc->tcg_ctx, tcg_ctx->cpu_env,
|
||||||
offsetof(CPUARMState, exclusive_high), "exclusive_high");
|
offsetof(CPUARMState, exclusive_high), "exclusive_high");
|
||||||
#ifdef CONFIG_USER_ONLY
|
|
||||||
cpu_exclusive_test = tcg_global_mem_new_i64(uc->tcg_ctx, tcg_ctx->cpu_env,
|
|
||||||
offsetof(CPUARMState, exclusive_test), "exclusive_test");
|
|
||||||
cpu_exclusive_info = tcg_global_mem_new_i32(uc->tcg_ctx, tcg_ctx->cpu_env,
|
|
||||||
offsetof(CPUARMState, exclusive_info), "exclusive_info");
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int get_a64_user_mem_index(DisasContext *s)
|
static inline int get_a64_user_mem_index(DisasContext *s)
|
||||||
|
@ -176,14 +165,13 @@ void aarch64_cpu_dump_state(CPUState *cs, FILE *f,
|
||||||
int el = arm_current_el(env);
|
int el = arm_current_el(env);
|
||||||
const char *ns_status;
|
const char *ns_status;
|
||||||
|
|
||||||
cpu_fprintf(f, "PC=%016"PRIx64" SP=%016"PRIx64"\n",
|
cpu_fprintf(f, " PC=%016" PRIx64 " ", env->pc);
|
||||||
env->pc, env->xregs[31]);
|
for (i = 0; i < 32; i++) {
|
||||||
for (i = 0; i < 31; i++) {
|
if (i == 31) {
|
||||||
cpu_fprintf(f, "X%02d=%016"PRIx64, i, env->xregs[i]);
|
cpu_fprintf(f, " SP=%016" PRIx64 "\n", env->xregs[i]);
|
||||||
if ((i % 4) == 3) {
|
|
||||||
cpu_fprintf(f, "\n");
|
|
||||||
} else {
|
} else {
|
||||||
cpu_fprintf(f, " ");
|
cpu_fprintf(f, "X%02d=%016" PRIx64 "%s", i, env->xregs[i],
|
||||||
|
(i + 2) % 3 ? " " : "\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,7 +180,6 @@ void aarch64_cpu_dump_state(CPUState *cs, FILE *f,
|
||||||
} else {
|
} else {
|
||||||
ns_status = "";
|
ns_status = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu_fprintf(f, "PSTATE=%08x %c%c%c%c %sEL%d%c",
|
cpu_fprintf(f, "PSTATE=%08x %c%c%c%c %sEL%d%c",
|
||||||
psr,
|
psr,
|
||||||
psr & PSTATE_N ? 'N' : '-',
|
psr & PSTATE_N ? 'N' : '-',
|
||||||
|
@ -202,6 +189,7 @@ void aarch64_cpu_dump_state(CPUState *cs, FILE *f,
|
||||||
ns_status,
|
ns_status,
|
||||||
el,
|
el,
|
||||||
psr & PSTATE_SP ? 'h' : 't');
|
psr & PSTATE_SP ? 'h' : 't');
|
||||||
|
|
||||||
if (cpu_isar_feature(aa64_bti, cpu)) {
|
if (cpu_isar_feature(aa64_bti, cpu)) {
|
||||||
cpu_fprintf(f, " BTYPE=%d", (psr & PSTATE_BTYPE) >> 10);
|
cpu_fprintf(f, " BTYPE=%d", (psr & PSTATE_BTYPE) >> 10);
|
||||||
}
|
}
|
||||||
|
@ -10333,7 +10321,6 @@ static void handle_vec_simd_shri(DisasContext *s, bool is_q, bool is_u,
|
||||||
unallocated_encoding(s);
|
unallocated_encoding(s);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tcg_debug_assert(size <= 3);
|
tcg_debug_assert(size <= 3);
|
||||||
|
|
||||||
if (!fp_access_check(s)) {
|
if (!fp_access_check(s)) {
|
||||||
|
@ -13198,6 +13185,17 @@ static void disas_simd_indexed(DisasContext *s, uint32_t insn)
|
||||||
}
|
}
|
||||||
is_fp = 2;
|
is_fp = 2;
|
||||||
break;
|
break;
|
||||||
|
case 0x00: /* FMLAL */
|
||||||
|
case 0x04: /* FMLSL */
|
||||||
|
case 0x18: /* FMLAL2 */
|
||||||
|
case 0x1c: /* FMLSL2 */
|
||||||
|
if (is_scalar || size != MO_32 || !dc_isar_feature(aa64_fhm, s)) {
|
||||||
|
unallocated_encoding(s);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
size = MO_16;
|
||||||
|
/* is_fp, but we pass cpu_env not fp_status. */
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
unallocated_encoding(s);
|
unallocated_encoding(s);
|
||||||
return;
|
return;
|
||||||
|
@ -13308,6 +13306,22 @@ static void disas_simd_indexed(DisasContext *s, uint32_t insn)
|
||||||
tcg_temp_free_ptr(tcg_ctx, fpst);
|
tcg_temp_free_ptr(tcg_ctx, fpst);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
case 0x00: /* FMLAL */
|
||||||
|
case 0x04: /* FMLSL */
|
||||||
|
case 0x18: /* FMLAL2 */
|
||||||
|
case 0x1c: /* FMLSL2 */
|
||||||
|
{
|
||||||
|
int is_s = extract32(opcode, 2, 1);
|
||||||
|
int is_2 = u;
|
||||||
|
int data = (index << 2) | (is_2 << 1) | is_s;
|
||||||
|
tcg_gen_gvec_3_ptr(tcg_ctx, vec_full_reg_offset(s, rd),
|
||||||
|
vec_full_reg_offset(s, rn),
|
||||||
|
vec_full_reg_offset(s, rm), tcg_ctx->cpu_env,
|
||||||
|
is_q ? 16 : 8, vec_full_reg_size(s),
|
||||||
|
data, gen_helper_gvec_fmlal_idx_a64);
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size == 3) {
|
if (size == 3) {
|
||||||
|
@ -14730,11 +14744,11 @@ static void aarch64_tr_disas_log(const DisasContextBase *dcbase,
|
||||||
}
|
}
|
||||||
|
|
||||||
const TranslatorOps aarch64_translator_ops = {
|
const TranslatorOps aarch64_translator_ops = {
|
||||||
aarch64_tr_init_disas_context,
|
.init_disas_context = aarch64_tr_init_disas_context,
|
||||||
aarch64_tr_tb_start,
|
.tb_start = aarch64_tr_tb_start,
|
||||||
aarch64_tr_insn_start,
|
.insn_start = aarch64_tr_insn_start,
|
||||||
aarch64_tr_breakpoint_check,
|
.breakpoint_check = aarch64_tr_breakpoint_check,
|
||||||
aarch64_tr_translate_insn,
|
.translate_insn = aarch64_tr_translate_insn,
|
||||||
aarch64_tr_tb_stop,
|
.tb_stop = aarch64_tr_tb_stop,
|
||||||
aarch64_tr_disas_log,
|
.disas_log = aarch64_tr_disas_log,
|
||||||
};
|
};
|
||||||
|
|
|
@ -4858,6 +4858,11 @@ static void gen_exception_return(DisasContext *s, TCGv_i32 pc)
|
||||||
static void gen_nop_hint(DisasContext *s, int val)
|
static void gen_nop_hint(DisasContext *s, int val)
|
||||||
{
|
{
|
||||||
switch (val) {
|
switch (val) {
|
||||||
|
/* When running in MTTCG we don't generate jumps to the yield and
|
||||||
|
* WFE helpers as it won't affect the scheduling of other vCPUs.
|
||||||
|
* If we wanted to more completely model WFE/SEV so we don't busy
|
||||||
|
* spin unnecessarily we would need to do something more involved.
|
||||||
|
*/
|
||||||
case 1: /* yield */
|
case 1: /* yield */
|
||||||
if (!s->uc->parallel_cpus) {
|
if (!s->uc->parallel_cpus) {
|
||||||
gen_set_pc_im(s, s->pc);
|
gen_set_pc_im(s, s->pc);
|
||||||
|
@ -5306,6 +5311,7 @@ static int disas_neon_ls_insn(DisasContext *s, uint32_t insn)
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
reg_idx = (insn >> 7) & 1;
|
reg_idx = (insn >> 7) & 1;
|
||||||
|
stride = (insn & (1 << 6)) ? 2 : 1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
abort();
|
abort();
|
||||||
|
@ -5599,7 +5605,7 @@ static void gen_neon_narrow_op(DisasContext *s, int op, int u, int size,
|
||||||
#define NEON_3R_VABA 15
|
#define NEON_3R_VABA 15
|
||||||
#define NEON_3R_VADD_VSUB 16
|
#define NEON_3R_VADD_VSUB 16
|
||||||
#define NEON_3R_VTST_VCEQ 17
|
#define NEON_3R_VTST_VCEQ 17
|
||||||
#define NEON_3R_VML 18 /* VMLA, VMLAL, VMLS, VMLSL */
|
#define NEON_3R_VML 18 /* VMLA, VMLS */
|
||||||
#define NEON_3R_VMUL 19
|
#define NEON_3R_VMUL 19
|
||||||
#define NEON_3R_VPMAX 20
|
#define NEON_3R_VPMAX 20
|
||||||
#define NEON_3R_VPMIN 21
|
#define NEON_3R_VPMIN 21
|
||||||
|
@ -5615,38 +5621,38 @@ static void gen_neon_narrow_op(DisasContext *s, int op, int u, int size,
|
||||||
#define NEON_3R_FLOAT_MISC 31 /* float VRECPS, VRSQRTS, VMAXNM/MINNM */
|
#define NEON_3R_FLOAT_MISC 31 /* float VRECPS, VRSQRTS, VMAXNM/MINNM */
|
||||||
|
|
||||||
static const uint8_t neon_3r_sizes[] = {
|
static const uint8_t neon_3r_sizes[] = {
|
||||||
/*NEON_3R_VHADD*/ 0x7,
|
[NEON_3R_VHADD] = 0x7,
|
||||||
/*NEON_3R_VQADD*/ 0xf,
|
[NEON_3R_VQADD] = 0xf,
|
||||||
/*NEON_3R_VRHADD*/ 0x7,
|
[NEON_3R_VRHADD] = 0x7,
|
||||||
/*NEON_3R_LOGIC*/ 0xf, /* size field encodes op type */
|
[NEON_3R_LOGIC] = 0xf, /* size field encodes op type */
|
||||||
/*NEON_3R_VHSUB*/ 0x7,
|
[NEON_3R_VHSUB] = 0x7,
|
||||||
/*NEON_3R_VQSUB*/ 0xf,
|
[NEON_3R_VQSUB] = 0xf,
|
||||||
/*NEON_3R_VCGT*/ 0x7,
|
[NEON_3R_VCGT] = 0x7,
|
||||||
/*NEON_3R_VCGE*/ 0x7,
|
[NEON_3R_VCGE] = 0x7,
|
||||||
/*NEON_3R_VSHL*/ 0xf,
|
[NEON_3R_VSHL] = 0xf,
|
||||||
/*NEON_3R_VQSHL*/ 0xf,
|
[NEON_3R_VQSHL] = 0xf,
|
||||||
/*NEON_3R_VRSHL*/ 0xf,
|
[NEON_3R_VRSHL] = 0xf,
|
||||||
/*NEON_3R_VQRSHL*/ 0xf,
|
[NEON_3R_VQRSHL] = 0xf,
|
||||||
/*NEON_3R_VMAX*/ 0x7,
|
[NEON_3R_VMAX] = 0x7,
|
||||||
/*NEON_3R_VMIN*/ 0x7,
|
[NEON_3R_VMIN] = 0x7,
|
||||||
/*NEON_3R_VABD*/ 0x7,
|
[NEON_3R_VABD] = 0x7,
|
||||||
/*NEON_3R_VABA*/ 0x7,
|
[NEON_3R_VABA] = 0x7,
|
||||||
/*NEON_3R_VADD_VSUB*/ 0xf,
|
[NEON_3R_VADD_VSUB] = 0xf,
|
||||||
/*NEON_3R_VTST_VCEQ*/ 0x7,
|
[NEON_3R_VTST_VCEQ] = 0x7,
|
||||||
/*NEON_3R_VML*/ 0x7,
|
[NEON_3R_VML] = 0x7,
|
||||||
/*NEON_3R_VMUL*/ 0x7,
|
[NEON_3R_VMUL] = 0x7,
|
||||||
/*NEON_3R_VPMAX*/ 0x7,
|
[NEON_3R_VPMAX] = 0x7,
|
||||||
/*NEON_3R_VPMIN*/ 0x7,
|
[NEON_3R_VPMIN] = 0x7,
|
||||||
/*NEON_3R_VQDMULH_VQRDMULH*/ 0x6,
|
[NEON_3R_VQDMULH_VQRDMULH] = 0x6,
|
||||||
/*NEON_3R_VPADD_VQRDMLAH*/ 0x7,
|
[NEON_3R_VPADD_VQRDMLAH] = 0x7,
|
||||||
/*NEON_3R_SHA*/ 0xf, /* size field encodes op type */
|
[NEON_3R_SHA] = 0xf, /* size field encodes op type */
|
||||||
/*NEON_3R_VFM_VQRDMLSH*/ 0x7, /* For VFM, size bit 1 encodes op */
|
[NEON_3R_VFM_VQRDMLSH] = 0x7, /* For VFM, size bit 1 encodes op */
|
||||||
/*NEON_3R_FLOAT_ARITH*/ 0x5, /* size bit 1 encodes op */
|
[NEON_3R_FLOAT_ARITH] = 0x5, /* size bit 1 encodes op */
|
||||||
/*NEON_3R_FLOAT_MULTIPLY*/ 0x5, /* size bit 1 encodes op */
|
[NEON_3R_FLOAT_MULTIPLY] = 0x5, /* size bit 1 encodes op */
|
||||||
/*NEON_3R_FLOAT_CMP*/ 0x5, /* size bit 1 encodes op */
|
[NEON_3R_FLOAT_CMP] = 0x5, /* size bit 1 encodes op */
|
||||||
/*NEON_3R_FLOAT_ACMP*/ 0x5, /* size bit 1 encodes op */
|
[NEON_3R_FLOAT_ACMP] = 0x5, /* size bit 1 encodes op */
|
||||||
/*NEON_3R_FLOAT_MINMAX*/ 0x5, /* size bit 1 encodes op */
|
[NEON_3R_FLOAT_MINMAX] = 0x5, /* size bit 1 encodes op */
|
||||||
/*NEON_3R_FLOAT_MISC*/ 0x5, /* size bit 1 encodes op */
|
[NEON_3R_FLOAT_MISC] = 0x5, /* size bit 1 encodes op */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Symbolic constants for op fields for Neon 2-register miscellaneous.
|
/* Symbolic constants for op fields for Neon 2-register miscellaneous.
|
||||||
|
@ -5755,70 +5761,68 @@ static bool neon_2rm_is_v8_op(int op)
|
||||||
* op values will have no bits set they always UNDEF.
|
* op values will have no bits set they always UNDEF.
|
||||||
*/
|
*/
|
||||||
static const uint8_t neon_2rm_sizes[] = {
|
static const uint8_t neon_2rm_sizes[] = {
|
||||||
/*NEON_2RM_VREV64*/ 0x7,
|
[NEON_2RM_VREV64] = 0x7,
|
||||||
/*NEON_2RM_VREV32*/ 0x3,
|
[NEON_2RM_VREV32] = 0x3,
|
||||||
/*NEON_2RM_VREV16*/ 0x1,
|
[NEON_2RM_VREV16] = 0x1,
|
||||||
0,
|
[NEON_2RM_VPADDL] = 0x7,
|
||||||
/*NEON_2RM_VPADDL*/ 0x7,
|
[NEON_2RM_VPADDL_U] = 0x7,
|
||||||
/*NEON_2RM_VPADDL_U*/ 0x7,
|
[NEON_2RM_AESE] = 0x1,
|
||||||
/*NEON_2RM_AESE*/ 0x1,
|
[NEON_2RM_AESMC] = 0x1,
|
||||||
/*NEON_2RM_AESMC*/ 0x1,
|
[NEON_2RM_VCLS] = 0x7,
|
||||||
/*NEON_2RM_VCLS*/ 0x7,
|
[NEON_2RM_VCLZ] = 0x7,
|
||||||
/*NEON_2RM_VCLZ*/ 0x7,
|
[NEON_2RM_VCNT] = 0x1,
|
||||||
/*NEON_2RM_VCNT*/ 0x1,
|
[NEON_2RM_VMVN] = 0x1,
|
||||||
/*NEON_2RM_VMVN*/ 0x1,
|
[NEON_2RM_VPADAL] = 0x7,
|
||||||
/*NEON_2RM_VPADAL*/ 0x7,
|
[NEON_2RM_VPADAL_U] = 0x7,
|
||||||
/*NEON_2RM_VPADAL_U*/ 0x7,
|
[NEON_2RM_VQABS] = 0x7,
|
||||||
/*NEON_2RM_VQABS*/ 0x7,
|
[NEON_2RM_VQNEG] = 0x7,
|
||||||
/*NEON_2RM_VQNEG*/ 0x7,
|
[NEON_2RM_VCGT0] = 0x7,
|
||||||
/*NEON_2RM_VCGT0*/ 0x7,
|
[NEON_2RM_VCGE0] = 0x7,
|
||||||
/*NEON_2RM_VCGE0*/ 0x7,
|
[NEON_2RM_VCEQ0] = 0x7,
|
||||||
/*NEON_2RM_VCEQ0*/ 0x7,
|
[NEON_2RM_VCLE0] = 0x7,
|
||||||
/*NEON_2RM_VCLE0*/ 0x7,
|
[NEON_2RM_VCLT0] = 0x7,
|
||||||
/*NEON_2RM_VCLT0*/ 0x7,
|
[NEON_2RM_SHA1H] = 0x4,
|
||||||
/*NEON_2RM_SHA1H*/ 0x4,
|
[NEON_2RM_VABS] = 0x7,
|
||||||
/*NEON_2RM_VABS*/ 0x7,
|
[NEON_2RM_VNEG] = 0x7,
|
||||||
/*NEON_2RM_VNEG*/ 0x7,
|
[NEON_2RM_VCGT0_F] = 0x4,
|
||||||
/*NEON_2RM_VCGT0_F*/ 0x4,
|
[NEON_2RM_VCGE0_F] = 0x4,
|
||||||
/*NEON_2RM_VCGE0_F*/ 0x4,
|
[NEON_2RM_VCEQ0_F] = 0x4,
|
||||||
/*NEON_2RM_VCEQ0_F*/ 0x4,
|
[NEON_2RM_VCLE0_F] = 0x4,
|
||||||
/*NEON_2RM_VCLE0_F*/ 0x4,
|
[NEON_2RM_VCLT0_F] = 0x4,
|
||||||
/*NEON_2RM_VCLT0_F*/ 0x4,
|
[NEON_2RM_VABS_F] = 0x4,
|
||||||
0,
|
[NEON_2RM_VNEG_F] = 0x4,
|
||||||
/*NEON_2RM_VABS_F*/ 0x4,
|
[NEON_2RM_VSWP] = 0x1,
|
||||||
/*NEON_2RM_VNEG_F*/ 0x4,
|
[NEON_2RM_VTRN] = 0x7,
|
||||||
/*NEON_2RM_VSWP*/ 0x1,
|
[NEON_2RM_VUZP] = 0x7,
|
||||||
/*NEON_2RM_VTRN*/ 0x7,
|
[NEON_2RM_VZIP] = 0x7,
|
||||||
/*NEON_2RM_VUZP*/ 0x7,
|
[NEON_2RM_VMOVN] = 0x7,
|
||||||
/*NEON_2RM_VZIP*/ 0x7,
|
[NEON_2RM_VQMOVN] = 0x7,
|
||||||
/*NEON_2RM_VMOVN*/ 0x7,
|
[NEON_2RM_VSHLL] = 0x7,
|
||||||
/*NEON_2RM_VQMOVN*/ 0x7,
|
[NEON_2RM_SHA1SU1] = 0x4,
|
||||||
/*NEON_2RM_VSHLL*/ 0x7,
|
[NEON_2RM_VRINTN] = 0x4,
|
||||||
/*NEON_2RM_SHA1SU1*/ 0x4,
|
[NEON_2RM_VRINTX] = 0x4,
|
||||||
/*NEON_2RM_VRINTN*/ 0x4,
|
[NEON_2RM_VRINTA] = 0x4,
|
||||||
/*NEON_2RM_VRINTX*/ 0x4,
|
[NEON_2RM_VRINTZ] = 0x4,
|
||||||
/*NEON_2RM_VRINTA*/ 0x4,
|
[NEON_2RM_VCVT_F16_F32] = 0x2,
|
||||||
/*NEON_2RM_VRINTZ*/ 0x4,
|
[NEON_2RM_VRINTM] = 0x4,
|
||||||
/*NEON_2RM_VCVT_F16_F32*/ 0x2,
|
[NEON_2RM_VCVT_F32_F16] = 0x2,
|
||||||
/*NEON_2RM_VRINTM*/ 0x4,
|
[NEON_2RM_VRINTP] = 0x4,
|
||||||
/*NEON_2RM_VCVT_F32_F16*/ 0x2,
|
[NEON_2RM_VCVTAU] = 0x4,
|
||||||
/*NEON_2RM_VRINTP*/ 0x4,
|
[NEON_2RM_VCVTAS] = 0x4,
|
||||||
/*NEON_2RM_VCVTAU*/ 0x4,
|
[NEON_2RM_VCVTNU] = 0x4,
|
||||||
/*NEON_2RM_VCVTAS*/ 0x4,
|
[NEON_2RM_VCVTNS] = 0x4,
|
||||||
/*NEON_2RM_VCVTNU*/ 0x4,
|
[NEON_2RM_VCVTPU] = 0x4,
|
||||||
/*NEON_2RM_VCVTNS*/ 0x4,
|
[NEON_2RM_VCVTPS] = 0x4,
|
||||||
/*NEON_2RM_VCVTPU*/ 0x4,
|
[NEON_2RM_VCVTMU] = 0x4,
|
||||||
/*NEON_2RM_VCVTPS*/ 0x4,
|
[NEON_2RM_VCVTMS] = 0x4,
|
||||||
/*NEON_2RM_VCVTMU*/ 0x4,
|
[NEON_2RM_VRECPE] = 0x4,
|
||||||
/*NEON_2RM_VCVTMS*/ 0x4,
|
[NEON_2RM_VRSQRTE] = 0x4,
|
||||||
/*NEON_2RM_VRECPE*/ 0x4,
|
[NEON_2RM_VRECPE_F] = 0x4,
|
||||||
/*NEON_2RM_VRSQRTE*/ 0x4,
|
[NEON_2RM_VRSQRTE_F] = 0x4,
|
||||||
/*NEON_2RM_VRECPE_F*/ 0x4,
|
[NEON_2RM_VCVT_FS] = 0x4,
|
||||||
/*NEON_2RM_VRSQRTE_F*/ 0x4,
|
[NEON_2RM_VCVT_FU] = 0x4,
|
||||||
/*NEON_2RM_VCVT_FS*/ 0x4,
|
[NEON_2RM_VCVT_SF] = 0x4,
|
||||||
/*NEON_2RM_VCVT_FU*/ 0x4,
|
[NEON_2RM_VCVT_UF] = 0x4,
|
||||||
/*NEON_2RM_VCVT_SF*/ 0x4,
|
|
||||||
/*NEON_2RM_VCVT_UF*/ 0x4,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -6140,27 +6144,24 @@ static void gen_shl_ins_vec(TCGContext *s, unsigned vece, TCGv_vec d, TCGv_vec a
|
||||||
const GVecGen2i sli_op[4] = {
|
const GVecGen2i sli_op[4] = {
|
||||||
{ .fni8 = gen_shl8_ins_i64,
|
{ .fni8 = gen_shl8_ins_i64,
|
||||||
.fniv = gen_shl_ins_vec,
|
.fniv = gen_shl_ins_vec,
|
||||||
.opc = INDEX_op_shli_vec,
|
|
||||||
.prefer_i64 = TCG_TARGET_REG_BITS == 64,
|
|
||||||
.load_dest = true,
|
.load_dest = true,
|
||||||
|
.opc = INDEX_op_shli_vec,
|
||||||
.vece = MO_8 },
|
.vece = MO_8 },
|
||||||
{ .fni8 = gen_shl16_ins_i64,
|
{ .fni8 = gen_shl16_ins_i64,
|
||||||
.fniv = gen_shl_ins_vec,
|
.fniv = gen_shl_ins_vec,
|
||||||
.opc = INDEX_op_shli_vec,
|
|
||||||
.prefer_i64 = TCG_TARGET_REG_BITS == 64,
|
|
||||||
.load_dest = true,
|
.load_dest = true,
|
||||||
|
.opc = INDEX_op_shli_vec,
|
||||||
.vece = MO_16 },
|
.vece = MO_16 },
|
||||||
{ .fni4 = gen_shl32_ins_i32,
|
{ .fni4 = gen_shl32_ins_i32,
|
||||||
.fniv = gen_shl_ins_vec,
|
.fniv = gen_shl_ins_vec,
|
||||||
.opc = INDEX_op_shli_vec,
|
|
||||||
.prefer_i64 = TCG_TARGET_REG_BITS == 64,
|
|
||||||
.load_dest = true,
|
.load_dest = true,
|
||||||
|
.opc = INDEX_op_shli_vec,
|
||||||
.vece = MO_32 },
|
.vece = MO_32 },
|
||||||
{ .fni8 = gen_shl64_ins_i64,
|
{ .fni8 = gen_shl64_ins_i64,
|
||||||
.fniv = gen_shl_ins_vec,
|
.fniv = gen_shl_ins_vec,
|
||||||
.opc = INDEX_op_shli_vec,
|
|
||||||
.prefer_i64 = TCG_TARGET_REG_BITS == 64,
|
.prefer_i64 = TCG_TARGET_REG_BITS == 64,
|
||||||
.load_dest = true,
|
.load_dest = true,
|
||||||
|
.opc = INDEX_op_shli_vec,
|
||||||
.vece = MO_64 },
|
.vece = MO_64 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -7436,6 +7437,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
|
||||||
for (pass = 0; pass <= q; ++pass) {
|
for (pass = 0; pass <= q; ++pass) {
|
||||||
uint64_t val = 0;
|
uint64_t val = 0;
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
for (n = 0; n < 8; n++) {
|
for (n = 0; n < 8; n++) {
|
||||||
if (imm & (1 << (n + pass * 8))) {
|
if (imm & (1 << (n + pass * 8))) {
|
||||||
val |= 0xffull << (n * 8);
|
val |= 0xffull << (n * 8);
|
||||||
|
@ -8068,7 +8070,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
|
||||||
{
|
{
|
||||||
TCGv_ptr fpst;
|
TCGv_ptr fpst;
|
||||||
TCGv_i32 ahp;
|
TCGv_i32 ahp;
|
||||||
|
|
||||||
if (!dc_isar_feature(aa32_fp16_spconv, s) ||
|
if (!dc_isar_feature(aa32_fp16_spconv, s) ||
|
||||||
q || (rd & 1)) {
|
q || (rd & 1)) {
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -1072,6 +1072,7 @@ int arm_rmode_to_sf(int rmode)
|
||||||
/* FIXME: add support for TIEAWAY and ODD */
|
/* FIXME: add support for TIEAWAY and ODD */
|
||||||
qemu_log_mask(LOG_UNIMP, "arm: unimplemented rounding mode: %d\n",
|
qemu_log_mask(LOG_UNIMP, "arm: unimplemented rounding mode: %d\n",
|
||||||
rmode);
|
rmode);
|
||||||
|
/* fall through for now */
|
||||||
case FPROUNDING_TIEEVEN:
|
case FPROUNDING_TIEEVEN:
|
||||||
default:
|
default:
|
||||||
rmode = float_round_nearest_even;
|
rmode = float_round_nearest_even;
|
||||||
|
|
Loading…
Reference in a new issue