[PATCH v4 39/47] target/arm/tcg/cpu64: add the cortex-a78ae CPU

Luc Michel posted 47 patches 2 months, 3 weeks ago
Maintainers: Alistair Francis <alistair@alistair23.me>, "Edgar E. Iglesias" <edgar.iglesias@gmail.com>, Peter Maydell <peter.maydell@linaro.org>
There is a newer version of this series
[PATCH v4 39/47] target/arm/tcg/cpu64: add the cortex-a78ae CPU
Posted by Luc Michel 2 months, 3 weeks ago
Add support for the ARM Cortex-A78AE CPU.

Signed-off-by: Luc Michel <luc.michel@amd.com>
---
 target/arm/tcg/cpu64.c | 79 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 79 insertions(+)

diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c
index 35cddbafa4c..b56677c1a5d 100644
--- a/target/arm/tcg/cpu64.c
+++ b/target/arm/tcg/cpu64.c
@@ -404,10 +404,84 @@ static void aarch64_a76_initfn(Object *obj)
 
     /* From D5.1 AArch64 PMU register summary */
     cpu->isar.reset_pmcr_el0 = 0x410b3000;
 }
 
+static void aarch64_a78ae_initfn(Object *obj)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+    ARMISARegisters *isar = &cpu->isar;
+
+    cpu->dtb_compatible = "arm,cortex-a78ae";
+    set_feature(&cpu->env, ARM_FEATURE_V8);
+    set_feature(&cpu->env, ARM_FEATURE_NEON);
+    set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
+    set_feature(&cpu->env, ARM_FEATURE_BACKCOMPAT_CNTFRQ);
+    set_feature(&cpu->env, ARM_FEATURE_AARCH64);
+    set_feature(&cpu->env, ARM_FEATURE_CBAR_RO);
+    set_feature(&cpu->env, ARM_FEATURE_EL2);
+    set_feature(&cpu->env, ARM_FEATURE_EL3);
+    set_feature(&cpu->env, ARM_FEATURE_PMU);
+
+    /* Ordered by B2.4 AArch64 registers by functional group */
+    SET_IDREG(isar, CLIDR, 0x82000023);
+    cpu->ctr = 0x9444c004;
+    cpu->dcz_blocksize = 4;
+    SET_IDREG(isar, ID_AA64DFR0, 0x0000000110305408ull);
+    SET_IDREG(isar, ID_AA64ISAR0, 0x0010100010211120ull);
+    SET_IDREG(isar, ID_AA64ISAR1, 0x0000000001200031ull);
+    SET_IDREG(isar, ID_AA64MMFR0, 0x0000000000101125ull);
+    SET_IDREG(isar, ID_AA64MMFR1, 0x0000000010212122ull);
+    SET_IDREG(isar, ID_AA64MMFR2, 0x0000000100001011ull);
+    SET_IDREG(isar, ID_AA64PFR0, 0x1100000010111112ull); /* GIC filled in later */
+    SET_IDREG(isar, ID_AA64PFR1, 0x0000000000000010ull);
+    SET_IDREG(isar, ID_AFR0, 0x00000000);
+    SET_IDREG(isar, ID_DFR0, 0x04010088);
+    SET_IDREG(isar, ID_ISAR0, 0x02101110);
+    SET_IDREG(isar, ID_ISAR1, 0x13112111);
+    SET_IDREG(isar, ID_ISAR2, 0x21232042);
+    SET_IDREG(isar, ID_ISAR3, 0x01112131);
+    SET_IDREG(isar, ID_ISAR4, 0x00010142);
+    SET_IDREG(isar, ID_ISAR5, 0x01011121);
+    SET_IDREG(isar, ID_ISAR6, 0x00000010);
+    SET_IDREG(isar, ID_MMFR0, 0x10201105);
+    SET_IDREG(isar, ID_MMFR1, 0x40000000);
+    SET_IDREG(isar, ID_MMFR2, 0x01260000);
+    SET_IDREG(isar, ID_MMFR3, 0x02122211);
+    SET_IDREG(isar, ID_MMFR4, 0x00021110);
+    SET_IDREG(isar, ID_PFR0, 0x10010131);
+    SET_IDREG(isar, ID_PFR1, 0x00010000); /* GIC filled in later */
+    SET_IDREG(isar, ID_PFR2, 0x00000011);
+    cpu->midr = 0x410fd421;          /* r0p1 */
+    cpu->revidr = 0;
+
+    /* From B2.18 CCSIDR_EL1 */
+    /* 64KB L1 dcache */
+    cpu->ccsidr[0] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 4, 64, 64 * KiB, 7);
+    /* 64KB L1 icache */
+    cpu->ccsidr[1] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 4, 64, 64 * KiB, 2);
+    /* 512KB L2 cache */
+    cpu->ccsidr[2] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 8, 64, 512 * KiB, 7);
+
+    /* From B2.93 SCTLR_EL3 */
+    cpu->reset_sctlr = 0x30c50838;
+
+    /* From B4.23 ICH_VTR_EL2 */
+    cpu->gic_num_lrs = 4;
+    cpu->gic_vpribits = 5;
+    cpu->gic_vprebits = 5;
+    cpu->gic_pribits = 5;
+
+    /* From B5.1 AdvSIMD AArch64 register summary */
+    cpu->isar.mvfr0 = 0x10110222;
+    cpu->isar.mvfr1 = 0x13211111;
+    cpu->isar.mvfr2 = 0x00000043;
+
+    /* From D5.1 AArch64 PMU register summary */
+    cpu->isar.reset_pmcr_el0 = 0x41223000;
+}
+
 static void aarch64_a64fx_initfn(Object *obj)
 {
     ARMCPU *cpu = ARM_CPU(obj);
     ARMISARegisters *isar = &cpu->isar;
 
@@ -1313,10 +1387,15 @@ void aarch64_max_tcg_initfn(Object *obj)
 static const ARMCPUInfo aarch64_cpus[] = {
     { .name = "cortex-a35",         .initfn = aarch64_a35_initfn },
     { .name = "cortex-a55",         .initfn = aarch64_a55_initfn },
     { .name = "cortex-a72",         .initfn = aarch64_a72_initfn },
     { .name = "cortex-a76",         .initfn = aarch64_a76_initfn },
+    /*
+     * The Cortex-A78AE differs slightly from the plain Cortex-A78. We don't
+     * currently model the latter.
+     */
+    { .name = "cortex-a78ae",       .initfn = aarch64_a78ae_initfn },
     { .name = "cortex-a710",        .initfn = aarch64_a710_initfn },
     { .name = "a64fx",              .initfn = aarch64_a64fx_initfn },
     { .name = "neoverse-n1",        .initfn = aarch64_neoverse_n1_initfn },
     { .name = "neoverse-v1",        .initfn = aarch64_neoverse_v1_initfn },
     { .name = "neoverse-n2",        .initfn = aarch64_neoverse_n2_initfn },
-- 
2.50.1
Re: [PATCH v4 39/47] target/arm/tcg/cpu64: add the cortex-a78ae CPU
Posted by Peter Maydell 2 months ago
On Fri, 22 Aug 2025 at 16:17, Luc Michel <luc.michel@amd.com> wrote:
>
> Add support for the ARM Cortex-A78AE CPU.
>
> Signed-off-by: Luc Michel <luc.michel@amd.com>
> ---
>  target/arm/tcg/cpu64.c | 79 ++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 79 insertions(+)
>
> diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c
> index 35cddbafa4c..b56677c1a5d 100644
> --- a/target/arm/tcg/cpu64.c
> +++ b/target/arm/tcg/cpu64.c
> @@ -404,10 +404,84 @@ static void aarch64_a76_initfn(Object *obj)
>
>      /* From D5.1 AArch64 PMU register summary */
>      cpu->isar.reset_pmcr_el0 = 0x410b3000;
>  }
>
> +static void aarch64_a78ae_initfn(Object *obj)
> +{
> +    ARMCPU *cpu = ARM_CPU(obj);
> +    ARMISARegisters *isar = &cpu->isar;
> +
> +    cpu->dtb_compatible = "arm,cortex-a78ae";
> +    set_feature(&cpu->env, ARM_FEATURE_V8);
> +    set_feature(&cpu->env, ARM_FEATURE_NEON);
> +    set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
> +    set_feature(&cpu->env, ARM_FEATURE_BACKCOMPAT_CNTFRQ);

From cpu.h:

    /*
     * ARM_FEATURE_BACKCOMPAT_CNTFRQ makes the CPU default cntfrq be 62.5MHz
     * if the board doesn't set a value, instead of 1GHz. It is for backwards
     * compatibility and used only with CPU definitions that were already
     * in QEMU before we changed the default. It should not be set on any
     * CPU types added in future.
     */

This is a new CPU type, so don't set this.

> +    set_feature(&cpu->env, ARM_FEATURE_AARCH64);
> +    set_feature(&cpu->env, ARM_FEATURE_CBAR_RO);

The TRM says this CPU doesn't have a CBAR register, so
don't set this.

> +    set_feature(&cpu->env, ARM_FEATURE_EL2);
> +    set_feature(&cpu->env, ARM_FEATURE_EL3);
> +    set_feature(&cpu->env, ARM_FEATURE_PMU);
> +
> +    /* Ordered by B2.4 AArch64 registers by functional group */

There is no B2.4 in the Cortex-A78AE TRM. Please don't
just cut-and-paste things from other CPU definitions.
Similarly for other comments here referencing TRM sections.

In this case what you want is section 3.2.4.

> +    SET_IDREG(isar, CLIDR, 0x82000023);
> +    cpu->ctr = 0x9444c004;
> +    cpu->dcz_blocksize = 4;
> +    SET_IDREG(isar, ID_AA64DFR0, 0x0000000110305408ull);
> +    SET_IDREG(isar, ID_AA64ISAR0, 0x0010100010211120ull);
> +    SET_IDREG(isar, ID_AA64ISAR1, 0x0000000001200031ull);
> +    SET_IDREG(isar, ID_AA64MMFR0, 0x0000000000101125ull);
> +    SET_IDREG(isar, ID_AA64MMFR1, 0x0000000010212122ull);
> +    SET_IDREG(isar, ID_AA64MMFR2, 0x0000000100001011ull);
> +    SET_IDREG(isar, ID_AA64PFR0, 0x1100000010111112ull); /* GIC filled in later */
> +    SET_IDREG(isar, ID_AA64PFR1, 0x0000000000000010ull);
> +    SET_IDREG(isar, ID_AFR0, 0x00000000);
> +    SET_IDREG(isar, ID_DFR0, 0x04010088);
> +    SET_IDREG(isar, ID_ISAR0, 0x02101110);
> +    SET_IDREG(isar, ID_ISAR1, 0x13112111);
> +    SET_IDREG(isar, ID_ISAR2, 0x21232042);
> +    SET_IDREG(isar, ID_ISAR3, 0x01112131);
> +    SET_IDREG(isar, ID_ISAR4, 0x00010142);
> +    SET_IDREG(isar, ID_ISAR5, 0x01011121);
> +    SET_IDREG(isar, ID_ISAR6, 0x00000010);
> +    SET_IDREG(isar, ID_MMFR0, 0x10201105);
> +    SET_IDREG(isar, ID_MMFR1, 0x40000000);
> +    SET_IDREG(isar, ID_MMFR2, 0x01260000);
> +    SET_IDREG(isar, ID_MMFR3, 0x02122211);
> +    SET_IDREG(isar, ID_MMFR4, 0x00021110);
> +    SET_IDREG(isar, ID_PFR0, 0x10010131);
> +    SET_IDREG(isar, ID_PFR1, 0x00010000); /* GIC filled in later */
> +    SET_IDREG(isar, ID_PFR2, 0x00000011);
> +    cpu->midr = 0x410fd421;          /* r0p1 */

r0p3 is the latest...

> +    cpu->revidr = 0;
> +
> +    /* From B2.18 CCSIDR_EL1 */
> +    /* 64KB L1 dcache */
> +    cpu->ccsidr[0] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 4, 64, 64 * KiB, 7);
> +    /* 64KB L1 icache */
> +    cpu->ccsidr[1] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 4, 64, 64 * KiB, 2);
> +    /* 512KB L2 cache */
> +    cpu->ccsidr[2] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 8, 64, 512 * KiB, 7);
> +
> +    /* From B2.93 SCTLR_EL3 */
> +    cpu->reset_sctlr = 0x30c50838;
> +
> +    /* From B4.23 ICH_VTR_EL2 */
> +    cpu->gic_num_lrs = 4;
> +    cpu->gic_vpribits = 5;
> +    cpu->gic_vprebits = 5;
> +    cpu->gic_pribits = 5;
> +
> +    /* From B5.1 AdvSIMD AArch64 register summary */
> +    cpu->isar.mvfr0 = 0x10110222;
> +    cpu->isar.mvfr1 = 0x13211111;
> +    cpu->isar.mvfr2 = 0x00000043;
> +
> +    /* From D5.1 AArch64 PMU register summary */
> +    cpu->isar.reset_pmcr_el0 = 0x41223000;
> +}

