// license:BSD-3-Clause
// copyright-holders:Curt Coder
/***************************************************************************
Zilog Z80 Parallel Input/Output Controller implementation
***************************************************************************
_____ _____
D2 1 |* \_/ | 40 D3
D7 2 | | 39 D4
D6 3 | | 38 D5
_CE 4 | | 37 _M1
C/_D 5 | | 36 _IORQ
B/_A 6 | | 35 RD
PA7 7 | | 34 PB7
PA6 8 | | 33 PB6
PA5 9 | | 32 PB5
PA4 10 | Z8420 | 31 PB4
GND 11 | | 30 PB3
PA3 12 | | 29 PB2
PA2 13 | | 28 PB1
PA1 14 | | 27 PB0
PA0 15 | | 26 +5V
_ASTB 16 | | 25 CLK
_BSTB 17 | | 24 IEI
ARDY 18 | | 23 _INT
D0 19 | | 22 IEO
D1 20 |_____________| 21 BRDY
***************************************************************************/
#ifndef MAME_MACHINE_Z80PIO_H
#define MAME_MACHINE_Z80PIO_H
#pragma once
#include "machine/z80daisy.h"
//**************************************************************************
// DEVICE CONFIGURATION MACROS
//**************************************************************************
#define MCFG_Z80PIO_OUT_INT_CB(_devcb) \
devcb = &downcast<z80pio_device &>(*device).set_out_int_callback(DEVCB_##_devcb);
#define MCFG_Z80PIO_IN_PA_CB(_devcb) \
devcb = &downcast<z80pio_device &>(*device).set_in_pa_callback(DEVCB_##_devcb);
#define MCFG_Z80PIO_OUT_PA_CB(_devcb) \
devcb = &downcast<z80pio_device &>(*device).set_out_pa_callback(DEVCB_##_devcb);
#define MCFG_Z80PIO_OUT_ARDY_CB(_devcb) \
devcb = &downcast<z80pio_device &>(*device).set_out_ardy_callback(DEVCB_##_devcb);
#define MCFG_Z80PIO_IN_PB_CB(_devcb) \
devcb = &downcast<z80pio_device &>(*device).set_in_pb_callback(DEVCB_##_devcb);
#define MCFG_Z80PIO_OUT_PB_CB(_devcb) \
devcb = &downcast<z80pio_device &>(*device).set_out_pb_callback(DEVCB_##_devcb);
#define MCFG_Z80PIO_OUT_BRDY_CB(_devcb) \
devcb = &downcast<z80pio_device &>(*device).set_out_brdy_callback(DEVCB_##_devcb);
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
// ======================> z80pio_device
class z80pio_device : public device_t,
public device_z80daisy_interface
{
public:
enum
{
PORT_A = 0,
PORT_B,
PORT_COUNT
};
// construction/destruction
z80pio_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
template <class Object> devcb_base &set_out_int_callback(Object &&cb) { return m_out_int_cb.set_callback(std::forward<Object>(cb)); }
template <class Object> devcb_base &set_in_pa_callback(Object &&cb) { return m_in_pa_cb.set_callback(std::forward<Object>(cb)); }
template <class Object> devcb_base &set_out_pa_callback(Object &&cb) { return m_out_pa_cb.set_callback(std::forward<Object>(cb)); }
template <class Object> devcb_base &set_out_ardy_callback(Object &&cb) { return m_out_ardy_cb.set_callback(std::forward<Object>(cb)); }
template <class Object> devcb_base &set_in_pb_callback(Object &&cb) { return m_in_pb_cb.set_callback(std::forward<Object>(cb)); }
template <class Object> devcb_base &set_out_pb_callback(Object &&cb) { return m_out_pb_cb.set_callback(std::forward<Object>(cb)); }
template <class Object> devcb_base &set_out_brdy_callback(Object &&cb) { return m_out_brdy_cb.set_callback(std::forward<Object>(cb)); }
// I/O line access
int rdy(int which) { return m_port[which].rdy(); }
void strobe(int which, bool state) { m_port[which].strobe(state); }
DECLARE_READ_LINE_MEMBER( rdy_a ) { return rdy(PORT_A); }
DECLARE_READ_LINE_MEMBER( rdy_b ) { return rdy(PORT_B); }
DECLARE_WRITE_LINE_MEMBER( strobe_a ) { strobe(PORT_A, state); }
DECLARE_WRITE_LINE_MEMBER( strobe_b ) { strobe(PORT_B, state); }
// control register I/O
uint8_t control_read();
void control_write(int offset, uint8_t data) { m_port[offset & 1].control_write(data); }
void control_a_write(uint8_t data) { control_write(PORT_A, data); }
void control_b_write(uint8_t data) { control_write(PORT_B, data); }
// data register I/O
uint8_t data_read(int offset) { return m_port[offset & 1].data_read(); }
void data_write(int offset, uint8_t data) { m_port[offset & 1].data_write(data); }
uint8_t data_a_read() { return data_read(PORT_A); }
uint8_t data_b_read() { return data_read(PORT_B); }
void data_a_write(uint8_t data) { data_write(PORT_A, data); }
void data_b_write(uint8_t data) { data_write(PORT_B, data); }
// port I/O
uint8_t port_read(int offset) { return m_port[offset & 1].read(); }
void port_write(int offset, uint8_t data) { m_port[offset & 1].write(data); }
void port_write(int offset, int bit, int state) { port_write(offset, (m_port[offset & 1].m_input & ~(1 << bit)) | (state << bit)); }
uint8_t port_a_read() { return port_read(PORT_A); }
uint8_t port_b_read() { return port_read(PORT_B); }
void port_a_write(uint8_t data) { port_write(PORT_A, data); }
void port_b_write(uint8_t data) { port_write(PORT_B, data); }
DECLARE_WRITE8_MEMBER( pa_w ) { port_a_write(data); }
DECLARE_READ8_MEMBER( pa_r ) { return port_a_read(); }
DECLARE_WRITE8_MEMBER( pb_w ) { port_b_write(data); }
DECLARE_READ8_MEMBER( pb_r ) { return port_b_read(); }
DECLARE_WRITE_LINE_MEMBER( pa0_w ) { port_write(PORT_A, 0, state); }
DECLARE_WRITE_LINE_MEMBER( pa1_w ) { port_write(PORT_A, 1, state); }
DECLARE_WRITE_LINE_MEMBER( pa2_w ) { port_write(PORT_A, 2, state); }
DECLARE_WRITE_LINE_MEMBER( pa3_w ) { port_write(PORT_A, 3, state); }
DECLARE_WRITE_LINE_MEMBER( pa4_w ) { port_write(PORT_A, 4, state); }
DECLARE_WRITE_LINE_MEMBER( pa5_w ) { port_write(PORT_A, 5, state); }
DECLARE_WRITE_LINE_MEMBER( pa6_w ) { port_write(PORT_A, 6, state); }
DECLARE_WRITE_LINE_MEMBER( pa7_w ) { port_write(PORT_A, 7, state); }
DECLARE_WRITE_LINE_MEMBER( pb0_w ) { port_write(PORT_B, 0, state); }
DECLARE_WRITE_LINE_MEMBER( pb1_w ) { port_write(PORT_B, 1, state); }
DECLARE_WRITE_LINE_MEMBER( pb2_w ) { port_write(PORT_B, 2, state); }
DECLARE_WRITE_LINE_MEMBER( pb3_w ) { port_write(PORT_B, 3, state); }
DECLARE_WRITE_LINE_MEMBER( pb4_w ) { port_write(PORT_B, 4, state); }
DECLARE_WRITE_LINE_MEMBER( pb5_w ) { port_write(PORT_B, 5, state); }
DECLARE_WRITE_LINE_MEMBER( pb6_w ) { port_write(PORT_B, 6, state); }
DECLARE_WRITE_LINE_MEMBER( pb7_w ) { port_write(PORT_B, 7, state); }
// standard read/write, with C/D in bit 1, B/A in bit 0
DECLARE_READ8_MEMBER( read );
DECLARE_WRITE8_MEMBER( write );
// alternate read/write, with C/D in bit 0, B/A in bit 1
DECLARE_READ8_MEMBER( read_alt );
DECLARE_WRITE8_MEMBER( write_alt );
private:
enum
{
MODE_OUTPUT = 0,
MODE_INPUT,
MODE_BIDIRECTIONAL,
MODE_BIT_CONTROL
};
enum
{
ANY = 0,
IOR,
MASK
};
enum
{
ICW_ENABLE_INT = 0x80,
ICW_AND_OR = 0x40,
ICW_AND = 0x40,
ICW_OR = 0x00,
ICW_HIGH_LOW = 0x20,
ICW_HIGH = 0x20,
ICW_LOW = 0x00,
ICW_MASK_FOLLOWS = 0x10
};
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
// device_z80daisy_interface overrides
virtual int z80daisy_irq_state() override;
virtual int z80daisy_irq_ack() override;
virtual void z80daisy_irq_reti() override;
// internal helpers
void check_interrupts();
// a single PIO port
class pio_port
{
friend class z80pio_device;
public:
pio_port();
void start(z80pio_device *device, int index);
void reset();
void trigger_interrupt();
int rdy() const { return m_rdy; }
void set_rdy(bool state);
void set_mode(int mode);
void strobe(bool state);
uint8_t read();
void write(uint8_t data);
void control_write(uint8_t data);
uint8_t data_read();
void data_write(uint8_t data);
private:
void check_interrupts() { m_device->check_interrupts(); }
z80pio_device * m_device;
int m_index;
int m_mode; // mode register
int m_next_control_word; // next control word
uint8_t m_input; // input latch
uint8_t m_output; // output latch
uint8_t m_ior; // input/output register
bool m_rdy; // ready
bool m_stb; // strobe
// interrupts
bool m_ie; // interrupt enabled
bool m_ip; // interrupt pending
bool m_ius; // interrupt under service
uint8_t m_icw; // interrupt control word
uint8_t m_vector; // interrupt vector
uint8_t m_mask; // interrupt mask
bool m_match; // logic equation match
};
// internal state
pio_port m_port[2];
devcb_write_line m_out_int_cb;
devcb_read8 m_in_pa_cb;
devcb_write8 m_out_pa_cb;
devcb_write_line m_out_ardy_cb;
devcb_read8 m_in_pb_cb;
devcb_write8 m_out_pb_cb;
devcb_write_line m_out_brdy_cb;
};
// device type definition
DECLARE_DEVICE_TYPE(Z80PIO, z80pio_device)
#endif // MAME_MACHINE_Z80PIO_H