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