pmu.cc (13848:8a47fb0e701f) pmu.cc (14172:bba55ff08279)
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_EL0:
337 case MISCREG_PMSELR:
338 return reg_pmselr;
339
340 case MISCREG_PMCEID0_EL0:
341 return reg_pmceid0;
342
343 case MISCREG_PMCEID1_EL0:
344 return reg_pmceid1;
345
346 //TODO: implement MISCREF_PMCEID{2,3}
347 case MISCREG_PMCEID0: // Common Event ID register
348 return reg_pmceid0 & 0xFFFFFFFF;
349
350 case MISCREG_PMCEID1: // Common Event ID register
351 return reg_pmceid1 & 0xFFFFFFFF;
352
353 case MISCREG_PMCCNTR_EL0:
354 return cycleCounter.getValue();
355
356 case MISCREG_PMCCNTR:
357 return cycleCounter.getValue() & 0xFFFFFFFF;
358
359 case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0:
360 return getCounterTypeRegister(misc_reg - MISCREG_PMEVTYPER0_EL0);
361
362 case MISCREG_PMCCFILTR:
363 case MISCREG_PMCCFILTR_EL0:
364 return getCounterTypeRegister(PMCCNTR);
365
366 case MISCREG_PMXEVTYPER_PMCCFILTR:
367 case MISCREG_PMXEVTYPER_EL0:
368 case MISCREG_PMXEVTYPER:
369 return getCounterTypeRegister(reg_pmselr.sel);
370
371 case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0: {
372 return getCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0) &
373 0xFFFFFFFF;
374
375 }
376
377 case MISCREG_PMXEVCNTR_EL0:
378 case MISCREG_PMXEVCNTR:
379 return getCounterValue(reg_pmselr.sel) & 0xFFFFFFFF;
380
381 case MISCREG_PMUSERENR_EL0:
382 case MISCREG_PMUSERENR:
383 // TODO
384 return 0;
385
386 case MISCREG_PMINTENSET_EL1:
387 case MISCREG_PMINTENCLR_EL1:
388 case MISCREG_PMINTENSET:
389 case MISCREG_PMINTENCLR:
390 return reg_pminten;
391
392 default:
393 panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]);
394 }
395
396 warn("Not doing anything for read from miscreg %s\n",
397 miscRegName[misc_reg]);
398 return 0;
399}
400
401void
402PMU::setControlReg(PMCR_t val)
403{
404 DPRINTF(PMUVerbose, "Set Control Reg 0x%08x.\n", val);
405
406 if (val.p) {
407 DPRINTF(PMUVerbose, "PMU reset all events to zero.\n");
408 resetEventCounts();
409 }
410
411 if (val.c) {
412 DPRINTF(PMUVerbose, "PMU reset cycle counter to zero.\n");
413 cycleCounter.setValue(0);
414 }
415
416 // Reset the clock remainder if divide by 64-mode is toggled.
417 if (reg_pmcr.d != val.d)
418 clock_remainder = 0;
419
420 reg_pmcr = val & reg_pmcr_wr_mask;
421 updateAllCounters();
422}
423
424void
425PMU::updateAllCounters()
426{
427 const bool global_enable(reg_pmcr.e);
428
429 for (int i = 0; i < counters.size(); ++i) {
430 CounterState &ctr(counters[i]);
431 const bool enable(global_enable && (reg_pmcnten & (1 << i)));
432 if (ctr.enabled != enable) {
433 ctr.enabled = enable;
434 updateCounter(ctr);
435 }
436 }
437
438 const bool ccntr_enable(global_enable && (reg_pmcnten & (1 << PMCCNTR)));
439 if (cycleCounter.enabled != ccntr_enable) {
440 cycleCounter.enabled = ccntr_enable;
441 updateCounter(cycleCounter);
442 }
443}
444
445void
446PMU::PMUEvent::attachEvent(PMU::CounterState *user)
447{
448 if (userCounters.empty()) {
449 enable();
450 }
451 userCounters.insert(user);
452 updateAttachedCounters();
453}
454
455void
456PMU::PMUEvent::increment(const uint64_t val)
457{
458 for (auto& counter: userCounters) {
459 counter->add(val);
460 }
461}
462
463void
464PMU::PMUEvent::detachEvent(PMU::CounterState *user)
465{
466 userCounters.erase(user);
467
468 if (userCounters.empty()) {
469 disable();
470 }
471}
472
473void
474PMU::RegularEvent::RegularProbe::notify(const uint64_t &val)
475{
476 parentEvent->increment(val);
477}
478
479void
480PMU::RegularEvent::enable()
481{
482 for (auto& subEvents: microArchitectureEventSet) {
483 attachedProbePointList.emplace_back(
484 new RegularProbe(this, subEvents.first, subEvents.second));
485 }
486}
487
488void
489PMU::RegularEvent::disable()
490{
491 attachedProbePointList.clear();
492}
493
494bool
495PMU::CounterState::isFiltered() const
496{
497 assert(pmu.isa);
498
499 const PMEVTYPER_t filter(this->filter);
500 const SCR scr(pmu.isa->readMiscRegNoEffect(MISCREG_SCR));
501 const CPSR cpsr(pmu.isa->readMiscRegNoEffect(MISCREG_CPSR));
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_EL0:
337 case MISCREG_PMSELR:
338 return reg_pmselr;
339
340 case MISCREG_PMCEID0_EL0:
341 return reg_pmceid0;
342
343 case MISCREG_PMCEID1_EL0:
344 return reg_pmceid1;
345
346 //TODO: implement MISCREF_PMCEID{2,3}
347 case MISCREG_PMCEID0: // Common Event ID register
348 return reg_pmceid0 & 0xFFFFFFFF;
349
350 case MISCREG_PMCEID1: // Common Event ID register
351 return reg_pmceid1 & 0xFFFFFFFF;
352
353 case MISCREG_PMCCNTR_EL0:
354 return cycleCounter.getValue();
355
356 case MISCREG_PMCCNTR:
357 return cycleCounter.getValue() & 0xFFFFFFFF;
358
359 case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0:
360 return getCounterTypeRegister(misc_reg - MISCREG_PMEVTYPER0_EL0);
361
362 case MISCREG_PMCCFILTR:
363 case MISCREG_PMCCFILTR_EL0:
364 return getCounterTypeRegister(PMCCNTR);
365
366 case MISCREG_PMXEVTYPER_PMCCFILTR:
367 case MISCREG_PMXEVTYPER_EL0:
368 case MISCREG_PMXEVTYPER:
369 return getCounterTypeRegister(reg_pmselr.sel);
370
371 case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0: {
372 return getCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0) &
373 0xFFFFFFFF;
374
375 }
376
377 case MISCREG_PMXEVCNTR_EL0:
378 case MISCREG_PMXEVCNTR:
379 return getCounterValue(reg_pmselr.sel) & 0xFFFFFFFF;
380
381 case MISCREG_PMUSERENR_EL0:
382 case MISCREG_PMUSERENR:
383 // TODO
384 return 0;
385
386 case MISCREG_PMINTENSET_EL1:
387 case MISCREG_PMINTENCLR_EL1:
388 case MISCREG_PMINTENSET:
389 case MISCREG_PMINTENCLR:
390 return reg_pminten;
391
392 default:
393 panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]);
394 }
395
396 warn("Not doing anything for read from miscreg %s\n",
397 miscRegName[misc_reg]);
398 return 0;
399}
400
401void
402PMU::setControlReg(PMCR_t val)
403{
404 DPRINTF(PMUVerbose, "Set Control Reg 0x%08x.\n", val);
405
406 if (val.p) {
407 DPRINTF(PMUVerbose, "PMU reset all events to zero.\n");
408 resetEventCounts();
409 }
410
411 if (val.c) {
412 DPRINTF(PMUVerbose, "PMU reset cycle counter to zero.\n");
413 cycleCounter.setValue(0);
414 }
415
416 // Reset the clock remainder if divide by 64-mode is toggled.
417 if (reg_pmcr.d != val.d)
418 clock_remainder = 0;
419
420 reg_pmcr = val & reg_pmcr_wr_mask;
421 updateAllCounters();
422}
423
424void
425PMU::updateAllCounters()
426{
427 const bool global_enable(reg_pmcr.e);
428
429 for (int i = 0; i < counters.size(); ++i) {
430 CounterState &ctr(counters[i]);
431 const bool enable(global_enable && (reg_pmcnten & (1 << i)));
432 if (ctr.enabled != enable) {
433 ctr.enabled = enable;
434 updateCounter(ctr);
435 }
436 }
437
438 const bool ccntr_enable(global_enable && (reg_pmcnten & (1 << PMCCNTR)));
439 if (cycleCounter.enabled != ccntr_enable) {
440 cycleCounter.enabled = ccntr_enable;
441 updateCounter(cycleCounter);
442 }
443}
444
445void
446PMU::PMUEvent::attachEvent(PMU::CounterState *user)
447{
448 if (userCounters.empty()) {
449 enable();
450 }
451 userCounters.insert(user);
452 updateAttachedCounters();
453}
454
455void
456PMU::PMUEvent::increment(const uint64_t val)
457{
458 for (auto& counter: userCounters) {
459 counter->add(val);
460 }
461}
462
463void
464PMU::PMUEvent::detachEvent(PMU::CounterState *user)
465{
466 userCounters.erase(user);
467
468 if (userCounters.empty()) {
469 disable();
470 }
471}
472
473void
474PMU::RegularEvent::RegularProbe::notify(const uint64_t &val)
475{
476 parentEvent->increment(val);
477}
478
479void
480PMU::RegularEvent::enable()
481{
482 for (auto& subEvents: microArchitectureEventSet) {
483 attachedProbePointList.emplace_back(
484 new RegularProbe(this, subEvents.first, subEvents.second));
485 }
486}
487
488void
489PMU::RegularEvent::disable()
490{
491 attachedProbePointList.clear();
492}
493
494bool
495PMU::CounterState::isFiltered() const
496{
497 assert(pmu.isa);
498
499 const PMEVTYPER_t filter(this->filter);
500 const SCR scr(pmu.isa->readMiscRegNoEffect(MISCREG_SCR));
501 const CPSR cpsr(pmu.isa->readMiscRegNoEffect(MISCREG_CPSR));
502 const ExceptionLevel el(opModeToEL((OperatingMode)(uint8_t)cpsr.mode));
502 const ExceptionLevel el(currEL(cpsr));
503 const bool secure(inSecureState(scr, cpsr));
504
505 switch (el) {
506 case EL0:
507 return secure ? filter.u : (filter.u != filter.nsu);
508
509 case EL1:
510 return secure ? filter.p : (filter.p != filter.nsk);
511
512 case EL2:
513 return !filter.nsh;
514
515 case EL3:
516 return filter.p != filter.m;
517
518 default:
519 panic("Unexpected execution level in PMU::isFiltered.\n");
520 }
521}
522
523void
524PMU::CounterState::detach()
525{
526 if (sourceEvent) {
527 sourceEvent->detachEvent(this);
528 sourceEvent = nullptr;
529 } else {
530 debugCounter("detaching event not currently attached"
531 " to any event\n");
532 }
533}
534
535void
536PMU::CounterState::attach(PMUEvent* event)
537{
538 if (!resetValue) {
539 value = 0;
540 resetValue = true;
541 }
542 sourceEvent = event;
543 sourceEvent->attachEvent(this);
544}
545
546uint64_t
547PMU::CounterState::getValue() const
548{
549 if (sourceEvent) {
550 sourceEvent->updateAttachedCounters();
551 } else {
552 debugCounter("attempted to get value from a counter without"
553 " an associated event\n");
554 }
555 return value;
556}
557
558void
559PMU::CounterState::setValue(uint64_t val)
560{
561 value = val;
562 resetValue = true;
563
564 if (sourceEvent) {
565 sourceEvent->updateAttachedCounters();
566 } else {
567 debugCounter("attempted to set value from a counter without"
568 " an associated event\n");
569 }
570}
571
572void
573PMU::updateCounter(CounterState &ctr)
574{
575 if (!ctr.enabled) {
576 DPRINTF(PMUVerbose, "updateCounter(%i): Disabling counter\n",
577 ctr.getCounterId());
578 ctr.detach();
579
580 } else {
581 DPRINTF(PMUVerbose, "updateCounter(%i): Enable event id 0x%x\n",
582 ctr.getCounterId(), ctr.eventId);
583
584 auto sourceEvent = eventMap.find(ctr.eventId);
585 if (sourceEvent == eventMap.end()) {
586 warn("Can't enable PMU counter of type '0x%x': "
587 "No such event type.\n", ctr.eventId);
588 } else {
589 ctr.attach(sourceEvent->second);
590 }
591 }
592}
593
594
595void
596PMU::resetEventCounts()
597{
598 for (CounterState &ctr : counters)
599 ctr.setValue(0);
600}
601
602void
603PMU::setCounterValue(CounterId id, uint64_t val)
604{
605 if (!isValidCounter(id)) {
606 warn_once("Can't change counter value: Counter %i does not exist.\n",
607 id);
608 return;
609 }
610
611 CounterState &ctr(getCounter(id));
612 ctr.setValue(val);
613}
614
615PMU::PMEVTYPER_t
616PMU::getCounterTypeRegister(CounterId id) const
617{
618 if (!isValidCounter(id))
619 return 0;
620
621 const CounterState &cs(getCounter(id));
622 PMEVTYPER_t type(cs.filter);
623
624 type.evtCount = cs.eventId;
625
626 return type;
627}
628
629void
630PMU::setCounterTypeRegister(CounterId id, PMEVTYPER_t val)
631{
632 DPRINTF(PMUVerbose, "Set Event [%d] = 0x%08x\n", id, val);
633 if (!isValidCounter(id)) {
634 warn_once("Can't change counter type: Counter %i does not exist.\n",
635 id);
636 return;
637 }
638
639 CounterState &ctr(getCounter(id));
640 const EventTypeId old_event_id(ctr.eventId);
641
642 ctr.filter = val;
643
644 // If PMCCNTR Register, do not change event type. PMCCNTR can
645 // count processor cycles only. If we change the event type, we
646 // need to update the probes the counter is using.
647 if (id != PMCCNTR && old_event_id != val.evtCount) {
648 ctr.eventId = val.evtCount;
649 updateCounter(ctr);
650 }
651}
652
653void
654PMU::setOverflowStatus(RegVal new_val)
655{
656 const bool int_old = reg_pmovsr != 0;
657 const bool int_new = new_val != 0;
658
659 reg_pmovsr = new_val;
660 if (int_old && !int_new) {
661 clearInterrupt();
662 } else if (!int_old && int_new && (reg_pminten & reg_pmovsr)) {
663 raiseInterrupt();
664 }
665}
666
667void
668PMU::raiseInterrupt()
669{
670 if (interrupt) {
671 DPRINTF(PMUVerbose, "Delivering PMU interrupt.\n");
672 interrupt->raise();
673 } else {
674 warn_once("Dropping PMU interrupt as no interrupt has "
675 "been specified\n");
676 }
677}
678
679void
680PMU::clearInterrupt()
681{
682 if (interrupt) {
683 DPRINTF(PMUVerbose, "Clearing PMU interrupt.\n");
684 interrupt->clear();
685 } else {
686 warn_once("Dropping PMU interrupt as no interrupt has "
687 "been specified\n");
688 }
689}
690
691void
692PMU::serialize(CheckpointOut &cp) const
693{
694 DPRINTF(Checkpoint, "Serializing Arm PMU\n");
695
696 SERIALIZE_SCALAR(reg_pmcr);
697 SERIALIZE_SCALAR(reg_pmcnten);
698 SERIALIZE_SCALAR(reg_pmselr);
699 SERIALIZE_SCALAR(reg_pminten);
700 SERIALIZE_SCALAR(reg_pmovsr);
701 SERIALIZE_SCALAR(reg_pmceid0);
702 SERIALIZE_SCALAR(reg_pmceid1);
703 SERIALIZE_SCALAR(clock_remainder);
704
705 for (size_t i = 0; i < counters.size(); ++i)
706 counters[i].serializeSection(cp, csprintf("counters.%i", i));
707
708 cycleCounter.serializeSection(cp, "cycleCounter");
709}
710
711void
712PMU::unserialize(CheckpointIn &cp)
713{
714 DPRINTF(Checkpoint, "Unserializing Arm PMU\n");
715
716 UNSERIALIZE_SCALAR(reg_pmcr);
717 UNSERIALIZE_SCALAR(reg_pmcnten);
718 UNSERIALIZE_SCALAR(reg_pmselr);
719 UNSERIALIZE_SCALAR(reg_pminten);
720 UNSERIALIZE_SCALAR(reg_pmovsr);
721
722 // Old checkpoints used to store the entire PMCEID value in a
723 // single 64-bit entry (reg_pmceid). The register was extended in
724 // ARMv8.1, so we now need to store it as two 64-bit registers.
725 if (!UNSERIALIZE_OPT_SCALAR(reg_pmceid0))
726 paramIn(cp, "reg_pmceid", reg_pmceid0);
727
728 if (!UNSERIALIZE_OPT_SCALAR(reg_pmceid1))
729 reg_pmceid1 = 0;
730
731 UNSERIALIZE_SCALAR(clock_remainder);
732
733 for (size_t i = 0; i < counters.size(); ++i)
734 counters[i].unserializeSection(cp, csprintf("counters.%i", i));
735
736 cycleCounter.unserializeSection(cp, "cycleCounter");
737}
738
739PMU::PMUEvent*
740PMU::getEvent(uint64_t eventId)
741{
742 auto entry = eventMap.find(eventId);
743
744 if (entry == eventMap.end()) {
745 warn("event %d does not exist\n", eventId);
746 return nullptr;
747 } else {
748 return entry->second;
749 }
750}
751
752void
753PMU::CounterState::serialize(CheckpointOut &cp) const
754{
755 SERIALIZE_SCALAR(eventId);
756 SERIALIZE_SCALAR(value);
757 SERIALIZE_SCALAR(overflow64);
758}
759
760void
761PMU::CounterState::unserialize(CheckpointIn &cp)
762{
763 UNSERIALIZE_SCALAR(eventId);
764 UNSERIALIZE_SCALAR(value);
765 UNSERIALIZE_SCALAR(overflow64);
766}
767
768uint64_t
769PMU::CounterState::add(uint64_t delta)
770{
771 uint64_t value_until_overflow;
772 if (overflow64) {
773 value_until_overflow = UINT64_MAX - value;
774 } else {
775 value_until_overflow = UINT32_MAX - (uint32_t)value;
776 }
777
778 if (isFiltered())
779 return value_until_overflow;
780
781 if (resetValue) {
782 delta = 0;
783 resetValue = false;
784 } else {
785 value += delta;
786 }
787
788 if (delta > value_until_overflow) {
789
790 // overflow situation detected
791 // flag the overflow occurence
792 pmu.reg_pmovsr |= (1 << counterId);
793
794 // Deliver a PMU interrupt if interrupt delivery is enabled
795 // for this counter.
796 if (pmu.reg_pminten & (1 << counterId)) {
797 pmu.raiseInterrupt();
798 }
799 return overflow64 ? UINT64_MAX : UINT32_MAX;
800 }
801 return value_until_overflow - delta + 1;
802}
803
804void
805PMU::SWIncrementEvent::write(uint64_t val)
806{
807 for (auto& counter: userCounters) {
808 if (val & (0x1 << counter->getCounterId())) {
809 counter->add(1);
810 }
811 }
812}
813
814} // namespace ArmISA
815
816ArmISA::PMU *
817ArmPMUParams::create()
818{
819 return new ArmISA::PMU(this);
820}
503 const bool secure(inSecureState(scr, cpsr));
504
505 switch (el) {
506 case EL0:
507 return secure ? filter.u : (filter.u != filter.nsu);
508
509 case EL1:
510 return secure ? filter.p : (filter.p != filter.nsk);
511
512 case EL2:
513 return !filter.nsh;
514
515 case EL3:
516 return filter.p != filter.m;
517
518 default:
519 panic("Unexpected execution level in PMU::isFiltered.\n");
520 }
521}
522
523void
524PMU::CounterState::detach()
525{
526 if (sourceEvent) {
527 sourceEvent->detachEvent(this);
528 sourceEvent = nullptr;
529 } else {
530 debugCounter("detaching event not currently attached"
531 " to any event\n");
532 }
533}
534
535void
536PMU::CounterState::attach(PMUEvent* event)
537{
538 if (!resetValue) {
539 value = 0;
540 resetValue = true;
541 }
542 sourceEvent = event;
543 sourceEvent->attachEvent(this);
544}
545
546uint64_t
547PMU::CounterState::getValue() const
548{
549 if (sourceEvent) {
550 sourceEvent->updateAttachedCounters();
551 } else {
552 debugCounter("attempted to get value from a counter without"
553 " an associated event\n");
554 }
555 return value;
556}
557
558void
559PMU::CounterState::setValue(uint64_t val)
560{
561 value = val;
562 resetValue = true;
563
564 if (sourceEvent) {
565 sourceEvent->updateAttachedCounters();
566 } else {
567 debugCounter("attempted to set value from a counter without"
568 " an associated event\n");
569 }
570}
571
572void
573PMU::updateCounter(CounterState &ctr)
574{
575 if (!ctr.enabled) {
576 DPRINTF(PMUVerbose, "updateCounter(%i): Disabling counter\n",
577 ctr.getCounterId());
578 ctr.detach();
579
580 } else {
581 DPRINTF(PMUVerbose, "updateCounter(%i): Enable event id 0x%x\n",
582 ctr.getCounterId(), ctr.eventId);
583
584 auto sourceEvent = eventMap.find(ctr.eventId);
585 if (sourceEvent == eventMap.end()) {
586 warn("Can't enable PMU counter of type '0x%x': "
587 "No such event type.\n", ctr.eventId);
588 } else {
589 ctr.attach(sourceEvent->second);
590 }
591 }
592}
593
594
595void
596PMU::resetEventCounts()
597{
598 for (CounterState &ctr : counters)
599 ctr.setValue(0);
600}
601
602void
603PMU::setCounterValue(CounterId id, uint64_t val)
604{
605 if (!isValidCounter(id)) {
606 warn_once("Can't change counter value: Counter %i does not exist.\n",
607 id);
608 return;
609 }
610
611 CounterState &ctr(getCounter(id));
612 ctr.setValue(val);
613}
614
615PMU::PMEVTYPER_t
616PMU::getCounterTypeRegister(CounterId id) const
617{
618 if (!isValidCounter(id))
619 return 0;
620
621 const CounterState &cs(getCounter(id));
622 PMEVTYPER_t type(cs.filter);
623
624 type.evtCount = cs.eventId;
625
626 return type;
627}
628
629void
630PMU::setCounterTypeRegister(CounterId id, PMEVTYPER_t val)
631{
632 DPRINTF(PMUVerbose, "Set Event [%d] = 0x%08x\n", id, val);
633 if (!isValidCounter(id)) {
634 warn_once("Can't change counter type: Counter %i does not exist.\n",
635 id);
636 return;
637 }
638
639 CounterState &ctr(getCounter(id));
640 const EventTypeId old_event_id(ctr.eventId);
641
642 ctr.filter = val;
643
644 // If PMCCNTR Register, do not change event type. PMCCNTR can
645 // count processor cycles only. If we change the event type, we
646 // need to update the probes the counter is using.
647 if (id != PMCCNTR && old_event_id != val.evtCount) {
648 ctr.eventId = val.evtCount;
649 updateCounter(ctr);
650 }
651}
652
653void
654PMU::setOverflowStatus(RegVal new_val)
655{
656 const bool int_old = reg_pmovsr != 0;
657 const bool int_new = new_val != 0;
658
659 reg_pmovsr = new_val;
660 if (int_old && !int_new) {
661 clearInterrupt();
662 } else if (!int_old && int_new && (reg_pminten & reg_pmovsr)) {
663 raiseInterrupt();
664 }
665}
666
667void
668PMU::raiseInterrupt()
669{
670 if (interrupt) {
671 DPRINTF(PMUVerbose, "Delivering PMU interrupt.\n");
672 interrupt->raise();
673 } else {
674 warn_once("Dropping PMU interrupt as no interrupt has "
675 "been specified\n");
676 }
677}
678
679void
680PMU::clearInterrupt()
681{
682 if (interrupt) {
683 DPRINTF(PMUVerbose, "Clearing PMU interrupt.\n");
684 interrupt->clear();
685 } else {
686 warn_once("Dropping PMU interrupt as no interrupt has "
687 "been specified\n");
688 }
689}
690
691void
692PMU::serialize(CheckpointOut &cp) const
693{
694 DPRINTF(Checkpoint, "Serializing Arm PMU\n");
695
696 SERIALIZE_SCALAR(reg_pmcr);
697 SERIALIZE_SCALAR(reg_pmcnten);
698 SERIALIZE_SCALAR(reg_pmselr);
699 SERIALIZE_SCALAR(reg_pminten);
700 SERIALIZE_SCALAR(reg_pmovsr);
701 SERIALIZE_SCALAR(reg_pmceid0);
702 SERIALIZE_SCALAR(reg_pmceid1);
703 SERIALIZE_SCALAR(clock_remainder);
704
705 for (size_t i = 0; i < counters.size(); ++i)
706 counters[i].serializeSection(cp, csprintf("counters.%i", i));
707
708 cycleCounter.serializeSection(cp, "cycleCounter");
709}
710
711void
712PMU::unserialize(CheckpointIn &cp)
713{
714 DPRINTF(Checkpoint, "Unserializing Arm PMU\n");
715
716 UNSERIALIZE_SCALAR(reg_pmcr);
717 UNSERIALIZE_SCALAR(reg_pmcnten);
718 UNSERIALIZE_SCALAR(reg_pmselr);
719 UNSERIALIZE_SCALAR(reg_pminten);
720 UNSERIALIZE_SCALAR(reg_pmovsr);
721
722 // Old checkpoints used to store the entire PMCEID value in a
723 // single 64-bit entry (reg_pmceid). The register was extended in
724 // ARMv8.1, so we now need to store it as two 64-bit registers.
725 if (!UNSERIALIZE_OPT_SCALAR(reg_pmceid0))
726 paramIn(cp, "reg_pmceid", reg_pmceid0);
727
728 if (!UNSERIALIZE_OPT_SCALAR(reg_pmceid1))
729 reg_pmceid1 = 0;
730
731 UNSERIALIZE_SCALAR(clock_remainder);
732
733 for (size_t i = 0; i < counters.size(); ++i)
734 counters[i].unserializeSection(cp, csprintf("counters.%i", i));
735
736 cycleCounter.unserializeSection(cp, "cycleCounter");
737}
738
739PMU::PMUEvent*
740PMU::getEvent(uint64_t eventId)
741{
742 auto entry = eventMap.find(eventId);
743
744 if (entry == eventMap.end()) {
745 warn("event %d does not exist\n", eventId);
746 return nullptr;
747 } else {
748 return entry->second;
749 }
750}
751
752void
753PMU::CounterState::serialize(CheckpointOut &cp) const
754{
755 SERIALIZE_SCALAR(eventId);
756 SERIALIZE_SCALAR(value);
757 SERIALIZE_SCALAR(overflow64);
758}
759
760void
761PMU::CounterState::unserialize(CheckpointIn &cp)
762{
763 UNSERIALIZE_SCALAR(eventId);
764 UNSERIALIZE_SCALAR(value);
765 UNSERIALIZE_SCALAR(overflow64);
766}
767
768uint64_t
769PMU::CounterState::add(uint64_t delta)
770{
771 uint64_t value_until_overflow;
772 if (overflow64) {
773 value_until_overflow = UINT64_MAX - value;
774 } else {
775 value_until_overflow = UINT32_MAX - (uint32_t)value;
776 }
777
778 if (isFiltered())
779 return value_until_overflow;
780
781 if (resetValue) {
782 delta = 0;
783 resetValue = false;
784 } else {
785 value += delta;
786 }
787
788 if (delta > value_until_overflow) {
789
790 // overflow situation detected
791 // flag the overflow occurence
792 pmu.reg_pmovsr |= (1 << counterId);
793
794 // Deliver a PMU interrupt if interrupt delivery is enabled
795 // for this counter.
796 if (pmu.reg_pminten & (1 << counterId)) {
797 pmu.raiseInterrupt();
798 }
799 return overflow64 ? UINT64_MAX : UINT32_MAX;
800 }
801 return value_until_overflow - delta + 1;
802}
803
804void
805PMU::SWIncrementEvent::write(uint64_t val)
806{
807 for (auto& counter: userCounters) {
808 if (val & (0x1 << counter->getCounterId())) {
809 counter->add(1);
810 }
811 }
812}
813
814} // namespace ArmISA
815
816ArmISA::PMU *
817ArmPMUParams::create()
818{
819 return new ArmISA::PMU(this);
820}