summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/emu/machine/6522via.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/emu/machine/6522via.c')
-rw-r--r--trunk/src/emu/machine/6522via.c1072
1 files changed, 1072 insertions, 0 deletions
diff --git a/trunk/src/emu/machine/6522via.c b/trunk/src/emu/machine/6522via.c
new file mode 100644
index 00000000000..1b3f89f0d3b
--- /dev/null
+++ b/trunk/src/emu/machine/6522via.c
@@ -0,0 +1,1072 @@
+/**********************************************************************
+
+ Rockwell 6522 VIA interface and emulation
+
+ This function emulates the functionality of up to 8 6522
+ versatile interface adapters.
+
+ This is based on the M6821 emulation in MAME.
+
+ To do:
+
+ T2 pulse counting mode
+ Pulse mode handshake output
+ More shift register
+
+**********************************************************************/
+
+/*
+ 1999-Dec-22 PeT
+ vc20 random number generation only partly working
+ (reads (uninitialized) timer 1 and timer 2 counter)
+ timer init, reset, read changed
+ */
+
+#include "emu.h"
+#include "6522via.h"
+#include "devhelpr.h"
+
+/***************************************************************************
+ PARAMETERS
+***************************************************************************/
+
+#define TRACE_VIA 0
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+/* Macros for PCR */
+#define CA1_LOW_TO_HIGH(c) (c & 0x01)
+#define CA1_HIGH_TO_LOW(c) (!(c & 0x01))
+
+#define CB1_LOW_TO_HIGH(c) (c & 0x10)
+#define CB1_HIGH_TO_LOW(c) (!(c & 0x10))
+
+#define CA2_INPUT(c) (!(c & 0x08))
+#define CA2_LOW_TO_HIGH(c) ((c & 0x0c) == 0x04)
+#define CA2_HIGH_TO_LOW(c) ((c & 0x0c) == 0x00)
+#define CA2_IND_IRQ(c) ((c & 0x0a) == 0x02)
+
+#define CA2_OUTPUT(c) (c & 0x08)
+#define CA2_AUTO_HS(c) ((c & 0x0c) == 0x08)
+#define CA2_HS_OUTPUT(c) ((c & 0x0e) == 0x08)
+#define CA2_PULSE_OUTPUT(c) ((c & 0x0e) == 0x0a)
+#define CA2_FIX_OUTPUT(c) ((c & 0x0c) == 0x0c)
+#define CA2_OUTPUT_LEVEL(c) ((c & 0x02) >> 1)
+
+#define CB2_INPUT(c) (!(c & 0x80))
+#define CB2_LOW_TO_HIGH(c) ((c & 0xc0) == 0x40)
+#define CB2_HIGH_TO_LOW(c) ((c & 0xc0) == 0x00)
+#define CB2_IND_IRQ(c) ((c & 0xa0) == 0x20)
+
+#define CB2_OUTPUT(c) (c & 0x80)
+#define CB2_AUTO_HS(c) ((c & 0xc0) == 0x80)
+#define CB2_HS_OUTPUT(c) ((c & 0xe0) == 0x80)
+#define CB2_PULSE_OUTPUT(c) ((c & 0xe0) == 0xa0)
+#define CB2_FIX_OUTPUT(c) ((c & 0xc0) == 0xc0)
+#define CB2_OUTPUT_LEVEL(c) ((c & 0x20) >> 5)
+
+/* Macros for ACR */
+#define PA_LATCH_ENABLE(c) (c & 0x01)
+#define PB_LATCH_ENABLE(c) (c & 0x02)
+
+#define SR_DISABLED(c) (!(c & 0x1c))
+#define SI_T2_CONTROL(c) ((c & 0x1c) == 0x04)
+#define SI_O2_CONTROL(c) ((c & 0x1c) == 0x08)
+#define SI_EXT_CONTROL(c) ((c & 0x1c) == 0x0c)
+#define SO_T2_RATE(c) ((c & 0x1c) == 0x10)
+#define SO_T2_CONTROL(c) ((c & 0x1c) == 0x14)
+#define SO_O2_CONTROL(c) ((c & 0x1c) == 0x18)
+#define SO_EXT_CONTROL(c) ((c & 0x1c) == 0x1c)
+
+#define T1_SET_PB7(c) (c & 0x80)
+#define T1_CONTINUOUS(c) (c & 0x40)
+#define T2_COUNT_PB6(c) (c & 0x20)
+
+/* Interrupt flags */
+#define INT_CA2 0x01
+#define INT_CA1 0x02
+#define INT_SR 0x04
+#define INT_CB2 0x08
+#define INT_CB1 0x10
+#define INT_T2 0x20
+#define INT_T1 0x40
+#define INT_ANY 0x80
+
+#define CLR_PA_INT() clear_int(INT_CA1 | ((!CA2_IND_IRQ(m_pcr)) ? INT_CA2: 0))
+#define CLR_PB_INT() clear_int(INT_CB1 | ((!CB2_IND_IRQ(m_pcr)) ? INT_CB2: 0))
+
+#define IFR_DELAY 3
+
+#define TIMER1_VALUE (m_t1ll+(m_t1lh<<8))
+#define TIMER2_VALUE (m_t2ll+(m_t2lh<<8))
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+attotime via6522_device::cycles_to_time(int c)
+{
+ return attotime::from_hz(clock()) * c;
+}
+
+
+UINT32 via6522_device::time_to_cycles(attotime t)
+{
+ return (t * clock()).as_double();
+}
+
+
+UINT16 via6522_device::get_counter1_value()
+{
+ UINT16 val;
+
+ if(m_t1_active)
+ {
+ val = time_to_cycles(m_t1->remaining()) - IFR_DELAY;
+ }
+ else
+ {
+ val = 0xffff - time_to_cycles(machine().time() - m_time1);
+ }
+
+ return val;
+}
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+// device type definition
+const device_type VIA6522 = &device_creator<via6522_device>;
+
+//-------------------------------------------------
+// via6522_device - constructor
+//-------------------------------------------------
+
+via6522_device::via6522_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, VIA6522, "6522 VIA", tag, owner, clock)
+{
+
+}
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void via6522_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const via6522_interface *intf = reinterpret_cast<const via6522_interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<via6522_interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_in_a_cb, 0, sizeof(m_in_a_cb));
+ memset(&m_in_b_cb, 0, sizeof(m_in_b_cb));
+ memset(&m_in_ca1_cb, 0, sizeof(m_in_ca1_cb));
+ memset(&m_in_cb1_cb, 0, sizeof(m_in_cb1_cb));
+ memset(&m_in_ca2_cb, 0, sizeof(m_in_ca2_cb));
+ memset(&m_in_cb2_cb, 0, sizeof(m_in_cb2_cb));
+ memset(&m_out_a_cb, 0, sizeof(m_out_a_cb));
+ memset(&m_out_b_cb, 0, sizeof(m_out_b_cb));
+ memset(&m_out_ca2_cb, 0, sizeof(m_out_ca2_cb));
+ memset(&m_out_cb2_cb, 0, sizeof(m_out_cb2_cb));
+ memset(&m_irq_cb, 0, sizeof(m_irq_cb));
+ }
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void via6522_device::device_start()
+{
+ 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_ca1_func.resolve(m_out_ca1_cb, *this);
+ m_out_cb1_func.resolve(m_out_cb1_cb, *this);
+ m_out_ca2_func.resolve(m_out_ca2_cb, *this);
+ m_out_cb2_func.resolve(m_out_cb2_cb, *this);
+ m_irq_func.resolve(m_irq_cb, *this);
+
+ m_t1ll = 0xf3; /* via at 0x9110 in vic20 show these values */
+ m_t1lh = 0xb5; /* ports are not written by kernel! */
+ m_t2ll = 0xff; /* taken from vice */
+ m_t2lh = 0xff;
+ m_time2 = m_time1 = machine().time();
+ m_t1 = timer_alloc(TIMER_T1);
+ m_t2 = timer_alloc(TIMER_T2);
+ m_shift_timer = timer_alloc(TIMER_SHIFT);
+
+ /* Default clock is from CPU1 */
+ if (clock() == 0)
+ {
+ set_unscaled_clock(machine().firstcpu->clock());
+ }
+
+ /* save state register */
+ 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_ddr_a));
+ 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_ddr_b));
+ save_item(NAME(m_t1cl));
+ save_item(NAME(m_t1ch));
+ save_item(NAME(m_t1ll));
+ save_item(NAME(m_t1lh));
+ save_item(NAME(m_t2cl));
+ save_item(NAME(m_t2ch));
+ save_item(NAME(m_t2ll));
+ save_item(NAME(m_t2lh));
+ save_item(NAME(m_sr));
+ save_item(NAME(m_pcr));
+ save_item(NAME(m_acr));
+ save_item(NAME(m_ier));
+ save_item(NAME(m_ifr));
+ save_item(NAME(m_t1_active));
+ save_item(NAME(m_t2_active));
+ save_item(NAME(m_shift_counter));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void via6522_device::device_reset()
+{
+ m_in_a = 0;
+ m_in_ca1 = 0;
+ m_in_ca2 = 0;
+ m_out_a = 0;
+ m_out_ca2 = 0;
+ m_ddr_a = 0;
+ m_in_b = 0;
+ m_in_cb1 = 0;
+ m_in_cb2 = 0;
+ m_out_b = 0;
+ m_out_cb2 = 0;
+ m_ddr_b = 0;
+
+ m_t1cl = 0;
+ m_t1ch = 0;
+ m_t2cl = 0;
+ m_t2ch = 0;
+
+ m_sr = 0;
+ m_pcr = 0;
+ m_acr = 0;
+ m_ier = 0;
+ m_ifr = 0;
+ m_t1_active = 0;
+ m_t2_active = 0;
+ m_shift_counter = 0;
+}
+
+
+/*-------------------------------------------------
+ via_set_int - external interrupt check
+-------------------------------------------------*/
+
+void via6522_device::set_int(int data)
+{
+ m_ifr |= data;
+ if (TRACE_VIA)
+ {
+ logerror("%s:6522VIA chip %s: IFR = %02X\n", machine().describe_context(), tag(), m_ifr);
+ }
+
+ if (m_ier & m_ifr)
+ {
+ m_ifr |= INT_ANY;
+ m_irq_func(ASSERT_LINE);
+ }
+}
+
+
+/*-------------------------------------------------
+ via_clear_int - external interrupt check
+-------------------------------------------------*/
+
+void via6522_device::clear_int(int data)
+{
+ m_ifr = (m_ifr & ~data) & 0x7f;
+
+ if (TRACE_VIA)
+ {
+ logerror("%s:6522VIA chip %s: IFR = %02X\n", machine().describe_context(), tag(), m_ifr);
+ }
+
+ if (m_ifr & m_ier)
+ {
+ m_ifr |= INT_ANY;
+ }
+ else
+ {
+ m_irq_func(CLEAR_LINE);
+ }
+}
+
+
+/*-------------------------------------------------
+ via_shift
+-------------------------------------------------*/
+
+void via6522_device::shift()
+{
+ if (SO_O2_CONTROL(m_acr) || SO_T2_CONTROL(m_acr))
+ {
+ m_out_cb2 = (m_sr >> 7) & 1;
+ m_sr = (m_sr << 1) | m_out_cb2;
+
+ m_out_cb2_func(m_out_cb2);
+
+ m_in_cb1=1;
+
+ /* this should be one cycle wide */
+ m_out_cb1_func(0);
+ m_out_cb1_func(1);
+
+ m_shift_counter = (m_shift_counter + 1) % 8;
+
+ if (m_shift_counter)
+ {
+ if (SO_O2_CONTROL(m_acr)) {
+ m_shift_timer->adjust(cycles_to_time(2));
+ } else {
+ m_shift_timer->adjust(cycles_to_time((m_t2ll + 2)*2));
+ }
+ }
+ else
+ {
+ if (!(m_ifr & INT_SR))
+ {
+ set_int(INT_SR);
+ }
+ }
+ }
+ if (SO_EXT_CONTROL(m_acr))
+ {
+ m_out_cb2 = (m_sr >> 7) & 1;
+ m_sr = (m_sr << 1) | m_out_cb2;
+
+ m_out_cb2_func(m_out_cb2);
+
+ m_shift_counter = (m_shift_counter + 1) % 8;
+
+ if (m_shift_counter == 0)
+ {
+ if (!(m_ifr & INT_SR))
+ {
+ set_int(INT_SR);
+ }
+ }
+ }
+ if (SI_EXT_CONTROL(m_acr))
+ {
+ if (!m_in_cb2_func.isnull())
+ {
+ m_in_cb2 = m_in_cb2_func();
+ }
+
+ m_sr = (m_sr << 1) | (m_in_cb2 & 1);
+
+ m_shift_counter = (m_shift_counter + 1) % 8;
+
+ if (m_shift_counter == 0)
+ {
+ if (!(m_ifr & INT_SR))
+ {
+ set_int(INT_SR);
+ }
+ }
+ }
+}
+
+
+void via6522_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch (id)
+ {
+ // shift timer
+ case TIMER_SHIFT:
+ shift();
+ break;
+
+ // t1 timeout
+ case TIMER_T1:
+ if (T1_CONTINUOUS (m_acr))
+ {
+ if (T1_SET_PB7(m_acr))
+ {
+ m_out_b ^= 0x80;
+ }
+ m_t1->adjust(cycles_to_time(TIMER1_VALUE + IFR_DELAY));
+ }
+ else
+ {
+ if (T1_SET_PB7(m_acr))
+ {
+ m_out_b |= 0x80;
+ }
+ m_t1_active = 0;
+ m_time1 = machine().time();
+ }
+ if (m_ddr_b)
+ {
+ UINT8 write_data = (m_out_b & m_ddr_b) | (m_ddr_b ^ 0xff);
+ m_out_b_func(0, write_data);
+ }
+
+ if (!(m_ifr & INT_T1))
+ {
+ set_int(INT_T1);
+ }
+ break;
+
+ // t2 timeout
+ case TIMER_T2:
+ m_t2_active = 0;
+ m_time2 = machine().time();
+
+ if (!(m_ifr & INT_T2))
+ {
+ set_int(INT_T2);
+ }
+ break;
+ }
+}
+
+/*-------------------------------------------------
+ via_r - CPU interface for VIA read
+-------------------------------------------------*/
+
+READ8_MEMBER( via6522_device::read )
+{
+ int val = 0;
+
+ offset &= 0xf;
+
+ switch (offset)
+ {
+ case VIA_PB:
+ /* update the input */
+ if (PB_LATCH_ENABLE(m_acr) == 0)
+ {
+ if (m_ddr_b != 0xff)
+ {
+ if (!m_in_b_func.isnull())
+ {
+ m_in_b = m_in_b_func(0);
+ }
+ else
+ {
+ logerror("%s:6522VIA chip %s: Port B is being read but has no handler\n", machine().describe_context(), tag());
+ }
+ }
+ }
+
+ CLR_PB_INT();
+
+ /* combine input and output values, hold DDRB bit 7 high if T1_SET_PB7 */
+ if (T1_SET_PB7(m_acr))
+ {
+ val = (m_out_b & (m_ddr_b | 0x80)) | (m_in_b & ~(m_ddr_b | 0x80));
+ }
+ else
+ {
+ val = (m_out_b & m_ddr_b) + (m_in_b & ~m_ddr_b);
+ }
+ break;
+
+ case VIA_PA:
+ /* update the input */
+ if (PA_LATCH_ENABLE(m_acr) == 0)
+ {
+ if (m_ddr_a != 0xff)
+ {
+ if (!m_in_a_func.isnull())
+ {
+ m_in_a = m_in_a_func(0);
+ }
+ else
+ {
+ logerror("%s:6522VIA chip %s: Port A is being read but has no handler\n", machine().describe_context(), tag());
+ }
+ }
+ }
+
+ /* combine input and output values */
+ val = (m_out_a & m_ddr_a) + (m_in_a & ~m_ddr_a);
+
+ CLR_PA_INT();
+
+ /* If CA2 is configured as output and in pulse or handshake mode,
+ CA2 is set now */
+ if (CA2_AUTO_HS(m_pcr))
+ {
+ if (m_out_ca2)
+ {
+ /* set CA2 */
+ m_out_ca2 = 0;
+
+ /* call the CA2 output function */
+ m_out_ca2_func(0);
+ }
+ }
+
+ break;
+
+ case VIA_PANH:
+ /* update the input */
+ if (PA_LATCH_ENABLE(m_acr) == 0)
+ {
+ if (!m_in_a_func.isnull())
+ {
+ m_in_a = m_in_a_func(0);
+ }
+ else
+ {
+ logerror("%s:6522VIA chip %s: Port A is being read but has no handler\n", machine().describe_context(), tag());
+ }
+ }
+
+ /* combine input and output values */
+ val = (m_out_a & m_ddr_a) + (m_in_a & ~m_ddr_a);
+ break;
+
+ case VIA_DDRB:
+ val = m_ddr_b;
+ break;
+
+ case VIA_DDRA:
+ val = m_ddr_a;
+ break;
+
+ case VIA_T1CL:
+ clear_int(INT_T1);
+ val = get_counter1_value() & 0xFF;
+ break;
+
+ case VIA_T1CH:
+ val = get_counter1_value() >> 8;
+ break;
+
+ case VIA_T1LL:
+ val = m_t1ll;
+ break;
+
+ case VIA_T1LH:
+ val = m_t1lh;
+ break;
+
+ case VIA_T2CL:
+ clear_int(INT_T2);
+ if (m_t2_active)
+ {
+ val = time_to_cycles(m_t2->remaining()) & 0xff;
+ }
+ else
+ {
+ if (T2_COUNT_PB6(m_acr))
+ {
+ val = m_t2cl;
+ }
+ else
+ {
+ val = (0x10000 - (time_to_cycles(machine().time() - m_time2) & 0xffff) - 1) & 0xff;
+ }
+ }
+ break;
+
+ case VIA_T2CH:
+ if (m_t2_active)
+ {
+ val = time_to_cycles(m_t2->remaining()) >> 8;
+ }
+ else
+ {
+ if (T2_COUNT_PB6(m_acr))
+ {
+ val = m_t2ch;
+ }
+ else
+ {
+ val = (0x10000 - (time_to_cycles(machine().time() - m_time2) & 0xffff) - 1) >> 8;
+ }
+ }
+ break;
+
+ case VIA_SR:
+ val = m_sr;
+ m_shift_counter=0;
+ clear_int(INT_SR);
+ if (SO_O2_CONTROL(m_acr))
+ {
+ m_shift_timer->adjust(cycles_to_time(2));
+ }
+ if (SO_T2_CONTROL(m_acr))
+ {
+ m_shift_timer->adjust(cycles_to_time((m_t2ll + 2)*2));
+ }
+ break;
+
+ case VIA_PCR:
+ val = m_pcr;
+ break;
+
+ case VIA_ACR:
+ val = m_acr;
+ break;
+
+ case VIA_IER:
+ val = m_ier | 0x80;
+ break;
+
+ case VIA_IFR:
+ val = m_ifr;
+ break;
+ }
+ return val;
+}
+
+
+/*-------------------------------------------------
+ via_w - CPU interface for VIA write
+-------------------------------------------------*/
+
+WRITE8_MEMBER( via6522_device::write )
+{
+ offset &=0x0f;
+
+ switch (offset)
+ {
+ case VIA_PB:
+ if (T1_SET_PB7(m_acr))
+ m_out_b = (m_out_b & 0x80) | (data & 0x7f);
+ else
+ m_out_b = data;
+
+ if (m_ddr_b)
+ {
+ UINT8 write_data = (m_out_b & m_ddr_b) | (m_ddr_b ^ 0xff);
+ m_out_b_func(0, write_data);
+ }
+
+ CLR_PB_INT();
+
+ /* If CB2 is configured as output and in pulse or handshake mode,
+ CB2 is set now */
+ if (CB2_AUTO_HS(m_pcr))
+ {
+ if (m_out_cb2)
+ {
+ /* set CB2 */
+ m_out_cb2 = 0;
+
+ /* call the CB2 output function */
+ m_out_cb2_func(0);
+ }
+ }
+ break;
+
+ case VIA_PA:
+ m_out_a = data;
+
+ if (m_ddr_a)
+ {
+ UINT8 write_data = (m_out_a & m_ddr_a) | (m_ddr_a ^ 0xff);
+ m_out_a_func(0, write_data);
+ }
+
+ CLR_PA_INT();
+
+ /* If CA2 is configured as output and in pulse or handshake mode,
+ CA2 is set now */
+ if (CA2_PULSE_OUTPUT(m_pcr))
+ {
+ /* call the CA2 output function */
+ m_out_ca2_func(0);
+ m_out_ca2_func(1);
+
+ /* set CA2 (shouldn't be needed) */
+ m_out_ca2 = 1;
+ }
+ else if (CA2_AUTO_HS(m_pcr))
+ {
+ if (m_out_ca2)
+ {
+ /* set CA2 */
+ m_out_ca2 = 0;
+
+ /* call the CA2 output function */
+ m_out_ca2_func(0);
+ }
+ }
+
+ break;
+
+ case VIA_PANH:
+ m_out_a = data;
+
+ if (m_ddr_a)
+ {
+ UINT8 write_data = (m_out_a & m_ddr_a) | (m_ddr_a ^ 0xff);
+ m_out_a_func(0, write_data);
+ }
+
+ break;
+
+ case VIA_DDRB:
+ /* EHC 03/04/2000 - If data direction changed, present output on the lines */
+ if ( data != m_ddr_b )
+ {
+ m_ddr_b = data;
+
+ //if (m_ddr_b)
+ {
+ UINT8 write_data = (m_out_b & m_ddr_b) | (m_ddr_b ^ 0xff);
+ m_out_b_func(0, write_data);
+ }
+ }
+ break;
+
+ case VIA_DDRA:
+ /* EHC 03/04/2000 - If data direction changed, present output on the lines */
+ if ( data != m_ddr_a )
+ {
+ m_ddr_a = data;
+
+ //if (m_ddr_a)
+ {
+ UINT8 write_data = (m_out_a & m_ddr_a) | (m_ddr_a ^ 0xff);
+ m_out_a_func(0, write_data);
+ }
+ }
+ break;
+
+ case VIA_T1CL:
+ case VIA_T1LL:
+ m_t1ll = data;
+ break;
+
+ case VIA_T1LH:
+ m_t1lh = data;
+ clear_int(INT_T1);
+ break;
+
+ case VIA_T1CH:
+ m_t1ch = m_t1lh = data;
+ m_t1cl = m_t1ll;
+
+ clear_int(INT_T1);
+
+ if (T1_SET_PB7(m_acr))
+ {
+ m_out_b &= 0x7f;
+
+ //if (m_ddr_b)
+ {
+ UINT8 write_data = (m_out_b & m_ddr_b) | (m_ddr_b ^ 0xff);
+ m_out_b_func(0, write_data);
+ }
+ }
+ m_t1->adjust(cycles_to_time(TIMER1_VALUE + IFR_DELAY));
+ m_t1_active = 1;
+ break;
+
+ case VIA_T2CL:
+ m_t2ll = data;
+ break;
+
+ case VIA_T2CH:
+ m_t2ch = m_t2lh = data;
+ m_t2cl = m_t2ll;
+
+ clear_int(INT_T2);
+
+ if (!T2_COUNT_PB6(m_acr))
+ {
+ m_t2->adjust(cycles_to_time(TIMER2_VALUE + IFR_DELAY));
+ m_t2_active = 1;
+ }
+ else
+ {
+ m_t2->adjust(cycles_to_time(TIMER2_VALUE));
+ m_t2_active = 1;
+ m_time2 = machine().time();
+ }
+ break;
+
+ case VIA_SR:
+ m_sr = data;
+ m_shift_counter=0;
+ clear_int(INT_SR);
+ if (SO_O2_CONTROL(m_acr))
+ {
+ m_shift_timer->adjust(cycles_to_time(2));
+ }
+ if (SO_T2_CONTROL(m_acr))
+ {
+ m_shift_timer->adjust(cycles_to_time((m_t2ll + 2)*2));
+ }
+ break;
+
+ case VIA_PCR:
+ m_pcr = data;
+
+ if (TRACE_VIA)
+ {
+ logerror("%s:6522VIA chip %s: PCR = %02X\n", machine().describe_context(), tag(), data);
+ }
+
+ if (CA2_FIX_OUTPUT(data) && CA2_OUTPUT_LEVEL(data) ^ m_out_ca2)
+ {
+ m_out_ca2 = CA2_OUTPUT_LEVEL(data);
+ m_out_ca2_func(m_out_ca2);
+ }
+
+ if (CB2_FIX_OUTPUT(data) && CB2_OUTPUT_LEVEL(data) ^ m_out_cb2)
+ {
+ m_out_cb2 = CB2_OUTPUT_LEVEL(data);
+ m_out_cb2_func(m_out_cb2);
+ }
+ break;
+
+ case VIA_ACR:
+ {
+ UINT16 counter1 = get_counter1_value();
+ m_acr = data;
+ if (T1_SET_PB7(m_acr))
+ {
+ if (m_t1_active)
+ {
+ m_out_b &= ~0x80;
+ }
+ else
+ {
+ m_out_b |= 0x80;
+ }
+
+ //if (m_ddr_b)
+ {
+ UINT8 write_data = (m_out_b & m_ddr_b) | (m_ddr_b ^ 0xff);
+ m_out_b_func(0, write_data);
+ }
+ }
+ if (T1_CONTINUOUS(data))
+ {
+ m_t1->adjust(cycles_to_time(counter1 + IFR_DELAY));
+ m_t1_active = 1;
+ }
+ }
+ break;
+
+ case VIA_IER:
+ if (data & 0x80)
+ {
+ m_ier |= data & 0x7f;
+ }
+ else
+ {
+ m_ier &= ~(data & 0x7f);
+ }
+
+ if (m_ifr & INT_ANY)
+ {
+ if (((m_ifr & m_ier) & 0x7f) == 0)
+ {
+ m_ifr &= ~INT_ANY;
+ m_irq_func(CLEAR_LINE);
+ }
+ }
+ else
+ {
+ if ((m_ier & m_ifr) & 0x7f)
+ {
+ m_ifr |= INT_ANY;
+ m_irq_func(ASSERT_LINE);
+ }
+ }
+ break;
+
+ case VIA_IFR:
+ if (data & INT_ANY)
+ {
+ data = 0x7f;
+ }
+ clear_int(data);
+ break;
+ }
+}
+
+
+/*-------------------------------------------------
+ ca1_w - interface setting VIA port CA1 input
+-------------------------------------------------*/
+
+WRITE_LINE_MEMBER( via6522_device::write_ca1 )
+{
+ /* handle the active transition */
+ if (state != m_in_ca1)
+ {
+ if (TRACE_VIA)
+ logerror("%s:6522VIA chip %s: CA1 = %02X\n", machine().describe_context(), tag(), state);
+
+ if ((CA1_LOW_TO_HIGH(m_pcr) && state) || (CA1_HIGH_TO_LOW(m_pcr) && !state))
+ {
+ if (PA_LATCH_ENABLE(m_acr))
+ {
+ if (!m_in_a_func.isnull())
+ {
+ m_in_a = m_in_a_func(0);
+ }
+ else
+ {
+ logerror("%s:6522VIA chip %s: Port A is being read but has no handler\n", machine().describe_context(), tag());
+ }
+ }
+
+ set_int(INT_CA1);
+
+ /* CA2 is configured as output and in pulse or handshake mode,
+ CA2 is cleared now */
+ if (CA2_AUTO_HS(m_pcr))
+ {
+ if (!m_out_ca2)
+ {
+ /* clear CA2 */
+ m_out_ca2 = 1;
+
+ /* call the CA2 output function */
+ m_out_ca2_func(1);
+ }
+ }
+ }
+
+ m_in_ca1 = state;
+ }
+}
+
+
+/*-------------------------------------------------
+ ca2_w - interface setting VIA port CA2 input
+-------------------------------------------------*/
+
+WRITE_LINE_MEMBER( via6522_device::write_ca2 )
+{
+ /* CA2 is in input mode */
+ if (CA2_INPUT(m_pcr))
+ {
+ /* the new state has caused a transition */
+ if (m_in_ca2 != state)
+ {
+ /* handle the active transition */
+ if ((state && CA2_LOW_TO_HIGH(m_pcr)) || (!state && CA2_HIGH_TO_LOW(m_pcr)))
+ {
+ /* mark the IRQ */
+ set_int(INT_CA2);
+ }
+ /* set the new value for CA2 */
+ m_in_ca2 = state;
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ cb1_w - interface setting VIA port CB1 input
+-------------------------------------------------*/
+
+WRITE_LINE_MEMBER( via6522_device::write_cb1 )
+{
+ /* handle the active transition */
+ if (state != m_in_cb1)
+ {
+ if ((CB1_LOW_TO_HIGH(m_pcr) && state) || (CB1_HIGH_TO_LOW(m_pcr) && !state))
+ {
+ if (PB_LATCH_ENABLE(m_acr))
+ {
+ if (!m_in_b_func.isnull())
+ {
+ m_in_b = m_in_b_func(0);
+ }
+ else
+ {
+ logerror("%s:6522VIA chip %s: Port B is being read but has no handler\n", machine().describe_context(), tag());
+ }
+ }
+ if (SO_EXT_CONTROL(m_acr) || SI_EXT_CONTROL(m_acr))
+ {
+ shift();
+ }
+
+ set_int(INT_CB1);
+
+ /* CB2 is configured as output and in pulse or handshake mode,
+ CB2 is cleared now */
+ if (CB2_AUTO_HS(m_pcr))
+ {
+ if (!m_out_cb2)
+ {
+ /* clear CB2 */
+ m_out_cb2 = 1;
+
+ /* call the CB2 output function */
+ m_out_cb2_func(1);
+ }
+ }
+ }
+ m_in_cb1 = state;
+ }
+}
+
+
+/*-------------------------------------------------
+ cb2_w - interface setting VIA port CB2 input
+-------------------------------------------------*/
+
+WRITE_LINE_MEMBER( via6522_device::write_cb2 )
+{
+ /* CB2 is in input mode */
+ if (CB2_INPUT(m_pcr))
+ {
+ /* the new state has caused a transition */
+ if (m_in_cb2 != state)
+ {
+ /* handle the active transition */
+ if ((state && CB2_LOW_TO_HIGH(m_pcr)) || (!state && CB2_HIGH_TO_LOW(m_pcr)))
+ {
+ /* mark the IRQ */
+ set_int(INT_CB2);
+ }
+ /* set the new value for CB2 */
+ m_in_cb2 = state;
+ }
+ }
+}