pmu.cc revision 12286
110461SAndreas.Sandberg@ARM.com/*
212117Sjose.marinho@arm.com * Copyright (c) 2011-2014, 2017 ARM Limited
310461SAndreas.Sandberg@ARM.com * All rights reserved
410461SAndreas.Sandberg@ARM.com *
510461SAndreas.Sandberg@ARM.com * The license below extends only to copyright in the software and shall
610461SAndreas.Sandberg@ARM.com * not be construed as granting a license to any other intellectual
710461SAndreas.Sandberg@ARM.com * property including but not limited to intellectual property relating
810461SAndreas.Sandberg@ARM.com * to a hardware implementation of the functionality of the software
910461SAndreas.Sandberg@ARM.com * licensed hereunder.  You may use the software subject to the license
1010461SAndreas.Sandberg@ARM.com * terms below provided that you ensure that this notice is replicated
1110461SAndreas.Sandberg@ARM.com * unmodified and in its entirety in all distributions of the software,
1210461SAndreas.Sandberg@ARM.com * modified or unmodified, in source code or in binary form.
1310461SAndreas.Sandberg@ARM.com *
1410461SAndreas.Sandberg@ARM.com * Redistribution and use in source and binary forms, with or without
1510461SAndreas.Sandberg@ARM.com * modification, are permitted provided that the following conditions are
1610461SAndreas.Sandberg@ARM.com * met: redistributions of source code must retain the above copyright
1710461SAndreas.Sandberg@ARM.com * notice, this list of conditions and the following disclaimer;
1810461SAndreas.Sandberg@ARM.com * redistributions in binary form must reproduce the above copyright
1910461SAndreas.Sandberg@ARM.com * notice, this list of conditions and the following disclaimer in the
2010461SAndreas.Sandberg@ARM.com * documentation and/or other materials provided with the distribution;
2110461SAndreas.Sandberg@ARM.com * neither the name of the copyright holders nor the names of its
2210461SAndreas.Sandberg@ARM.com * contributors may be used to endorse or promote products derived from
2310461SAndreas.Sandberg@ARM.com * this software without specific prior written permission.
2410461SAndreas.Sandberg@ARM.com *
2510461SAndreas.Sandberg@ARM.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2610461SAndreas.Sandberg@ARM.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2710461SAndreas.Sandberg@ARM.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2810461SAndreas.Sandberg@ARM.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2910461SAndreas.Sandberg@ARM.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3010461SAndreas.Sandberg@ARM.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3110461SAndreas.Sandberg@ARM.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3210461SAndreas.Sandberg@ARM.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3310461SAndreas.Sandberg@ARM.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3410461SAndreas.Sandberg@ARM.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3510461SAndreas.Sandberg@ARM.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3610461SAndreas.Sandberg@ARM.com *
3710461SAndreas.Sandberg@ARM.com * Authors: Dam Sunwoo
3810461SAndreas.Sandberg@ARM.com *          Matt Horsnell
3910461SAndreas.Sandberg@ARM.com *          Andreas Sandberg
4012286Sjose.marinho@arm.com *          Jose Marinho
4110461SAndreas.Sandberg@ARM.com */
4210461SAndreas.Sandberg@ARM.com
4310461SAndreas.Sandberg@ARM.com#include "arch/arm/pmu.hh"
4410461SAndreas.Sandberg@ARM.com
4510609Sandreas.sandberg@arm.com#include "arch/arm/isa.hh"
4610609Sandreas.sandberg@arm.com#include "arch/arm/utility.hh"
4710461SAndreas.Sandberg@ARM.com#include "base/trace.hh"
4810461SAndreas.Sandberg@ARM.com#include "cpu/base.hh"
4910461SAndreas.Sandberg@ARM.com#include "debug/Checkpoint.hh"
5010461SAndreas.Sandberg@ARM.com#include "debug/PMUVerbose.hh"
5110461SAndreas.Sandberg@ARM.com#include "dev/arm/base_gic.hh"
5212286Sjose.marinho@arm.com#include "dev/arm/generic_timer.hh"
5310461SAndreas.Sandberg@ARM.com#include "dev/arm/realview.hh"
5410461SAndreas.Sandberg@ARM.com#include "params/ArmPMU.hh"
5510461SAndreas.Sandberg@ARM.com
5610461SAndreas.Sandberg@ARM.comnamespace ArmISA {
5710461SAndreas.Sandberg@ARM.com
5810461SAndreas.Sandberg@ARM.comconst MiscReg PMU::reg_pmcr_wr_mask = 0x39;
5910461SAndreas.Sandberg@ARM.com
6010461SAndreas.Sandberg@ARM.comPMU::PMU(const ArmPMUParams *p)
6110461SAndreas.Sandberg@ARM.com    : SimObject(p), BaseISADevice(),
6210461SAndreas.Sandberg@ARM.com      reg_pmcnten(0), reg_pmcr(0),
6310461SAndreas.Sandberg@ARM.com      reg_pmselr(0), reg_pminten(0), reg_pmovsr(0),
6412117Sjose.marinho@arm.com      reg_pmceid0(0),reg_pmceid1(0),
6510461SAndreas.Sandberg@ARM.com      clock_remainder(0),
6612286Sjose.marinho@arm.com      maximumCounterCount(p->eventCounters),
6712286Sjose.marinho@arm.com      cycleCounter(*this, maximumCounterCount),
6812286Sjose.marinho@arm.com      cycleCounterEventId(p->cycleEventId),
6912286Sjose.marinho@arm.com      swIncrementEvent(nullptr),
7010461SAndreas.Sandberg@ARM.com      reg_pmcr_conf(0),
7110461SAndreas.Sandberg@ARM.com      pmuInterrupt(p->pmuInterrupt),
7210461SAndreas.Sandberg@ARM.com      platform(p->platform)
7310461SAndreas.Sandberg@ARM.com{
7410461SAndreas.Sandberg@ARM.com    DPRINTF(PMUVerbose, "Initializing the PMU.\n");
7510461SAndreas.Sandberg@ARM.com
7612286Sjose.marinho@arm.com    if (maximumCounterCount > 31) {
7710461SAndreas.Sandberg@ARM.com        fatal("The PMU can only accept 31 counters, %d counters requested.\n",
7812286Sjose.marinho@arm.com              maximumCounterCount);
7910461SAndreas.Sandberg@ARM.com    }
8010461SAndreas.Sandberg@ARM.com
8110461SAndreas.Sandberg@ARM.com    /* Setup the performance counter ID registers */
8210461SAndreas.Sandberg@ARM.com    reg_pmcr_conf.imp = 0x41;    // ARM Ltd.
8310461SAndreas.Sandberg@ARM.com    reg_pmcr_conf.idcode = 0x00;
8410461SAndreas.Sandberg@ARM.com    reg_pmcr_conf.n = p->eventCounters;
8510461SAndreas.Sandberg@ARM.com
8610461SAndreas.Sandberg@ARM.com    // Setup the hard-coded cycle counter, which is equivalent to
8710461SAndreas.Sandberg@ARM.com    // architected counter event type 0x11.
8810461SAndreas.Sandberg@ARM.com    cycleCounter.eventId = 0x11;
8910461SAndreas.Sandberg@ARM.com}
9010461SAndreas.Sandberg@ARM.com
9110461SAndreas.Sandberg@ARM.comPMU::~PMU()
9210461SAndreas.Sandberg@ARM.com{
9310461SAndreas.Sandberg@ARM.com}
9410461SAndreas.Sandberg@ARM.com
9510461SAndreas.Sandberg@ARM.comvoid
9612286Sjose.marinho@arm.comPMU::addSoftwareIncrementEvent(unsigned int id)
9712286Sjose.marinho@arm.com{
9812286Sjose.marinho@arm.com    auto old_event = eventMap.find(id);
9912286Sjose.marinho@arm.com    DPRINTF(PMUVerbose, "PMU: Adding SW increment event with id '0x%x'\n", id);
10012286Sjose.marinho@arm.com
10112286Sjose.marinho@arm.com    if (swIncrementEvent) {
10212286Sjose.marinho@arm.com        fatal_if(old_event == eventMap.end() ||
10312286Sjose.marinho@arm.com                 old_event->second != swIncrementEvent,
10412286Sjose.marinho@arm.com                 "Trying to add a software increment event with multiple"
10512286Sjose.marinho@arm.com                 "IDs. This is not supported.\n");
10612286Sjose.marinho@arm.com        return;
10712286Sjose.marinho@arm.com    }
10812286Sjose.marinho@arm.com
10912286Sjose.marinho@arm.com    fatal_if(old_event != eventMap.end(), "An event with id %d has "
11012286Sjose.marinho@arm.com             "been previously defined\n", id);
11112286Sjose.marinho@arm.com
11212286Sjose.marinho@arm.com    swIncrementEvent = new SWIncrementEvent();
11312286Sjose.marinho@arm.com    eventMap[id] = swIncrementEvent;
11412286Sjose.marinho@arm.com    registerEvent(id);
11512286Sjose.marinho@arm.com}
11612286Sjose.marinho@arm.com
11712286Sjose.marinho@arm.comvoid
11810461SAndreas.Sandberg@ARM.comPMU::addEventProbe(unsigned int id, SimObject *obj, const char *probe_name)
11910461SAndreas.Sandberg@ARM.com{
12010461SAndreas.Sandberg@ARM.com
12112286Sjose.marinho@arm.com    DPRINTF(PMUVerbose, "PMU: Adding Probe Driven event with id '0x%x'"
12212286Sjose.marinho@arm.com        "as probe %s:%s\n",id, obj->name(), probe_name);
12312286Sjose.marinho@arm.com
12412286Sjose.marinho@arm.com    RegularEvent *event = nullptr;
12512286Sjose.marinho@arm.com    auto event_entry = eventMap.find(id);
12612286Sjose.marinho@arm.com    if (event_entry == eventMap.end()) {
12712286Sjose.marinho@arm.com
12812286Sjose.marinho@arm.com        event = new RegularEvent();
12912286Sjose.marinho@arm.com        eventMap[id] = event;
13012286Sjose.marinho@arm.com
13112286Sjose.marinho@arm.com    } else {
13212286Sjose.marinho@arm.com        event = dynamic_cast<RegularEvent*>(event_entry->second);
13312286Sjose.marinho@arm.com        if (!event) {
13412286Sjose.marinho@arm.com            fatal("Event with id %d is not probe driven\n", id);
13512286Sjose.marinho@arm.com        }
13612286Sjose.marinho@arm.com    }
13712286Sjose.marinho@arm.com    event->addMicroarchitectureProbe(obj, probe_name);
13812286Sjose.marinho@arm.com
13912286Sjose.marinho@arm.com    registerEvent(id);
14012286Sjose.marinho@arm.com
14112286Sjose.marinho@arm.com}
14212286Sjose.marinho@arm.com
14312286Sjose.marinho@arm.comvoid
14412286Sjose.marinho@arm.comPMU::registerEvent(uint32_t id)
14512286Sjose.marinho@arm.com{
14612117Sjose.marinho@arm.com    // Flag the event as available in the corresponding PMCEID register if it
14712117Sjose.marinho@arm.com    // is an architected event.
14812117Sjose.marinho@arm.com    if (id < 0x20) {
14912117Sjose.marinho@arm.com        reg_pmceid0 |= ((uint64_t)1) << id;
15012117Sjose.marinho@arm.com    } else if (id > 0x20 && id < 0x40) {
15112117Sjose.marinho@arm.com        reg_pmceid1 |= ((uint64_t)1) << (id - 0x20);
15212117Sjose.marinho@arm.com    } else if (id >= 0x4000 && id < 0x4020) {
15312117Sjose.marinho@arm.com        reg_pmceid0 |= ((uint64_t)1) << (id - 0x4000 + 32);
15412117Sjose.marinho@arm.com    } else if (id >= 0x4020 && id < 0x4040) {
15512117Sjose.marinho@arm.com        reg_pmceid1 |= ((uint64_t)1) << (id - 0x4020 + 32);
15612117Sjose.marinho@arm.com    }
15710461SAndreas.Sandberg@ARM.com}
15810461SAndreas.Sandberg@ARM.com
15910461SAndreas.Sandberg@ARM.comvoid
16010461SAndreas.Sandberg@ARM.comPMU::drainResume()
16110461SAndreas.Sandberg@ARM.com{
16210461SAndreas.Sandberg@ARM.com    // Re-attach enabled counters after a resume in case they changed.
16310461SAndreas.Sandberg@ARM.com    updateAllCounters();
16410461SAndreas.Sandberg@ARM.com}
16510461SAndreas.Sandberg@ARM.com
16610461SAndreas.Sandberg@ARM.comvoid
16712286Sjose.marinho@arm.comPMU::regProbeListeners()
16812286Sjose.marinho@arm.com{
16912286Sjose.marinho@arm.com
17012286Sjose.marinho@arm.com    // at this stage all probe configurations are done
17112286Sjose.marinho@arm.com    // counters can be configured
17212286Sjose.marinho@arm.com    for (uint32_t index = 0; index < maximumCounterCount-1; index++) {
17312286Sjose.marinho@arm.com        counters.emplace_back(*this, index);
17412286Sjose.marinho@arm.com    }
17512286Sjose.marinho@arm.com
17612286Sjose.marinho@arm.com    PMUEvent *event = getEvent(cycleCounterEventId);
17712286Sjose.marinho@arm.com    panic_if(!event, "core cycle event is not present\n");
17812286Sjose.marinho@arm.com    cycleCounter.enabled = true;
17912286Sjose.marinho@arm.com    cycleCounter.attach(event);
18012286Sjose.marinho@arm.com}
18112286Sjose.marinho@arm.com
18212286Sjose.marinho@arm.comvoid
18310461SAndreas.Sandberg@ARM.comPMU::setMiscReg(int misc_reg, MiscReg val)
18410461SAndreas.Sandberg@ARM.com{
18510461SAndreas.Sandberg@ARM.com    DPRINTF(PMUVerbose, "setMiscReg(%s, 0x%x)\n",
18610461SAndreas.Sandberg@ARM.com            miscRegName[unflattenMiscReg(misc_reg)], val);
18710461SAndreas.Sandberg@ARM.com
18810461SAndreas.Sandberg@ARM.com    switch (unflattenMiscReg(misc_reg)) {
18910461SAndreas.Sandberg@ARM.com      case MISCREG_PMCR_EL0:
19010461SAndreas.Sandberg@ARM.com      case MISCREG_PMCR:
19110461SAndreas.Sandberg@ARM.com        setControlReg(val);
19210461SAndreas.Sandberg@ARM.com        return;
19310461SAndreas.Sandberg@ARM.com
19410461SAndreas.Sandberg@ARM.com      case MISCREG_PMCNTENSET_EL0:
19510461SAndreas.Sandberg@ARM.com      case MISCREG_PMCNTENSET:
19610461SAndreas.Sandberg@ARM.com        reg_pmcnten |= val;
19710461SAndreas.Sandberg@ARM.com        updateAllCounters();
19810461SAndreas.Sandberg@ARM.com        return;
19910461SAndreas.Sandberg@ARM.com
20010461SAndreas.Sandberg@ARM.com      case MISCREG_PMCNTENCLR_EL0:
20110461SAndreas.Sandberg@ARM.com      case MISCREG_PMCNTENCLR:
20210461SAndreas.Sandberg@ARM.com        reg_pmcnten &= ~val;
20310461SAndreas.Sandberg@ARM.com        updateAllCounters();
20410461SAndreas.Sandberg@ARM.com        return;
20510461SAndreas.Sandberg@ARM.com
20610461SAndreas.Sandberg@ARM.com      case MISCREG_PMOVSCLR_EL0:
20710461SAndreas.Sandberg@ARM.com      case MISCREG_PMOVSR:
20810461SAndreas.Sandberg@ARM.com        reg_pmovsr &= ~val;
20910461SAndreas.Sandberg@ARM.com        return;
21010461SAndreas.Sandberg@ARM.com
21110461SAndreas.Sandberg@ARM.com      case MISCREG_PMSWINC_EL0:
21210461SAndreas.Sandberg@ARM.com      case MISCREG_PMSWINC:
21312286Sjose.marinho@arm.com        if (swIncrementEvent) {
21412286Sjose.marinho@arm.com            swIncrementEvent->write(val);
21510461SAndreas.Sandberg@ARM.com        }
21612286Sjose.marinho@arm.com        return;
21710461SAndreas.Sandberg@ARM.com
21810461SAndreas.Sandberg@ARM.com      case MISCREG_PMCCNTR_EL0:
21910461SAndreas.Sandberg@ARM.com      case MISCREG_PMCCNTR:
22012286Sjose.marinho@arm.com        cycleCounter.setValue(val);
22110461SAndreas.Sandberg@ARM.com        return;
22210461SAndreas.Sandberg@ARM.com
22310461SAndreas.Sandberg@ARM.com      case MISCREG_PMSELR_EL0:
22410461SAndreas.Sandberg@ARM.com      case MISCREG_PMSELR:
22510461SAndreas.Sandberg@ARM.com        reg_pmselr = val;
22610461SAndreas.Sandberg@ARM.com        return;
22712117Sjose.marinho@arm.com      //TODO: implement MISCREF_PMCEID{2,3}
22810461SAndreas.Sandberg@ARM.com      case MISCREG_PMCEID0_EL0:
22910461SAndreas.Sandberg@ARM.com      case MISCREG_PMCEID0:
23010461SAndreas.Sandberg@ARM.com      case MISCREG_PMCEID1_EL0:
23110461SAndreas.Sandberg@ARM.com      case MISCREG_PMCEID1:
23210461SAndreas.Sandberg@ARM.com        // Ignore writes
23310461SAndreas.Sandberg@ARM.com        return;
23410461SAndreas.Sandberg@ARM.com
23510461SAndreas.Sandberg@ARM.com      case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0:
23612042Sandreas.sandberg@arm.com        setCounterTypeRegister(misc_reg - MISCREG_PMEVTYPER0_EL0, val);
23710461SAndreas.Sandberg@ARM.com        return;
23810461SAndreas.Sandberg@ARM.com
23910461SAndreas.Sandberg@ARM.com      case MISCREG_PMCCFILTR:
24010461SAndreas.Sandberg@ARM.com      case MISCREG_PMCCFILTR_EL0:
24110461SAndreas.Sandberg@ARM.com        DPRINTF(PMUVerbose, "Setting PMCCFILTR: 0x%x\n", val);
24210461SAndreas.Sandberg@ARM.com        setCounterTypeRegister(PMCCNTR, val);
24310461SAndreas.Sandberg@ARM.com        return;
24410461SAndreas.Sandberg@ARM.com
24510461SAndreas.Sandberg@ARM.com      case MISCREG_PMXEVTYPER_PMCCFILTR:
24610461SAndreas.Sandberg@ARM.com      case MISCREG_PMXEVTYPER_EL0:
24710461SAndreas.Sandberg@ARM.com      case MISCREG_PMXEVTYPER:
24810461SAndreas.Sandberg@ARM.com        DPRINTF(PMUVerbose, "Setting counter type: "
24910461SAndreas.Sandberg@ARM.com                "[PMSELR: 0x%x, PMSELER.sel: 0x%x, EVTYPER: 0x%x]\n",
25010461SAndreas.Sandberg@ARM.com                reg_pmselr, reg_pmselr.sel, val);
25110461SAndreas.Sandberg@ARM.com        setCounterTypeRegister(reg_pmselr.sel, val);
25210461SAndreas.Sandberg@ARM.com        return;
25310461SAndreas.Sandberg@ARM.com
25410461SAndreas.Sandberg@ARM.com      case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0:
25510461SAndreas.Sandberg@ARM.com        setCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0, val);
25610461SAndreas.Sandberg@ARM.com        return;
25710461SAndreas.Sandberg@ARM.com
25810461SAndreas.Sandberg@ARM.com      case MISCREG_PMXEVCNTR_EL0:
25910461SAndreas.Sandberg@ARM.com      case MISCREG_PMXEVCNTR:
26010461SAndreas.Sandberg@ARM.com        setCounterValue(reg_pmselr.sel, val);
26110461SAndreas.Sandberg@ARM.com        return;
26210461SAndreas.Sandberg@ARM.com
26310461SAndreas.Sandberg@ARM.com      case MISCREG_PMUSERENR_EL0:
26410461SAndreas.Sandberg@ARM.com      case MISCREG_PMUSERENR:
26510461SAndreas.Sandberg@ARM.com        // TODO
26610461SAndreas.Sandberg@ARM.com        break;
26710461SAndreas.Sandberg@ARM.com
26810461SAndreas.Sandberg@ARM.com      case MISCREG_PMINTENSET_EL1:
26910461SAndreas.Sandberg@ARM.com      case MISCREG_PMINTENSET:
27010461SAndreas.Sandberg@ARM.com        reg_pminten |= val;
27110461SAndreas.Sandberg@ARM.com        return;
27210461SAndreas.Sandberg@ARM.com
27310461SAndreas.Sandberg@ARM.com      case MISCREG_PMINTENCLR_EL1:
27410461SAndreas.Sandberg@ARM.com      case MISCREG_PMINTENCLR:
27510461SAndreas.Sandberg@ARM.com        reg_pminten &= ~val;
27610461SAndreas.Sandberg@ARM.com        return;
27710461SAndreas.Sandberg@ARM.com
27810461SAndreas.Sandberg@ARM.com      case MISCREG_PMOVSSET_EL0:
27910461SAndreas.Sandberg@ARM.com      case MISCREG_PMOVSSET:
28010461SAndreas.Sandberg@ARM.com        reg_pmovsr |= val;
28110461SAndreas.Sandberg@ARM.com        return;
28210461SAndreas.Sandberg@ARM.com
28310461SAndreas.Sandberg@ARM.com      default:
28410461SAndreas.Sandberg@ARM.com        panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]);
28510461SAndreas.Sandberg@ARM.com    }
28610461SAndreas.Sandberg@ARM.com
28710461SAndreas.Sandberg@ARM.com    warn("Not doing anything for write to miscreg %s\n",
28810461SAndreas.Sandberg@ARM.com         miscRegName[misc_reg]);
28910461SAndreas.Sandberg@ARM.com}
29010461SAndreas.Sandberg@ARM.com
29110461SAndreas.Sandberg@ARM.comMiscReg
29210461SAndreas.Sandberg@ARM.comPMU::readMiscReg(int misc_reg)
29310461SAndreas.Sandberg@ARM.com{
29410461SAndreas.Sandberg@ARM.com    MiscReg val(readMiscRegInt(misc_reg));
29510461SAndreas.Sandberg@ARM.com    DPRINTF(PMUVerbose, "readMiscReg(%s): 0x%x\n",
29610461SAndreas.Sandberg@ARM.com            miscRegName[unflattenMiscReg(misc_reg)], val);
29710461SAndreas.Sandberg@ARM.com    return val;
29810461SAndreas.Sandberg@ARM.com}
29910461SAndreas.Sandberg@ARM.com
30010461SAndreas.Sandberg@ARM.comMiscReg
30110461SAndreas.Sandberg@ARM.comPMU::readMiscRegInt(int misc_reg)
30210461SAndreas.Sandberg@ARM.com{
30310461SAndreas.Sandberg@ARM.com    misc_reg = unflattenMiscReg(misc_reg);
30410461SAndreas.Sandberg@ARM.com    switch (misc_reg) {
30510461SAndreas.Sandberg@ARM.com      case MISCREG_PMCR_EL0:
30610461SAndreas.Sandberg@ARM.com      case MISCREG_PMCR:
30710461SAndreas.Sandberg@ARM.com        return reg_pmcr_conf | (reg_pmcr & reg_pmcr_wr_mask);
30810461SAndreas.Sandberg@ARM.com
30910461SAndreas.Sandberg@ARM.com      case MISCREG_PMCNTENSET_EL0:
31010461SAndreas.Sandberg@ARM.com      case MISCREG_PMCNTENCLR_EL0:
31110461SAndreas.Sandberg@ARM.com      case MISCREG_PMCNTENSET:
31210461SAndreas.Sandberg@ARM.com      case MISCREG_PMCNTENCLR:
31310461SAndreas.Sandberg@ARM.com        return reg_pmcnten;
31410461SAndreas.Sandberg@ARM.com
31510461SAndreas.Sandberg@ARM.com      case MISCREG_PMOVSCLR_EL0:
31610461SAndreas.Sandberg@ARM.com      case MISCREG_PMOVSSET_EL0:
31710461SAndreas.Sandberg@ARM.com      case MISCREG_PMOVSR:  // Overflow Status Register
31810461SAndreas.Sandberg@ARM.com      case MISCREG_PMOVSSET:
31910461SAndreas.Sandberg@ARM.com        return reg_pmovsr;
32010461SAndreas.Sandberg@ARM.com
32110461SAndreas.Sandberg@ARM.com      case MISCREG_PMSWINC_EL0:
32210461SAndreas.Sandberg@ARM.com      case MISCREG_PMSWINC: // Software Increment Register (RAZ)
32310461SAndreas.Sandberg@ARM.com        return 0;
32410461SAndreas.Sandberg@ARM.com
32510461SAndreas.Sandberg@ARM.com      case MISCREG_PMSELR:
32610461SAndreas.Sandberg@ARM.com        return reg_pmselr;
32710461SAndreas.Sandberg@ARM.com
32810461SAndreas.Sandberg@ARM.com      case MISCREG_PMCEID0_EL0:
32912117Sjose.marinho@arm.com        return reg_pmceid0;
33010461SAndreas.Sandberg@ARM.com
33110461SAndreas.Sandberg@ARM.com      case MISCREG_PMCEID1_EL0:
33212117Sjose.marinho@arm.com        return reg_pmceid1;
33312117Sjose.marinho@arm.com
33412117Sjose.marinho@arm.com      //TODO: implement MISCREF_PMCEID{2,3}
33512117Sjose.marinho@arm.com      case MISCREG_PMCEID0: // Common Event ID register
33612117Sjose.marinho@arm.com        return reg_pmceid0 & 0xFFFFFFFF;
33712117Sjose.marinho@arm.com
33810461SAndreas.Sandberg@ARM.com      case MISCREG_PMCEID1: // Common Event ID register
33912117Sjose.marinho@arm.com        return reg_pmceid1 & 0xFFFFFFFF;
34010461SAndreas.Sandberg@ARM.com
34110461SAndreas.Sandberg@ARM.com      case MISCREG_PMCCNTR_EL0:
34212286Sjose.marinho@arm.com        return cycleCounter.getValue();
34310461SAndreas.Sandberg@ARM.com
34410461SAndreas.Sandberg@ARM.com      case MISCREG_PMCCNTR:
34512286Sjose.marinho@arm.com        return cycleCounter.getValue() & 0xFFFFFFFF;
34610461SAndreas.Sandberg@ARM.com
34710461SAndreas.Sandberg@ARM.com      case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0:
34810461SAndreas.Sandberg@ARM.com        return getCounterTypeRegister(misc_reg - MISCREG_PMEVTYPER0_EL0);
34910461SAndreas.Sandberg@ARM.com
35010461SAndreas.Sandberg@ARM.com      case MISCREG_PMCCFILTR:
35110461SAndreas.Sandberg@ARM.com      case MISCREG_PMCCFILTR_EL0:
35210461SAndreas.Sandberg@ARM.com        return getCounterTypeRegister(PMCCNTR);
35310461SAndreas.Sandberg@ARM.com
35410461SAndreas.Sandberg@ARM.com      case MISCREG_PMXEVTYPER_PMCCFILTR:
35510461SAndreas.Sandberg@ARM.com      case MISCREG_PMXEVTYPER_EL0:
35610461SAndreas.Sandberg@ARM.com      case MISCREG_PMXEVTYPER:
35710461SAndreas.Sandberg@ARM.com        return getCounterTypeRegister(reg_pmselr.sel);
35810461SAndreas.Sandberg@ARM.com
35912286Sjose.marinho@arm.com      case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0: {
36012286Sjose.marinho@arm.com            return getCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0) &
36112286Sjose.marinho@arm.com                0xFFFFFFFF;
36212286Sjose.marinho@arm.com
36312286Sjose.marinho@arm.com        }
36410461SAndreas.Sandberg@ARM.com
36510461SAndreas.Sandberg@ARM.com      case MISCREG_PMXEVCNTR_EL0:
36610461SAndreas.Sandberg@ARM.com      case MISCREG_PMXEVCNTR:
36710461SAndreas.Sandberg@ARM.com        return getCounterValue(reg_pmselr.sel) & 0xFFFFFFFF;
36810461SAndreas.Sandberg@ARM.com
36910461SAndreas.Sandberg@ARM.com      case MISCREG_PMUSERENR_EL0:
37010461SAndreas.Sandberg@ARM.com      case MISCREG_PMUSERENR:
37110461SAndreas.Sandberg@ARM.com        // TODO
37210461SAndreas.Sandberg@ARM.com        return 0;
37310461SAndreas.Sandberg@ARM.com
37410461SAndreas.Sandberg@ARM.com      case MISCREG_PMINTENSET_EL1:
37510461SAndreas.Sandberg@ARM.com      case MISCREG_PMINTENCLR_EL1:
37610461SAndreas.Sandberg@ARM.com      case MISCREG_PMINTENSET:
37710461SAndreas.Sandberg@ARM.com      case MISCREG_PMINTENCLR:
37810461SAndreas.Sandberg@ARM.com        return reg_pminten;
37910461SAndreas.Sandberg@ARM.com
38010461SAndreas.Sandberg@ARM.com      default:
38110461SAndreas.Sandberg@ARM.com        panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]);
38210461SAndreas.Sandberg@ARM.com    }
38310461SAndreas.Sandberg@ARM.com
38410461SAndreas.Sandberg@ARM.com    warn("Not doing anything for read from miscreg %s\n",
38510461SAndreas.Sandberg@ARM.com         miscRegName[misc_reg]);
38610461SAndreas.Sandberg@ARM.com    return 0;
38710461SAndreas.Sandberg@ARM.com}
38810461SAndreas.Sandberg@ARM.com
38910461SAndreas.Sandberg@ARM.comvoid
39010461SAndreas.Sandberg@ARM.comPMU::setControlReg(PMCR_t val)
39110461SAndreas.Sandberg@ARM.com{
39210461SAndreas.Sandberg@ARM.com    DPRINTF(PMUVerbose, "Set Control Reg 0x%08x.\n", val);
39310461SAndreas.Sandberg@ARM.com
39410461SAndreas.Sandberg@ARM.com    if (val.p) {
39510461SAndreas.Sandberg@ARM.com        DPRINTF(PMUVerbose, "PMU reset all events to zero.\n");
39610461SAndreas.Sandberg@ARM.com        resetEventCounts();
39710461SAndreas.Sandberg@ARM.com    }
39810461SAndreas.Sandberg@ARM.com
39910461SAndreas.Sandberg@ARM.com    if (val.c) {
40010461SAndreas.Sandberg@ARM.com        DPRINTF(PMUVerbose, "PMU reset cycle counter to zero.\n");
40112286Sjose.marinho@arm.com        cycleCounter.setValue(0);
40210461SAndreas.Sandberg@ARM.com    }
40310461SAndreas.Sandberg@ARM.com
40410461SAndreas.Sandberg@ARM.com    // Reset the clock remainder if divide by 64-mode is toggled.
40510461SAndreas.Sandberg@ARM.com    if (reg_pmcr.d != val.d)
40610461SAndreas.Sandberg@ARM.com        clock_remainder = 0;
40710461SAndreas.Sandberg@ARM.com
40810461SAndreas.Sandberg@ARM.com    reg_pmcr = val & reg_pmcr_wr_mask;
40910461SAndreas.Sandberg@ARM.com    updateAllCounters();
41010461SAndreas.Sandberg@ARM.com}
41110461SAndreas.Sandberg@ARM.com
41210461SAndreas.Sandberg@ARM.comvoid
41310461SAndreas.Sandberg@ARM.comPMU::updateAllCounters()
41410461SAndreas.Sandberg@ARM.com{
41510461SAndreas.Sandberg@ARM.com    const bool global_enable(reg_pmcr.e);
41610461SAndreas.Sandberg@ARM.com
41710461SAndreas.Sandberg@ARM.com    for (int i = 0; i < counters.size(); ++i) {
41810461SAndreas.Sandberg@ARM.com        CounterState &ctr(counters[i]);
41910461SAndreas.Sandberg@ARM.com        const bool enable(global_enable && (reg_pmcnten & (1 << i)));
42010461SAndreas.Sandberg@ARM.com        if (ctr.enabled != enable) {
42110461SAndreas.Sandberg@ARM.com            ctr.enabled = enable;
42212286Sjose.marinho@arm.com            updateCounter(ctr);
42310461SAndreas.Sandberg@ARM.com        }
42410461SAndreas.Sandberg@ARM.com    }
42510461SAndreas.Sandberg@ARM.com
42610461SAndreas.Sandberg@ARM.com    const bool ccntr_enable(global_enable && (reg_pmcnten & (1 << PMCCNTR)));
42710461SAndreas.Sandberg@ARM.com    if (cycleCounter.enabled != ccntr_enable) {
42810461SAndreas.Sandberg@ARM.com        cycleCounter.enabled = ccntr_enable;
42912286Sjose.marinho@arm.com        updateCounter(cycleCounter);
43010461SAndreas.Sandberg@ARM.com    }
43110461SAndreas.Sandberg@ARM.com}
43210461SAndreas.Sandberg@ARM.com
43312286Sjose.marinho@arm.comvoid
43412286Sjose.marinho@arm.comPMU::PMUEvent::attachEvent(PMU::CounterState *user)
43512286Sjose.marinho@arm.com{
43612286Sjose.marinho@arm.com    if (userCounters.empty()) {
43712286Sjose.marinho@arm.com        enable();
43812286Sjose.marinho@arm.com    }
43912286Sjose.marinho@arm.com    userCounters.insert(user);
44012286Sjose.marinho@arm.com    updateAttachedCounters();
44112286Sjose.marinho@arm.com}
44212286Sjose.marinho@arm.com
44312286Sjose.marinho@arm.comvoid
44412286Sjose.marinho@arm.comPMU::PMUEvent::increment(const uint64_t val)
44512286Sjose.marinho@arm.com{
44612286Sjose.marinho@arm.com    for (auto& counter: userCounters) {
44712286Sjose.marinho@arm.com        counter->add(val);
44812286Sjose.marinho@arm.com    }
44912286Sjose.marinho@arm.com}
45012286Sjose.marinho@arm.com
45112286Sjose.marinho@arm.comvoid
45212286Sjose.marinho@arm.comPMU::PMUEvent::detachEvent(PMU::CounterState *user)
45312286Sjose.marinho@arm.com{
45412286Sjose.marinho@arm.com    userCounters.erase(user);
45512286Sjose.marinho@arm.com
45612286Sjose.marinho@arm.com    if (userCounters.empty()) {
45712286Sjose.marinho@arm.com        disable();
45812286Sjose.marinho@arm.com    }
45912286Sjose.marinho@arm.com}
46012286Sjose.marinho@arm.com
46112286Sjose.marinho@arm.comvoid
46212286Sjose.marinho@arm.comPMU::RegularEvent::RegularProbe::notify(const uint64_t &val)
46312286Sjose.marinho@arm.com{
46412286Sjose.marinho@arm.com    parentEvent->increment(val);
46512286Sjose.marinho@arm.com}
46612286Sjose.marinho@arm.com
46712286Sjose.marinho@arm.comvoid
46812286Sjose.marinho@arm.comPMU::RegularEvent::enable()
46912286Sjose.marinho@arm.com{
47012286Sjose.marinho@arm.com    for (auto& subEvents: microArchitectureEventSet) {
47112286Sjose.marinho@arm.com        attachedProbePointList.emplace_back(
47212286Sjose.marinho@arm.com            new RegularProbe(this, subEvents.first, subEvents.second));
47312286Sjose.marinho@arm.com    }
47412286Sjose.marinho@arm.com}
47512286Sjose.marinho@arm.com
47612286Sjose.marinho@arm.comvoid
47712286Sjose.marinho@arm.comPMU::RegularEvent::disable()
47812286Sjose.marinho@arm.com{
47912286Sjose.marinho@arm.com    attachedProbePointList.clear();
48012286Sjose.marinho@arm.com}
48112286Sjose.marinho@arm.com
48210609Sandreas.sandberg@arm.combool
48312286Sjose.marinho@arm.comPMU::CounterState::isFiltered() const
48410609Sandreas.sandberg@arm.com{
48512286Sjose.marinho@arm.com    assert(pmu.isa);
48610609Sandreas.sandberg@arm.com
48712286Sjose.marinho@arm.com    const PMEVTYPER_t filter(this->filter);
48812286Sjose.marinho@arm.com    const SCR scr(pmu.isa->readMiscRegNoEffect(MISCREG_SCR));
48912286Sjose.marinho@arm.com    const CPSR cpsr(pmu.isa->readMiscRegNoEffect(MISCREG_CPSR));
49010609Sandreas.sandberg@arm.com    const ExceptionLevel el(opModeToEL((OperatingMode)(uint8_t)cpsr.mode));
49110609Sandreas.sandberg@arm.com    const bool secure(inSecureState(scr, cpsr));
49210609Sandreas.sandberg@arm.com
49310609Sandreas.sandberg@arm.com    switch (el) {
49410609Sandreas.sandberg@arm.com      case EL0:
49510609Sandreas.sandberg@arm.com        return secure ? filter.u : (filter.u != filter.nsu);
49610609Sandreas.sandberg@arm.com
49710609Sandreas.sandberg@arm.com      case EL1:
49810609Sandreas.sandberg@arm.com        return secure ? filter.p : (filter.p != filter.nsk);
49910609Sandreas.sandberg@arm.com
50010609Sandreas.sandberg@arm.com      case EL2:
50110609Sandreas.sandberg@arm.com        return !filter.nsh;
50210609Sandreas.sandberg@arm.com
50310609Sandreas.sandberg@arm.com      case EL3:
50410609Sandreas.sandberg@arm.com        return filter.p != filter.m;
50510609Sandreas.sandberg@arm.com
50610609Sandreas.sandberg@arm.com      default:
50710609Sandreas.sandberg@arm.com        panic("Unexpected execution level in PMU::isFiltered.\n");
50810609Sandreas.sandberg@arm.com    }
50910609Sandreas.sandberg@arm.com}
51010609Sandreas.sandberg@arm.com
51110461SAndreas.Sandberg@ARM.comvoid
51212286Sjose.marinho@arm.comPMU::CounterState::detach()
51310461SAndreas.Sandberg@ARM.com{
51412286Sjose.marinho@arm.com    if (sourceEvent) {
51512286Sjose.marinho@arm.com        sourceEvent->detachEvent(this);
51612286Sjose.marinho@arm.com        sourceEvent = nullptr;
51712286Sjose.marinho@arm.com    } else {
51812286Sjose.marinho@arm.com        debugCounter("detaching event not currently attached"
51912286Sjose.marinho@arm.com            " to any event\n");
52010461SAndreas.Sandberg@ARM.com    }
52110461SAndreas.Sandberg@ARM.com}
52210461SAndreas.Sandberg@ARM.com
52310461SAndreas.Sandberg@ARM.comvoid
52412286Sjose.marinho@arm.comPMU::CounterState::attach(PMUEvent* event)
52512286Sjose.marinho@arm.com{
52612286Sjose.marinho@arm.com    value = 0;
52712286Sjose.marinho@arm.com    sourceEvent = event;
52812286Sjose.marinho@arm.com    sourceEvent->attachEvent(this);
52912286Sjose.marinho@arm.com}
53012286Sjose.marinho@arm.com
53112286Sjose.marinho@arm.comuint64_t
53212286Sjose.marinho@arm.comPMU::CounterState::getValue() const
53312286Sjose.marinho@arm.com{
53412286Sjose.marinho@arm.com    if (sourceEvent) {
53512286Sjose.marinho@arm.com        sourceEvent->updateAttachedCounters();
53612286Sjose.marinho@arm.com    } else {
53712286Sjose.marinho@arm.com        debugCounter("attempted to get value from a counter without"
53812286Sjose.marinho@arm.com            " an associated event\n");
53912286Sjose.marinho@arm.com    }
54012286Sjose.marinho@arm.com    return value;
54112286Sjose.marinho@arm.com}
54212286Sjose.marinho@arm.com
54312286Sjose.marinho@arm.comvoid
54412286Sjose.marinho@arm.comPMU::CounterState::setValue(uint64_t val)
54512286Sjose.marinho@arm.com{
54612286Sjose.marinho@arm.com    value = val;
54712286Sjose.marinho@arm.com    resetValue = true;
54812286Sjose.marinho@arm.com
54912286Sjose.marinho@arm.com    if (sourceEvent) {
55012286Sjose.marinho@arm.com        sourceEvent->updateAttachedCounters();
55112286Sjose.marinho@arm.com    } else {
55212286Sjose.marinho@arm.com        debugCounter("attempted to set value from a counter without"
55312286Sjose.marinho@arm.com            " an associated event\n");
55412286Sjose.marinho@arm.com    }
55512286Sjose.marinho@arm.com}
55612286Sjose.marinho@arm.com
55712286Sjose.marinho@arm.comvoid
55812286Sjose.marinho@arm.comPMU::updateCounter(CounterState &ctr)
55910461SAndreas.Sandberg@ARM.com{
56010461SAndreas.Sandberg@ARM.com    if (!ctr.enabled) {
56112286Sjose.marinho@arm.com        DPRINTF(PMUVerbose, "updateCounter(%i): Disabling counter\n",
56212286Sjose.marinho@arm.com            ctr.getCounterId());
56312286Sjose.marinho@arm.com        ctr.detach();
56412286Sjose.marinho@arm.com
56510461SAndreas.Sandberg@ARM.com    } else {
56610461SAndreas.Sandberg@ARM.com        DPRINTF(PMUVerbose, "updateCounter(%i): Enable event id 0x%x\n",
56712286Sjose.marinho@arm.com                ctr.getCounterId(), ctr.eventId);
56810461SAndreas.Sandberg@ARM.com
56912286Sjose.marinho@arm.com        auto sourceEvent = eventMap.find(ctr.eventId);
57012286Sjose.marinho@arm.com        if (sourceEvent == eventMap.end()) {
57110461SAndreas.Sandberg@ARM.com            warn("Can't enable PMU counter of type '0x%x': "
57210461SAndreas.Sandberg@ARM.com                 "No such event type.\n", ctr.eventId);
57312286Sjose.marinho@arm.com        } else {
57412286Sjose.marinho@arm.com            ctr.attach(sourceEvent->second);
57510461SAndreas.Sandberg@ARM.com        }
57610461SAndreas.Sandberg@ARM.com    }
57710461SAndreas.Sandberg@ARM.com}
57810461SAndreas.Sandberg@ARM.com
57910461SAndreas.Sandberg@ARM.com
58010461SAndreas.Sandberg@ARM.comvoid
58110461SAndreas.Sandberg@ARM.comPMU::resetEventCounts()
58210461SAndreas.Sandberg@ARM.com{
58310461SAndreas.Sandberg@ARM.com    for (CounterState &ctr : counters)
58412286Sjose.marinho@arm.com        ctr.setValue(0);
58510461SAndreas.Sandberg@ARM.com}
58610461SAndreas.Sandberg@ARM.com
58710461SAndreas.Sandberg@ARM.comvoid
58810461SAndreas.Sandberg@ARM.comPMU::setCounterValue(CounterId id, uint64_t val)
58910461SAndreas.Sandberg@ARM.com{
59010461SAndreas.Sandberg@ARM.com    if (!isValidCounter(id)) {
59110461SAndreas.Sandberg@ARM.com        warn_once("Can't change counter value: Counter %i does not exist.\n",
59210461SAndreas.Sandberg@ARM.com                  id);
59310461SAndreas.Sandberg@ARM.com        return;
59410461SAndreas.Sandberg@ARM.com    }
59510461SAndreas.Sandberg@ARM.com
59610461SAndreas.Sandberg@ARM.com    CounterState &ctr(getCounter(id));
59712286Sjose.marinho@arm.com    ctr.setValue(val);
59810461SAndreas.Sandberg@ARM.com}
59910461SAndreas.Sandberg@ARM.com
60010461SAndreas.Sandberg@ARM.comPMU::PMEVTYPER_t
60110461SAndreas.Sandberg@ARM.comPMU::getCounterTypeRegister(CounterId id) const
60210461SAndreas.Sandberg@ARM.com{
60310461SAndreas.Sandberg@ARM.com    if (!isValidCounter(id))
60410461SAndreas.Sandberg@ARM.com        return 0;
60510461SAndreas.Sandberg@ARM.com
60610461SAndreas.Sandberg@ARM.com    const CounterState &cs(getCounter(id));
60710609Sandreas.sandberg@arm.com    PMEVTYPER_t type(cs.filter);
60810461SAndreas.Sandberg@ARM.com
60910461SAndreas.Sandberg@ARM.com    type.evtCount = cs.eventId;
61010461SAndreas.Sandberg@ARM.com
61110461SAndreas.Sandberg@ARM.com    return type;
61210461SAndreas.Sandberg@ARM.com}
61310461SAndreas.Sandberg@ARM.com
61410461SAndreas.Sandberg@ARM.comvoid
61510461SAndreas.Sandberg@ARM.comPMU::setCounterTypeRegister(CounterId id, PMEVTYPER_t val)
61610461SAndreas.Sandberg@ARM.com{
61710461SAndreas.Sandberg@ARM.com    DPRINTF(PMUVerbose, "Set Event [%d] = 0x%08x\n", id, val);
61810461SAndreas.Sandberg@ARM.com    if (!isValidCounter(id)) {
61910461SAndreas.Sandberg@ARM.com        warn_once("Can't change counter type: Counter %i does not exist.\n",
62010461SAndreas.Sandberg@ARM.com                  id);
62110461SAndreas.Sandberg@ARM.com        return;
62210461SAndreas.Sandberg@ARM.com    }
62310461SAndreas.Sandberg@ARM.com
62410461SAndreas.Sandberg@ARM.com    CounterState &ctr(getCounter(id));
62510609Sandreas.sandberg@arm.com    const EventTypeId old_event_id(ctr.eventId);
62610461SAndreas.Sandberg@ARM.com
62710609Sandreas.sandberg@arm.com    ctr.filter = val;
62810609Sandreas.sandberg@arm.com
62910609Sandreas.sandberg@arm.com    // If PMCCNTR Register, do not change event type. PMCCNTR can
63010609Sandreas.sandberg@arm.com    // count processor cycles only. If we change the event type, we
63110609Sandreas.sandberg@arm.com    // need to update the probes the counter is using.
63210609Sandreas.sandberg@arm.com    if (id != PMCCNTR && old_event_id != val.evtCount) {
63310461SAndreas.Sandberg@ARM.com        ctr.eventId = val.evtCount;
63412286Sjose.marinho@arm.com        updateCounter(ctr);
63510461SAndreas.Sandberg@ARM.com    }
63610461SAndreas.Sandberg@ARM.com}
63710461SAndreas.Sandberg@ARM.com
63810461SAndreas.Sandberg@ARM.comvoid
63910461SAndreas.Sandberg@ARM.comPMU::raiseInterrupt()
64010461SAndreas.Sandberg@ARM.com{
64110461SAndreas.Sandberg@ARM.com    RealView *rv(dynamic_cast<RealView *>(platform));
64210461SAndreas.Sandberg@ARM.com    if (!rv || !rv->gic) {
64310461SAndreas.Sandberg@ARM.com        warn_once("ARM PMU: GIC missing, can't raise interrupt.\n");
64410461SAndreas.Sandberg@ARM.com        return;
64510461SAndreas.Sandberg@ARM.com    }
64610461SAndreas.Sandberg@ARM.com
64710461SAndreas.Sandberg@ARM.com    DPRINTF(PMUVerbose, "Delivering PMU interrupt.\n");
64810461SAndreas.Sandberg@ARM.com    rv->gic->sendInt(pmuInterrupt);
64910461SAndreas.Sandberg@ARM.com}
65010461SAndreas.Sandberg@ARM.com
65110461SAndreas.Sandberg@ARM.comvoid
65210905Sandreas.sandberg@arm.comPMU::serialize(CheckpointOut &cp) const
65310461SAndreas.Sandberg@ARM.com{
65410461SAndreas.Sandberg@ARM.com    DPRINTF(Checkpoint, "Serializing Arm PMU\n");
65510461SAndreas.Sandberg@ARM.com
65610461SAndreas.Sandberg@ARM.com    SERIALIZE_SCALAR(reg_pmcr);
65710461SAndreas.Sandberg@ARM.com    SERIALIZE_SCALAR(reg_pmcnten);
65810461SAndreas.Sandberg@ARM.com    SERIALIZE_SCALAR(reg_pmselr);
65910461SAndreas.Sandberg@ARM.com    SERIALIZE_SCALAR(reg_pminten);
66010461SAndreas.Sandberg@ARM.com    SERIALIZE_SCALAR(reg_pmovsr);
66112117Sjose.marinho@arm.com    SERIALIZE_SCALAR(reg_pmceid0);
66212117Sjose.marinho@arm.com    SERIALIZE_SCALAR(reg_pmceid1);
66310461SAndreas.Sandberg@ARM.com    SERIALIZE_SCALAR(clock_remainder);
66410461SAndreas.Sandberg@ARM.com
66510905Sandreas.sandberg@arm.com    for (size_t i = 0; i < counters.size(); ++i)
66610905Sandreas.sandberg@arm.com        counters[i].serializeSection(cp, csprintf("counters.%i", i));
66710461SAndreas.Sandberg@ARM.com
66810905Sandreas.sandberg@arm.com    cycleCounter.serializeSection(cp, "cycleCounter");
66910461SAndreas.Sandberg@ARM.com}
67010461SAndreas.Sandberg@ARM.com
67110461SAndreas.Sandberg@ARM.comvoid
67210905Sandreas.sandberg@arm.comPMU::unserialize(CheckpointIn &cp)
67310461SAndreas.Sandberg@ARM.com{
67410461SAndreas.Sandberg@ARM.com    DPRINTF(Checkpoint, "Unserializing Arm PMU\n");
67510461SAndreas.Sandberg@ARM.com
67610461SAndreas.Sandberg@ARM.com    UNSERIALIZE_SCALAR(reg_pmcr);
67710461SAndreas.Sandberg@ARM.com    UNSERIALIZE_SCALAR(reg_pmcnten);
67810461SAndreas.Sandberg@ARM.com    UNSERIALIZE_SCALAR(reg_pmselr);
67910461SAndreas.Sandberg@ARM.com    UNSERIALIZE_SCALAR(reg_pminten);
68010461SAndreas.Sandberg@ARM.com    UNSERIALIZE_SCALAR(reg_pmovsr);
68112117Sjose.marinho@arm.com
68212117Sjose.marinho@arm.com    // Old checkpoints used to store the entire PMCEID value in a
68312117Sjose.marinho@arm.com    // single 64-bit entry (reg_pmceid). The register was extended in
68412117Sjose.marinho@arm.com    // ARMv8.1, so we now need to store it as two 64-bit registers.
68512117Sjose.marinho@arm.com    if (!UNSERIALIZE_OPT_SCALAR(reg_pmceid0))
68612117Sjose.marinho@arm.com        paramIn(cp, "reg_pmceid", reg_pmceid0);
68712117Sjose.marinho@arm.com
68812117Sjose.marinho@arm.com    if (!UNSERIALIZE_OPT_SCALAR(reg_pmceid1))
68912117Sjose.marinho@arm.com        reg_pmceid1 = 0;
69012117Sjose.marinho@arm.com
69110461SAndreas.Sandberg@ARM.com    UNSERIALIZE_SCALAR(clock_remainder);
69210461SAndreas.Sandberg@ARM.com
69310461SAndreas.Sandberg@ARM.com    for (size_t i = 0; i < counters.size(); ++i)
69410905Sandreas.sandberg@arm.com        counters[i].unserializeSection(cp, csprintf("counters.%i", i));
69510461SAndreas.Sandberg@ARM.com
69610905Sandreas.sandberg@arm.com    cycleCounter.unserializeSection(cp, "cycleCounter");
69710461SAndreas.Sandberg@ARM.com}
69810461SAndreas.Sandberg@ARM.com
69912286Sjose.marinho@arm.comPMU::PMUEvent*
70012286Sjose.marinho@arm.comPMU::getEvent(uint64_t eventId)
70112286Sjose.marinho@arm.com{
70212286Sjose.marinho@arm.com    auto entry = eventMap.find(eventId);
70312286Sjose.marinho@arm.com
70412286Sjose.marinho@arm.com    if (entry == eventMap.end()) {
70512286Sjose.marinho@arm.com        warn("event %d does not exist\n", eventId);
70612286Sjose.marinho@arm.com        return nullptr;
70712286Sjose.marinho@arm.com    } else {
70812286Sjose.marinho@arm.com        return entry->second;
70912286Sjose.marinho@arm.com    }
71012286Sjose.marinho@arm.com}
71112286Sjose.marinho@arm.com
71210461SAndreas.Sandberg@ARM.comvoid
71310905Sandreas.sandberg@arm.comPMU::CounterState::serialize(CheckpointOut &cp) const
71410461SAndreas.Sandberg@ARM.com{
71510461SAndreas.Sandberg@ARM.com    SERIALIZE_SCALAR(eventId);
71610461SAndreas.Sandberg@ARM.com    SERIALIZE_SCALAR(value);
71710461SAndreas.Sandberg@ARM.com    SERIALIZE_SCALAR(overflow64);
71810461SAndreas.Sandberg@ARM.com}
71910461SAndreas.Sandberg@ARM.com
72010461SAndreas.Sandberg@ARM.comvoid
72110905Sandreas.sandberg@arm.comPMU::CounterState::unserialize(CheckpointIn &cp)
72210461SAndreas.Sandberg@ARM.com{
72310461SAndreas.Sandberg@ARM.com    UNSERIALIZE_SCALAR(eventId);
72410461SAndreas.Sandberg@ARM.com    UNSERIALIZE_SCALAR(value);
72510461SAndreas.Sandberg@ARM.com    UNSERIALIZE_SCALAR(overflow64);
72610461SAndreas.Sandberg@ARM.com}
72710461SAndreas.Sandberg@ARM.com
72812286Sjose.marinho@arm.comuint64_t
72910461SAndreas.Sandberg@ARM.comPMU::CounterState::add(uint64_t delta)
73010461SAndreas.Sandberg@ARM.com{
73112286Sjose.marinho@arm.com    uint64_t value_until_overflow;
73212286Sjose.marinho@arm.com    if (overflow64) {
73312286Sjose.marinho@arm.com        value_until_overflow = UINT64_MAX - value;
73412286Sjose.marinho@arm.com    } else {
73512286Sjose.marinho@arm.com        value_until_overflow = UINT32_MAX - (uint32_t)value;
73612286Sjose.marinho@arm.com    }
73710461SAndreas.Sandberg@ARM.com
73812286Sjose.marinho@arm.com    if (isFiltered())
73912286Sjose.marinho@arm.com        return value_until_overflow;
74010461SAndreas.Sandberg@ARM.com
74112286Sjose.marinho@arm.com    if (resetValue) {
74212286Sjose.marinho@arm.com        delta = 0;
74312286Sjose.marinho@arm.com        resetValue = false;
74412286Sjose.marinho@arm.com    } else {
74512286Sjose.marinho@arm.com        value += delta;
74612286Sjose.marinho@arm.com    }
74712286Sjose.marinho@arm.com
74812286Sjose.marinho@arm.com    if (delta > value_until_overflow) {
74912286Sjose.marinho@arm.com
75012286Sjose.marinho@arm.com        // overflow situation detected
75112286Sjose.marinho@arm.com        // flag the overflow occurence
75212286Sjose.marinho@arm.com        pmu.reg_pmovsr |= (1 << counterId);
75312286Sjose.marinho@arm.com
75412286Sjose.marinho@arm.com        // Deliver a PMU interrupt if interrupt delivery is enabled
75512286Sjose.marinho@arm.com        // for this counter.
75612286Sjose.marinho@arm.com        if (pmu.reg_pminten  & (1 << counterId)) {
75712286Sjose.marinho@arm.com            pmu.raiseInterrupt();
75812286Sjose.marinho@arm.com        }
75912286Sjose.marinho@arm.com        return overflow64 ? UINT64_MAX : UINT32_MAX;
76012286Sjose.marinho@arm.com    }
76112286Sjose.marinho@arm.com    return value_until_overflow - delta + 1;
76212286Sjose.marinho@arm.com}
76312286Sjose.marinho@arm.com
76412286Sjose.marinho@arm.comvoid
76512286Sjose.marinho@arm.comPMU::SWIncrementEvent::write(uint64_t val)
76612286Sjose.marinho@arm.com{
76712286Sjose.marinho@arm.com    for (auto& counter: userCounters) {
76812286Sjose.marinho@arm.com        if (val & (0x1 << counter->getCounterId())) {
76912286Sjose.marinho@arm.com            counter->add(1);
77012286Sjose.marinho@arm.com        }
77112286Sjose.marinho@arm.com    }
77210461SAndreas.Sandberg@ARM.com}
77310461SAndreas.Sandberg@ARM.com
77410461SAndreas.Sandberg@ARM.com} // namespace ArmISA
77510461SAndreas.Sandberg@ARM.com
77610461SAndreas.Sandberg@ARM.comArmISA::PMU *
77710461SAndreas.Sandberg@ARM.comArmPMUParams::create()
77810461SAndreas.Sandberg@ARM.com{
77910461SAndreas.Sandberg@ARM.com    return new ArmISA::PMU(this);
78010461SAndreas.Sandberg@ARM.com}
781