dev,arm: remove and recreate timer events around drains
[gem5.git] / src / dev / arm / generic_timer.cc
1 /*
2 * Copyright (c) 2013, 2015, 2017 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(_freq);
73 SERIALIZE_SCALAR(_period);
74 SERIALIZE_SCALAR(_resetTick);
75 }
76
77 void
78 SystemCounter::unserialize(CheckpointIn &cp)
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
91 ArchTimer::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]{ counterLimitReached(); }, name)
99 {
100 }
101
102 void
103 ArchTimer::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
117 void
118 ArchTimer::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
132 void
133 ArchTimer::setCompareValue(uint64_t val)
134 {
135 _counterLimit = val;
136 updateCounter();
137 }
138
139 void
140 ArchTimer::setTimerValue(uint32_t val)
141 {
142 setCompareValue(value() + sext<32>(val));
143 }
144
145 void
146 ArchTimer::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
163 void
164 ArchTimer::setOffset(uint64_t val)
165 {
166 _offset = val;
167 updateCounter();
168 }
169
170 uint64_t
171 ArchTimer::value() const
172 {
173 return _systemCounter.value() - _offset;
174 }
175
176 void
177 ArchTimer::serialize(CheckpointOut &cp) const
178 {
179 paramOut(cp, "control_serial", _control);
180 SERIALIZE_SCALAR(_counterLimit);
181 SERIALIZE_SCALAR(_offset);
182 }
183
184 void
185 ArchTimer::unserialize(CheckpointIn &cp)
186 {
187 paramIn(cp, "control_serial", _control);
188 // We didn't serialize an offset before we added support for the
189 // virtual timer. Consider it optional to maintain backwards
190 // compatibility.
191 if (!UNSERIALIZE_OPT_SCALAR(_offset))
192 _offset = 0;
193
194 // We no longer schedule an event here because we may enter KVM
195 // emulation. The event creation is delayed until drainResume().
196 }
197
198 DrainState
199 ArchTimer::drain()
200 {
201 if (_counterLimitReachedEvent.scheduled())
202 _parent.deschedule(_counterLimitReachedEvent);
203
204 return DrainState::Drained;
205 }
206
207 void
208 ArchTimer::drainResume()
209 {
210 updateCounter();
211 }
212
213 void
214 ArchTimer::Interrupt::send()
215 {
216 if (_ppi) {
217 _gic.sendPPInt(_irq, _cpu);
218 } else {
219 _gic.sendInt(_irq);
220 }
221 }
222
223
224 void
225 ArchTimer::Interrupt::clear()
226 {
227 if (_ppi) {
228 _gic.clearPPInt(_irq, _cpu);
229 } else {
230 _gic.clearInt(_irq);
231 }
232 }
233
234
235 GenericTimer::GenericTimer(GenericTimerParams *p)
236 : SimObject(p),
237 gic(p->gic),
238 irqPhys(p->int_phys),
239 irqVirt(p->int_virt)
240 {
241 fatal_if(!p->system, "No system specified, can't instantiate timer.\n");
242 p->system->setGenericTimer(this);
243 }
244
245 void
246 GenericTimer::serialize(CheckpointOut &cp) const
247 {
248 paramOut(cp, "cpu_count", timers.size());
249
250 systemCounter.serializeSection(cp, "sys_counter");
251
252 for (int i = 0; i < timers.size(); ++i) {
253 const CoreTimers &core(*timers[i]);
254
255 // This should really be phys_timerN, but we are stuck with
256 // arch_timer for backwards compatibility.
257 core.phys.serializeSection(cp, csprintf("arch_timer%d", i));
258 core.virt.serializeSection(cp, csprintf("virt_timer%d", i));
259 }
260 }
261
262 void
263 GenericTimer::unserialize(CheckpointIn &cp)
264 {
265 systemCounter.unserializeSection(cp, "sys_counter");
266
267 // Try to unserialize the CPU count. Old versions of the timer
268 // model assumed a 8 CPUs, so we fall back to that if the field
269 // isn't present.
270 static const unsigned OLD_CPU_MAX = 8;
271 unsigned cpu_count;
272 if (!UNSERIALIZE_OPT_SCALAR(cpu_count)) {
273 warn("Checkpoint does not contain CPU count, assuming %i CPUs\n",
274 OLD_CPU_MAX);
275 cpu_count = OLD_CPU_MAX;
276 }
277
278 for (int i = 0; i < cpu_count; ++i) {
279 CoreTimers &core(getTimers(i));
280 // This should really be phys_timerN, but we are stuck with
281 // arch_timer for backwards compatibility.
282 core.phys.unserializeSection(cp, csprintf("arch_timer%d", i));
283 core.virt.unserializeSection(cp, csprintf("virt_timer%d", i));
284 }
285 }
286
287
288 GenericTimer::CoreTimers &
289 GenericTimer::getTimers(int cpu_id)
290 {
291 if (cpu_id >= timers.size())
292 createTimers(cpu_id + 1);
293
294 return *timers[cpu_id];
295 }
296
297 void
298 GenericTimer::createTimers(unsigned cpus)
299 {
300 assert(timers.size() < cpus);
301
302 const unsigned old_cpu_count(timers.size());
303 timers.resize(cpus);
304 for (unsigned i = old_cpu_count; i < cpus; ++i) {
305 timers[i].reset(
306 new CoreTimers(*this, i, irqPhys, irqVirt));
307 }
308 }
309
310
311 void
312 GenericTimer::setMiscReg(int reg, unsigned cpu, MiscReg val)
313 {
314 // This method might have been called from another context if we
315 // are running in multi-core KVM. Migrate to the SimObject's event
316 // queue to prevent surprising race conditions.
317 EventQueue::ScopedMigration migrate(eventQueue());
318
319 CoreTimers &core(getTimers(cpu));
320
321 switch (reg) {
322 case MISCREG_CNTFRQ:
323 case MISCREG_CNTFRQ_EL0:
324 systemCounter.setFreq(val);
325 return;
326
327 case MISCREG_CNTKCTL:
328 case MISCREG_CNTKCTL_EL1:
329 systemCounter.setKernelControl(val);
330 return;
331
332 // Physical timer
333 case MISCREG_CNTP_CVAL:
334 case MISCREG_CNTP_CVAL_NS:
335 case MISCREG_CNTP_CVAL_EL0:
336 core.phys.setCompareValue(val);
337 return;
338
339 case MISCREG_CNTP_TVAL:
340 case MISCREG_CNTP_TVAL_NS:
341 case MISCREG_CNTP_TVAL_EL0:
342 core.phys.setTimerValue(val);
343 return;
344
345 case MISCREG_CNTP_CTL:
346 case MISCREG_CNTP_CTL_NS:
347 case MISCREG_CNTP_CTL_EL0:
348 core.phys.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 // PL1 phys. timer, secure
382 case MISCREG_CNTP_CTL_S:
383 case MISCREG_CNTPS_CVAL_EL1:
384 case MISCREG_CNTPS_TVAL_EL1:
385 case MISCREG_CNTPS_CTL_EL1:
386 /* FALLTHROUGH */
387
388 // PL2 phys. timer, non-secure
389 case MISCREG_CNTHCTL:
390 case MISCREG_CNTHCTL_EL2:
391 case MISCREG_CNTHP_CVAL:
392 case MISCREG_CNTHP_CVAL_EL2:
393 case MISCREG_CNTHP_TVAL:
394 case MISCREG_CNTHP_TVAL_EL2:
395 case MISCREG_CNTHP_CTL:
396 case MISCREG_CNTHP_CTL_EL2:
397 warn("Writing to unimplemented register: %s\n",
398 miscRegName[reg]);
399 return;
400
401 default:
402 warn("Writing to unknown register: %s\n", miscRegName[reg]);
403 return;
404 }
405 }
406
407
408 MiscReg
409 GenericTimer::readMiscReg(int reg, unsigned cpu)
410 {
411 // This method might have been called from another context if we
412 // are running in multi-core KVM. Migrate to the SimObject's event
413 // queue to prevent surprising race conditions.
414 EventQueue::ScopedMigration migrate(eventQueue());
415
416 CoreTimers &core(getTimers(cpu));
417
418 switch (reg) {
419 case MISCREG_CNTFRQ:
420 case MISCREG_CNTFRQ_EL0:
421 return systemCounter.freq();
422
423 case MISCREG_CNTKCTL:
424 case MISCREG_CNTKCTL_EL1:
425 return systemCounter.getKernelControl();
426
427 // Physical timer
428 case MISCREG_CNTP_CVAL:
429 case MISCREG_CNTP_CVAL_EL0:
430 return core.phys.compareValue();
431
432 case MISCREG_CNTP_TVAL:
433 case MISCREG_CNTP_TVAL_EL0:
434 return core.phys.timerValue();
435
436 case MISCREG_CNTP_CTL:
437 case MISCREG_CNTP_CTL_EL0:
438 case MISCREG_CNTP_CTL_NS:
439 return core.phys.control();
440
441 case MISCREG_CNTPCT:
442 case MISCREG_CNTPCT_EL0:
443 return core.phys.value();
444
445
446 // Virtual timer
447 case MISCREG_CNTVCT:
448 case MISCREG_CNTVCT_EL0:
449 return core.virt.value();
450
451 case MISCREG_CNTVOFF:
452 case MISCREG_CNTVOFF_EL2:
453 return core.virt.offset();
454
455 case MISCREG_CNTV_CVAL:
456 case MISCREG_CNTV_CVAL_EL0:
457 return core.virt.compareValue();
458
459 case MISCREG_CNTV_TVAL:
460 case MISCREG_CNTV_TVAL_EL0:
461 return core.virt.timerValue();
462
463 case MISCREG_CNTV_CTL:
464 case MISCREG_CNTV_CTL_EL0:
465 return core.virt.control();
466
467 // PL1 phys. timer, secure
468 case MISCREG_CNTP_CTL_S:
469 case MISCREG_CNTPS_CVAL_EL1:
470 case MISCREG_CNTPS_TVAL_EL1:
471 case MISCREG_CNTPS_CTL_EL1:
472 /* FALLTHROUGH */
473
474 // PL2 phys. timer, non-secure
475 case MISCREG_CNTHCTL:
476 case MISCREG_CNTHCTL_EL2:
477 case MISCREG_CNTHP_CVAL:
478 case MISCREG_CNTHP_CVAL_EL2:
479 case MISCREG_CNTHP_TVAL:
480 case MISCREG_CNTHP_TVAL_EL2:
481 case MISCREG_CNTHP_CTL:
482 case MISCREG_CNTHP_CTL_EL2:
483 warn("Reading from unimplemented register: %s\n",
484 miscRegName[reg]);
485 return 0;
486
487
488 default:
489 warn("Reading from unknown register: %s\n", miscRegName[reg]);
490 return 0;
491 }
492 }
493
494
495
496 GenericTimerMem::GenericTimerMem(GenericTimerMemParams *p)
497 : PioDevice(p),
498 ctrlRange(RangeSize(p->base, TheISA::PageBytes)),
499 timerRange(RangeSize(p->base + TheISA::PageBytes, TheISA::PageBytes)),
500 addrRanges{ctrlRange, timerRange},
501 systemCounter(),
502 physTimer(csprintf("%s.phys_timer0", name()),
503 *this, systemCounter,
504 ArchTimer::Interrupt(*p->gic, p->int_phys)),
505 virtTimer(csprintf("%s.virt_timer0", name()),
506 *this, systemCounter,
507 ArchTimer::Interrupt(*p->gic, p->int_virt))
508 {
509 }
510
511 void
512 GenericTimerMem::serialize(CheckpointOut &cp) const
513 {
514 paramOut(cp, "timer_count", 1);
515
516 systemCounter.serializeSection(cp, "sys_counter");
517
518 physTimer.serializeSection(cp, "phys_timer0");
519 virtTimer.serializeSection(cp, "virt_timer0");
520 }
521
522 void
523 GenericTimerMem::unserialize(CheckpointIn &cp)
524 {
525 systemCounter.unserializeSection(cp, "sys_counter");
526
527 unsigned timer_count;
528 UNSERIALIZE_SCALAR(timer_count);
529 // The timer count variable is just here for future versions where
530 // we support more than one set of timers.
531 if (timer_count != 1)
532 panic("Incompatible checkpoint: Only one set of timers supported");
533
534 physTimer.unserializeSection(cp, "phys_timer0");
535 virtTimer.unserializeSection(cp, "virt_timer0");
536 }
537
538 Tick
539 GenericTimerMem::read(PacketPtr pkt)
540 {
541 const unsigned size(pkt->getSize());
542 const Addr addr(pkt->getAddr());
543 uint64_t value;
544
545 pkt->makeResponse();
546 if (ctrlRange.contains(addr)) {
547 value = ctrlRead(addr - ctrlRange.start(), size);
548 } else if (timerRange.contains(addr)) {
549 value = timerRead(addr - timerRange.start(), size);
550 } else {
551 panic("Invalid address: 0x%x\n", addr);
552 }
553
554 DPRINTF(Timer, "Read 0x%x <- 0x%x(%i)\n", value, addr, size);
555
556 if (size == 8) {
557 pkt->set<uint64_t>(value);
558 } else if (size == 4) {
559 pkt->set<uint32_t>(value);
560 } else {
561 panic("Unexpected access size: %i\n", size);
562 }
563
564 return 0;
565 }
566
567 Tick
568 GenericTimerMem::write(PacketPtr pkt)
569 {
570 const unsigned size(pkt->getSize());
571 if (size != 8 && size != 4)
572 panic("Unexpected access size\n");
573
574 const Addr addr(pkt->getAddr());
575 const uint64_t value(size == 8 ?
576 pkt->get<uint64_t>() : pkt->get<uint32_t>());
577
578 DPRINTF(Timer, "Write 0x%x -> 0x%x(%i)\n", value, addr, size);
579 if (ctrlRange.contains(addr)) {
580 ctrlWrite(addr - ctrlRange.start(), size, value);
581 } else if (timerRange.contains(addr)) {
582 timerWrite(addr - timerRange.start(), size, value);
583 } else {
584 panic("Invalid address: 0x%x\n", addr);
585 }
586
587 pkt->makeResponse();
588 return 0;
589 }
590
591 uint64_t
592 GenericTimerMem::ctrlRead(Addr addr, size_t size) const
593 {
594 if (size == 4) {
595 switch (addr) {
596 case CTRL_CNTFRQ:
597 return systemCounter.freq();
598
599 case CTRL_CNTTIDR:
600 return 0x3; // Frame 0 implemented with virtual timers
601
602 case CTRL_CNTNSAR:
603 case CTRL_CNTACR_BASE:
604 warn("Reading from unimplemented control register (0x%x)\n", addr);
605 return 0;
606
607 case CTRL_CNTVOFF_LO_BASE:
608 return virtTimer.offset();
609
610 case CTRL_CNTVOFF_HI_BASE:
611 return virtTimer.offset() >> 32;
612
613 default:
614 warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size);
615 return 0;
616 }
617 } else if (size == 8) {
618 switch (addr) {
619 case CTRL_CNTVOFF_LO_BASE:
620 return virtTimer.offset();
621
622 default:
623 warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size);
624 return 0;
625 }
626 } else {
627 panic("Invalid access size: %i\n", size);
628 }
629 }
630
631 void
632 GenericTimerMem::ctrlWrite(Addr addr, size_t size, uint64_t value)
633 {
634 if (size == 4) {
635 switch (addr) {
636 case CTRL_CNTFRQ:
637 case CTRL_CNTNSAR:
638 case CTRL_CNTTIDR:
639 case CTRL_CNTACR_BASE:
640 warn("Write to unimplemented control register (0x%x)\n", addr);
641 return;
642
643 case CTRL_CNTVOFF_LO_BASE:
644 virtTimer.setOffset(
645 insertBits(virtTimer.offset(), 31, 0, value));
646 return;
647
648 case CTRL_CNTVOFF_HI_BASE:
649 virtTimer.setOffset(
650 insertBits(virtTimer.offset(), 63, 32, value));
651 return;
652
653 default:
654 warn("Ignoring write to unexpected address (0x%x:%i)\n",
655 addr, size);
656 return;
657 }
658 } else if (size == 8) {
659 switch (addr) {
660 case CTRL_CNTVOFF_LO_BASE:
661 virtTimer.setOffset(value);
662 return;
663
664 default:
665 warn("Ignoring write to unexpected address (0x%x:%i)\n",
666 addr, size);
667 return;
668 }
669 } else {
670 panic("Invalid access size: %i\n", size);
671 }
672 }
673
674 uint64_t
675 GenericTimerMem::timerRead(Addr addr, size_t size) const
676 {
677 if (size == 4) {
678 switch (addr) {
679 case TIMER_CNTPCT_LO:
680 return physTimer.value();
681
682 case TIMER_CNTPCT_HI:
683 return physTimer.value() >> 32;
684
685 case TIMER_CNTVCT_LO:
686 return virtTimer.value();
687
688 case TIMER_CNTVCT_HI:
689 return virtTimer.value() >> 32;
690
691 case TIMER_CNTFRQ:
692 return systemCounter.freq();
693
694 case TIMER_CNTEL0ACR:
695 warn("Read from unimplemented timer register (0x%x)\n", addr);
696 return 0;
697
698 case CTRL_CNTVOFF_LO_BASE:
699 return virtTimer.offset();
700
701 case CTRL_CNTVOFF_HI_BASE:
702 return virtTimer.offset() >> 32;
703
704 case TIMER_CNTP_CVAL_LO:
705 return physTimer.compareValue();
706
707 case TIMER_CNTP_CVAL_HI:
708 return physTimer.compareValue() >> 32;
709
710 case TIMER_CNTP_TVAL:
711 return physTimer.timerValue();
712
713 case TIMER_CNTP_CTL:
714 return physTimer.control();
715
716 case TIMER_CNTV_CVAL_LO:
717 return virtTimer.compareValue();
718
719 case TIMER_CNTV_CVAL_HI:
720 return virtTimer.compareValue() >> 32;
721
722 case TIMER_CNTV_TVAL:
723 return virtTimer.timerValue();
724
725 case TIMER_CNTV_CTL:
726 return virtTimer.control();
727
728 default:
729 warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size);
730 return 0;
731 }
732 } else if (size == 8) {
733 switch (addr) {
734 case TIMER_CNTPCT_LO:
735 return physTimer.value();
736
737 case TIMER_CNTVCT_LO:
738 return virtTimer.value();
739
740 case CTRL_CNTVOFF_LO_BASE:
741 return virtTimer.offset();
742
743 case TIMER_CNTP_CVAL_LO:
744 return physTimer.compareValue();
745
746 case TIMER_CNTV_CVAL_LO:
747 return virtTimer.compareValue();
748
749 default:
750 warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size);
751 return 0;
752 }
753 } else {
754 panic("Invalid access size: %i\n", size);
755 }
756 }
757
758 void
759 GenericTimerMem::timerWrite(Addr addr, size_t size, uint64_t value)
760 {
761 if (size == 4) {
762 switch (addr) {
763 case TIMER_CNTEL0ACR:
764 warn("Unimplemented timer register (0x%x)\n", addr);
765 return;
766
767 case TIMER_CNTP_CVAL_LO:
768 physTimer.setCompareValue(
769 insertBits(physTimer.compareValue(), 31, 0, value));
770 return;
771
772 case TIMER_CNTP_CVAL_HI:
773 physTimer.setCompareValue(
774 insertBits(physTimer.compareValue(), 63, 32, value));
775 return;
776
777 case TIMER_CNTP_TVAL:
778 physTimer.setTimerValue(value);
779 return;
780
781 case TIMER_CNTP_CTL:
782 physTimer.setControl(value);
783 return;
784
785 case TIMER_CNTV_CVAL_LO:
786 virtTimer.setCompareValue(
787 insertBits(virtTimer.compareValue(), 31, 0, value));
788 return;
789
790 case TIMER_CNTV_CVAL_HI:
791 virtTimer.setCompareValue(
792 insertBits(virtTimer.compareValue(), 63, 32, value));
793 return;
794
795 case TIMER_CNTV_TVAL:
796 virtTimer.setTimerValue(value);
797 return;
798
799 case TIMER_CNTV_CTL:
800 virtTimer.setControl(value);
801 return;
802
803 default:
804 warn("Unexpected address (0x%x:%i), ignoring write\n", addr, size);
805 return;
806 }
807 } else if (size == 8) {
808 switch (addr) {
809 case TIMER_CNTP_CVAL_LO:
810 return physTimer.setCompareValue(value);
811
812 case TIMER_CNTV_CVAL_LO:
813 return virtTimer.setCompareValue(value);
814
815 default:
816 warn("Unexpected address (0x%x:%i), ignoring write\n", addr, size);
817 return;
818 }
819 } else {
820 panic("Invalid access size: %i\n", size);
821 }
822 }
823
824 GenericTimer *
825 GenericTimerParams::create()
826 {
827 return new GenericTimer(this);
828 }
829
830 GenericTimerMem *
831 GenericTimerMemParams::create()
832 {
833 return new GenericTimerMem(this);
834 }