1 // license:BSD-3-Clause
2 // copyright-holders:Curt Coder
3 /*********************************************************************
4 
5     mc146818.c
6 
7     Implementation of the MC146818 chip
8 
9     Real time clock chip with CMOS battery backed ram
10     Used in IBM PC/AT, several PC clones, Amstrad NC200, Apollo workstations
11 
12 *********************************************************************/
13 
14 #include "emu.h"
15 #include "coreutil.h"
16 #include "machine/mc146818.h"
17 
18 //#define VERBOSE 1
19 #include "logmacro.h"
20 
21 
22 
23 // device type definition
24 DEFINE_DEVICE_TYPE(MC146818, mc146818_device, "mc146818", "MC146818 RTC")
25 
26 //-------------------------------------------------
27 //  mc146818_device - constructor
28 //-------------------------------------------------
29 
mc146818_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)30 mc146818_device::mc146818_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
31 	: mc146818_device(mconfig, MC146818, tag, owner, clock)
32 {
33 }
34 
mc146818_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,uint32_t clock)35 mc146818_device::mc146818_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
36 	: device_t(mconfig, type, tag, owner, clock),
37 		device_nvram_interface(mconfig, *this),
38 		m_region(*this, DEVICE_SELF),
39 		m_index(0),
40 		m_last_refresh(attotime::zero), m_clock_timer(nullptr), m_periodic_timer(nullptr),
41 		m_write_irq(*this),
42 		m_century_index(-1),
43 		m_epoch(0),
44 		m_use_utc(false),
45 		m_binary(false),
46 		m_hour(false),
47 		m_binyear(false)
48 {
49 }
50 
51 //-------------------------------------------------
52 //  device_start - device-specific startup
53 //-------------------------------------------------
54 
device_start()55 void mc146818_device::device_start()
56 {
57 	m_data = make_unique_clear<uint8_t[]>(data_size());
58 	m_last_refresh = machine().time();
59 	m_clock_timer = timer_alloc(TIMER_CLOCK);
60 	m_periodic_timer = timer_alloc(TIMER_PERIODIC);
61 
62 	m_write_irq.resolve_safe();
63 
64 	save_pointer(NAME(m_data), data_size());
65 	save_item(NAME(m_index));
66 }
67 
68 
69 //-------------------------------------------------
70 //  device_reset - device-specific reset
71 //-------------------------------------------------
72 
device_reset()73 void mc146818_device::device_reset()
74 {
75 	m_data[REG_B] &= ~(REG_B_UIE | REG_B_AIE | REG_B_PIE | REG_B_SQWE);
76 	m_data[REG_C] = 0;
77 
78 	update_irq();
79 }
80 
81 //-------------------------------------------------
82 //  device_timer - handler timer events
83 //-------------------------------------------------
84 
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)85 void mc146818_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
86 {
87 	switch (id)
88 	{
89 	case TIMER_PERIODIC:
90 		m_data[REG_C] |= REG_C_PF;
91 		update_irq();
92 		break;
93 
94 	case TIMER_CLOCK:
95 		if (!(m_data[REG_B] & REG_B_SET))
96 		{
97 			/// TODO: find out how the real chip deals with updates when binary/bcd values are already outside the normal range
98 			int seconds = get_seconds() + 1;
99 			if (seconds < 60)
100 			{
101 				set_seconds(seconds);
102 			}
103 			else
104 			{
105 				set_seconds(0);
106 
107 				int minutes = get_minutes() + 1;
108 				if (minutes < 60)
109 				{
110 					set_minutes(minutes);
111 				}
112 				else
113 				{
114 					set_minutes(0);
115 
116 					int hours = get_hours() + 1;
117 					if (hours < 24)
118 					{
119 						set_hours(hours);
120 					}
121 					else
122 					{
123 						set_hours(0);
124 
125 						int dayofweek = get_dayofweek() + 1;
126 						if (dayofweek <= 7)
127 						{
128 							set_dayofweek(dayofweek);
129 						}
130 						else
131 						{
132 							set_dayofweek(1);
133 						}
134 
135 						int dayofmonth = get_dayofmonth() + 1;
136 						if (dayofmonth <= gregorian_days_in_month(get_month(), get_year() + 2000))
137 						{
138 							set_dayofmonth(dayofmonth);
139 						}
140 						else
141 						{
142 							set_dayofmonth(1);
143 
144 							int month = get_month() + 1;
145 							if (month <= 12)
146 							{
147 								set_month(month);
148 							}
149 							else
150 							{
151 								set_month(1);
152 
153 								int year = get_year() + 1;
154 								if (year <= 99)
155 								{
156 									set_year(year);
157 								}
158 								else
159 								{
160 									set_year(0);
161 
162 									if (century_count_enabled())
163 									{
164 										set_century((get_century() + 1) % 100);
165 									}
166 								}
167 							}
168 						}
169 					}
170 				}
171 			}
172 
173 			if ((m_data[REG_ALARM_SECONDS] == m_data[REG_SECONDS] || (m_data[REG_ALARM_SECONDS] & ALARM_DONTCARE) == ALARM_DONTCARE) &&
174 				(m_data[REG_ALARM_MINUTES] == m_data[REG_MINUTES] || (m_data[REG_ALARM_MINUTES] & ALARM_DONTCARE) == ALARM_DONTCARE) &&
175 				(m_data[REG_ALARM_HOURS] == m_data[REG_HOURS] || (m_data[REG_ALARM_HOURS] & ALARM_DONTCARE) == ALARM_DONTCARE))
176 			{
177 				// set the alarm interrupt flag AF
178 				m_data[REG_C] |= REG_C_AF;
179 			}
180 
181 			// set the update-ended interrupt Flag UF
182 			m_data[REG_C] |=  REG_C_UF;
183 			update_irq();
184 
185 			m_last_refresh = machine().time();
186 		}
187 		break;
188 	}
189 }
190 
191 
192 //-------------------------------------------------
193 //  nvram_default - called to initialize NVRAM to
194 //  its default state
195 //-------------------------------------------------
196 
nvram_default()197 void mc146818_device::nvram_default()
198 {
199 	// populate from a memory region if present
200 	if (m_region.found())
201 	{
202 		uint32_t bytes = m_region->bytes();
203 
204 		if (bytes > data_size())
205 			bytes = data_size();
206 
207 		memcpy(&m_data[0], m_region->base(), bytes);
208 	}
209 	else
210 	{
211 		memset(&m_data[0], 0, data_size());
212 	}
213 
214 	if(m_binary)
215 		m_data[REG_B] |= REG_B_DM;
216 	if(m_hour)
217 		m_data[REG_B] |= REG_B_24_12;
218 
219 	set_base_datetime();
220 	update_timer();
221 	update_irq();
222 }
223 
224 
225 //-------------------------------------------------
226 //  nvram_read - called to read NVRAM from the
227 //  .nv file
228 //-------------------------------------------------
229 
nvram_read(emu_file & file)230 void mc146818_device::nvram_read(emu_file &file)
231 {
232 	file.read(&m_data[0], data_size());
233 
234 	set_base_datetime();
235 	update_timer();
236 	update_irq();
237 }
238 
239 
240 //-------------------------------------------------
241 //  nvram_write - called to write NVRAM to the
242 //  .nv file
243 //-------------------------------------------------
244 
nvram_write(emu_file & file)245 void mc146818_device::nvram_write(emu_file &file)
246 {
247 	file.write(&m_data[0], data_size());
248 }
249 
250 
251 //-------------------------------------------------
252 //  to_ram - convert value to current ram format
253 //-------------------------------------------------
254 
to_ram(int a) const255 int mc146818_device::to_ram(int a) const
256 {
257 	if (!(m_data[REG_B] & REG_B_DM))
258 		return dec_2_bcd(a);
259 
260 	return a;
261 }
262 
263 
264 //-------------------------------------------------
265 //  from_ram - convert value from current ram format
266 //-------------------------------------------------
267 
from_ram(int a) const268 int mc146818_device::from_ram(int a) const
269 {
270 	if (!(m_data[REG_B] & REG_B_DM))
271 		return bcd_2_dec(a);
272 
273 	return a;
274 }
275 
276 
get_seconds() const277 int mc146818_device::get_seconds() const
278 {
279 	return from_ram(m_data[REG_SECONDS]);
280 }
281 
set_seconds(int seconds)282 void mc146818_device::set_seconds(int seconds)
283 {
284 	m_data[REG_SECONDS] = to_ram(seconds);
285 }
286 
get_minutes() const287 int mc146818_device::get_minutes() const
288 {
289 	return from_ram(m_data[REG_MINUTES]);
290 }
291 
set_minutes(int minutes)292 void mc146818_device::set_minutes(int minutes)
293 {
294 	m_data[REG_MINUTES] = to_ram(minutes);
295 }
296 
get_hours() const297 int mc146818_device::get_hours() const
298 {
299 	if (!(m_data[REG_B] & REG_B_24_12))
300 	{
301 		int hours = from_ram(m_data[REG_HOURS] & ~HOURS_PM);
302 
303 		if (hours == 12)
304 		{
305 			hours = 0;
306 		}
307 
308 		if (m_data[REG_HOURS] & HOURS_PM)
309 		{
310 			hours += 12;
311 		}
312 
313 		return hours;
314 	}
315 	else
316 	{
317 		return from_ram(m_data[REG_HOURS]);
318 	}
319 }
320 
set_hours(int hours)321 void mc146818_device::set_hours(int hours)
322 {
323 	if (!(m_data[REG_B] & REG_B_24_12))
324 	{
325 		int pm = 0;
326 
327 		if (hours >= 12)
328 		{
329 			hours -= 12;
330 			pm = HOURS_PM;
331 		}
332 
333 		if (hours == 0)
334 		{
335 			hours = 12;
336 		}
337 
338 		m_data[REG_HOURS] = to_ram(hours) | pm;
339 	}
340 	else
341 	{
342 		m_data[REG_HOURS] = to_ram(hours);
343 	}
344 }
345 
get_dayofweek() const346 int mc146818_device::get_dayofweek() const
347 {
348 	return from_ram(m_data[REG_DAYOFWEEK]);
349 }
350 
set_dayofweek(int dayofweek)351 void mc146818_device::set_dayofweek(int dayofweek)
352 {
353 	m_data[REG_DAYOFWEEK] = to_ram(dayofweek);
354 }
355 
get_dayofmonth() const356 int mc146818_device::get_dayofmonth() const
357 {
358 	return from_ram(m_data[REG_DAYOFMONTH]);
359 }
360 
set_dayofmonth(int dayofmonth)361 void mc146818_device::set_dayofmonth(int dayofmonth)
362 {
363 	m_data[REG_DAYOFMONTH] = to_ram(dayofmonth);
364 }
365 
get_month() const366 int mc146818_device::get_month() const
367 {
368 	return from_ram(m_data[REG_MONTH]);
369 }
370 
set_month(int month)371 void mc146818_device::set_month(int month)
372 {
373 	m_data[REG_MONTH] = to_ram(month);
374 }
375 
get_year() const376 int mc146818_device::get_year() const
377 {
378 	return from_ram(m_data[REG_YEAR]);
379 }
380 
set_year(int year)381 void mc146818_device::set_year(int year)
382 {
383 	m_data[REG_YEAR] = to_ram(year);
384 }
385 
get_century() const386 int mc146818_device::get_century() const
387 {
388 	assert(m_century_index != -1);
389 	return from_ram(m_data[m_century_index]);
390 }
391 
set_century(int century)392 void mc146818_device::set_century(int century)
393 {
394 	assert(m_century_index != -1);
395 	m_data[m_century_index] = to_ram(century);
396 }
397 
398 
399 
400 //-------------------------------------------------
401 //  set_base_datetime - update clock with real time
402 //-------------------------------------------------
403 
set_base_datetime()404 void mc146818_device::set_base_datetime()
405 {
406 	system_time systime;
407 	system_time::full_time current_time;
408 
409 	machine().base_datetime(systime);
410 
411 	current_time = (m_use_utc) ? systime.utc_time: systime.local_time;
412 
413 //  logerror("mc146818_set_base_datetime %02d/%02d/%02d %02d:%02d:%02d\n",
414 //          current_time.year % 100, current_time.month + 1, current_time.mday,
415 //          current_time.hour,current_time.minute, current_time.second);
416 
417 	set_seconds(current_time.second);
418 	set_minutes(current_time.minute);
419 	set_hours(current_time.hour);
420 	set_dayofweek(current_time.weekday + 1);
421 	set_dayofmonth(current_time.mday);
422 	set_month(current_time.month + 1);
423 
424 	if(m_binyear)
425 		set_year((current_time.year - m_epoch) % (m_data[REG_B] & REG_B_DM ? 0x100 : 100)); // pcd actually depends on this
426 	else
427 		set_year((current_time.year - m_epoch) % 100);
428 
429 	if (m_century_index >= 0)
430 		set_century(current_time.year / 100);
431 }
432 
433 
434 //-------------------------------------------------
435 //  update_timer - update timer based on A register
436 //-------------------------------------------------
437 
update_timer()438 void mc146818_device::update_timer()
439 {
440 	int bypass = get_timer_bypass();
441 
442 	attotime update_period = attotime::never;
443 	attotime update_interval = attotime::never;
444 	attotime periodic_period = attotime::never;
445 	attotime periodic_interval = attotime::never;
446 
447 	if (bypass < 22)
448 	{
449 		int shift = 22 - bypass;
450 
451 		double update_hz = (double) clock() / (1 << shift);
452 
453 		// TODO: take the time since last timer into account
454 		update_period = attotime::from_hz(update_hz * 2);
455 		update_interval = attotime::from_hz(update_hz);
456 
457 		int rate_select = m_data[REG_A] & (REG_A_RS3 | REG_A_RS2 | REG_A_RS1 | REG_A_RS0);
458 		if (rate_select != 0)
459 		{
460 			shift = (rate_select + 6) - bypass;
461 			if (shift <= 1)
462 				shift += 7;
463 
464 			double periodic_hz = (double) clock() / (1 << shift);
465 
466 			// TODO: take the time since last timer into account
467 			periodic_period = attotime::from_hz(periodic_hz * 2);
468 			periodic_interval = attotime::from_hz(periodic_hz);
469 		}
470 	}
471 
472 	m_clock_timer->adjust(update_period, 0, update_interval);
473 	m_periodic_timer->adjust(periodic_period, 0, periodic_interval);
474 }
475 
476 //---------------------------------------------------------------
477 //  get_timer_bypass - get main clock divisor based on A register
478 //---------------------------------------------------------------
479 
get_timer_bypass() const480 int mc146818_device::get_timer_bypass() const
481 {
482 	int bypass;
483 
484 	switch (m_data[REG_A] & (REG_A_DV2 | REG_A_DV1 | REG_A_DV0))
485 	{
486 	case 0:
487 		bypass = 0;
488 		break;
489 
490 	case REG_A_DV0:
491 		bypass = 2;
492 		break;
493 
494 	case REG_A_DV1:
495 		bypass = 7;
496 		break;
497 
498 	case REG_A_DV2 | REG_A_DV1:
499 	case REG_A_DV2 | REG_A_DV1 | REG_A_DV0:
500 		bypass = 22;
501 		break;
502 
503 	default:
504 		// TODO: other combinations of divider bits are used for test purposes only
505 		bypass = 22;
506 		break;
507 	}
508 
509 	return bypass;
510 }
511 
512 //-------------------------------------------------
513 //  update_irq - Update irq based on B & C register
514 //-------------------------------------------------
515 
update_irq()516 void mc146818_device::update_irq()
517 {
518 	if (((m_data[REG_C] & REG_C_UF) && (m_data[REG_B] & REG_B_UIE)) ||
519 		((m_data[REG_C] & REG_C_AF) && (m_data[REG_B] & REG_B_AIE)) ||
520 		((m_data[REG_C] & REG_C_PF) && (m_data[REG_B] & REG_B_PIE)))
521 	{
522 		m_data[REG_C] |= REG_C_IRQF;
523 		m_write_irq(ASSERT_LINE);
524 	}
525 	else
526 	{
527 		m_data[REG_C] &= ~REG_C_IRQF;
528 		m_write_irq(CLEAR_LINE);
529 	}
530 }
531 
532 
533 
534 //-------------------------------------------------
535 //  read - I/O handler for reading
536 //-------------------------------------------------
537 
read(offs_t offset)538 uint8_t mc146818_device::read(offs_t offset)
539 {
540 	uint8_t data = 0;
541 	switch (offset)
542 	{
543 	case 0:
544 		data = m_index;
545 		break;
546 
547 	case 1:
548 		data = internal_read(m_index);
549 		LOG("mc146818_port_r(): offset=0x%02x data=0x%02x\n", m_index, data);
550 		break;
551 	}
552 
553 	return data;
554 }
555 
read_direct(offs_t offset)556 uint8_t mc146818_device::read_direct(offs_t offset)
557 {
558 	offset %= data_logical_size();
559 	if (!machine().side_effects_disabled())
560 		internal_set_address(offset);
561 
562 	uint8_t data = internal_read(offset);
563 
564 	LOG("mc146818_port_r(): offset=0x%02x data=0x%02x\n", offset, data);
565 
566 	return data;
567 }
568 
569 //-------------------------------------------------
570 //  write - I/O handler for writing
571 //-------------------------------------------------
572 
write(offs_t offset,uint8_t data)573 void mc146818_device::write(offs_t offset, uint8_t data)
574 {
575 	switch (offset)
576 	{
577 	case 0:
578 		internal_set_address(data % data_logical_size());
579 		break;
580 
581 	case 1:
582 		LOG("mc146818_port_w(): offset=0x%02x data=0x%02x\n", m_index, data);
583 		internal_write(m_index, data);
584 		break;
585 	}
586 }
587 
write_direct(offs_t offset,uint8_t data)588 void mc146818_device::write_direct(offs_t offset, uint8_t data)
589 {
590 	offset %= data_logical_size();
591 	if (!machine().side_effects_disabled())
592 		internal_set_address(offset);
593 
594 	LOG("mc146818_port_w(): offset=0x%02x data=0x%02x\n", offset, data);
595 
596 	internal_write(offset, data);
597 }
598 
internal_set_address(uint8_t address)599 void mc146818_device::internal_set_address(uint8_t address)
600 {
601 	m_index = address;
602 }
603 
internal_read(offs_t offset)604 uint8_t mc146818_device::internal_read(offs_t offset)
605 {
606 	uint8_t data = 0;
607 
608 	switch (offset)
609 	{
610 	case REG_A:
611 		data = m_data[REG_A];
612 		// Update In Progress (UIP) time for 32768 Hz is 244+1984usec
613 		/// TODO: support other dividers
614 		/// TODO: don't set this if update is stopped
615 		if ((machine().time() - m_last_refresh) < attotime::from_usec(244+1984))
616 			data |= REG_A_UIP;
617 		break;
618 
619 	case REG_C:
620 		// the unused bits b0 ... b3 are always read as 0
621 		data = m_data[REG_C] & (REG_C_IRQF | REG_C_PF | REG_C_AF | REG_C_UF);
622 		// read 0x0c will clear all IRQ flags in register 0x0c
623 		if (!machine().side_effects_disabled())
624 		{
625 			m_data[REG_C] &= ~(REG_C_IRQF | REG_C_PF | REG_C_AF | REG_C_UF);
626 			update_irq();
627 		}
628 		break;
629 
630 	case REG_D:
631 		/* battery ok */
632 		data = m_data[REG_D] | REG_D_VRT;
633 		break;
634 
635 	default:
636 		data = m_data[offset];
637 		break;
638 	}
639 
640 	return data;
641 }
642 
internal_write(offs_t offset,uint8_t data)643 void mc146818_device::internal_write(offs_t offset, uint8_t data)
644 {
645 	switch (offset)
646 	{
647 	case REG_SECONDS:
648 		// top bit of SECONDS is read only
649 		m_data[REG_SECONDS] = data & ~0x80;
650 		break;
651 
652 	case REG_A:
653 		// top bit of A is read only
654 		if ((data ^ m_data[REG_A]) & ~REG_A_UIP)
655 		{
656 			m_data[REG_A] = data & ~REG_A_UIP;
657 			update_timer();
658 		}
659 		break;
660 
661 	case REG_B:
662 		if ((data & REG_B_SET) && !(m_data[REG_B] & REG_B_SET))
663 			data &= ~REG_B_UIE;
664 
665 		m_data[REG_B] = data;
666 		update_irq();
667 		break;
668 
669 	case REG_C:
670 	case REG_D:
671 		// register C & D is readonly
672 		break;
673 
674 	default:
675 		m_data[offset] = data;
676 		break;
677 	}
678 }
679