arch-arm: ArmPMU refactor
authorJose Marinho <jose.marinho@arm.com>
Tue, 26 Sep 2017 13:33:49 +0000 (14:33 +0100)
committerAndreas Sandberg <andreas.sandberg@arm.com>
Tue, 21 Nov 2017 17:09:18 +0000 (17:09 +0000)
Change the definition of PMU events in order to integrate events not
cannot easily be represented by probe points. The software
increment event is now defined as a special type with its separate
implementation in pmu.cc and pmu.hh.

Change-Id: I43874b9641bf38c54f6ba2c26386542b6a73e282
Signed-off-by: Jose Marinho <jose.marinho@arm.com>
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/5764
Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>

src/arch/arm/ArmPMU.py
src/arch/arm/pmu.cc
src/arch/arm/pmu.hh

index 83c7dd48e81ea5a1227ae288fc4d89df27aa02fd..a87c20b4a81199ad18469d45d467e499800bc930 100644 (file)
@@ -43,38 +43,61 @@ from m5.params import *
 from m5.params import isNullPointer
 from m5.proxy import *
 
+class ProbeEvent(object):
+    def __init__(self, pmu, _eventId, obj, *listOfNames):
+        self.obj = obj
+        self.names = listOfNames
+        self.eventId = _eventId
+        self.pmu = pmu
+
+    def register(self):
+        if self.obj:
+            for name in self.names:
+                self.pmu.getCCObject().addEventProbe(self.eventId,
+                    self.obj.getCCObject(), name)
+
+class SoftwareIncrement(object):
+    def __init__(self,pmu, _eventId):
+        self.eventId = _eventId
+        self.pmu = pmu
+
+    def register(self):
+        self.pmu.getCCObject().addSoftwareIncrementEvent(self.eventId)
+
+ARCH_EVENT_CORE_CYCLES = 0x11
+
 class ArmPMU(SimObject):
+
     type = 'ArmPMU'
     cxx_class = 'ArmISA::PMU'
     cxx_header = 'arch/arm/pmu.hh'
 
     cxx_exports = [
         PyBindMethod("addEventProbe"),
+        PyBindMethod("addSoftwareIncrementEvent"),
     ]
 
-    # To prevent cycles in the configuration hierarchy, we don't keep
-    # a list of supported events as a configuration param. Instead, we
-    # keep them in a local list and register them using the
-    # addEventProbe interface when other SimObjects register their
-    # probe listeners.
-    _deferred_event_types = []
+    _events = None
+
+    def addEvent(self, newObject):
+        if not (isinstance(newObject, ProbeEvent)
+            or isinstance(newObject, SoftwareIncrement)):
+            raise TypeError("argument must be of ProbeEvent or "
+                "SoftwareIncrement type")
+
+        if not self._events:
+            self._events = []
+
+        self._events.append(newObject)
+
     # Override the normal SimObject::regProbeListeners method and
     # register deferred event handlers.
     def regProbeListeners(self):
-        for event_id, obj, name in self._deferred_event_types:
-            self.getCCObject().addEventProbe(event_id, obj.getCCObject(), name)
+        for event in self._events:
+           event.register()
 
         self.getCCObject().regProbeListeners()
 
