summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/ins8250.h
blob: 2ad59e05389ac1e3084ce5c65278a25c95d317ae (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
// license:BSD-3-Clause
// copyright-holders:smf, Carl
/**********************************************************************

    8250 UART interface and emulation

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

#ifndef MAME_MACHINE_INS8250_H
#define MAME_MACHINE_INS8250_H

#pragma once

#include "diserial.h"

/***************************************************************************
    CLASS DEFINITIONS
***************************************************************************/

class ins8250_uart_device : public device_t, public device_serial_interface
{
public:
	auto out_tx_callback() { return m_out_tx_cb.bind(); }
	auto out_dtr_callback() { return m_out_dtr_cb.bind(); }
	auto out_rts_callback() { return m_out_rts_cb.bind(); }
	auto out_int_callback() { return m_out_int_cb.bind(); }
	auto out_out1_callback() { return m_out_out1_cb.bind(); }
	auto out_out2_callback() { return m_out_out2_cb.bind(); }
	auto out_baudout_callback() { return m_out_baudout_cb.bind(); }

	void ins8250_w(offs_t offset, u8 data);
	u8 ins8250_r(offs_t offset);

	DECLARE_WRITE_LINE_MEMBER(rclk_w);
	DECLARE_WRITE_LINE_MEMBER(dcd_w);
	DECLARE_WRITE_LINE_MEMBER(dsr_w);
	DECLARE_WRITE_LINE_MEMBER(ri_w);
	DECLARE_WRITE_LINE_MEMBER(cts_w);
	DECLARE_WRITE_LINE_MEMBER(rx_w);
	DECLARE_READ_LINE_MEMBER(intrpt_r);

protected:
	enum class dev_type {
		INS8250,
		INS8250A,
		NS16450,
		NS16550,
		NS16550A
	};

	ins8250_uart_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, dev_type device_type);

	virtual void device_start() override;
	virtual void device_reset() override;
	virtual void rcv_complete() override;
	virtual void tra_complete() override;
	virtual void tra_callback() override;

	virtual void set_fcr(u8 data) { }
	virtual void push_tx(u8 data) { }
	virtual u8 pop_rx() { return 0; }

	void trigger_int(int flag);
	void clear_int(int flag);

	void update_baud_rate();

	const dev_type m_device_type;
	struct {
		u8 thr;  /* 0 -W transmitter holding register */
		u8 rbr;  /* 0 R- receiver buffer register */
		u8 ier;  /* 1 RW interrupt enable register */
		u16 dl;  /* 0/1 RW divisor latch (if DLAB = 1) */
		u8 iir;  /* 2 R- interrupt identification register */
		u8 fcr;
		u8 lcr;  /* 3 RW line control register (bit 7: DLAB) */
		u8 mcr;  /* 4 RW modem control register */
		u8 lsr;  /* 5 R- line status register */
		u8 msr;  /* 6 R- modem status register */
		u8 scr;  /* 7 RW scratch register */
	} m_regs;
private:
	u8 m_int_pending;

	devcb_write_line    m_out_tx_cb;
	devcb_write_line    m_out_dtr_cb;
	devcb_write_line    m_out_rts_cb;
	devcb_write_line    m_out_int_cb;
	devcb_write_line    m_out_out1_cb;
	devcb_write_line    m_out_out2_cb;
	devcb_write_line    m_out_baudout_cb;

	emu_timer *m_brg;
	TIMER_CALLBACK_MEMBER(brg_clock);
	bool m_brg_clock;

	void update_interrupt();
	void update_msr();

	int m_txd;
	int m_rxd;
	int m_dcd;
	int m_dsr;
	int m_ri;
	int m_cts;
};

class ins8250_device : public ins8250_uart_device
{
public:
	ins8250_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
};

class ns16450_device : public ins8250_uart_device
{
public:
	ns16450_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
};

class ns16550_device : public ins8250_uart_device
{
public:
	ns16550_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
protected:
	virtual void device_start() override;
	virtual void device_reset() override;
	virtual void rcv_complete() override;
	virtual void tra_complete() override;
	virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
	virtual void set_fcr(u8 data) override;
	virtual void push_tx(u8 data) override;
	virtual u8 pop_rx() override;
private:
	void set_timer() { m_timeout->adjust(attotime::from_hz((clock()*4*8)/(m_regs.dl*16))); }
	int m_rintlvl;
	u8 m_rfifo[16];
	u8 m_efifo[16];
	u8 m_tfifo[16];
	int m_rhead, m_rtail, m_rnum;
	int m_thead, m_ttail;
	emu_timer *m_timeout;
};

class pc16552_device : public device_t
{
public:
	pc16552_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);

	u8 read(offs_t offset) { return ((offset & 8) ? m_chan1 : m_chan0)->ins8250_r(offset & 7); }
	void write(offs_t offset, u8 data) { ((offset & 8) ? m_chan1 : m_chan0)->ins8250_w(offset & 7, data); }

protected:
	virtual void device_start() override;

private:
	ns16550_device *m_chan0;
	ns16550_device *m_chan1;
};

DECLARE_DEVICE_TYPE(PC16552D, pc16552_device)
DECLARE_DEVICE_TYPE(INS8250,  ins8250_device)
DECLARE_DEVICE_TYPE(NS16450,  ns16450_device)
DECLARE_DEVICE_TYPE(NS16550,  ns16550_device)

#endif // MAME_MACHINE_INS8250_H