#include <stdio.h>
#include "defs.h"
#include "memory.h"
#include "6502P.h"

#ifdef DEBUG

#define MODE_NULL	0
#define MODE_IMM	1
#define MODE_ZP		2
#define MODE_ZP_X	3
#define MODE_ZP_Y	4
#define MODE_IND_ZP	5
#define MODE_ABS	6
#define MODE_ABS_X	7
#define MODE_ABS_Y	8
#define MODE_IND_ZP_X	9
#define MODE_IND_ZP_Y  10
#define MODE_IND_ABS   11
#define MODE_REL       12
#define MODE_BBS       13
#define MODE_A	       14
#define MODE_IND_ABS_X 15

struct op_info {
    char *name;
    int mode;
};

static struct op_info ops[256] = {
    {"BRK", MODE_NULL},
    {"ORA", MODE_IND_ZP_X},
    {"DAT", MODE_NULL},
    {"DAT", MODE_NULL},
    {"TSB", MODE_ZP},
    {"ORA", MODE_ZP},
    {"ASL", MODE_ZP},
    {"DAT", MODE_NULL},
    {"PHP", MODE_NULL},
    {"ORA", MODE_IMM},
    {"ASL", MODE_A},
    {"DAT", MODE_NULL},
    {"TSB", MODE_ABS},
    {"ORA", MODE_ABS},
    {"ASL", MODE_ABS},
    {"BBR", MODE_BBS},
    {"BPL", MODE_REL},
    {"ORA", MODE_IND_ZP_Y},
    {"ORA", MODE_IND_ZP},
    {"DAT", MODE_NULL},
    {"TRB", MODE_ZP},
    {"ORA", MODE_ZP_X},
    {"ASL", MODE_ZP_X},
    {"DAT", MODE_NULL},
    {"CLC", MODE_NULL},
    {"ORA", MODE_ABS_Y},
    {"INA", MODE_NULL},
    {"DAT", MODE_NULL},
    {"TRB", MODE_ABS},
    {"ORA", MODE_ABS_X},
    {"ASL", MODE_ABS_X},
    {"BBR", MODE_BBS},
    {"JSR", MODE_ABS},
    {"AND", MODE_IND_ZP_X},
    {"DAT", MODE_NULL},
    {"DAT", MODE_NULL},
    {"BIT", MODE_ZP},
    {"AND", MODE_ZP},
    {"ROL", MODE_ZP},
    {"DAT", MODE_NULL},
    {"PLP", MODE_NULL},
    {"AND", MODE_IMM},
    {"ROL", MODE_A},
    {"DAT", MODE_NULL},
    {"BIT", MODE_ABS},
    {"AND", MODE_ABS},
    {"ROL", MODE_ABS},
    {"BBR", MODE_BBS},
    {"BMI", MODE_REL},
    {"AND", MODE_IND_ZP_Y},
    {"AND", MODE_IND_ZP},
    {"DAT", MODE_NULL},
    {"BIT", MODE_ZP_X},
    {"AND", MODE_ZP_X},
    {"ROL", MODE_ZP_X},
    {"DAT", MODE_NULL},
    {"SEC", MODE_NULL},
    {"AND", MODE_ABS_Y},
    {"DEA", MODE_NULL},
    {"DAT", MODE_NULL},
    {"BIT", MODE_ABS_X},
    {"AND", MODE_ABS_X},
    {"ROL", MODE_ABS_X},
    {"BBR", MODE_BBS},
    {"RTI", MODE_NULL},
    {"EOR", MODE_IND_ZP_X},
    {"DAT", MODE_NULL},
    {"DAT", MODE_NULL},
    {"DAT", MODE_NULL},
    {"EOR", MODE_ZP},
    {"LSR", MODE_ZP},
    {"DAT", MODE_NULL},
    {"PHA", MODE_NULL},
    {"EOR", MODE_IMM},
    {"LSR", MODE_A},
    {"DAT", MODE_NULL},
    {"JMP", MODE_ABS},
    {"EOR", MODE_ABS},
    {"LSR", MODE_ABS},
    {"BBR", MODE_BBS},
    {"BVC", MODE_REL},
    {"EOR", MODE_IND_ZP_Y},
    {"EOR", MODE_IND_ZP},
    {"DAT", MODE_NULL},
    {"DAT", MODE_NULL},
    {"EOR", MODE_ZP_X},
    {"LSR", MODE_ZP_X},
    {"DAT", MODE_NULL},
    {"CLI", MODE_NULL},
    {"EOR", MODE_ABS_Y},
    {"PHY", MODE_NULL},
    {"DAT", MODE_NULL},
    {"DAT", MODE_NULL},
    {"EOR", MODE_ABS_X},
    {"LSR", MODE_ABS_X},
    {"BBR", MODE_BBS},
    {"RTS", MODE_NULL},
    {"ADC", MODE_IND_ZP_X},
    {"DAT", MODE_NULL},
    {"DAT", MODE_NULL},
    {"STZ", MODE_ZP},
    {"ADC", MODE_ZP},
    {"ROR", MODE_ZP},
    {"DAT", MODE_NULL},
    {"PLA", MODE_NULL},
    {"ADC", MODE_IMM},
    {"ROR", MODE_A},
    {"DAT", MODE_NULL},
    {"JMP", MODE_IND_ABS},
    {"ADC", MODE_ABS},
    {"ROR", MODE_ABS},
    {"BBR", MODE_BBS},
    {"BVS", MODE_REL},
    {"ADC", MODE_IND_ZP_Y},
    {"ADC", MODE_IND_ZP},
    {"DAT", MODE_NULL},
    {"STZ", MODE_ZP_X},
    {"ADC", MODE_ZP_X},
    {"ROR", MODE_ZP_X},
    {"DAT", MODE_NULL},
    {"SEI", MODE_NULL},
    {"ADC", MODE_ABS_Y},
    {"PLY", MODE_NULL},
    {"DAT", MODE_NULL},
    {"JMP", MODE_IND_ABS_X},
    {"ADC", MODE_ABS_X},
    {"ROR", MODE_ABS_X},
    {"BBR", MODE_BBS},
    {"BRA", MODE_NULL},
    {"STA", MODE_IND_ZP_X},
    {"DAT", MODE_NULL},
    {"DAT", MODE_NULL},
    {"STY", MODE_ZP},
    {"STA", MODE_ZP},
    {"STX", MODE_ZP},
    {"DAT", MODE_NULL},
    {"DEY", MODE_NULL},
    {"BIT", MODE_IMM},
    {"TXA", MODE_NULL},
    {"DAT", MODE_NULL},
    {"STY", MODE_ABS},
    {"STA", MODE_ABS},
    {"STX", MODE_ABS},
    {"BBS", MODE_BBS},
    {"BCC", MODE_REL},
    {"STA", MODE_IND_ZP_Y},
    {"STA", MODE_IND_ZP},
    {"DAT", MODE_NULL},
    {"STY", MODE_ZP_X},
    {"STA", MODE_ZP_X},
    {"STX", MODE_ZP_Y},
    {"DAT", MODE_NULL},
    {"TYA", MODE_NULL},
    {"STA", MODE_ABS_Y},
    {"TXS", MODE_NULL},
    {"DAT", MODE_NULL},
    {"STZ", MODE_ABS},
    {"STA", MODE_ABS_X},
    {"STZ", MODE_ABS_X},
    {"BBS", MODE_BBS},
    {"LDY", MODE_IMM},
    {"LDA", MODE_IND_ZP_X},
    {"LDX", MODE_IMM},
    {"DAT", MODE_NULL},
    {"LDY", MODE_ZP},
    {"LDA", MODE_ZP},
    {"LDX", MODE_ZP},
    {"DAT", MODE_NULL},
    {"TAY", MODE_NULL},
    {"LDA", MODE_IMM},
    {"TAX", MODE_NULL},
    {"DAT", MODE_NULL},
    {"LDY", MODE_ABS},
    {"LDA", MODE_ABS},
    {"LDX", MODE_ABS},
    {"BBS", MODE_BBS},
    {"BCS", MODE_REL},
    {"LDA", MODE_IND_ZP_Y},
    {"LDA", MODE_IND_ZP},
    {"DAT", MODE_NULL},
    {"LDY", MODE_ZP_X},
    {"LDA", MODE_ZP_X},
    {"LDX", MODE_ZP_Y},
    {"DAT", MODE_NULL},
    {"CLV", MODE_NULL},
    {"LDA", MODE_ABS_Y},
    {"TSX", MODE_NULL},
    {"DAT", MODE_NULL},
    {"LDY", MODE_ABS_X},
    {"LDA", MODE_ABS_X},
    {"LDX", MODE_ABS_Y},
    {"BBS", MODE_BBS},
    {"CPY", MODE_IMM},
    {"CMP", MODE_IND_ZP_X},
    {"DAT", MODE_NULL},
    {"DAT", MODE_NULL},
    {"CPY", MODE_ZP},
    {"CMP", MODE_ZP},
    {"DEC", MODE_ZP},
    {"DAT", MODE_NULL},
    {"INY", MODE_NULL},
    {"CMP", MODE_IMM},
    {"DEX", MODE_NULL},
    {"DAT", MODE_NULL},
    {"CPY", MODE_ABS},
    {"CMP", MODE_ABS},
    {"DEC", MODE_ABS},
    {"BBS", MODE_BBS},
    {"BNE", MODE_REL},
    {"CMP", MODE_IND_ZP_Y},
    {"CMP", MODE_IND_ZP},
    {"DAT", MODE_NULL},
    {"UNX", MODE_IMM},
    {"CMP", MODE_ZP_X},
    {"DEC", MODE_ZP_X},
    {"DAT", MODE_NULL},
    {"CLD", MODE_NULL},
    {"CMP", MODE_ABS_Y},
    {"PHX", MODE_NULL},
    {"DAT", MODE_NULL},
    {"DAT", MODE_NULL},
    {"CMP", MODE_ABS_X},
    {"DEC", MODE_ABS_X},
    {"BBS", MODE_BBS},
    {"CPX", MODE_IMM},
    {"SBC", MODE_IND_ZP_X},
    {"DAT", MODE_NULL},
    {"DAT", MODE_NULL},
    {"CPX", MODE_ZP},
    {"SBC", MODE_ZP},
    {"INC", MODE_ZP},
    {"DAT", MODE_NULL},
    {"INX", MODE_NULL},
    {"SBC", MODE_IMM},
    {"NOP", MODE_NULL},
    {"DAT", MODE_NULL},
    {"CPX", MODE_ABS},
    {"SBC", MODE_ABS},
    {"INC", MODE_ABS},
    {"BBS", MODE_BBS},
    {"BEQ", MODE_REL},
    {"SBC", MODE_IND_ZP_Y},
    {"SBC", MODE_IND_ZP},
    {"DAT", MODE_NULL},
    {"DAT", MODE_NULL},
    {"SBC", MODE_ZP_X},
    {"INC", MODE_ZP_X},
    {"DAT", MODE_NULL},
    {"SED", MODE_NULL},
    {"SBC", MODE_ABS_Y},
    {"PLX", MODE_NULL},
    {"DAT", MODE_NULL},
    {"DAT", MODE_NULL},
    {"SBC", MODE_ABS_X},
    {"INC", MODE_ABS_X},
    {"BBS", MODE_BBS}
};

