gem5  v20.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 
39 
40 #include "arch/arm/system.hh"
41 #include "base/intmath.hh"
42 #include "base/trace.hh"
43 #include "debug/Checkpoint.hh"
44 #include "debug/Timer.hh"
45 #include "dev/arm/base_gic.hh"
46 #include "mem/packet.hh"
47 #include "mem/packet_access.hh"
48 
50  : BasicPioDevice(p, 0x38)
51 {
52 }
53 
54 void
56 {
57  auto p = params();
58  // Initialize the timer registers for each per cpu timer
59  for (int i = 0; i < sys->numContexts(); i++) {
61  std::stringstream oss;
62  oss << name() << ".timer" << i;
63 
64  localTimer.emplace_back(
65  new Timer(oss.str(), this,
66  p->int_timer->get(tc),
67  p->int_watchdog->get(tc)));
68  }
69 
71 }
72 
73 CpuLocalTimer::Timer::Timer(const std::string &timer_name,
74  CpuLocalTimer* _parent,
75  ArmInterruptPin* int_timer,
76  ArmInterruptPin* int_watchdog)
77  : _name(timer_name), parent(_parent), intTimer(int_timer),
78  intWatchdog(int_watchdog), timerControl(0x0), watchdogControl(0x0),
79  rawIntTimer(false), rawIntWatchdog(false),
80  rawResetWatchdog(false), watchdogDisableReg(0x0),
81  pendingIntTimer(false), pendingIntWatchdog(false),
82  timerLoadValue(0x0), watchdogLoadValue(0x0),
83  timerZeroEvent([this]{ timerAtZero(); }, name()),
84  watchdogZeroEvent([this]{ watchdogAtZero(); }, name())
85 {
86 }
87 
88 Tick
90 {
91  assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
92  assert(pkt->getSize() == 4);
93  Addr daddr = pkt->getAddr() - pioAddr;
94  ContextID cpu_id = pkt->req->contextId();
95  DPRINTF(Timer, "Reading from CpuLocalTimer at offset: %#x\n", daddr);
96  assert(cpu_id >= 0);
97  assert(cpu_id < localTimer.size());
98 
99  if (daddr < Timer::Size)
100  localTimer[cpu_id]->read(pkt, daddr);
101  else
102  panic("Tried to read CpuLocalTimer at offset %#x that doesn't exist\n", daddr);
103  pkt->makeAtomicResponse();
104  return pioDelay;
105 }
106 
107 
108 void
110 {
111  DPRINTF(Timer, "Reading from CpuLocalTimer at offset: %#x\n", daddr);
112  Tick time;
113 
114  switch(daddr) {
115  case TimerLoadReg:
116  pkt->setLE<uint32_t>(timerLoadValue);
117  break;
118  case TimerCounterReg:
119  DPRINTF(Timer, "Event schedule for timer %d, clock=%d, prescale=%d\n",
121  timerControl.prescalar);
122  time = timerZeroEvent.when() - curTick();
123  time = time / parent->clockPeriod() /
124  power(16, timerControl.prescalar);
125  DPRINTF(Timer, "-- returning counter at %d\n", time);
126  pkt->setLE<uint32_t>(time);
127  break;
128  case TimerControlReg:
129  pkt->setLE<uint32_t>(timerControl);
130  break;
131  case TimerIntStatusReg:
132  pkt->setLE<uint32_t>(rawIntTimer);
133  break;
134  case WatchdogLoadReg:
135  pkt->setLE<uint32_t>(watchdogLoadValue);
136  break;
137  case WatchdogCounterReg:
138  DPRINTF(Timer,
139  "Event schedule for watchdog %d, clock=%d, prescale=%d\n",
141  watchdogControl.prescalar);
142  time = watchdogZeroEvent.when() - curTick();
143  time = time / parent->clockPeriod() /
144  power(16, watchdogControl.prescalar);
145  DPRINTF(Timer, "-- returning counter at %d\n", time);
146  pkt->setLE<uint32_t>(time);
147  break;
148  case WatchdogControlReg:
149  pkt->setLE<uint32_t>(watchdogControl);
150  break;
152  pkt->setLE<uint32_t>(rawIntWatchdog);
153  break;
155  pkt->setLE<uint32_t>(rawResetWatchdog);
156  break;
157  case WatchdogDisableReg:
158  panic("Tried to read from WatchdogDisableRegister\n");
159  break;
160  default:
161  panic("Tried to read CpuLocalTimer at offset %#x\n", daddr);
162  break;
163  }
164 }
165 
166 Tick
168 {
169  assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
170  assert(pkt->getSize() == 4);
171  Addr daddr = pkt->getAddr() - pioAddr;
172  ContextID cpu_id = pkt->req->contextId();
173  DPRINTF(Timer, "Writing to CpuLocalTimer at offset: %#x\n", daddr);
174  assert(cpu_id >= 0);
175  assert(cpu_id < localTimer.size());
176 
177  if (daddr < Timer::Size)
178  localTimer[cpu_id]->write(pkt, daddr);
179  else
180  panic("Tried to write CpuLocalTimer at offset %#x that doesn't exist\n", daddr);
181  pkt->makeAtomicResponse();
182  return pioDelay;
183 }
184 
185 void
187 {
188  DPRINTF(Timer, "Writing to CpuLocalTimer at offset: %#x\n", daddr);
189  bool old_enable;
190  bool old_wd_mode;
191  uint32_t old_val;
192 
193  switch (daddr) {
194  case TimerLoadReg:
195  // Writing to this register also resets the counter register and
196  // starts decrementing if the counter is enabled.
197  timerLoadValue = pkt->getLE<uint32_t>();
199  break;
200  case TimerCounterReg:
201  // Can be written, doesn't start counting unless the timer is enabled
202  restartTimerCounter(pkt->getLE<uint32_t>());
203  break;
204  case TimerControlReg:
205  old_enable = timerControl.enable;
206  timerControl = pkt->getLE<uint32_t>();
207  if ((old_enable == 0) && timerControl.enable)
209  break;
210  case TimerIntStatusReg:
211  rawIntTimer = false;
212  if (pendingIntTimer) {
213  pendingIntTimer = false;
214  DPRINTF(Timer, "Clearing interrupt\n");
215  }
216  break;
217  case WatchdogLoadReg:
218  watchdogLoadValue = pkt->getLE<uint32_t>();
220  break;
221  case WatchdogCounterReg:
222  // Can't be written when in watchdog mode, but can in timer mode
223  if (!watchdogControl.watchdogMode) {
224  restartWatchdogCounter(pkt->getLE<uint32_t>());
225  }
226  break;
227  case WatchdogControlReg:
228  old_enable = watchdogControl.enable;
229  old_wd_mode = watchdogControl.watchdogMode;
230  watchdogControl = pkt->getLE<uint32_t>();
231  if ((old_enable == 0) && watchdogControl.enable)
233  // cannot disable watchdog using control register
234  if ((old_wd_mode == 1) && watchdogControl.watchdogMode == 0)
235  watchdogControl.watchdogMode = 1;
236  break;
238  rawIntWatchdog = false;
239  if (pendingIntWatchdog) {
240  pendingIntWatchdog = false;
241  DPRINTF(Timer, "Clearing watchdog interrupt\n");
242  }
243  break;
245  rawResetWatchdog = false;
246  DPRINTF(Timer, "Clearing watchdog reset flag\n");
247  break;
248  case WatchdogDisableReg:
249  old_val = watchdogDisableReg;
250  watchdogDisableReg = pkt->getLE<uint32_t>();
251  // if this sequence is observed, turn off watchdog mode
252  if (old_val == 0x12345678 && watchdogDisableReg == 0x87654321)
253  watchdogControl.watchdogMode = 0;
254  break;
255  default:
256  panic("Tried to write CpuLocalTimer timer at offset %#x\n", daddr);
257  break;
258  }
259 }
260 
261 //XXX: Two functions are needed because the control registers are different types
262 void
264 {
265  DPRINTF(Timer, "Resetting timer counter with value %#x\n", val);
266  if (!timerControl.enable)
267  return;
268 
269  Tick time = parent->clockPeriod() * power(16, timerControl.prescalar);
270  time *= val;
271 
272  if (timerZeroEvent.scheduled()) {
273  DPRINTF(Timer, "-- Event was already schedule, de-scheduling\n");
275  }
277  DPRINTF(Timer, "-- Scheduling new event for: %d\n", curTick() + time);
278 }
279 
280 void
282 {
283  DPRINTF(Timer, "Resetting watchdog counter with value %#x\n", val);
284  if (!watchdogControl.enable)
285  return;
286 
287  Tick time = parent->clockPeriod() * power(16, watchdogControl.prescalar);
288  time *= val;
289 
291  DPRINTF(Timer, "-- Event was already schedule, de-scheduling\n");
293  }
295  DPRINTF(Timer, "-- Scheduling new event for: %d\n", curTick() + time);
296 }
298 
299 void
301 {
302  if (!timerControl.enable)
303  return;
304 
305  DPRINTF(Timer, "Timer Counter reached zero\n");
306 
307  rawIntTimer = true;
308  bool old_pending = pendingIntTimer;
309  if (timerControl.intEnable)
310  pendingIntTimer = true;
311  if (pendingIntTimer && !old_pending) {
312  DPRINTF(Timer, "-- Causing interrupt\n");
313  intTimer->raise();
314  }
315 
316  if (!timerControl.autoReload)
317  return;
318  else
320 }
321 
322 void
324 {
325  if (!watchdogControl.enable)
326  return;
327 
328  DPRINTF(Timer, "Watchdog Counter reached zero\n");
329 
330  rawIntWatchdog = true;
331  bool old_pending = pendingIntWatchdog;
332  // generates an interrupt only if the watchdog is in timer
333  // mode.
334  if (watchdogControl.intEnable && !watchdogControl.watchdogMode)
335  pendingIntWatchdog = true;
336  else if (watchdogControl.watchdogMode) {
337  rawResetWatchdog = true;
338  fatal("gem5 ARM Model does not support true watchdog operation!\n");
339  //XXX: Should we ever support a true watchdog reset?
340  }
341 
342  if (pendingIntWatchdog && !old_pending) {
343  DPRINTF(Timer, "-- Causing interrupt\n");
344  intWatchdog->raise();
345  }
346 
347  if (watchdogControl.watchdogMode)
348  return;
349  else if (watchdogControl.autoReload)
351 }
352 
353 void
355 {
356  DPRINTF(Checkpoint, "Serializing Arm CpuLocalTimer\n");
357 
358  uint32_t timer_control_serial = timerControl;
359  uint32_t watchdog_control_serial = watchdogControl;
360  SERIALIZE_SCALAR(timer_control_serial);
361  SERIALIZE_SCALAR(watchdog_control_serial);
362 
371 
372  bool timer_is_in_event = timerZeroEvent.scheduled();
373  SERIALIZE_SCALAR(timer_is_in_event);
374  bool watchdog_is_in_event = watchdogZeroEvent.scheduled();
375  SERIALIZE_SCALAR(watchdog_is_in_event);
376 
377  Tick timer_event_time;
378  if (timer_is_in_event){
379  timer_event_time = timerZeroEvent.when();
380  SERIALIZE_SCALAR(timer_event_time);
381  }
382  Tick watchdog_event_time;
383  if (watchdog_is_in_event){
384  watchdog_event_time = watchdogZeroEvent.when();
385  SERIALIZE_SCALAR(watchdog_event_time);
386  }
387 }
388 
389 void
391 {
392  DPRINTF(Checkpoint, "Unserializing Arm CpuLocalTimer\n");
393 
394  uint32_t timer_control_serial;
395  UNSERIALIZE_SCALAR(timer_control_serial);
396  timerControl = timer_control_serial;
397  uint32_t watchdog_control_serial;
398  UNSERIALIZE_SCALAR(watchdog_control_serial);
399  watchdogControl = watchdog_control_serial;
400 
409 
410  bool timer_is_in_event;
411  UNSERIALIZE_SCALAR(timer_is_in_event);
412  bool watchdog_is_in_event;
413  UNSERIALIZE_SCALAR(watchdog_is_in_event);
414 
415  Tick timer_event_time;
416  if (timer_is_in_event){
417  UNSERIALIZE_SCALAR(timer_event_time);
418  parent->schedule(timerZeroEvent, timer_event_time);
419  }
420  Tick watchdog_event_time;
421  if (watchdog_is_in_event) {
422  UNSERIALIZE_SCALAR(watchdog_event_time);
423  parent->schedule(watchdogZeroEvent, watchdog_event_time);
424  }
425 }
426 
427 
428 
429 void
431 {
432  for (int i = 0; i < sys->numContexts(); i++)
433  localTimer[i]->serializeSection(cp, csprintf("timer%d", i));
434 }
435 
436 void
438 {
439  for (int i = 0; i < sys->numContexts(); i++)
440  localTimer[i]->unserializeSection(cp, csprintf("timer%d", i));
441 }
442 
444 CpuLocalTimerParams::create()
445 {
446  return new CpuLocalTimer(this);
447 }
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:163
#define DPRINTF(x,...)
Definition: trace.hh:225
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:171
Bitfield< 7 > i
ArmInterruptPin * intWatchdog
void restartTimerCounter(uint32_t val)
Restart the counter ticking at val.
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:56
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:40
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 serializeSection(CheckpointOut &cp, const char *name) const
Serialize an object into a new section.
Definition: serialize.cc:171
EventFunctionWrapper timerZeroEvent
Bitfield< 63 > val
Definition: misc.hh:769
void setLE(T v)
Set the value in the data pointer to v as little endian.
ThreadContext * getThreadContext(ContextID tid) const
Definition: system.hh:186
void serialize(CheckpointOut &cp) const override
Serialize an object.
CpuLocalTimerParams Params
RequestPtr req
A pointer to the original request.
Definition: packet.hh:321
unsigned getSize() const
Definition: packet.hh:730
friend class CpuLocalTimer
#define UNSERIALIZE_SCALAR(scalar)
Definition: serialize.hh:770
Tick curTick()
The current simulated tick.
Definition: core.hh:44
std::string csprintf(const char *format, const Args &...args)
Definition: cprintf.hh:158
ArmInterruptPin * intTimer
Interrupt to cause/clear.
Addr pioSize
Size that the device&#39;s address range.
Definition: io_device.hh:157
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:943
TimerCtrl timerControl
Control register as specified above.
uint64_t Tick
Tick count type.
Definition: types.hh:61
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
void deschedule(Event &event)
Definition: eventq.hh:943
Addr getAddr() const
Definition: packet.hh:720
unsigned numContexts() const
Definition: system.hh:198
void schedule(Event &event, Tick when)
Definition: eventq.hh:934
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:140
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:102
A Packet is used to encapsulate a transfer between two objects in the memory system (e...
Definition: packet.hh:249
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:763
bool scheduled() const
Determine if the current event is scheduled.
Definition: eventq.hh:459
virtual const std::string name() const
Definition: sim_object.hh:129
Base class for ARM GIC implementations.
Declaration of the Packet class.
virtual void raise()=0
Signal an interrupt.
std::ostream CheckpointOut
Definition: serialize.hh:63
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:160
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
Tick when() const
Get the time that the event is scheduled.
Definition: eventq.hh:499
Addr pioAddr
Address that the device listens to.
Definition: io_device.hh:154
Generic representation of an Arm interrupt pin.
Definition: base_gic.hh:176
CpuLocalTimer(Params *p)
The constructor for RealView just registers itself with the MMU.
int ContextID
Globally unique thread context ID.
Definition: types.hh:229
WatchdogCtrl watchdogControl
void unserializeSection(CheckpointIn &cp, const char *name)
Unserialize an a child object.
Definition: serialize.cc:178

Generated on Thu May 28 2020 16:21:32 for gem5 by doxygen 1.8.13