The register values look OK; checked against the TRM.

thanks
-- PMM
Re: [PATCH v4 39/47] target/arm/tcg/cpu64: add the cortex-a78ae CPU
Posted by Luc Michel 2 months ago
On 15:31 Thu 11 Sep     , Peter Maydell wrote:
> On Fri, 22 Aug 2025 at 16:17, Luc Michel <luc.michel@amd.com> wrote:
> >
> > Add support for the ARM Cortex-A78AE CPU.
> >
> > Signed-off-by: Luc Michel <luc.michel@amd.com>
> > ---
> >  target/arm/tcg/cpu64.c | 79 ++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 79 insertions(+)
> >
> > diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c
> > index 35cddbafa4c..b56677c1a5d 100644
> > --- a/target/arm/tcg/cpu64.c
> > +++ b/target/arm/tcg/cpu64.c
> > @@ -404,10 +404,84 @@ static void aarch64_a76_initfn(Object *obj)
> >
> >      /* From D5.1 AArch64 PMU register summary */
> >      cpu->isar.reset_pmcr_el0 = 0x410b3000;
> >  }
> >
> > +static void aarch64_a78ae_initfn(Object *obj)
> > +{
> > +    ARMCPU *cpu = ARM_CPU(obj);
> > +    ARMISARegisters *isar = &cpu->isar;
> > +
> > +    cpu->dtb_compatible = "arm,cortex-a78ae";
> > +    set_feature(&cpu->env, ARM_FEATURE_V8);
> > +    set_feature(&cpu->env, ARM_FEATURE_NEON);
> > +    set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
> > +    set_feature(&cpu->env, ARM_FEATURE_BACKCOMPAT_CNTFRQ);
> 
> From cpu.h:
> 
>     /*
>      * ARM_FEATURE_BACKCOMPAT_CNTFRQ makes the CPU default cntfrq be 62.5MHz
>      * if the board doesn't set a value, instead of 1GHz. It is for backwards
>      * compatibility and used only with CPU definitions that were already
>      * in QEMU before we changed the default. It should not be set on any
>      * CPU types added in future.
>      */
> 
> This is a new CPU type, so don't set this.
> 
> > +    set_feature(&cpu->env, ARM_FEATURE_AARCH64);
> > +    set_feature(&cpu->env, ARM_FEATURE_CBAR_RO);
> 
> The TRM says this CPU doesn't have a CBAR register, so
> don't set this.
> 
> > +    set_feature(&cpu->env, ARM_FEATURE_EL2);
> > +    set_feature(&cpu->env, ARM_FEATURE_EL3);
> > +    set_feature(&cpu->env, ARM_FEATURE_PMU);
> > +
> > +    /* Ordered by B2.4 AArch64 registers by functional group */
> 
> There is no B2.4 in the Cortex-A78AE TRM. Please don't
> just cut-and-paste things from other CPU definitions.
> Similarly for other comments here referencing TRM sections.
> 
> In this case what you want is section 3.2.4.

Sorry. All of this come from the fact that I mistakenly used the r0p1
revision TRM. Section numbering seems to have changed between the
revisions.

I'll redo this based on r0p3.

Thanks

Luc

> 
> > +    SET_IDREG(isar, CLIDR, 0x82000023);
> > +    cpu->ctr = 0x9444c004;
> > +    cpu->dcz_blocksize = 4;
> > +    SET_IDREG(isar, ID_AA64DFR0, 0x0000000110305408ull);
> > +    SET_IDREG(isar, ID_AA64ISAR0, 0x0010100010211120ull);
> > +    SET_IDREG(isar, ID_AA64ISAR1, 0x0000000001200031ull);
> > +    SET_IDREG(isar, ID_AA64MMFR0, 0x0000000000101125ull);
> > +    SET_IDREG(isar, ID_AA64MMFR1, 0x0000000010212122ull);
> > +    SET_IDREG(isar, ID_AA64MMFR2, 0x0000000100001011ull);
> > +    SET_IDREG(isar, ID_AA64PFR0, 0x1100000010111112ull); /* GIC filled in later */
> > +    SET_IDREG(isar, ID_AA64PFR1, 0x0000000000000010ull);
> > +    SET_IDREG(isar, ID_AFR0, 0x00000000);
> > +    SET_IDREG(isar, ID_DFR0, 0x04010088);
> > +    SET_IDREG(isar, ID_ISAR0, 0x02101110);
> > +    SET_IDREG(isar, ID_ISAR1, 0x13112111);
> > +    SET_IDREG(isar, ID_ISAR2, 0x21232042);
> > +    SET_IDREG(isar, ID_ISAR3, 0x01112131);
> > +    SET_IDREG(isar, ID_ISAR4, 0x00010142);
> > +    SET_IDREG(isar, ID_ISAR5, 0x01011121);
> > +    SET_IDREG(isar, ID_ISAR6, 0x00000010);
> > +    SET_IDREG(isar, ID_MMFR0, 0x10201105);
> > +    SET_IDREG(isar, ID_MMFR1, 0x40000000);
> > +    SET_IDREG(isar, ID_MMFR2, 0x01260000);
> > +    SET_IDREG(isar, ID_MMFR3, 0x02122211);
> > +    SET_IDREG(isar, ID_MMFR4, 0x00021110);
> > +    SET_IDREG(isar, ID_PFR0, 0x10010131);
> > +    SET_IDREG(isar, ID_PFR1, 0x00010000); /* GIC filled in later */
> > +    SET_IDREG(isar, ID_PFR2, 0x00000011);
> > +    cpu->midr = 0x410fd421;          /* r0p1 */
> 
> r0p3 is the latest...
> 
> > +    cpu->revidr = 0;
> > +
> > +    /* From B2.18 CCSIDR_EL1 */
> > +    /* 64KB L1 dcache */
> > +    cpu->ccsidr[0] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 4, 64, 64 * KiB, 7);
> > +    /* 64KB L1 icache */
> > +    cpu->ccsidr[1] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 4, 64, 64 * KiB, 2);
> > +    /* 512KB L2 cache */
> > +    cpu->ccsidr[2] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 8, 64, 512 * KiB, 7);
> > +
> > +    /* From B2.93 SCTLR_EL3 */
> > +    cpu->reset_sctlr = 0x30c50838;
> > +
> > +    /* From B4.23 ICH_VTR_EL2 */
> > +    cpu->gic_num_lrs = 4;
> > +    cpu->gic_vpribits = 5;
> > +    cpu->gic_vprebits = 5;
> > +    cpu->gic_pribits = 5;
> > +
> > +    /* From B5.1 AdvSIMD AArch64 register summary */
> > +    cpu->isar.mvfr0 = 0x10110222;
> > +    cpu->isar.mvfr1 = 0x13211111;
> > +    cpu->isar.mvfr2 = 0x00000043;
> > +
> > +    /* From D5.1 AArch64 PMU register summary */
> > +    cpu->isar.reset_pmcr_el0 = 0x41223000;
> > +}
> 
> The register values look OK; checked against the TRM.
> 
> thanks
> -- PMM

--