mc146818.cc revision 5813
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 <sys/time.h> 34#include <time.h> 35 36#include <string> 37 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" 43 44using namespace std; 45 46MC146818::MC146818(EventManager *em, const string &n, const struct tm time, 47 bool bcd, Tick frequency) 48 : EventManager(em), _name(n), event(this, frequency) 49{ 50 memset(clock_data, 0, sizeof(clock_data)); 51 stat_regA = RTCA_32768HZ | RTCA_1024HZ; 52 stat_regB = RTCB_PRDC_IE |RTCB_BIN | RTCB_24HR; 53 54 year = time.tm_year; 55 56 if (bcd) { 57 // The datasheet says that the year field can be either BCD or 58 // years since 1900. Linux seems to be happy with years since 59 // 1900. 60 year = year % 100; 61 int tens = year / 10; 62 int ones = year % 10; 63 year = (tens << 4) + ones; 64 } 65 66 // Unix is 0-11 for month, data seet says start at 1 67 mon = time.tm_mon + 1; 68 mday = time.tm_mday; 69 hour = time.tm_hour; 70 min = time.tm_min; 71 sec = time.tm_sec; 72 73 // Datasheet says 1 is sunday 74 wday = time.tm_wday + 1; 75 76 DPRINTFN("Real-time clock set to %s", asctime(&time)); 77} 78 79MC146818::~MC146818() 80{ 81} 82 83void 84MC146818::writeData(const uint8_t addr, const uint8_t data) 85{ 86 if (addr < RTC_STAT_REGA) 87 clock_data[addr] = data; 88 else { 89 switch (addr) { 90 case RTC_STAT_REGA: 91 // The "update in progress" bit is read only. 92 if ((data & ~RTCA_UIP) != (RTCA_32768HZ | RTCA_1024HZ)) 93 panic("Unimplemented RTC register A value write!\n"); 94 replaceBits(stat_regA, data, 6, 0); 95 break; 96 case RTC_STAT_REGB: 97 if ((data & ~(RTCB_PRDC_IE | RTCB_SQWE)) != (RTCB_BIN | RTCB_24HR)) 98 panic("Write to RTC reg B bits that are not implemented!\n"); 99 100 if (data & RTCB_PRDC_IE) { 101 if (!event.scheduled()) 102 event.scheduleIntr(); 103 } else { 104 if (event.scheduled()) 105 deschedule(event); 106 } 107 stat_regB = data; 108 break; 109 case RTC_STAT_REGC: 110 case RTC_STAT_REGD: 111 panic("RTC status registers C and D are not implemented.\n"); 112 break; 113 } 114 } 115} 116 117uint8_t 118MC146818::readData(uint8_t addr) 119{ 120 if (addr < RTC_STAT_REGA) 121 return clock_data[addr]; 122 else { 123 switch (addr) { 124 case RTC_STAT_REGA: 125 // toggle UIP bit for linux 126 stat_regA ^= RTCA_UIP; 127 return stat_regA; 128 break; 129 case RTC_STAT_REGB: 130 return stat_regB; 131 break; 132 case RTC_STAT_REGC: 133 case RTC_STAT_REGD: 134 return 0x00; 135 break; 136 default: 137 panic("Shouldn't be here"); 138 } 139 } 140} 141 142void 143MC146818::serialize(const string &base, ostream &os) 144{ 145 arrayParamOut(os, base + ".clock_data", clock_data, sizeof(clock_data)); 146 paramOut(os, base + ".stat_regA", stat_regA); 147 paramOut(os, base + ".stat_regB", stat_regB); 148} 149 150void 151MC146818::unserialize(const string &base, Checkpoint *cp, 152 const string §ion) 153{ 154 arrayParamIn(cp, section, base + ".clock_data", clock_data, 155 sizeof(clock_data)); 156 paramIn(cp, section, base + ".stat_regA", stat_regA); 157 paramIn(cp, section, base + ".stat_regB", stat_regB); 158 159 // We're not unserializing the event here, but we need to 160 // rescehedule the event since curTick was moved forward by the 161 // checkpoint 162 reschedule(event, curTick + event.interval); 163} 164 165MC146818::RTCEvent::RTCEvent(MC146818 * _parent, Tick i) 166 : parent(_parent), interval(i) 167{ 168 DPRINTF(MC146818, "RTC Event Initilizing\n"); 169 parent->schedule(this, curTick + interval); 170} 171 172void 173MC146818::RTCEvent::scheduleIntr() 174{ 175 parent->schedule(this, curTick + interval); 176} 177 178void 179MC146818::RTCEvent::process() 180{ 181 DPRINTF(MC146818, "RTC Timer Interrupt\n"); 182 parent->schedule(this, curTick + interval); 183 parent->handleEvent(); 184} 185 186const char * 187MC146818::RTCEvent::description() const 188{ 189 return "RTC interrupt"; 190} 191