gem5  v22.1.0.0
generic_timer.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013, 2015, 2017-2018,2020,2022 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 
38 #include "dev/arm/generic_timer.hh"
39 
40 #include <cmath>
41 #include <string_view>
42 
43 #include "arch/arm/page_size.hh"
44 #include "arch/arm/system.hh"
45 #include "arch/arm/utility.hh"
46 #include "base/logging.hh"
47 #include "base/trace.hh"
48 #include "config/kvm_isa.hh"
49 #include "config/use_kvm.hh"
50 #include "cpu/base.hh"
51 #include "cpu/kvm/vm.hh"
52 #include "debug/Timer.hh"
53 #include "dev/arm/base_gic.hh"
54 #include "mem/packet_access.hh"
55 #include "params/GenericTimer.hh"
56 #include "params/GenericTimerFrame.hh"
57 #include "params/GenericTimerMem.hh"
58 #include "params/SystemCounter.hh"
59 #include "sim/core.hh"
60 #include "sim/cur_tick.hh"
61 
62 namespace gem5
63 {
64 
65 using namespace ArmISA;
66 
67 SystemCounter::SystemCounter(const SystemCounterParams &p)
68  : SimObject(p),
69  _enabled(true),
70  _value(0),
71  _increment(1),
72  _freqTable(p.freqs),
73  _activeFreqEntry(0),
74  _updateTick(0),
75  _freqUpdateEvent([this]{ freqUpdateCallback(); }, name()),
76  _nextFreqEntry(0)
77 {
78  fatal_if(_freqTable.empty(), "SystemCounter::SystemCounter: Base "
79  "frequency not provided\n");
80  // Store the table end marker as a 32-bit zero word
81  _freqTable.push_back(0);
83  "SystemCounter::SystemCounter: Architecture states a maximum of 1004 "
84  "frequency table entries, limit surpassed\n");
85  // Set the active frequency to be the base
86  _freq = _freqTable.front();
88 }
89 
90 void
92 {
93  fatal_if(!sys_cnt, "SystemCounter::validateCounterRef: No valid system "
94  "counter, can't instantiate system timers\n");
95 }
96 
97 void
99 {
100  DPRINTF(Timer, "SystemCounter::enable: Counter enabled\n");
101  _enabled = true;
102  updateTick();
103 }
104 
105 void
107 {
108  DPRINTF(Timer, "SystemCounter::disable: Counter disabled\n");
109  updateValue();
110  _enabled = false;
111 }
112 
113 uint64_t
115 {
116  if (_enabled)
117  updateValue();
118  return _value;
119 }
120 
121 void
123 {
124  uint64_t new_value =
126  if (new_value > _value) {
127  _value = new_value;
128  updateTick();
129  }
130 }
131 
132 void
133 SystemCounter::setValue(uint64_t new_value)
134 {
135  if (_enabled)
136  warn("Explicit value set with counter enabled, UNKNOWNN result\n");
137  _value = new_value;
138  updateTick();
139  notifyListeners();
140 }
141 
142 Tick
143 SystemCounter::whenValue(uint64_t cur_val, uint64_t target_val) const
144 {
145  Tick when = curTick();
146  if (target_val > cur_val) {
147  uint64_t num_cycles =
148  std::ceil((target_val - cur_val) / ((double) _increment));
149  // Take into account current cycle remaining ticks
150  Tick rem_ticks = _period - (curTick() % _period);
151  if (rem_ticks < _period) {
152  when += rem_ticks;
153  num_cycles -= 1;
154  }
155  when += num_cycles * _period;
156  }
157  return when;
158 }
159 
160 Tick
161 SystemCounter::whenValue(uint64_t target_val)
162 {
163  return whenValue(value(), target_val);
164 }
165 
166 void
168 {
169  _updateTick = curTick() - (curTick() % _period);
170 }
171 
172 void
173 SystemCounter::freqUpdateSchedule(size_t new_freq_entry)
174 {
175  if (new_freq_entry < _freqTable.size()) {
176  auto &new_freq = _freqTable[new_freq_entry];
177  if (new_freq != _freq) {
178  _nextFreqEntry = new_freq_entry;
179  // Wait until the value for which the lowest frequency increment
180  // is a exact divisor. This covers both high to low and low to
181  // high transitions
182  uint64_t new_incr = _freqTable[0] / new_freq;
183  uint64_t target_val = value();
184  target_val += target_val % std::max(_increment, new_incr);
185  reschedule(_freqUpdateEvent, whenValue(target_val), true);
186  }
187  }
188 }
189 
190 void
192 {
193  DPRINTF(Timer, "SystemCounter::freqUpdateCallback: Changing counter "
194  "frequency\n");
195  if (_enabled)
196  updateValue();
199  _increment = _freqTable[0] / _freq;
200  _period = (1.0 / _freq) * sim_clock::Frequency;
201  notifyListeners();
202 }
203 
204 void
206 {
207  _listeners.push_back(listener);
208 }
209 
210 void
212 {
213  for (auto &listener : _listeners)
214  listener->notify();
215 }
216 
217 void
219 {
220  DPRINTF(Timer, "SystemCounter::serialize: Serializing\n");
228  bool pending_freq_update = _freqUpdateEvent.scheduled();
229  SERIALIZE_SCALAR(pending_freq_update);
230  if (pending_freq_update) {
231  Tick when_freq_update = _freqUpdateEvent.when();
232  SERIALIZE_SCALAR(when_freq_update);
233  }
235 }
236 
237 void
239 {
240  DPRINTF(Timer, "SystemCounter::unserialize: Unserializing\n");
248  bool pending_freq_update;
249  UNSERIALIZE_SCALAR(pending_freq_update);
250  if (pending_freq_update) {
251  Tick when_freq_update;
252  UNSERIALIZE_SCALAR(when_freq_update);
253  reschedule(_freqUpdateEvent, when_freq_update, true);
254  }
256 
257  _period = (1.0 / _freq) * sim_clock::Frequency;
258 }
259 
260 ArchTimer::ArchTimer(const std::string &name,
261  SimObject &parent,
262  SystemCounter &sysctr,
263  ArmInterruptPin *interrupt)
264  : _name(name), _parent(parent), _systemCounter(sysctr),
265  _interrupt(interrupt),
266  _control(0), _counterLimit(0), _offset(0),
267  _counterLimitReachedEvent([this]{ counterLimitReached(); }, name)
268 {
269  _systemCounter.registerListener(this);
270 }
271 
272 void
274 {
275  if (!_control.enable)
276  return;
277 
278  DPRINTF(Timer, "Counter limit reached\n");
279  _control.istatus = 1;
280  if (!_control.imask) {
281  if (scheduleEvents()) {
282  DPRINTF(Timer, "Causing interrupt\n");
283  _interrupt->raise();
284  } else {
285  DPRINTF(Timer, "Kvm mode; skipping simulated interrupt\n");
286  }
287  }
288 }
289 
290 void
292 {
295  if (value() >= _counterLimit) {
297  } else {
298  // Clear the interurpt when timers conditions are not met
299  if (_interrupt->active()) {
300  DPRINTF(Timer, "Clearing interrupt\n");
301  _interrupt->clear();
302  }
303 
304  _control.istatus = 0;
305 
306  if (scheduleEvents()) {
309  }
310  }
311 }
312 
313 void
315 {
316  _counterLimit = val;
317  updateCounter();
318 }
319 
320 void
322 {
323  setCompareValue(value() + sext<32>(val));
324 }
325 
326 void
328 {
329  ArchTimerCtrl old_ctl = _control, new_ctl = val;
330  _control.enable = new_ctl.enable;
331  _control.imask = new_ctl.imask;
332  _control.istatus = old_ctl.istatus;
333  // Timer unmasked or enabled
334  if ((old_ctl.imask && !new_ctl.imask) ||
335  (!old_ctl.enable && new_ctl.enable))
336  updateCounter();
337  // Timer masked or disabled
338  else if ((!old_ctl.imask && new_ctl.imask) ||
339  (old_ctl.enable && !new_ctl.enable)) {
340 
341  if (_interrupt->active()) {
342  DPRINTF(Timer, "Clearing interrupt\n");
343  // We are clearing the interrupt but we are not
344  // setting istatus to 0 as we are doing
345  // in the updateCounter.
346  // istatus signals that Timer conditions are met.
347  // It shouldn't depend on masking.
348  // if enable is zero. istatus is unknown.
349  _interrupt->clear();
350  }
351  }
352 }
353 
354 void
356 {
357  _offset = val;
358  updateCounter();
359 }
360 
361 uint64_t
363 {
364  return _systemCounter.value() - _offset;
365 }
366 
367 void
369 {
370  updateCounter();
371 }
372 
373 void
375 {
376  paramOut(cp, "control_serial", _control);
379 }
380 
381 void
383 {
384  paramIn(cp, "control_serial", _control);
385  // We didn't serialize an offset before we added support for the
386  // virtual timer. Consider it optional to maintain backwards
387  // compatibility.
389  _offset = 0;
390 
391  // We no longer schedule an event here because we may enter KVM
392  // emulation. The event creation is delayed until drainResume().
393 }
394 
397 {
400 
401  return DrainState::Drained;
402 }
403 
404 void
406 {
407  updateCounter();
408 }
409 
410 bool
412 {
413  if constexpr (USE_KVM &&
414  std::string_view(KVM_ISA) == std::string_view("arm")) {
415  auto *vm = system.getKvmVM();
416  return !vm || !vm->validEnvironment();
417  } else {
418  return true;
419  }
420 }
421 
422 GenericTimer::GenericTimer(const GenericTimerParams &p)
423  : SimObject(p),
424  systemCounter(*p.counter),
425  system(*p.system)
426 {
428  fatal_if(!p.system, "GenericTimer::GenericTimer: No system specified, "
429  "can't instantiate architected timers\n");
430  system.setGenericTimer(this);
431 }
432 
433 void
435 {
436  paramOut(cp, "cpu_count", timers.size());
437 
438  for (int i = 0; i < timers.size(); ++i) {
439  const CoreTimers &core(*timers[i]);
440  core.serializeSection(cp, csprintf("pe_implementation%d", i));
441  }
442 }
443 
444 void
446 {
447  // Try to unserialize the CPU count. Old versions of the timer
448  // model assumed a 8 CPUs, so we fall back to that if the field
449  // isn't present.
450  static const unsigned OLD_CPU_MAX = 8;
451  unsigned cpu_count;
452  if (!UNSERIALIZE_OPT_SCALAR(cpu_count)) {
453  warn("Checkpoint does not contain CPU count, assuming %i CPUs\n",
454  OLD_CPU_MAX);
455  cpu_count = OLD_CPU_MAX;
456  }
457 
458  // We cannot assert for equality here because CPU timers are dynamically
459  // created on the first miscreg access. Therefore, if we take the checkpoint
460  // before any timer registers have been accessed, the number of counters
461  // is actually smaller than the total number of CPUs.
462  if (cpu_count > system.threads.size()) {
463  fatal("The simulated system has been initialized with %d CPUs, "
464  "but the Generic Timer checkpoint expects %d CPUs. Consider "
465  "restoring the checkpoint specifying %d CPUs.",
466  system.threads.size(), cpu_count, cpu_count);
467  }
468 
469  for (int i = 0; i < cpu_count; ++i) {
470  CoreTimers &core(getTimers(i));
471  core.unserializeSection(cp, csprintf("pe_implementation%d", i));
472  }
473 }
474 
477 {
478  if (cpu_id >= timers.size())
479  createTimers(cpu_id + 1);
480 
481  return *timers[cpu_id];
482 }
483 
484 void
486 {
487  assert(timers.size() < cpus);
488  auto &p = params();
489 
490  const unsigned old_cpu_count(timers.size());
491  timers.resize(cpus);
492  for (unsigned i = old_cpu_count; i < cpus; ++i) {
493 
494  ThreadContext *tc = system.threads[i];
495 
496  timers[i].reset(
497  new CoreTimers(*this, system, i,
498  p.int_el3_phys->get(tc),
499  p.int_el1_phys->get(tc),
500  p.int_el1_virt->get(tc),
501  p.int_el2_ns_phys->get(tc),
502  p.int_el2_ns_virt->get(tc),
503  p.int_el2_s_phys->get(tc),
504  p.int_el2_s_virt->get(tc)));
505  }
506 }
507 
508 void
510  ArchTimer *timer, RegVal old_cnt_ctl, RegVal cnt_ctl)
511 {
512  uint64_t evnten = bits(cnt_ctl, 2);
513  uint64_t old_evnten = bits(old_cnt_ctl, 2);
514  uint8_t old_trans_to = ev_stream->transitionTo;
515  uint8_t old_trans_bit = ev_stream->transitionBit;
516  ev_stream->transitionTo = !bits(cnt_ctl, 3);
517  ev_stream->transitionBit = bits(cnt_ctl, 7, 4);
518  // Reschedule the Event Stream if enabled and any change in
519  // configuration
520  if (evnten && ((old_evnten != evnten) ||
521  (old_trans_to != ev_stream->transitionTo) ||
522  (old_trans_bit != ev_stream->transitionBit))) {
523 
524  Tick when = timer->whenValue(
525  ev_stream->eventTargetValue(timer->value()));
526  reschedule(ev_stream->event, when, true);
527  } else if (old_evnten && !evnten) {
528  // Event Stream generation disabled
529  if (ev_stream->event.scheduled())
530  deschedule(ev_stream->event);
531  }
532 }
533 
534 void
536 {
537  CoreTimers &core(getTimers(cpu));
538 
539  switch (reg) {
540  case MISCREG_CNTFRQ:
541  case MISCREG_CNTFRQ_EL0:
542  core.cntfrq = val;
543  warn_if(core.cntfrq != systemCounter.freq(), "CNTFRQ configured freq "
544  "does not match the system counter freq\n");
545  return;
546  case MISCREG_CNTKCTL:
547  case MISCREG_CNTKCTL_EL1:
548  {
549  RegVal old_cnt_ctl = core.cntkctl;
550  core.cntkctl = val;
551 
552  ArchTimer *timer = &core.virtEL1;
553  CoreTimers::EventStream *ev_stream = &core.virtEvStream;
554 
555  handleStream(ev_stream, timer, old_cnt_ctl, val);
556  return;
557  }
558  case MISCREG_CNTHCTL:
559  case MISCREG_CNTHCTL_EL2:
560  {
561  RegVal old_cnt_ctl = core.cnthctl;
562  core.cnthctl = val;
563 
564  ArchTimer *timer = &core.physEL1;
565  CoreTimers::EventStream *ev_stream = &core.physEvStream;
566 
567  handleStream(ev_stream, timer, old_cnt_ctl, val);
568  return;
569  }
570  // EL1 physical timer
574  return;
575 
578  core.physEL1.setTimerValue(val);
579  return;
580 
581  case MISCREG_CNTP_CTL_NS:
583  core.physEL1.setControl(val);
584  return;
585 
586  // Count registers
587  case MISCREG_CNTPCT:
588  case MISCREG_CNTPCT_EL0:
589  case MISCREG_CNTVCT:
590  case MISCREG_CNTVCT_EL0:
591  warn("Ignoring write to read only count register: %s\n",
592  miscRegName[reg]);
593  return;
594 
595  // EL1 virtual timer
596  case MISCREG_CNTVOFF:
597  case MISCREG_CNTVOFF_EL2:
598  core.virtEL1.setOffset(val);
599  return;
600 
601  case MISCREG_CNTV_CVAL:
604  return;
605 
606  case MISCREG_CNTV_TVAL:
608  core.virtEL1.setTimerValue(val);
609  return;
610 
611  case MISCREG_CNTV_CTL:
613  core.virtEL1.setControl(val);
614  return;
615 
616  // EL3 physical timer
617  case MISCREG_CNTP_CTL_S:
619  core.physEL3.setControl(val);
620  return;
621 
622  case MISCREG_CNTP_CVAL_S:
625  return;
626 
627  case MISCREG_CNTP_TVAL_S:
629  core.physEL3.setTimerValue(val);
630  return;
631 
632  // EL2 Non-secure physical timer
633  case MISCREG_CNTHP_CTL:
635  core.physNsEL2.setControl(val);
636  return;
637 
638  case MISCREG_CNTHP_CVAL:
641  return;
642 
643  case MISCREG_CNTHP_TVAL:
646  return;
647 
648  // EL2 Non-secure virtual timer
650  core.virtNsEL2.setControl(val);
651  return;
652 
655  return;
656 
659  return;
660 
661  // EL2 Secure physical timer
663  core.physSEL2.setControl(val);
664  return;
665 
668  return;
669 
671  core.physSEL2.setTimerValue(val);
672  return;
673 
674  // EL2 Secure virtual timer
676  core.virtSEL2.setControl(val);
677  return;
678 
681  return;
682 
684  core.virtSEL2.setTimerValue(val);
685  return;
686 
687  default:
688  warn("Writing to unknown register: %s\n", miscRegName[reg]);
689  return;
690  }
691 }
692 
693 
694 RegVal
695 GenericTimer::readMiscReg(int reg, unsigned cpu)
696 {
697  CoreTimers &core(getTimers(cpu));
698 
699  switch (reg) {
700  case MISCREG_CNTFRQ:
701  case MISCREG_CNTFRQ_EL0:
702  return core.cntfrq;
703  case MISCREG_CNTKCTL:
704  case MISCREG_CNTKCTL_EL1:
705  return core.cntkctl & 0x00000000ffffffff;
706  case MISCREG_CNTHCTL:
707  case MISCREG_CNTHCTL_EL2:
708  return core.cnthctl & 0x00000000ffffffff;
709  // EL1 physical timer
712  return core.physEL1.compareValue();
713 
716  return core.physEL1.timerValue();
717 
719  case MISCREG_CNTP_CTL_NS:
720  return core.physEL1.control();
721 
722  case MISCREG_CNTPCT:
723  case MISCREG_CNTPCT_EL0:
724  return core.physEL1.value();
725 
726 
727  // EL1 virtual timer
728  case MISCREG_CNTVCT:
729  case MISCREG_CNTVCT_EL0:
730  return core.virtEL1.value();
731 
732  case MISCREG_CNTVOFF:
733  case MISCREG_CNTVOFF_EL2:
734  return core.virtEL1.offset();
735 
736  case MISCREG_CNTV_CVAL:
738  return core.virtEL1.compareValue();
739 
740  case MISCREG_CNTV_TVAL:
742  return core.virtEL1.timerValue();
743 
744  case MISCREG_CNTV_CTL:
746  return core.virtEL1.control();
747 
748  // EL3 physical timer
749  case MISCREG_CNTP_CTL_S:
751  return core.physEL3.control();
752 
753  case MISCREG_CNTP_CVAL_S:
755  return core.physEL3.compareValue();
756 
757  case MISCREG_CNTP_TVAL_S:
759  return core.physEL3.timerValue();
760 
761  // EL2 Non-secure physical timer
762  case MISCREG_CNTHP_CTL:
764  return core.physNsEL2.control();
765 
766  case MISCREG_CNTHP_CVAL:
768  return core.physNsEL2.compareValue();
769 
770  case MISCREG_CNTHP_TVAL:
772  return core.physNsEL2.timerValue();
773 
774  // EL2 Non-secure virtual timer
776  return core.virtNsEL2.control();
777 
779  return core.virtNsEL2.compareValue();
780 
782  return core.virtNsEL2.timerValue();
783 
784  // EL2 Secure physical timer
786  return core.physSEL2.control();
787 
789  return core.physSEL2.compareValue();
790 
792  return core.physSEL2.timerValue();
793 
794  // EL2 Secure virtual timer
796  return core.virtSEL2.control();
797 
799  return core.virtSEL2.compareValue();
800 
802  return core.virtSEL2.timerValue();
803 
804  default:
805  warn("Reading from unknown register: %s\n", miscRegName[reg]);
806  return 0;
807  }
808 }
809 
811  ArmSystem &system, unsigned cpu,
812  ArmInterruptPin *irq_el3_phys, ArmInterruptPin *irq_el1_phys,
813  ArmInterruptPin *irq_el1_virt, ArmInterruptPin *irq_el2_ns_phys,
814  ArmInterruptPin *irq_el2_ns_virt, ArmInterruptPin *irq_el2_s_phys,
815  ArmInterruptPin *irq_el2_s_virt)
816  : parent(_parent),
817  cntfrq(parent.params().cntfrq),
818  cntkctl(0), cnthctl(0),
819  threadContext(system.threads[cpu]),
820  irqPhysEL3(irq_el3_phys),
821  irqPhysEL1(irq_el1_phys),
822  irqVirtEL1(irq_el1_virt),
823  irqPhysNsEL2(irq_el2_ns_phys),
824  irqVirtNsEL2(irq_el2_ns_virt),
825  irqPhysSEL2(irq_el2_s_phys),
826  irqVirtSEL2(irq_el2_s_virt),
827  physEL3(csprintf("%s.el3_phys_timer%d", parent.name(), cpu),
828  system, parent, parent.systemCounter,
829  irq_el3_phys),
830  physEL1(csprintf("%s.el1_phys_timer%d", parent.name(), cpu),
831  system, parent, parent.systemCounter,
832  irq_el1_phys),
833  virtEL1(csprintf("%s.el1_virt_timer%d", parent.name(), cpu),
834  system, parent, parent.systemCounter,
835  irq_el1_virt),
836  physNsEL2(csprintf("%s.el2_ns_phys_timer%d", parent.name(), cpu),
837  system, parent, parent.systemCounter,
838  irq_el2_ns_phys),
839  virtNsEL2(csprintf("%s.el2_ns_virt_timer%d", parent.name(), cpu),
840  system, parent, parent.systemCounter,
841  irq_el2_ns_virt),
842  physSEL2(csprintf("%s.el2_s_phys_timer%d", parent.name(), cpu),
843  system, parent, parent.systemCounter,
844  irq_el2_s_phys),
845  virtSEL2(csprintf("%s.el2_s_virt_timer%d", parent.name(), cpu),
846  system, parent, parent.systemCounter,
847  irq_el2_s_virt),
848  physEvStream{
850  csprintf("%s.phys_event_gen%d", parent.name(), cpu)), 0, 0
851  },
852  virtEvStream{
853  EventFunctionWrapper([this]{ virtEventStreamCallback(); },
854  csprintf("%s.virt_event_gen%d", parent.name(), cpu)), 0, 0
855  }
856 {
857 }
858 
859 void
861 {
864 }
865 
866 void
868 {
869  eventStreamCallback();
870  schedNextEvent(virtEvStream, virtEL1);
871 }
872 
873 void
875 {
876  sendEvent(threadContext);
877  threadContext->getCpuPtr()->wakeup(threadContext->threadId());
878 }
879 
880 void
882  ArchTimer &timer)
883 {
884  parent.reschedule(ev_stream.event, timer.whenValue(
885  ev_stream.eventTargetValue(timer.value())), true);
886 }
887 
888 void
890 {
891  schedNextEvent(virtEvStream, virtEL1);
892  schedNextEvent(physEvStream, physEL1);
893 }
894 
895 void
897 {
898  SERIALIZE_SCALAR(cntfrq);
899  SERIALIZE_SCALAR(cntkctl);
900  SERIALIZE_SCALAR(cnthctl);
901 
902  const bool phys_ev_scheduled = physEvStream.event.scheduled();
903  SERIALIZE_SCALAR(phys_ev_scheduled);
904  if (phys_ev_scheduled) {
905  const Tick phys_ev_when = physEvStream.event.when();
906  SERIALIZE_SCALAR(phys_ev_when);
907  }
908  SERIALIZE_SCALAR(physEvStream.transitionTo);
909  SERIALIZE_SCALAR(physEvStream.transitionBit);
910 
911  const bool virt_ev_scheduled = virtEvStream.event.scheduled();
912  SERIALIZE_SCALAR(virt_ev_scheduled);
913  if (virt_ev_scheduled) {
914  const Tick virt_ev_when = virtEvStream.event.when();
915  SERIALIZE_SCALAR(virt_ev_when);
916  }
917  SERIALIZE_SCALAR(virtEvStream.transitionTo);
918  SERIALIZE_SCALAR(virtEvStream.transitionBit);
919 
920  physEL3.serializeSection(cp, "phys_el3_timer");
921  physEL1.serializeSection(cp, "phys_el1_timer");
922  virtEL1.serializeSection(cp, "virt_el1_timer");
923  physNsEL2.serializeSection(cp, "phys_ns_el2_timer");
924  virtNsEL2.serializeSection(cp, "virt_ns_el2_timer");
925  physSEL2.serializeSection(cp, "phys_s_el2_timer");
926  virtSEL2.serializeSection(cp, "virt_s_el2_timer");
927 }
928 
929 void
931 {
932  UNSERIALIZE_SCALAR(cntfrq);
933  UNSERIALIZE_SCALAR(cntkctl);
934  UNSERIALIZE_SCALAR(cnthctl);
935 
936  bool phys_ev_scheduled;
937  UNSERIALIZE_SCALAR(phys_ev_scheduled);
938  if (phys_ev_scheduled) {
939  Tick phys_ev_when;
940  UNSERIALIZE_SCALAR(phys_ev_when);
941  parent.reschedule(physEvStream.event, phys_ev_when, true);
942  }
943  UNSERIALIZE_SCALAR(physEvStream.transitionTo);
944  UNSERIALIZE_SCALAR(physEvStream.transitionBit);
945 
946  bool virt_ev_scheduled;
947  UNSERIALIZE_SCALAR(virt_ev_scheduled);
948  if (virt_ev_scheduled) {
949  Tick virt_ev_when;
950  UNSERIALIZE_SCALAR(virt_ev_when);
951  parent.reschedule(virtEvStream.event, virt_ev_when, true);
952  }
953  UNSERIALIZE_SCALAR(virtEvStream.transitionTo);
954  UNSERIALIZE_SCALAR(virtEvStream.transitionBit);
955 
956  physEL3.unserializeSection(cp, "phys_el3_timer");
957  physEL1.unserializeSection(cp, "phys_el1_timer");
958  virtEL1.unserializeSection(cp, "virt_el1_timer");
959  physNsEL2.unserializeSection(cp, "phys_ns_el2_timer");
960  virtNsEL2.unserializeSection(cp, "virt_ns_el2_timer");
961  physSEL2.unserializeSection(cp, "phys_s_el2_timer");
962  virtSEL2.unserializeSection(cp, "virt_s_el2_timer");
963 }
964 
965 void
967 {
968  DPRINTF(Timer, "Setting %s := 0x%x\n", miscRegName[reg], val);
969  parent.setMiscReg(reg, cpu, val);
970 }
971 
972 RegVal
974 {
975  RegVal value = parent.readMiscReg(reg, cpu);
976  DPRINTF(Timer, "Reading %s as 0x%x\n", miscRegName[reg], value);
977  return value;
978 }
979 
980 GenericTimerFrame::GenericTimerFrame(const GenericTimerFrameParams &p)
981  : PioDevice(p),
982  timerRange(RangeSize(p.cnt_base, ArmSystem::PageBytes)),
983  addrRanges({timerRange}),
984  systemCounter(*p.counter),
985  physTimer(csprintf("%s.phys_timer", name()),
986  *this, systemCounter, p.int_phys->get()),
987  virtTimer(csprintf("%s.virt_timer", name()),
988  *this, systemCounter,
989  p.int_virt->get()),
990  accessBits(0x3f),
991  system(*dynamic_cast<ArmSystem *>(sys))
992 {
994  // Expose optional CNTEL0Base register frame
995  if (p.cnt_el0_base != MaxAddr) {
996  timerEl0Range = RangeSize(p.cnt_el0_base, ArmSystem::PageBytes);
997  accessBitsEl0 = 0x303;
998  addrRanges.push_back(timerEl0Range);
999  }
1000  for (auto &range : addrRanges)
1002 }
1003 
1004 void
1006 {
1007  SERIALIZE_SCALAR(accessBits);
1008  if (hasEl0View())
1009  SERIALIZE_SCALAR(accessBitsEl0);
1011 
1012  physTimer.serializeSection(cp, "phys_timer");
1013  virtTimer.serializeSection(cp, "virt_timer");
1014 }
1015 
1016 void
1018 {
1019  UNSERIALIZE_SCALAR(accessBits);
1020  if (hasEl0View())
1021  UNSERIALIZE_SCALAR(accessBitsEl0);
1023 
1024  physTimer.unserializeSection(cp, "phys_timer");
1025  virtTimer.unserializeSection(cp, "virt_timer");
1026 }
1027 
1028 uint64_t
1030 {
1031  return virtTimer.offset();
1032 }
1033 
1034 void
1036 {
1037  virtTimer.setOffset(new_offset);
1038 }
1039 
1040 bool
1042 {
1043  return timerEl0Range.valid();
1044 }
1045 
1046 uint8_t
1048 {
1049  return accessBits;
1050 }
1051 
1052 void
1054 {
1055  accessBits = data & 0x3f;
1056 }
1057 
1058 bool
1060 {
1061  return nonSecureAccess;
1062 }
1063 
1064 void
1066 {
1067  nonSecureAccess = true;
1068 }
1069 
1070 bool
1072 {
1073  return accessBits.rvoff;
1074 }
1075 
1078 {
1079  return addrRanges;
1080 }
1081 
1082 Tick
1084 {
1085  const Addr addr = pkt->getAddr();
1086  const size_t size = pkt->getSize();
1087  const bool is_sec = pkt->isSecure();
1088  panic_if(size != 4 && size != 8,
1089  "GenericTimerFrame::read: Invalid size %i\n", size);
1090 
1091  bool to_el0 = false;
1092  uint64_t resp = 0;
1093  Addr offset = 0;
1094  if (timerRange.contains(addr)) {
1095  offset = addr - timerRange.start();
1096  } else if (hasEl0View() && timerEl0Range.contains(addr)) {
1098  to_el0 = true;
1099  } else {
1100  panic("GenericTimerFrame::read: Invalid address: 0x%x\n", addr);
1101  }
1102 
1103  resp = timerRead(offset, size, is_sec, to_el0);
1104 
1105  DPRINTF(Timer, "GenericTimerFrame::read: 0x%x<-0x%x(%i) [S = %u]\n", resp,
1106  addr, size, is_sec);
1107 
1108  pkt->setUintX(resp, ByteOrder::little);
1109  pkt->makeResponse();
1110  return 0;
1111 }
1112 
1113 Tick
1115 {
1116  const Addr addr = pkt->getAddr();
1117  const size_t size = pkt->getSize();
1118  const bool is_sec = pkt->isSecure();
1119  panic_if(size != 4 && size != 8,
1120  "GenericTimerFrame::write: Invalid size %i\n", size);
1121 
1122  bool to_el0 = false;
1123  const uint64_t data = pkt->getUintX(ByteOrder::little);
1124  Addr offset = 0;
1125  if (timerRange.contains(addr)) {
1126  offset = addr - timerRange.start();
1127  } else if (hasEl0View() && timerEl0Range.contains(addr)) {
1129  to_el0 = true;
1130  } else {
1131  panic("GenericTimerFrame::write: Invalid address: 0x%x\n", addr);
1132  }
1133 
1134  timerWrite(offset, size, data, is_sec, to_el0);
1135 
1136  DPRINTF(Timer, "GenericTimerFrame::write: 0x%x->0x%x(%i) [S = %u]\n", data,
1137  addr, size, is_sec);
1138 
1139  pkt->makeResponse();
1140  return 0;
1141 }
1142 
1143 uint64_t
1144 GenericTimerFrame::timerRead(Addr addr, size_t size, bool is_sec,
1145  bool to_el0) const
1146 {
1148  !nonSecureAccess)
1149  return 0;
1150 
1151  switch (addr) {
1152  case TIMER_CNTPCT_LO:
1153  if (!accessBits.rpct || (to_el0 && !accessBitsEl0.pcten))
1154  return 0;
1155  else
1156  return physTimer.value();
1157 
1158  case TIMER_CNTPCT_HI:
1159  if (!accessBits.rpct || (to_el0 && !accessBitsEl0.pcten))
1160  return 0;
1161  else
1162  return physTimer.value() >> 32;
1163 
1164  case TIMER_CNTFRQ:
1165  if ((!accessBits.rfrq) ||
1166  (to_el0 && (!accessBitsEl0.pcten && !accessBitsEl0.vcten)))
1167  return 0;
1168  else
1169  return systemCounter.freq();
1170 
1171  case TIMER_CNTEL0ACR:
1172  if (!hasEl0View() || to_el0)
1173  return 0;
1174  else
1175  return accessBitsEl0;
1176 
1177  case TIMER_CNTP_CVAL_LO:
1178  if (!accessBits.rwpt || (to_el0 && !accessBitsEl0.pten))
1179  return 0;
1180  else
1181  return physTimer.compareValue();
1182 
1183  case TIMER_CNTP_CVAL_HI:
1184  if (!accessBits.rwpt || (to_el0 && !accessBitsEl0.pten))
1185  return 0;
1186  else
1187  return physTimer.compareValue() >> 32;
1188 
1189  case TIMER_CNTP_TVAL:
1190  if (!accessBits.rwpt || (to_el0 && !accessBitsEl0.pten))
1191  return 0;
1192  else
1193  return physTimer.timerValue();
1194  case TIMER_CNTP_CTL:
1195  if (!accessBits.rwpt || (to_el0 && !accessBitsEl0.pten))
1196  return 0;
1197  else
1198  return physTimer.control();
1199 
1200  case TIMER_CNTVCT_LO:
1201  if (!accessBits.rvct || (to_el0 && !accessBitsEl0.vcten))
1202  return 0;
1203  else
1204  return virtTimer.value();
1205 
1206  case TIMER_CNTVCT_HI:
1207  if (!accessBits.rvct || (to_el0 && !accessBitsEl0.vcten))
1208  return 0;
1209  else
1210  return virtTimer.value() >> 32;
1211 
1212  case TIMER_CNTVOFF_LO:
1213  if (!accessBits.rvoff || (to_el0))
1214  return 0;
1215  else
1216  return virtTimer.offset();
1217 
1218  case TIMER_CNTVOFF_HI:
1219  if (!accessBits.rvoff || (to_el0))
1220  return 0;
1221  else
1222  return virtTimer.offset() >> 32;
1223 
1224  case TIMER_CNTV_CVAL_LO:
1225  if (!accessBits.rwvt || (to_el0 && !accessBitsEl0.vten))
1226  return 0;
1227  else
1228  return virtTimer.compareValue();
1229 
1230  case TIMER_CNTV_CVAL_HI:
1231  if (!accessBits.rwvt || (to_el0 && !accessBitsEl0.vten))
1232  return 0;
1233  else
1234  return virtTimer.compareValue() >> 32;
1235 
1236  case TIMER_CNTV_TVAL:
1237  if (!accessBits.rwvt || (to_el0 && !accessBitsEl0.vten))
1238  return 0;
1239  else
1240  return virtTimer.timerValue();
1241 
1242  case TIMER_CNTV_CTL:
1243  if (!accessBits.rwvt || (to_el0 && !accessBitsEl0.vten))
1244  return 0;
1245  else
1246  return virtTimer.control();
1247 
1248  default:
1249  warn("GenericTimerFrame::timerRead: Unexpected address (0x%x:%i), "
1250  "assuming RAZ\n", addr, size);
1251  return 0;
1252  }
1253 }
1254 
1255 void
1257  bool is_sec, bool to_el0)
1258 {
1260  !nonSecureAccess)
1261  return;
1262 
1263  switch (addr) {
1265  warn("GenericTimerFrame::timerWrite: RO reg (0x%x) [CNTPCT]\n",
1266  addr);
1267  return;
1268 
1269  case TIMER_CNTFRQ:
1270  warn("GenericTimerFrame::timerWrite: RO reg (0x%x) [CNTFRQ]\n",
1271  addr);
1272  return;
1273 
1274  case TIMER_CNTEL0ACR:
1275  if (!hasEl0View() || to_el0)
1276  return;
1277 
1278  insertBits(accessBitsEl0, 9, 8, data);
1279  insertBits(accessBitsEl0, 1, 0, data);
1280  return;
1281 
1282  case TIMER_CNTP_CVAL_LO:
1283  if ((!accessBits.rwpt) || (to_el0 && !accessBitsEl0.pten))
1284  return;
1285  data = size == 4 ? insertBits(physTimer.compareValue(),
1286  31, 0, data) : data;
1288  return;
1289 
1290  case TIMER_CNTP_CVAL_HI:
1291  if ((!accessBits.rwpt) || (to_el0 && !accessBitsEl0.pten))
1292  return;
1293  data = insertBits(physTimer.compareValue(), 63, 32, data);
1295  return;
1296 
1297  case TIMER_CNTP_TVAL:
1298  if ((!accessBits.rwpt) || (to_el0 && !accessBitsEl0.pten))
1299  return;
1301  return;
1302 
1303  case TIMER_CNTP_CTL:
1304  if ((!accessBits.rwpt) || (to_el0 && !accessBitsEl0.pten))
1305  return;
1307  return;
1308 
1310  warn("GenericTimerFrame::timerWrite: RO reg (0x%x) [CNTVCT]\n",
1311  addr);
1312  return;
1314  warn("GenericTimerFrame::timerWrite: RO reg (0x%x) [CNTVOFF]\n",
1315  addr);
1316  return;
1317 
1318  case TIMER_CNTV_CVAL_LO:
1319  if ((!accessBits.rwvt) || (to_el0 && !accessBitsEl0.vten))
1320  return;
1321  data = size == 4 ? insertBits(virtTimer.compareValue(),
1322  31, 0, data) : data;
1324  return;
1325 
1326  case TIMER_CNTV_CVAL_HI:
1327  if ((!accessBits.rwvt) || (to_el0 && !accessBitsEl0.vten))
1328  return;
1329  data = insertBits(virtTimer.compareValue(), 63, 32, data);
1331  return;
1332 
1333  case TIMER_CNTV_TVAL:
1334  if ((!accessBits.rwvt) || (to_el0 && !accessBitsEl0.vten))
1335  return;
1337  return;
1338 
1339  case TIMER_CNTV_CTL:
1340  if ((!accessBits.rwvt) || (to_el0 && !accessBitsEl0.vten))
1341  return;
1343  return;
1344 
1345  default:
1346  warn("GenericTimerFrame::timerWrite: Unexpected address (0x%x:%i), "
1347  "assuming WI\n", addr, size);
1348  }
1349 }
1350 
1351 GenericTimerMem::GenericTimerMem(const GenericTimerMemParams &p)
1352  : PioDevice(p),
1353  counterCtrlRange(RangeSize(p.cnt_control_base, ArmSystem::PageBytes)),
1354  counterStatusRange(RangeSize(p.cnt_read_base, ArmSystem::PageBytes)),
1355  timerCtrlRange(RangeSize(p.cnt_ctl_base, ArmSystem::PageBytes)),
1356  cnttidr(0x0),
1357  addrRanges{counterCtrlRange, counterStatusRange, timerCtrlRange},
1358  systemCounter(*p.counter),
1359  frames(p.frames),
1360  system(*dynamic_cast<ArmSystem *>(sys))
1361 {
1363  for (auto &range : addrRanges)
1365  fatal_if(frames.size() > MAX_TIMER_FRAMES,
1366  "GenericTimerMem::GenericTimerMem: Architecture states a maximum of "
1367  "8 memory-mapped timer frames, limit surpassed\n");
1368  // Initialize CNTTIDR with each frame's features
1369  for (int i = 0; i < frames.size(); i++) {
1370  uint32_t features = 0x1;
1371  features |= 0x2;
1372  if (frames[i]->hasEl0View())
1373  features |= 0x4;
1374  features <<= i * 4;
1375  replaceBits(cnttidr, (i + 1) * 4 - 1, i * 4, features);
1376  }
1377 }
1378 
1379 void
1381 {
1383  "GenericTimerMem::validateFrameRange: Architecture states each "
1384  "register frame should be in a separate memory page, specified "
1385  "range base address [0x%x] is not compliant\n");
1386 }
1387 
1388 bool
1390 {
1391  return !sys.has(ArmExtension::SECURITY) || is_sec;
1392 }
1393 
1396 {
1397  return addrRanges;
1398 }
1399 
1400 Tick
1402 {
1403  const Addr addr = pkt->getAddr();
1404  const size_t size = pkt->getSize();
1405  const bool is_sec = pkt->isSecure();
1406  panic_if(size != 4 && size != 8,
1407  "GenericTimerMem::read: Invalid size %i\n", size);
1408 
1409  uint64_t resp = 0;
1411  resp = counterCtrlRead(addr - counterCtrlRange.start(), size, is_sec);
1412  else if (counterStatusRange.contains(addr))
1413  resp = counterStatusRead(addr - counterStatusRange.start(), size);
1414  else if (timerCtrlRange.contains(addr))
1415  resp = timerCtrlRead(addr - timerCtrlRange.start(), size, is_sec);
1416  else
1417  panic("GenericTimerMem::read: Invalid address: 0x%x\n", addr);
1418 
1419  DPRINTF(Timer, "GenericTimerMem::read: 0x%x<-0x%x(%i) [S = %u]\n", resp,
1420  addr, size, is_sec);
1421 
1422  pkt->setUintX(resp, ByteOrder::little);
1423  pkt->makeResponse();
1424  return 0;
1425 }
1426 
1427 Tick
1429 {
1430  const Addr addr = pkt->getAddr();
1431  const size_t size = pkt->getSize();
1432  const bool is_sec = pkt->isSecure();
1433  panic_if(size != 4 && size != 8,
1434  "GenericTimerMem::write: Invalid size %i\n", size);
1435 
1436  const uint64_t data = pkt->getUintX(ByteOrder::little);
1438  counterCtrlWrite(addr - counterCtrlRange.start(), size, data, is_sec);
1439  else if (counterStatusRange.contains(addr))
1441  else if (timerCtrlRange.contains(addr))
1442  timerCtrlWrite(addr - timerCtrlRange.start(), size, data, is_sec);
1443  else
1444  panic("GenericTimerMem::write: Invalid address: 0x%x\n", addr);
1445 
1446  DPRINTF(Timer, "GenericTimerMem::write: 0x%x->0x%x(%i) [S = %u]\n", data,
1447  addr, size, is_sec);
1448 
1449  pkt->makeResponse();
1450  return 0;
1451 }
1452 
1453 uint64_t
1454 GenericTimerMem::counterCtrlRead(Addr addr, size_t size, bool is_sec) const
1455 {
1457  return 0;
1458  switch (addr) {
1459  case COUNTER_CTRL_CNTCR:
1460  {
1461  CNTCR cntcr = 0;
1462  cntcr.en = systemCounter.enabled();
1463  cntcr.fcreq = systemCounter.activeFreqEntry();
1464  return cntcr;
1465  }
1466  case COUNTER_CTRL_CNTSR:
1467  {
1468  CNTSR cntsr = 0;
1469  cntsr.fcack = systemCounter.activeFreqEntry();
1470  return cntsr;
1471  }
1472  case COUNTER_CTRL_CNTCV_LO: return systemCounter.value();
1473  case COUNTER_CTRL_CNTCV_HI: return systemCounter.value() >> 32;
1474  case COUNTER_CTRL_CNTSCR: return 0;
1475  case COUNTER_CTRL_CNTID: return 0;
1476  default:
1477  {
1478  auto &freq_table = systemCounter.freqTable();
1479  for (int i = 0; i < (freq_table.size() - 1); i++) {
1480  Addr offset = COUNTER_CTRL_CNTFID + (i * 0x4);
1481  if (addr == offset)
1482  return freq_table[i];
1483  }
1484  warn("GenericTimerMem::counterCtrlRead: Unexpected address "
1485  "(0x%x:%i), assuming RAZ\n", addr, size);
1486  return 0;
1487  }
1488  }
1489 }
1490 
1491 void
1493  bool is_sec)
1494 {
1496  return;
1497 
1498  switch (addr) {
1499  case COUNTER_CTRL_CNTCR:
1500  {
1501  CNTCR val = data;
1502  if (!systemCounter.enabled() && val.en)
1504  else if (systemCounter.enabled() && !val.en)
1506 
1507  if (val.hdbg)
1508  warn("GenericTimerMem::counterCtrlWrite: Halt-on-debug is not "
1509  "supported\n");
1510  if (val.scen)
1511  warn("GenericTimerMem::counterCtrlWrite: Counter Scaling is not "
1512  "supported\n");
1513  if (val.fcreq != systemCounter.activeFreqEntry())
1515  return;
1516  }
1517 
1518  case COUNTER_CTRL_CNTSR:
1519  warn("GenericTimerMem::counterCtrlWrite: RO reg (0x%x) [CNTSR]\n",
1520  addr);
1521  return;
1522 
1523  case COUNTER_CTRL_CNTCV_LO:
1524  data = size == 4 ? insertBits(systemCounter.value(), 31, 0, data)
1525  : data;
1527  return;
1528 
1529  case COUNTER_CTRL_CNTCV_HI:
1530  data = insertBits(systemCounter.value(), 63, 32, data);
1532  return;
1533 
1534  case COUNTER_CTRL_CNTSCR:
1535  return;
1536 
1537  case COUNTER_CTRL_CNTID:
1538  warn("GenericTimerMem::counterCtrlWrite: RO reg (0x%x) [CNTID]\n",
1539  addr);
1540  return;
1541 
1542  default:
1543  {
1544  auto &freq_table = systemCounter.freqTable();
1545  for (int i = 0; i < (freq_table.size() - 1); i++) {
1546  Addr offset = COUNTER_CTRL_CNTFID + (i * 0x4);
1547  if (addr == offset) {
1548  freq_table[i] = data;
1549  // This is changing the currently selected frequency
1550  if (i == systemCounter.activeFreqEntry()) {
1551  // We've changed the frequency in the table entry,
1552  // however the counter will still work with the
1553  // current one until transition is completed
1555  }
1556  return;
1557  }
1558  }
1559  warn("GenericTimerMem::counterCtrlWrite: Unexpected address "
1560  "(0x%x:%i), assuming WI\n", addr, size);
1561  }
1562  }
1563 }
1564 
1565 uint64_t
1567 {
1568  switch (addr) {
1570  case COUNTER_STATUS_CNTCV_HI: return systemCounter.value() >> 32;
1571  default:
1572  warn("GenericTimerMem::counterStatusRead: Unexpected address "
1573  "(0x%x:%i), assuming RAZ\n", addr, size);
1574  return 0;
1575  }
1576 }
1577 
1578 void
1580 {
1581  switch (addr) {
1583  warn("GenericTimerMem::counterStatusWrite: RO reg (0x%x) [CNTCV]\n",
1584  addr);
1585  return;
1586  default:
1587  warn("GenericTimerMem::counterStatusWrite: Unexpected address "
1588  "(0x%x:%i), assuming WI\n", addr, size);
1589  }
1590 }
1591 
1592 uint64_t
1593 GenericTimerMem::timerCtrlRead(Addr addr, size_t size, bool is_sec) const
1594 {
1595  switch (addr) {
1596  case TIMER_CTRL_CNTFRQ:
1597  if (!GenericTimerMem::validateAccessPerm(system, is_sec)) return 0;
1598  return systemCounter.freq();
1599  case TIMER_CTRL_CNTNSAR:
1600  {
1601  if (!GenericTimerMem::validateAccessPerm(system, is_sec)) return 0;
1602  uint32_t cntnsar = 0x0;
1603  for (int i = 0; i < frames.size(); i++) {
1604  if (frames[i]->hasNonSecureAccess())
1605  cntnsar |= 0x1 << i;
1606  }
1607  return cntnsar;
1608  }
1609  case TIMER_CTRL_CNTTIDR: return cnttidr;
1610  default:
1611  for (int i = 0; i < frames.size(); i++) {
1612  Addr cntacr_off = TIMER_CTRL_CNTACR + (i * 0x4);
1613  Addr cntvoff_lo_off = TIMER_CTRL_CNTVOFF_LO + (i * 0x4);
1614  Addr cntvoff_hi_off = TIMER_CTRL_CNTVOFF_HI + (i * 0x4);
1615  // CNTNSAR.NS determines if CNTACR/CNTVOFF are accessible from
1616  // normal world
1617  bool hit = addr == cntacr_off || addr == cntvoff_lo_off ||
1618  addr == cntvoff_hi_off;
1619  bool has_access =
1621  frames[i]->hasNonSecureAccess();
1622  if (hit && !has_access) return 0;
1623  if (addr == cntacr_off)
1624  return frames[i]->getAccessBits();
1625  if (addr == cntvoff_lo_off || addr == cntvoff_hi_off) {
1626  return addr == cntvoff_lo_off ? frames[i]->getVirtOffset()
1627  : frames[i]->getVirtOffset() >> 32;
1628  }
1629  }
1630  warn("GenericTimerMem::timerCtrlRead: Unexpected address (0x%x:%i), "
1631  "assuming RAZ\n", addr, size);
1632  return 0;
1633  }
1634 }
1635 
1636 void
1638  bool is_sec)
1639 {
1640  switch (addr) {
1641  case TIMER_CTRL_CNTFRQ:
1642  if (!GenericTimerMem::validateAccessPerm(system, is_sec)) return;
1644  "GenericTimerMem::timerCtrlWrite: CNTFRQ configured freq "
1645  "does not match the counter freq, ignoring\n");
1646  return;
1647  case TIMER_CTRL_CNTNSAR:
1648  if (!GenericTimerMem::validateAccessPerm(system, is_sec)) return;
1649  for (int i = 0; i < frames.size(); i++) {
1650  // Check if the CNTNSAR.NS bit is set for this frame
1651  if (data & (0x1 << i))
1652  frames[i]->setNonSecureAccess();
1653  }
1654  return;
1655  case TIMER_CTRL_CNTTIDR:
1656  warn("GenericTimerMem::timerCtrlWrite: RO reg (0x%x) [CNTTIDR]\n",
1657  addr);
1658  return;
1659  default:
1660  for (int i = 0; i < frames.size(); i++) {
1661  Addr cntacr_off = TIMER_CTRL_CNTACR + (i * 0x4);
1662  Addr cntvoff_lo_off = TIMER_CTRL_CNTVOFF_LO + (i * 0x4);
1663  Addr cntvoff_hi_off = TIMER_CTRL_CNTVOFF_HI + (i * 0x4);
1664  // CNTNSAR.NS determines if CNTACR/CNTVOFF are accessible from
1665  // normal world
1666  bool hit = addr == cntacr_off || addr == cntvoff_lo_off ||
1667  addr == cntvoff_hi_off;
1668  bool has_access =
1670  frames[i]->hasNonSecureAccess();
1671  if (hit && !has_access) return;
1672  if (addr == cntacr_off) {
1673  frames[i]->setAccessBits(data);
1674  return;
1675  }
1676  if (addr == cntvoff_lo_off || addr == cntvoff_hi_off) {
1677  if (addr == cntvoff_lo_off)
1678  data = size == 4 ? insertBits(frames[i]->getVirtOffset(),
1679  31, 0, data) : data;
1680  else
1681  data = insertBits(frames[i]->getVirtOffset(),
1682  63, 32, data);
1683  frames[i]->setVirtOffset(data);
1684  return;
1685  }
1686  }
1687  warn("GenericTimerMem::timerCtrlWrite: Unexpected address "
1688  "(0x%x:%i), assuming WI\n", addr, size);
1689  }
1690 }
1691 
1692 } // namespace gem5
#define DPRINTF(x,...)
Definition: trace.hh:186
Base class for ARM GIC implementations.
const char data[]
The AddrRange class encapsulates an address range, and supports a number of tests to check if two ran...
Definition: addr_range.hh:82
bool scheduleEvents() override
Per-CPU architected timer.
EventFunctionWrapper _counterLimitReachedEvent
void setTimerValue(uint32_t val)
Sets the TimerValue view of the timer.
uint32_t timerValue() const
Returns the TimerValue view of the timer.
virtual bool scheduleEvents()
DrainState drain() override
Draining is the process of clearing out the states of SimObjects.These are the SimObjects that are pa...
EndBitUnion(ArchTimerCtrl) const std SimObject & _parent
Name of this timer.
void drainResume() override
Resume execution after a successful drain.
uint64_t compareValue() const
Returns the CompareValue view of the timer.
uint64_t _offset
Offset relative to the physical timer (CNTVOFF)
void notify(void) override
Called from the SystemCounter when a change in counting speed occurred Events should be rescheduled p...
void setCompareValue(uint64_t val)
Sets the CompareValue view of the timer.
ArchTimer(const std::string &name, SimObject &parent, SystemCounter &sysctr, ArmInterruptPin *interrupt)
ArchTimerCtrl _control
Value of the control register ({CNTP/CNTHP/CNTV}_CTL).
void setOffset(uint64_t val)
void serialize(CheckpointOut &cp) const override
Serialize an object.
void unserialize(CheckpointIn &cp) override
Unserialize an object.
uint64_t value() const
Returns the value of the counter which this timer relies on.
void setControl(uint32_t val)
uint32_t control() const
Sets the control register.
void updateCounter()
Timer settings or the offset has changed, re-evaluate trigger condition and raise interrupt if necess...
SystemCounter & _systemCounter
void counterLimitReached()
Called when the upcounter reaches the programmed value.
uint64_t offset() const
ArmInterruptPin *const _interrupt
uint64_t _counterLimit
Programmed limit value for the upcounter ({CNTP/CNTHP/CNTV}_CVAL).
Tick whenValue(uint64_t target_val)
Generic representation of an Arm interrupt pin.
Definition: base_gic.hh:200
virtual void clear()=0
Clear a signalled interrupt.
virtual void raise()=0
Signal an interrupt.
bool active() const
True if interrupt pin is active, false otherwise.
Definition: base_gic.hh:219
void setGenericTimer(GenericTimer *generic_timer)
Sets the pointer to the Generic Timer.
Definition: system.hh:159
static constexpr Addr PageBytes
Definition: system.hh:143
GenericTimerFrame(const GenericTimerFrameParams &p)
static const Addr TIMER_CNTP_CTL
void serialize(CheckpointOut &cp) const override
Serialize an object.
static const Addr TIMER_CNTV_TVAL
bool nonSecureAccess
Reports whether non-secure accesses are allowed to this frame.
uint64_t timerRead(Addr addr, size_t size, bool is_sec, bool to_el0) const
CNTBase/CNTEL0Base (Memory-mapped timer frame)
bool hasEl0View() const
Indicates if this frame implements a second EL0 view.
static const Addr TIMER_CNTP_CVAL_HI
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Tick read(PacketPtr pkt) override
Pure virtual function that the device must implement.
static const Addr TIMER_CNTV_CVAL_LO
static const Addr TIMER_CNTVCT_LO
uint8_t getAccessBits() const
Returns the access bits for this frame.
static const Addr TIMER_CNTFRQ
SystemCounter & systemCounter
System counter reference.
bool hasNonSecureAccess() const
Indicates if non-secure accesses are allowed to this frame.
ArchTimer physTimer
Physical and virtual timers.
static const Addr TIMER_CNTP_CVAL_LO
void setAccessBits(uint8_t data)
Updates the access bits after a write to CNTCTLBase.CNTACR.
static const Addr TIMER_CNTV_CVAL_HI
void setVirtOffset(uint64_t new_offset)
Sets the virtual offset for this frame's virtual timer after a write to CNTVOFF.
const AddrRange timerRange
AddrRangeList getAddrRanges() const override
Every PIO device is obliged to provide an implementation that returns the address ranges the device r...
static const Addr TIMER_CNTP_TVAL
static const Addr TIMER_CNTVOFF_HI
static const Addr TIMER_CNTVCT_HI
AddrRangeList addrRanges
All MMIO ranges GenericTimerFrame responds to.
bool hasReadableVoff() const
Indicates if CNTVOFF is readable for this frame.
static const Addr TIMER_CNTPCT_LO
static const Addr TIMER_CNTVOFF_LO
static const Addr TIMER_CNTPCT_HI
uint64_t getVirtOffset() const
Returns the virtual offset for this frame if a virtual timer is implemented.
static const Addr TIMER_CNTEL0ACR
void setNonSecureAccess()
Allows non-secure accesses after an enabling write to CNTCTLBase.CNTNSAR.
static const Addr TIMER_CNTV_CTL
void timerWrite(Addr addr, size_t size, uint64_t data, bool is_sec, bool to_el0)
Tick write(PacketPtr pkt) override
Pure virtual function that the device must implement.
RegVal readMiscReg(int misc_reg) override
Read a system register belonging to this device.
void setMiscReg(int misc_reg, RegVal val) override
Write to a system register belonging to this device.
void counterCtrlWrite(Addr addr, size_t size, uint64_t data, bool is_sec)
static const Addr COUNTER_CTRL_CNTID
uint64_t counterCtrlRead(Addr addr, size_t size, bool is_sec) const
CNTControlBase (System counter control frame)
const AddrRange timerCtrlRange
static const Addr TIMER_CTRL_CNTTIDR
static const Addr COUNTER_CTRL_CNTCV_HI
static const Addr COUNTER_CTRL_CNTFID
GenericTimerMem(const GenericTimerMemParams &p)
static const Addr COUNTER_CTRL_CNTCV_LO
void counterStatusWrite(Addr addr, size_t size, uint64_t data)
std::vector< GenericTimerFrame * > frames
Timer frame references.
static const Addr TIMER_CTRL_CNTFRQ
static const Addr COUNTER_STATUS_CNTCV_HI
static const Addr COUNTER_CTRL_CNTSCR
const AddrRange counterStatusRange
static const Addr TIMER_CTRL_CNTACR
uint64_t timerCtrlRead(Addr addr, size_t size, bool is_sec) const
CNTCTLBase (Memory-mapped timer global control frame)
const AddrRange counterCtrlRange
Tick read(PacketPtr pkt) override
Pure virtual function that the device must implement.
static const Addr TIMER_CTRL_CNTVOFF_LO
static void validateFrameRange(const AddrRange &range)
Validates a Generic Timer register frame address range.
uint64_t counterStatusRead(Addr addr, size_t size) const
CNTReadBase (System counter status frame)
static const Addr COUNTER_STATUS_CNTCV_LO
AddrRangeList getAddrRanges() const override
Every PIO device is obliged to provide an implementation that returns the address ranges the device r...
void timerCtrlWrite(Addr addr, size_t size, uint64_t data, bool is_sec)
Tick write(PacketPtr pkt) override
Pure virtual function that the device must implement.
uint32_t cnttidr
ID register for reporting features of implemented timer frames.
static const Addr COUNTER_CTRL_CNTSR
SystemCounter & systemCounter
System counter reference.
const AddrRangeList addrRanges
All MMIO ranges GenericTimerMem responds to.
static constexpr size_t MAX_TIMER_FRAMES
Maximum architectural number of memory-mapped timer frames.
static const Addr TIMER_CTRL_CNTNSAR
static bool validateAccessPerm(ArmSystem &sys, bool is_sec)
Validates an MMIO access permissions.
static const Addr TIMER_CTRL_CNTVOFF_HI
void notify(void) override
Called from the SystemCounter when a change in counting speed occurred Events should be rescheduled p...
void serialize(CheckpointOut &cp) const override
Serialize an object.
void schedNextEvent(EventStream &ev_stream, ArchTimer &timer)
uint32_t cntfrq
System counter frequency as visible from this core.
void unserialize(CheckpointIn &cp) override
Unserialize an object.
CoreTimers(GenericTimer &_parent, ArmSystem &system, unsigned cpu, ArmInterruptPin *irq_el3_phys, ArmInterruptPin *irq_el1_phys, ArmInterruptPin *irq_el1_virt, ArmInterruptPin *irq_el2_ns_phys, ArmInterruptPin *irq_el2_ns_virt, ArmInterruptPin *irq_el2_s_phys, ArmInterruptPin *irq_el2_s_virt)
ArmISA::CNTHCTL cnthctl
Hypervisor control register.
ArmISA::CNTKCTL cntkctl
Kernel control register.
std::vector< std::unique_ptr< CoreTimers > > timers
Per-CPU physical architected timers.
void serialize(CheckpointOut &cp) const override
Serialize an object.
void setMiscReg(int misc_reg, unsigned cpu, RegVal val)
CoreTimers & getTimers(int cpu_id)
RegVal readMiscReg(int misc_reg, unsigned cpu)
void unserialize(CheckpointIn &cp) override
Unserialize an object.
void createTimers(unsigned cpus)
SystemCounter & systemCounter
System counter reference.
void handleStream(CoreTimers::EventStream *ev_stream, ArchTimer *timer, RegVal old_cnt_ctl, RegVal cnt_ctl)
ArmSystem & system
ARM system containing this timer.
GenericTimer(const Params &p)
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
Definition: packet.hh:294
bool isSecure() const
Definition: packet.hh:834
Addr getAddr() const
Definition: packet.hh:805
void setUintX(uint64_t w, ByteOrder endian)
Set the value in the word w after truncating it to the length of the packet and then byteswapping it ...
Definition: packet.cc:361
void makeResponse()
Take a request packet and modify it in place to be suitable for returning as a response to that reque...
Definition: packet.hh:1059
unsigned getSize() const
Definition: packet.hh:815
uint64_t getUintX(ByteOrder endian) const
Get the data in the packet byte swapped from the specified endianness and zero-extended to 64 bits.
Definition: packet.cc:352
This device is the base class which all devices senstive to an address range inherit from.
Definition: io_device.hh:103
System * sys
Definition: io_device.hh:105
Abstract superclass for simulation objects.
Definition: sim_object.hh:148
Abstract class for elements whose events depend on the counting speed of the System Counter.
Global system counter.
void updateValue(void)
Updates the counter value.
uint32_t _freq
Counter frequency (as specified by CNTFRQ).
std::vector< uint32_t > _freqTable
Frequency modes table with all possible frequencies for the counter.
bool enabled() const
Indicates if the counter is enabled.
std::vector< SystemCounterListener * > _listeners
Listeners to changes in counting speed.
void setValue(uint64_t new_value)
Sets the value explicitly from writes to CNTCR.CNTCV.
Tick _period
Cached copy of the counter period (inverse of the frequency).
std::vector< uint32_t > & freqTable()
Returns a reference to the frequency modes table.
Tick whenValue(uint64_t target_val)
Returns the tick at which a certain counter value is reached.
SystemCounter(const SystemCounterParams &p)
EventFunctionWrapper _freqUpdateEvent
Frequency update event handling.
size_t activeFreqEntry() const
Returns the currently active frequency table entry.
static constexpr size_t MAX_FREQ_ENTRIES
Maximum architectural number of frequency table entries.
static void validateCounterRef(SystemCounter *sys_cnt)
Validates a System Counter reference.
void updateTick(void)
Updates the update tick, normalizes to the lower cycle start tick.
uint64_t value()
Updates and returns the counter value.
void disable()
Disables the counter after a CNTCR.EN == 0.
void notifyListeners(void) const
Notifies counting speed changes to listeners.
void serialize(CheckpointOut &cp) const override
Serialize an object.
void enable()
Enables the counter after a CNTCR.EN == 1.
uint64_t _value
Counter value (as specified in CNTCV).
uint32_t freq() const
Returns the counter frequency.
void freqUpdateCallback()
Callback for the frequency update.
Tick _updateTick
Counter cycle start Tick when the counter status affecting its value has been updated.
uint64_t _increment
Value increment in each counter cycle.
size_t _activeFreqEntry
Currently selected entry in the table, its contents should match _freq.
void registerListener(SystemCounterListener *listener)
Called from System Counter Listeners to register.
void freqUpdateSchedule(size_t new_freq_entry)
Schedules a counter frequency update after a CNTCR.FCREQ == 1 This complies with frequency transition...
void unserialize(CheckpointIn &cp) override
Unserialize an object.
bool _enabled
Indicates if the counter is enabled.
int size() const
Definition: system.hh:213
KvmVM * getKvmVM() const
Get a pointer to the Kernel Virtual Machine (KVM) SimObject, if present.
Definition: system.hh:336
Threads threads
Definition: system.hh:313
ThreadContext is the external interface to all thread state for anything outside of the CPU.
This module implements the global system counter and the local per-CPU architected timers as specifie...
AddrRange RangeSize(Addr start, Addr size)
Definition: addr_range.hh:815
bool valid() const
Determine if the range is valid.
Definition: addr_range.hh:336
bool contains(const Addr &a) const
Determine if the range contains an address.
Definition: addr_range.hh:471
Addr start() const
Get the start address of the range.
Definition: addr_range.hh:343
constexpr T bits(T val, unsigned first, unsigned last)
Extract the bitfield from position 'first' to 'last' (inclusive) from 'val' and right justify it.
Definition: bitfield.hh:76
constexpr T insertBits(T val, unsigned first, unsigned last, B bit_val)
Returns val with bits first to last set to the LSBs of bit_val.
Definition: bitfield.hh:166
constexpr void replaceBits(T &val, unsigned first, unsigned last, B bit_val)
A convenience function to replace bits first to last of val with bit_val in place.
Definition: bitfield.hh:197
DrainState
Object drain/handover states.
Definition: drain.hh:75
@ Drained
Buffers drained, ready for serialization/handover.
void deschedule(Event &event)
Definition: eventq.hh:1028
bool scheduled() const
Determine if the current event is scheduled.
Definition: eventq.hh:465
void schedule(Event &event, Tick when)
Definition: eventq.hh:1019
void reschedule(Event &event, Tick when, bool always=false)
Definition: eventq.hh:1037
Tick when() const
Get the time that the event is scheduled.
Definition: eventq.hh:508
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:178
#define fatal_if(cond,...)
Conditional fatal macro that checks the supplied condition and only causes a fatal error if the condi...
Definition: logging.hh:226
#define fatal(...)
This implements a cprintf based fatal() function.
Definition: logging.hh:190
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
Definition: logging.hh:204
#define UNSERIALIZE_CONTAINER(member)
Definition: serialize.hh:634
#define UNSERIALIZE_OPT_SCALAR(scalar)
Definition: serialize.hh:582
void serializeSection(CheckpointOut &cp, const char *name) const
Serialize an object into a new section.
Definition: serialize.cc:74
#define SERIALIZE_CONTAINER(member)
Definition: serialize.hh:626
void unserializeSection(CheckpointIn &cp, const char *name)
Unserialize an a child object.
Definition: serialize.cc:81
const Params & params() const
Definition: sim_object.hh:176
#define warn(...)
Definition: logging.hh:246
#define warn_if(cond,...)
Conditional warning macro that checks the supplied condition and only prints a warning if the conditi...
Definition: logging.hh:273
Bitfield< 7 > i
Definition: misc_types.hh:67
void sendEvent(ThreadContext *tc)
Send an event (SEV) to a specific PE if there isn't already a pending event.
Definition: utility.cc:65
Bitfield< 23, 0 > offset
Definition: types.hh:144
Bitfield< 0 > vm
Definition: misc_types.hh:291
@ MISCREG_CNTV_CTL_EL0
Definition: misc.hh:764
@ MISCREG_CNTP_CTL_EL0
Definition: misc.hh:761
@ MISCREG_CNTFRQ
Definition: misc.hh:418
@ MISCREG_CNTV_TVAL
Definition: misc.hh:432
@ MISCREG_CNTPS_TVAL_EL1
Definition: misc.hh:777
@ MISCREG_CNTV_CVAL
Definition: misc.hh:431
@ MISCREG_CNTVCT
Definition: misc.hh:420
@ MISCREG_CNTPCT_EL0
Definition: misc.hh:759
@ MISCREG_CNTHV_CTL_EL2
Definition: misc.hh:786
@ MISCREG_CNTP_TVAL_NS
Definition: misc.hh:428
@ MISCREG_CNTV_CTL
Definition: misc.hh:430
@ MISCREG_CNTHP_TVAL
Definition: misc.hh:437
@ MISCREG_CNTVCT_EL0
Definition: misc.hh:760
@ MISCREG_CNTKCTL_EL1
Definition: misc.hh:773
@ MISCREG_CNTPCT
Definition: misc.hh:419
@ MISCREG_CNTPS_CTL_EL1
Definition: misc.hh:775
@ MISCREG_CNTHPS_CVAL_EL2
Definition: misc.hh:783
@ MISCREG_CNTP_CVAL_NS
Definition: misc.hh:425
@ MISCREG_CNTHPS_TVAL_EL2
Definition: misc.hh:784
@ MISCREG_CNTP_TVAL_S
Definition: misc.hh:429
@ MISCREG_CNTHCTL_EL2
Definition: misc.hh:778
@ MISCREG_CNTP_CTL_S
Definition: misc.hh:423
@ MISCREG_CNTHVS_TVAL_EL2
Definition: misc.hh:791
@ MISCREG_CNTP_CVAL_EL0
Definition: misc.hh:762
@ MISCREG_CNTHVS_CVAL_EL2
Definition: misc.hh:790
@ MISCREG_CNTVOFF_EL2
Definition: misc.hh:793
@ MISCREG_CNTHCTL
Definition: misc.hh:434
@ MISCREG_CNTHPS_CTL_EL2
Definition: misc.hh:782
@ MISCREG_CNTHV_TVAL_EL2
Definition: misc.hh:788
@ MISCREG_CNTPS_CVAL_EL1
Definition: misc.hh:776
@ MISCREG_CNTVOFF
Definition: misc.hh:438
@ MISCREG_CNTHP_CTL
Definition: misc.hh:435
@ MISCREG_CNTHP_CVAL_EL2
Definition: misc.hh:780
@ MISCREG_CNTV_TVAL_EL0
Definition: misc.hh:766
@ MISCREG_CNTP_CTL_NS
Definition: misc.hh:422
@ MISCREG_CNTP_TVAL_EL0
Definition: misc.hh:763
@ MISCREG_CNTHP_TVAL_EL2
Definition: misc.hh:781
@ MISCREG_CNTHP_CVAL
Definition: misc.hh:436
@ MISCREG_CNTHVS_CTL_EL2
Definition: misc.hh:789
@ MISCREG_CNTHP_CTL_EL2
Definition: misc.hh:779
@ MISCREG_CNTP_CVAL_S
Definition: misc.hh:426
@ MISCREG_CNTKCTL
Definition: misc.hh:433
@ MISCREG_CNTHV_CVAL_EL2
Definition: misc.hh:787
@ MISCREG_CNTFRQ_EL0
Definition: misc.hh:758
@ MISCREG_CNTV_CVAL_EL0
Definition: misc.hh:765
const char *const miscRegName[]
Definition: misc.hh:1697
const Addr PageBytes
Definition: page_size.hh:42
Bitfield< 54 > p
Definition: pagetable.hh:70
Bitfield< 5, 3 > reg
Definition: types.hh:92
Bitfield< 15 > system
Definition: misc.hh:1004
Bitfield< 63 > val
Definition: misc.hh:776
Bitfield< 3 > addr
Definition: types.hh:84
Tick Frequency
The simulated frequency of curTick(). (In ticks per second)
Definition: core.cc:48
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
Tick curTick()
The universal simulation clock.
Definition: cur_tick.hh:46
std::ostream CheckpointOut
Definition: serialize.hh:66
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:147
void paramOut(CheckpointOut &cp, const std::string &name, ExtMachInst const &machInst)
Definition: types.cc:40
void paramIn(CheckpointIn &cp, const std::string &name, ExtMachInst &machInst)
Definition: types.cc:72
uint64_t Tick
Tick count type.
Definition: types.hh:58
uint64_t RegVal
Definition: types.hh:173
std::string csprintf(const char *format, const Args &...args)
Definition: cprintf.hh:161
const Addr MaxAddr
Definition: types.hh:171
#define UNSERIALIZE_SCALAR(scalar)
Definition: serialize.hh:575
#define SERIALIZE_SCALAR(scalar)
Definition: serialize.hh:568
uint64_t eventTargetValue(uint64_t val) const
const std::string & name()
Definition: trace.cc:49

Generated on Wed Dec 21 2022 10:22:32 for gem5 by doxygen 1.9.1