-    def addEventProbe(self, event_id, obj, *args):
-        """Add a probe-based event to the PMU if obj is not None."""
-
-        if obj is None:
-            return
-
-        for name in args:
-            self._deferred_event_types.append((event_id, obj, name))
-
     def addArchEvents(self,
                       cpu=None,
                       itb=None, dtb=None,
@@ -95,25 +118,28 @@ class ArmPMU(SimObject):
         bpred = cpu.branchPred if cpu and not isNullPointer(cpu.branchPred) \
             else None
 
+        self.addEvent(SoftwareIncrement(self,0x00))
         # 0x01: L1I_CACHE_REFILL
-        self.addEventProbe(0x02, itb, "Refills")
+        self.addEvent(ProbeEvent(self,0x02, itb, "Refills"))
         # 0x03: L1D_CACHE_REFILL
         # 0x04: L1D_CACHE
-        self.addEventProbe(0x05, dtb, "Refills")
-        self.addEventProbe(0x06, cpu, "RetiredLoads")
-        self.addEventProbe(0x07, cpu, "RetiredStores")
-        self.addEventProbe(0x08, cpu, "RetiredInsts")
+        self.addEvent(ProbeEvent(self,0x05, dtb, "Refills"))
+        self.addEvent(ProbeEvent(self,0x06, cpu, "RetiredLoads"))
+        self.addEvent(ProbeEvent(self,0x07, cpu, "RetiredStores"))
+        self.addEvent(ProbeEvent(self,0x08, cpu, "RetiredInsts"))
         # 0x09: EXC_TAKEN
         # 0x0A: EXC_RETURN
         # 0x0B: CID_WRITE_RETIRED
-        self.addEventProbe(0x0C, cpu, "RetiredBranches")
+        self.addEvent(ProbeEvent(self,0x0C, cpu, "RetiredBranches"))
         # 0x0D: BR_IMMED_RETIRED
         # 0x0E: BR_RETURN_RETIRED
         # 0x0F: UNALIGEND_LDST_RETIRED
-        self.addEventProbe(0x10, bpred, "Misses")
-        self.addEventProbe(0x11, cpu, "ActiveCycles")
-        self.addEventProbe(0x12, bpred, "Branches")
-        self.addEventProbe(0x13, cpu, "RetiredLoads", "RetiredStores")
+        self.addEvent(ProbeEvent(self,0x10, bpred, "Misses"))
+        self.addEvent(ProbeEvent(self, ARCH_EVENT_CORE_CYCLES, cpu,
+                                 "ActiveCycles"))
+        self.addEvent(ProbeEvent(self,0x12, bpred, "Branches"))
+        self.addEvent(ProbeEvent(self,0x13, cpu, "RetiredLoads",
+                                 "RetiredStores"))
         # 0x14: L1I_CACHE
         # 0x15: L1D_CACHE_WB
         # 0x16: L2D_CACHE
@@ -144,6 +170,7 @@ class ArmPMU(SimObject):
         # 0x2F: L2D_TLB
         # 0x30: L2I_TLB
 
+    cycleEventId = Param.Int(ARCH_EVENT_CORE_CYCLES, "Cycle event id")
     platform = Param.Platform(Parent.any, "Platform this device is part of.")
     eventCounters = Param.Int(31, "Number of supported PMU counters")
     pmuInterrupt = Param.Int(68, "PMU GIC interrupt number")
index baf0d19487f0a45c8c6b2be877853a8ba54990ae..0bdae4936876d4cc24c8690973fc4977b6f0d2c1 100644 (file)
@@ -37,6 +37,7 @@
  * Authors: Dam Sunwoo
  *          Matt Horsnell
  *          Andreas Sandberg
+ *          Jose Marinho
  */
 
 #include "arch/arm/pmu.hh"
@@ -48,6 +49,7 @@
 #include "debug/Checkpoint.hh"
 #include "debug/PMUVerbose.hh"
 #include "dev/arm/base_gic.hh"
+#include "dev/arm/generic_timer.hh"
 #include "dev/arm/realview.hh"
 #include "params/ArmPMU.hh"
 
@@ -61,16 +63,19 @@ PMU::PMU(const ArmPMUParams *p)
       reg_pmselr(0), reg_pminten(0), reg_pmovsr(0),
       reg_pmceid0(0),reg_pmceid1(0),
       clock_remainder(0),
-      counters(p->eventCounters),
+      maximumCounterCount(p->eventCounters),
+      cycleCounter(*this, maximumCounterCount),
+      cycleCounterEventId(p->cycleEventId),
+      swIncrementEvent(nullptr),
       reg_pmcr_conf(0),
       pmuInterrupt(p->pmuInterrupt),
       platform(p->platform)
 {
     DPRINTF(PMUVerbose, "Initializing the PMU.\n");
 
-    if (p->eventCounters > 31) {
+    if (maximumCounterCount > 31) {
         fatal("The PMU can only accept 31 counters, %d counters requested.\n",
-              p->eventCounters);
+              maximumCounterCount);
     }
 
     /* Setup the performance counter ID registers */
@@ -87,13 +92,57 @@ PMU::~PMU()
 {
 }
 
+void
+PMU::addSoftwareIncrementEvent(unsigned int id)
+{
+    auto old_event = eventMap.find(id);
+    DPRINTF(PMUVerbose, "PMU: Adding SW increment event with id '0x%x'\n", id);
+
+    if (swIncrementEvent) {
+        fatal_if(old_event == eventMap.end() ||
+                 old_event->second != swIncrementEvent,
+                 "Trying to add a software increment event with multiple"
+                 "IDs. This is not supported.\n");
+        return;
+    }
+
+    fatal_if(old_event != eventMap.end(), "An event with id %d has "
+             "been previously defined\n", id);
+
+    swIncrementEvent = new SWIncrementEvent();
+    eventMap[id] = swIncrementEvent;
+    registerEvent(id);
+}
+
 void
 PMU::addEventProbe(unsigned int id, SimObject *obj, const char *probe_name)
 {
-    DPRINTF(PMUVerbose, "PMU: Adding event type '0x%x' as probe %s:%s\n",
-            id, obj->name(), probe_name);
-    pmuEventTypes.insert(std::make_pair(id, EventType(obj, probe_name)));
 
+    DPRINTF(PMUVerbose, "PMU: Adding Probe Driven event with id '0x%x'"
+        "as probe %s:%s\n",id, obj->name(), probe_name);
+
+    RegularEvent *event = nullptr;
+    auto event_entry = eventMap.find(id);
+    if (event_entry == eventMap.end()) {
+
+        event = new RegularEvent();
+        eventMap[id] = event;
+
+    } else {
+        event = dynamic_cast<RegularEvent*>(event_entry->second);
+        if (!event) {
+            fatal("Event with id %d is not probe driven\n", id);
+        }
+    }
+    event->addMicroarchitectureProbe(obj, probe_name);
+
+    registerEvent(id);
+
+}
+
+void
+PMU::registerEvent(uint32_t id)
+{
     // Flag the event as available in the corresponding PMCEID register if it
     // is an architected event.
     if (id < 0x20) {
@@ -114,6 +163,22 @@ PMU::drainResume()
     updateAllCounters();
 }
 
+void
+PMU::regProbeListeners()
+{
+
+    // at this stage all probe configurations are done
+    // counters can be configured
+    for (uint32_t index = 0; index < maximumCounterCount-1; index++) {
+        counters.emplace_back(*this, index);
+    }
+
+    PMUEvent *event = getEvent(cycleCounterEventId);
+    panic_if(!event, "core cycle event is not present\n");
+    cycleCounter.enabled = true;
+    cycleCounter.attach(event);
+}
+
 void
 PMU::setMiscReg(int misc_reg, MiscReg val)
 {
@@ -145,18 +210,14 @@ PMU::setMiscReg(int misc_reg, MiscReg val)
 
       case MISCREG_PMSWINC_EL0:
       case MISCREG_PMSWINC:
-        for (int i = 0; i < counters.size(); ++i) {
-            CounterState &ctr(getCounter(i));
-            if (ctr.enabled && (val & (1 << i))
-                && ctr.eventId == ARCH_EVENT_SW_INCR ) {
-                ++ctr.value;
-            }
+        if (swIncrementEvent) {
+            swIncrementEvent->write(val);
         }
-        break;
+        return;
 
       case MISCREG_PMCCNTR_EL0:
       case MISCREG_PMCCNTR:
-        cycleCounter.value = val;
+        cycleCounter.setValue(val);
         return;
 
       case MISCREG_PMSELR_EL0:
@@ -278,10 +339,10 @@ PMU::readMiscRegInt(int misc_reg)
         return reg_pmceid1 & 0xFFFFFFFF;
 
       case MISCREG_PMCCNTR_EL0:
-        return cycleCounter.value;
+        return cycleCounter.getValue();
 
       case MISCREG_PMCCNTR:
-        return cycleCounter.value & 0xFFFFFFFF;
+        return cycleCounter.getValue() & 0xFFFFFFFF;
 
       case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0:
         return getCounterTypeRegister(misc_reg - MISCREG_PMEVTYPER0_EL0);
@@ -295,8 +356,11 @@ PMU::readMiscRegInt(int misc_reg)
       case MISCREG_PMXEVTYPER:
         return getCounterTypeRegister(reg_pmselr.sel);
 
-      case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0:
-        return getCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0) & 0xFFFFFFFF;
+      case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0: {
+            return getCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0) &
+                0xFFFFFFFF;
+
+        }
 
       case MISCREG_PMXEVCNTR_EL0:
       case MISCREG_PMXEVCNTR:
@@ -334,7 +398,7 @@ PMU::setControlReg(PMCR_t val)
 
     if (val.c) {
         DPRINTF(PMUVerbose, "PMU reset cycle counter to zero.\n");
-        cycleCounter.value = 0;
+        cycleCounter.setValue(0);
     }
 
     // Reset the clock remainder if divide by 64-mode is toggled.
@@ -355,25 +419,74 @@ PMU::updateAllCounters()
         const bool enable(global_enable && (reg_pmcnten & (1 << i)));
         if (ctr.enabled != enable) {
             ctr.enabled = enable;
-            updateCounter(i, ctr);
+            updateCounter(ctr);
         }
     }
 
     const bool ccntr_enable(global_enable && (reg_pmcnten & (1 << PMCCNTR)));
     if (cycleCounter.enabled != ccntr_enable) {
         cycleCounter.enabled = ccntr_enable;
-        updateCounter(PMCCNTR, cycleCounter);
+        updateCounter(cycleCounter);
+    }
+}
+
+void
+PMU::PMUEvent::attachEvent(PMU::CounterState *user)
+{
+    if (userCounters.empty()) {
+        enable();
     }
+    userCounters.insert(user);
+    updateAttachedCounters();
+}
+
+void
+PMU::PMUEvent::increment(const uint64_t val)
+{
+    for (auto& counter: userCounters) {
+        counter->add(val);
+    }
+}
+
+void
+PMU::PMUEvent::detachEvent(PMU::CounterState *user)
+{
+    userCounters.erase(user);
+
+    if (userCounters.empty()) {
+        disable();
+    }
+}
+
+void
+PMU::RegularEvent::RegularProbe::notify(const uint64_t &val)
+{
+    parentEvent->increment(val);
+}
+
+void
+PMU::RegularEvent::enable()
+{
+    for (auto& subEvents: microArchitectureEventSet) {
+        attachedProbePointList.emplace_back(
+            new RegularProbe(this, subEvents.first, subEvents.second));
+    }
+}
+
+void
+PMU::RegularEvent::disable()
+{
+    attachedProbePointList.clear();
 }
 
 bool
-PMU::isFiltered(const CounterState &ctr) const
+PMU::CounterState::isFiltered() const
 {
-    assert(isa);
+    assert(pmu.isa);
 
-    const PMEVTYPER_t filter(ctr.filter);
-    const SCR scr(isa->readMiscRegNoEffect(MISCREG_SCR));
-    const CPSR cpsr(isa->readMiscRegNoEffect(MISCREG_CPSR));
+    const PMEVTYPER_t filter(this->filter);
+    const SCR scr(pmu.isa->readMiscRegNoEffect(MISCREG_SCR));
+    const CPSR cpsr(pmu.isa->readMiscRegNoEffect(MISCREG_CPSR));
     const ExceptionLevel el(opModeToEL((OperatingMode)(uint8_t)cpsr.mode));
     const bool secure(inSecureState(scr, cpsr));
 
@@ -396,60 +509,69 @@ PMU::isFiltered(const CounterState &ctr) const
 }
 
 void
-PMU::handleEvent(CounterId id, uint64_t delta)
+PMU::CounterState::detach()
 {
-    CounterState &ctr(getCounter(id));
-    const bool overflowed(reg_pmovsr & (1 << id));
+    if (sourceEvent) {
+        sourceEvent->detachEvent(this);
+        sourceEvent = nullptr;
+    } else {
+        debugCounter("detaching event not currently attached"
+            " to any event\n");
+    }
+}
 
-    if (isFiltered(ctr))
-        return;
+void
+PMU::CounterState::attach(PMUEvent* event)
+{
+    value = 0;
+    sourceEvent = event;
+    sourceEvent->attachEvent(this);
+}
 
-    // Handle the "count every 64 cycles" mode
-    if (id == PMCCNTR && reg_pmcr.d) {
-        clock_remainder += delta;
-        delta = (clock_remainder >> 6);
-        clock_remainder &= 63;
+uint64_t
+PMU::CounterState::getValue() const
+{
+    if (sourceEvent) {
+        sourceEvent->updateAttachedCounters();
+    } else {
+        debugCounter("attempted to get value from a counter without"
+            " an associated event\n");
     }
+    return value;
+}
 
-    // Add delta and handle (new) overflows
-    if (ctr.add(delta) && !overflowed) {
-        DPRINTF(PMUVerbose, "PMU counter '%i' overflowed.\n", id);
-        reg_pmovsr |= (1 << id);
-        // Deliver a PMU interrupt if interrupt delivery is enabled
-        // for this counter.
-        if (reg_pminten  & (1 << id))
-            raiseInterrupt();
+void
+PMU::CounterState::setValue(uint64_t val)
+{
+    value = val;
+    resetValue = true;
+
+    if (sourceEvent) {
+        sourceEvent->updateAttachedCounters();
+    } else {
+        debugCounter("attempted to set value from a counter without"
+            " an associated event\n");
     }
 }
 
 void
-PMU::updateCounter(CounterId id, CounterState &ctr)
+PMU::updateCounter(CounterState &ctr)
 {
     if (!ctr.enabled) {
-        if (!ctr.listeners.empty()) {
-            DPRINTF(PMUVerbose, "updateCounter(%i): Disabling counter\n", id);
-            ctr.listeners.clear();
-        }
+        DPRINTF(PMUVerbose, "updateCounter(%i): Disabling counter\n",
+            ctr.getCounterId());
+        ctr.detach();
+
     } else {
         DPRINTF(PMUVerbose, "updateCounter(%i): Enable event id 0x%x\n",
-                id, ctr.eventId);
-
-        // Attach all probes belonging to this event
-        auto range(pmuEventTypes.equal_range(ctr.eventId));
-        for (auto it = range.first; it != range.second; ++it) {
-            const EventType &et(it->second);
+                ctr.getCounterId(), ctr.eventId);
 
-            DPRINTF(PMUVerbose, "\tProbe: %s:%s\n", et.obj->name(), et.name);
-            ctr.listeners.emplace_back(et.create(*this, id));
-        }
-
-        /* The SW_INCR event type is a special case which doesn't need
-         * any probes since it is controlled by software and the PMU
-         * itself.
-         */
-        if (ctr.listeners.empty() && ctr.eventId != ARCH_EVENT_SW_INCR) {
+        auto sourceEvent = eventMap.find(ctr.eventId);
+        if (sourceEvent == eventMap.end()) {
             warn("Can't enable PMU counter of type '0x%x': "
                  "No such event type.\n", ctr.eventId);
+        } else {
+            ctr.attach(sourceEvent->second);
         }
     }
 }
@@ -459,7 +581,7 @@ void
 PMU::resetEventCounts()
 {
     for (CounterState &ctr : counters)
-        ctr.value = 0;
+        ctr.setValue(0);
 }
 
 void
@@ -472,7 +594,7 @@ PMU::setCounterValue(CounterId id, uint64_t val)
     }
 
     CounterState &ctr(getCounter(id));
-    ctr.value = val;
+    ctr.setValue(val);
 }
 
 PMU::PMEVTYPER_t
@@ -509,7 +631,7 @@ PMU::setCounterTypeRegister(CounterId id, PMEVTYPER_t val)
     // need to update the probes the counter is using.
     if (id != PMCCNTR && old_event_id != val.evtCount) {
         ctr.eventId = val.evtCount;
-        updateCounter(reg_pmselr.sel, ctr);
+        updateCounter(ctr);
     }
 }
 
