pmu.cc revision 13104:4a0713e11ef7
1/* 2 * Copyright (c) 2011-2014, 2017-2018 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 * Jose Marinho 41 */ 42 43#include "arch/arm/pmu.hh" 44 45#include "arch/arm/isa.hh" 46#include "arch/arm/utility.hh" 47#include "base/trace.hh" 48#include "cpu/base.hh" 49#include "debug/Checkpoint.hh" 50#include "debug/PMUVerbose.hh" 51#include "dev/arm/base_gic.hh" 52#include "dev/arm/generic_timer.hh" 53#include "params/ArmPMU.hh" 54 55namespace ArmISA { 56 57const MiscReg PMU::reg_pmcr_wr_mask = 0x39; 58 59PMU::PMU(const ArmPMUParams *p) 60 : SimObject(p), BaseISADevice(), 61 reg_pmcnten(0), reg_pmcr(0), 62 reg_pmselr(0), reg_pminten(0), reg_pmovsr(0), 63 reg_pmceid0(0),reg_pmceid1(0), 64 clock_remainder(0), 65 maximumCounterCount(p->eventCounters), 66 cycleCounter(*this, maximumCounterCount), 67 cycleCounterEventId(p->cycleEventId), 68 swIncrementEvent(nullptr), 69 reg_pmcr_conf(0), 70 interrupt(p->interrupt->get()) 71{ 72 DPRINTF(PMUVerbose, "Initializing the PMU.\n"); 73 74 if (maximumCounterCount > 31) { 75 fatal("The PMU can only accept 31 counters, %d counters requested.\n", 76 maximumCounterCount); 77 } 78 79 warn_if(!interrupt, "ARM PMU: No interrupt specified, interrupt " \ 80 "delivery disabled.\n"); 81 82 /* Setup the performance counter ID registers */ 83 reg_pmcr_conf.imp = 0x41; // ARM Ltd. 84 reg_pmcr_conf.idcode = 0x00; 85 reg_pmcr_conf.n = p->eventCounters; 86 87 // Setup the hard-coded cycle counter, which is equivalent to 88 // architected counter event type 0x11. 89 cycleCounter.eventId = 0x11; 90} 91 92PMU::~PMU() 93{ 94} 95 96void 97PMU::setThreadContext(ThreadContext *tc) 98{ 99 DPRINTF(PMUVerbose, "Assigning PMU to ContextID %i.\n", tc->contextId()); 100 if (interrupt) 101 interrupt->setThreadContext(tc); 102} 103 104void 105PMU::addSoftwareIncrementEvent(unsigned int id) 106{ 107 auto old_event = eventMap.find(id); 108 DPRINTF(PMUVerbose, "PMU: Adding SW increment event with id '0x%x'\n", id); 109 110 if (swIncrementEvent) { 111 fatal_if(old_event == eventMap.end() || 112 old_event->second != swIncrementEvent, 113 "Trying to add a software increment event with multiple" 114 "IDs. This is not supported.\n"); 115 return; 116 } 117 118 fatal_if(old_event != eventMap.end(), "An event with id %d has " 119 "been previously defined\n", id); 120 121 swIncrementEvent = new SWIncrementEvent(); 122 eventMap[id] = swIncrementEvent; 123 registerEvent(id); 124} 125 126void 127PMU::addEventProbe(unsigned int id, SimObject *obj, const char *probe_name) 128{ 129 130 DPRINTF(PMUVerbose, "PMU: Adding Probe Driven event with id '0x%x'" 131 "as probe %s:%s\n",id, obj->name(), probe_name); 132 133 RegularEvent *event = nullptr; 134 auto event_entry = eventMap.find(id); 135 if (event_entry == eventMap.end()) { 136 137 event = new RegularEvent(); 138 eventMap[id] = event; 139 140 } else { 141 event = dynamic_cast<RegularEvent*>(event_entry->second); 142 if (!event) { 143 fatal("Event with id %d is not probe driven\n", id); 144 } 145 } 146 event->addMicroarchitectureProbe(obj, probe_name); 147 148 registerEvent(id); 149 150} 151 152void 153PMU::registerEvent(uint32_t id) 154{ 155 // Flag the event as available in the corresponding PMCEID register if it 156 // is an architected event. 157 if (id < 0x20) { 158 reg_pmceid0 |= ((uint64_t)1) << id; 159 } else if (id > 0x20 && id < 0x40) { 160 reg_pmceid1 |= ((uint64_t)1) << (id - 0x20); 161 } else if (id >= 0x4000 && id < 0x4020) { 162 reg_pmceid0 |= ((uint64_t)1) << (id - 0x4000 + 32); 163 } else if (id >= 0x4020 && id < 0x4040) { 164 reg_pmceid1 |= ((uint64_t)1) << (id - 0x4020 + 32); 165 } 166} 167 168void 169PMU::drainResume() 170{ 171 // Re-attach enabled counters after a resume in case they changed. 172 updateAllCounters(); 173} 174 175void 176PMU::regProbeListeners() 177{ 178 179 // at this stage all probe configurations are done 180 // counters can be configured 181 for (uint32_t index = 0; index < maximumCounterCount-1; index++) { 182 counters.emplace_back(*this, index); 183 } 184 185 PMUEvent *event = getEvent(cycleCounterEventId); 186 panic_if(!event, "core cycle event is not present\n"); 187 cycleCounter.enabled = true; 188 cycleCounter.attach(event); 189} 190 191void 192PMU::setMiscReg(int misc_reg, MiscReg val) 193{ 194 DPRINTF(PMUVerbose, "setMiscReg(%s, 0x%x)\n", 195 miscRegName[unflattenMiscReg(misc_reg)], val); 196 197 switch (unflattenMiscReg(misc_reg)) { 198 case MISCREG_PMCR_EL0: 199 case MISCREG_PMCR: 200 setControlReg(val); 201 return; 202 203 case MISCREG_PMCNTENSET_EL0: 204 case MISCREG_PMCNTENSET: 205 reg_pmcnten |= val; 206 updateAllCounters(); 207 return; 208 209 case MISCREG_PMCNTENCLR_EL0: 210 case MISCREG_PMCNTENCLR: 211 reg_pmcnten &= ~val; 212 updateAllCounters(); 213 return; 214 215 case MISCREG_PMOVSCLR_EL0: 216 case MISCREG_PMOVSR: 217 setOverflowStatus(reg_pmovsr & ~val); 218 return; 219 220 case MISCREG_PMSWINC_EL0: 221 case MISCREG_PMSWINC: 222 if (swIncrementEvent) { 223 swIncrementEvent->write(val); 224 } 225 return; 226 227 case MISCREG_PMCCNTR_EL0: 228 case MISCREG_PMCCNTR: 229 cycleCounter.setValue(val); 230 return; 231 232 case MISCREG_PMSELR_EL0: 233 case MISCREG_PMSELR: 234 reg_pmselr = val; 235 return; 236 //TODO: implement MISCREF_PMCEID{2,3} 237 case MISCREG_PMCEID0_EL0: 238 case MISCREG_PMCEID0: 239 case MISCREG_PMCEID1_EL0: 240 case MISCREG_PMCEID1: 241 // Ignore writes 242 return; 243 244 case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0: 245 setCounterTypeRegister(misc_reg - MISCREG_PMEVTYPER0_EL0, val); 246 return; 247 248 case MISCREG_PMCCFILTR: 249 case MISCREG_PMCCFILTR_EL0: 250 DPRINTF(PMUVerbose, "Setting PMCCFILTR: 0x%x\n", val); 251 setCounterTypeRegister(PMCCNTR, val); 252 return; 253 254 case MISCREG_PMXEVTYPER_PMCCFILTR: 255 case MISCREG_PMXEVTYPER_EL0: 256 case MISCREG_PMXEVTYPER: 257 DPRINTF(PMUVerbose, "Setting counter type: " 258 "[PMSELR: 0x%x, PMSELER.sel: 0x%x, EVTYPER: 0x%x]\n", 259 reg_pmselr, reg_pmselr.sel, val); 260 setCounterTypeRegister(reg_pmselr.sel, val); 261 return; 262 263 case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0: 264 setCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0, val); 265 return; 266 267 case MISCREG_PMXEVCNTR_EL0: 268 case MISCREG_PMXEVCNTR: 269 setCounterValue(reg_pmselr.sel, val); 270 return; 271 272 case MISCREG_PMUSERENR_EL0: 273 case MISCREG_PMUSERENR: 274 // TODO 275 break; 276 277 case MISCREG_PMINTENSET_EL1: 278 case MISCREG_PMINTENSET: 279 reg_pminten |= val; 280 return; 281 282 case MISCREG_PMINTENCLR_EL1: 283 case MISCREG_PMINTENCLR: 284 reg_pminten &= ~val; 285 return; 286 287 case MISCREG_PMOVSSET_EL0: 288 case MISCREG_PMOVSSET: 289 setOverflowStatus(reg_pmovsr | val); 290 return; 291 292 default: 293 panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]); 294 } 295 296 warn("Not doing anything for write to miscreg %s\n", 297 miscRegName[misc_reg]); 298} 299 300MiscReg 301PMU::readMiscReg(int misc_reg) 302{ 303 MiscReg val(readMiscRegInt(misc_reg)); 304 DPRINTF(PMUVerbose, "readMiscReg(%s): 0x%x\n", 305 miscRegName[unflattenMiscReg(misc_reg)], val); 306 return val; 307} 308 309MiscReg 310PMU::readMiscRegInt(int misc_reg) 311{ 312 misc_reg = unflattenMiscReg(misc_reg); 313 switch (misc_reg) { 314 case MISCREG_PMCR_EL0: 315 case MISCREG_PMCR: 316 return reg_pmcr_conf | (reg_pmcr & reg_pmcr_wr_mask); 317 318 case MISCREG_PMCNTENSET_EL0: 319 case MISCREG_PMCNTENCLR_EL0: 320 case MISCREG_PMCNTENSET: 321 case MISCREG_PMCNTENCLR: 322 return reg_pmcnten; 323 324 case MISCREG_PMOVSCLR_EL0: 325 case MISCREG_PMOVSSET_EL0: 326 case MISCREG_PMOVSR: // Overflow Status Register 327 case MISCREG_PMOVSSET: 328 return reg_pmovsr; 329 330 case MISCREG_PMSWINC_EL0: 331 case MISCREG_PMSWINC: // Software Increment Register (RAZ) 332 return 0; 333 334 case MISCREG_PMSELR: 335 return reg_pmselr; 336 337 case MISCREG_PMCEID0_EL0: 338 return reg_pmceid0; 339 340 case MISCREG_PMCEID1_EL0: 341 return reg_pmceid1; 342 343 //TODO: implement MISCREF_PMCEID{2,3} 344 case MISCREG_PMCEID0: // Common Event ID register 345 return reg_pmceid0 & 0xFFFFFFFF; 346 347 case MISCREG_PMCEID1: // Common Event ID register 348 return reg_pmceid1 & 0xFFFFFFFF; 349 350 case MISCREG_PMCCNTR_EL0: 351 return cycleCounter.getValue(); 352 353 case MISCREG_PMCCNTR: 354 return cycleCounter.getValue() & 0xFFFFFFFF; 355 356 case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0: 357 return getCounterTypeRegister(misc_reg - MISCREG_PMEVTYPER0_EL0); 358 359 case MISCREG_PMCCFILTR: 360 case MISCREG_PMCCFILTR_EL0: 361 return getCounterTypeRegister(PMCCNTR); 362 363 case MISCREG_PMXEVTYPER_PMCCFILTR: 364 case MISCREG_PMXEVTYPER_EL0: 365 case MISCREG_PMXEVTYPER: 366 return getCounterTypeRegister(reg_pmselr.sel); 367 368 case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0: { 369 return getCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0) & 370 0xFFFFFFFF; 371 372 } 373 374 case MISCREG_PMXEVCNTR_EL0: 375 case MISCREG_PMXEVCNTR: 376 return getCounterValue(reg_pmselr.sel) & 0xFFFFFFFF; 377 378 case MISCREG_PMUSERENR_EL0: 379 case MISCREG_PMUSERENR: 380 // TODO 381 return 0; 382 383 case MISCREG_PMINTENSET_EL1: 384 case MISCREG_PMINTENCLR_EL1: 385 case MISCREG_PMINTENSET: 386 case MISCREG_PMINTENCLR: 387 return reg_pminten; 388 389 default: 390 panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]); 391 } 392 393 warn("Not doing anything for read from miscreg %s\n", 394 miscRegName[misc_reg]); 395 return 0; 396} 397 398void 399PMU::setControlReg(PMCR_t val) 400{ 401 DPRINTF(PMUVerbose, "Set Control Reg 0x%08x.\n", val); 402 403 if (val.p) { 404 DPRINTF(PMUVerbose, "PMU reset all events to zero.\n"); 405 resetEventCounts(); 406 } 407 408 if (val.c) { 409 DPRINTF(PMUVerbose, "PMU reset cycle counter to zero.\n"); 410 cycleCounter.setValue(0); 411 } 412 413 // Reset the clock remainder if divide by 64-mode is toggled. 414 if (reg_pmcr.d != val.d) 415 clock_remainder = 0; 416 417 reg_pmcr = val & reg_pmcr_wr_mask; 418 updateAllCounters(); 419} 420 421void 422PMU::updateAllCounters() 423{ 424 const bool global_enable(reg_pmcr.e); 425 426 for (int i = 0; i < counters.size(); ++i) { 427 CounterState &ctr(counters[i]); 428 const bool enable(global_enable && (reg_pmcnten & (1 << i))); 429 if (ctr.enabled != enable) { 430 ctr.enabled = enable; 431 updateCounter(ctr); 432 } 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 value = 0; 536 sourceEvent = event; 537 sourceEvent->attachEvent(this); 538} 539 540uint64_t 541PMU::CounterState::getValue() const 542{ 543 if (sourceEvent) { 544 sourceEvent->updateAttachedCounters(); 545 } else { 546 debugCounter("attempted to get value from a counter without" 547 " an associated event\n"); 548 } 549 return value; 550} 551 552void 553PMU::CounterState::setValue(uint64_t val) 554{ 555 value = val; 556 resetValue = true; 557 558 if (sourceEvent) { 559 sourceEvent->updateAttachedCounters(); 560 } else { 561 debugCounter("attempted to set value from a counter without" 562 " an associated event\n"); 563 } 564} 565 566void 567PMU::updateCounter(CounterState &ctr) 568{ 569 if (!ctr.enabled) { 570 DPRINTF(PMUVerbose, "updateCounter(%i): Disabling counter\n", 571 ctr.getCounterId()); 572 ctr.detach(); 573 574 } else { 575 DPRINTF(PMUVerbose, "updateCounter(%i): Enable event id 0x%x\n", 576 ctr.getCounterId(), ctr.eventId); 577 578 auto sourceEvent = eventMap.find(ctr.eventId); 579 if (sourceEvent == eventMap.end()) { 580 warn("Can't enable PMU counter of type '0x%x': " 581 "No such event type.\n", ctr.eventId); 582 } else { 583 ctr.attach(sourceEvent->second); 584 } 585 } 586} 587 588 589void 590PMU::resetEventCounts() 591{ 592 for (CounterState &ctr : counters) 593 ctr.setValue(0); 594} 595 596void 597PMU::setCounterValue(CounterId id, uint64_t val) 598{ 599 if (!isValidCounter(id)) { 600 warn_once("Can't change counter value: Counter %i does not exist.\n", 601 id); 602 return; 603 } 604 605 CounterState &ctr(getCounter(id)); 606 ctr.setValue(val); 607} 608 609PMU::PMEVTYPER_t 610PMU::getCounterTypeRegister(CounterId id) const 611{ 612 if (!isValidCounter(id)) 613 return 0; 614 615 const CounterState &cs(getCounter(id)); 616 PMEVTYPER_t type(cs.filter); 617 618 type.evtCount = cs.eventId; 619 620 return type; 621} 622 623void 624PMU::setCounterTypeRegister(CounterId id, PMEVTYPER_t val) 625{ 626 DPRINTF(PMUVerbose, "Set Event [%d] = 0x%08x\n", id, val); 627 if (!isValidCounter(id)) { 628 warn_once("Can't change counter type: Counter %i does not exist.\n", 629 id); 630 return; 631 } 632 633 CounterState &ctr(getCounter(id)); 634 const EventTypeId old_event_id(ctr.eventId); 635 636 ctr.filter = val; 637 638 // If PMCCNTR Register, do not change event type. PMCCNTR can 639 // count processor cycles only. If we change the event type, we 640 // need to update the probes the counter is using. 641 if (id != PMCCNTR && old_event_id != val.evtCount) { 642 ctr.eventId = val.evtCount; 643 updateCounter(ctr); 644 } 645} 646 647void 648PMU::setOverflowStatus(MiscReg new_val) 649{ 650 const bool int_old = reg_pmovsr != 0; 651 const bool int_new = new_val != 0; 652 653 reg_pmovsr = new_val; 654 if (int_old && !int_new) { 655 clearInterrupt(); 656 } else if (!int_old && int_new && (reg_pminten & reg_pmovsr)) { 657 raiseInterrupt(); 658 } 659} 660 661void 662PMU::raiseInterrupt() 663{ 664 if (interrupt) { 665 DPRINTF(PMUVerbose, "Delivering PMU interrupt.\n"); 666 interrupt->raise(); 667 } else { 668 warn_once("Dropping PMU interrupt as no interrupt has " 669 "been specified\n"); 670 } 671} 672 673void 674PMU::clearInterrupt() 675{ 676 if (interrupt) { 677 DPRINTF(PMUVerbose, "Clearing PMU interrupt.\n"); 678 interrupt->clear(); 679 } else { 680 warn_once("Dropping PMU interrupt as no interrupt has " 681 "been specified\n"); 682 } 683} 684 685void 686PMU::serialize(CheckpointOut &cp) const 687{ 688 DPRINTF(Checkpoint, "Serializing Arm PMU\n"); 689 690 SERIALIZE_SCALAR(reg_pmcr); 691 SERIALIZE_SCALAR(reg_pmcnten); 692 SERIALIZE_SCALAR(reg_pmselr); 693 SERIALIZE_SCALAR(reg_pminten); 694 SERIALIZE_SCALAR(reg_pmovsr); 695 SERIALIZE_SCALAR(reg_pmceid0); 696 SERIALIZE_SCALAR(reg_pmceid1); 697 SERIALIZE_SCALAR(clock_remainder); 698 699 for (size_t i = 0; i < counters.size(); ++i) 700 counters[i].serializeSection(cp, csprintf("counters.%i", i)); 701 702 cycleCounter.serializeSection(cp, "cycleCounter"); 703} 704 705void 706PMU::unserialize(CheckpointIn &cp) 707{ 708 DPRINTF(Checkpoint, "Unserializing Arm PMU\n"); 709 710 UNSERIALIZE_SCALAR(reg_pmcr); 711 UNSERIALIZE_SCALAR(reg_pmcnten); 712 UNSERIALIZE_SCALAR(reg_pmselr); 713 UNSERIALIZE_SCALAR(reg_pminten); 714 UNSERIALIZE_SCALAR(reg_pmovsr); 715 716 // Old checkpoints used to store the entire PMCEID value in a 717 // single 64-bit entry (reg_pmceid). The register was extended in 718 // ARMv8.1, so we now need to store it as two 64-bit registers. 719 if (!UNSERIALIZE_OPT_SCALAR(reg_pmceid0)) 720 paramIn(cp, "reg_pmceid", reg_pmceid0); 721 722 if (!UNSERIALIZE_OPT_SCALAR(reg_pmceid1)) 723 reg_pmceid1 = 0; 724 725 UNSERIALIZE_SCALAR(clock_remainder); 726 727 for (size_t i = 0; i < counters.size(); ++i) 728 counters[i].unserializeSection(cp, csprintf("counters.%i", i)); 729 730 cycleCounter.unserializeSection(cp, "cycleCounter"); 731} 732 733PMU::PMUEvent* 734PMU::getEvent(uint64_t eventId) 735{ 736 auto entry = eventMap.find(eventId); 737 738 if (entry == eventMap.end()) { 739 warn("event %d does not exist\n", eventId); 740 return nullptr; 741 } else { 742 return entry->second; 743 } 744} 745 746void 747PMU::CounterState::serialize(CheckpointOut &cp) const 748{ 749 SERIALIZE_SCALAR(eventId); 750 SERIALIZE_SCALAR(value); 751 SERIALIZE_SCALAR(overflow64); 752} 753 754void 755PMU::CounterState::unserialize(CheckpointIn &cp) 756{ 757 UNSERIALIZE_SCALAR(eventId); 758 UNSERIALIZE_SCALAR(value); 759 UNSERIALIZE_SCALAR(overflow64); 760} 761 762uint64_t 763PMU::CounterState::add(uint64_t delta) 764{ 765 uint64_t value_until_overflow; 766 if (overflow64) { 767 value_until_overflow = UINT64_MAX - value; 768 } else { 769 value_until_overflow = UINT32_MAX - (uint32_t)value; 770 } 771 772 if (isFiltered()) 773 return value_until_overflow; 774 775 if (resetValue) { 776 delta = 0; 777 resetValue = false; 778 } else { 779 value += delta; 780 } 781 782 if (delta > value_until_overflow) { 783 784 // overflow situation detected 785 // flag the overflow occurence 786 pmu.reg_pmovsr |= (1 << counterId); 787 788 // Deliver a PMU interrupt if interrupt delivery is enabled 789 // for this counter. 790 if (pmu.reg_pminten & (1 << counterId)) { 791 pmu.raiseInterrupt(); 792 } 793 return overflow64 ? UINT64_MAX : UINT32_MAX; 794 } 795 return value_until_overflow - delta + 1; 796} 797 798void 799PMU::SWIncrementEvent::write(uint64_t val) 800{ 801 for (auto& counter: userCounters) { 802 if (val & (0x1 << counter->getCounterId())) { 803 counter->add(1); 804 } 805 } 806} 807 808} // namespace ArmISA 809 810ArmISA::PMU * 811ArmPMUParams::create() 812{ 813 return new ArmISA::PMU(this); 814} 815