generic_timer.cc (10847:1826ee736709) generic_timer.cc (10905:a6ca6831e775)
1/*
2 * Copyright (c) 2013, 2015 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: Giacomo Gabrielli
38 * Andreas Sandberg
39 */
40
41#include "dev/arm/generic_timer.hh"
42
43#include "arch/arm/system.hh"
44#include "debug/Timer.hh"
45#include "dev/arm/base_gic.hh"
46#include "mem/packet_access.hh"
47#include "params/GenericTimer.hh"
48#include "params/GenericTimerMem.hh"
49
50SystemCounter::SystemCounter()
51 : _freq(0), _period(0), _resetTick(0), _regCntkctl(0)
52{
53 setFreq(0x01800000);
54}
55
56void
57SystemCounter::setFreq(uint32_t freq)
58{
59 if (_freq != 0) {
60 // Altering the frequency after boot shouldn't be done in practice.
61 warn_once("The frequency of the system counter has already been set");
62 }
63 _freq = freq;
64 _period = (1.0 / freq) * SimClock::Frequency;
65 _resetTick = curTick();
66}
67
68void
1/*
2 * Copyright (c) 2013, 2015 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: Giacomo Gabrielli
38 * Andreas Sandberg
39 */
40
41#include "dev/arm/generic_timer.hh"
42
43#include "arch/arm/system.hh"
44#include "debug/Timer.hh"
45#include "dev/arm/base_gic.hh"
46#include "mem/packet_access.hh"
47#include "params/GenericTimer.hh"
48#include "params/GenericTimerMem.hh"
49
50SystemCounter::SystemCounter()
51 : _freq(0), _period(0), _resetTick(0), _regCntkctl(0)
52{
53 setFreq(0x01800000);
54}
55
56void
57SystemCounter::setFreq(uint32_t freq)
58{
59 if (_freq != 0) {
60 // Altering the frequency after boot shouldn't be done in practice.
61 warn_once("The frequency of the system counter has already been set");
62 }
63 _freq = freq;
64 _period = (1.0 / freq) * SimClock::Frequency;
65 _resetTick = curTick();
66}
67
68void
69SystemCounter::serialize(std::ostream &os) const
69SystemCounter::serialize(CheckpointOut &cp) const
70{
71 SERIALIZE_SCALAR(_regCntkctl);
72 SERIALIZE_SCALAR(_freq);
73 SERIALIZE_SCALAR(_period);
74 SERIALIZE_SCALAR(_resetTick);
75}
76
77void
70{
71 SERIALIZE_SCALAR(_regCntkctl);
72 SERIALIZE_SCALAR(_freq);
73 SERIALIZE_SCALAR(_period);
74 SERIALIZE_SCALAR(_resetTick);
75}
76
77void
78SystemCounter::unserialize(Checkpoint *cp,
79 const std::string &section)
78SystemCounter::unserialize(CheckpointIn &cp)
80{
81 // We didn't handle CNTKCTL in this class before, assume it's zero
82 // if it isn't present.
83 if (!UNSERIALIZE_OPT_SCALAR(_regCntkctl))
84 _regCntkctl = 0;
85 UNSERIALIZE_SCALAR(_freq);
86 UNSERIALIZE_SCALAR(_period);
87 UNSERIALIZE_SCALAR(_resetTick);
88}
89
90
91
92ArchTimer::ArchTimer(const std::string &name,
93 SimObject &parent,
94 SystemCounter &sysctr,
95 const Interrupt &interrupt)
96 : _name(name), _parent(parent), _systemCounter(sysctr),
97 _interrupt(interrupt),
98 _control(0), _counterLimit(0), _offset(0),
99 _counterLimitReachedEvent(this)
100{
101}
102
103void
104ArchTimer::counterLimitReached()
105{
106 _control.istatus = 1;
107
108 if (!_control.enable)
109 return;
110
111 DPRINTF(Timer, "Counter limit reached\n");
112 if (!_control.imask) {
113 DPRINTF(Timer, "Causing interrupt\n");
114 _interrupt.send();
115 }
116}
117
118void
119ArchTimer::updateCounter()
120{
121 if (_counterLimitReachedEvent.scheduled())
122 _parent.deschedule(_counterLimitReachedEvent);
123 if (value() >= _counterLimit) {
124 counterLimitReached();
125 } else {
126 const auto period(_systemCounter.period());
127 _control.istatus = 0;
128 _parent.schedule(_counterLimitReachedEvent,
129 curTick() + (_counterLimit - value()) * period);
130 }
131}
132
133void
134ArchTimer::setCompareValue(uint64_t val)
135{
136 _counterLimit = val;
137 updateCounter();
138}
139
140void
141ArchTimer::setTimerValue(uint32_t val)
142{
143 setCompareValue(value() + sext<32>(val));
144}
145
146void
147ArchTimer::setControl(uint32_t val)
148{
149 ArchTimerCtrl new_ctl = val;
150 if ((new_ctl.enable && !new_ctl.imask) &&
151 !(_control.enable && !_control.imask)) {
152 // Re-evalute the timer condition
153 if (_counterLimit >= value()) {
154 _control.istatus = 1;
155
156 DPRINTF(Timer, "Causing interrupt in control\n");
157 //_interrupt.send();
158 }
159 }
160 _control.enable = new_ctl.enable;
161 _control.imask = new_ctl.imask;
162}
163
164void
165ArchTimer::setOffset(uint64_t val)
166{
167 _offset = val;
168 updateCounter();
169}
170
171uint64_t
172ArchTimer::value() const
173{
174 return _systemCounter.value() - _offset;
175}
176
177void
79{
80 // We didn't handle CNTKCTL in this class before, assume it's zero
81 // if it isn't present.
82 if (!UNSERIALIZE_OPT_SCALAR(_regCntkctl))
83 _regCntkctl = 0;
84 UNSERIALIZE_SCALAR(_freq);
85 UNSERIALIZE_SCALAR(_period);
86 UNSERIALIZE_SCALAR(_resetTick);
87}
88
89
90
91ArchTimer::ArchTimer(const std::string &name,
92 SimObject &parent,
93 SystemCounter &sysctr,
94 const Interrupt &interrupt)
95 : _name(name), _parent(parent), _systemCounter(sysctr),
96 _interrupt(interrupt),
97 _control(0), _counterLimit(0), _offset(0),
98 _counterLimitReachedEvent(this)
99{
100}
101
102void
103ArchTimer::counterLimitReached()
104{
105 _control.istatus = 1;
106
107 if (!_control.enable)
108 return;
109
110 DPRINTF(Timer, "Counter limit reached\n");
111 if (!_control.imask) {
112 DPRINTF(Timer, "Causing interrupt\n");
113 _interrupt.send();
114 }
115}
116
117void
118ArchTimer::updateCounter()
119{
120 if (_counterLimitReachedEvent.scheduled())
121 _parent.deschedule(_counterLimitReachedEvent);
122 if (value() >= _counterLimit) {
123 counterLimitReached();
124 } else {
125 const auto period(_systemCounter.period());
126 _control.istatus = 0;
127 _parent.schedule(_counterLimitReachedEvent,
128 curTick() + (_counterLimit - value()) * period);
129 }
130}
131
132void
133ArchTimer::setCompareValue(uint64_t val)
134{
135 _counterLimit = val;
136 updateCounter();
137}
138
139void
140ArchTimer::setTimerValue(uint32_t val)
141{
142 setCompareValue(value() + sext<32>(val));
143}
144
145void
146ArchTimer::setControl(uint32_t val)
147{
148 ArchTimerCtrl new_ctl = val;
149 if ((new_ctl.enable && !new_ctl.imask) &&
150 !(_control.enable && !_control.imask)) {
151 // Re-evalute the timer condition
152 if (_counterLimit >= value()) {
153 _control.istatus = 1;
154
155 DPRINTF(Timer, "Causing interrupt in control\n");
156 //_interrupt.send();
157 }
158 }
159 _control.enable = new_ctl.enable;
160 _control.imask = new_ctl.imask;
161}
162
163void
164ArchTimer::setOffset(uint64_t val)
165{
166 _offset = val;
167 updateCounter();
168}
169
170uint64_t
171ArchTimer::value() const
172{
173 return _systemCounter.value() - _offset;
174}
175
176void
178ArchTimer::serialize(std::ostream &os) const
177ArchTimer::serialize(CheckpointOut &cp) const
179{
178{
180 paramOut(os, "control_serial", _control);
179 paramOut(cp, "control_serial", _control);
181 SERIALIZE_SCALAR(_counterLimit);
182 SERIALIZE_SCALAR(_offset);
183
184 const bool event_scheduled(_counterLimitReachedEvent.scheduled());
185 SERIALIZE_SCALAR(event_scheduled);
186 if (event_scheduled) {
187 const Tick event_time(_counterLimitReachedEvent.when());
188 SERIALIZE_SCALAR(event_time);
189 }
190}
191
192void
180 SERIALIZE_SCALAR(_counterLimit);
181 SERIALIZE_SCALAR(_offset);
182
183 const bool event_scheduled(_counterLimitReachedEvent.scheduled());
184 SERIALIZE_SCALAR(event_scheduled);
185 if (event_scheduled) {
186 const Tick event_time(_counterLimitReachedEvent.when());
187 SERIALIZE_SCALAR(event_time);
188 }
189}
190
191void
193ArchTimer::unserialize(Checkpoint *cp,
194 const std::string &section)
192ArchTimer::unserialize(CheckpointIn &cp)
195{
193{
196 paramIn(cp, section, "control_serial", _control);
194 paramIn(cp, "control_serial", _control);
197 // We didn't serialize an offset before we added support for the
198 // virtual timer. Consider it optional to maintain backwards
199 // compatibility.
200 if (!UNSERIALIZE_OPT_SCALAR(_offset))
201 _offset = 0;
202 bool event_scheduled;
203 UNSERIALIZE_SCALAR(event_scheduled);
204 if (event_scheduled) {
205 Tick event_time;
206 UNSERIALIZE_SCALAR(event_time);
207 _parent.schedule(_counterLimitReachedEvent, event_time);
208 }
209}
210
211void
212ArchTimer::Interrupt::send()
213{
214 if (_ppi) {
215 _gic.sendPPInt(_irq, _cpu);
216 } else {
217 _gic.sendInt(_irq);
218 }
219}
220
221
222void
223ArchTimer::Interrupt::clear()
224{
225 if (_ppi) {
226 _gic.clearPPInt(_irq, _cpu);
227 } else {
228 _gic.clearInt(_irq);
229 }
230}
231
232
233GenericTimer::GenericTimer(GenericTimerParams *p)
234 : SimObject(p),
235 gic(p->gic),
236 irqPhys(p->int_phys),
237 irqVirt(p->int_virt)
238{
239 dynamic_cast<ArmSystem &>(*p->system).setGenericTimer(this);
240}
241
242void
195 // We didn't serialize an offset before we added support for the
196 // virtual timer. Consider it optional to maintain backwards
197 // compatibility.
198 if (!UNSERIALIZE_OPT_SCALAR(_offset))
199 _offset = 0;
200 bool event_scheduled;
201 UNSERIALIZE_SCALAR(event_scheduled);
202 if (event_scheduled) {
203 Tick event_time;
204 UNSERIALIZE_SCALAR(event_time);
205 _parent.schedule(_counterLimitReachedEvent, event_time);
206 }
207}
208
209void
210ArchTimer::Interrupt::send()
211{
212 if (_ppi) {
213 _gic.sendPPInt(_irq, _cpu);
214 } else {
215 _gic.sendInt(_irq);
216 }
217}
218
219
220void
221ArchTimer::Interrupt::clear()
222{
223 if (_ppi) {
224 _gic.clearPPInt(_irq, _cpu);
225 } else {
226 _gic.clearInt(_irq);
227 }
228}
229
230
231GenericTimer::GenericTimer(GenericTimerParams *p)
232 : SimObject(p),
233 gic(p->gic),
234 irqPhys(p->int_phys),
235 irqVirt(p->int_virt)
236{
237 dynamic_cast<ArmSystem &>(*p->system).setGenericTimer(this);
238}
239
240void
243GenericTimer::serialize(std::ostream &os)
241GenericTimer::serialize(CheckpointOut &cp) const
244{
242{
245 paramOut(os, "cpu_count", timers.size());
243 paramOut(cp, "cpu_count", timers.size());
246
244
247 nameOut(os, csprintf("%s.sys_counter", name()));
248 systemCounter.serialize(os);
245 systemCounter.serializeSection(cp, "sys_counter");
249
250 for (int i = 0; i < timers.size(); ++i) {
246
247 for (int i = 0; i < timers.size(); ++i) {
251 CoreTimers &core(getTimers(i));
248 const CoreTimers &core(*timers[i]);
252
249
253 nameOut(os, core.phys.name());
254 core.phys.serialize(os);
255
256 nameOut(os, core.virt.name());
257 core.virt.serialize(os);
250 // This should really be phys_timerN, but we are stuck with
251 // arch_timer for backwards compatibility.
252 core.phys.serializeSection(cp, csprintf("arch_timer%d", i));
253 core.virt.serializeSection(cp, csprintf("virt_timer%d", i));
258 }
259}
260
261void
254 }
255}
256
257void
262GenericTimer::unserialize(Checkpoint *cp, const std::string &section)
258GenericTimer::unserialize(CheckpointIn &cp)
263{
259{
264 systemCounter.unserialize(cp, csprintf("%s.sys_counter", section));
260 systemCounter.unserializeSection(cp, "sys_counter");
265
266 // Try to unserialize the CPU count. Old versions of the timer
267 // model assumed a 8 CPUs, so we fall back to that if the field
268 // isn't present.
269 static const unsigned OLD_CPU_MAX = 8;
270 unsigned cpu_count;
271 if (!UNSERIALIZE_OPT_SCALAR(cpu_count)) {
272 warn("Checkpoint does not contain CPU count, assuming %i CPUs\n",
273 OLD_CPU_MAX);
274 cpu_count = OLD_CPU_MAX;
275 }
276
277 for (int i = 0; i < cpu_count; ++i) {
278 CoreTimers &core(getTimers(i));
279 // This should really be phys_timerN, but we are stuck with
280 // arch_timer for backwards compatibility.
261
262 // Try to unserialize the CPU count. Old versions of the timer
263 // model assumed a 8 CPUs, so we fall back to that if the field
264 // isn't present.
265 static const unsigned OLD_CPU_MAX = 8;
266 unsigned cpu_count;
267 if (!UNSERIALIZE_OPT_SCALAR(cpu_count)) {
268 warn("Checkpoint does not contain CPU count, assuming %i CPUs\n",
269 OLD_CPU_MAX);
270 cpu_count = OLD_CPU_MAX;
271 }
272
273 for (int i = 0; i < cpu_count; ++i) {
274 CoreTimers &core(getTimers(i));
275 // This should really be phys_timerN, but we are stuck with
276 // arch_timer for backwards compatibility.
281 core.phys.unserialize(cp, csprintf("%s.arch_timer%d", section, i));
282 core.virt.unserialize(cp, csprintf("%s.virt_timer%d", section, i));
277 core.phys.unserializeSection(cp, csprintf("arch_timer%d", i));
278 core.virt.unserializeSection(cp, csprintf("virt_timer%d", i));
283 }
284}
285
286
287GenericTimer::CoreTimers &
288GenericTimer::getTimers(int cpu_id)
289{
290 if (cpu_id >= timers.size())
291 createTimers(cpu_id + 1);
292
293 return *timers[cpu_id];
294}
295
296void
297GenericTimer::createTimers(unsigned cpus)
298{
299 assert(timers.size() < cpus);
300
301 const unsigned old_cpu_count(timers.size());
302 timers.resize(cpus);
303 for (unsigned i = old_cpu_count; i < cpus; ++i) {
304 timers[i].reset(
305 new CoreTimers(*this, i, irqPhys, irqVirt));
306 }
307}
308
309
310void
311GenericTimer::setMiscReg(int reg, unsigned cpu, MiscReg val)
312{
313 CoreTimers &core(getTimers(cpu));
314
315 switch (reg) {
316 case MISCREG_CNTFRQ:
317 case MISCREG_CNTFRQ_EL0:
318 systemCounter.setFreq(val);
319 return;
320
321 case MISCREG_CNTKCTL:
322 case MISCREG_CNTKCTL_EL1:
323 systemCounter.setKernelControl(val);
324 return;
325
326 // Physical timer
327 case MISCREG_CNTP_CVAL:
328 case MISCREG_CNTP_CVAL_NS:
329 case MISCREG_CNTP_CVAL_EL0:
330 core.phys.setCompareValue(val);
331 return;
332
333 case MISCREG_CNTP_TVAL:
334 case MISCREG_CNTP_TVAL_NS:
335 case MISCREG_CNTP_TVAL_EL0:
336 core.phys.setTimerValue(val);
337 return;
338
339 case MISCREG_CNTP_CTL:
340 case MISCREG_CNTP_CTL_NS:
341 case MISCREG_CNTP_CTL_EL0:
342 core.phys.setControl(val);
343 return;
344
345 // Count registers
346 case MISCREG_CNTPCT:
347 case MISCREG_CNTPCT_EL0:
348 case MISCREG_CNTVCT:
349 case MISCREG_CNTVCT_EL0:
350 warn("Ignoring write to read only count register: %s\n",
351 miscRegName[reg]);
352 return;
353
354 // Virtual timer
355 case MISCREG_CNTVOFF:
356 case MISCREG_CNTVOFF_EL2:
357 core.virt.setOffset(val);
358 return;
359
360 case MISCREG_CNTV_CVAL:
361 case MISCREG_CNTV_CVAL_EL0:
362 core.virt.setCompareValue(val);
363 return;
364
365 case MISCREG_CNTV_TVAL:
366 case MISCREG_CNTV_TVAL_EL0:
367 core.virt.setTimerValue(val);
368 return;
369
370 case MISCREG_CNTV_CTL:
371 case MISCREG_CNTV_CTL_EL0:
372 core.virt.setControl(val);
373 return;
374
375 // PL1 phys. timer, secure
376 case MISCREG_CNTP_CTL_S:
377 case MISCREG_CNTPS_CVAL_EL1:
378 case MISCREG_CNTPS_TVAL_EL1:
379 case MISCREG_CNTPS_CTL_EL1:
380 /* FALLTHROUGH */
381
382 // PL2 phys. timer, non-secure
383 case MISCREG_CNTHCTL:
384 case MISCREG_CNTHCTL_EL2:
385 case MISCREG_CNTHP_CVAL:
386 case MISCREG_CNTHP_CVAL_EL2:
387 case MISCREG_CNTHP_TVAL:
388 case MISCREG_CNTHP_TVAL_EL2:
389 case MISCREG_CNTHP_CTL:
390 case MISCREG_CNTHP_CTL_EL2:
391 warn("Writing to unimplemented register: %s\n",
392 miscRegName[reg]);
393 return;
394
395 default:
396 warn("Writing to unknown register: %s\n", miscRegName[reg]);
397 return;
398 }
399}
400
401
402MiscReg
403GenericTimer::readMiscReg(int reg, unsigned cpu)
404{
405 CoreTimers &core(getTimers(cpu));
406
407 switch (reg) {
408 case MISCREG_CNTFRQ:
409 case MISCREG_CNTFRQ_EL0:
410 return systemCounter.freq();
411
412 case MISCREG_CNTKCTL:
413 case MISCREG_CNTKCTL_EL1:
414 return systemCounter.getKernelControl();
415
416 // Physical timer
417 case MISCREG_CNTP_CVAL:
418 case MISCREG_CNTP_CVAL_EL0:
419 return core.phys.compareValue();
420
421 case MISCREG_CNTP_TVAL:
422 case MISCREG_CNTP_TVAL_EL0:
423 return core.phys.timerValue();
424
425 case MISCREG_CNTP_CTL:
426 case MISCREG_CNTP_CTL_EL0:
427 case MISCREG_CNTP_CTL_NS:
428 return core.phys.control();
429
430 case MISCREG_CNTPCT:
431 case MISCREG_CNTPCT_EL0:
432 return core.phys.value();
433
434
435 // Virtual timer
436 case MISCREG_CNTVCT:
437 case MISCREG_CNTVCT_EL0:
438 return core.virt.value();
439
440 case MISCREG_CNTVOFF:
441 case MISCREG_CNTVOFF_EL2:
442 return core.virt.offset();
443
444 case MISCREG_CNTV_CVAL:
445 case MISCREG_CNTV_CVAL_EL0:
446 return core.virt.compareValue();
447
448 case MISCREG_CNTV_TVAL:
449 case MISCREG_CNTV_TVAL_EL0:
450 return core.virt.timerValue();
451
452 case MISCREG_CNTV_CTL:
453 case MISCREG_CNTV_CTL_EL0:
454 return core.virt.control();
455
456 // PL1 phys. timer, secure
457 case MISCREG_CNTP_CTL_S:
458 case MISCREG_CNTPS_CVAL_EL1:
459 case MISCREG_CNTPS_TVAL_EL1:
460 case MISCREG_CNTPS_CTL_EL1:
461 /* FALLTHROUGH */
462
463 // PL2 phys. timer, non-secure
464 case MISCREG_CNTHCTL:
465 case MISCREG_CNTHCTL_EL2:
466 case MISCREG_CNTHP_CVAL:
467 case MISCREG_CNTHP_CVAL_EL2:
468 case MISCREG_CNTHP_TVAL:
469 case MISCREG_CNTHP_TVAL_EL2:
470 case MISCREG_CNTHP_CTL:
471 case MISCREG_CNTHP_CTL_EL2:
472 warn("Reading from unimplemented register: %s\n",
473 miscRegName[reg]);
474 return 0;
475
476
477 default:
478 warn("Reading from unknown register: %s\n", miscRegName[reg]);
479 return 0;
480 }
481}
482
483
484
485GenericTimerMem::GenericTimerMem(GenericTimerMemParams *p)
486 : PioDevice(p),
487 ctrlRange(RangeSize(p->base, TheISA::PageBytes)),
488 timerRange(RangeSize(p->base + TheISA::PageBytes, TheISA::PageBytes)),
489 addrRanges{ctrlRange, timerRange},
490 systemCounter(),
491 physTimer(csprintf("%s.phys_timer0", name()),
492 *this, systemCounter,
493 ArchTimer::Interrupt(*p->gic, p->int_phys)),
494 virtTimer(csprintf("%s.virt_timer0", name()),
495 *this, systemCounter,
496 ArchTimer::Interrupt(*p->gic, p->int_virt))
497{
498}
499
500void
279 }
280}
281
282
283GenericTimer::CoreTimers &
284GenericTimer::getTimers(int cpu_id)
285{
286 if (cpu_id >= timers.size())
287 createTimers(cpu_id + 1);
288
289 return *timers[cpu_id];
290}
291
292void
293GenericTimer::createTimers(unsigned cpus)
294{
295 assert(timers.size() < cpus);
296
297 const unsigned old_cpu_count(timers.size());
298 timers.resize(cpus);
299 for (unsigned i = old_cpu_count; i < cpus; ++i) {
300 timers[i].reset(
301 new CoreTimers(*this, i, irqPhys, irqVirt));
302 }
303}
304
305
306void
307GenericTimer::setMiscReg(int reg, unsigned cpu, MiscReg val)
308{
309 CoreTimers &core(getTimers(cpu));
310
311 switch (reg) {
312 case MISCREG_CNTFRQ:
313 case MISCREG_CNTFRQ_EL0:
314 systemCounter.setFreq(val);
315 return;
316
317 case MISCREG_CNTKCTL:
318 case MISCREG_CNTKCTL_EL1:
319 systemCounter.setKernelControl(val);
320 return;
321
322 // Physical timer
323 case MISCREG_CNTP_CVAL:
324 case MISCREG_CNTP_CVAL_NS:
325 case MISCREG_CNTP_CVAL_EL0:
326 core.phys.setCompareValue(val);
327 return;
328
329 case MISCREG_CNTP_TVAL:
330 case MISCREG_CNTP_TVAL_NS:
331 case MISCREG_CNTP_TVAL_EL0:
332 core.phys.setTimerValue(val);
333 return;
334
335 case MISCREG_CNTP_CTL:
336 case MISCREG_CNTP_CTL_NS:
337 case MISCREG_CNTP_CTL_EL0:
338 core.phys.setControl(val);
339 return;
340
341 // Count registers
342 case MISCREG_CNTPCT:
343 case MISCREG_CNTPCT_EL0:
344 case MISCREG_CNTVCT:
345 case MISCREG_CNTVCT_EL0:
346 warn("Ignoring write to read only count register: %s\n",
347 miscRegName[reg]);
348 return;
349
350 // Virtual timer
351 case MISCREG_CNTVOFF:
352 case MISCREG_CNTVOFF_EL2:
353 core.virt.setOffset(val);
354 return;
355
356 case MISCREG_CNTV_CVAL:
357 case MISCREG_CNTV_CVAL_EL0:
358 core.virt.setCompareValue(val);
359 return;
360
361 case MISCREG_CNTV_TVAL:
362 case MISCREG_CNTV_TVAL_EL0:
363 core.virt.setTimerValue(val);
364 return;
365
366 case MISCREG_CNTV_CTL:
367 case MISCREG_CNTV_CTL_EL0:
368 core.virt.setControl(val);
369 return;
370
371 // PL1 phys. timer, secure
372 case MISCREG_CNTP_CTL_S:
373 case MISCREG_CNTPS_CVAL_EL1:
374 case MISCREG_CNTPS_TVAL_EL1:
375 case MISCREG_CNTPS_CTL_EL1:
376 /* FALLTHROUGH */
377
378 // PL2 phys. timer, non-secure
379 case MISCREG_CNTHCTL:
380 case MISCREG_CNTHCTL_EL2:
381 case MISCREG_CNTHP_CVAL:
382 case MISCREG_CNTHP_CVAL_EL2:
383 case MISCREG_CNTHP_TVAL:
384 case MISCREG_CNTHP_TVAL_EL2:
385 case MISCREG_CNTHP_CTL:
386 case MISCREG_CNTHP_CTL_EL2:
387 warn("Writing to unimplemented register: %s\n",
388 miscRegName[reg]);
389 return;
390
391 default:
392 warn("Writing to unknown register: %s\n", miscRegName[reg]);
393 return;
394 }
395}
396
397
398MiscReg
399GenericTimer::readMiscReg(int reg, unsigned cpu)
400{
401 CoreTimers &core(getTimers(cpu));
402
403 switch (reg) {
404 case MISCREG_CNTFRQ:
405 case MISCREG_CNTFRQ_EL0:
406 return systemCounter.freq();
407
408 case MISCREG_CNTKCTL:
409 case MISCREG_CNTKCTL_EL1:
410 return systemCounter.getKernelControl();
411
412 // Physical timer
413 case MISCREG_CNTP_CVAL:
414 case MISCREG_CNTP_CVAL_EL0:
415 return core.phys.compareValue();
416
417 case MISCREG_CNTP_TVAL:
418 case MISCREG_CNTP_TVAL_EL0:
419 return core.phys.timerValue();
420
421 case MISCREG_CNTP_CTL:
422 case MISCREG_CNTP_CTL_EL0:
423 case MISCREG_CNTP_CTL_NS:
424 return core.phys.control();
425
426 case MISCREG_CNTPCT:
427 case MISCREG_CNTPCT_EL0:
428 return core.phys.value();
429
430
431 // Virtual timer
432 case MISCREG_CNTVCT:
433 case MISCREG_CNTVCT_EL0:
434 return core.virt.value();
435
436 case MISCREG_CNTVOFF:
437 case MISCREG_CNTVOFF_EL2:
438 return core.virt.offset();
439
440 case MISCREG_CNTV_CVAL:
441 case MISCREG_CNTV_CVAL_EL0:
442 return core.virt.compareValue();
443
444 case MISCREG_CNTV_TVAL:
445 case MISCREG_CNTV_TVAL_EL0:
446 return core.virt.timerValue();
447
448 case MISCREG_CNTV_CTL:
449 case MISCREG_CNTV_CTL_EL0:
450 return core.virt.control();
451
452 // PL1 phys. timer, secure
453 case MISCREG_CNTP_CTL_S:
454 case MISCREG_CNTPS_CVAL_EL1:
455 case MISCREG_CNTPS_TVAL_EL1:
456 case MISCREG_CNTPS_CTL_EL1:
457 /* FALLTHROUGH */
458
459 // PL2 phys. timer, non-secure
460 case MISCREG_CNTHCTL:
461 case MISCREG_CNTHCTL_EL2:
462 case MISCREG_CNTHP_CVAL:
463 case MISCREG_CNTHP_CVAL_EL2:
464 case MISCREG_CNTHP_TVAL:
465 case MISCREG_CNTHP_TVAL_EL2:
466 case MISCREG_CNTHP_CTL:
467 case MISCREG_CNTHP_CTL_EL2:
468 warn("Reading from unimplemented register: %s\n",
469 miscRegName[reg]);
470 return 0;
471
472
473 default:
474 warn("Reading from unknown register: %s\n", miscRegName[reg]);
475 return 0;
476 }
477}
478
479
480
481GenericTimerMem::GenericTimerMem(GenericTimerMemParams *p)
482 : PioDevice(p),
483 ctrlRange(RangeSize(p->base, TheISA::PageBytes)),
484 timerRange(RangeSize(p->base + TheISA::PageBytes, TheISA::PageBytes)),
485 addrRanges{ctrlRange, timerRange},
486 systemCounter(),
487 physTimer(csprintf("%s.phys_timer0", name()),
488 *this, systemCounter,
489 ArchTimer::Interrupt(*p->gic, p->int_phys)),
490 virtTimer(csprintf("%s.virt_timer0", name()),
491 *this, systemCounter,
492 ArchTimer::Interrupt(*p->gic, p->int_virt))
493{
494}
495
496void
501GenericTimerMem::serialize(std::ostream &os)
497GenericTimerMem::serialize(CheckpointOut &cp) const
502{
498{
503 paramOut(os, "timer_count", 1);
499 paramOut(cp, "timer_count", 1);
504
500
505 nameOut(os, csprintf("%s.sys_counter", name()));
506 systemCounter.serialize(os);
501 systemCounter.serializeSection(cp, "sys_counter");
507
502
508 nameOut(os, physTimer.name());
509 physTimer.serialize(os);
510
511 nameOut(os, virtTimer.name());
512 virtTimer.serialize(os);
503 physTimer.serializeSection(cp, "phys_timer0");
504 virtTimer.serializeSection(cp, "virt_timer0");
513}
514
515void
505}
506
507void
516GenericTimerMem::unserialize(Checkpoint *cp, const std::string &section)
508GenericTimerMem::unserialize(CheckpointIn &cp)
517{
509{
518 systemCounter.unserialize(cp, csprintf("%s.sys_counter", section));
510 systemCounter.unserializeSection(cp, "sys_counter");
519
520 unsigned timer_count;
521 UNSERIALIZE_SCALAR(timer_count);
522 // The timer count variable is just here for future versions where
523 // we support more than one set of timers.
524 if (timer_count != 1)
525 panic("Incompatible checkpoint: Only one set of timers supported");
526
511
512 unsigned timer_count;
513 UNSERIALIZE_SCALAR(timer_count);
514 // The timer count variable is just here for future versions where
515 // we support more than one set of timers.
516 if (timer_count != 1)
517 panic("Incompatible checkpoint: Only one set of timers supported");
518
527 physTimer.unserialize(cp, csprintf("%s.phys_timer0", section));
528 virtTimer.unserialize(cp, csprintf("%s.virt_timer0", section));
519 physTimer.unserializeSection(cp, "phys_timer0");
520 virtTimer.unserializeSection(cp, "virt_timer0");
529}
530
531Tick
532GenericTimerMem::read(PacketPtr pkt)
533{
534 const unsigned size(pkt->getSize());
535 const Addr addr(pkt->getAddr());
536 uint64_t value;
537
538 pkt->makeResponse();
539 if (ctrlRange.contains(addr)) {
540 value = ctrlRead(addr - ctrlRange.start(), size);
541 } else if (timerRange.contains(addr)) {
542 value = timerRead(addr - timerRange.start(), size);
543 } else {
544 panic("Invalid address: 0x%x\n", addr);
545 }
546
547 DPRINTF(Timer, "Read 0x%x <- 0x%x(%i)\n", value, addr, size);
548
549 if (size == 8) {
550 pkt->set<uint64_t>(value);
551 } else if (size == 4) {
552 pkt->set<uint32_t>(value);
553 } else {
554 panic("Unexpected access size: %i\n", size);
555 }
556
557 return 0;
558}
559
560Tick
561GenericTimerMem::write(PacketPtr pkt)
562{
563 const unsigned size(pkt->getSize());
564 if (size != 8 && size != 4)
565 panic("Unexpected access size\n");
566
567 const Addr addr(pkt->getAddr());
568 const uint64_t value(size == 8 ?
569 pkt->get<uint64_t>() : pkt->get<uint32_t>());
570
571 DPRINTF(Timer, "Write 0x%x -> 0x%x(%i)\n", value, addr, size);
572 if (ctrlRange.contains(addr)) {
573 ctrlWrite(addr - ctrlRange.start(), size, value);
574 } else if (timerRange.contains(addr)) {
575 timerWrite(addr - timerRange.start(), size, value);
576 } else {
577 panic("Invalid address: 0x%x\n", addr);
578 }
579
580 pkt->makeResponse();
581 return 0;
582}
583
584uint64_t
585GenericTimerMem::ctrlRead(Addr addr, size_t size) const
586{
587 if (size == 4) {
588 switch (addr) {
589 case CTRL_CNTFRQ:
590 return systemCounter.freq();
591
592 case CTRL_CNTTIDR:
593 return 0x3; // Frame 0 implemented with virtual timers
594
595 case CTRL_CNTNSAR:
596 case CTRL_CNTACR_BASE:
597 warn("Reading from unimplemented control register (0x%x)\n", addr);
598 return 0;
599
600 case CTRL_CNTVOFF_LO_BASE:
601 return virtTimer.offset();
602
603 case CTRL_CNTVOFF_HI_BASE:
604 return virtTimer.offset() >> 32;
605
606 default:
607 warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size);
608 return 0;
609 }
610 } else if (size == 8) {
611 switch (addr) {
612 case CTRL_CNTVOFF_LO_BASE:
613 return virtTimer.offset();
614
615 default:
616 warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size);
617 return 0;
618 }
619 } else {
620 panic("Invalid access size: %i\n", size);
621 }
622}
623
624void
625GenericTimerMem::ctrlWrite(Addr addr, size_t size, uint64_t value)
626{
627 if (size == 4) {
628 switch (addr) {
629 case CTRL_CNTFRQ:
630 case CTRL_CNTNSAR:
631 case CTRL_CNTTIDR:
632 case CTRL_CNTACR_BASE:
633 warn("Write to unimplemented control register (0x%x)\n", addr);
634 return;
635
636 case CTRL_CNTVOFF_LO_BASE:
637 virtTimer.setOffset(
638 insertBits(virtTimer.offset(), 31, 0, value));
639 return;
640
641 case CTRL_CNTVOFF_HI_BASE:
642 virtTimer.setOffset(
643 insertBits(virtTimer.offset(), 63, 32, value));
644 return;
645
646 default:
647 warn("Ignoring write to unexpected address (0x%x:%i)\n",
648 addr, size);
649 return;
650 }
651 } else if (size == 8) {
652 switch (addr) {
653 case CTRL_CNTVOFF_LO_BASE:
654 virtTimer.setOffset(value);
655 return;
656
657 default:
658 warn("Ignoring write to unexpected address (0x%x:%i)\n",
659 addr, size);
660 return;
661 }
662 } else {
663 panic("Invalid access size: %i\n", size);
664 }
665}
666
667uint64_t
668GenericTimerMem::timerRead(Addr addr, size_t size) const
669{
670 if (size == 4) {
671 switch (addr) {
672 case TIMER_CNTPCT_LO:
673 return physTimer.value();
674
675 case TIMER_CNTPCT_HI:
676 return physTimer.value() >> 32;
677
678 case TIMER_CNTVCT_LO:
679 return virtTimer.value();
680
681 case TIMER_CNTVCT_HI:
682 return virtTimer.value() >> 32;
683
684 case TIMER_CNTFRQ:
685 return systemCounter.freq();
686
687 case TIMER_CNTEL0ACR:
688 warn("Read from unimplemented timer register (0x%x)\n", addr);
689 return 0;
690
691 case CTRL_CNTVOFF_LO_BASE:
692 return virtTimer.offset();
693
694 case CTRL_CNTVOFF_HI_BASE:
695 return virtTimer.offset() >> 32;
696
697 case TIMER_CNTP_CVAL_LO:
698 return physTimer.compareValue();
699
700 case TIMER_CNTP_CVAL_HI:
701 return physTimer.compareValue() >> 32;
702
703 case TIMER_CNTP_TVAL:
704 return physTimer.timerValue();
705
706 case TIMER_CNTP_CTL:
707 return physTimer.control();
708
709 case TIMER_CNTV_CVAL_LO:
710 return virtTimer.compareValue();
711
712 case TIMER_CNTV_CVAL_HI:
713 return virtTimer.compareValue() >> 32;
714
715 case TIMER_CNTV_TVAL:
716 return virtTimer.timerValue();
717
718 case TIMER_CNTV_CTL:
719 return virtTimer.control();
720
721 default:
722 warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size);
723 return 0;
724 }
725 } else if (size == 8) {
726 switch (addr) {
727 case TIMER_CNTPCT_LO:
728 return physTimer.value();
729
730 case TIMER_CNTVCT_LO:
731 return virtTimer.value();
732
733 case CTRL_CNTVOFF_LO_BASE:
734 return virtTimer.offset();
735
736 case TIMER_CNTP_CVAL_LO:
737 return physTimer.compareValue();
738
739 case TIMER_CNTV_CVAL_LO:
740 return virtTimer.compareValue();
741
742 default:
743 warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size);
744 return 0;
745 }
746 } else {
747 panic("Invalid access size: %i\n", size);
748 }
749}
750
751void
752GenericTimerMem::timerWrite(Addr addr, size_t size, uint64_t value)
753{
754 if (size == 4) {
755 switch (addr) {
756 case TIMER_CNTEL0ACR:
757 warn("Unimplemented timer register (0x%x)\n", addr);
758 return;
759
760 case TIMER_CNTP_CVAL_LO:
761 physTimer.setCompareValue(
762 insertBits(physTimer.compareValue(), 31, 0, value));
763 return;
764
765 case TIMER_CNTP_CVAL_HI:
766 physTimer.setCompareValue(
767 insertBits(physTimer.compareValue(), 63, 32, value));
768 return;
769
770 case TIMER_CNTP_TVAL:
771 physTimer.setTimerValue(value);
772 return;
773
774 case TIMER_CNTP_CTL:
775 physTimer.setControl(value);
776 return;
777
778 case TIMER_CNTV_CVAL_LO:
779 virtTimer.setCompareValue(
780 insertBits(virtTimer.compareValue(), 31, 0, value));
781 return;
782
783 case TIMER_CNTV_CVAL_HI:
784 virtTimer.setCompareValue(
785 insertBits(virtTimer.compareValue(), 63, 32, value));
786 return;
787
788 case TIMER_CNTV_TVAL:
789 virtTimer.setTimerValue(value);
790 return;
791
792 case TIMER_CNTV_CTL:
793 virtTimer.setControl(value);
794 return;
795
796 default:
797 warn("Unexpected address (0x%x:%i), ignoring write\n", addr, size);
798 return;
799 }
800 } else if (size == 8) {
801 switch (addr) {
802 case TIMER_CNTP_CVAL_LO:
803 return physTimer.setCompareValue(value);
804
805 case TIMER_CNTV_CVAL_LO:
806 return virtTimer.setCompareValue(value);
807
808 default:
809 warn("Unexpected address (0x%x:%i), ignoring write\n", addr, size);
810 return;
811 }
812 } else {
813 panic("Invalid access size: %i\n", size);
814 }
815}
816
817GenericTimer *
818GenericTimerParams::create()
819{
820 return new GenericTimer(this);
821}
822
823GenericTimerMem *
824GenericTimerMemParams::create()
825{
826 return new GenericTimerMem(this);
827}
521}
522
523Tick
524GenericTimerMem::read(PacketPtr pkt)
525{
526 const unsigned size(pkt->getSize());
527 const Addr addr(pkt->getAddr());
528 uint64_t value;
529
530 pkt->makeResponse();
531 if (ctrlRange.contains(addr)) {
532 value = ctrlRead(addr - ctrlRange.start(), size);
533 } else if (timerRange.contains(addr)) {
534 value = timerRead(addr - timerRange.start(), size);
535 } else {
536 panic("Invalid address: 0x%x\n", addr);
537 }
538
539 DPRINTF(Timer, "Read 0x%x <- 0x%x(%i)\n", value, addr, size);
540
541 if (size == 8) {
542 pkt->set<uint64_t>(value);
543 } else if (size == 4) {
544 pkt->set<uint32_t>(value);
545 } else {
546 panic("Unexpected access size: %i\n", size);
547 }
548
549 return 0;
550}
551
552Tick
553GenericTimerMem::write(PacketPtr pkt)
554{
555 const unsigned size(pkt->getSize());
556 if (size != 8 && size != 4)
557 panic("Unexpected access size\n");
558
559 const Addr addr(pkt->getAddr());
560 const uint64_t value(size == 8 ?
561 pkt->get<uint64_t>() : pkt->get<uint32_t>());
562
563 DPRINTF(Timer, "Write 0x%x -> 0x%x(%i)\n", value, addr, size);
564 if (ctrlRange.contains(addr)) {
565 ctrlWrite(addr - ctrlRange.start(), size, value);
566 } else if (timerRange.contains(addr)) {
567 timerWrite(addr - timerRange.start(), size, value);
568 } else {
569 panic("Invalid address: 0x%x\n", addr);
570 }
571
572 pkt->makeResponse();
573 return 0;
574}
575
576uint64_t
577GenericTimerMem::ctrlRead(Addr addr, size_t size) const
578{
579 if (size == 4) {
580 switch (addr) {
581 case CTRL_CNTFRQ:
582 return systemCounter.freq();
583
584 case CTRL_CNTTIDR:
585 return 0x3; // Frame 0 implemented with virtual timers
586
587 case CTRL_CNTNSAR:
588 case CTRL_CNTACR_BASE:
589 warn("Reading from unimplemented control register (0x%x)\n", addr);
590 return 0;
591
592 case CTRL_CNTVOFF_LO_BASE:
593 return virtTimer.offset();
594
595 case CTRL_CNTVOFF_HI_BASE:
596 return virtTimer.offset() >> 32;
597
598 default:
599 warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size);
600 return 0;
601 }
602 } else if (size == 8) {
603 switch (addr) {
604 case CTRL_CNTVOFF_LO_BASE:
605 return virtTimer.offset();
606
607 default:
608 warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size);
609 return 0;
610 }
611 } else {
612 panic("Invalid access size: %i\n", size);
613 }
614}
615
616void
617GenericTimerMem::ctrlWrite(Addr addr, size_t size, uint64_t value)
618{
619 if (size == 4) {
620 switch (addr) {
621 case CTRL_CNTFRQ:
622 case CTRL_CNTNSAR:
623 case CTRL_CNTTIDR:
624 case CTRL_CNTACR_BASE:
625 warn("Write to unimplemented control register (0x%x)\n", addr);
626 return;
627
628 case CTRL_CNTVOFF_LO_BASE:
629 virtTimer.setOffset(
630 insertBits(virtTimer.offset(), 31, 0, value));
631 return;
632
633 case CTRL_CNTVOFF_HI_BASE:
634 virtTimer.setOffset(
635 insertBits(virtTimer.offset(), 63, 32, value));
636 return;
637
638 default:
639 warn("Ignoring write to unexpected address (0x%x:%i)\n",
640 addr, size);
641 return;
642 }
643 } else if (size == 8) {
644 switch (addr) {
645 case CTRL_CNTVOFF_LO_BASE:
646 virtTimer.setOffset(value);
647 return;
648
649 default:
650 warn("Ignoring write to unexpected address (0x%x:%i)\n",
651 addr, size);
652 return;
653 }
654 } else {
655 panic("Invalid access size: %i\n", size);
656 }
657}
658
659uint64_t
660GenericTimerMem::timerRead(Addr addr, size_t size) const
661{
662 if (size == 4) {
663 switch (addr) {
664 case TIMER_CNTPCT_LO:
665 return physTimer.value();
666
667 case TIMER_CNTPCT_HI:
668 return physTimer.value() >> 32;
669
670 case TIMER_CNTVCT_LO:
671 return virtTimer.value();
672
673 case TIMER_CNTVCT_HI:
674 return virtTimer.value() >> 32;
675
676 case TIMER_CNTFRQ:
677 return systemCounter.freq();
678
679 case TIMER_CNTEL0ACR:
680 warn("Read from unimplemented timer register (0x%x)\n", addr);
681 return 0;
682
683 case CTRL_CNTVOFF_LO_BASE:
684 return virtTimer.offset();
685
686 case CTRL_CNTVOFF_HI_BASE:
687 return virtTimer.offset() >> 32;
688
689 case TIMER_CNTP_CVAL_LO:
690 return physTimer.compareValue();
691
692 case TIMER_CNTP_CVAL_HI:
693 return physTimer.compareValue() >> 32;
694
695 case TIMER_CNTP_TVAL:
696 return physTimer.timerValue();
697
698 case TIMER_CNTP_CTL:
699 return physTimer.control();
700
701 case TIMER_CNTV_CVAL_LO:
702 return virtTimer.compareValue();
703
704 case TIMER_CNTV_CVAL_HI:
705 return virtTimer.compareValue() >> 32;
706
707 case TIMER_CNTV_TVAL:
708 return virtTimer.timerValue();
709
710 case TIMER_CNTV_CTL:
711 return virtTimer.control();
712
713 default:
714 warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size);
715 return 0;
716 }
717 } else if (size == 8) {
718 switch (addr) {
719 case TIMER_CNTPCT_LO:
720 return physTimer.value();
721
722 case TIMER_CNTVCT_LO:
723 return virtTimer.value();
724
725 case CTRL_CNTVOFF_LO_BASE:
726 return virtTimer.offset();
727
728 case TIMER_CNTP_CVAL_LO:
729 return physTimer.compareValue();
730
731 case TIMER_CNTV_CVAL_LO:
732 return virtTimer.compareValue();
733
734 default:
735 warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size);
736 return 0;
737 }
738 } else {
739 panic("Invalid access size: %i\n", size);
740 }
741}
742
743void
744GenericTimerMem::timerWrite(Addr addr, size_t size, uint64_t value)
745{
746 if (size == 4) {
747 switch (addr) {
748 case TIMER_CNTEL0ACR:
749 warn("Unimplemented timer register (0x%x)\n", addr);
750 return;
751
752 case TIMER_CNTP_CVAL_LO:
753 physTimer.setCompareValue(
754 insertBits(physTimer.compareValue(), 31, 0, value));
755 return;
756
757 case TIMER_CNTP_CVAL_HI:
758 physTimer.setCompareValue(
759 insertBits(physTimer.compareValue(), 63, 32, value));
760 return;
761
762 case TIMER_CNTP_TVAL:
763 physTimer.setTimerValue(value);
764 return;
765
766 case TIMER_CNTP_CTL:
767 physTimer.setControl(value);
768 return;
769
770 case TIMER_CNTV_CVAL_LO:
771 virtTimer.setCompareValue(
772 insertBits(virtTimer.compareValue(), 31, 0, value));
773 return;
774
775 case TIMER_CNTV_CVAL_HI:
776 virtTimer.setCompareValue(
777 insertBits(virtTimer.compareValue(), 63, 32, value));
778 return;
779
780 case TIMER_CNTV_TVAL:
781 virtTimer.setTimerValue(value);
782 return;
783
784 case TIMER_CNTV_CTL:
785 virtTimer.setControl(value);
786 return;
787
788 default:
789 warn("Unexpected address (0x%x:%i), ignoring write\n", addr, size);
790 return;
791 }
792 } else if (size == 8) {
793 switch (addr) {
794 case TIMER_CNTP_CVAL_LO:
795 return physTimer.setCompareValue(value);
796
797 case TIMER_CNTV_CVAL_LO:
798 return virtTimer.setCompareValue(value);
799
800 default:
801 warn("Unexpected address (0x%x:%i), ignoring write\n", addr, size);
802 return;
803 }
804 } else {
805 panic("Invalid access size: %i\n", size);
806 }
807}
808
809GenericTimer *
810GenericTimerParams::create()
811{
812 return new GenericTimer(this);
813}
814
815GenericTimerMem *
816GenericTimerMemParams::create()
817{
818 return new GenericTimerMem(this);
819}