@@ -574,6 +696,19 @@ PMU::unserialize(CheckpointIn &cp)
     cycleCounter.unserializeSection(cp, "cycleCounter");
 }
 
+PMU::PMUEvent*
+PMU::getEvent(uint64_t eventId)
+{
+    auto entry = eventMap.find(eventId);
+
+    if (entry == eventMap.end()) {
+        warn("event %d does not exist\n", eventId);
+        return nullptr;
+    } else {
+        return entry->second;
+    }
+}
+
 void
 PMU::CounterState::serialize(CheckpointOut &cp) const
 {
@@ -590,16 +725,50 @@ PMU::CounterState::unserialize(CheckpointIn &cp)
     UNSERIALIZE_SCALAR(overflow64);
 }
 
-bool
+uint64_t
 PMU::CounterState::add(uint64_t delta)
 {
-    const uint64_t msb(1ULL << (overflow64 ? 63 : 31));
-    const uint64_t old_value(value);
+    uint64_t value_until_overflow;
+    if (overflow64) {
+        value_until_overflow = UINT64_MAX - value;
+    } else {
+        value_until_overflow = UINT32_MAX - (uint32_t)value;
+    }
+
+    if (isFiltered())
+        return value_until_overflow;
+
+    if (resetValue) {
+        delta = 0;
+        resetValue = false;
+    } else {
+        value += delta;
+    }
 
-    value += delta;
+    if (delta > value_until_overflow) {
 
-    // Overflow if the msb goes from 1 to 0
-    return (old_value & msb) && !(value & msb);
+        // overflow situation detected
+        // flag the overflow occurence
+        pmu.reg_pmovsr |= (1 << counterId);
+
+        // Deliver a PMU interrupt if interrupt delivery is enabled
+        // for this counter.
+        if (pmu.reg_pminten  & (1 << counterId)) {
+            pmu.raiseInterrupt();
+        }
+        return overflow64 ? UINT64_MAX : UINT32_MAX;
+    }
+    return value_until_overflow - delta + 1;
+}
+
+void
+PMU::SWIncrementEvent::write(uint64_t val)
+{
+    for (auto& counter: userCounters) {
+        if (val & (0x1 << counter->getCounterId())) {
+            counter->add(1);
+        }
+    }
 }
 
 } // namespace ArmISA
