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

#ifndef MAME_MACHINE_Z8038_H
#define MAME_MACHINE_Z8038_H

#pragma once

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

	// port 1 and 2 I̅N̅T̅ output lines
	template <u8 Port> auto out_int_cb() { return m_out_int_cb[Port - 1].bind(); }

	// port 2 output lines
	auto out_E() { return m_out_E_cb.bind(); }
	auto out_F() { return m_out_F_cb.bind(); }
	auto out_H() { return m_out_H_cb.bind(); }
	auto out_J() { return m_out_J_cb.bind(); }

	// port 2 input lines
	void in_E(int state); // C̅L̅E̅A̅R̅
	void in_F(int state); // Data Direction
	void in_G(int state); // IN0

	// indirect register access
	template <u8 Port> u8 reg_r()           { return reg_r(Port - 1); }
	template <u8 Port> void reg_w(u8 data)  { reg_w(Port - 1, data); }

	// direct register access
	template <u8 Port> void zbus_map(address_map &map);
	template <u8 Port> u8 zbus_reg_r(offs_t offset)            { m_port[Port - 1].reg_state = 1; m_port[Port - 1].reg_pointer = offset & 0xf; return reg_r(Port - 1); }
	template <u8 Port> void zbus_reg_w(offs_t offset, u8 data) { m_port[Port - 1].reg_state = 1; m_port[Port - 1].reg_pointer = offset & 0xf; reg_w(Port - 1, data); }

	// direct fifo access
	template <u8 Port> u8 fifo_r()          { return fifo_r(Port - 1); }
	template <u8 Port> void fifo_w(u8 data) { fifo_w(Port - 1, data); }

protected:
	// standard device_interface overrides
	virtual void device_start() override;
	virtual void device_reset() override;

	// primary device read/write handlers
	u8 reg_r(u8 const port);
	void reg_w(u8 const port, u8 data);
	u8 fifo_r(u8 const port);
	void fifo_w(u8 const port, u8 data);

	// register read helpers
	u8 control_0_r(u8 const port) { return m_port[port].control_0; }
	u8 control_1_r(u8 const port);
	template <u8 Number> u8 interrupt_status_r(u8 const port) { return m_port[port].interrupt_status[Number]; }
	u8 interrupt_vector_r(u8 const port);
	u8 byte_count_r(u8 const port);
	u8 byte_count_comparison_r(u8 const port) { return m_port[port].byte_count_comparison; }
	u8 control_2_r(u8 const port) { return (port == 0) ? m_control_2 : 0; }
	u8 control_3_r(u8 const port);
	u8 message_out_r(u8 const port) { return m_port[!port].message_in; }
	u8 message_in_r(u8 const port);
	u8 pattern_match_r(u8 const port) { return m_port[port].pattern_match; }
	u8 pattern_mask_r(u8 const port) { return m_port[port].pattern_mask; }

	// register write helpers
	void control_0_w(u8 const port, u8 data);
	void control_1_w(u8 const port, u8 data);
	template <u8 Number> void interrupt_status_w(u8 const port, u8 data);
	void interrupt_vector_w(u8 const port, u8 data) { m_port[port].interrupt_vector = data; }
	void byte_count_comparison_w(u8 const port, u8 data);
	void control_2_w(u8 const port, u8 data);
	void control_3_w(u8 const port, u8 data);
	void message_out_w(u8 const port, u8 data);
	void pattern_match_w(u8 const port, u8 data) { m_port[port].pattern_match = data; }
	void pattern_mask_w(u8 const port, u8 data) { m_port[port].pattern_mask = data; }

	// other helpers
	void port_reset(u8 const port);
	void fifo_clear();
	void fifo_update();
	TIMER_CALLBACK_MEMBER(int_check);
	void set_int_state(u8 const port, bool asserted);

