pmu.cc revision 13637
18981Sandreas.hansson@arm.com/* 28981Sandreas.hansson@arm.com * Copyright (c) 2011-2014, 2017-2019 ARM Limited 38981Sandreas.hansson@arm.com * All rights reserved 48981Sandreas.hansson@arm.com * 58981Sandreas.hansson@arm.com * The license below extends only to copyright in the software and shall 68981Sandreas.hansson@arm.com * not be construed as granting a license to any other intellectual 78981Sandreas.hansson@arm.com * property including but not limited to intellectual property relating 88981Sandreas.hansson@arm.com * to a hardware implementation of the functionality of the software 98981Sandreas.hansson@arm.com * licensed hereunder. You may use the software subject to the license 108981Sandreas.hansson@arm.com * terms below provided that you ensure that this notice is replicated 118981Sandreas.hansson@arm.com * unmodified and in its entirety in all distributions of the software, 128981Sandreas.hansson@arm.com * modified or unmodified, in source code or in binary form. 138981Sandreas.hansson@arm.com * 148981Sandreas.hansson@arm.com * Redistribution and use in source and binary forms, with or without 158981Sandreas.hansson@arm.com * modification, are permitted provided that the following conditions are 168981Sandreas.hansson@arm.com * met: redistributions of source code must retain the above copyright 178981Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer; 188981Sandreas.hansson@arm.com * redistributions in binary form must reproduce the above copyright 198981Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer in the 208981Sandreas.hansson@arm.com * documentation and/or other materials provided with the distribution; 218981Sandreas.hansson@arm.com * neither the name of the copyright holders nor the names of its 228981Sandreas.hansson@arm.com * contributors may be used to endorse or promote products derived from 238981Sandreas.hansson@arm.com * this software without specific prior written permission. 248981Sandreas.hansson@arm.com * 258981Sandreas.hansson@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 268981Sandreas.hansson@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 278981Sandreas.hansson@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 288981Sandreas.hansson@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 298981Sandreas.hansson@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 308981Sandreas.hansson@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 318981Sandreas.hansson@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 328981Sandreas.hansson@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 338981Sandreas.hansson@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 348981Sandreas.hansson@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 358981Sandreas.hansson@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 368981Sandreas.hansson@arm.com * 378981Sandreas.hansson@arm.com * Authors: Dam Sunwoo 388981Sandreas.hansson@arm.com * Matt Horsnell 398981Sandreas.hansson@arm.com * Andreas Sandberg 408981Sandreas.hansson@arm.com * Jose Marinho 418981Sandreas.hansson@arm.com */ 428981Sandreas.hansson@arm.com 438981Sandreas.hansson@arm.com#include "arch/arm/pmu.hh" 448981Sandreas.hansson@arm.com 458981Sandreas.hansson@arm.com#include "arch/arm/isa.hh" 468981Sandreas.hansson@arm.com#include "arch/arm/utility.hh" 478981Sandreas.hansson@arm.com#include "base/trace.hh" 488981Sandreas.hansson@arm.com#include "cpu/base.hh" 498981Sandreas.hansson@arm.com#include "debug/Checkpoint.hh" 508981Sandreas.hansson@arm.com#include "debug/PMUVerbose.hh" 518981Sandreas.hansson@arm.com#include "dev/arm/base_gic.hh" 528981Sandreas.hansson@arm.com#include "dev/arm/generic_timer.hh" 538981Sandreas.hansson@arm.com#include "params/ArmPMU.hh" 548981Sandreas.hansson@arm.com 558981Sandreas.hansson@arm.comnamespace ArmISA { 568981Sandreas.hansson@arm.com 578981Sandreas.hansson@arm.comconst RegVal PMU::reg_pmcr_wr_mask = 0x39; 588981Sandreas.hansson@arm.com 598981Sandreas.hansson@arm.comPMU::PMU(const ArmPMUParams *p) 608981Sandreas.hansson@arm.com : SimObject(p), BaseISADevice(), 618981Sandreas.hansson@arm.com reg_pmcnten(0), reg_pmcr(0), 628981Sandreas.hansson@arm.com reg_pmselr(0), reg_pminten(0), reg_pmovsr(0), 638981Sandreas.hansson@arm.com reg_pmceid0(0),reg_pmceid1(0), 648981Sandreas.hansson@arm.com clock_remainder(0), 658981Sandreas.hansson@arm.com maximumCounterCount(p->eventCounters), 668981Sandreas.hansson@arm.com cycleCounter(*this, maximumCounterCount), 678981Sandreas.hansson@arm.com cycleCounterEventId(p->cycleEventId), 688981Sandreas.hansson@arm.com swIncrementEvent(nullptr), 698981Sandreas.hansson@arm.com reg_pmcr_conf(0), 708981Sandreas.hansson@arm.com interrupt(p->interrupt->get()) 718981Sandreas.hansson@arm.com{ 728981Sandreas.hansson@arm.com DPRINTF(PMUVerbose, "Initializing the PMU.\n"); 738981Sandreas.hansson@arm.com 748981Sandreas.hansson@arm.com if (maximumCounterCount > 31) { 758981Sandreas.hansson@arm.com fatal("The PMU can only accept 31 counters, %d counters requested.\n", 768981Sandreas.hansson@arm.com maximumCounterCount); 778981Sandreas.hansson@arm.com } 788981Sandreas.hansson@arm.com 798981Sandreas.hansson@arm.com warn_if(!interrupt, "ARM PMU: No interrupt specified, interrupt " \ 808981Sandreas.hansson@arm.com "delivery disabled.\n"); 818981Sandreas.hansson@arm.com 828981Sandreas.hansson@arm.com /* Setup the performance counter ID registers */ 838981Sandreas.hansson@arm.com reg_pmcr_conf.imp = 0x41; // ARM Ltd. 848981Sandreas.hansson@arm.com reg_pmcr_conf.idcode = 0x00; 858981Sandreas.hansson@arm.com reg_pmcr_conf.n = p->eventCounters; 868981Sandreas.hansson@arm.com 878981Sandreas.hansson@arm.com // Setup the hard-coded cycle counter, which is equivalent to 888981Sandreas.hansson@arm.com // architected counter event type 0x11. 898981Sandreas.hansson@arm.com cycleCounter.eventId = 0x11; 908981Sandreas.hansson@arm.com} 918981Sandreas.hansson@arm.com 928981Sandreas.hansson@arm.comPMU::~PMU() 938981Sandreas.hansson@arm.com{ 948981Sandreas.hansson@arm.com} 958981Sandreas.hansson@arm.com 968981Sandreas.hansson@arm.comvoid 978981Sandreas.hansson@arm.comPMU::setThreadContext(ThreadContext *tc) 988981Sandreas.hansson@arm.com{ 998981Sandreas.hansson@arm.com DPRINTF(PMUVerbose, "Assigning PMU to ContextID %i.\n", tc->contextId()); 1008981Sandreas.hansson@arm.com if (interrupt) 1018981Sandreas.hansson@arm.com interrupt->setThreadContext(tc); 1028981Sandreas.hansson@arm.com} 1038981Sandreas.hansson@arm.com 1048981Sandreas.hansson@arm.comvoid 1058981Sandreas.hansson@arm.comPMU::addSoftwareIncrementEvent(unsigned int id) 1068981Sandreas.hansson@arm.com{ 1078981Sandreas.hansson@arm.com auto old_event = eventMap.find(id); 1088981Sandreas.hansson@arm.com DPRINTF(PMUVerbose, "PMU: Adding SW increment event with id '0x%x'\n", id); 1098981Sandreas.hansson@arm.com 1108981Sandreas.hansson@arm.com if (swIncrementEvent) { 1118981Sandreas.hansson@arm.com fatal_if(old_event == eventMap.end() || 1128981Sandreas.hansson@arm.com old_event->second != swIncrementEvent, 1138981Sandreas.hansson@arm.com "Trying to add a software increment event with multiple" 1148981Sandreas.hansson@arm.com "IDs. This is not supported.\n"); 1158981Sandreas.hansson@arm.com return; 1168981Sandreas.hansson@arm.com } 1178981Sandreas.hansson@arm.com 1188981Sandreas.hansson@arm.com fatal_if(old_event != eventMap.end(), "An event with id %d has " 1198981Sandreas.hansson@arm.com "been previously defined\n", id); 1208981Sandreas.hansson@arm.com 1218981Sandreas.hansson@arm.com swIncrementEvent = new SWIncrementEvent(); 1228981Sandreas.hansson@arm.com eventMap[id] = swIncrementEvent; 1238981Sandreas.hansson@arm.com registerEvent(id); 1248981Sandreas.hansson@arm.com} 1258981Sandreas.hansson@arm.com 1268981Sandreas.hansson@arm.comvoid 1278981Sandreas.hansson@arm.comPMU::addEventProbe(unsigned int id, SimObject *obj, const char *probe_name) 1288981Sandreas.hansson@arm.com{ 1298981Sandreas.hansson@arm.com 1308981Sandreas.hansson@arm.com DPRINTF(PMUVerbose, "PMU: Adding Probe Driven event with id '0x%x'" 1318981Sandreas.hansson@arm.com "as probe %s:%s\n",id, obj->name(), probe_name); 1328981Sandreas.hansson@arm.com 1338981Sandreas.hansson@arm.com RegularEvent *event = nullptr; 1348981Sandreas.hansson@arm.com auto event_entry = eventMap.find(id); 1358981Sandreas.hansson@arm.com if (event_entry == eventMap.end()) { 1368981Sandreas.hansson@arm.com 1378981Sandreas.hansson@arm.com event = new RegularEvent(); 1388981Sandreas.hansson@arm.com eventMap[id] = event; 1398981Sandreas.hansson@arm.com 1408981Sandreas.hansson@arm.com } else { 1418981Sandreas.hansson@arm.com event = dynamic_cast<RegularEvent*>(event_entry->second); 1428981Sandreas.hansson@arm.com if (!event) { 1438981Sandreas.hansson@arm.com fatal("Event with id %d is not probe driven\n", id); 1448981Sandreas.hansson@arm.com } 1458981Sandreas.hansson@arm.com } 1468981Sandreas.hansson@arm.com event->addMicroarchitectureProbe(obj, probe_name); 1478981Sandreas.hansson@arm.com 1488981Sandreas.hansson@arm.com registerEvent(id); 1498981Sandreas.hansson@arm.com 1508981Sandreas.hansson@arm.com} 1518981Sandreas.hansson@arm.com 1528981Sandreas.hansson@arm.comvoid 1538981Sandreas.hansson@arm.comPMU::registerEvent(uint32_t id) 1548981Sandreas.hansson@arm.com{ 1558981Sandreas.hansson@arm.com // Flag the event as available in the corresponding PMCEID register if it 1568981Sandreas.hansson@arm.com // is an architected event. 1578981Sandreas.hansson@arm.com if (id < 0x20) { 1588981Sandreas.hansson@arm.com reg_pmceid0 |= ((uint64_t)1) << id; 1598981Sandreas.hansson@arm.com } else if (id > 0x20 && id < 0x40) { 1608981Sandreas.hansson@arm.com reg_pmceid1 |= ((uint64_t)1) << (id - 0x20); 1618981Sandreas.hansson@arm.com } else if (id >= 0x4000 && id < 0x4020) { 1628981Sandreas.hansson@arm.com reg_pmceid0 |= ((uint64_t)1) << (id - 0x4000 + 32); 1638981Sandreas.hansson@arm.com } else if (id >= 0x4020 && id < 0x4040) { 1648981Sandreas.hansson@arm.com reg_pmceid1 |= ((uint64_t)1) << (id - 0x4020 + 32); 1658981Sandreas.hansson@arm.com } 1668981Sandreas.hansson@arm.com} 1678981Sandreas.hansson@arm.com 1688981Sandreas.hansson@arm.comvoid 1698981Sandreas.hansson@arm.comPMU::drainResume() 1708981Sandreas.hansson@arm.com{ 1718981Sandreas.hansson@arm.com // Re-attach enabled counters after a resume in case they changed. 1728981Sandreas.hansson@arm.com updateAllCounters(); 1738981Sandreas.hansson@arm.com} 1748981Sandreas.hansson@arm.com 1758981Sandreas.hansson@arm.comvoid 1768981Sandreas.hansson@arm.comPMU::regProbeListeners() 1778981Sandreas.hansson@arm.com{ 1788981Sandreas.hansson@arm.com 1798981Sandreas.hansson@arm.com // at this stage all probe configurations are done 1808981Sandreas.hansson@arm.com // counters can be configured 1818981Sandreas.hansson@arm.com for (uint32_t index = 0; index < maximumCounterCount-1; index++) { 1828981Sandreas.hansson@arm.com counters.emplace_back(*this, index); 1838981Sandreas.hansson@arm.com } 1848981Sandreas.hansson@arm.com 1858981Sandreas.hansson@arm.com PMUEvent *event = getEvent(cycleCounterEventId); 1868981Sandreas.hansson@arm.com panic_if(!event, "core cycle event is not present\n"); 1878981Sandreas.hansson@arm.com cycleCounter.enabled = true; 1888981Sandreas.hansson@arm.com cycleCounter.attach(event); 1898981Sandreas.hansson@arm.com} 1908981Sandreas.hansson@arm.com 1918981Sandreas.hansson@arm.comvoid 1928981Sandreas.hansson@arm.comPMU::setMiscReg(int misc_reg, RegVal val) 1938981Sandreas.hansson@arm.com{ 1948981Sandreas.hansson@arm.com DPRINTF(PMUVerbose, "setMiscReg(%s, 0x%x)\n", 1958981Sandreas.hansson@arm.com miscRegName[unflattenMiscReg(misc_reg)], val); 1968981Sandreas.hansson@arm.com 1978981Sandreas.hansson@arm.com switch (unflattenMiscReg(misc_reg)) { 1988981Sandreas.hansson@arm.com case MISCREG_PMCR_EL0: 1998981Sandreas.hansson@arm.com case MISCREG_PMCR: 2008981Sandreas.hansson@arm.com setControlReg(val); 2018981Sandreas.hansson@arm.com return; 2028981Sandreas.hansson@arm.com 2038981Sandreas.hansson@arm.com case MISCREG_PMCNTENSET_EL0: 2048981Sandreas.hansson@arm.com case MISCREG_PMCNTENSET: 2058981Sandreas.hansson@arm.com reg_pmcnten |= val; 2068981Sandreas.hansson@arm.com updateAllCounters(); 2078981Sandreas.hansson@arm.com return; 2088981Sandreas.hansson@arm.com 2098981Sandreas.hansson@arm.com case MISCREG_PMCNTENCLR_EL0: 2108981Sandreas.hansson@arm.com case MISCREG_PMCNTENCLR: 2118981Sandreas.hansson@arm.com reg_pmcnten &= ~val; 2128981Sandreas.hansson@arm.com updateAllCounters(); 2138981Sandreas.hansson@arm.com return; 2148981Sandreas.hansson@arm.com 2158981Sandreas.hansson@arm.com case MISCREG_PMOVSCLR_EL0: 2168981Sandreas.hansson@arm.com case MISCREG_PMOVSR: 2178981Sandreas.hansson@arm.com setOverflowStatus(reg_pmovsr & ~val); 2188981Sandreas.hansson@arm.com return; 2198981Sandreas.hansson@arm.com 2208981Sandreas.hansson@arm.com case MISCREG_PMSWINC_EL0: 2218981Sandreas.hansson@arm.com case MISCREG_PMSWINC: 2228981Sandreas.hansson@arm.com if (swIncrementEvent) { 2238981Sandreas.hansson@arm.com swIncrementEvent->write(val); 2248981Sandreas.hansson@arm.com } 2258981Sandreas.hansson@arm.com return; 2268981Sandreas.hansson@arm.com 2278981Sandreas.hansson@arm.com case MISCREG_PMCCNTR_EL0: 2288981Sandreas.hansson@arm.com case MISCREG_PMCCNTR: 2298981Sandreas.hansson@arm.com cycleCounter.setValue(val); 2308981Sandreas.hansson@arm.com return; 2318981Sandreas.hansson@arm.com 2328981Sandreas.hansson@arm.com case MISCREG_PMSELR_EL0: 2338981Sandreas.hansson@arm.com case MISCREG_PMSELR: 2348981Sandreas.hansson@arm.com reg_pmselr = val; 2358981Sandreas.hansson@arm.com return; 2368981Sandreas.hansson@arm.com //TODO: implement MISCREF_PMCEID{2,3} 2378981Sandreas.hansson@arm.com case MISCREG_PMCEID0_EL0: 2388981Sandreas.hansson@arm.com case MISCREG_PMCEID0: 2398981Sandreas.hansson@arm.com case MISCREG_PMCEID1_EL0: 2408981Sandreas.hansson@arm.com case MISCREG_PMCEID1: 2418981Sandreas.hansson@arm.com // Ignore writes 2428981Sandreas.hansson@arm.com return; 2438981Sandreas.hansson@arm.com 2448981Sandreas.hansson@arm.com case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0: 2458981Sandreas.hansson@arm.com setCounterTypeRegister(misc_reg - MISCREG_PMEVTYPER0_EL0, val); 2468981Sandreas.hansson@arm.com return; 2478981Sandreas.hansson@arm.com 2488981Sandreas.hansson@arm.com case MISCREG_PMCCFILTR: 2498981Sandreas.hansson@arm.com case MISCREG_PMCCFILTR_EL0: 2508981Sandreas.hansson@arm.com DPRINTF(PMUVerbose, "Setting PMCCFILTR: 0x%x\n", val); 2518981Sandreas.hansson@arm.com setCounterTypeRegister(PMCCNTR, val); 2528981Sandreas.hansson@arm.com return; 2538981Sandreas.hansson@arm.com 2548981Sandreas.hansson@arm.com case MISCREG_PMXEVTYPER_PMCCFILTR: 2558981Sandreas.hansson@arm.com case MISCREG_PMXEVTYPER_EL0: 2568981Sandreas.hansson@arm.com case MISCREG_PMXEVTYPER: 2578981Sandreas.hansson@arm.com DPRINTF(PMUVerbose, "Setting counter type: " 2588981Sandreas.hansson@arm.com "[PMSELR: 0x%x, PMSELER.sel: 0x%x, EVTYPER: 0x%x]\n", 2598981Sandreas.hansson@arm.com reg_pmselr, reg_pmselr.sel, val); 2608981Sandreas.hansson@arm.com setCounterTypeRegister(reg_pmselr.sel, val); 2618981Sandreas.hansson@arm.com return; 2628981Sandreas.hansson@arm.com 2638981Sandreas.hansson@arm.com case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0: 2648981Sandreas.hansson@arm.com setCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0, val); 2658981Sandreas.hansson@arm.com return; 2668981Sandreas.hansson@arm.com 2678981Sandreas.hansson@arm.com case MISCREG_PMXEVCNTR_EL0: 2688981Sandreas.hansson@arm.com case MISCREG_PMXEVCNTR: 2698981Sandreas.hansson@arm.com setCounterValue(reg_pmselr.sel, val); 2708981Sandreas.hansson@arm.com return; 2718981Sandreas.hansson@arm.com 2728981Sandreas.hansson@arm.com case MISCREG_PMUSERENR_EL0: 2738981Sandreas.hansson@arm.com case MISCREG_PMUSERENR: 2748981Sandreas.hansson@arm.com // TODO 2758981Sandreas.hansson@arm.com break; 2768981Sandreas.hansson@arm.com 2778981Sandreas.hansson@arm.com case MISCREG_PMINTENSET_EL1: 2788981Sandreas.hansson@arm.com case MISCREG_PMINTENSET: 2798981Sandreas.hansson@arm.com reg_pminten |= val; 2808981Sandreas.hansson@arm.com return; 2818981Sandreas.hansson@arm.com 2828981Sandreas.hansson@arm.com case MISCREG_PMINTENCLR_EL1: 2838981Sandreas.hansson@arm.com case MISCREG_PMINTENCLR: 2848981Sandreas.hansson@arm.com reg_pminten &= ~val; 2858981Sandreas.hansson@arm.com return; 2868981Sandreas.hansson@arm.com 2878981Sandreas.hansson@arm.com case MISCREG_PMOVSSET_EL0: 2888981Sandreas.hansson@arm.com case MISCREG_PMOVSSET: 2898981Sandreas.hansson@arm.com setOverflowStatus(reg_pmovsr | val); 2908981Sandreas.hansson@arm.com return; 2918981Sandreas.hansson@arm.com 2928981Sandreas.hansson@arm.com default: 2938981Sandreas.hansson@arm.com panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]); 2948981Sandreas.hansson@arm.com } 2958981Sandreas.hansson@arm.com 2968981Sandreas.hansson@arm.com warn("Not doing anything for write to miscreg %s\n", 2978981Sandreas.hansson@arm.com miscRegName[misc_reg]); 2988981Sandreas.hansson@arm.com} 2998981Sandreas.hansson@arm.com 3008981Sandreas.hansson@arm.comRegVal 3018981Sandreas.hansson@arm.comPMU::readMiscReg(int misc_reg) 3028981Sandreas.hansson@arm.com{ 3038981Sandreas.hansson@arm.com RegVal val(readMiscRegInt(misc_reg)); 3048981Sandreas.hansson@arm.com DPRINTF(PMUVerbose, "readMiscReg(%s): 0x%x\n", 3058981Sandreas.hansson@arm.com miscRegName[unflattenMiscReg(misc_reg)], val); 3068981Sandreas.hansson@arm.com return val; 3078981Sandreas.hansson@arm.com} 3088981Sandreas.hansson@arm.com 3098981Sandreas.hansson@arm.comRegVal 3108981Sandreas.hansson@arm.comPMU::readMiscRegInt(int misc_reg) 3118981Sandreas.hansson@arm.com{ 3128981Sandreas.hansson@arm.com misc_reg = unflattenMiscReg(misc_reg); 3138981Sandreas.hansson@arm.com switch (misc_reg) { 3148981Sandreas.hansson@arm.com case MISCREG_PMCR_EL0: 3158981Sandreas.hansson@arm.com case MISCREG_PMCR: 3168981Sandreas.hansson@arm.com return reg_pmcr_conf | (reg_pmcr & reg_pmcr_wr_mask); 3178981Sandreas.hansson@arm.com 3188981Sandreas.hansson@arm.com case MISCREG_PMCNTENSET_EL0: 3198981Sandreas.hansson@arm.com case MISCREG_PMCNTENCLR_EL0: 3208981Sandreas.hansson@arm.com case MISCREG_PMCNTENSET: 3218981Sandreas.hansson@arm.com case MISCREG_PMCNTENCLR: 3228981Sandreas.hansson@arm.com return reg_pmcnten; 3238981Sandreas.hansson@arm.com 3248981Sandreas.hansson@arm.com case MISCREG_PMOVSCLR_EL0: 3258981Sandreas.hansson@arm.com case MISCREG_PMOVSSET_EL0: 3268981Sandreas.hansson@arm.com case MISCREG_PMOVSR: // Overflow Status Register 3278981Sandreas.hansson@arm.com case MISCREG_PMOVSSET: 3288981Sandreas.hansson@arm.com return reg_pmovsr; 3298981Sandreas.hansson@arm.com 3308981Sandreas.hansson@arm.com case MISCREG_PMSWINC_EL0: 3318981Sandreas.hansson@arm.com case MISCREG_PMSWINC: // Software Increment Register (RAZ) 3328981Sandreas.hansson@arm.com return 0; 3338981Sandreas.hansson@arm.com 3348981Sandreas.hansson@arm.com case MISCREG_PMSELR: 3358981Sandreas.hansson@arm.com return reg_pmselr; 3368981Sandreas.hansson@arm.com 3378981Sandreas.hansson@arm.com case MISCREG_PMCEID0_EL0: 3388981Sandreas.hansson@arm.com return reg_pmceid0; 3398981Sandreas.hansson@arm.com 3408981Sandreas.hansson@arm.com case MISCREG_PMCEID1_EL0: 3418981Sandreas.hansson@arm.com return reg_pmceid1; 3428981Sandreas.hansson@arm.com 3438981Sandreas.hansson@arm.com //TODO: implement MISCREF_PMCEID{2,3} 3448981Sandreas.hansson@arm.com case MISCREG_PMCEID0: // Common Event ID register 3458981Sandreas.hansson@arm.com return reg_pmceid0 & 0xFFFFFFFF; 3468981Sandreas.hansson@arm.com 3478981Sandreas.hansson@arm.com case MISCREG_PMCEID1: // Common Event ID register 3488981Sandreas.hansson@arm.com return reg_pmceid1 & 0xFFFFFFFF; 3498981Sandreas.hansson@arm.com 3508981Sandreas.hansson@arm.com case MISCREG_PMCCNTR_EL0: 3518981Sandreas.hansson@arm.com return cycleCounter.getValue(); 3528981Sandreas.hansson@arm.com 3538981Sandreas.hansson@arm.com case MISCREG_PMCCNTR: 3548981Sandreas.hansson@arm.com return cycleCounter.getValue() & 0xFFFFFFFF; 3558981Sandreas.hansson@arm.com 3568981Sandreas.hansson@arm.com case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0: 3578981Sandreas.hansson@arm.com return getCounterTypeRegister(misc_reg - MISCREG_PMEVTYPER0_EL0); 3588981Sandreas.hansson@arm.com 3598981Sandreas.hansson@arm.com case MISCREG_PMCCFILTR: 3608981Sandreas.hansson@arm.com case MISCREG_PMCCFILTR_EL0: 3618981Sandreas.hansson@arm.com return getCounterTypeRegister(PMCCNTR); 3628981Sandreas.hansson@arm.com 3638981Sandreas.hansson@arm.com case MISCREG_PMXEVTYPER_PMCCFILTR: 3648981Sandreas.hansson@arm.com case MISCREG_PMXEVTYPER_EL0: 3658981Sandreas.hansson@arm.com case MISCREG_PMXEVTYPER: 3668981Sandreas.hansson@arm.com return getCounterTypeRegister(reg_pmselr.sel); 3678981Sandreas.hansson@arm.com 3688981Sandreas.hansson@arm.com case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0: { 3698981Sandreas.hansson@arm.com return getCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0) & 3708981Sandreas.hansson@arm.com 0xFFFFFFFF; 3718981Sandreas.hansson@arm.com 3728981Sandreas.hansson@arm.com } 3738981Sandreas.hansson@arm.com 3748981Sandreas.hansson@arm.com case MISCREG_PMXEVCNTR_EL0: 3758981Sandreas.hansson@arm.com case MISCREG_PMXEVCNTR: 3768981Sandreas.hansson@arm.com return getCounterValue(reg_pmselr.sel) & 0xFFFFFFFF; 3778981Sandreas.hansson@arm.com 3788981Sandreas.hansson@arm.com case MISCREG_PMUSERENR_EL0: 3798981Sandreas.hansson@arm.com case MISCREG_PMUSERENR: 3808981Sandreas.hansson@arm.com // TODO 3818981Sandreas.hansson@arm.com return 0; 3828981Sandreas.hansson@arm.com 3838981Sandreas.hansson@arm.com case MISCREG_PMINTENSET_EL1: 3848981Sandreas.hansson@arm.com case MISCREG_PMINTENCLR_EL1: 3858981Sandreas.hansson@arm.com case MISCREG_PMINTENSET: 3868981Sandreas.hansson@arm.com case MISCREG_PMINTENCLR: 3878981Sandreas.hansson@arm.com return reg_pminten; 3888981Sandreas.hansson@arm.com 3898981Sandreas.hansson@arm.com default: 3908981Sandreas.hansson@arm.com panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]); 3918981Sandreas.hansson@arm.com } 3928981Sandreas.hansson@arm.com 3938981Sandreas.hansson@arm.com warn("Not doing anything for read from miscreg %s\n", 3948981Sandreas.hansson@arm.com miscRegName[misc_reg]); 3958981Sandreas.hansson@arm.com return 0; 3968981Sandreas.hansson@arm.com} 3978981Sandreas.hansson@arm.com 3988981Sandreas.hansson@arm.comvoid 3998981Sandreas.hansson@arm.comPMU::setControlReg(PMCR_t val) 4008981Sandreas.hansson@arm.com{ 4018981Sandreas.hansson@arm.com DPRINTF(PMUVerbose, "Set Control Reg 0x%08x.\n", val); 4028981Sandreas.hansson@arm.com 4038981Sandreas.hansson@arm.com if (val.p) { 4048981Sandreas.hansson@arm.com DPRINTF(PMUVerbose, "PMU reset all events to zero.\n"); 4058981Sandreas.hansson@arm.com resetEventCounts(); 4068981Sandreas.hansson@arm.com } 4078981Sandreas.hansson@arm.com 4088981Sandreas.hansson@arm.com if (val.c) { 4098981Sandreas.hansson@arm.com DPRINTF(PMUVerbose, "PMU reset cycle counter to zero.\n"); 4108981Sandreas.hansson@arm.com cycleCounter.setValue(0); 4118981Sandreas.hansson@arm.com } 4128981Sandreas.hansson@arm.com 4138981Sandreas.hansson@arm.com // Reset the clock remainder if divide by 64-mode is toggled. 4148981Sandreas.hansson@arm.com if (reg_pmcr.d != val.d) 4158981Sandreas.hansson@arm.com clock_remainder = 0; 4168981Sandreas.hansson@arm.com 4178981Sandreas.hansson@arm.com reg_pmcr = val & reg_pmcr_wr_mask; 4188981Sandreas.hansson@arm.com updateAllCounters(); 4198981Sandreas.hansson@arm.com} 4208981Sandreas.hansson@arm.com 4218981Sandreas.hansson@arm.comvoid 4228981Sandreas.hansson@arm.comPMU::updateAllCounters() 4238981Sandreas.hansson@arm.com{ 4248981Sandreas.hansson@arm.com const bool global_enable(reg_pmcr.e); 4258981Sandreas.hansson@arm.com 4268981Sandreas.hansson@arm.com for (int i = 0; i < counters.size(); ++i) { 4278981Sandreas.hansson@arm.com CounterState &ctr(counters[i]); 4288981Sandreas.hansson@arm.com const bool enable(global_enable && (reg_pmcnten & (1 << i))); 4298981Sandreas.hansson@arm.com if (ctr.enabled != enable) { 4308981Sandreas.hansson@arm.com ctr.enabled = enable; 4318981Sandreas.hansson@arm.com updateCounter(ctr); 4328981Sandreas.hansson@arm.com } 433 } 434 435 const bool ccntr_enable(global_enable && (reg_pmcnten & (1 << PMCCNTR))); 436 if (cycleCounter.enabled != ccntr_enable) { 437 cycleCounter.enabled = ccntr_enable; 438 updateCounter(cycleCounter); 439 } 440} 441 442void 443PMU::PMUEvent::attachEvent(PMU::CounterState *user) 444{ 445 if (userCounters.empty()) { 446 enable(); 447 } 448 userCounters.insert(user); 449 updateAttachedCounters(); 450} 451 452void 453PMU::PMUEvent::increment(const uint64_t val) 454{ 455 for (auto& counter: userCounters) { 456 counter->add(val); 457 } 458} 459 460void 461PMU::PMUEvent::detachEvent(PMU::CounterState *user) 462{ 463 userCounters.erase(user); 464 465 if (userCounters.empty()) { 466 disable(); 467 } 468} 469 470void 471PMU::RegularEvent::RegularProbe::notify(const uint64_t &val) 472{ 473 parentEvent->increment(val); 474} 475 476void 477PMU::RegularEvent::enable() 478{ 479 for (auto& subEvents: microArchitectureEventSet) { 480 attachedProbePointList.emplace_back( 481 new RegularProbe(this, subEvents.first, subEvents.second)); 482 } 483} 484 485void 486PMU::RegularEvent::disable() 487{ 488 attachedProbePointList.clear(); 489} 490 491bool 492PMU::CounterState::isFiltered() const 493{ 494 assert(pmu.isa); 495 496 const PMEVTYPER_t filter(this->filter); 497 const SCR scr(pmu.isa->readMiscRegNoEffect(MISCREG_SCR)); 498 const CPSR cpsr(pmu.isa->readMiscRegNoEffect(MISCREG_CPSR)); 499 const ExceptionLevel el(opModeToEL((OperatingMode)(uint8_t)cpsr.mode)); 500 const bool secure(inSecureState(scr, cpsr)); 501 502 switch (el) { 503 case EL0: 504 return secure ? filter.u : (filter.u != filter.nsu); 505 506 case EL1: 507 return secure ? filter.p : (filter.p != filter.nsk); 508 509 case EL2: 510 return !filter.nsh; 511 512 case EL3: 513 return filter.p != filter.m; 514 515 default: 516 panic("Unexpected execution level in PMU::isFiltered.\n"); 517 } 518} 519 520void 521PMU::CounterState::detach() 522{ 523 if (sourceEvent) { 524 sourceEvent->detachEvent(this); 525 sourceEvent = nullptr; 526 } else { 527 debugCounter("detaching event not currently attached" 528 " to any event\n"); 529 } 530} 531 532void 533PMU::CounterState::attach(PMUEvent* event) 534{ 535 if (!resetValue) { 536 value = 0; 537 resetValue = true; 538 } 539 sourceEvent = event; 540 sourceEvent->attachEvent(this); 541} 542 543uint64_t 544PMU::CounterState::getValue() const 545{ 546 if (sourceEvent) { 547 sourceEvent->updateAttachedCounters(); 548 } else { 549 debugCounter("attempted to get value from a counter without" 550 " an associated event\n"); 551 } 552 return value; 553} 554 555void 556PMU::CounterState::setValue(uint64_t val) 557{ 558 value = val; 559 resetValue = true; 560 561 if (sourceEvent) { 562 sourceEvent->updateAttachedCounters(); 563 } else { 564 debugCounter("attempted to set value from a counter without" 565 " an associated event\n"); 566 } 567} 568 569void 570PMU::updateCounter(CounterState &ctr) 571{ 572 if (!ctr.enabled) { 573 DPRINTF(PMUVerbose, "updateCounter(%i): Disabling counter\n", 574 ctr.getCounterId()); 575 ctr.detach(); 576 577 } else { 578 DPRINTF(PMUVerbose, "updateCounter(%i): Enable event id 0x%x\n", 579 ctr.getCounterId(), ctr.eventId); 580 581 auto sourceEvent = eventMap.find(ctr.eventId); 582 if (sourceEvent == eventMap.end()) { 583 warn("Can't enable PMU counter of type '0x%x': " 584 "No such event type.\n", ctr.eventId); 585 } else { 586 ctr.attach(sourceEvent->second); 587 } 588 } 589} 590 591 592void 593PMU::resetEventCounts() 594{ 595 for (CounterState &ctr : counters) 596 ctr.setValue(0); 597} 598 599void 600PMU::setCounterValue(CounterId id, uint64_t val) 601{ 602 if (!isValidCounter(id)) { 603 warn_once("Can't change counter value: Counter %i does not exist.\n", 604 id); 605 return; 606 } 607 608 CounterState &ctr(getCounter(id)); 609 ctr.setValue(val); 610} 611 612PMU::PMEVTYPER_t 613PMU::getCounterTypeRegister(CounterId id) const 614{ 615 if (!isValidCounter(id)) 616 return 0; 617 618 const CounterState &cs(getCounter(id)); 619 PMEVTYPER_t type(cs.filter); 620 621 type.evtCount = cs.eventId; 622 623 return type; 624} 625 626void 627PMU::setCounterTypeRegister(CounterId id, PMEVTYPER_t val) 628{ 629 DPRINTF(PMUVerbose, "Set Event [%d] = 0x%08x\n", id, val); 630 if (!isValidCounter(id)) { 631 warn_once("Can't change counter type: Counter %i does not exist.\n", 632 id); 633 return; 634 } 635 636 CounterState &ctr(getCounter(id)); 637 const EventTypeId old_event_id(ctr.eventId); 638 639 ctr.filter = val; 640 641 // If PMCCNTR Register, do not change event type. PMCCNTR can 642 // count processor cycles only. If we change the event type, we 643 // need to update the probes the counter is using. 644 if (id != PMCCNTR && old_event_id != val.evtCount) { 645 ctr.eventId = val.evtCount; 646 updateCounter(ctr); 647 } 648} 649 650void 651PMU::setOverflowStatus(RegVal new_val) 652{ 653 const bool int_old = reg_pmovsr != 0; 654 const bool int_new = new_val != 0; 655 656 reg_pmovsr = new_val; 657 if (int_old && !int_new) { 658 clearInterrupt(); 659 } else if (!int_old && int_new && (reg_pminten & reg_pmovsr)) { 660 raiseInterrupt(); 661 } 662} 663 664void 665PMU::raiseInterrupt() 666{ 667 if (interrupt) { 668 DPRINTF(PMUVerbose, "Delivering PMU interrupt.\n"); 669 interrupt->raise(); 670 } else { 671 warn_once("Dropping PMU interrupt as no interrupt has " 672 "been specified\n"); 673 } 674} 675 676void 677PMU::clearInterrupt() 678{ 679 if (interrupt) { 680 DPRINTF(PMUVerbose, "Clearing PMU interrupt.\n"); 681 interrupt->clear(); 682 } else { 683 warn_once("Dropping PMU interrupt as no interrupt has " 684 "been specified\n"); 685 } 686} 687 688void 689PMU::serialize(CheckpointOut &cp) const 690{ 691 DPRINTF(Checkpoint, "Serializing Arm PMU\n"); 692 693 SERIALIZE_SCALAR(reg_pmcr); 694 SERIALIZE_SCALAR(reg_pmcnten); 695 SERIALIZE_SCALAR(reg_pmselr); 696 SERIALIZE_SCALAR(reg_pminten); 697 SERIALIZE_SCALAR(reg_pmovsr); 698 SERIALIZE_SCALAR(reg_pmceid0); 699 SERIALIZE_SCALAR(reg_pmceid1); 700 SERIALIZE_SCALAR(clock_remainder); 701 702 for (size_t i = 0; i < counters.size(); ++i) 703 counters[i].serializeSection(cp, csprintf("counters.%i", i)); 704 705 cycleCounter.serializeSection(cp, "cycleCounter"); 706} 707 708void 709PMU::unserialize(CheckpointIn &cp) 710{ 711 DPRINTF(Checkpoint, "Unserializing Arm PMU\n"); 712 713 UNSERIALIZE_SCALAR(reg_pmcr); 714 UNSERIALIZE_SCALAR(reg_pmcnten); 715 UNSERIALIZE_SCALAR(reg_pmselr); 716 UNSERIALIZE_SCALAR(reg_pminten); 717 UNSERIALIZE_SCALAR(reg_pmovsr); 718 719 // Old checkpoints used to store the entire PMCEID value in a 720 // single 64-bit entry (reg_pmceid). The register was extended in 721 // ARMv8.1, so we now need to store it as two 64-bit registers. 722 if (!UNSERIALIZE_OPT_SCALAR(reg_pmceid0)) 723 paramIn(cp, "reg_pmceid", reg_pmceid0); 724 725 if (!UNSERIALIZE_OPT_SCALAR(reg_pmceid1)) 726 reg_pmceid1 = 0; 727 728 UNSERIALIZE_SCALAR(clock_remainder); 729 730 for (size_t i = 0; i < counters.size(); ++i) 731 counters[i].unserializeSection(cp, csprintf("counters.%i", i)); 732 733 cycleCounter.unserializeSection(cp, "cycleCounter"); 734} 735 736PMU::PMUEvent* 737PMU::getEvent(uint64_t eventId) 738{ 739 auto entry = eventMap.find(eventId); 740 741 if (entry == eventMap.end()) { 742 warn("event %d does not exist\n", eventId); 743 return nullptr; 744 } else { 745 return entry->second; 746 } 747} 748 749void 750PMU::CounterState::serialize(CheckpointOut &cp) const 751{ 752 SERIALIZE_SCALAR(eventId); 753 SERIALIZE_SCALAR(value); 754 SERIALIZE_SCALAR(overflow64); 755} 756 757void 758PMU::CounterState::unserialize(CheckpointIn &cp) 759{ 760 UNSERIALIZE_SCALAR(eventId); 761 UNSERIALIZE_SCALAR(value); 762 UNSERIALIZE_SCALAR(overflow64); 763} 764 765uint64_t 766PMU::CounterState::add(uint64_t delta) 767{ 768 uint64_t value_until_overflow; 769 if (overflow64) { 770 value_until_overflow = UINT64_MAX - value; 771 } else { 772 value_until_overflow = UINT32_MAX - (uint32_t)value; 773 } 774 775 if (isFiltered()) 776 return value_until_overflow; 777 778 if (resetValue) { 779 delta = 0; 780 resetValue = false; 781 } else { 782 value += delta; 783 } 784 785 if (delta > value_until_overflow) { 786 787 // overflow situation detected 788 // flag the overflow occurence 789 pmu.reg_pmovsr |= (1 << counterId); 790 791 // Deliver a PMU interrupt if interrupt delivery is enabled 792 // for this counter. 793 if (pmu.reg_pminten & (1 << counterId)) { 794 pmu.raiseInterrupt(); 795 } 796 return overflow64 ? UINT64_MAX : UINT32_MAX; 797 } 798 return value_until_overflow - delta + 1; 799} 800 801void 802PMU::SWIncrementEvent::write(uint64_t val) 803{ 804 for (auto& counter: userCounters) { 805 if (val & (0x1 << counter->getCounterId())) { 806 counter->add(1); 807 } 808 } 809} 810 811} // namespace ArmISA 812 813ArmISA::PMU * 814ArmPMUParams::create() 815{ 816 return new ArmISA::PMU(this); 817} 818