pmu.cc revision 12042
110461SAndreas.Sandberg@ARM.com/* 210461SAndreas.Sandberg@ARM.com * Copyright (c) 2011-2014 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 4010461SAndreas.Sandberg@ARM.com */ 4110461SAndreas.Sandberg@ARM.com 4210461SAndreas.Sandberg@ARM.com#include "arch/arm/pmu.hh" 4310461SAndreas.Sandberg@ARM.com 4410609Sandreas.sandberg@arm.com#include "arch/arm/isa.hh" 4510609Sandreas.sandberg@arm.com#include "arch/arm/utility.hh" 4610461SAndreas.Sandberg@ARM.com#include "base/trace.hh" 4710461SAndreas.Sandberg@ARM.com#include "cpu/base.hh" 4810461SAndreas.Sandberg@ARM.com#include "debug/Checkpoint.hh" 4910461SAndreas.Sandberg@ARM.com#include "debug/PMUVerbose.hh" 5010461SAndreas.Sandberg@ARM.com#include "dev/arm/base_gic.hh" 5110461SAndreas.Sandberg@ARM.com#include "dev/arm/realview.hh" 5210461SAndreas.Sandberg@ARM.com#include "params/ArmPMU.hh" 5310461SAndreas.Sandberg@ARM.com 5410461SAndreas.Sandberg@ARM.comnamespace ArmISA { 5510461SAndreas.Sandberg@ARM.com 5610461SAndreas.Sandberg@ARM.comconst MiscReg PMU::reg_pmcr_wr_mask = 0x39; 5710461SAndreas.Sandberg@ARM.com 5810461SAndreas.Sandberg@ARM.comPMU::PMU(const ArmPMUParams *p) 5910461SAndreas.Sandberg@ARM.com : SimObject(p), BaseISADevice(), 6010461SAndreas.Sandberg@ARM.com reg_pmcnten(0), reg_pmcr(0), 6110461SAndreas.Sandberg@ARM.com reg_pmselr(0), reg_pminten(0), reg_pmovsr(0), 6210461SAndreas.Sandberg@ARM.com reg_pmceid(0), 6310461SAndreas.Sandberg@ARM.com clock_remainder(0), 6410461SAndreas.Sandberg@ARM.com counters(p->eventCounters), 6510461SAndreas.Sandberg@ARM.com reg_pmcr_conf(0), 6610461SAndreas.Sandberg@ARM.com pmuInterrupt(p->pmuInterrupt), 6710461SAndreas.Sandberg@ARM.com platform(p->platform) 6810461SAndreas.Sandberg@ARM.com{ 6910461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "Initializing the PMU.\n"); 7010461SAndreas.Sandberg@ARM.com 7110461SAndreas.Sandberg@ARM.com if (p->eventCounters > 31) { 7210461SAndreas.Sandberg@ARM.com fatal("The PMU can only accept 31 counters, %d counters requested.\n", 7310461SAndreas.Sandberg@ARM.com p->eventCounters); 7410461SAndreas.Sandberg@ARM.com } 7510461SAndreas.Sandberg@ARM.com 7610461SAndreas.Sandberg@ARM.com /* Setup the performance counter ID registers */ 7710461SAndreas.Sandberg@ARM.com reg_pmcr_conf.imp = 0x41; // ARM Ltd. 7810461SAndreas.Sandberg@ARM.com reg_pmcr_conf.idcode = 0x00; 7910461SAndreas.Sandberg@ARM.com reg_pmcr_conf.n = p->eventCounters; 8010461SAndreas.Sandberg@ARM.com 8110461SAndreas.Sandberg@ARM.com // Setup the hard-coded cycle counter, which is equivalent to 8210461SAndreas.Sandberg@ARM.com // architected counter event type 0x11. 8310461SAndreas.Sandberg@ARM.com cycleCounter.eventId = 0x11; 8410461SAndreas.Sandberg@ARM.com} 8510461SAndreas.Sandberg@ARM.com 8610461SAndreas.Sandberg@ARM.comPMU::~PMU() 8710461SAndreas.Sandberg@ARM.com{ 8810461SAndreas.Sandberg@ARM.com} 8910461SAndreas.Sandberg@ARM.com 9010461SAndreas.Sandberg@ARM.comvoid 9110461SAndreas.Sandberg@ARM.comPMU::addEventProbe(unsigned int id, SimObject *obj, const char *probe_name) 9210461SAndreas.Sandberg@ARM.com{ 9310461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "PMU: Adding event type '0x%x' as probe %s:%s\n", 9410461SAndreas.Sandberg@ARM.com id, obj->name(), probe_name); 9510461SAndreas.Sandberg@ARM.com pmuEventTypes.insert(std::make_pair(id, EventType(obj, probe_name))); 9610461SAndreas.Sandberg@ARM.com 9710461SAndreas.Sandberg@ARM.com // Flag the event as available in the PMCEID register if it is an 9810461SAndreas.Sandberg@ARM.com // architected event. 9910461SAndreas.Sandberg@ARM.com if (id < 0x40) 10010537Sandreas.hansson@arm.com reg_pmceid |= (ULL(1) << id); 10110461SAndreas.Sandberg@ARM.com} 10210461SAndreas.Sandberg@ARM.com 10310461SAndreas.Sandberg@ARM.comvoid 10410461SAndreas.Sandberg@ARM.comPMU::drainResume() 10510461SAndreas.Sandberg@ARM.com{ 10610461SAndreas.Sandberg@ARM.com // Re-attach enabled counters after a resume in case they changed. 10710461SAndreas.Sandberg@ARM.com updateAllCounters(); 10810461SAndreas.Sandberg@ARM.com} 10910461SAndreas.Sandberg@ARM.com 11010461SAndreas.Sandberg@ARM.comvoid 11110461SAndreas.Sandberg@ARM.comPMU::setMiscReg(int misc_reg, MiscReg val) 11210461SAndreas.Sandberg@ARM.com{ 11310461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "setMiscReg(%s, 0x%x)\n", 11410461SAndreas.Sandberg@ARM.com miscRegName[unflattenMiscReg(misc_reg)], val); 11510461SAndreas.Sandberg@ARM.com 11610461SAndreas.Sandberg@ARM.com switch (unflattenMiscReg(misc_reg)) { 11710461SAndreas.Sandberg@ARM.com case MISCREG_PMCR_EL0: 11810461SAndreas.Sandberg@ARM.com case MISCREG_PMCR: 11910461SAndreas.Sandberg@ARM.com setControlReg(val); 12010461SAndreas.Sandberg@ARM.com return; 12110461SAndreas.Sandberg@ARM.com 12210461SAndreas.Sandberg@ARM.com case MISCREG_PMCNTENSET_EL0: 12310461SAndreas.Sandberg@ARM.com case MISCREG_PMCNTENSET: 12410461SAndreas.Sandberg@ARM.com reg_pmcnten |= val; 12510461SAndreas.Sandberg@ARM.com updateAllCounters(); 12610461SAndreas.Sandberg@ARM.com return; 12710461SAndreas.Sandberg@ARM.com 12810461SAndreas.Sandberg@ARM.com case MISCREG_PMCNTENCLR_EL0: 12910461SAndreas.Sandberg@ARM.com case MISCREG_PMCNTENCLR: 13010461SAndreas.Sandberg@ARM.com reg_pmcnten &= ~val; 13110461SAndreas.Sandberg@ARM.com updateAllCounters(); 13210461SAndreas.Sandberg@ARM.com return; 13310461SAndreas.Sandberg@ARM.com 13410461SAndreas.Sandberg@ARM.com case MISCREG_PMOVSCLR_EL0: 13510461SAndreas.Sandberg@ARM.com case MISCREG_PMOVSR: 13610461SAndreas.Sandberg@ARM.com reg_pmovsr &= ~val; 13710461SAndreas.Sandberg@ARM.com return; 13810461SAndreas.Sandberg@ARM.com 13910461SAndreas.Sandberg@ARM.com case MISCREG_PMSWINC_EL0: 14010461SAndreas.Sandberg@ARM.com case MISCREG_PMSWINC: 14110461SAndreas.Sandberg@ARM.com for (int i = 0; i < counters.size(); ++i) { 14210461SAndreas.Sandberg@ARM.com CounterState &ctr(getCounter(i)); 14310461SAndreas.Sandberg@ARM.com if (ctr.enabled && (val & (1 << i))) 14410461SAndreas.Sandberg@ARM.com ++ctr.value; 14510461SAndreas.Sandberg@ARM.com } 14610461SAndreas.Sandberg@ARM.com break; 14710461SAndreas.Sandberg@ARM.com 14810461SAndreas.Sandberg@ARM.com case MISCREG_PMCCNTR_EL0: 14910461SAndreas.Sandberg@ARM.com case MISCREG_PMCCNTR: 15010461SAndreas.Sandberg@ARM.com cycleCounter.value = val; 15110461SAndreas.Sandberg@ARM.com return; 15210461SAndreas.Sandberg@ARM.com 15310461SAndreas.Sandberg@ARM.com case MISCREG_PMSELR_EL0: 15410461SAndreas.Sandberg@ARM.com case MISCREG_PMSELR: 15510461SAndreas.Sandberg@ARM.com reg_pmselr = val; 15610461SAndreas.Sandberg@ARM.com return; 15710461SAndreas.Sandberg@ARM.com 15810461SAndreas.Sandberg@ARM.com case MISCREG_PMCEID0_EL0: 15910461SAndreas.Sandberg@ARM.com case MISCREG_PMCEID0: 16010461SAndreas.Sandberg@ARM.com case MISCREG_PMCEID1_EL0: 16110461SAndreas.Sandberg@ARM.com case MISCREG_PMCEID1: 16210461SAndreas.Sandberg@ARM.com // Ignore writes 16310461SAndreas.Sandberg@ARM.com return; 16410461SAndreas.Sandberg@ARM.com 16510461SAndreas.Sandberg@ARM.com case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0: 16612042Sandreas.sandberg@arm.com setCounterTypeRegister(misc_reg - MISCREG_PMEVTYPER0_EL0, val); 16710461SAndreas.Sandberg@ARM.com return; 16810461SAndreas.Sandberg@ARM.com 16910461SAndreas.Sandberg@ARM.com case MISCREG_PMCCFILTR: 17010461SAndreas.Sandberg@ARM.com case MISCREG_PMCCFILTR_EL0: 17110461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "Setting PMCCFILTR: 0x%x\n", val); 17210461SAndreas.Sandberg@ARM.com setCounterTypeRegister(PMCCNTR, val); 17310461SAndreas.Sandberg@ARM.com return; 17410461SAndreas.Sandberg@ARM.com 17510461SAndreas.Sandberg@ARM.com case MISCREG_PMXEVTYPER_PMCCFILTR: 17610461SAndreas.Sandberg@ARM.com case MISCREG_PMXEVTYPER_EL0: 17710461SAndreas.Sandberg@ARM.com case MISCREG_PMXEVTYPER: 17810461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "Setting counter type: " 17910461SAndreas.Sandberg@ARM.com "[PMSELR: 0x%x, PMSELER.sel: 0x%x, EVTYPER: 0x%x]\n", 18010461SAndreas.Sandberg@ARM.com reg_pmselr, reg_pmselr.sel, val); 18110461SAndreas.Sandberg@ARM.com setCounterTypeRegister(reg_pmselr.sel, val); 18210461SAndreas.Sandberg@ARM.com return; 18310461SAndreas.Sandberg@ARM.com 18410461SAndreas.Sandberg@ARM.com case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0: 18510461SAndreas.Sandberg@ARM.com setCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0, val); 18610461SAndreas.Sandberg@ARM.com return; 18710461SAndreas.Sandberg@ARM.com 18810461SAndreas.Sandberg@ARM.com case MISCREG_PMXEVCNTR_EL0: 18910461SAndreas.Sandberg@ARM.com case MISCREG_PMXEVCNTR: 19010461SAndreas.Sandberg@ARM.com setCounterValue(reg_pmselr.sel, val); 19110461SAndreas.Sandberg@ARM.com return; 19210461SAndreas.Sandberg@ARM.com 19310461SAndreas.Sandberg@ARM.com case MISCREG_PMUSERENR_EL0: 19410461SAndreas.Sandberg@ARM.com case MISCREG_PMUSERENR: 19510461SAndreas.Sandberg@ARM.com // TODO 19610461SAndreas.Sandberg@ARM.com break; 19710461SAndreas.Sandberg@ARM.com 19810461SAndreas.Sandberg@ARM.com case MISCREG_PMINTENSET_EL1: 19910461SAndreas.Sandberg@ARM.com case MISCREG_PMINTENSET: 20010461SAndreas.Sandberg@ARM.com reg_pminten |= val; 20110461SAndreas.Sandberg@ARM.com return; 20210461SAndreas.Sandberg@ARM.com 20310461SAndreas.Sandberg@ARM.com case MISCREG_PMINTENCLR_EL1: 20410461SAndreas.Sandberg@ARM.com case MISCREG_PMINTENCLR: 20510461SAndreas.Sandberg@ARM.com reg_pminten &= ~val; 20610461SAndreas.Sandberg@ARM.com return; 20710461SAndreas.Sandberg@ARM.com 20810461SAndreas.Sandberg@ARM.com case MISCREG_PMOVSSET_EL0: 20910461SAndreas.Sandberg@ARM.com case MISCREG_PMOVSSET: 21010461SAndreas.Sandberg@ARM.com reg_pmovsr |= val; 21110461SAndreas.Sandberg@ARM.com return; 21210461SAndreas.Sandberg@ARM.com 21310461SAndreas.Sandberg@ARM.com default: 21410461SAndreas.Sandberg@ARM.com panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]); 21510461SAndreas.Sandberg@ARM.com } 21610461SAndreas.Sandberg@ARM.com 21710461SAndreas.Sandberg@ARM.com warn("Not doing anything for write to miscreg %s\n", 21810461SAndreas.Sandberg@ARM.com miscRegName[misc_reg]); 21910461SAndreas.Sandberg@ARM.com} 22010461SAndreas.Sandberg@ARM.com 22110461SAndreas.Sandberg@ARM.comMiscReg 22210461SAndreas.Sandberg@ARM.comPMU::readMiscReg(int misc_reg) 22310461SAndreas.Sandberg@ARM.com{ 22410461SAndreas.Sandberg@ARM.com MiscReg val(readMiscRegInt(misc_reg)); 22510461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "readMiscReg(%s): 0x%x\n", 22610461SAndreas.Sandberg@ARM.com miscRegName[unflattenMiscReg(misc_reg)], val); 22710461SAndreas.Sandberg@ARM.com return val; 22810461SAndreas.Sandberg@ARM.com} 22910461SAndreas.Sandberg@ARM.com 23010461SAndreas.Sandberg@ARM.comMiscReg 23110461SAndreas.Sandberg@ARM.comPMU::readMiscRegInt(int misc_reg) 23210461SAndreas.Sandberg@ARM.com{ 23310461SAndreas.Sandberg@ARM.com misc_reg = unflattenMiscReg(misc_reg); 23410461SAndreas.Sandberg@ARM.com switch (misc_reg) { 23510461SAndreas.Sandberg@ARM.com case MISCREG_PMCR_EL0: 23610461SAndreas.Sandberg@ARM.com case MISCREG_PMCR: 23710461SAndreas.Sandberg@ARM.com return reg_pmcr_conf | (reg_pmcr & reg_pmcr_wr_mask); 23810461SAndreas.Sandberg@ARM.com 23910461SAndreas.Sandberg@ARM.com case MISCREG_PMCNTENSET_EL0: 24010461SAndreas.Sandberg@ARM.com case MISCREG_PMCNTENCLR_EL0: 24110461SAndreas.Sandberg@ARM.com case MISCREG_PMCNTENSET: 24210461SAndreas.Sandberg@ARM.com case MISCREG_PMCNTENCLR: 24310461SAndreas.Sandberg@ARM.com return reg_pmcnten; 24410461SAndreas.Sandberg@ARM.com 24510461SAndreas.Sandberg@ARM.com case MISCREG_PMOVSCLR_EL0: 24610461SAndreas.Sandberg@ARM.com case MISCREG_PMOVSSET_EL0: 24710461SAndreas.Sandberg@ARM.com case MISCREG_PMOVSR: // Overflow Status Register 24810461SAndreas.Sandberg@ARM.com case MISCREG_PMOVSSET: 24910461SAndreas.Sandberg@ARM.com return reg_pmovsr; 25010461SAndreas.Sandberg@ARM.com 25110461SAndreas.Sandberg@ARM.com case MISCREG_PMSWINC_EL0: 25210461SAndreas.Sandberg@ARM.com case MISCREG_PMSWINC: // Software Increment Register (RAZ) 25310461SAndreas.Sandberg@ARM.com return 0; 25410461SAndreas.Sandberg@ARM.com 25510461SAndreas.Sandberg@ARM.com case MISCREG_PMSELR: 25610461SAndreas.Sandberg@ARM.com return reg_pmselr; 25710461SAndreas.Sandberg@ARM.com 25810461SAndreas.Sandberg@ARM.com case MISCREG_PMCEID0_EL0: 25910461SAndreas.Sandberg@ARM.com case MISCREG_PMCEID0: // Common Event ID register 26010461SAndreas.Sandberg@ARM.com return reg_pmceid & 0xFFFFFFFF; 26110461SAndreas.Sandberg@ARM.com 26210461SAndreas.Sandberg@ARM.com case MISCREG_PMCEID1_EL0: 26310461SAndreas.Sandberg@ARM.com case MISCREG_PMCEID1: // Common Event ID register 26410461SAndreas.Sandberg@ARM.com return (reg_pmceid >> 32) & 0xFFFFFFFF; 26510461SAndreas.Sandberg@ARM.com 26610461SAndreas.Sandberg@ARM.com case MISCREG_PMCCNTR_EL0: 26710461SAndreas.Sandberg@ARM.com return cycleCounter.value; 26810461SAndreas.Sandberg@ARM.com 26910461SAndreas.Sandberg@ARM.com case MISCREG_PMCCNTR: 27010461SAndreas.Sandberg@ARM.com return cycleCounter.value & 0xFFFFFFFF; 27110461SAndreas.Sandberg@ARM.com 27210461SAndreas.Sandberg@ARM.com case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0: 27310461SAndreas.Sandberg@ARM.com return getCounterTypeRegister(misc_reg - MISCREG_PMEVTYPER0_EL0); 27410461SAndreas.Sandberg@ARM.com 27510461SAndreas.Sandberg@ARM.com case MISCREG_PMCCFILTR: 27610461SAndreas.Sandberg@ARM.com case MISCREG_PMCCFILTR_EL0: 27710461SAndreas.Sandberg@ARM.com return getCounterTypeRegister(PMCCNTR); 27810461SAndreas.Sandberg@ARM.com 27910461SAndreas.Sandberg@ARM.com case MISCREG_PMXEVTYPER_PMCCFILTR: 28010461SAndreas.Sandberg@ARM.com case MISCREG_PMXEVTYPER_EL0: 28110461SAndreas.Sandberg@ARM.com case MISCREG_PMXEVTYPER: 28210461SAndreas.Sandberg@ARM.com return getCounterTypeRegister(reg_pmselr.sel); 28310461SAndreas.Sandberg@ARM.com 28410461SAndreas.Sandberg@ARM.com case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0: 28510461SAndreas.Sandberg@ARM.com return getCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0) & 0xFFFFFFFF; 28610461SAndreas.Sandberg@ARM.com 28710461SAndreas.Sandberg@ARM.com case MISCREG_PMXEVCNTR_EL0: 28810461SAndreas.Sandberg@ARM.com case MISCREG_PMXEVCNTR: 28910461SAndreas.Sandberg@ARM.com return getCounterValue(reg_pmselr.sel) & 0xFFFFFFFF; 29010461SAndreas.Sandberg@ARM.com 29110461SAndreas.Sandberg@ARM.com case MISCREG_PMUSERENR_EL0: 29210461SAndreas.Sandberg@ARM.com case MISCREG_PMUSERENR: 29310461SAndreas.Sandberg@ARM.com // TODO 29410461SAndreas.Sandberg@ARM.com return 0; 29510461SAndreas.Sandberg@ARM.com 29610461SAndreas.Sandberg@ARM.com case MISCREG_PMINTENSET_EL1: 29710461SAndreas.Sandberg@ARM.com case MISCREG_PMINTENCLR_EL1: 29810461SAndreas.Sandberg@ARM.com case MISCREG_PMINTENSET: 29910461SAndreas.Sandberg@ARM.com case MISCREG_PMINTENCLR: 30010461SAndreas.Sandberg@ARM.com return reg_pminten; 30110461SAndreas.Sandberg@ARM.com 30210461SAndreas.Sandberg@ARM.com default: 30310461SAndreas.Sandberg@ARM.com panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]); 30410461SAndreas.Sandberg@ARM.com } 30510461SAndreas.Sandberg@ARM.com 30610461SAndreas.Sandberg@ARM.com warn("Not doing anything for read from miscreg %s\n", 30710461SAndreas.Sandberg@ARM.com miscRegName[misc_reg]); 30810461SAndreas.Sandberg@ARM.com return 0; 30910461SAndreas.Sandberg@ARM.com} 31010461SAndreas.Sandberg@ARM.com 31110461SAndreas.Sandberg@ARM.comvoid 31210461SAndreas.Sandberg@ARM.comPMU::setControlReg(PMCR_t val) 31310461SAndreas.Sandberg@ARM.com{ 31410461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "Set Control Reg 0x%08x.\n", val); 31510461SAndreas.Sandberg@ARM.com 31610461SAndreas.Sandberg@ARM.com if (val.p) { 31710461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "PMU reset all events to zero.\n"); 31810461SAndreas.Sandberg@ARM.com resetEventCounts(); 31910461SAndreas.Sandberg@ARM.com } 32010461SAndreas.Sandberg@ARM.com 32110461SAndreas.Sandberg@ARM.com if (val.c) { 32210461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "PMU reset cycle counter to zero.\n"); 32310461SAndreas.Sandberg@ARM.com cycleCounter.value = 0; 32410461SAndreas.Sandberg@ARM.com } 32510461SAndreas.Sandberg@ARM.com 32610461SAndreas.Sandberg@ARM.com // Reset the clock remainder if divide by 64-mode is toggled. 32710461SAndreas.Sandberg@ARM.com if (reg_pmcr.d != val.d) 32810461SAndreas.Sandberg@ARM.com clock_remainder = 0; 32910461SAndreas.Sandberg@ARM.com 33010461SAndreas.Sandberg@ARM.com reg_pmcr = val & reg_pmcr_wr_mask; 33110461SAndreas.Sandberg@ARM.com updateAllCounters(); 33210461SAndreas.Sandberg@ARM.com} 33310461SAndreas.Sandberg@ARM.com 33410461SAndreas.Sandberg@ARM.comvoid 33510461SAndreas.Sandberg@ARM.comPMU::updateAllCounters() 33610461SAndreas.Sandberg@ARM.com{ 33710461SAndreas.Sandberg@ARM.com const bool global_enable(reg_pmcr.e); 33810461SAndreas.Sandberg@ARM.com 33910461SAndreas.Sandberg@ARM.com for (int i = 0; i < counters.size(); ++i) { 34010461SAndreas.Sandberg@ARM.com CounterState &ctr(counters[i]); 34110461SAndreas.Sandberg@ARM.com const bool enable(global_enable && (reg_pmcnten & (1 << i))); 34210461SAndreas.Sandberg@ARM.com if (ctr.enabled != enable) { 34310461SAndreas.Sandberg@ARM.com ctr.enabled = enable; 34410461SAndreas.Sandberg@ARM.com updateCounter(i, ctr); 34510461SAndreas.Sandberg@ARM.com } 34610461SAndreas.Sandberg@ARM.com } 34710461SAndreas.Sandberg@ARM.com 34810461SAndreas.Sandberg@ARM.com const bool ccntr_enable(global_enable && (reg_pmcnten & (1 << PMCCNTR))); 34910461SAndreas.Sandberg@ARM.com if (cycleCounter.enabled != ccntr_enable) { 35010461SAndreas.Sandberg@ARM.com cycleCounter.enabled = ccntr_enable; 35110461SAndreas.Sandberg@ARM.com updateCounter(PMCCNTR, cycleCounter); 35210461SAndreas.Sandberg@ARM.com } 35310461SAndreas.Sandberg@ARM.com} 35410461SAndreas.Sandberg@ARM.com 35510609Sandreas.sandberg@arm.combool 35610609Sandreas.sandberg@arm.comPMU::isFiltered(const CounterState &ctr) const 35710609Sandreas.sandberg@arm.com{ 35810609Sandreas.sandberg@arm.com assert(isa); 35910609Sandreas.sandberg@arm.com 36010609Sandreas.sandberg@arm.com const PMEVTYPER_t filter(ctr.filter); 36110609Sandreas.sandberg@arm.com const SCR scr(isa->readMiscRegNoEffect(MISCREG_SCR)); 36210609Sandreas.sandberg@arm.com const CPSR cpsr(isa->readMiscRegNoEffect(MISCREG_CPSR)); 36310609Sandreas.sandberg@arm.com const ExceptionLevel el(opModeToEL((OperatingMode)(uint8_t)cpsr.mode)); 36410609Sandreas.sandberg@arm.com const bool secure(inSecureState(scr, cpsr)); 36510609Sandreas.sandberg@arm.com 36610609Sandreas.sandberg@arm.com switch (el) { 36710609Sandreas.sandberg@arm.com case EL0: 36810609Sandreas.sandberg@arm.com return secure ? filter.u : (filter.u != filter.nsu); 36910609Sandreas.sandberg@arm.com 37010609Sandreas.sandberg@arm.com case EL1: 37110609Sandreas.sandberg@arm.com return secure ? filter.p : (filter.p != filter.nsk); 37210609Sandreas.sandberg@arm.com 37310609Sandreas.sandberg@arm.com case EL2: 37410609Sandreas.sandberg@arm.com return !filter.nsh; 37510609Sandreas.sandberg@arm.com 37610609Sandreas.sandberg@arm.com case EL3: 37710609Sandreas.sandberg@arm.com return filter.p != filter.m; 37810609Sandreas.sandberg@arm.com 37910609Sandreas.sandberg@arm.com default: 38010609Sandreas.sandberg@arm.com panic("Unexpected execution level in PMU::isFiltered.\n"); 38110609Sandreas.sandberg@arm.com } 38210609Sandreas.sandberg@arm.com} 38310609Sandreas.sandberg@arm.com 38410461SAndreas.Sandberg@ARM.comvoid 38510461SAndreas.Sandberg@ARM.comPMU::handleEvent(CounterId id, uint64_t delta) 38610461SAndreas.Sandberg@ARM.com{ 38710461SAndreas.Sandberg@ARM.com CounterState &ctr(getCounter(id)); 38810461SAndreas.Sandberg@ARM.com const bool overflowed(reg_pmovsr & (1 << id)); 38910461SAndreas.Sandberg@ARM.com 39010609Sandreas.sandberg@arm.com if (isFiltered(ctr)) 39110609Sandreas.sandberg@arm.com return; 39210609Sandreas.sandberg@arm.com 39310461SAndreas.Sandberg@ARM.com // Handle the "count every 64 cycles" mode 39410461SAndreas.Sandberg@ARM.com if (id == PMCCNTR && reg_pmcr.d) { 39510461SAndreas.Sandberg@ARM.com clock_remainder += delta; 39610461SAndreas.Sandberg@ARM.com delta = (clock_remainder >> 6); 39710461SAndreas.Sandberg@ARM.com clock_remainder &= 63; 39810461SAndreas.Sandberg@ARM.com } 39910461SAndreas.Sandberg@ARM.com 40010461SAndreas.Sandberg@ARM.com // Add delta and handle (new) overflows 40110461SAndreas.Sandberg@ARM.com if (ctr.add(delta) && !overflowed) { 40210461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "PMU counter '%i' overflowed.\n", id); 40310461SAndreas.Sandberg@ARM.com reg_pmovsr |= (1 << id); 40410461SAndreas.Sandberg@ARM.com // Deliver a PMU interrupt if interrupt delivery is enabled 40510461SAndreas.Sandberg@ARM.com // for this counter. 40610461SAndreas.Sandberg@ARM.com if (reg_pminten & (1 << id)) 40710461SAndreas.Sandberg@ARM.com raiseInterrupt(); 40810461SAndreas.Sandberg@ARM.com } 40910461SAndreas.Sandberg@ARM.com} 41010461SAndreas.Sandberg@ARM.com 41110461SAndreas.Sandberg@ARM.comvoid 41210461SAndreas.Sandberg@ARM.comPMU::updateCounter(CounterId id, CounterState &ctr) 41310461SAndreas.Sandberg@ARM.com{ 41410461SAndreas.Sandberg@ARM.com if (!ctr.enabled) { 41510461SAndreas.Sandberg@ARM.com if (!ctr.listeners.empty()) { 41610461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "updateCounter(%i): Disabling counter\n", id); 41710461SAndreas.Sandberg@ARM.com ctr.listeners.clear(); 41810461SAndreas.Sandberg@ARM.com } 41910461SAndreas.Sandberg@ARM.com } else { 42010461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "updateCounter(%i): Enable event id 0x%x\n", 42110461SAndreas.Sandberg@ARM.com id, ctr.eventId); 42210461SAndreas.Sandberg@ARM.com 42310461SAndreas.Sandberg@ARM.com // Attach all probes belonging to this event 42410461SAndreas.Sandberg@ARM.com auto range(pmuEventTypes.equal_range(ctr.eventId)); 42510461SAndreas.Sandberg@ARM.com for (auto it = range.first; it != range.second; ++it) { 42610461SAndreas.Sandberg@ARM.com const EventType &et(it->second); 42710461SAndreas.Sandberg@ARM.com 42810461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "\tProbe: %s:%s\n", et.obj->name(), et.name); 42910461SAndreas.Sandberg@ARM.com ctr.listeners.emplace_back(et.create(*this, id)); 43010461SAndreas.Sandberg@ARM.com } 43110461SAndreas.Sandberg@ARM.com 43210461SAndreas.Sandberg@ARM.com /* The SW_INCR event type is a special case which doesn't need 43310461SAndreas.Sandberg@ARM.com * any probes since it is controlled by software and the PMU 43410461SAndreas.Sandberg@ARM.com * itself. 43510461SAndreas.Sandberg@ARM.com */ 43610461SAndreas.Sandberg@ARM.com if (ctr.listeners.empty() && ctr.eventId != ARCH_EVENT_SW_INCR) { 43710461SAndreas.Sandberg@ARM.com warn("Can't enable PMU counter of type '0x%x': " 43810461SAndreas.Sandberg@ARM.com "No such event type.\n", ctr.eventId); 43910461SAndreas.Sandberg@ARM.com } 44010461SAndreas.Sandberg@ARM.com } 44110461SAndreas.Sandberg@ARM.com} 44210461SAndreas.Sandberg@ARM.com 44310461SAndreas.Sandberg@ARM.com 44410461SAndreas.Sandberg@ARM.comvoid 44510461SAndreas.Sandberg@ARM.comPMU::resetEventCounts() 44610461SAndreas.Sandberg@ARM.com{ 44710461SAndreas.Sandberg@ARM.com for (CounterState &ctr : counters) 44810461SAndreas.Sandberg@ARM.com ctr.value = 0; 44910461SAndreas.Sandberg@ARM.com} 45010461SAndreas.Sandberg@ARM.com 45110461SAndreas.Sandberg@ARM.comvoid 45210461SAndreas.Sandberg@ARM.comPMU::setCounterValue(CounterId id, uint64_t val) 45310461SAndreas.Sandberg@ARM.com{ 45410461SAndreas.Sandberg@ARM.com if (!isValidCounter(id)) { 45510461SAndreas.Sandberg@ARM.com warn_once("Can't change counter value: Counter %i does not exist.\n", 45610461SAndreas.Sandberg@ARM.com id); 45710461SAndreas.Sandberg@ARM.com return; 45810461SAndreas.Sandberg@ARM.com } 45910461SAndreas.Sandberg@ARM.com 46010461SAndreas.Sandberg@ARM.com CounterState &ctr(getCounter(id)); 46110461SAndreas.Sandberg@ARM.com ctr.value = val; 46210461SAndreas.Sandberg@ARM.com} 46310461SAndreas.Sandberg@ARM.com 46410461SAndreas.Sandberg@ARM.comPMU::PMEVTYPER_t 46510461SAndreas.Sandberg@ARM.comPMU::getCounterTypeRegister(CounterId id) const 46610461SAndreas.Sandberg@ARM.com{ 46710461SAndreas.Sandberg@ARM.com if (!isValidCounter(id)) 46810461SAndreas.Sandberg@ARM.com return 0; 46910461SAndreas.Sandberg@ARM.com 47010461SAndreas.Sandberg@ARM.com const CounterState &cs(getCounter(id)); 47110609Sandreas.sandberg@arm.com PMEVTYPER_t type(cs.filter); 47210461SAndreas.Sandberg@ARM.com 47310461SAndreas.Sandberg@ARM.com type.evtCount = cs.eventId; 47410461SAndreas.Sandberg@ARM.com 47510461SAndreas.Sandberg@ARM.com return type; 47610461SAndreas.Sandberg@ARM.com} 47710461SAndreas.Sandberg@ARM.com 47810461SAndreas.Sandberg@ARM.comvoid 47910461SAndreas.Sandberg@ARM.comPMU::setCounterTypeRegister(CounterId id, PMEVTYPER_t val) 48010461SAndreas.Sandberg@ARM.com{ 48110461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "Set Event [%d] = 0x%08x\n", id, val); 48210461SAndreas.Sandberg@ARM.com if (!isValidCounter(id)) { 48310461SAndreas.Sandberg@ARM.com warn_once("Can't change counter type: Counter %i does not exist.\n", 48410461SAndreas.Sandberg@ARM.com id); 48510461SAndreas.Sandberg@ARM.com return; 48610461SAndreas.Sandberg@ARM.com } 48710461SAndreas.Sandberg@ARM.com 48810461SAndreas.Sandberg@ARM.com CounterState &ctr(getCounter(id)); 48910609Sandreas.sandberg@arm.com const EventTypeId old_event_id(ctr.eventId); 49010461SAndreas.Sandberg@ARM.com 49110609Sandreas.sandberg@arm.com ctr.filter = val; 49210609Sandreas.sandberg@arm.com 49310609Sandreas.sandberg@arm.com // If PMCCNTR Register, do not change event type. PMCCNTR can 49410609Sandreas.sandberg@arm.com // count processor cycles only. If we change the event type, we 49510609Sandreas.sandberg@arm.com // need to update the probes the counter is using. 49610609Sandreas.sandberg@arm.com if (id != PMCCNTR && old_event_id != val.evtCount) { 49710461SAndreas.Sandberg@ARM.com ctr.eventId = val.evtCount; 49810461SAndreas.Sandberg@ARM.com updateCounter(reg_pmselr.sel, ctr); 49910461SAndreas.Sandberg@ARM.com } 50010461SAndreas.Sandberg@ARM.com} 50110461SAndreas.Sandberg@ARM.com 50210461SAndreas.Sandberg@ARM.comvoid 50310461SAndreas.Sandberg@ARM.comPMU::raiseInterrupt() 50410461SAndreas.Sandberg@ARM.com{ 50510461SAndreas.Sandberg@ARM.com RealView *rv(dynamic_cast<RealView *>(platform)); 50610461SAndreas.Sandberg@ARM.com if (!rv || !rv->gic) { 50710461SAndreas.Sandberg@ARM.com warn_once("ARM PMU: GIC missing, can't raise interrupt.\n"); 50810461SAndreas.Sandberg@ARM.com return; 50910461SAndreas.Sandberg@ARM.com } 51010461SAndreas.Sandberg@ARM.com 51110461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "Delivering PMU interrupt.\n"); 51210461SAndreas.Sandberg@ARM.com rv->gic->sendInt(pmuInterrupt); 51310461SAndreas.Sandberg@ARM.com} 51410461SAndreas.Sandberg@ARM.com 51510461SAndreas.Sandberg@ARM.comvoid 51610905Sandreas.sandberg@arm.comPMU::serialize(CheckpointOut &cp) const 51710461SAndreas.Sandberg@ARM.com{ 51810461SAndreas.Sandberg@ARM.com DPRINTF(Checkpoint, "Serializing Arm PMU\n"); 51910461SAndreas.Sandberg@ARM.com 52010461SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(reg_pmcr); 52110461SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(reg_pmcnten); 52210461SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(reg_pmselr); 52310461SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(reg_pminten); 52410461SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(reg_pmovsr); 52510461SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(reg_pmceid); 52610461SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(clock_remainder); 52710461SAndreas.Sandberg@ARM.com 52810905Sandreas.sandberg@arm.com for (size_t i = 0; i < counters.size(); ++i) 52910905Sandreas.sandberg@arm.com counters[i].serializeSection(cp, csprintf("counters.%i", i)); 53010461SAndreas.Sandberg@ARM.com 53110905Sandreas.sandberg@arm.com cycleCounter.serializeSection(cp, "cycleCounter"); 53210461SAndreas.Sandberg@ARM.com} 53310461SAndreas.Sandberg@ARM.com 53410461SAndreas.Sandberg@ARM.comvoid 53510905Sandreas.sandberg@arm.comPMU::unserialize(CheckpointIn &cp) 53610461SAndreas.Sandberg@ARM.com{ 53710461SAndreas.Sandberg@ARM.com DPRINTF(Checkpoint, "Unserializing Arm PMU\n"); 53810461SAndreas.Sandberg@ARM.com 53910461SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(reg_pmcr); 54010461SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(reg_pmcnten); 54110461SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(reg_pmselr); 54210461SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(reg_pminten); 54310461SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(reg_pmovsr); 54410461SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(reg_pmceid); 54510461SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(clock_remainder); 54610461SAndreas.Sandberg@ARM.com 54710461SAndreas.Sandberg@ARM.com for (size_t i = 0; i < counters.size(); ++i) 54810905Sandreas.sandberg@arm.com counters[i].unserializeSection(cp, csprintf("counters.%i", i)); 54910461SAndreas.Sandberg@ARM.com 55010905Sandreas.sandberg@arm.com cycleCounter.unserializeSection(cp, "cycleCounter"); 55110461SAndreas.Sandberg@ARM.com} 55210461SAndreas.Sandberg@ARM.com 55310461SAndreas.Sandberg@ARM.comvoid 55410905Sandreas.sandberg@arm.comPMU::CounterState::serialize(CheckpointOut &cp) const 55510461SAndreas.Sandberg@ARM.com{ 55610461SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(eventId); 55710461SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(value); 55810461SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(enabled); 55910461SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(overflow64); 56010461SAndreas.Sandberg@ARM.com} 56110461SAndreas.Sandberg@ARM.com 56210461SAndreas.Sandberg@ARM.comvoid 56310905Sandreas.sandberg@arm.comPMU::CounterState::unserialize(CheckpointIn &cp) 56410461SAndreas.Sandberg@ARM.com{ 56510461SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(eventId); 56610461SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(value); 56710461SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(enabled); 56810461SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(overflow64); 56910461SAndreas.Sandberg@ARM.com} 57010461SAndreas.Sandberg@ARM.com 57110461SAndreas.Sandberg@ARM.combool 57210461SAndreas.Sandberg@ARM.comPMU::CounterState::add(uint64_t delta) 57310461SAndreas.Sandberg@ARM.com{ 57410461SAndreas.Sandberg@ARM.com const uint64_t msb(1ULL << (overflow64 ? 63 : 31)); 57510461SAndreas.Sandberg@ARM.com const uint64_t old_value(value); 57610461SAndreas.Sandberg@ARM.com 57710461SAndreas.Sandberg@ARM.com value += delta; 57810461SAndreas.Sandberg@ARM.com 57910461SAndreas.Sandberg@ARM.com // Overflow if the msb goes from 1 to 0 58010461SAndreas.Sandberg@ARM.com return (old_value & msb) && !(value & msb); 58110461SAndreas.Sandberg@ARM.com} 58210461SAndreas.Sandberg@ARM.com 58310461SAndreas.Sandberg@ARM.com} // namespace ArmISA 58410461SAndreas.Sandberg@ARM.com 58510461SAndreas.Sandberg@ARM.comArmISA::PMU * 58610461SAndreas.Sandberg@ARM.comArmPMUParams::create() 58710461SAndreas.Sandberg@ARM.com{ 58810461SAndreas.Sandberg@ARM.com return new ArmISA::PMU(this); 58910461SAndreas.Sandberg@ARM.com} 590