gem5  v20.1.0.0
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 
29 #include "dev/mc146818.hh"
30 
31 #include <sys/time.h>
32 
33 #include <ctime>
34 #include <string>
35 
36 #include "base/bitfield.hh"
37 #include "base/time.hh"
38 #include "base/trace.hh"
39 #include "debug/MC146818.hh"
40 #include "dev/rtcreg.h"
41 
42 using namespace std;
43 
44 static uint8_t
45 bcdize(uint8_t val)
46 {
47  uint8_t result;
48  result = val % 10;
49  result += (val / 10) << 4;
50  return result;
51 }
52 
53 static uint8_t
54 unbcdize(uint8_t val)
55 {
56  uint8_t result;
57  result = val & 0xf;
58  result += (val >> 4) * 10;
59  return result;
60 }
61 
62 void
63 MC146818::setTime(const struct tm time)
64 {
65  curTime = time;
66  year = time.tm_year;
67  // Unix is 0-11 for month, data seet says start at 1
68  mon = time.tm_mon + 1;
69  mday = time.tm_mday;
70  hour = time.tm_hour;
71  min = time.tm_min;
72  sec = time.tm_sec;
73 
74  // Datasheet says 1 is sunday
75  wday = time.tm_wday + 1;
76 
77  if (!stat_regB.dm) {
78  // The datasheet says that the year field can be either BCD or
79  // years since 1900. Linux seems to be happy with years since
80  // 1900.
81  year = bcdize(year % 100);
82  mon = bcdize(mon);
83  mday = bcdize(mday);
84  hour = bcdize(hour);
85  min = bcdize(min);
86  sec = bcdize(sec);
87  }
88 }
89 
90 MC146818::MC146818(EventManager *em, const string &n, const struct tm time,
91  bool bcd, Tick frequency)
92  : EventManager(em), _name(n), event(this, frequency), tickEvent(this)
93 {
94  memset(clock_data, 0, sizeof(clock_data));
95 
96  stat_regA = 0;
97  stat_regA.dv = RTCA_DV_32768HZ;
98  stat_regA.rs = RTCA_RS_1024HZ;
99 
100  stat_regB = 0;
101  stat_regB.pie = 1;
102  stat_regB.format24h = 1;
103  stat_regB.dm = bcd ? 0 : 1;
104 
105  setTime(time);
106  DPRINTFN("Real-time clock set to %s", asctime(&time));
107 }
108 
110 {
112  deschedule(event);
113 }
114 
115 bool
116 MC146818::rega_dv_disabled(const RtcRegA &reg)
117 {
118  return reg.dv == RTCA_DV_DISABLED0 ||
119  reg.dv == RTCA_DV_DISABLED1;
120 }
121 
122 void
124 {
125  assert(!event.scheduled());
126  assert(!tickEvent.scheduled());
127 
128  if (stat_regB.pie)
130  if (!rega_dv_disabled(stat_regA))
132 }
133 
134 void
135 MC146818::writeData(const uint8_t addr, const uint8_t data)
136 {
137  bool panic_unsupported(false);
138 
139  if (addr < RTC_STAT_REGA) {
140  clock_data[addr] = data;
141  curTime.tm_sec = unbcdize(sec);
142  curTime.tm_min = unbcdize(min);
143  curTime.tm_hour = unbcdize(hour);
144  curTime.tm_mday = unbcdize(mday);
145  curTime.tm_mon = unbcdize(mon) - 1;
146  curTime.tm_year = ((unbcdize(year) + 50) % 100) + 1950;
147  curTime.tm_wday = unbcdize(wday) - 1;
148  } else {
149  switch (addr) {
150  case RTC_STAT_REGA: {
151  RtcRegA old_rega(stat_regA);
152  stat_regA = data;
153  // The "update in progress" bit is read only.
154  stat_regA.uip = old_rega;
155 
156  if (!rega_dv_disabled(stat_regA) &&
157  stat_regA.dv != RTCA_DV_32768HZ) {
158  inform("RTC: Unimplemented divider configuration: %i\n",
159  stat_regA.dv);
160  panic_unsupported = true;
161  }
162 
163  if (stat_regA.rs != RTCA_RS_1024HZ) {
164  inform("RTC: Unimplemented interrupt rate: %i\n",
165  stat_regA.rs);
166  panic_unsupported = true;
167  }
168 
169  if (rega_dv_disabled(stat_regA)) {
170  // The divider is disabled, make sure that we don't
171  // schedule any ticks.
172  if (tickEvent.scheduled())
174  } else if (rega_dv_disabled(old_rega)) {
175  // According to the specification, the next tick
176  // happens after 0.5s when the divider chain goes
177  // from reset to active. So, we simply schedule the
178  // tick after 0.5s.
179  assert(!tickEvent.scheduled());
181  }
182  } break;
183  case RTC_STAT_REGB:
184  stat_regB = data;
185  if (stat_regB.aie || stat_regB.uie) {
186  inform("RTC: Unimplemented interrupt configuration: %s %s\n",
187  stat_regB.aie ? "alarm" : "",
188  stat_regB.uie ? "update" : "");
189  panic_unsupported = true;
190  }
191 
192  if (stat_regB.dm) {
193  inform("RTC: The binary interface is not fully implemented.\n");
194  panic_unsupported = true;
195  }
196 
197  if (!stat_regB.format24h) {
198  inform("RTC: The 12h time format not supported.\n");
199  panic_unsupported = true;
200  }
201 
202  if (stat_regB.dse) {
203  inform("RTC: Automatic daylight saving time not supported.\n");
204  panic_unsupported = true;
205  }
206 
207  if (stat_regB.pie) {
208  if (!event.scheduled())
209  event.scheduleIntr();
210  } else {
211  if (event.scheduled())
212  deschedule(event);
213  }
214  break;
215  case RTC_STAT_REGC:
216  case RTC_STAT_REGD:
217  panic("RTC status registers C and D are not implemented.\n");
218  break;
219  }
220  }
221 
222  if (panic_unsupported)
223  panic("Unimplemented RTC configuration!\n");
224 
225 }
226 
227 uint8_t
229 {
230  if (addr < RTC_STAT_REGA)
231  return clock_data[addr];
232  else {
233  switch (addr) {
234  case RTC_STAT_REGA:
235  // toggle UIP bit for linux
236  stat_regA.uip = !stat_regA.uip;
237  return stat_regA;
238  break;
239  case RTC_STAT_REGB:
240  return stat_regB;
241  break;
242  case RTC_STAT_REGC:
243  case RTC_STAT_REGD:
244  return 0x00;
245  break;
246  default:
247  panic("Shouldn't be here");
248  }
249  }
250 }
251 
252 void
254 {
255  assert(!rega_dv_disabled(stat_regA));
256 
257  if (stat_regB.set)
258  return;
259  time_t calTime = mkutctime(&curTime);
260  calTime++;
261  setTime(*gmtime(&calTime));
262 }
263 
264 void
265 MC146818::serialize(const string &base, CheckpointOut &cp) const
266 {
267  uint8_t regA_serial(stat_regA);
268  uint8_t regB_serial(stat_regB);
269 
270  arrayParamOut(cp, base + ".clock_data", clock_data, sizeof(clock_data));
271  paramOut(cp, base + ".stat_regA", (uint8_t)regA_serial);
272  paramOut(cp, base + ".stat_regB", (uint8_t)regB_serial);
273 
274  //
275  // save the timer tick and rtc clock tick values to correctly reschedule
276  // them during unserialize
277  //
278  Tick rtcTimerInterruptTickOffset = event.when() - curTick();
279  SERIALIZE_SCALAR(rtcTimerInterruptTickOffset);
280  Tick rtcClockTickOffset = tickEvent.when() - curTick();
281  SERIALIZE_SCALAR(rtcClockTickOffset);
282 }
283 
284 void
286 {
287  uint8_t tmp8;
288 
289  arrayParamIn(cp, base + ".clock_data", clock_data,
290  sizeof(clock_data));
291 
292  paramIn(cp, base + ".stat_regA", tmp8);
293  stat_regA = tmp8;
294  paramIn(cp, base + ".stat_regB", tmp8);
295  stat_regB = tmp8;
296 
297  //
298  // properly schedule the timer and rtc clock events
299  //
300  Tick rtcTimerInterruptTickOffset;
301  UNSERIALIZE_SCALAR(rtcTimerInterruptTickOffset);
302  event.offset = rtcTimerInterruptTickOffset;
303  Tick rtcClockTickOffset;
304  UNSERIALIZE_SCALAR(rtcClockTickOffset);
305  tickEvent.offset = rtcClockTickOffset;
306 }
307 
309  : parent(_parent), interval(i), offset(i)
310 {
311  DPRINTF(MC146818, "RTC Event Initilizing\n");
312 }
313 
314 void
316 {
317  parent->schedule(this, curTick() + interval);
318 }
319 
320 void
322 {
323  DPRINTF(MC146818, "RTC Timer Interrupt\n");
324  parent->schedule(this, curTick() + interval);
325  parent->handleEvent();
326 }
327 
328 const char *
330 {
331  return "RTC interrupt";
332 }
333 
334 void
336 {
337  DPRINTF(MC146818, "RTC clock tick\n");
338  parent->schedule(this, curTick() + SimClock::Int::s);
339  parent->tickClock();
340 }
341 
342 const char *
344 {
345  return "RTC clock tick";
346 }
unbcdize
static uint8_t unbcdize(uint8_t val)
Definition: mc146818.cc:54
RTC_STAT_REGA
static const int RTC_STAT_REGA
Definition: rtcreg.h:40
Event::scheduled
bool scheduled() const
Determine if the current event is scheduled.
Definition: eventq.hh:460
MC146818::year
uint8_t year
Definition: mc146818.hh:107
MC146818::unserialize
void unserialize(const std::string &base, CheckpointIn &cp)
Reconstruct the state of this object from a checkpoint.
Definition: mc146818.cc:285
RTC_STAT_REGD
static const int RTC_STAT_REGD
Definition: rtcreg.h:54
data
const char data[]
Definition: circlebuf.test.cc:42
UNSERIALIZE_SCALAR
#define UNSERIALIZE_SCALAR(scalar)
Definition: serialize.hh:797
ArmISA::i
Bitfield< 7 > i
Definition: miscregs_types.hh:63
MC146818::RTCEvent::scheduleIntr
void scheduleIntr()
Schedule the RTC periodic interrupt.
Definition: mc146818.cc:315
mkutctime
time_t mkutctime(struct tm *time)
Definition: time.cc:153
time.hh
MC146818::RTCTickEvent::description
const char * description() const
Event description.
Definition: mc146818.cc:343
Tick
uint64_t Tick
Tick count type.
Definition: types.hh:63
X86ISA::base
Bitfield< 51, 12 > base
Definition: pagetable.hh:141
EventManager::deschedule
void deschedule(Event &event)
Definition: eventq.hh:1014
MC146818::stat_regB
RtcRegB stat_regB
RTC status register B.
Definition: mc146818.hh:148
MC146818::tickEvent
RTCTickEvent tickEvent
RTC tick event.
Definition: mc146818.hh:91
MC146818::hour
uint8_t hour
Definition: mc146818.hh:102
RTC_STAT_REGB
static const int RTC_STAT_REGB
Definition: rtcreg.h:51
Event::when
Tick when() const
Get the time that the event is scheduled.
Definition: eventq.hh:503
X86ISA::reg
Bitfield< 5, 3 > reg
Definition: types.hh:87
MC146818::wday
uint8_t wday
Definition: mc146818.hh:104
paramOut
void paramOut(CheckpointOut &cp, const string &name, ExtMachInst const &machInst)
Definition: types.cc:38
RTCA_DV_DISABLED1
static const int RTCA_DV_DISABLED1
Definition: rtcreg.h:46
MC146818::serialize
void serialize(const std::string &base, CheckpointOut &cp) const
Serialize this object to the given output stream.
Definition: mc146818.cc:265
ArmISA::n
Bitfield< 31 > n
Definition: miscregs_types.hh:450
MC146818::mon
uint8_t mon
Definition: mc146818.hh:106
MC146818::mday
uint8_t mday
Definition: mc146818.hh:105
MC146818::tickClock
void tickClock()
Definition: mc146818.cc:253
cp
Definition: cprintf.cc:40
EventManager::schedule
void schedule(Event &event, Tick when)
Definition: eventq.hh:1005
bitfield.hh
MC146818::readData
uint8_t readData(const uint8_t addr)
RTC read data.
Definition: mc146818.cc:228
DPRINTF
#define DPRINTF(x,...)
Definition: trace.hh:234
MipsISA::event
Bitfield< 10, 5 > event
Definition: pra_constants.hh:297
RTCA_DV_DISABLED0
static const int RTCA_DV_DISABLED0
Definition: rtcreg.h:45
SimClock::Int::s
Tick s
second
Definition: core.cc:62
X86ISA::em
Bitfield< 2 > em
Definition: misc.hh:602
MC146818::RTCEvent::RTCEvent
RTCEvent(MC146818 *_parent, Tick i)
Definition: mc146818.cc:308
MC146818::RTCEvent::process
virtual void process()
Event process to occur at interrupt.
Definition: mc146818.cc:321
MC146818
Real-Time Clock (MC146818)
Definition: mc146818.hh:38
MC146818::RTCEvent::description
virtual const char * description() const
Event description.
Definition: mc146818.cc:329
X86ISA::val
Bitfield< 63 > val
Definition: misc.hh:769
MC146818::RTCTickEvent::process
void process()
Event process to occur at interrupt.
Definition: mc146818.cc:335
arrayParamOut
void arrayParamOut(CheckpointOut &cp, const std::string &name, const CircleBuf< T > &param)
Definition: circlebuf.hh:174
SERIALIZE_SCALAR
#define SERIALIZE_SCALAR(scalar)
Definition: serialize.hh:790
bcdize
static uint8_t bcdize(uint8_t val)
Definition: mc146818.cc:45
MC146818::curTime
struct tm curTime
Definition: mc146818.hh:111
RTCA_DV_32768HZ
static const int RTCA_DV_32768HZ
Definition: rtcreg.h:44
MC146818::RTCTickEvent::offset
Tick offset
Definition: mc146818.hh:70
MC146818::RTCEvent::offset
Tick offset
Definition: mc146818.hh:52
RTCA_RS_1024HZ
static const int RTCA_RS_1024HZ
Definition: rtcreg.h:49
inform
#define inform(...)
Definition: logging.hh:240
MC146818::writeData
void writeData(const uint8_t addr, const uint8_t data)
RTC write data.
Definition: mc146818.cc:135
std
Overload hash function for BasicBlockRange type.
Definition: vec_reg.hh:587
RTC_STAT_REGC
static const int RTC_STAT_REGC
Definition: rtcreg.h:53
MC146818::MC146818
MC146818(EventManager *em, const std::string &name, const struct tm time, bool bcd, Tick frequency)
Definition: mc146818.cc:90
MC146818::~MC146818
virtual ~MC146818()
Definition: mc146818.cc:109
addr
ip6_addr_t addr
Definition: inet.hh:423
paramIn
void paramIn(CheckpointIn &cp, const string &name, ExtMachInst &machInst)
Definition: types.cc:69
CheckpointOut
std::ostream CheckpointOut
Definition: serialize.hh:63
arrayParamIn
void arrayParamIn(CheckpointIn &cp, const std::string &name, CircleBuf< T > &param)
Definition: circlebuf.hh:184
MC146818::clock_data
uint8_t clock_data[10]
Definition: mc146818.hh:95
rtcreg.h
EventManager
Definition: eventq.hh:973
MC146818::min
uint8_t min
Definition: mc146818.hh:100
trace.hh
DPRINTFN
#define DPRINTFN(...)
Definition: trace.hh:238
MC146818::setTime
void setTime(const struct tm time)
Definition: mc146818.cc:63
CheckpointIn
Definition: serialize.hh:67
MC146818::event
RTCEvent event
RTC periodic interrupt event.
Definition: mc146818.hh:88
MC146818::sec
uint8_t sec
Definition: mc146818.hh:98
panic
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:171
mc146818.hh
curTick
Tick curTick()
The current simulated tick.
Definition: core.hh:45
ArmISA::offset
Bitfield< 23, 0 > offset
Definition: types.hh:153
MC146818::startup
virtual void startup()
Start ticking.
Definition: mc146818.cc:123

Generated on Wed Sep 30 2020 14:02:11 for gem5 by doxygen 1.8.17