summaryrefslogtreecommitdiff
path: root/src/arch/arm/pmu.hh
diff options
context:
space:
mode:
Diffstat (limited to 'src/arch/arm/pmu.hh')
-rw-r--r--src/arch/arm/pmu.hh495
1 files changed, 495 insertions, 0 deletions
diff --git a/src/arch/arm/pmu.hh b/src/arch/arm/pmu.hh
new file mode 100644
index 000000000..989ad76c6
--- /dev/null
+++ b/src/arch/arm/pmu.hh
@@ -0,0 +1,495 @@
+/*
+ * Copyright (c) 2011-2014 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Dam Sunwoo
+ * Matt Horsnell
+ * Andreas Sandberg
+ */
+#ifndef __ARCH_ARM_PMU_HH__
+#define __ARCH_ARM_PMU_HH__
+
+#include <map>
+#include <memory>
+#include <vector>
+
+#include "arch/arm/isa_device.hh"
+#include "arch/arm/registers.hh"
+#include "sim/probe/probe.hh"
+#include "sim/sim_object.hh"
+
+class ArmPMUParams;
+class Platform;
+class ThreadContext;
+
+namespace ArmISA {
+
+
+/**
+ * Model of an ARM PMU version 3
+ *
+ * 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:
+ *
+ * <ul>
+ * <li>Event filtering (e.g., from different privilege levels).
+ * <li>Access controls (the PMU currently ignores the execution level).
+ * <li>The chain counter (event no. 0x1E) is unimplemented.
+ * </ul>
+ *
+ * The PMU itself does not implement any events, in 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.
+ *
+ * @see The ARM Architecture Refererence Manual (DDI 0487A)
+ *
+ */
+class PMU : public SimObject, public ArmISA::BaseISADevice {
+ public:
+ PMU(const ArmPMUParams *p);
+ ~PMU();
+
+ void addEventProbe(unsigned int id, SimObject *obj, const char *name);
+
+ public: // SimObject and related interfaces
+ void serialize(std::ostream &os) M5_ATTR_OVERRIDE;
+ void unserialize(Checkpoint *cp, const std::string &sec) M5_ATTR_OVERRIDE;
+
+ void drainResume() M5_ATTR_OVERRIDE;
+
+
+ public: // ISA Device interface
+ /**
+ * Set a register within the PMU.
+ *
+ * @param misc_reg Register number (see miscregs.hh)
+ * @param val Value to store
+ */
+ void setMiscReg(int misc_reg, MiscReg val) M5_ATTR_OVERRIDE;
+ /**
+ * Read a register within the PMU.
+ *
+ * @param misc_reg Register number (see miscregs.hh)
+ * @return Register value.
+ */
+ MiscReg readMiscReg(int misc_reg) M5_ATTR_OVERRIDE;
+
+ protected: // PMU register types and constants
+ BitUnion32(PMCR_t)
+ // PMU Enable
+ Bitfield<0> e;
+ // Event counter reset
+ Bitfield<1> p;
+ // Cycle counter reset
+ Bitfield<2> c;
+ // Cycle counter divider enable
+ Bitfield<3> d;
+ // Export enable
+ Bitfield<4> x;
+ // Disable PMCCNTR when event counting is prohibited
+ Bitfield<5> dp;
+ // Long Cycle counter enable
+ Bitfield<6> lc;
+ // Number of event counters implemented
+ Bitfield<15, 11> n;
+ // Implementation ID
+ Bitfield<23, 16> idcode;
+ // Implementer code
+ Bitfield<31, 24> imp;
+ EndBitUnion(PMCR_t)
+
+ BitUnion32(PMSELR_t)
+ // Performance counter selector
+ Bitfield<4, 0> sel;
+ EndBitUnion(PMSELR_t)
+
+ BitUnion32(PMEVTYPER_t)
+ Bitfield<9, 0> evtCount;
+
+ // Secure EL3 filtering
+ Bitfield<26> m;
+ // Non-secure EL2 mode filtering
+ Bitfield<27> nsh;
+ // Non-secure EL0 mode filtering
+ Bitfield<28> nsu;
+ // Non-secure EL1 mode filtering
+ Bitfield<29> nsk;
+ // EL0 filtering
+ Bitfield<30> u;
+ // EL1 filtering
+ Bitfield<31> p;
+ EndBitUnion(PMEVTYPER_t)
+
+ /**
+ * Counter ID within the PMU.
+ *
+ * This value is typically used to index into various registers
+ * controlling interrupts and overflows. The value normally in the
+ * [0, 31] range, where 31 refers to the cycle counter.
+ */
+ typedef unsigned int CounterId;
+
+ /** Cycle Count Register Number */
+ static const CounterId PMCCNTR = 31;
+
+ /**
+ * Event type ID.
+ *
+ * See the PMU documentation for a list of architected IDs.
+ */
+ typedef unsigned int EventTypeId;
+
+ /** ID of the software increment event */
+ static const EventTypeId ARCH_EVENT_SW_INCR = 0x00;
+
+ protected: /* High-level register and interrupt handling */
+ MiscReg readMiscRegInt(int misc_reg);
+
+ /**
+ * PMCR write handling
+ *
+ * The PMCR register needs special handling since writing to it
+ * changes PMU-global state (e.g., resets all counters).
+ *
+ * @param val New PMCR value
+ */
+ void setControlReg(PMCR_t val);
+
+ /**
+ * Reset all event counters excluding the cycle counter to zero.
+ */
+ void resetEventCounts();
+
+ /**
+ * Deliver a PMU interrupt to the GIC
+ */
+ void raiseInterrupt();
+
+ /**
+ * Get the value of a performance counter.
+ *
+ * This method returns the value of a general purpose performance
+ * counter or the fixed-function cycle counter. Non-existing
+ * counters are treated as constant '0'.
+ *
+ * @return Value of the performance counter, 0 if the counter does
+ * not exist.
+ */
+ uint64_t getCounterValue(CounterId id) const {
+ return isValidCounter(id) ? getCounter(id).value : 0;
+ }
+
+ /**
+ * Set the value of a performance counter.
+ *
+ * This method sets the value of a general purpose performance
+ * counter or the fixed-function cycle counter. Writes to
+ * non-existing counters are ignored.
+ */
+ void setCounterValue(CounterId id, uint64_t val);
+
+ /**
+ * Get the type and filter settings of a counter (PMEVTYPER)
+ *
+ * This method implements a read from a PMEVTYPER register. It
+ * returns the type value and filter settings of a general purpose
+ * performance counter or the cycle counter. Non-existing counters
+ * are treated as constant '0'.
+ *
+ * @param id Counter ID within the PMU.
+ * @return Performance counter type ID.
+ */
+ PMEVTYPER_t getCounterTypeRegister(CounterId id) const;
+
+ /**
+ * Set the type and filter settings of a performance counter
+ * (PMEVTYPER)
+ *
+ * This method implements a write to a PMEVTYPER register. It sets
+ * the type value and filter settings of a general purpose
+ * performance counter or the cycle counter. Writes to
+ * non-existing counters are ignored. The method automatically
+ * updates the probes used by the counter if it is enabled.
+ *
+ * @param id Counter ID within the PMU.
+ * @param type Performance counter type and filter configuration..
+ */
+ void setCounterTypeRegister(CounterId id, PMEVTYPER_t type);
+
+ protected: /* Probe handling and counter state */
+ class ProbeListener : public ProbeListenerArgBase<uint64_t>
+ {
+ public:
+ ProbeListener(PMU &_pmu, CounterId _id,
+ ProbeManager *pm, const std::string &name)
+ : ProbeListenerArgBase(pm, name),
+ pmu(_pmu), id(_id) {}
+
+ void notify(const uint64_t &val) M5_ATTR_OVERRIDE
+ {
+ pmu.handleEvent(id, val);
+ }
+
+ protected:
+ PMU &pmu;
+ const CounterId id;
+ };
+ typedef std::unique_ptr<ProbeListener> ProbeListenerUPtr;
+
+ /**
+ * Event type configuration
+ *
+ * The main purpose of this class is to describe how a PMU event
+ * type is sampled. It is implemented as a probe factory that
+ * returns a probe attached to the object the event is mointoring.
+ */
+ struct EventType {
+ /**
+ * @param _obj Target SimObject
+ * @param _name Probe name
+ */
+ EventType(SimObject *_obj, const std::string &_name)
+ : obj(_obj), name(_name) {}
+
+ /**
+ * Create and attach a probe used to drive this event.
+ *
+ * @param pmu PMU owning the probe.
+ * @param CounterID counter ID within the PMU.
+ * @return Pointer to a probe listener.
+ */
+ std::unique_ptr<ProbeListener> create(PMU &pmu, CounterId cid) const
+ {
+ std::unique_ptr<ProbeListener> ptr;
+ ptr.reset(new ProbeListener(pmu, cid,
+ obj->getProbeManager(), name));
+ return ptr;
+ }
+
+ /** SimObject being measured by this probe */
+ SimObject *const obj;
+ /** Probe name within obj */
+ const std::string name;
+
+ private:
+ // Disable the default constructor
+ EventType();
+ };
+
+ /** State of a counter within the PMU. */
+ struct CounterState {
+ CounterState()
+ : eventId(0), value(0), enabled(false),
+ overflow64(false) {
+
+ listeners.reserve(4);
+ }
+
+ void serialize(std::ostream &os);
+ void unserialize(Checkpoint *cp, const std::string &section);
+
+ /**
+ * Add an event count to the counter and check for overflow.
+ *
+ * @param delta Number of events to add to the counter.
+ * @return true on overflow, false otherwise.
+ */
+ bool add(uint64_t delta);
+
+ public: /* Serializable state */
+ /** Counter event ID */
+ EventTypeId eventId;
+
+ /** Current value of the counter */
+ uint64_t value;
+
+ /** Is the counter enabled? */
+ bool enabled;
+
+ /** Is this a 64-bit counter? */
+ bool overflow64;
+
+ public: /* Configuration */
+ /** Probe listeners driving this counter */
+ std::vector<ProbeListenerUPtr> listeners;
+ };
+
+ /**
+ * Handle an counting event triggered by a probe.
+ *
+ * This method is called by the ProbeListener class whenever an
+ * active probe is triggered. Ths method adds the event count from
+ * the probe to the affected counter, checks for overflows, and
+ * delivers an interrupt if needed.
+ *
+ * @param id Counter ID affected by the probe.
+ * @param delta Counter increment
+ */
+ void handleEvent(CounterId id, uint64_t delta);
+
+ /**
+ * Is this a valid counter ID?
+ *
+ * @param id ID of counter within the PMU.
+ *
+ * @return true if counter is within the allowed range or the
+ * cycle counter, false otherwise.
+ */
+ bool isValidCounter(CounterId id) const {
+ return id < counters.size() || id == PMCCNTR;
+ }
+
+ /**
+ * Return the state of a counter.
+ *
+ * @param id ID of counter within the PMU.
+ * @return Reference to a CounterState instance representing the
+ * counter.
+ */
+ CounterState &getCounter(CounterId id) {
+ assert(isValidCounter(id));
+ return id == PMCCNTR ? cycleCounter : counters[id];
+ }
+
+
+ /**
+ * Return the state of a counter.
+ *
+ * @param id ID of counter within the PMU.
+ * @return Reference to a CounterState instance representing the
+ * counter.
+ */
+ const CounterState &getCounter(CounterId id) const {
+ assert(isValidCounter(id));
+ return id == PMCCNTR ? cycleCounter : counters[id];
+ }
+
+ /**
+ * Depending on counter configuration, add or remove the probes
+ * driving the counter.
+ *
+ * Look at the state of a counter and (re-)attach the probes
+ * needed to drive a counter if it is currently active. All probes
+ * for the counter are detached if the counter is inactive.
+ *
+ * @param id ID of counter within the PMU.
+ * @param ctr Reference to the counter's state
+ */
+ void updateCounter(CounterId id, CounterState &ctr);
+
+ /**
+ * Call updateCounter() for each counter in the PMU if the
+ * counter's state has changed..
+ *
+ * @see updateCounter()
+ */
+ void updateAllCounters();
+
+ protected: /* State that needs to be serialized */
+ /** Performance Monitor Count Enable Register */
+ MiscReg reg_pmcnten;
+
+ /** Performance Monitor Control Register */
+ PMCR_t reg_pmcr;
+
+ /** Performance Monitor Selection Register */
+ PMSELR_t reg_pmselr;
+
+ /** Performance Monitor Interrupt Enable Register */
+ MiscReg reg_pminten;
+
+ /** Performance Monitor Overflow Status Register */
+ MiscReg reg_pmovsr;
+
+ /**
+ * Performance counter ID register
+ *
+ * This register contains a bitmask of available architected
+ * counters.
+ */
+ uint64_t reg_pmceid;
+
+ /** Remainder part when the clock counter is divided by 64 */
+ unsigned clock_remainder;
+
+ /** State of all general-purpose counters supported by PMU */
+ std::vector<CounterState> counters;
+ /** State of the cycle counter */
+ CounterState cycleCounter;
+
+ protected: /* Configuration and constants */
+ /** Constant (configuration-dependent) part of the PMCR */
+ PMCR_t reg_pmcr_conf;
+ /** PMCR write mask when accessed from the guest */
+ static const MiscReg reg_pmcr_wr_mask;
+
+ /** Performance monitor interrupt number */
+ const unsigned int pmuInterrupt;
+ /** Platform this device belongs to */
+ Platform *const platform;
+
+ /**
+ * Event types supported by this PMU.
+ *
+ * Each event type ID can map to multiple EventType structures,
+ * which enables the PMU to use multiple probes for a single
+ * event. This can be useful in the following cases:
+ * <ul>
+ * <li>Some events can are increment by multiple different probe
+ * points (e.g., the CPU memory access counter gets
+ * incremented for both loads and stores).
+ *
+ * <li>A system switching between multiple CPU models can
+ * register events for all models that will execute a thread
+ * and tehreby ensure that the PMU continues to work.
+ * </ul>
+ */
+ std::multimap<EventTypeId, EventType> pmuEventTypes;
+};
+
+} // namespace ArmISA
+#endif