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