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