1 /* DS1287-based DEC 5000/200 Real-Time Clock emulation.
2 Copyright 2003 Brian R. Gaeke.
3
4 This file is part of VMIPS.
5
6 VMIPS is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2 of the License, or (at your
9 option) any later version.
10
11 VMIPS is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 for more details.
15
16 You should have received a copy of the GNU General Public License along
17 with VMIPS; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
19
20 /* Dallas Semiconductor DS1287 real-time clock chip, as implemented
21 * as a memory-mapped device in the DEC 5000/200 (KN02).
22 */
23
24 #include "devicemap.h"
25 #include "clock.h"
26 #include "decrtcreg.h"
27 #include "decrtc.h"
28 #include "mapper.h"
29 #include "vmips.h"
30 #include <cstdio>
31 #include <cassert>
32
33 static const uint32 int_freqs [16] = {
34 0, 3906250, 7812500, 122070, 244141, 488281, 976562, 1953125,
35 3906250, 7812500, 15625000, 31250000, 62500000, 125000000,
36 250000000, 500000000
37 };
38
39 #if defined(RTC_DEBUG)
40 static const char *reg_names [15] = {
41 "RTC_SEC", "RTC_ALMS", "RTC_MIN", "RTC_ALMM", "RTC_HOUR",
42 "RTC_ALMH", "RTC_DOW", "RTC_DAY", "RTC_MON", "RTC_YEAR",
43 "RTC_REGA", "RTC_REGB", "RTC_REGC", "RTC_REGD", "RTC_RAM"
44 };
45 #endif
46
DECRTCDevice(Clock * _clock,uint32 _irq)47 DECRTCDevice::DECRTCDevice (Clock *_clock, uint32 _irq) :
48 clock(_clock), frequency_ns (0), irq (_irq), interrupt_enable (false)
49 {
50 extent = 0x80000;
51 // Initialize registers
52 for (int i = 0; i < 64; ++i) {
53 rtc_reg[i] = 0x00;
54 }
55 rtc_reg[RTC_REGA] = 0x20; // Timebase divisor = 010 (32.768 kHz)
56 // Set up write masks
57 for (int i = 0; i < 64; ++i) {
58 write_masks[i] = 0xff;
59 }
60 write_masks[RTC_REGA] = 0x7f;
61 write_masks[RTC_REGB] = 0xd7;
62 write_masks[RTC_REGC] = 0x00;
63 write_masks[RTC_REGD] = 0x00;
64 }
65
66 const struct tm *
get_host_time() const67 DECRTCDevice::get_host_time () const {
68 time_t real_time = clock->get_time().tv_sec;
69 return gmtime(&real_time);
70 }
71
72 uint32
fetch_word(uint32 offset,int mode,DeviceExc * client)73 DECRTCDevice::fetch_word(uint32 offset, int mode, DeviceExc *client)
74 {
75 uint32 reg_no = (offset / 4);
76 uint32 rv = 0;
77 #if defined(RTC_DEBUG)
78 fprintf(stderr, "RTC fetch word, offset=0x%x\n", offset);
79 #endif
80 if (reg_no == RTC_REGA) {
81 // Fake "update in progress" once a second
82 time_t real_nanos = clock->get_time().tv_nsec;
83 if ((real_nanos + ((244 + 1948)*1000)) > 1000000000) {
84 rtc_reg[RTC_REGA] |= REGA_UIP;
85 } else {
86 rtc_reg[RTC_REGA] &= ~REGA_UIP;
87 }
88 }
89 if (reg_no < 10)
90 update_host_time ();
91 if (reg_no < 64)
92 rv = rtc_reg[reg_no];
93 if (reg_no == RTC_REGC) {
94 #if defined(RTC_DEBUG)
95 fprintf(stderr, "RTC read REGC -- deassert IRQ\n");
96 #endif
97 unready_clock ();
98 }
99
100 return machine->physmem->mips_to_host_word(rv);
101 }
102
103 void
update_host_time()104 DECRTCDevice::update_host_time ()
105 {
106 const struct tm *host_time = get_host_time ();
107 rtc_reg[RTC_SEC] = host_time->tm_sec; /* second 0..59 */
108 rtc_reg[RTC_MIN] = host_time->tm_min; /* minute 0..59 */
109 rtc_reg[RTC_HOUR] = host_time->tm_hour; /* hour 0..23 */
110 rtc_reg[RTC_DOW] = 1 + host_time->tm_wday; /* day of week 1..7 */
111 rtc_reg[RTC_MON] = 1 + host_time->tm_mon; /* month 1..12 */
112 rtc_reg[RTC_YEAR] = host_time->tm_year % 100; /* year 0..99 */
113 }
114
115 void
store_word(uint32 offset,uint32 data,DeviceExc * client)116 DECRTCDevice::store_word(uint32 offset, uint32 data, DeviceExc *client)
117 {
118 data = machine->physmem->host_to_mips_word(data);
119
120 bool old_interrupt_enable = rtc_reg[RTC_REGB] & REGB_PIE;
121 uint32 reg_no = (offset / 4);
122 #if defined(RTC_DEBUG)
123 fprintf (stderr, "RTC %s (%u) written with 0x%x\n",
124 reg_names[(reg_no > 14) ? 14 : reg_no], reg_no, data);
125 #endif
126 if (reg_no < 64)
127 rtc_reg[reg_no] = (rtc_reg[reg_no] & ~write_masks[reg_no])
128 | (((uint8) data) & write_masks[reg_no]);
129 if (reg_no == RTC_REGA) {
130 /* Maybe they changed the interrupt rate selector. */
131 uint8 rate_selector = rtc_reg[RTC_REGA] & REGA_RSX;
132 #if defined(RTC_DEBUG)
133 fprintf (stderr, "RTC rate_selector set to 0x%x (%u)\n", rate_selector,
134 int_freqs[rate_selector]);
135 #endif
136 frequency_ns = int_freqs[rate_selector];
137 } else if (reg_no == RTC_REGB) {
138 /* Maybe they enabled or disabled interrupts. */
139 bool new_interrupt_enable = rtc_reg[RTC_REGB] & REGB_PIE;
140 #if defined(RTC_DEBUG)
141 fprintf (stderr, "RTC interrupt_enable set to %d\n", new_interrupt_enable);
142 #endif
143 if ((!old_interrupt_enable) && new_interrupt_enable) {
144 #if defined(RTC_DEBUG)
145 fprintf (stderr, "RTC turning interrupts on\n");
146 #endif
147 ready_clock ();
148 } else if (old_interrupt_enable && (!new_interrupt_enable)) {
149 #if defined(RTC_DEBUG)
150 fprintf (stderr, "RTC turning interrupts off\n");
151 #endif
152 unready_clock ();
153 }
154 interrupt_enable = new_interrupt_enable;
155 }
156 }
157
158 void
ready_clock()159 DECRTCDevice::ready_clock ()
160 {
161 if (interrupt_enable) {
162 #if defined(RTC_DEBUG)
163 static unsigned long counter = 0;
164 counter++;
165 if ((counter % 50000) == 0)
166 fprintf (stderr, "RTC counted %lu interrupts\n", counter);
167 #endif
168 assertInt (irq);
169 }
170
171 if (frequency_ns > 0) {
172 clock_trigger = new ClockTrigger (this);
173 clock->add_deferred_task (clock_trigger, frequency_ns);
174 } else {
175 clock_trigger = NULL;
176 }
177 }
178
179 void
unready_clock()180 DECRTCDevice::unready_clock ()
181 {
182 deassertInt (irq);
183 }
184
~DECRTCDevice()185 DECRTCDevice::~DECRTCDevice ()
186 {
187 if (clock_trigger) {
188 clock_trigger->cancel ();
189 //delete clock_trigger;
190 // If the clock_trigger exists, it will have been added to
191 // a DeferredTasks list, and so the destruction of the
192 // Clock will cause it to be deleted.
193 // So don't delete it here; otherwise, we risk a crash
194 // due to double deletion.
195 }
196 }
197
ClockTrigger(DECRTCDevice * clock_device)198 DECRTCDevice::ClockTrigger::ClockTrigger (DECRTCDevice *clock_device)
199 : rtc (clock_device)
200 {
201 assert (rtc);
202 }
203
~ClockTrigger()204 DECRTCDevice::ClockTrigger::~ClockTrigger ()
205 {
206 }
207
208 void
real_task()209 DECRTCDevice::ClockTrigger::real_task ()
210 {
211 rtc->ready_clock ();
212 }
213