diff options
Diffstat (limited to 'src/mame/machine/vs9209.cpp')
-rw-r--r-- | src/mame/machine/vs9209.cpp | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/src/mame/machine/vs9209.cpp b/src/mame/machine/vs9209.cpp new file mode 100644 index 00000000000..02620a286a1 --- /dev/null +++ b/src/mame/machine/vs9209.cpp @@ -0,0 +1,157 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/********************************************************************** + + VS9209 (4L01F1429) custom QFP80 I/O + + This chip, which appears on various Video System PCBs from 1992 + to 1995, provides a programmable interface for up to eight ports. + + There are at least four configuration registers that control the + directions of individual bits on some of the ports (low for input + and high for output). However, the game programs always write + zero to the first register, except for Super Slams which doesn't + write to it at all. + + No program attempts to write to Ports A, B, C or D, with the + dubious exception of Tao Taido writing to the Port C offset on + its second VS9209 (whose inputs are mostly unused) at + initialization time. It seems possible that only the latter four + ports may be configured for output. + + Much like CXD1095, the last port is apparently only half width. + +**********************************************************************/ + +#include "emu.h" +#include "machine/vs9209.h" + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type VS9209 = device_creator<vs9209_device>; + +//************************************************************************** +// DEVICE DEFINITION +//************************************************************************** + +//------------------------------------------------- +// vs9209_device - constructor +//------------------------------------------------- + +vs9209_device::vs9209_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : device_t(mconfig, VS9209, "VS9209 I/O", tag, owner, clock, "vs9209", __FILE__), + m_input_cb{{*this}, {*this}, {*this}, {*this}, {*this}, {*this}, {*this}, {*this}}, + m_output_cb{{*this}, {*this}, {*this}, {*this}, {*this}, {*this}, {*this}, {*this}} +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void vs9209_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); + + // save state + save_item(NAME(m_data_latch)); + save_item(NAME(m_data_dir)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void vs9209_device::device_reset() +{ + std::fill(std::begin(m_data_dir), std::end(m_data_dir), 0); +} + +//------------------------------------------------- +// read - read from an input port +//------------------------------------------------- + +READ8_MEMBER(vs9209_device::read) +{ + int port = offset & 7; + + if ((offset & 8) == 0) + { + u8 input_data = 0; + u8 input_mask = ~m_data_dir[port]; + if (port == 7) + input_mask &= 0x0f; + + // read through callback if port not configured entirely for output + if (input_mask != 0 && !m_input_cb[port].isnull()) + input_data = m_input_cb[port](0, input_mask) & input_mask; + else if (m_data_dir[port] == 0) + logerror("%s: Read from undefined input port %c\n", machine().describe_context(), 'A' + port); + + // combine live inputs with latched data + return input_data | (m_data_latch[port] & m_data_dir[port]); + } + + //logerror("%s: Read from write-only/nonexistent register %d\n", machine().describe_context(), offset); + return space.unmap(); +} + +//------------------------------------------------- +// write - write to an output port or one of two +// control registers +//------------------------------------------------- + +WRITE8_MEMBER(vs9209_device::write) +{ + // port H is probably only 4 bits wide + int port = offset & 7; + if (port == 7 && (data & 0xf0) != 0) + { + logerror("%s: Attempt to write %02X to port H%s", machine().describe_context(), data, (offset & 8) != 0 ? " direction register" : ""); + data &= 0x0f; + } + + if ((offset & 8) == 0) + { + // update our latched data + m_data_latch[port] = data; + + if (m_data_dir[port] != 0) + { + u8 dataout = data & m_data_dir[port]; + + // send output through callback + if (!m_output_cb[port].isnull()) + m_output_cb[port](0, dataout, m_data_dir[port]); + else + logerror("%s: Writing %02X to undefined output port %c\n", machine().describe_context(), dataout, 'A' + port); + } + else if (m_output_cb[port].isnull()) + logerror("%s: Writing %02X to input-only port %c\n", machine().describe_context(), data, 'A' + port); + } + else + { + u8 old_data_dir = m_data_dir[port]; + m_data_dir[port] = data; + + u8 all_port_bits = (port == 7) ? 0x0f : 0xff; + if (data != all_port_bits) + logerror("Port %c & %02X configured for input\n", 'A' + port, all_port_bits ^ data); + if (data != 0) + { + logerror("Port %c & %02X configured for output\n", 'A' + port, data); + + // if direction changed to output, begin output from latch + if ((data & ~old_data_dir) != 0 && !m_output_cb[port].isnull()) + m_output_cb[port](0, m_data_latch[port], data); + } + } +} |