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

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