diff options
Diffstat (limited to 'trunk/src/emu/machine/6821pia.c')
-rw-r--r-- | trunk/src/emu/machine/6821pia.c | 1180 |
1 files changed, 1180 insertions, 0 deletions
diff --git a/trunk/src/emu/machine/6821pia.c b/trunk/src/emu/machine/6821pia.c new file mode 100644 index 00000000000..decc1d2a439 --- /dev/null +++ b/trunk/src/emu/machine/6821pia.c @@ -0,0 +1,1180 @@ +/********************************************************************** + + Motorola 6821 PIA interface and emulation + +**********************************************************************/ + +#include "emu.h" +#include "6821pia.h" + + +//************************************************************************** +// MACROS +//************************************************************************** + +#define VERBOSE 0 + +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + +#define PIA_IRQ1 (0x80) +#define PIA_IRQ2 (0x40) + +#define IRQ1_ENABLED(c) ( (((c) >> 0) & 0x01)) +#define C1_LOW_TO_HIGH(c) ( (((c) >> 1) & 0x01)) +#define C1_HIGH_TO_LOW(c) (!(((c) >> 1) & 0x01)) +#define OUTPUT_SELECTED(c) ( (((c) >> 2) & 0x01)) +#define IRQ2_ENABLED(c) ( (((c) >> 3) & 0x01)) +#define STROBE_E_RESET(c) ( (((c) >> 3) & 0x01)) +#define STROBE_C1_RESET(c) (!(((c) >> 3) & 0x01)) +#define C2_SET(c) ( (((c) >> 3) & 0x01)) +#define C2_LOW_TO_HIGH(c) ( (((c) >> 4) & 0x01)) +#define C2_HIGH_TO_LOW(c) (!(((c) >> 4) & 0x01)) +#define C2_SET_MODE(c) ( (((c) >> 4) & 0x01)) +#define C2_STROBE_MODE(c) (!(((c) >> 4) & 0x01)) +#define C2_OUTPUT(c) ( (((c) >> 5) & 0x01)) +#define C2_INPUT(c) (!(((c) >> 5) & 0x01)) + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +// device type definition +const device_type PIA6821 = &device_creator<pia6821_device>; + + +//------------------------------------------------- +// pia6821_device - constructor +//------------------------------------------------- + +pia6821_device::pia6821_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, PIA6821, "6822 PIA", tag, owner, clock) +{ + memset(static_cast<pia6821_interface *>(this), 0, sizeof(pia6821_interface)); +} + + +//------------------------------------------------- +// static_set_interface - set the interface +// struct +//------------------------------------------------- + +void pia6821_device::static_set_interface(device_t &device, const pia6821_interface &interface) +{ + pia6821_device &ptm = downcast<pia6821_device &>(device); + static_cast<pia6821_interface &>(ptm) = interface; +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void pia6821_device::device_start() +{ + // resolve callbacks + m_in_a_func.resolve(m_in_a_cb, *this); + m_in_b_func.resolve(m_in_b_cb, *this); + m_in_ca1_func.resolve(m_in_ca1_cb, *this); + m_in_cb1_func.resolve(m_in_cb1_cb, *this); + m_in_ca2_func.resolve(m_in_ca2_cb, *this); + m_in_cb2_func.resolve(m_in_cb2_cb, *this); + m_out_a_func.resolve(m_out_a_cb, *this); + m_out_b_func.resolve(m_out_b_cb, *this); + m_out_ca2_func.resolve(m_out_ca2_cb, *this); + m_out_cb2_func.resolve(m_out_cb2_cb, *this); + m_irq_a_func.resolve(m_irq_a_cb, *this); + m_irq_b_func.resolve(m_irq_b_cb, *this); + + save_item(NAME(m_in_a)); + save_item(NAME(m_in_ca1)); + save_item(NAME(m_in_ca2)); + save_item(NAME(m_out_a)); + save_item(NAME(m_out_ca2)); + save_item(NAME(m_port_a_z_mask)); + save_item(NAME(m_ddr_a)); + save_item(NAME(m_ctl_a)); + save_item(NAME(m_irq_a1)); + save_item(NAME(m_irq_a2)); + save_item(NAME(m_irq_a_state)); + save_item(NAME(m_in_b)); + save_item(NAME(m_in_cb1)); + save_item(NAME(m_in_cb2)); + save_item(NAME(m_out_b)); + save_item(NAME(m_out_cb2)); + save_item(NAME(m_last_out_cb2_z)); + save_item(NAME(m_ddr_b)); + save_item(NAME(m_ctl_b)); + save_item(NAME(m_irq_b1)); + save_item(NAME(m_irq_b2)); + save_item(NAME(m_irq_b_state)); + save_item(NAME(m_in_a_pushed)); + save_item(NAME(m_out_a_needs_pulled)); + save_item(NAME(m_in_ca1_pushed)); + save_item(NAME(m_in_ca2_pushed)); + save_item(NAME(m_out_ca2_needs_pulled)); + save_item(NAME(m_in_b_pushed)); + save_item(NAME(m_out_b_needs_pulled)); + save_item(NAME(m_in_cb1_pushed)); + save_item(NAME(m_in_cb2_pushed)); + save_item(NAME(m_out_cb2_needs_pulled)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void pia6821_device::device_reset() +{ + // + // set default read values. + // + // ports A,CA1,CA2 default to 1 + // ports B,CB1,CB2 are three-state and undefined (set to 0) + // + m_in_a = 0xff; + m_in_ca1 = TRUE; + m_in_ca2 = TRUE; + m_out_a = 0; + m_out_ca2 = 0; + m_port_a_z_mask = 0; + m_ddr_a = 0; + m_ctl_a = 0; + m_irq_a1 = 0; + m_irq_a2 = 0; + m_irq_a_state = 0; + m_in_b = 0; + m_in_cb1 = 0; + m_in_cb2 = 0; + m_out_b = 0; + m_out_cb2 = 0; + m_last_out_cb2_z = 0; + m_ddr_b = 0; + m_ctl_b = 0; + m_irq_b1 = 0; + m_irq_b2 = 0; + m_irq_b_state = 0; + m_in_a_pushed = false; + m_out_a_needs_pulled = false; + m_in_ca1_pushed = false; + m_in_ca2_pushed = false; + m_out_ca2_needs_pulled = false; + m_in_b_pushed = false; + m_out_b_needs_pulled = false; + m_in_cb1_pushed = false; + m_in_cb2_pushed = false; + m_out_cb2_needs_pulled = false; + m_logged_port_a_not_connected = false; + m_logged_port_b_not_connected = false; + m_logged_ca1_not_connected = false; + m_logged_ca2_not_connected = false; + m_logged_cb1_not_connected = false; + m_logged_cb2_not_connected = false; + + + // clear the IRQs + m_irq_a_func(FALSE); + m_irq_b_func(FALSE); +} + + +//------------------------------------------------- +// update_interrupts +//------------------------------------------------- + +void pia6821_device::update_interrupts() +{ + // start with IRQ A + int new_state = (m_irq_a1 && IRQ1_ENABLED(m_ctl_a)) || (m_irq_a2 && IRQ2_ENABLED(m_ctl_a)); + + if (new_state != m_irq_a_state) + { + m_irq_a_state = new_state; + m_irq_a_func(m_irq_a_state); + } + + // then do IRQ B + new_state = (m_irq_b1 && IRQ1_ENABLED(m_ctl_b)) || (m_irq_b2 && IRQ2_ENABLED(m_ctl_b)); + + if (new_state != m_irq_b_state) + { + m_irq_b_state = new_state; + m_irq_b_func(m_irq_b_state); + } +} + + +//------------------------------------------------- +// get_in_a_value +//------------------------------------------------- + +UINT8 pia6821_device::get_in_a_value() +{ + UINT8 port_a_data = 0; + UINT8 ret; + + // update the input + if (!m_in_a_func.isnull()) + { + port_a_data = m_in_a_func(0); + } + else + { + if (m_in_a_pushed) + { + port_a_data = m_in_a; + } + else + { + // mark all pins disconnected + m_port_a_z_mask = 0xff; + + if (!m_logged_port_a_not_connected && (m_ddr_a != 0xff)) + { + logerror("PIA #%s: Warning! No port A read handler. Assuming pins 0x%02X not connected\n", tag(), m_ddr_a ^ 0xff); + m_logged_port_a_not_connected = true; + } + } + } + + // - connected pins are always read + // - disconnected pins read the output buffer in output mode + // - disconnected pins are HI in input mode + ret = (~m_port_a_z_mask & port_a_data) | + ( m_port_a_z_mask & m_ddr_a & m_out_a) | + ( m_port_a_z_mask & ~m_ddr_a); + + return ret; +} + + +//------------------------------------------------- +// get_in_b_value +//------------------------------------------------- + +UINT8 pia6821_device::get_in_b_value() +{ + UINT8 ret; + + if (m_ddr_b == 0xff) + { + // all output, just return buffer + ret = m_out_b; + } + else + { + UINT8 port_b_data; + + // update the input + if (!m_in_b_func.isnull()) + { + port_b_data = m_in_b_func(0); + } + else + { + if (m_in_b_pushed) + { + port_b_data = m_in_b; + } + else + { + if (!m_logged_port_b_not_connected && (m_ddr_b != 0xff)) + { + logerror("PIA #%s: Error! No port B read handler. Three-state pins 0x%02X are undefined\n", tag(), m_ddr_b ^ 0xff); + m_logged_port_b_not_connected = true; + } + + // undefined -- need to return something + port_b_data = 0x00; + } + } + + // the DDR determines if the pin or the output buffer is read + ret = (m_out_b & m_ddr_b) | (port_b_data & ~m_ddr_b); + } + + return ret; +} + + +//------------------------------------------------- +// get_out_a_value +//------------------------------------------------- + +UINT8 pia6821_device::get_out_a_value() +{ + UINT8 ret; + + if (m_ddr_a == 0xff) + { + // all output + ret = m_out_a; + } + else + { + // input pins don't change + ret = (m_out_a & m_ddr_a) | (get_in_a_value() & ~m_ddr_a); + } + + return ret; +} + + +//------------------------------------------------- +// get_out_b_value +//------------------------------------------------- + +UINT8 pia6821_device::get_out_b_value() +{ + // input pins are high-impedance - we just send them as zeros for backwards compatibility + return m_out_b & m_ddr_b; +} + + +//------------------------------------------------- +// set_out_ca2 +//------------------------------------------------- + +void pia6821_device::set_out_ca2(int data) +{ + if (data != m_out_ca2) + { + m_out_ca2 = data; + + // send to output function + if (!m_out_ca2_func.isnull()) + { + m_out_ca2_func(m_out_ca2); + } + else + { + if (m_out_ca2_needs_pulled) + { + logerror("PIA #%s: Warning! No port CA2 write handler. Previous value has been lost!\n", tag()); + } + + m_out_ca2_needs_pulled = true; + } + } +} + + +//------------------------------------------------- +// set_out_cb2 +//------------------------------------------------- + +void pia6821_device::set_out_cb2(int data) +{ + int z = cb2_output_z(); + + if ((data != m_out_cb2) || (z != m_last_out_cb2_z)) + { + m_out_cb2 = data; + m_last_out_cb2_z = z; + + // send to output function + if (!m_out_cb2_func.isnull()) + { + m_out_cb2_func(m_out_cb2); + } + else + { + if (m_out_cb2_needs_pulled) + { + logerror("PIA #%s: Warning! No port CB2 write handler. Previous value has been lost!\n", tag()); + } + + m_out_cb2_needs_pulled = true; + } + } +} + + +//------------------------------------------------- +// port_a_r +//------------------------------------------------- + +UINT8 pia6821_device::port_a_r() +{ + UINT8 ret = get_in_a_value(); + + // IRQ flags implicitly cleared by a read + m_irq_a1 = FALSE; + m_irq_a2 = FALSE; + update_interrupts(); + + // CA2 is configured as output and in read strobe mode + if(C2_OUTPUT(m_ctl_a) && C2_STROBE_MODE(m_ctl_a)) + { + // this will cause a transition low + set_out_ca2(FALSE); + + // if the CA2 strobe is cleared by the E, reset it right away + if(STROBE_E_RESET(m_ctl_a)) + { + set_out_ca2(TRUE); + } + } + + LOG(("PIA #%s: port A read = %02X\n", tag(), ret)); + + return ret; +} + + +//------------------------------------------------- +// ddr_a_r +//------------------------------------------------- + +UINT8 pia6821_device::ddr_a_r() +{ + UINT8 ret = m_ddr_a; + + LOG(("PIA #%s: DDR A read = %02X\n", tag(), ret)); + + return ret; +} + + +//------------------------------------------------- +// port_b_r +//------------------------------------------------- + +UINT8 pia6821_device::port_b_r() +{ + UINT8 ret = get_in_b_value(); + + // This read will implicitly clear the IRQ B1 flag. If CB2 is in write-strobe + // mode with CB1 restore, and a CB1 active transition set the flag, + // clearing it will cause CB2 to go high again. Note that this is different + // from what happens with port A. + if(m_irq_b1 && C2_STROBE_MODE(m_ctl_b) && STROBE_C1_RESET(m_ctl_b)) + { + set_out_cb2(TRUE); + } + + // IRQ flags implicitly cleared by a read + m_irq_b1 = FALSE; + m_irq_b2 = FALSE; + update_interrupts(); + + LOG(("PIA #%s: port B read = %02X\n", tag(), ret)); + + return ret; +} + + +//------------------------------------------------- +// ddr_b_r +//------------------------------------------------- + +UINT8 pia6821_device::ddr_b_r() +{ + UINT8 ret = m_ddr_b; + + LOG(("PIA #%s: DDR B read = %02X\n", tag(), ret)); + + return ret; +} + + +//------------------------------------------------- +// control_a_r +//------------------------------------------------- + +UINT8 pia6821_device::control_a_r() +{ + UINT8 ret; + + // update CA1 & CA2 if callback exists, these in turn may update IRQ's + if (!m_in_ca1_func.isnull()) + { + ca1_w(m_in_ca1_func()); + } + else if(!m_logged_ca1_not_connected && (!m_in_ca1_pushed)) + { + logerror("PIA #%s: Warning! No CA1 read handler. Assuming pin not connected\n", tag()); + m_logged_ca1_not_connected = true; + } + + if (!m_in_ca2_func.isnull()) + { + ca2_w(m_in_ca2_func()); + } + else if ( !m_logged_ca2_not_connected && C2_INPUT(m_ctl_a) && !m_in_ca2_pushed) + { + logerror("PIA #%s: Warning! No CA2 read handler. Assuming pin not connected\n", tag()); + m_logged_ca2_not_connected = true; + } + + // read control register + ret = m_ctl_a; + + // set the IRQ flags if we have pending IRQs + if(m_irq_a1) + { + ret |= PIA_IRQ1; + } + + if(m_irq_a2 && C2_INPUT(m_ctl_a)) + { + ret |= PIA_IRQ2; + } + + LOG(("PIA #%s: control A read = %02X\n", tag(), ret)); + + return ret; +} + + +//------------------------------------------------- +// control_b_r +//------------------------------------------------- + +UINT8 pia6821_device::control_b_r() +{ + UINT8 ret; + + // update CB1 & CB2 if callback exists, these in turn may update IRQ's + if(!m_in_cb1_func.isnull()) + { + cb1_w(m_in_cb1_func()); + } + else if(!m_logged_cb1_not_connected && !m_in_cb1_pushed) + { + logerror("PIA #%s: Error! no CB1 read handler. Three-state pin is undefined\n", tag()); + m_logged_cb1_not_connected = true; + } + + if(!m_in_cb2_func.isnull()) + { + cb2_w(m_in_cb2_func()); + } + else if(!m_logged_cb2_not_connected && C2_INPUT(m_ctl_b) && !m_in_cb2_pushed) + { + logerror("PIA #%s: Error! No CB2 read handler. Three-state pin is undefined\n", tag()); + m_logged_cb2_not_connected = true; + } + + // read control register + ret = m_ctl_b; + + // set the IRQ flags if we have pending IRQs + if(m_irq_b1) + { + ret |= PIA_IRQ1; + } + + if(m_irq_b2 && C2_INPUT(m_ctl_b)) + { + ret |= PIA_IRQ2; + } + + LOG(("PIA #%s: control B read = %02X\n", tag(), ret)); + + return ret; +} + + +//------------------------------------------------- +// read +//------------------------------------------------- + +UINT8 pia6821_device::reg_r(UINT8 offset) +{ + UINT8 ret; + + switch (offset & 0x03) + { + default: // impossible + case 0x00: + if (OUTPUT_SELECTED(m_ctl_a)) + { + ret = port_a_r(); + } + else + { + ret = ddr_a_r(); + } + break; + + case 0x01: + ret = control_a_r(); + break; + + case 0x02: + if (OUTPUT_SELECTED(m_ctl_b)) + { + ret = port_b_r(); + } + else + { + ret = ddr_b_r(); + } + break; + + case 0x03: + ret = control_b_r(); + break; + } + + return ret; +} + + + +//------------------------------------------------- +// send_to_out_a_func +//------------------------------------------------- + +void pia6821_device::send_to_out_a_func(const char* message) +{ + // input pins are pulled high + UINT8 data = get_out_a_value(); + + LOG(("PIA #%s: %s = %02X\n", tag(), message, data)); + + if(!m_out_a_func.isnull()) + { + m_out_a_func(0, data); + } + else + { + if(m_out_a_needs_pulled) + { + logerror("PIA #%s: Warning! No port A write handler. Previous value has been lost!\n", tag()); + } + + m_out_a_needs_pulled = true; + } +} + + +//------------------------------------------------- +// send_to_out_b_func +//------------------------------------------------- + +void pia6821_device::send_to_out_b_func(const char* message) +{ + // input pins are high-impedance - we just send them as zeros for backwards compatibility + UINT8 data = get_out_b_value(); + + LOG(("PIA #%s: %s = %02X\n", tag(), message, data)); + + if(!m_out_b_func.isnull()) + { + m_out_b_func(0, data); + } + else + { + if(m_out_b_needs_pulled) + { + logerror("PIA #%s: Warning! No port B write handler. Previous value has been lost!\n", tag()); + } + + m_out_b_needs_pulled = true; + } +} + + +//------------------------------------------------- +// port_a_w +//------------------------------------------------- + +void pia6821_device::port_a_w(UINT8 data) +{ + // buffer the output value + m_out_a = data; + + send_to_out_a_func("port A write"); +} + + +//------------------------------------------------- +// ddr_a_w +//------------------------------------------------- + +void pia6821_device::ddr_a_w(UINT8 data) +{ + if(data == 0x00) + { + LOG(("PIA #%s: DDR A write = %02X (input mode)\n", tag(), data)); + } + else if(data == 0xff) + { + LOG(("PIA #%s: DDR A write = %02X (output mode)\n", tag(), data)); + } + else + { + LOG(("PIA #%s: DDR A write = %02X (mixed mode)\n", tag(), data)); + } + + if(m_ddr_a != data) + { + // DDR changed, call the callback again + m_ddr_a = data; + m_logged_port_a_not_connected = false; + send_to_out_a_func("port A write due to DDR change"); + } +} + + +//------------------------------------------------- +// port_b_w +//------------------------------------------------- + +void pia6821_device::port_b_w(UINT8 data) +{ + // buffer the output value + m_out_b = data; + + send_to_out_b_func("port B write"); + + // CB2 in write strobe mode + if(C2_STROBE_MODE(m_ctl_b)) + { + // this will cause a transition low + set_out_cb2(FALSE); + + // if the CB2 strobe is cleared by the E, reset it right away + if(STROBE_E_RESET(m_ctl_b)) + { + set_out_cb2(TRUE); + } + } +} + + +//------------------------------------------------- +// ddr_b_w +//------------------------------------------------- + +void pia6821_device::ddr_b_w(UINT8 data) +{ + if (data == 0x00) + { + LOG(("PIA #%s: DDR B write = %02X (input mode)\n", tag(), data)); + } + else if (data == 0xff) + { + LOG(("PIA #%s: DDR B write = %02X (output mode)\n", tag(), data)); + } + else + { + LOG(("PIA #%s: DDR B write = %02X (mixed mode)\n", tag(), data)); + } + + if(m_ddr_b != data) + { + // DDR changed, call the callback again + m_ddr_b = data; + m_logged_port_b_not_connected = false; + send_to_out_b_func("port B write due to DDR change"); + } +} + + +//------------------------------------------------- +// control_a_w +//------------------------------------------------- + +void pia6821_device::control_a_w(UINT8 data) +{ + // bit 7 and 6 are read only + data &= 0x3f; + + LOG(("PIA #%s: control A write = %02X\n", tag(), data)); + + // update the control register + m_ctl_a = data; + + // CA2 is configured as output + if(C2_OUTPUT(m_ctl_a)) + { + int temp; + + if(C2_SET_MODE(m_ctl_a)) + { + // set/reset mode - bit value determines the new output + temp = C2_SET(m_ctl_a); + } + else + { + // strobe mode - output is always high unless strobed + temp = TRUE; + } + + set_out_ca2(temp); + } + + // update externals + update_interrupts(); +} + + +//------------------------------------------------- +// control_b_w +//------------------------------------------------- + +void pia6821_device::control_b_w(UINT8 data) +{ + int temp; + + // bit 7 and 6 are read only + data &= 0x3f; + + LOG(("PIA #%s: control B write = %02X\n", tag(), data)); + + // update the control register + m_ctl_b = data; + + if (C2_SET_MODE(m_ctl_b)) + { + // set/reset mode - bit value determines the new output + temp = C2_SET(m_ctl_b); + } + else + { + // strobe mode - output is always high unless strobed + temp = TRUE; + } + + set_out_cb2(temp); + + // update externals + update_interrupts(); +} + + +//------------------------------------------------- +// write +//------------------------------------------------- + +void pia6821_device::reg_w(UINT8 offset, UINT8 data) +{ + switch (offset & 0x03) + { + default: // impossible + case 0x00: + if (OUTPUT_SELECTED(m_ctl_a)) + { + port_a_w(data); + } + else + { + ddr_a_w(data); + } + break; + + case 0x01: + control_a_w( data); + break; + + case 0x02: + if(OUTPUT_SELECTED(m_ctl_b)) + { + port_b_w(data); + } + else + { + ddr_b_w(data); + } + break; + + case 0x03: + control_b_w(data); + break; + } +} + + +//------------------------------------------------- +// porta_r +//------------------------------------------------- + +READ8_MEMBER( pia6821_device::porta_r ) +{ + return m_in_a; +} + + +//------------------------------------------------- +// set_a_input +//------------------------------------------------- + +void pia6821_device::set_a_input(UINT8 data, UINT8 z_mask) +{ + assert_always(m_in_a_func.isnull(), "pia6821_porta_w() called when in_a_func implemented"); + + LOG(("PIA #%s: set input port A = %02X\n", tag(), data)); + + m_in_a = data; + m_port_a_z_mask = z_mask; + m_in_a_pushed = true; +} + + +//------------------------------------------------- +// pia6821_porta_w +//------------------------------------------------- + +WRITE8_MEMBER( pia6821_device::porta_w ) +{ + set_a_input(data, 0); +} + + +//------------------------------------------------- +// a_output +//------------------------------------------------- + +UINT8 pia6821_device::a_output() +{ + m_out_a_needs_pulled = false; + + return get_out_a_value(); +} + + +//------------------------------------------------- +// ca1_r +//------------------------------------------------- + +READ_LINE_MEMBER( pia6821_device::ca1_r ) +{ + return m_in_ca1; +} + + +//------------------------------------------------- +// ca1_w +//------------------------------------------------- + +WRITE_LINE_MEMBER( pia6821_device::ca1_w ) +{ + LOG(("PIA #%s: set input CA1 = %d\n", tag(), state)); + + // the new state has caused a transition + if((m_in_ca1 != state) && ((state && C1_LOW_TO_HIGH(m_ctl_a)) || (!state && C1_HIGH_TO_LOW(m_ctl_a)))) + { + LOG(("PIA #%s: CA1 triggering\n", tag())); + + // mark the IRQ + m_irq_a1 = TRUE; + + // update externals + update_interrupts(); + + // CA2 is configured as output and in read strobe mode and cleared by a CA1 transition + if(C2_OUTPUT(m_ctl_a) && C2_STROBE_MODE(m_ctl_a) && STROBE_C1_RESET(m_ctl_a)) + { + set_out_ca2(TRUE); + } + } + + // set the new value for CA1 + m_in_ca1 = state; + m_in_ca1_pushed = true; +} + + +//------------------------------------------------- +// ca2_r +//------------------------------------------------- + +READ_LINE_MEMBER( pia6821_device::ca2_r ) +{ + return m_in_ca2; +} + + +//------------------------------------------------- +// ca2_w +//------------------------------------------------- + +WRITE_LINE_MEMBER( pia6821_device::ca2_w ) +{ + LOG(("PIA #%s: set input CA2 = %d\n", tag(), state)); + + // if input mode and the new state has caused a transition + if(C2_INPUT(m_ctl_a) && (m_in_ca2 != state) && ((state && C2_LOW_TO_HIGH(m_ctl_a)) || (!state && C2_HIGH_TO_LOW(m_ctl_a)))) + { + LOG(("PIA #%s: CA2 triggering\n", tag())); + + // mark the IRQ + m_irq_a2 = TRUE; + + // update externals + update_interrupts(); + } + + // set the new value for CA2 + m_in_ca2 = state; + m_in_ca2_pushed = true; +} + + +//------------------------------------------------- +// ca2_output +//------------------------------------------------- + +int pia6821_device::ca2_output() +{ + m_out_ca2_needs_pulled = false; + + return m_out_ca2; +} + + +//------------------------------------------------- +// ca2_output_z - version of ca2_output which +// takes account of internal pullup resistor +//------------------------------------------------- + +int pia6821_device::ca2_output_z() +{ + m_out_ca2_needs_pulled = false; + + // If it's an output, output the bit, if it's an input, it's + // pulled up + return m_out_ca2 | C2_INPUT(m_ctl_a); +} + + +//------------------------------------------------- +// portb_r +//------------------------------------------------- + +READ8_MEMBER( pia6821_device::portb_r ) +{ + return m_in_b; +} + + +//------------------------------------------------- +// portb_w +//------------------------------------------------- + +WRITE8_MEMBER( pia6821_device::portb_w ) +{ + assert_always(m_in_b_func.isnull(), "pia_set_input_b() called when in_b_func implemented"); + + LOG(("PIA #%s: set input port B = %02X\n", tag(), data)); + + m_in_b = data; + m_in_b_pushed = true; +} + + +//------------------------------------------------- +// b_output +//------------------------------------------------- + +UINT8 pia6821_device::b_output() +{ + m_out_b_needs_pulled = false; + + return get_out_b_value(); +} + + +//------------------------------------------------- +// cb1_r +//------------------------------------------------- + +READ_LINE_MEMBER( pia6821_device::cb1_r ) +{ + return m_in_cb1; +} + + +//------------------------------------------------- +// cb1_w +//------------------------------------------------- + +WRITE_LINE_MEMBER( pia6821_device::cb1_w ) +{ + LOG(("PIA #%s: set input CB1 = %d\n", tag(), state)); + + // the new state has caused a transition + if((m_in_cb1 != state) && ((state && C1_LOW_TO_HIGH(m_ctl_b)) || (!state && C1_HIGH_TO_LOW(m_ctl_b)))) + { + LOG(("PIA #%s: CB1 triggering\n", tag())); + + // mark the IRQ + m_irq_b1 = 1; + + // update externals + update_interrupts(); + + // If CB2 is configured as a write-strobe output which is reset by a CB1 + // transition, this reset will only happen when a read from port B implicitly + // clears the IRQ B1 flag. So we handle the CB2 reset there. Note that this + // is different from what happens with port A. + } + + // set the new value for CB1 + m_in_cb1 = state; + m_in_cb1_pushed = true; +} + + +//------------------------------------------------- +// cb2_r +//------------------------------------------------- + +READ_LINE_MEMBER( pia6821_device::cb2_r ) +{ + return m_in_cb2; +} + + +//------------------------------------------------- +// cb2_w +//------------------------------------------------- + +WRITE_LINE_MEMBER( pia6821_device::cb2_w ) +{ + LOG(("PIA #%s: set input CB2 = %d\n", tag(), state)); + + // if input mode and the new state has caused a transition + if (C2_INPUT(m_ctl_b) && + (m_in_cb2 != state) && + ((state && C2_LOW_TO_HIGH(m_ctl_b)) || (!state && C2_HIGH_TO_LOW(m_ctl_b)))) + { + LOG(("PIA #%s: CB2 triggering\n", tag())); + + // mark the IRQ + m_irq_b2 = 1; + + // update externals + update_interrupts(); + } + + // set the new value for CA2 + m_in_cb2 = state; + m_in_cb2_pushed = true; +} + + +//------------------------------------------------- +// output_cb2 +//------------------------------------------------- + +int pia6821_device::cb2_output() +{ + m_out_cb2_needs_pulled = false; + + return m_out_cb2; +} + + +//------------------------------------------------- +// cb2_output_z +//------------------------------------------------- + +int pia6821_device::cb2_output_z() +{ + return !C2_OUTPUT(m_ctl_b); +} |