summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/emu/machine/i8255.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/emu/machine/i8255.c')
-rw-r--r--trunk/src/emu/machine/i8255.c1031
1 files changed, 1031 insertions, 0 deletions
diff --git a/trunk/src/emu/machine/i8255.c b/trunk/src/emu/machine/i8255.c
new file mode 100644
index 00000000000..b2543a5a231
--- /dev/null
+++ b/trunk/src/emu/machine/i8255.c
@@ -0,0 +1,1031 @@
+/**********************************************************************
+
+ Intel 8255(A) Programmable Peripheral Interface emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "i8255.h"
+#include "machine/devhelpr.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define LOG 0
+
+
+enum
+{
+ PORT_A = 0,
+ PORT_B,
+ PORT_C,
+ CONTROL
+};
+
+
+enum
+{
+ GROUP_A = 0,
+ GROUP_B
+};
+
+
+enum
+{
+ MODE_0 = 0,
+ MODE_1,
+ MODE_2
+};
+
+
+enum
+{
+ MODE_OUTPUT = 0,
+ MODE_INPUT,
+};
+
+
+#define CONTROL_PORT_C_LOWER_INPUT 0x01
+#define CONTROL_PORT_B_INPUT 0x02
+#define CONTROL_GROUP_B_MODE_1 0x04
+#define CONTROL_PORT_C_UPPER_INPUT 0x08
+#define CONTROL_PORT_A_INPUT 0x10
+#define CONTROL_GROUP_A_MODE_MASK 0x60
+#define CONTROL_MODE_SET 0x80
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type I8255 = &device_creator<i8255_device>;
+const device_type I8255A = &device_creator<i8255_device>;
+
+
+
+//**************************************************************************
+// INLINE HELPERS
+//**************************************************************************
+
+//-------------------------------------------------
+// check_interrupt -
+//-------------------------------------------------
+
+inline void i8255_device::check_interrupt(int port)
+{
+ switch (group_mode(port))
+ {
+ case MODE_1:
+ switch (port_mode(port))
+ {
+ case MODE_INPUT:
+ set_intr(port, (m_inte[port] && m_ibf[port]));
+ break;
+
+ case MODE_OUTPUT:
+ set_intr(port, (m_inte[port] && m_obf[port]));
+ break;
+ }
+ break;
+
+ case MODE_2:
+ set_intr(port, ((m_inte1 && m_obf[port]) || (m_inte2 && m_ibf[port])));
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// set_ibf -
+//-------------------------------------------------
+
+inline void i8255_device::set_ibf(int port, int state)
+{
+ if (LOG) logerror("I8255 '%s' Port %c IBF: %u\n", tag(), 'A' + port, state);
+
+ m_ibf[port] = state;
+
+ check_interrupt(port);
+}
+
+
+//-------------------------------------------------
+// set_obf -
+//-------------------------------------------------
+
+inline void i8255_device::set_obf(int port, int state)
+{
+ if (LOG) logerror("I8255 '%s' Port %c OBF: %u\n", tag(), 'A' + port, state);
+
+ m_obf[port] = state;
+
+ check_interrupt(port);
+}
+
+
+//-------------------------------------------------
+// set_inte -
+//-------------------------------------------------
+
+inline void i8255_device::set_inte(int port, int state)
+{
+ if (LOG) logerror("I8255 '%s' Port %c INTE: %u\n", tag(), 'A' + port, state);
+
+ m_inte[port] = state;
+
+ check_interrupt(port);
+}
+
+
+//-------------------------------------------------
+// set_inte1 -
+//-------------------------------------------------
+
+inline void i8255_device::set_inte1(int state)
+{
+ if (LOG) logerror("I8255 '%s' Port A INTE1: %u\n", tag(), state);
+
+ m_inte1 = state;
+
+ check_interrupt(PORT_A);
+}
+
+
+//-------------------------------------------------
+// set_inte2 -
+//-------------------------------------------------
+
+inline void i8255_device::set_inte2(int state)
+{
+ if (LOG) logerror("I8255 '%s' Port A INTE2: %u\n", tag(), state);
+
+ m_inte2 = state;
+
+ check_interrupt(PORT_A);
+}
+
+
+//-------------------------------------------------
+// set_intr -
+//-------------------------------------------------
+
+inline void i8255_device::set_intr(int port, int state)
+{
+ if (LOG) logerror("I8255 '%s' Port %c INTR: %u\n", tag(), 'A' + port, state);
+
+ m_intr[port] = state;
+
+ output_pc();
+}
+
+
+//-------------------------------------------------
+// group_mode -
+//-------------------------------------------------
+
+inline int i8255_device::group_mode(int group)
+{
+ int mode = 0;
+
+ switch (group)
+ {
+ case GROUP_A:
+ switch ((m_control & CONTROL_GROUP_A_MODE_MASK) >> 5)
+ {
+ case 0: mode = MODE_0; break;
+ case 1: mode = MODE_1; break;
+ case 2: case 3: mode = MODE_2; break;
+ }
+ break;
+
+ case GROUP_B:
+ mode = m_control & CONTROL_GROUP_B_MODE_1 ? MODE_1 : MODE_0;
+ break;
+ }
+
+ return mode;
+}
+
+
+//-------------------------------------------------
+// port_mode -
+//-------------------------------------------------
+
+inline int i8255_device::port_mode(int port)
+{
+ int mode = 0;
+
+ switch (port)
+ {
+ case PORT_A: mode = m_control & CONTROL_PORT_A_INPUT ? MODE_INPUT : MODE_OUTPUT; break;
+ case PORT_B: mode = m_control & CONTROL_PORT_B_INPUT ? MODE_INPUT : MODE_OUTPUT; break;
+ }
+
+ return mode;
+}
+
+
+//-------------------------------------------------
+// port_c_lower_mode -
+//-------------------------------------------------
+
+inline int i8255_device::port_c_lower_mode()
+{
+ return m_control & CONTROL_PORT_C_LOWER_INPUT ? MODE_INPUT : MODE_OUTPUT;
+}
+
+
+//-------------------------------------------------
+// port_c_upper_mode -
+//-------------------------------------------------
+
+inline int i8255_device::port_c_upper_mode()
+{
+ return m_control & CONTROL_PORT_C_UPPER_INPUT ? MODE_INPUT : MODE_OUTPUT;
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// i8255_device - constructor
+//-------------------------------------------------
+
+i8255_device::i8255_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, I8255, "I8255", tag, owner, clock)
+{
+ m_intr[PORT_A] = m_intr[PORT_B] = 0;
+}
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void i8255_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const i8255_interface *intf = reinterpret_cast<const i8255_interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<i8255_interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_in_pa_cb, 0, sizeof(m_in_pa_cb));
+ memset(&m_out_pa_cb, 0, sizeof(m_out_pa_cb));
+ memset(&m_in_pb_cb, 0, sizeof(m_in_pb_cb));
+ memset(&m_out_pb_cb, 0, sizeof(m_out_pb_cb));
+ memset(&m_in_pc_cb, 0, sizeof(m_in_pc_cb));
+ memset(&m_out_pc_cb, 0, sizeof(m_out_pc_cb));
+ }
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void i8255_device::device_start()
+{
+ // resolve callbacks
+ m_in_port_func[PORT_A].resolve(m_in_pa_cb, *this);
+ m_out_port_func[PORT_A].resolve(m_out_pa_cb, *this);
+ m_in_port_func[PORT_B].resolve(m_in_pb_cb, *this);
+ m_out_port_func[PORT_B].resolve(m_out_pb_cb, *this);
+ m_in_port_func[PORT_C].resolve(m_in_pc_cb, *this);
+ m_out_port_func[PORT_C].resolve(m_out_pc_cb, *this);
+
+ // register for state saving
+ save_item(NAME(m_control));
+ save_item(NAME(m_output));
+ save_item(NAME(m_input));
+ save_item(NAME(m_ibf));
+ save_item(NAME(m_obf));
+ save_item(NAME(m_inte));
+ save_item(NAME(m_inte1));
+ save_item(NAME(m_inte2));
+ save_item(NAME(m_intr));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void i8255_device::device_reset()
+{
+ set_mode(0x9b);
+}
+
+
+//-------------------------------------------------
+// read_mode0 -
+//-------------------------------------------------
+
+UINT8 i8255_device::read_mode0(int port)
+{
+ UINT8 data = 0;
+
+ if (port_mode(port) == MODE_OUTPUT)
+ {
+ // read data from output latch
+ data = m_output[port];
+ }
+ else
+ {
+ // read data from port
+ data = m_in_port_func[port](0);
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// read_mode1 -
+//-------------------------------------------------
+
+UINT8 i8255_device::read_mode1(int port)
+{
+ UINT8 data = 0;
+
+ if (port_mode(port) == MODE_OUTPUT)
+ {
+ // read data from output latch
+ data = m_output[port];
+ }
+ else
+ {
+ // read data from input latch
+ data = m_input[port];
+
+ // clear input buffer full flag
+ set_ibf(port, 0);
+
+ // clear interrupt
+ set_intr(port, 0);
+
+ // clear input latch
+ m_input[port] = 0;
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// read_mode2 -
+//-------------------------------------------------
+
+UINT8 i8255_device::read_mode2()
+{
+ UINT8 data = 0;
+
+ // read data from input latch
+ data = m_input[PORT_A];
+
+ // clear input buffer full flag
+ set_ibf(PORT_A, 0);
+
+ // clear interrupt
+ set_intr(PORT_A, 0);
+
+ // clear input latch
+ m_input[PORT_A] = 0;
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// read_pc -
+//-------------------------------------------------
+
+UINT8 i8255_device::read_pc()
+{
+ UINT8 data = 0;
+ UINT8 mask = 0;
+
+ // PC upper
+ switch (group_mode(GROUP_A))
+ {
+ case MODE_0:
+ if (port_c_upper_mode() == MODE_OUTPUT)
+ {
+ // read data from output latch
+ data |= m_output[PORT_C] & 0xf0;
+ }
+ else
+ {
+ // read data from port
+ mask |= 0xf0;
+ }
+ break;
+
+ case MODE_1:
+ data |= m_intr[PORT_A] ? 0x08 : 0x00;
+
+ if (port_mode(PORT_A) == MODE_OUTPUT)
+ {
+ data |= m_obf[PORT_A] ? 0x80 : 0x00;
+ data |= m_inte[PORT_A] ? 0x40 : 0x00;
+ mask |= 0x30;
+ }
+ else
+ {
+ data |= m_ibf[PORT_A] ? 0x20 : 0x00;
+ data |= m_inte[PORT_A] ? 0x10 : 0x00;
+ mask |= 0xc0;
+ }
+ break;
+
+ case MODE_2:
+ data |= m_intr[PORT_A] ? 0x08 : 0x00;
+ data |= m_inte2 ? 0x10 : 0x00;
+ data |= m_ibf[PORT_A] ? 0x20 : 0x00;
+ data |= m_inte1 ? 0x40 : 0x00;
+ data |= m_obf[PORT_A] ? 0x80 : 0x00;
+ break;
+ }
+
+ // PC lower
+ switch (group_mode(GROUP_B))
+ {
+ case MODE_0:
+ if (port_c_lower_mode() == MODE_OUTPUT)
+ {
+ // read data from output latch
+ data |= m_output[PORT_C] & 0x0f;
+ }
+ else
+ {
+ // read data from port
+ mask |= 0x0f;
+ }
+ break;
+
+ case MODE_1:
+ data |= m_inte[PORT_B] ? 0x04 : 0x00;
+ data |= m_intr[PORT_B] ? 0x01 : 0x00;
+
+ if (port_mode(PORT_B) == MODE_OUTPUT)
+ {
+ data |= m_obf[PORT_B] ? 0x02 : 0x00;
+ }
+ else
+ {
+ data |= m_ibf[PORT_B] ? 0x02 : 0x00;
+ }
+ }
+
+ if (mask)
+ {
+ // read data from port
+ data |= m_in_port_func[PORT_C](0) & mask;
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// write_mode0 -
+//-------------------------------------------------
+
+void i8255_device::write_mode0(int port, UINT8 data)
+{
+ if (port_mode(port) == MODE_OUTPUT)
+ {
+ // latch output data
+ m_output[port] = data;
+
+ // write data to port
+ m_out_port_func[port](0, data);
+ }
+}
+
+
+//-------------------------------------------------
+// write_mode1 -
+//-------------------------------------------------
+
+void i8255_device::write_mode1(int port, UINT8 data)
+{
+ if (port_mode(port) == MODE_OUTPUT)
+ {
+ // latch output data
+ m_output[port] = data;
+
+ // write data to port
+ m_out_port_func[port](0, data);
+
+ // set output buffer full flag
+ set_obf(port, 0);
+
+ // clear interrupt
+ set_intr(port, 0);
+ }
+}
+
+
+//-------------------------------------------------
+// write_mode2 -
+//-------------------------------------------------
+
+void i8255_device::write_mode2(UINT8 data)
+{
+ // latch output data
+ m_output[PORT_A] = data;
+
+ // write data to port
+ m_out_port_func[PORT_A](0, data);
+
+ // set output buffer full flag
+ set_obf(PORT_A, 0);
+
+ // clear interrupt
+ set_intr(PORT_A, 0);
+}
+
+
+//-------------------------------------------------
+// write_pc -
+//-------------------------------------------------
+
+void i8255_device::write_pc(UINT8 data)
+{
+ int changed = 0;
+
+ if (group_mode(GROUP_A) == MODE_0)
+ {
+ // PC upper
+ if (port_c_upper_mode() == MODE_OUTPUT)
+ {
+ m_output[PORT_C] = (data & 0xf0) | (m_output[PORT_C] & 0x0f);
+ changed = 1;
+ }
+
+ // PC lower
+ if (port_c_lower_mode() == MODE_OUTPUT)
+ {
+ m_output[PORT_C] = (m_output[PORT_C] & 0xf0) | (data & 0x0f);
+ changed = 1;
+ }
+ }
+
+ if (changed)
+ {
+ output_pc();
+ }
+}
+
+
+//-------------------------------------------------
+// output_pc -
+//-------------------------------------------------
+
+void i8255_device::output_pc()
+{
+ UINT8 data = 0;
+ UINT8 mask = 0;
+
+ // PC upper
+ switch (group_mode(GROUP_A))
+ {
+ case MODE_0:
+ if (port_c_upper_mode() == MODE_OUTPUT)
+ {
+ mask |= 0xf0;
+ }
+ else
+ {
+ // TTL inputs float high
+ data |= 0xf0;
+ }
+ break;
+
+ case MODE_1:
+ data |= m_intr[PORT_A] ? 0x08 : 0x00;
+
+ if (port_mode(PORT_A) == MODE_OUTPUT)
+ {
+ data |= m_obf[PORT_A] ? 0x80 : 0x00;
+ mask |= 0x30;
+ }
+ else
+ {
+ data |= m_ibf[PORT_A] ? 0x20 : 0x00;
+ mask |= 0xc0;
+ }
+ break;
+
+ case MODE_2:
+ data |= m_intr[PORT_A] ? 0x08 : 0x00;
+ data |= m_ibf[PORT_A] ? 0x20 : 0x00;
+ data |= m_obf[PORT_A] ? 0x80 : 0x00;
+ break;
+ }
+
+ // PC lower
+ switch (group_mode(GROUP_B))
+ {
+ case MODE_0:
+ if (port_c_lower_mode() == MODE_OUTPUT)
+ {
+ mask |= 0x0f;
+ }
+ else
+ {
+ // TTL inputs float high
+ data |= 0x0f;
+ }
+ break;
+
+ case MODE_1:
+ data |= m_intr[PORT_B] ? 0x01 : 0x00;
+
+ if (port_mode(PORT_B) == MODE_OUTPUT)
+ {
+ data |= m_obf[PORT_B] ? 0x02 : 0x00;
+ }
+ else
+ {
+ data |= m_ibf[PORT_B] ? 0x02 : 0x00;
+ }
+ }
+
+ data |= m_output[PORT_C] & mask;
+
+ m_out_port_func[PORT_C](0, data);
+}
+
+
+//-------------------------------------------------
+// set_mode -
+//-------------------------------------------------
+
+void i8255_device::set_mode(UINT8 data)
+{
+ m_control = data;
+
+ // group A
+ m_output[PORT_A] = 0;
+ m_input[PORT_A] = 0;
+ m_ibf[PORT_A] = 0;
+ m_obf[PORT_A] = 1;
+ m_inte[PORT_A] = 0;
+ m_inte1 = 0;
+ m_inte2 = 0;
+
+ if (port_mode(PORT_A) == MODE_OUTPUT)
+ {
+ m_out_port_func[PORT_A](0, m_output[PORT_A]);
+ }
+ else
+ {
+ // TTL inputs float high
+ m_out_port_func[PORT_A](0, 0xff);
+ }
+
+ if (LOG)
+ {
+ logerror("I8255 '%s' Group A Mode: %u\n", tag(), group_mode(GROUP_A));
+ logerror("I8255 '%s' Port A Mode: %s\n", tag(), (port_mode(PORT_A) == MODE_OUTPUT) ? "output" : "input");
+ logerror("I8255 '%s' Port C Upper Mode: %s\n", tag(), (port_c_upper_mode() == MODE_OUTPUT) ? "output" : "input");
+ logerror("I8255 '%s' Group B Mode: %u\n", tag(), group_mode(GROUP_B));
+ logerror("I8255 '%s' Port B Mode: %s\n", tag(), (port_mode(PORT_B) == MODE_OUTPUT) ? "output" : "input");
+ logerror("I8255 '%s' Port C Lower Mode: %s\n", tag(), (port_c_lower_mode() == MODE_OUTPUT) ? "output" : "input");
+ }
+
+ // group B
+ m_output[PORT_B] = 0;
+ m_input[PORT_B] = 0;
+ m_ibf[PORT_B] = 0;
+ m_obf[PORT_B] = 1;
+ m_inte[PORT_B] = 0;
+
+ if (port_mode(PORT_B) == MODE_OUTPUT)
+ {
+ m_out_port_func[PORT_B](0, m_output[PORT_B]);
+ }
+ else
+ {
+ // TTL inputs float high
+ m_out_port_func[PORT_B](0, 0xff);
+ }
+
+ m_output[PORT_C] = 0;
+ m_input[PORT_C] = 0;
+
+ output_pc();
+}
+
+
+//-------------------------------------------------
+// set_pc_bit -
+//-------------------------------------------------
+
+void i8255_device::set_pc_bit(int bit, int state)
+{
+ // set output latch bit
+ m_output[PORT_C] &= ~(1 << bit);
+ m_output[PORT_C] |= state << bit;
+
+ switch (group_mode(GROUP_A))
+ {
+ case MODE_1:
+ if (port_mode(PORT_A) == MODE_OUTPUT)
+ {
+ switch (bit)
+ {
+ case 3: set_intr(PORT_A, state); break;
+ case 6: set_inte(PORT_A, state); break;
+ case 7: set_obf(PORT_A, state); break;
+ }
+ }
+ else
+ {
+ switch (bit)
+ {
+ case 3: set_intr(PORT_A, state); break;
+ case 4: set_inte(PORT_A, state); break;
+ case 5: set_ibf(PORT_A, state); break;
+ }
+ }
+ break;
+
+ case MODE_2:
+ switch (bit)
+ {
+ case 3: set_intr(PORT_A, state); break;
+ case 4: set_inte2(state); break;
+ case 5: set_ibf(PORT_A, state); break;
+ case 6: set_inte1(state); break;
+ case 7: set_obf(PORT_A, state); break;
+ }
+ break;
+ }
+
+ if (group_mode(GROUP_B) == MODE_1)
+ {
+ switch (bit)
+ {
+ case 0: set_intr(PORT_B, state); break;
+ case 1:
+ if (port_mode(PORT_B) == MODE_OUTPUT)
+ set_obf(PORT_B, state);
+ else
+ set_ibf(PORT_B, state);
+ break;
+ case 2: set_inte(PORT_B, state); break;
+ }
+ }
+
+ output_pc();
+}
+
+
+//-------------------------------------------------
+// read -
+//-------------------------------------------------
+
+READ8_MEMBER( i8255_device::read )
+{
+ UINT8 data = 0;
+
+ switch (offset & 0x03)
+ {
+ case PORT_A:
+ switch (group_mode(GROUP_A))
+ {
+ case MODE_0: data = read_mode0(PORT_A); break;
+ case MODE_1: data = read_mode1(PORT_A); break;
+ case MODE_2: data = read_mode2(); break;
+ }
+ if (LOG) logerror("I8255 '%s' Port A Read: %02x\n", tag(), data);
+ break;
+
+ case PORT_B:
+ switch (group_mode(GROUP_B))
+ {
+ case MODE_0: data = read_mode0(PORT_B); break;
+ case MODE_1: data = read_mode1(PORT_B); break;
+ }
+ if (LOG) logerror("I8255 '%s' Port B Read: %02x\n", tag(), data);
+ break;
+
+ case PORT_C:
+ data = read_pc();
+ if (LOG) logerror("I8255 '%s' Port C Read: %02x\n", tag(), data);
+ break;
+
+ case CONTROL:
+ data = m_control;
+ if (LOG) logerror("I8255 '%s' Mode Control Word Read: %02x\n", tag(), data);
+ break;
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// write -
+//-------------------------------------------------
+
+WRITE8_MEMBER( i8255_device::write )
+{
+ switch (offset & 0x03)
+ {
+ case PORT_A:
+ if (LOG) logerror("I8255 '%s' Port A Write: %02x\n", tag(), data);
+
+ switch (group_mode(GROUP_A))
+ {
+ case MODE_0: write_mode0(PORT_A, data); break;
+ case MODE_1: write_mode1(PORT_A, data); break;
+ case MODE_2: write_mode2(data); break;
+ }
+ break;
+
+ case PORT_B:
+ if (LOG) logerror("I8255 '%s' Port B Write: %02x\n", tag(), data);
+
+ switch (group_mode(GROUP_B))
+ {
+ case MODE_0: write_mode0(PORT_B, data); break;
+ case MODE_1: write_mode1(PORT_B, data); break;
+ }
+ break;
+
+ case PORT_C:
+ if (LOG) logerror("I8255 '%s' Port C Write: %02x\n", tag(), data);
+
+ write_pc(data);
+ break;
+
+ case CONTROL:
+ if (data & CONTROL_MODE_SET)
+ {
+ if (LOG) logerror("I8255 '%s' Mode Control Word: %02x\n", tag(), data);
+
+ set_mode(data);
+ }
+ else
+ {
+ int bit = (data >> 1) & 0x07;
+ int state = BIT(data, 0);
+
+ if (LOG) logerror("I8255 '%s' %s Port C Bit %u\n", tag(), state ? "Set" : "Reset", bit);
+
+ set_pc_bit(bit, state);
+ }
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// pa_r -
+//-------------------------------------------------
+
+READ8_MEMBER( i8255_device::pa_r )
+{
+ return pa_r();
+}
+
+
+//-------------------------------------------------
+// pb_r - port A read
+//-------------------------------------------------
+
+UINT8 i8255_device::pa_r()
+{
+ UINT8 data = 0xff;
+
+ if (port_mode(PORT_A) == MODE_OUTPUT)
+ {
+ data = m_output[PORT_A];
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// pb_r -
+//-------------------------------------------------
+
+READ8_MEMBER( i8255_device::pb_r )
+{
+ return pb_r();
+}
+
+
+//-------------------------------------------------
+// pb_r - port B read
+//-------------------------------------------------
+
+UINT8 i8255_device::pb_r()
+{
+ UINT8 data = 0xff;
+
+ if (port_mode(PORT_B) == MODE_OUTPUT)
+ {
+ data = m_output[PORT_B];
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// pc2_w -
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( i8255_device::pc2_w )
+{
+ if (group_mode(GROUP_B) == 1)
+ {
+ if (port_mode(PORT_B) == MODE_OUTPUT)
+ {
+ // port B acknowledge
+ if (!m_obf[PORT_B] && !state)
+ {
+ if (LOG) logerror("I8255 '%s' Port B Acknowledge\n", tag());
+
+ // clear output buffer flag
+ set_obf(PORT_B, 1);
+ }
+ }
+ else
+ {
+ // port B strobe
+ if (!m_ibf[PORT_B] && !state)
+ {
+ if (LOG) logerror("I8255 '%s' Port B Strobe\n", tag());
+
+ // read port into latch
+ m_input[PORT_B] = m_in_port_func[PORT_B](0);
+
+ // set input buffer flag
+ set_ibf(PORT_B, 1);
+ }
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// pc4_w -
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( i8255_device::pc4_w )
+{
+ if ((group_mode(GROUP_A) == 2) || ((group_mode(GROUP_A) == 1) && (port_mode(PORT_A) == MODE_INPUT)))
+ {
+ // port A strobe
+ if (!m_ibf[PORT_A] && !state)
+ {
+ if (LOG) logerror("I8255 '%s' Port A Strobe\n", tag());
+
+ // read port into latch
+ m_input[PORT_A] = m_in_port_func[PORT_A](0);
+
+ // set input buffer flag
+ set_ibf(PORT_A, 1);
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// pc6_w -
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( i8255_device::pc6_w )
+{
+ if ((group_mode(GROUP_A) == 2) || ((group_mode(GROUP_A) == 1) && (port_mode(PORT_A) == MODE_OUTPUT)))
+ {
+ // port A acknowledge
+ if (!m_obf[PORT_A] && !state)
+ {
+ if (LOG) logerror("I8255 '%s' Port A Acknowledge\n", tag());
+
+ // clear output buffer flag
+ set_obf(PORT_A, 1);
+ }
+ }
+}