diff options
Diffstat (limited to 'trunk/src/emu/machine/6522via.c')
-rw-r--r-- | trunk/src/emu/machine/6522via.c | 1072 |
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; + } + } +} |