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