| /* | 
 |  * Copyright (c) 2011-2014, 2017 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 "arch/arm/system.hh" | 
 | #include "base/cprintf.hh" | 
 | #include "cpu/base.hh" | 
 | #include "debug/PMUVerbose.hh" | 
 | #include "sim/eventq.hh" | 
 | #include "sim/sim_object.hh" | 
 | #include "sim/system.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); | 
 |     void addSoftwareIncrementEvent(unsigned int id); | 
 |  | 
 |     void registerEvent(uint32_t id); | 
 |  | 
 |   public: // SimObject and related interfaces | 
 |     void serialize(CheckpointOut &cp) const override; | 
 |     void unserialize(CheckpointIn &cp) override; | 
 |  | 
 |     void drainResume() override; | 
 |  | 
 |     void regProbeListeners() 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) override; | 
 |     /** | 
 |      * Read a register within the PMU. | 
 |      * | 
 |      * @param misc_reg Register number (see miscregs.hh) | 
 |      * @return Register value. | 
 |      */ | 
 |     MiscReg readMiscReg(int misc_reg) 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<15, 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; | 
 |  | 
 |   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).getValue() : 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 */ | 
 |     struct CounterState; | 
 |  | 
 |     /** | 
 |      * Event definition base class | 
 |      */ | 
 |     struct PMUEvent { | 
 |  | 
 |         PMUEvent() {} | 
 |  | 
 |         virtual ~PMUEvent() {} | 
 |  | 
 |         /** | 
 |          * attach this event to a given counter | 
 |          * | 
 |          * @param a pointer to the counter where to attach this event | 
 |          */ | 
 |         void attachEvent(PMU::CounterState *user); | 
 |  | 
 |         /** | 
 |          * detach this event from a given counter | 
 |          * | 
 |          * @param a pointer to the counter where to detach this event from | 
 |          */ | 
 |         void detachEvent(PMU::CounterState *user); | 
 |  | 
 |         /** | 
 |          * notify an event increment of val units, all the attached counters' | 
 |          * value is incremented by val units. | 
 |          * | 
 |          * @param the quantity by which to increment the attached counter | 
 |          * values | 
 |          */ | 
 |         virtual void increment(const uint64_t val); | 
 |  | 
 |         /** | 
 |          * Enable the current event | 
 |          */ | 
 |         virtual void enable() = 0; | 
 |  | 
 |         /** | 
 |          * Disable the current event | 
 |          */ | 
 |         virtual void disable() = 0; | 
 |  | 
 |         /** | 
 |          *  Method called immediately before a counter access in order for | 
 |          *  the associated event to update its state (if required) | 
 |          */ | 
 |         virtual void updateAttachedCounters() {} | 
 |  | 
 |       protected: | 
 |  | 
 |         /** set of counters using this event  **/ | 
 |         std::set<PMU::CounterState*> userCounters; | 
 |     }; | 
 |  | 
 |     struct RegularEvent : public PMUEvent { | 
 |         typedef std::pair<SimObject*, std::string> EventTypeEntry; | 
 |  | 
 |         void addMicroarchitectureProbe(SimObject* object, | 
 |             std::string name) { | 
 |  | 
 |             panic_if(!object,"malformed probe-point" | 
 |                 " definition with name %s\n", name); | 
 |  | 
 |             microArchitectureEventSet.emplace(object, name); | 
 |         } | 
 |  | 
 |       protected: | 
 |         struct RegularProbe: public  ProbeListenerArgBase<uint64_t> | 
 |         { | 
 |             RegularProbe(RegularEvent *parent, SimObject* obj, | 
 |                 std::string name) | 
 |                 : ProbeListenerArgBase(obj->getProbeManager(), name), | 
 |                   parentEvent(parent) {} | 
 |  | 
 |             RegularProbe() = delete; | 
 |  | 
 |             void notify(const uint64_t &val); | 
 |  | 
 |           protected: | 
 |             RegularEvent *parentEvent; | 
 |         }; | 
 |  | 
 |         /** The set of events driving the event value **/ | 
 |         std::set<EventTypeEntry> microArchitectureEventSet; | 
 |  | 
 |         /** Set of probe listeners tapping onto each of the input micro-arch | 
 |          *  events which compose this pmu event | 
 |          */ | 
 |         std::vector<std::unique_ptr<RegularProbe>> attachedProbePointList; | 
 |  | 
 |         void enable() override; | 
 |  | 
 |         void disable() override; | 
 |     }; | 
 |  | 
 |     class SWIncrementEvent : public PMUEvent | 
 |     { | 
 |         void enable() override {} | 
 |         void disable() override {} | 
 |  | 
 |       public: | 
 |  | 
 |         /** | 
 |          * write on the sw increment register inducing an increment of the | 
 |          * counters with this event selected according to the bitfield written. | 
 |          * | 
 |          * @param the bitfield selecting the counters to increment. | 
 |          */ | 
 |         void write(uint64_t val); | 
 |     }; | 
 |  | 
 |     /** | 
 |      * Obtain the event of a given id | 
 |      * | 
 |      * @param the id of the event to obtain | 
 |      * @return a pointer to the event with id eventId | 
 |      */ | 
 |     PMUEvent* getEvent(uint64_t eventId); | 
 |  | 
 |     /** State of a counter within the PMU. **/ | 
 |     struct CounterState : public Serializable { | 
 |         CounterState(PMU &pmuReference, uint64_t counter_id) | 
 |             : eventId(0), filter(0), enabled(false), | 
 |               overflow64(false), sourceEvent(nullptr), | 
 |               counterId(counter_id), value(0), resetValue(false), | 
 |               pmu(pmuReference) {} | 
 |  | 
 |         void serialize(CheckpointOut &cp) const override; | 
 |         void unserialize(CheckpointIn &cp)  override; | 
 |  | 
 |         /** | 
 |          * Add an event count to the counter and check for overflow. | 
 |          * | 
 |          * @param delta Number of events to add to the counter. | 
 |          * @return the quantity remaining until a counter overflow occurs. | 
 |          */ | 
 |         uint64_t add(uint64_t delta); | 
 |  | 
 |         bool isFiltered() const; | 
 |  | 
 |         /** | 
 |          * Detach the counter from its event | 
 |          */ | 
 |         void detach(); | 
 |  | 
 |         /** | 
 |          * Attach this counter to an event | 
 |          * | 
 |          * @param the event to attach the counter to | 
 |          */ | 
 |         void attach(PMUEvent* event); | 
 |  | 
 |         /** | 
 |          * Obtain the counter id | 
 |          * | 
 |          * @return the pysical counter id | 
 |          */ | 
 |         uint64_t getCounterId() const{ | 
 |             return counterId; | 
 |         } | 
 |  | 
 |         /** | 
 |          * rReturn the counter value | 
 |          * | 
 |          * @return the counter value | 
 |          */ | 
 |         uint64_t getValue() const; | 
 |  | 
 |         /** | 
 |          * overwrite the value of the counter | 
 |          * | 
 |          * @param the new counter value | 
 |          */ | 
 |         void setValue(uint64_t val); | 
 |  | 
 |       public: /* Serializable state */ | 
 |         /** Counter event ID */ | 
 |         EventTypeId eventId; | 
 |  | 
 |         /** Filtering settings (evtCount is unused) */ | 
 |         PMEVTYPER_t filter; | 
 |  | 
 |         /** Is the counter enabled? */ | 
 |         bool enabled; | 
 |  | 
 |         /** Is this a 64-bit counter? */ | 
 |         bool overflow64; | 
 |  | 
 |       protected: /* Configuration */ | 
 |         /** PmuEvent currently in use (if any) **/ | 
 |         PMUEvent *sourceEvent; | 
 |  | 
 |         /** id of the counter instance **/ | 
 |         uint64_t counterId; | 
 |  | 
 |         /** Current value of the counter */ | 
 |         uint64_t value; | 
 |  | 
 |         /** Flag keeping track if the counter has been reset **/ | 
 |         bool resetValue; | 
 |  | 
 |         PMU &pmu; | 
 |  | 
 |         template <typename ...Args> | 
 |         void debugCounter(const char* mainString, Args &...args) const { | 
 |  | 
 |             std::string userString = csprintf(mainString, args...); | 
 |  | 
 |             warn("[counterId = %d, eventId = %d, sourceEvent = 0x%x] %s", | 
 |                 counterId, eventId, sourceEvent, userString.c_str()); | 
 |  | 
 |         } | 
 |     }; | 
 |  | 
 |     /** | 
 |      * 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(CounterState &ctr); | 
 |  | 
 |     /** | 
 |      * Check if a counter's settings allow it to be counted. | 
 |      * | 
 |      * @param ctr Counter state instance representing this counter. | 
 |      * @return false if the counter is active, true otherwise. | 
 |      */ | 
 |     bool isFiltered(const CounterState &ctr) const; | 
 |  | 
 |     /** | 
 |      * 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 | 
 |      * | 
 |      * These registers contain a bitmask of available architected | 
 |      * counters. | 
 |      */ | 
 |     uint64_t reg_pmceid0; | 
 |     uint64_t reg_pmceid1; | 
 |  | 
 |     /** Remainder part when the clock counter is divided by 64 */ | 
 |     unsigned clock_remainder; | 
 |  | 
 |     /** The number of regular event counters **/ | 
 |     uint64_t maximumCounterCount; | 
 |  | 
 |     /** State of all general-purpose counters supported by PMU */ | 
 |     std::vector<CounterState> counters; | 
 |  | 
 |     /** State of the cycle counter */ | 
 |     CounterState cycleCounter; | 
 |  | 
 |     /** The id of the counter hardwired to the cpu cycle counter **/ | 
 |     const uint64_t cycleCounterEventId; | 
 |  | 
 |     /** The event that implements the software increment **/ | 
 |     SWIncrementEvent *swIncrementEvent; | 
 |  | 
 |   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; | 
 |  | 
 |     /** | 
 |      * List of event types supported by this PMU. | 
 |      */ | 
 |     std::map<EventTypeId, PMUEvent*> eventMap; | 
 | }; | 
 |  | 
 | } // namespace ArmISA | 
 | #endif |