misc: Delete the now unnecessary create methods.
[gem5.git] / src / arch / arm / pmu.cc
1 /*
2 * Copyright (c) 2011-2014, 2017-2019 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
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
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
38 #include "arch/arm/pmu.hh"
39
40 #include "arch/arm/isa.hh"
41 #include "arch/arm/utility.hh"
42 #include "base/trace.hh"
43 #include "cpu/base.hh"
44 #include "debug/Checkpoint.hh"
45 #include "debug/PMUVerbose.hh"
46 #include "dev/arm/base_gic.hh"
47 #include "dev/arm/generic_timer.hh"
48 #include "params/ArmPMU.hh"
49
50 namespace ArmISA {
51
52 const RegVal PMU::reg_pmcr_wr_mask = 0x39;
53
54 PMU::PMU(const ArmPMUParams &p)
55 : SimObject(p), BaseISADevice(),
56 reg_pmcnten(0), reg_pmcr(0),
57 reg_pmselr(0), reg_pminten(0), reg_pmovsr(0),
58 reg_pmceid0(0),reg_pmceid1(0),
59 clock_remainder(0),
60 maximumCounterCount(p.eventCounters),
61 cycleCounter(*this, maximumCounterCount),
62 cycleCounterEventId(p.cycleEventId),
63 swIncrementEvent(nullptr),
64 reg_pmcr_conf(0),
65 interrupt(nullptr)
66 {
67 DPRINTF(PMUVerbose, "Initializing the PMU.\n");
68
69 if (maximumCounterCount > 31) {
70 fatal("The PMU can only accept 31 counters, %d counters requested.\n",
71 maximumCounterCount);
72 }
73
74 warn_if(!p.interrupt, "ARM PMU: No interrupt specified, interrupt " \
75 "delivery disabled.\n");
76
77 /* Setup the performance counter ID registers */
78 reg_pmcr_conf.imp = 0x41; // ARM Ltd.
79 reg_pmcr_conf.idcode = 0x00;
80 reg_pmcr_conf.n = p.eventCounters;
81
82 // Setup the hard-coded cycle counter, which is equivalent to
83 // architected counter event type 0x11.
84 cycleCounter.eventId = 0x11;
85 }
86
87 PMU::~PMU()
88 {
89 }
90
91 void
92 PMU::setThreadContext(ThreadContext *tc)
93 {
94 DPRINTF(PMUVerbose, "Assigning PMU to ContextID %i.\n", tc->contextId());
95 const auto &pmu_params = static_cast<const ArmPMUParams &>(params());
96
97 if (pmu_params.interrupt)
98 interrupt = pmu_params.interrupt->get(tc);
99 }
100
101 void
102 PMU::addSoftwareIncrementEvent(unsigned int id)
103 {
104 auto old_event = eventMap.find(id);
105 DPRINTF(PMUVerbose, "PMU: Adding SW increment event with id '0x%x'\n", id);
106
107 if (swIncrementEvent) {
108 fatal_if(old_event == eventMap.end() ||
109 old_event->second != swIncrementEvent,
110 "Trying to add a software increment event with multiple"
111 "IDs. This is not supported.\n");
112 return;
113 }
114
115 fatal_if(old_event != eventMap.end(), "An event with id %d has "
116 "been previously defined\n", id);
117
118 swIncrementEvent = new SWIncrementEvent();
119 eventMap[id] = swIncrementEvent;
120 registerEvent(id);
121 }
122
123 void
124 PMU::addEventProbe(unsigned int id, SimObject *obj, const char *probe_name)
125 {
126
127 DPRINTF(PMUVerbose, "PMU: Adding Probe Driven event with id '0x%x'"
128 "as probe %s:%s\n",id, obj->name(), probe_name);
129
130 RegularEvent *event = nullptr;
131 auto event_entry = eventMap.find(id);
132 if (event_entry == eventMap.end()) {
133
134 event = new RegularEvent();
135 eventMap[id] = event;
136
137 } else {
138 event = dynamic_cast<RegularEvent*>(event_entry->second);
139 if (!event) {
140 fatal("Event with id %d is not probe driven\n", id);
141 }
142 }
143 event->addMicroarchitectureProbe(obj, probe_name);
144
145 registerEvent(id);
146
147 }
148
149 void
150 PMU::registerEvent(uint32_t id)
151 {
152 // Flag the event as available in the corresponding PMCEID register if it
153 // is an architected event.
154 if (id < 0x20) {
155 reg_pmceid0 |= ((uint64_t)1) << id;
156 } else if (id > 0x20 && id < 0x40) {
157 reg_pmceid1 |= ((uint64_t)1) << (id - 0x20);
158 } else if (id >= 0x4000 && id < 0x4020) {
159 reg_pmceid0 |= ((uint64_t)1) << (id - 0x4000 + 32);
160 } else if (id >= 0x4020 && id < 0x4040) {
161 reg_pmceid1 |= ((uint64_t)1) << (id - 0x4020 + 32);
162 }
163 }
164
165 void
166 PMU::drainResume()
167 {
168 // Re-attach enabled counters after a resume in case they changed.
169 updateAllCounters();
170 }
171
172 void
173 PMU::regProbeListeners()
174 {
175
176 // at this stage all probe configurations are done
177 // counters can be configured
178 for (uint32_t index = 0; index < maximumCounterCount-1; index++) {
179 counters.emplace_back(*this, index);
180 }
181
182 PMUEvent *event = getEvent(cycleCounterEventId);
183 panic_if(!event, "core cycle event is not present\n");
184 cycleCounter.enabled = true;
185 cycleCounter.attach(event);
186 }
187
188 void
189 PMU::setMiscReg(int misc_reg, RegVal val)
190 {
191 DPRINTF(PMUVerbose, "setMiscReg(%s, 0x%x)\n",
192 miscRegName[unflattenMiscReg(misc_reg)], val);
193
194 switch (unflattenMiscReg(misc_reg)) {
195 case MISCREG_PMCR_EL0:
196 case MISCREG_PMCR:
197 setControlReg(val);
198 return;
199
200 case MISCREG_PMCNTENSET_EL0:
201 case MISCREG_PMCNTENSET:
202 reg_pmcnten |= val;
203 updateAllCounters();
204 return;
205
206 case MISCREG_PMCNTENCLR_EL0:
207 case MISCREG_PMCNTENCLR:
208 reg_pmcnten &= ~val;
209 updateAllCounters();
210 return;
211
212 case MISCREG_PMOVSCLR_EL0:
213 case MISCREG_PMOVSR:
214 setOverflowStatus(reg_pmovsr & ~val);
215 return;
216
217 case MISCREG_PMSWINC_EL0:
218 case MISCREG_PMSWINC:
219 if (swIncrementEvent) {
220 swIncrementEvent->write(val);
221 }
222 return;
223
224 case MISCREG_PMCCNTR_EL0:
225 case MISCREG_PMCCNTR:
226 cycleCounter.setValue(val);
227 return;
228
229 case MISCREG_PMSELR_EL0:
230 case MISCREG_PMSELR:
231 reg_pmselr = val;
232 return;
233 //TODO: implement MISCREF_PMCEID{2,3}
234 case MISCREG_PMCEID0_EL0:
235 case MISCREG_PMCEID0:
236 case MISCREG_PMCEID1_EL0:
237 case MISCREG_PMCEID1:
238 // Ignore writes
239 return;
240
241 case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0:
242 setCounterTypeRegister(misc_reg - MISCREG_PMEVTYPER0_EL0, val);
243 return;
244
245 case MISCREG_PMCCFILTR:
246 case MISCREG_PMCCFILTR_EL0:
247 DPRINTF(PMUVerbose, "Setting PMCCFILTR: 0x%x\n", val);
248 setCounterTypeRegister(PMCCNTR, val);
249 return;
250
251 case MISCREG_PMXEVTYPER_PMCCFILTR:
252 case MISCREG_PMXEVTYPER_EL0:
253 case MISCREG_PMXEVTYPER:
254 DPRINTF(PMUVerbose, "Setting counter type: "
255 "[PMSELR: 0x%x, PMSELER.sel: 0x%x, EVTYPER: 0x%x]\n",
256 reg_pmselr, reg_pmselr.sel, val);
257 setCounterTypeRegister(reg_pmselr.sel, val);
258 return;
259
260 case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0:
261 setCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0, val);
262 return;
263
264 case MISCREG_PMXEVCNTR_EL0:
265 case MISCREG_PMXEVCNTR:
266 setCounterValue(reg_pmselr.sel, val);
267 return;
268
269 case MISCREG_PMUSERENR_EL0:
270 case MISCREG_PMUSERENR:
271 // TODO
272 break;
273
274 case MISCREG_PMINTENSET_EL1:
275 case MISCREG_PMINTENSET:
276 reg_pminten |= val;
277 return;
278
279 case MISCREG_PMINTENCLR_EL1:
280 case MISCREG_PMINTENCLR:
281 reg_pminten &= ~val;
282 return;
283
284 case MISCREG_PMOVSSET_EL0:
285 case MISCREG_PMOVSSET:
286 setOverflowStatus(reg_pmovsr | val);
287 return;
288
289 default:
290 panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]);
291 }
292
293 warn("Not doing anything for write to miscreg %s\n",
294 miscRegName[misc_reg]);
295 }
296
297 RegVal
298 PMU::readMiscReg(int misc_reg)
299 {
300 RegVal val(readMiscRegInt(misc_reg));
301 DPRINTF(PMUVerbose, "readMiscReg(%s): 0x%x\n",
302 miscRegName[unflattenMiscReg(misc_reg)], val);
303 return val;
304 }
305
306 RegVal
307 PMU::readMiscRegInt(int misc_reg)
308 {
309 misc_reg = unflattenMiscReg(misc_reg);
310 switch (misc_reg) {
311 case MISCREG_PMCR_EL0:
312 case MISCREG_PMCR:
313 return reg_pmcr_conf | (reg_pmcr & reg_pmcr_wr_mask);
314
315 case MISCREG_PMCNTENSET_EL0:
316 case MISCREG_PMCNTENCLR_EL0:
317 case MISCREG_PMCNTENSET:
318 case MISCREG_PMCNTENCLR:
319 return reg_pmcnten;
320
321 case MISCREG_PMOVSCLR_EL0:
322 case MISCREG_PMOVSSET_EL0:
323 case MISCREG_PMOVSR: // Overflow Status Register
324 case MISCREG_PMOVSSET:
325 return reg_pmovsr;
326
327 case MISCREG_PMSWINC_EL0:
328 case MISCREG_PMSWINC: // Software Increment Register (RAZ)
329 return 0;
330
331 case MISCREG_PMSELR_EL0:
332 case MISCREG_PMSELR:
333 return reg_pmselr;
334
335 case MISCREG_PMCEID0_EL0:
336 return reg_pmceid0;
337
338 case MISCREG_PMCEID1_EL0:
339 return reg_pmceid1;
340
341 //TODO: implement MISCREF_PMCEID{2,3}
342 case MISCREG_PMCEID0: // Common Event ID register
343 return reg_pmceid0 & 0xFFFFFFFF;
344
345 case MISCREG_PMCEID1: // Common Event ID register
346 return reg_pmceid1 & 0xFFFFFFFF;
347
348 case MISCREG_PMCCNTR_EL0:
349 return cycleCounter.getValue();
350
351 case MISCREG_PMCCNTR:
352 return cycleCounter.getValue() & 0xFFFFFFFF;
353
354 case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0:
355 return getCounterTypeRegister(misc_reg - MISCREG_PMEVTYPER0_EL0);
356
357 case MISCREG_PMCCFILTR:
358 case MISCREG_PMCCFILTR_EL0:
359 return getCounterTypeRegister(PMCCNTR);
360
361 case MISCREG_PMXEVTYPER_PMCCFILTR:
362 case MISCREG_PMXEVTYPER_EL0:
363 case MISCREG_PMXEVTYPER:
364 return getCounterTypeRegister(reg_pmselr.sel);
365
366 case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0: {
367 return getCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0) &
368 0xFFFFFFFF;
369
370 }
371
372 case MISCREG_PMXEVCNTR_EL0:
373 case MISCREG_PMXEVCNTR:
374 return getCounterValue(reg_pmselr.sel) & 0xFFFFFFFF;
375
376 case MISCREG_PMUSERENR_EL0:
377 case MISCREG_PMUSERENR:
378 // TODO
379 return 0;
380
381 case MISCREG_PMINTENSET_EL1:
382 case MISCREG_PMINTENCLR_EL1:
383 case MISCREG_PMINTENSET:
384 case MISCREG_PMINTENCLR:
385 return reg_pminten;
386
387 default:
388 panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]);
389 }
390
391 warn("Not doing anything for read from miscreg %s\n",
392 miscRegName[misc_reg]);
393 return 0;
394 }
395
396 void
397 PMU::setControlReg(PMCR_t val)
398 {
399 DPRINTF(PMUVerbose, "Set Control Reg 0x%08x.\n", val);
400
401 if (val.p) {
402 DPRINTF(PMUVerbose, "PMU reset all events to zero.\n");
403 resetEventCounts();
404 }
405
406 if (val.c) {
407 DPRINTF(PMUVerbose, "PMU reset cycle counter to zero.\n");
408 cycleCounter.setValue(0);
409 }
410
411 // Reset the clock remainder if divide by 64-mode is toggled.
412 if (reg_pmcr.d != val.d)
413 clock_remainder = 0;
414
415 reg_pmcr = val & reg_pmcr_wr_mask;
416 updateAllCounters();
417 }
418
419 void
420 PMU::updateAllCounters()
421 {
422 const bool global_enable(reg_pmcr.e);
423
424 for (int i = 0; i < counters.size(); ++i) {
425 CounterState &ctr(counters[i]);
426 const bool enable(global_enable && (reg_pmcnten & (1 << i)));
427 if (ctr.enabled != enable) {
428 ctr.enabled = enable;
429 updateCounter(ctr);
430 }
431 }
432
433 const bool ccntr_enable(global_enable && (reg_pmcnten & (1 << PMCCNTR)));
434 if (cycleCounter.enabled != ccntr_enable) {
435 cycleCounter.enabled = ccntr_enable;
436 updateCounter(cycleCounter);
437 }
438 }
439
440 void
441 PMU::PMUEvent::attachEvent(PMU::CounterState *user)
442 {
443 if (userCounters.empty()) {
444 enable();
445 }
446 userCounters.insert(user);
447 updateAttachedCounters();
448 }
449
450 void
451 PMU::PMUEvent::increment(const uint64_t val)
452 {
453 for (auto& counter: userCounters) {
454 counter->add(val);
455 }
456 }
457
458 void
459 PMU::PMUEvent::detachEvent(PMU::CounterState *user)
460 {
461 userCounters.erase(user);
462
463 if (userCounters.empty()) {
464 disable();
465 }
466 }
467
468 void
469 PMU::RegularEvent::RegularProbe::notify(const uint64_t &val)
470 {
471 parentEvent->increment(val);
472 }
473
474 void
475 PMU::RegularEvent::enable()
476 {
477 for (auto& subEvents: microArchitectureEventSet) {
478 attachedProbePointList.emplace_back(
479 new RegularProbe(this, subEvents.first, subEvents.second));
480 }
481 }
482
483 void
484 PMU::RegularEvent::disable()
485 {
486 attachedProbePointList.clear();
487 }
488
489 bool
490 PMU::CounterState::isFiltered() const
491 {
492 assert(pmu.isa);
493
494 const PMEVTYPER_t filter(this->filter);
495 const SCR scr(pmu.isa->readMiscRegNoEffect(MISCREG_SCR));
496 const CPSR cpsr(pmu.isa->readMiscRegNoEffect(MISCREG_CPSR));
497 const ExceptionLevel el(currEL(cpsr));
498 const bool secure(inSecureState(scr, cpsr));
499
500 switch (el) {
501 case EL0:
502 return secure ? filter.u : (filter.u != filter.nsu);
503
504 case EL1:
505 return secure ? filter.p : (filter.p != filter.nsk);
506
507 case EL2:
508 return !filter.nsh;
509
510 case EL3:
511 return filter.p != filter.m;
512
513 default:
514 panic("Unexpected execution level in PMU::isFiltered.\n");
515 }
516 }
517
518 void
519 PMU::CounterState::detach()
520 {
521 if (sourceEvent) {
522 sourceEvent->detachEvent(this);
523 sourceEvent = nullptr;
524 } else {
525 debugCounter("detaching event not currently attached"
526 " to any event\n");
527 }
528 }
529
530 void
531 PMU::CounterState::attach(PMUEvent* event)
532 {
533 if (!resetValue) {
534 value = 0;
535 resetValue = true;
536 }
537 sourceEvent = event;
538 sourceEvent->attachEvent(this);
539 }
540
541 uint64_t
542 PMU::CounterState::getValue() const
543 {
544 if (sourceEvent) {
545 sourceEvent->updateAttachedCounters();
546 } else {
547 debugCounter("attempted to get value from a counter without"
548 " an associated event\n");
549 }
550 return value;
551 }
552
553 void
554 PMU::CounterState::setValue(uint64_t val)
555 {
556 value = val;
557 resetValue = true;
558
559 if (sourceEvent) {
560 sourceEvent->updateAttachedCounters();
561 } else {
562 debugCounter("attempted to set value from a counter without"
563 " an associated event\n");
564 }
565 }
566
567 void
568 PMU::updateCounter(CounterState &ctr)
569 {
570 if (!ctr.enabled) {
571 DPRINTF(PMUVerbose, "updateCounter(%i): Disabling counter\n",
572 ctr.getCounterId());
573 ctr.detach();
574
575 } else {
576 DPRINTF(PMUVerbose, "updateCounter(%i): Enable event id 0x%x\n",
577 ctr.getCounterId(), ctr.eventId);
578
579 auto sourceEvent = eventMap.find(ctr.eventId);
580 if (sourceEvent == eventMap.end()) {
581 warn("Can't enable PMU counter of type '0x%x': "
582 "No such event type.\n", ctr.eventId);
583 } else {
584 ctr.attach(sourceEvent->second);
585 }
586 }
587 }
588
589
590 void
591 PMU::resetEventCounts()
592 {
593 for (CounterState &ctr : counters)
594 ctr.setValue(0);
595 }
596
597 void
598 PMU::setCounterValue(CounterId id, uint64_t val)
599 {
600 if (!isValidCounter(id)) {
601 warn_once("Can't change counter value: Counter %i does not exist.\n",
602 id);
603 return;
604 }
605
606 CounterState &ctr(getCounter(id));
607 ctr.setValue(val);
608 }
609
610 PMU::PMEVTYPER_t
611 PMU::getCounterTypeRegister(CounterId id) const
612 {
613 if (!isValidCounter(id))
614 return 0;
615
616 const CounterState &cs(getCounter(id));
617 PMEVTYPER_t type(cs.filter);
618
619 type.evtCount = cs.eventId;
620
621 return type;
622 }
623
624 void
625 PMU::setCounterTypeRegister(CounterId id, PMEVTYPER_t val)
626 {
627 DPRINTF(PMUVerbose, "Set Event [%d] = 0x%08x\n", id, val);
628 if (!isValidCounter(id)) {
629 warn_once("Can't change counter type: Counter %i does not exist.\n",
630 id);
631 return;
632 }
633
634 CounterState &ctr(getCounter(id));
635 const EventTypeId old_event_id(ctr.eventId);
636
637 ctr.filter = val;
638
639 // If PMCCNTR Register, do not change event type. PMCCNTR can
640 // count processor cycles only. If we change the event type, we
641 // need to update the probes the counter is using.
642 if (id != PMCCNTR && old_event_id != val.evtCount) {
643 ctr.eventId = val.evtCount;
644 updateCounter(ctr);
645 }
646 }
647
648 void
649 PMU::setOverflowStatus(RegVal new_val)
650 {
651 const bool int_old = reg_pmovsr != 0;
652 const bool int_new = new_val != 0;
653
654 reg_pmovsr = new_val;
655 if (int_old && !int_new) {
656 clearInterrupt();
657 } else if (!int_old && int_new && (reg_pminten & reg_pmovsr)) {
658 raiseInterrupt();
659 }
660 }
661
662 void
663 PMU::raiseInterrupt()
664 {
665 if (interrupt) {
666 DPRINTF(PMUVerbose, "Delivering PMU interrupt.\n");
667 interrupt->raise();
668 } else {
669 warn_once("Dropping PMU interrupt as no interrupt has "
670 "been specified\n");
671 }
672 }
673
674 void
675 PMU::clearInterrupt()
676 {
677 if (interrupt) {
678 DPRINTF(PMUVerbose, "Clearing PMU interrupt.\n");
679 interrupt->clear();
680 } else {
681 warn_once("Dropping PMU interrupt as no interrupt has "
682 "been specified\n");
683 }
684 }
685
686 void
687 PMU::serialize(CheckpointOut &cp) const
688 {
689 DPRINTF(Checkpoint, "Serializing Arm PMU\n");
690
691 SERIALIZE_SCALAR(reg_pmcr);
692 SERIALIZE_SCALAR(reg_pmcnten);
693 SERIALIZE_SCALAR(reg_pmselr);
694 SERIALIZE_SCALAR(reg_pminten);
695 SERIALIZE_SCALAR(reg_pmovsr);
696 SERIALIZE_SCALAR(reg_pmceid0);
697 SERIALIZE_SCALAR(reg_pmceid1);
698 SERIALIZE_SCALAR(clock_remainder);
699
700 for (size_t i = 0; i < counters.size(); ++i)
701 counters[i].serializeSection(cp, csprintf("counters.%i", i));
702
703 cycleCounter.serializeSection(cp, "cycleCounter");
704 }
705
706 void
707 PMU::unserialize(CheckpointIn &cp)
708 {
709 DPRINTF(Checkpoint, "Unserializing Arm PMU\n");
710
711 UNSERIALIZE_SCALAR(reg_pmcr);
712 UNSERIALIZE_SCALAR(reg_pmcnten);
713 UNSERIALIZE_SCALAR(reg_pmselr);
714 UNSERIALIZE_SCALAR(reg_pminten);
715 UNSERIALIZE_SCALAR(reg_pmovsr);
716
717 // Old checkpoints used to store the entire PMCEID value in a
718 // single 64-bit entry (reg_pmceid). The register was extended in
719 // ARMv8.1, so we now need to store it as two 64-bit registers.
720 if (!UNSERIALIZE_OPT_SCALAR(reg_pmceid0))
721 paramIn(cp, "reg_pmceid", reg_pmceid0);
722
723 if (!UNSERIALIZE_OPT_SCALAR(reg_pmceid1))
724 reg_pmceid1 = 0;
725
726 UNSERIALIZE_SCALAR(clock_remainder);
727
728 for (size_t i = 0; i < counters.size(); ++i)
729 counters[i].unserializeSection(cp, csprintf("counters.%i", i));
730
731 cycleCounter.unserializeSection(cp, "cycleCounter");
732 }
733
734 PMU::PMUEvent*
735 PMU::getEvent(uint64_t eventId)
736 {
737 auto entry = eventMap.find(eventId);
738
739 if (entry == eventMap.end()) {
740 warn("event %d does not exist\n", eventId);
741 return nullptr;
742 } else {
743 return entry->second;
744 }
745 }
746
747 void
748 PMU::CounterState::serialize(CheckpointOut &cp) const
749 {
750 SERIALIZE_SCALAR(eventId);
751 SERIALIZE_SCALAR(value);
752 SERIALIZE_SCALAR(overflow64);
753 }
754
755 void
756 PMU::CounterState::unserialize(CheckpointIn &cp)
757 {
758 UNSERIALIZE_SCALAR(eventId);
759 UNSERIALIZE_SCALAR(value);
760 UNSERIALIZE_SCALAR(overflow64);
761 }
762
763 uint64_t
764 PMU::CounterState::add(uint64_t delta)
765 {
766 uint64_t value_until_overflow;
767 if (overflow64) {
768 value_until_overflow = UINT64_MAX - value;
769 } else {
770 value_until_overflow = UINT32_MAX - (uint32_t)value;
771 }
772
773 if (isFiltered())
774 return value_until_overflow;
775
776 if (resetValue) {
777 delta = 0;
778 resetValue = false;
779 } else {
780 value += delta;
781 }
782
783 if (delta > value_until_overflow) {
784
785 // overflow situation detected
786 // flag the overflow occurence
787 pmu.reg_pmovsr |= (1 << counterId);
788
789 // Deliver a PMU interrupt if interrupt delivery is enabled
790 // for this counter.
791 if (pmu.reg_pminten & (1 << counterId)) {
792 pmu.raiseInterrupt();
793 }
794 return overflow64 ? UINT64_MAX : UINT32_MAX;
795 }
796 return value_until_overflow - delta + 1;
797 }
798
799 void
800 PMU::SWIncrementEvent::write(uint64_t val)
801 {
802 for (auto& counter: userCounters) {
803 if (val & (0x1 << counter->getCounterId())) {
804 counter->add(1);
805 }
806 }
807 }
808
809 } // namespace ArmISA