49 #include "debug/Checkpoint.hh" 50 #include "debug/PMUVerbose.hh" 53 #include "params/ArmPMU.hh" 61 reg_pmcnten(0), reg_pmcr(0),
62 reg_pmselr(0), reg_pminten(0), reg_pmovsr(0),
63 reg_pmceid0(0),reg_pmceid1(0),
65 maximumCounterCount(p->eventCounters),
66 cycleCounter(*this, maximumCounterCount),
67 cycleCounterEventId(p->cycleEventId),
68 swIncrementEvent(nullptr),
72 DPRINTF(PMUVerbose,
"Initializing the PMU.\n");
75 fatal(
"The PMU can only accept 31 counters, %d counters requested.\n",
79 warn_if(!p->interrupt,
"ARM PMU: No interrupt specified, interrupt " \
80 "delivery disabled.\n");
100 auto pmu_params =
static_cast<const ArmPMUParams *
>(
params());
102 if (pmu_params->interrupt)
103 interrupt = pmu_params->interrupt->get(tc);
110 DPRINTF(PMUVerbose,
"PMU: Adding SW increment event with id '0x%x'\n",
id);
115 "Trying to add a software increment event with multiple" 116 "IDs. This is not supported.\n");
121 "been previously defined\n",
id);
132 DPRINTF(PMUVerbose,
"PMU: Adding Probe Driven event with id '0x%x'" 133 "as probe %s:%s\n",
id, obj->
name(), probe_name);
136 auto event_entry =
eventMap.find(
id);
137 if (event_entry ==
eventMap.end()) {
139 event =
new RegularEvent();
143 event =
dynamic_cast<RegularEvent*
>(event_entry->second);
145 fatal(
"Event with id %d is not probe driven\n",
id);
148 event->addMicroarchitectureProbe(obj, probe_name);
161 }
else if (
id > 0x20 &&
id < 0x40) {
163 }
else if (
id >= 0x4000 &&
id < 0x4020) {
164 reg_pmceid0 |= ((uint64_t)1) << (
id - 0x4000 + 32);
165 }
else if (
id >= 0x4020 &&
id < 0x4040) {
166 reg_pmceid1 |= ((uint64_t)1) << (
id - 0x4020 + 32);
196 DPRINTF(PMUVerbose,
"setMiscReg(%s, 0x%x)\n",
252 DPRINTF(PMUVerbose,
"Setting PMCCFILTR: 0x%x\n", val);
259 DPRINTF(PMUVerbose,
"Setting counter type: " 260 "[PMSELR: 0x%x, PMSELER.sel: 0x%x, EVTYPER: 0x%x]\n",
298 warn(
"Not doing anything for write to miscreg %s\n",
306 DPRINTF(PMUVerbose,
"readMiscReg(%s): 0x%x\n",
396 warn(
"Not doing anything for read from miscreg %s\n",
404 DPRINTF(PMUVerbose,
"Set Control Reg 0x%08x.\n", val);
407 DPRINTF(PMUVerbose,
"PMU reset all events to zero.\n");
412 DPRINTF(PMUVerbose,
"PMU reset cycle counter to zero.\n");
427 const bool global_enable(
reg_pmcr.e);
448 if (userCounters.empty()) {
451 userCounters.insert(user);
452 updateAttachedCounters();
458 for (
auto& counter: userCounters) {
466 userCounters.erase(user);
468 if (userCounters.empty()) {
476 parentEvent->increment(val);
482 for (
auto& subEvents: microArchitectureEventSet) {
483 attachedProbePointList.emplace_back(
484 new RegularProbe(
this, subEvents.first, subEvents.second));
491 attachedProbePointList.clear();
499 const PMEVTYPER_t filter(this->filter);
500 const SCR scr(pmu.isa->readMiscRegNoEffect(
MISCREG_SCR));
501 const CPSR cpsr(pmu.isa->readMiscRegNoEffect(
MISCREG_CPSR));
507 return secure ? filter.u : (filter.u != filter.nsu);
510 return secure ? filter.p : (filter.p != filter.nsk);
516 return filter.p != filter.m;
519 panic(
"Unexpected execution level in PMU::isFiltered.\n");
527 sourceEvent->detachEvent(
this);
528 sourceEvent =
nullptr;
530 debugCounter(
"detaching event not currently attached" 543 sourceEvent->attachEvent(
this);
550 sourceEvent->updateAttachedCounters();
552 debugCounter(
"attempted to get value from a counter without" 553 " an associated event\n");
565 sourceEvent->updateAttachedCounters();
567 debugCounter(
"attempted to set value from a counter without" 568 " an associated event\n");
576 DPRINTF(PMUVerbose,
"updateCounter(%i): Disabling counter\n",
581 DPRINTF(PMUVerbose,
"updateCounter(%i): Enable event id 0x%x\n",
585 if (sourceEvent ==
eventMap.end()) {
586 warn(
"Can't enable PMU counter of type '0x%x': " 587 "No such event type.\n", ctr.
eventId);
589 ctr.
attach(sourceEvent->second);
606 warn_once(
"Can't change counter value: Counter %i does not exist.\n",
632 DPRINTF(PMUVerbose,
"Set Event [%d] = 0x%08x\n",
id, val);
634 warn_once(
"Can't change counter type: Counter %i does not exist.\n",
647 if (
id !=
PMCCNTR && old_event_id != val.evtCount) {
657 const bool int_new = new_val != 0;
660 if (int_old && !int_new) {
671 DPRINTF(PMUVerbose,
"Delivering PMU interrupt.\n");
674 warn_once(
"Dropping PMU interrupt as no interrupt has " 683 DPRINTF(PMUVerbose,
"Clearing PMU interrupt.\n");
686 warn_once(
"Dropping PMU interrupt as no interrupt has " 694 DPRINTF(Checkpoint,
"Serializing Arm PMU\n");
714 DPRINTF(Checkpoint,
"Unserializing Arm PMU\n");
742 auto entry =
eventMap.find(eventId);
745 warn(
"event %d does not exist\n", eventId);
748 return entry->second;
771 uint64_t value_until_overflow;
773 value_until_overflow = UINT64_MAX - value;
775 value_until_overflow = UINT32_MAX - (uint32_t)value;
779 return value_until_overflow;
788 if (delta > value_until_overflow) {
792 pmu.reg_pmovsr |= (1 << counterId);
796 if (pmu.reg_pminten & (1 << counterId)) {
797 pmu.raiseInterrupt();
799 return overflow64 ? UINT64_MAX : UINT32_MAX;
801 return value_until_overflow - delta + 1;
807 for (
auto& counter: userCounters) {
808 if (val & (0x1 << counter->getCounterId())) {
817 ArmPMUParams::create()
RegVal reg_pminten
Performance Monitor Interrupt Enable Register.
void updateAllCounters()
Call updateCounter() for each counter in the PMU if the counter's state has changed.
void enable() override
Enable the current event.
#define panic(...)
This implements a cprintf based panic() function.
void drainResume() override
Resume execution after a successful drain.
unsigned clock_remainder
Remainder part when the clock counter is divided by 64.
RegVal reg_pmcnten
Performance Monitor Count Enable Register.
static ExceptionLevel currEL(ThreadContext *tc)
#define fatal(...)
This implements a cprintf based fatal() function.
void detachEvent(PMU::CounterState *user)
detach this event from a given counter
void serializeSection(CheckpointOut &cp, const char *name) const
Serialize an object into a new section.
This module implements the global system counter and the local per-CPU architected timers as specifie...
uint64_t reg_pmceid0
Performance counter ID register.
#define UNSERIALIZE_OPT_SCALAR(scalar)
CounterState & getCounter(CounterId id)
Return the state of a counter.
void addEventProbe(unsigned int id, SimObject *obj, const char *name)
void unserializeSection(CheckpointIn &cp, const char *name)
Unserialize an a child object.
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Model of an ARM PMU version 3.
std::map< EventTypeId, PMUEvent * > eventMap
List of event types supported by this PMU.
void unserialize(CheckpointIn &cp) override
Unserialize an object.
RegVal readMiscRegInt(int misc_reg)
PMSELR_t reg_pmselr
Performance Monitor Selection Register.
void clearInterrupt()
Clear a PMU interrupt.
PMCR_t reg_pmcr
Performance Monitor Control Register.
Base class for devices that use the MiscReg interfaces.
virtual void clear()=0
Clear a signalled interrupt.
bool isFiltered(const CounterState &ctr) const
Check if a counter's settings allow it to be counted.
CounterState cycleCounter
State of the cycle counter.
uint64_t getCounterValue(CounterId id) const
Get the value of a performance counter.
const uint64_t cycleCounterEventId
The id of the counter hardwired to the cpu cycle counter.
const char *const miscRegName[]
Event definition base class.
void regProbeListeners() override
Register probe listeners for this object.
void setThreadContext(ThreadContext *tc) override
void detach()
Detach the counter from its event.
ThreadContext is the external interface to all thread state for anything outside of the CPU...
void disable() override
Disable the current event.
uint64_t maximumCounterCount
The number of regular event counters.
void addSoftwareIncrementEvent(unsigned int id)
#define UNSERIALIZE_SCALAR(scalar)
int unflattenMiscReg(int reg)
std::string csprintf(const char *format, const Args &...args)
std::vector< CounterState > counters
State of all general-purpose counters supported by PMU.
void setOverflowStatus(RegVal new_val)
Used for writing the Overflow Flag Status Register (SET/CLR)
ArmInterruptPin * interrupt
Performance monitor interrupt number.
const Params * params() const
void raiseInterrupt()
Deliver a PMU interrupt to the GIC.
#define warn_if(cond,...)
Conditional warning macro that checks the supplied condition and only prints a warning if the conditi...
void registerEvent(uint32_t id)
uint64_t getValue() const
rReturn the counter value
void setValue(uint64_t val)
overwrite the value of the counter
void setControlReg(PMCR_t val)
PMCR write handling.
#define fatal_if(cond,...)
Conditional fatal macro that checks the supplied condition and only causes a fatal error if the condi...
virtual void increment(const uint64_t val)
notify an event increment of val units, all the attached counters' value is incremented by val units...
void resetEventCounts()
Reset all event counters excluding the cycle counter to zero.
virtual const std::string name() const
void updateCounter(CounterState &ctr)
Depending on counter configuration, add or remove the probes driving the counter. ...
PMEVTYPER_t filter
Filtering settings (evtCount is unused)
void setCounterValue(CounterId id, uint64_t val)
Set the value of a performance counter.
#define SERIALIZE_SCALAR(scalar)
bool isValidCounter(CounterId id) const
Is this a valid counter ID?
PMCR_t reg_pmcr_conf
Constant (configuration-dependent) part of the PMCR.
PMU(const ArmPMUParams *p)
void attachEvent(PMU::CounterState *user)
attach this event to a given counter
RegVal reg_pmovsr
Performance Monitor Overflow Status Register.
Base class for ARM GIC implementations.
virtual void raise()=0
Signal an interrupt.
SWIncrementEvent * swIncrementEvent
The event that implements the software increment.
std::ostream CheckpointOut
void write(uint64_t val)
write on the sw increment register inducing an increment of the counters with this event selected acc...
PMUEvent * getEvent(uint64_t eventId)
Obtain the event of a given id.
void serialize(CheckpointOut &cp) const override
Serialize an object.
static const CounterId PMCCNTR
Cycle Count Register Number.
virtual ContextID contextId() const =0
unsigned int EventTypeId
Event type ID.
void setCounterTypeRegister(CounterId id, PMEVTYPER_t type)
Set the type and filter settings of a performance counter (PMEVTYPER)
void paramIn(CheckpointIn &cp, const string &name, ExtMachInst &machInst)
void setMiscReg(int misc_reg, RegVal val) override
Set a register within the PMU.
RegVal readMiscReg(int misc_reg) override
Read a register within the PMU.
EventTypeId eventId
Counter event ID.
bool inSecureState(ThreadContext *tc)
uint64_t getCounterId() const
Obtain the counter id.
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
uint64_t add(uint64_t delta)
Add an event count to the counter and check for overflow.
ProbePointArg< uint64_t > PMU
PMU probe point.
PMEVTYPER_t getCounterTypeRegister(CounterId id) const
Get the type and filter settings of a counter (PMEVTYPER)
static const RegVal reg_pmcr_wr_mask
PMCR write mask when accessed from the guest.
void serialize(CheckpointOut &cp) const override
Serialize an object.
Abstract superclass for simulation objects.
void attach(PMUEvent *event)
Attach this counter to an event.
State of a counter within the PMU.
void notify(const uint64_t &val)
bool enabled
Is the counter enabled?