index aecdfd84e66851c619da3540228bccd4400c97b2..7090b4a785db7408294ad50566cc6614c65e3113 100644 (file)
 
 #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;
@@ -94,6 +99,9 @@ class PMU : public SimObject, public ArmISA::BaseISADevice {
     ~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;
@@ -101,6 +109,7 @@ class PMU : public SimObject, public ArmISA::BaseISADevice {
 
     void drainResume() override;
 
+    void regProbeListeners() override;
 
   public: // ISA Device interface
     /**
@@ -183,9 +192,6 @@ class PMU : public SimObject, public ArmISA::BaseISADevice {
      */
     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);
 
@@ -220,7 +226,7 @@ class PMU : public SimObject, public ArmISA::BaseISADevice {
      * not exist.
      */
     uint64_t getCounterValue(CounterId id) const {
-        return isValidCounter(id) ? getCounter(id).value : 0;
+        return isValidCounter(id) ? getCounter(id).getValue() : 0;
     }
 
     /**
@@ -261,74 +267,135 @@ class PMU : public SimObject, public ArmISA::BaseISADevice {
     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) override
-        {
-            pmu.handleEvent(id, val);
-        }
-
-      protected:
-        PMU &pmu;
-        const CounterId id;
-    };
-    typedef std::unique_ptr<ProbeListener> ProbeListenerUPtr;
+    struct CounterState;
 
     /**
-     * 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.
+     * Event definition base class
      */
-    struct EventType {
+    struct PMUEvent {
+
+        PMUEvent() {}
+
+        virtual ~PMUEvent() {}
+
         /**
-         * @param _obj Target SimObject
-         * @param _name Probe name
+         * attach this event to a given counter
+         *
+         * @param a pointer to the counter where to attach this event
          */
-        EventType(SimObject *_obj, const std::string &_name)
-            : obj(_obj), name(_name) {}
+        void attachEvent(PMU::CounterState *user);
 
         /**
-         * Create and attach a probe used to drive this event.
+         * detach this event from a given counter
          *
-         * @param pmu PMU owning the probe.
-         * @param CounterID counter ID within the PMU.
-         * @return Pointer to a probe listener.
+         * @param a pointer to the counter where to detach this event from
          */
-        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;
-        }
+        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;
 
-        /** SimObject being measured by this probe */
-        SimObject *const obj;
-        /** Probe name within obj */
-        const std::string name;
+        /**
+         *  Method called immediately before a counter access in order for
+         *  the associated event to update its state (if required)
+         */
+        virtual void updateAttachedCounters() {}
+
+      protected:
 
-      private:
-        // Disable the default constructor
-        EventType();
+        /** set of counters using this event  **/
+        std::set<PMU::CounterState*> userCounters;
     };
 
-    /** State of a counter within the PMU. */
-    struct CounterState : public Serializable {
-        CounterState()
-            : eventId(0), filter(0), value(0), enabled(false),
-              overflow64(false) {
+    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);
 
-            listeners.reserve(4);
+            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;
 
@@ -336,9 +403,46 @@ class PMU : public SimObject, public ArmISA::BaseISADevice {
          * 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.
+         * @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
          */
-        bool add(uint64_t delta);
+        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 */
@@ -347,32 +451,37 @@ class PMU : public SimObject, public ArmISA::BaseISADevice {
         /** 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?
@@ -398,7 +507,6 @@ class PMU : public SimObject, public ArmISA::BaseISADevice {
         return id == PMCCNTR ? cycleCounter : counters[id];
     }
 
-
     /**
      * Return the state of a counter.
      *
@@ -422,7 +530,7 @@ class PMU : public SimObject, public ArmISA::BaseISADevice {
      * @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.
@@ -468,14 +576,25 @@ class PMU : public SimObject, public ArmISA::BaseISADevice {
     /** 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;
 
@@ -485,22 +604,9 @@ class PMU : public SimObject, public ArmISA::BaseISADevice {
     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>
+     * List of event types supported by this PMU.
      */
-    std::multimap<EventTypeId, EventType> pmuEventTypes;
+    std::map<EventTypeId, PMUEvent*> eventMap;
 };
 
 } // namespace ArmISA