gem5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
mc146818.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2004-2005 The Regents of The University of Michigan
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met: redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer;
9  * redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution;
12  * neither the name of the copyright holders nor the names of its
13  * contributors may be used to endorse or promote products derived from
14  * this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * Authors: Ali Saidi
29  * Andrew Schultz
30  * Miguel Serrano
31  */
32 
33 #include "dev/mc146818.hh"
34 
35 #include <sys/time.h>
36 
37 #include <ctime>
38 #include <string>
39 
40 #include "base/bitfield.hh"
41 #include "base/time.hh"
42 #include "base/trace.hh"
43 #include "debug/MC146818.hh"
44 #include "dev/rtcreg.h"
45 
46 using namespace std;
47 
48 static uint8_t
49 bcdize(uint8_t val)
50 {
51  uint8_t result;
52  result = val % 10;
53  result += (val / 10) << 4;
54  return result;
55 }
56 
57 static uint8_t
58 unbcdize(uint8_t val)
59 {
60  uint8_t result;
61  result = val & 0xf;
62  result += (val >> 4) * 10;
63  return result;
64 }
65 
66 void
67 MC146818::setTime(const struct tm time)
68 {
69  curTime = time;
70  year = time.tm_year;
71  // Unix is 0-11 for month, data seet says start at 1
72  mon = time.tm_mon + 1;
73  mday = time.tm_mday;
74  hour = time.tm_hour;
75  min = time.tm_min;
76  sec = time.tm_sec;
77 
78  // Datasheet says 1 is sunday
79  wday = time.tm_wday + 1;
80 
81  if (!stat_regB.dm) {
82  // The datasheet says that the year field can be either BCD or
83  // years since 1900. Linux seems to be happy with years since
84  // 1900.
85  year = bcdize(year % 100);
86  mon = bcdize(mon);
87  mday = bcdize(mday);
88  hour = bcdize(hour);
89  min = bcdize(min);
90  sec = bcdize(sec);
91  }
92 }
93 
94 MC146818::MC146818(EventManager *em, const string &n, const struct tm time,
95  bool bcd, Tick frequency)
96  : EventManager(em), _name(n), event(this, frequency), tickEvent(this)
97 {
98  memset(clock_data, 0, sizeof(clock_data));
99 
100  stat_regA = 0;
101  stat_regA.dv = RTCA_DV_32768HZ;
102  stat_regA.rs = RTCA_RS_1024HZ;
103 
104  stat_regB = 0;
105  stat_regB.pie = 1;
106  stat_regB.format24h = 1;
107  stat_regB.dm = bcd ? 0 : 1;
108 
109  setTime(time);
110  DPRINTFN("Real-time clock set to %s", asctime(&time));
111 }
112 
114 {
116  deschedule(event);
117 }
118 
119 bool
120 MC146818::rega_dv_disabled(const RtcRegA &reg)
121 {
122  return reg.dv == RTCA_DV_DISABLED0 ||
123  reg.dv == RTCA_DV_DISABLED1;
124 }
125 
126 void
128 {
129  assert(!event.scheduled());
130  assert(!tickEvent.scheduled());
131 
132  if (stat_regB.pie)
134  if (!rega_dv_disabled(stat_regA))
136 }
137 
138 void
139 MC146818::writeData(const uint8_t addr, const uint8_t data)
140 {
141  bool panic_unsupported(false);
142 
143  if (addr < RTC_STAT_REGA) {
144  clock_data[addr] = data;
145  curTime.tm_sec = unbcdize(sec);
146  curTime.tm_min = unbcdize(min);
147  curTime.tm_hour = unbcdize(hour);
148  curTime.tm_mday = unbcdize(mday);
149  curTime.tm_mon = unbcdize(mon) - 1;
150  curTime.tm_year = ((unbcdize(year) + 50) % 100) + 1950;
151  curTime.tm_wday = unbcdize(wday) - 1;
152  } else {
153  switch (addr) {
154  case RTC_STAT_REGA: {
155  RtcRegA old_rega(stat_regA);
156  stat_regA = data;
157  // The "update in progress" bit is read only.
158  stat_regA.uip = old_rega;
159 
160  if (!rega_dv_disabled(stat_regA) &&
161  stat_regA.dv != RTCA_DV_32768HZ) {
162  inform("RTC: Unimplemented divider configuration: %i\n",
163  stat_regA.dv);
164  panic_unsupported = true;
165  }
166 
167  if (stat_regA.rs != RTCA_RS_1024HZ) {
168  inform("RTC: Unimplemented interrupt rate: %i\n",
169  stat_regA.rs);
170  panic_unsupported = true;
171  }
172 
173  if (rega_dv_disabled(stat_regA)) {
174  // The divider is disabled, make sure that we don't
175  // schedule any ticks.
176  if (tickEvent.scheduled())
178  } else if (rega_dv_disabled(old_rega)) {
179  // According to the specification, the next tick
180  // happens after 0.5s when the divider chain goes
181  // from reset to active. So, we simply schedule the
182  // tick after 0.5s.
183  assert(!tickEvent.scheduled());
185  }
186  } break;
187  case RTC_STAT_REGB:
188  stat_regB = data;
189  if (stat_regB.aie || stat_regB.uie) {
190  inform("RTC: Unimplemented interrupt configuration: %s %s\n",
191  stat_regB.aie ? "alarm" : "",
192  stat_regB.uie ? "update" : "");
193  panic_unsupported = true;
194  }
195 
196  if (stat_regB.dm) {
197  inform("RTC: The binary interface is not fully implemented.\n");
198  panic_unsupported = true;
199  }
200 
201  if (!stat_regB.format24h) {
202  inform("RTC: The 12h time format not supported.\n");
203  panic_unsupported = true;
204  }
205 
206  if (stat_regB.dse) {
207  inform("RTC: Automatic daylight saving time not supported.\n");
208  panic_unsupported = true;
209  }
210 
211  if (stat_regB.pie) {
212  if (!event.scheduled())
214  } else {
215  if (event.scheduled())
216  deschedule(event);
217  }
218  break;
219  case RTC_STAT_REGC:
220  case RTC_STAT_REGD:
221  panic("RTC status registers C and D are not implemented.\n");
222  break;
223  }
224  }
225 
226  if (panic_unsupported)
227  panic("Unimplemented RTC configuration!\n");
228 
229 }
230 
231 uint8_t
233 {
234  if (addr < RTC_STAT_REGA)
235  return clock_data[addr];
236  else {
237  switch (addr) {
238  case RTC_STAT_REGA:
239  // toggle UIP bit for linux
240  stat_regA.uip = !stat_regA.uip;
241  return stat_regA;
242  break;
243  case RTC_STAT_REGB:
244  return stat_regB;
245  break;
246  case RTC_STAT_REGC:
247  case RTC_STAT_REGD:
248  return 0x00;
249  break;
250  default:
251  panic("Shouldn't be here");
252  }
253  }
254 }
255 
256 void
258 {
259  assert(!rega_dv_disabled(stat_regA));
260 
261  if (stat_regB.set)
262  return;
263  time_t calTime = mkutctime(&curTime);
264  calTime++;
265  setTime(*gmtime(&calTime));
266 }
267 
268 void
269 MC146818::serialize(const string &base, CheckpointOut &cp) const
270 {
271  uint8_t regA_serial(stat_regA);
272  uint8_t regB_serial(stat_regB);
273 
274  arrayParamOut(cp, base + ".clock_data", clock_data, sizeof(clock_data));
275  paramOut(cp, base + ".stat_regA", (uint8_t)regA_serial);
276  paramOut(cp, base + ".stat_regB", (uint8_t)regB_serial);
277 
278  //
279  // save the timer tick and rtc clock tick values to correctly reschedule
280  // them during unserialize
281  //
282  Tick rtcTimerInterruptTickOffset = event.when() - curTick();
283  SERIALIZE_SCALAR(rtcTimerInterruptTickOffset);
284  Tick rtcClockTickOffset = tickEvent.when() - curTick();
285  SERIALIZE_SCALAR(rtcClockTickOffset);
286 }
287 
288 void
290 {
291  uint8_t tmp8;
292 
293  arrayParamIn(cp, base + ".clock_data", clock_data,
294  sizeof(clock_data));
295 
296  paramIn(cp, base + ".stat_regA", tmp8);
297  stat_regA = tmp8;
298  paramIn(cp, base + ".stat_regB", tmp8);
299  stat_regB = tmp8;
300 
301  //
302  // properly schedule the timer and rtc clock events
303  //
304  Tick rtcTimerInterruptTickOffset;
305  UNSERIALIZE_SCALAR(rtcTimerInterruptTickOffset);
306  event.offset = rtcTimerInterruptTickOffset;
307  Tick rtcClockTickOffset;
308  UNSERIALIZE_SCALAR(rtcClockTickOffset);
309  tickEvent.offset = rtcClockTickOffset;
310 }
311 
313  : parent(_parent), interval(i), offset(i)
314 {
315  DPRINTF(MC146818, "RTC Event Initilizing\n");
316 }
317 
318 void
320 {
321  parent->schedule(this, curTick() + interval);
322 }
323 
324 void
326 {
327  DPRINTF(MC146818, "RTC Timer Interrupt\n");
328  parent->schedule(this, curTick() + interval);
329  parent->handleEvent();
330 }
331 
332 const char *
334 {
335  return "RTC interrupt";
336 }
337 
338 void
340 {
341  DPRINTF(MC146818, "RTC clock tick\n");
342  parent->schedule(this, curTick() + SimClock::Int::s);
343  parent->tickClock();
344 }
345 
346 const char *
348 {
349  return "RTC clock tick";
350 }
#define DPRINTF(x,...)
Definition: trace.hh:212
void tickClock()
Definition: mc146818.cc:257
static uint8_t bcdize(uint8_t val)
Definition: mc146818.cc:49
Bitfield< 5, 3 > reg
Definition: types.hh:89
uint8_t readData(const uint8_t addr)
RTC read data.
Definition: mc146818.cc:232
Bitfield< 7 > i
Definition: miscregs.hh:1378
#define panic(...)
Definition: misc.hh:153
Real-Time Clock (MC146818)
Definition: mc146818.hh:41
uint8_t mon
Definition: mc146818.hh:109
void writeData(const uint8_t addr, const uint8_t data)
RTC write data.
Definition: mc146818.cc:139
MC146818(EventManager *em, const std::string &name, const struct tm time, bool bcd, Tick frequency)
Definition: mc146818.cc:94
ip6_addr_t addr
Definition: inet.hh:335
static const int RTC_STAT_REGA
Definition: rtcreg.h:44
static uint8_t unbcdize(uint8_t val)
Definition: mc146818.cc:58
bool scheduled() const
Determine if the current event is scheduled.
Definition: eventq.hh:381
Bitfield< 2 > em
Definition: misc.hh:603
uint8_t sec
Definition: mc146818.hh:101
const char * description() const
Event description.
Definition: mc146818.cc:347
Bitfield< 23, 0 > offset
Definition: types.hh:149
static const int RTC_STAT_REGC
Definition: rtcreg.h:57
#define DPRINTFN(...)
Definition: trace.hh:216
void serialize(const std::string &base, CheckpointOut &cp) const
Serialize this object to the given output stream.
Definition: mc146818.cc:269
void deschedule(Event &event)
Definition: eventq.hh:734
Bitfield< 63 > val
Definition: misc.hh:770
Bitfield< 31 > n
Definition: miscregs.hh:1636
const char data[]
Definition: circlebuf.cc:43
RtcRegB stat_regB
RTC status register B.
Definition: mc146818.hh:151
#define UNSERIALIZE_SCALAR(scalar)
Definition: serialize.hh:145
Tick curTick()
The current simulated tick.
Definition: core.hh:47
RTCEvent(MC146818 *_parent, Tick i)
Definition: mc146818.cc:312
RTCEvent event
RTC periodic interrupt event.
Definition: mc146818.hh:91
virtual void process()
Event process to occur at interrupt.
Definition: mc146818.cc:325
RTCTickEvent tickEvent
RTC tick event.
Definition: mc146818.hh:94
virtual ~MC146818()
Definition: mc146818.cc:113
Tick when() const
Get the time that the event is scheduled.
Definition: eventq.hh:397
uint64_t Tick
Tick count type.
Definition: types.hh:63
void scheduleIntr()
Schedule the RTC periodic interrupt.
Definition: mc146818.cc:319
uint8_t clock_data[10]
Definition: mc146818.hh:98
void paramOut(CheckpointOut &cp, const string &name, ExtMachInst const &machInst)
Definition: types.cc:40
uint8_t mday
Definition: mc146818.hh:108
Bitfield< 51, 12 > base
Definition: pagetable.hh:85
uint8_t wday
Definition: mc146818.hh:107
static const int RTC_STAT_REGB
Definition: rtcreg.h:55
static const int RTCA_RS_1024HZ
Definition: rtcreg.h:53
void arrayParamOut(CheckpointOut &cp, const std::string &name, const CircleBuf< T > &param)
Definition: circlebuf.hh:251
void setTime(const struct tm time)
Definition: mc146818.cc:67
virtual const char * description() const
Event description.
Definition: mc146818.cc:333
struct tm curTime
Definition: mc146818.hh:114
static const int RTCA_DV_DISABLED1
Definition: rtcreg.h:50
Bitfield< 10, 5 > event
#define SERIALIZE_SCALAR(scalar)
Definition: serialize.hh:143
Tick s
second
Definition: core.cc:63
std::ostream CheckpointOut
Definition: serialize.hh:67
time_t mkutctime(struct tm *time)
Definition: time.cc:152
virtual void startup()
Start ticking.
Definition: mc146818.cc:127
void unserialize(const std::string &base, CheckpointIn &cp)
Reconstruct the state of this object from a checkpoint.
Definition: mc146818.cc:289
static const int RTCA_DV_DISABLED0
Definition: rtcreg.h:49
void schedule(Event &event, Tick when)
Definition: eventq.hh:728
uint8_t hour
Definition: mc146818.hh:105
void paramIn(CheckpointIn &cp, const string &name, ExtMachInst &machInst)
Definition: types.cc:71
void arrayParamIn(CheckpointIn &cp, const std::string &name, CircleBuf< T > &param)
Definition: circlebuf.hh:261
static const int RTC_STAT_REGD
Definition: rtcreg.h:58
#define inform(...)
Definition: misc.hh:221
static const int RTCA_DV_32768HZ
Definition: rtcreg.h:48
void process()
Event process to occur at interrupt.
Definition: mc146818.cc:339
uint8_t min
Definition: mc146818.hh:103
uint8_t year
Definition: mc146818.hh:110

Generated on Fri Jun 9 2017 13:03:46 for gem5 by doxygen 1.8.6