summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/machine/6522via.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/machine/6522via.c')
-rw-r--r--src/emu/machine/6522via.c1153
1 files changed, 1153 insertions, 0 deletions
diff --git a/src/emu/machine/6522via.c b/src/emu/machine/6522via.c
new file mode 100644
index 00000000000..21a067d8d3b
--- /dev/null
+++ b/src/emu/machine/6522via.c
@@ -0,0 +1,1153 @@
+/**********************************************************************
+
+ 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 "driver.h"
+#include "6522via.h"
+
+//#define TRACE_VIA
+
+/******************* internal VIA data structure *******************/
+
+struct via6522
+{
+ const struct via6522_interface *intf;
+
+ UINT8 in_a;
+ UINT8 in_ca1;
+ UINT8 in_ca2;
+ UINT8 out_a;
+ UINT8 out_ca2;
+ UINT8 ddr_a;
+
+ UINT8 in_b;
+ UINT8 in_cb1;
+ UINT8 in_cb2;
+ UINT8 out_b;
+ UINT8 out_cb2;
+ UINT8 ddr_b;
+
+ UINT8 t1cl;
+ UINT8 t1ch;
+ UINT8 t1ll;
+ UINT8 t1lh;
+ UINT8 t2cl;
+ UINT8 t2ch;
+ UINT8 t2ll;
+ UINT8 t2lh;
+
+ UINT8 sr;
+ UINT8 pcr;
+ UINT8 acr;
+ UINT8 ier;
+ UINT8 ifr;
+
+ emu_timer *t1;
+ attotime time1;
+ UINT8 t1_active;
+ emu_timer *t2;
+ attotime time2;
+ UINT8 t2_active;
+ UINT8 shift_counter;
+
+ int clock;
+};
+
+
+/******************* convenince macros and defines *******************/
+
+/* 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(v, which) via_clear_int (which, INT_CA1 | ((!CA2_IND_IRQ(v->pcr)) ? INT_CA2: 0))
+#define CLR_PB_INT(v, which) via_clear_int (which, INT_CB1 | ((!CB2_IND_IRQ(v->pcr)) ? INT_CB2: 0))
+
+#define IFR_DELAY 3
+
+#define TIMER1_VALUE(v) (v->t1ll+(v->t1lh<<8))
+#define TIMER2_VALUE(v) (v->t2ll+(v->t2lh<<8))
+
+/******************* static variables *******************/
+
+static struct via6522 via[MAX_VIA];
+
+/******************* configuration *******************/
+
+void via_set_clock(int which,int clock)
+{
+ via[which].clock = clock;
+}
+
+void via_config(int which, const struct via6522_interface *intf)
+{
+ assert(which < MAX_VIA);
+
+ via[which].intf = intf;
+ via[which].t1ll = 0xf3; /* via at 0x9110 in vic20 show these values */
+ via[which].t1lh = 0xb5; /* ports are not written by kernel! */
+ via[which].t2ll = 0xff; /* taken from vice */
+ via[which].t2lh = 0xff;
+ via[which].time2 = via[which].time1 = timer_get_time();
+
+ /* Default clock is from CPU1 */
+ via_set_clock (which, Machine->drv->cpu[0].clock);
+}
+
+/******************* external interrupt check *******************/
+
+static void via_set_int (int which, int data)
+{
+ struct via6522 *v = via + which;
+
+
+ v->ifr |= data;
+#ifdef TRACE_VIA
+logerror("6522VIA chip %d: IFR = %02X. PC: %08X\n", which, v->ifr, safe_activecpu_get_pc());
+#endif
+
+ if (v->ier & v->ifr)
+ {
+ v->ifr |= INT_ANY;
+ if (v->intf->irq_func)
+ (*v->intf->irq_func)(ASSERT_LINE);
+ else
+ logerror("6522VIA chip %d: Interrupt is asserted but there is no callback function. PC: %08X\n", which, safe_activecpu_get_pc());
+ }
+}
+
+static void via_clear_int (int which, int data)
+{
+ struct via6522 *v = via + which;
+
+
+ v->ifr = (v->ifr & ~data) & 0x7f;
+#ifdef TRACE_VIA
+logerror("6522VIA chip %d: IFR = %02X. PC: %08X\n", which, v->ifr, safe_activecpu_get_pc());
+#endif
+
+ if (v->ifr & v->ier)
+ v->ifr |= INT_ANY;
+ else
+ {
+ if (v->intf->irq_func)
+ (*v->intf->irq_func)(CLEAR_LINE);
+// else
+// logerror("6522VIA chip %d: Interrupt is cleared but there is no callback function. PC: %08X\n", which, safe_activecpu_get_pc());
+ }
+}
+
+
+INLINE attotime v_cycles_to_time(struct via6522 *v, int c)
+{
+ return attotime_mul(ATTOTIME_IN_HZ(v->clock), c);
+}
+
+
+INLINE UINT32 v_time_to_cycles(struct via6522 *v, attotime t)
+{
+ return attotime_to_double(attotime_mul(t, v->clock));
+}
+
+
+/************************ shift register ************************/
+
+static TIMER_CALLBACK( via_shift_callback );
+
+static void via_shift(int which)
+{
+ struct via6522 *v = via + which;
+
+ if (SO_O2_CONTROL(v->acr))
+ {
+ v->out_cb2 = (v->sr >> 7) & 1;
+ v->sr = (v->sr << 1) | v->out_cb2;
+
+ if (v->intf->out_cb2_func)
+ v->intf->out_cb2_func(0, v->out_cb2);
+
+ v->in_cb1=1;
+ if (v->intf->out_cb1_func)
+ {
+ /* this should be one cycle wide */
+ v->intf->out_cb1_func(0, 0);
+ v->intf->out_cb1_func(0, 1);
+ }
+
+ v->shift_counter = (v->shift_counter + 1) % 8;
+
+ if (v->shift_counter)
+ timer_set(v_cycles_to_time(v, 2), which, via_shift_callback);
+ else
+ {
+ if (!(v->ifr & INT_SR))
+ via_set_int(which, INT_SR);
+ }
+ }
+ if (SO_EXT_CONTROL(v->acr))
+ {
+ v->out_cb2 = (v->sr >> 7) & 1;
+ v->sr = (v->sr << 1) | v->out_cb2;
+
+ if (v->intf->out_cb2_func)
+ v->intf->out_cb2_func(0, v->out_cb2);
+
+ v->shift_counter = (v->shift_counter + 1) % 8;
+
+ if (v->shift_counter == 0)
+ {
+ if (!(v->ifr & INT_SR))
+ via_set_int(which, INT_SR);
+ }
+ }
+ if (SI_EXT_CONTROL(v->acr))
+ {
+ if (v->intf->in_cb2_func)
+ v->in_cb2 = v->intf->in_cb2_func(0);
+
+ v->sr = (v->sr << 1) | (v->in_cb2 & 1);
+
+ v->shift_counter = (v->shift_counter + 1) % 8;
+
+ if (v->shift_counter == 0)
+ {
+ if (!(v->ifr & INT_SR))
+ {
+ via_set_int(which, INT_SR);
+ }
+ }
+ }
+}
+
+static TIMER_CALLBACK( via_shift_callback )
+{
+ via_shift(param);
+}
+
+/******************* Timer timeouts *************************/
+
+static TIMER_CALLBACK( via_t1_timeout )
+{
+ int which = param;
+ struct via6522 *v = via + which;
+
+
+ if (T1_CONTINUOUS (v->acr))
+ {
+ if (T1_SET_PB7(v->acr))
+ v->out_b ^= 0x80;
+ timer_adjust(v->t1, v_cycles_to_time(v, TIMER1_VALUE(v) + IFR_DELAY), which, attotime_zero);
+ }
+ else
+ {
+ if (T1_SET_PB7(v->acr))
+ v->out_b |= 0x80;
+ v->t1_active = 0;
+ v->time1 = timer_get_time();
+ }
+ if (v->ddr_b)
+ {
+ UINT8 write_data = (v->out_b & v->ddr_b) | (v->ddr_b ^ 0xff);
+
+ if (v->intf->out_b_func)
+ v->intf->out_b_func(0, write_data);
+ else
+ logerror("6522VIA chip %d: Port B is being written to but has no handler. PC: %08X - %02X\n", which, safe_activecpu_get_pc(), write_data);
+ }
+
+ if (!(v->ifr & INT_T1))
+ via_set_int (which, INT_T1);
+}
+
+static TIMER_CALLBACK( via_t2_timeout )
+{
+ int which = param;
+ struct via6522 *v = via + which;
+
+ v->t2_active = 0;
+ v->time2 = timer_get_time();
+
+ if (!(v->ifr & INT_T2))
+ via_set_int (which, INT_T2);
+}
+
+/******************* reset *******************/
+
+void via_reset(void)
+{
+ int i;
+ struct via6522 v;
+
+ memset(&v, 0, sizeof(v));
+
+ for (i = 0; i < MAX_VIA; i++)
+ {
+ v.intf = via[i].intf;
+ v.t1ll = via[i].t1ll;
+ v.t1lh = via[i].t1lh;
+ v.t2ll = via[i].t2ll;
+ v.t2lh = via[i].t2lh;
+ v.time1 = via[i].time1;
+ v.time2 = via[i].time2;
+ v.clock = via[i].clock;
+
+ v.t1 = timer_alloc(via_t1_timeout);
+ v.t1_active = 0;
+ v.t2 = timer_alloc(via_t2_timeout);
+ v.t2_active = 0;
+
+ via[i] = v;
+ }
+}
+
+/******************* CPU interface for VIA read *******************/
+
+int via_read(int which, int offset)
+{
+ struct via6522 *v = via + which;
+ int val = 0;
+
+ offset &= 0xf;
+
+ switch (offset)
+ {
+ case VIA_PB:
+ /* update the input */
+ if (PB_LATCH_ENABLE(v->acr) == 0)
+ {
+ if (v->intf->in_b_func)
+ v->in_b = v->intf->in_b_func(0);
+ else
+ logerror("6522VIA chip %d: Port B is being read but has no handler. PC: %08X\n", which, safe_activecpu_get_pc());
+ }
+
+ CLR_PB_INT(v, which);
+
+ /* combine input and output values, hold DDRB bit 7 high if T1_SET_PB7 */
+ if (T1_SET_PB7(v->acr))
+ val = (v->out_b & (v->ddr_b | 0x80)) | (v->in_b & ~(v->ddr_b | 0x80));
+ else
+ val = (v->out_b & v->ddr_b) + (v->in_b & ~v->ddr_b);
+ break;
+
+ case VIA_PA:
+ /* update the input */
+ if (PA_LATCH_ENABLE(v->acr) == 0)
+ {
+ if (v->intf->in_a_func)
+ v->in_a = v->intf->in_a_func(0);
+ else
+ logerror("6522VIA chip %d: Port A is being read but has no handler. PC: %08X\n", which, safe_activecpu_get_pc());
+ }
+
+ /* combine input and output values */
+ val = (v->out_a & v->ddr_a) + (v->in_a & ~v->ddr_a);
+
+ CLR_PA_INT(v, which);
+
+ /* If CA2 is configured as output and in pulse or handshake mode,
+ CA2 is set now */
+ if (CA2_AUTO_HS(v->pcr))
+ {
+ if (v->out_ca2)
+ {
+ /* set CA2 */
+ v->out_ca2 = 0;
+
+ /* call the CA2 output function */
+ if (v->intf->out_ca2_func)
+ v->intf->out_ca2_func(0, 0);
+ else
+ logerror("6522VIA chip %d: Port CA2 is being written to but has no handler. PC: %08X - %02X\n", which, safe_activecpu_get_pc(), 0);
+ }
+ }
+
+ break;
+
+ case VIA_PANH:
+ /* update the input */
+ if (PA_LATCH_ENABLE(v->acr) == 0)
+ {
+ if (v->intf->in_a_func)
+ v->in_a = v->intf->in_a_func(0);
+ else
+ logerror("6522VIA chip %d: Port A is being read but has no handler. PC: %08X\n", which, safe_activecpu_get_pc());
+ }
+
+ /* combine input and output values */
+ val = (v->out_a & v->ddr_a) + (v->in_a & ~v->ddr_a);
+ break;
+
+ case VIA_DDRB:
+ val = v->ddr_b;
+ break;
+
+ case VIA_DDRA:
+ val = v->ddr_a;
+ break;
+
+ case VIA_T1CL:
+ via_clear_int (which, INT_T1);
+ if (v->t1_active)
+ val = v_time_to_cycles(v, timer_timeleft(v->t1)) & 0xff;
+ else
+ {
+ if ( T1_CONTINUOUS(v->acr) )
+ val = (TIMER1_VALUE(v) - (v_time_to_cycles(v, attotime_sub(timer_get_time(), v->time1)) % TIMER1_VALUE(v)) - 1) & 0xff;
+ else
+ val = (0x10000 - (v_time_to_cycles(v, attotime_sub(timer_get_time(), v->time1)) & 0xffff) - 1) & 0xff;
+ }
+ break;
+
+ case VIA_T1CH:
+ if (v->t1_active)
+ val = v_time_to_cycles(v, timer_timeleft(v->t1)) >> 8;
+ else
+ {
+ if ( T1_CONTINUOUS(v->acr) )
+ val = (TIMER1_VALUE(v)- (v_time_to_cycles(v, attotime_sub(timer_get_time(), v->time1)) % TIMER1_VALUE(v)) - 1) >> 8;
+ else
+ val = (0x10000- (v_time_to_cycles(v, attotime_sub(timer_get_time(), v->time1)) & 0xffff) - 1) >> 8;
+ }
+ break;
+
+ case VIA_T1LL:
+ val = v->t1ll;
+ break;
+
+ case VIA_T1LH:
+ val = v->t1lh;
+ break;
+
+ case VIA_T2CL:
+ via_clear_int (which, INT_T2);
+ if (v->t2_active)
+ val = v_time_to_cycles(v, timer_timeleft(v->t2)) & 0xff;
+ else
+ {
+ if (T2_COUNT_PB6(v->acr))
+ val = v->t2cl;
+ else
+ val = (0x10000- (v_time_to_cycles(v, attotime_sub(timer_get_time(), v->time2)) & 0xffff) - 1) & 0xff;
+ }
+ break;
+
+ case VIA_T2CH:
+ if (v->t2_active)
+ val = v_time_to_cycles(v, timer_timeleft(v->t2)) >> 8;
+ else
+ {
+ if (T2_COUNT_PB6(v->acr))
+ val = v->t2ch;
+ else
+ val = (0x10000- (v_time_to_cycles(v, attotime_sub(timer_get_time(), v->time2)) & 0xffff) - 1) >> 8;
+ }
+ break;
+
+ case VIA_SR:
+ val = v->sr;
+ via_clear_int(which, INT_SR);
+ if (SO_O2_CONTROL(v->acr))
+ {
+ v->shift_counter=0;
+ timer_set(v_cycles_to_time(v, 2), which,via_shift_callback);
+ }
+ break;
+
+ case VIA_PCR:
+ val = v->pcr;
+ break;
+
+ case VIA_ACR:
+ val = v->acr;
+ break;
+
+ case VIA_IER:
+ val = v->ier | 0x80;
+ break;
+
+ case VIA_IFR:
+ val = v->ifr;
+ break;
+ }
+ return val;
+}
+
+
+/******************* CPU interface for VIA write *******************/
+
+void via_write(int which, int offset, int data)
+{
+ struct via6522 *v = via + which;
+
+ offset &=0x0f;
+
+ switch (offset)
+ {
+ case VIA_PB:
+ if (T1_SET_PB7(v->acr))
+ v->out_b = (v->out_b & 0x80) | (data & 0x7f);
+ else
+ v->out_b = data;
+
+ if (v->ddr_b)
+ {
+ UINT8 write_data = (v->out_b & v->ddr_b) | (v->ddr_b ^ 0xff);
+
+ if (v->intf->out_b_func)
+ v->intf->out_b_func(0, write_data);
+ else
+ logerror("6522VIA chip %d: Port B is being written to but has no handler. PC: %08X - %02X\n", which, safe_activecpu_get_pc(), write_data);
+ }
+
+ CLR_PB_INT(v, which);
+
+ /* If CB2 is configured as output and in pulse or handshake mode,
+ CB2 is set now */
+ if (CB2_AUTO_HS(v->pcr))
+ {
+ if (v->out_cb2)
+ {
+ /* set CB2 */
+ v->out_cb2 = 0;
+
+ /* call the CB2 output function */
+ if (v->intf->out_cb2_func)
+ v->intf->out_cb2_func(0, 0);
+ else
+ logerror("6522VIA chip %d: Port CB2 is being written to but has no handler. PC: %08X - %02X\n", which, safe_activecpu_get_pc(), 0);
+ }
+ }
+ break;
+
+ case VIA_PA:
+ v->out_a = data;
+
+ if (v->ddr_a)
+ {
+ UINT8 write_data = (v->out_a & v->ddr_a) | (v->ddr_a ^ 0xff);
+
+ if (v->intf->out_a_func)
+ v->intf->out_a_func(0, write_data);
+ else
+ logerror("6522VIA chip %d: Port A is being written to but has no handler. PC: %08X - %02X\n", which, safe_activecpu_get_pc(), write_data);
+ }
+
+ CLR_PA_INT(v, which);
+
+ /* If CA2 is configured as output and in pulse or handshake mode,
+ CA2 is set now */
+ if (CA2_PULSE_OUTPUT(v->pcr))
+ {
+ /* call the CA2 output function */
+ if (v->intf->out_ca2_func)
+ {
+ v->intf->out_ca2_func(0, 0);
+ v->intf->out_ca2_func(0, 1);
+ }
+ else
+ logerror("6522VIA chip %d: Port CA2 is being pulsed but has no handler. PC: %08X\n", which, safe_activecpu_get_pc());
+
+ /* set CA2 (shouldn't be needed) */
+ v->out_ca2 = 1;
+ }
+ else if (CA2_AUTO_HS(v->pcr))
+ {
+ if (v->out_ca2)
+ {
+ /* set CA2 */
+ v->out_ca2 = 0;
+
+ /* call the CA2 output function */
+ if (v->intf->out_ca2_func)
+ v->intf->out_ca2_func(0, 0);
+ else
+ logerror("6522VIA chip %d: Port CA2 is being written to but has no handler. PC: %08X - %02X\n", which, safe_activecpu_get_pc(), 0);
+ }
+ }
+
+ break;
+
+ case VIA_PANH:
+ v->out_a = data;
+
+ if (v->ddr_a)
+ {
+ UINT8 write_data = (v->out_a & v->ddr_a) | (v->ddr_a ^ 0xff);
+
+ if (v->intf->out_a_func)
+ v->intf->out_a_func(0, write_data);
+ else
+ logerror("6522VIA chip %d: Port A is being written to but has no handler. PC: %08X - %02X\n", which, safe_activecpu_get_pc(), write_data);
+ }
+
+ break;
+
+ case VIA_DDRB:
+ /* EHC 03/04/2000 - If data direction changed, present output on the lines */
+ if ( data != v->ddr_b )
+ {
+ v->ddr_b = data;
+
+ //if (v->ddr_b)
+ {
+ UINT8 write_data = (v->out_b & v->ddr_b) | (v->ddr_b ^ 0xff);
+
+ if (v->intf->out_b_func)
+ v->intf->out_b_func(0, write_data);
+ else
+ logerror("6522VIA chip %d: Port B is being written to but has no handler. PC: %08X - %02X\n", which, safe_activecpu_get_pc(), write_data);
+ }
+ }
+ break;
+
+ case VIA_DDRA:
+ /* EHC 03/04/2000 - If data direction changed, present output on the lines */
+ if ( data != v->ddr_a )
+ {
+ v->ddr_a = data;
+
+ //if (v->ddr_a)
+ {
+ UINT8 write_data = (v->out_a & v->ddr_a) | (v->ddr_a ^ 0xff);
+
+ if (v->intf->out_a_func)
+ v->intf->out_a_func(0, write_data);
+ else
+ logerror("6522VIA chip %d: Port A is being written to but has no handler. PC: %08X - %02X\n", which, safe_activecpu_get_pc(), write_data);
+ }
+ }
+ break;
+
+ case VIA_T1CL:
+ case VIA_T1LL:
+ v->t1ll = data;
+ break;
+
+ case VIA_T1LH:
+ v->t1lh = data;
+ via_clear_int (which, INT_T1);
+ break;
+
+ case VIA_T1CH:
+ v->t1ch = v->t1lh = data;
+ v->t1cl = v->t1ll;
+
+ via_clear_int (which, INT_T1);
+
+ if (T1_SET_PB7(v->acr))
+ {
+ v->out_b &= 0x7f;
+
+ //if (v->ddr_b)
+ {
+ UINT8 write_data = (v->out_b & v->ddr_b) | (v->ddr_b ^ 0xff);
+
+ if (v->intf->out_b_func)
+ v->intf->out_b_func(0, write_data);
+ else
+ logerror("6522VIA chip %d: Port B is being written to but has no handler. PC: %08X - %02X\n", which, safe_activecpu_get_pc(), write_data);
+ }
+ }
+ timer_adjust(v->t1, v_cycles_to_time(v, TIMER1_VALUE(v) + IFR_DELAY), which, attotime_zero);
+ v->t1_active = 1;
+ break;
+
+ case VIA_T2CL:
+ v->t2ll = data;
+ break;
+
+ case VIA_T2CH:
+ v->t2ch = v->t2lh = data;
+ v->t2cl = v->t2ll;
+
+ via_clear_int (which, INT_T2);
+
+ if (!T2_COUNT_PB6(v->acr))
+ {
+ timer_adjust(v->t2, v_cycles_to_time(v, TIMER2_VALUE(v) + IFR_DELAY), which, attotime_zero);
+ v->t2_active = 1;
+ }
+ else
+ {
+ v->time2 = timer_get_time();
+ }
+ break;
+
+ case VIA_SR:
+ v->sr = data;
+ v->shift_counter=0;
+ via_clear_int(which, INT_SR);
+ if (SO_O2_CONTROL(v->acr))
+ {
+ timer_set(v_cycles_to_time(v, 2), which,via_shift_callback);
+ }
+ break;
+
+ case VIA_PCR:
+ v->pcr = data;
+#ifdef TRACE_VIA
+logerror("6522VIA chip %d: PCR = %02X. PC: %08X\n", which, data, safe_activecpu_get_pc());
+#endif
+
+ if (CA2_FIX_OUTPUT(data) && CA2_OUTPUT_LEVEL(data) ^ v->out_ca2)
+ {
+ v->out_ca2 = CA2_OUTPUT_LEVEL(data);
+ if (v->intf->out_ca2_func)
+ v->intf->out_ca2_func(0, v->out_ca2);
+ else
+ logerror("6522VIA chip %d: Port CA2 is being written to but has no handler. PC: %08X - %02X\n", which, safe_activecpu_get_pc(), v->out_ca2);
+ }
+
+ if (CB2_FIX_OUTPUT(data) && CB2_OUTPUT_LEVEL(data) ^ v->out_cb2)
+ {
+ v->out_cb2 = CB2_OUTPUT_LEVEL(data);
+ if (v->intf->out_cb2_func)
+ v->intf->out_cb2_func(0, v->out_cb2);
+ else
+ logerror("6522VIA chip %d: Port CB2 is being written to but has no handler. PC: %08X - %02X\n", which, safe_activecpu_get_pc(), v->out_cb2);
+ }
+ break;
+
+ case VIA_ACR:
+ v->acr = data;
+ if (T1_SET_PB7(v->acr))
+ {
+ if (v->t1_active)
+ v->out_b &= ~0x80;
+ else
+ v->out_b |= 0x80;
+
+ //if (v->ddr_b)
+ {
+ UINT8 write_data = (v->out_b & v->ddr_b) | (v->ddr_b ^ 0xff);
+
+ if (v->intf->out_b_func)
+ v->intf->out_b_func(0, write_data);
+ else
+ logerror("6522VIA chip %d: Port B is being written to but has no handler. PC: %08X - %02X\n", which, safe_activecpu_get_pc(), write_data);
+ }
+ }
+ if (T1_CONTINUOUS(data))
+ {
+ timer_adjust(v->t1, v_cycles_to_time(v, TIMER1_VALUE(v) + IFR_DELAY), which, attotime_zero);
+ v->t1_active = 1;
+ }
+ break;
+
+ case VIA_IER:
+ if (data & 0x80)
+ v->ier |= data & 0x7f;
+ else
+ v->ier &= ~(data & 0x7f);
+
+ if (v->ifr & INT_ANY)
+ {
+ if (((v->ifr & v->ier) & 0x7f) == 0)
+ {
+ v->ifr &= ~INT_ANY;
+ if (v->intf->irq_func)
+ (*v->intf->irq_func)(CLEAR_LINE);
+// else
+// logerror("6522VIA chip %d: Interrupt is cleared but there is no callback function. PC: %08X\n", which, safe_activecpu_get_pc());
+ }
+ }
+ else
+ {
+ if ((v->ier & v->ifr) & 0x7f)
+ {
+ v->ifr |= INT_ANY;
+ if (v->intf->irq_func)
+ (*v->intf->irq_func)(ASSERT_LINE);
+ else
+ logerror("6522VIA chip %d: Interrupt is asserted but there is no callback function. PC: %08X\n", which, safe_activecpu_get_pc());
+ }
+ }
+ break;
+
+ case VIA_IFR:
+ if (data & INT_ANY)
+ data = 0x7f;
+ via_clear_int (which, data);
+ break;
+ }
+}
+
+/******************* interface setting VIA port A input *******************/
+
+void via_set_input_a(int which, int data)
+{
+ struct via6522 *v = via + which;
+
+ /* set the input, what could be easier? */
+ v->in_a = data;
+}
+
+/******************* interface setting VIA port CA1 input *******************/
+
+void via_set_input_ca1(int which, int data)
+{
+ struct via6522 *v = via + which;
+
+ /* limit the data to 0 or 1 */
+ data = data ? 1 : 0;
+
+ /* handle the active transition */
+ if (data != v->in_ca1)
+ {
+#ifdef TRACE_VIA
+logerror("6522VIA chip %d: CA1 = %02X. PC: %08X\n", which, data, safe_activecpu_get_pc());
+#endif
+ if ((CA1_LOW_TO_HIGH(v->pcr) && data) || (CA1_HIGH_TO_LOW(v->pcr) && !data))
+ {
+ if (PA_LATCH_ENABLE(v->acr))
+ {
+ if (v->intf->in_a_func)
+ v->in_a = v->intf->in_a_func(0);
+ else
+ logerror("6522VIA chip %d: Port A is being read but has no handler. PC: %08X\n", which, safe_activecpu_get_pc());
+ }
+
+ via_set_int (which, INT_CA1);
+
+ /* CA2 is configured as output and in pulse or handshake mode,
+ CA2 is cleared now */
+ if (CA2_AUTO_HS(v->pcr))
+ {
+ if (!v->out_ca2)
+ {
+ /* clear CA2 */
+ v->out_ca2 = 1;
+
+ /* call the CA2 output function */
+ if (v->intf->out_ca2_func)
+ v->intf->out_ca2_func(0, 1);
+ else
+ logerror("6522VIA chip %d: Port CA2 is being written to but has no handler. PC: %08X - %02X\n", which, safe_activecpu_get_pc(), 1);
+ }
+ }
+ }
+
+ v->in_ca1 = data;
+ }
+}
+
+/******************* interface setting VIA port CA2 input *******************/
+
+void via_set_input_ca2(int which, int data)
+{
+ struct via6522 *v = via + which;
+
+ /* limit the data to 0 or 1 */
+ data = data ? 1 : 0;
+
+ /* CA2 is in input mode */
+ if (CA2_INPUT(v->pcr))
+ {
+ /* the new state has caused a transition */
+ if (v->in_ca2 != data)
+ {
+ /* handle the active transition */
+ if ((data && CA2_LOW_TO_HIGH(v->pcr)) || (!data && CA2_HIGH_TO_LOW(v->pcr)))
+ {
+ /* mark the IRQ */
+ via_set_int (which, INT_CA2);
+ }
+ /* set the new value for CA2 */
+ v->in_ca2 = data;
+ }
+ }
+
+
+}
+
+/******************* interface setting VIA port B input *******************/
+
+void via_set_input_b(int which, int data)
+{
+ struct via6522 *v = via + which;
+
+ /* set the input, what could be easier? */
+ v->in_b = data;
+}
+
+
+
+/******************* interface setting VIA port CB1 input *******************/
+
+void via_set_input_cb1(int which, int data)
+{
+ struct via6522 *v = via + which;
+
+ /* limit the data to 0 or 1 */
+ data = data ? 1 : 0;
+
+ /* handle the active transition */
+ if (data != v->in_cb1)
+ {
+ if ((CB1_LOW_TO_HIGH(v->pcr) && data) || (CB1_HIGH_TO_LOW(v->pcr) && !data))
+ {
+ if (PB_LATCH_ENABLE(v->acr))
+ {
+ if (v->intf->in_b_func)
+ v->in_b = v->intf->in_b_func(0);
+ else
+ logerror("6522VIA chip %d: Port B is being read but has no handler. PC: %08X\n", which, safe_activecpu_get_pc());
+ }
+ if (SO_EXT_CONTROL(v->acr) || SI_EXT_CONTROL(v->acr))
+ via_shift (which);
+
+ via_set_int (which, INT_CB1);
+
+ /* CB2 is configured as output and in pulse or handshake mode,
+ CB2 is cleared now */
+ if (CB2_AUTO_HS(v->pcr))
+ {
+ if (!v->out_cb2)
+ {
+ /* clear CB2 */
+ v->out_cb2 = 1;
+
+ /* call the CB2 output function */
+ if (v->intf->out_cb2_func)
+ v->intf->out_cb2_func(0, 1);
+ else
+ logerror("6522VIA chip %d: Port CB2 is being written to but has no handler. PC: %08X - %02X\n", which, safe_activecpu_get_pc(), 1);
+ }
+ }
+ }
+ v->in_cb1 = data;
+ }
+}
+
+/******************* interface setting VIA port CB2 input *******************/
+
+void via_set_input_cb2(int which, int data)
+{
+ struct via6522 *v = via + which;
+
+ /* limit the data to 0 or 1 */
+ data = data ? 1 : 0;
+
+ /* CB2 is in input mode */
+ if (CB2_INPUT(v->pcr))
+ {
+ /* the new state has caused a transition */
+ if (v->in_cb2 != data)
+ {
+ /* handle the active transition */
+ if ((data && CB2_LOW_TO_HIGH(v->pcr)) || (!data && CB2_HIGH_TO_LOW(v->pcr)))
+ {
+ /* mark the IRQ */
+ via_set_int (which, INT_CB2);
+ }
+ /* set the new value for CB2 */
+ v->in_cb2 = data;
+ }
+ }
+}
+
+/******************* Standard 8-bit CPU interfaces, D0-D7 *******************/
+
+READ8_HANDLER( via_0_r) { return via_read(0, offset); }
+READ8_HANDLER( via_1_r) { return via_read(1, offset); }
+READ8_HANDLER( via_2_r) { return via_read(2, offset); }
+READ8_HANDLER( via_3_r) { return via_read(3, offset); }
+READ8_HANDLER( via_4_r) { return via_read(4, offset); }
+READ8_HANDLER( via_5_r) { return via_read(5, offset); }
+READ8_HANDLER( via_6_r) { return via_read(6, offset); }
+READ8_HANDLER( via_7_r) { return via_read(7, offset); }
+
+WRITE8_HANDLER( via_0_w) { via_write(0, offset, data); }
+WRITE8_HANDLER( via_1_w) { via_write(1, offset, data); }
+WRITE8_HANDLER( via_2_w) { via_write(2, offset, data); }
+WRITE8_HANDLER( via_3_w) { via_write(3, offset, data); }
+WRITE8_HANDLER( via_4_w) { via_write(4, offset, data); }
+WRITE8_HANDLER( via_5_w) { via_write(5, offset, data); }
+WRITE8_HANDLER( via_6_w) { via_write(6, offset, data); }
+WRITE8_HANDLER( via_7_w) { via_write(7, offset, data); }
+
+/******************* 8-bit A/B port interfaces *******************/
+
+WRITE8_HANDLER( via_0_porta_w) { via_set_input_a(0, data); }
+WRITE8_HANDLER( via_1_porta_w) { via_set_input_a(1, data); }
+WRITE8_HANDLER( via_2_porta_w) { via_set_input_a(2, data); }
+WRITE8_HANDLER( via_3_porta_w) { via_set_input_a(3, data); }
+WRITE8_HANDLER( via_4_porta_w) { via_set_input_a(4, data); }
+WRITE8_HANDLER( via_5_porta_w) { via_set_input_a(5, data); }
+WRITE8_HANDLER( via_6_porta_w) { via_set_input_a(6, data); }
+WRITE8_HANDLER( via_7_porta_w) { via_set_input_a(7, data); }
+
+WRITE8_HANDLER( via_0_portb_w) { via_set_input_b(0, data); }
+WRITE8_HANDLER( via_1_portb_w) { via_set_input_b(1, data); }
+WRITE8_HANDLER( via_2_portb_w) { via_set_input_b(2, data); }
+WRITE8_HANDLER( via_3_portb_w) { via_set_input_b(3, data); }
+WRITE8_HANDLER( via_4_portb_w) { via_set_input_b(4, data); }
+WRITE8_HANDLER( via_5_portb_w) { via_set_input_b(5, data); }
+WRITE8_HANDLER( via_6_portb_w) { via_set_input_b(6, data); }
+WRITE8_HANDLER( via_7_portb_w) { via_set_input_b(7, data); }
+
+READ8_HANDLER( via_0_porta_r) { return via[0].in_a; }
+READ8_HANDLER( via_1_porta_r) { return via[1].in_a; }
+READ8_HANDLER( via_2_porta_r) { return via[2].in_a; }
+READ8_HANDLER( via_3_porta_r) { return via[3].in_a; }
+READ8_HANDLER( via_4_porta_r) { return via[4].in_a; }
+READ8_HANDLER( via_5_porta_r) { return via[5].in_a; }
+READ8_HANDLER( via_6_porta_r) { return via[6].in_a; }
+READ8_HANDLER( via_7_porta_r) { return via[7].in_a; }
+
+READ8_HANDLER( via_0_portb_r) { return via[0].in_b; }
+READ8_HANDLER( via_1_portb_r) { return via[1].in_b; }
+READ8_HANDLER( via_2_portb_r) { return via[2].in_b; }
+READ8_HANDLER( via_3_portb_r) { return via[3].in_b; }
+READ8_HANDLER( via_4_portb_r) { return via[4].in_b; }
+READ8_HANDLER( via_5_portb_r) { return via[5].in_b; }
+READ8_HANDLER( via_6_portb_r) { return via[6].in_b; }
+READ8_HANDLER( via_7_portb_r) { return via[7].in_b; }
+
+/******************* 1-bit CA1/CA2/CB1/CB2 port interfaces *******************/
+
+WRITE8_HANDLER( via_0_ca1_w) { via_set_input_ca1(0, data); }
+WRITE8_HANDLER( via_1_ca1_w) { via_set_input_ca1(1, data); }
+WRITE8_HANDLER( via_2_ca1_w) { via_set_input_ca1(2, data); }
+WRITE8_HANDLER( via_3_ca1_w) { via_set_input_ca1(3, data); }
+WRITE8_HANDLER( via_4_ca1_w) { via_set_input_ca1(4, data); }
+WRITE8_HANDLER( via_5_ca1_w) { via_set_input_ca1(5, data); }
+WRITE8_HANDLER( via_6_ca1_w) { via_set_input_ca1(6, data); }
+WRITE8_HANDLER( via_7_ca1_w) { via_set_input_ca1(7, data); }
+WRITE8_HANDLER( via_0_ca2_w) { via_set_input_ca2(0, data); }
+WRITE8_HANDLER( via_1_ca2_w) { via_set_input_ca2(1, data); }
+WRITE8_HANDLER( via_2_ca2_w) { via_set_input_ca2(2, data); }
+WRITE8_HANDLER( via_3_ca2_w) { via_set_input_ca2(3, data); }
+WRITE8_HANDLER( via_4_ca2_w) { via_set_input_ca2(4, data); }
+WRITE8_HANDLER( via_5_ca2_w) { via_set_input_ca2(5, data); }
+WRITE8_HANDLER( via_6_ca2_w) { via_set_input_ca2(6, data); }
+WRITE8_HANDLER( via_7_ca2_w) { via_set_input_ca2(7, data); }
+
+WRITE8_HANDLER( via_0_cb1_w) { via_set_input_cb1(0, data); }
+WRITE8_HANDLER( via_1_cb1_w) { via_set_input_cb1(1, data); }
+WRITE8_HANDLER( via_2_cb1_w) { via_set_input_cb1(2, data); }
+WRITE8_HANDLER( via_3_cb1_w) { via_set_input_cb1(3, data); }
+WRITE8_HANDLER( via_4_cb1_w) { via_set_input_cb1(4, data); }
+WRITE8_HANDLER( via_5_cb1_w) { via_set_input_cb1(5, data); }
+WRITE8_HANDLER( via_6_cb1_w) { via_set_input_cb1(6, data); }
+WRITE8_HANDLER( via_7_cb1_w) { via_set_input_cb1(7, data); }
+WRITE8_HANDLER( via_0_cb2_w) { via_set_input_cb2(0, data); }
+WRITE8_HANDLER( via_1_cb2_w) { via_set_input_cb2(1, data); }
+WRITE8_HANDLER( via_2_cb2_w) { via_set_input_cb2(2, data); }
+WRITE8_HANDLER( via_3_cb2_w) { via_set_input_cb2(3, data); }
+WRITE8_HANDLER( via_4_cb2_w) { via_set_input_cb2(4, data); }
+WRITE8_HANDLER( via_5_cb2_w) { via_set_input_cb2(5, data); }
+WRITE8_HANDLER( via_6_cb2_w) { via_set_input_cb2(6, data); }
+WRITE8_HANDLER( via_7_cb2_w) { via_set_input_cb2(7, data); }
+
+READ8_HANDLER( via_0_ca1_r) { return via[0].in_ca1; }
+READ8_HANDLER( via_1_ca1_r) { return via[1].in_ca1; }
+READ8_HANDLER( via_2_ca1_r) { return via[2].in_ca1; }
+READ8_HANDLER( via_3_ca1_r) { return via[3].in_ca1; }
+READ8_HANDLER( via_4_ca1_r) { return via[4].in_ca1; }
+READ8_HANDLER( via_5_ca1_r) { return via[5].in_ca1; }
+READ8_HANDLER( via_6_ca1_r) { return via[6].in_ca1; }
+READ8_HANDLER( via_7_ca1_r) { return via[7].in_ca1; }
+READ8_HANDLER( via_0_ca2_r) { return via[0].in_ca2; }
+READ8_HANDLER( via_1_ca2_r) { return via[1].in_ca2; }
+READ8_HANDLER( via_2_ca2_r) { return via[2].in_ca2; }
+READ8_HANDLER( via_3_ca2_r) { return via[3].in_ca2; }
+READ8_HANDLER( via_4_ca2_r) { return via[4].in_ca2; }
+READ8_HANDLER( via_5_ca2_r) { return via[5].in_ca2; }
+READ8_HANDLER( via_6_ca2_r) { return via[6].in_ca2; }
+READ8_HANDLER( via_7_ca2_r) { return via[7].in_ca2; }
+
+READ8_HANDLER( via_0_cb1_r) { return via[0].in_cb1; }
+READ8_HANDLER( via_1_cb1_r) { return via[1].in_cb1; }
+READ8_HANDLER( via_2_cb1_r) { return via[2].in_cb1; }
+READ8_HANDLER( via_3_cb1_r) { return via[3].in_cb1; }
+READ8_HANDLER( via_4_cb1_r) { return via[4].in_cb1; }
+READ8_HANDLER( via_5_cb1_r) { return via[5].in_cb1; }
+READ8_HANDLER( via_6_cb1_r) { return via[6].in_cb1; }
+READ8_HANDLER( via_7_cb1_r) { return via[7].in_cb1; }
+READ8_HANDLER( via_0_cb2_r) { return via[0].in_cb2; }
+READ8_HANDLER( via_1_cb2_r) { return via[1].in_cb2; }
+READ8_HANDLER( via_2_cb2_r) { return via[2].in_cb2; }
+READ8_HANDLER( via_3_cb2_r) { return via[3].in_cb2; }
+READ8_HANDLER( via_4_cb2_r) { return via[4].in_cb2; }
+READ8_HANDLER( via_5_cb2_r) { return via[5].in_cb2; }
+READ8_HANDLER( via_6_cb2_r) { return via[6].in_cb2; }
+READ8_HANDLER( via_7_cb2_r) { return via[7].in_cb2; }
+
+
+#undef TRACE_VIA