1 // license:BSD-3-Clause
2 // copyright-holders:Curt Coder
3 /***************************************************************************
4 
5     Zilog Z80 Parallel Input/Output Controller implementation
6 
7 ***************************************************************************
8                             _____   _____
9                     D2   1 |*    \_/     | 40  D3
10                     D7   2 |             | 39  D4
11                     D6   3 |             | 38  D5
12                    _CE   4 |             | 37  _M1
13                   C/_D   5 |             | 36  _IORQ
14                   B/_A   6 |             | 35  RD
15                    PA7   7 |             | 34  PB7
16                    PA6   8 |             | 33  PB6
17                    PA5   9 |             | 32  PB5
18                    PA4  10 |    Z8420    | 31  PB4
19                    GND  11 |             | 30  PB3
20                    PA3  12 |             | 29  PB2
21                    PA2  13 |             | 28  PB1
22                    PA1  14 |             | 27  PB0
23                    PA0  15 |             | 26  +5V
24                  _ASTB  16 |             | 25  CLK
25                  _BSTB  17 |             | 24  IEI
26                   ARDY  18 |             | 23  _INT
27                     D0  19 |             | 22  IEO
28                     D1  20 |_____________| 21  BRDY
29 
30 ***************************************************************************/
31 
32 #ifndef MAME_MACHINE_Z80PIO_H
33 #define MAME_MACHINE_Z80PIO_H
34 
35 #pragma once
36 
37 #include "machine/z80daisy.h"
38 
39 
40 //**************************************************************************
41 //  TYPE DEFINITIONS
42 //**************************************************************************
43 
44 
45 // ======================> z80pio_device
46 
47 class z80pio_device :   public device_t,
48 						public device_z80daisy_interface
49 {
50 public:
51 	enum
52 	{
53 		PORT_A = 0,
54 		PORT_B,
55 		PORT_COUNT
56 	};
57 
58 	// construction/destruction
59 	z80pio_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
60 
out_int_callback()61 	auto out_int_callback() { return m_out_int_cb.bind(); }
in_pa_callback()62 	auto in_pa_callback() { return m_in_pa_cb.bind(); }
out_pa_callback()63 	auto out_pa_callback() { return m_out_pa_cb.bind(); }
out_ardy_callback()64 	auto out_ardy_callback() { return m_out_ardy_cb.bind(); }
in_pb_callback()65 	auto in_pb_callback() { return m_in_pb_cb.bind(); }
out_pb_callback()66 	auto out_pb_callback() { return m_out_pb_cb.bind(); }
out_brdy_callback()67 	auto out_brdy_callback() { return m_out_brdy_cb.bind(); }
68 
69 
70 	// I/O line access
rdy(int which)71 	int rdy(int which) { return m_port[which].rdy(); }
strobe(int which,bool state)72 	void strobe(int which, bool state) { m_port[which].strobe(state); }
DECLARE_READ_LINE_MEMBER(rdy_a)73 	DECLARE_READ_LINE_MEMBER( rdy_a ) { return rdy(PORT_A); }
DECLARE_READ_LINE_MEMBER(rdy_b)74 	DECLARE_READ_LINE_MEMBER( rdy_b ) { return rdy(PORT_B); }
DECLARE_WRITE_LINE_MEMBER(strobe_a)75 	DECLARE_WRITE_LINE_MEMBER( strobe_a ) { strobe(PORT_A, state); }
DECLARE_WRITE_LINE_MEMBER(strobe_b)76 	DECLARE_WRITE_LINE_MEMBER( strobe_b ) { strobe(PORT_B, state); }
77 
78 	// control register I/O
79 	uint8_t control_read();
control_write(int offset,uint8_t data)80 	void control_write(int offset, uint8_t data) { m_port[offset & 1].control_write(data); }
control_a_write(uint8_t data)81 	void control_a_write(uint8_t data) { control_write(PORT_A, data); }
control_b_write(uint8_t data)82 	void control_b_write(uint8_t data) { control_write(PORT_B, data); }
83 
84 	// data register I/O
data_read(int offset)85 	uint8_t data_read(int offset) { return m_port[offset & 1].data_read(); }
data_write(int offset,uint8_t data)86 	void data_write(int offset, uint8_t data) { m_port[offset & 1].data_write(data); }
data_a_read()87 	uint8_t data_a_read() { return data_read(PORT_A); }
data_b_read()88 	uint8_t data_b_read() { return data_read(PORT_B); }
data_a_write(uint8_t data)89 	void data_a_write(uint8_t data) { data_write(PORT_A, data); }
data_b_write(uint8_t data)90 	void data_b_write(uint8_t data) { data_write(PORT_B, data); }
91 
92 	// port I/O
port_read(int offset)93 	uint8_t port_read(int offset) { return m_port[offset & 1].read(); }
port_write(int offset,uint8_t data)94 	void port_write(int offset, uint8_t data) { m_port[offset & 1].write(data); }
port_write(int offset,int bit,int state)95 	void port_write(int offset, int bit, int state) { port_write(offset, (m_port[offset & 1].m_input & ~(1 << bit)) | (state << bit));  }
port_a_read()96 	uint8_t port_a_read() { return port_read(PORT_A); }
port_b_read()97 	uint8_t port_b_read() { return port_read(PORT_B); }
port_a_write(uint8_t data)98 	void port_a_write(uint8_t data) { port_write(PORT_A, data); }
port_b_write(uint8_t data)99 	void port_b_write(uint8_t data) { port_write(PORT_B, data); }
DECLARE_WRITE_LINE_MEMBER(pa0_w)100 	DECLARE_WRITE_LINE_MEMBER( pa0_w ) { port_write(PORT_A, 0, state); }
DECLARE_WRITE_LINE_MEMBER(pa1_w)101 	DECLARE_WRITE_LINE_MEMBER( pa1_w ) { port_write(PORT_A, 1, state); }
DECLARE_WRITE_LINE_MEMBER(pa2_w)102 	DECLARE_WRITE_LINE_MEMBER( pa2_w ) { port_write(PORT_A, 2, state); }
DECLARE_WRITE_LINE_MEMBER(pa3_w)103 	DECLARE_WRITE_LINE_MEMBER( pa3_w ) { port_write(PORT_A, 3, state); }
DECLARE_WRITE_LINE_MEMBER(pa4_w)104 	DECLARE_WRITE_LINE_MEMBER( pa4_w ) { port_write(PORT_A, 4, state); }
DECLARE_WRITE_LINE_MEMBER(pa5_w)105 	DECLARE_WRITE_LINE_MEMBER( pa5_w ) { port_write(PORT_A, 5, state); }
DECLARE_WRITE_LINE_MEMBER(pa6_w)106 	DECLARE_WRITE_LINE_MEMBER( pa6_w ) { port_write(PORT_A, 6, state); }
DECLARE_WRITE_LINE_MEMBER(pa7_w)107 	DECLARE_WRITE_LINE_MEMBER( pa7_w ) { port_write(PORT_A, 7, state); }
DECLARE_WRITE_LINE_MEMBER(pb0_w)108 	DECLARE_WRITE_LINE_MEMBER( pb0_w ) { port_write(PORT_B, 0, state); }
DECLARE_WRITE_LINE_MEMBER(pb1_w)109 	DECLARE_WRITE_LINE_MEMBER( pb1_w ) { port_write(PORT_B, 1, state); }
DECLARE_WRITE_LINE_MEMBER(pb2_w)110 	DECLARE_WRITE_LINE_MEMBER( pb2_w ) { port_write(PORT_B, 2, state); }
DECLARE_WRITE_LINE_MEMBER(pb3_w)111 	DECLARE_WRITE_LINE_MEMBER( pb3_w ) { port_write(PORT_B, 3, state); }
DECLARE_WRITE_LINE_MEMBER(pb4_w)112 	DECLARE_WRITE_LINE_MEMBER( pb4_w ) { port_write(PORT_B, 4, state); }
DECLARE_WRITE_LINE_MEMBER(pb5_w)113 	DECLARE_WRITE_LINE_MEMBER( pb5_w ) { port_write(PORT_B, 5, state); }
DECLARE_WRITE_LINE_MEMBER(pb6_w)114 	DECLARE_WRITE_LINE_MEMBER( pb6_w ) { port_write(PORT_B, 6, state); }
DECLARE_WRITE_LINE_MEMBER(pb7_w)115 	DECLARE_WRITE_LINE_MEMBER( pb7_w ) { port_write(PORT_B, 7, state); }
116 
117 	// standard read/write, with C/D in bit 1, B/A in bit 0
118 	u8 read(offs_t offset);
119 	void write(offs_t offset, u8 data);
120 
121 	// alternate read/write, with C/D in bit 0, B/A in bit 1
122 	u8 read_alt(offs_t offset);
123 	void write_alt(offs_t offset, u8 data);
124 
125 private:
126 	enum
127 	{
128 		MODE_OUTPUT = 0,
129 		MODE_INPUT,
130 		MODE_BIDIRECTIONAL,
131 		MODE_BIT_CONTROL
132 	};
133 
134 	enum
135 	{
136 		ANY = 0,
137 		IOR,
138 		MASK
139 	};
140 
141 	enum
142 	{
143 		ICW_ENABLE_INT    = 0x80,
144 		ICW_AND_OR        = 0x40,
145 		ICW_AND           = 0x40,
146 		ICW_OR            = 0x00,
147 		ICW_HIGH_LOW      = 0x20,
148 		ICW_HIGH          = 0x20,
149 		ICW_LOW           = 0x00,
150 		ICW_MASK_FOLLOWS  = 0x10
151 	};
152 
153 	// device-level overrides
154 	virtual void device_start() override;
155 	virtual void device_reset() override;
156 
157 	// device_z80daisy_interface overrides
158 	virtual int z80daisy_irq_state() override;
159 	virtual int z80daisy_irq_ack() override;
160 	virtual void z80daisy_irq_reti() override;
161 
162 	// internal helpers
163 	void check_interrupts();
164 
165 	// a single PIO port
166 	class pio_port
167 	{
168 		friend class z80pio_device;
169 
170 	public:
171 		pio_port();
172 
173 		void start(z80pio_device *device, int index);
174 		void reset();
175 
176 		void trigger_interrupt();
177 
rdy()178 		int rdy() const { return m_rdy; }
179 		void set_rdy(bool state);
180 		void set_mode(int mode);
181 		void strobe(bool state);
182 
183 		uint8_t read();
184 		void write(uint8_t data);
185 
186 		void control_write(uint8_t data);
187 
188 		uint8_t data_read();
189 		void data_write(uint8_t data);
190 
191 	private:
check_interrupts()192 		void check_interrupts() { m_device->check_interrupts(); }
193 
194 		z80pio_device *             m_device;
195 		int                         m_index;
196 
197 		int m_mode;                 // mode register
198 		int m_next_control_word;    // next control word
199 		uint8_t m_input;              // input latch
200 		uint8_t m_output;             // output latch
201 		uint8_t m_ior;                // input/output register
202 		bool m_rdy;                 // ready
203 		bool m_stb;                 // strobe
204 
205 		// interrupts
206 		bool m_ie;                  // interrupt enabled
207 		bool m_ip;                  // interrupt pending
208 		bool m_ius;                 // interrupt under service
209 		uint8_t m_icw;                // interrupt control word
210 		uint8_t m_vector;             // interrupt vector
211 		uint8_t m_mask;               // interrupt mask
212 		bool m_match;               // logic equation match
213 	};
214 
215 	// internal state
216 	pio_port             m_port[2];
217 	devcb_write_line    m_out_int_cb;
218 
219 	devcb_read8         m_in_pa_cb;
220 	devcb_write8        m_out_pa_cb;
221 	devcb_write_line    m_out_ardy_cb;
222 
223 	devcb_read8         m_in_pb_cb;
224 	devcb_write8        m_out_pb_cb;
225 	devcb_write_line    m_out_brdy_cb;
226 };
227 
228 
229 // device type definition
230 DECLARE_DEVICE_TYPE(Z80PIO, z80pio_device)
231 
232 #endif // MAME_MACHINE_Z80PIO_H
233