summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/spg2xx_io.h
blob: 6cbe3f95098986cffc3620229fac846bf5e4bf84 (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
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
// license:BSD-3-Clause
// copyright-holders:Ryan Holtz

#ifndef MAME_MACHINE_SPG2XX_IO_H
#define MAME_MACHINE_SPG2XX_IO_H

#pragma once

#include "cpu/unsp/unsp.h"
#include "screen.h"

class spg2xx_io_device : public device_t
{
public:
	spg2xx_io_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);

	auto porta_out() { return m_porta_out.bind(); }
	auto portb_out() { return m_portb_out.bind(); }
	auto portc_out() { return m_portc_out.bind(); }
	auto porta_in() { return m_porta_in.bind(); }
	auto portb_in() { return m_portb_in.bind(); }
	auto portc_in() { return m_portc_in.bind(); }

	template <size_t Line> auto adc_in() { return m_adc_in[Line].bind(); }

	auto i2c_w() { return m_i2c_w.bind(); }
	auto i2c_r() { return m_i2c_r.bind(); }

	auto uart_tx() { return m_uart_tx.bind(); }
	auto spi_tx() { return m_spi_tx.bind(); }
	auto chip_select() { return m_chip_sel.bind(); }

	void uart_rx(uint8_t data);
	void spi_rx(int state);

	void extint_w(int channel, bool state);

	uint16_t io_r(offs_t offset);
	void io_w(offs_t offset, uint16_t data);

	virtual uint16_t io_extended_r(offs_t offset);
	virtual void io_extended_w(offs_t offset, uint16_t data);

	auto pal_read_callback() { return m_pal_read_cb.bind(); };

	auto write_timer_irq_callback() { return m_timer_irq_cb.bind(); };
	auto write_uart_adc_irq_callback() { return m_uart_adc_irq_cb.bind(); };
	auto write_external_irq_callback() { return m_external_irq_cb.bind(); };
	auto write_ffrq_tmr1_irq_callback() { return m_ffreq_tmr1_irq_cb.bind(); };
	auto write_ffrq_tmr2_irq_callback() { return m_ffreq_tmr2_irq_cb.bind(); };

	auto write_fiq_vector_callback() { return m_fiq_vector_w.bind(); };

	template <size_t Line> uint16_t adc_r() { return m_adc_in[Line](); }

protected:
	spg2xx_io_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, const uint32_t sprite_limit)
		: spg2xx_io_device(mconfig, type, tag, owner, clock)
	{
	}

	enum
	{
		REG_IO_MODE,
		REG_IOA_DATA,
		REG_IOA_BUFFER,
		REG_IOA_DIR,
		REG_IOA_ATTRIB,
		REG_IOA_MASK,
		REG_IOB_DATA,
		REG_IOB_BUFFER,
		REG_IOB_DIR,
		REG_IOB_ATTRIB,
		REG_IOB_MASK,
		REG_IOC_DATA,
		REG_IOC_BUFFER,
		REG_IOC_DIR,
		REG_IOC_ATTRIB,
		REG_IOC_MASK,

		REG_TIMEBASE_SETUP,
		REG_TIMEBASE_CLEAR,
		REG_TIMERA_DATA,
		REG_TIMERA_CTRL,
		REG_TIMERA_ON,
		REG_TIMERA_IRQCLR,
		REG_TIMERB_DATA,
		REG_TIMERB_CTRL,
		REG_TIMERB_ON,
		REG_TIMERB_IRQCLR,

		REG_VERT_LINE = 0x1c,

		REG_SYSTEM_CTRL = 0x20,
		REG_INT_CTRL,
		REG_INT_CLEAR,
		REG_EXT_MEMORY_CTRL,
		REG_WATCHDOG_CLEAR,
		REG_ADC_CTRL,
		REG_ADC_PAD,
		REG_ADC_DATA,

		REG_SLEEP_MODE,
		REG_WAKEUP_SOURCE,
		REG_WAKEUP_TIME,

		REG_NTSC_PAL,

		REG_PRNG1 = 0x2c,
		REG_PRNG2,

		REG_FIQ_SEL,
		REG_DATA_SEGMENT,

		REG_UART_CTRL,
		REG_UART_STATUS,
		REG_UART_RESET,
		REG_UART_BAUD1,
		REG_UART_BAUD2,
		REG_UART_TXBUF,
		REG_UART_RXBUF,
		REG_UART_RXFIFO,

		REG_SPI_CTRL = 0x40,
		REG_SPI_TXSTATUS,
		REG_SPI_TXDATA,
		REG_SPI_RXSTATUS,
		REG_SPI_RXDATA,
		REG_SPI_MISC,

		REG_SIO_SETUP = 0x50,
		REG_SIO_STATUS,
		REG_SIO_ADDRL,
		REG_SIO_ADDRH,
		REG_SIO_DATA,
		REG_SIO_AUTO_TX_NUM,

		REG_I2C_CMD = 0x58,
		REG_I2C_STATUS,
		REG_I2C_ACCESS,
		REG_I2C_ADDR,
		REG_I2C_SUBADDR,
		REG_I2C_DATA_OUT,
		REG_I2C_DATA_IN,
		REG_I2C_MODE,

		REG_REGULATOR_CTRL = 0x60,
		REG_CLOCK_CTRL,
		REG_IO_DRIVE_CTRL
	};
	void check_extint_irq(int channel);
	void check_irqs(const uint16_t changed);

	static const device_timer_id TIMER_TMB1 = 0;
	static const device_timer_id TIMER_TMB2 = 1;
	static const device_timer_id TIMER_UART_TX = 4;
	static const device_timer_id TIMER_UART_RX = 5;
	static const device_timer_id TIMER_4KHZ = 6;
	static const device_timer_id TIMER_SRC_AB = 7;
	static const device_timer_id TIMER_SRC_C = 8;
	static const device_timer_id TIMER_RNG = 9;
	static const device_timer_id TIMER_WATCHDOG = 10;
	static const device_timer_id TIMER_SPI_TX = 11;
	static const device_timer_id TIMER_ADC0 = 12;
	static const device_timer_id TIMER_ADC1 = 13;
	static const device_timer_id TIMER_ADC2 = 14;
	static const device_timer_id TIMER_ADC3 = 15;

	virtual void device_start() override;
	virtual void device_reset() override;
	virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;

	uint16_t clock_rng(int which);

	void update_porta_special_modes();
	void update_portb_special_modes();
	void do_gpio(uint32_t offset, bool write);
	uint16_t do_special_gpio(uint32_t index, uint16_t mask);

	void update_timer_b_rate();
	void update_timer_ab_src();
	void update_timer_c_src();
	void increment_timer_a();

	void uart_transmit_tick();
	void uart_receive_tick();

	void system_timer_tick();

	void do_spi_tx();
	void set_spi_irq(bool set);
	void update_spi_irqs();

	void do_i2c();

	void do_adc_capture(int channel);

	uint16_t m_io_regs[0x100];

	uint8_t m_uart_rx_fifo[8];
	uint8_t m_uart_rx_fifo_start;
	uint8_t m_uart_rx_fifo_end;
	uint8_t m_uart_rx_fifo_count;
	bool m_uart_rx_available;
	bool m_uart_rx_irq;
	bool m_uart_tx_irq;

	uint8_t m_spi_tx_fifo[16];
	uint8_t m_spi_tx_fifo_start;
	uint8_t m_spi_tx_fifo_end;
	uint8_t m_spi_tx_fifo_count;
	uint8_t m_spi_tx_buf;
	uint8_t m_spi_tx_bit;

	uint8_t m_spi_rx_fifo[16];
	uint8_t m_spi_rx_fifo_start;
	uint8_t m_spi_rx_fifo_end;
	uint8_t m_spi_rx_fifo_count;
	uint8_t m_spi_rx_buf;
	uint8_t m_spi_rx_bit;

	bool m_extint[2];

	devcb_write16 m_porta_out;
	devcb_write16 m_portb_out;
	devcb_write16 m_portc_out;
	devcb_read16 m_porta_in;
	devcb_read16 m_portb_in;
	devcb_read16 m_portc_in;

	devcb_read16::array<4> m_adc_in;
	emu_timer *m_adc_timer[4];

	devcb_write8 m_i2c_w;
	devcb_read8 m_i2c_r;

	devcb_write8 m_uart_tx;
	devcb_write_line m_spi_tx;

	devcb_write8 m_chip_sel;

	uint16_t m_timer_a_preload;
	uint16_t m_timer_b_preload;
	uint16_t m_timer_b_divisor;
	uint16_t m_timer_b_tick_rate;

	emu_timer *m_tmb1;
	emu_timer *m_tmb2;
	emu_timer *m_timer_src_ab;
	emu_timer *m_timer_src_c;

	emu_timer *m_4khz_timer;
	uint32_t m_2khz_divider;
	uint32_t m_1khz_divider;
	uint32_t m_4hz_divider;

	uint32_t m_uart_baud_rate;
	emu_timer *m_uart_tx_timer;
	emu_timer *m_uart_rx_timer;

	emu_timer *m_rng_timer;
	emu_timer *m_watchdog_timer;

	uint32_t m_spi_rate;
	emu_timer* m_spi_tx_timer;

	uint8_t m_sio_bits_remaining;
	bool m_sio_writing;

	required_device<unsp_device> m_cpu;
	required_device<screen_device> m_screen;

	devcb_read16 m_pal_read_cb;

	devcb_write_line m_timer_irq_cb;
	devcb_write_line m_uart_adc_irq_cb;
	devcb_write_line m_external_irq_cb;
	devcb_write_line m_ffreq_tmr1_irq_cb;
	devcb_write_line m_ffreq_tmr2_irq_cb;

	devcb_write8 m_fiq_vector_w;
};

class spg24x_io_device : public spg2xx_io_device
{
public:
	template <typename T, typename U>
	spg24x_io_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu_tag, U &&screen_tag)
		: spg24x_io_device(mconfig, tag, owner, clock)
	{
		m_cpu.set_tag(std::forward<T>(cpu_tag));
		m_screen.set_tag(std::forward<U>(screen_tag));
	}

	spg24x_io_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
};

class spg28x_io_device : public spg2xx_io_device
{
public:
	template <typename T, typename U>
	spg28x_io_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu_tag, U &&screen_tag)
		: spg28x_io_device(mconfig, tag, owner, clock)
	{
		m_cpu.set_tag(std::forward<T>(cpu_tag));
		m_screen.set_tag(std::forward<U>(screen_tag));
	}

	spg28x_io_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);

	virtual void io_extended_w(offs_t offset, uint16_t data) override;
};

DECLARE_DEVICE_TYPE(SPG24X_IO, spg24x_io_device)
DECLARE_DEVICE_TYPE(SPG28X_IO, spg28x_io_device)

#endif // MAME_MACHINE_SPG2XX_IO_H