aboutsummaryrefslogtreecommitdiff
path: root/target/arm
diff options
context:
space:
mode:
Diffstat (limited to 'target/arm')
-rw-r--r--target/arm/cpregs-pmu.c34
-rw-r--r--target/arm/cpu-features.h24
-rw-r--r--target/arm/cpu.c26
-rw-r--r--target/arm/cpu.h17
-rw-r--r--target/arm/helper.c186
-rw-r--r--target/arm/hvf/hvf.c6
-rw-r--r--target/arm/internals.h28
-rw-r--r--target/arm/ptw.c8
-rw-r--r--target/arm/tcg/a64.decode26
-rw-r--r--target/arm/tcg/cpu64.c9
-rw-r--r--target/arm/tcg/translate-a64.c191
11 files changed, 485 insertions, 70 deletions
diff --git a/target/arm/cpregs-pmu.c b/target/arm/cpregs-pmu.c
index 9c4431c..31c01ed 100644
--- a/target/arm/cpregs-pmu.c
+++ b/target/arm/cpregs-pmu.c
@@ -228,22 +228,27 @@ static bool event_supported(uint16_t number)
return supported_event_map[number] != UNSUPPORTED_EVENT;
}
-static CPAccessResult pmreg_access(CPUARMState *env, const ARMCPRegInfo *ri,
- bool isread)
+static CPAccessResult do_pmreg_access(CPUARMState *env, bool is_pmcr)
{
/*
* Performance monitor registers user accessibility is controlled
- * by PMUSERENR. MDCR_EL2.TPM and MDCR_EL3.TPM allow configurable
+ * by PMUSERENR. MDCR_EL2.TPM/TPMCR and MDCR_EL3.TPM allow configurable
* trapping to EL2 or EL3 for other accesses.
*/
int el = arm_current_el(env);
- uint64_t mdcr_el2 = arm_mdcr_el2_eff(env);
if (el == 0 && !(env->cp15.c9_pmuserenr & 1)) {
return CP_ACCESS_TRAP_EL1;
}
- if (el < 2 && (mdcr_el2 & MDCR_TPM)) {
- return CP_ACCESS_TRAP_EL2;
+ if (el < 2) {
+ uint64_t mdcr_el2 = arm_mdcr_el2_eff(env);
+
+ if (mdcr_el2 & MDCR_TPM) {
+ return CP_ACCESS_TRAP_EL2;
+ }
+ if (is_pmcr && (mdcr_el2 & MDCR_TPMCR)) {
+ return CP_ACCESS_TRAP_EL2;
+ }
}
if (el < 3 && (env->cp15.mdcr_el3 & MDCR_TPM)) {
return CP_ACCESS_TRAP_EL3;
@@ -252,6 +257,19 @@ static CPAccessResult pmreg_access(CPUARMState *env, const ARMCPRegInfo *ri,
return CP_ACCESS_OK;
}
+static CPAccessResult pmreg_access(CPUARMState *env, const ARMCPRegInfo *ri,
+ bool isread)
+{
+ return do_pmreg_access(env, false);
+}
+
+static CPAccessResult pmreg_access_pmcr(CPUARMState *env,
+ const ARMCPRegInfo *ri,
+ bool isread)
+{
+ return do_pmreg_access(env, true);
+}
+
static CPAccessResult pmreg_access_xevcntr(CPUARMState *env,
const ARMCPRegInfo *ri,
bool isread)
@@ -1187,14 +1205,14 @@ void define_pm_cpregs(ARMCPU *cpu)
.fgt = FGT_PMCR_EL0,
.type = ARM_CP_IO | ARM_CP_ALIAS,
.fieldoffset = offsetoflow32(CPUARMState, cp15.c9_pmcr),
- .accessfn = pmreg_access,
+ .accessfn = pmreg_access_pmcr,
.readfn = pmcr_read, .raw_readfn = raw_read,
.writefn = pmcr_write, .raw_writefn = raw_write,
};
const ARMCPRegInfo pmcr64 = {
.name = "PMCR_EL0", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 3, .crn = 9, .crm = 12, .opc2 = 0,
- .access = PL0_RW, .accessfn = pmreg_access,
+ .access = PL0_RW, .accessfn = pmreg_access_pmcr,
.fgt = FGT_PMCR_EL0,
.type = ARM_CP_IO,
.fieldoffset = offsetof(CPUARMState, cp15.c9_pmcr),
diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h
index 5876162..e49e0ae 100644
--- a/target/arm/cpu-features.h
+++ b/target/arm/cpu-features.h
@@ -406,9 +406,14 @@ static inline bool isar_feature_aa64_crc32(const ARMISARegisters *id)
return FIELD_EX64_IDREG(id, ID_AA64ISAR0, CRC32) != 0;
}
-static inline bool isar_feature_aa64_atomics(const ARMISARegisters *id)
+static inline bool isar_feature_aa64_lse(const ARMISARegisters *id)
{
- return FIELD_EX64_IDREG(id, ID_AA64ISAR0, ATOMIC) != 0;
+ return FIELD_EX64_IDREG(id, ID_AA64ISAR0, ATOMIC) >= 2;
+}
+
+static inline bool isar_feature_aa64_lse128(const ARMISARegisters *id)
+{
+ return FIELD_EX64_IDREG(id, ID_AA64ISAR0, ATOMIC) >= 3;
}
static inline bool isar_feature_aa64_rdm(const ARMISARegisters *id)
@@ -604,6 +609,11 @@ static inline bool isar_feature_aa64_rpres(const ARMISARegisters *id)
return FIELD_EX64_IDREG(id, ID_AA64ISAR2, RPRES);
}
+static inline bool isar_feature_aa64_cssc(const ARMISARegisters *id)
+{
+ return FIELD_EX64_IDREG(id, ID_AA64ISAR2, CSSC) != 0;
+}
+
static inline bool isar_feature_aa64_lut(const ARMISARegisters *id)
{
return FIELD_EX64_IDREG(id, ID_AA64ISAR2, LUT);
@@ -904,6 +914,16 @@ static inline bool isar_feature_aa64_nv2(const ARMISARegisters *id)
return FIELD_EX64_IDREG(id, ID_AA64MMFR2, NV) >= 2;
}
+static inline bool isar_feature_aa64_tcr2(const ARMISARegisters *id)
+{
+ return FIELD_EX64_IDREG(id, ID_AA64MMFR3, TCRX) != 0;
+}
+
+static inline bool isar_feature_aa64_sctlr2(const ARMISARegisters *id)
+{
+ return FIELD_EX64_IDREG(id, ID_AA64MMFR3, SCTLRX) != 0;
+}
+
static inline bool isar_feature_aa64_pmuv3p1(const ARMISARegisters *id)
{
return FIELD_EX64_IDREG(id, ID_AA64DFR0, PMUVER) >= 4 &&
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index e2b2337..d0f6fcd 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -142,11 +142,11 @@ static bool arm_cpu_has_work(CPUState *cs)
ARMCPU *cpu = ARM_CPU(cs);
return (cpu->power_state != PSCI_OFF)
- && cs->interrupt_request &
- (CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD
- | CPU_INTERRUPT_NMI | CPU_INTERRUPT_VINMI | CPU_INTERRUPT_VFNMI
- | CPU_INTERRUPT_VFIQ | CPU_INTERRUPT_VIRQ | CPU_INTERRUPT_VSERR
- | CPU_INTERRUPT_EXITTB);
+ && cpu_test_interrupt(cs,
+ CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD
+ | CPU_INTERRUPT_NMI | CPU_INTERRUPT_VINMI | CPU_INTERRUPT_VFNMI
+ | CPU_INTERRUPT_VFIQ | CPU_INTERRUPT_VIRQ | CPU_INTERRUPT_VSERR
+ | CPU_INTERRUPT_EXITTB);
}
#endif /* !CONFIG_USER_ONLY */
@@ -644,6 +644,12 @@ void arm_emulate_firmware_reset(CPUState *cpustate, int target_el)
if (cpu_isar_feature(aa64_fgt, cpu)) {
env->cp15.scr_el3 |= SCR_FGTEN;
}
+ if (cpu_isar_feature(aa64_tcr2, cpu)) {
+ env->cp15.scr_el3 |= SCR_TCR2EN;
+ }
+ if (cpu_isar_feature(aa64_sctlr2, cpu)) {
+ env->cp15.scr_el3 |= SCR_SCTLR2EN;
+ }
}
if (target_el == 2) {
@@ -958,7 +964,7 @@ void arm_cpu_update_virq(ARMCPU *cpu)
!(arm_hcrx_el2_eff(env) & HCRX_VINMI)) ||
(env->irq_line_state & CPU_INTERRUPT_VIRQ);
- if (new_state != ((cs->interrupt_request & CPU_INTERRUPT_VIRQ) != 0)) {
+ if (new_state != cpu_test_interrupt(cs, CPU_INTERRUPT_VIRQ)) {
if (new_state) {
cpu_interrupt(cs, CPU_INTERRUPT_VIRQ);
} else {
@@ -980,7 +986,7 @@ void arm_cpu_update_vfiq(ARMCPU *cpu)
!(arm_hcrx_el2_eff(env) & HCRX_VFNMI)) ||
(env->irq_line_state & CPU_INTERRUPT_VFIQ);
- if (new_state != ((cs->interrupt_request & CPU_INTERRUPT_VFIQ) != 0)) {
+ if (new_state != cpu_test_interrupt(cs, CPU_INTERRUPT_VFIQ)) {
if (new_state) {
cpu_interrupt(cs, CPU_INTERRUPT_VFIQ);
} else {
@@ -1002,7 +1008,7 @@ void arm_cpu_update_vinmi(ARMCPU *cpu)
(arm_hcrx_el2_eff(env) & HCRX_VINMI)) ||
(env->irq_line_state & CPU_INTERRUPT_VINMI);
- if (new_state != ((cs->interrupt_request & CPU_INTERRUPT_VINMI) != 0)) {
+ if (new_state != cpu_test_interrupt(cs, CPU_INTERRUPT_VINMI)) {
if (new_state) {
cpu_interrupt(cs, CPU_INTERRUPT_VINMI);
} else {
@@ -1022,7 +1028,7 @@ void arm_cpu_update_vfnmi(ARMCPU *cpu)
bool new_state = (arm_hcr_el2_eff(env) & HCR_VF) &&
(arm_hcrx_el2_eff(env) & HCRX_VFNMI);
- if (new_state != ((cs->interrupt_request & CPU_INTERRUPT_VFNMI) != 0)) {
+ if (new_state != cpu_test_interrupt(cs, CPU_INTERRUPT_VFNMI)) {
if (new_state) {
cpu_interrupt(cs, CPU_INTERRUPT_VFNMI);
} else {
@@ -1041,7 +1047,7 @@ void arm_cpu_update_vserr(ARMCPU *cpu)
bool new_state = env->cp15.hcr_el2 & HCR_VSE;
- if (new_state != ((cs->interrupt_request & CPU_INTERRUPT_VSERR) != 0)) {
+ if (new_state != cpu_test_interrupt(cs, CPU_INTERRUPT_VSERR)) {
if (new_state) {
cpu_interrupt(cs, CPU_INTERRUPT_VSERR);
} else {
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index dc9b6dc..c15d79a 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -337,6 +337,7 @@ typedef struct CPUArchState {
};
uint64_t sctlr_el[4];
};
+ uint64_t sctlr2_el[4]; /* Extension to System control register. */
uint64_t vsctlr; /* Virtualization System control register. */
uint64_t cpacr_el1; /* Architectural feature access control register */
uint64_t cptr_el[4]; /* ARMv8 feature trap registers */
@@ -365,6 +366,7 @@ typedef struct CPUArchState {
uint64_t vsttbr_el2; /* Secure Virtualization Translation Table. */
/* MMU translation table base control. */
uint64_t tcr_el[4];
+ uint64_t tcr2_el[3];
uint64_t vtcr_el2; /* Virtualization Translation Control. */
uint64_t vstcr_el2; /* Secure Virtualization Translation Control. */
uint32_t c2_data; /* MPU data cacheable bits. */
@@ -1420,6 +1422,19 @@ void pmu_init(ARMCPU *cpu);
#define SCTLR_SPINTMASK (1ULL << 62) /* FEAT_NMI */
#define SCTLR_TIDCP (1ULL << 63) /* FEAT_TIDCP1 */
+#define SCTLR2_EMEC (1ULL << 1) /* FEAT_MEC */
+#define SCTLR2_NMEA (1ULL << 2) /* FEAT_DoubleFault2 */
+#define SCTLR2_ENADERR (1ULL << 3) /* FEAT_ADERR */
+#define SCTLR2_ENANERR (1ULL << 4) /* FEAT_ANERR */
+#define SCTLR2_EASE (1ULL << 5) /* FEAT_DoubleFault2 */
+#define SCTLR2_ENIDCP128 (1ULL << 6) /* FEAT_SYSREG128 */
+#define SCTLR2_ENPACM (1ULL << 7) /* FEAT_PAuth_LR */
+#define SCTLR2_ENPACM0 (1ULL << 8) /* FEAT_PAuth_LR */
+#define SCTLR2_CPTA (1ULL << 9) /* FEAT_CPA2 */
+#define SCTLR2_CPTA0 (1ULL << 10) /* FEAT_CPA2 */
+#define SCTLR2_CPTM (1ULL << 11) /* FEAT_CPA2 */
+#define SCTLR2_CPTM0 (1ULL << 12) /* FEAT_CAP2 */
+
#define CPSR_M (0x1fU)
#define CPSR_T (1U << 5)
#define CPSR_F (1U << 6)
@@ -1712,6 +1727,8 @@ static inline void xpsr_write(CPUARMState *env, uint32_t val, uint32_t mask)
#define SCR_HXEN (1ULL << 38)
#define SCR_TRNDR (1ULL << 40)
#define SCR_ENTP2 (1ULL << 41)
+#define SCR_TCR2EN (1ULL << 43)
+#define SCR_SCTLR2EN (1ULL << 44)
#define SCR_GPF (1ULL << 48)
#define SCR_NSE (1ULL << 62)
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 0c1299f..19637e7 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -741,6 +741,12 @@ static void scr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
if (cpu_isar_feature(aa64_ecv, cpu)) {
valid_mask |= SCR_ECVEN;
}
+ if (cpu_isar_feature(aa64_tcr2, cpu)) {
+ valid_mask |= SCR_TCR2EN;
+ }
+ if (cpu_isar_feature(aa64_sctlr2, cpu)) {
+ valid_mask |= SCR_SCTLR2EN;
+ }
} else {
valid_mask &= ~(SCR_RW | SCR_ST);
if (cpu_isar_feature(aa32_ras, cpu)) {
@@ -833,40 +839,40 @@ static uint64_t isr_read(CPUARMState *env, const ARMCPRegInfo *ri)
uint64_t ret = 0;
if (hcr_el2 & HCR_IMO) {
- if (cs->interrupt_request & CPU_INTERRUPT_VIRQ) {
+ if (cpu_test_interrupt(cs, CPU_INTERRUPT_VIRQ)) {
ret |= CPSR_I;
}
- if (cs->interrupt_request & CPU_INTERRUPT_VINMI) {
+ if (cpu_test_interrupt(cs, CPU_INTERRUPT_VINMI)) {
ret |= ISR_IS;
ret |= CPSR_I;
}
} else {
- if (cs->interrupt_request & CPU_INTERRUPT_HARD) {
+ if (cpu_test_interrupt(cs, CPU_INTERRUPT_HARD)) {
ret |= CPSR_I;
}
- if (cs->interrupt_request & CPU_INTERRUPT_NMI) {
+ if (cpu_test_interrupt(cs, CPU_INTERRUPT_NMI)) {
ret |= ISR_IS;
ret |= CPSR_I;
}
}
if (hcr_el2 & HCR_FMO) {
- if (cs->interrupt_request & CPU_INTERRUPT_VFIQ) {
+ if (cpu_test_interrupt(cs, CPU_INTERRUPT_VFIQ)) {
ret |= CPSR_F;
}
- if (cs->interrupt_request & CPU_INTERRUPT_VFNMI) {
+ if (cpu_test_interrupt(cs, CPU_INTERRUPT_VFNMI)) {
ret |= ISR_FS;
ret |= CPSR_F;
}
} else {
- if (cs->interrupt_request & CPU_INTERRUPT_FIQ) {
+ if (cpu_test_interrupt(cs, CPU_INTERRUPT_FIQ)) {
ret |= CPSR_F;
}
}
if (hcr_el2 & HCR_AMO) {
- if (cs->interrupt_request & CPU_INTERRUPT_VSERR) {
+ if (cpu_test_interrupt(cs, CPU_INTERRUPT_VSERR)) {
ret |= CPSR_A;
}
}
@@ -3907,23 +3913,24 @@ static void hcrx_write(CPUARMState *env, const ARMCPRegInfo *ri,
ARMCPU *cpu = env_archcpu(env);
uint64_t valid_mask = 0;
- /* FEAT_MOPS adds MSCEn and MCE2 */
if (cpu_isar_feature(aa64_mops, cpu)) {
valid_mask |= HCRX_MSCEN | HCRX_MCE2;
}
-
- /* FEAT_NMI adds TALLINT, VINMI and VFNMI */
if (cpu_isar_feature(aa64_nmi, cpu)) {
valid_mask |= HCRX_TALLINT | HCRX_VINMI | HCRX_VFNMI;
}
- /* FEAT_CMOW adds CMOW */
if (cpu_isar_feature(aa64_cmow, cpu)) {
valid_mask |= HCRX_CMOW;
}
- /* FEAT_XS adds FGTnXS, FnXS */
if (cpu_isar_feature(aa64_xs, cpu)) {
valid_mask |= HCRX_FGTNXS | HCRX_FNXS;
}
+ if (cpu_isar_feature(aa64_tcr2, cpu)) {
+ valid_mask |= HCRX_TCR2EN;
+ }
+ if (cpu_isar_feature(aa64_sctlr2, cpu)) {
+ valid_mask |= HCRX_SCTLR2EN;
+ }
/* Clear RES0 bits. */
env->cp15.hcrx_el2 = value & valid_mask;
@@ -3981,11 +3988,19 @@ uint64_t arm_hcrx_el2_eff(CPUARMState *env)
* This may need to be revisited for future bits.
*/
if (!arm_is_el2_enabled(env)) {
+ ARMCPU *cpu = env_archcpu(env);
uint64_t hcrx = 0;
- if (cpu_isar_feature(aa64_mops, env_archcpu(env))) {
- /* MSCEn behaves as 1 if EL2 is not enabled */
+
+ /* Bits which whose effective value is 1 if el2 not enabled. */
+ if (cpu_isar_feature(aa64_mops, cpu)) {
hcrx |= HCRX_MSCEN;
}
+ if (cpu_isar_feature(aa64_tcr2, cpu)) {
+ hcrx |= HCRX_TCR2EN;
+ }
+ if (cpu_isar_feature(aa64_sctlr2, cpu)) {
+ hcrx |= HCRX_SCTLR2EN;
+ }
return hcrx;
}
if (arm_feature(env, ARM_FEATURE_EL3) && !(env->cp15.scr_el3 & SCR_HXEN)) {
@@ -4513,6 +4528,8 @@ static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu)
static const struct E2HAlias aliases[] = {
{ K(3, 0, 1, 0, 0), K(3, 4, 1, 0, 0), K(3, 5, 1, 0, 0),
"SCTLR", "SCTLR_EL2", "SCTLR_EL12" },
+ { K(3, 0, 1, 0, 3), K(3, 4, 1, 0, 3), K(3, 5, 1, 0, 3),
+ "SCTLR2_EL1", "SCTLR2_EL2", "SCTLR2_EL12", isar_feature_aa64_sctlr2 },
{ K(3, 0, 1, 0, 2), K(3, 4, 1, 1, 2), K(3, 5, 1, 0, 2),
"CPACR", "CPTR_EL2", "CPACR_EL12" },
{ K(3, 0, 2, 0, 0), K(3, 4, 2, 0, 0), K(3, 5, 2, 0, 0),
@@ -4521,6 +4538,8 @@ static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu)
"TTBR1_EL1", "TTBR1_EL2", "TTBR1_EL12" },
{ K(3, 0, 2, 0, 2), K(3, 4, 2, 0, 2), K(3, 5, 2, 0, 2),
"TCR_EL1", "TCR_EL2", "TCR_EL12" },
+ { K(3, 0, 2, 0, 3), K(3, 4, 2, 0, 3), K(3, 5, 2, 0, 3),
+ "TCR2_EL1", "TCR2_EL2", "TCR2_EL12", isar_feature_aa64_tcr2 },
{ K(3, 0, 4, 0, 0), K(3, 4, 4, 0, 0), K(3, 5, 4, 0, 0),
"SPSR_EL1", "SPSR_EL2", "SPSR_EL12" },
{ K(3, 0, 4, 0, 1), K(3, 4, 4, 0, 1), K(3, 5, 4, 0, 1),
@@ -5994,6 +6013,133 @@ static const ARMCPRegInfo actlr2_hactlr2_reginfo[] = {
.resetvalue = 0 },
};
+static CPAccessResult sctlr2_el2_access(CPUARMState *env,
+ const ARMCPRegInfo *ri,
+ bool isread)
+{
+ if (arm_current_el(env) < 3
+ && arm_feature(env, ARM_FEATURE_EL3)
+ && !(env->cp15.scr_el3 & SCR_SCTLR2EN)) {
+ return CP_ACCESS_TRAP_EL3;
+ }
+ return CP_ACCESS_OK;
+}
+
+static CPAccessResult sctlr2_el1_access(CPUARMState *env,
+ const ARMCPRegInfo *ri,
+ bool isread)
+{
+ CPAccessResult ret = access_tvm_trvm(env, ri, isread);
+ if (ret != CP_ACCESS_OK) {
+ return ret;
+ }
+ if (arm_current_el(env) < 2 && !(arm_hcrx_el2_eff(env) & HCRX_SCTLR2EN)) {
+ return CP_ACCESS_TRAP_EL2;
+ }
+ return sctlr2_el2_access(env, ri, isread);
+}
+
+static void sctlr2_el1_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ uint64_t valid_mask = 0;
+
+ value &= valid_mask;
+ raw_write(env, ri, value);
+}
+
+static void sctlr2_el2_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ uint64_t valid_mask = 0;
+
+ value &= valid_mask;
+ raw_write(env, ri, value);
+}
+
+static void sctlr2_el3_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ uint64_t valid_mask = 0;
+
+ value &= valid_mask;
+ raw_write(env, ri, value);
+}
+
+static const ARMCPRegInfo sctlr2_reginfo[] = {
+ { .name = "SCTLR2_EL1", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 0, .opc2 = 3, .crn = 1, .crm = 0,
+ .access = PL1_RW, .accessfn = sctlr2_el1_access,
+ .writefn = sctlr2_el1_write, .fgt = FGT_SCTLR_EL1,
+ .nv2_redirect_offset = 0x278 | NV2_REDIR_NV1,
+ .fieldoffset = offsetof(CPUARMState, cp15.sctlr2_el[1]) },
+ { .name = "SCTLR2_EL2", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 4, .opc2 = 3, .crn = 1, .crm = 0,
+ .access = PL2_RW, .accessfn = sctlr2_el2_access,
+ .writefn = sctlr2_el2_write,
+ .fieldoffset = offsetof(CPUARMState, cp15.sctlr2_el[2]) },
+ { .name = "SCTLR2_EL3", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 6, .opc2 = 3, .crn = 1, .crm = 0,
+ .access = PL3_RW, .writefn = sctlr2_el3_write,
+ .fieldoffset = offsetof(CPUARMState, cp15.sctlr2_el[3]) },
+};
+
+static CPAccessResult tcr2_el2_access(CPUARMState *env, const ARMCPRegInfo *ri,
+ bool isread)
+{
+ if (arm_current_el(env) < 3
+ && arm_feature(env, ARM_FEATURE_EL3)
+ && !(env->cp15.scr_el3 & SCR_TCR2EN)) {
+ return CP_ACCESS_TRAP_EL3;
+ }
+ return CP_ACCESS_OK;
+}
+
+static CPAccessResult tcr2_el1_access(CPUARMState *env, const ARMCPRegInfo *ri,
+ bool isread)
+{
+ CPAccessResult ret = access_tvm_trvm(env, ri, isread);
+ if (ret != CP_ACCESS_OK) {
+ return ret;
+ }
+ if (arm_current_el(env) < 2 && !(arm_hcrx_el2_eff(env) & HCRX_TCR2EN)) {
+ return CP_ACCESS_TRAP_EL2;
+ }
+ return tcr2_el2_access(env, ri, isread);
+}
+
+static void tcr2_el1_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ uint64_t valid_mask = 0;
+
+ value &= valid_mask;
+ raw_write(env, ri, value);
+}
+
+static void tcr2_el2_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ uint64_t valid_mask = 0;
+
+ value &= valid_mask;
+ raw_write(env, ri, value);
+}
+
+static const ARMCPRegInfo tcr2_reginfo[] = {
+ { .name = "TCR2_EL1", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 0, .opc2 = 3, .crn = 2, .crm = 0,
+ .access = PL1_RW, .accessfn = tcr2_el1_access,
+ .writefn = tcr2_el1_write, .fgt = FGT_TCR_EL1,
+ .nv2_redirect_offset = 0x270 | NV2_REDIR_NV1,
+ .fieldoffset = offsetof(CPUARMState, cp15.tcr2_el[1]) },
+ { .name = "TCR2_EL2", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 4, .opc2 = 3, .crn = 2, .crm = 0,
+ .access = PL2_RW, .accessfn = tcr2_el2_access,
+ .writefn = tcr2_el2_write,
+ .fieldoffset = offsetof(CPUARMState, cp15.tcr2_el[2]) },
+};
+
void register_cp_regs_for_features(ARMCPU *cpu)
{
/* Register all the coprocessor registers based on feature bits */
@@ -7223,6 +7369,14 @@ void register_cp_regs_for_features(ARMCPU *cpu)
define_arm_cp_regs(cpu, nmi_reginfo);
}
+ if (cpu_isar_feature(aa64_sctlr2, cpu)) {
+ define_arm_cp_regs(cpu, sctlr2_reginfo);
+ }
+
+ if (cpu_isar_feature(aa64_tcr2, cpu)) {
+ define_arm_cp_regs(cpu, tcr2_reginfo);
+ }
+
if (cpu_isar_feature(any_predinv, cpu)) {
define_arm_cp_regs(cpu, predinv_reginfo);
}
@@ -9147,7 +9301,7 @@ void arm_cpu_do_interrupt(CPUState *cs)
arm_call_el_change_hook(cpu);
if (!kvm_enabled()) {
- cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
+ cpu_set_interrupt(cs, CPU_INTERRUPT_EXITTB);
}
}
#endif /* !CONFIG_USER_ONLY */
diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
index 47b0cd3..b77db99 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -1782,13 +1782,13 @@ static int hvf_sysreg_write(CPUState *cpu, uint32_t reg, uint64_t val)
static int hvf_inject_interrupts(CPUState *cpu)
{
- if (cpu->interrupt_request & CPU_INTERRUPT_FIQ) {
+ if (cpu_test_interrupt(cpu, CPU_INTERRUPT_FIQ)) {
trace_hvf_inject_fiq();
hv_vcpu_set_pending_interrupt(cpu->accel->fd, HV_INTERRUPT_TYPE_FIQ,
true);
}
- if (cpu->interrupt_request & CPU_INTERRUPT_HARD) {
+ if (cpu_test_interrupt(cpu, CPU_INTERRUPT_HARD)) {
trace_hvf_inject_irq();
hv_vcpu_set_pending_interrupt(cpu->accel->fd, HV_INTERRUPT_TYPE_IRQ,
true);
@@ -1840,7 +1840,7 @@ static void hvf_wfi(CPUState *cpu)
uint64_t nanos;
uint32_t cntfrq;
- if (cpu->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_FIQ)) {
+ if (cpu_test_interrupt(cpu, CPU_INTERRUPT_HARD | CPU_INTERRUPT_FIQ)) {
/* Interrupt pending, no need to wait */
return;
}
diff --git a/target/arm/internals.h b/target/arm/internals.h
index 1b3d024..f5a1e75 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -113,11 +113,6 @@ FIELD(DBGWCR, WT, 20, 1)
FIELD(DBGWCR, MASK, 24, 5)
FIELD(DBGWCR, SSCE, 29, 1)
-#define VTCR_NSW (1u << 29)
-#define VTCR_NSA (1u << 30)
-#define VSTCR_SW VTCR_NSW
-#define VSTCR_SA VTCR_NSA
-
/* Bit definitions for CPACR (AArch32 only) */
FIELD(CPACR, CP10, 20, 2)
FIELD(CPACR, CP11, 22, 2)
@@ -201,6 +196,24 @@ FIELD(CPTR_EL3, TCPAC, 31, 1)
#define TTBCR_SH1 (1U << 28)
#define TTBCR_EAE (1U << 31)
+#define TCR2_PNCH (1ULL << 0)
+#define TCR2_PIE (1ULL << 1)
+#define TCR2_E0POE (1ULL << 2)
+#define TCR2_POE (1ULL << 3)
+#define TCR2_AIE (1ULL << 4)
+#define TCR2_D128 (1ULL << 5)
+#define TCR2_PTTWI (1ULL << 10)
+#define TCR2_HAFT (1ULL << 11)
+#define TCR2_AMEC0 (1ULL << 12)
+#define TCR2_AMEC1 (1ULL << 13)
+#define TCR2_DISCH0 (1ULL << 14)
+#define TCR2_DISCH1 (1ULL << 15)
+#define TCR2_A2 (1ULL << 16)
+#define TCR2_FNG0 (1ULL << 17)
+#define TCR2_FNG1 (1ULL << 18)
+#define TCR2_FNGNA0 (1ULL << 20)
+#define TCR2_FNGNA1 (1ULL << 21)
+
FIELD(VTCR, T0SZ, 0, 6)
FIELD(VTCR, SL0, 6, 2)
FIELD(VTCR, IRGN0, 8, 2)
@@ -220,6 +233,9 @@ FIELD(VTCR, NSA, 30, 1)
FIELD(VTCR, DS, 32, 1)
FIELD(VTCR, SL2, 33, 1)
+FIELD(VSTCR, SW, 29, 1)
+FIELD(VSTCR, SA, 30, 1)
+
#define HCRX_ENAS0 (1ULL << 0)
#define HCRX_ENALS (1ULL << 1)
#define HCRX_ENASR (1ULL << 2)
@@ -232,6 +248,8 @@ FIELD(VTCR, SL2, 33, 1)
#define HCRX_CMOW (1ULL << 9)
#define HCRX_MCE2 (1ULL << 10)
#define HCRX_MSCEN (1ULL << 11)
+#define HCRX_TCR2EN (1ULL << 14)
+#define HCRX_SCTLR2EN (1ULL << 15)
#define HPFAR_NS (1ULL << 63)
diff --git a/target/arm/ptw.c b/target/arm/ptw.c
index 561bf26..ed5c728 100644
--- a/target/arm/ptw.c
+++ b/target/arm/ptw.c
@@ -193,9 +193,9 @@ static ARMMMUIdx ptw_idx_for_stage_2(CPUARMState *env, ARMMMUIdx stage2idx)
return ARMMMUIdx_Phys_Realm;
case ARMSS_Secure:
if (stage2idx == ARMMMUIdx_Stage2_S) {
- s2walk_secure = !(env->cp15.vstcr_el2 & VSTCR_SW);
+ s2walk_secure = !(env->cp15.vstcr_el2 & R_VSTCR_SW_MASK);
} else {
- s2walk_secure = !(env->cp15.vtcr_el2 & VTCR_NSW);
+ s2walk_secure = !(env->cp15.vtcr_el2 & R_VTCR_NSW_MASK);
}
return s2walk_secure ? ARMMMUIdx_Phys_S : ARMMMUIdx_Phys_NS;
default:
@@ -3372,9 +3372,9 @@ static bool get_phys_addr_twostage(CPUARMState *env, S1Translate *ptw,
*/
if (in_space == ARMSS_Secure) {
result->f.attrs.secure =
- !(env->cp15.vstcr_el2 & (VSTCR_SA | VSTCR_SW))
+ !(env->cp15.vstcr_el2 & (R_VSTCR_SA_MASK | R_VSTCR_SW_MASK))
&& (ipa_secure
- || !(env->cp15.vtcr_el2 & (VTCR_NSA | VTCR_NSW)));
+ || !(env->cp15.vtcr_el2 & (R_VTCR_NSA_MASK | R_VTCR_NSW_MASK)));
result->f.attrs.space = arm_secure_to_space(result->f.attrs.secure);
}
diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode
index 8c798cd..55ff6c5 100644
--- a/target/arm/tcg/a64.decode
+++ b/target/arm/tcg/a64.decode
@@ -156,6 +156,16 @@ MOVZ . 10 100101 .. ................ ..... @movw_32
MOVK . 11 100101 .. ................ ..... @movw_64
MOVK . 11 100101 .. ................ ..... @movw_32
+# Min/Max (immediate)
+
+@minmaxi_s sf:1 .. ........... imm:s8 rn:5 rd:5 &rri_sf
+@minmaxi_u sf:1 .. ........... imm:8 rn:5 rd:5 &rri_sf
+
+SMAX_i . 00 1000111 0000 ........ ..... ..... @minmaxi_s
+SMIN_i . 00 1000111 0010 ........ ..... ..... @minmaxi_s
+UMAX_i . 00 1000111 0001 ........ ..... ..... @minmaxi_u
+UMIN_i . 00 1000111 0011 ........ ..... ..... @minmaxi_u
+
# Bitfield
&bitfield rd rn sf immr imms
@@ -536,6 +546,13 @@ SWP .. 111 0 00 . . 1 ..... 1000 00 ..... ..... @atomic
LDAPR sz:2 111 0 00 1 0 1 11111 1100 00 rn:5 rt:5
+# Atomic 128-bit memory operations
+&atomic128 rn rt rt2 a r
+@atomic128 ........ a:1 r:1 . rt2:5 ...... rn:5 rt:5 &atomic128
+LDCLRP 00011001 . . 1 ..... 000100 ..... ..... @atomic128
+LDSETP 00011001 . . 1 ..... 001100 ..... ..... @atomic128
+SWPP 00011001 . . 1 ..... 100000 ..... ..... @atomic128
+
# Load/store register (pointer authentication)
# LDRA immediate is 10 bits signed and scaled, but the bits aren't all contiguous
@@ -698,6 +715,11 @@ GMI 1 00 11010110 ..... 000101 ..... ..... @rrr
PACGA 1 00 11010110 ..... 001100 ..... ..... @rrr
+SMAX . 00 11010110 ..... 011000 ..... ..... @rrr_sf
+SMIN . 00 11010110 ..... 011010 ..... ..... @rrr_sf
+UMAX . 00 11010110 ..... 011001 ..... ..... @rrr_sf
+UMIN . 00 11010110 ..... 011011 ..... ..... @rrr_sf
+
# Data Processing (1-source)
@rr . .......... ..... ...... rn:5 rd:5 &rr
@@ -711,6 +733,10 @@ REV64 1 10 11010110 00000 000011 ..... ..... @rr
CLZ . 10 11010110 00000 000100 ..... ..... @rr_sf
CLS . 10 11010110 00000 000101 ..... ..... @rr_sf
+CTZ . 10 11010110 00000 000110 ..... ..... @rr_sf
+CNT . 10 11010110 00000 000111 ..... ..... @rr_sf
+ABS . 10 11010110 00000 001000 ..... ..... @rr_sf
+
&pacaut rd rn z
@pacaut . .. ........ ..... .. z:1 ... rn:5 rd:5 &pacaut
diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c
index 35cddba..b8b1981 100644
--- a/target/arm/tcg/cpu64.c
+++ b/target/arm/tcg/cpu64.c
@@ -1145,7 +1145,7 @@ void aarch64_max_tcg_initfn(Object *obj)
t = FIELD_DP64(t, ID_AA64ISAR0, SHA1, 1); /* FEAT_SHA1 */
t = FIELD_DP64(t, ID_AA64ISAR0, SHA2, 2); /* FEAT_SHA512 */
t = FIELD_DP64(t, ID_AA64ISAR0, CRC32, 1); /* FEAT_CRC32 */
- t = FIELD_DP64(t, ID_AA64ISAR0, ATOMIC, 2); /* FEAT_LSE */
+ t = FIELD_DP64(t, ID_AA64ISAR0, ATOMIC, 3); /* FEAT_LSE, FEAT_LSE128 */
t = FIELD_DP64(t, ID_AA64ISAR0, RDM, 1); /* FEAT_RDM */
t = FIELD_DP64(t, ID_AA64ISAR0, SHA3, 1); /* FEAT_SHA3 */
t = FIELD_DP64(t, ID_AA64ISAR0, SM3, 1); /* FEAT_SM3 */
@@ -1178,6 +1178,7 @@ void aarch64_max_tcg_initfn(Object *obj)
t = FIELD_DP64(t, ID_AA64ISAR2, MOPS, 1); /* FEAT_MOPS */
t = FIELD_DP64(t, ID_AA64ISAR2, BC, 1); /* FEAT_HBC */
t = FIELD_DP64(t, ID_AA64ISAR2, WFXT, 2); /* FEAT_WFxT */
+ t = FIELD_DP64(t, ID_AA64ISAR2, CSSC, 1); /* FEAT_CSSC */
SET_IDREG(isar, ID_AA64ISAR2, t);
t = GET_IDREG(isar, ID_AA64PFR0);
@@ -1247,7 +1248,11 @@ void aarch64_max_tcg_initfn(Object *obj)
t = FIELD_DP64(t, ID_AA64MMFR2, E0PD, 1); /* FEAT_E0PD */
SET_IDREG(isar, ID_AA64MMFR2, t);
- FIELD_DP64_IDREG(isar, ID_AA64MMFR3, SPEC_FPACC, 1); /* FEAT_FPACC_SPEC */
+ t = GET_IDREG(isar, ID_AA64MMFR3);
+ t = FIELD_DP64(t, ID_AA64MMFR3, TCRX, 1); /* FEAT_TCR2 */
+ t = FIELD_DP64(t, ID_AA64MMFR3, SCTLRX, 1); /* FEAT_SCTLR2 */
+ t = FIELD_DP64(t, ID_AA64MMFR3, SPEC_FPACC, 1); /* FEAT_FPACC_SPEC */
+ SET_IDREG(isar, ID_AA64MMFR3, t);
t = GET_IDREG(isar, ID_AA64ZFR0);
t = FIELD_DP64(t, ID_AA64ZFR0, SVEVER, 2); /* FEAT_SVE2p1 */
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
index dbf4759..37bedc3 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -3237,7 +3237,7 @@ static bool trans_LDXP(DisasContext *s, arg_stxr *a)
static bool trans_CASP(DisasContext *s, arg_CASP *a)
{
- if (!dc_isar_feature(aa64_atomics, s)) {
+ if (!dc_isar_feature(aa64_lse, s)) {
return false;
}
if (((a->rt | a->rs) & 1) != 0) {
@@ -3250,7 +3250,7 @@ static bool trans_CASP(DisasContext *s, arg_CASP *a)
static bool trans_CAS(DisasContext *s, arg_CAS *a)
{
- if (!dc_isar_feature(aa64_atomics, s)) {
+ if (!dc_isar_feature(aa64_lse, s)) {
return false;
}
gen_compare_and_swap(s, a->rs, a->rt, a->rn, a->sz);
@@ -3743,15 +3743,64 @@ static bool do_atomic_ld(DisasContext *s, arg_atomic *a, AtomicThreeOpFn *fn,
return true;
}
-TRANS_FEAT(LDADD, aa64_atomics, do_atomic_ld, a, tcg_gen_atomic_fetch_add_i64, 0, false)
-TRANS_FEAT(LDCLR, aa64_atomics, do_atomic_ld, a, tcg_gen_atomic_fetch_and_i64, 0, true)
-TRANS_FEAT(LDEOR, aa64_atomics, do_atomic_ld, a, tcg_gen_atomic_fetch_xor_i64, 0, false)
-TRANS_FEAT(LDSET, aa64_atomics, do_atomic_ld, a, tcg_gen_atomic_fetch_or_i64, 0, false)
-TRANS_FEAT(LDSMAX, aa64_atomics, do_atomic_ld, a, tcg_gen_atomic_fetch_smax_i64, MO_SIGN, false)
-TRANS_FEAT(LDSMIN, aa64_atomics, do_atomic_ld, a, tcg_gen_atomic_fetch_smin_i64, MO_SIGN, false)
-TRANS_FEAT(LDUMAX, aa64_atomics, do_atomic_ld, a, tcg_gen_atomic_fetch_umax_i64, 0, false)
-TRANS_FEAT(LDUMIN, aa64_atomics, do_atomic_ld, a, tcg_gen_atomic_fetch_umin_i64, 0, false)
-TRANS_FEAT(SWP, aa64_atomics, do_atomic_ld, a, tcg_gen_atomic_xchg_i64, 0, false)
+TRANS_FEAT(LDADD, aa64_lse, do_atomic_ld, a, tcg_gen_atomic_fetch_add_i64, 0, false)
+TRANS_FEAT(LDCLR, aa64_lse, do_atomic_ld, a, tcg_gen_atomic_fetch_and_i64, 0, true)
+TRANS_FEAT(LDEOR, aa64_lse, do_atomic_ld, a, tcg_gen_atomic_fetch_xor_i64, 0, false)
+TRANS_FEAT(LDSET, aa64_lse, do_atomic_ld, a, tcg_gen_atomic_fetch_or_i64, 0, false)
+TRANS_FEAT(LDSMAX, aa64_lse, do_atomic_ld, a, tcg_gen_atomic_fetch_smax_i64, MO_SIGN, false)
+TRANS_FEAT(LDSMIN, aa64_lse, do_atomic_ld, a, tcg_gen_atomic_fetch_smin_i64, MO_SIGN, false)
+TRANS_FEAT(LDUMAX, aa64_lse, do_atomic_ld, a, tcg_gen_atomic_fetch_umax_i64, 0, false)
+TRANS_FEAT(LDUMIN, aa64_lse, do_atomic_ld, a, tcg_gen_atomic_fetch_umin_i64, 0, false)
+TRANS_FEAT(SWP, aa64_lse, do_atomic_ld, a, tcg_gen_atomic_xchg_i64, 0, false)
+
+typedef void Atomic128ThreeOpFn(TCGv_i128, TCGv_i64, TCGv_i128, TCGArg, MemOp);
+
+static bool do_atomic128_ld(DisasContext *s, arg_atomic128 *a,
+ Atomic128ThreeOpFn *fn, bool invert)
+{
+ MemOp mop;
+ int rlo, rhi;
+ TCGv_i64 clean_addr, tlo, thi;
+ TCGv_i128 t16;
+
+ if (a->rt == 31 || a->rt2 == 31 || a->rt == a->rt2) {
+ return false;
+ }
+ if (a->rn == 31) {
+ gen_check_sp_alignment(s);
+ }
+ mop = check_atomic_align(s, a->rn, MO_128);
+ clean_addr = gen_mte_check1(s, cpu_reg_sp(s, a->rn), false,
+ a->rn != 31, mop);
+
+ rlo = (s->be_data == MO_LE ? a->rt : a->rt2);
+ rhi = (s->be_data == MO_LE ? a->rt2 : a->rt);
+
+ tlo = read_cpu_reg(s, rlo, true);
+ thi = read_cpu_reg(s, rhi, true);
+ if (invert) {
+ tcg_gen_not_i64(tlo, tlo);
+ tcg_gen_not_i64(thi, thi);
+ }
+ /*
+ * The tcg atomic primitives are all full barriers. Therefore we
+ * can ignore the Acquire and Release bits of this instruction.
+ */
+ t16 = tcg_temp_new_i128();
+ tcg_gen_concat_i64_i128(t16, tlo, thi);
+
+ fn(t16, clean_addr, t16, get_mem_index(s), mop);
+
+ tcg_gen_extr_i128_i64(cpu_reg(s, rlo), cpu_reg(s, rhi), t16);
+ return true;
+}
+
+TRANS_FEAT(LDCLRP, aa64_lse128, do_atomic128_ld,
+ a, tcg_gen_atomic_fetch_and_i128, true)
+TRANS_FEAT(LDSETP, aa64_lse128, do_atomic128_ld,
+ a, tcg_gen_atomic_fetch_or_i128, false)
+TRANS_FEAT(SWPP, aa64_lse128, do_atomic128_ld,
+ a, tcg_gen_atomic_xchg_i128, false)
static bool trans_LDAPR(DisasContext *s, arg_LDAPR *a)
{
@@ -3759,7 +3808,7 @@ static bool trans_LDAPR(DisasContext *s, arg_LDAPR *a)
TCGv_i64 clean_addr;
MemOp mop;
- if (!dc_isar_feature(aa64_atomics, s) ||
+ if (!dc_isar_feature(aa64_lse, s) ||
!dc_isar_feature(aa64_rcpc_8_3, s)) {
return false;
}
@@ -4553,6 +4602,50 @@ TRANS(ADDS_i, gen_rri, a, 0, 1, a->sf ? gen_add64_CC : gen_add32_CC)
TRANS(SUBS_i, gen_rri, a, 0, 1, a->sf ? gen_sub64_CC : gen_sub32_CC)
/*
+ * Min/Max (immediate)
+ */
+
+static void gen_wrap3_i32(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m, NeonGenTwoOpFn fn)
+{
+ TCGv_i32 t1 = tcg_temp_new_i32();
+ TCGv_i32 t2 = tcg_temp_new_i32();
+
+ tcg_gen_extrl_i64_i32(t1, n);
+ tcg_gen_extrl_i64_i32(t2, m);
+ fn(t1, t1, t2);
+ tcg_gen_extu_i32_i64(d, t1);
+}
+
+static void gen_smax32_i64(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m)
+{
+ gen_wrap3_i32(d, n, m, tcg_gen_smax_i32);
+}
+
+static void gen_smin32_i64(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m)
+{
+ gen_wrap3_i32(d, n, m, tcg_gen_smin_i32);
+}
+
+static void gen_umax32_i64(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m)
+{
+ gen_wrap3_i32(d, n, m, tcg_gen_umax_i32);
+}
+
+static void gen_umin32_i64(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m)
+{
+ gen_wrap3_i32(d, n, m, tcg_gen_umin_i32);
+}
+
+TRANS_FEAT(SMAX_i, aa64_cssc, gen_rri, a, 0, 0,
+ a->sf ? tcg_gen_smax_i64 : gen_smax32_i64)
+TRANS_FEAT(SMIN_i, aa64_cssc, gen_rri, a, 0, 0,
+ a->sf ? tcg_gen_smin_i64 : gen_smin32_i64)
+TRANS_FEAT(UMAX_i, aa64_cssc, gen_rri, a, 0, 0,
+ a->sf ? tcg_gen_umax_i64 : gen_umax32_i64)
+TRANS_FEAT(UMIN_i, aa64_cssc, gen_rri, a, 0, 0,
+ a->sf ? tcg_gen_umin_i64 : gen_umin32_i64)
+
+/*
* Add/subtract (immediate, with tags)
*/
@@ -8157,6 +8250,28 @@ static bool trans_PACGA(DisasContext *s, arg_rrr *a)
return false;
}
+static bool gen_rrr(DisasContext *s, arg_rrr_sf *a, ArithTwoOp fn)
+{
+ TCGv_i64 tcg_rm = cpu_reg(s, a->rm);
+ TCGv_i64 tcg_rn = cpu_reg(s, a->rn);
+ TCGv_i64 tcg_rd = cpu_reg(s, a->rd);
+
+ fn(tcg_rd, tcg_rn, tcg_rm);
+ if (!a->sf) {
+ tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
+ }
+ return true;
+}
+
+TRANS_FEAT(SMAX, aa64_cssc, gen_rrr, a,
+ a->sf ? tcg_gen_smax_i64 : gen_smax32_i64)
+TRANS_FEAT(SMIN, aa64_cssc, gen_rrr, a,
+ a->sf ? tcg_gen_smin_i64 : gen_smin32_i64)
+TRANS_FEAT(UMAX, aa64_cssc, gen_rrr, a,
+ a->sf ? tcg_gen_umax_i64 : gen_umax32_i64)
+TRANS_FEAT(UMIN, aa64_cssc, gen_rrr, a,
+ a->sf ? tcg_gen_umin_i64 : gen_umin32_i64)
+
typedef void ArithOneOp(TCGv_i64, TCGv_i64);
static bool gen_rr(DisasContext *s, int rd, int rn, ArithOneOp fn)
@@ -8165,13 +8280,22 @@ static bool gen_rr(DisasContext *s, int rd, int rn, ArithOneOp fn)
return true;
}
-static void gen_rbit32(TCGv_i64 tcg_rd, TCGv_i64 tcg_rn)
+/*
+ * Perform 32-bit operation fn on the low half of n;
+ * the high half of the output is zeroed.
+ */
+static void gen_wrap2_i32(TCGv_i64 d, TCGv_i64 n, NeonGenOneOpFn fn)
{
- TCGv_i32 t32 = tcg_temp_new_i32();
+ TCGv_i32 t = tcg_temp_new_i32();
- tcg_gen_extrl_i64_i32(t32, tcg_rn);
- gen_helper_rbit(t32, t32);
- tcg_gen_extu_i32_i64(tcg_rd, t32);
+ tcg_gen_extrl_i64_i32(t, n);
+ fn(t, t);
+ tcg_gen_extu_i32_i64(d, t);
+}
+
+static void gen_rbit32(TCGv_i64 tcg_rd, TCGv_i64 tcg_rn)
+{
+ gen_wrap2_i32(tcg_rd, tcg_rn, gen_helper_rbit);
}
static void gen_rev16_xx(TCGv_i64 tcg_rd, TCGv_i64 tcg_rn, TCGv_i64 mask)
@@ -8227,15 +8351,42 @@ static void gen_clz64(TCGv_i64 tcg_rd, TCGv_i64 tcg_rn)
static void gen_cls32(TCGv_i64 tcg_rd, TCGv_i64 tcg_rn)
{
+ gen_wrap2_i32(tcg_rd, tcg_rn, tcg_gen_clrsb_i32);
+}
+
+TRANS(CLZ, gen_rr, a->rd, a->rn, a->sf ? gen_clz64 : gen_clz32)
+TRANS(CLS, gen_rr, a->rd, a->rn, a->sf ? tcg_gen_clrsb_i64 : gen_cls32)
+
+static void gen_ctz32(TCGv_i64 tcg_rd, TCGv_i64 tcg_rn)
+{
TCGv_i32 t32 = tcg_temp_new_i32();
tcg_gen_extrl_i64_i32(t32, tcg_rn);
- tcg_gen_clrsb_i32(t32, t32);
+ tcg_gen_ctzi_i32(t32, t32, 32);
tcg_gen_extu_i32_i64(tcg_rd, t32);
}
-TRANS(CLZ, gen_rr, a->rd, a->rn, a->sf ? gen_clz64 : gen_clz32)
-TRANS(CLS, gen_rr, a->rd, a->rn, a->sf ? tcg_gen_clrsb_i64 : gen_cls32)
+static void gen_ctz64(TCGv_i64 tcg_rd, TCGv_i64 tcg_rn)
+{
+ tcg_gen_ctzi_i64(tcg_rd, tcg_rn, 64);
+}
+
+static void gen_cnt32(TCGv_i64 tcg_rd, TCGv_i64 tcg_rn)
+{
+ gen_wrap2_i32(tcg_rd, tcg_rn, tcg_gen_ctpop_i32);
+}
+
+static void gen_abs32(TCGv_i64 tcg_rd, TCGv_i64 tcg_rn)
+{
+ gen_wrap2_i32(tcg_rd, tcg_rn, tcg_gen_abs_i32);
+}
+
+TRANS_FEAT(CTZ, aa64_cssc, gen_rr, a->rd, a->rn,
+ a->sf ? gen_ctz64 : gen_ctz32)
+TRANS_FEAT(CNT, aa64_cssc, gen_rr, a->rd, a->rn,
+ a->sf ? tcg_gen_ctpop_i64 : gen_cnt32)
+TRANS_FEAT(ABS, aa64_cssc, gen_rr, a->rd, a->rn,
+ a->sf ? tcg_gen_abs_i64 : gen_abs32)
static bool gen_pacaut(DisasContext *s, arg_pacaut *a, NeonGenTwo64OpEnvFn fn)
{