2 * Copyright (c) 2004-2005 The Regents of The University of Michigan
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.
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.
38 #include "base/bitfield.hh"
39 #include "base/time.hh"
40 #include "base/trace.hh"
41 #include "dev/mc146818.hh"
42 #include "dev/rtcreg.h"
51 result
+= (val
/ 10) << 4;
60 result
+= (val
>> 4) * 10;
65 MC146818::setTime(const struct tm time
)
69 // Unix is 0-11 for month, data seet says start at 1
70 mon
= time
.tm_mon
+ 1;
76 // Datasheet says 1 is sunday
77 wday
= time
.tm_wday
+ 1;
79 if (!(stat_regB
& RTCB_BIN
)) {
80 // The datasheet says that the year field can be either BCD or
81 // years since 1900. Linux seems to be happy with years since
83 year
= bcdize(year
% 100);
92 MC146818::MC146818(EventManager
*em
, const string
&n
, const struct tm time
,
93 bool bcd
, Tick frequency
)
94 : EventManager(em
), _name(n
), event(this, frequency
), tickEvent(this)
96 memset(clock_data
, 0, sizeof(clock_data
));
97 stat_regA
= RTCA_32768HZ
| RTCA_1024HZ
;
98 stat_regB
= RTCB_PRDC_IE
| RTCB_24HR
;
100 stat_regB
|= RTCB_BIN
;
103 DPRINTFN("Real-time clock set to %s", asctime(&time
));
106 MC146818::~MC146818()
108 deschedule(tickEvent
);
113 MC146818::writeData(const uint8_t addr
, const uint8_t data
)
115 if (addr
< RTC_STAT_REGA
) {
116 clock_data
[addr
] = data
;
117 curTime
.tm_sec
= unbcdize(sec
);
118 curTime
.tm_min
= unbcdize(min
);
119 curTime
.tm_hour
= unbcdize(hour
);
120 curTime
.tm_mday
= unbcdize(mday
);
121 curTime
.tm_mon
= unbcdize(mon
) - 1;
122 curTime
.tm_year
= ((unbcdize(year
) + 50) % 100) + 1950;
123 curTime
.tm_wday
= unbcdize(wday
) - 1;
127 // The "update in progress" bit is read only.
128 if ((data
& ~RTCA_UIP
) != (RTCA_32768HZ
| RTCA_1024HZ
))
129 panic("Unimplemented RTC register A value write!\n");
130 replaceBits(stat_regA
, data
, 6, 0);
133 if ((data
& ~(RTCB_PRDC_IE
| RTCB_SQWE
)) != RTCB_24HR
)
134 panic("Write to RTC reg B bits that are not implemented!\n");
136 if (data
& RTCB_PRDC_IE
) {
137 if (!event
.scheduled())
138 event
.scheduleIntr();
140 if (event
.scheduled())
147 panic("RTC status registers C and D are not implemented.\n");
154 MC146818::readData(uint8_t addr
)
156 if (addr
< RTC_STAT_REGA
)
157 return clock_data
[addr
];
161 // toggle UIP bit for linux
162 stat_regA
^= RTCA_UIP
;
173 panic("Shouldn't be here");
179 mkutctime(struct tm
*time
)
197 MC146818::tickClock()
199 if (stat_regB
& RTCB_NO_UPDT
)
201 time_t calTime
= mkutctime(&curTime
);
203 setTime(*gmtime(&calTime
));
207 MC146818::serialize(const string
&base
, ostream
&os
)
209 arrayParamOut(os
, base
+ ".clock_data", clock_data
, sizeof(clock_data
));
210 paramOut(os
, base
+ ".stat_regA", stat_regA
);
211 paramOut(os
, base
+ ".stat_regB", stat_regB
);
214 // save the timer tick and rtc clock tick values to correctly reschedule
215 // them during unserialize
217 Tick rtcTimerInterruptTickOffset
= event
.when() - curTick();
218 SERIALIZE_SCALAR(rtcTimerInterruptTickOffset
);
219 Tick rtcClockTickOffset
= event
.when() - curTick();
220 SERIALIZE_SCALAR(rtcClockTickOffset
);
224 MC146818::unserialize(const string
&base
, Checkpoint
*cp
,
225 const string
§ion
)
227 arrayParamIn(cp
, section
, base
+ ".clock_data", clock_data
,
229 paramIn(cp
, section
, base
+ ".stat_regA", stat_regA
);
230 paramIn(cp
, section
, base
+ ".stat_regB", stat_regB
);
233 // properly schedule the timer and rtc clock events
235 Tick rtcTimerInterruptTickOffset
;
236 UNSERIALIZE_SCALAR(rtcTimerInterruptTickOffset
);
237 reschedule(event
, curTick() + rtcTimerInterruptTickOffset
);
238 Tick rtcClockTickOffset
;
239 UNSERIALIZE_SCALAR(rtcClockTickOffset
);
240 reschedule(tickEvent
, curTick() + rtcClockTickOffset
);
243 MC146818::RTCEvent::RTCEvent(MC146818
* _parent
, Tick i
)
244 : parent(_parent
), interval(i
)
246 DPRINTF(MC146818
, "RTC Event Initilizing\n");
247 parent
->schedule(this, curTick() + interval
);
251 MC146818::RTCEvent::scheduleIntr()
253 parent
->schedule(this, curTick() + interval
);
257 MC146818::RTCEvent::process()
259 DPRINTF(MC146818
, "RTC Timer Interrupt\n");
260 parent
->schedule(this, curTick() + interval
);
261 parent
->handleEvent();
265 MC146818::RTCEvent::description() const
267 return "RTC interrupt";
271 MC146818::RTCTickEvent::process()
273 DPRINTF(MC146818
, "RTC clock tick\n");
274 parent
->schedule(this, curTick() + SimClock::Int::s
);
279 MC146818::RTCTickEvent::description() const
281 return "RTC clock tick";