1/* 2 * Copyright (c) 2011-2014 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions are 16 * met: redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer; 18 * redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution; 21 * neither the name of the copyright holders nor the names of its 22 * contributors may be used to endorse or promote products derived from 23 * this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 * 37 * Authors: Dam Sunwoo 38 * Matt Horsnell 39 * Andreas Sandberg 40 */ 41 42#include "arch/arm/pmu.hh" 43
| 1/* 2 * Copyright (c) 2011-2014 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions are 16 * met: redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer; 18 * redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution; 21 * neither the name of the copyright holders nor the names of its 22 * contributors may be used to endorse or promote products derived from 23 * this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 * 37 * Authors: Dam Sunwoo 38 * Matt Horsnell 39 * Andreas Sandberg 40 */ 41 42#include "arch/arm/pmu.hh" 43
|
| 44#include "arch/arm/isa.hh" 45#include "arch/arm/utility.hh"
|
44#include "base/trace.hh" 45#include "cpu/base.hh" 46#include "debug/Checkpoint.hh" 47#include "debug/PMUVerbose.hh" 48#include "dev/arm/base_gic.hh" 49#include "dev/arm/realview.hh" 50#include "params/ArmPMU.hh" 51 52namespace ArmISA { 53 54const MiscReg PMU::reg_pmcr_wr_mask = 0x39; 55 56PMU::PMU(const ArmPMUParams *p) 57 : SimObject(p), BaseISADevice(), 58 reg_pmcnten(0), reg_pmcr(0), 59 reg_pmselr(0), reg_pminten(0), reg_pmovsr(0), 60 reg_pmceid(0), 61 clock_remainder(0), 62 counters(p->eventCounters), 63 reg_pmcr_conf(0), 64 pmuInterrupt(p->pmuInterrupt), 65 platform(p->platform) 66{ 67 DPRINTF(PMUVerbose, "Initializing the PMU.\n"); 68 69 if (p->eventCounters > 31) { 70 fatal("The PMU can only accept 31 counters, %d counters requested.\n", 71 p->eventCounters); 72 } 73 74 /* Setup the performance counter ID registers */ 75 reg_pmcr_conf.imp = 0x41; // ARM Ltd. 76 reg_pmcr_conf.idcode = 0x00; 77 reg_pmcr_conf.n = p->eventCounters; 78 79 // Setup the hard-coded cycle counter, which is equivalent to 80 // architected counter event type 0x11. 81 cycleCounter.eventId = 0x11; 82} 83 84PMU::~PMU() 85{ 86} 87 88void 89PMU::addEventProbe(unsigned int id, SimObject *obj, const char *probe_name) 90{ 91 DPRINTF(PMUVerbose, "PMU: Adding event type '0x%x' as probe %s:%s\n", 92 id, obj->name(), probe_name); 93 pmuEventTypes.insert(std::make_pair(id, EventType(obj, probe_name))); 94 95 // Flag the event as available in the PMCEID register if it is an 96 // architected event. 97 if (id < 0x40) 98 reg_pmceid |= (ULL(1) << id); 99} 100 101void 102PMU::drainResume() 103{ 104 // Re-attach enabled counters after a resume in case they changed. 105 updateAllCounters(); 106} 107 108void 109PMU::setMiscReg(int misc_reg, MiscReg val) 110{ 111 DPRINTF(PMUVerbose, "setMiscReg(%s, 0x%x)\n", 112 miscRegName[unflattenMiscReg(misc_reg)], val); 113 114 switch (unflattenMiscReg(misc_reg)) { 115 case MISCREG_PMCR_EL0: 116 case MISCREG_PMCR: 117 setControlReg(val); 118 return; 119 120 case MISCREG_PMCNTENSET_EL0: 121 case MISCREG_PMCNTENSET: 122 reg_pmcnten |= val; 123 updateAllCounters(); 124 return; 125 126 case MISCREG_PMCNTENCLR_EL0: 127 case MISCREG_PMCNTENCLR: 128 reg_pmcnten &= ~val; 129 updateAllCounters(); 130 return; 131 132 case MISCREG_PMOVSCLR_EL0: 133 case MISCREG_PMOVSR: 134 reg_pmovsr &= ~val; 135 return; 136 137 case MISCREG_PMSWINC_EL0: 138 case MISCREG_PMSWINC: 139 for (int i = 0; i < counters.size(); ++i) { 140 CounterState &ctr(getCounter(i)); 141 if (ctr.enabled && (val & (1 << i))) 142 ++ctr.value; 143 } 144 break; 145 146 case MISCREG_PMCCNTR_EL0: 147 case MISCREG_PMCCNTR: 148 cycleCounter.value = val; 149 return; 150 151 case MISCREG_PMSELR_EL0: 152 case MISCREG_PMSELR: 153 reg_pmselr = val; 154 return; 155 156 case MISCREG_PMCEID0_EL0: 157 case MISCREG_PMCEID0: 158 case MISCREG_PMCEID1_EL0: 159 case MISCREG_PMCEID1: 160 // Ignore writes 161 return; 162 163 case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0: 164 setCounterTypeRegister(misc_reg - MISCREG_PMEVCNTR0_EL0, val); 165 return; 166 167 case MISCREG_PMCCFILTR: 168 case MISCREG_PMCCFILTR_EL0: 169 DPRINTF(PMUVerbose, "Setting PMCCFILTR: 0x%x\n", val); 170 setCounterTypeRegister(PMCCNTR, val); 171 return; 172 173 case MISCREG_PMXEVTYPER_PMCCFILTR: 174 case MISCREG_PMXEVTYPER_EL0: 175 case MISCREG_PMXEVTYPER: 176 DPRINTF(PMUVerbose, "Setting counter type: " 177 "[PMSELR: 0x%x, PMSELER.sel: 0x%x, EVTYPER: 0x%x]\n", 178 reg_pmselr, reg_pmselr.sel, val); 179 setCounterTypeRegister(reg_pmselr.sel, val); 180 return; 181 182 case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0: 183 setCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0, val); 184 return; 185 186 case MISCREG_PMXEVCNTR_EL0: 187 case MISCREG_PMXEVCNTR: 188 setCounterValue(reg_pmselr.sel, val); 189 return; 190 191 case MISCREG_PMUSERENR_EL0: 192 case MISCREG_PMUSERENR: 193 // TODO 194 break; 195 196 case MISCREG_PMINTENSET_EL1: 197 case MISCREG_PMINTENSET: 198 reg_pminten |= val; 199 return; 200 201 case MISCREG_PMINTENCLR_EL1: 202 case MISCREG_PMINTENCLR: 203 reg_pminten &= ~val; 204 return; 205 206 case MISCREG_PMOVSSET_EL0: 207 case MISCREG_PMOVSSET: 208 reg_pmovsr |= val; 209 return; 210 211 default: 212 panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]); 213 } 214 215 warn("Not doing anything for write to miscreg %s\n", 216 miscRegName[misc_reg]); 217} 218 219MiscReg 220PMU::readMiscReg(int misc_reg) 221{ 222 MiscReg val(readMiscRegInt(misc_reg)); 223 DPRINTF(PMUVerbose, "readMiscReg(%s): 0x%x\n", 224 miscRegName[unflattenMiscReg(misc_reg)], val); 225 return val; 226} 227 228MiscReg 229PMU::readMiscRegInt(int misc_reg) 230{ 231 misc_reg = unflattenMiscReg(misc_reg); 232 switch (misc_reg) { 233 case MISCREG_PMCR_EL0: 234 case MISCREG_PMCR: 235 return reg_pmcr_conf | (reg_pmcr & reg_pmcr_wr_mask); 236 237 case MISCREG_PMCNTENSET_EL0: 238 case MISCREG_PMCNTENCLR_EL0: 239 case MISCREG_PMCNTENSET: 240 case MISCREG_PMCNTENCLR: 241 return reg_pmcnten; 242 243 case MISCREG_PMOVSCLR_EL0: 244 case MISCREG_PMOVSSET_EL0: 245 case MISCREG_PMOVSR: // Overflow Status Register 246 case MISCREG_PMOVSSET: 247 return reg_pmovsr; 248 249 case MISCREG_PMSWINC_EL0: 250 case MISCREG_PMSWINC: // Software Increment Register (RAZ) 251 return 0; 252 253 case MISCREG_PMSELR: 254 return reg_pmselr; 255 256 case MISCREG_PMCEID0_EL0: 257 case MISCREG_PMCEID0: // Common Event ID register 258 return reg_pmceid & 0xFFFFFFFF; 259 260 case MISCREG_PMCEID1_EL0: 261 case MISCREG_PMCEID1: // Common Event ID register 262 return (reg_pmceid >> 32) & 0xFFFFFFFF; 263 264 case MISCREG_PMCCNTR_EL0: 265 return cycleCounter.value; 266 267 case MISCREG_PMCCNTR: 268 return cycleCounter.value & 0xFFFFFFFF; 269 270 case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0: 271 return getCounterTypeRegister(misc_reg - MISCREG_PMEVTYPER0_EL0); 272 273 case MISCREG_PMCCFILTR: 274 case MISCREG_PMCCFILTR_EL0: 275 return getCounterTypeRegister(PMCCNTR); 276 277 case MISCREG_PMXEVTYPER_PMCCFILTR: 278 case MISCREG_PMXEVTYPER_EL0: 279 case MISCREG_PMXEVTYPER: 280 return getCounterTypeRegister(reg_pmselr.sel); 281 282 case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0: 283 return getCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0) & 0xFFFFFFFF; 284 285 case MISCREG_PMXEVCNTR_EL0: 286 case MISCREG_PMXEVCNTR: 287 return getCounterValue(reg_pmselr.sel) & 0xFFFFFFFF; 288 289 case MISCREG_PMUSERENR_EL0: 290 case MISCREG_PMUSERENR: 291 // TODO 292 return 0; 293 294 case MISCREG_PMINTENSET_EL1: 295 case MISCREG_PMINTENCLR_EL1: 296 case MISCREG_PMINTENSET: 297 case MISCREG_PMINTENCLR: 298 return reg_pminten; 299 300 default: 301 panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]); 302 } 303 304 warn("Not doing anything for read from miscreg %s\n", 305 miscRegName[misc_reg]); 306 return 0; 307} 308 309void 310PMU::setControlReg(PMCR_t val) 311{ 312 DPRINTF(PMUVerbose, "Set Control Reg 0x%08x.\n", val); 313 314 if (val.p) { 315 DPRINTF(PMUVerbose, "PMU reset all events to zero.\n"); 316 resetEventCounts(); 317 } 318 319 if (val.c) { 320 DPRINTF(PMUVerbose, "PMU reset cycle counter to zero.\n"); 321 cycleCounter.value = 0; 322 } 323 324 // Reset the clock remainder if divide by 64-mode is toggled. 325 if (reg_pmcr.d != val.d) 326 clock_remainder = 0; 327 328 reg_pmcr = val & reg_pmcr_wr_mask; 329 updateAllCounters(); 330} 331 332void 333PMU::updateAllCounters() 334{ 335 const bool global_enable(reg_pmcr.e); 336 337 for (int i = 0; i < counters.size(); ++i) { 338 CounterState &ctr(counters[i]); 339 const bool enable(global_enable && (reg_pmcnten & (1 << i))); 340 if (ctr.enabled != enable) { 341 ctr.enabled = enable; 342 updateCounter(i, ctr); 343 } 344 } 345 346 const bool ccntr_enable(global_enable && (reg_pmcnten & (1 << PMCCNTR))); 347 if (cycleCounter.enabled != ccntr_enable) { 348 cycleCounter.enabled = ccntr_enable; 349 updateCounter(PMCCNTR, cycleCounter); 350 } 351} 352
| 46#include "base/trace.hh" 47#include "cpu/base.hh" 48#include "debug/Checkpoint.hh" 49#include "debug/PMUVerbose.hh" 50#include "dev/arm/base_gic.hh" 51#include "dev/arm/realview.hh" 52#include "params/ArmPMU.hh" 53 54namespace ArmISA { 55 56const MiscReg PMU::reg_pmcr_wr_mask = 0x39; 57 58PMU::PMU(const ArmPMUParams *p) 59 : SimObject(p), BaseISADevice(), 60 reg_pmcnten(0), reg_pmcr(0), 61 reg_pmselr(0), reg_pminten(0), reg_pmovsr(0), 62 reg_pmceid(0), 63 clock_remainder(0), 64 counters(p->eventCounters), 65 reg_pmcr_conf(0), 66 pmuInterrupt(p->pmuInterrupt), 67 platform(p->platform) 68{ 69 DPRINTF(PMUVerbose, "Initializing the PMU.\n"); 70 71 if (p->eventCounters > 31) { 72 fatal("The PMU can only accept 31 counters, %d counters requested.\n", 73 p->eventCounters); 74 } 75 76 /* Setup the performance counter ID registers */ 77 reg_pmcr_conf.imp = 0x41; // ARM Ltd. 78 reg_pmcr_conf.idcode = 0x00; 79 reg_pmcr_conf.n = p->eventCounters; 80 81 // Setup the hard-coded cycle counter, which is equivalent to 82 // architected counter event type 0x11. 83 cycleCounter.eventId = 0x11; 84} 85 86PMU::~PMU() 87{ 88} 89 90void 91PMU::addEventProbe(unsigned int id, SimObject *obj, const char *probe_name) 92{ 93 DPRINTF(PMUVerbose, "PMU: Adding event type '0x%x' as probe %s:%s\n", 94 id, obj->name(), probe_name); 95 pmuEventTypes.insert(std::make_pair(id, EventType(obj, probe_name))); 96 97 // Flag the event as available in the PMCEID register if it is an 98 // architected event. 99 if (id < 0x40) 100 reg_pmceid |= (ULL(1) << id); 101} 102 103void 104PMU::drainResume() 105{ 106 // Re-attach enabled counters after a resume in case they changed. 107 updateAllCounters(); 108} 109 110void 111PMU::setMiscReg(int misc_reg, MiscReg val) 112{ 113 DPRINTF(PMUVerbose, "setMiscReg(%s, 0x%x)\n", 114 miscRegName[unflattenMiscReg(misc_reg)], val); 115 116 switch (unflattenMiscReg(misc_reg)) { 117 case MISCREG_PMCR_EL0: 118 case MISCREG_PMCR: 119 setControlReg(val); 120 return; 121 122 case MISCREG_PMCNTENSET_EL0: 123 case MISCREG_PMCNTENSET: 124 reg_pmcnten |= val; 125 updateAllCounters(); 126 return; 127 128 case MISCREG_PMCNTENCLR_EL0: 129 case MISCREG_PMCNTENCLR: 130 reg_pmcnten &= ~val; 131 updateAllCounters(); 132 return; 133 134 case MISCREG_PMOVSCLR_EL0: 135 case MISCREG_PMOVSR: 136 reg_pmovsr &= ~val; 137 return; 138 139 case MISCREG_PMSWINC_EL0: 140 case MISCREG_PMSWINC: 141 for (int i = 0; i < counters.size(); ++i) { 142 CounterState &ctr(getCounter(i)); 143 if (ctr.enabled && (val & (1 << i))) 144 ++ctr.value; 145 } 146 break; 147 148 case MISCREG_PMCCNTR_EL0: 149 case MISCREG_PMCCNTR: 150 cycleCounter.value = val; 151 return; 152 153 case MISCREG_PMSELR_EL0: 154 case MISCREG_PMSELR: 155 reg_pmselr = val; 156 return; 157 158 case MISCREG_PMCEID0_EL0: 159 case MISCREG_PMCEID0: 160 case MISCREG_PMCEID1_EL0: 161 case MISCREG_PMCEID1: 162 // Ignore writes 163 return; 164 165 case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0: 166 setCounterTypeRegister(misc_reg - MISCREG_PMEVCNTR0_EL0, val); 167 return; 168 169 case MISCREG_PMCCFILTR: 170 case MISCREG_PMCCFILTR_EL0: 171 DPRINTF(PMUVerbose, "Setting PMCCFILTR: 0x%x\n", val); 172 setCounterTypeRegister(PMCCNTR, val); 173 return; 174 175 case MISCREG_PMXEVTYPER_PMCCFILTR: 176 case MISCREG_PMXEVTYPER_EL0: 177 case MISCREG_PMXEVTYPER: 178 DPRINTF(PMUVerbose, "Setting counter type: " 179 "[PMSELR: 0x%x, PMSELER.sel: 0x%x, EVTYPER: 0x%x]\n", 180 reg_pmselr, reg_pmselr.sel, val); 181 setCounterTypeRegister(reg_pmselr.sel, val); 182 return; 183 184 case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0: 185 setCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0, val); 186 return; 187 188 case MISCREG_PMXEVCNTR_EL0: 189 case MISCREG_PMXEVCNTR: 190 setCounterValue(reg_pmselr.sel, val); 191 return; 192 193 case MISCREG_PMUSERENR_EL0: 194 case MISCREG_PMUSERENR: 195 // TODO 196 break; 197 198 case MISCREG_PMINTENSET_EL1: 199 case MISCREG_PMINTENSET: 200 reg_pminten |= val; 201 return; 202 203 case MISCREG_PMINTENCLR_EL1: 204 case MISCREG_PMINTENCLR: 205 reg_pminten &= ~val; 206 return; 207 208 case MISCREG_PMOVSSET_EL0: 209 case MISCREG_PMOVSSET: 210 reg_pmovsr |= val; 211 return; 212 213 default: 214 panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]); 215 } 216 217 warn("Not doing anything for write to miscreg %s\n", 218 miscRegName[misc_reg]); 219} 220 221MiscReg 222PMU::readMiscReg(int misc_reg) 223{ 224 MiscReg val(readMiscRegInt(misc_reg)); 225 DPRINTF(PMUVerbose, "readMiscReg(%s): 0x%x\n", 226 miscRegName[unflattenMiscReg(misc_reg)], val); 227 return val; 228} 229 230MiscReg 231PMU::readMiscRegInt(int misc_reg) 232{ 233 misc_reg = unflattenMiscReg(misc_reg); 234 switch (misc_reg) { 235 case MISCREG_PMCR_EL0: 236 case MISCREG_PMCR: 237 return reg_pmcr_conf | (reg_pmcr & reg_pmcr_wr_mask); 238 239 case MISCREG_PMCNTENSET_EL0: 240 case MISCREG_PMCNTENCLR_EL0: 241 case MISCREG_PMCNTENSET: 242 case MISCREG_PMCNTENCLR: 243 return reg_pmcnten; 244 245 case MISCREG_PMOVSCLR_EL0: 246 case MISCREG_PMOVSSET_EL0: 247 case MISCREG_PMOVSR: // Overflow Status Register 248 case MISCREG_PMOVSSET: 249 return reg_pmovsr; 250 251 case MISCREG_PMSWINC_EL0: 252 case MISCREG_PMSWINC: // Software Increment Register (RAZ) 253 return 0; 254 255 case MISCREG_PMSELR: 256 return reg_pmselr; 257 258 case MISCREG_PMCEID0_EL0: 259 case MISCREG_PMCEID0: // Common Event ID register 260 return reg_pmceid & 0xFFFFFFFF; 261 262 case MISCREG_PMCEID1_EL0: 263 case MISCREG_PMCEID1: // Common Event ID register 264 return (reg_pmceid >> 32) & 0xFFFFFFFF; 265 266 case MISCREG_PMCCNTR_EL0: 267 return cycleCounter.value; 268 269 case MISCREG_PMCCNTR: 270 return cycleCounter.value & 0xFFFFFFFF; 271 272 case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0: 273 return getCounterTypeRegister(misc_reg - MISCREG_PMEVTYPER0_EL0); 274 275 case MISCREG_PMCCFILTR: 276 case MISCREG_PMCCFILTR_EL0: 277 return getCounterTypeRegister(PMCCNTR); 278 279 case MISCREG_PMXEVTYPER_PMCCFILTR: 280 case MISCREG_PMXEVTYPER_EL0: 281 case MISCREG_PMXEVTYPER: 282 return getCounterTypeRegister(reg_pmselr.sel); 283 284 case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0: 285 return getCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0) & 0xFFFFFFFF; 286 287 case MISCREG_PMXEVCNTR_EL0: 288 case MISCREG_PMXEVCNTR: 289 return getCounterValue(reg_pmselr.sel) & 0xFFFFFFFF; 290 291 case MISCREG_PMUSERENR_EL0: 292 case MISCREG_PMUSERENR: 293 // TODO 294 return 0; 295 296 case MISCREG_PMINTENSET_EL1: 297 case MISCREG_PMINTENCLR_EL1: 298 case MISCREG_PMINTENSET: 299 case MISCREG_PMINTENCLR: 300 return reg_pminten; 301 302 default: 303 panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]); 304 } 305 306 warn("Not doing anything for read from miscreg %s\n", 307 miscRegName[misc_reg]); 308 return 0; 309} 310 311void 312PMU::setControlReg(PMCR_t val) 313{ 314 DPRINTF(PMUVerbose, "Set Control Reg 0x%08x.\n", val); 315 316 if (val.p) { 317 DPRINTF(PMUVerbose, "PMU reset all events to zero.\n"); 318 resetEventCounts(); 319 } 320 321 if (val.c) { 322 DPRINTF(PMUVerbose, "PMU reset cycle counter to zero.\n"); 323 cycleCounter.value = 0; 324 } 325 326 // Reset the clock remainder if divide by 64-mode is toggled. 327 if (reg_pmcr.d != val.d) 328 clock_remainder = 0; 329 330 reg_pmcr = val & reg_pmcr_wr_mask; 331 updateAllCounters(); 332} 333 334void 335PMU::updateAllCounters() 336{ 337 const bool global_enable(reg_pmcr.e); 338 339 for (int i = 0; i < counters.size(); ++i) { 340 CounterState &ctr(counters[i]); 341 const bool enable(global_enable && (reg_pmcnten & (1 << i))); 342 if (ctr.enabled != enable) { 343 ctr.enabled = enable; 344 updateCounter(i, ctr); 345 } 346 } 347 348 const bool ccntr_enable(global_enable && (reg_pmcnten & (1 << PMCCNTR))); 349 if (cycleCounter.enabled != ccntr_enable) { 350 cycleCounter.enabled = ccntr_enable; 351 updateCounter(PMCCNTR, cycleCounter); 352 } 353} 354
|
| 355bool 356PMU::isFiltered(const CounterState &ctr) const 357{ 358 assert(isa); 359 360 const PMEVTYPER_t filter(ctr.filter); 361 const SCR scr(isa->readMiscRegNoEffect(MISCREG_SCR)); 362 const CPSR cpsr(isa->readMiscRegNoEffect(MISCREG_CPSR)); 363 const ExceptionLevel el(opModeToEL((OperatingMode)(uint8_t)cpsr.mode)); 364 const bool secure(inSecureState(scr, cpsr)); 365 366 switch (el) { 367 case EL0: 368 return secure ? filter.u : (filter.u != filter.nsu); 369 370 case EL1: 371 return secure ? filter.p : (filter.p != filter.nsk); 372 373 case EL2: 374 return !filter.nsh; 375 376 case EL3: 377 return filter.p != filter.m; 378 379 default: 380 panic("Unexpected execution level in PMU::isFiltered.\n"); 381 } 382} 383
|
353void 354PMU::handleEvent(CounterId id, uint64_t delta) 355{ 356 CounterState &ctr(getCounter(id)); 357 const bool overflowed(reg_pmovsr & (1 << id)); 358
| 384void 385PMU::handleEvent(CounterId id, uint64_t delta) 386{ 387 CounterState &ctr(getCounter(id)); 388 const bool overflowed(reg_pmovsr & (1 << id)); 389
|
| 390 if (isFiltered(ctr)) 391 return; 392
|
359 // Handle the "count every 64 cycles" mode 360 if (id == PMCCNTR && reg_pmcr.d) { 361 clock_remainder += delta; 362 delta = (clock_remainder >> 6); 363 clock_remainder &= 63; 364 } 365 366 // Add delta and handle (new) overflows 367 if (ctr.add(delta) && !overflowed) { 368 DPRINTF(PMUVerbose, "PMU counter '%i' overflowed.\n", id); 369 reg_pmovsr |= (1 << id); 370 // Deliver a PMU interrupt if interrupt delivery is enabled 371 // for this counter. 372 if (reg_pminten & (1 << id)) 373 raiseInterrupt(); 374 } 375} 376 377void 378PMU::updateCounter(CounterId id, CounterState &ctr) 379{ 380 if (!ctr.enabled) { 381 if (!ctr.listeners.empty()) { 382 DPRINTF(PMUVerbose, "updateCounter(%i): Disabling counter\n", id); 383 ctr.listeners.clear(); 384 } 385 } else { 386 DPRINTF(PMUVerbose, "updateCounter(%i): Enable event id 0x%x\n", 387 id, ctr.eventId); 388 389 // Attach all probes belonging to this event 390 auto range(pmuEventTypes.equal_range(ctr.eventId)); 391 for (auto it = range.first; it != range.second; ++it) { 392 const EventType &et(it->second); 393 394 DPRINTF(PMUVerbose, "\tProbe: %s:%s\n", et.obj->name(), et.name); 395 ctr.listeners.emplace_back(et.create(*this, id)); 396 } 397 398 /* The SW_INCR event type is a special case which doesn't need 399 * any probes since it is controlled by software and the PMU 400 * itself. 401 */ 402 if (ctr.listeners.empty() && ctr.eventId != ARCH_EVENT_SW_INCR) { 403 warn("Can't enable PMU counter of type '0x%x': " 404 "No such event type.\n", ctr.eventId); 405 } 406 } 407} 408 409 410void 411PMU::resetEventCounts() 412{ 413 for (CounterState &ctr : counters) 414 ctr.value = 0; 415} 416 417void 418PMU::setCounterValue(CounterId id, uint64_t val) 419{ 420 if (!isValidCounter(id)) { 421 warn_once("Can't change counter value: Counter %i does not exist.\n", 422 id); 423 return; 424 } 425 426 CounterState &ctr(getCounter(id)); 427 ctr.value = val; 428} 429 430PMU::PMEVTYPER_t 431PMU::getCounterTypeRegister(CounterId id) const 432{ 433 if (!isValidCounter(id)) 434 return 0; 435 436 const CounterState &cs(getCounter(id));
| 393 // Handle the "count every 64 cycles" mode 394 if (id == PMCCNTR && reg_pmcr.d) { 395 clock_remainder += delta; 396 delta = (clock_remainder >> 6); 397 clock_remainder &= 63; 398 } 399 400 // Add delta and handle (new) overflows 401 if (ctr.add(delta) && !overflowed) { 402 DPRINTF(PMUVerbose, "PMU counter '%i' overflowed.\n", id); 403 reg_pmovsr |= (1 << id); 404 // Deliver a PMU interrupt if interrupt delivery is enabled 405 // for this counter. 406 if (reg_pminten & (1 << id)) 407 raiseInterrupt(); 408 } 409} 410 411void 412PMU::updateCounter(CounterId id, CounterState &ctr) 413{ 414 if (!ctr.enabled) { 415 if (!ctr.listeners.empty()) { 416 DPRINTF(PMUVerbose, "updateCounter(%i): Disabling counter\n", id); 417 ctr.listeners.clear(); 418 } 419 } else { 420 DPRINTF(PMUVerbose, "updateCounter(%i): Enable event id 0x%x\n", 421 id, ctr.eventId); 422 423 // Attach all probes belonging to this event 424 auto range(pmuEventTypes.equal_range(ctr.eventId)); 425 for (auto it = range.first; it != range.second; ++it) { 426 const EventType &et(it->second); 427 428 DPRINTF(PMUVerbose, "\tProbe: %s:%s\n", et.obj->name(), et.name); 429 ctr.listeners.emplace_back(et.create(*this, id)); 430 } 431 432 /* The SW_INCR event type is a special case which doesn't need 433 * any probes since it is controlled by software and the PMU 434 * itself. 435 */ 436 if (ctr.listeners.empty() && ctr.eventId != ARCH_EVENT_SW_INCR) { 437 warn("Can't enable PMU counter of type '0x%x': " 438 "No such event type.\n", ctr.eventId); 439 } 440 } 441} 442 443 444void 445PMU::resetEventCounts() 446{ 447 for (CounterState &ctr : counters) 448 ctr.value = 0; 449} 450 451void 452PMU::setCounterValue(CounterId id, uint64_t val) 453{ 454 if (!isValidCounter(id)) { 455 warn_once("Can't change counter value: Counter %i does not exist.\n", 456 id); 457 return; 458 } 459 460 CounterState &ctr(getCounter(id)); 461 ctr.value = val; 462} 463 464PMU::PMEVTYPER_t 465PMU::getCounterTypeRegister(CounterId id) const 466{ 467 if (!isValidCounter(id)) 468 return 0; 469 470 const CounterState &cs(getCounter(id));
|
437 PMEVTYPER_t type(0);
| 471 PMEVTYPER_t type(cs.filter);
|
438
| 472
|
439 // TODO: Re-create filtering settings from counter state
| |
440 type.evtCount = cs.eventId; 441 442 return type; 443} 444 445void 446PMU::setCounterTypeRegister(CounterId id, PMEVTYPER_t val) 447{ 448 DPRINTF(PMUVerbose, "Set Event [%d] = 0x%08x\n", id, val); 449 if (!isValidCounter(id)) { 450 warn_once("Can't change counter type: Counter %i does not exist.\n", 451 id); 452 return; 453 } 454 455 CounterState &ctr(getCounter(id));
| 473 type.evtCount = cs.eventId; 474 475 return type; 476} 477 478void 479PMU::setCounterTypeRegister(CounterId id, PMEVTYPER_t val) 480{ 481 DPRINTF(PMUVerbose, "Set Event [%d] = 0x%08x\n", id, val); 482 if (!isValidCounter(id)) { 483 warn_once("Can't change counter type: Counter %i does not exist.\n", 484 id); 485 return; 486 } 487 488 CounterState &ctr(getCounter(id));
|
456 // TODO: Handle filtering (both for general purpose counters and 457 // the cycle counter)
| 489 const EventTypeId old_event_id(ctr.eventId);
|
458
| 490
|
459 // If PMCCNTR Register, do not change event type. PMCCNTR can count 460 // processor cycles only. 461 if (id != PMCCNTR) {
| 491 ctr.filter = val; 492 493 // If PMCCNTR Register, do not change event type. PMCCNTR can 494 // count processor cycles only. If we change the event type, we 495 // need to update the probes the counter is using. 496 if (id != PMCCNTR && old_event_id != val.evtCount) {
|
462 ctr.eventId = val.evtCount; 463 updateCounter(reg_pmselr.sel, ctr); 464 } 465} 466 467void 468PMU::raiseInterrupt() 469{ 470 RealView *rv(dynamic_cast<RealView *>(platform)); 471 if (!rv || !rv->gic) { 472 warn_once("ARM PMU: GIC missing, can't raise interrupt.\n"); 473 return; 474 } 475 476 DPRINTF(PMUVerbose, "Delivering PMU interrupt.\n"); 477 rv->gic->sendInt(pmuInterrupt); 478} 479 480void 481PMU::serialize(std::ostream &os) 482{ 483 DPRINTF(Checkpoint, "Serializing Arm PMU\n"); 484 485 SERIALIZE_SCALAR(reg_pmcr); 486 SERIALIZE_SCALAR(reg_pmcnten); 487 SERIALIZE_SCALAR(reg_pmselr); 488 SERIALIZE_SCALAR(reg_pminten); 489 SERIALIZE_SCALAR(reg_pmovsr); 490 SERIALIZE_SCALAR(reg_pmceid); 491 SERIALIZE_SCALAR(clock_remainder); 492 493 for (size_t i = 0; i < counters.size(); ++i) { 494 nameOut(os, csprintf("%s.counters.%i", name(), i)); 495 counters[i].serialize(os); 496 } 497 498 nameOut(os, csprintf("%s.cycleCounter", name())); 499 cycleCounter.serialize(os); 500} 501 502void 503PMU::unserialize(Checkpoint *cp, const std::string §ion) 504{ 505 DPRINTF(Checkpoint, "Unserializing Arm PMU\n"); 506 507 UNSERIALIZE_SCALAR(reg_pmcr); 508 UNSERIALIZE_SCALAR(reg_pmcnten); 509 UNSERIALIZE_SCALAR(reg_pmselr); 510 UNSERIALIZE_SCALAR(reg_pminten); 511 UNSERIALIZE_SCALAR(reg_pmovsr); 512 UNSERIALIZE_SCALAR(reg_pmceid); 513 UNSERIALIZE_SCALAR(clock_remainder); 514 515 for (size_t i = 0; i < counters.size(); ++i) 516 counters[i].unserialize(cp, csprintf("%s.counters.%i", section, i)); 517 518 cycleCounter.unserialize(cp, csprintf("%s.cycleCounter", section)); 519} 520 521void 522PMU::CounterState::serialize(std::ostream &os) 523{ 524 SERIALIZE_SCALAR(eventId); 525 SERIALIZE_SCALAR(value); 526 SERIALIZE_SCALAR(enabled); 527 SERIALIZE_SCALAR(overflow64); 528} 529 530void 531PMU::CounterState::unserialize(Checkpoint *cp, const std::string §ion) 532{ 533 UNSERIALIZE_SCALAR(eventId); 534 UNSERIALIZE_SCALAR(value); 535 UNSERIALIZE_SCALAR(enabled); 536 UNSERIALIZE_SCALAR(overflow64); 537} 538 539bool 540PMU::CounterState::add(uint64_t delta) 541{ 542 const uint64_t msb(1ULL << (overflow64 ? 63 : 31)); 543 const uint64_t old_value(value); 544 545 assert(delta > 0); 546 547 value += delta; 548 549 // Overflow if the msb goes from 1 to 0 550 return (old_value & msb) && !(value & msb); 551} 552 553} // namespace ArmISA 554 555ArmISA::PMU * 556ArmPMUParams::create() 557{ 558 return new ArmISA::PMU(this); 559}
| 497 ctr.eventId = val.evtCount; 498 updateCounter(reg_pmselr.sel, ctr); 499 } 500} 501 502void 503PMU::raiseInterrupt() 504{ 505 RealView *rv(dynamic_cast<RealView *>(platform)); 506 if (!rv || !rv->gic) { 507 warn_once("ARM PMU: GIC missing, can't raise interrupt.\n"); 508 return; 509 } 510 511 DPRINTF(PMUVerbose, "Delivering PMU interrupt.\n"); 512 rv->gic->sendInt(pmuInterrupt); 513} 514 515void 516PMU::serialize(std::ostream &os) 517{ 518 DPRINTF(Checkpoint, "Serializing Arm PMU\n"); 519 520 SERIALIZE_SCALAR(reg_pmcr); 521 SERIALIZE_SCALAR(reg_pmcnten); 522 SERIALIZE_SCALAR(reg_pmselr); 523 SERIALIZE_SCALAR(reg_pminten); 524 SERIALIZE_SCALAR(reg_pmovsr); 525 SERIALIZE_SCALAR(reg_pmceid); 526 SERIALIZE_SCALAR(clock_remainder); 527 528 for (size_t i = 0; i < counters.size(); ++i) { 529 nameOut(os, csprintf("%s.counters.%i", name(), i)); 530 counters[i].serialize(os); 531 } 532 533 nameOut(os, csprintf("%s.cycleCounter", name())); 534 cycleCounter.serialize(os); 535} 536 537void 538PMU::unserialize(Checkpoint *cp, const std::string §ion) 539{ 540 DPRINTF(Checkpoint, "Unserializing Arm PMU\n"); 541 542 UNSERIALIZE_SCALAR(reg_pmcr); 543 UNSERIALIZE_SCALAR(reg_pmcnten); 544 UNSERIALIZE_SCALAR(reg_pmselr); 545 UNSERIALIZE_SCALAR(reg_pminten); 546 UNSERIALIZE_SCALAR(reg_pmovsr); 547 UNSERIALIZE_SCALAR(reg_pmceid); 548 UNSERIALIZE_SCALAR(clock_remainder); 549 550 for (size_t i = 0; i < counters.size(); ++i) 551 counters[i].unserialize(cp, csprintf("%s.counters.%i", section, i)); 552 553 cycleCounter.unserialize(cp, csprintf("%s.cycleCounter", section)); 554} 555 556void 557PMU::CounterState::serialize(std::ostream &os) 558{ 559 SERIALIZE_SCALAR(eventId); 560 SERIALIZE_SCALAR(value); 561 SERIALIZE_SCALAR(enabled); 562 SERIALIZE_SCALAR(overflow64); 563} 564 565void 566PMU::CounterState::unserialize(Checkpoint *cp, const std::string §ion) 567{ 568 UNSERIALIZE_SCALAR(eventId); 569 UNSERIALIZE_SCALAR(value); 570 UNSERIALIZE_SCALAR(enabled); 571 UNSERIALIZE_SCALAR(overflow64); 572} 573 574bool 575PMU::CounterState::add(uint64_t delta) 576{ 577 const uint64_t msb(1ULL << (overflow64 ? 63 : 31)); 578 const uint64_t old_value(value); 579 580 assert(delta > 0); 581 582 value += delta; 583 584 // Overflow if the msb goes from 1 to 0 585 return (old_value & msb) && !(value & msb); 586} 587 588} // namespace ArmISA 589 590ArmISA::PMU * 591ArmPMUParams::create() 592{ 593 return new ArmISA::PMU(this); 594}
|