diff options
author | Andreas Sandberg <Andreas.Sandberg@ARM.com> | 2014-10-16 05:49:39 -0400 |
---|---|---|
committer | Andreas Sandberg <Andreas.Sandberg@ARM.com> | 2014-10-16 05:49:39 -0400 |
commit | 3697990c27243f0c454f2fab0f12ed06759c97b9 (patch) | |
tree | c7fe75d2cf328c26bc31cfe405d91afc2c4aa757 /src/arch/arm/isa.cc | |
parent | 132ea6319ab9292bef7c0ea87f396ef9de2db0fe (diff) | |
download | gem5-3697990c27243f0c454f2fab0f12ed06759c97b9.tar.xz |
arm: Add a model of an ARM PMUv3
This class implements a subset of the ARM PMU v3 specification as
described in the ARMv8 reference manual. It supports most of the
features of the PMU, however the following features are known to be
missing:
* Event filtering (e.g., from different privilege levels).
* Access controls (the PMU currently ignores the execution level).
* The chain counter (event no. 0x1E) is unimplemented.
The PMU itself does not implement any events, it merely provides an
interface for the configuration scripts to hook up probes that drive
events. Configuration scripts should call addEventProbe() to configure
custom events or high-level methods to configure architected
events. The Python implementation of addEventProbe() automatically
delays event type registration until after instantiation.
In order to support CPU switching and some combined counters (e.g.,
memory references synthesized from loads and stores), the PMU allows
multiple probes per event type. When creating a system that switches
between CPU models that share the same PMU, PMU events for all of the
CPU models can be registered with the PMU.
Kudos to Matt Horsnell for the initial gem5 implementation of the PMU.
Diffstat (limited to 'src/arch/arm/isa.cc')
-rw-r--r-- | src/arch/arm/isa.cc | 67 |
1 files changed, 39 insertions, 28 deletions
diff --git a/src/arch/arm/isa.cc b/src/arch/arm/isa.cc index e76ff452d..c2250e38a 100644 --- a/src/arch/arm/isa.cc +++ b/src/arch/arm/isa.cc @@ -39,8 +39,10 @@ */ #include "arch/arm/isa.hh" +#include "arch/arm/pmu.hh" #include "arch/arm/system.hh" #include "cpu/checker/cpu.hh" +#include "cpu/base.hh" #include "debug/Arm.hh" #include "debug/MiscRegs.hh" #include "params/ArmISA.hh" @@ -122,12 +124,21 @@ const struct ISA::MiscRegInitializerEntry ISA::ISA(Params *p) - : SimObject(p), system(NULL), lookUpMiscReg(NUM_MISCREGS, {0,0}) + : SimObject(p), + system(NULL), + pmu(p->pmu), + lookUpMiscReg(NUM_MISCREGS, {0,0}) { SCTLR sctlr; sctlr = 0; miscRegs[MISCREG_SCTLR_RST] = sctlr; + // Hook up a dummy device if we haven't been configured with a + // real PMU. By using a dummy device, we don't need to check that + // the PMU exist every time we try to access a PMU register. + if (!pmu) + pmu = &dummyDevice; + system = dynamic_cast<ArmSystem *>(p->system); DPRINTFN("ISA system set to: %p %p\n", system, p->system); @@ -356,7 +367,10 @@ ISA::clear64(const ArmISAParams *p) // Initialize configurable id registers miscRegs[MISCREG_ID_AA64AFR0_EL1] = p->id_aa64afr0_el1; miscRegs[MISCREG_ID_AA64AFR1_EL1] = p->id_aa64afr1_el1; - miscRegs[MISCREG_ID_AA64DFR0_EL1] = p->id_aa64dfr0_el1; + miscRegs[MISCREG_ID_AA64DFR0_EL1] = + (p->id_aa64dfr0_el1 & 0xfffffffffffff0ffULL) | + (p->pmu ? 0x0000000000000100ULL : 0); // Enable PMUv3 + miscRegs[MISCREG_ID_AA64DFR1_EL1] = p->id_aa64dfr1_el1; miscRegs[MISCREG_ID_AA64ISAR0_EL1] = p->id_aa64isar0_el1; miscRegs[MISCREG_ID_AA64ISAR1_EL1] = p->id_aa64isar1_el1; @@ -365,6 +379,11 @@ ISA::clear64(const ArmISAParams *p) miscRegs[MISCREG_ID_AA64PFR0_EL1] = p->id_aa64pfr0_el1; miscRegs[MISCREG_ID_AA64PFR1_EL1] = p->id_aa64pfr1_el1; + miscRegs[MISCREG_ID_DFR0_EL1] = + (p->pmu ? 0x03000000ULL : 0); // Enable PMUv3 + + miscRegs[MISCREG_ID_DFR0] = miscRegs[MISCREG_ID_DFR0_EL1]; + // Enforce consistency with system-level settings... // EL3 @@ -491,7 +510,6 @@ ISA::readMiscReg(int misc_reg, ThreadContext *tc) // top bit defined as RES1 return readMiscRegNoEffect(misc_reg) | 0x80000000; case MISCREG_ID_AFR0: // not implemented, so alias MIDR - case MISCREG_ID_DFR0: // not implemented, so alias MIDR case MISCREG_REVIDR: // not implemented, so alias MIDR case MISCREG_MIDR: cpsr = readMiscRegNoEffect(MISCREG_CPSR); @@ -549,12 +567,13 @@ ISA::readMiscReg(int misc_reg, ThreadContext *tc) case MISCREG_ACTLR: warn("Not doing anything for miscreg ACTLR\n"); break; - case MISCREG_PMCR: - case MISCREG_PMCCNTR: - case MISCREG_PMSELR: - warn("Not doing anything for read to miscreg %s\n", - miscRegName[misc_reg]); - break; + + case MISCREG_PMXEVTYPER_PMCCFILTR: + case MISCREG_PMINTENSET_EL1 ... MISCREG_PMOVSSET_EL0: + case MISCREG_PMEVCNTR0_EL0 ... MISCREG_PMEVTYPER5_EL0: + case MISCREG_PMCR ... MISCREG_PMOVSSET: + return pmu->readMiscReg(misc_reg); + case MISCREG_CPSR_Q: panic("shouldn't be reading this register seperately\n"); case MISCREG_FPSCR_QC: @@ -640,9 +659,9 @@ ISA::readMiscReg(int misc_reg, ThreadContext *tc) } case MISCREG_DBGDIDR: /* For now just implement the version number. - * Return 0 as we don't support debug architecture yet. + * ARMv7, v7.1 Debug architecture (0b0101 --> 0x5) */ - return 0; + return 0x5 << 16; case MISCREG_DBGDSCRint: return 0; case MISCREG_ISR: @@ -1112,6 +1131,7 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc) case MISCREG_MIDR: case MISCREG_ID_PFR0: case MISCREG_ID_PFR1: + case MISCREG_ID_DFR0: case MISCREG_ID_MMFR0: case MISCREG_ID_MMFR1: case MISCREG_ID_MMFR2: @@ -1443,24 +1463,15 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc) case MISCREG_ACTLR: warn("Not doing anything for write of miscreg ACTLR\n"); break; - case MISCREG_PMCR: - { - // Performance counters not implemented. Instead, interpret - // a reset command to this register to reset the simulator - // statistics. - // PMCR_E | PMCR_P | PMCR_C - const int ResetAndEnableCounters = 0x7; - if (newVal == ResetAndEnableCounters) { - inform("Resetting all simobject stats\n"); - Stats::schedStatEvent(false, true); - break; - } - } - case MISCREG_PMCCNTR: - case MISCREG_PMSELR: - warn("Not doing anything for write to miscreg %s\n", - miscRegName[misc_reg]); + + case MISCREG_PMXEVTYPER_PMCCFILTR: + case MISCREG_PMINTENSET_EL1 ... MISCREG_PMOVSSET_EL0: + case MISCREG_PMEVCNTR0_EL0 ... MISCREG_PMEVTYPER5_EL0: + case MISCREG_PMCR ... MISCREG_PMOVSSET: + pmu->setMiscReg(misc_reg, newVal); break; + + case MISCREG_HSTR: // TJDBX, now redifined to be RES0 { HSTR hstrMask = 0; |