summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/edlc.h
blob: bbcd91d2589f7f1a3ce87aadbd7e0111d9d12661 (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
// license:BSD-3-Clause
// copyright-holders:Patrick Mackinlay

#ifndef MAME_MACHINE_EDLC_H
#define MAME_MACHINE_EDLC_H

#pragma once

#include "machine/bankdev.h"
#include "dinetwork.h"

class seeq8003_device :
	public device_t,
	public device_network_interface
{
public:
	// callback configuration
	auto out_int_cb() { return m_out_int.bind(); }
	auto out_rxrdy_cb() { return m_out_rxrdy.bind(); }
	auto out_txrdy_cb() { return m_out_txrdy.bind(); }

	seeq8003_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock = 0);

	// register interface
	virtual void map(address_map &map);
	virtual u8 read(offs_t offset);
	virtual void write(offs_t offset, u8 data);

	// input and output lines
	int rxeof_r();
	void reset_w(int state);
	void txeof_w(int state);

	// fifo interface
	u8 fifo_r();
	void fifo_w(u8 data);

protected:
	seeq8003_device(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock = 0);

	// device_t overrides
	virtual void device_start() override;
	virtual void device_reset() override;

	// device_network_interface overrides
	virtual int recv_start_cb(u8 *buf, int length) override;

	// register read handlers
	u8 unused_r() { return 0xff; }
	u8 rx_status_r();
	u8 tx_status_r();

	// register write handlers
	void station_address_w(offs_t offset, u8 data) { m_station_address[offset] = data; }
	void rx_command_w(u8 data);
	virtual void tx_command_w(u8 data);

	// helpers
	void transmit(int param);
	int receive(u8 *buf, int length);
	void interrupt(int param = 0);
	virtual bool address_filter(u8 *address);
	void dump_bytes(u8 *buf, int length);

	// 80c03 option helpers
	virtual bool mode_tx_pad() const { return false; }
	virtual bool mode_tx_crc() const { return true; }
	virtual bool mode_rx_crc() const { return false; }

	// constants and masks
	static const unsigned MAX_FRAME_SIZE = 1518;
	static const u32 FCS_RESIDUE = 0xdebb20e3;

	enum rx_status_mask : u8
	{
		RXS_V = 0x01, // received frame with overflow error
		RXS_C = 0x02, // received frame with crc error
		RXS_D = 0x04, // received frame with dribble error
		RXS_S = 0x08, // received short frame
		RXS_E = 0x10, // received end of frame
		RXS_G = 0x20, // received good frame
		RXS_O = 0x80, // old/new status

		RXS_M = 0x3f, // interrupt mask
	};
	enum rx_command_mask : u8
	{
		RXC_V = 0x01, // interrupt on receive overflow error
		RXC_C = 0x02, // interrupt on receive crc error
		RXC_D = 0x04, // interrupt on receive dribble error
		RXC_S = 0x08, // interrupt on short frame
		RXC_E = 0x10, // interrupt on end of frame
		RXC_G = 0x20, // interrupt on good frame
		RXC_M = 0xc0, // match mode
	};
	enum rx_match_mask : u8
	{
		RXC_M0 = 0x00, // receiver disable
		RXC_M1 = 0x40, // receive all frames
		RXC_M2 = 0x80, // receive station or broadcast frames
		RXC_M3 = 0xc0, // receive station, broadcast/multicast frames
	};
	enum tx_status_mask : u8
	{
		TXS_U = 0x01, // transmit underflow
		TXS_C = 0x02, // transmit collision
		TXS_R = 0x04, // 16 transmission attempts
		TXS_S = 0x08, // transmission successful
		TXS_O = 0x80, // old/new status

		TXS_M = 0x0f, // interrupt mask
	};
	enum tx_command_mask : u8
	{
		TXC_U = 0x01, // interrupt on transmit underflow
		TXC_C = 0x02, // interrupt on transmit collision
		TXC_R = 0x04, // interrupt on 16 transmission attempts
		TXC_S = 0x08, // interrupt on transmit success

		TXC_B = 0x60, // register bank select (80c03 only)
	};

	emu_timer *m_tx_timer;
	emu_timer *m_int_timer;

	// device state
	devcb_write_line m_out_int;
	devcb_write_line m_out_rxrdy;
	devcb_write_line m_out_txrdy;

	int m_int_state;
	int m_reset_state;
	u8 m_station_address[6];
	u8 m_rx_status;
	u8 m_tx_status;
	u8 m_rx_command;
	u8 m_tx_command;

	util::fifo<u8, MAX_FRAME_SIZE> m_rx_fifo;
	util::fifo<u8, MAX_FRAME_SIZE> m_tx_fifo;
};

class seeq80c03_device : public seeq8003_device
{
public:
	seeq80c03_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock = 0);

	// register interface
	virtual void map(address_map &map) override;
	virtual u8 read(offs_t offset) override;
	virtual void write(offs_t offset, u8 data) override;

protected:
	// device_t overrides
	virtual void device_add_mconfig(machine_config &config) override;
	virtual void device_start() override;
	virtual void device_reset() override;

	// device_network_interface overrides
	virtual void send_complete_cb(int result) override;

	// banked register map
	void map_reg(address_map &map);

	// register read handlers
	u8 tx_ccl_r() { return u8(m_tx_cc >> 0); }
	u8 tx_cch_r() { return u8(m_tx_cc >> 8); }
	u8 ccl_r() { return u8(m_cc >> 0); }
	u8 cch_r() { return u8(m_cc >> 8); }
	u8 test_r() { return 0; }
	u8 flags_r() { return m_flags; }

	// register write handlers
	void multicast_filter_w(offs_t offset, u8 data);
	virtual void tx_command_w(u8 data) override;
	void control_w(u8 data);
	void config_w(u8 data);

	// helpers
	virtual bool address_filter(u8 *address) override;

	// 80c03 option helpers
	virtual bool mode_tx_pad() const override { return bool(m_config & CFG_TPA); }
	virtual bool mode_tx_crc() const override { return !bool(m_config & CFG_TNC); }
	virtual bool mode_rx_crc() const override { return bool(m_config & CFG_RXC); }

	required_device<address_map_bank_device> m_regbank;

	enum flags_mask : u8
	{
		FLAGS_SQE = 0x01,
		FLAGS_TNC = 0x02, // txen_no_carrier
	};
	enum control_mask : u8
	{
		CTL_TCC = 0x01, // transmit collision counter
		CTL_CC  = 0x02, // collision counter
		CTL_SQE = 0x04, // sqe function
		CTL_MHF = 0x08, // multicast hash filter
		CTL_DRF = 0x10, // discard short frames
		CTL_TNC = 0x20, // txen_no_carrier function
	};
	enum config_mask : u8
	{
		CFG_GAM = 0x01, // group address
		CFG_TPA = 0x02, // transmit packet autopad
		CFG_TNP = 0x04, // transmit no preamble
		CFG_RTD = 0x08, // receive own transmit disable
		CFG_TNC = 0x10, // transmit no crc
		CFG_FDX = 0x20, // full duplex
		CFG_RXC = 0x40, // receive crc
		CFG_FRD = 0x80, // fast receive discard
	};
	u16 m_tx_cc;
	u16 m_cc;
	u8 m_flags;

	u8 m_control;
	u8 m_config;

	u64 m_multicast_filter;
};

DECLARE_DEVICE_TYPE(SEEQ8003,  seeq8003_device)
DECLARE_DEVICE_TYPE(SEEQ80C03, seeq80c03_device)

#endif // MAME_MACHINE_EDLC_H