gem5  v21.0.1.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
timer_cpulocal.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010-2013,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 
39 
40 #include <cassert>
41 
42 #include "arch/arm/system.hh"
43 #include "base/intmath.hh"
44 #include "base/logging.hh"
45 #include "base/trace.hh"
46 #include "debug/Checkpoint.hh"
47 #include "debug/Timer.hh"
48 #include "dev/arm/base_gic.hh"
49 #include "mem/packet.hh"
50 #include "mem/packet_access.hh"
51 
53  : BasicPioDevice(p, 0x38)
54 {
55 }
56 
57 void
59 {
60  const auto &p = params();
61  // Initialize the timer registers for each per cpu timer
62  for (int i = 0; i < sys->threads.size(); i++) {
63  ThreadContext* tc = sys->threads[i];
64  std::stringstream oss;
65  oss << name() << ".timer" << i;
66 
67  localTimer.emplace_back(
68  new Timer(oss.str(), this,
69  p.int_timer->get(tc),
70  p.int_watchdog->get(tc)));
71  }
72 
74 }
75 
76 CpuLocalTimer::Timer::Timer(const std::string &timer_name,
77  CpuLocalTimer* _parent,
78  ArmInterruptPin* int_timer,
79  ArmInterruptPin* int_watchdog)
80  : _name(timer_name), parent(_parent), intTimer(int_timer),
81  intWatchdog(int_watchdog), timerControl(0x0), watchdogControl(0x0),
82  rawIntTimer(false), rawIntWatchdog(false),
83  rawResetWatchdog(false), watchdogDisableReg(0x0),
84  pendingIntTimer(false), pendingIntWatchdog(false),
85  timerLoadValue(0x0), watchdogLoadValue(0x0),
86  timerZeroEvent([this]{ timerAtZero(); }, name()),
87  watchdogZeroEvent([this]{ watchdogAtZero(); }, name())
88 {
89 }
90 
91 Tick
93 {
94  assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
95  assert(pkt->getSize() == 4);
96  Addr daddr = pkt->getAddr() - pioAddr;
97  ContextID cpu_id = pkt->req->contextId();
98  DPRINTF(Timer, "Reading from CpuLocalTimer at offset: %#x\n", daddr);
99  assert(cpu_id >= 0);
100  assert(cpu_id < localTimer.size());
101 
102  if (daddr < Timer::Size)
103  localTimer[cpu_id]->read(pkt, daddr);
104  else
105  panic("Tried to read CpuLocalTimer at offset %#x that doesn't exist\n", daddr);
106  pkt->makeAtomicResponse();
107  return pioDelay;
108 }
109 
110 
111 void
113 {
114  DPRINTF(Timer, "Reading from CpuLocalTimer at offset: %#x\n", daddr);
115  Tick time;
116 
117  switch(daddr) {
118  case TimerLoadReg:
119  pkt->setLE<uint32_t>(timerLoadValue);
120  break;
121  case TimerCounterReg:
122  DPRINTF(Timer, "Event schedule for timer %d, clock=%d, prescale=%d\n",
123  timerZeroEvent.when(), parent->clockPeriod(),
124  timerControl.prescalar);
125  time = timerZeroEvent.when() - curTick();
126  time = time / parent->clockPeriod() /
127  power(16, timerControl.prescalar);
128  DPRINTF(Timer, "-- returning counter at %d\n", time);
129  pkt->setLE<uint32_t>(time);
130  break;
131  case TimerControlReg:
132  pkt->setLE<uint32_t>(timerControl);
133  break;
134  case TimerIntStatusReg:
135  pkt->setLE<uint32_t>(rawIntTimer);
136  break;
137  case WatchdogLoadReg:
138  pkt->setLE<uint32_t>(watchdogLoadValue);
139  break;
140  case WatchdogCounterReg:
141  DPRINTF(Timer,
142  "Event schedule for watchdog %d, clock=%d, prescale=%d\n",
143  watchdogZeroEvent.when(), parent->clockPeriod(),
144  watchdogControl.prescalar);
145  time = watchdogZeroEvent.when() - curTick();
146  time = time / parent->clockPeriod() /
147  power(16, watchdogControl.prescalar);
148  DPRINTF(Timer, "-- returning counter at %d\n", time);
149  pkt->setLE<uint32_t>(time);
150  break;
151  case WatchdogControlReg:
152  pkt->setLE<uint32_t>(watchdogControl);
153  break;
154  case WatchdogIntStatusReg:
155  pkt->setLE<uint32_t>(rawIntWatchdog);
156  break;
157  case WatchdogResetStatusReg:
158  pkt->setLE<uint32_t>(rawResetWatchdog);
159  break;
160  case WatchdogDisableReg:
161  panic("Tried to read from WatchdogDisableRegister\n");
162  break;
163  default:
164  panic("Tried to read CpuLocalTimer at offset %#x\n", daddr);
165  break;
166  }
167 }
168 
169 Tick
171 {
172  assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
173  assert(pkt->getSize() == 4);
174  Addr daddr = pkt->getAddr() - pioAddr;
175  ContextID cpu_id = pkt->req->contextId();
176  DPRINTF(Timer, "Writing to CpuLocalTimer at offset: %#x\n", daddr);
177  assert(cpu_id >= 0);
178  assert(cpu_id < localTimer.size());
179 
180  if (daddr < Timer::Size)
181  localTimer[cpu_id]->write(pkt, daddr);
182  else
183  panic("Tried to write CpuLocalTimer at offset %#x that doesn't exist\n", daddr);
184  pkt->makeAtomicResponse();
185  return pioDelay;
186 }
187 
188 void
190 {
191  DPRINTF(Timer, "Writing to CpuLocalTimer at offset: %#x\n", daddr);
192  bool old_enable;
193  bool old_wd_mode;
194  uint32_t old_val;
195 
196  switch (daddr) {
197  case TimerLoadReg:
198  // Writing to this register also resets the counter register and
199  // starts decrementing if the counter is enabled.
200  timerLoadValue = pkt->getLE<uint32_t>();
201  restartTimerCounter(timerLoadValue);
202  break;
203  case TimerCounterReg:
204  // Can be written, doesn't start counting unless the timer is enabled
205  restartTimerCounter(pkt->getLE<uint32_t>());
206  break;
207  case TimerControlReg:
208  old_enable = timerControl.enable;
209  timerControl = pkt->getLE<uint32_t>();
210  if ((old_enable == 0) && timerControl.enable)
211  restartTimerCounter(timerLoadValue);
212  break;
213  case TimerIntStatusReg:
214  rawIntTimer = false;
215  if (pendingIntTimer) {
216  pendingIntTimer = false;
217  DPRINTF(Timer, "Clearing interrupt\n");
218  }
219  break;
220  case WatchdogLoadReg:
221  watchdogLoadValue = pkt->getLE<uint32_t>();
222  restartWatchdogCounter(watchdogLoadValue);
223  break;
224  case WatchdogCounterReg:
225  // Can't be written when in watchdog mode, but can in timer mode
226  if (!watchdogControl.watchdogMode) {
227  restartWatchdogCounter(pkt->getLE<uint32_t>());
228  }
229  break;
230  case WatchdogControlReg:
231  old_enable = watchdogControl.enable;
232  old_wd_mode = watchdogControl.watchdogMode;
233  watchdogControl = pkt->getLE<uint32_t>();
234  if ((old_enable == 0) && watchdogControl.enable)
235  restartWatchdogCounter(watchdogLoadValue);
236  // cannot disable watchdog using control register
237  if ((old_wd_mode == 1) && watchdogControl.watchdogMode == 0)
238  watchdogControl.watchdogMode = 1;
239  break;
240  case WatchdogIntStatusReg:
241  rawIntWatchdog = false;
242  if (pendingIntWatchdog) {
243  pendingIntWatchdog = false;
244  DPRINTF(Timer, "Clearing watchdog interrupt\n");
245  }
246  break;
247  case WatchdogResetStatusReg:
248  rawResetWatchdog = false;
249  DPRINTF(Timer, "Clearing watchdog reset flag\n");
250  break;
251  case WatchdogDisableReg:
252  old_val = watchdogDisableReg;
253  watchdogDisableReg = pkt->getLE<uint32_t>();
254  // if this sequence is observed, turn off watchdog mode
255  if (old_val == 0x12345678 && watchdogDisableReg == 0x87654321)
256  watchdogControl.watchdogMode = 0;
257  break;
258  default:
259  panic("Tried to write CpuLocalTimer timer at offset %#x\n", daddr);
260  break;
261  }
262 }
263 
264 //XXX: Two functions are needed because the control registers are different types
265 void
267 {
268  DPRINTF(Timer, "Resetting timer counter with value %#x\n", val);
269  if (!timerControl.enable)
270  return;
271 
272  Tick time = parent->clockPeriod() * power(16, timerControl.prescalar);
273  time *= val;
274 
275  if (timerZeroEvent.scheduled()) {
276  DPRINTF(Timer, "-- Event was already schedule, de-scheduling\n");
277  parent->deschedule(timerZeroEvent);
278  }
279  parent->schedule(timerZeroEvent, curTick() + time);
280  DPRINTF(Timer, "-- Scheduling new event for: %d\n", curTick() + time);
281 }
282 
283 void
285 {
286  DPRINTF(Timer, "Resetting watchdog counter with value %#x\n", val);
287  if (!watchdogControl.enable)
288  return;
289 
290  Tick time = parent->clockPeriod() * power(16, watchdogControl.prescalar);
291  time *= val;
292 
293  if (watchdogZeroEvent.scheduled()) {
294  DPRINTF(Timer, "-- Event was already schedule, de-scheduling\n");
295  parent->deschedule(watchdogZeroEvent);
296  }
297  parent->schedule(watchdogZeroEvent, curTick() + time);
298  DPRINTF(Timer, "-- Scheduling new event for: %d\n", curTick() + time);
299 }
301 
302 void
304 {
305  if (!timerControl.enable)
306  return;
307 
308  DPRINTF(Timer, "Timer Counter reached zero\n");
309 
310  rawIntTimer = true;
311  bool old_pending = pendingIntTimer;
312  if (timerControl.intEnable)
313  pendingIntTimer = true;
314  if (pendingIntTimer && !old_pending) {
315  DPRINTF(Timer, "-- Causing interrupt\n");
316  intTimer->raise();
317  }
318 
319  if (!timerControl.autoReload)
320  return;
321  else
322  restartTimerCounter(timerLoadValue);
323 }
324 
325 void
327 {
328  if (!watchdogControl.enable)
329  return;
330 
331  DPRINTF(Timer, "Watchdog Counter reached zero\n");
332 
333  rawIntWatchdog = true;
334  bool old_pending = pendingIntWatchdog;
335  // generates an interrupt only if the watchdog is in timer
336  // mode.
337  if (watchdogControl.intEnable && !watchdogControl.watchdogMode)
338  pendingIntWatchdog = true;
339  else if (watchdogControl.watchdogMode) {
340  rawResetWatchdog = true;
341  fatal("gem5 ARM Model does not support true watchdog operation!\n");
342  //XXX: Should we ever support a true watchdog reset?
343  }
344 
345  if (pendingIntWatchdog && !old_pending) {
346  DPRINTF(Timer, "-- Causing interrupt\n");
347  intWatchdog->raise();
348  }
349 
350  if (watchdogControl.watchdogMode)
351  return;
352  else if (watchdogControl.autoReload)
353  restartWatchdogCounter(watchdogLoadValue);
354 }
355 
356 void
358 {
359  DPRINTF(Checkpoint, "Serializing Arm CpuLocalTimer\n");
360 
361  uint32_t timer_control_serial = timerControl;
362  uint32_t watchdog_control_serial = watchdogControl;
363  SERIALIZE_SCALAR(timer_control_serial);
364  SERIALIZE_SCALAR(watchdog_control_serial);
365 
366  SERIALIZE_SCALAR(rawIntTimer);
367  SERIALIZE_SCALAR(rawIntWatchdog);
368  SERIALIZE_SCALAR(rawResetWatchdog);
369  SERIALIZE_SCALAR(watchdogDisableReg);
370  SERIALIZE_SCALAR(pendingIntTimer);
371  SERIALIZE_SCALAR(pendingIntWatchdog);
372  SERIALIZE_SCALAR(timerLoadValue);
373  SERIALIZE_SCALAR(watchdogLoadValue);
374 
375  bool timer_is_in_event = timerZeroEvent.scheduled();
376  SERIALIZE_SCALAR(timer_is_in_event);
377  bool watchdog_is_in_event = watchdogZeroEvent.scheduled();
378  SERIALIZE_SCALAR(watchdog_is_in_event);
379 
380  Tick timer_event_time;
381  if (timer_is_in_event){
382  timer_event_time = timerZeroEvent.when();
383  SERIALIZE_SCALAR(timer_event_time);
384  }
385  Tick watchdog_event_time;
386  if (watchdog_is_in_event){
387  watchdog_event_time = watchdogZeroEvent.when();
388  SERIALIZE_SCALAR(watchdog_event_time);
389  }
390 }
391 
392 void
394 {
395  DPRINTF(Checkpoint, "Unserializing Arm CpuLocalTimer\n");
396 
397  uint32_t timer_control_serial;
398  UNSERIALIZE_SCALAR(timer_control_serial);
399  timerControl = timer_control_serial;
400  uint32_t watchdog_control_serial;
401  UNSERIALIZE_SCALAR(watchdog_control_serial);
402  watchdogControl = watchdog_control_serial;
403 
404  UNSERIALIZE_SCALAR(rawIntTimer);
405  UNSERIALIZE_SCALAR(rawIntWatchdog);
406  UNSERIALIZE_SCALAR(rawResetWatchdog);
407  UNSERIALIZE_SCALAR(watchdogDisableReg);
408  UNSERIALIZE_SCALAR(pendingIntTimer);
409  UNSERIALIZE_SCALAR(pendingIntWatchdog);
410  UNSERIALIZE_SCALAR(timerLoadValue);
411  UNSERIALIZE_SCALAR(watchdogLoadValue);
412 
413  bool timer_is_in_event;
414  UNSERIALIZE_SCALAR(timer_is_in_event);
415  bool watchdog_is_in_event;
416  UNSERIALIZE_SCALAR(watchdog_is_in_event);
417 
418  Tick timer_event_time;
419  if (timer_is_in_event){
420  UNSERIALIZE_SCALAR(timer_event_time);
421  parent->schedule(timerZeroEvent, timer_event_time);
422  }
423  Tick watchdog_event_time;
424  if (watchdog_is_in_event) {
425  UNSERIALIZE_SCALAR(watchdog_event_time);
426  parent->schedule(watchdogZeroEvent, watchdog_event_time);
427  }
428 }
429 
430 
431 
432 void
434 {
435  for (int i = 0; i < sys->threads.size(); i++)
436  localTimer[i]->serializeSection(cp, csprintf("timer%d", i));
437 }
438 
439 void
441 {
442  for (int i = 0; i < sys->threads.size(); i++)
443  localTimer[i]->unserializeSection(cp, csprintf("timer%d", i));
444 }
CpuLocalTimer::Timer::Size
@ Size
Definition: timer_cpulocal.hh:77
fatal
#define fatal(...)
This implements a cprintf based fatal() function.
Definition: logging.hh:183
Packet::makeAtomicResponse
void makeAtomicResponse()
Definition: packet.hh:1017
BasicPioDevice::pioAddr
Addr pioAddr
Address that the device listens to.
Definition: io_device.hh:148
Serializable::unserializeSection
void unserializeSection(CheckpointIn &cp, const char *name)
Unserialize an a child object.
Definition: serialize.cc:177
CpuLocalTimer::Timer::watchdogAtZero
void watchdogAtZero()
Definition: timer_cpulocal.cc:326
CpuLocalTimer::unserialize
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: timer_cpulocal.cc:440
CpuLocalTimer::Timer::serialize
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition: timer_cpulocal.cc:357
CpuLocalTimer::Timer::unserialize
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: timer_cpulocal.cc:393
UNSERIALIZE_SCALAR
#define UNSERIALIZE_SCALAR(scalar)
Definition: serialize.hh:591
Packet::getAddr
Addr getAddr() const
Definition: packet.hh:755
PioDevice::init
void init() override
init() is called after all C++ SimObjects have been created and all ports are connected.
Definition: io_device.cc:56
ArmISA::i
Bitfield< 7 > i
Definition: miscregs_types.hh:63
CpuLocalTimer::Timer::write
void write(PacketPtr pkt, Addr daddr)
Handle write for a single timer.
Definition: timer_cpulocal.cc:189
ContextID
int ContextID
Globally unique thread context ID.
Definition: types.hh:237
base_gic.hh
Tick
uint64_t Tick
Tick count type.
Definition: types.hh:59
Packet::req
RequestPtr req
A pointer to the original request.
Definition: packet.hh:341
CpuLocalTimer::Timer::prescalar
Bitfield< 15, 8 > prescalar
Definition: timer_cpulocal.hh:85
Packet::getSize
unsigned getSize() const
Definition: packet.hh:765
CpuLocalTimer::Timer::restartWatchdogCounter
void restartWatchdogCounter(uint32_t val)
Definition: timer_cpulocal.cc:284
system.hh
Serializable::serializeSection
void serializeSection(CheckpointOut &cp, const char *name) const
Serialize an object into a new section.
Definition: serialize.cc:170
CpuLocalTimer::init
void init() override
Inits the local timers.
Definition: timer_cpulocal.cc:58
packet.hh
PioDevice::sys
System * sys
Definition: io_device.hh:102
cp
Definition: cprintf.cc:37
ThreadContext
ThreadContext is the external interface to all thread state for anything outside of the CPU.
Definition: thread_context.hh:88
CpuLocalTimer::read
Tick read(PacketPtr pkt) override
Handle a read to the device.
Definition: timer_cpulocal.cc:92
CpuLocalTimer
Definition: timer_cpulocal.hh:59
DPRINTF
#define DPRINTF(x,...)
Definition: trace.hh:237
CpuLocalTimer::write
Tick write(PacketPtr pkt) override
Handle a write to the device.
Definition: timer_cpulocal.cc:170
System::Threads::size
int size() const
Definition: system.hh:204
BasicPioDevice::pioSize
Addr pioSize
Size that the device's address range.
Definition: io_device.hh:151
X86ISA::val
Bitfield< 63 > val
Definition: misc.hh:769
Addr
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:148
SERIALIZE_SCALAR
#define SERIALIZE_SCALAR(scalar)
Definition: serialize.hh:584
packet_access.hh
SimObject::name
virtual const std::string name() const
Definition: sim_object.hh:182
timer_cpulocal.hh
System::threads
Threads threads
Definition: system.hh:304
Packet::getLE
T getLE() const
Get the data in the packet byte swapped from little endian to host endian.
Definition: packet_access.hh:75
CpuLocalTimer::Timer::restartTimerCounter
void restartTimerCounter(uint32_t val)
Restart the counter ticking at val.
Definition: timer_cpulocal.cc:266
Packet
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
Definition: packet.hh:258
BasicPioDevice
Definition: io_device.hh:144
ArmInterruptPin
Generic representation of an Arm interrupt pin.
Definition: base_gic.hh:179
logging.hh
CpuLocalTimer::Timer::read
void read(PacketPtr pkt, Addr daddr)
Handle read for a single timer.
Definition: timer_cpulocal.cc:112
BasicPioDevice::pioDelay
Tick pioDelay
Delay that the device experinces on an access.
Definition: io_device.hh:154
Packet::setLE
void setLE(T v)
Set the value in the data pointer to v as little endian.
Definition: packet_access.hh:105
CheckpointOut
std::ostream CheckpointOut
Definition: serialize.hh:64
CpuLocalTimer::Timer
Definition: timer_cpulocal.hh:62
curTick
Tick curTick()
The universal simulation clock.
Definition: cur_tick.hh:43
trace.hh
SimObject::params
const Params & params() const
Definition: sim_object.hh:168
MipsISA::p
Bitfield< 0 > p
Definition: pra_constants.hh:323
intmath.hh
power
uint64_t power(uint32_t n, uint32_t e)
Definition: intmath.hh:43
CheckpointIn
Definition: serialize.hh:68
CpuLocalTimer::Timer::timerAtZero
void timerAtZero()
Called when the counter reaches 0.
Definition: timer_cpulocal.cc:303
CpuLocalTimer::localTimer
std::vector< std::unique_ptr< Timer > > localTimer
Timers that do the actual work.
Definition: timer_cpulocal.hh:162
csprintf
std::string csprintf(const char *format, const Args &...args)
Definition: cprintf.hh:158
PioDevice::Params
PioDeviceParams Params
Definition: io_device.hh:131
CpuLocalTimer::serialize
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition: timer_cpulocal.cc:433
CpuLocalTimer::CpuLocalTimer
CpuLocalTimer(const Params &p)
The constructor for RealView just registers itself with the MMU.
Definition: timer_cpulocal.cc:52
CpuLocalTimer::Timer::Timer
Timer(const std::string &name, CpuLocalTimer *_parent, ArmInterruptPin *int_timer, ArmInterruptPin *int_watchdog)
Definition: timer_cpulocal.cc:76
panic
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:171

Generated on Tue Jun 22 2021 15:28:27 for gem5 by doxygen 1.8.17