pmu.cc revision 10461
111988Sandreas.sandberg@arm.com/*
28839Sandreas.hansson@arm.com * Copyright (c) 2011-2014 ARM Limited
38839Sandreas.hansson@arm.com * All rights reserved
48839Sandreas.hansson@arm.com *
58839Sandreas.hansson@arm.com * The license below extends only to copyright in the software and shall
68839Sandreas.hansson@arm.com * not be construed as granting a license to any other intellectual
78839Sandreas.hansson@arm.com * property including but not limited to intellectual property relating
88839Sandreas.hansson@arm.com * to a hardware implementation of the functionality of the software
98839Sandreas.hansson@arm.com * licensed hereunder.  You may use the software subject to the license
108839Sandreas.hansson@arm.com * terms below provided that you ensure that this notice is replicated
118839Sandreas.hansson@arm.com * unmodified and in its entirety in all distributions of the software,
128839Sandreas.hansson@arm.com * modified or unmodified, in source code or in binary form.
133101Sstever@eecs.umich.edu *
148579Ssteve.reinhardt@amd.com * Redistribution and use in source and binary forms, with or without
153101Sstever@eecs.umich.edu * modification, are permitted provided that the following conditions are
163101Sstever@eecs.umich.edu * met: redistributions of source code must retain the above copyright
173101Sstever@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
183101Sstever@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
193101Sstever@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
203101Sstever@eecs.umich.edu * documentation and/or other materials provided with the distribution;
213101Sstever@eecs.umich.edu * neither the name of the copyright holders nor the names of its
223101Sstever@eecs.umich.edu * contributors may be used to endorse or promote products derived from
233101Sstever@eecs.umich.edu * this software without specific prior written permission.
243101Sstever@eecs.umich.edu *
253101Sstever@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
263101Sstever@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
273101Sstever@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
283101Sstever@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
293101Sstever@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
303101Sstever@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
313101Sstever@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
323101Sstever@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
333101Sstever@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
343101Sstever@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
353101Sstever@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
363101Sstever@eecs.umich.edu *
373101Sstever@eecs.umich.edu * Authors: Dam Sunwoo
383101Sstever@eecs.umich.edu *          Matt Horsnell
393101Sstever@eecs.umich.edu *          Andreas Sandberg
403101Sstever@eecs.umich.edu */
413101Sstever@eecs.umich.edu
427778Sgblack@eecs.umich.edu#include "arch/arm/pmu.hh"
438839Sandreas.hansson@arm.com
443101Sstever@eecs.umich.edu#include "base/trace.hh"
453101Sstever@eecs.umich.edu#include "cpu/base.hh"
463101Sstever@eecs.umich.edu#include "debug/Checkpoint.hh"
473101Sstever@eecs.umich.edu#include "debug/PMUVerbose.hh"
483101Sstever@eecs.umich.edu#include "dev/arm/base_gic.hh"
493101Sstever@eecs.umich.edu#include "dev/arm/realview.hh"
503101Sstever@eecs.umich.edu#include "params/ArmPMU.hh"
513101Sstever@eecs.umich.edu
523101Sstever@eecs.umich.edunamespace ArmISA {
533101Sstever@eecs.umich.edu
543101Sstever@eecs.umich.educonst MiscReg PMU::reg_pmcr_wr_mask = 0x39;
553101Sstever@eecs.umich.edu
563101Sstever@eecs.umich.eduPMU::PMU(const ArmPMUParams *p)
573101Sstever@eecs.umich.edu    : SimObject(p), BaseISADevice(),
583101Sstever@eecs.umich.edu      reg_pmcnten(0), reg_pmcr(0),
593101Sstever@eecs.umich.edu      reg_pmselr(0), reg_pminten(0), reg_pmovsr(0),
603101Sstever@eecs.umich.edu      reg_pmceid(0),
613101Sstever@eecs.umich.edu      clock_remainder(0),
6212563Sgabeblack@google.com      counters(p->eventCounters),
6312563Sgabeblack@google.com      reg_pmcr_conf(0),
643885Sbinkertn@umich.edu      pmuInterrupt(p->pmuInterrupt),
653885Sbinkertn@umich.edu      platform(p->platform)
664762Snate@binkert.org{
673885Sbinkertn@umich.edu    DPRINTF(PMUVerbose, "Initializing the PMU.\n");
683885Sbinkertn@umich.edu
697528Ssteve.reinhardt@amd.com    if (p->eventCounters > 31) {
703885Sbinkertn@umich.edu        fatal("The PMU can only accept 31 counters, %d counters requested.\n",
714380Sbinkertn@umich.edu              p->eventCounters);
724167Sbinkertn@umich.edu    }
733102Sstever@eecs.umich.edu
743101Sstever@eecs.umich.edu    /* Setup the performance counter ID registers */
754762Snate@binkert.org    reg_pmcr_conf.imp = 0x41;    // ARM Ltd.
764762Snate@binkert.org    reg_pmcr_conf.idcode = 0x00;
774762Snate@binkert.org    reg_pmcr_conf.n = p->eventCounters;
784762Snate@binkert.org
794762Snate@binkert.org    // Setup the hard-coded cycle counter, which is equivalent to
804762Snate@binkert.org    // architected counter event type 0x11.
814762Snate@binkert.org    cycleCounter.eventId = 0x11;
824762Snate@binkert.org}
834762Snate@binkert.org
845033Smilesck@eecs.umich.eduPMU::~PMU()
855033Smilesck@eecs.umich.edu{
865033Smilesck@eecs.umich.edu}
875033Smilesck@eecs.umich.edu
885033Smilesck@eecs.umich.eduvoid
895033Smilesck@eecs.umich.eduPMU::addEventProbe(unsigned int id, SimObject *obj, const char *probe_name)
905033Smilesck@eecs.umich.edu{
915033Smilesck@eecs.umich.edu    DPRINTF(PMUVerbose, "PMU: Adding event type '0x%x' as probe %s:%s\n",
925033Smilesck@eecs.umich.edu            id, obj->name(), probe_name);
935033Smilesck@eecs.umich.edu    pmuEventTypes.insert(std::make_pair(id, EventType(obj, probe_name)));
943101Sstever@eecs.umich.edu
953101Sstever@eecs.umich.edu    // Flag the event as available in the PMCEID register if it is an
963101Sstever@eecs.umich.edu    // architected event.
975033Smilesck@eecs.umich.edu    if (id < 0x40)
9810267SGeoffrey.Blake@arm.com        reg_pmceid |= (1 << id);
998596Ssteve.reinhardt@amd.com}
1008596Ssteve.reinhardt@amd.com
1018596Ssteve.reinhardt@amd.comvoid
1028596Ssteve.reinhardt@amd.comPMU::drainResume()
1037673Snate@binkert.org{
1047673Snate@binkert.org    // Re-attach enabled counters after a resume in case they changed.
1057673Snate@binkert.org    updateAllCounters();
1067673Snate@binkert.org}
10711988Sandreas.sandberg@arm.com
10811988Sandreas.sandberg@arm.comvoid
10911988Sandreas.sandberg@arm.comPMU::setMiscReg(int misc_reg, MiscReg val)
11011988Sandreas.sandberg@arm.com{
1113101Sstever@eecs.umich.edu    DPRINTF(PMUVerbose, "setMiscReg(%s, 0x%x)\n",
1123101Sstever@eecs.umich.edu            miscRegName[unflattenMiscReg(misc_reg)], val);
1133101Sstever@eecs.umich.edu
1143101Sstever@eecs.umich.edu    switch (unflattenMiscReg(misc_reg)) {
1153101Sstever@eecs.umich.edu      case MISCREG_PMCR_EL0:
11610380SAndrew.Bardsley@arm.com      case MISCREG_PMCR:
11710380SAndrew.Bardsley@arm.com        setControlReg(val);
11810380SAndrew.Bardsley@arm.com        return;
11910380SAndrew.Bardsley@arm.com
12010380SAndrew.Bardsley@arm.com      case MISCREG_PMCNTENSET_EL0:
12110380SAndrew.Bardsley@arm.com      case MISCREG_PMCNTENSET:
12210458Sandreas.hansson@arm.com        reg_pmcnten |= val;
12310458Sandreas.hansson@arm.com        updateAllCounters();
12410458Sandreas.hansson@arm.com        return;
12510458Sandreas.hansson@arm.com
12610458Sandreas.hansson@arm.com      case MISCREG_PMCNTENCLR_EL0:
12710458Sandreas.hansson@arm.com      case MISCREG_PMCNTENCLR:
12810458Sandreas.hansson@arm.com        reg_pmcnten &= ~val;
12910458Sandreas.hansson@arm.com        updateAllCounters();
13010458Sandreas.hansson@arm.com        return;
13110458Sandreas.hansson@arm.com
13210458Sandreas.hansson@arm.com      case MISCREG_PMOVSCLR_EL0:
13310458Sandreas.hansson@arm.com      case MISCREG_PMOVSR:
1343101Sstever@eecs.umich.edu        reg_pmovsr &= ~val;
1353101Sstever@eecs.umich.edu        return;
1363101Sstever@eecs.umich.edu
1373101Sstever@eecs.umich.edu      case MISCREG_PMSWINC_EL0:
1383101Sstever@eecs.umich.edu      case MISCREG_PMSWINC:
13910267SGeoffrey.Blake@arm.com        for (int i = 0; i < counters.size(); ++i) {
14010267SGeoffrey.Blake@arm.com            CounterState &ctr(getCounter(i));
14110267SGeoffrey.Blake@arm.com            if (ctr.enabled && (val & (1 << i)))
14210267SGeoffrey.Blake@arm.com                ++ctr.value;
1433101Sstever@eecs.umich.edu        }
1443101Sstever@eecs.umich.edu        break;
1453101Sstever@eecs.umich.edu
1463101Sstever@eecs.umich.edu      case MISCREG_PMCCNTR_EL0:
1473101Sstever@eecs.umich.edu      case MISCREG_PMCCNTR:
1483101Sstever@eecs.umich.edu        cycleCounter.value = val;
1493101Sstever@eecs.umich.edu        return;
1503101Sstever@eecs.umich.edu
1513101Sstever@eecs.umich.edu      case MISCREG_PMSELR_EL0:
1523101Sstever@eecs.umich.edu      case MISCREG_PMSELR:
1533101Sstever@eecs.umich.edu        reg_pmselr = val;
1543101Sstever@eecs.umich.edu        return;
1553101Sstever@eecs.umich.edu
1563101Sstever@eecs.umich.edu      case MISCREG_PMCEID0_EL0:
1573101Sstever@eecs.umich.edu      case MISCREG_PMCEID0:
1583101Sstever@eecs.umich.edu      case MISCREG_PMCEID1_EL0:
1593101Sstever@eecs.umich.edu      case MISCREG_PMCEID1:
1603101Sstever@eecs.umich.edu        // Ignore writes
1613101Sstever@eecs.umich.edu        return;
1623101Sstever@eecs.umich.edu
1633101Sstever@eecs.umich.edu      case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0:
1643101Sstever@eecs.umich.edu        setCounterTypeRegister(misc_reg - MISCREG_PMEVCNTR0_EL0, val);
1653101Sstever@eecs.umich.edu        return;
1663101Sstever@eecs.umich.edu
1673101Sstever@eecs.umich.edu      case MISCREG_PMCCFILTR:
1683101Sstever@eecs.umich.edu      case MISCREG_PMCCFILTR_EL0:
1693101Sstever@eecs.umich.edu        DPRINTF(PMUVerbose, "Setting PMCCFILTR: 0x%x\n", val);
1703101Sstever@eecs.umich.edu        setCounterTypeRegister(PMCCNTR, val);
1713101Sstever@eecs.umich.edu        return;
1723101Sstever@eecs.umich.edu
1733101Sstever@eecs.umich.edu      case MISCREG_PMXEVTYPER_PMCCFILTR:
1743101Sstever@eecs.umich.edu      case MISCREG_PMXEVTYPER_EL0:
1753101Sstever@eecs.umich.edu      case MISCREG_PMXEVTYPER:
1763101Sstever@eecs.umich.edu        DPRINTF(PMUVerbose, "Setting counter type: "
1773101Sstever@eecs.umich.edu                "[PMSELR: 0x%x, PMSELER.sel: 0x%x, EVTYPER: 0x%x]\n",
1785033Smilesck@eecs.umich.edu                reg_pmselr, reg_pmselr.sel, val);
1796656Snate@binkert.org        setCounterTypeRegister(reg_pmselr.sel, val);
1805033Smilesck@eecs.umich.edu        return;
1815033Smilesck@eecs.umich.edu
1825033Smilesck@eecs.umich.edu      case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0:
1833101Sstever@eecs.umich.edu        setCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0, val);
1843101Sstever@eecs.umich.edu        return;
1853101Sstever@eecs.umich.edu
18610267SGeoffrey.Blake@arm.com      case MISCREG_PMXEVCNTR_EL0:
18710267SGeoffrey.Blake@arm.com      case MISCREG_PMXEVCNTR:
18810267SGeoffrey.Blake@arm.com        setCounterValue(reg_pmselr.sel, val);
18910267SGeoffrey.Blake@arm.com        return;
19010267SGeoffrey.Blake@arm.com
19110267SGeoffrey.Blake@arm.com      case MISCREG_PMUSERENR_EL0:
19210267SGeoffrey.Blake@arm.com      case MISCREG_PMUSERENR:
19310267SGeoffrey.Blake@arm.com        // TODO
19410267SGeoffrey.Blake@arm.com        break;
19510267SGeoffrey.Blake@arm.com
19610267SGeoffrey.Blake@arm.com      case MISCREG_PMINTENSET_EL1:
19710267SGeoffrey.Blake@arm.com      case MISCREG_PMINTENSET:
19810267SGeoffrey.Blake@arm.com        reg_pminten |= val;
1993101Sstever@eecs.umich.edu        return;
2003101Sstever@eecs.umich.edu
2013101Sstever@eecs.umich.edu      case MISCREG_PMINTENCLR_EL1:
2023101Sstever@eecs.umich.edu      case MISCREG_PMINTENCLR:
2033101Sstever@eecs.umich.edu        reg_pminten &= ~val;
2043101Sstever@eecs.umich.edu        return;
2053101Sstever@eecs.umich.edu
2063101Sstever@eecs.umich.edu      case MISCREG_PMOVSSET_EL0:
2073101Sstever@eecs.umich.edu      case MISCREG_PMOVSSET:
2083101Sstever@eecs.umich.edu        reg_pmovsr |= val;
2093102Sstever@eecs.umich.edu        return;
2103101Sstever@eecs.umich.edu
2113101Sstever@eecs.umich.edu      default:
2123101Sstever@eecs.umich.edu        panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]);
21310267SGeoffrey.Blake@arm.com    }
21410267SGeoffrey.Blake@arm.com
21510267SGeoffrey.Blake@arm.com    warn("Not doing anything for write to miscreg %s\n",
21610267SGeoffrey.Blake@arm.com         miscRegName[misc_reg]);
21710267SGeoffrey.Blake@arm.com}
21810267SGeoffrey.Blake@arm.com
21910267SGeoffrey.Blake@arm.comMiscReg
2207673Snate@binkert.orgPMU::readMiscReg(int misc_reg)
2218607Sgblack@eecs.umich.edu{
2227673Snate@binkert.org    MiscReg val(readMiscRegInt(misc_reg));
2233101Sstever@eecs.umich.edu    DPRINTF(PMUVerbose, "readMiscReg(%s): 0x%x\n",
22411988Sandreas.sandberg@arm.com            miscRegName[unflattenMiscReg(misc_reg)], val);
22511988Sandreas.sandberg@arm.com    return val;
22611988Sandreas.sandberg@arm.com}
2277673Snate@binkert.org
2287673Snate@binkert.orgMiscReg
2293101Sstever@eecs.umich.eduPMU::readMiscRegInt(int misc_reg)
2303101Sstever@eecs.umich.edu{
2313101Sstever@eecs.umich.edu    misc_reg = unflattenMiscReg(misc_reg);
2323101Sstever@eecs.umich.edu    switch (misc_reg) {
2333101Sstever@eecs.umich.edu      case MISCREG_PMCR_EL0:
2343101Sstever@eecs.umich.edu      case MISCREG_PMCR:
2355033Smilesck@eecs.umich.edu        return reg_pmcr_conf | (reg_pmcr & reg_pmcr_wr_mask);
2365475Snate@binkert.org
2375475Snate@binkert.org      case MISCREG_PMCNTENSET_EL0:
2385475Snate@binkert.org      case MISCREG_PMCNTENCLR_EL0:
2395475Snate@binkert.org      case MISCREG_PMCNTENSET:
24010380SAndrew.Bardsley@arm.com      case MISCREG_PMCNTENCLR:
24110380SAndrew.Bardsley@arm.com        return reg_pmcnten;
24210380SAndrew.Bardsley@arm.com
2433101Sstever@eecs.umich.edu      case MISCREG_PMOVSCLR_EL0:
2443101Sstever@eecs.umich.edu      case MISCREG_PMOVSSET_EL0:
2453101Sstever@eecs.umich.edu      case MISCREG_PMOVSR:  // Overflow Status Register
2464762Snate@binkert.org      case MISCREG_PMOVSSET:
2474762Snate@binkert.org        return reg_pmovsr;
2484762Snate@binkert.org
2493101Sstever@eecs.umich.edu      case MISCREG_PMSWINC_EL0:
25012050Snikos.nikoleris@arm.com      case MISCREG_PMSWINC: // Software Increment Register (RAZ)
25112050Snikos.nikoleris@arm.com        return 0;
25212050Snikos.nikoleris@arm.com
2538459SAli.Saidi@ARM.com      case MISCREG_PMSELR:
2548459SAli.Saidi@ARM.com        return reg_pmselr;
25512050Snikos.nikoleris@arm.com
2563101Sstever@eecs.umich.edu      case MISCREG_PMCEID0_EL0:
2577528Ssteve.reinhardt@amd.com      case MISCREG_PMCEID0: // Common Event ID register
2587528Ssteve.reinhardt@amd.com        return reg_pmceid & 0xFFFFFFFF;
2597528Ssteve.reinhardt@amd.com
2607528Ssteve.reinhardt@amd.com      case MISCREG_PMCEID1_EL0:
2617528Ssteve.reinhardt@amd.com      case MISCREG_PMCEID1: // Common Event ID register
2627528Ssteve.reinhardt@amd.com        return (reg_pmceid >> 32) & 0xFFFFFFFF;
2633101Sstever@eecs.umich.edu
2647528Ssteve.reinhardt@amd.com      case MISCREG_PMCCNTR_EL0:
2657528Ssteve.reinhardt@amd.com        return cycleCounter.value;
2667528Ssteve.reinhardt@amd.com
2677528Ssteve.reinhardt@amd.com      case MISCREG_PMCCNTR:
2687528Ssteve.reinhardt@amd.com        return cycleCounter.value & 0xFFFFFFFF;
2697528Ssteve.reinhardt@amd.com
2707528Ssteve.reinhardt@amd.com      case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0:
2717528Ssteve.reinhardt@amd.com        return getCounterTypeRegister(misc_reg - MISCREG_PMEVTYPER0_EL0);
2727528Ssteve.reinhardt@amd.com
2737528Ssteve.reinhardt@amd.com      case MISCREG_PMCCFILTR:
2748321Ssteve.reinhardt@amd.com      case MISCREG_PMCCFILTR_EL0:
27512194Sgabeblack@google.com        return getCounterTypeRegister(PMCCNTR);
2767528Ssteve.reinhardt@amd.com
2777528Ssteve.reinhardt@amd.com      case MISCREG_PMXEVTYPER_PMCCFILTR:
2787528Ssteve.reinhardt@amd.com      case MISCREG_PMXEVTYPER_EL0:
2797528Ssteve.reinhardt@amd.com      case MISCREG_PMXEVTYPER:
2807528Ssteve.reinhardt@amd.com        return getCounterTypeRegister(reg_pmselr.sel);
2817528Ssteve.reinhardt@amd.com
2827528Ssteve.reinhardt@amd.com      case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0:
2837528Ssteve.reinhardt@amd.com        return getCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0) & 0xFFFFFFFF;
2847528Ssteve.reinhardt@amd.com
2857528Ssteve.reinhardt@amd.com      case MISCREG_PMXEVCNTR_EL0:
2867528Ssteve.reinhardt@amd.com      case MISCREG_PMXEVCNTR:
2877528Ssteve.reinhardt@amd.com        return getCounterValue(reg_pmselr.sel) & 0xFFFFFFFF;
2887528Ssteve.reinhardt@amd.com
2893101Sstever@eecs.umich.edu      case MISCREG_PMUSERENR_EL0:
2908664SAli.Saidi@ARM.com      case MISCREG_PMUSERENR:
2918664SAli.Saidi@ARM.com        // TODO
2928664SAli.Saidi@ARM.com        return 0;
2938664SAli.Saidi@ARM.com
2948664SAli.Saidi@ARM.com      case MISCREG_PMINTENSET_EL1:
2958664SAli.Saidi@ARM.com      case MISCREG_PMINTENCLR_EL1:
2969953Sgeoffrey.blake@arm.com      case MISCREG_PMINTENSET:
2979953Sgeoffrey.blake@arm.com      case MISCREG_PMINTENCLR:
2989953Sgeoffrey.blake@arm.com        return reg_pminten;
2999953Sgeoffrey.blake@arm.com
3009953Sgeoffrey.blake@arm.com      default:
3019953Sgeoffrey.blake@arm.com        panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]);
3029953Sgeoffrey.blake@arm.com    }
3039953Sgeoffrey.blake@arm.com
3049953Sgeoffrey.blake@arm.com    warn("Not doing anything for read from miscreg %s\n",
3059953Sgeoffrey.blake@arm.com         miscRegName[misc_reg]);
3069953Sgeoffrey.blake@arm.com    return 0;
3079953Sgeoffrey.blake@arm.com}
3089953Sgeoffrey.blake@arm.com
30910267SGeoffrey.Blake@arm.comvoid
31010267SGeoffrey.Blake@arm.comPMU::setControlReg(PMCR_t val)
31110267SGeoffrey.Blake@arm.com{
31210267SGeoffrey.Blake@arm.com    DPRINTF(PMUVerbose, "Set Control Reg 0x%08x.\n", val);
31310267SGeoffrey.Blake@arm.com
31410267SGeoffrey.Blake@arm.com    if (val.p) {
31510267SGeoffrey.Blake@arm.com        DPRINTF(PMUVerbose, "PMU reset all events to zero.\n");
31612563Sgabeblack@google.com        resetEventCounts();
31710267SGeoffrey.Blake@arm.com    }
31810267SGeoffrey.Blake@arm.com
31910267SGeoffrey.Blake@arm.com    if (val.c) {
32010267SGeoffrey.Blake@arm.com        DPRINTF(PMUVerbose, "PMU reset cycle counter to zero.\n");
32110267SGeoffrey.Blake@arm.com        cycleCounter.value = 0;
32210267SGeoffrey.Blake@arm.com    }
32310267SGeoffrey.Blake@arm.com
32410267SGeoffrey.Blake@arm.com    // Reset the clock remainder if divide by 64-mode is toggled.
32510267SGeoffrey.Blake@arm.com    if (reg_pmcr.d != val.d)
32610267SGeoffrey.Blake@arm.com        clock_remainder = 0;
32710267SGeoffrey.Blake@arm.com
32810267SGeoffrey.Blake@arm.com    reg_pmcr = val & reg_pmcr_wr_mask;
3293101Sstever@eecs.umich.edu    updateAllCounters();
3303101Sstever@eecs.umich.edu}
3313101Sstever@eecs.umich.edu
3323101Sstever@eecs.umich.eduvoid
3333101Sstever@eecs.umich.eduPMU::updateAllCounters()
3343101Sstever@eecs.umich.edu{
3353101Sstever@eecs.umich.edu    const bool global_enable(reg_pmcr.e);
33610364SGeoffrey.Blake@arm.com
33710364SGeoffrey.Blake@arm.com    for (int i = 0; i < counters.size(); ++i) {
33810364SGeoffrey.Blake@arm.com        CounterState &ctr(counters[i]);
33910364SGeoffrey.Blake@arm.com        const bool enable(global_enable && (reg_pmcnten & (1 << i)));
3403101Sstever@eecs.umich.edu        if (ctr.enabled != enable) {
3414762Snate@binkert.org            ctr.enabled = enable;
3424762Snate@binkert.org            updateCounter(i, ctr);
3434762Snate@binkert.org        }
3444762Snate@binkert.org    }
3457528Ssteve.reinhardt@amd.com
3464762Snate@binkert.org    const bool ccntr_enable(global_enable && (reg_pmcnten & (1 << PMCCNTR)));
3474762Snate@binkert.org    if (cycleCounter.enabled != ccntr_enable) {
3484762Snate@binkert.org        cycleCounter.enabled = ccntr_enable;
34910267SGeoffrey.Blake@arm.com        updateCounter(PMCCNTR, cycleCounter);
35010267SGeoffrey.Blake@arm.com    }
35110267SGeoffrey.Blake@arm.com}
35210267SGeoffrey.Blake@arm.com
35310267SGeoffrey.Blake@arm.comvoid
35410267SGeoffrey.Blake@arm.comPMU::handleEvent(CounterId id, uint64_t delta)
35510267SGeoffrey.Blake@arm.com{
35610267SGeoffrey.Blake@arm.com    CounterState &ctr(getCounter(id));
35710267SGeoffrey.Blake@arm.com    const bool overflowed(reg_pmovsr & (1 << id));
35810267SGeoffrey.Blake@arm.com
35910267SGeoffrey.Blake@arm.com    // Handle the "count every 64 cycles" mode
36010267SGeoffrey.Blake@arm.com    if (id == PMCCNTR && reg_pmcr.d) {
36110267SGeoffrey.Blake@arm.com        clock_remainder += delta;
36210267SGeoffrey.Blake@arm.com        delta = (clock_remainder >> 6);
36310267SGeoffrey.Blake@arm.com        clock_remainder &= 63;
36410267SGeoffrey.Blake@arm.com    }
36510267SGeoffrey.Blake@arm.com
36610267SGeoffrey.Blake@arm.com    // Add delta and handle (new) overflows
36710267SGeoffrey.Blake@arm.com    if (ctr.add(delta) && !overflowed) {
36810267SGeoffrey.Blake@arm.com        DPRINTF(PMUVerbose, "PMU counter '%i' overflowed.\n", id);
36910267SGeoffrey.Blake@arm.com        reg_pmovsr |= (1 << id);
37010267SGeoffrey.Blake@arm.com        // Deliver a PMU interrupt if interrupt delivery is enabled
37110267SGeoffrey.Blake@arm.com        // for this counter.
37210267SGeoffrey.Blake@arm.com        if (reg_pminten  & (1 << id))
37310267SGeoffrey.Blake@arm.com            raiseInterrupt();
37410267SGeoffrey.Blake@arm.com    }
37510364SGeoffrey.Blake@arm.com}
37610364SGeoffrey.Blake@arm.com
37710267SGeoffrey.Blake@arm.comvoid
37810267SGeoffrey.Blake@arm.comPMU::updateCounter(CounterId id, CounterState &ctr)
37910267SGeoffrey.Blake@arm.com{
38010267SGeoffrey.Blake@arm.com    if (!ctr.enabled) {
38110267SGeoffrey.Blake@arm.com        if (!ctr.listeners.empty()) {
38210267SGeoffrey.Blake@arm.com            DPRINTF(PMUVerbose, "updateCounter(%i): Disabling counter\n", id);
3837673Snate@binkert.org            ctr.listeners.clear();
3847673Snate@binkert.org        }
3857673Snate@binkert.org    } else {
3863101Sstever@eecs.umich.edu        DPRINTF(PMUVerbose, "updateCounter(%i): Enable event id 0x%x\n",
38711988Sandreas.sandberg@arm.com                id, ctr.eventId);
38811988Sandreas.sandberg@arm.com
38911988Sandreas.sandberg@arm.com        // Attach all probes belonging to this event
39011988Sandreas.sandberg@arm.com        auto range(pmuEventTypes.equal_range(ctr.eventId));
3917673Snate@binkert.org        for (auto it = range.first; it != range.second; ++it) {
3927673Snate@binkert.org            const EventType &et(it->second);
3933101Sstever@eecs.umich.edu
3943101Sstever@eecs.umich.edu            DPRINTF(PMUVerbose, "\tProbe: %s:%s\n", et.obj->name(), et.name);
3953101Sstever@eecs.umich.edu            ctr.listeners.emplace_back(et.create(*this, id));
3963101Sstever@eecs.umich.edu        }
3973101Sstever@eecs.umich.edu
3983101Sstever@eecs.umich.edu        /* The SW_INCR event type is a special case which doesn't need
3993101Sstever@eecs.umich.edu         * any probes since it is controlled by software and the PMU
4003101Sstever@eecs.umich.edu         * itself.
4013101Sstever@eecs.umich.edu         */
4023101Sstever@eecs.umich.edu        if (ctr.listeners.empty() && ctr.eventId != ARCH_EVENT_SW_INCR) {
4033101Sstever@eecs.umich.edu            warn("Can't enable PMU counter of type '0x%x': "
4043101Sstever@eecs.umich.edu                 "No such event type.\n", ctr.eventId);
4053101Sstever@eecs.umich.edu        }
4063101Sstever@eecs.umich.edu    }
4073101Sstever@eecs.umich.edu}
4085033Smilesck@eecs.umich.edu
4095033Smilesck@eecs.umich.edu
4103101Sstever@eecs.umich.eduvoid
4113101Sstever@eecs.umich.eduPMU::resetEventCounts()
4123101Sstever@eecs.umich.edu{
4133101Sstever@eecs.umich.edu    for (CounterState &ctr : counters)
4143101Sstever@eecs.umich.edu        ctr.value = 0;
4153101Sstever@eecs.umich.edu}
4163101Sstever@eecs.umich.edu
4173101Sstever@eecs.umich.eduvoid
4183101Sstever@eecs.umich.eduPMU::setCounterValue(CounterId id, uint64_t val)
4193101Sstever@eecs.umich.edu{
4203101Sstever@eecs.umich.edu    if (!isValidCounter(id)) {
4213101Sstever@eecs.umich.edu        warn_once("Can't change counter value: Counter %i does not exist.\n",
4223101Sstever@eecs.umich.edu                  id);
4233101Sstever@eecs.umich.edu        return;
4243101Sstever@eecs.umich.edu    }
4253101Sstever@eecs.umich.edu
4263101Sstever@eecs.umich.edu    CounterState &ctr(getCounter(id));
4273101Sstever@eecs.umich.edu    ctr.value = val;
4283101Sstever@eecs.umich.edu}
4293101Sstever@eecs.umich.edu
4303101Sstever@eecs.umich.eduPMU::PMEVTYPER_t
4313101Sstever@eecs.umich.eduPMU::getCounterTypeRegister(CounterId id) const
4323101Sstever@eecs.umich.edu{
4333101Sstever@eecs.umich.edu    if (!isValidCounter(id))
4343101Sstever@eecs.umich.edu        return 0;
43510267SGeoffrey.Blake@arm.com
4367673Snate@binkert.org    const CounterState &cs(getCounter(id));
4377673Snate@binkert.org    PMEVTYPER_t type(0);
4387673Snate@binkert.org
4397673Snate@binkert.org    // TODO: Re-create filtering settings from counter state
4407673Snate@binkert.org    type.evtCount = cs.eventId;
44110267SGeoffrey.Blake@arm.com
44210267SGeoffrey.Blake@arm.com    return type;
44310267SGeoffrey.Blake@arm.com}
44410267SGeoffrey.Blake@arm.com
44510458Sandreas.hansson@arm.comvoid
44610458Sandreas.hansson@arm.comPMU::setCounterTypeRegister(CounterId id, PMEVTYPER_t val)
44710458Sandreas.hansson@arm.com{
44810458Sandreas.hansson@arm.com    DPRINTF(PMUVerbose, "Set Event [%d] = 0x%08x\n", id, val);
44910458Sandreas.hansson@arm.com    if (!isValidCounter(id)) {
4504762Snate@binkert.org        warn_once("Can't change counter type: Counter %i does not exist.\n",
4514762Snate@binkert.org                  id);
4523101Sstever@eecs.umich.edu        return;
4533101Sstever@eecs.umich.edu    }
4543101Sstever@eecs.umich.edu
4553101Sstever@eecs.umich.edu    CounterState &ctr(getCounter(id));
4563101Sstever@eecs.umich.edu    // TODO: Handle filtering (both for general purpose counters and
4573101Sstever@eecs.umich.edu    // the cycle counter)
4583101Sstever@eecs.umich.edu
4593101Sstever@eecs.umich.edu    // If PMCCNTR Register, do not change event type. PMCCNTR can count
4603101Sstever@eecs.umich.edu    // processor cycles only.
4613101Sstever@eecs.umich.edu    if (id != PMCCNTR) {
4623101Sstever@eecs.umich.edu        ctr.eventId = val.evtCount;
4633714Sstever@eecs.umich.edu        updateCounter(reg_pmselr.sel, ctr);
4643714Sstever@eecs.umich.edu    }
4653714Sstever@eecs.umich.edu}
4663714Sstever@eecs.umich.edu
4673714Sstever@eecs.umich.eduvoid
4683714Sstever@eecs.umich.eduPMU::raiseInterrupt()
4693101Sstever@eecs.umich.edu{
4703101Sstever@eecs.umich.edu    RealView *rv(dynamic_cast<RealView *>(platform));
4713101Sstever@eecs.umich.edu    if (!rv || !rv->gic) {
4723101Sstever@eecs.umich.edu        warn_once("ARM PMU: GIC missing, can't raise interrupt.\n");
4733101Sstever@eecs.umich.edu        return;
4743101Sstever@eecs.umich.edu    }
4753101Sstever@eecs.umich.edu
4763101Sstever@eecs.umich.edu    DPRINTF(PMUVerbose, "Delivering PMU interrupt.\n");
4773101Sstever@eecs.umich.edu    rv->gic->sendInt(pmuInterrupt);
4783101Sstever@eecs.umich.edu}
4793101Sstever@eecs.umich.edu
4803101Sstever@eecs.umich.eduvoid
4813101Sstever@eecs.umich.eduPMU::serialize(std::ostream &os)
4823101Sstever@eecs.umich.edu{
4833101Sstever@eecs.umich.edu    DPRINTF(Checkpoint, "Serializing Arm PMU\n");
4843101Sstever@eecs.umich.edu
4853101Sstever@eecs.umich.edu    SERIALIZE_SCALAR(reg_pmcr);
4863101Sstever@eecs.umich.edu    SERIALIZE_SCALAR(reg_pmcnten);
4873101Sstever@eecs.umich.edu    SERIALIZE_SCALAR(reg_pmselr);
4883101Sstever@eecs.umich.edu    SERIALIZE_SCALAR(reg_pminten);
4893101Sstever@eecs.umich.edu    SERIALIZE_SCALAR(reg_pmovsr);
4903101Sstever@eecs.umich.edu    SERIALIZE_SCALAR(reg_pmceid);
4913101Sstever@eecs.umich.edu    SERIALIZE_SCALAR(clock_remainder);
4923101Sstever@eecs.umich.edu
49310380SAndrew.Bardsley@arm.com    for (size_t i = 0; i < counters.size(); ++i) {
49410380SAndrew.Bardsley@arm.com        nameOut(os, csprintf("%s.counters.%i", name(), i));
49510380SAndrew.Bardsley@arm.com        counters[i].serialize(os);
49610458Sandreas.hansson@arm.com    }
49710458Sandreas.hansson@arm.com
49810458Sandreas.hansson@arm.com    nameOut(os, csprintf("%s.cycleCounter", name()));
49910458Sandreas.hansson@arm.com    cycleCounter.serialize(os);
50010458Sandreas.hansson@arm.com}
50110458Sandreas.hansson@arm.com
50210458Sandreas.hansson@arm.comvoid
50310458Sandreas.hansson@arm.comPMU::unserialize(Checkpoint *cp, const std::string &section)
50410458Sandreas.hansson@arm.com{
50510458Sandreas.hansson@arm.com    DPRINTF(Checkpoint, "Unserializing Arm PMU\n");
50610458Sandreas.hansson@arm.com
50710458Sandreas.hansson@arm.com    UNSERIALIZE_SCALAR(reg_pmcr);
50810458Sandreas.hansson@arm.com    UNSERIALIZE_SCALAR(reg_pmcnten);
5093101Sstever@eecs.umich.edu    UNSERIALIZE_SCALAR(reg_pmselr);
5105033Smilesck@eecs.umich.edu    UNSERIALIZE_SCALAR(reg_pminten);
5113101Sstever@eecs.umich.edu    UNSERIALIZE_SCALAR(reg_pmovsr);
5123101Sstever@eecs.umich.edu    UNSERIALIZE_SCALAR(reg_pmceid);
5133101Sstever@eecs.umich.edu    UNSERIALIZE_SCALAR(clock_remainder);
5143101Sstever@eecs.umich.edu
5153101Sstever@eecs.umich.edu    for (size_t i = 0; i < counters.size(); ++i)
5163101Sstever@eecs.umich.edu        counters[i].unserialize(cp, csprintf("%s.counters.%i", section, i));
5173101Sstever@eecs.umich.edu
5183101Sstever@eecs.umich.edu    cycleCounter.unserialize(cp, csprintf("%s.cycleCounter", section));
5193101Sstever@eecs.umich.edu}
5203101Sstever@eecs.umich.edu
5213101Sstever@eecs.umich.eduvoid
5223101Sstever@eecs.umich.eduPMU::CounterState::serialize(std::ostream &os)
5235822Ssaidi@eecs.umich.edu{
5245822Ssaidi@eecs.umich.edu    SERIALIZE_SCALAR(eventId);
5253101Sstever@eecs.umich.edu    SERIALIZE_SCALAR(value);
5263101Sstever@eecs.umich.edu    SERIALIZE_SCALAR(enabled);
5273101Sstever@eecs.umich.edu    SERIALIZE_SCALAR(overflow64);
5283101Sstever@eecs.umich.edu}
5293101Sstever@eecs.umich.edu
5303101Sstever@eecs.umich.eduvoid
5313101Sstever@eecs.umich.eduPMU::CounterState::unserialize(Checkpoint *cp, const std::string &section)
5323101Sstever@eecs.umich.edu{
5333101Sstever@eecs.umich.edu    UNSERIALIZE_SCALAR(eventId);
5343101Sstever@eecs.umich.edu    UNSERIALIZE_SCALAR(value);
5353101Sstever@eecs.umich.edu    UNSERIALIZE_SCALAR(enabled);
5363101Sstever@eecs.umich.edu    UNSERIALIZE_SCALAR(overflow64);
5373101Sstever@eecs.umich.edu}
53810267SGeoffrey.Blake@arm.com
5393101Sstever@eecs.umich.edubool
5403101Sstever@eecs.umich.eduPMU::CounterState::add(uint64_t delta)
5413101Sstever@eecs.umich.edu{
5423101Sstever@eecs.umich.edu    const uint64_t msb(1ULL << (overflow64 ? 63 : 31));
5433101Sstever@eecs.umich.edu    const uint64_t old_value(value);
5443101Sstever@eecs.umich.edu
5453101Sstever@eecs.umich.edu    assert(delta > 0);
5463101Sstever@eecs.umich.edu
5473102Sstever@eecs.umich.edu    value += delta;
5483714Sstever@eecs.umich.edu
5493101Sstever@eecs.umich.edu    // Overflow if the msb goes from 1 to 0
5503714Sstever@eecs.umich.edu    return (old_value & msb) && !(value & msb);
5513714Sstever@eecs.umich.edu}
5523714Sstever@eecs.umich.edu
5533101Sstever@eecs.umich.edu} // namespace ArmISA
5543101Sstever@eecs.umich.edu
55510267SGeoffrey.Blake@arm.comArmISA::PMU *
55610267SGeoffrey.Blake@arm.comArmPMUParams::create()
55710267SGeoffrey.Blake@arm.com{
55810267SGeoffrey.Blake@arm.com    return new ArmISA::PMU(this);
5597673Snate@binkert.org}
5607673Snate@binkert.org