pmu.cc (10537:47fe87b0cf97) pmu.cc (10609:ae5582819481)
1/*
2 * Copyright (c) 2011-2014 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 */
41
42#include "arch/arm/pmu.hh"
43
1/*
2 * Copyright (c) 2011-2014 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 */
41
42#include "arch/arm/pmu.hh"
43
44#include "arch/arm/isa.hh"
45#include "arch/arm/utility.hh"
44#include "base/trace.hh"
45#include "cpu/base.hh"
46#include "debug/Checkpoint.hh"
47#include "debug/PMUVerbose.hh"
48#include "dev/arm/base_gic.hh"
49#include "dev/arm/realview.hh"
50#include "params/ArmPMU.hh"
51
52namespace ArmISA {
53
54const MiscReg PMU::reg_pmcr_wr_mask = 0x39;
55
56PMU::PMU(const ArmPMUParams *p)
57 : SimObject(p), BaseISADevice(),
58 reg_pmcnten(0), reg_pmcr(0),
59 reg_pmselr(0), reg_pminten(0), reg_pmovsr(0),
60 reg_pmceid(0),
61 clock_remainder(0),
62 counters(p->eventCounters),
63 reg_pmcr_conf(0),
64 pmuInterrupt(p->pmuInterrupt),
65 platform(p->platform)
66{
67 DPRINTF(PMUVerbose, "Initializing the PMU.\n");
68
69 if (p->eventCounters > 31) {
70 fatal("The PMU can only accept 31 counters, %d counters requested.\n",
71 p->eventCounters);
72 }
73
74 /* Setup the performance counter ID registers */
75 reg_pmcr_conf.imp = 0x41; // ARM Ltd.
76 reg_pmcr_conf.idcode = 0x00;
77 reg_pmcr_conf.n = p->eventCounters;
78
79 // Setup the hard-coded cycle counter, which is equivalent to
80 // architected counter event type 0x11.
81 cycleCounter.eventId = 0x11;
82}
83
84PMU::~PMU()
85{
86}
87
88void
89PMU::addEventProbe(unsigned int id, SimObject *obj, const char *probe_name)
90{
91 DPRINTF(PMUVerbose, "PMU: Adding event type '0x%x' as probe %s:%s\n",
92 id, obj->name(), probe_name);
93 pmuEventTypes.insert(std::make_pair(id, EventType(obj, probe_name)));
94
95 // Flag the event as available in the PMCEID register if it is an
96 // architected event.
97 if (id < 0x40)
98 reg_pmceid |= (ULL(1) << id);
99}
100
101void
102PMU::drainResume()
103{
104 // Re-attach enabled counters after a resume in case they changed.
105 updateAllCounters();
106}
107
108void
109PMU::setMiscReg(int misc_reg, MiscReg val)
110{
111 DPRINTF(PMUVerbose, "setMiscReg(%s, 0x%x)\n",
112 miscRegName[unflattenMiscReg(misc_reg)], val);
113
114 switch (unflattenMiscReg(misc_reg)) {
115 case MISCREG_PMCR_EL0:
116 case MISCREG_PMCR:
117 setControlReg(val);
118 return;
119
120 case MISCREG_PMCNTENSET_EL0:
121 case MISCREG_PMCNTENSET:
122 reg_pmcnten |= val;
123 updateAllCounters();
124 return;
125
126 case MISCREG_PMCNTENCLR_EL0:
127 case MISCREG_PMCNTENCLR:
128 reg_pmcnten &= ~val;
129 updateAllCounters();
130 return;
131
132 case MISCREG_PMOVSCLR_EL0:
133 case MISCREG_PMOVSR:
134 reg_pmovsr &= ~val;
135 return;
136
137 case MISCREG_PMSWINC_EL0:
138 case MISCREG_PMSWINC:
139 for (int i = 0; i < counters.size(); ++i) {
140 CounterState &ctr(getCounter(i));
141 if (ctr.enabled && (val & (1 << i)))
142 ++ctr.value;
143 }
144 break;
145
146 case MISCREG_PMCCNTR_EL0:
147 case MISCREG_PMCCNTR:
148 cycleCounter.value = val;
149 return;
150
151 case MISCREG_PMSELR_EL0:
152 case MISCREG_PMSELR:
153 reg_pmselr = val;
154 return;
155
156 case MISCREG_PMCEID0_EL0:
157 case MISCREG_PMCEID0:
158 case MISCREG_PMCEID1_EL0:
159 case MISCREG_PMCEID1:
160 // Ignore writes
161 return;
162
163 case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0:
164 setCounterTypeRegister(misc_reg - MISCREG_PMEVCNTR0_EL0, val);
165 return;
166
167 case MISCREG_PMCCFILTR:
168 case MISCREG_PMCCFILTR_EL0:
169 DPRINTF(PMUVerbose, "Setting PMCCFILTR: 0x%x\n", val);
170 setCounterTypeRegister(PMCCNTR, val);
171 return;
172
173 case MISCREG_PMXEVTYPER_PMCCFILTR:
174 case MISCREG_PMXEVTYPER_EL0:
175 case MISCREG_PMXEVTYPER:
176 DPRINTF(PMUVerbose, "Setting counter type: "
177 "[PMSELR: 0x%x, PMSELER.sel: 0x%x, EVTYPER: 0x%x]\n",
178 reg_pmselr, reg_pmselr.sel, val);
179 setCounterTypeRegister(reg_pmselr.sel, val);
180 return;
181
182 case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0:
183 setCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0, val);
184 return;
185
186 case MISCREG_PMXEVCNTR_EL0:
187 case MISCREG_PMXEVCNTR:
188 setCounterValue(reg_pmselr.sel, val);
189 return;
190
191 case MISCREG_PMUSERENR_EL0:
192 case MISCREG_PMUSERENR:
193 // TODO
194 break;
195
196 case MISCREG_PMINTENSET_EL1:
197 case MISCREG_PMINTENSET:
198 reg_pminten |= val;
199 return;
200
201 case MISCREG_PMINTENCLR_EL1:
202 case MISCREG_PMINTENCLR:
203 reg_pminten &= ~val;
204 return;
205
206 case MISCREG_PMOVSSET_EL0:
207 case MISCREG_PMOVSSET:
208 reg_pmovsr |= val;
209 return;
210
211 default:
212 panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]);
213 }
214
215 warn("Not doing anything for write to miscreg %s\n",
216 miscRegName[misc_reg]);
217}
218
219MiscReg
220PMU::readMiscReg(int misc_reg)
221{
222 MiscReg val(readMiscRegInt(misc_reg));
223 DPRINTF(PMUVerbose, "readMiscReg(%s): 0x%x\n",
224 miscRegName[unflattenMiscReg(misc_reg)], val);
225 return val;
226}
227
228MiscReg
229PMU::readMiscRegInt(int misc_reg)
230{
231 misc_reg = unflattenMiscReg(misc_reg);
232 switch (misc_reg) {
233 case MISCREG_PMCR_EL0:
234 case MISCREG_PMCR:
235 return reg_pmcr_conf | (reg_pmcr & reg_pmcr_wr_mask);
236
237 case MISCREG_PMCNTENSET_EL0:
238 case MISCREG_PMCNTENCLR_EL0:
239 case MISCREG_PMCNTENSET:
240 case MISCREG_PMCNTENCLR:
241 return reg_pmcnten;
242
243 case MISCREG_PMOVSCLR_EL0:
244 case MISCREG_PMOVSSET_EL0:
245 case MISCREG_PMOVSR: // Overflow Status Register
246 case MISCREG_PMOVSSET:
247 return reg_pmovsr;
248
249 case MISCREG_PMSWINC_EL0:
250 case MISCREG_PMSWINC: // Software Increment Register (RAZ)
251 return 0;
252
253 case MISCREG_PMSELR:
254 return reg_pmselr;
255
256 case MISCREG_PMCEID0_EL0:
257 case MISCREG_PMCEID0: // Common Event ID register
258 return reg_pmceid & 0xFFFFFFFF;
259
260 case MISCREG_PMCEID1_EL0:
261 case MISCREG_PMCEID1: // Common Event ID register
262 return (reg_pmceid >> 32) & 0xFFFFFFFF;
263
264 case MISCREG_PMCCNTR_EL0:
265 return cycleCounter.value;
266
267 case MISCREG_PMCCNTR:
268 return cycleCounter.value & 0xFFFFFFFF;
269
270 case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0:
271 return getCounterTypeRegister(misc_reg - MISCREG_PMEVTYPER0_EL0);
272
273 case MISCREG_PMCCFILTR:
274 case MISCREG_PMCCFILTR_EL0:
275 return getCounterTypeRegister(PMCCNTR);
276
277 case MISCREG_PMXEVTYPER_PMCCFILTR:
278 case MISCREG_PMXEVTYPER_EL0:
279 case MISCREG_PMXEVTYPER:
280 return getCounterTypeRegister(reg_pmselr.sel);
281
282 case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0:
283 return getCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0) & 0xFFFFFFFF;
284
285 case MISCREG_PMXEVCNTR_EL0:
286 case MISCREG_PMXEVCNTR:
287 return getCounterValue(reg_pmselr.sel) & 0xFFFFFFFF;
288
289 case MISCREG_PMUSERENR_EL0:
290 case MISCREG_PMUSERENR:
291 // TODO
292 return 0;
293
294 case MISCREG_PMINTENSET_EL1:
295 case MISCREG_PMINTENCLR_EL1:
296 case MISCREG_PMINTENSET:
297 case MISCREG_PMINTENCLR:
298 return reg_pminten;
299
300 default:
301 panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]);
302 }
303
304 warn("Not doing anything for read from miscreg %s\n",
305 miscRegName[misc_reg]);
306 return 0;
307}
308
309void
310PMU::setControlReg(PMCR_t val)
311{
312 DPRINTF(PMUVerbose, "Set Control Reg 0x%08x.\n", val);
313
314 if (val.p) {
315 DPRINTF(PMUVerbose, "PMU reset all events to zero.\n");
316 resetEventCounts();
317 }
318
319 if (val.c) {
320 DPRINTF(PMUVerbose, "PMU reset cycle counter to zero.\n");
321 cycleCounter.value = 0;
322 }
323
324 // Reset the clock remainder if divide by 64-mode is toggled.
325 if (reg_pmcr.d != val.d)
326 clock_remainder = 0;
327
328 reg_pmcr = val & reg_pmcr_wr_mask;
329 updateAllCounters();
330}
331
332void
333PMU::updateAllCounters()
334{
335 const bool global_enable(reg_pmcr.e);
336
337 for (int i = 0; i < counters.size(); ++i) {
338 CounterState &ctr(counters[i]);
339 const bool enable(global_enable && (reg_pmcnten & (1 << i)));
340 if (ctr.enabled != enable) {
341 ctr.enabled = enable;
342 updateCounter(i, ctr);
343 }
344 }
345
346 const bool ccntr_enable(global_enable && (reg_pmcnten & (1 << PMCCNTR)));
347 if (cycleCounter.enabled != ccntr_enable) {
348 cycleCounter.enabled = ccntr_enable;
349 updateCounter(PMCCNTR, cycleCounter);
350 }
351}
352
46#include "base/trace.hh"
47#include "cpu/base.hh"
48#include "debug/Checkpoint.hh"
49#include "debug/PMUVerbose.hh"
50#include "dev/arm/base_gic.hh"
51#include "dev/arm/realview.hh"
52#include "params/ArmPMU.hh"
53
54namespace ArmISA {
55
56const MiscReg PMU::reg_pmcr_wr_mask = 0x39;
57
58PMU::PMU(const ArmPMUParams *p)
59 : SimObject(p), BaseISADevice(),
60 reg_pmcnten(0), reg_pmcr(0),
61 reg_pmselr(0), reg_pminten(0), reg_pmovsr(0),
62 reg_pmceid(0),
63 clock_remainder(0),
64 counters(p->eventCounters),
65 reg_pmcr_conf(0),
66 pmuInterrupt(p->pmuInterrupt),
67 platform(p->platform)
68{
69 DPRINTF(PMUVerbose, "Initializing the PMU.\n");
70
71 if (p->eventCounters > 31) {
72 fatal("The PMU can only accept 31 counters, %d counters requested.\n",
73 p->eventCounters);
74 }
75
76 /* Setup the performance counter ID registers */
77 reg_pmcr_conf.imp = 0x41; // ARM Ltd.
78 reg_pmcr_conf.idcode = 0x00;
79 reg_pmcr_conf.n = p->eventCounters;
80
81 // Setup the hard-coded cycle counter, which is equivalent to
82 // architected counter event type 0x11.
83 cycleCounter.eventId = 0x11;
84}
85
86PMU::~PMU()
87{
88}
89
90void
91PMU::addEventProbe(unsigned int id, SimObject *obj, const char *probe_name)
92{
93 DPRINTF(PMUVerbose, "PMU: Adding event type '0x%x' as probe %s:%s\n",
94 id, obj->name(), probe_name);
95 pmuEventTypes.insert(std::make_pair(id, EventType(obj, probe_name)));
96
97 // Flag the event as available in the PMCEID register if it is an
98 // architected event.
99 if (id < 0x40)
100 reg_pmceid |= (ULL(1) << id);
101}
102
103void
104PMU::drainResume()
105{
106 // Re-attach enabled counters after a resume in case they changed.
107 updateAllCounters();
108}
109
110void
111PMU::setMiscReg(int misc_reg, MiscReg val)
112{
113 DPRINTF(PMUVerbose, "setMiscReg(%s, 0x%x)\n",
114 miscRegName[unflattenMiscReg(misc_reg)], val);
115
116 switch (unflattenMiscReg(misc_reg)) {
117 case MISCREG_PMCR_EL0:
118 case MISCREG_PMCR:
119 setControlReg(val);
120 return;
121
122 case MISCREG_PMCNTENSET_EL0:
123 case MISCREG_PMCNTENSET:
124 reg_pmcnten |= val;
125 updateAllCounters();
126 return;
127
128 case MISCREG_PMCNTENCLR_EL0:
129 case MISCREG_PMCNTENCLR:
130 reg_pmcnten &= ~val;
131 updateAllCounters();
132 return;
133
134 case MISCREG_PMOVSCLR_EL0:
135 case MISCREG_PMOVSR:
136 reg_pmovsr &= ~val;
137 return;
138
139 case MISCREG_PMSWINC_EL0:
140 case MISCREG_PMSWINC:
141 for (int i = 0; i < counters.size(); ++i) {
142 CounterState &ctr(getCounter(i));
143 if (ctr.enabled && (val & (1 << i)))
144 ++ctr.value;
145 }
146 break;
147
148 case MISCREG_PMCCNTR_EL0:
149 case MISCREG_PMCCNTR:
150 cycleCounter.value = val;
151 return;
152
153 case MISCREG_PMSELR_EL0:
154 case MISCREG_PMSELR:
155 reg_pmselr = val;
156 return;
157
158 case MISCREG_PMCEID0_EL0:
159 case MISCREG_PMCEID0:
160 case MISCREG_PMCEID1_EL0:
161 case MISCREG_PMCEID1:
162 // Ignore writes
163 return;
164
165 case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0:
166 setCounterTypeRegister(misc_reg - MISCREG_PMEVCNTR0_EL0, val);
167 return;
168
169 case MISCREG_PMCCFILTR:
170 case MISCREG_PMCCFILTR_EL0:
171 DPRINTF(PMUVerbose, "Setting PMCCFILTR: 0x%x\n", val);
172 setCounterTypeRegister(PMCCNTR, val);
173 return;
174
175 case MISCREG_PMXEVTYPER_PMCCFILTR:
176 case MISCREG_PMXEVTYPER_EL0:
177 case MISCREG_PMXEVTYPER:
178 DPRINTF(PMUVerbose, "Setting counter type: "
179 "[PMSELR: 0x%x, PMSELER.sel: 0x%x, EVTYPER: 0x%x]\n",
180 reg_pmselr, reg_pmselr.sel, val);
181 setCounterTypeRegister(reg_pmselr.sel, val);
182 return;
183
184 case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0:
185 setCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0, val);
186 return;
187
188 case MISCREG_PMXEVCNTR_EL0:
189 case MISCREG_PMXEVCNTR:
190 setCounterValue(reg_pmselr.sel, val);
191 return;
192
193 case MISCREG_PMUSERENR_EL0:
194 case MISCREG_PMUSERENR:
195 // TODO
196 break;
197
198 case MISCREG_PMINTENSET_EL1:
199 case MISCREG_PMINTENSET:
200 reg_pminten |= val;
201 return;
202
203 case MISCREG_PMINTENCLR_EL1:
204 case MISCREG_PMINTENCLR:
205 reg_pminten &= ~val;
206 return;
207
208 case MISCREG_PMOVSSET_EL0:
209 case MISCREG_PMOVSSET:
210 reg_pmovsr |= val;
211 return;
212
213 default:
214 panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]);
215 }
216
217 warn("Not doing anything for write to miscreg %s\n",
218 miscRegName[misc_reg]);
219}
220
221MiscReg
222PMU::readMiscReg(int misc_reg)
223{
224 MiscReg val(readMiscRegInt(misc_reg));
225 DPRINTF(PMUVerbose, "readMiscReg(%s): 0x%x\n",
226 miscRegName[unflattenMiscReg(misc_reg)], val);
227 return val;
228}
229
230MiscReg
231PMU::readMiscRegInt(int misc_reg)
232{
233 misc_reg = unflattenMiscReg(misc_reg);
234 switch (misc_reg) {
235 case MISCREG_PMCR_EL0:
236 case MISCREG_PMCR:
237 return reg_pmcr_conf | (reg_pmcr & reg_pmcr_wr_mask);
238
239 case MISCREG_PMCNTENSET_EL0:
240 case MISCREG_PMCNTENCLR_EL0:
241 case MISCREG_PMCNTENSET:
242 case MISCREG_PMCNTENCLR:
243 return reg_pmcnten;
244
245 case MISCREG_PMOVSCLR_EL0:
246 case MISCREG_PMOVSSET_EL0:
247 case MISCREG_PMOVSR: // Overflow Status Register
248 case MISCREG_PMOVSSET:
249 return reg_pmovsr;
250
251 case MISCREG_PMSWINC_EL0:
252 case MISCREG_PMSWINC: // Software Increment Register (RAZ)
253 return 0;
254
255 case MISCREG_PMSELR:
256 return reg_pmselr;
257
258 case MISCREG_PMCEID0_EL0:
259 case MISCREG_PMCEID0: // Common Event ID register
260 return reg_pmceid & 0xFFFFFFFF;
261
262 case MISCREG_PMCEID1_EL0:
263 case MISCREG_PMCEID1: // Common Event ID register
264 return (reg_pmceid >> 32) & 0xFFFFFFFF;
265
266 case MISCREG_PMCCNTR_EL0:
267 return cycleCounter.value;
268
269 case MISCREG_PMCCNTR:
270 return cycleCounter.value & 0xFFFFFFFF;
271
272 case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0:
273 return getCounterTypeRegister(misc_reg - MISCREG_PMEVTYPER0_EL0);
274
275 case MISCREG_PMCCFILTR:
276 case MISCREG_PMCCFILTR_EL0:
277 return getCounterTypeRegister(PMCCNTR);
278
279 case MISCREG_PMXEVTYPER_PMCCFILTR:
280 case MISCREG_PMXEVTYPER_EL0:
281 case MISCREG_PMXEVTYPER:
282 return getCounterTypeRegister(reg_pmselr.sel);
283
284 case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0:
285 return getCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0) & 0xFFFFFFFF;
286
287 case MISCREG_PMXEVCNTR_EL0:
288 case MISCREG_PMXEVCNTR:
289 return getCounterValue(reg_pmselr.sel) & 0xFFFFFFFF;
290
291 case MISCREG_PMUSERENR_EL0:
292 case MISCREG_PMUSERENR:
293 // TODO
294 return 0;
295
296 case MISCREG_PMINTENSET_EL1:
297 case MISCREG_PMINTENCLR_EL1:
298 case MISCREG_PMINTENSET:
299 case MISCREG_PMINTENCLR:
300 return reg_pminten;
301
302 default:
303 panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]);
304 }
305
306 warn("Not doing anything for read from miscreg %s\n",
307 miscRegName[misc_reg]);
308 return 0;
309}
310
311void
312PMU::setControlReg(PMCR_t val)
313{
314 DPRINTF(PMUVerbose, "Set Control Reg 0x%08x.\n", val);
315
316 if (val.p) {
317 DPRINTF(PMUVerbose, "PMU reset all events to zero.\n");
318 resetEventCounts();
319 }
320
321 if (val.c) {
322 DPRINTF(PMUVerbose, "PMU reset cycle counter to zero.\n");
323 cycleCounter.value = 0;
324 }
325
326 // Reset the clock remainder if divide by 64-mode is toggled.
327 if (reg_pmcr.d != val.d)
328 clock_remainder = 0;
329
330 reg_pmcr = val & reg_pmcr_wr_mask;
331 updateAllCounters();
332}
333
334void
335PMU::updateAllCounters()
336{
337 const bool global_enable(reg_pmcr.e);
338
339 for (int i = 0; i < counters.size(); ++i) {
340 CounterState &ctr(counters[i]);
341 const bool enable(global_enable && (reg_pmcnten & (1 << i)));
342 if (ctr.enabled != enable) {
343 ctr.enabled = enable;
344 updateCounter(i, ctr);
345 }
346 }
347
348 const bool ccntr_enable(global_enable && (reg_pmcnten & (1 << PMCCNTR)));
349 if (cycleCounter.enabled != ccntr_enable) {
350 cycleCounter.enabled = ccntr_enable;
351 updateCounter(PMCCNTR, cycleCounter);
352 }
353}
354
355bool
356PMU::isFiltered(const CounterState &ctr) const
357{
358 assert(isa);
359
360 const PMEVTYPER_t filter(ctr.filter);
361 const SCR scr(isa->readMiscRegNoEffect(MISCREG_SCR));
362 const CPSR cpsr(isa->readMiscRegNoEffect(MISCREG_CPSR));
363 const ExceptionLevel el(opModeToEL((OperatingMode)(uint8_t)cpsr.mode));
364 const bool secure(inSecureState(scr, cpsr));
365
366 switch (el) {
367 case EL0:
368 return secure ? filter.u : (filter.u != filter.nsu);
369
370 case EL1:
371 return secure ? filter.p : (filter.p != filter.nsk);
372
373 case EL2:
374 return !filter.nsh;
375
376 case EL3:
377 return filter.p != filter.m;
378
379 default:
380 panic("Unexpected execution level in PMU::isFiltered.\n");
381 }
382}
383
353void
354PMU::handleEvent(CounterId id, uint64_t delta)
355{
356 CounterState &ctr(getCounter(id));
357 const bool overflowed(reg_pmovsr & (1 << id));
358
384void
385PMU::handleEvent(CounterId id, uint64_t delta)
386{
387 CounterState &ctr(getCounter(id));
388 const bool overflowed(reg_pmovsr & (1 << id));
389
390 if (isFiltered(ctr))
391 return;
392
359 // Handle the "count every 64 cycles" mode
360 if (id == PMCCNTR && reg_pmcr.d) {
361 clock_remainder += delta;
362 delta = (clock_remainder >> 6);
363 clock_remainder &= 63;
364 }
365
366 // Add delta and handle (new) overflows
367 if (ctr.add(delta) && !overflowed) {
368 DPRINTF(PMUVerbose, "PMU counter '%i' overflowed.\n", id);
369 reg_pmovsr |= (1 << id);
370 // Deliver a PMU interrupt if interrupt delivery is enabled
371 // for this counter.
372 if (reg_pminten & (1 << id))
373 raiseInterrupt();
374 }
375}
376
377void
378PMU::updateCounter(CounterId id, CounterState &ctr)
379{
380 if (!ctr.enabled) {
381 if (!ctr.listeners.empty()) {
382 DPRINTF(PMUVerbose, "updateCounter(%i): Disabling counter\n", id);
383 ctr.listeners.clear();
384 }
385 } else {
386 DPRINTF(PMUVerbose, "updateCounter(%i): Enable event id 0x%x\n",
387 id, ctr.eventId);
388
389 // Attach all probes belonging to this event
390 auto range(pmuEventTypes.equal_range(ctr.eventId));
391 for (auto it = range.first; it != range.second; ++it) {
392 const EventType &et(it->second);
393
394 DPRINTF(PMUVerbose, "\tProbe: %s:%s\n", et.obj->name(), et.name);
395 ctr.listeners.emplace_back(et.create(*this, id));
396 }
397
398 /* The SW_INCR event type is a special case which doesn't need
399 * any probes since it is controlled by software and the PMU
400 * itself.
401 */
402 if (ctr.listeners.empty() && ctr.eventId != ARCH_EVENT_SW_INCR) {
403 warn("Can't enable PMU counter of type '0x%x': "
404 "No such event type.\n", ctr.eventId);
405 }
406 }
407}
408
409
410void
411PMU::resetEventCounts()
412{
413 for (CounterState &ctr : counters)
414 ctr.value = 0;
415}
416
417void
418PMU::setCounterValue(CounterId id, uint64_t val)
419{
420 if (!isValidCounter(id)) {
421 warn_once("Can't change counter value: Counter %i does not exist.\n",
422 id);
423 return;
424 }
425
426 CounterState &ctr(getCounter(id));
427 ctr.value = val;
428}
429
430PMU::PMEVTYPER_t
431PMU::getCounterTypeRegister(CounterId id) const
432{
433 if (!isValidCounter(id))
434 return 0;
435
436 const CounterState &cs(getCounter(id));
393 // Handle the "count every 64 cycles" mode
394 if (id == PMCCNTR && reg_pmcr.d) {
395 clock_remainder += delta;
396 delta = (clock_remainder >> 6);
397 clock_remainder &= 63;
398 }
399
400 // Add delta and handle (new) overflows
401 if (ctr.add(delta) && !overflowed) {
402 DPRINTF(PMUVerbose, "PMU counter '%i' overflowed.\n", id);
403 reg_pmovsr |= (1 << id);
404 // Deliver a PMU interrupt if interrupt delivery is enabled
405 // for this counter.
406 if (reg_pminten & (1 << id))
407 raiseInterrupt();
408 }
409}
410
411void
412PMU::updateCounter(CounterId id, CounterState &ctr)
413{
414 if (!ctr.enabled) {
415 if (!ctr.listeners.empty()) {
416 DPRINTF(PMUVerbose, "updateCounter(%i): Disabling counter\n", id);
417 ctr.listeners.clear();
418 }
419 } else {
420 DPRINTF(PMUVerbose, "updateCounter(%i): Enable event id 0x%x\n",
421 id, ctr.eventId);
422
423 // Attach all probes belonging to this event
424 auto range(pmuEventTypes.equal_range(ctr.eventId));
425 for (auto it = range.first; it != range.second; ++it) {
426 const EventType &et(it->second);
427
428 DPRINTF(PMUVerbose, "\tProbe: %s:%s\n", et.obj->name(), et.name);
429 ctr.listeners.emplace_back(et.create(*this, id));
430 }
431
432 /* The SW_INCR event type is a special case which doesn't need
433 * any probes since it is controlled by software and the PMU
434 * itself.
435 */
436 if (ctr.listeners.empty() && ctr.eventId != ARCH_EVENT_SW_INCR) {
437 warn("Can't enable PMU counter of type '0x%x': "
438 "No such event type.\n", ctr.eventId);
439 }
440 }
441}
442
443
444void
445PMU::resetEventCounts()
446{
447 for (CounterState &ctr : counters)
448 ctr.value = 0;
449}
450
451void
452PMU::setCounterValue(CounterId id, uint64_t val)
453{
454 if (!isValidCounter(id)) {
455 warn_once("Can't change counter value: Counter %i does not exist.\n",
456 id);
457 return;
458 }
459
460 CounterState &ctr(getCounter(id));
461 ctr.value = val;
462}
463
464PMU::PMEVTYPER_t
465PMU::getCounterTypeRegister(CounterId id) const
466{
467 if (!isValidCounter(id))
468 return 0;
469
470 const CounterState &cs(getCounter(id));
437 PMEVTYPER_t type(0);
471 PMEVTYPER_t type(cs.filter);
438
472
439 // TODO: Re-create filtering settings from counter state
440 type.evtCount = cs.eventId;
441
442 return type;
443}
444
445void
446PMU::setCounterTypeRegister(CounterId id, PMEVTYPER_t val)
447{
448 DPRINTF(PMUVerbose, "Set Event [%d] = 0x%08x\n", id, val);
449 if (!isValidCounter(id)) {
450 warn_once("Can't change counter type: Counter %i does not exist.\n",
451 id);
452 return;
453 }
454
455 CounterState &ctr(getCounter(id));
473 type.evtCount = cs.eventId;
474
475 return type;
476}
477
478void
479PMU::setCounterTypeRegister(CounterId id, PMEVTYPER_t val)
480{
481 DPRINTF(PMUVerbose, "Set Event [%d] = 0x%08x\n", id, val);
482 if (!isValidCounter(id)) {
483 warn_once("Can't change counter type: Counter %i does not exist.\n",
484 id);
485 return;
486 }
487
488 CounterState &ctr(getCounter(id));
456 // TODO: Handle filtering (both for general purpose counters and
457 // the cycle counter)
489 const EventTypeId old_event_id(ctr.eventId);
458
490
459 // If PMCCNTR Register, do not change event type. PMCCNTR can count
460 // processor cycles only.
461 if (id != PMCCNTR) {
491 ctr.filter = val;
492
493 // If PMCCNTR Register, do not change event type. PMCCNTR can
494 // count processor cycles only. If we change the event type, we
495 // need to update the probes the counter is using.
496 if (id != PMCCNTR && old_event_id != val.evtCount) {
462 ctr.eventId = val.evtCount;
463 updateCounter(reg_pmselr.sel, ctr);
464 }
465}
466
467void
468PMU::raiseInterrupt()
469{
470 RealView *rv(dynamic_cast<RealView *>(platform));
471 if (!rv || !rv->gic) {
472 warn_once("ARM PMU: GIC missing, can't raise interrupt.\n");
473 return;
474 }
475
476 DPRINTF(PMUVerbose, "Delivering PMU interrupt.\n");
477 rv->gic->sendInt(pmuInterrupt);
478}
479
480void
481PMU::serialize(std::ostream &os)
482{
483 DPRINTF(Checkpoint, "Serializing Arm PMU\n");
484
485 SERIALIZE_SCALAR(reg_pmcr);
486 SERIALIZE_SCALAR(reg_pmcnten);
487 SERIALIZE_SCALAR(reg_pmselr);
488 SERIALIZE_SCALAR(reg_pminten);
489 SERIALIZE_SCALAR(reg_pmovsr);
490 SERIALIZE_SCALAR(reg_pmceid);
491 SERIALIZE_SCALAR(clock_remainder);
492
493 for (size_t i = 0; i < counters.size(); ++i) {
494 nameOut(os, csprintf("%s.counters.%i", name(), i));
495 counters[i].serialize(os);
496 }
497
498 nameOut(os, csprintf("%s.cycleCounter", name()));
499 cycleCounter.serialize(os);
500}
501
502void
503PMU::unserialize(Checkpoint *cp, const std::string &section)
504{
505 DPRINTF(Checkpoint, "Unserializing Arm PMU\n");
506
507 UNSERIALIZE_SCALAR(reg_pmcr);
508 UNSERIALIZE_SCALAR(reg_pmcnten);
509 UNSERIALIZE_SCALAR(reg_pmselr);
510 UNSERIALIZE_SCALAR(reg_pminten);
511 UNSERIALIZE_SCALAR(reg_pmovsr);
512 UNSERIALIZE_SCALAR(reg_pmceid);
513 UNSERIALIZE_SCALAR(clock_remainder);
514
515 for (size_t i = 0; i < counters.size(); ++i)
516 counters[i].unserialize(cp, csprintf("%s.counters.%i", section, i));
517
518 cycleCounter.unserialize(cp, csprintf("%s.cycleCounter", section));
519}
520
521void
522PMU::CounterState::serialize(std::ostream &os)
523{
524 SERIALIZE_SCALAR(eventId);
525 SERIALIZE_SCALAR(value);
526 SERIALIZE_SCALAR(enabled);
527 SERIALIZE_SCALAR(overflow64);
528}
529
530void
531PMU::CounterState::unserialize(Checkpoint *cp, const std::string &section)
532{
533 UNSERIALIZE_SCALAR(eventId);
534 UNSERIALIZE_SCALAR(value);
535 UNSERIALIZE_SCALAR(enabled);
536 UNSERIALIZE_SCALAR(overflow64);
537}
538
539bool
540PMU::CounterState::add(uint64_t delta)
541{
542 const uint64_t msb(1ULL << (overflow64 ? 63 : 31));
543 const uint64_t old_value(value);
544
545 assert(delta > 0);
546
547 value += delta;
548
549 // Overflow if the msb goes from 1 to 0
550 return (old_value & msb) && !(value & msb);
551}
552
553} // namespace ArmISA
554
555ArmISA::PMU *
556ArmPMUParams::create()
557{
558 return new ArmISA::PMU(this);
559}
497 ctr.eventId = val.evtCount;
498 updateCounter(reg_pmselr.sel, ctr);
499 }
500}
501
502void
503PMU::raiseInterrupt()
504{
505 RealView *rv(dynamic_cast<RealView *>(platform));
506 if (!rv || !rv->gic) {
507 warn_once("ARM PMU: GIC missing, can't raise interrupt.\n");
508 return;
509 }
510
511 DPRINTF(PMUVerbose, "Delivering PMU interrupt.\n");
512 rv->gic->sendInt(pmuInterrupt);
513}
514
515void
516PMU::serialize(std::ostream &os)
517{
518 DPRINTF(Checkpoint, "Serializing Arm PMU\n");
519
520 SERIALIZE_SCALAR(reg_pmcr);
521 SERIALIZE_SCALAR(reg_pmcnten);
522 SERIALIZE_SCALAR(reg_pmselr);
523 SERIALIZE_SCALAR(reg_pminten);
524 SERIALIZE_SCALAR(reg_pmovsr);
525 SERIALIZE_SCALAR(reg_pmceid);
526 SERIALIZE_SCALAR(clock_remainder);
527
528 for (size_t i = 0; i < counters.size(); ++i) {
529 nameOut(os, csprintf("%s.counters.%i", name(), i));
530 counters[i].serialize(os);
531 }
532
533 nameOut(os, csprintf("%s.cycleCounter", name()));
534 cycleCounter.serialize(os);
535}
536
537void
538PMU::unserialize(Checkpoint *cp, const std::string &section)
539{
540 DPRINTF(Checkpoint, "Unserializing Arm PMU\n");
541
542 UNSERIALIZE_SCALAR(reg_pmcr);
543 UNSERIALIZE_SCALAR(reg_pmcnten);
544 UNSERIALIZE_SCALAR(reg_pmselr);
545 UNSERIALIZE_SCALAR(reg_pminten);
546 UNSERIALIZE_SCALAR(reg_pmovsr);
547 UNSERIALIZE_SCALAR(reg_pmceid);
548 UNSERIALIZE_SCALAR(clock_remainder);
549
550 for (size_t i = 0; i < counters.size(); ++i)
551 counters[i].unserialize(cp, csprintf("%s.counters.%i", section, i));
552
553 cycleCounter.unserialize(cp, csprintf("%s.cycleCounter", section));
554}
555
556void
557PMU::CounterState::serialize(std::ostream &os)
558{
559 SERIALIZE_SCALAR(eventId);
560 SERIALIZE_SCALAR(value);
561 SERIALIZE_SCALAR(enabled);
562 SERIALIZE_SCALAR(overflow64);
563}
564
565void
566PMU::CounterState::unserialize(Checkpoint *cp, const std::string &section)
567{
568 UNSERIALIZE_SCALAR(eventId);
569 UNSERIALIZE_SCALAR(value);
570 UNSERIALIZE_SCALAR(enabled);
571 UNSERIALIZE_SCALAR(overflow64);
572}
573
574bool
575PMU::CounterState::add(uint64_t delta)
576{
577 const uint64_t msb(1ULL << (overflow64 ? 63 : 31));
578 const uint64_t old_value(value);
579
580 assert(delta > 0);
581
582 value += delta;
583
584 // Overflow if the msb goes from 1 to 0
585 return (old_value & msb) && !(value & msb);
586}
587
588} // namespace ArmISA
589
590ArmISA::PMU *
591ArmPMUParams::create()
592{
593 return new ArmISA::PMU(this);
594}