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
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(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
78void
79SystemCounter::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
94ArchTimer::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
105void
106ArchTimer::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
124void
125ArchTimer::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
141void
142ArchTimer::setCompareValue(uint64_t val)
143{
144    _counterLimit = val;
145    updateCounter();
146}
147
148void
149ArchTimer::setTimerValue(uint32_t val)
150{
151    setCompareValue(value() + sext<32>(val));
152}
153
154void
155ArchTimer::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
172void
173ArchTimer::setOffset(uint64_t val)
174{
175    _offset = val;
176    updateCounter();
177}
178
179uint64_t
180ArchTimer::value() const
181{
182    return _systemCounter.value() - _offset;
183}
184
185void
186ArchTimer::serialize(CheckpointOut &cp) const
187{
188    paramOut(cp, "control_serial", _control);
189    SERIALIZE_SCALAR(_counterLimit);
190    SERIALIZE_SCALAR(_offset);
191}
192
193void
194ArchTimer::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
207DrainState
208ArchTimer::drain()
209{
210    if (_counterLimitReachedEvent.scheduled())
211        _parent.deschedule(_counterLimitReachedEvent);
212
213    return DrainState::Drained;
214}
215
216void
217ArchTimer::drainResume()
218{
219    updateCounter();
220}
221
222GenericTimer::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
230const GenericTimerParams *
231GenericTimer::params() const
232{
233    return dynamic_cast<const GenericTimerParams *>(_params);
234}
235
236void
237GenericTimer::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
255void
256GenericTimer::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
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    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
314void
315GenericTimer::setMiscReg(int reg, unsigned cpu, RegVal 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
420RegVal
421GenericTimer::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
510void
511GenericTimerISA::setMiscReg(int reg, RegVal val)
512{
513    DPRINTF(Timer, "Setting %s := 0x%x\n", miscRegName[reg], val);
514    parent.setMiscReg(reg, cpu, val);
515}
516
517RegVal
518GenericTimerISA::readMiscReg(int reg)
519{
520    RegVal value = parent.readMiscReg(reg, cpu);
521    DPRINTF(Timer, "Reading %s as 0x%x\n", miscRegName[reg], value);
522    return value;
523}
524
525GenericTimerMem::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
540void
541GenericTimerMem::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
551void
552GenericTimerMem::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
567Tick
568GenericTimerMem::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
596Tick
597GenericTimerMem::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
620uint64_t
621GenericTimerMem::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
660void
661GenericTimerMem::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
703uint64_t
704GenericTimerMem::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
787void
788GenericTimerMem::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
853GenericTimer *
854GenericTimerParams::create()
855{
856    return new GenericTimer(this);
857}
858
859GenericTimerMem *
860GenericTimerMemParams::create()
861{
862    return new GenericTimerMem(this);
863}
864