gem5  v19.0.0.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  * Authors: Ali Saidi
38  * Geoffrey Blake
39  */
40 
42 
43 #include "arch/arm/system.hh"
44 #include "base/intmath.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  auto p = params();
61  // Initialize the timer registers for each per cpu timer
62  for (int i = 0; i < sys->numContexts(); 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",
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",
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;
155  pkt->setLE<uint32_t>(rawIntWatchdog);
156  break;
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>();
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)
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>();
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)
236  // cannot disable watchdog using control register
237  if ((old_wd_mode == 1) && watchdogControl.watchdogMode == 0)
238  watchdogControl.watchdogMode = 1;
239  break;
241  rawIntWatchdog = false;
242  if (pendingIntWatchdog) {
243  pendingIntWatchdog = false;
244  DPRINTF(Timer, "Clearing watchdog interrupt\n");
245  }
246  break;
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");
278  }
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 
294  DPRINTF(Timer, "-- Event was already schedule, de-scheduling\n");
296  }
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
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)
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 
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 
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->numContexts(); i++)
436  localTimer[i]->serializeSection(cp, csprintf("timer%d", i));
437 }
438 
439 void
441 {
442  for (int i = 0; i < sys->numContexts(); i++)
443  localTimer[i]->unserializeSection(cp, csprintf("timer%d", i));
444 }
445 
447 CpuLocalTimerParams::create()
448 {
449  return new CpuLocalTimer(this);
450 }
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:167
#define DPRINTF(x,...)
Definition: trace.hh:229
Tick write(PacketPtr pkt) override
Handle a write to the device.
void read(PacketPtr pkt, Addr daddr)
Handle read for a single timer.
#define fatal(...)
This implements a cprintf based fatal() function.
Definition: logging.hh:175
void serializeSection(CheckpointOut &cp, const char *name) const
Serialize an object into a new section.
Definition: serialize.cc:176
Bitfield< 7 > i
ArmInterruptPin * intWatchdog
Tick when() const
Get the time that the event is scheduled.
Definition: eventq.hh:401
void restartTimerCounter(uint32_t val)
Restart the counter ticking at val.
void unserializeSection(CheckpointIn &cp, const char *name)
Unserialize an a child object.
Definition: serialize.cc:183
bool pendingIntTimer
If an interrupt is currently pending.
void init() override
init() is called after all C++ SimObjects have been created and all ports are connected.
Definition: io_device.cc:59
Timer(const std::string &name, CpuLocalTimer *_parent, ArmInterruptPin *int_timer, ArmInterruptPin *int_watchdog)
uint32_t timerLoadValue
Value to load into counters when periodic mode reaches 0.
Definition: cprintf.cc:42
Tick clockPeriod() const
ThreadContext is the external interface to all thread state for anything outside of the CPU...
const Params * params() const
EndBitUnion(WatchdogCtrl) protected CpuLocalTimer * parent
Pointer to parent class.
void deschedule(Event &event)
Definition: eventq.hh:750
EventFunctionWrapper timerZeroEvent
Bitfield< 63 > val
Definition: misc.hh:771
void setLE(T v)
Set the value in the data pointer to v as little endian.
ThreadContext * getThreadContext(ContextID tid) const
Definition: system.hh:194
void serialize(CheckpointOut &cp) const override
Serialize an object.
CpuLocalTimerParams Params
RequestPtr req
A pointer to the original request.
Definition: packet.hh:327
unsigned getSize() const
Definition: packet.hh:736
friend class CpuLocalTimer
#define UNSERIALIZE_SCALAR(scalar)
Definition: serialize.hh:645
Tick curTick()
The current simulated tick.
Definition: core.hh:47
std::string csprintf(const char *format, const Args &...args)
Definition: cprintf.hh:162
ArmInterruptPin * intTimer
Interrupt to cause/clear.
bool scheduled() const
Determine if the current event is scheduled.
Definition: eventq.hh:385
Addr pioSize
Size that the device&#39;s address range.
Definition: io_device.hh:160
std::vector< std::unique_ptr< Timer > > localTimer
Timers that do the actual work.
void serialize(CheckpointOut &cp) const override
Serialize an object.
void makeAtomicResponse()
Definition: packet.hh:949
TimerCtrl timerControl
Control register as specified above.
uint64_t Tick
Tick count type.
Definition: types.hh:63
uint64_t power(uint32_t n, uint32_t e)
Definition: intmath.hh:40
void write(PacketPtr pkt, Addr daddr)
Handle write for a single timer.
EventFunctionWrapper watchdogZeroEvent
Addr getAddr() const
Definition: packet.hh:726
unsigned numContexts() const
Definition: system.hh:206
void unserialize(CheckpointIn &cp) override
Unserialize an object.
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:142
bool rawIntTimer
If timer has caused an interrupt.
This implements the cpu local timer from the Cortex-A9 MPCore Technical Reference Manual rev r2p2 (AR...
System * sys
Definition: io_device.hh:105
virtual const std::string name() const
Definition: sim_object.hh:120
A Packet is used to encapsulate a transfer between two objects in the memory system (e...
Definition: packet.hh:255
void restartWatchdogCounter(uint32_t val)
void timerAtZero()
Called when the counter reaches 0.
void init() override
Inits the local timers.
#define SERIALIZE_SCALAR(scalar)
Definition: serialize.hh:643
Base class for ARM GIC implementations.
Declaration of the Packet class.
virtual void raise()=0
Signal an interrupt.
std::ostream CheckpointOut
Definition: serialize.hh:68
Tick read(PacketPtr pkt) override
Handle a read to the device.
Tick pioDelay
Delay that the device experinces on an access.
Definition: io_device.hh:163
void schedule(Event &event, Tick when)
Definition: eventq.hh:744
std::string name() const
T getLE() const
Get the data in the packet byte swapped from little endian to host endian.
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Bitfield< 0 > p
Addr pioAddr
Address that the device listens to.
Definition: io_device.hh:157
Generic representation of an Arm interrupt pin.
Definition: base_gic.hh:178
CpuLocalTimer(Params *p)
The constructor for RealView just registers itself with the MMU.
int ContextID
Globally unique thread context ID.
Definition: types.hh:231
WatchdogCtrl watchdogControl

Generated on Fri Feb 28 2020 16:27:00 for gem5 by doxygen 1.8.13