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