/*
 * 6522 module
 *
 * 12/02/94 jkb  creation
 *
 * TODO: add T2 code
 */

#include <stdio.h>
#include <unistd.h>
#include <errno.h>

#include "6522.h"
#include "module_inc.h"
#include "memory.h"
#include "6502P.h"
#include "timer.h"

#define DEBUG_VIA

static byte read_via(word addr);
static byte write_via(word addr, byte val);

extern int scan_key();
extern int debug;


t_6522 i_6522_user = {
    init, update,
    read_via, write_via
};

extern int do_irq;
static byte ora, orb, ddra, ddrb, sr, acr, pcr, ifr=0, ier;
static int t1_timer = 0;

#ifdef VIAS
static int latch;
#include "keyboard.c"
#endif

/* ARGSUSED */
static void sig_alarm(int x) {
    int c;

    return;

    /* set IFR T1 time-out */
    ifr |= IFR_SET | IFR_T1;

#ifdef VIAS
    if (scan_key()) {
	/* key_pressed(c); */
	do_irq = 1;
    }
#ifdef DEBUG_VIA
    printf("keyp => %02x\n", ifr);
#endif
#endif

    /* generate interrupt */
    do_irq = 1;
}

static byte read_via(word addr) {
    addr &= 0x0f;

#ifdef DEBUG_VIA
    printf("1read %04x => %02x\n", addr, ifr);
#endif

    switch (addr) {
    case 0: /* output reg B */
    case 15:
	ifr &= ~IFR_CB1;
	if (pcr & 0xa0 != 0x20)
	    ifr &= ~IFR_CB2;
	if (ifr & 0x7f == 0) ifr = 0;
	return orb;
    case 1: /* output reg A */
	ifr &= ~IFR_CA1;
	if (pcr & 0x0a != 0x02)
	    ifr &= ~IFR_CA2;
	if (ifr & 0x7f == 0) ifr = 0;
	return ora;
    case 2: /* DDRB */
	return ddrb;
    case 3: /* DDRA */
	return ddra;
    case 4: /* T1 low order counter */
	ifr &= ~IFR_T1;
	if (ifr & 0x7f == 0) ifr = 0;
	return query_timer_expire(t1_timer) & 0x00ff;
    case 5: /* T1 high order counter */
	ifr &= ~IFR_T1;
	if (ifr & 0x7f == 0) ifr = 0;
	return query_timer_expire(t1_timer) & 0x00ff;
    case 6: /* T1 low order latch */
	/* is this (& T2L-L) correct regarding IFR? */
	ifr &= ~IFR_T1;
	if (ifr & 0x7f == 0) ifr = 0;
	return query_timer_interval(t1_timer) & 0x00ff;
    case 7: /* T1 high order latch */
	return 0xff; /* unreadable? */
    case 8: /* T2 low order latch */
	ifr &= ~IFR_T2;
	if (ifr & 0x7f == 0) ifr = 0;
	return 0; /* fixme */
    case 9: /* T2 high order latch */
	return 0; /* fixme */
    case 10: /* Shift reg */
	ifr &= ~IFR_SR;
	if (ifr & 0x7f == 0) ifr = 0;
	return sr;
    case 11: /* Auxiliary control reg */
	return acr;
    case 12: /* Peripheral control reg */
	return pcr;
    case 13: /* interrupt flag reg */
	if (ifr==0x81) debug=1;
	return ifr;
    case 14: /* interrupt enable reg */
	return ier;
    }

#ifdef DEBUG_VIA
    printf("2read %04x => %02x\n", addr, ifr);
#endif
}

static byte write_via(word addr, byte val) {
    addr &= 0x0f;
 
#ifdef DEBUG_VIA
    printf("1write %04x => %02x %02x\n", addr, ifr, val);
#endif

    switch (addr) {
    case 0: /* output reg B */
    case 15: /* no handshake - ignore such differences at the moment */
	/* printf("strt ifr to %x, orb to %d\n", ifr, orb); */

	ifr &= ~IFR_CB1;
	if (pcr & 0xa0 != 0x20)
	    ifr &= ~IFR_CB2;
	orb = val;

	/* printf("1set ifr to %x, orb to %d\n", ifr, orb); */
#ifdef VIAS
	if (orb & 0x08)
	    latch |= (1 << (orb & 7));
	else
	    latch &= ~(1 << (orb & 7));

/*
	{
	    int i;
	    for (i=0; i<16; i++)
		printf("%d", column[i]);
	    puts("");
	    for (i=0; i<8; i++)
		printf("%d", row[i]);
	    puts("");
	}
*/
	/* should only work with keyboard enabled on latch */
	if (latch & LATCH_KBD) {
	    int both = 0;

	    if (column[val & 0x0f]) {
		ifr |= IFR_SET | IFR_CA2;
		both++;
	    }

	    if (row[(val >> 4) & 0x07]) {
		ifr |= IFR_SET | IFR_CA2;
		both++;
	    }

	    if (both == 2)
		orb |= 0x80;
	}
	    
	if (ifr & 0x7f == 0) ifr = 0;
	/* printf("2set ifr to %x, orb to %d\n", ifr, orb); */

#endif
	break;
    case 1: /* output reg A */
	ifr &= ~IFR_CA1;
	if (pcr & 0x0a != 0x02)
	    ifr &= ~IFR_CA2;
	ora = val;
	break;
    case 2: /* DDRB */
	ddrb = val;
	break;
    case 3: /* DDRA */
	ddra = val;
	break;
    case 5: /* T1 high order counter */
	/* copy low order latch and clear T1 interrupt */
	change_timer(t1_timer, TIMER_VALUE, 0, 
		     0x100 * val + query_timer_interval(t1_timer), NULL);
	ifr &= ~IFR_T1;
	if (ifr & 0x7f == 0) ifr = 0;
	break;
    case 4: /* T1 low order latch */
    case 6:	
	change_timer(t1_timer, TIMER_INTERVAL,
		     (query_timer_interval(t1_timer) & 0xff00) + val,
		     0, NULL);
	break;
    case 7: /* T1 high order latch */
	change_timer(t1_timer, TIMER_INTERVAL,
		     (query_timer_interval(t1_timer) & 0x00ff) + 0x100 * val,
		     0, NULL);
	break;
    case 8: /* T2 low order latch */
	/* fixme */
	break;
    case 9: /* T2 high order latch */
	ifr &= ~IFR_T2;
	if (ifr & 0x7f == 0) ifr = 0;
	/* fixme */
	break;
    case 10: /* Shift reg */
	ifr &= ~IFR_SR;
	sr = val;
	break;
    case 11: /* Auxiliary control reg */
	acr = val;
	break;
    case 12: /* Peripheral control reg */
	pcr = val;
	break;
    case 13: /* interrupt flag reg */
	ifr &= ~val; /* clear bits written */
	if (ifr & 0x7f)
	    ifr |= 0x80;
	else
	    ifr = 0;

	break;
    case 14: /* interrupt enable reg */
	if (val & 0x80) /* enable */
	    ier |= (val & 0x7f);
	else
	    ier &= ~(val & 0x7f);
	break;
    }

#ifdef DEBUG_VIA
    printf("2write %04x => %02x\n", addr, ifr);
#endif

    return 0;
}

static void init() {
/*    t1_timer = add_timer(1000000/HZ_6502, 1000000/HZ_6502, sig_alarm);*/
}

static time_t update(time_t inc) {
    static time_t time = 0;

/*    printf("Updating 6522 by %d ticks\n", inc); */
    return time += inc;
}
