summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/mc146818.h
blob: 8fc89185e6aba1311613b27a02963c00147af699 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
// license:BSD-3-Clause
// copyright-holders:Curt Coder
/*********************************************************************

    mc146818.h

    Implementation of the MC146818 chip

    Real time clock chip with CMOS battery backed ram
    Used in IBM PC/AT, several PC clones, Amstrad NC200, Apollo workstations

*********************************************************************/

#ifndef MAME_MACHINE_MC146818_H
#define MAME_MACHINE_MC146818_H

#pragma once

#include "dirtc.h"


class mc146818_device : public device_t,
						public device_nvram_interface,
						public device_rtc_interface
{
public:
	// construction/destruction
	mc146818_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);

	// callbacks
	auto irq() { return m_write_irq.bind(); }
	auto sqw() { return m_write_sqw.bind(); }

	// The MC146818 doesn't have century support (some variants do), but when syncing the date & time at startup we can optionally store the century.
	void set_century_index(int century_index) { assert(!century_count_enabled()); m_century_index = century_index; }

	void set_binary(bool binary) { m_binary = binary; }
	void set_24hrs(bool hour) { m_hour = hour; }
	void set_epoch(int epoch) { m_epoch = epoch; }

	// read/write access
	void address_w(uint8_t data);
	uint8_t data_r();
	void data_w(uint8_t data);

	// direct-mapped read/write access
	uint8_t read_direct(offs_t offset);
	void write_direct(offs_t offset, uint8_t data);

	// FIXME: Addresses are read-only on a standard MC146818. Do some chipsets permit readback?
	uint8_t get_address() const { return m_index; }

protected:
	mc146818_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);

	// device-level overrides
	virtual void device_start() override ATTR_COLD;
	virtual void device_reset() override ATTR_COLD;

	// device_nvram_interface overrides
	virtual void nvram_default() override;
	virtual bool nvram_read(util::read_stream &file) override;
	virtual bool nvram_write(util::write_stream &file) override;

	// device_rtc_interface overrides
	virtual bool rtc_feature_y2k() const override { return m_epoch != 0 || m_century_index >= 0; }
	virtual bool rtc_feature_leap_year() const override { return true; }
	virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) override;

	static constexpr unsigned char ALARM_DONTCARE = 0xc0;
	static constexpr unsigned char HOURS_PM = 0x80;

	virtual int data_size() const { return 64; }
	virtual int data_logical_size() const { return data_size(); }
	virtual bool century_count_enabled() const { return false; }

	virtual void internal_set_address(uint8_t address);
	virtual uint8_t internal_read(offs_t offset);
	virtual void internal_write(offs_t offset, uint8_t data);

	TIMER_CALLBACK_MEMBER(periodic_tick);
	TIMER_CALLBACK_MEMBER(clock_tick);
	TIMER_CALLBACK_MEMBER(time_tick);

	enum
	{
		REG_SECONDS = 0,
		REG_ALARM_SECONDS = 1,
		REG_MINUTES = 2,
		REG_ALARM_MINUTES = 3,
		REG_HOURS = 4,
		REG_ALARM_HOURS = 5,
		REG_DAYOFWEEK = 6,
		REG_DAYOFMONTH = 7,
		REG_MONTH = 8,
		REG_YEAR = 9,
		REG_A = 0xa,
		REG_B = 0xb,
		REG_C = 0xc,
		REG_D = 0xd
	};

	enum
	{
		REG_A_RS0 = 1,
		REG_A_RS1 = 2,
		REG_A_RS2 = 4,
		REG_A_RS3 = 8,
		REG_A_DV0 = 16,
		REG_A_DV1 = 32,
		REG_A_DV2 = 64,
		REG_A_UIP = 128
	};

	enum
	{
		REG_B_DSE = 1, // TODO: When set the chip will adjust the clock by an hour at start and end of DST
		REG_B_24_12 = 2,
		REG_B_DM = 4,
		REG_B_SQWE = 8, // TODO: When set the chip will output a square wave on SQW pin
		REG_B_UIE = 16,
		REG_B_AIE = 32,
		REG_B_PIE = 64,
		REG_B_SET = 128
	};

	enum
	{
		REG_C_UF = 16,
		REG_C_AF = 32,
		REG_C_PF = 64,
		REG_C_IRQF = 128
	};

	enum
	{
		REG_D_VRT = 128
	};

	// internal helpers
	int to_ram(int a) const;
	int from_ram(int a) const;
	void update_irq();
	void update_timer();
	virtual int get_timer_bypass() const;
	int get_seconds() const;
	void set_seconds(int seconds);
	int get_minutes() const;
	void set_minutes(int minutes);
	int get_hours() const;
	void set_hours(int hours);
	int get_dayofweek() const;
	void set_dayofweek(int dayofweek);
	int get_dayofmonth() const;
	void set_dayofmonth(int dayofmonth);
	int get_month() const;
	void set_month(int month);
	int get_year() const;
	void set_year(int year);
	int get_century() const;
	void set_century(int year);

	optional_memory_region m_region;

	// internal state

	uint8_t           m_index;
	std::unique_ptr<uint8_t[]> m_data;

	emu_timer *m_clock_timer;
	emu_timer *m_update_timer;
	emu_timer *m_periodic_timer;

	devcb_write_line m_write_irq;
	devcb_write_line m_write_sqw;
	int m_century_index, m_epoch;
	bool m_binary, m_hour;
	bool m_sqw_state;
	unsigned m_tuc; // update cycle time
};

class ds1287_device : public mc146818_device
{
public:
	ds1287_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
};

class ds1397_device : public mc146818_device
{
public:
	ds1397_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);

	virtual void device_start() override ATTR_COLD;
	virtual void device_reset() override ATTR_COLD;

	u8 xram_r(offs_t offset);
	void xram_w(offs_t offset, u8 data);

protected:
	virtual int data_size() const override { return 64 + 4096; }

	u8 m_xram_page;
};

// device type definition
DECLARE_DEVICE_TYPE(MC146818, mc146818_device)
DECLARE_DEVICE_TYPE(DS1287, ds1287_device)
DECLARE_DEVICE_TYPE(DS1397, ds1397_device)

#endif // MAME_MACHINE_MC146818_H