1 // license:BSD-3-Clause
2 // copyright-holders:Curt Coder
3 /*********************************************************************
4 
5     mc146818.h
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 #ifndef MAME_MACHINE_MC146818_H
15 #define MAME_MACHINE_MC146818_H
16 
17 #pragma once
18 
19 
20 class mc146818_device : public device_t,
21 						public device_nvram_interface
22 {
23 public:
24 	// construction/destruction
25 	mc146818_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
26 
27 	// callbacks
irq()28 	auto irq() { return m_write_irq.bind(); }
29 
30 	// The MC146818 doesn't have century support (some variants do), but when syncing the date & time at startup we can optionally store the century.
set_century_index(int century_index)31 	void set_century_index(int century_index) { assert(!century_count_enabled()); m_century_index = century_index; }
32 
33 	// The MC146818 doesn't have UTC support, but when syncing the data & time at startup we can use UTC instead of local time.
set_use_utc(bool use_utc)34 	void set_use_utc(bool use_utc) { m_use_utc = use_utc; }
35 
set_binary(bool binary)36 	void set_binary(bool binary) { m_binary = binary; }
set_24hrs(bool hour)37 	void set_24hrs(bool hour) { m_hour = hour; }
set_epoch(int epoch)38 	void set_epoch(int epoch) { m_epoch = epoch; }
set_binary_year(int bin)39 	void set_binary_year(int bin) { m_binyear = bin; }
40 
41 	// read/write access
42 	uint8_t read(offs_t offset);
43 	void write(offs_t offset, uint8_t data);
44 
45 	// direct-mapped read/write access
46 	uint8_t read_direct(offs_t offset);
47 	void write_direct(offs_t offset, uint8_t data);
48 
49 protected:
50 	mc146818_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
51 
52 	// device-level overrides
53 	virtual void device_start() override;
54 	virtual void device_reset() override;
55 	virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
56 
57 	// device_nvram_interface overrides
58 	virtual void nvram_default() override;
59 	virtual void nvram_read(emu_file &file) override;
60 	virtual void nvram_write(emu_file &file) override;
61 
62 	static constexpr unsigned char ALARM_DONTCARE = 0xc0;
63 	static constexpr unsigned char HOURS_PM = 0x80;
64 
data_size()65 	virtual int data_size() const { return 64; }
data_logical_size()66 	virtual int data_logical_size() const { return data_size(); }
century_count_enabled()67 	virtual bool century_count_enabled() const { return false; }
68 
69 	virtual void internal_set_address(uint8_t address);
70 	virtual uint8_t internal_read(offs_t offset);
71 	virtual void internal_write(offs_t offset, uint8_t data);
72 
73 	enum
74 	{
75 		REG_SECONDS = 0,
76 		REG_ALARM_SECONDS = 1,
77 		REG_MINUTES = 2,
78 		REG_ALARM_MINUTES = 3,
79 		REG_HOURS = 4,
80 		REG_ALARM_HOURS = 5,
81 		REG_DAYOFWEEK = 6,
82 		REG_DAYOFMONTH = 7,
83 		REG_MONTH = 8,
84 		REG_YEAR = 9,
85 		REG_A = 0xa,
86 		REG_B = 0xb,
87 		REG_C = 0xc,
88 		REG_D = 0xd
89 	};
90 
91 	enum
92 	{
93 		REG_A_RS0 = 1,
94 		REG_A_RS1 = 2,
95 		REG_A_RS2 = 4,
96 		REG_A_RS3 = 8,
97 		REG_A_DV0 = 16,
98 		REG_A_DV1 = 32,
99 		REG_A_DV2 = 64,
100 		REG_A_UIP = 128
101 	};
102 
103 	enum
104 	{
105 		REG_B_DSE = 1, // TODO: When set the chip will adjust the clock by an hour at start and end of DST
106 		REG_B_24_12 = 2,
107 		REG_B_DM = 4,
108 		REG_B_SQWE = 8, // TODO: When set the chip will output a square wave on SQW pin
109 		REG_B_UIE = 16,
110 		REG_B_AIE = 32,
111 		REG_B_PIE = 64,
112 		REG_B_SET = 128
113 	};
114 
115 	enum
116 	{
117 		REG_C_UF = 16,
118 		REG_C_AF = 32,
119 		REG_C_PF = 64,
120 		REG_C_IRQF = 128
121 	};
122 
123 	enum
124 	{
125 		REG_D_VRT = 128
126 	};
127 
128 	// internal helpers
129 	int to_ram(int a) const;
130 	int from_ram(int a) const;
131 	void set_base_datetime();
132 	void update_irq();
133 	void update_timer();
134 	virtual int get_timer_bypass() const;
135 	int get_seconds() const;
136 	void set_seconds(int seconds);
137 	int get_minutes() const;
138 	void set_minutes(int minutes);
139 	int get_hours() const;
140 	void set_hours(int hours);
141 	int get_dayofweek() const;
142 	void set_dayofweek(int dayofweek);
143 	int get_dayofmonth() const;
144 	void set_dayofmonth(int dayofmonth);
145 	int get_month() const;
146 	void set_month(int month);
147 	int get_year() const;
148 	void set_year(int year);
149 	int get_century() const;
150 	void set_century(int year);
151 
152 	optional_memory_region m_region;
153 
154 	// internal state
155 
156 	uint8_t           m_index;
157 	std::unique_ptr<uint8_t[]> m_data;
158 
159 	attotime        m_last_refresh;
160 
161 	static const device_timer_id TIMER_CLOCK = 0;
162 	static const device_timer_id TIMER_PERIODIC = 1;
163 
164 	emu_timer *m_clock_timer;
165 	emu_timer *m_periodic_timer;
166 
167 	devcb_write_line m_write_irq;
168 	int m_century_index, m_epoch;
169 	bool m_use_utc, m_binary, m_hour, m_binyear;
170 };
171 
172 
173 // device type definition
174 DECLARE_DEVICE_TYPE(MC146818, mc146818_device)
175 
176 #endif // MAME_MACHINE_MC146818_H
177