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