summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/cxd1095.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/machine/cxd1095.cpp')
-rw-r--r--src/devices/machine/cxd1095.cpp138
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]);
+ }
+}