pmu.cc revision 13637
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),
7012974Sgiacomo.travaglini@arm.com      interrupt(p->interrupt->get())
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
7912973Sandreas.sandberg@arm.com    warn_if(!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());
10012973Sandreas.sandberg@arm.com    if (interrupt)
10112973Sandreas.sandberg@arm.com        interrupt->setThreadContext(tc);
10212973Sandreas.sandberg@arm.com}
10312973Sandreas.sandberg@arm.com
10412973Sandreas.sandberg@arm.comvoid
10512286Sjose.marinho@arm.comPMU::addSoftwareIncrementEvent(unsigned int id)
10612286Sjose.marinho@arm.com{
10712286Sjose.marinho@arm.com    auto old_event = eventMap.find(id);
10812286Sjose.marinho@arm.com    DPRINTF(PMUVerbose, "PMU: Adding SW increment event with id '0x%x'\n", id);
10912286Sjose.marinho@arm.com
11012286Sjose.marinho@arm.com    if (swIncrementEvent) {
11112286Sjose.marinho@arm.com        fatal_if(old_event == eventMap.end() ||
11212286Sjose.marinho@arm.com                 old_event->second != swIncrementEvent,
11312286Sjose.marinho@arm.com                 "Trying to add a software increment event with multiple"
11412286Sjose.marinho@arm.com                 "IDs. This is not supported.\n");
11512286Sjose.marinho@arm.com        return;
11612286Sjose.marinho@arm.com    }
11712286Sjose.marinho@arm.com
11812286Sjose.marinho@arm.com    fatal_if(old_event != eventMap.end(), "An event with id %d has "
11912286Sjose.marinho@arm.com             "been previously defined\n", id);
12012286Sjose.marinho@arm.com
12112286Sjose.marinho@arm.com    swIncrementEvent = new SWIncrementEvent();
12212286Sjose.marinho@arm.com    eventMap[id] = swIncrementEvent;
12312286Sjose.marinho@arm.com    registerEvent(id);
12412286Sjose.marinho@arm.com}
12512286Sjose.marinho@arm.com
12612286Sjose.marinho@arm.comvoid
12710461SAndreas.Sandberg@ARM.comPMU::addEventProbe(unsigned int id, SimObject *obj, const char *probe_name)
12810461SAndreas.Sandberg@ARM.com{
12910461SAndreas.Sandberg@ARM.com
13012286Sjose.marinho@arm.com    DPRINTF(PMUVerbose, "PMU: Adding Probe Driven event with id '0x%x'"
13112286Sjose.marinho@arm.com        "as probe %s:%s\n",id, obj->name(), probe_name);
13212286Sjose.marinho@arm.com
13312286Sjose.marinho@arm.com    RegularEvent *event = nullptr;
13412286Sjose.marinho@arm.com    auto event_entry = eventMap.find(id);
13512286Sjose.marinho@arm.com    if (event_entry == eventMap.end()) {
13612286Sjose.marinho@arm.com
13712286Sjose.marinho@arm.com        event = new RegularEvent();
13812286Sjose.marinho@arm.com        eventMap[id] = event;
13912286Sjose.marinho@arm.com
14012286Sjose.marinho@arm.com    } else {
14112286Sjose.marinho@arm.com        event = dynamic_cast<RegularEvent*>(event_entry->second);
14212286Sjose.marinho@arm.com        if (!event) {
14312286Sjose.marinho@arm.com            fatal("Event with id %d is not probe driven\n", id);
14412286Sjose.marinho@arm.com        }
14512286Sjose.marinho@arm.com    }
14612286Sjose.marinho@arm.com    event->addMicroarchitectureProbe(obj, probe_name);
14712286Sjose.marinho@arm.com
14812286Sjose.marinho@arm.com    registerEvent(id);
14912286Sjose.marinho@arm.com
15012286Sjose.marinho@arm.com}
15112286Sjose.marinho@arm.com
15212286Sjose.marinho@arm.comvoid
15312286Sjose.marinho@arm.comPMU::registerEvent(uint32_t id)
15412286Sjose.marinho@arm.com{
15512117Sjose.marinho@arm.com    // Flag the event as available in the corresponding PMCEID register if it
15612117Sjose.marinho@arm.com    // is an architected event.
15712117Sjose.marinho@arm.com    if (id < 0x20) {
15812117Sjose.marinho@arm.com        reg_pmceid0 |= ((uint64_t)1) << id;
15912117Sjose.marinho@arm.com    } else if (id > 0x20 && id < 0x40) {
16012117Sjose.marinho@arm.com        reg_pmceid1 |= ((uint64_t)1) << (id - 0x20);
16112117Sjose.marinho@arm.com    } else if (id >= 0x4000 && id < 0x4020) {
16212117Sjose.marinho@arm.com        reg_pmceid0 |= ((uint64_t)1) << (id - 0x4000 + 32);
16312117Sjose.marinho@arm.com    } else if (id >= 0x4020 && id < 0x4040) {
16412117Sjose.marinho@arm.com        reg_pmceid1 |= ((uint64_t)1) << (id - 0x4020 + 32);
16512117Sjose.marinho@arm.com    }
16610461SAndreas.Sandberg@ARM.com}
16710461SAndreas.Sandberg@ARM.com
16810461SAndreas.Sandberg@ARM.comvoid
16910461SAndreas.Sandberg@ARM.comPMU::drainResume()
17010461SAndreas.Sandberg@ARM.com{
17110461SAndreas.Sandberg@ARM.com    // Re-attach enabled counters after a resume in case they changed.
17210461SAndreas.Sandberg@ARM.com    updateAllCounters();
17310461SAndreas.Sandberg@ARM.com}
17410461SAndreas.Sandberg@ARM.com
17510461SAndreas.Sandberg@ARM.comvoid
17612286Sjose.marinho@arm.comPMU::regProbeListeners()
17712286Sjose.marinho@arm.com{
17812286Sjose.marinho@arm.com
17912286Sjose.marinho@arm.com    // at this stage all probe configurations are done
18012286Sjose.marinho@arm.com    // counters can be configured
18112286Sjose.marinho@arm.com    for (uint32_t index = 0; index < maximumCounterCount-1; index++) {
18212286Sjose.marinho@arm.com        counters.emplace_back(*this, index);
18312286Sjose.marinho@arm.com    }
18412286Sjose.marinho@arm.com
18512286Sjose.marinho@arm.com    PMUEvent *event = getEvent(cycleCounterEventId);
18612286Sjose.marinho@arm.com    panic_if(!event, "core cycle event is not present\n");
18712286Sjose.marinho@arm.com    cycleCounter.enabled = true;
18812286Sjose.marinho@arm.com    cycleCounter.attach(event);
18912286Sjose.marinho@arm.com}
19012286Sjose.marinho@arm.com
19112286Sjose.marinho@arm.comvoid
19213581Sgabeblack@google.comPMU::setMiscReg(int misc_reg, RegVal val)
19310461SAndreas.Sandberg@ARM.com{
19410461SAndreas.Sandberg@ARM.com    DPRINTF(PMUVerbose, "setMiscReg(%s, 0x%x)\n",
19510461SAndreas.Sandberg@ARM.com            miscRegName[unflattenMiscReg(misc_reg)], val);
19610461SAndreas.Sandberg@ARM.com
19710461SAndreas.Sandberg@ARM.com    switch (unflattenMiscReg(misc_reg)) {
19810461SAndreas.Sandberg@ARM.com      case MISCREG_PMCR_EL0:
19910461SAndreas.Sandberg@ARM.com      case MISCREG_PMCR:
20010461SAndreas.Sandberg@ARM.com        setControlReg(val);
20110461SAndreas.Sandberg@ARM.com        return;
20210461SAndreas.Sandberg@ARM.com
20310461SAndreas.Sandberg@ARM.com      case MISCREG_PMCNTENSET_EL0:
20410461SAndreas.Sandberg@ARM.com      case MISCREG_PMCNTENSET:
20510461SAndreas.Sandberg@ARM.com        reg_pmcnten |= val;
20610461SAndreas.Sandberg@ARM.com        updateAllCounters();
20710461SAndreas.Sandberg@ARM.com        return;
20810461SAndreas.Sandberg@ARM.com
20910461SAndreas.Sandberg@ARM.com      case MISCREG_PMCNTENCLR_EL0:
21010461SAndreas.Sandberg@ARM.com      case MISCREG_PMCNTENCLR:
21110461SAndreas.Sandberg@ARM.com        reg_pmcnten &= ~val;
21210461SAndreas.Sandberg@ARM.com        updateAllCounters();
21310461SAndreas.Sandberg@ARM.com        return;
21410461SAndreas.Sandberg@ARM.com
21510461SAndreas.Sandberg@ARM.com      case MISCREG_PMOVSCLR_EL0:
21610461SAndreas.Sandberg@ARM.com      case MISCREG_PMOVSR:
21713104Sgiacomo.travaglini@arm.com        setOverflowStatus(reg_pmovsr & ~val);
21810461SAndreas.Sandberg@ARM.com        return;
21910461SAndreas.Sandberg@ARM.com
22010461SAndreas.Sandberg@ARM.com      case MISCREG_PMSWINC_EL0:
22110461SAndreas.Sandberg@ARM.com      case MISCREG_PMSWINC:
22212286Sjose.marinho@arm.com        if (swIncrementEvent) {
22312286Sjose.marinho@arm.com            swIncrementEvent->write(val);
22410461SAndreas.Sandberg@ARM.com        }
22512286Sjose.marinho@arm.com        return;
22610461SAndreas.Sandberg@ARM.com
22710461SAndreas.Sandberg@ARM.com      case MISCREG_PMCCNTR_EL0:
22810461SAndreas.Sandberg@ARM.com      case MISCREG_PMCCNTR:
22912286Sjose.marinho@arm.com        cycleCounter.setValue(val);
23010461SAndreas.Sandberg@ARM.com        return;
23110461SAndreas.Sandberg@ARM.com
23210461SAndreas.Sandberg@ARM.com      case MISCREG_PMSELR_EL0:
23310461SAndreas.Sandberg@ARM.com      case MISCREG_PMSELR:
23410461SAndreas.Sandberg@ARM.com        reg_pmselr = val;
23510461SAndreas.Sandberg@ARM.com        return;
23612117Sjose.marinho@arm.com      //TODO: implement MISCREF_PMCEID{2,3}
23710461SAndreas.Sandberg@ARM.com      case MISCREG_PMCEID0_EL0:
23810461SAndreas.Sandberg@ARM.com      case MISCREG_PMCEID0:
23910461SAndreas.Sandberg@ARM.com      case MISCREG_PMCEID1_EL0:
24010461SAndreas.Sandberg@ARM.com      case MISCREG_PMCEID1:
24110461SAndreas.Sandberg@ARM.com        // Ignore writes
24210461SAndreas.Sandberg@ARM.com        return;
24310461SAndreas.Sandberg@ARM.com
24410461SAndreas.Sandberg@ARM.com      case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0:
24512042Sandreas.sandberg@arm.com        setCounterTypeRegister(misc_reg - MISCREG_PMEVTYPER0_EL0, val);
24610461SAndreas.Sandberg@ARM.com        return;
24710461SAndreas.Sandberg@ARM.com
24810461SAndreas.Sandberg@ARM.com      case MISCREG_PMCCFILTR:
24910461SAndreas.Sandberg@ARM.com      case MISCREG_PMCCFILTR_EL0:
25010461SAndreas.Sandberg@ARM.com        DPRINTF(PMUVerbose, "Setting PMCCFILTR: 0x%x\n", val);
25110461SAndreas.Sandberg@ARM.com        setCounterTypeRegister(PMCCNTR, val);
25210461SAndreas.Sandberg@ARM.com        return;
25310461SAndreas.Sandberg@ARM.com
25410461SAndreas.Sandberg@ARM.com      case MISCREG_PMXEVTYPER_PMCCFILTR:
25510461SAndreas.Sandberg@ARM.com      case MISCREG_PMXEVTYPER_EL0:
25610461SAndreas.Sandberg@ARM.com      case MISCREG_PMXEVTYPER:
25710461SAndreas.Sandberg@ARM.com        DPRINTF(PMUVerbose, "Setting counter type: "
25810461SAndreas.Sandberg@ARM.com                "[PMSELR: 0x%x, PMSELER.sel: 0x%x, EVTYPER: 0x%x]\n",
25910461SAndreas.Sandberg@ARM.com                reg_pmselr, reg_pmselr.sel, val);
26010461SAndreas.Sandberg@ARM.com        setCounterTypeRegister(reg_pmselr.sel, val);
26110461SAndreas.Sandberg@ARM.com        return;
26210461SAndreas.Sandberg@ARM.com
26310461SAndreas.Sandberg@ARM.com      case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0:
26410461SAndreas.Sandberg@ARM.com        setCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0, val);
26510461SAndreas.Sandberg@ARM.com        return;
26610461SAndreas.Sandberg@ARM.com
26710461SAndreas.Sandberg@ARM.com      case MISCREG_PMXEVCNTR_EL0:
26810461SAndreas.Sandberg@ARM.com      case MISCREG_PMXEVCNTR:
26910461SAndreas.Sandberg@ARM.com        setCounterValue(reg_pmselr.sel, val);
27010461SAndreas.Sandberg@ARM.com        return;
27110461SAndreas.Sandberg@ARM.com
27210461SAndreas.Sandberg@ARM.com      case MISCREG_PMUSERENR_EL0:
27310461SAndreas.Sandberg@ARM.com      case MISCREG_PMUSERENR:
27410461SAndreas.Sandberg@ARM.com        // TODO
27510461SAndreas.Sandberg@ARM.com        break;
27610461SAndreas.Sandberg@ARM.com
27710461SAndreas.Sandberg@ARM.com      case MISCREG_PMINTENSET_EL1:
27810461SAndreas.Sandberg@ARM.com      case MISCREG_PMINTENSET:
27910461SAndreas.Sandberg@ARM.com        reg_pminten |= val;
28010461SAndreas.Sandberg@ARM.com        return;
28110461SAndreas.Sandberg@ARM.com
28210461SAndreas.Sandberg@ARM.com      case MISCREG_PMINTENCLR_EL1:
28310461SAndreas.Sandberg@ARM.com      case MISCREG_PMINTENCLR:
28410461SAndreas.Sandberg@ARM.com        reg_pminten &= ~val;
28510461SAndreas.Sandberg@ARM.com        return;
28610461SAndreas.Sandberg@ARM.com
28710461SAndreas.Sandberg@ARM.com      case MISCREG_PMOVSSET_EL0:
28810461SAndreas.Sandberg@ARM.com      case MISCREG_PMOVSSET:
28913104Sgiacomo.travaglini@arm.com        setOverflowStatus(reg_pmovsr | val);
29010461SAndreas.Sandberg@ARM.com        return;
29110461SAndreas.Sandberg@ARM.com
29210461SAndreas.Sandberg@ARM.com      default:
29310461SAndreas.Sandberg@ARM.com        panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]);
29410461SAndreas.Sandberg@ARM.com    }
29510461SAndreas.Sandberg@ARM.com
29610461SAndreas.Sandberg@ARM.com    warn("Not doing anything for write to miscreg %s\n",
29710461SAndreas.Sandberg@ARM.com         miscRegName[misc_reg]);
29810461SAndreas.Sandberg@ARM.com}
29910461SAndreas.Sandberg@ARM.com
30013581Sgabeblack@google.comRegVal
30110461SAndreas.Sandberg@ARM.comPMU::readMiscReg(int misc_reg)
30210461SAndreas.Sandberg@ARM.com{
30313581Sgabeblack@google.com    RegVal val(readMiscRegInt(misc_reg));
30410461SAndreas.Sandberg@ARM.com    DPRINTF(PMUVerbose, "readMiscReg(%s): 0x%x\n",
30510461SAndreas.Sandberg@ARM.com            miscRegName[unflattenMiscReg(misc_reg)], val);
30610461SAndreas.Sandberg@ARM.com    return val;
30710461SAndreas.Sandberg@ARM.com}
30810461SAndreas.Sandberg@ARM.com
30913581Sgabeblack@google.comRegVal
31010461SAndreas.Sandberg@ARM.comPMU::readMiscRegInt(int misc_reg)
31110461SAndreas.Sandberg@ARM.com{
31210461SAndreas.Sandberg@ARM.com    misc_reg = unflattenMiscReg(misc_reg);
31310461SAndreas.Sandberg@ARM.com    switch (misc_reg) {
31410461SAndreas.Sandberg@ARM.com      case MISCREG_PMCR_EL0:
31510461SAndreas.Sandberg@ARM.com      case MISCREG_PMCR:
31610461SAndreas.Sandberg@ARM.com        return reg_pmcr_conf | (reg_pmcr & reg_pmcr_wr_mask);
31710461SAndreas.Sandberg@ARM.com
31810461SAndreas.Sandberg@ARM.com      case MISCREG_PMCNTENSET_EL0:
31910461SAndreas.Sandberg@ARM.com      case MISCREG_PMCNTENCLR_EL0:
32010461SAndreas.Sandberg@ARM.com      case MISCREG_PMCNTENSET:
32110461SAndreas.Sandberg@ARM.com      case MISCREG_PMCNTENCLR:
32210461SAndreas.Sandberg@ARM.com        return reg_pmcnten;
32310461SAndreas.Sandberg@ARM.com
32410461SAndreas.Sandberg@ARM.com      case MISCREG_PMOVSCLR_EL0:
32510461SAndreas.Sandberg@ARM.com      case MISCREG_PMOVSSET_EL0:
32610461SAndreas.Sandberg@ARM.com      case MISCREG_PMOVSR:  // Overflow Status Register
32710461SAndreas.Sandberg@ARM.com      case MISCREG_PMOVSSET:
32810461SAndreas.Sandberg@ARM.com        return reg_pmovsr;
32910461SAndreas.Sandberg@ARM.com
33010461SAndreas.Sandberg@ARM.com      case MISCREG_PMSWINC_EL0:
33110461SAndreas.Sandberg@ARM.com      case MISCREG_PMSWINC: // Software Increment Register (RAZ)
33210461SAndreas.Sandberg@ARM.com        return 0;
33310461SAndreas.Sandberg@ARM.com
33410461SAndreas.Sandberg@ARM.com      case MISCREG_PMSELR:
33510461SAndreas.Sandberg@ARM.com        return reg_pmselr;
33610461SAndreas.Sandberg@ARM.com
33710461SAndreas.Sandberg@ARM.com      case MISCREG_PMCEID0_EL0:
33812117Sjose.marinho@arm.com        return reg_pmceid0;
33910461SAndreas.Sandberg@ARM.com
34010461SAndreas.Sandberg@ARM.com      case MISCREG_PMCEID1_EL0:
34112117Sjose.marinho@arm.com        return reg_pmceid1;
34212117Sjose.marinho@arm.com
34312117Sjose.marinho@arm.com      //TODO: implement MISCREF_PMCEID{2,3}
34412117Sjose.marinho@arm.com      case MISCREG_PMCEID0: // Common Event ID register
34512117Sjose.marinho@arm.com        return reg_pmceid0 & 0xFFFFFFFF;
34612117Sjose.marinho@arm.com
34710461SAndreas.Sandberg@ARM.com      case MISCREG_PMCEID1: // Common Event ID register
34812117Sjose.marinho@arm.com        return reg_pmceid1 & 0xFFFFFFFF;
34910461SAndreas.Sandberg@ARM.com
35010461SAndreas.Sandberg@ARM.com      case MISCREG_PMCCNTR_EL0:
35112286Sjose.marinho@arm.com        return cycleCounter.getValue();
35210461SAndreas.Sandberg@ARM.com
35310461SAndreas.Sandberg@ARM.com      case MISCREG_PMCCNTR:
35412286Sjose.marinho@arm.com        return cycleCounter.getValue() & 0xFFFFFFFF;
35510461SAndreas.Sandberg@ARM.com
35610461SAndreas.Sandberg@ARM.com      case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0:
35710461SAndreas.Sandberg@ARM.com        return getCounterTypeRegister(misc_reg - MISCREG_PMEVTYPER0_EL0);
35810461SAndreas.Sandberg@ARM.com
35910461SAndreas.Sandberg@ARM.com      case MISCREG_PMCCFILTR:
36010461SAndreas.Sandberg@ARM.com      case MISCREG_PMCCFILTR_EL0:
36110461SAndreas.Sandberg@ARM.com        return getCounterTypeRegister(PMCCNTR);
36210461SAndreas.Sandberg@ARM.com
36310461SAndreas.Sandberg@ARM.com      case MISCREG_PMXEVTYPER_PMCCFILTR:
36410461SAndreas.Sandberg@ARM.com      case MISCREG_PMXEVTYPER_EL0:
36510461SAndreas.Sandberg@ARM.com      case MISCREG_PMXEVTYPER:
36610461SAndreas.Sandberg@ARM.com        return getCounterTypeRegister(reg_pmselr.sel);
36710461SAndreas.Sandberg@ARM.com
36812286Sjose.marinho@arm.com      case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0: {
36912286Sjose.marinho@arm.com            return getCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0) &
37012286Sjose.marinho@arm.com                0xFFFFFFFF;
37112286Sjose.marinho@arm.com
37212286Sjose.marinho@arm.com        }
37310461SAndreas.Sandberg@ARM.com
37410461SAndreas.Sandberg@ARM.com      case MISCREG_PMXEVCNTR_EL0:
37510461SAndreas.Sandberg@ARM.com      case MISCREG_PMXEVCNTR:
37610461SAndreas.Sandberg@ARM.com        return getCounterValue(reg_pmselr.sel) & 0xFFFFFFFF;
37710461SAndreas.Sandberg@ARM.com
37810461SAndreas.Sandberg@ARM.com      case MISCREG_PMUSERENR_EL0:
37910461SAndreas.Sandberg@ARM.com      case MISCREG_PMUSERENR:
38010461SAndreas.Sandberg@ARM.com        // TODO
38110461SAndreas.Sandberg@ARM.com        return 0;
38210461SAndreas.Sandberg@ARM.com
38310461SAndreas.Sandberg@ARM.com      case MISCREG_PMINTENSET_EL1:
38410461SAndreas.Sandberg@ARM.com      case MISCREG_PMINTENCLR_EL1:
38510461SAndreas.Sandberg@ARM.com      case MISCREG_PMINTENSET:
38610461SAndreas.Sandberg@ARM.com      case MISCREG_PMINTENCLR:
38710461SAndreas.Sandberg@ARM.com        return reg_pminten;
38810461SAndreas.Sandberg@ARM.com
38910461SAndreas.Sandberg@ARM.com      default:
39010461SAndreas.Sandberg@ARM.com        panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]);
39110461SAndreas.Sandberg@ARM.com    }
39210461SAndreas.Sandberg@ARM.com
39310461SAndreas.Sandberg@ARM.com    warn("Not doing anything for read from miscreg %s\n",
39410461SAndreas.Sandberg@ARM.com         miscRegName[misc_reg]);
39510461SAndreas.Sandberg@ARM.com    return 0;
39610461SAndreas.Sandberg@ARM.com}
39710461SAndreas.Sandberg@ARM.com
39810461SAndreas.Sandberg@ARM.comvoid
39910461SAndreas.Sandberg@ARM.comPMU::setControlReg(PMCR_t val)
40010461SAndreas.Sandberg@ARM.com{
40110461SAndreas.Sandberg@ARM.com    DPRINTF(PMUVerbose, "Set Control Reg 0x%08x.\n", val);
40210461SAndreas.Sandberg@ARM.com
40310461SAndreas.Sandberg@ARM.com    if (val.p) {
40410461SAndreas.Sandberg@ARM.com        DPRINTF(PMUVerbose, "PMU reset all events to zero.\n");
40510461SAndreas.Sandberg@ARM.com        resetEventCounts();
40610461SAndreas.Sandberg@ARM.com    }
40710461SAndreas.Sandberg@ARM.com
40810461SAndreas.Sandberg@ARM.com    if (val.c) {
40910461SAndreas.Sandberg@ARM.com        DPRINTF(PMUVerbose, "PMU reset cycle counter to zero.\n");
41012286Sjose.marinho@arm.com        cycleCounter.setValue(0);
41110461SAndreas.Sandberg@ARM.com    }
41210461SAndreas.Sandberg@ARM.com
41310461SAndreas.Sandberg@ARM.com    // Reset the clock remainder if divide by 64-mode is toggled.
41410461SAndreas.Sandberg@ARM.com    if (reg_pmcr.d != val.d)
41510461SAndreas.Sandberg@ARM.com        clock_remainder = 0;
41610461SAndreas.Sandberg@ARM.com
41710461SAndreas.Sandberg@ARM.com    reg_pmcr = val & reg_pmcr_wr_mask;
41810461SAndreas.Sandberg@ARM.com    updateAllCounters();
41910461SAndreas.Sandberg@ARM.com}
42010461SAndreas.Sandberg@ARM.com
42110461SAndreas.Sandberg@ARM.comvoid
42210461SAndreas.Sandberg@ARM.comPMU::updateAllCounters()
42310461SAndreas.Sandberg@ARM.com{
42410461SAndreas.Sandberg@ARM.com    const bool global_enable(reg_pmcr.e);
42510461SAndreas.Sandberg@ARM.com
42610461SAndreas.Sandberg@ARM.com    for (int i = 0; i < counters.size(); ++i) {
42710461SAndreas.Sandberg@ARM.com        CounterState &ctr(counters[i]);
42810461SAndreas.Sandberg@ARM.com        const bool enable(global_enable && (reg_pmcnten & (1 << i)));
42910461SAndreas.Sandberg@ARM.com        if (ctr.enabled != enable) {
43010461SAndreas.Sandberg@ARM.com            ctr.enabled = enable;
43112286Sjose.marinho@arm.com            updateCounter(ctr);
43210461SAndreas.Sandberg@ARM.com        }
43310461SAndreas.Sandberg@ARM.com    }
43410461SAndreas.Sandberg@ARM.com
43510461SAndreas.Sandberg@ARM.com    const bool ccntr_enable(global_enable && (reg_pmcnten & (1 << PMCCNTR)));
43610461SAndreas.Sandberg@ARM.com    if (cycleCounter.enabled != ccntr_enable) {
43710461SAndreas.Sandberg@ARM.com        cycleCounter.enabled = ccntr_enable;
43812286Sjose.marinho@arm.com        updateCounter(cycleCounter);
43910461SAndreas.Sandberg@ARM.com    }
44010461SAndreas.Sandberg@ARM.com}
44110461SAndreas.Sandberg@ARM.com
44212286Sjose.marinho@arm.comvoid
44312286Sjose.marinho@arm.comPMU::PMUEvent::attachEvent(PMU::CounterState *user)
44412286Sjose.marinho@arm.com{
44512286Sjose.marinho@arm.com    if (userCounters.empty()) {
44612286Sjose.marinho@arm.com        enable();
44712286Sjose.marinho@arm.com    }
44812286Sjose.marinho@arm.com    userCounters.insert(user);
44912286Sjose.marinho@arm.com    updateAttachedCounters();
45012286Sjose.marinho@arm.com}
45112286Sjose.marinho@arm.com
45212286Sjose.marinho@arm.comvoid
45312286Sjose.marinho@arm.comPMU::PMUEvent::increment(const uint64_t val)
45412286Sjose.marinho@arm.com{
45512286Sjose.marinho@arm.com    for (auto& counter: userCounters) {
45612286Sjose.marinho@arm.com        counter->add(val);
45712286Sjose.marinho@arm.com    }
45812286Sjose.marinho@arm.com}
45912286Sjose.marinho@arm.com
46012286Sjose.marinho@arm.comvoid
46112286Sjose.marinho@arm.comPMU::PMUEvent::detachEvent(PMU::CounterState *user)
46212286Sjose.marinho@arm.com{
46312286Sjose.marinho@arm.com    userCounters.erase(user);
46412286Sjose.marinho@arm.com
46512286Sjose.marinho@arm.com    if (userCounters.empty()) {
46612286Sjose.marinho@arm.com        disable();
46712286Sjose.marinho@arm.com    }
46812286Sjose.marinho@arm.com}
46912286Sjose.marinho@arm.com
47012286Sjose.marinho@arm.comvoid
47112286Sjose.marinho@arm.comPMU::RegularEvent::RegularProbe::notify(const uint64_t &val)
47212286Sjose.marinho@arm.com{
47312286Sjose.marinho@arm.com    parentEvent->increment(val);
47412286Sjose.marinho@arm.com}
47512286Sjose.marinho@arm.com
47612286Sjose.marinho@arm.comvoid
47712286Sjose.marinho@arm.comPMU::RegularEvent::enable()
47812286Sjose.marinho@arm.com{
47912286Sjose.marinho@arm.com    for (auto& subEvents: microArchitectureEventSet) {
48012286Sjose.marinho@arm.com        attachedProbePointList.emplace_back(
48112286Sjose.marinho@arm.com            new RegularProbe(this, subEvents.first, subEvents.second));
48212286Sjose.marinho@arm.com    }
48312286Sjose.marinho@arm.com}
48412286Sjose.marinho@arm.com
48512286Sjose.marinho@arm.comvoid
48612286Sjose.marinho@arm.comPMU::RegularEvent::disable()
48712286Sjose.marinho@arm.com{
48812286Sjose.marinho@arm.com    attachedProbePointList.clear();
48912286Sjose.marinho@arm.com}
49012286Sjose.marinho@arm.com
49110609Sandreas.sandberg@arm.combool
49212286Sjose.marinho@arm.comPMU::CounterState::isFiltered() const
49310609Sandreas.sandberg@arm.com{
49412286Sjose.marinho@arm.com    assert(pmu.isa);
49510609Sandreas.sandberg@arm.com
49612286Sjose.marinho@arm.com    const PMEVTYPER_t filter(this->filter);
49712286Sjose.marinho@arm.com    const SCR scr(pmu.isa->readMiscRegNoEffect(MISCREG_SCR));
49812286Sjose.marinho@arm.com    const CPSR cpsr(pmu.isa->readMiscRegNoEffect(MISCREG_CPSR));
49910609Sandreas.sandberg@arm.com    const ExceptionLevel el(opModeToEL((OperatingMode)(uint8_t)cpsr.mode));
50010609Sandreas.sandberg@arm.com    const bool secure(inSecureState(scr, cpsr));
50110609Sandreas.sandberg@arm.com
50210609Sandreas.sandberg@arm.com    switch (el) {
50310609Sandreas.sandberg@arm.com      case EL0:
50410609Sandreas.sandberg@arm.com        return secure ? filter.u : (filter.u != filter.nsu);
50510609Sandreas.sandberg@arm.com
50610609Sandreas.sandberg@arm.com      case EL1:
50710609Sandreas.sandberg@arm.com        return secure ? filter.p : (filter.p != filter.nsk);
50810609Sandreas.sandberg@arm.com
50910609Sandreas.sandberg@arm.com      case EL2:
51010609Sandreas.sandberg@arm.com        return !filter.nsh;
51110609Sandreas.sandberg@arm.com
51210609Sandreas.sandberg@arm.com      case EL3:
51310609Sandreas.sandberg@arm.com        return filter.p != filter.m;
51410609Sandreas.sandberg@arm.com
51510609Sandreas.sandberg@arm.com      default:
51610609Sandreas.sandberg@arm.com        panic("Unexpected execution level in PMU::isFiltered.\n");
51710609Sandreas.sandberg@arm.com    }
51810609Sandreas.sandberg@arm.com}
51910609Sandreas.sandberg@arm.com
52010461SAndreas.Sandberg@ARM.comvoid
52112286Sjose.marinho@arm.comPMU::CounterState::detach()
52210461SAndreas.Sandberg@ARM.com{
52312286Sjose.marinho@arm.com    if (sourceEvent) {
52412286Sjose.marinho@arm.com        sourceEvent->detachEvent(this);
52512286Sjose.marinho@arm.com        sourceEvent = nullptr;
52612286Sjose.marinho@arm.com    } else {
52712286Sjose.marinho@arm.com        debugCounter("detaching event not currently attached"
52812286Sjose.marinho@arm.com            " to any event\n");
52910461SAndreas.Sandberg@ARM.com    }
53010461SAndreas.Sandberg@ARM.com}
53110461SAndreas.Sandberg@ARM.com
53210461SAndreas.Sandberg@ARM.comvoid
53312286Sjose.marinho@arm.comPMU::CounterState::attach(PMUEvent* event)
53412286Sjose.marinho@arm.com{
53513637Sruben.ayrapetyan@arm.com    if (!resetValue) {
53613637Sruben.ayrapetyan@arm.com      value = 0;
53713637Sruben.ayrapetyan@arm.com      resetValue = true;
53813637Sruben.ayrapetyan@arm.com    }
53912286Sjose.marinho@arm.com    sourceEvent = event;
54012286Sjose.marinho@arm.com    sourceEvent->attachEvent(this);
54112286Sjose.marinho@arm.com}
54212286Sjose.marinho@arm.com
54312286Sjose.marinho@arm.comuint64_t
54412286Sjose.marinho@arm.comPMU::CounterState::getValue() const
54512286Sjose.marinho@arm.com{
54612286Sjose.marinho@arm.com    if (sourceEvent) {
54712286Sjose.marinho@arm.com        sourceEvent->updateAttachedCounters();
54812286Sjose.marinho@arm.com    } else {
54912286Sjose.marinho@arm.com        debugCounter("attempted to get value from a counter without"
55012286Sjose.marinho@arm.com            " an associated event\n");
55112286Sjose.marinho@arm.com    }
55212286Sjose.marinho@arm.com    return value;
55312286Sjose.marinho@arm.com}
55412286Sjose.marinho@arm.com
55512286Sjose.marinho@arm.comvoid
55612286Sjose.marinho@arm.comPMU::CounterState::setValue(uint64_t val)
55712286Sjose.marinho@arm.com{
55812286Sjose.marinho@arm.com    value = val;
55912286Sjose.marinho@arm.com    resetValue = true;
56012286Sjose.marinho@arm.com
56112286Sjose.marinho@arm.com    if (sourceEvent) {
56212286Sjose.marinho@arm.com        sourceEvent->updateAttachedCounters();
56312286Sjose.marinho@arm.com    } else {
56412286Sjose.marinho@arm.com        debugCounter("attempted to set value from a counter without"
56512286Sjose.marinho@arm.com            " an associated event\n");
56612286Sjose.marinho@arm.com    }
56712286Sjose.marinho@arm.com}
56812286Sjose.marinho@arm.com
56912286Sjose.marinho@arm.comvoid
57012286Sjose.marinho@arm.comPMU::updateCounter(CounterState &ctr)
57110461SAndreas.Sandberg@ARM.com{
57210461SAndreas.Sandberg@ARM.com    if (!ctr.enabled) {
57312286Sjose.marinho@arm.com        DPRINTF(PMUVerbose, "updateCounter(%i): Disabling counter\n",
57412286Sjose.marinho@arm.com            ctr.getCounterId());
57512286Sjose.marinho@arm.com        ctr.detach();
57612286Sjose.marinho@arm.com
57710461SAndreas.Sandberg@ARM.com    } else {
57810461SAndreas.Sandberg@ARM.com        DPRINTF(PMUVerbose, "updateCounter(%i): Enable event id 0x%x\n",
57912286Sjose.marinho@arm.com                ctr.getCounterId(), ctr.eventId);
58010461SAndreas.Sandberg@ARM.com
58112286Sjose.marinho@arm.com        auto sourceEvent = eventMap.find(ctr.eventId);
58212286Sjose.marinho@arm.com        if (sourceEvent == eventMap.end()) {
58310461SAndreas.Sandberg@ARM.com            warn("Can't enable PMU counter of type '0x%x': "
58410461SAndreas.Sandberg@ARM.com                 "No such event type.\n", ctr.eventId);
58512286Sjose.marinho@arm.com        } else {
58612286Sjose.marinho@arm.com            ctr.attach(sourceEvent->second);
58710461SAndreas.Sandberg@ARM.com        }
58810461SAndreas.Sandberg@ARM.com    }
58910461SAndreas.Sandberg@ARM.com}
59010461SAndreas.Sandberg@ARM.com
59110461SAndreas.Sandberg@ARM.com
59210461SAndreas.Sandberg@ARM.comvoid
59310461SAndreas.Sandberg@ARM.comPMU::resetEventCounts()
59410461SAndreas.Sandberg@ARM.com{
59510461SAndreas.Sandberg@ARM.com    for (CounterState &ctr : counters)
59612286Sjose.marinho@arm.com        ctr.setValue(0);
59710461SAndreas.Sandberg@ARM.com}
59810461SAndreas.Sandberg@ARM.com
59910461SAndreas.Sandberg@ARM.comvoid
60010461SAndreas.Sandberg@ARM.comPMU::setCounterValue(CounterId id, uint64_t val)
60110461SAndreas.Sandberg@ARM.com{
60210461SAndreas.Sandberg@ARM.com    if (!isValidCounter(id)) {
60310461SAndreas.Sandberg@ARM.com        warn_once("Can't change counter value: Counter %i does not exist.\n",
60410461SAndreas.Sandberg@ARM.com                  id);
60510461SAndreas.Sandberg@ARM.com        return;
60610461SAndreas.Sandberg@ARM.com    }
60710461SAndreas.Sandberg@ARM.com
60810461SAndreas.Sandberg@ARM.com    CounterState &ctr(getCounter(id));
60912286Sjose.marinho@arm.com    ctr.setValue(val);
61010461SAndreas.Sandberg@ARM.com}
61110461SAndreas.Sandberg@ARM.com
61210461SAndreas.Sandberg@ARM.comPMU::PMEVTYPER_t
61310461SAndreas.Sandberg@ARM.comPMU::getCounterTypeRegister(CounterId id) const
61410461SAndreas.Sandberg@ARM.com{
61510461SAndreas.Sandberg@ARM.com    if (!isValidCounter(id))
61610461SAndreas.Sandberg@ARM.com        return 0;
61710461SAndreas.Sandberg@ARM.com
61810461SAndreas.Sandberg@ARM.com    const CounterState &cs(getCounter(id));
61910609Sandreas.sandberg@arm.com    PMEVTYPER_t type(cs.filter);
62010461SAndreas.Sandberg@ARM.com
62110461SAndreas.Sandberg@ARM.com    type.evtCount = cs.eventId;
62210461SAndreas.Sandberg@ARM.com
62310461SAndreas.Sandberg@ARM.com    return type;
62410461SAndreas.Sandberg@ARM.com}
62510461SAndreas.Sandberg@ARM.com
62610461SAndreas.Sandberg@ARM.comvoid
62710461SAndreas.Sandberg@ARM.comPMU::setCounterTypeRegister(CounterId id, PMEVTYPER_t val)
62810461SAndreas.Sandberg@ARM.com{
62910461SAndreas.Sandberg@ARM.com    DPRINTF(PMUVerbose, "Set Event [%d] = 0x%08x\n", id, val);
63010461SAndreas.Sandberg@ARM.com    if (!isValidCounter(id)) {
63110461SAndreas.Sandberg@ARM.com        warn_once("Can't change counter type: Counter %i does not exist.\n",
63210461SAndreas.Sandberg@ARM.com                  id);
63310461SAndreas.Sandberg@ARM.com        return;
63410461SAndreas.Sandberg@ARM.com    }
63510461SAndreas.Sandberg@ARM.com
63610461SAndreas.Sandberg@ARM.com    CounterState &ctr(getCounter(id));
63710609Sandreas.sandberg@arm.com    const EventTypeId old_event_id(ctr.eventId);
63810461SAndreas.Sandberg@ARM.com
63910609Sandreas.sandberg@arm.com    ctr.filter = val;
64010609Sandreas.sandberg@arm.com
64110609Sandreas.sandberg@arm.com    // If PMCCNTR Register, do not change event type. PMCCNTR can
64210609Sandreas.sandberg@arm.com    // count processor cycles only. If we change the event type, we
64310609Sandreas.sandberg@arm.com    // need to update the probes the counter is using.
64410609Sandreas.sandberg@arm.com    if (id != PMCCNTR && old_event_id != val.evtCount) {
64510461SAndreas.Sandberg@ARM.com        ctr.eventId = val.evtCount;
64612286Sjose.marinho@arm.com        updateCounter(ctr);
64710461SAndreas.Sandberg@ARM.com    }
64810461SAndreas.Sandberg@ARM.com}
64910461SAndreas.Sandberg@ARM.com
65010461SAndreas.Sandberg@ARM.comvoid
65113581Sgabeblack@google.comPMU::setOverflowStatus(RegVal new_val)
65213104Sgiacomo.travaglini@arm.com{
65313104Sgiacomo.travaglini@arm.com    const bool int_old = reg_pmovsr != 0;
65413104Sgiacomo.travaglini@arm.com    const bool int_new = new_val != 0;
65513104Sgiacomo.travaglini@arm.com
65613104Sgiacomo.travaglini@arm.com    reg_pmovsr = new_val;
65713104Sgiacomo.travaglini@arm.com    if (int_old && !int_new) {
65813104Sgiacomo.travaglini@arm.com        clearInterrupt();
65913104Sgiacomo.travaglini@arm.com    } else if (!int_old && int_new && (reg_pminten & reg_pmovsr)) {
66013104Sgiacomo.travaglini@arm.com        raiseInterrupt();
66113104Sgiacomo.travaglini@arm.com    }
66213104Sgiacomo.travaglini@arm.com}
66313104Sgiacomo.travaglini@arm.com
66413104Sgiacomo.travaglini@arm.comvoid
66510461SAndreas.Sandberg@ARM.comPMU::raiseInterrupt()
66610461SAndreas.Sandberg@ARM.com{
66712973Sandreas.sandberg@arm.com    if (interrupt) {
66812973Sandreas.sandberg@arm.com        DPRINTF(PMUVerbose, "Delivering PMU interrupt.\n");
66912973Sandreas.sandberg@arm.com        interrupt->raise();
67012973Sandreas.sandberg@arm.com    } else {
67112973Sandreas.sandberg@arm.com        warn_once("Dropping PMU interrupt as no interrupt has "
67212973Sandreas.sandberg@arm.com                  "been specified\n");
67310461SAndreas.Sandberg@ARM.com    }
67410461SAndreas.Sandberg@ARM.com}
67510461SAndreas.Sandberg@ARM.com
67610461SAndreas.Sandberg@ARM.comvoid
67713104Sgiacomo.travaglini@arm.comPMU::clearInterrupt()
67813104Sgiacomo.travaglini@arm.com{
67913104Sgiacomo.travaglini@arm.com    if (interrupt) {
68013104Sgiacomo.travaglini@arm.com        DPRINTF(PMUVerbose, "Clearing PMU interrupt.\n");
68113104Sgiacomo.travaglini@arm.com        interrupt->clear();
68213104Sgiacomo.travaglini@arm.com    } else {
68313104Sgiacomo.travaglini@arm.com        warn_once("Dropping PMU interrupt as no interrupt has "
68413104Sgiacomo.travaglini@arm.com                  "been specified\n");
68513104Sgiacomo.travaglini@arm.com    }
68613104Sgiacomo.travaglini@arm.com}
68713104Sgiacomo.travaglini@arm.com
68813104Sgiacomo.travaglini@arm.comvoid
68910905Sandreas.sandberg@arm.comPMU::serialize(CheckpointOut &cp) const
69010461SAndreas.Sandberg@ARM.com{
69110461SAndreas.Sandberg@ARM.com    DPRINTF(Checkpoint, "Serializing Arm PMU\n");
69210461SAndreas.Sandberg@ARM.com
69310461SAndreas.Sandberg@ARM.com    SERIALIZE_SCALAR(reg_pmcr);
69410461SAndreas.Sandberg@ARM.com    SERIALIZE_SCALAR(reg_pmcnten);
69510461SAndreas.Sandberg@ARM.com    SERIALIZE_SCALAR(reg_pmselr);
69610461SAndreas.Sandberg@ARM.com    SERIALIZE_SCALAR(reg_pminten);
69710461SAndreas.Sandberg@ARM.com    SERIALIZE_SCALAR(reg_pmovsr);
69812117Sjose.marinho@arm.com    SERIALIZE_SCALAR(reg_pmceid0);
69912117Sjose.marinho@arm.com    SERIALIZE_SCALAR(reg_pmceid1);
70010461SAndreas.Sandberg@ARM.com    SERIALIZE_SCALAR(clock_remainder);
70110461SAndreas.Sandberg@ARM.com
70210905Sandreas.sandberg@arm.com    for (size_t i = 0; i < counters.size(); ++i)
70310905Sandreas.sandberg@arm.com        counters[i].serializeSection(cp, csprintf("counters.%i", i));
70410461SAndreas.Sandberg@ARM.com
70510905Sandreas.sandberg@arm.com    cycleCounter.serializeSection(cp, "cycleCounter");
70610461SAndreas.Sandberg@ARM.com}
70710461SAndreas.Sandberg@ARM.com
70810461SAndreas.Sandberg@ARM.comvoid
70910905Sandreas.sandberg@arm.comPMU::unserialize(CheckpointIn &cp)
71010461SAndreas.Sandberg@ARM.com{
71110461SAndreas.Sandberg@ARM.com    DPRINTF(Checkpoint, "Unserializing Arm PMU\n");
71210461SAndreas.Sandberg@ARM.com
71310461SAndreas.Sandberg@ARM.com    UNSERIALIZE_SCALAR(reg_pmcr);
71410461SAndreas.Sandberg@ARM.com    UNSERIALIZE_SCALAR(reg_pmcnten);
71510461SAndreas.Sandberg@ARM.com    UNSERIALIZE_SCALAR(reg_pmselr);
71610461SAndreas.Sandberg@ARM.com    UNSERIALIZE_SCALAR(reg_pminten);
71710461SAndreas.Sandberg@ARM.com    UNSERIALIZE_SCALAR(reg_pmovsr);
71812117Sjose.marinho@arm.com
71912117Sjose.marinho@arm.com    // Old checkpoints used to store the entire PMCEID value in a
72012117Sjose.marinho@arm.com    // single 64-bit entry (reg_pmceid). The register was extended in
72112117Sjose.marinho@arm.com    // ARMv8.1, so we now need to store it as two 64-bit registers.
72212117Sjose.marinho@arm.com    if (!UNSERIALIZE_OPT_SCALAR(reg_pmceid0))
72312117Sjose.marinho@arm.com        paramIn(cp, "reg_pmceid", reg_pmceid0);
72412117Sjose.marinho@arm.com
72512117Sjose.marinho@arm.com    if (!UNSERIALIZE_OPT_SCALAR(reg_pmceid1))
72612117Sjose.marinho@arm.com        reg_pmceid1 = 0;
72712117Sjose.marinho@arm.com
72810461SAndreas.Sandberg@ARM.com    UNSERIALIZE_SCALAR(clock_remainder);
72910461SAndreas.Sandberg@ARM.com
73010461SAndreas.Sandberg@ARM.com    for (size_t i = 0; i < counters.size(); ++i)
73110905Sandreas.sandberg@arm.com        counters[i].unserializeSection(cp, csprintf("counters.%i", i));
73210461SAndreas.Sandberg@ARM.com
73310905Sandreas.sandberg@arm.com    cycleCounter.unserializeSection(cp, "cycleCounter");
73410461SAndreas.Sandberg@ARM.com}
73510461SAndreas.Sandberg@ARM.com
73612286Sjose.marinho@arm.comPMU::PMUEvent*
73712286Sjose.marinho@arm.comPMU::getEvent(uint64_t eventId)
73812286Sjose.marinho@arm.com{
73912286Sjose.marinho@arm.com    auto entry = eventMap.find(eventId);
74012286Sjose.marinho@arm.com
74112286Sjose.marinho@arm.com    if (entry == eventMap.end()) {
74212286Sjose.marinho@arm.com        warn("event %d does not exist\n", eventId);
74312286Sjose.marinho@arm.com        return nullptr;
74412286Sjose.marinho@arm.com    } else {
74512286Sjose.marinho@arm.com        return entry->second;
74612286Sjose.marinho@arm.com    }
74712286Sjose.marinho@arm.com}
74812286Sjose.marinho@arm.com
74910461SAndreas.Sandberg@ARM.comvoid
75010905Sandreas.sandberg@arm.comPMU::CounterState::serialize(CheckpointOut &cp) const
75110461SAndreas.Sandberg@ARM.com{
75210461SAndreas.Sandberg@ARM.com    SERIALIZE_SCALAR(eventId);
75310461SAndreas.Sandberg@ARM.com    SERIALIZE_SCALAR(value);
75410461SAndreas.Sandberg@ARM.com    SERIALIZE_SCALAR(overflow64);
75510461SAndreas.Sandberg@ARM.com}
75610461SAndreas.Sandberg@ARM.com
75710461SAndreas.Sandberg@ARM.comvoid
75810905Sandreas.sandberg@arm.comPMU::CounterState::unserialize(CheckpointIn &cp)
75910461SAndreas.Sandberg@ARM.com{
76010461SAndreas.Sandberg@ARM.com    UNSERIALIZE_SCALAR(eventId);
76110461SAndreas.Sandberg@ARM.com    UNSERIALIZE_SCALAR(value);
76210461SAndreas.Sandberg@ARM.com    UNSERIALIZE_SCALAR(overflow64);
76310461SAndreas.Sandberg@ARM.com}
76410461SAndreas.Sandberg@ARM.com
76512286Sjose.marinho@arm.comuint64_t
76610461SAndreas.Sandberg@ARM.comPMU::CounterState::add(uint64_t delta)
76710461SAndreas.Sandberg@ARM.com{
76812286Sjose.marinho@arm.com    uint64_t value_until_overflow;
76912286Sjose.marinho@arm.com    if (overflow64) {
77012286Sjose.marinho@arm.com        value_until_overflow = UINT64_MAX - value;
77112286Sjose.marinho@arm.com    } else {
77212286Sjose.marinho@arm.com        value_until_overflow = UINT32_MAX - (uint32_t)value;
77312286Sjose.marinho@arm.com    }
77410461SAndreas.Sandberg@ARM.com
77512286Sjose.marinho@arm.com    if (isFiltered())
77612286Sjose.marinho@arm.com        return value_until_overflow;
77710461SAndreas.Sandberg@ARM.com
77812286Sjose.marinho@arm.com    if (resetValue) {
77912286Sjose.marinho@arm.com        delta = 0;
78012286Sjose.marinho@arm.com        resetValue = false;
78112286Sjose.marinho@arm.com    } else {
78212286Sjose.marinho@arm.com        value += delta;
78312286Sjose.marinho@arm.com    }
78412286Sjose.marinho@arm.com
78512286Sjose.marinho@arm.com    if (delta > value_until_overflow) {
78612286Sjose.marinho@arm.com
78712286Sjose.marinho@arm.com        // overflow situation detected
78812286Sjose.marinho@arm.com        // flag the overflow occurence
78912286Sjose.marinho@arm.com        pmu.reg_pmovsr |= (1 << counterId);
79012286Sjose.marinho@arm.com
79112286Sjose.marinho@arm.com        // Deliver a PMU interrupt if interrupt delivery is enabled
79212286Sjose.marinho@arm.com        // for this counter.
79312286Sjose.marinho@arm.com        if (pmu.reg_pminten  & (1 << counterId)) {
79412286Sjose.marinho@arm.com            pmu.raiseInterrupt();
79512286Sjose.marinho@arm.com        }
79612286Sjose.marinho@arm.com        return overflow64 ? UINT64_MAX : UINT32_MAX;
79712286Sjose.marinho@arm.com    }
79812286Sjose.marinho@arm.com    return value_until_overflow - delta + 1;
79912286Sjose.marinho@arm.com}
80012286Sjose.marinho@arm.com
80112286Sjose.marinho@arm.comvoid
80212286Sjose.marinho@arm.comPMU::SWIncrementEvent::write(uint64_t val)
80312286Sjose.marinho@arm.com{
80412286Sjose.marinho@arm.com    for (auto& counter: userCounters) {
80512286Sjose.marinho@arm.com        if (val & (0x1 << counter->getCounterId())) {
80612286Sjose.marinho@arm.com            counter->add(1);
80712286Sjose.marinho@arm.com        }
80812286Sjose.marinho@arm.com    }
80910461SAndreas.Sandberg@ARM.com}
81010461SAndreas.Sandberg@ARM.com
81110461SAndreas.Sandberg@ARM.com} // namespace ArmISA
81210461SAndreas.Sandberg@ARM.com
81310461SAndreas.Sandberg@ARM.comArmISA::PMU *
81410461SAndreas.Sandberg@ARM.comArmPMUParams::create()
81510461SAndreas.Sandberg@ARM.com{
81610461SAndreas.Sandberg@ARM.com    return new ArmISA::PMU(this);
81710461SAndreas.Sandberg@ARM.com}
818