pmu.cc revision 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
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 "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),
66      maximumCounterCount(p->eventCounters),
67      cycleCounter(*this, maximumCounterCount),
68      cycleCounterEventId(p->cycleEventId),
69      swIncrementEvent(nullptr),
70      reg_pmcr_conf(0),
71      pmuInterrupt(p->pmuInterrupt),
72      platform(p->platform)
73{
74    DPRINTF(PMUVerbose, "Initializing the PMU.\n");
75
76    if (maximumCounterCount > 31) {
77        fatal("The PMU can only accept 31 counters, %d counters requested.\n",
78              maximumCounterCount);
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
118PMU::addEventProbe(unsigned int id, SimObject *obj, const char *probe_name)
119{
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{
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);
154    } else if (id >= 0x4020 && id < 0x4040) {
155        reg_pmceid1 |= ((uint64_t)1) << (id - 0x4020 + 32);
156    }
157}
158
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
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:
191        setControlReg(val);
192        return;
193
194      case MISCREG_PMCNTENSET_EL0:
195      case MISCREG_PMCNTENSET:
196        reg_pmcnten |= val;
197        updateAllCounters();
198        return;
199
200      case MISCREG_PMCNTENCLR_EL0:
201      case MISCREG_PMCNTENCLR:
202        reg_pmcnten &= ~val;
203        updateAllCounters();
204        return;
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:
213        if (swIncrementEvent) {
214            swIncrementEvent->write(val);
215        }
216        return;
217
218      case MISCREG_PMCCNTR_EL0:
219      case MISCREG_PMCCNTR:
220        cycleCounter.setValue(val);
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:
229      case MISCREG_PMCEID0:
230      case MISCREG_PMCEID1_EL0:
231      case MISCREG_PMCEID1:
232        // Ignore writes
233        return;
234
235      case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0:
236        setCounterTypeRegister(misc_reg - MISCREG_PMEVTYPER0_EL0, val);
237        return;
238
239      case MISCREG_PMCCFILTR:
240      case MISCREG_PMCCFILTR_EL0:
241        DPRINTF(PMUVerbose, "Setting PMCCFILTR: 0x%x\n", val);
242        setCounterTypeRegister(PMCCNTR, val);
243        return;
244
245      case MISCREG_PMXEVTYPER_PMCCFILTR:
246      case MISCREG_PMXEVTYPER_EL0:
247      case MISCREG_PMXEVTYPER:
248        DPRINTF(PMUVerbose, "Setting counter type: "
249                "[PMSELR: 0x%x, PMSELER.sel: 0x%x, EVTYPER: 0x%x]\n",
250                reg_pmselr, reg_pmselr.sel, val);
251        setCounterTypeRegister(reg_pmselr.sel, val);
252        return;
253
254      case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0:
255        setCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0, val);
256        return;
257
258      case MISCREG_PMXEVCNTR_EL0:
259      case MISCREG_PMXEVCNTR:
260        setCounterValue(reg_pmselr.sel, val);
261        return;
262
263      case MISCREG_PMUSERENR_EL0:
264      case MISCREG_PMUSERENR:
265        // TODO
266        break;
267
268      case MISCREG_PMINTENSET_EL1:
269      case MISCREG_PMINTENSET:
270        reg_pminten |= val;
271        return;
272
273      case MISCREG_PMINTENCLR_EL1:
274      case MISCREG_PMINTENCLR:
275        reg_pminten &= ~val;
276        return;
277
278      case MISCREG_PMOVSSET_EL0:
279      case MISCREG_PMOVSSET:
280        reg_pmovsr |= val;
281        return;
282
283      default:
284        panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]);
285    }
286
287    warn("Not doing anything for write to miscreg %s\n",
288         miscRegName[misc_reg]);
289}
290
291MiscReg
292PMU::readMiscReg(int misc_reg)
293{
294    MiscReg val(readMiscRegInt(misc_reg));
295    DPRINTF(PMUVerbose, "readMiscReg(%s): 0x%x\n",
296            miscRegName[unflattenMiscReg(misc_reg)], val);
297    return val;
298}
299
300MiscReg
301PMU::readMiscRegInt(int misc_reg)
302{
303    misc_reg = unflattenMiscReg(misc_reg);
304    switch (misc_reg) {
305      case MISCREG_PMCR_EL0:
306      case MISCREG_PMCR:
307        return reg_pmcr_conf | (reg_pmcr & reg_pmcr_wr_mask);
308
309      case MISCREG_PMCNTENSET_EL0:
310      case MISCREG_PMCNTENCLR_EL0:
311      case MISCREG_PMCNTENSET:
312      case MISCREG_PMCNTENCLR:
313        return reg_pmcnten;
314
315      case MISCREG_PMOVSCLR_EL0:
316      case MISCREG_PMOVSSET_EL0:
317      case MISCREG_PMOVSR:  // Overflow Status Register
318      case MISCREG_PMOVSSET:
319        return reg_pmovsr;
320
321      case MISCREG_PMSWINC_EL0:
322      case MISCREG_PMSWINC: // Software Increment Register (RAZ)
323        return 0;
324
325      case MISCREG_PMSELR:
326        return reg_pmselr;
327
328      case MISCREG_PMCEID0_EL0:
329        return reg_pmceid0;
330
331      case MISCREG_PMCEID1_EL0:
332        return reg_pmceid1;
333
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:
342        return cycleCounter.getValue();
343
344      case MISCREG_PMCCNTR:
345        return cycleCounter.getValue() & 0xFFFFFFFF;
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
359      case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0: {
360            return getCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0) &
361                0xFFFFFFFF;
362
363        }
364
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;
373
374      case MISCREG_PMINTENSET_EL1:
375      case MISCREG_PMINTENCLR_EL1:
376      case MISCREG_PMINTENSET:
377      case MISCREG_PMINTENCLR:
378        return reg_pminten;
379
380      default:
381        panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]);
382    }
383
384    warn("Not doing anything for read from miscreg %s\n",
385         miscRegName[misc_reg]);
386    return 0;
387}
388
389void
390PMU::setControlReg(PMCR_t val)
391{
392    DPRINTF(PMUVerbose, "Set Control Reg 0x%08x.\n", val);
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");
401        cycleCounter.setValue(0);
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();
410}
411
412void
413PMU::updateAllCounters()
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;
422            updateCounter(ctr);
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;
429        updateCounter(cycleCounter);
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
482bool
483PMU::CounterState::isFiltered() const
484{
485    assert(pmu.isa);
486
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));
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:
498        return secure ? filter.p : (filter.p != filter.nsk);
499
500      case EL2:
501        return !filter.nsh;
502
503      case EL3:
504        return filter.p != filter.m;
505
506      default:
507        panic("Unexpected execution level in PMU::isFiltered.\n");
508    }
509}
510
511void
512PMU::CounterState::detach()
513{
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}
522
523void
524PMU::CounterState::attach(PMUEvent* event)
525{
526    value = 0;
527    sourceEvent = event;
528    sourceEvent->attachEvent(this);
529}
530
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");
539    }
540    return value;
541}
542
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");
554    }
555}
556
557void
558PMU::updateCounter(CounterState &ctr)
559{
560    if (!ctr.enabled) {
561        DPRINTF(PMUVerbose, "updateCounter(%i): Disabling counter\n",
562            ctr.getCounterId());
563        ctr.detach();
564
565    } else {
566        DPRINTF(PMUVerbose, "updateCounter(%i): Enable event id 0x%x\n",
567                ctr.getCounterId(), ctr.eventId);
568
569        auto sourceEvent = eventMap.find(ctr.eventId);
570        if (sourceEvent == eventMap.end()) {
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);
575        }
576    }
577}
578
579
580void
581PMU::resetEventCounts()
582{
583    for (CounterState &ctr : counters)
584        ctr.setValue(0);
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));
597    ctr.setValue(val);
598}
599
600PMU::PMEVTYPER_t
601PMU::getCounterTypeRegister(CounterId id) const
602{
603    if (!isValidCounter(id))
604        return 0;
605
606    const CounterState &cs(getCounter(id));
607    PMEVTYPER_t type(cs.filter);
608
609    type.evtCount = cs.eventId;
610
611    return type;
612}
613
614void
615PMU::setCounterTypeRegister(CounterId id, PMEVTYPER_t val)
616{
617    DPRINTF(PMUVerbose, "Set Event [%d] = 0x%08x\n", id, val);
618    if (!isValidCounter(id)) {
619        warn_once("Can't change counter type: Counter %i does not exist.\n",
620                  id);
621        return;
622    }
623
624    CounterState &ctr(getCounter(id));
625    const EventTypeId old_event_id(ctr.eventId);
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;
634        updateCounter(ctr);
635    }
636}
637
638void
639PMU::raiseInterrupt()
640{
641    RealView *rv(dynamic_cast<RealView *>(platform));
642    if (!rv || !rv->gic) {
643        warn_once("ARM PMU: GIC missing, can't raise interrupt.\n");
644        return;
645    }
646
647    DPRINTF(PMUVerbose, "Delivering PMU interrupt.\n");
648    rv->gic->sendInt(pmuInterrupt);
649}
650
651void
652PMU::serialize(CheckpointOut &cp) const
653{
654    DPRINTF(Checkpoint, "Serializing Arm PMU\n");
655
656    SERIALIZE_SCALAR(reg_pmcr);
657    SERIALIZE_SCALAR(reg_pmcnten);
658    SERIALIZE_SCALAR(reg_pmselr);
659    SERIALIZE_SCALAR(reg_pminten);
660    SERIALIZE_SCALAR(reg_pmovsr);
661    SERIALIZE_SCALAR(reg_pmceid0);
662    SERIALIZE_SCALAR(reg_pmceid1);
663    SERIALIZE_SCALAR(clock_remainder);
664
665    for (size_t i = 0; i < counters.size(); ++i)
666        counters[i].serializeSection(cp, csprintf("counters.%i", i));
667
668    cycleCounter.serializeSection(cp, "cycleCounter");
669}
670
671void
672PMU::unserialize(CheckpointIn &cp)
673{
674    DPRINTF(Checkpoint, "Unserializing Arm PMU\n");
675
676    UNSERIALIZE_SCALAR(reg_pmcr);
677    UNSERIALIZE_SCALAR(reg_pmcnten);
678    UNSERIALIZE_SCALAR(reg_pmselr);
679    UNSERIALIZE_SCALAR(reg_pminten);
680    UNSERIALIZE_SCALAR(reg_pmovsr);
681
682    // Old checkpoints used to store the entire PMCEID value in a
683    // single 64-bit entry (reg_pmceid). The register was extended in
684    // ARMv8.1, so we now need to store it as two 64-bit registers.
685    if (!UNSERIALIZE_OPT_SCALAR(reg_pmceid0))
686        paramIn(cp, "reg_pmceid", reg_pmceid0);
687
688    if (!UNSERIALIZE_OPT_SCALAR(reg_pmceid1))
689        reg_pmceid1 = 0;
690
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
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
728uint64_t
729PMU::CounterState::add(uint64_t delta)
730{
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    }
737
738    if (isFiltered())
739        return value_until_overflow;
740
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;
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
774} // namespace ArmISA
775
776ArmISA::PMU *
777ArmPMUParams::create()
778{
779    return new ArmISA::PMU(this);
780}
781