pmu.cc (12278:3a5e50b4f9d9) pmu.cc (12286:fb69c03c88e1)
1/*
2 * Copyright (c) 2011-2014, 2017 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software

--- 23 unchanged lines hidden (view full) ---

32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 * Authors: Dam Sunwoo
38 * Matt Horsnell
39 * Andreas Sandberg
1/*
2 * Copyright (c) 2011-2014, 2017 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software

--- 23 unchanged lines hidden (view full) ---

32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 * Authors: Dam Sunwoo
38 * Matt Horsnell
39 * Andreas Sandberg
40 * Jose Marinho
40 */
41
42#include "arch/arm/pmu.hh"
43
44#include "arch/arm/isa.hh"
45#include "arch/arm/utility.hh"
46#include "base/trace.hh"
47#include "cpu/base.hh"
48#include "debug/Checkpoint.hh"
49#include "debug/PMUVerbose.hh"
50#include "dev/arm/base_gic.hh"
41 */
42
43#include "arch/arm/pmu.hh"
44
45#include "arch/arm/isa.hh"
46#include "arch/arm/utility.hh"
47#include "base/trace.hh"
48#include "cpu/base.hh"
49#include "debug/Checkpoint.hh"
50#include "debug/PMUVerbose.hh"
51#include "dev/arm/base_gic.hh"
52#include "dev/arm/generic_timer.hh"
51#include "dev/arm/realview.hh"
52#include "params/ArmPMU.hh"
53
54namespace ArmISA {
55
56const MiscReg PMU::reg_pmcr_wr_mask = 0x39;
57
58PMU::PMU(const ArmPMUParams *p)
59 : SimObject(p), BaseISADevice(),
60 reg_pmcnten(0), reg_pmcr(0),
61 reg_pmselr(0), reg_pminten(0), reg_pmovsr(0),
62 reg_pmceid0(0),reg_pmceid1(0),
63 clock_remainder(0),
53#include "dev/arm/realview.hh"
54#include "params/ArmPMU.hh"
55
56namespace ArmISA {
57
58const MiscReg PMU::reg_pmcr_wr_mask = 0x39;
59
60PMU::PMU(const ArmPMUParams *p)
61 : SimObject(p), BaseISADevice(),
62 reg_pmcnten(0), reg_pmcr(0),
63 reg_pmselr(0), reg_pminten(0), reg_pmovsr(0),
64 reg_pmceid0(0),reg_pmceid1(0),
65 clock_remainder(0),
64 counters(p->eventCounters),
66 maximumCounterCount(p->eventCounters),
67 cycleCounter(*this, maximumCounterCount),
68 cycleCounterEventId(p->cycleEventId),
69 swIncrementEvent(nullptr),
65 reg_pmcr_conf(0),
66 pmuInterrupt(p->pmuInterrupt),
67 platform(p->platform)
68{
69 DPRINTF(PMUVerbose, "Initializing the PMU.\n");
70
70 reg_pmcr_conf(0),
71 pmuInterrupt(p->pmuInterrupt),
72 platform(p->platform)
73{
74 DPRINTF(PMUVerbose, "Initializing the PMU.\n");
75
71 if (p->eventCounters > 31) {
76 if (maximumCounterCount > 31) {
72 fatal("The PMU can only accept 31 counters, %d counters requested.\n",
77 fatal("The PMU can only accept 31 counters, %d counters requested.\n",
73 p->eventCounters);
78 maximumCounterCount);
74 }
75
76 /* Setup the performance counter ID registers */
77 reg_pmcr_conf.imp = 0x41; // ARM Ltd.
78 reg_pmcr_conf.idcode = 0x00;
79 reg_pmcr_conf.n = p->eventCounters;
80
81 // Setup the hard-coded cycle counter, which is equivalent to
82 // architected counter event type 0x11.
83 cycleCounter.eventId = 0x11;
84}
85
86PMU::~PMU()
87{
88}
89
90void
79 }
80
81 /* Setup the performance counter ID registers */
82 reg_pmcr_conf.imp = 0x41; // ARM Ltd.
83 reg_pmcr_conf.idcode = 0x00;
84 reg_pmcr_conf.n = p->eventCounters;
85
86 // Setup the hard-coded cycle counter, which is equivalent to
87 // architected counter event type 0x11.
88 cycleCounter.eventId = 0x11;
89}
90
91PMU::~PMU()
92{
93}
94
95void
96PMU::addSoftwareIncrementEvent(unsigned int id)
97{
98 auto old_event = eventMap.find(id);
99 DPRINTF(PMUVerbose, "PMU: Adding SW increment event with id '0x%x'\n", id);
100
101 if (swIncrementEvent) {
102 fatal_if(old_event == eventMap.end() ||
103 old_event->second != swIncrementEvent,
104 "Trying to add a software increment event with multiple"
105 "IDs. This is not supported.\n");
106 return;
107 }
108
109 fatal_if(old_event != eventMap.end(), "An event with id %d has "
110 "been previously defined\n", id);
111
112 swIncrementEvent = new SWIncrementEvent();
113 eventMap[id] = swIncrementEvent;
114 registerEvent(id);
115}
116
117void
91PMU::addEventProbe(unsigned int id, SimObject *obj, const char *probe_name)
92{
118PMU::addEventProbe(unsigned int id, SimObject *obj, const char *probe_name)
119{
93 DPRINTF(PMUVerbose, "PMU: Adding event type '0x%x' as probe %s:%s\n",
94 id, obj->name(), probe_name);
95 pmuEventTypes.insert(std::make_pair(id, EventType(obj, probe_name)));
96
120
121 DPRINTF(PMUVerbose, "PMU: Adding Probe Driven event with id '0x%x'"
122 "as probe %s:%s\n",id, obj->name(), probe_name);
123
124 RegularEvent *event = nullptr;
125 auto event_entry = eventMap.find(id);
126 if (event_entry == eventMap.end()) {
127
128 event = new RegularEvent();
129 eventMap[id] = event;
130
131 } else {
132 event = dynamic_cast<RegularEvent*>(event_entry->second);
133 if (!event) {
134 fatal("Event with id %d is not probe driven\n", id);
135 }
136 }
137 event->addMicroarchitectureProbe(obj, probe_name);
138
139 registerEvent(id);
140
141}
142
143void
144PMU::registerEvent(uint32_t id)
145{
97 // Flag the event as available in the corresponding PMCEID register if it
98 // is an architected event.
99 if (id < 0x20) {
100 reg_pmceid0 |= ((uint64_t)1) << id;
101 } else if (id > 0x20 && id < 0x40) {
102 reg_pmceid1 |= ((uint64_t)1) << (id - 0x20);
103 } else if (id >= 0x4000 && id < 0x4020) {
104 reg_pmceid0 |= ((uint64_t)1) << (id - 0x4000 + 32);

--- 5 unchanged lines hidden (view full) ---

110void
111PMU::drainResume()
112{
113 // Re-attach enabled counters after a resume in case they changed.
114 updateAllCounters();
115}
116
117void
146 // Flag the event as available in the corresponding PMCEID register if it
147 // is an architected event.
148 if (id < 0x20) {
149 reg_pmceid0 |= ((uint64_t)1) << id;
150 } else if (id > 0x20 && id < 0x40) {
151 reg_pmceid1 |= ((uint64_t)1) << (id - 0x20);
152 } else if (id >= 0x4000 && id < 0x4020) {
153 reg_pmceid0 |= ((uint64_t)1) << (id - 0x4000 + 32);

--- 5 unchanged lines hidden (view full) ---

159void
160PMU::drainResume()
161{
162 // Re-attach enabled counters after a resume in case they changed.
163 updateAllCounters();
164}
165
166void
167PMU::regProbeListeners()
168{
169
170 // at this stage all probe configurations are done
171 // counters can be configured
172 for (uint32_t index = 0; index < maximumCounterCount-1; index++) {
173 counters.emplace_back(*this, index);
174 }
175
176 PMUEvent *event = getEvent(cycleCounterEventId);
177 panic_if(!event, "core cycle event is not present\n");
178 cycleCounter.enabled = true;
179 cycleCounter.attach(event);
180}
181
182void
118PMU::setMiscReg(int misc_reg, MiscReg val)
119{
120 DPRINTF(PMUVerbose, "setMiscReg(%s, 0x%x)\n",
121 miscRegName[unflattenMiscReg(misc_reg)], val);
122
123 switch (unflattenMiscReg(misc_reg)) {
124 case MISCREG_PMCR_EL0:
125 case MISCREG_PMCR:

--- 14 unchanged lines hidden (view full) ---

140
141 case MISCREG_PMOVSCLR_EL0:
142 case MISCREG_PMOVSR:
143 reg_pmovsr &= ~val;
144 return;
145
146 case MISCREG_PMSWINC_EL0:
147 case MISCREG_PMSWINC:
183PMU::setMiscReg(int misc_reg, MiscReg val)
184{
185 DPRINTF(PMUVerbose, "setMiscReg(%s, 0x%x)\n",
186 miscRegName[unflattenMiscReg(misc_reg)], val);
187
188 switch (unflattenMiscReg(misc_reg)) {
189 case MISCREG_PMCR_EL0:
190 case MISCREG_PMCR:

--- 14 unchanged lines hidden (view full) ---

205
206 case MISCREG_PMOVSCLR_EL0:
207 case MISCREG_PMOVSR:
208 reg_pmovsr &= ~val;
209 return;
210
211 case MISCREG_PMSWINC_EL0:
212 case MISCREG_PMSWINC:
148 for (int i = 0; i < counters.size(); ++i) {
149 CounterState &ctr(getCounter(i));
150 if (ctr.enabled && (val & (1 << i))
151 && ctr.eventId == ARCH_EVENT_SW_INCR ) {
152 ++ctr.value;
153 }
213 if (swIncrementEvent) {
214 swIncrementEvent->write(val);
154 }
215 }
155 break;
216 return;
156
157 case MISCREG_PMCCNTR_EL0:
158 case MISCREG_PMCCNTR:
217
218 case MISCREG_PMCCNTR_EL0:
219 case MISCREG_PMCCNTR:
159 cycleCounter.value = val;
220 cycleCounter.setValue(val);
160 return;
161
162 case MISCREG_PMSELR_EL0:
163 case MISCREG_PMSELR:
164 reg_pmselr = val;
165 return;
166 //TODO: implement MISCREF_PMCEID{2,3}
167 case MISCREG_PMCEID0_EL0:

--- 105 unchanged lines hidden (view full) ---

273 //TODO: implement MISCREF_PMCEID{2,3}
274 case MISCREG_PMCEID0: // Common Event ID register
275 return reg_pmceid0 & 0xFFFFFFFF;
276
277 case MISCREG_PMCEID1: // Common Event ID register
278 return reg_pmceid1 & 0xFFFFFFFF;
279
280 case MISCREG_PMCCNTR_EL0:
221 return;
222
223 case MISCREG_PMSELR_EL0:
224 case MISCREG_PMSELR:
225 reg_pmselr = val;
226 return;
227 //TODO: implement MISCREF_PMCEID{2,3}
228 case MISCREG_PMCEID0_EL0:

--- 105 unchanged lines hidden (view full) ---

334 //TODO: implement MISCREF_PMCEID{2,3}
335 case MISCREG_PMCEID0: // Common Event ID register
336 return reg_pmceid0 & 0xFFFFFFFF;
337
338 case MISCREG_PMCEID1: // Common Event ID register
339 return reg_pmceid1 & 0xFFFFFFFF;
340
341 case MISCREG_PMCCNTR_EL0:
281 return cycleCounter.value;
342 return cycleCounter.getValue();
282
283 case MISCREG_PMCCNTR:
343
344 case MISCREG_PMCCNTR:
284 return cycleCounter.value & 0xFFFFFFFF;
345 return cycleCounter.getValue() & 0xFFFFFFFF;
285
286 case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0:
287 return getCounterTypeRegister(misc_reg - MISCREG_PMEVTYPER0_EL0);
288
289 case MISCREG_PMCCFILTR:
290 case MISCREG_PMCCFILTR_EL0:
291 return getCounterTypeRegister(PMCCNTR);
292
293 case MISCREG_PMXEVTYPER_PMCCFILTR:
294 case MISCREG_PMXEVTYPER_EL0:
295 case MISCREG_PMXEVTYPER:
296 return getCounterTypeRegister(reg_pmselr.sel);
297
346
347 case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0:
348 return getCounterTypeRegister(misc_reg - MISCREG_PMEVTYPER0_EL0);
349
350 case MISCREG_PMCCFILTR:
351 case MISCREG_PMCCFILTR_EL0:
352 return getCounterTypeRegister(PMCCNTR);
353
354 case MISCREG_PMXEVTYPER_PMCCFILTR:
355 case MISCREG_PMXEVTYPER_EL0:
356 case MISCREG_PMXEVTYPER:
357 return getCounterTypeRegister(reg_pmselr.sel);
358
298 case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0:
299 return getCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0) & 0xFFFFFFFF;
359 case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0: {
360 return getCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0) &
361 0xFFFFFFFF;
300
362
363 }
364
301 case MISCREG_PMXEVCNTR_EL0:
302 case MISCREG_PMXEVCNTR:
303 return getCounterValue(reg_pmselr.sel) & 0xFFFFFFFF;
304
305 case MISCREG_PMUSERENR_EL0:
306 case MISCREG_PMUSERENR:
307 // TODO
308 return 0;

--- 20 unchanged lines hidden (view full) ---

329
330 if (val.p) {
331 DPRINTF(PMUVerbose, "PMU reset all events to zero.\n");
332 resetEventCounts();
333 }
334
335 if (val.c) {
336 DPRINTF(PMUVerbose, "PMU reset cycle counter to zero.\n");
365 case MISCREG_PMXEVCNTR_EL0:
366 case MISCREG_PMXEVCNTR:
367 return getCounterValue(reg_pmselr.sel) & 0xFFFFFFFF;
368
369 case MISCREG_PMUSERENR_EL0:
370 case MISCREG_PMUSERENR:
371 // TODO
372 return 0;

--- 20 unchanged lines hidden (view full) ---

393
394 if (val.p) {
395 DPRINTF(PMUVerbose, "PMU reset all events to zero.\n");
396 resetEventCounts();
397 }
398
399 if (val.c) {
400 DPRINTF(PMUVerbose, "PMU reset cycle counter to zero.\n");
337 cycleCounter.value = 0;
401 cycleCounter.setValue(0);
338 }
339
340 // Reset the clock remainder if divide by 64-mode is toggled.
341 if (reg_pmcr.d != val.d)
342 clock_remainder = 0;
343
344 reg_pmcr = val & reg_pmcr_wr_mask;
345 updateAllCounters();

--- 4 unchanged lines hidden (view full) ---

350{
351 const bool global_enable(reg_pmcr.e);
352
353 for (int i = 0; i < counters.size(); ++i) {
354 CounterState &ctr(counters[i]);
355 const bool enable(global_enable && (reg_pmcnten & (1 << i)));
356 if (ctr.enabled != enable) {
357 ctr.enabled = enable;
402 }
403
404 // Reset the clock remainder if divide by 64-mode is toggled.
405 if (reg_pmcr.d != val.d)
406 clock_remainder = 0;
407
408 reg_pmcr = val & reg_pmcr_wr_mask;
409 updateAllCounters();

--- 4 unchanged lines hidden (view full) ---

414{
415 const bool global_enable(reg_pmcr.e);
416
417 for (int i = 0; i < counters.size(); ++i) {
418 CounterState &ctr(counters[i]);
419 const bool enable(global_enable && (reg_pmcnten & (1 << i)));
420 if (ctr.enabled != enable) {
421 ctr.enabled = enable;
358 updateCounter(i, ctr);
422 updateCounter(ctr);
359 }
360 }
361
362 const bool ccntr_enable(global_enable && (reg_pmcnten & (1 << PMCCNTR)));
363 if (cycleCounter.enabled != ccntr_enable) {
364 cycleCounter.enabled = ccntr_enable;
423 }
424 }
425
426 const bool ccntr_enable(global_enable && (reg_pmcnten & (1 << PMCCNTR)));
427 if (cycleCounter.enabled != ccntr_enable) {
428 cycleCounter.enabled = ccntr_enable;
365 updateCounter(PMCCNTR, cycleCounter);
429 updateCounter(cycleCounter);
366 }
367}
368
430 }
431}
432
433void
434PMU::PMUEvent::attachEvent(PMU::CounterState *user)
435{
436 if (userCounters.empty()) {
437 enable();
438 }
439 userCounters.insert(user);
440 updateAttachedCounters();
441}
442
443void
444PMU::PMUEvent::increment(const uint64_t val)
445{
446 for (auto& counter: userCounters) {
447 counter->add(val);
448 }
449}
450
451void
452PMU::PMUEvent::detachEvent(PMU::CounterState *user)
453{
454 userCounters.erase(user);
455
456 if (userCounters.empty()) {
457 disable();
458 }
459}
460
461void
462PMU::RegularEvent::RegularProbe::notify(const uint64_t &val)
463{
464 parentEvent->increment(val);
465}
466
467void
468PMU::RegularEvent::enable()
469{
470 for (auto& subEvents: microArchitectureEventSet) {
471 attachedProbePointList.emplace_back(
472 new RegularProbe(this, subEvents.first, subEvents.second));
473 }
474}
475
476void
477PMU::RegularEvent::disable()
478{
479 attachedProbePointList.clear();
480}
481
369bool
482bool
370PMU::isFiltered(const CounterState &ctr) const
483PMU::CounterState::isFiltered() const
371{
484{
372 assert(isa);
485 assert(pmu.isa);
373
486
374 const PMEVTYPER_t filter(ctr.filter);
375 const SCR scr(isa->readMiscRegNoEffect(MISCREG_SCR));
376 const CPSR cpsr(isa->readMiscRegNoEffect(MISCREG_CPSR));
487 const PMEVTYPER_t filter(this->filter);
488 const SCR scr(pmu.isa->readMiscRegNoEffect(MISCREG_SCR));
489 const CPSR cpsr(pmu.isa->readMiscRegNoEffect(MISCREG_CPSR));
377 const ExceptionLevel el(opModeToEL((OperatingMode)(uint8_t)cpsr.mode));
378 const bool secure(inSecureState(scr, cpsr));
379
380 switch (el) {
381 case EL0:
382 return secure ? filter.u : (filter.u != filter.nsu);
383
384 case EL1:

--- 6 unchanged lines hidden (view full) ---

391 return filter.p != filter.m;
392
393 default:
394 panic("Unexpected execution level in PMU::isFiltered.\n");
395 }
396}
397
398void
490 const ExceptionLevel el(opModeToEL((OperatingMode)(uint8_t)cpsr.mode));
491 const bool secure(inSecureState(scr, cpsr));
492
493 switch (el) {
494 case EL0:
495 return secure ? filter.u : (filter.u != filter.nsu);
496
497 case EL1:

--- 6 unchanged lines hidden (view full) ---

504 return filter.p != filter.m;
505
506 default:
507 panic("Unexpected execution level in PMU::isFiltered.\n");
508 }
509}
510
511void
399PMU::handleEvent(CounterId id, uint64_t delta)
512PMU::CounterState::detach()
400{
513{
401 CounterState &ctr(getCounter(id));
402 const bool overflowed(reg_pmovsr & (1 << id));
514 if (sourceEvent) {
515 sourceEvent->detachEvent(this);
516 sourceEvent = nullptr;
517 } else {
518 debugCounter("detaching event not currently attached"
519 " to any event\n");
520 }
521}
403
522
404 if (isFiltered(ctr))
405 return;
523void
524PMU::CounterState::attach(PMUEvent* event)
525{
526 value = 0;
527 sourceEvent = event;
528 sourceEvent->attachEvent(this);
529}
406
530
407 // Handle the "count every 64 cycles" mode
408 if (id == PMCCNTR && reg_pmcr.d) {
409 clock_remainder += delta;
410 delta = (clock_remainder >> 6);
411 clock_remainder &= 63;
531uint64_t
532PMU::CounterState::getValue() const
533{
534 if (sourceEvent) {
535 sourceEvent->updateAttachedCounters();
536 } else {
537 debugCounter("attempted to get value from a counter without"
538 " an associated event\n");
412 }
539 }
540 return value;
541}
413
542
414 // Add delta and handle (new) overflows
415 if (ctr.add(delta) && !overflowed) {
416 DPRINTF(PMUVerbose, "PMU counter '%i' overflowed.\n", id);
417 reg_pmovsr |= (1 << id);
418 // Deliver a PMU interrupt if interrupt delivery is enabled
419 // for this counter.
420 if (reg_pminten & (1 << id))
421 raiseInterrupt();
543void
544PMU::CounterState::setValue(uint64_t val)
545{
546 value = val;
547 resetValue = true;
548
549 if (sourceEvent) {
550 sourceEvent->updateAttachedCounters();
551 } else {
552 debugCounter("attempted to set value from a counter without"
553 " an associated event\n");
422 }
423}
424
425void
554 }
555}
556
557void
426PMU::updateCounter(CounterId id, CounterState &ctr)
558PMU::updateCounter(CounterState &ctr)
427{
428 if (!ctr.enabled) {
559{
560 if (!ctr.enabled) {
429 if (!ctr.listeners.empty()) {
430 DPRINTF(PMUVerbose, "updateCounter(%i): Disabling counter\n", id);
431 ctr.listeners.clear();
432 }
561 DPRINTF(PMUVerbose, "updateCounter(%i): Disabling counter\n",
562 ctr.getCounterId());
563 ctr.detach();
564
433 } else {
434 DPRINTF(PMUVerbose, "updateCounter(%i): Enable event id 0x%x\n",
565 } else {
566 DPRINTF(PMUVerbose, "updateCounter(%i): Enable event id 0x%x\n",
435 id, ctr.eventId);
567 ctr.getCounterId(), ctr.eventId);
436
568
437 // Attach all probes belonging to this event
438 auto range(pmuEventTypes.equal_range(ctr.eventId));
439 for (auto it = range.first; it != range.second; ++it) {
440 const EventType &et(it->second);
441
442 DPRINTF(PMUVerbose, "\tProbe: %s:%s\n", et.obj->name(), et.name);
443 ctr.listeners.emplace_back(et.create(*this, id));
444 }
445
446 /* The SW_INCR event type is a special case which doesn't need
447 * any probes since it is controlled by software and the PMU
448 * itself.
449 */
450 if (ctr.listeners.empty() && ctr.eventId != ARCH_EVENT_SW_INCR) {
569 auto sourceEvent = eventMap.find(ctr.eventId);
570 if (sourceEvent == eventMap.end()) {
451 warn("Can't enable PMU counter of type '0x%x': "
452 "No such event type.\n", ctr.eventId);
571 warn("Can't enable PMU counter of type '0x%x': "
572 "No such event type.\n", ctr.eventId);
573 } else {
574 ctr.attach(sourceEvent->second);
453 }
454 }
455}
456
457
458void
459PMU::resetEventCounts()
460{
461 for (CounterState &ctr : counters)
575 }
576 }
577}
578
579
580void
581PMU::resetEventCounts()
582{
583 for (CounterState &ctr : counters)
462 ctr.value = 0;
584 ctr.setValue(0);
463}
464
465void
466PMU::setCounterValue(CounterId id, uint64_t val)
467{
468 if (!isValidCounter(id)) {
469 warn_once("Can't change counter value: Counter %i does not exist.\n",
470 id);
471 return;
472 }
473
474 CounterState &ctr(getCounter(id));
585}
586
587void
588PMU::setCounterValue(CounterId id, uint64_t val)
589{
590 if (!isValidCounter(id)) {
591 warn_once("Can't change counter value: Counter %i does not exist.\n",
592 id);
593 return;
594 }
595
596 CounterState &ctr(getCounter(id));
475 ctr.value = val;
597 ctr.setValue(val);
476}
477
478PMU::PMEVTYPER_t
479PMU::getCounterTypeRegister(CounterId id) const
480{
481 if (!isValidCounter(id))
482 return 0;
483

--- 20 unchanged lines hidden (view full) ---

504
505 ctr.filter = val;
506
507 // If PMCCNTR Register, do not change event type. PMCCNTR can
508 // count processor cycles only. If we change the event type, we
509 // need to update the probes the counter is using.
510 if (id != PMCCNTR && old_event_id != val.evtCount) {
511 ctr.eventId = val.evtCount;
598}
599
600PMU::PMEVTYPER_t
601PMU::getCounterTypeRegister(CounterId id) const
602{
603 if (!isValidCounter(id))
604 return 0;
605

--- 20 unchanged lines hidden (view full) ---

626
627 ctr.filter = val;
628
629 // If PMCCNTR Register, do not change event type. PMCCNTR can
630 // count processor cycles only. If we change the event type, we
631 // need to update the probes the counter is using.
632 if (id != PMCCNTR && old_event_id != val.evtCount) {
633 ctr.eventId = val.evtCount;
512 updateCounter(reg_pmselr.sel, ctr);
634 updateCounter(ctr);
513 }
514}
515
516void
517PMU::raiseInterrupt()
518{
519 RealView *rv(dynamic_cast<RealView *>(platform));
520 if (!rv || !rv->gic) {

--- 48 unchanged lines hidden (view full) ---

569 UNSERIALIZE_SCALAR(clock_remainder);
570
571 for (size_t i = 0; i < counters.size(); ++i)
572 counters[i].unserializeSection(cp, csprintf("counters.%i", i));
573
574 cycleCounter.unserializeSection(cp, "cycleCounter");
575}
576
635 }
636}
637
638void
639PMU::raiseInterrupt()
640{
641 RealView *rv(dynamic_cast<RealView *>(platform));
642 if (!rv || !rv->gic) {

--- 48 unchanged lines hidden (view full) ---

691 UNSERIALIZE_SCALAR(clock_remainder);
692
693 for (size_t i = 0; i < counters.size(); ++i)
694 counters[i].unserializeSection(cp, csprintf("counters.%i", i));
695
696 cycleCounter.unserializeSection(cp, "cycleCounter");
697}
698
699PMU::PMUEvent*
700PMU::getEvent(uint64_t eventId)
701{
702 auto entry = eventMap.find(eventId);
703
704 if (entry == eventMap.end()) {
705 warn("event %d does not exist\n", eventId);
706 return nullptr;
707 } else {
708 return entry->second;
709 }
710}
711
577void
578PMU::CounterState::serialize(CheckpointOut &cp) const
579{
580 SERIALIZE_SCALAR(eventId);
581 SERIALIZE_SCALAR(value);
582 SERIALIZE_SCALAR(overflow64);
583}
584
585void
586PMU::CounterState::unserialize(CheckpointIn &cp)
587{
588 UNSERIALIZE_SCALAR(eventId);
589 UNSERIALIZE_SCALAR(value);
590 UNSERIALIZE_SCALAR(overflow64);
591}
592
712void
713PMU::CounterState::serialize(CheckpointOut &cp) const
714{
715 SERIALIZE_SCALAR(eventId);
716 SERIALIZE_SCALAR(value);
717 SERIALIZE_SCALAR(overflow64);
718}
719
720void
721PMU::CounterState::unserialize(CheckpointIn &cp)
722{
723 UNSERIALIZE_SCALAR(eventId);
724 UNSERIALIZE_SCALAR(value);
725 UNSERIALIZE_SCALAR(overflow64);
726}
727
593bool
728uint64_t
594PMU::CounterState::add(uint64_t delta)
595{
729PMU::CounterState::add(uint64_t delta)
730{
596 const uint64_t msb(1ULL << (overflow64 ? 63 : 31));
597 const uint64_t old_value(value);
731 uint64_t value_until_overflow;
732 if (overflow64) {
733 value_until_overflow = UINT64_MAX - value;
734 } else {
735 value_until_overflow = UINT32_MAX - (uint32_t)value;
736 }
598
737
599 value += delta;
738 if (isFiltered())
739 return value_until_overflow;
600
740
601 // Overflow if the msb goes from 1 to 0
602 return (old_value & msb) && !(value & msb);
741 if (resetValue) {
742 delta = 0;
743 resetValue = false;
744 } else {
745 value += delta;
746 }
747
748 if (delta > value_until_overflow) {
749
750 // overflow situation detected
751 // flag the overflow occurence
752 pmu.reg_pmovsr |= (1 << counterId);
753
754 // Deliver a PMU interrupt if interrupt delivery is enabled
755 // for this counter.
756 if (pmu.reg_pminten & (1 << counterId)) {
757 pmu.raiseInterrupt();
758 }
759 return overflow64 ? UINT64_MAX : UINT32_MAX;
760 }
761 return value_until_overflow - delta + 1;
603}
604
762}
763
764void
765PMU::SWIncrementEvent::write(uint64_t val)
766{
767 for (auto& counter: userCounters) {
768 if (val & (0x1 << counter->getCounterId())) {
769 counter->add(1);
770 }
771 }
772}
773
605} // namespace ArmISA
606
607ArmISA::PMU *
608ArmPMUParams::create()
609{
610 return new ArmISA::PMU(this);
611}
774} // namespace ArmISA
775
776ArmISA::PMU *
777ArmPMUParams::create()
778{
779 return new ArmISA::PMU(this);
780}