pmu.cc revision 13639
110461SAndreas.Sandberg@ARM.com/* 213637Sruben.ayrapetyan@arm.com * Copyright (c) 2011-2014, 2017-2019 ARM Limited 310461SAndreas.Sandberg@ARM.com * All rights reserved 410461SAndreas.Sandberg@ARM.com * 510461SAndreas.Sandberg@ARM.com * The license below extends only to copyright in the software and shall 610461SAndreas.Sandberg@ARM.com * not be construed as granting a license to any other intellectual 710461SAndreas.Sandberg@ARM.com * property including but not limited to intellectual property relating 810461SAndreas.Sandberg@ARM.com * to a hardware implementation of the functionality of the software 910461SAndreas.Sandberg@ARM.com * licensed hereunder. You may use the software subject to the license 1010461SAndreas.Sandberg@ARM.com * terms below provided that you ensure that this notice is replicated 1110461SAndreas.Sandberg@ARM.com * unmodified and in its entirety in all distributions of the software, 1210461SAndreas.Sandberg@ARM.com * modified or unmodified, in source code or in binary form. 1310461SAndreas.Sandberg@ARM.com * 1410461SAndreas.Sandberg@ARM.com * Redistribution and use in source and binary forms, with or without 1510461SAndreas.Sandberg@ARM.com * modification, are permitted provided that the following conditions are 1610461SAndreas.Sandberg@ARM.com * met: redistributions of source code must retain the above copyright 1710461SAndreas.Sandberg@ARM.com * notice, this list of conditions and the following disclaimer; 1810461SAndreas.Sandberg@ARM.com * redistributions in binary form must reproduce the above copyright 1910461SAndreas.Sandberg@ARM.com * notice, this list of conditions and the following disclaimer in the 2010461SAndreas.Sandberg@ARM.com * documentation and/or other materials provided with the distribution; 2110461SAndreas.Sandberg@ARM.com * neither the name of the copyright holders nor the names of its 2210461SAndreas.Sandberg@ARM.com * contributors may be used to endorse or promote products derived from 2310461SAndreas.Sandberg@ARM.com * this software without specific prior written permission. 2410461SAndreas.Sandberg@ARM.com * 2510461SAndreas.Sandberg@ARM.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2610461SAndreas.Sandberg@ARM.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2710461SAndreas.Sandberg@ARM.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 2810461SAndreas.Sandberg@ARM.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2910461SAndreas.Sandberg@ARM.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3010461SAndreas.Sandberg@ARM.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3110461SAndreas.Sandberg@ARM.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3210461SAndreas.Sandberg@ARM.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3310461SAndreas.Sandberg@ARM.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3410461SAndreas.Sandberg@ARM.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3510461SAndreas.Sandberg@ARM.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3610461SAndreas.Sandberg@ARM.com * 3710461SAndreas.Sandberg@ARM.com * Authors: Dam Sunwoo 3810461SAndreas.Sandberg@ARM.com * Matt Horsnell 3910461SAndreas.Sandberg@ARM.com * Andreas Sandberg 4012286Sjose.marinho@arm.com * Jose Marinho 4110461SAndreas.Sandberg@ARM.com */ 4210461SAndreas.Sandberg@ARM.com 4310461SAndreas.Sandberg@ARM.com#include "arch/arm/pmu.hh" 4410461SAndreas.Sandberg@ARM.com 4510609Sandreas.sandberg@arm.com#include "arch/arm/isa.hh" 4610609Sandreas.sandberg@arm.com#include "arch/arm/utility.hh" 4710461SAndreas.Sandberg@ARM.com#include "base/trace.hh" 4810461SAndreas.Sandberg@ARM.com#include "cpu/base.hh" 4910461SAndreas.Sandberg@ARM.com#include "debug/Checkpoint.hh" 5010461SAndreas.Sandberg@ARM.com#include "debug/PMUVerbose.hh" 5110461SAndreas.Sandberg@ARM.com#include "dev/arm/base_gic.hh" 5212286Sjose.marinho@arm.com#include "dev/arm/generic_timer.hh" 5310461SAndreas.Sandberg@ARM.com#include "params/ArmPMU.hh" 5410461SAndreas.Sandberg@ARM.com 5510461SAndreas.Sandberg@ARM.comnamespace ArmISA { 5610461SAndreas.Sandberg@ARM.com 5713581Sgabeblack@google.comconst RegVal PMU::reg_pmcr_wr_mask = 0x39; 5810461SAndreas.Sandberg@ARM.com 5910461SAndreas.Sandberg@ARM.comPMU::PMU(const ArmPMUParams *p) 6010461SAndreas.Sandberg@ARM.com : SimObject(p), BaseISADevice(), 6110461SAndreas.Sandberg@ARM.com reg_pmcnten(0), reg_pmcr(0), 6210461SAndreas.Sandberg@ARM.com reg_pmselr(0), reg_pminten(0), reg_pmovsr(0), 6312117Sjose.marinho@arm.com reg_pmceid0(0),reg_pmceid1(0), 6410461SAndreas.Sandberg@ARM.com clock_remainder(0), 6512286Sjose.marinho@arm.com maximumCounterCount(p->eventCounters), 6612286Sjose.marinho@arm.com cycleCounter(*this, maximumCounterCount), 6712286Sjose.marinho@arm.com cycleCounterEventId(p->cycleEventId), 6812286Sjose.marinho@arm.com swIncrementEvent(nullptr), 6910461SAndreas.Sandberg@ARM.com reg_pmcr_conf(0), 7013639Sgiacomo.travaglini@arm.com interrupt(nullptr) 7110461SAndreas.Sandberg@ARM.com{ 7210461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "Initializing the PMU.\n"); 7310461SAndreas.Sandberg@ARM.com 7412286Sjose.marinho@arm.com if (maximumCounterCount > 31) { 7510461SAndreas.Sandberg@ARM.com fatal("The PMU can only accept 31 counters, %d counters requested.\n", 7612286Sjose.marinho@arm.com maximumCounterCount); 7710461SAndreas.Sandberg@ARM.com } 7810461SAndreas.Sandberg@ARM.com 7913638Sgiacomo.travaglini@arm.com warn_if(!p->interrupt, "ARM PMU: No interrupt specified, interrupt " \ 8012973Sandreas.sandberg@arm.com "delivery disabled.\n"); 8112973Sandreas.sandberg@arm.com 8210461SAndreas.Sandberg@ARM.com /* Setup the performance counter ID registers */ 8310461SAndreas.Sandberg@ARM.com reg_pmcr_conf.imp = 0x41; // ARM Ltd. 8410461SAndreas.Sandberg@ARM.com reg_pmcr_conf.idcode = 0x00; 8510461SAndreas.Sandberg@ARM.com reg_pmcr_conf.n = p->eventCounters; 8610461SAndreas.Sandberg@ARM.com 8710461SAndreas.Sandberg@ARM.com // Setup the hard-coded cycle counter, which is equivalent to 8810461SAndreas.Sandberg@ARM.com // architected counter event type 0x11. 8910461SAndreas.Sandberg@ARM.com cycleCounter.eventId = 0x11; 9010461SAndreas.Sandberg@ARM.com} 9110461SAndreas.Sandberg@ARM.com 9210461SAndreas.Sandberg@ARM.comPMU::~PMU() 9310461SAndreas.Sandberg@ARM.com{ 9410461SAndreas.Sandberg@ARM.com} 9510461SAndreas.Sandberg@ARM.com 9610461SAndreas.Sandberg@ARM.comvoid 9712973Sandreas.sandberg@arm.comPMU::setThreadContext(ThreadContext *tc) 9812973Sandreas.sandberg@arm.com{ 9912973Sandreas.sandberg@arm.com DPRINTF(PMUVerbose, "Assigning PMU to ContextID %i.\n", tc->contextId()); 10013638Sgiacomo.travaglini@arm.com auto pmu_params = static_cast<const ArmPMUParams *>(params()); 10113638Sgiacomo.travaglini@arm.com 10213638Sgiacomo.travaglini@arm.com if (pmu_params->interrupt) 10313638Sgiacomo.travaglini@arm.com interrupt = pmu_params->interrupt->get(tc); 10412973Sandreas.sandberg@arm.com} 10512973Sandreas.sandberg@arm.com 10612973Sandreas.sandberg@arm.comvoid 10712286Sjose.marinho@arm.comPMU::addSoftwareIncrementEvent(unsigned int id) 10812286Sjose.marinho@arm.com{ 10912286Sjose.marinho@arm.com auto old_event = eventMap.find(id); 11012286Sjose.marinho@arm.com DPRINTF(PMUVerbose, "PMU: Adding SW increment event with id '0x%x'\n", id); 11112286Sjose.marinho@arm.com 11212286Sjose.marinho@arm.com if (swIncrementEvent) { 11312286Sjose.marinho@arm.com fatal_if(old_event == eventMap.end() || 11412286Sjose.marinho@arm.com old_event->second != swIncrementEvent, 11512286Sjose.marinho@arm.com "Trying to add a software increment event with multiple" 11612286Sjose.marinho@arm.com "IDs. This is not supported.\n"); 11712286Sjose.marinho@arm.com return; 11812286Sjose.marinho@arm.com } 11912286Sjose.marinho@arm.com 12012286Sjose.marinho@arm.com fatal_if(old_event != eventMap.end(), "An event with id %d has " 12112286Sjose.marinho@arm.com "been previously defined\n", id); 12212286Sjose.marinho@arm.com 12312286Sjose.marinho@arm.com swIncrementEvent = new SWIncrementEvent(); 12412286Sjose.marinho@arm.com eventMap[id] = swIncrementEvent; 12512286Sjose.marinho@arm.com registerEvent(id); 12612286Sjose.marinho@arm.com} 12712286Sjose.marinho@arm.com 12812286Sjose.marinho@arm.comvoid 12910461SAndreas.Sandberg@ARM.comPMU::addEventProbe(unsigned int id, SimObject *obj, const char *probe_name) 13010461SAndreas.Sandberg@ARM.com{ 13110461SAndreas.Sandberg@ARM.com 13212286Sjose.marinho@arm.com DPRINTF(PMUVerbose, "PMU: Adding Probe Driven event with id '0x%x'" 13312286Sjose.marinho@arm.com "as probe %s:%s\n",id, obj->name(), probe_name); 13412286Sjose.marinho@arm.com 13512286Sjose.marinho@arm.com RegularEvent *event = nullptr; 13612286Sjose.marinho@arm.com auto event_entry = eventMap.find(id); 13712286Sjose.marinho@arm.com if (event_entry == eventMap.end()) { 13812286Sjose.marinho@arm.com 13912286Sjose.marinho@arm.com event = new RegularEvent(); 14012286Sjose.marinho@arm.com eventMap[id] = event; 14112286Sjose.marinho@arm.com 14212286Sjose.marinho@arm.com } else { 14312286Sjose.marinho@arm.com event = dynamic_cast<RegularEvent*>(event_entry->second); 14412286Sjose.marinho@arm.com if (!event) { 14512286Sjose.marinho@arm.com fatal("Event with id %d is not probe driven\n", id); 14612286Sjose.marinho@arm.com } 14712286Sjose.marinho@arm.com } 14812286Sjose.marinho@arm.com event->addMicroarchitectureProbe(obj, probe_name); 14912286Sjose.marinho@arm.com 15012286Sjose.marinho@arm.com registerEvent(id); 15112286Sjose.marinho@arm.com 15212286Sjose.marinho@arm.com} 15312286Sjose.marinho@arm.com 15412286Sjose.marinho@arm.comvoid 15512286Sjose.marinho@arm.comPMU::registerEvent(uint32_t id) 15612286Sjose.marinho@arm.com{ 15712117Sjose.marinho@arm.com // Flag the event as available in the corresponding PMCEID register if it 15812117Sjose.marinho@arm.com // is an architected event. 15912117Sjose.marinho@arm.com if (id < 0x20) { 16012117Sjose.marinho@arm.com reg_pmceid0 |= ((uint64_t)1) << id; 16112117Sjose.marinho@arm.com } else if (id > 0x20 && id < 0x40) { 16212117Sjose.marinho@arm.com reg_pmceid1 |= ((uint64_t)1) << (id - 0x20); 16312117Sjose.marinho@arm.com } else if (id >= 0x4000 && id < 0x4020) { 16412117Sjose.marinho@arm.com reg_pmceid0 |= ((uint64_t)1) << (id - 0x4000 + 32); 16512117Sjose.marinho@arm.com } else if (id >= 0x4020 && id < 0x4040) { 16612117Sjose.marinho@arm.com reg_pmceid1 |= ((uint64_t)1) << (id - 0x4020 + 32); 16712117Sjose.marinho@arm.com } 16810461SAndreas.Sandberg@ARM.com} 16910461SAndreas.Sandberg@ARM.com 17010461SAndreas.Sandberg@ARM.comvoid 17110461SAndreas.Sandberg@ARM.comPMU::drainResume() 17210461SAndreas.Sandberg@ARM.com{ 17310461SAndreas.Sandberg@ARM.com // Re-attach enabled counters after a resume in case they changed. 17410461SAndreas.Sandberg@ARM.com updateAllCounters(); 17510461SAndreas.Sandberg@ARM.com} 17610461SAndreas.Sandberg@ARM.com 17710461SAndreas.Sandberg@ARM.comvoid 17812286Sjose.marinho@arm.comPMU::regProbeListeners() 17912286Sjose.marinho@arm.com{ 18012286Sjose.marinho@arm.com 18112286Sjose.marinho@arm.com // at this stage all probe configurations are done 18212286Sjose.marinho@arm.com // counters can be configured 18312286Sjose.marinho@arm.com for (uint32_t index = 0; index < maximumCounterCount-1; index++) { 18412286Sjose.marinho@arm.com counters.emplace_back(*this, index); 18512286Sjose.marinho@arm.com } 18612286Sjose.marinho@arm.com 18712286Sjose.marinho@arm.com PMUEvent *event = getEvent(cycleCounterEventId); 18812286Sjose.marinho@arm.com panic_if(!event, "core cycle event is not present\n"); 18912286Sjose.marinho@arm.com cycleCounter.enabled = true; 19012286Sjose.marinho@arm.com cycleCounter.attach(event); 19112286Sjose.marinho@arm.com} 19212286Sjose.marinho@arm.com 19312286Sjose.marinho@arm.comvoid 19413581Sgabeblack@google.comPMU::setMiscReg(int misc_reg, RegVal val) 19510461SAndreas.Sandberg@ARM.com{ 19610461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "setMiscReg(%s, 0x%x)\n", 19710461SAndreas.Sandberg@ARM.com miscRegName[unflattenMiscReg(misc_reg)], val); 19810461SAndreas.Sandberg@ARM.com 19910461SAndreas.Sandberg@ARM.com switch (unflattenMiscReg(misc_reg)) { 20010461SAndreas.Sandberg@ARM.com case MISCREG_PMCR_EL0: 20110461SAndreas.Sandberg@ARM.com case MISCREG_PMCR: 20210461SAndreas.Sandberg@ARM.com setControlReg(val); 20310461SAndreas.Sandberg@ARM.com return; 20410461SAndreas.Sandberg@ARM.com 20510461SAndreas.Sandberg@ARM.com case MISCREG_PMCNTENSET_EL0: 20610461SAndreas.Sandberg@ARM.com case MISCREG_PMCNTENSET: 20710461SAndreas.Sandberg@ARM.com reg_pmcnten |= val; 20810461SAndreas.Sandberg@ARM.com updateAllCounters(); 20910461SAndreas.Sandberg@ARM.com return; 21010461SAndreas.Sandberg@ARM.com 21110461SAndreas.Sandberg@ARM.com case MISCREG_PMCNTENCLR_EL0: 21210461SAndreas.Sandberg@ARM.com case MISCREG_PMCNTENCLR: 21310461SAndreas.Sandberg@ARM.com reg_pmcnten &= ~val; 21410461SAndreas.Sandberg@ARM.com updateAllCounters(); 21510461SAndreas.Sandberg@ARM.com return; 21610461SAndreas.Sandberg@ARM.com 21710461SAndreas.Sandberg@ARM.com case MISCREG_PMOVSCLR_EL0: 21810461SAndreas.Sandberg@ARM.com case MISCREG_PMOVSR: 21913104Sgiacomo.travaglini@arm.com setOverflowStatus(reg_pmovsr & ~val); 22010461SAndreas.Sandberg@ARM.com return; 22110461SAndreas.Sandberg@ARM.com 22210461SAndreas.Sandberg@ARM.com case MISCREG_PMSWINC_EL0: 22310461SAndreas.Sandberg@ARM.com case MISCREG_PMSWINC: 22412286Sjose.marinho@arm.com if (swIncrementEvent) { 22512286Sjose.marinho@arm.com swIncrementEvent->write(val); 22610461SAndreas.Sandberg@ARM.com } 22712286Sjose.marinho@arm.com return; 22810461SAndreas.Sandberg@ARM.com 22910461SAndreas.Sandberg@ARM.com case MISCREG_PMCCNTR_EL0: 23010461SAndreas.Sandberg@ARM.com case MISCREG_PMCCNTR: 23112286Sjose.marinho@arm.com cycleCounter.setValue(val); 23210461SAndreas.Sandberg@ARM.com return; 23310461SAndreas.Sandberg@ARM.com 23410461SAndreas.Sandberg@ARM.com case MISCREG_PMSELR_EL0: 23510461SAndreas.Sandberg@ARM.com case MISCREG_PMSELR: 23610461SAndreas.Sandberg@ARM.com reg_pmselr = val; 23710461SAndreas.Sandberg@ARM.com return; 23812117Sjose.marinho@arm.com //TODO: implement MISCREF_PMCEID{2,3} 23910461SAndreas.Sandberg@ARM.com case MISCREG_PMCEID0_EL0: 24010461SAndreas.Sandberg@ARM.com case MISCREG_PMCEID0: 24110461SAndreas.Sandberg@ARM.com case MISCREG_PMCEID1_EL0: 24210461SAndreas.Sandberg@ARM.com case MISCREG_PMCEID1: 24310461SAndreas.Sandberg@ARM.com // Ignore writes 24410461SAndreas.Sandberg@ARM.com return; 24510461SAndreas.Sandberg@ARM.com 24610461SAndreas.Sandberg@ARM.com case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0: 24712042Sandreas.sandberg@arm.com setCounterTypeRegister(misc_reg - MISCREG_PMEVTYPER0_EL0, val); 24810461SAndreas.Sandberg@ARM.com return; 24910461SAndreas.Sandberg@ARM.com 25010461SAndreas.Sandberg@ARM.com case MISCREG_PMCCFILTR: 25110461SAndreas.Sandberg@ARM.com case MISCREG_PMCCFILTR_EL0: 25210461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "Setting PMCCFILTR: 0x%x\n", val); 25310461SAndreas.Sandberg@ARM.com setCounterTypeRegister(PMCCNTR, val); 25410461SAndreas.Sandberg@ARM.com return; 25510461SAndreas.Sandberg@ARM.com 25610461SAndreas.Sandberg@ARM.com case MISCREG_PMXEVTYPER_PMCCFILTR: 25710461SAndreas.Sandberg@ARM.com case MISCREG_PMXEVTYPER_EL0: 25810461SAndreas.Sandberg@ARM.com case MISCREG_PMXEVTYPER: 25910461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "Setting counter type: " 26010461SAndreas.Sandberg@ARM.com "[PMSELR: 0x%x, PMSELER.sel: 0x%x, EVTYPER: 0x%x]\n", 26110461SAndreas.Sandberg@ARM.com reg_pmselr, reg_pmselr.sel, val); 26210461SAndreas.Sandberg@ARM.com setCounterTypeRegister(reg_pmselr.sel, val); 26310461SAndreas.Sandberg@ARM.com return; 26410461SAndreas.Sandberg@ARM.com 26510461SAndreas.Sandberg@ARM.com case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0: 26610461SAndreas.Sandberg@ARM.com setCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0, val); 26710461SAndreas.Sandberg@ARM.com return; 26810461SAndreas.Sandberg@ARM.com 26910461SAndreas.Sandberg@ARM.com case MISCREG_PMXEVCNTR_EL0: 27010461SAndreas.Sandberg@ARM.com case MISCREG_PMXEVCNTR: 27110461SAndreas.Sandberg@ARM.com setCounterValue(reg_pmselr.sel, val); 27210461SAndreas.Sandberg@ARM.com return; 27310461SAndreas.Sandberg@ARM.com 27410461SAndreas.Sandberg@ARM.com case MISCREG_PMUSERENR_EL0: 27510461SAndreas.Sandberg@ARM.com case MISCREG_PMUSERENR: 27610461SAndreas.Sandberg@ARM.com // TODO 27710461SAndreas.Sandberg@ARM.com break; 27810461SAndreas.Sandberg@ARM.com 27910461SAndreas.Sandberg@ARM.com case MISCREG_PMINTENSET_EL1: 28010461SAndreas.Sandberg@ARM.com case MISCREG_PMINTENSET: 28110461SAndreas.Sandberg@ARM.com reg_pminten |= val; 28210461SAndreas.Sandberg@ARM.com return; 28310461SAndreas.Sandberg@ARM.com 28410461SAndreas.Sandberg@ARM.com case MISCREG_PMINTENCLR_EL1: 28510461SAndreas.Sandberg@ARM.com case MISCREG_PMINTENCLR: 28610461SAndreas.Sandberg@ARM.com reg_pminten &= ~val; 28710461SAndreas.Sandberg@ARM.com return; 28810461SAndreas.Sandberg@ARM.com 28910461SAndreas.Sandberg@ARM.com case MISCREG_PMOVSSET_EL0: 29010461SAndreas.Sandberg@ARM.com case MISCREG_PMOVSSET: 29113104Sgiacomo.travaglini@arm.com setOverflowStatus(reg_pmovsr | val); 29210461SAndreas.Sandberg@ARM.com return; 29310461SAndreas.Sandberg@ARM.com 29410461SAndreas.Sandberg@ARM.com default: 29510461SAndreas.Sandberg@ARM.com panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]); 29610461SAndreas.Sandberg@ARM.com } 29710461SAndreas.Sandberg@ARM.com 29810461SAndreas.Sandberg@ARM.com warn("Not doing anything for write to miscreg %s\n", 29910461SAndreas.Sandberg@ARM.com miscRegName[misc_reg]); 30010461SAndreas.Sandberg@ARM.com} 30110461SAndreas.Sandberg@ARM.com 30213581Sgabeblack@google.comRegVal 30310461SAndreas.Sandberg@ARM.comPMU::readMiscReg(int misc_reg) 30410461SAndreas.Sandberg@ARM.com{ 30513581Sgabeblack@google.com RegVal val(readMiscRegInt(misc_reg)); 30610461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "readMiscReg(%s): 0x%x\n", 30710461SAndreas.Sandberg@ARM.com miscRegName[unflattenMiscReg(misc_reg)], val); 30810461SAndreas.Sandberg@ARM.com return val; 30910461SAndreas.Sandberg@ARM.com} 31010461SAndreas.Sandberg@ARM.com 31113581Sgabeblack@google.comRegVal 31210461SAndreas.Sandberg@ARM.comPMU::readMiscRegInt(int misc_reg) 31310461SAndreas.Sandberg@ARM.com{ 31410461SAndreas.Sandberg@ARM.com misc_reg = unflattenMiscReg(misc_reg); 31510461SAndreas.Sandberg@ARM.com switch (misc_reg) { 31610461SAndreas.Sandberg@ARM.com case MISCREG_PMCR_EL0: 31710461SAndreas.Sandberg@ARM.com case MISCREG_PMCR: 31810461SAndreas.Sandberg@ARM.com return reg_pmcr_conf | (reg_pmcr & reg_pmcr_wr_mask); 31910461SAndreas.Sandberg@ARM.com 32010461SAndreas.Sandberg@ARM.com case MISCREG_PMCNTENSET_EL0: 32110461SAndreas.Sandberg@ARM.com case MISCREG_PMCNTENCLR_EL0: 32210461SAndreas.Sandberg@ARM.com case MISCREG_PMCNTENSET: 32310461SAndreas.Sandberg@ARM.com case MISCREG_PMCNTENCLR: 32410461SAndreas.Sandberg@ARM.com return reg_pmcnten; 32510461SAndreas.Sandberg@ARM.com 32610461SAndreas.Sandberg@ARM.com case MISCREG_PMOVSCLR_EL0: 32710461SAndreas.Sandberg@ARM.com case MISCREG_PMOVSSET_EL0: 32810461SAndreas.Sandberg@ARM.com case MISCREG_PMOVSR: // Overflow Status Register 32910461SAndreas.Sandberg@ARM.com case MISCREG_PMOVSSET: 33010461SAndreas.Sandberg@ARM.com return reg_pmovsr; 33110461SAndreas.Sandberg@ARM.com 33210461SAndreas.Sandberg@ARM.com case MISCREG_PMSWINC_EL0: 33310461SAndreas.Sandberg@ARM.com case MISCREG_PMSWINC: // Software Increment Register (RAZ) 33410461SAndreas.Sandberg@ARM.com return 0; 33510461SAndreas.Sandberg@ARM.com 33610461SAndreas.Sandberg@ARM.com case MISCREG_PMSELR: 33710461SAndreas.Sandberg@ARM.com return reg_pmselr; 33810461SAndreas.Sandberg@ARM.com 33910461SAndreas.Sandberg@ARM.com case MISCREG_PMCEID0_EL0: 34012117Sjose.marinho@arm.com return reg_pmceid0; 34110461SAndreas.Sandberg@ARM.com 34210461SAndreas.Sandberg@ARM.com case MISCREG_PMCEID1_EL0: 34312117Sjose.marinho@arm.com return reg_pmceid1; 34412117Sjose.marinho@arm.com 34512117Sjose.marinho@arm.com //TODO: implement MISCREF_PMCEID{2,3} 34612117Sjose.marinho@arm.com case MISCREG_PMCEID0: // Common Event ID register 34712117Sjose.marinho@arm.com return reg_pmceid0 & 0xFFFFFFFF; 34812117Sjose.marinho@arm.com 34910461SAndreas.Sandberg@ARM.com case MISCREG_PMCEID1: // Common Event ID register 35012117Sjose.marinho@arm.com return reg_pmceid1 & 0xFFFFFFFF; 35110461SAndreas.Sandberg@ARM.com 35210461SAndreas.Sandberg@ARM.com case MISCREG_PMCCNTR_EL0: 35312286Sjose.marinho@arm.com return cycleCounter.getValue(); 35410461SAndreas.Sandberg@ARM.com 35510461SAndreas.Sandberg@ARM.com case MISCREG_PMCCNTR: 35612286Sjose.marinho@arm.com return cycleCounter.getValue() & 0xFFFFFFFF; 35710461SAndreas.Sandberg@ARM.com 35810461SAndreas.Sandberg@ARM.com case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0: 35910461SAndreas.Sandberg@ARM.com return getCounterTypeRegister(misc_reg - MISCREG_PMEVTYPER0_EL0); 36010461SAndreas.Sandberg@ARM.com 36110461SAndreas.Sandberg@ARM.com case MISCREG_PMCCFILTR: 36210461SAndreas.Sandberg@ARM.com case MISCREG_PMCCFILTR_EL0: 36310461SAndreas.Sandberg@ARM.com return getCounterTypeRegister(PMCCNTR); 36410461SAndreas.Sandberg@ARM.com 36510461SAndreas.Sandberg@ARM.com case MISCREG_PMXEVTYPER_PMCCFILTR: 36610461SAndreas.Sandberg@ARM.com case MISCREG_PMXEVTYPER_EL0: 36710461SAndreas.Sandberg@ARM.com case MISCREG_PMXEVTYPER: 36810461SAndreas.Sandberg@ARM.com return getCounterTypeRegister(reg_pmselr.sel); 36910461SAndreas.Sandberg@ARM.com 37012286Sjose.marinho@arm.com case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0: { 37112286Sjose.marinho@arm.com return getCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0) & 37212286Sjose.marinho@arm.com 0xFFFFFFFF; 37312286Sjose.marinho@arm.com 37412286Sjose.marinho@arm.com } 37510461SAndreas.Sandberg@ARM.com 37610461SAndreas.Sandberg@ARM.com case MISCREG_PMXEVCNTR_EL0: 37710461SAndreas.Sandberg@ARM.com case MISCREG_PMXEVCNTR: 37810461SAndreas.Sandberg@ARM.com return getCounterValue(reg_pmselr.sel) & 0xFFFFFFFF; 37910461SAndreas.Sandberg@ARM.com 38010461SAndreas.Sandberg@ARM.com case MISCREG_PMUSERENR_EL0: 38110461SAndreas.Sandberg@ARM.com case MISCREG_PMUSERENR: 38210461SAndreas.Sandberg@ARM.com // TODO 38310461SAndreas.Sandberg@ARM.com return 0; 38410461SAndreas.Sandberg@ARM.com 38510461SAndreas.Sandberg@ARM.com case MISCREG_PMINTENSET_EL1: 38610461SAndreas.Sandberg@ARM.com case MISCREG_PMINTENCLR_EL1: 38710461SAndreas.Sandberg@ARM.com case MISCREG_PMINTENSET: 38810461SAndreas.Sandberg@ARM.com case MISCREG_PMINTENCLR: 38910461SAndreas.Sandberg@ARM.com return reg_pminten; 39010461SAndreas.Sandberg@ARM.com 39110461SAndreas.Sandberg@ARM.com default: 39210461SAndreas.Sandberg@ARM.com panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]); 39310461SAndreas.Sandberg@ARM.com } 39410461SAndreas.Sandberg@ARM.com 39510461SAndreas.Sandberg@ARM.com warn("Not doing anything for read from miscreg %s\n", 39610461SAndreas.Sandberg@ARM.com miscRegName[misc_reg]); 39710461SAndreas.Sandberg@ARM.com return 0; 39810461SAndreas.Sandberg@ARM.com} 39910461SAndreas.Sandberg@ARM.com 40010461SAndreas.Sandberg@ARM.comvoid 40110461SAndreas.Sandberg@ARM.comPMU::setControlReg(PMCR_t val) 40210461SAndreas.Sandberg@ARM.com{ 40310461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "Set Control Reg 0x%08x.\n", val); 40410461SAndreas.Sandberg@ARM.com 40510461SAndreas.Sandberg@ARM.com if (val.p) { 40610461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "PMU reset all events to zero.\n"); 40710461SAndreas.Sandberg@ARM.com resetEventCounts(); 40810461SAndreas.Sandberg@ARM.com } 40910461SAndreas.Sandberg@ARM.com 41010461SAndreas.Sandberg@ARM.com if (val.c) { 41110461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "PMU reset cycle counter to zero.\n"); 41212286Sjose.marinho@arm.com cycleCounter.setValue(0); 41310461SAndreas.Sandberg@ARM.com } 41410461SAndreas.Sandberg@ARM.com 41510461SAndreas.Sandberg@ARM.com // Reset the clock remainder if divide by 64-mode is toggled. 41610461SAndreas.Sandberg@ARM.com if (reg_pmcr.d != val.d) 41710461SAndreas.Sandberg@ARM.com clock_remainder = 0; 41810461SAndreas.Sandberg@ARM.com 41910461SAndreas.Sandberg@ARM.com reg_pmcr = val & reg_pmcr_wr_mask; 42010461SAndreas.Sandberg@ARM.com updateAllCounters(); 42110461SAndreas.Sandberg@ARM.com} 42210461SAndreas.Sandberg@ARM.com 42310461SAndreas.Sandberg@ARM.comvoid 42410461SAndreas.Sandberg@ARM.comPMU::updateAllCounters() 42510461SAndreas.Sandberg@ARM.com{ 42610461SAndreas.Sandberg@ARM.com const bool global_enable(reg_pmcr.e); 42710461SAndreas.Sandberg@ARM.com 42810461SAndreas.Sandberg@ARM.com for (int i = 0; i < counters.size(); ++i) { 42910461SAndreas.Sandberg@ARM.com CounterState &ctr(counters[i]); 43010461SAndreas.Sandberg@ARM.com const bool enable(global_enable && (reg_pmcnten & (1 << i))); 43110461SAndreas.Sandberg@ARM.com if (ctr.enabled != enable) { 43210461SAndreas.Sandberg@ARM.com ctr.enabled = enable; 43312286Sjose.marinho@arm.com updateCounter(ctr); 43410461SAndreas.Sandberg@ARM.com } 43510461SAndreas.Sandberg@ARM.com } 43610461SAndreas.Sandberg@ARM.com 43710461SAndreas.Sandberg@ARM.com const bool ccntr_enable(global_enable && (reg_pmcnten & (1 << PMCCNTR))); 43810461SAndreas.Sandberg@ARM.com if (cycleCounter.enabled != ccntr_enable) { 43910461SAndreas.Sandberg@ARM.com cycleCounter.enabled = ccntr_enable; 44012286Sjose.marinho@arm.com updateCounter(cycleCounter); 44110461SAndreas.Sandberg@ARM.com } 44210461SAndreas.Sandberg@ARM.com} 44310461SAndreas.Sandberg@ARM.com 44412286Sjose.marinho@arm.comvoid 44512286Sjose.marinho@arm.comPMU::PMUEvent::attachEvent(PMU::CounterState *user) 44612286Sjose.marinho@arm.com{ 44712286Sjose.marinho@arm.com if (userCounters.empty()) { 44812286Sjose.marinho@arm.com enable(); 44912286Sjose.marinho@arm.com } 45012286Sjose.marinho@arm.com userCounters.insert(user); 45112286Sjose.marinho@arm.com updateAttachedCounters(); 45212286Sjose.marinho@arm.com} 45312286Sjose.marinho@arm.com 45412286Sjose.marinho@arm.comvoid 45512286Sjose.marinho@arm.comPMU::PMUEvent::increment(const uint64_t val) 45612286Sjose.marinho@arm.com{ 45712286Sjose.marinho@arm.com for (auto& counter: userCounters) { 45812286Sjose.marinho@arm.com counter->add(val); 45912286Sjose.marinho@arm.com } 46012286Sjose.marinho@arm.com} 46112286Sjose.marinho@arm.com 46212286Sjose.marinho@arm.comvoid 46312286Sjose.marinho@arm.comPMU::PMUEvent::detachEvent(PMU::CounterState *user) 46412286Sjose.marinho@arm.com{ 46512286Sjose.marinho@arm.com userCounters.erase(user); 46612286Sjose.marinho@arm.com 46712286Sjose.marinho@arm.com if (userCounters.empty()) { 46812286Sjose.marinho@arm.com disable(); 46912286Sjose.marinho@arm.com } 47012286Sjose.marinho@arm.com} 47112286Sjose.marinho@arm.com 47212286Sjose.marinho@arm.comvoid 47312286Sjose.marinho@arm.comPMU::RegularEvent::RegularProbe::notify(const uint64_t &val) 47412286Sjose.marinho@arm.com{ 47512286Sjose.marinho@arm.com parentEvent->increment(val); 47612286Sjose.marinho@arm.com} 47712286Sjose.marinho@arm.com 47812286Sjose.marinho@arm.comvoid 47912286Sjose.marinho@arm.comPMU::RegularEvent::enable() 48012286Sjose.marinho@arm.com{ 48112286Sjose.marinho@arm.com for (auto& subEvents: microArchitectureEventSet) { 48212286Sjose.marinho@arm.com attachedProbePointList.emplace_back( 48312286Sjose.marinho@arm.com new RegularProbe(this, subEvents.first, subEvents.second)); 48412286Sjose.marinho@arm.com } 48512286Sjose.marinho@arm.com} 48612286Sjose.marinho@arm.com 48712286Sjose.marinho@arm.comvoid 48812286Sjose.marinho@arm.comPMU::RegularEvent::disable() 48912286Sjose.marinho@arm.com{ 49012286Sjose.marinho@arm.com attachedProbePointList.clear(); 49112286Sjose.marinho@arm.com} 49212286Sjose.marinho@arm.com 49310609Sandreas.sandberg@arm.combool 49412286Sjose.marinho@arm.comPMU::CounterState::isFiltered() const 49510609Sandreas.sandberg@arm.com{ 49612286Sjose.marinho@arm.com assert(pmu.isa); 49710609Sandreas.sandberg@arm.com 49812286Sjose.marinho@arm.com const PMEVTYPER_t filter(this->filter); 49912286Sjose.marinho@arm.com const SCR scr(pmu.isa->readMiscRegNoEffect(MISCREG_SCR)); 50012286Sjose.marinho@arm.com const CPSR cpsr(pmu.isa->readMiscRegNoEffect(MISCREG_CPSR)); 50110609Sandreas.sandberg@arm.com const ExceptionLevel el(opModeToEL((OperatingMode)(uint8_t)cpsr.mode)); 50210609Sandreas.sandberg@arm.com const bool secure(inSecureState(scr, cpsr)); 50310609Sandreas.sandberg@arm.com 50410609Sandreas.sandberg@arm.com switch (el) { 50510609Sandreas.sandberg@arm.com case EL0: 50610609Sandreas.sandberg@arm.com return secure ? filter.u : (filter.u != filter.nsu); 50710609Sandreas.sandberg@arm.com 50810609Sandreas.sandberg@arm.com case EL1: 50910609Sandreas.sandberg@arm.com return secure ? filter.p : (filter.p != filter.nsk); 51010609Sandreas.sandberg@arm.com 51110609Sandreas.sandberg@arm.com case EL2: 51210609Sandreas.sandberg@arm.com return !filter.nsh; 51310609Sandreas.sandberg@arm.com 51410609Sandreas.sandberg@arm.com case EL3: 51510609Sandreas.sandberg@arm.com return filter.p != filter.m; 51610609Sandreas.sandberg@arm.com 51710609Sandreas.sandberg@arm.com default: 51810609Sandreas.sandberg@arm.com panic("Unexpected execution level in PMU::isFiltered.\n"); 51910609Sandreas.sandberg@arm.com } 52010609Sandreas.sandberg@arm.com} 52110609Sandreas.sandberg@arm.com 52210461SAndreas.Sandberg@ARM.comvoid 52312286Sjose.marinho@arm.comPMU::CounterState::detach() 52410461SAndreas.Sandberg@ARM.com{ 52512286Sjose.marinho@arm.com if (sourceEvent) { 52612286Sjose.marinho@arm.com sourceEvent->detachEvent(this); 52712286Sjose.marinho@arm.com sourceEvent = nullptr; 52812286Sjose.marinho@arm.com } else { 52912286Sjose.marinho@arm.com debugCounter("detaching event not currently attached" 53012286Sjose.marinho@arm.com " to any event\n"); 53110461SAndreas.Sandberg@ARM.com } 53210461SAndreas.Sandberg@ARM.com} 53310461SAndreas.Sandberg@ARM.com 53410461SAndreas.Sandberg@ARM.comvoid 53512286Sjose.marinho@arm.comPMU::CounterState::attach(PMUEvent* event) 53612286Sjose.marinho@arm.com{ 53713637Sruben.ayrapetyan@arm.com if (!resetValue) { 53813637Sruben.ayrapetyan@arm.com value = 0; 53913637Sruben.ayrapetyan@arm.com resetValue = true; 54013637Sruben.ayrapetyan@arm.com } 54112286Sjose.marinho@arm.com sourceEvent = event; 54212286Sjose.marinho@arm.com sourceEvent->attachEvent(this); 54312286Sjose.marinho@arm.com} 54412286Sjose.marinho@arm.com 54512286Sjose.marinho@arm.comuint64_t 54612286Sjose.marinho@arm.comPMU::CounterState::getValue() const 54712286Sjose.marinho@arm.com{ 54812286Sjose.marinho@arm.com if (sourceEvent) { 54912286Sjose.marinho@arm.com sourceEvent->updateAttachedCounters(); 55012286Sjose.marinho@arm.com } else { 55112286Sjose.marinho@arm.com debugCounter("attempted to get value from a counter without" 55212286Sjose.marinho@arm.com " an associated event\n"); 55312286Sjose.marinho@arm.com } 55412286Sjose.marinho@arm.com return value; 55512286Sjose.marinho@arm.com} 55612286Sjose.marinho@arm.com 55712286Sjose.marinho@arm.comvoid 55812286Sjose.marinho@arm.comPMU::CounterState::setValue(uint64_t val) 55912286Sjose.marinho@arm.com{ 56012286Sjose.marinho@arm.com value = val; 56112286Sjose.marinho@arm.com resetValue = true; 56212286Sjose.marinho@arm.com 56312286Sjose.marinho@arm.com if (sourceEvent) { 56412286Sjose.marinho@arm.com sourceEvent->updateAttachedCounters(); 56512286Sjose.marinho@arm.com } else { 56612286Sjose.marinho@arm.com debugCounter("attempted to set value from a counter without" 56712286Sjose.marinho@arm.com " an associated event\n"); 56812286Sjose.marinho@arm.com } 56912286Sjose.marinho@arm.com} 57012286Sjose.marinho@arm.com 57112286Sjose.marinho@arm.comvoid 57212286Sjose.marinho@arm.comPMU::updateCounter(CounterState &ctr) 57310461SAndreas.Sandberg@ARM.com{ 57410461SAndreas.Sandberg@ARM.com if (!ctr.enabled) { 57512286Sjose.marinho@arm.com DPRINTF(PMUVerbose, "updateCounter(%i): Disabling counter\n", 57612286Sjose.marinho@arm.com ctr.getCounterId()); 57712286Sjose.marinho@arm.com ctr.detach(); 57812286Sjose.marinho@arm.com 57910461SAndreas.Sandberg@ARM.com } else { 58010461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "updateCounter(%i): Enable event id 0x%x\n", 58112286Sjose.marinho@arm.com ctr.getCounterId(), ctr.eventId); 58210461SAndreas.Sandberg@ARM.com 58312286Sjose.marinho@arm.com auto sourceEvent = eventMap.find(ctr.eventId); 58412286Sjose.marinho@arm.com if (sourceEvent == eventMap.end()) { 58510461SAndreas.Sandberg@ARM.com warn("Can't enable PMU counter of type '0x%x': " 58610461SAndreas.Sandberg@ARM.com "No such event type.\n", ctr.eventId); 58712286Sjose.marinho@arm.com } else { 58812286Sjose.marinho@arm.com ctr.attach(sourceEvent->second); 58910461SAndreas.Sandberg@ARM.com } 59010461SAndreas.Sandberg@ARM.com } 59110461SAndreas.Sandberg@ARM.com} 59210461SAndreas.Sandberg@ARM.com 59310461SAndreas.Sandberg@ARM.com 59410461SAndreas.Sandberg@ARM.comvoid 59510461SAndreas.Sandberg@ARM.comPMU::resetEventCounts() 59610461SAndreas.Sandberg@ARM.com{ 59710461SAndreas.Sandberg@ARM.com for (CounterState &ctr : counters) 59812286Sjose.marinho@arm.com ctr.setValue(0); 59910461SAndreas.Sandberg@ARM.com} 60010461SAndreas.Sandberg@ARM.com 60110461SAndreas.Sandberg@ARM.comvoid 60210461SAndreas.Sandberg@ARM.comPMU::setCounterValue(CounterId id, uint64_t val) 60310461SAndreas.Sandberg@ARM.com{ 60410461SAndreas.Sandberg@ARM.com if (!isValidCounter(id)) { 60510461SAndreas.Sandberg@ARM.com warn_once("Can't change counter value: Counter %i does not exist.\n", 60610461SAndreas.Sandberg@ARM.com id); 60710461SAndreas.Sandberg@ARM.com return; 60810461SAndreas.Sandberg@ARM.com } 60910461SAndreas.Sandberg@ARM.com 61010461SAndreas.Sandberg@ARM.com CounterState &ctr(getCounter(id)); 61112286Sjose.marinho@arm.com ctr.setValue(val); 61210461SAndreas.Sandberg@ARM.com} 61310461SAndreas.Sandberg@ARM.com 61410461SAndreas.Sandberg@ARM.comPMU::PMEVTYPER_t 61510461SAndreas.Sandberg@ARM.comPMU::getCounterTypeRegister(CounterId id) const 61610461SAndreas.Sandberg@ARM.com{ 61710461SAndreas.Sandberg@ARM.com if (!isValidCounter(id)) 61810461SAndreas.Sandberg@ARM.com return 0; 61910461SAndreas.Sandberg@ARM.com 62010461SAndreas.Sandberg@ARM.com const CounterState &cs(getCounter(id)); 62110609Sandreas.sandberg@arm.com PMEVTYPER_t type(cs.filter); 62210461SAndreas.Sandberg@ARM.com 62310461SAndreas.Sandberg@ARM.com type.evtCount = cs.eventId; 62410461SAndreas.Sandberg@ARM.com 62510461SAndreas.Sandberg@ARM.com return type; 62610461SAndreas.Sandberg@ARM.com} 62710461SAndreas.Sandberg@ARM.com 62810461SAndreas.Sandberg@ARM.comvoid 62910461SAndreas.Sandberg@ARM.comPMU::setCounterTypeRegister(CounterId id, PMEVTYPER_t val) 63010461SAndreas.Sandberg@ARM.com{ 63110461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "Set Event [%d] = 0x%08x\n", id, val); 63210461SAndreas.Sandberg@ARM.com if (!isValidCounter(id)) { 63310461SAndreas.Sandberg@ARM.com warn_once("Can't change counter type: Counter %i does not exist.\n", 63410461SAndreas.Sandberg@ARM.com id); 63510461SAndreas.Sandberg@ARM.com return; 63610461SAndreas.Sandberg@ARM.com } 63710461SAndreas.Sandberg@ARM.com 63810461SAndreas.Sandberg@ARM.com CounterState &ctr(getCounter(id)); 63910609Sandreas.sandberg@arm.com const EventTypeId old_event_id(ctr.eventId); 64010461SAndreas.Sandberg@ARM.com 64110609Sandreas.sandberg@arm.com ctr.filter = val; 64210609Sandreas.sandberg@arm.com 64310609Sandreas.sandberg@arm.com // If PMCCNTR Register, do not change event type. PMCCNTR can 64410609Sandreas.sandberg@arm.com // count processor cycles only. If we change the event type, we 64510609Sandreas.sandberg@arm.com // need to update the probes the counter is using. 64610609Sandreas.sandberg@arm.com if (id != PMCCNTR && old_event_id != val.evtCount) { 64710461SAndreas.Sandberg@ARM.com ctr.eventId = val.evtCount; 64812286Sjose.marinho@arm.com updateCounter(ctr); 64910461SAndreas.Sandberg@ARM.com } 65010461SAndreas.Sandberg@ARM.com} 65110461SAndreas.Sandberg@ARM.com 65210461SAndreas.Sandberg@ARM.comvoid 65313581Sgabeblack@google.comPMU::setOverflowStatus(RegVal new_val) 65413104Sgiacomo.travaglini@arm.com{ 65513104Sgiacomo.travaglini@arm.com const bool int_old = reg_pmovsr != 0; 65613104Sgiacomo.travaglini@arm.com const bool int_new = new_val != 0; 65713104Sgiacomo.travaglini@arm.com 65813104Sgiacomo.travaglini@arm.com reg_pmovsr = new_val; 65913104Sgiacomo.travaglini@arm.com if (int_old && !int_new) { 66013104Sgiacomo.travaglini@arm.com clearInterrupt(); 66113104Sgiacomo.travaglini@arm.com } else if (!int_old && int_new && (reg_pminten & reg_pmovsr)) { 66213104Sgiacomo.travaglini@arm.com raiseInterrupt(); 66313104Sgiacomo.travaglini@arm.com } 66413104Sgiacomo.travaglini@arm.com} 66513104Sgiacomo.travaglini@arm.com 66613104Sgiacomo.travaglini@arm.comvoid 66710461SAndreas.Sandberg@ARM.comPMU::raiseInterrupt() 66810461SAndreas.Sandberg@ARM.com{ 66912973Sandreas.sandberg@arm.com if (interrupt) { 67012973Sandreas.sandberg@arm.com DPRINTF(PMUVerbose, "Delivering PMU interrupt.\n"); 67112973Sandreas.sandberg@arm.com interrupt->raise(); 67212973Sandreas.sandberg@arm.com } else { 67312973Sandreas.sandberg@arm.com warn_once("Dropping PMU interrupt as no interrupt has " 67412973Sandreas.sandberg@arm.com "been specified\n"); 67510461SAndreas.Sandberg@ARM.com } 67610461SAndreas.Sandberg@ARM.com} 67710461SAndreas.Sandberg@ARM.com 67810461SAndreas.Sandberg@ARM.comvoid 67913104Sgiacomo.travaglini@arm.comPMU::clearInterrupt() 68013104Sgiacomo.travaglini@arm.com{ 68113104Sgiacomo.travaglini@arm.com if (interrupt) { 68213104Sgiacomo.travaglini@arm.com DPRINTF(PMUVerbose, "Clearing PMU interrupt.\n"); 68313104Sgiacomo.travaglini@arm.com interrupt->clear(); 68413104Sgiacomo.travaglini@arm.com } else { 68513104Sgiacomo.travaglini@arm.com warn_once("Dropping PMU interrupt as no interrupt has " 68613104Sgiacomo.travaglini@arm.com "been specified\n"); 68713104Sgiacomo.travaglini@arm.com } 68813104Sgiacomo.travaglini@arm.com} 68913104Sgiacomo.travaglini@arm.com 69013104Sgiacomo.travaglini@arm.comvoid 69110905Sandreas.sandberg@arm.comPMU::serialize(CheckpointOut &cp) const 69210461SAndreas.Sandberg@ARM.com{ 69310461SAndreas.Sandberg@ARM.com DPRINTF(Checkpoint, "Serializing Arm PMU\n"); 69410461SAndreas.Sandberg@ARM.com 69510461SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(reg_pmcr); 69610461SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(reg_pmcnten); 69710461SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(reg_pmselr); 69810461SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(reg_pminten); 69910461SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(reg_pmovsr); 70012117Sjose.marinho@arm.com SERIALIZE_SCALAR(reg_pmceid0); 70112117Sjose.marinho@arm.com SERIALIZE_SCALAR(reg_pmceid1); 70210461SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(clock_remainder); 70310461SAndreas.Sandberg@ARM.com 70410905Sandreas.sandberg@arm.com for (size_t i = 0; i < counters.size(); ++i) 70510905Sandreas.sandberg@arm.com counters[i].serializeSection(cp, csprintf("counters.%i", i)); 70610461SAndreas.Sandberg@ARM.com 70710905Sandreas.sandberg@arm.com cycleCounter.serializeSection(cp, "cycleCounter"); 70810461SAndreas.Sandberg@ARM.com} 70910461SAndreas.Sandberg@ARM.com 71010461SAndreas.Sandberg@ARM.comvoid 71110905Sandreas.sandberg@arm.comPMU::unserialize(CheckpointIn &cp) 71210461SAndreas.Sandberg@ARM.com{ 71310461SAndreas.Sandberg@ARM.com DPRINTF(Checkpoint, "Unserializing Arm PMU\n"); 71410461SAndreas.Sandberg@ARM.com 71510461SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(reg_pmcr); 71610461SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(reg_pmcnten); 71710461SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(reg_pmselr); 71810461SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(reg_pminten); 71910461SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(reg_pmovsr); 72012117Sjose.marinho@arm.com 72112117Sjose.marinho@arm.com // Old checkpoints used to store the entire PMCEID value in a 72212117Sjose.marinho@arm.com // single 64-bit entry (reg_pmceid). The register was extended in 72312117Sjose.marinho@arm.com // ARMv8.1, so we now need to store it as two 64-bit registers. 72412117Sjose.marinho@arm.com if (!UNSERIALIZE_OPT_SCALAR(reg_pmceid0)) 72512117Sjose.marinho@arm.com paramIn(cp, "reg_pmceid", reg_pmceid0); 72612117Sjose.marinho@arm.com 72712117Sjose.marinho@arm.com if (!UNSERIALIZE_OPT_SCALAR(reg_pmceid1)) 72812117Sjose.marinho@arm.com reg_pmceid1 = 0; 72912117Sjose.marinho@arm.com 73010461SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(clock_remainder); 73110461SAndreas.Sandberg@ARM.com 73210461SAndreas.Sandberg@ARM.com for (size_t i = 0; i < counters.size(); ++i) 73310905Sandreas.sandberg@arm.com counters[i].unserializeSection(cp, csprintf("counters.%i", i)); 73410461SAndreas.Sandberg@ARM.com 73510905Sandreas.sandberg@arm.com cycleCounter.unserializeSection(cp, "cycleCounter"); 73610461SAndreas.Sandberg@ARM.com} 73710461SAndreas.Sandberg@ARM.com 73812286Sjose.marinho@arm.comPMU::PMUEvent* 73912286Sjose.marinho@arm.comPMU::getEvent(uint64_t eventId) 74012286Sjose.marinho@arm.com{ 74112286Sjose.marinho@arm.com auto entry = eventMap.find(eventId); 74212286Sjose.marinho@arm.com 74312286Sjose.marinho@arm.com if (entry == eventMap.end()) { 74412286Sjose.marinho@arm.com warn("event %d does not exist\n", eventId); 74512286Sjose.marinho@arm.com return nullptr; 74612286Sjose.marinho@arm.com } else { 74712286Sjose.marinho@arm.com return entry->second; 74812286Sjose.marinho@arm.com } 74912286Sjose.marinho@arm.com} 75012286Sjose.marinho@arm.com 75110461SAndreas.Sandberg@ARM.comvoid 75210905Sandreas.sandberg@arm.comPMU::CounterState::serialize(CheckpointOut &cp) const 75310461SAndreas.Sandberg@ARM.com{ 75410461SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(eventId); 75510461SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(value); 75610461SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(overflow64); 75710461SAndreas.Sandberg@ARM.com} 75810461SAndreas.Sandberg@ARM.com 75910461SAndreas.Sandberg@ARM.comvoid 76010905Sandreas.sandberg@arm.comPMU::CounterState::unserialize(CheckpointIn &cp) 76110461SAndreas.Sandberg@ARM.com{ 76210461SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(eventId); 76310461SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(value); 76410461SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(overflow64); 76510461SAndreas.Sandberg@ARM.com} 76610461SAndreas.Sandberg@ARM.com 76712286Sjose.marinho@arm.comuint64_t 76810461SAndreas.Sandberg@ARM.comPMU::CounterState::add(uint64_t delta) 76910461SAndreas.Sandberg@ARM.com{ 77012286Sjose.marinho@arm.com uint64_t value_until_overflow; 77112286Sjose.marinho@arm.com if (overflow64) { 77212286Sjose.marinho@arm.com value_until_overflow = UINT64_MAX - value; 77312286Sjose.marinho@arm.com } else { 77412286Sjose.marinho@arm.com value_until_overflow = UINT32_MAX - (uint32_t)value; 77512286Sjose.marinho@arm.com } 77610461SAndreas.Sandberg@ARM.com 77712286Sjose.marinho@arm.com if (isFiltered()) 77812286Sjose.marinho@arm.com return value_until_overflow; 77910461SAndreas.Sandberg@ARM.com 78012286Sjose.marinho@arm.com if (resetValue) { 78112286Sjose.marinho@arm.com delta = 0; 78212286Sjose.marinho@arm.com resetValue = false; 78312286Sjose.marinho@arm.com } else { 78412286Sjose.marinho@arm.com value += delta; 78512286Sjose.marinho@arm.com } 78612286Sjose.marinho@arm.com 78712286Sjose.marinho@arm.com if (delta > value_until_overflow) { 78812286Sjose.marinho@arm.com 78912286Sjose.marinho@arm.com // overflow situation detected 79012286Sjose.marinho@arm.com // flag the overflow occurence 79112286Sjose.marinho@arm.com pmu.reg_pmovsr |= (1 << counterId); 79212286Sjose.marinho@arm.com 79312286Sjose.marinho@arm.com // Deliver a PMU interrupt if interrupt delivery is enabled 79412286Sjose.marinho@arm.com // for this counter. 79512286Sjose.marinho@arm.com if (pmu.reg_pminten & (1 << counterId)) { 79612286Sjose.marinho@arm.com pmu.raiseInterrupt(); 79712286Sjose.marinho@arm.com } 79812286Sjose.marinho@arm.com return overflow64 ? UINT64_MAX : UINT32_MAX; 79912286Sjose.marinho@arm.com } 80012286Sjose.marinho@arm.com return value_until_overflow - delta + 1; 80112286Sjose.marinho@arm.com} 80212286Sjose.marinho@arm.com 80312286Sjose.marinho@arm.comvoid 80412286Sjose.marinho@arm.comPMU::SWIncrementEvent::write(uint64_t val) 80512286Sjose.marinho@arm.com{ 80612286Sjose.marinho@arm.com for (auto& counter: userCounters) { 80712286Sjose.marinho@arm.com if (val & (0x1 << counter->getCounterId())) { 80812286Sjose.marinho@arm.com counter->add(1); 80912286Sjose.marinho@arm.com } 81012286Sjose.marinho@arm.com } 81110461SAndreas.Sandberg@ARM.com} 81210461SAndreas.Sandberg@ARM.com 81310461SAndreas.Sandberg@ARM.com} // namespace ArmISA 81410461SAndreas.Sandberg@ARM.com 81510461SAndreas.Sandberg@ARM.comArmISA::PMU * 81610461SAndreas.Sandberg@ARM.comArmPMUParams::create() 81710461SAndreas.Sandberg@ARM.com{ 81810461SAndreas.Sandberg@ARM.com return new ArmISA::PMU(this); 81910461SAndreas.Sandberg@ARM.com} 820