1 // license:BSD-3-Clause
2 // copyright-holders:Curt Coder
3 /***************************************************************************
4 
5     dirtc.cpp
6 
7     Device Real Time Clock interfaces.
8 
9 ***************************************************************************/
10 
11 #include "emu.h"
12 #include "dirtc.h"
13 
14 
15 //**************************************************************************
16 //  MACROS / CONSTANTS
17 //**************************************************************************
18 
19 static const int DAYS_PER_MONTH[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
20 
21 
22 
23 //**************************************************************************
24 //  DEVICE RTC INTERFACE
25 //**************************************************************************
26 
27 //-------------------------------------------------
28 //  device_rtc_interface - constructor
29 //-------------------------------------------------
30 
device_rtc_interface(const machine_config & mconfig,device_t & device)31 device_rtc_interface::device_rtc_interface(const machine_config &mconfig, device_t &device)
32 	: device_interface(device, "rtc")
33 {
34 }
35 
36 
37 //-------------------------------------------------
38 //  ~device_rtc_interface - destructor
39 //-------------------------------------------------
40 
~device_rtc_interface()41 device_rtc_interface::~device_rtc_interface()
42 {
43 }
44 
45 
46 //-------------------------------------------------
47 //  set_time - called to initialize the RTC to
48 //  a known date/time
49 //-------------------------------------------------
50 
set_time(bool update,int year,int month,int day,int day_of_week,int hour,int minute,int second)51 void device_rtc_interface::set_time(bool update, int year, int month, int day, int day_of_week, int hour, int minute, int second)
52 {
53 	if (!rtc_feature_y2k())
54 	{
55 		year %= 100;
56 	}
57 
58 	set_clock_register(RTC_YEAR, year);
59 	set_clock_register(RTC_MONTH, month);
60 	set_clock_register(RTC_DAY, day);
61 	set_clock_register(RTC_DAY_OF_WEEK, day_of_week);
62 	set_clock_register(RTC_HOUR, hour);
63 	set_clock_register(RTC_MINUTE, minute);
64 	set_clock_register(RTC_SECOND, second);
65 
66 	if (update)
67 	{
68 		rtc_clock_updated(m_register[RTC_YEAR], m_register[RTC_MONTH], m_register[RTC_DAY], m_register[RTC_DAY_OF_WEEK],
69 			m_register[RTC_HOUR], m_register[RTC_MINUTE], m_register[RTC_SECOND]);
70 	}
71 }
72 
73 
74 //-------------------------------------------------
75 //  set_current_time - called to initialize the RTC
76 //  to the current system time
77 //-------------------------------------------------
78 
set_current_time(const system_time & systime)79 void device_rtc_interface::set_current_time(const system_time &systime)
80 {
81 	set_time(true, systime.local_time.year, systime.local_time.month + 1, systime.local_time.mday, systime.local_time.weekday + 1,
82 		systime.local_time.hour, systime.local_time.minute, systime.local_time.second);
83 }
84 
85 
86 //-------------------------------------------------
87 //  convert_to_bcd -
88 //-------------------------------------------------
89 
convert_to_bcd(int val)90 u8 device_rtc_interface::convert_to_bcd(int val)
91 {
92 	return ((val / 10) << 4) | (val % 10);
93 }
94 
95 
96 //-------------------------------------------------
97 //  bcd_to_integer -
98 //-------------------------------------------------
99 
bcd_to_integer(u8 val)100 int device_rtc_interface::bcd_to_integer(u8 val)
101 {
102 	return (((val & 0xf0) >> 4) * 10) + (val & 0x0f);
103 }
104 
105 
106 //-------------------------------------------------
107 //  set_clock_register -
108 //-------------------------------------------------
109 
set_clock_register(int reg,int value)110 void device_rtc_interface::set_clock_register(int reg, int value)
111 {
112 	m_register[reg] = value;
113 }
114 
115 
116 //-------------------------------------------------
117 //  get_clock_register -
118 //-------------------------------------------------
119 
get_clock_register(int reg)120 int device_rtc_interface::get_clock_register(int reg)
121 {
122 	return m_register[reg];
123 }
124 
125 
126 //-------------------------------------------------
127 //  clock_updated -
128 //-------------------------------------------------
129 
clock_updated()130 void device_rtc_interface::clock_updated()
131 {
132 	rtc_clock_updated(m_register[RTC_YEAR], m_register[RTC_MONTH], m_register[RTC_DAY], m_register[RTC_DAY_OF_WEEK],
133 		m_register[RTC_HOUR], m_register[RTC_MINUTE], m_register[RTC_SECOND]);
134 }
135 
136 
137 //-------------------------------------------------
138 //  advance_seconds -
139 //-------------------------------------------------
140 
advance_seconds()141 void device_rtc_interface::advance_seconds()
142 {
143 	m_register[RTC_SECOND]++;
144 
145 	if (m_register[RTC_SECOND] == 60)
146 	{
147 		m_register[RTC_SECOND] = 0;
148 
149 		advance_minutes();
150 	}
151 	else
152 	{
153 		clock_updated();
154 	}
155 }
156 
157 
158 //-------------------------------------------------
159 //  advance_minutes
160 //-------------------------------------------------
161 
advance_minutes()162 void device_rtc_interface::advance_minutes()
163 {
164 	m_register[RTC_MINUTE]++;
165 
166 	if (m_register[RTC_MINUTE] == 60)
167 	{
168 		m_register[RTC_MINUTE] = 0;
169 		m_register[RTC_HOUR]++;
170 	}
171 
172 	if (m_register[RTC_HOUR] == 24)
173 	{
174 		m_register[RTC_HOUR] = 0;
175 		advance_days();
176 	}
177 	else
178 	{
179 		clock_updated();
180 	}
181 }
182 
183 
184 //-------------------------------------------------
185 //  advance_days
186 //-------------------------------------------------
187 
advance_days()188 void device_rtc_interface::advance_days()
189 {
190 	m_register[RTC_DAY]++;
191 	m_register[RTC_DAY_OF_WEEK]++;
192 
193 	if (m_register[RTC_DAY_OF_WEEK] == 8)
194 	{
195 		m_register[RTC_DAY_OF_WEEK] = 1;
196 	}
197 
198 	if (m_register[RTC_MONTH] > 0 && m_register[RTC_DAY] > DAYS_PER_MONTH[m_register[RTC_MONTH] - 1])
199 	{
200 		if (m_register[RTC_MONTH] != 2 || m_register[RTC_DAY] != 29 || !rtc_feature_leap_year() || !(m_register[RTC_YEAR] % 4))
201 		{
202 			m_register[RTC_DAY] = 1;
203 			m_register[RTC_MONTH]++;
204 		}
205 	}
206 
207 	if (m_register[RTC_MONTH] == 13)
208 	{
209 		m_register[RTC_MONTH] = 1;
210 		m_register[RTC_YEAR]++;
211 
212 		if (!rtc_feature_y2k() && m_register[RTC_YEAR] == 100)
213 		{
214 			m_register[RTC_YEAR] = 0;
215 		}
216 	}
217 
218 	clock_updated();
219 }
220 
221 
222 //-------------------------------------------------
223 //  adjust_seconds -
224 //-------------------------------------------------
225 
adjust_seconds()226 void device_rtc_interface::adjust_seconds()
227 {
228 	int seconds = get_clock_register(RTC_SECOND);
229 
230 	set_clock_register(RTC_SECOND, 0);
231 
232 	if (seconds >= 30)
233 	{
234 		advance_minutes();
235 	}
236 	else
237 	{
238 		clock_updated();
239 	}
240 }
241