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