#include "defs.h"
#include "6522.h"

/* #define DEBUG_KEY */

extern int do_irq;
extern int debug;

int matrix[16][16]; /* [row][column] */

void do_key_matrix(int ddra, byte *ora, byte *ifr, byte ier) {
    /*
     * When PB4 is zero, the keyboard performs a fetch from PA to
     * scan the keyboard matrix.
     *
     * bits 0-3 represent the columns, and 4-6 the rows.
     * bit 7 is filled with either 1 or 0 to determine whether
     * the column or row is set.
     *
     * I'm unsure of how ddra effects things here. The OS explicitly
     * sets this though during keyboard polling so I must assume
     * we are required to use it.
     *
     * LDA #&0B  %00001011 - set keyboard enable on latch
     * STA &FE40
     * CLI
     * SEI
     * LDA #&0B
     * STA &FE40
     *
     * Why does the OS use the above? A CLI and SEI between
     * consecutive keyboard accesses? It's not even forcing a poll
     * anywhere. Is it to protect against missing keys? Maybe I'm
     * missing something!
     *
     * Also, with the keyboard latch held low for a long while, are
     * we required to continually generate interrupts? If so move
     * this to a 'poll' timer. Currently I ignore this.
     */
    
    int r, c, i;
    
    c = *ora & ddra & 0x0f;
    r = (*ora & ddra & 0x70) >> 4;
    
    /* if row & col are set, then bit 7 or ora is set */
    if (matrix[r][c]) {
#ifdef DEBUG_KEY
	printf("row & col set. ora = (80 & ~%x) | (%x & ~%x) = %x | %x = %x\n",
	       ddra, *ora, ddra,
	       (0x80 & ~ddra), (*ora & ddra),
	       (0x80 & ~ddra) | (*ora & ddra));
#endif
	/*
	 * The OS during startup does:
	 *
	 * f02a: A=06, X=06, Y=7f, S=fc, P=34 ; LDY #&03
	 * f02c: A=06, X=06, Y=03, S=fc, P=34 ; STY &FE40
	 * f02f: A=06, X=06, Y=03, S=fc, P=34 ; LDY #&7F
	 * f031: A=06, X=06, Y=7f, S=fc, P=34 ; STY &FE43
	 * f034: A=06, X=06, Y=7f, S=fc, P=34 ; STX &FE4F
	 * f037: A=06, X=06, Y=7f, S=fc, P=34 ; LDX &FE4F
	 * f03a: A=06, X=80, Y=7f, S=fc, P=b4 ; RTS
	 * da15: A=06, X=80, Y=7f, S=fe, P=b4 ; CPX #&80
	 *
	 * We actually store &86 is FE4F, but due to disabled input latching
	 * at this point the LDX reads 0x86 & ~0x7f (= 0x80).
	 */
	*ora = (0x80 & ~ddra) | (*ora & ddra);
    } else {
	*ora = (0x00 & ~ddra) | (*ora & ddra);
    }

    
    /* The OS appears to check for interrupts during the initial
     * column scan. We'll cater for it :-)
     * Should we do this when writing to the non handshaking ora?
     */
    for (i = 0; i < 16; i ++) {
	if (matrix[i][c]) {
	    *ifr |= IFR_SET | IFR_CA2;
	    if (ier & IFR_CA2)
		do_irq = 1;
	}
    }
}
