pmu.cc revision 13638
110461SAndreas.Sandberg@ARM.com/*
213637Sruben.ayrapetyan@arm.com * Copyright (c) 2011-2014, 2017-2019 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 "params/ArmPMU.hh"
5410461SAndreas.Sandberg@ARM.com
5510461SAndreas.Sandberg@ARM.comnamespace ArmISA {
5610461SAndreas.Sandberg@ARM.com
5713581Sgabeblack@google.comconst RegVal PMU::reg_pmcr_wr_mask = 0x39;
5810461SAndreas.Sandberg@ARM.com
5910461SAndreas.Sandberg@ARM.comPMU::PMU(const ArmPMUParams *p)
6010461SAndreas.Sandberg@ARM.com    : SimObject(p), BaseISADevice(),
6110461SAndreas.Sandberg@ARM.com      reg_pmcnten(0), reg_pmcr(0),
6210461SAndreas.Sandberg@ARM.com      reg_pmselr(0), reg_pminten(0), reg_pmovsr(0),
6312117Sjose.marinho@arm.com      reg_pmceid0(0),reg_pmceid1(0),
6410461SAndreas.Sandberg@ARM.com      clock_remainder(0),
6512286Sjose.marinho@arm.com      maximumCounterCount(p->eventCounters),
6612286Sjose.marinho@arm.com      cycleCounter(*this, maximumCounterCount),
6712286Sjose.marinho@arm.com      cycleCounterEventId(p->cycleEventId),
6812286Sjose.marinho@arm.com      swIncrementEvent(nullptr),
6910461SAndreas.Sandberg@ARM.com      reg_pmcr_conf(0),
7013638Sgiacomo.travaglini@arm.com      interrupt(nullptr),
7110461SAndreas.Sandberg@ARM.com{
7210461SAndreas.Sandberg@ARM.com    DPRINTF(PMUVerbose, "Initializing the PMU.\n");
7310461SAndreas.Sandberg@ARM.com
7412286Sjose.marinho@arm.com    if (maximumCounterCount > 31) {
7510461SAndreas.Sandberg@ARM.com        fatal("The PMU can only accept 31 counters, %d counters requested.\n",
7612286Sjose.marinho@arm.com              maximumCounterCount);
7710461SAndreas.Sandberg@ARM.com    }
7810461SAndreas.Sandberg@ARM.com
7913638Sgiacomo.travaglini@arm.com    warn_if(!p->interrupt, "ARM PMU: No interrupt specified, interrupt " \
8012973Sandreas.sandberg@arm.com            "delivery disabled.\n");
8112973Sandreas.sandberg@arm.com
8210461SAndreas.Sandberg@ARM.com    /* Setup the performance counter ID registers */
8310461SAndreas.Sandberg@ARM.com    reg_pmcr_conf.imp = 0x41;    // ARM Ltd.
8410461SAndreas.Sandberg@ARM.com    reg_pmcr_conf.idcode = 0x00;
8510461SAndreas.Sandberg@ARM.com    reg_pmcr_conf.n = p->eventCounters;
8610461SAndreas.Sandberg@ARM.com
8710461SAndreas.Sandberg@ARM.com    // Setup the hard-coded cycle counter, which is equivalent to
8810461SAndreas.Sandberg@ARM.com    // architected counter event type 0x11.
8910461SAndreas.Sandberg@ARM.com    cycleCounter.eventId = 0x11;
9010461SAndreas.Sandberg@ARM.com}
9110461SAndreas.Sandberg@ARM.com
9210461SAndreas.Sandberg@ARM.comPMU::~PMU()
9310461SAndreas.Sandberg@ARM.com{
9410461SAndreas.Sandberg@ARM.com}
9510461SAndreas.Sandberg@ARM.com
9610461SAndreas.Sandberg@ARM.comvoid
9712973Sandreas.sandberg@arm.comPMU::setThreadContext(ThreadContext *tc)
9812973Sandreas.sandberg@arm.com{
9912973Sandreas.sandberg@arm.com    DPRINTF(PMUVerbose, "Assigning PMU to ContextID %i.\n", tc->contextId());
10013638Sgiacomo.travaglini@arm.com    auto pmu_params = static_cast<const ArmPMUParams *>(params());
10113638Sgiacomo.travaglini@arm.com
10213638Sgiacomo.travaglini@arm.com    if (pmu_params->interrupt)
10313638Sgiacomo.travaglini@arm.com        interrupt = pmu_params->interrupt->get(tc);
10412973Sandreas.sandberg@arm.com}
10512973Sandreas.sandberg@arm.com
10612973Sandreas.sandberg@arm.comvoid
10712286Sjose.marinho@arm.comPMU::addSoftwareIncrementEvent(unsigned int id)
10812286Sjose.marinho@arm.com{
10912286Sjose.marinho@arm.com    auto old_event = eventMap.find(id);
11012286Sjose.marinho@arm.com    DPRINTF(PMUVerbose, "PMU: Adding SW increment event with id '0x%x'\n", id);
11112286Sjose.marinho@arm.com
11212286Sjose.marinho@arm.com    if (swIncrementEvent) {
11312286Sjose.marinho@arm.com        fatal_if(old_event == eventMap.end() ||
11412286Sjose.marinho@arm.com                 old_event->second != swIncrementEvent,
11512286Sjose.marinho@arm.com                 "Trying to add a software increment event with multiple"
11612286Sjose.marinho@arm.com                 "IDs. This is not supported.\n");
11712286Sjose.marinho@arm.com        return;
11812286Sjose.marinho@arm.com    }
11912286Sjose.marinho@arm.com
12012286Sjose.marinho@arm.com    fatal_if(old_event != eventMap.end(), "An event with id %d has "
12112286Sjose.marinho@arm.com             "been previously defined\n", id);
12212286Sjose.marinho@arm.com
12312286Sjose.marinho@arm.com    swIncrementEvent = new SWIncrementEvent();
12412286Sjose.marinho@arm.com    eventMap[id] = swIncrementEvent;
12512286Sjose.marinho@arm.com    registerEvent(id);
12612286Sjose.marinho@arm.com}
12712286Sjose.marinho@arm.com
12812286Sjose.marinho@arm.comvoid
12910461SAndreas.Sandberg@ARM.comPMU::addEventProbe(unsigned int id, SimObject *obj, const char *probe_name)
13010461SAndreas.Sandberg@ARM.com{
13110461SAndreas.Sandberg@ARM.com
13212286Sjose.marinho@arm.com    DPRINTF(PMUVerbose, "PMU: Adding Probe Driven event with id '0x%x'"
13312286Sjose.marinho@arm.com        "as probe %s:%s\n",id, obj->name(), probe_name);
13412286Sjose.marinho@arm.com
13512286Sjose.marinho@arm.com    RegularEvent *event = nullptr;
13612286Sjose.marinho@arm.com    auto event_entry = eventMap.find(id);
13712286Sjose.marinho@arm.com    if (event_entry == eventMap.end()) {
13812286Sjose.marinho@arm.com
13912286Sjose.marinho@arm.com        event = new RegularEvent();
14012286Sjose.marinho@arm.com        eventMap[id] = event;
14112286Sjose.marinho@arm.com
14212286Sjose.marinho@arm.com    } else {
14312286Sjose.marinho@arm.com        event = dynamic_cast<RegularEvent*>(event_entry->second);
14412286Sjose.marinho@arm.com        if (!event) {
14512286Sjose.marinho@arm.com            fatal("Event with id %d is not probe driven\n", id);
14612286Sjose.marinho@arm.com        }
14712286Sjose.marinho@arm.com    }
14812286Sjose.marinho@arm.com    event->addMicroarchitectureProbe(obj, probe_name);
14912286Sjose.marinho@arm.com
15012286Sjose.marinho@arm.com    registerEvent(id);
15112286Sjose.marinho@arm.com
15212286Sjose.marinho@arm.com}
15312286Sjose.marinho@arm.com
15412286Sjose.marinho@arm.comvoid
15512286Sjose.marinho@arm.comPMU::registerEvent(uint32_t id)
15612286Sjose.marinho@arm.com{
15712117Sjose.marinho@arm.com    // Flag the event as available in the corresponding PMCEID register if it
15812117Sjose.marinho@arm.com    // is an architected event.
15912117Sjose.marinho@arm.com    if (id < 0x20) {
16012117Sjose.marinho@arm.com        reg_pmceid0 |= ((uint64_t)1) << id;
16112117Sjose.marinho@arm.com    } else if (id > 0x20 && id < 0x40) {
16212117Sjose.marinho@arm.com        reg_pmceid1 |= ((uint64_t)1) << (id - 0x20);
16312117Sjose.marinho@arm.com    } else if (id >= 0x4000 && id < 0x4020) {
16412117Sjose.marinho@arm.com        reg_pmceid0 |= ((uint64_t)1) << (id - 0x4000 + 32);
16512117Sjose.marinho@arm.com    } else if (id >= 0x4020 && id < 0x4040) {
16612117Sjose.marinho@arm.com        reg_pmceid1 |= ((uint64_t)1) << (id - 0x4020 + 32);
16712117Sjose.marinho@arm.com    }
16810461SAndreas.Sandberg@ARM.com}
16910461SAndreas.Sandberg@ARM.com
17010461SAndreas.Sandberg@ARM.comvoid
17110461SAndreas.Sandberg@ARM.comPMU::drainResume()
17210461SAndreas.Sandberg@ARM.com{
17310461SAndreas.Sandberg@ARM.com    // Re-attach enabled counters after a resume in case they changed.
17410461SAndreas.Sandberg@ARM.com    updateAllCounters();
17510461SAndreas.Sandberg@ARM.com}
17610461SAndreas.Sandberg@ARM.com
17710461SAndreas.Sandberg@ARM.comvoid
17812286Sjose.marinho@arm.comPMU::regProbeListeners()
17912286Sjose.marinho@arm.com{
18012286Sjose.marinho@arm.com
18112286Sjose.marinho@arm.com    // at this stage all probe configurations are done
18212286Sjose.marinho@arm.com    // counters can be configured
18312286Sjose.marinho@arm.com    for (uint32_t index = 0; index < maximumCounterCount-1; index++) {
18412286Sjose.marinho@arm.com        counters.emplace_back(*this, index);
18512286Sjose.marinho@arm.com    }
18612286Sjose.marinho@arm.com
18712286Sjose.marinho@arm.com    PMUEvent *event = getEvent(cycleCounterEventId);
18812286Sjose.marinho@arm.com    panic_if(!event, "core cycle event is not present\n");
18912286Sjose.marinho@arm.com    cycleCounter.enabled = true;
19012286Sjose.marinho@arm.com    cycleCounter.attach(event);
19112286Sjose.marinho@arm.com}
19212286Sjose.marinho@arm.com
19312286Sjose.marinho@arm.comvoid
19413581Sgabeblack@google.comPMU::setMiscReg(int misc_reg, RegVal val)
19510461SAndreas.Sandberg@ARM.com{
19610461SAndreas.Sandberg@ARM.com    DPRINTF(PMUVerbose, "setMiscReg(%s, 0x%x)\n",
19710461SAndreas.Sandberg@ARM.com            miscRegName[unflattenMiscReg(misc_reg)], val);
19810461SAndreas.Sandberg@ARM.com
19910461SAndreas.Sandberg@ARM.com    switch (unflattenMiscReg(misc_reg)) {
20010461SAndreas.Sandberg@ARM.com      case MISCREG_PMCR_EL0:
20110461SAndreas.Sandberg@ARM.com      case MISCREG_PMCR:
20210461SAndreas.Sandberg@ARM.com        setControlReg(val);
20310461SAndreas.Sandberg@ARM.com        return;
20410461SAndreas.Sandberg@ARM.com
20510461SAndreas.Sandberg@ARM.com      case MISCREG_PMCNTENSET_EL0:
20610461SAndreas.Sandberg@ARM.com      case MISCREG_PMCNTENSET:
20710461SAndreas.Sandberg@ARM.com        reg_pmcnten |= val;
20810461SAndreas.Sandberg@ARM.com        updateAllCounters();
20910461SAndreas.Sandberg@ARM.com        return;
21010461SAndreas.Sandberg@ARM.com
21110461SAndreas.Sandberg@ARM.com      case MISCREG_PMCNTENCLR_EL0:
21210461SAndreas.Sandberg@ARM.com      case MISCREG_PMCNTENCLR:
21310461SAndreas.Sandberg@ARM.com        reg_pmcnten &= ~val;
21410461SAndreas.Sandberg@ARM.com        updateAllCounters();
21510461SAndreas.Sandberg@ARM.com        return;
21610461SAndreas.Sandberg@ARM.com
21710461SAndreas.Sandberg@ARM.com      case MISCREG_PMOVSCLR_EL0:
21810461SAndreas.Sandberg@ARM.com      case MISCREG_PMOVSR:
21913104Sgiacomo.travaglini@arm.com        setOverflowStatus(reg_pmovsr & ~val);
22010461SAndreas.Sandberg@ARM.com        return;
22110461SAndreas.Sandberg@ARM.com
22210461SAndreas.Sandberg@ARM.com      case MISCREG_PMSWINC_EL0:
22310461SAndreas.Sandberg@ARM.com      case MISCREG_PMSWINC:
22412286Sjose.marinho@arm.com        if (swIncrementEvent) {
22512286Sjose.marinho@arm.com            swIncrementEvent->write(val);
22610461SAndreas.Sandberg@ARM.com        }
22712286Sjose.marinho@arm.com        return;
22810461SAndreas.Sandberg@ARM.com
22910461SAndreas.Sandberg@ARM.com      case MISCREG_PMCCNTR_EL0:
23010461SAndreas.Sandberg@ARM.com      case MISCREG_PMCCNTR:
23112286Sjose.marinho@arm.com        cycleCounter.setValue(val);
23210461SAndreas.Sandberg@ARM.com        return;
23310461SAndreas.Sandberg@ARM.com
23410461SAndreas.Sandberg@ARM.com      case MISCREG_PMSELR_EL0:
23510461SAndreas.Sandberg@ARM.com      case MISCREG_PMSELR:
23610461SAndreas.Sandberg@ARM.com        reg_pmselr = val;
23710461SAndreas.Sandberg@ARM.com        return;
23812117Sjose.marinho@arm.com      //TODO: implement MISCREF_PMCEID{2,3}
23910461SAndreas.Sandberg@ARM.com      case MISCREG_PMCEID0_EL0:
24010461SAndreas.Sandberg@ARM.com      case MISCREG_PMCEID0:
24110461SAndreas.Sandberg@ARM.com      case MISCREG_PMCEID1_EL0:
24210461SAndreas.Sandberg@ARM.com      case MISCREG_PMCEID1:
24310461SAndreas.Sandberg@ARM.com        // Ignore writes
24410461SAndreas.Sandberg@ARM.com        return;
24510461SAndreas.Sandberg@ARM.com
24610461SAndreas.Sandberg@ARM.com      case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0:
24712042Sandreas.sandberg@arm.com        setCounterTypeRegister(misc_reg - MISCREG_PMEVTYPER0_EL0, val);
24810461SAndreas.Sandberg@ARM.com        return;
24910461SAndreas.Sandberg@ARM.com
25010461SAndreas.Sandberg@ARM.com      case MISCREG_PMCCFILTR:
25110461SAndreas.Sandberg@ARM.com      case MISCREG_PMCCFILTR_EL0:
25210461SAndreas.Sandberg@ARM.com        DPRINTF(PMUVerbose, "Setting PMCCFILTR: 0x%x\n", val);
25310461SAndreas.Sandberg@ARM.com        setCounterTypeRegister(PMCCNTR, val);
25410461SAndreas.Sandberg@ARM.com        return;
25510461SAndreas.Sandberg@ARM.com
25610461SAndreas.Sandberg@ARM.com      case MISCREG_PMXEVTYPER_PMCCFILTR:
25710461SAndreas.Sandberg@ARM.com      case MISCREG_PMXEVTYPER_EL0:
25810461SAndreas.Sandberg@ARM.com      case MISCREG_PMXEVTYPER:
25910461SAndreas.Sandberg@ARM.com        DPRINTF(PMUVerbose, "Setting counter type: "
26010461SAndreas.Sandberg@ARM.com                "[PMSELR: 0x%x, PMSELER.sel: 0x%x, EVTYPER: 0x%x]\n",
26110461SAndreas.Sandberg@ARM.com                reg_pmselr, reg_pmselr.sel, val);
26210461SAndreas.Sandberg@ARM.com        setCounterTypeRegister(reg_pmselr.sel, val);
26310461SAndreas.Sandberg@ARM.com        return;
26410461SAndreas.Sandberg@ARM.com
26510461SAndreas.Sandberg@ARM.com      case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0:
26610461SAndreas.Sandberg@ARM.com        setCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0, val);
26710461SAndreas.Sandberg@ARM.com        return;
26810461SAndreas.Sandberg@ARM.com
26910461SAndreas.Sandberg@ARM.com      case MISCREG_PMXEVCNTR_EL0:
27010461SAndreas.Sandberg@ARM.com      case MISCREG_PMXEVCNTR:
27110461SAndreas.Sandberg@ARM.com        setCounterValue(reg_pmselr.sel, val);
27210461SAndreas.Sandberg@ARM.com        return;
27310461SAndreas.Sandberg@ARM.com
27410461SAndreas.Sandberg@ARM.com      case MISCREG_PMUSERENR_EL0:
27510461SAndreas.Sandberg@ARM.com      case MISCREG_PMUSERENR:
27610461SAndreas.Sandberg@ARM.com        // TODO
27710461SAndreas.Sandberg@ARM.com        break;
27810461SAndreas.Sandberg@ARM.com
27910461SAndreas.Sandberg@ARM.com      case MISCREG_PMINTENSET_EL1:
28010461SAndreas.Sandberg@ARM.com      case MISCREG_PMINTENSET:
28110461SAndreas.Sandberg@ARM.com        reg_pminten |= val;
28210461SAndreas.Sandberg@ARM.com        return;
28310461SAndreas.Sandberg@ARM.com
28410461SAndreas.Sandberg@ARM.com      case MISCREG_PMINTENCLR_EL1:
28510461SAndreas.Sandberg@ARM.com      case MISCREG_PMINTENCLR:
28610461SAndreas.Sandberg@ARM.com        reg_pminten &= ~val;
28710461SAndreas.Sandberg@ARM.com        return;
28810461SAndreas.Sandberg@ARM.com
28910461SAndreas.Sandberg@ARM.com      case MISCREG_PMOVSSET_EL0:
29010461SAndreas.Sandberg@ARM.com      case MISCREG_PMOVSSET:
29113104Sgiacomo.travaglini@arm.com        setOverflowStatus(reg_pmovsr | val);
29210461SAndreas.Sandberg@ARM.com        return;
29310461SAndreas.Sandberg@ARM.com
29410461SAndreas.Sandberg@ARM.com      default:
29510461SAndreas.Sandberg@ARM.com        panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]);
29610461SAndreas.Sandberg@ARM.com    }
29710461SAndreas.Sandberg@ARM.com
29810461SAndreas.Sandberg@ARM.com    warn("Not doing anything for write to miscreg %s\n",
29910461SAndreas.Sandberg@ARM.com         miscRegName[misc_reg]);
30010461SAndreas.Sandberg@ARM.com}
30110461SAndreas.Sandberg@ARM.com
30213581Sgabeblack@google.comRegVal
30310461SAndreas.Sandberg@ARM.comPMU::readMiscReg(int misc_reg)
30410461SAndreas.Sandberg@ARM.com{
30513581Sgabeblack@google.com    RegVal val(readMiscRegInt(misc_reg));
30610461SAndreas.Sandberg@ARM.com    DPRINTF(PMUVerbose, "readMiscReg(%s): 0x%x\n",
30710461SAndreas.Sandberg@ARM.com            miscRegName[unflattenMiscReg(misc_reg)], val);
30810461SAndreas.Sandberg@ARM.com    return val;
30910461SAndreas.Sandberg@ARM.com}
31010461SAndreas.Sandberg@ARM.com
31113581Sgabeblack@google.comRegVal
31210461SAndreas.Sandberg@ARM.comPMU::readMiscRegInt(int misc_reg)
31310461SAndreas.Sandberg@ARM.com{
31410461SAndreas.Sandberg@ARM.com    misc_reg = unflattenMiscReg(misc_reg);
31510461SAndreas.Sandberg@ARM.com    switch (misc_reg) {
31610461SAndreas.Sandberg@ARM.com      case MISCREG_PMCR_EL0:
31710461SAndreas.Sandberg@ARM.com      case MISCREG_PMCR:
31810461SAndreas.Sandberg@ARM.com        return reg_pmcr_conf | (reg_pmcr & reg_pmcr_wr_mask);
31910461SAndreas.Sandberg@ARM.com
32010461SAndreas.Sandberg@ARM.com      case MISCREG_PMCNTENSET_EL0:
32110461SAndreas.Sandberg@ARM.com      case MISCREG_PMCNTENCLR_EL0:
32210461SAndreas.Sandberg@ARM.com      case MISCREG_PMCNTENSET:
32310461SAndreas.Sandberg@ARM.com      case MISCREG_PMCNTENCLR:
32410461SAndreas.Sandberg@ARM.com        return reg_pmcnten;
32510461SAndreas.Sandberg@ARM.com
32610461SAndreas.Sandberg@ARM.com      case MISCREG_PMOVSCLR_EL0:
32710461SAndreas.Sandberg@ARM.com      case MISCREG_PMOVSSET_EL0:
32810461SAndreas.Sandberg@ARM.com      case MISCREG_PMOVSR:  // Overflow Status Register
32910461SAndreas.Sandberg@ARM.com      case MISCREG_PMOVSSET:
33010461SAndreas.Sandberg@ARM.com        return reg_pmovsr;
33110461SAndreas.Sandberg@ARM.com
33210461SAndreas.Sandberg@ARM.com      case MISCREG_PMSWINC_EL0:
33310461SAndreas.Sandberg@ARM.com      case MISCREG_PMSWINC: // Software Increment Register (RAZ)
33410461SAndreas.Sandberg@ARM.com        return 0;
33510461SAndreas.Sandberg@ARM.com
33610461SAndreas.Sandberg@ARM.com      case MISCREG_PMSELR:
33710461SAndreas.Sandberg@ARM.com        return reg_pmselr;
33810461SAndreas.Sandberg@ARM.com
33910461SAndreas.Sandberg@ARM.com      case MISCREG_PMCEID0_EL0:
34012117Sjose.marinho@arm.com        return reg_pmceid0;
34110461SAndreas.Sandberg@ARM.com
34210461SAndreas.Sandberg@ARM.com      case MISCREG_PMCEID1_EL0:
34312117Sjose.marinho@arm.com        return reg_pmceid1;
34412117Sjose.marinho@arm.com
34512117Sjose.marinho@arm.com      //TODO: implement MISCREF_PMCEID{2,3}
34612117Sjose.marinho@arm.com      case MISCREG_PMCEID0: // Common Event ID register
34712117Sjose.marinho@arm.com        return reg_pmceid0 & 0xFFFFFFFF;
34812117Sjose.marinho@arm.com
34910461SAndreas.Sandberg@ARM.com      case MISCREG_PMCEID1: // Common Event ID register
35012117Sjose.marinho@arm.com        return reg_pmceid1 & 0xFFFFFFFF;
35110461SAndreas.Sandberg@ARM.com
35210461SAndreas.Sandberg@ARM.com      case MISCREG_PMCCNTR_EL0:
35312286Sjose.marinho@arm.com        return cycleCounter.getValue();
35410461SAndreas.Sandberg@ARM.com
35510461SAndreas.Sandberg@ARM.com      case MISCREG_PMCCNTR:
35612286Sjose.marinho@arm.com        return cycleCounter.getValue() & 0xFFFFFFFF;
35710461SAndreas.Sandberg@ARM.com
35810461SAndreas.Sandberg@ARM.com      case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0:
35910461SAndreas.Sandberg@ARM.com        return getCounterTypeRegister(misc_reg - MISCREG_PMEVTYPER0_EL0);
36010461SAndreas.Sandberg@ARM.com
36110461SAndreas.Sandberg@ARM.com      case MISCREG_PMCCFILTR:
36210461SAndreas.Sandberg@ARM.com      case MISCREG_PMCCFILTR_EL0:
36310461SAndreas.Sandberg@ARM.com        return getCounterTypeRegister(PMCCNTR);
36410461SAndreas.Sandberg@ARM.com
36510461SAndreas.Sandberg@ARM.com      case MISCREG_PMXEVTYPER_PMCCFILTR:
36610461SAndreas.Sandberg@ARM.com      case MISCREG_PMXEVTYPER_EL0:
36710461SAndreas.Sandberg@ARM.com      case MISCREG_PMXEVTYPER:
36810461SAndreas.Sandberg@ARM.com        return getCounterTypeRegister(reg_pmselr.sel);
36910461SAndreas.Sandberg@ARM.com
37012286Sjose.marinho@arm.com      case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0: {
37112286Sjose.marinho@arm.com            return getCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0) &
37212286Sjose.marinho@arm.com                0xFFFFFFFF;
37312286Sjose.marinho@arm.com
37412286Sjose.marinho@arm.com        }
37510461SAndreas.Sandberg@ARM.com
37610461SAndreas.Sandberg@ARM.com      case MISCREG_PMXEVCNTR_EL0:
37710461SAndreas.Sandberg@ARM.com      case MISCREG_PMXEVCNTR:
37810461SAndreas.Sandberg@ARM.com        return getCounterValue(reg_pmselr.sel) & 0xFFFFFFFF;
37910461SAndreas.Sandberg@ARM.com
38010461SAndreas.Sandberg@ARM.com      case MISCREG_PMUSERENR_EL0:
38110461SAndreas.Sandberg@ARM.com      case MISCREG_PMUSERENR:
38210461SAndreas.Sandberg@ARM.com        // TODO
38310461SAndreas.Sandberg@ARM.com        return 0;
38410461SAndreas.Sandberg@ARM.com
38510461SAndreas.Sandberg@ARM.com      case MISCREG_PMINTENSET_EL1:
38610461SAndreas.Sandberg@ARM.com      case MISCREG_PMINTENCLR_EL1:
38710461SAndreas.Sandberg@ARM.com      case MISCREG_PMINTENSET:
38810461SAndreas.Sandberg@ARM.com      case MISCREG_PMINTENCLR:
38910461SAndreas.Sandberg@ARM.com        return reg_pminten;
39010461SAndreas.Sandberg@ARM.com
39110461SAndreas.Sandberg@ARM.com      default:
39210461SAndreas.Sandberg@ARM.com        panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]);
39310461SAndreas.Sandberg@ARM.com    }
39410461SAndreas.Sandberg@ARM.com
39510461SAndreas.Sandberg@ARM.com    warn("Not doing anything for read from miscreg %s\n",
39610461SAndreas.Sandberg@ARM.com         miscRegName[misc_reg]);
39710461SAndreas.Sandberg@ARM.com    return 0;
39810461SAndreas.Sandberg@ARM.com}
39910461SAndreas.Sandberg@ARM.com
40010461SAndreas.Sandberg@ARM.comvoid
40110461SAndreas.Sandberg@ARM.comPMU::setControlReg(PMCR_t val)
40210461SAndreas.Sandberg@ARM.com{
40310461SAndreas.Sandberg@ARM.com    DPRINTF(PMUVerbose, "Set Control Reg 0x%08x.\n", val);
40410461SAndreas.Sandberg@ARM.com
40510461SAndreas.Sandberg@ARM.com    if (val.p) {
40610461SAndreas.Sandberg@ARM.com        DPRINTF(PMUVerbose, "PMU reset all events to zero.\n");
40710461SAndreas.Sandberg@ARM.com        resetEventCounts();
40810461SAndreas.Sandberg@ARM.com    }
40910461SAndreas.Sandberg@ARM.com
41010461SAndreas.Sandberg@ARM.com    if (val.c) {
41110461SAndreas.Sandberg@ARM.com        DPRINTF(PMUVerbose, "PMU reset cycle counter to zero.\n");
41212286Sjose.marinho@arm.com        cycleCounter.setValue(0);
41310461SAndreas.Sandberg@ARM.com    }
41410461SAndreas.Sandberg@ARM.com
41510461SAndreas.Sandberg@ARM.com    // Reset the clock remainder if divide by 64-mode is toggled.
41610461SAndreas.Sandberg@ARM.com    if (reg_pmcr.d != val.d)
41710461SAndreas.Sandberg@ARM.com        clock_remainder = 0;
41810461SAndreas.Sandberg@ARM.com
41910461SAndreas.Sandberg@ARM.com    reg_pmcr = val & reg_pmcr_wr_mask;
42010461SAndreas.Sandberg@ARM.com    updateAllCounters();
42110461SAndreas.Sandberg@ARM.com}
42210461SAndreas.Sandberg@ARM.com
42310461SAndreas.Sandberg@ARM.comvoid
42410461SAndreas.Sandberg@ARM.comPMU::updateAllCounters()
42510461SAndreas.Sandberg@ARM.com{
42610461SAndreas.Sandberg@ARM.com    const bool global_enable(reg_pmcr.e);
42710461SAndreas.Sandberg@ARM.com
42810461SAndreas.Sandberg@ARM.com    for (int i = 0; i < counters.size(); ++i) {
42910461SAndreas.Sandberg@ARM.com        CounterState &ctr(counters[i]);
43010461SAndreas.Sandberg@ARM.com        const bool enable(global_enable && (reg_pmcnten & (1 << i)));
43110461SAndreas.Sandberg@ARM.com        if (ctr.enabled != enable) {
43210461SAndreas.Sandberg@ARM.com            ctr.enabled = enable;
43312286Sjose.marinho@arm.com            updateCounter(ctr);
43410461SAndreas.Sandberg@ARM.com        }
43510461SAndreas.Sandberg@ARM.com    }
43610461SAndreas.Sandberg@ARM.com
43710461SAndreas.Sandberg@ARM.com    const bool ccntr_enable(global_enable && (reg_pmcnten & (1 << PMCCNTR)));
43810461SAndreas.Sandberg@ARM.com    if (cycleCounter.enabled != ccntr_enable) {
43910461SAndreas.Sandberg@ARM.com        cycleCounter.enabled = ccntr_enable;
44012286Sjose.marinho@arm.com        updateCounter(cycleCounter);
44110461SAndreas.Sandberg@ARM.com    }
44210461SAndreas.Sandberg@ARM.com}
44310461SAndreas.Sandberg@ARM.com
44412286Sjose.marinho@arm.comvoid
44512286Sjose.marinho@arm.comPMU::PMUEvent::attachEvent(PMU::CounterState *user)
44612286Sjose.marinho@arm.com{
44712286Sjose.marinho@arm.com    if (userCounters.empty()) {
44812286Sjose.marinho@arm.com        enable();
44912286Sjose.marinho@arm.com    }
45012286Sjose.marinho@arm.com    userCounters.insert(user);
45112286Sjose.marinho@arm.com    updateAttachedCounters();
45212286Sjose.marinho@arm.com}
45312286Sjose.marinho@arm.com
45412286Sjose.marinho@arm.comvoid
45512286Sjose.marinho@arm.comPMU::PMUEvent::increment(const uint64_t val)
45612286Sjose.marinho@arm.com{
45712286Sjose.marinho@arm.com    for (auto& counter: userCounters) {
45812286Sjose.marinho@arm.com        counter->add(val);
45912286Sjose.marinho@arm.com    }
46012286Sjose.marinho@arm.com}
46112286Sjose.marinho@arm.com
46212286Sjose.marinho@arm.comvoid
46312286Sjose.marinho@arm.comPMU::PMUEvent::detachEvent(PMU::CounterState *user)
46412286Sjose.marinho@arm.com{
46512286Sjose.marinho@arm.com    userCounters.erase(user);
46612286Sjose.marinho@arm.com
46712286Sjose.marinho@arm.com    if (userCounters.empty()) {
46812286Sjose.marinho@arm.com        disable();
46912286Sjose.marinho@arm.com    }
47012286Sjose.marinho@arm.com}
47112286Sjose.marinho@arm.com
47212286Sjose.marinho@arm.comvoid
47312286Sjose.marinho@arm.comPMU::RegularEvent::RegularProbe::notify(const uint64_t &val)
47412286Sjose.marinho@arm.com{
47512286Sjose.marinho@arm.com    parentEvent->increment(val);
47612286Sjose.marinho@arm.com}
47712286Sjose.marinho@arm.com
47812286Sjose.marinho@arm.comvoid
47912286Sjose.marinho@arm.comPMU::RegularEvent::enable()
48012286Sjose.marinho@arm.com{
48112286Sjose.marinho@arm.com    for (auto& subEvents: microArchitectureEventSet) {
48212286Sjose.marinho@arm.com        attachedProbePointList.emplace_back(
48312286Sjose.marinho@arm.com            new RegularProbe(this, subEvents.first, subEvents.second));
48412286Sjose.marinho@arm.com    }
48512286Sjose.marinho@arm.com}
48612286Sjose.marinho@arm.com
48712286Sjose.marinho@arm.comvoid
48812286Sjose.marinho@arm.comPMU::RegularEvent::disable()
48912286Sjose.marinho@arm.com{
49012286Sjose.marinho@arm.com    attachedProbePointList.clear();
49112286Sjose.marinho@arm.com}
49212286Sjose.marinho@arm.com
49310609Sandreas.sandberg@arm.combool
49412286Sjose.marinho@arm.comPMU::CounterState::isFiltered() const
49510609Sandreas.sandberg@arm.com{
49612286Sjose.marinho@arm.com    assert(pmu.isa);
49710609Sandreas.sandberg@arm.com
49812286Sjose.marinho@arm.com    const PMEVTYPER_t filter(this->filter);
49912286Sjose.marinho@arm.com    const SCR scr(pmu.isa->readMiscRegNoEffect(MISCREG_SCR));
50012286Sjose.marinho@arm.com    const CPSR cpsr(pmu.isa->readMiscRegNoEffect(MISCREG_CPSR));
50110609Sandreas.sandberg@arm.com    const ExceptionLevel el(opModeToEL((OperatingMode)(uint8_t)cpsr.mode));
50210609Sandreas.sandberg@arm.com    const bool secure(inSecureState(scr, cpsr));
50310609Sandreas.sandberg@arm.com
50410609Sandreas.sandberg@arm.com    switch (el) {
50510609Sandreas.sandberg@arm.com      case EL0:
50610609Sandreas.sandberg@arm.com        return secure ? filter.u : (filter.u != filter.nsu);
50710609Sandreas.sandberg@arm.com
50810609Sandreas.sandberg@arm.com      case EL1:
50910609Sandreas.sandberg@arm.com        return secure ? filter.p : (filter.p != filter.nsk);
51010609Sandreas.sandberg@arm.com
51110609Sandreas.sandberg@arm.com      case EL2:
51210609Sandreas.sandberg@arm.com        return !filter.nsh;
51310609Sandreas.sandberg@arm.com
51410609Sandreas.sandberg@arm.com      case EL3:
51510609Sandreas.sandberg@arm.com        return filter.p != filter.m;
51610609Sandreas.sandberg@arm.com
51710609Sandreas.sandberg@arm.com      default:
51810609Sandreas.sandberg@arm.com        panic("Unexpected execution level in PMU::isFiltered.\n");
51910609Sandreas.sandberg@arm.com    }
52010609Sandreas.sandberg@arm.com}
52110609Sandreas.sandberg@arm.com
52210461SAndreas.Sandberg@ARM.comvoid
52312286Sjose.marinho@arm.comPMU::CounterState::detach()
52410461SAndreas.Sandberg@ARM.com{
52512286Sjose.marinho@arm.com    if (sourceEvent) {
52612286Sjose.marinho@arm.com        sourceEvent->detachEvent(this);
52712286Sjose.marinho@arm.com        sourceEvent = nullptr;
52812286Sjose.marinho@arm.com    } else {
52912286Sjose.marinho@arm.com        debugCounter("detaching event not currently attached"
53012286Sjose.marinho@arm.com            " to any event\n");
53110461SAndreas.Sandberg@ARM.com    }
53210461SAndreas.Sandberg@ARM.com}
53310461SAndreas.Sandberg@ARM.com
53410461SAndreas.Sandberg@ARM.comvoid
53512286Sjose.marinho@arm.comPMU::CounterState::attach(PMUEvent* event)
53612286Sjose.marinho@arm.com{
53713637Sruben.ayrapetyan@arm.com    if (!resetValue) {
53813637Sruben.ayrapetyan@arm.com      value = 0;
53913637Sruben.ayrapetyan@arm.com      resetValue = true;
54013637Sruben.ayrapetyan@arm.com    }
54112286Sjose.marinho@arm.com    sourceEvent = event;
54212286Sjose.marinho@arm.com    sourceEvent->attachEvent(this);
54312286Sjose.marinho@arm.com}
54412286Sjose.marinho@arm.com
54512286Sjose.marinho@arm.comuint64_t
54612286Sjose.marinho@arm.comPMU::CounterState::getValue() const
54712286Sjose.marinho@arm.com{
54812286Sjose.marinho@arm.com    if (sourceEvent) {
54912286Sjose.marinho@arm.com        sourceEvent->updateAttachedCounters();
55012286Sjose.marinho@arm.com    } else {
55112286Sjose.marinho@arm.com        debugCounter("attempted to get value from a counter without"
55212286Sjose.marinho@arm.com            " an associated event\n");
55312286Sjose.marinho@arm.com    }
55412286Sjose.marinho@arm.com    return value;
55512286Sjose.marinho@arm.com}
55612286Sjose.marinho@arm.com
55712286Sjose.marinho@arm.comvoid
55812286Sjose.marinho@arm.comPMU::CounterState::setValue(uint64_t val)
55912286Sjose.marinho@arm.com{
56012286Sjose.marinho@arm.com    value = val;
56112286Sjose.marinho@arm.com    resetValue = true;
56212286Sjose.marinho@arm.com
56312286Sjose.marinho@arm.com    if (sourceEvent) {
56412286Sjose.marinho@arm.com        sourceEvent->updateAttachedCounters();
56512286Sjose.marinho@arm.com    } else {
56612286Sjose.marinho@arm.com        debugCounter("attempted to set value from a counter without"
56712286Sjose.marinho@arm.com            " an associated event\n");
56812286Sjose.marinho@arm.com    }
56912286Sjose.marinho@arm.com}
57012286Sjose.marinho@arm.com
57112286Sjose.marinho@arm.comvoid
57212286Sjose.marinho@arm.comPMU::updateCounter(CounterState &ctr)
57310461SAndreas.Sandberg@ARM.com{
57410461SAndreas.Sandberg@ARM.com    if (!ctr.enabled) {
57512286Sjose.marinho@arm.com        DPRINTF(PMUVerbose, "updateCounter(%i): Disabling counter\n",
57612286Sjose.marinho@arm.com            ctr.getCounterId());
57712286Sjose.marinho@arm.com        ctr.detach();
57812286Sjose.marinho@arm.com
57910461SAndreas.Sandberg@ARM.com    } else {
58010461SAndreas.Sandberg@ARM.com        DPRINTF(PMUVerbose, "updateCounter(%i): Enable event id 0x%x\n",
58112286Sjose.marinho@arm.com                ctr.getCounterId(), ctr.eventId);
58210461SAndreas.Sandberg@ARM.com
58312286Sjose.marinho@arm.com        auto sourceEvent = eventMap.find(ctr.eventId);
58412286Sjose.marinho@arm.com        if (sourceEvent == eventMap.end()) {
58510461SAndreas.Sandberg@ARM.com            warn("Can't enable PMU counter of type '0x%x': "
58610461SAndreas.Sandberg@ARM.com                 "No such event type.\n", ctr.eventId);
58712286Sjose.marinho@arm.com        } else {
58812286Sjose.marinho@arm.com            ctr.attach(sourceEvent->second);
58910461SAndreas.Sandberg@ARM.com        }
59010461SAndreas.Sandberg@ARM.com    }
59110461SAndreas.Sandberg@ARM.com}
59210461SAndreas.Sandberg@ARM.com
59310461SAndreas.Sandberg@ARM.com
59410461SAndreas.Sandberg@ARM.comvoid
59510461SAndreas.Sandberg@ARM.comPMU::resetEventCounts()
59610461SAndreas.Sandberg@ARM.com{
59710461SAndreas.Sandberg@ARM.com    for (CounterState &ctr : counters)
59812286Sjose.marinho@arm.com        ctr.setValue(0);
59910461SAndreas.Sandberg@ARM.com}
60010461SAndreas.Sandberg@ARM.com
60110461SAndreas.Sandberg@ARM.comvoid
60210461SAndreas.Sandberg@ARM.comPMU::setCounterValue(CounterId id, uint64_t val)
60310461SAndreas.Sandberg@ARM.com{
60410461SAndreas.Sandberg@ARM.com    if (!isValidCounter(id)) {
60510461SAndreas.Sandberg@ARM.com        warn_once("Can't change counter value: Counter %i does not exist.\n",
60610461SAndreas.Sandberg@ARM.com                  id);
60710461SAndreas.Sandberg@ARM.com        return;
60810461SAndreas.Sandberg@ARM.com    }
60910461SAndreas.Sandberg@ARM.com
61010461SAndreas.Sandberg@ARM.com    CounterState &ctr(getCounter(id));
61112286Sjose.marinho@arm.com    ctr.setValue(val);
61210461SAndreas.Sandberg@ARM.com}
61310461SAndreas.Sandberg@ARM.com
61410461SAndreas.Sandberg@ARM.comPMU::PMEVTYPER_t
61510461SAndreas.Sandberg@ARM.comPMU::getCounterTypeRegister(CounterId id) const
61610461SAndreas.Sandberg@ARM.com{
61710461SAndreas.Sandberg@ARM.com    if (!isValidCounter(id))
61810461SAndreas.Sandberg@ARM.com        return 0;
61910461SAndreas.Sandberg@ARM.com
62010461SAndreas.Sandberg@ARM.com    const CounterState &cs(getCounter(id));
62110609Sandreas.sandberg@arm.com    PMEVTYPER_t type(cs.filter);
62210461SAndreas.Sandberg@ARM.com
62310461SAndreas.Sandberg@ARM.com    type.evtCount = cs.eventId;
62410461SAndreas.Sandberg@ARM.com
62510461SAndreas.Sandberg@ARM.com    return type;
62610461SAndreas.Sandberg@ARM.com}
62710461SAndreas.Sandberg@ARM.com
62810461SAndreas.Sandberg@ARM.comvoid
62910461SAndreas.Sandberg@ARM.comPMU::setCounterTypeRegister(CounterId id, PMEVTYPER_t val)
63010461SAndreas.Sandberg@ARM.com{
63110461SAndreas.Sandberg@ARM.com    DPRINTF(PMUVerbose, "Set Event [%d] = 0x%08x\n", id, val);
63210461SAndreas.Sandberg@ARM.com    if (!isValidCounter(id)) {
63310461SAndreas.Sandberg@ARM.com        warn_once("Can't change counter type: Counter %i does not exist.\n",
63410461SAndreas.Sandberg@ARM.com                  id);
63510461SAndreas.Sandberg@ARM.com        return;
63610461SAndreas.Sandberg@ARM.com    }
63710461SAndreas.Sandberg@ARM.com
63810461SAndreas.Sandberg@ARM.com    CounterState &ctr(getCounter(id));
63910609Sandreas.sandberg@arm.com    const EventTypeId old_event_id(ctr.eventId);
64010461SAndreas.Sandberg@ARM.com
64110609Sandreas.sandberg@arm.com    ctr.filter = val;
64210609Sandreas.sandberg@arm.com
64310609Sandreas.sandberg@arm.com    // If PMCCNTR Register, do not change event type. PMCCNTR can
64410609Sandreas.sandberg@arm.com    // count processor cycles only. If we change the event type, we
64510609Sandreas.sandberg@arm.com    // need to update the probes the counter is using.
64610609Sandreas.sandberg@arm.com    if (id != PMCCNTR && old_event_id != val.evtCount) {
64710461SAndreas.Sandberg@ARM.com        ctr.eventId = val.evtCount;
64812286Sjose.marinho@arm.com        updateCounter(ctr);
64910461SAndreas.Sandberg@ARM.com    }
65010461SAndreas.Sandberg@ARM.com}
65110461SAndreas.Sandberg@ARM.com
65210461SAndreas.Sandberg@ARM.comvoid
65313581Sgabeblack@google.comPMU::setOverflowStatus(RegVal new_val)
65413104Sgiacomo.travaglini@arm.com{
65513104Sgiacomo.travaglini@arm.com    const bool int_old = reg_pmovsr != 0;
65613104Sgiacomo.travaglini@arm.com    const bool int_new = new_val != 0;
65713104Sgiacomo.travaglini@arm.com
65813104Sgiacomo.travaglini@arm.com    reg_pmovsr = new_val;
65913104Sgiacomo.travaglini@arm.com    if (int_old && !int_new) {
66013104Sgiacomo.travaglini@arm.com        clearInterrupt();
66113104Sgiacomo.travaglini@arm.com    } else if (!int_old && int_new && (reg_pminten & reg_pmovsr)) {
66213104Sgiacomo.travaglini@arm.com        raiseInterrupt();
66313104Sgiacomo.travaglini@arm.com    }
66413104Sgiacomo.travaglini@arm.com}
66513104Sgiacomo.travaglini@arm.com
66613104Sgiacomo.travaglini@arm.comvoid
66710461SAndreas.Sandberg@ARM.comPMU::raiseInterrupt()
66810461SAndreas.Sandberg@ARM.com{
66912973Sandreas.sandberg@arm.com    if (interrupt) {
67012973Sandreas.sandberg@arm.com        DPRINTF(PMUVerbose, "Delivering PMU interrupt.\n");
67112973Sandreas.sandberg@arm.com        interrupt->raise();
67212973Sandreas.sandberg@arm.com    } else {
67312973Sandreas.sandberg@arm.com        warn_once("Dropping PMU interrupt as no interrupt has "
67412973Sandreas.sandberg@arm.com                  "been specified\n");
67510461SAndreas.Sandberg@ARM.com    }
67610461SAndreas.Sandberg@ARM.com}
67710461SAndreas.Sandberg@ARM.com
67810461SAndreas.Sandberg@ARM.comvoid
67913104Sgiacomo.travaglini@arm.comPMU::clearInterrupt()
68013104Sgiacomo.travaglini@arm.com{
68113104Sgiacomo.travaglini@arm.com    if (interrupt) {
68213104Sgiacomo.travaglini@arm.com        DPRINTF(PMUVerbose, "Clearing PMU interrupt.\n");
68313104Sgiacomo.travaglini@arm.com        interrupt->clear();
68413104Sgiacomo.travaglini@arm.com    } else {
68513104Sgiacomo.travaglini@arm.com        warn_once("Dropping PMU interrupt as no interrupt has "
68613104Sgiacomo.travaglini@arm.com                  "been specified\n");
68713104Sgiacomo.travaglini@arm.com    }
68813104Sgiacomo.travaglini@arm.com}
68913104Sgiacomo.travaglini@arm.com
69013104Sgiacomo.travaglini@arm.comvoid
69110905Sandreas.sandberg@arm.comPMU::serialize(CheckpointOut &cp) const
69210461SAndreas.Sandberg@ARM.com{
69310461SAndreas.Sandberg@ARM.com    DPRINTF(Checkpoint, "Serializing Arm PMU\n");
69410461SAndreas.Sandberg@ARM.com
69510461SAndreas.Sandberg@ARM.com    SERIALIZE_SCALAR(reg_pmcr);
69610461SAndreas.Sandberg@ARM.com    SERIALIZE_SCALAR(reg_pmcnten);
69710461SAndreas.Sandberg@ARM.com    SERIALIZE_SCALAR(reg_pmselr);
69810461SAndreas.Sandberg@ARM.com    SERIALIZE_SCALAR(reg_pminten);
69910461SAndreas.Sandberg@ARM.com    SERIALIZE_SCALAR(reg_pmovsr);
70012117Sjose.marinho@arm.com    SERIALIZE_SCALAR(reg_pmceid0);
70112117Sjose.marinho@arm.com    SERIALIZE_SCALAR(reg_pmceid1);
70210461SAndreas.Sandberg@ARM.com    SERIALIZE_SCALAR(clock_remainder);
70310461SAndreas.Sandberg@ARM.com
70410905Sandreas.sandberg@arm.com    for (size_t i = 0; i < counters.size(); ++i)
70510905Sandreas.sandberg@arm.com        counters[i].serializeSection(cp, csprintf("counters.%i", i));
70610461SAndreas.Sandberg@ARM.com
70710905Sandreas.sandberg@arm.com    cycleCounter.serializeSection(cp, "cycleCounter");
70810461SAndreas.Sandberg@ARM.com}
70910461SAndreas.Sandberg@ARM.com
71010461SAndreas.Sandberg@ARM.comvoid
71110905Sandreas.sandberg@arm.comPMU::unserialize(CheckpointIn &cp)
71210461SAndreas.Sandberg@ARM.com{
71310461SAndreas.Sandberg@ARM.com    DPRINTF(Checkpoint, "Unserializing Arm PMU\n");
71410461SAndreas.Sandberg@ARM.com
71510461SAndreas.Sandberg@ARM.com    UNSERIALIZE_SCALAR(reg_pmcr);
71610461SAndreas.Sandberg@ARM.com    UNSERIALIZE_SCALAR(reg_pmcnten);
71710461SAndreas.Sandberg@ARM.com    UNSERIALIZE_SCALAR(reg_pmselr);
71810461SAndreas.Sandberg@ARM.com    UNSERIALIZE_SCALAR(reg_pminten);
71910461SAndreas.Sandberg@ARM.com    UNSERIALIZE_SCALAR(reg_pmovsr);
72012117Sjose.marinho@arm.com
72112117Sjose.marinho@arm.com    // Old checkpoints used to store the entire PMCEID value in a
72212117Sjose.marinho@arm.com    // single 64-bit entry (reg_pmceid). The register was extended in
72312117Sjose.marinho@arm.com    // ARMv8.1, so we now need to store it as two 64-bit registers.
72412117Sjose.marinho@arm.com    if (!UNSERIALIZE_OPT_SCALAR(reg_pmceid0))
72512117Sjose.marinho@arm.com        paramIn(cp, "reg_pmceid", reg_pmceid0);
72612117Sjose.marinho@arm.com
72712117Sjose.marinho@arm.com    if (!UNSERIALIZE_OPT_SCALAR(reg_pmceid1))
72812117Sjose.marinho@arm.com        reg_pmceid1 = 0;
72912117Sjose.marinho@arm.com
73010461SAndreas.Sandberg@ARM.com    UNSERIALIZE_SCALAR(clock_remainder);
73110461SAndreas.Sandberg@ARM.com
73210461SAndreas.Sandberg@ARM.com    for (size_t i = 0; i < counters.size(); ++i)
73310905Sandreas.sandberg@arm.com        counters[i].unserializeSection(cp, csprintf("counters.%i", i));
73410461SAndreas.Sandberg@ARM.com
73510905Sandreas.sandberg@arm.com    cycleCounter.unserializeSection(cp, "cycleCounter");
73610461SAndreas.Sandberg@ARM.com}
73710461SAndreas.Sandberg@ARM.com
73812286Sjose.marinho@arm.comPMU::PMUEvent*
73912286Sjose.marinho@arm.comPMU::getEvent(uint64_t eventId)
74012286Sjose.marinho@arm.com{
74112286Sjose.marinho@arm.com    auto entry = eventMap.find(eventId);
74212286Sjose.marinho@arm.com
74312286Sjose.marinho@arm.com    if (entry == eventMap.end()) {
74412286Sjose.marinho@arm.com        warn("event %d does not exist\n", eventId);
74512286Sjose.marinho@arm.com        return nullptr;
74612286Sjose.marinho@arm.com    } else {
74712286Sjose.marinho@arm.com        return entry->second;
74812286Sjose.marinho@arm.com    }
74912286Sjose.marinho@arm.com}
75012286Sjose.marinho@arm.com
75110461SAndreas.Sandberg@ARM.comvoid
75210905Sandreas.sandberg@arm.comPMU::CounterState::serialize(CheckpointOut &cp) const
75310461SAndreas.Sandberg@ARM.com{
75410461SAndreas.Sandberg@ARM.com    SERIALIZE_SCALAR(eventId);
75510461SAndreas.Sandberg@ARM.com    SERIALIZE_SCALAR(value);
75610461SAndreas.Sandberg@ARM.com    SERIALIZE_SCALAR(overflow64);
75710461SAndreas.Sandberg@ARM.com}
75810461SAndreas.Sandberg@ARM.com
75910461SAndreas.Sandberg@ARM.comvoid
76010905Sandreas.sandberg@arm.comPMU::CounterState::unserialize(CheckpointIn &cp)
76110461SAndreas.Sandberg@ARM.com{
76210461SAndreas.Sandberg@ARM.com    UNSERIALIZE_SCALAR(eventId);
76310461SAndreas.Sandberg@ARM.com    UNSERIALIZE_SCALAR(value);
76410461SAndreas.Sandberg@ARM.com    UNSERIALIZE_SCALAR(overflow64);
76510461SAndreas.Sandberg@ARM.com}
76610461SAndreas.Sandberg@ARM.com
76712286Sjose.marinho@arm.comuint64_t
76810461SAndreas.Sandberg@ARM.comPMU::CounterState::add(uint64_t delta)
76910461SAndreas.Sandberg@ARM.com{
77012286Sjose.marinho@arm.com    uint64_t value_until_overflow;
77112286Sjose.marinho@arm.com    if (overflow64) {
77212286Sjose.marinho@arm.com        value_until_overflow = UINT64_MAX - value;
77312286Sjose.marinho@arm.com    } else {
77412286Sjose.marinho@arm.com        value_until_overflow = UINT32_MAX - (uint32_t)value;
77512286Sjose.marinho@arm.com    }
77610461SAndreas.Sandberg@ARM.com
77712286Sjose.marinho@arm.com    if (isFiltered())
77812286Sjose.marinho@arm.com        return value_until_overflow;
77910461SAndreas.Sandberg@ARM.com
78012286Sjose.marinho@arm.com    if (resetValue) {
78112286Sjose.marinho@arm.com        delta = 0;
78212286Sjose.marinho@arm.com        resetValue = false;
78312286Sjose.marinho@arm.com    } else {
78412286Sjose.marinho@arm.com        value += delta;
78512286Sjose.marinho@arm.com    }
78612286Sjose.marinho@arm.com
78712286Sjose.marinho@arm.com    if (delta > value_until_overflow) {
78812286Sjose.marinho@arm.com
78912286Sjose.marinho@arm.com        // overflow situation detected
79012286Sjose.marinho@arm.com        // flag the overflow occurence
79112286Sjose.marinho@arm.com        pmu.reg_pmovsr |= (1 << counterId);
79212286Sjose.marinho@arm.com
79312286Sjose.marinho@arm.com        // Deliver a PMU interrupt if interrupt delivery is enabled
79412286Sjose.marinho@arm.com        // for this counter.
79512286Sjose.marinho@arm.com        if (pmu.reg_pminten  & (1 << counterId)) {
79612286Sjose.marinho@arm.com            pmu.raiseInterrupt();
79712286Sjose.marinho@arm.com        }
79812286Sjose.marinho@arm.com        return overflow64 ? UINT64_MAX : UINT32_MAX;
79912286Sjose.marinho@arm.com    }
80012286Sjose.marinho@arm.com    return value_until_overflow - delta + 1;
80112286Sjose.marinho@arm.com}
80212286Sjose.marinho@arm.com
80312286Sjose.marinho@arm.comvoid
80412286Sjose.marinho@arm.comPMU::SWIncrementEvent::write(uint64_t val)
80512286Sjose.marinho@arm.com{
80612286Sjose.marinho@arm.com    for (auto& counter: userCounters) {
80712286Sjose.marinho@arm.com        if (val & (0x1 << counter->getCounterId())) {
80812286Sjose.marinho@arm.com            counter->add(1);
80912286Sjose.marinho@arm.com        }
81012286Sjose.marinho@arm.com    }
81110461SAndreas.Sandberg@ARM.com}
81210461SAndreas.Sandberg@ARM.com
81310461SAndreas.Sandberg@ARM.com} // namespace ArmISA
81410461SAndreas.Sandberg@ARM.com
81510461SAndreas.Sandberg@ARM.comArmISA::PMU *
81610461SAndreas.Sandberg@ARM.comArmPMUParams::create()
81710461SAndreas.Sandberg@ARM.com{
81810461SAndreas.Sandberg@ARM.com    return new ArmISA::PMU(this);
81910461SAndreas.Sandberg@ARM.com}
820