diff options
Diffstat (limited to 'src/devices/machine/cxd1095.cpp')
-rw-r--r-- | src/devices/machine/cxd1095.cpp | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/src/devices/machine/cxd1095.cpp b/src/devices/machine/cxd1095.cpp new file mode 100644 index 00000000000..430348de631 --- /dev/null +++ b/src/devices/machine/cxd1095.cpp @@ -0,0 +1,138 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +// thanks-to:Aaron Giles +/********************************************************************** + + Sony CXD1095 CMOS I/O Port Expander + + Based on Sega X Board driver by Aaron Giles + + This device provides four 8-bit ports (PA-PD) and one 4-bit port + (PE or PX). All these ports can be configured for input or for + output, entirely or in parts. The upper and lower halves of ports + A-D can be separately configured by the first of the two + write-only control registers. The second control register + determines the direction of individual PE/PX bits. + +**********************************************************************/ + +#include "emu.h" +#include "machine/cxd1095.h" + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type CXD1095 = device_creator<cxd1095_device>; + +//************************************************************************** +// DEVICE DEFINITION +//************************************************************************** + +//------------------------------------------------- +// cxd1095_device - constructor +//------------------------------------------------- + +cxd1095_device::cxd1095_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : device_t(mconfig, CXD1095, "CXD1095 I/O Expander", tag, owner, clock, "cxd1095", __FILE__), + m_input_cb{{*this}, {*this}, {*this}, {*this}, {*this}}, + m_output_cb{{*this}, {*this}, {*this}, {*this}, {*this}} +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cxd1095_device::device_start() +{ + // resolve callbacks + for (auto &cb : m_input_cb) + cb.resolve(); + for (auto &cb : m_output_cb) + cb.resolve(); + + std::fill(std::begin(m_data_latch), std::end(m_data_latch), 0); + std::fill(std::begin(m_data_dir), std::end(m_data_dir), 0xff); + + // save state + save_item(NAME(m_data_latch)); + save_item(NAME(m_data_dir)); +} + +//------------------------------------------------- +// read - read from an input port +//------------------------------------------------- + +READ8_MEMBER(cxd1095_device::read) +{ + if (offset < 5) + { + u8 input_data = 0; + u8 input_mask = m_data_dir[offset]; + if (offset == 4) + input_mask &= 0x0f; + + // read through callback if port not configured entirely for output + if (input_mask != 0 && !m_input_cb[offset].isnull()) + input_data = m_input_cb[offset](0, input_mask) & input_mask; + else if (m_data_dir[offset] == 0xff) + logerror("Reading from undefined input port %c\n", 'A' + offset); + + // combine live inputs with latched data + return input_data | (m_data_latch[offset] & ~m_data_dir[offset]); + } + + logerror("Reading from nonexistent port %c\n", 'A' + offset); + return 0; +} + +//------------------------------------------------- +// write - write to an output port or one of two +// control registers +//------------------------------------------------- + +WRITE8_MEMBER(cxd1095_device::write) +{ + if (offset < 5) + { + // port E is only 4 bits wide + if (offset == 4) + data &= 0x0f; + + // update our latched data + m_data_latch[offset] = data; + + // send output through callback + u8 dataout = data & ~m_data_dir[offset]; + if (!m_output_cb[offset].isnull()) + m_output_cb[offset](0, dataout, ~m_data_dir[offset]); + else + logerror("Writing %02X to undefined output port %c\n", dataout, 'A' + offset); + } + else if (offset == 6) + { + // control register 1 determines direction of each half of ports A-D + for (int port = 0; port < 4; port++) + { + m_data_dir[port] = (BIT(data, 0) ? 0x0f : 0) | (BIT(data, 1) ? 0xf0 : 0); + + if (m_data_dir[port] != 0) + logerror("Port %c & %02X configured for input\n", 'A' + port, m_data_dir[port]); + if (m_data_dir[port] != 0xff) + logerror("Port %c & %02X configured for output\n", 'A' + port, 0xff ^ m_data_dir[port]); + + data >>= 2; + } + } + else if (offset == 7) + { + // control register 2 determines direction of the four port E bits + m_data_dir[4] = (data & 0x0f) | 0xf0; + + if (m_data_dir[4] != 0xf0) + logerror("Port E & %X configured for input\n", 0x0f & m_data_dir[4]); + if (m_data_dir[4] != 0xff) + logerror("Port E & %X configured for output\n", 0xff ^ m_data_dir[4]); + } +} |