void disassemble(byte op) {
    printf("%s ", ops[op].name);
    switch (ops[op].mode) {
    case MODE_NULL:
	putchar('\n');
	break;
    case MODE_IMM:
	printf("#&%02X\n", readb(PC+1));
	break;
    case MODE_ZP:
	printf("&%02X\n", readb(PC+1));
	break;
    case MODE_ZP_X:
	printf("&%02X,X\n", readb(PC+1));
	break;
    case MODE_ZP_Y:
	printf("&%02X,Y\n", readb(PC+1));
	break;
    case MODE_IND_ZP:
	printf("(&%02X)\n", readb(PC+1));
	break;
    case MODE_ABS:
	printf("&%04X\n", readw(PC+1));
	break;
    case MODE_ABS_X:
	printf("&%04X,X\n", readw(PC+1));
	break;
    case MODE_ABS_Y:
	printf("&%04X,Y\n", readw(PC+1));
	break;
    case MODE_IND_ZP_X:
	printf("(&%02X,X)\n", readb(PC+1));
	break;
    case MODE_IND_ZP_Y:
	printf("(&%02X),Y\n", readb(PC+1));
	break;
    case MODE_IND_ABS:
	printf("(&%04X)\n", readw(PC+1));
	break;
    case MODE_REL:
	printf("&%04X\n", PC + 2 + (signed char)readb(PC+1));
	break;
    case MODE_BBS:
	printf("%d &%02X &%04X\n", op & 0xf, readb(PC+1),
	       PC + 3 + (signed char)readb(PC+2));
	break;
    case MODE_A:
	printf("A\n");
	break;
    case MODE_IND_ABS_X:
	printf("(&%04X,X)\n", readw(PC+1));
	break;
    }
}

#endif /* DEBUG */
