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),
7013639Sgiacomo.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
33613848Sgiacomo.travaglini@arm.com      case MISCREG_PMSELR_EL0:
33710461SAndreas.Sandberg@ARM.com      case MISCREG_PMSELR:
33810461SAndreas.Sandberg@ARM.com        return reg_pmselr;
33910461SAndreas.Sandberg@ARM.com
34010461SAndreas.Sandberg@ARM.com      case MISCREG_PMCEID0_EL0:
34112117Sjose.marinho@arm.com        return reg_pmceid0;
34210461SAndreas.Sandberg@ARM.com
34310461SAndreas.Sandberg@ARM.com      case MISCREG_PMCEID1_EL0:
34412117Sjose.marinho@arm.com        return reg_pmceid1;
34512117Sjose.marinho@arm.com
34612117Sjose.marinho@arm.com      //TODO: implement MISCREF_PMCEID{2,3}
34712117Sjose.marinho@arm.com      case MISCREG_PMCEID0: // Common Event ID register
34812117Sjose.marinho@arm.com        return reg_pmceid0 & 0xFFFFFFFF;
34912117Sjose.marinho@arm.com
35010461SAndreas.Sandberg@ARM.com      case MISCREG_PMCEID1: // Common Event ID register
35112117Sjose.marinho@arm.com        return reg_pmceid1 & 0xFFFFFFFF;
35210461SAndreas.Sandberg@ARM.com
35310461SAndreas.Sandberg@ARM.com      case MISCREG_PMCCNTR_EL0:
35412286Sjose.marinho@arm.com        return cycleCounter.getValue();
35510461SAndreas.Sandberg@ARM.com
35610461SAndreas.Sandberg@ARM.com      case MISCREG_PMCCNTR:
35712286Sjose.marinho@arm.com        return cycleCounter.getValue() & 0xFFFFFFFF;
35810461SAndreas.Sandberg@ARM.com
35910461SAndreas.Sandberg@ARM.com      case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0:
36010461SAndreas.Sandberg@ARM.com        return getCounterTypeRegister(misc_reg - MISCREG_PMEVTYPER0_EL0);
36110461SAndreas.Sandberg@ARM.com
36210461SAndreas.Sandberg@ARM.com      case MISCREG_PMCCFILTR:
36310461SAndreas.Sandberg@ARM.com      case MISCREG_PMCCFILTR_EL0:
36410461SAndreas.Sandberg@ARM.com        return getCounterTypeRegister(PMCCNTR);
36510461SAndreas.Sandberg@ARM.com
36610461SAndreas.Sandberg@ARM.com      case MISCREG_PMXEVTYPER_PMCCFILTR:
36710461SAndreas.Sandberg@ARM.com      case MISCREG_PMXEVTYPER_EL0:
36810461SAndreas.Sandberg@ARM.com      case MISCREG_PMXEVTYPER:
36910461SAndreas.Sandberg@ARM.com        return getCounterTypeRegister(reg_pmselr.sel);
37010461SAndreas.Sandberg@ARM.com
37112286Sjose.marinho@arm.com      case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0: {
37212286Sjose.marinho@arm.com            return getCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0) &
37312286Sjose.marinho@arm.com                0xFFFFFFFF;
37412286Sjose.marinho@arm.com
37512286Sjose.marinho@arm.com        }
37610461SAndreas.Sandberg@ARM.com
37710461SAndreas.Sandberg@ARM.com      case MISCREG_PMXEVCNTR_EL0:
37810461SAndreas.Sandberg@ARM.com      case MISCREG_PMXEVCNTR:
37910461SAndreas.Sandberg@ARM.com        return getCounterValue(reg_pmselr.sel) & 0xFFFFFFFF;
38010461SAndreas.Sandberg@ARM.com
38110461SAndreas.Sandberg@ARM.com      case MISCREG_PMUSERENR_EL0:
38210461SAndreas.Sandberg@ARM.com      case MISCREG_PMUSERENR:
38310461SAndreas.Sandberg@ARM.com        // TODO
38410461SAndreas.Sandberg@ARM.com        return 0;
38510461SAndreas.Sandberg@ARM.com
38610461SAndreas.Sandberg@ARM.com      case MISCREG_PMINTENSET_EL1:
38710461SAndreas.Sandberg@ARM.com      case MISCREG_PMINTENCLR_EL1:
38810461SAndreas.Sandberg@ARM.com      case MISCREG_PMINTENSET:
38910461SAndreas.Sandberg@ARM.com      case MISCREG_PMINTENCLR:
39010461SAndreas.Sandberg@ARM.com        return reg_pminten;
39110461SAndreas.Sandberg@ARM.com
39210461SAndreas.Sandberg@ARM.com      default:
39310461SAndreas.Sandberg@ARM.com        panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]);
39410461SAndreas.Sandberg@ARM.com    }
39510461SAndreas.Sandberg@ARM.com
39610461SAndreas.Sandberg@ARM.com    warn("Not doing anything for read from miscreg %s\n",
39710461SAndreas.Sandberg@ARM.com         miscRegName[misc_reg]);
39810461SAndreas.Sandberg@ARM.com    return 0;
39910461SAndreas.Sandberg@ARM.com}
40010461SAndreas.Sandberg@ARM.com
40110461SAndreas.Sandberg@ARM.comvoid
40210461SAndreas.Sandberg@ARM.comPMU::setControlReg(PMCR_t val)
40310461SAndreas.Sandberg@ARM.com{
40410461SAndreas.Sandberg@ARM.com    DPRINTF(PMUVerbose, "Set Control Reg 0x%08x.\n", val);
40510461SAndreas.Sandberg@ARM.com
40610461SAndreas.Sandberg@ARM.com    if (val.p) {
40710461SAndreas.Sandberg@ARM.com        DPRINTF(PMUVerbose, "PMU reset all events to zero.\n");
40810461SAndreas.Sandberg@ARM.com        resetEventCounts();
40910461SAndreas.Sandberg@ARM.com    }
41010461SAndreas.Sandberg@ARM.com
41110461SAndreas.Sandberg@ARM.com    if (val.c) {
41210461SAndreas.Sandberg@ARM.com        DPRINTF(PMUVerbose, "PMU reset cycle counter to zero.\n");
41312286Sjose.marinho@arm.com        cycleCounter.setValue(0);
41410461SAndreas.Sandberg@ARM.com    }
41510461SAndreas.Sandberg@ARM.com
41610461SAndreas.Sandberg@ARM.com    // Reset the clock remainder if divide by 64-mode is toggled.
41710461SAndreas.Sandberg@ARM.com    if (reg_pmcr.d != val.d)
41810461SAndreas.Sandberg@ARM.com        clock_remainder = 0;
41910461SAndreas.Sandberg@ARM.com
42010461SAndreas.Sandberg@ARM.com    reg_pmcr = val & reg_pmcr_wr_mask;
42110461SAndreas.Sandberg@ARM.com    updateAllCounters();
42210461SAndreas.Sandberg@ARM.com}
42310461SAndreas.Sandberg@ARM.com
42410461SAndreas.Sandberg@ARM.comvoid
42510461SAndreas.Sandberg@ARM.comPMU::updateAllCounters()
42610461SAndreas.Sandberg@ARM.com{
42710461SAndreas.Sandberg@ARM.com    const bool global_enable(reg_pmcr.e);
42810461SAndreas.Sandberg@ARM.com
42910461SAndreas.Sandberg@ARM.com    for (int i = 0; i < counters.size(); ++i) {
43010461SAndreas.Sandberg@ARM.com        CounterState &ctr(counters[i]);
43110461SAndreas.Sandberg@ARM.com        const bool enable(global_enable && (reg_pmcnten & (1 << i)));
43210461SAndreas.Sandberg@ARM.com        if (ctr.enabled != enable) {
43310461SAndreas.Sandberg@ARM.com            ctr.enabled = enable;
43412286Sjose.marinho@arm.com            updateCounter(ctr);
43510461SAndreas.Sandberg@ARM.com        }
43610461SAndreas.Sandberg@ARM.com    }
43710461SAndreas.Sandberg@ARM.com
43810461SAndreas.Sandberg@ARM.com    const bool ccntr_enable(global_enable && (reg_pmcnten & (1 << PMCCNTR)));
43910461SAndreas.Sandberg@ARM.com    if (cycleCounter.enabled != ccntr_enable) {
44010461SAndreas.Sandberg@ARM.com        cycleCounter.enabled = ccntr_enable;
44112286Sjose.marinho@arm.com        updateCounter(cycleCounter);
44210461SAndreas.Sandberg@ARM.com    }
44310461SAndreas.Sandberg@ARM.com}
44410461SAndreas.Sandberg@ARM.com
44512286Sjose.marinho@arm.comvoid
44612286Sjose.marinho@arm.comPMU::PMUEvent::attachEvent(PMU::CounterState *user)
44712286Sjose.marinho@arm.com{
44812286Sjose.marinho@arm.com    if (userCounters.empty()) {
44912286Sjose.marinho@arm.com        enable();
45012286Sjose.marinho@arm.com    }
45112286Sjose.marinho@arm.com    userCounters.insert(user);
45212286Sjose.marinho@arm.com    updateAttachedCounters();
45312286Sjose.marinho@arm.com}
45412286Sjose.marinho@arm.com
45512286Sjose.marinho@arm.comvoid
45612286Sjose.marinho@arm.comPMU::PMUEvent::increment(const uint64_t val)
45712286Sjose.marinho@arm.com{
45812286Sjose.marinho@arm.com    for (auto& counter: userCounters) {
45912286Sjose.marinho@arm.com        counter->add(val);
46012286Sjose.marinho@arm.com    }
46112286Sjose.marinho@arm.com}
46212286Sjose.marinho@arm.com
46312286Sjose.marinho@arm.comvoid
46412286Sjose.marinho@arm.comPMU::PMUEvent::detachEvent(PMU::CounterState *user)
46512286Sjose.marinho@arm.com{
46612286Sjose.marinho@arm.com    userCounters.erase(user);
46712286Sjose.marinho@arm.com
46812286Sjose.marinho@arm.com    if (userCounters.empty()) {
46912286Sjose.marinho@arm.com        disable();
47012286Sjose.marinho@arm.com    }
47112286Sjose.marinho@arm.com}
47212286Sjose.marinho@arm.com
47312286Sjose.marinho@arm.comvoid
47412286Sjose.marinho@arm.comPMU::RegularEvent::RegularProbe::notify(const uint64_t &val)
47512286Sjose.marinho@arm.com{
47612286Sjose.marinho@arm.com    parentEvent->increment(val);
47712286Sjose.marinho@arm.com}
47812286Sjose.marinho@arm.com
47912286Sjose.marinho@arm.comvoid
48012286Sjose.marinho@arm.comPMU::RegularEvent::enable()
48112286Sjose.marinho@arm.com{
48212286Sjose.marinho@arm.com    for (auto& subEvents: microArchitectureEventSet) {
48312286Sjose.marinho@arm.com        attachedProbePointList.emplace_back(
48412286Sjose.marinho@arm.com            new RegularProbe(this, subEvents.first, subEvents.second));
48512286Sjose.marinho@arm.com    }
48612286Sjose.marinho@arm.com}
48712286Sjose.marinho@arm.com
48812286Sjose.marinho@arm.comvoid
48912286Sjose.marinho@arm.comPMU::RegularEvent::disable()
49012286Sjose.marinho@arm.com{
49112286Sjose.marinho@arm.com    attachedProbePointList.clear();
49212286Sjose.marinho@arm.com}
49312286Sjose.marinho@arm.com
49410609Sandreas.sandberg@arm.combool
49512286Sjose.marinho@arm.comPMU::CounterState::isFiltered() const
49610609Sandreas.sandberg@arm.com{
49712286Sjose.marinho@arm.com    assert(pmu.isa);
49810609Sandreas.sandberg@arm.com
49912286Sjose.marinho@arm.com    const PMEVTYPER_t filter(this->filter);
50012286Sjose.marinho@arm.com    const SCR scr(pmu.isa->readMiscRegNoEffect(MISCREG_SCR));
50112286Sjose.marinho@arm.com    const CPSR cpsr(pmu.isa->readMiscRegNoEffect(MISCREG_CPSR));
50214172Sgiacomo.travaglini@arm.com    const ExceptionLevel el(currEL(cpsr));
50310609Sandreas.sandberg@arm.com    const bool secure(inSecureState(scr, cpsr));
50410609Sandreas.sandberg@arm.com
50510609Sandreas.sandberg@arm.com    switch (el) {
50610609Sandreas.sandberg@arm.com      case EL0:
50710609Sandreas.sandberg@arm.com        return secure ? filter.u : (filter.u != filter.nsu);
50810609Sandreas.sandberg@arm.com
50910609Sandreas.sandberg@arm.com      case EL1:
51010609Sandreas.sandberg@arm.com        return secure ? filter.p : (filter.p != filter.nsk);
51110609Sandreas.sandberg@arm.com
51210609Sandreas.sandberg@arm.com      case EL2:
51310609Sandreas.sandberg@arm.com        return !filter.nsh;
51410609Sandreas.sandberg@arm.com
51510609Sandreas.sandberg@arm.com      case EL3:
51610609Sandreas.sandberg@arm.com        return filter.p != filter.m;
51710609Sandreas.sandberg@arm.com
51810609Sandreas.sandberg@arm.com      default:
51910609Sandreas.sandberg@arm.com        panic("Unexpected execution level in PMU::isFiltered.\n");
52010609Sandreas.sandberg@arm.com    }
52110609Sandreas.sandberg@arm.com}
52210609Sandreas.sandberg@arm.com
52310461SAndreas.Sandberg@ARM.comvoid
52412286Sjose.marinho@arm.comPMU::CounterState::detach()
52510461SAndreas.Sandberg@ARM.com{
52612286Sjose.marinho@arm.com    if (sourceEvent) {
52712286Sjose.marinho@arm.com        sourceEvent->detachEvent(this);
52812286Sjose.marinho@arm.com        sourceEvent = nullptr;
52912286Sjose.marinho@arm.com    } else {
53012286Sjose.marinho@arm.com        debugCounter("detaching event not currently attached"
53112286Sjose.marinho@arm.com            " to any event\n");
53210461SAndreas.Sandberg@ARM.com    }
53310461SAndreas.Sandberg@ARM.com}
53410461SAndreas.Sandberg@ARM.com
53510461SAndreas.Sandberg@ARM.comvoid
53612286Sjose.marinho@arm.comPMU::CounterState::attach(PMUEvent* event)
53712286Sjose.marinho@arm.com{
53813637Sruben.ayrapetyan@arm.com    if (!resetValue) {
53913637Sruben.ayrapetyan@arm.com      value = 0;
54013637Sruben.ayrapetyan@arm.com      resetValue = true;
54113637Sruben.ayrapetyan@arm.com    }
54212286Sjose.marinho@arm.com    sourceEvent = event;
54312286Sjose.marinho@arm.com    sourceEvent->attachEvent(this);
54412286Sjose.marinho@arm.com}
54512286Sjose.marinho@arm.com
54612286Sjose.marinho@arm.comuint64_t
54712286Sjose.marinho@arm.comPMU::CounterState::getValue() const
54812286Sjose.marinho@arm.com{
54912286Sjose.marinho@arm.com    if (sourceEvent) {
55012286Sjose.marinho@arm.com        sourceEvent->updateAttachedCounters();
55112286Sjose.marinho@arm.com    } else {
55212286Sjose.marinho@arm.com        debugCounter("attempted to get value from a counter without"
55312286Sjose.marinho@arm.com            " an associated event\n");
55412286Sjose.marinho@arm.com    }
55512286Sjose.marinho@arm.com    return value;
55612286Sjose.marinho@arm.com}
55712286Sjose.marinho@arm.com
55812286Sjose.marinho@arm.comvoid
55912286Sjose.marinho@arm.comPMU::CounterState::setValue(uint64_t val)
56012286Sjose.marinho@arm.com{
56112286Sjose.marinho@arm.com    value = val;
56212286Sjose.marinho@arm.com    resetValue = true;
56312286Sjose.marinho@arm.com
56412286Sjose.marinho@arm.com    if (sourceEvent) {
56512286Sjose.marinho@arm.com        sourceEvent->updateAttachedCounters();
56612286Sjose.marinho@arm.com    } else {
56712286Sjose.marinho@arm.com        debugCounter("attempted to set value from a counter without"
56812286Sjose.marinho@arm.com            " an associated event\n");
56912286Sjose.marinho@arm.com    }
57012286Sjose.marinho@arm.com}
57112286Sjose.marinho@arm.com
57212286Sjose.marinho@arm.comvoid
57312286Sjose.marinho@arm.comPMU::updateCounter(CounterState &ctr)
57410461SAndreas.Sandberg@ARM.com{
57510461SAndreas.Sandberg@ARM.com    if (!ctr.enabled) {
57612286Sjose.marinho@arm.com        DPRINTF(PMUVerbose, "updateCounter(%i): Disabling counter\n",
57712286Sjose.marinho@arm.com            ctr.getCounterId());
57812286Sjose.marinho@arm.com        ctr.detach();
57912286Sjose.marinho@arm.com
58010461SAndreas.Sandberg@ARM.com    } else {
58110461SAndreas.Sandberg@ARM.com        DPRINTF(PMUVerbose, "updateCounter(%i): Enable event id 0x%x\n",
58212286Sjose.marinho@arm.com                ctr.getCounterId(), ctr.eventId);
58310461SAndreas.Sandberg@ARM.com
58412286Sjose.marinho@arm.com        auto sourceEvent = eventMap.find(ctr.eventId);
58512286Sjose.marinho@arm.com        if (sourceEvent == eventMap.end()) {
58610461SAndreas.Sandberg@ARM.com            warn("Can't enable PMU counter of type '0x%x': "
58710461SAndreas.Sandberg@ARM.com                 "No such event type.\n", ctr.eventId);
58812286Sjose.marinho@arm.com        } else {
58912286Sjose.marinho@arm.com            ctr.attach(sourceEvent->second);
59010461SAndreas.Sandberg@ARM.com        }
59110461SAndreas.Sandberg@ARM.com    }
59210461SAndreas.Sandberg@ARM.com}
59310461SAndreas.Sandberg@ARM.com
59410461SAndreas.Sandberg@ARM.com
59510461SAndreas.Sandberg@ARM.comvoid
59610461SAndreas.Sandberg@ARM.comPMU::resetEventCounts()
59710461SAndreas.Sandberg@ARM.com{
59810461SAndreas.Sandberg@ARM.com    for (CounterState &ctr : counters)
59912286Sjose.marinho@arm.com        ctr.setValue(0);
60010461SAndreas.Sandberg@ARM.com}
60110461SAndreas.Sandberg@ARM.com
60210461SAndreas.Sandberg@ARM.comvoid
60310461SAndreas.Sandberg@ARM.comPMU::setCounterValue(CounterId id, uint64_t val)
60410461SAndreas.Sandberg@ARM.com{
60510461SAndreas.Sandberg@ARM.com    if (!isValidCounter(id)) {
60610461SAndreas.Sandberg@ARM.com        warn_once("Can't change counter value: Counter %i does not exist.\n",
60710461SAndreas.Sandberg@ARM.com                  id);
60810461SAndreas.Sandberg@ARM.com        return;
60910461SAndreas.Sandberg@ARM.com    }
61010461SAndreas.Sandberg@ARM.com
61110461SAndreas.Sandberg@ARM.com    CounterState &ctr(getCounter(id));
61212286Sjose.marinho@arm.com    ctr.setValue(val);
61310461SAndreas.Sandberg@ARM.com}
61410461SAndreas.Sandberg@ARM.com
61510461SAndreas.Sandberg@ARM.comPMU::PMEVTYPER_t
61610461SAndreas.Sandberg@ARM.comPMU::getCounterTypeRegister(CounterId id) const
61710461SAndreas.Sandberg@ARM.com{
61810461SAndreas.Sandberg@ARM.com    if (!isValidCounter(id))
61910461SAndreas.Sandberg@ARM.com        return 0;
62010461SAndreas.Sandberg@ARM.com
62110461SAndreas.Sandberg@ARM.com    const CounterState &cs(getCounter(id));
62210609Sandreas.sandberg@arm.com    PMEVTYPER_t type(cs.filter);
62310461SAndreas.Sandberg@ARM.com
62410461SAndreas.Sandberg@ARM.com    type.evtCount = cs.eventId;
62510461SAndreas.Sandberg@ARM.com
62610461SAndreas.Sandberg@ARM.com    return type;
62710461SAndreas.Sandberg@ARM.com}
62810461SAndreas.Sandberg@ARM.com
62910461SAndreas.Sandberg@ARM.comvoid
63010461SAndreas.Sandberg@ARM.comPMU::setCounterTypeRegister(CounterId id, PMEVTYPER_t val)
63110461SAndreas.Sandberg@ARM.com{
63210461SAndreas.Sandberg@ARM.com    DPRINTF(PMUVerbose, "Set Event [%d] = 0x%08x\n", id, val);
63310461SAndreas.Sandberg@ARM.com    if (!isValidCounter(id)) {
63410461SAndreas.Sandberg@ARM.com        warn_once("Can't change counter type: Counter %i does not exist.\n",
63510461SAndreas.Sandberg@ARM.com                  id);
63610461SAndreas.Sandberg@ARM.com        return;
63710461SAndreas.Sandberg@ARM.com    }
63810461SAndreas.Sandberg@ARM.com
63910461SAndreas.Sandberg@ARM.com    CounterState &ctr(getCounter(id));
64010609Sandreas.sandberg@arm.com    const EventTypeId old_event_id(ctr.eventId);
64110461SAndreas.Sandberg@ARM.com
64210609Sandreas.sandberg@arm.com    ctr.filter = val;
64310609Sandreas.sandberg@arm.com
64410609Sandreas.sandberg@arm.com    // If PMCCNTR Register, do not change event type. PMCCNTR can
64510609Sandreas.sandberg@arm.com    // count processor cycles only. If we change the event type, we
64610609Sandreas.sandberg@arm.com    // need to update the probes the counter is using.
64710609Sandreas.sandberg@arm.com    if (id != PMCCNTR && old_event_id != val.evtCount) {
64810461SAndreas.Sandberg@ARM.com        ctr.eventId = val.evtCount;
64912286Sjose.marinho@arm.com        updateCounter(ctr);
65010461SAndreas.Sandberg@ARM.com    }
65110461SAndreas.Sandberg@ARM.com}
65210461SAndreas.Sandberg@ARM.com
65310461SAndreas.Sandberg@ARM.comvoid
65413581Sgabeblack@google.comPMU::setOverflowStatus(RegVal new_val)
65513104Sgiacomo.travaglini@arm.com{
65613104Sgiacomo.travaglini@arm.com    const bool int_old = reg_pmovsr != 0;
65713104Sgiacomo.travaglini@arm.com    const bool int_new = new_val != 0;
65813104Sgiacomo.travaglini@arm.com
65913104Sgiacomo.travaglini@arm.com    reg_pmovsr = new_val;
66013104Sgiacomo.travaglini@arm.com    if (int_old && !int_new) {
66113104Sgiacomo.travaglini@arm.com        clearInterrupt();
66213104Sgiacomo.travaglini@arm.com    } else if (!int_old && int_new && (reg_pminten & reg_pmovsr)) {
66313104Sgiacomo.travaglini@arm.com        raiseInterrupt();
66413104Sgiacomo.travaglini@arm.com    }
66513104Sgiacomo.travaglini@arm.com}
66613104Sgiacomo.travaglini@arm.com
66713104Sgiacomo.travaglini@arm.comvoid
66810461SAndreas.Sandberg@ARM.comPMU::raiseInterrupt()
66910461SAndreas.Sandberg@ARM.com{
67012973Sandreas.sandberg@arm.com    if (interrupt) {
67112973Sandreas.sandberg@arm.com        DPRINTF(PMUVerbose, "Delivering PMU interrupt.\n");
67212973Sandreas.sandberg@arm.com        interrupt->raise();
67312973Sandreas.sandberg@arm.com    } else {
67412973Sandreas.sandberg@arm.com        warn_once("Dropping PMU interrupt as no interrupt has "
67512973Sandreas.sandberg@arm.com                  "been specified\n");
67610461SAndreas.Sandberg@ARM.com    }
67710461SAndreas.Sandberg@ARM.com}
67810461SAndreas.Sandberg@ARM.com
67910461SAndreas.Sandberg@ARM.comvoid
68013104Sgiacomo.travaglini@arm.comPMU::clearInterrupt()
68113104Sgiacomo.travaglini@arm.com{
68213104Sgiacomo.travaglini@arm.com    if (interrupt) {
68313104Sgiacomo.travaglini@arm.com        DPRINTF(PMUVerbose, "Clearing PMU interrupt.\n");
68413104Sgiacomo.travaglini@arm.com        interrupt->clear();
68513104Sgiacomo.travaglini@arm.com    } else {
68613104Sgiacomo.travaglini@arm.com        warn_once("Dropping PMU interrupt as no interrupt has "
68713104Sgiacomo.travaglini@arm.com                  "been specified\n");
68813104Sgiacomo.travaglini@arm.com    }
68913104Sgiacomo.travaglini@arm.com}
69013104Sgiacomo.travaglini@arm.com
69113104Sgiacomo.travaglini@arm.comvoid
69210905Sandreas.sandberg@arm.comPMU::serialize(CheckpointOut &cp) const
69310461SAndreas.Sandberg@ARM.com{
69410461SAndreas.Sandberg@ARM.com    DPRINTF(Checkpoint, "Serializing Arm PMU\n");
69510461SAndreas.Sandberg@ARM.com
69610461SAndreas.Sandberg@ARM.com    SERIALIZE_SCALAR(reg_pmcr);
69710461SAndreas.Sandberg@ARM.com    SERIALIZE_SCALAR(reg_pmcnten);
69810461SAndreas.Sandberg@ARM.com    SERIALIZE_SCALAR(reg_pmselr);
69910461SAndreas.Sandberg@ARM.com    SERIALIZE_SCALAR(reg_pminten);
70010461SAndreas.Sandberg@ARM.com    SERIALIZE_SCALAR(reg_pmovsr);
70112117Sjose.marinho@arm.com    SERIALIZE_SCALAR(reg_pmceid0);
70212117Sjose.marinho@arm.com    SERIALIZE_SCALAR(reg_pmceid1);
70310461SAndreas.Sandberg@ARM.com    SERIALIZE_SCALAR(clock_remainder);
70410461SAndreas.Sandberg@ARM.com
70510905Sandreas.sandberg@arm.com    for (size_t i = 0; i < counters.size(); ++i)
70610905Sandreas.sandberg@arm.com        counters[i].serializeSection(cp, csprintf("counters.%i", i));
70710461SAndreas.Sandberg@ARM.com
70810905Sandreas.sandberg@arm.com    cycleCounter.serializeSection(cp, "cycleCounter");
70910461SAndreas.Sandberg@ARM.com}
71010461SAndreas.Sandberg@ARM.com
71110461SAndreas.Sandberg@ARM.comvoid
71210905Sandreas.sandberg@arm.comPMU::unserialize(CheckpointIn &cp)
71310461SAndreas.Sandberg@ARM.com{
71410461SAndreas.Sandberg@ARM.com    DPRINTF(Checkpoint, "Unserializing Arm PMU\n");
71510461SAndreas.Sandberg@ARM.com
71610461SAndreas.Sandberg@ARM.com    UNSERIALIZE_SCALAR(reg_pmcr);
71710461SAndreas.Sandberg@ARM.com    UNSERIALIZE_SCALAR(reg_pmcnten);
71810461SAndreas.Sandberg@ARM.com    UNSERIALIZE_SCALAR(reg_pmselr);
71910461SAndreas.Sandberg@ARM.com    UNSERIALIZE_SCALAR(reg_pminten);
72010461SAndreas.Sandberg@ARM.com    UNSERIALIZE_SCALAR(reg_pmovsr);
72112117Sjose.marinho@arm.com
72212117Sjose.marinho@arm.com    // Old checkpoints used to store the entire PMCEID value in a
72312117Sjose.marinho@arm.com    // single 64-bit entry (reg_pmceid). The register was extended in
72412117Sjose.marinho@arm.com    // ARMv8.1, so we now need to store it as two 64-bit registers.
72512117Sjose.marinho@arm.com    if (!UNSERIALIZE_OPT_SCALAR(reg_pmceid0))
72612117Sjose.marinho@arm.com        paramIn(cp, "reg_pmceid", reg_pmceid0);
72712117Sjose.marinho@arm.com
72812117Sjose.marinho@arm.com    if (!UNSERIALIZE_OPT_SCALAR(reg_pmceid1))
72912117Sjose.marinho@arm.com        reg_pmceid1 = 0;
73012117Sjose.marinho@arm.com
73110461SAndreas.Sandberg@ARM.com    UNSERIALIZE_SCALAR(clock_remainder);
73210461SAndreas.Sandberg@ARM.com
73310461SAndreas.Sandberg@ARM.com    for (size_t i = 0; i < counters.size(); ++i)
73410905Sandreas.sandberg@arm.com        counters[i].unserializeSection(cp, csprintf("counters.%i", i));
73510461SAndreas.Sandberg@ARM.com
73610905Sandreas.sandberg@arm.com    cycleCounter.unserializeSection(cp, "cycleCounter");
73710461SAndreas.Sandberg@ARM.com}
73810461SAndreas.Sandberg@ARM.com
73912286Sjose.marinho@arm.comPMU::PMUEvent*
74012286Sjose.marinho@arm.comPMU::getEvent(uint64_t eventId)
74112286Sjose.marinho@arm.com{
74212286Sjose.marinho@arm.com    auto entry = eventMap.find(eventId);
74312286Sjose.marinho@arm.com
74412286Sjose.marinho@arm.com    if (entry == eventMap.end()) {
74512286Sjose.marinho@arm.com        warn("event %d does not exist\n", eventId);
74612286Sjose.marinho@arm.com        return nullptr;
74712286Sjose.marinho@arm.com    } else {
74812286Sjose.marinho@arm.com        return entry->second;
74912286Sjose.marinho@arm.com    }
75012286Sjose.marinho@arm.com}
75112286Sjose.marinho@arm.com
75210461SAndreas.Sandberg@ARM.comvoid
75310905Sandreas.sandberg@arm.comPMU::CounterState::serialize(CheckpointOut &cp) const
75410461SAndreas.Sandberg@ARM.com{
75510461SAndreas.Sandberg@ARM.com    SERIALIZE_SCALAR(eventId);
75610461SAndreas.Sandberg@ARM.com    SERIALIZE_SCALAR(value);
75710461SAndreas.Sandberg@ARM.com    SERIALIZE_SCALAR(overflow64);
75810461SAndreas.Sandberg@ARM.com}
75910461SAndreas.Sandberg@ARM.com
76010461SAndreas.Sandberg@ARM.comvoid
76110905Sandreas.sandberg@arm.comPMU::CounterState::unserialize(CheckpointIn &cp)
76210461SAndreas.Sandberg@ARM.com{
76310461SAndreas.Sandberg@ARM.com    UNSERIALIZE_SCALAR(eventId);
76410461SAndreas.Sandberg@ARM.com    UNSERIALIZE_SCALAR(value);
76510461SAndreas.Sandberg@ARM.com    UNSERIALIZE_SCALAR(overflow64);
76610461SAndreas.Sandberg@ARM.com}
76710461SAndreas.Sandberg@ARM.com
76812286Sjose.marinho@arm.comuint64_t
76910461SAndreas.Sandberg@ARM.comPMU::CounterState::add(uint64_t delta)
77010461SAndreas.Sandberg@ARM.com{
77112286Sjose.marinho@arm.com    uint64_t value_until_overflow;
77212286Sjose.marinho@arm.com    if (overflow64) {
77312286Sjose.marinho@arm.com        value_until_overflow = UINT64_MAX - value;
77412286Sjose.marinho@arm.com    } else {
77512286Sjose.marinho@arm.com        value_until_overflow = UINT32_MAX - (uint32_t)value;
77612286Sjose.marinho@arm.com    }
77710461SAndreas.Sandberg@ARM.com
77812286Sjose.marinho@arm.com    if (isFiltered())
77912286Sjose.marinho@arm.com        return value_until_overflow;
78010461SAndreas.Sandberg@ARM.com
78112286Sjose.marinho@arm.com    if (resetValue) {
78212286Sjose.marinho@arm.com        delta = 0;
78312286Sjose.marinho@arm.com        resetValue = false;
78412286Sjose.marinho@arm.com    } else {
78512286Sjose.marinho@arm.com        value += delta;
78612286Sjose.marinho@arm.com    }
78712286Sjose.marinho@arm.com
78812286Sjose.marinho@arm.com    if (delta > value_until_overflow) {
78912286Sjose.marinho@arm.com
79012286Sjose.marinho@arm.com        // overflow situation detected
79112286Sjose.marinho@arm.com        // flag the overflow occurence
79212286Sjose.marinho@arm.com        pmu.reg_pmovsr |= (1 << counterId);
79312286Sjose.marinho@arm.com
79412286Sjose.marinho@arm.com        // Deliver a PMU interrupt if interrupt delivery is enabled
79512286Sjose.marinho@arm.com        // for this counter.
79612286Sjose.marinho@arm.com        if (pmu.reg_pminten  & (1 << counterId)) {
79712286Sjose.marinho@arm.com            pmu.raiseInterrupt();
79812286Sjose.marinho@arm.com        }
79912286Sjose.marinho@arm.com        return overflow64 ? UINT64_MAX : UINT32_MAX;
80012286Sjose.marinho@arm.com    }
80112286Sjose.marinho@arm.com    return value_until_overflow - delta + 1;
80212286Sjose.marinho@arm.com}
80312286Sjose.marinho@arm.com
80412286Sjose.marinho@arm.comvoid
80512286Sjose.marinho@arm.comPMU::SWIncrementEvent::write(uint64_t val)
80612286Sjose.marinho@arm.com{
80712286Sjose.marinho@arm.com    for (auto& counter: userCounters) {
80812286Sjose.marinho@arm.com        if (val & (0x1 << counter->getCounterId())) {
80912286Sjose.marinho@arm.com            counter->add(1);
81012286Sjose.marinho@arm.com        }
81112286Sjose.marinho@arm.com    }
81210461SAndreas.Sandberg@ARM.com}
81310461SAndreas.Sandberg@ARM.com
81410461SAndreas.Sandberg@ARM.com} // namespace ArmISA
81510461SAndreas.Sandberg@ARM.com
81610461SAndreas.Sandberg@ARM.comArmISA::PMU *
81710461SAndreas.Sandberg@ARM.comArmPMUParams::create()
81810461SAndreas.Sandberg@ARM.com{
81910461SAndreas.Sandberg@ARM.com    return new ArmISA::PMU(this);
82010461SAndreas.Sandberg@ARM.com}
821