pmu.cc (13104:4a0713e11ef7) pmu.cc (13581:b6dcd0183747)
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
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;
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(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
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)
192PMU::setMiscReg(int misc_reg, RegVal 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
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
300RegVal
301PMU::readMiscReg(int misc_reg)
302{
301PMU::readMiscReg(int misc_reg)
302{
303 MiscReg val(readMiscRegInt(misc_reg));
303 RegVal val(readMiscRegInt(misc_reg));
304 DPRINTF(PMUVerbose, "readMiscReg(%s): 0x%x\n",
305 miscRegName[unflattenMiscReg(misc_reg)], val);
306 return val;
307}
308
304 DPRINTF(PMUVerbose, "readMiscReg(%s): 0x%x\n",
305 miscRegName[unflattenMiscReg(misc_reg)], val);
306 return val;
307}
308
309MiscReg
309RegVal
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
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)
648PMU::setOverflowStatus(RegVal 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}
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}