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