pmu.cc revision 12286
110461SAndreas.Sandberg@ARM.com/* 212117Sjose.marinho@arm.com * Copyright (c) 2011-2014, 2017 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 "dev/arm/realview.hh" 5410461SAndreas.Sandberg@ARM.com#include "params/ArmPMU.hh" 5510461SAndreas.Sandberg@ARM.com 5610461SAndreas.Sandberg@ARM.comnamespace ArmISA { 5710461SAndreas.Sandberg@ARM.com 5810461SAndreas.Sandberg@ARM.comconst MiscReg PMU::reg_pmcr_wr_mask = 0x39; 5910461SAndreas.Sandberg@ARM.com 6010461SAndreas.Sandberg@ARM.comPMU::PMU(const ArmPMUParams *p) 6110461SAndreas.Sandberg@ARM.com : SimObject(p), BaseISADevice(), 6210461SAndreas.Sandberg@ARM.com reg_pmcnten(0), reg_pmcr(0), 6310461SAndreas.Sandberg@ARM.com reg_pmselr(0), reg_pminten(0), reg_pmovsr(0), 6412117Sjose.marinho@arm.com reg_pmceid0(0),reg_pmceid1(0), 6510461SAndreas.Sandberg@ARM.com clock_remainder(0), 6612286Sjose.marinho@arm.com maximumCounterCount(p->eventCounters), 6712286Sjose.marinho@arm.com cycleCounter(*this, maximumCounterCount), 6812286Sjose.marinho@arm.com cycleCounterEventId(p->cycleEventId), 6912286Sjose.marinho@arm.com swIncrementEvent(nullptr), 7010461SAndreas.Sandberg@ARM.com reg_pmcr_conf(0), 7110461SAndreas.Sandberg@ARM.com pmuInterrupt(p->pmuInterrupt), 7210461SAndreas.Sandberg@ARM.com platform(p->platform) 7310461SAndreas.Sandberg@ARM.com{ 7410461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "Initializing the PMU.\n"); 7510461SAndreas.Sandberg@ARM.com 7612286Sjose.marinho@arm.com if (maximumCounterCount > 31) { 7710461SAndreas.Sandberg@ARM.com fatal("The PMU can only accept 31 counters, %d counters requested.\n", 7812286Sjose.marinho@arm.com maximumCounterCount); 7910461SAndreas.Sandberg@ARM.com } 8010461SAndreas.Sandberg@ARM.com 8110461SAndreas.Sandberg@ARM.com /* Setup the performance counter ID registers */ 8210461SAndreas.Sandberg@ARM.com reg_pmcr_conf.imp = 0x41; // ARM Ltd. 8310461SAndreas.Sandberg@ARM.com reg_pmcr_conf.idcode = 0x00; 8410461SAndreas.Sandberg@ARM.com reg_pmcr_conf.n = p->eventCounters; 8510461SAndreas.Sandberg@ARM.com 8610461SAndreas.Sandberg@ARM.com // Setup the hard-coded cycle counter, which is equivalent to 8710461SAndreas.Sandberg@ARM.com // architected counter event type 0x11. 8810461SAndreas.Sandberg@ARM.com cycleCounter.eventId = 0x11; 8910461SAndreas.Sandberg@ARM.com} 9010461SAndreas.Sandberg@ARM.com 9110461SAndreas.Sandberg@ARM.comPMU::~PMU() 9210461SAndreas.Sandberg@ARM.com{ 9310461SAndreas.Sandberg@ARM.com} 9410461SAndreas.Sandberg@ARM.com 9510461SAndreas.Sandberg@ARM.comvoid 9612286Sjose.marinho@arm.comPMU::addSoftwareIncrementEvent(unsigned int id) 9712286Sjose.marinho@arm.com{ 9812286Sjose.marinho@arm.com auto old_event = eventMap.find(id); 9912286Sjose.marinho@arm.com DPRINTF(PMUVerbose, "PMU: Adding SW increment event with id '0x%x'\n", id); 10012286Sjose.marinho@arm.com 10112286Sjose.marinho@arm.com if (swIncrementEvent) { 10212286Sjose.marinho@arm.com fatal_if(old_event == eventMap.end() || 10312286Sjose.marinho@arm.com old_event->second != swIncrementEvent, 10412286Sjose.marinho@arm.com "Trying to add a software increment event with multiple" 10512286Sjose.marinho@arm.com "IDs. This is not supported.\n"); 10612286Sjose.marinho@arm.com return; 10712286Sjose.marinho@arm.com } 10812286Sjose.marinho@arm.com 10912286Sjose.marinho@arm.com fatal_if(old_event != eventMap.end(), "An event with id %d has " 11012286Sjose.marinho@arm.com "been previously defined\n", id); 11112286Sjose.marinho@arm.com 11212286Sjose.marinho@arm.com swIncrementEvent = new SWIncrementEvent(); 11312286Sjose.marinho@arm.com eventMap[id] = swIncrementEvent; 11412286Sjose.marinho@arm.com registerEvent(id); 11512286Sjose.marinho@arm.com} 11612286Sjose.marinho@arm.com 11712286Sjose.marinho@arm.comvoid 11810461SAndreas.Sandberg@ARM.comPMU::addEventProbe(unsigned int id, SimObject *obj, const char *probe_name) 11910461SAndreas.Sandberg@ARM.com{ 12010461SAndreas.Sandberg@ARM.com 12112286Sjose.marinho@arm.com DPRINTF(PMUVerbose, "PMU: Adding Probe Driven event with id '0x%x'" 12212286Sjose.marinho@arm.com "as probe %s:%s\n",id, obj->name(), probe_name); 12312286Sjose.marinho@arm.com 12412286Sjose.marinho@arm.com RegularEvent *event = nullptr; 12512286Sjose.marinho@arm.com auto event_entry = eventMap.find(id); 12612286Sjose.marinho@arm.com if (event_entry == eventMap.end()) { 12712286Sjose.marinho@arm.com 12812286Sjose.marinho@arm.com event = new RegularEvent(); 12912286Sjose.marinho@arm.com eventMap[id] = event; 13012286Sjose.marinho@arm.com 13112286Sjose.marinho@arm.com } else { 13212286Sjose.marinho@arm.com event = dynamic_cast<RegularEvent*>(event_entry->second); 13312286Sjose.marinho@arm.com if (!event) { 13412286Sjose.marinho@arm.com fatal("Event with id %d is not probe driven\n", id); 13512286Sjose.marinho@arm.com } 13612286Sjose.marinho@arm.com } 13712286Sjose.marinho@arm.com event->addMicroarchitectureProbe(obj, probe_name); 13812286Sjose.marinho@arm.com 13912286Sjose.marinho@arm.com registerEvent(id); 14012286Sjose.marinho@arm.com 14112286Sjose.marinho@arm.com} 14212286Sjose.marinho@arm.com 14312286Sjose.marinho@arm.comvoid 14412286Sjose.marinho@arm.comPMU::registerEvent(uint32_t id) 14512286Sjose.marinho@arm.com{ 14612117Sjose.marinho@arm.com // Flag the event as available in the corresponding PMCEID register if it 14712117Sjose.marinho@arm.com // is an architected event. 14812117Sjose.marinho@arm.com if (id < 0x20) { 14912117Sjose.marinho@arm.com reg_pmceid0 |= ((uint64_t)1) << id; 15012117Sjose.marinho@arm.com } else if (id > 0x20 && id < 0x40) { 15112117Sjose.marinho@arm.com reg_pmceid1 |= ((uint64_t)1) << (id - 0x20); 15212117Sjose.marinho@arm.com } else if (id >= 0x4000 && id < 0x4020) { 15312117Sjose.marinho@arm.com reg_pmceid0 |= ((uint64_t)1) << (id - 0x4000 + 32); 15412117Sjose.marinho@arm.com } else if (id >= 0x4020 && id < 0x4040) { 15512117Sjose.marinho@arm.com reg_pmceid1 |= ((uint64_t)1) << (id - 0x4020 + 32); 15612117Sjose.marinho@arm.com } 15710461SAndreas.Sandberg@ARM.com} 15810461SAndreas.Sandberg@ARM.com 15910461SAndreas.Sandberg@ARM.comvoid 16010461SAndreas.Sandberg@ARM.comPMU::drainResume() 16110461SAndreas.Sandberg@ARM.com{ 16210461SAndreas.Sandberg@ARM.com // Re-attach enabled counters after a resume in case they changed. 16310461SAndreas.Sandberg@ARM.com updateAllCounters(); 16410461SAndreas.Sandberg@ARM.com} 16510461SAndreas.Sandberg@ARM.com 16610461SAndreas.Sandberg@ARM.comvoid 16712286Sjose.marinho@arm.comPMU::regProbeListeners() 16812286Sjose.marinho@arm.com{ 16912286Sjose.marinho@arm.com 17012286Sjose.marinho@arm.com // at this stage all probe configurations are done 17112286Sjose.marinho@arm.com // counters can be configured 17212286Sjose.marinho@arm.com for (uint32_t index = 0; index < maximumCounterCount-1; index++) { 17312286Sjose.marinho@arm.com counters.emplace_back(*this, index); 17412286Sjose.marinho@arm.com } 17512286Sjose.marinho@arm.com 17612286Sjose.marinho@arm.com PMUEvent *event = getEvent(cycleCounterEventId); 17712286Sjose.marinho@arm.com panic_if(!event, "core cycle event is not present\n"); 17812286Sjose.marinho@arm.com cycleCounter.enabled = true; 17912286Sjose.marinho@arm.com cycleCounter.attach(event); 18012286Sjose.marinho@arm.com} 18112286Sjose.marinho@arm.com 18212286Sjose.marinho@arm.comvoid 18310461SAndreas.Sandberg@ARM.comPMU::setMiscReg(int misc_reg, MiscReg val) 18410461SAndreas.Sandberg@ARM.com{ 18510461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "setMiscReg(%s, 0x%x)\n", 18610461SAndreas.Sandberg@ARM.com miscRegName[unflattenMiscReg(misc_reg)], val); 18710461SAndreas.Sandberg@ARM.com 18810461SAndreas.Sandberg@ARM.com switch (unflattenMiscReg(misc_reg)) { 18910461SAndreas.Sandberg@ARM.com case MISCREG_PMCR_EL0: 19010461SAndreas.Sandberg@ARM.com case MISCREG_PMCR: 19110461SAndreas.Sandberg@ARM.com setControlReg(val); 19210461SAndreas.Sandberg@ARM.com return; 19310461SAndreas.Sandberg@ARM.com 19410461SAndreas.Sandberg@ARM.com case MISCREG_PMCNTENSET_EL0: 19510461SAndreas.Sandberg@ARM.com case MISCREG_PMCNTENSET: 19610461SAndreas.Sandberg@ARM.com reg_pmcnten |= val; 19710461SAndreas.Sandberg@ARM.com updateAllCounters(); 19810461SAndreas.Sandberg@ARM.com return; 19910461SAndreas.Sandberg@ARM.com 20010461SAndreas.Sandberg@ARM.com case MISCREG_PMCNTENCLR_EL0: 20110461SAndreas.Sandberg@ARM.com case MISCREG_PMCNTENCLR: 20210461SAndreas.Sandberg@ARM.com reg_pmcnten &= ~val; 20310461SAndreas.Sandberg@ARM.com updateAllCounters(); 20410461SAndreas.Sandberg@ARM.com return; 20510461SAndreas.Sandberg@ARM.com 20610461SAndreas.Sandberg@ARM.com case MISCREG_PMOVSCLR_EL0: 20710461SAndreas.Sandberg@ARM.com case MISCREG_PMOVSR: 20810461SAndreas.Sandberg@ARM.com reg_pmovsr &= ~val; 20910461SAndreas.Sandberg@ARM.com return; 21010461SAndreas.Sandberg@ARM.com 21110461SAndreas.Sandberg@ARM.com case MISCREG_PMSWINC_EL0: 21210461SAndreas.Sandberg@ARM.com case MISCREG_PMSWINC: 21312286Sjose.marinho@arm.com if (swIncrementEvent) { 21412286Sjose.marinho@arm.com swIncrementEvent->write(val); 21510461SAndreas.Sandberg@ARM.com } 21612286Sjose.marinho@arm.com return; 21710461SAndreas.Sandberg@ARM.com 21810461SAndreas.Sandberg@ARM.com case MISCREG_PMCCNTR_EL0: 21910461SAndreas.Sandberg@ARM.com case MISCREG_PMCCNTR: 22012286Sjose.marinho@arm.com cycleCounter.setValue(val); 22110461SAndreas.Sandberg@ARM.com return; 22210461SAndreas.Sandberg@ARM.com 22310461SAndreas.Sandberg@ARM.com case MISCREG_PMSELR_EL0: 22410461SAndreas.Sandberg@ARM.com case MISCREG_PMSELR: 22510461SAndreas.Sandberg@ARM.com reg_pmselr = val; 22610461SAndreas.Sandberg@ARM.com return; 22712117Sjose.marinho@arm.com //TODO: implement MISCREF_PMCEID{2,3} 22810461SAndreas.Sandberg@ARM.com case MISCREG_PMCEID0_EL0: 22910461SAndreas.Sandberg@ARM.com case MISCREG_PMCEID0: 23010461SAndreas.Sandberg@ARM.com case MISCREG_PMCEID1_EL0: 23110461SAndreas.Sandberg@ARM.com case MISCREG_PMCEID1: 23210461SAndreas.Sandberg@ARM.com // Ignore writes 23310461SAndreas.Sandberg@ARM.com return; 23410461SAndreas.Sandberg@ARM.com 23510461SAndreas.Sandberg@ARM.com case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0: 23612042Sandreas.sandberg@arm.com setCounterTypeRegister(misc_reg - MISCREG_PMEVTYPER0_EL0, val); 23710461SAndreas.Sandberg@ARM.com return; 23810461SAndreas.Sandberg@ARM.com 23910461SAndreas.Sandberg@ARM.com case MISCREG_PMCCFILTR: 24010461SAndreas.Sandberg@ARM.com case MISCREG_PMCCFILTR_EL0: 24110461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "Setting PMCCFILTR: 0x%x\n", val); 24210461SAndreas.Sandberg@ARM.com setCounterTypeRegister(PMCCNTR, val); 24310461SAndreas.Sandberg@ARM.com return; 24410461SAndreas.Sandberg@ARM.com 24510461SAndreas.Sandberg@ARM.com case MISCREG_PMXEVTYPER_PMCCFILTR: 24610461SAndreas.Sandberg@ARM.com case MISCREG_PMXEVTYPER_EL0: 24710461SAndreas.Sandberg@ARM.com case MISCREG_PMXEVTYPER: 24810461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "Setting counter type: " 24910461SAndreas.Sandberg@ARM.com "[PMSELR: 0x%x, PMSELER.sel: 0x%x, EVTYPER: 0x%x]\n", 25010461SAndreas.Sandberg@ARM.com reg_pmselr, reg_pmselr.sel, val); 25110461SAndreas.Sandberg@ARM.com setCounterTypeRegister(reg_pmselr.sel, val); 25210461SAndreas.Sandberg@ARM.com return; 25310461SAndreas.Sandberg@ARM.com 25410461SAndreas.Sandberg@ARM.com case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0: 25510461SAndreas.Sandberg@ARM.com setCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0, val); 25610461SAndreas.Sandberg@ARM.com return; 25710461SAndreas.Sandberg@ARM.com 25810461SAndreas.Sandberg@ARM.com case MISCREG_PMXEVCNTR_EL0: 25910461SAndreas.Sandberg@ARM.com case MISCREG_PMXEVCNTR: 26010461SAndreas.Sandberg@ARM.com setCounterValue(reg_pmselr.sel, val); 26110461SAndreas.Sandberg@ARM.com return; 26210461SAndreas.Sandberg@ARM.com 26310461SAndreas.Sandberg@ARM.com case MISCREG_PMUSERENR_EL0: 26410461SAndreas.Sandberg@ARM.com case MISCREG_PMUSERENR: 26510461SAndreas.Sandberg@ARM.com // TODO 26610461SAndreas.Sandberg@ARM.com break; 26710461SAndreas.Sandberg@ARM.com 26810461SAndreas.Sandberg@ARM.com case MISCREG_PMINTENSET_EL1: 26910461SAndreas.Sandberg@ARM.com case MISCREG_PMINTENSET: 27010461SAndreas.Sandberg@ARM.com reg_pminten |= val; 27110461SAndreas.Sandberg@ARM.com return; 27210461SAndreas.Sandberg@ARM.com 27310461SAndreas.Sandberg@ARM.com case MISCREG_PMINTENCLR_EL1: 27410461SAndreas.Sandberg@ARM.com case MISCREG_PMINTENCLR: 27510461SAndreas.Sandberg@ARM.com reg_pminten &= ~val; 27610461SAndreas.Sandberg@ARM.com return; 27710461SAndreas.Sandberg@ARM.com 27810461SAndreas.Sandberg@ARM.com case MISCREG_PMOVSSET_EL0: 27910461SAndreas.Sandberg@ARM.com case MISCREG_PMOVSSET: 28010461SAndreas.Sandberg@ARM.com reg_pmovsr |= val; 28110461SAndreas.Sandberg@ARM.com return; 28210461SAndreas.Sandberg@ARM.com 28310461SAndreas.Sandberg@ARM.com default: 28410461SAndreas.Sandberg@ARM.com panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]); 28510461SAndreas.Sandberg@ARM.com } 28610461SAndreas.Sandberg@ARM.com 28710461SAndreas.Sandberg@ARM.com warn("Not doing anything for write to miscreg %s\n", 28810461SAndreas.Sandberg@ARM.com miscRegName[misc_reg]); 28910461SAndreas.Sandberg@ARM.com} 29010461SAndreas.Sandberg@ARM.com 29110461SAndreas.Sandberg@ARM.comMiscReg 29210461SAndreas.Sandberg@ARM.comPMU::readMiscReg(int misc_reg) 29310461SAndreas.Sandberg@ARM.com{ 29410461SAndreas.Sandberg@ARM.com MiscReg val(readMiscRegInt(misc_reg)); 29510461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "readMiscReg(%s): 0x%x\n", 29610461SAndreas.Sandberg@ARM.com miscRegName[unflattenMiscReg(misc_reg)], val); 29710461SAndreas.Sandberg@ARM.com return val; 29810461SAndreas.Sandberg@ARM.com} 29910461SAndreas.Sandberg@ARM.com 30010461SAndreas.Sandberg@ARM.comMiscReg 30110461SAndreas.Sandberg@ARM.comPMU::readMiscRegInt(int misc_reg) 30210461SAndreas.Sandberg@ARM.com{ 30310461SAndreas.Sandberg@ARM.com misc_reg = unflattenMiscReg(misc_reg); 30410461SAndreas.Sandberg@ARM.com switch (misc_reg) { 30510461SAndreas.Sandberg@ARM.com case MISCREG_PMCR_EL0: 30610461SAndreas.Sandberg@ARM.com case MISCREG_PMCR: 30710461SAndreas.Sandberg@ARM.com return reg_pmcr_conf | (reg_pmcr & reg_pmcr_wr_mask); 30810461SAndreas.Sandberg@ARM.com 30910461SAndreas.Sandberg@ARM.com case MISCREG_PMCNTENSET_EL0: 31010461SAndreas.Sandberg@ARM.com case MISCREG_PMCNTENCLR_EL0: 31110461SAndreas.Sandberg@ARM.com case MISCREG_PMCNTENSET: 31210461SAndreas.Sandberg@ARM.com case MISCREG_PMCNTENCLR: 31310461SAndreas.Sandberg@ARM.com return reg_pmcnten; 31410461SAndreas.Sandberg@ARM.com 31510461SAndreas.Sandberg@ARM.com case MISCREG_PMOVSCLR_EL0: 31610461SAndreas.Sandberg@ARM.com case MISCREG_PMOVSSET_EL0: 31710461SAndreas.Sandberg@ARM.com case MISCREG_PMOVSR: // Overflow Status Register 31810461SAndreas.Sandberg@ARM.com case MISCREG_PMOVSSET: 31910461SAndreas.Sandberg@ARM.com return reg_pmovsr; 32010461SAndreas.Sandberg@ARM.com 32110461SAndreas.Sandberg@ARM.com case MISCREG_PMSWINC_EL0: 32210461SAndreas.Sandberg@ARM.com case MISCREG_PMSWINC: // Software Increment Register (RAZ) 32310461SAndreas.Sandberg@ARM.com return 0; 32410461SAndreas.Sandberg@ARM.com 32510461SAndreas.Sandberg@ARM.com case MISCREG_PMSELR: 32610461SAndreas.Sandberg@ARM.com return reg_pmselr; 32710461SAndreas.Sandberg@ARM.com 32810461SAndreas.Sandberg@ARM.com case MISCREG_PMCEID0_EL0: 32912117Sjose.marinho@arm.com return reg_pmceid0; 33010461SAndreas.Sandberg@ARM.com 33110461SAndreas.Sandberg@ARM.com case MISCREG_PMCEID1_EL0: 33212117Sjose.marinho@arm.com return reg_pmceid1; 33312117Sjose.marinho@arm.com 33412117Sjose.marinho@arm.com //TODO: implement MISCREF_PMCEID{2,3} 33512117Sjose.marinho@arm.com case MISCREG_PMCEID0: // Common Event ID register 33612117Sjose.marinho@arm.com return reg_pmceid0 & 0xFFFFFFFF; 33712117Sjose.marinho@arm.com 33810461SAndreas.Sandberg@ARM.com case MISCREG_PMCEID1: // Common Event ID register 33912117Sjose.marinho@arm.com return reg_pmceid1 & 0xFFFFFFFF; 34010461SAndreas.Sandberg@ARM.com 34110461SAndreas.Sandberg@ARM.com case MISCREG_PMCCNTR_EL0: 34212286Sjose.marinho@arm.com return cycleCounter.getValue(); 34310461SAndreas.Sandberg@ARM.com 34410461SAndreas.Sandberg@ARM.com case MISCREG_PMCCNTR: 34512286Sjose.marinho@arm.com return cycleCounter.getValue() & 0xFFFFFFFF; 34610461SAndreas.Sandberg@ARM.com 34710461SAndreas.Sandberg@ARM.com case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0: 34810461SAndreas.Sandberg@ARM.com return getCounterTypeRegister(misc_reg - MISCREG_PMEVTYPER0_EL0); 34910461SAndreas.Sandberg@ARM.com 35010461SAndreas.Sandberg@ARM.com case MISCREG_PMCCFILTR: 35110461SAndreas.Sandberg@ARM.com case MISCREG_PMCCFILTR_EL0: 35210461SAndreas.Sandberg@ARM.com return getCounterTypeRegister(PMCCNTR); 35310461SAndreas.Sandberg@ARM.com 35410461SAndreas.Sandberg@ARM.com case MISCREG_PMXEVTYPER_PMCCFILTR: 35510461SAndreas.Sandberg@ARM.com case MISCREG_PMXEVTYPER_EL0: 35610461SAndreas.Sandberg@ARM.com case MISCREG_PMXEVTYPER: 35710461SAndreas.Sandberg@ARM.com return getCounterTypeRegister(reg_pmselr.sel); 35810461SAndreas.Sandberg@ARM.com 35912286Sjose.marinho@arm.com case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0: { 36012286Sjose.marinho@arm.com return getCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0) & 36112286Sjose.marinho@arm.com 0xFFFFFFFF; 36212286Sjose.marinho@arm.com 36312286Sjose.marinho@arm.com } 36410461SAndreas.Sandberg@ARM.com 36510461SAndreas.Sandberg@ARM.com case MISCREG_PMXEVCNTR_EL0: 36610461SAndreas.Sandberg@ARM.com case MISCREG_PMXEVCNTR: 36710461SAndreas.Sandberg@ARM.com return getCounterValue(reg_pmselr.sel) & 0xFFFFFFFF; 36810461SAndreas.Sandberg@ARM.com 36910461SAndreas.Sandberg@ARM.com case MISCREG_PMUSERENR_EL0: 37010461SAndreas.Sandberg@ARM.com case MISCREG_PMUSERENR: 37110461SAndreas.Sandberg@ARM.com // TODO 37210461SAndreas.Sandberg@ARM.com return 0; 37310461SAndreas.Sandberg@ARM.com 37410461SAndreas.Sandberg@ARM.com case MISCREG_PMINTENSET_EL1: 37510461SAndreas.Sandberg@ARM.com case MISCREG_PMINTENCLR_EL1: 37610461SAndreas.Sandberg@ARM.com case MISCREG_PMINTENSET: 37710461SAndreas.Sandberg@ARM.com case MISCREG_PMINTENCLR: 37810461SAndreas.Sandberg@ARM.com return reg_pminten; 37910461SAndreas.Sandberg@ARM.com 38010461SAndreas.Sandberg@ARM.com default: 38110461SAndreas.Sandberg@ARM.com panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]); 38210461SAndreas.Sandberg@ARM.com } 38310461SAndreas.Sandberg@ARM.com 38410461SAndreas.Sandberg@ARM.com warn("Not doing anything for read from miscreg %s\n", 38510461SAndreas.Sandberg@ARM.com miscRegName[misc_reg]); 38610461SAndreas.Sandberg@ARM.com return 0; 38710461SAndreas.Sandberg@ARM.com} 38810461SAndreas.Sandberg@ARM.com 38910461SAndreas.Sandberg@ARM.comvoid 39010461SAndreas.Sandberg@ARM.comPMU::setControlReg(PMCR_t val) 39110461SAndreas.Sandberg@ARM.com{ 39210461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "Set Control Reg 0x%08x.\n", val); 39310461SAndreas.Sandberg@ARM.com 39410461SAndreas.Sandberg@ARM.com if (val.p) { 39510461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "PMU reset all events to zero.\n"); 39610461SAndreas.Sandberg@ARM.com resetEventCounts(); 39710461SAndreas.Sandberg@ARM.com } 39810461SAndreas.Sandberg@ARM.com 39910461SAndreas.Sandberg@ARM.com if (val.c) { 40010461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "PMU reset cycle counter to zero.\n"); 40112286Sjose.marinho@arm.com cycleCounter.setValue(0); 40210461SAndreas.Sandberg@ARM.com } 40310461SAndreas.Sandberg@ARM.com 40410461SAndreas.Sandberg@ARM.com // Reset the clock remainder if divide by 64-mode is toggled. 40510461SAndreas.Sandberg@ARM.com if (reg_pmcr.d != val.d) 40610461SAndreas.Sandberg@ARM.com clock_remainder = 0; 40710461SAndreas.Sandberg@ARM.com 40810461SAndreas.Sandberg@ARM.com reg_pmcr = val & reg_pmcr_wr_mask; 40910461SAndreas.Sandberg@ARM.com updateAllCounters(); 41010461SAndreas.Sandberg@ARM.com} 41110461SAndreas.Sandberg@ARM.com 41210461SAndreas.Sandberg@ARM.comvoid 41310461SAndreas.Sandberg@ARM.comPMU::updateAllCounters() 41410461SAndreas.Sandberg@ARM.com{ 41510461SAndreas.Sandberg@ARM.com const bool global_enable(reg_pmcr.e); 41610461SAndreas.Sandberg@ARM.com 41710461SAndreas.Sandberg@ARM.com for (int i = 0; i < counters.size(); ++i) { 41810461SAndreas.Sandberg@ARM.com CounterState &ctr(counters[i]); 41910461SAndreas.Sandberg@ARM.com const bool enable(global_enable && (reg_pmcnten & (1 << i))); 42010461SAndreas.Sandberg@ARM.com if (ctr.enabled != enable) { 42110461SAndreas.Sandberg@ARM.com ctr.enabled = enable; 42212286Sjose.marinho@arm.com updateCounter(ctr); 42310461SAndreas.Sandberg@ARM.com } 42410461SAndreas.Sandberg@ARM.com } 42510461SAndreas.Sandberg@ARM.com 42610461SAndreas.Sandberg@ARM.com const bool ccntr_enable(global_enable && (reg_pmcnten & (1 << PMCCNTR))); 42710461SAndreas.Sandberg@ARM.com if (cycleCounter.enabled != ccntr_enable) { 42810461SAndreas.Sandberg@ARM.com cycleCounter.enabled = ccntr_enable; 42912286Sjose.marinho@arm.com updateCounter(cycleCounter); 43010461SAndreas.Sandberg@ARM.com } 43110461SAndreas.Sandberg@ARM.com} 43210461SAndreas.Sandberg@ARM.com 43312286Sjose.marinho@arm.comvoid 43412286Sjose.marinho@arm.comPMU::PMUEvent::attachEvent(PMU::CounterState *user) 43512286Sjose.marinho@arm.com{ 43612286Sjose.marinho@arm.com if (userCounters.empty()) { 43712286Sjose.marinho@arm.com enable(); 43812286Sjose.marinho@arm.com } 43912286Sjose.marinho@arm.com userCounters.insert(user); 44012286Sjose.marinho@arm.com updateAttachedCounters(); 44112286Sjose.marinho@arm.com} 44212286Sjose.marinho@arm.com 44312286Sjose.marinho@arm.comvoid 44412286Sjose.marinho@arm.comPMU::PMUEvent::increment(const uint64_t val) 44512286Sjose.marinho@arm.com{ 44612286Sjose.marinho@arm.com for (auto& counter: userCounters) { 44712286Sjose.marinho@arm.com counter->add(val); 44812286Sjose.marinho@arm.com } 44912286Sjose.marinho@arm.com} 45012286Sjose.marinho@arm.com 45112286Sjose.marinho@arm.comvoid 45212286Sjose.marinho@arm.comPMU::PMUEvent::detachEvent(PMU::CounterState *user) 45312286Sjose.marinho@arm.com{ 45412286Sjose.marinho@arm.com userCounters.erase(user); 45512286Sjose.marinho@arm.com 45612286Sjose.marinho@arm.com if (userCounters.empty()) { 45712286Sjose.marinho@arm.com disable(); 45812286Sjose.marinho@arm.com } 45912286Sjose.marinho@arm.com} 46012286Sjose.marinho@arm.com 46112286Sjose.marinho@arm.comvoid 46212286Sjose.marinho@arm.comPMU::RegularEvent::RegularProbe::notify(const uint64_t &val) 46312286Sjose.marinho@arm.com{ 46412286Sjose.marinho@arm.com parentEvent->increment(val); 46512286Sjose.marinho@arm.com} 46612286Sjose.marinho@arm.com 46712286Sjose.marinho@arm.comvoid 46812286Sjose.marinho@arm.comPMU::RegularEvent::enable() 46912286Sjose.marinho@arm.com{ 47012286Sjose.marinho@arm.com for (auto& subEvents: microArchitectureEventSet) { 47112286Sjose.marinho@arm.com attachedProbePointList.emplace_back( 47212286Sjose.marinho@arm.com new RegularProbe(this, subEvents.first, subEvents.second)); 47312286Sjose.marinho@arm.com } 47412286Sjose.marinho@arm.com} 47512286Sjose.marinho@arm.com 47612286Sjose.marinho@arm.comvoid 47712286Sjose.marinho@arm.comPMU::RegularEvent::disable() 47812286Sjose.marinho@arm.com{ 47912286Sjose.marinho@arm.com attachedProbePointList.clear(); 48012286Sjose.marinho@arm.com} 48112286Sjose.marinho@arm.com 48210609Sandreas.sandberg@arm.combool 48312286Sjose.marinho@arm.comPMU::CounterState::isFiltered() const 48410609Sandreas.sandberg@arm.com{ 48512286Sjose.marinho@arm.com assert(pmu.isa); 48610609Sandreas.sandberg@arm.com 48712286Sjose.marinho@arm.com const PMEVTYPER_t filter(this->filter); 48812286Sjose.marinho@arm.com const SCR scr(pmu.isa->readMiscRegNoEffect(MISCREG_SCR)); 48912286Sjose.marinho@arm.com const CPSR cpsr(pmu.isa->readMiscRegNoEffect(MISCREG_CPSR)); 49010609Sandreas.sandberg@arm.com const ExceptionLevel el(opModeToEL((OperatingMode)(uint8_t)cpsr.mode)); 49110609Sandreas.sandberg@arm.com const bool secure(inSecureState(scr, cpsr)); 49210609Sandreas.sandberg@arm.com 49310609Sandreas.sandberg@arm.com switch (el) { 49410609Sandreas.sandberg@arm.com case EL0: 49510609Sandreas.sandberg@arm.com return secure ? filter.u : (filter.u != filter.nsu); 49610609Sandreas.sandberg@arm.com 49710609Sandreas.sandberg@arm.com case EL1: 49810609Sandreas.sandberg@arm.com return secure ? filter.p : (filter.p != filter.nsk); 49910609Sandreas.sandberg@arm.com 50010609Sandreas.sandberg@arm.com case EL2: 50110609Sandreas.sandberg@arm.com return !filter.nsh; 50210609Sandreas.sandberg@arm.com 50310609Sandreas.sandberg@arm.com case EL3: 50410609Sandreas.sandberg@arm.com return filter.p != filter.m; 50510609Sandreas.sandberg@arm.com 50610609Sandreas.sandberg@arm.com default: 50710609Sandreas.sandberg@arm.com panic("Unexpected execution level in PMU::isFiltered.\n"); 50810609Sandreas.sandberg@arm.com } 50910609Sandreas.sandberg@arm.com} 51010609Sandreas.sandberg@arm.com 51110461SAndreas.Sandberg@ARM.comvoid 51212286Sjose.marinho@arm.comPMU::CounterState::detach() 51310461SAndreas.Sandberg@ARM.com{ 51412286Sjose.marinho@arm.com if (sourceEvent) { 51512286Sjose.marinho@arm.com sourceEvent->detachEvent(this); 51612286Sjose.marinho@arm.com sourceEvent = nullptr; 51712286Sjose.marinho@arm.com } else { 51812286Sjose.marinho@arm.com debugCounter("detaching event not currently attached" 51912286Sjose.marinho@arm.com " to any event\n"); 52010461SAndreas.Sandberg@ARM.com } 52110461SAndreas.Sandberg@ARM.com} 52210461SAndreas.Sandberg@ARM.com 52310461SAndreas.Sandberg@ARM.comvoid 52412286Sjose.marinho@arm.comPMU::CounterState::attach(PMUEvent* event) 52512286Sjose.marinho@arm.com{ 52612286Sjose.marinho@arm.com value = 0; 52712286Sjose.marinho@arm.com sourceEvent = event; 52812286Sjose.marinho@arm.com sourceEvent->attachEvent(this); 52912286Sjose.marinho@arm.com} 53012286Sjose.marinho@arm.com 53112286Sjose.marinho@arm.comuint64_t 53212286Sjose.marinho@arm.comPMU::CounterState::getValue() const 53312286Sjose.marinho@arm.com{ 53412286Sjose.marinho@arm.com if (sourceEvent) { 53512286Sjose.marinho@arm.com sourceEvent->updateAttachedCounters(); 53612286Sjose.marinho@arm.com } else { 53712286Sjose.marinho@arm.com debugCounter("attempted to get value from a counter without" 53812286Sjose.marinho@arm.com " an associated event\n"); 53912286Sjose.marinho@arm.com } 54012286Sjose.marinho@arm.com return value; 54112286Sjose.marinho@arm.com} 54212286Sjose.marinho@arm.com 54312286Sjose.marinho@arm.comvoid 54412286Sjose.marinho@arm.comPMU::CounterState::setValue(uint64_t val) 54512286Sjose.marinho@arm.com{ 54612286Sjose.marinho@arm.com value = val; 54712286Sjose.marinho@arm.com resetValue = true; 54812286Sjose.marinho@arm.com 54912286Sjose.marinho@arm.com if (sourceEvent) { 55012286Sjose.marinho@arm.com sourceEvent->updateAttachedCounters(); 55112286Sjose.marinho@arm.com } else { 55212286Sjose.marinho@arm.com debugCounter("attempted to set value from a counter without" 55312286Sjose.marinho@arm.com " an associated event\n"); 55412286Sjose.marinho@arm.com } 55512286Sjose.marinho@arm.com} 55612286Sjose.marinho@arm.com 55712286Sjose.marinho@arm.comvoid 55812286Sjose.marinho@arm.comPMU::updateCounter(CounterState &ctr) 55910461SAndreas.Sandberg@ARM.com{ 56010461SAndreas.Sandberg@ARM.com if (!ctr.enabled) { 56112286Sjose.marinho@arm.com DPRINTF(PMUVerbose, "updateCounter(%i): Disabling counter\n", 56212286Sjose.marinho@arm.com ctr.getCounterId()); 56312286Sjose.marinho@arm.com ctr.detach(); 56412286Sjose.marinho@arm.com 56510461SAndreas.Sandberg@ARM.com } else { 56610461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "updateCounter(%i): Enable event id 0x%x\n", 56712286Sjose.marinho@arm.com ctr.getCounterId(), ctr.eventId); 56810461SAndreas.Sandberg@ARM.com 56912286Sjose.marinho@arm.com auto sourceEvent = eventMap.find(ctr.eventId); 57012286Sjose.marinho@arm.com if (sourceEvent == eventMap.end()) { 57110461SAndreas.Sandberg@ARM.com warn("Can't enable PMU counter of type '0x%x': " 57210461SAndreas.Sandberg@ARM.com "No such event type.\n", ctr.eventId); 57312286Sjose.marinho@arm.com } else { 57412286Sjose.marinho@arm.com ctr.attach(sourceEvent->second); 57510461SAndreas.Sandberg@ARM.com } 57610461SAndreas.Sandberg@ARM.com } 57710461SAndreas.Sandberg@ARM.com} 57810461SAndreas.Sandberg@ARM.com 57910461SAndreas.Sandberg@ARM.com 58010461SAndreas.Sandberg@ARM.comvoid 58110461SAndreas.Sandberg@ARM.comPMU::resetEventCounts() 58210461SAndreas.Sandberg@ARM.com{ 58310461SAndreas.Sandberg@ARM.com for (CounterState &ctr : counters) 58412286Sjose.marinho@arm.com ctr.setValue(0); 58510461SAndreas.Sandberg@ARM.com} 58610461SAndreas.Sandberg@ARM.com 58710461SAndreas.Sandberg@ARM.comvoid 58810461SAndreas.Sandberg@ARM.comPMU::setCounterValue(CounterId id, uint64_t val) 58910461SAndreas.Sandberg@ARM.com{ 59010461SAndreas.Sandberg@ARM.com if (!isValidCounter(id)) { 59110461SAndreas.Sandberg@ARM.com warn_once("Can't change counter value: Counter %i does not exist.\n", 59210461SAndreas.Sandberg@ARM.com id); 59310461SAndreas.Sandberg@ARM.com return; 59410461SAndreas.Sandberg@ARM.com } 59510461SAndreas.Sandberg@ARM.com 59610461SAndreas.Sandberg@ARM.com CounterState &ctr(getCounter(id)); 59712286Sjose.marinho@arm.com ctr.setValue(val); 59810461SAndreas.Sandberg@ARM.com} 59910461SAndreas.Sandberg@ARM.com 60010461SAndreas.Sandberg@ARM.comPMU::PMEVTYPER_t 60110461SAndreas.Sandberg@ARM.comPMU::getCounterTypeRegister(CounterId id) const 60210461SAndreas.Sandberg@ARM.com{ 60310461SAndreas.Sandberg@ARM.com if (!isValidCounter(id)) 60410461SAndreas.Sandberg@ARM.com return 0; 60510461SAndreas.Sandberg@ARM.com 60610461SAndreas.Sandberg@ARM.com const CounterState &cs(getCounter(id)); 60710609Sandreas.sandberg@arm.com PMEVTYPER_t type(cs.filter); 60810461SAndreas.Sandberg@ARM.com 60910461SAndreas.Sandberg@ARM.com type.evtCount = cs.eventId; 61010461SAndreas.Sandberg@ARM.com 61110461SAndreas.Sandberg@ARM.com return type; 61210461SAndreas.Sandberg@ARM.com} 61310461SAndreas.Sandberg@ARM.com 61410461SAndreas.Sandberg@ARM.comvoid 61510461SAndreas.Sandberg@ARM.comPMU::setCounterTypeRegister(CounterId id, PMEVTYPER_t val) 61610461SAndreas.Sandberg@ARM.com{ 61710461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "Set Event [%d] = 0x%08x\n", id, val); 61810461SAndreas.Sandberg@ARM.com if (!isValidCounter(id)) { 61910461SAndreas.Sandberg@ARM.com warn_once("Can't change counter type: Counter %i does not exist.\n", 62010461SAndreas.Sandberg@ARM.com id); 62110461SAndreas.Sandberg@ARM.com return; 62210461SAndreas.Sandberg@ARM.com } 62310461SAndreas.Sandberg@ARM.com 62410461SAndreas.Sandberg@ARM.com CounterState &ctr(getCounter(id)); 62510609Sandreas.sandberg@arm.com const EventTypeId old_event_id(ctr.eventId); 62610461SAndreas.Sandberg@ARM.com 62710609Sandreas.sandberg@arm.com ctr.filter = val; 62810609Sandreas.sandberg@arm.com 62910609Sandreas.sandberg@arm.com // If PMCCNTR Register, do not change event type. PMCCNTR can 63010609Sandreas.sandberg@arm.com // count processor cycles only. If we change the event type, we 63110609Sandreas.sandberg@arm.com // need to update the probes the counter is using. 63210609Sandreas.sandberg@arm.com if (id != PMCCNTR && old_event_id != val.evtCount) { 63310461SAndreas.Sandberg@ARM.com ctr.eventId = val.evtCount; 63412286Sjose.marinho@arm.com updateCounter(ctr); 63510461SAndreas.Sandberg@ARM.com } 63610461SAndreas.Sandberg@ARM.com} 63710461SAndreas.Sandberg@ARM.com 63810461SAndreas.Sandberg@ARM.comvoid 63910461SAndreas.Sandberg@ARM.comPMU::raiseInterrupt() 64010461SAndreas.Sandberg@ARM.com{ 64110461SAndreas.Sandberg@ARM.com RealView *rv(dynamic_cast<RealView *>(platform)); 64210461SAndreas.Sandberg@ARM.com if (!rv || !rv->gic) { 64310461SAndreas.Sandberg@ARM.com warn_once("ARM PMU: GIC missing, can't raise interrupt.\n"); 64410461SAndreas.Sandberg@ARM.com return; 64510461SAndreas.Sandberg@ARM.com } 64610461SAndreas.Sandberg@ARM.com 64710461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "Delivering PMU interrupt.\n"); 64810461SAndreas.Sandberg@ARM.com rv->gic->sendInt(pmuInterrupt); 64910461SAndreas.Sandberg@ARM.com} 65010461SAndreas.Sandberg@ARM.com 65110461SAndreas.Sandberg@ARM.comvoid 65210905Sandreas.sandberg@arm.comPMU::serialize(CheckpointOut &cp) const 65310461SAndreas.Sandberg@ARM.com{ 65410461SAndreas.Sandberg@ARM.com DPRINTF(Checkpoint, "Serializing Arm PMU\n"); 65510461SAndreas.Sandberg@ARM.com 65610461SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(reg_pmcr); 65710461SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(reg_pmcnten); 65810461SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(reg_pmselr); 65910461SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(reg_pminten); 66010461SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(reg_pmovsr); 66112117Sjose.marinho@arm.com SERIALIZE_SCALAR(reg_pmceid0); 66212117Sjose.marinho@arm.com SERIALIZE_SCALAR(reg_pmceid1); 66310461SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(clock_remainder); 66410461SAndreas.Sandberg@ARM.com 66510905Sandreas.sandberg@arm.com for (size_t i = 0; i < counters.size(); ++i) 66610905Sandreas.sandberg@arm.com counters[i].serializeSection(cp, csprintf("counters.%i", i)); 66710461SAndreas.Sandberg@ARM.com 66810905Sandreas.sandberg@arm.com cycleCounter.serializeSection(cp, "cycleCounter"); 66910461SAndreas.Sandberg@ARM.com} 67010461SAndreas.Sandberg@ARM.com 67110461SAndreas.Sandberg@ARM.comvoid 67210905Sandreas.sandberg@arm.comPMU::unserialize(CheckpointIn &cp) 67310461SAndreas.Sandberg@ARM.com{ 67410461SAndreas.Sandberg@ARM.com DPRINTF(Checkpoint, "Unserializing Arm PMU\n"); 67510461SAndreas.Sandberg@ARM.com 67610461SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(reg_pmcr); 67710461SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(reg_pmcnten); 67810461SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(reg_pmselr); 67910461SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(reg_pminten); 68010461SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(reg_pmovsr); 68112117Sjose.marinho@arm.com 68212117Sjose.marinho@arm.com // Old checkpoints used to store the entire PMCEID value in a 68312117Sjose.marinho@arm.com // single 64-bit entry (reg_pmceid). The register was extended in 68412117Sjose.marinho@arm.com // ARMv8.1, so we now need to store it as two 64-bit registers. 68512117Sjose.marinho@arm.com if (!UNSERIALIZE_OPT_SCALAR(reg_pmceid0)) 68612117Sjose.marinho@arm.com paramIn(cp, "reg_pmceid", reg_pmceid0); 68712117Sjose.marinho@arm.com 68812117Sjose.marinho@arm.com if (!UNSERIALIZE_OPT_SCALAR(reg_pmceid1)) 68912117Sjose.marinho@arm.com reg_pmceid1 = 0; 69012117Sjose.marinho@arm.com 69110461SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(clock_remainder); 69210461SAndreas.Sandberg@ARM.com 69310461SAndreas.Sandberg@ARM.com for (size_t i = 0; i < counters.size(); ++i) 69410905Sandreas.sandberg@arm.com counters[i].unserializeSection(cp, csprintf("counters.%i", i)); 69510461SAndreas.Sandberg@ARM.com 69610905Sandreas.sandberg@arm.com cycleCounter.unserializeSection(cp, "cycleCounter"); 69710461SAndreas.Sandberg@ARM.com} 69810461SAndreas.Sandberg@ARM.com 69912286Sjose.marinho@arm.comPMU::PMUEvent* 70012286Sjose.marinho@arm.comPMU::getEvent(uint64_t eventId) 70112286Sjose.marinho@arm.com{ 70212286Sjose.marinho@arm.com auto entry = eventMap.find(eventId); 70312286Sjose.marinho@arm.com 70412286Sjose.marinho@arm.com if (entry == eventMap.end()) { 70512286Sjose.marinho@arm.com warn("event %d does not exist\n", eventId); 70612286Sjose.marinho@arm.com return nullptr; 70712286Sjose.marinho@arm.com } else { 70812286Sjose.marinho@arm.com return entry->second; 70912286Sjose.marinho@arm.com } 71012286Sjose.marinho@arm.com} 71112286Sjose.marinho@arm.com 71210461SAndreas.Sandberg@ARM.comvoid 71310905Sandreas.sandberg@arm.comPMU::CounterState::serialize(CheckpointOut &cp) const 71410461SAndreas.Sandberg@ARM.com{ 71510461SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(eventId); 71610461SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(value); 71710461SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(overflow64); 71810461SAndreas.Sandberg@ARM.com} 71910461SAndreas.Sandberg@ARM.com 72010461SAndreas.Sandberg@ARM.comvoid 72110905Sandreas.sandberg@arm.comPMU::CounterState::unserialize(CheckpointIn &cp) 72210461SAndreas.Sandberg@ARM.com{ 72310461SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(eventId); 72410461SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(value); 72510461SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(overflow64); 72610461SAndreas.Sandberg@ARM.com} 72710461SAndreas.Sandberg@ARM.com 72812286Sjose.marinho@arm.comuint64_t 72910461SAndreas.Sandberg@ARM.comPMU::CounterState::add(uint64_t delta) 73010461SAndreas.Sandberg@ARM.com{ 73112286Sjose.marinho@arm.com uint64_t value_until_overflow; 73212286Sjose.marinho@arm.com if (overflow64) { 73312286Sjose.marinho@arm.com value_until_overflow = UINT64_MAX - value; 73412286Sjose.marinho@arm.com } else { 73512286Sjose.marinho@arm.com value_until_overflow = UINT32_MAX - (uint32_t)value; 73612286Sjose.marinho@arm.com } 73710461SAndreas.Sandberg@ARM.com 73812286Sjose.marinho@arm.com if (isFiltered()) 73912286Sjose.marinho@arm.com return value_until_overflow; 74010461SAndreas.Sandberg@ARM.com 74112286Sjose.marinho@arm.com if (resetValue) { 74212286Sjose.marinho@arm.com delta = 0; 74312286Sjose.marinho@arm.com resetValue = false; 74412286Sjose.marinho@arm.com } else { 74512286Sjose.marinho@arm.com value += delta; 74612286Sjose.marinho@arm.com } 74712286Sjose.marinho@arm.com 74812286Sjose.marinho@arm.com if (delta > value_until_overflow) { 74912286Sjose.marinho@arm.com 75012286Sjose.marinho@arm.com // overflow situation detected 75112286Sjose.marinho@arm.com // flag the overflow occurence 75212286Sjose.marinho@arm.com pmu.reg_pmovsr |= (1 << counterId); 75312286Sjose.marinho@arm.com 75412286Sjose.marinho@arm.com // Deliver a PMU interrupt if interrupt delivery is enabled 75512286Sjose.marinho@arm.com // for this counter. 75612286Sjose.marinho@arm.com if (pmu.reg_pminten & (1 << counterId)) { 75712286Sjose.marinho@arm.com pmu.raiseInterrupt(); 75812286Sjose.marinho@arm.com } 75912286Sjose.marinho@arm.com return overflow64 ? UINT64_MAX : UINT32_MAX; 76012286Sjose.marinho@arm.com } 76112286Sjose.marinho@arm.com return value_until_overflow - delta + 1; 76212286Sjose.marinho@arm.com} 76312286Sjose.marinho@arm.com 76412286Sjose.marinho@arm.comvoid 76512286Sjose.marinho@arm.comPMU::SWIncrementEvent::write(uint64_t val) 76612286Sjose.marinho@arm.com{ 76712286Sjose.marinho@arm.com for (auto& counter: userCounters) { 76812286Sjose.marinho@arm.com if (val & (0x1 << counter->getCounterId())) { 76912286Sjose.marinho@arm.com counter->add(1); 77012286Sjose.marinho@arm.com } 77112286Sjose.marinho@arm.com } 77210461SAndreas.Sandberg@ARM.com} 77310461SAndreas.Sandberg@ARM.com 77410461SAndreas.Sandberg@ARM.com} // namespace ArmISA 77510461SAndreas.Sandberg@ARM.com 77610461SAndreas.Sandberg@ARM.comArmISA::PMU * 77710461SAndreas.Sandberg@ARM.comArmPMUParams::create() 77810461SAndreas.Sandberg@ARM.com{ 77910461SAndreas.Sandberg@ARM.com return new ArmISA::PMU(this); 78010461SAndreas.Sandberg@ARM.com} 781