private:
	enum control_0_mask : u8
	{
		CR0_RESET = 0x01, // reset port
		CR0_RJA   = 0x02, // right-justify address
		CR0_P2M   = 0x0c, // port 2 mode (read-only from port 2 side)
		CR0_VIS   = 0x10, // vector includes status
		CR0_NV    = 0x20, // no vector on interrupt
		CR0_DLC   = 0x40, // disable lower daisy chain
		CR0_MIE   = 0x80, // master interrupt enable
	};
	enum control_0_p2mode_mask : u8
	{
		CR0_P2M_ZBUSCPU  = 0x00, // z-bus cpu
		CR0_P2M_NZBUSCPU = 0x04, // non z-bus cpu
		CR0_P2M_3WHSIO   = 0x08, // 3-wire handshake i/o
		CR0_P2M_2WHSIO   = 0x0c, // 2-wire handshake i/o

		CR0_P2M_IO       = 0x08, // i/o mode
	};
	enum control_1_mask : u8
	{
		CR1_RWE   = 0x01, // R̅E̅Q̅U̅E̅S̅T̅ or W̅A̅I̅T̅ enable
		CR1_RWS   = 0x02, // R̅E̅Q̅U̅E̅S̅T̅ or W̅A̅I̅T̅ select
		CR1_SDBC  = 0x04, // start dma on byte count
		CR1_SDPM  = 0x08, // stop dma on pattern match
		CR1_MMRUS = 0x10, // message mailbox register under service (read only)
		CR1_MMRF  = 0x20, // message mailbox register full (read only)
		CR1_FBCR  = 0x40, // freeze byte count register

		CR1_WMASK = 0x4f,
	};
	enum control_2_mask : u8
	{
		CR2_P2EN  = 0x01, // port 2 side enable
		CR2_P2HE  = 0x02, // port 2 side handshake enable

		CR2_WMASK = 0x03,
	};
	enum control_3_mask : u8
	{
		CR3_P2IN0  = 0x01, // port 2 input line 0
		CR3_P2OUT1 = 0x02, // port 2 output line 1
		CR3_UNUSED = 0x04, // not used (mut be programmed 0)
		CR3_P2OUT3 = 0x08, // port 2 output line 3
		CR3_DIR    = 0x10, // data direction
		CR3_P2DIR  = 0x20, // port 2 controls direction
		CR3_CLR    = 0x40, // clear fifo (active low)
		CR3_P2CLR  = 0x80, // port 2 controls clear
	};
	enum interrupt_status_0_mask : u8
	{
		ISR0_MIP    = 0x20, // message interrupt pending
		ISR0_MIE    = 0x40, // message interrupt enable
		ISR0_MIUS   = 0x80, // message interrupt under service

		ISR0_WMASK  = 0xe0
	};
	enum interrupt_status_1_mask : u8
	{
		ISR1_PMF    = 0x01, // pattern match flag
		ISR1_PMIP   = 0x02, // pattern match interrupt pending
		ISR1_PMIE   = 0x04, // pattern match interrupt enable
		ISR1_PMIUS  = 0x08, // pattern match interrupt under service
		ISR1_DDCIP  = 0x20, // data direction change interrupt pending
		ISR1_DDCIE  = 0x40, // data direction change interrupt enable
		ISR1_DDCIUS = 0x80, // data direction change interrupt under service
	};
	enum interrupt_status_2_mask : u8
	{
		ISR2_UF     = 0x01, // underflow error
		ISR2_EIP    = 0x02, // error interrupt pending
		ISR2_EIE    = 0x04, // error interrupt enable
		ISR2_EIUS   = 0x08, // error interrupt under service
		ISR2_OF     = 0x10, // overflow error
		ISR2_BCCIP  = 0x20, // byte count compare interrupt pending
		ISR2_BCCIE  = 0x40, // byte count compare interrupt enable
		ISR2_BCCIUS = 0x80, // byte count compare interrupt under service
	};
	enum interrupt_status_3_mask : u8
	{
		ISR3_BE   = 0x01, // buffer empty
		ISR3_EIP  = 0x02, // empty interrupt pending
		ISR3_EIE  = 0x04, // empty interrupt enable
		ISR3_EIUS = 0x08, // empty interrupt under service
		ISR3_BF   = 0x10, // buffer full
		ISR3_FIP  = 0x20, // full interrupt pending
		ISR3_FIE  = 0x40, // full interrupt enable
		ISR3_FIUS = 0x80, // full interrupt under service
	};

	// generic interrupt status bit names
	enum interrupt_status_mask : u8
	{
		ISR_LIP  = 0x02,  // low interrupt pending
		ISR_LIE  = 0x04,  // low interrupt enable
		ISR_LIUS = 0x08,  // low interrupt under service
		ISR_HIP  = 0x20,  // high interrupt pending
		ISR_HIE  = 0x40,  // high interrupt enable
		ISR_HIUS = 0x80,  // high interrupt under service

		ISR_LMASK = 0x0e,
		ISR_HMASK = 0xe0,
	};

	devcb_write_line::array<2> m_out_int_cb;
	devcb_write_line m_out_E_cb; // pin number 35
	devcb_write_line m_out_F_cb; // pin number 34
	devcb_write_line m_out_H_cb; // pin number 32
	devcb_write_line m_out_J_cb; // pin number 30

	emu_timer *m_int_check;

	// registers largely or entirely controlled by port 1
	u8 m_control_2;
	u8 m_control_3;

	struct port_state
	{
		// non-register, per-port state
		u8 reg_state;
		u8 reg_pointer;
		u8 int_code;
		bool int_asserted;

		// accessible registers
		u8 control_0;
		u8 control_1;
		u8 interrupt_status[4];
		u8 interrupt_vector;
		u8 byte_count;
		u8 byte_count_comparison;
		u8 message_in;
		u8 pattern_match;
		u8 pattern_mask;
		u8 data_buffer;
	}
	m_port[2];

	util::fifo <u8, 128> m_fifo;
};

DECLARE_DEVICE_TYPE(Z8038, z8038_device)

#endif // MAME_MACHINE_Z8038_H