2 * Copyright (c) 2013, 2015, 2017-2018, 2019 ARM Limited
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.
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.
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.
38 #include "dev/arm/generic_timer.hh"
40 #include "arch/arm/system.hh"
41 #include "debug/Timer.hh"
42 #include "dev/arm/base_gic.hh"
43 #include "mem/packet_access.hh"
44 #include "params/GenericTimer.hh"
45 #include "params/GenericTimerMem.hh"
47 SystemCounter::SystemCounter(std::vector
<uint32_t> &freqs
)
52 fatal_if(_freqTable
.empty(), "SystemCounter::SystemCounter: Base "
53 "frequency not provided\n");
54 // Store the table end marker as a 32-bit zero word
55 _freqTable
.push_back(0);
56 fatal_if(_freqTable
.size() > MAX_FREQ_ENTRIES
,
57 "SystemCounter::SystemCounter: Architecture states a maximum of 1004 "
58 "frequency table entries, limit surpassed\n");
59 // Set the active frequency to be the base
60 _freq
= freqs
.front();
61 _period
= (1.0 / _freq
) * SimClock::Frequency
;
65 SystemCounter::setFreq(uint32_t freq
)
68 // Altering the frequency after boot shouldn't be done in practice.
69 warn_once("The frequency of the system counter has already been set");
72 _period
= (1.0 / freq
) * SimClock::Frequency
;
73 _resetTick
= curTick();
77 SystemCounter::serialize(CheckpointOut
&cp
) const
79 SERIALIZE_SCALAR(_regCntkctl
);
80 SERIALIZE_SCALAR(_regCnthctl
);
81 SERIALIZE_SCALAR(_freq
);
82 SERIALIZE_SCALAR(_resetTick
);
86 SystemCounter::unserialize(CheckpointIn
&cp
)
88 // We didn't handle CNTKCTL in this class before, assume it's zero
89 // if it isn't present.
90 if (!UNSERIALIZE_OPT_SCALAR(_regCntkctl
))
92 if (!UNSERIALIZE_OPT_SCALAR(_regCnthctl
))
94 UNSERIALIZE_SCALAR(_freq
);
95 _period
= (1.0 / _freq
) * SimClock::Frequency
;
96 UNSERIALIZE_SCALAR(_resetTick
);
101 ArchTimer::ArchTimer(const std::string
&name
,
103 SystemCounter
&sysctr
,
104 ArmInterruptPin
*interrupt
)
105 : _name(name
), _parent(parent
), _systemCounter(sysctr
),
106 _interrupt(interrupt
),
107 _control(0), _counterLimit(0), _offset(0),
108 _counterLimitReachedEvent([this]{ counterLimitReached(); }, name
)
113 ArchTimer::counterLimitReached()
115 _control
.istatus
= 1;
117 if (!_control
.enable
)
120 DPRINTF(Timer
, "Counter limit reached\n");
121 if (!_control
.imask
) {
122 if (scheduleEvents()) {
123 DPRINTF(Timer
, "Causing interrupt\n");
126 DPRINTF(Timer
, "Kvm mode; skipping simulated interrupt\n");
132 ArchTimer::updateCounter()
134 if (_counterLimitReachedEvent
.scheduled())
135 _parent
.deschedule(_counterLimitReachedEvent
);
136 if (value() >= _counterLimit
) {
137 counterLimitReached();
139 _control
.istatus
= 0;
140 if (scheduleEvents()) {
141 const auto period(_systemCounter
.period());
142 _parent
.schedule(_counterLimitReachedEvent
,
143 curTick() + (_counterLimit
- value()) * period
);
149 ArchTimer::setCompareValue(uint64_t val
)
156 ArchTimer::setTimerValue(uint32_t val
)
158 setCompareValue(value() + sext
<32>(val
));
162 ArchTimer::setControl(uint32_t val
)
164 ArchTimerCtrl new_ctl
= val
;
165 if ((new_ctl
.enable
&& !new_ctl
.imask
) &&
166 !(_control
.enable
&& !_control
.imask
)) {
167 // Re-evalute the timer condition
168 if (_counterLimit
>= value()) {
169 _control
.istatus
= 1;
171 DPRINTF(Timer
, "Causing interrupt in control\n");
175 _control
.enable
= new_ctl
.enable
;
176 _control
.imask
= new_ctl
.imask
;
180 ArchTimer::setOffset(uint64_t val
)
187 ArchTimer::value() const
189 return _systemCounter
.value() - _offset
;
193 ArchTimer::serialize(CheckpointOut
&cp
) const
195 paramOut(cp
, "control_serial", _control
);
196 SERIALIZE_SCALAR(_counterLimit
);
197 SERIALIZE_SCALAR(_offset
);
201 ArchTimer::unserialize(CheckpointIn
&cp
)
203 paramIn(cp
, "control_serial", _control
);
204 // We didn't serialize an offset before we added support for the
205 // virtual timer. Consider it optional to maintain backwards
207 if (!UNSERIALIZE_OPT_SCALAR(_offset
))
210 // We no longer schedule an event here because we may enter KVM
211 // emulation. The event creation is delayed until drainResume().
217 if (_counterLimitReachedEvent
.scheduled())
218 _parent
.deschedule(_counterLimitReachedEvent
);
220 return DrainState::Drained
;
224 ArchTimer::drainResume()
229 GenericTimer::GenericTimer(GenericTimerParams
*p
)
231 systemCounter(p
->freqs
),
234 fatal_if(!p
->system
, "No system specified, can't instantiate timer.\n");
235 system
.setGenericTimer(this);
238 const GenericTimerParams
*
239 GenericTimer::params() const
241 return dynamic_cast<const GenericTimerParams
*>(_params
);
245 GenericTimer::serialize(CheckpointOut
&cp
) const
247 paramOut(cp
, "cpu_count", timers
.size());
249 systemCounter
.serializeSection(cp
, "sys_counter");
251 for (int i
= 0; i
< timers
.size(); ++i
) {
252 const CoreTimers
&core(*timers
[i
]);
254 // This should really be phys_timerN, but we are stuck with
255 // arch_timer for backwards compatibility.
256 core
.physNS
.serializeSection(cp
, csprintf("arch_timer%d", i
));
257 core
.physS
.serializeSection(cp
, csprintf("phys_s_timer%d", i
));
258 core
.virt
.serializeSection(cp
, csprintf("virt_timer%d", i
));
259 core
.hyp
.serializeSection(cp
, csprintf("hyp_timer%d", i
));
264 GenericTimer::unserialize(CheckpointIn
&cp
)
266 systemCounter
.unserializeSection(cp
, "sys_counter");
268 // Try to unserialize the CPU count. Old versions of the timer
269 // model assumed a 8 CPUs, so we fall back to that if the field
271 static const unsigned OLD_CPU_MAX
= 8;
273 if (!UNSERIALIZE_OPT_SCALAR(cpu_count
)) {
274 warn("Checkpoint does not contain CPU count, assuming %i CPUs\n",
276 cpu_count
= OLD_CPU_MAX
;
279 for (int i
= 0; i
< cpu_count
; ++i
) {
280 CoreTimers
&core(getTimers(i
));
281 // This should really be phys_timerN, but we are stuck with
282 // arch_timer for backwards compatibility.
283 core
.physNS
.unserializeSection(cp
, csprintf("arch_timer%d", i
));
284 core
.physS
.unserializeSection(cp
, csprintf("phys_s_timer%d", i
));
285 core
.virt
.unserializeSection(cp
, csprintf("virt_timer%d", i
));
286 core
.hyp
.unserializeSection(cp
, csprintf("hyp_timer%d", i
));
291 GenericTimer::CoreTimers
&
292 GenericTimer::getTimers(int cpu_id
)
294 if (cpu_id
>= timers
.size())
295 createTimers(cpu_id
+ 1);
297 return *timers
[cpu_id
];
301 GenericTimer::createTimers(unsigned cpus
)
303 assert(timers
.size() < cpus
);
304 auto p
= static_cast<const GenericTimerParams
*>(_params
);
306 const unsigned old_cpu_count(timers
.size());
308 for (unsigned i
= old_cpu_count
; i
< cpus
; ++i
) {
310 ThreadContext
*tc
= system
.getThreadContext(i
);
313 new CoreTimers(*this, system
, i
,
314 p
->int_phys_s
->get(tc
),
315 p
->int_phys_ns
->get(tc
),
316 p
->int_virt
->get(tc
),
317 p
->int_hyp
->get(tc
)));
323 GenericTimer::setMiscReg(int reg
, unsigned cpu
, RegVal val
)
325 CoreTimers
&core(getTimers(cpu
));
329 case MISCREG_CNTFRQ_EL0
:
330 systemCounter
.setFreq(val
);
333 case MISCREG_CNTKCTL
:
334 case MISCREG_CNTKCTL_EL1
:
335 systemCounter
.setKernelControl(val
);
338 case MISCREG_CNTHCTL
:
339 case MISCREG_CNTHCTL_EL2
:
340 systemCounter
.setHypControl(val
);
343 // Physical timer (NS)
344 case MISCREG_CNTP_CVAL_NS
:
345 case MISCREG_CNTP_CVAL_EL0
:
346 core
.physNS
.setCompareValue(val
);
349 case MISCREG_CNTP_TVAL_NS
:
350 case MISCREG_CNTP_TVAL_EL0
:
351 core
.physNS
.setTimerValue(val
);
354 case MISCREG_CNTP_CTL_NS
:
355 case MISCREG_CNTP_CTL_EL0
:
356 core
.physNS
.setControl(val
);
361 case MISCREG_CNTPCT_EL0
:
363 case MISCREG_CNTVCT_EL0
:
364 warn("Ignoring write to read only count register: %s\n",
369 case MISCREG_CNTVOFF
:
370 case MISCREG_CNTVOFF_EL2
:
371 core
.virt
.setOffset(val
);
374 case MISCREG_CNTV_CVAL
:
375 case MISCREG_CNTV_CVAL_EL0
:
376 core
.virt
.setCompareValue(val
);
379 case MISCREG_CNTV_TVAL
:
380 case MISCREG_CNTV_TVAL_EL0
:
381 core
.virt
.setTimerValue(val
);
384 case MISCREG_CNTV_CTL
:
385 case MISCREG_CNTV_CTL_EL0
:
386 core
.virt
.setControl(val
);
389 // Physical timer (S)
390 case MISCREG_CNTP_CTL_S
:
391 case MISCREG_CNTPS_CTL_EL1
:
392 core
.physS
.setControl(val
);
395 case MISCREG_CNTP_CVAL_S
:
396 case MISCREG_CNTPS_CVAL_EL1
:
397 core
.physS
.setCompareValue(val
);
400 case MISCREG_CNTP_TVAL_S
:
401 case MISCREG_CNTPS_TVAL_EL1
:
402 core
.physS
.setTimerValue(val
);
405 // Hyp phys. timer, non-secure
406 case MISCREG_CNTHP_CTL
:
407 case MISCREG_CNTHP_CTL_EL2
:
408 core
.hyp
.setControl(val
);
411 case MISCREG_CNTHP_CVAL
:
412 case MISCREG_CNTHP_CVAL_EL2
:
413 core
.hyp
.setCompareValue(val
);
416 case MISCREG_CNTHP_TVAL
:
417 case MISCREG_CNTHP_TVAL_EL2
:
418 core
.hyp
.setTimerValue(val
);
422 warn("Writing to unknown register: %s\n", miscRegName
[reg
]);
429 GenericTimer::readMiscReg(int reg
, unsigned cpu
)
431 CoreTimers
&core(getTimers(cpu
));
435 case MISCREG_CNTFRQ_EL0
:
436 return systemCounter
.freq();
438 case MISCREG_CNTKCTL
:
439 case MISCREG_CNTKCTL_EL1
:
440 return systemCounter
.getKernelControl();
442 case MISCREG_CNTHCTL
:
443 case MISCREG_CNTHCTL_EL2
:
444 return systemCounter
.getHypControl();
447 case MISCREG_CNTP_CVAL_NS
:
448 case MISCREG_CNTP_CVAL_EL0
:
449 return core
.physNS
.compareValue();
451 case MISCREG_CNTP_TVAL_NS
:
452 case MISCREG_CNTP_TVAL_EL0
:
453 return core
.physNS
.timerValue();
455 case MISCREG_CNTP_CTL_EL0
:
456 case MISCREG_CNTP_CTL_NS
:
457 return core
.physNS
.control();
460 case MISCREG_CNTPCT_EL0
:
461 return core
.physNS
.value();
466 case MISCREG_CNTVCT_EL0
:
467 return core
.virt
.value();
469 case MISCREG_CNTVOFF
:
470 case MISCREG_CNTVOFF_EL2
:
471 return core
.virt
.offset();
473 case MISCREG_CNTV_CVAL
:
474 case MISCREG_CNTV_CVAL_EL0
:
475 return core
.virt
.compareValue();
477 case MISCREG_CNTV_TVAL
:
478 case MISCREG_CNTV_TVAL_EL0
:
479 return core
.virt
.timerValue();
481 case MISCREG_CNTV_CTL
:
482 case MISCREG_CNTV_CTL_EL0
:
483 return core
.virt
.control();
485 // PL1 phys. timer, secure
486 case MISCREG_CNTP_CTL_S
:
487 case MISCREG_CNTPS_CTL_EL1
:
488 return core
.physS
.control();
490 case MISCREG_CNTP_CVAL_S
:
491 case MISCREG_CNTPS_CVAL_EL1
:
492 return core
.physS
.compareValue();
494 case MISCREG_CNTP_TVAL_S
:
495 case MISCREG_CNTPS_TVAL_EL1
:
496 return core
.physS
.timerValue();
498 // HYP phys. timer (NS)
499 case MISCREG_CNTHP_CTL
:
500 case MISCREG_CNTHP_CTL_EL2
:
501 return core
.hyp
.control();
503 case MISCREG_CNTHP_CVAL
:
504 case MISCREG_CNTHP_CVAL_EL2
:
505 return core
.hyp
.compareValue();
507 case MISCREG_CNTHP_TVAL
:
508 case MISCREG_CNTHP_TVAL_EL2
:
509 return core
.hyp
.timerValue();
512 warn("Reading from unknown register: %s\n", miscRegName
[reg
]);
519 GenericTimerISA::setMiscReg(int reg
, RegVal val
)
521 DPRINTF(Timer
, "Setting %s := 0x%x\n", miscRegName
[reg
], val
);
522 parent
.setMiscReg(reg
, cpu
, val
);
526 GenericTimerISA::readMiscReg(int reg
)
528 RegVal value
= parent
.readMiscReg(reg
, cpu
);
529 DPRINTF(Timer
, "Reading %s as 0x%x\n", miscRegName
[reg
], value
);
533 GenericTimerMem::GenericTimerMem(GenericTimerMemParams
*p
)
535 ctrlRange(RangeSize(p
->base
, sys
->getPageBytes())),
536 timerRange(RangeSize(p
->base
+ sys
->getPageBytes(),
537 sys
->getPageBytes())),
538 addrRanges
{ctrlRange
, timerRange
},
539 systemCounter(p
->freqs
),
540 physTimer(csprintf("%s.phys_timer0", name()),
541 *this, systemCounter
,
543 virtTimer(csprintf("%s.virt_timer0", name()),
544 *this, systemCounter
,
550 GenericTimerMem::serialize(CheckpointOut
&cp
) const
552 paramOut(cp
, "timer_count", 1);
554 systemCounter
.serializeSection(cp
, "sys_counter");
556 physTimer
.serializeSection(cp
, "phys_timer0");
557 virtTimer
.serializeSection(cp
, "virt_timer0");
561 GenericTimerMem::unserialize(CheckpointIn
&cp
)
563 systemCounter
.unserializeSection(cp
, "sys_counter");
565 unsigned timer_count
;
566 UNSERIALIZE_SCALAR(timer_count
);
567 // The timer count variable is just here for future versions where
568 // we support more than one set of timers.
569 if (timer_count
!= 1)
570 panic("Incompatible checkpoint: Only one set of timers supported");
572 physTimer
.unserializeSection(cp
, "phys_timer0");
573 virtTimer
.unserializeSection(cp
, "virt_timer0");
577 GenericTimerMem::read(PacketPtr pkt
)
579 const unsigned size(pkt
->getSize());
580 const Addr
addr(pkt
->getAddr());
584 if (ctrlRange
.contains(addr
)) {
585 value
= ctrlRead(addr
- ctrlRange
.start(), size
);
586 } else if (timerRange
.contains(addr
)) {
587 value
= timerRead(addr
- timerRange
.start(), size
);
589 panic("Invalid address: 0x%x\n", addr
);
592 DPRINTF(Timer
, "Read 0x%x <- 0x%x(%i)\n", value
, addr
, size
);
595 pkt
->setLE
<uint64_t>(value
);
596 } else if (size
== 4) {
597 pkt
->setLE
<uint32_t>(value
);
599 panic("Unexpected access size: %i\n", size
);
606 GenericTimerMem::write(PacketPtr pkt
)
608 const unsigned size(pkt
->getSize());
609 if (size
!= 8 && size
!= 4)
610 panic("Unexpected access size\n");
612 const Addr
addr(pkt
->getAddr());
613 const uint64_t value(size
== 8 ?
614 pkt
->getLE
<uint64_t>() : pkt
->getLE
<uint32_t>());
616 DPRINTF(Timer
, "Write 0x%x -> 0x%x(%i)\n", value
, addr
, size
);
617 if (ctrlRange
.contains(addr
)) {
618 ctrlWrite(addr
- ctrlRange
.start(), size
, value
);
619 } else if (timerRange
.contains(addr
)) {
620 timerWrite(addr
- timerRange
.start(), size
, value
);
622 panic("Invalid address: 0x%x\n", addr
);
630 GenericTimerMem::ctrlRead(Addr addr
, size_t size
) const
635 return systemCounter
.freq();
638 return 0x3; // Frame 0 implemented with virtual timers
641 case CTRL_CNTACR_BASE
:
642 warn("Reading from unimplemented control register (0x%x)\n", addr
);
645 case CTRL_CNTVOFF_LO_BASE
:
646 return virtTimer
.offset();
648 case CTRL_CNTVOFF_HI_BASE
:
649 return virtTimer
.offset() >> 32;
652 warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr
, size
);
655 } else if (size
== 8) {
657 case CTRL_CNTVOFF_LO_BASE
:
658 return virtTimer
.offset();
661 warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr
, size
);
665 panic("Invalid access size: %i\n", size
);
670 GenericTimerMem::ctrlWrite(Addr addr
, size_t size
, uint64_t value
)
677 case CTRL_CNTACR_BASE
:
678 warn("Write to unimplemented control register (0x%x)\n", addr
);
681 case CTRL_CNTVOFF_LO_BASE
:
683 insertBits(virtTimer
.offset(), 31, 0, value
));
686 case CTRL_CNTVOFF_HI_BASE
:
688 insertBits(virtTimer
.offset(), 63, 32, value
));
692 warn("Ignoring write to unexpected address (0x%x:%i)\n",
696 } else if (size
== 8) {
698 case CTRL_CNTVOFF_LO_BASE
:
699 virtTimer
.setOffset(value
);
703 warn("Ignoring write to unexpected address (0x%x:%i)\n",
708 panic("Invalid access size: %i\n", size
);
713 GenericTimerMem::timerRead(Addr addr
, size_t size
) const
717 case TIMER_CNTPCT_LO
:
718 return physTimer
.value();
720 case TIMER_CNTPCT_HI
:
721 return physTimer
.value() >> 32;
723 case TIMER_CNTVCT_LO
:
724 return virtTimer
.value();
726 case TIMER_CNTVCT_HI
:
727 return virtTimer
.value() >> 32;
730 return systemCounter
.freq();
732 case TIMER_CNTEL0ACR
:
733 warn("Read from unimplemented timer register (0x%x)\n", addr
);
736 case CTRL_CNTVOFF_LO_BASE
:
737 return virtTimer
.offset();
739 case CTRL_CNTVOFF_HI_BASE
:
740 return virtTimer
.offset() >> 32;
742 case TIMER_CNTP_CVAL_LO
:
743 return physTimer
.compareValue();
745 case TIMER_CNTP_CVAL_HI
:
746 return physTimer
.compareValue() >> 32;
748 case TIMER_CNTP_TVAL
:
749 return physTimer
.timerValue();
752 return physTimer
.control();
754 case TIMER_CNTV_CVAL_LO
:
755 return virtTimer
.compareValue();
757 case TIMER_CNTV_CVAL_HI
:
758 return virtTimer
.compareValue() >> 32;
760 case TIMER_CNTV_TVAL
:
761 return virtTimer
.timerValue();
764 return virtTimer
.control();
767 warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr
, size
);
770 } else if (size
== 8) {
772 case TIMER_CNTPCT_LO
:
773 return physTimer
.value();
775 case TIMER_CNTVCT_LO
:
776 return virtTimer
.value();
778 case CTRL_CNTVOFF_LO_BASE
:
779 return virtTimer
.offset();
781 case TIMER_CNTP_CVAL_LO
:
782 return physTimer
.compareValue();
784 case TIMER_CNTV_CVAL_LO
:
785 return virtTimer
.compareValue();
788 warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr
, size
);
792 panic("Invalid access size: %i\n", size
);
797 GenericTimerMem::timerWrite(Addr addr
, size_t size
, uint64_t value
)
801 case TIMER_CNTEL0ACR
:
802 warn("Unimplemented timer register (0x%x)\n", addr
);
805 case TIMER_CNTP_CVAL_LO
:
806 physTimer
.setCompareValue(
807 insertBits(physTimer
.compareValue(), 31, 0, value
));
810 case TIMER_CNTP_CVAL_HI
:
811 physTimer
.setCompareValue(
812 insertBits(physTimer
.compareValue(), 63, 32, value
));
815 case TIMER_CNTP_TVAL
:
816 physTimer
.setTimerValue(value
);
820 physTimer
.setControl(value
);
823 case TIMER_CNTV_CVAL_LO
:
824 virtTimer
.setCompareValue(
825 insertBits(virtTimer
.compareValue(), 31, 0, value
));
828 case TIMER_CNTV_CVAL_HI
:
829 virtTimer
.setCompareValue(
830 insertBits(virtTimer
.compareValue(), 63, 32, value
));
833 case TIMER_CNTV_TVAL
:
834 virtTimer
.setTimerValue(value
);
838 virtTimer
.setControl(value
);
842 warn("Unexpected address (0x%x:%i), ignoring write\n", addr
, size
);
845 } else if (size
== 8) {
847 case TIMER_CNTP_CVAL_LO
:
848 return physTimer
.setCompareValue(value
);
850 case TIMER_CNTV_CVAL_LO
:
851 return virtTimer
.setCompareValue(value
);
854 warn("Unexpected address (0x%x:%i), ignoring write\n", addr
, size
);
858 panic("Invalid access size: %i\n", size
);
863 GenericTimerParams::create()
865 return new GenericTimer(this);
869 GenericTimerMemParams::create()
871 return new GenericTimerMem(this);