1 // license:BSD-3-Clause
2 // copyright-holders:Curt Coder
3 /**********************************************************************
4
5 Ricoh RP5C01(A) Real Time Clock With Internal RAM emulation
6
7 *********************************************************************/
8
9 /*
10
11 TODO:
12
13 - 12 hour clock
14 - test register
15 - timer reset
16
17 */
18
19 #include "emu.h"
20 #include "rp5c01.h"
21
22
23 // device type definitions
24 DEFINE_DEVICE_TYPE(RP5C01, rp5c01_device, "rp5c01", "Ricoh RP5C01 RTC")
25 DEFINE_DEVICE_TYPE(TC8521, tc8521_device, "tc8521", "Toshiba TC8521 RTC")
26
27
28 //**************************************************************************
29 // MACROS / CONSTANTS
30 //**************************************************************************
31
32 #define LOG 0
33
34
35 #define RAM_SIZE 13
36
37
38 // registers
39 enum
40 {
41 REGISTER_1_SECOND = 0,
42 REGISTER_10_SECOND,
43 REGISTER_1_MINUTE,
44 REGISTER_10_MINUTE,
45 REGISTER_1_HOUR,
46 REGISTER_10_HOUR,
47 REGISTER_DAY_OF_THE_WEEK,
48 REGISTER_1_DAY,
49 REGISTER_10_DAY,
50 REGISTER_1_MONTH,
51 REGISTER_10_MONTH, REGISTER_12_24_SELECT = REGISTER_10_MONTH,
52 REGISTER_1_YEAR, REGISTER_LEAP_YEAR = REGISTER_1_YEAR,
53 REGISTER_10_YEAR,
54 REGISTER_MODE,
55 REGISTER_TEST,
56 REGISTER_RESET
57 };
58
59
60 // register write mask
61 static const int register_write_mask[2][16] =
62 {
63 { 0xf, 0x7, 0xf, 0x7, 0xf, 0x3, 0x7, 0xf, 0x3, 0xf, 0x1, 0xf, 0xf, 0xf, 0xf, 0xf },
64 { 0x0, 0x0, 0xf, 0x7, 0xf, 0x3, 0x7, 0xf, 0x3, 0x0, 0x1, 0x3, 0x0, 0xf, 0xf, 0xf }
65 };
66
67
68 // modes
69 enum
70 {
71 MODE00 = 0,
72 MODE01,
73 BLOCK10,
74 BLOCK11
75 };
76
77
78 // mode register
79 #define MODE_MASK 0x03
80 #define MODE_ALARM_EN 0x04
81 #define MODE_TIMER_EN 0x08
82
83
84 // test register
85 #define TEST_0 0x01
86 #define TEST_1 0x02
87 #define TEST_2 0x04
88 #define TEST_3 0x08
89
90
91 // reset register
92 #define RESET_ALARM 0x01
93 #define RESET_TIMER 0x02
94 #define RESET_16_HZ 0x04
95 #define RESET_1_HZ 0x08
96
97
98
99 //**************************************************************************
100 // INLINE HELPERS
101 //**************************************************************************
102
103 //-------------------------------------------------
104 // set_alarm_line -
105 //-------------------------------------------------
106
set_alarm_line()107 inline void rp5c01_device::set_alarm_line()
108 {
109 int alarm = ((m_mode & MODE_ALARM_EN) ? m_alarm_on : 1) &
110 ((m_reset & RESET_16_HZ) ? 1 : m_16hz) &
111 ((m_reset & RESET_1_HZ) ? 1 : m_1hz);
112
113 if (m_alarm != alarm)
114 {
115 if (LOG) logerror("RP5C01 '%s' Alarm %u\n", tag(), alarm);
116
117 m_out_alarm_cb(alarm);
118 m_alarm = alarm;
119 }
120 }
121
122
123 //-------------------------------------------------
124 // read_counter -
125 //-------------------------------------------------
126
read_counter(int counter)127 inline int rp5c01_device::read_counter(int counter)
128 {
129 return (m_reg[MODE00][counter + 1] * 10) + m_reg[MODE00][counter];
130 }
131
132
133 //-------------------------------------------------
134 // write_counter -
135 //-------------------------------------------------
136
write_counter(int counter,int value)137 inline void rp5c01_device::write_counter(int counter, int value)
138 {
139 m_reg[MODE00][counter] = value % 10;
140 m_reg[MODE00][counter + 1] = value / 10;
141 }
142
143
144 //-------------------------------------------------
145 // check_alarm -
146 //-------------------------------------------------
147
check_alarm()148 inline void rp5c01_device::check_alarm()
149 {
150 bool all_match = true;
151 bool all_zeroes = true;
152
153 for (int i = REGISTER_1_MINUTE; i < REGISTER_1_MONTH; i++)
154 {
155 if (m_reg[MODE01][i] != 0) all_zeroes = false;
156 if (m_reg[MODE01][i] != m_reg[MODE00][i]) all_match = false;
157 }
158
159 m_alarm_on = (all_match || (!m_alarm_on && all_zeroes)) ? 0 : 1;
160 }
161
162
163
164 //**************************************************************************
165 // LIVE DEVICE
166 //**************************************************************************
167
168 //-------------------------------------------------
169 // rp5c01_device - constructor
170 //-------------------------------------------------
171
rp5c01_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)172 rp5c01_device::rp5c01_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
173 : rp5c01_device(mconfig, RP5C01, tag, owner, clock)
174 {
175 }
176
rp5c01_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,uint32_t clock)177 rp5c01_device::rp5c01_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
178 : device_t(mconfig, type, tag, owner, clock),
179 device_rtc_interface(mconfig, *this),
180 device_nvram_interface(mconfig, *this),
181 m_out_alarm_cb(*this),
182 m_battery_backed(true),
183 m_mode(0),
184 m_reset(0),
185 m_alarm(1),
186 m_alarm_on(1),
187 m_1hz(1),
188 m_16hz(1)
189 {
190 }
191
192 //-------------------------------------------------
193 // device_start - device-specific startup
194 //-------------------------------------------------
195
device_start()196 void rp5c01_device::device_start()
197 {
198 // resolve callbacks
199 m_out_alarm_cb.resolve_safe();
200
201 // allocate timers
202 if (clock() > 0)
203 {
204 m_clock_timer = timer_alloc(TIMER_CLOCK);
205 m_clock_timer->adjust(attotime::from_hz(clock() / 16384), 0, attotime::from_hz(clock() / 16384));
206
207 m_16hz_timer = timer_alloc(TIMER_16HZ);
208 m_16hz_timer->adjust(attotime::from_hz(clock() / 1024), 0, attotime::from_hz(clock() / 1024));
209 }
210
211 memset(m_reg, 0, sizeof(m_reg));
212 memset(m_ram, 0, sizeof(m_ram));
213
214 // 24 hour mode
215 m_reg[MODE01][REGISTER_12_24_SELECT] = 1;
216
217 // state saving
218 save_item(NAME(m_reg[MODE00]));
219 save_item(NAME(m_reg[MODE01]));
220 save_item(NAME(m_mode));
221 save_item(NAME(m_reset));
222 save_item(NAME(m_alarm));
223 save_item(NAME(m_alarm_on));
224 save_item(NAME(m_1hz));
225 save_item(NAME(m_16hz));
226 }
227
228
229 //-------------------------------------------------
230 // device_timer - handler timer events
231 //-------------------------------------------------
232
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)233 void rp5c01_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
234 {
235 switch (id)
236 {
237 case TIMER_CLOCK:
238 if (m_1hz && (m_mode & MODE_TIMER_EN))
239 {
240 advance_seconds();
241 }
242
243 m_1hz = !m_1hz;
244 set_alarm_line();
245 break;
246
247 case TIMER_16HZ:
248 m_16hz = !m_16hz;
249 set_alarm_line();
250 break;
251 }
252 }
253
254
255 //-------------------------------------------------
256 // rtc_clock_updated -
257 //-------------------------------------------------
258
rtc_clock_updated(int year,int month,int day,int day_of_week,int hour,int minute,int second)259 void rp5c01_device::rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second)
260 {
261 m_reg[MODE01][REGISTER_LEAP_YEAR] = year % 4;
262 write_counter(REGISTER_1_YEAR, year);
263 write_counter(REGISTER_1_MONTH, month);
264 write_counter(REGISTER_1_DAY, day);
265 m_reg[MODE00][REGISTER_DAY_OF_THE_WEEK] = day_of_week;
266 write_counter(REGISTER_1_HOUR, hour);
267 write_counter(REGISTER_1_MINUTE, minute);
268 write_counter(REGISTER_1_SECOND, second);
269
270 check_alarm();
271 set_alarm_line();
272 }
273
274
275 //-------------------------------------------------
276 // nvram_default - called to initialize NVRAM to
277 // its default state
278 //-------------------------------------------------
279
nvram_default()280 void rp5c01_device::nvram_default()
281 {
282 }
283
284
285 //-------------------------------------------------
286 // nvram_read - called to read NVRAM from the
287 // .nv file
288 //-------------------------------------------------
289
nvram_read(emu_file & file)290 void rp5c01_device::nvram_read(emu_file &file)
291 {
292 if (m_battery_backed)
293 file.read(m_ram, RAM_SIZE);
294 }
295
296
297 //-------------------------------------------------
298 // nvram_write - called to write NVRAM to the
299 // .nv file
300 //-------------------------------------------------
301
nvram_write(emu_file & file)302 void rp5c01_device::nvram_write(emu_file &file)
303 {
304 if (m_battery_backed)
305 file.write(m_ram, RAM_SIZE);
306 }
307
308
309 //-------------------------------------------------
310 // read -
311 //-------------------------------------------------
312
read(offs_t offset)313 uint8_t rp5c01_device::read(offs_t offset)
314 {
315 uint8_t data = 0;
316 offset &= 0x0f;
317
318 switch (offset)
319 {
320 case REGISTER_MODE:
321 data = m_mode;
322 break;
323
324 case REGISTER_TEST:
325 case REGISTER_RESET:
326 // write only
327 break;
328
329 default:
330 switch (m_mode & MODE_MASK)
331 {
332 case MODE00:
333 case MODE01:
334 data = m_reg[m_mode & MODE_MASK][offset];
335 break;
336
337 case BLOCK10:
338 data = m_ram[offset];
339 break;
340
341 case BLOCK11:
342 data = m_ram[offset] >> 4;
343 break;
344 }
345 break;
346 }
347
348 if (LOG) logerror("RP5C01 '%s' Register %u Read %02x\n", tag(), offset, data);
349
350 return data & 0x0f;
351 }
352
353
354 //-------------------------------------------------
355 // write -
356 //-------------------------------------------------
357
write(offs_t offset,uint8_t data)358 void rp5c01_device::write(offs_t offset, uint8_t data)
359 {
360 data &= 0x0f;
361 offset &= 0x0f;
362
363 switch (offset)
364 {
365 case REGISTER_MODE:
366 m_mode = data;
367
368 if (LOG)
369 {
370 logerror("RP5C01 '%s' Mode %u\n", tag(), data & MODE_MASK);
371 logerror("RP5C01 '%s' Timer %s\n", tag(), (data & MODE_TIMER_EN) ? "enabled" : "disabled");
372 logerror("RP5C01 '%s' Alarm %s\n", tag(), (data & MODE_ALARM_EN) ? "enabled" : "disabled");
373 }
374 break;
375
376 case REGISTER_TEST:
377 if (LOG) logerror("RP5C01 '%s' Test %u not supported!\n", tag(), data);
378 break;
379
380 case REGISTER_RESET:
381 m_reset = data;
382
383 if (data & RESET_ALARM)
384 {
385 // reset alarm registers
386 for (int i = REGISTER_1_MINUTE; i < REGISTER_1_MONTH; i++)
387 {
388 m_reg[MODE01][i] = 0;
389 }
390 }
391
392 if (LOG)
393 {
394 if (data & RESET_ALARM) logerror("RP5C01 '%s' Alarm Reset\n", tag());
395 if (data & RESET_TIMER) logerror("RP5C01 '%s' Timer Reset not supported!\n", tag());
396 logerror("RP5C01 '%s' 16Hz Signal %s\n", tag(), (data & RESET_16_HZ) ? "disabled" : "enabled");
397 logerror("RP5C01 '%s' 1Hz Signal %s\n", tag(), (data & RESET_1_HZ) ? "disabled" : "enabled");
398 }
399 break;
400
401 default:
402 switch (m_mode & MODE_MASK)
403 {
404 case MODE00:
405 case MODE01:
406 m_reg[m_mode & MODE_MASK][offset] = data & register_write_mask[m_mode & MODE_MASK][offset];
407
408 set_time(false, read_counter(REGISTER_1_YEAR), read_counter(REGISTER_1_MONTH), read_counter(REGISTER_1_DAY), m_reg[MODE00][REGISTER_DAY_OF_THE_WEEK],
409 read_counter(REGISTER_1_HOUR), read_counter(REGISTER_1_MINUTE), read_counter(REGISTER_1_SECOND));
410 break;
411
412 case BLOCK10:
413 m_ram[offset] = (m_ram[offset] & 0xf0) | data;
414 break;
415
416 case BLOCK11:
417 m_ram[offset] = (data << 4) | (m_ram[offset] & 0x0f);
418 break;
419 }
420
421 if (LOG) logerror("RP5C01 '%s' Register %u Write %02x\n", tag(), offset, data);
422 break;
423 }
424 }
425
426 //-------------------------------------------------
427 // tc8521_device - constructor
428 //-------------------------------------------------
429
tc8521_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)430 tc8521_device::tc8521_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
431 : rp5c01_device(mconfig, TC8521, tag, owner, clock)
432 {
433 }
434