/*
- * Copyright (c) 2011-2014 ARM Limited
+ * Copyright (c) 2011-2014, 2017-2018 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
#include "arch/arm/isa_device.hh"
#include "arch/arm/registers.hh"
-#include "sim/probe/probe.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;
+class ArmInterruptPin;
namespace ArmISA {
~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(std::ostream &os) M5_ATTR_OVERRIDE;
- void unserialize(Checkpoint *cp, const std::string &sec) M5_ATTR_OVERRIDE;
+ void serialize(CheckpointOut &cp) const override;
+ void unserialize(CheckpointIn &cp) override;
- void drainResume() M5_ATTR_OVERRIDE;
+ void drainResume() override;
+ void regProbeListeners() override;
public: // ISA Device interface
+ void setThreadContext(ThreadContext *tc) override;
+
/**
* 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;
+ void setMiscReg(int misc_reg, RegVal val) 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;
+ RegVal readMiscReg(int misc_reg) override;
protected: // PMU register types and constants
BitUnion32(PMCR_t)
EndBitUnion(PMSELR_t)
BitUnion32(PMEVTYPER_t)
- Bitfield<9, 0> evtCount;
+ Bitfield<15, 0> evtCount;
// Secure EL3 filtering
Bitfield<26> m;
*/
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);
+ RegVal readMiscRegInt(int misc_reg);
/**
* PMCR write handling
*/
void raiseInterrupt();
+ /**
+ * Clear a PMU interrupt.
+ */
+ void clearInterrupt();
+
/**
* Get the value of a performance counter.
*
* not exist.
*/
uint64_t getCounterValue(CounterId id) const {
- return isValidCounter(id) ? getCounter(id).value : 0;
+ return isValidCounter(id) ? getCounter(id).getValue() : 0;
}
/**
*/
void setCounterTypeRegister(CounterId id, PMEVTYPER_t type);
+ /**
+ * Used for writing the Overflow Flag Status Register (SET/CLR)
+ *
+ * This method implements a write to the PMOVSSET/PMOVSCLR registers.
+ * It is capturing change of state in the register bits so that
+ * the overflow interrupt can be raised/cleared as a side effect
+ * of the write.
+ *
+ * @param new_val New value of the Overflow Status Register
+ */
+ void setOverflowStatus(RegVal new_val);
+
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) {}
+ struct CounterState;
- void notify(const uint64_t &val) M5_ATTR_OVERRIDE
- {
- pmu.handleEvent(id, val);
+ /**
+ * 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:
- PMU &pmu;
- const CounterId id;
+ 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);
};
- typedef std::unique_ptr<ProbeListener> ProbeListenerUPtr;
/**
- * Event type configuration
+ * Obtain the event of a given id
*
- * 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.
+ * @param the id of the event to obtain
+ * @return a pointer to the event with id eventId
*/
- struct EventType {
- /**
- * @param _obj Target SimObject
- * @param _name Probe name
- */
- EventType(SimObject *_obj, const std::string &_name)
- : obj(_obj), name(_name) {}
+ 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;
/**
- * Create and attach a probe used to drive this event.
+ * Add an event count to the counter and check for overflow.
*
- * @param pmu PMU owning the probe.
- * @param CounterID counter ID within the PMU.
- * @return Pointer to a probe listener.
+ * @param delta Number of events to add to the counter.
+ * @return the quantity remaining until a counter overflow occurs.
*/
- 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;
- }
+ uint64_t add(uint64_t delta);
- /** SimObject being measured by this probe */
- SimObject *const obj;
- /** Probe name within obj */
- const std::string name;
+ bool isFiltered() const;
- private:
- // Disable the default constructor
- EventType();
- };
+ /**
+ * Detach the counter from its event
+ */
+ void detach();
- /** State of a counter within the PMU. */
- struct CounterState {
- CounterState()
- : eventId(0), filter(0), value(0), enabled(false),
- overflow64(false) {
+ /**
+ * Attach this counter to an event
+ *
+ * @param the event to attach the counter to
+ */
+ void attach(PMUEvent* event);
- listeners.reserve(4);
+ /**
+ * Obtain the counter id
+ *
+ * @return the pysical counter id
+ */
+ uint64_t getCounterId() const{
+ return counterId;
}
- void serialize(std::ostream &os);
- void unserialize(Checkpoint *cp, const std::string §ion);
+ /**
+ * rReturn the counter value
+ *
+ * @return the counter value
+ */
+ uint64_t getValue() const;
/**
- * Add an event count to the counter and check for overflow.
+ * overwrite the value of the counter
*
- * @param delta Number of events to add to the counter.
- * @return true on overflow, false otherwise.
+ * @param the new counter value
*/
- bool add(uint64_t delta);
+ void setValue(uint64_t val);
public: /* Serializable state */
/** Counter event ID */
/** Filtering settings (evtCount is unused) */
PMEVTYPER_t filter;
- /** 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;
- };
+ protected: /* Configuration */
+ /** PmuEvent currently in use (if any) **/
+ PMUEvent *sourceEvent;
- /**
- * 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);
+ /** 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?
return id == PMCCNTR ? cycleCounter : counters[id];
}
-
/**
* Return the state of a counter.
*
* @param id ID of counter within the PMU.
* @param ctr Reference to the counter's state
*/
- void updateCounter(CounterId id, CounterState &ctr);
+ void updateCounter(CounterState &ctr);
/**
* Check if a counter's settings allow it to be counted.
protected: /* State that needs to be serialized */
/** Performance Monitor Count Enable Register */
- MiscReg reg_pmcnten;
+ RegVal reg_pmcnten;
/** Performance Monitor Control Register */
PMCR_t reg_pmcr;
PMSELR_t reg_pmselr;
/** Performance Monitor Interrupt Enable Register */
- MiscReg reg_pminten;
+ RegVal reg_pminten;
/** Performance Monitor Overflow Status Register */
- MiscReg reg_pmovsr;
+ RegVal reg_pmovsr;
/**
* Performance counter ID register
*
- * This register contains a bitmask of available architected
+ * These registers contain a bitmask of available architected
* counters.
*/
- uint64_t reg_pmceid;
+ 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;
+ static const RegVal reg_pmcr_wr_mask;
/** Performance monitor interrupt number */
- const unsigned int pmuInterrupt;
- /** Platform this device belongs to */
- Platform *const platform;
+ ArmInterruptPin *interrupt;
/**
- * 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>
+ * List of event types supported by this PMU.
*/
- std::multimap<EventTypeId, EventType> pmuEventTypes;
+ std::map<EventTypeId, PMUEvent*> eventMap;
};
} // namespace ArmISA