

#include <stdio.h>

#include "rockmacros.h"
#include "defs.h"
#include "cpu-gb.h"
#include "mem.h"
#include "fastmem.h"
#include "regs.h"

#include "cpuregs.h"


static char *mnemonic_table[256] =
{
    "NOP",
    "LD BC,%w",
    "LD (BC),A",
    "INC BC",
    "INC B",
    "DEC B",
    "LD B,%b",
    "RLCA",
    "LD (%w),SP",
    "ADD HL,BC",
    "LD A,(BC)",
    "DEC BC",
    "INC C",
    "DEC C",
    "LD C,%b",
    "RRCA",
    "STOP",
    "LD DE,%w",
    "LD (DE),A",
    "INC DE",
    "INC D",
    "DEC D",
    "LD D,%b",
    "RLA",
    "JR %o",
    "ADD HL,DE",
    "LD A,(DE)",
    "DEC DE",
    "INC E",
    "DEC E",
    "LD E,%b",
    "RRA",
    "JR NZ,%o",
    "LD HL,%w",
    "LD (HLI),A",
    "INC HL",
    "INC H",
    "DEC H",
    "LD H,%b",
    "DAA",
    "JR Z,%o",
    "ADD HL,HL",
    "LD A,(HLI)",
    "DEC HL",
    "INC L",
    "DEC L",
    "LD L,%b",
    "CPL",
    "JR NC,%o",
    "LD SP,%w",
    "LD (HLD),A",
    "INC SP",
    "INC (HL)",
    "DEC (HL)",
    "LD (HL),%b",
    "SCF",
    "JR C,%o",
    "ADD HL,SP",
    "LD A,(HLD)",
    "DEC SP",
    "INC A",
    "DEC A",
    "LD A,%b",
    "CCF",
    "LD B,B",
    "LD B,C",
    "LD B,D",
    "LD B,E",
    "LD B,H",
    "LD B,L",
    "LD B,(HL)",
    "LD B,A",
    "LD C,B",
    "LD C,C",
    "LD C,D",
    "LD C,E",
    "LD C,H",
    "LD C,L",
    "LD C,(HL)",
    "LD C,A",
    "LD D,B",
    "LD D,C",
    "LD D,D",
    "LD D,E",
    "LD D,H",
    "LD D,L",
    "LD D,(HL)",
    "LD D,A",
    "LD E,B",
    "LD E,C",
    "LD E,D",
    "LD E,E",
    "LD E,H",
    "LD E,L",
    "LD E,(HL)",
    "LD E,A",
    "LD H,B",
    "LD H,C",
    "LD H,D",
    "LD H,E",
    "LD H,H",
    "LD H,L",
    "LD H,(HL)",
    "LD H,A",
    "LD L,B",
    "LD L,C",
    "LD L,D",
    "LD L,E",
    "LD L,H",
    "LD L,L",
    "LD L,(HL)",
    "LD L,A",
    "LD (HL),B",
    "LD (HL),C",
    "LD (HL),D",
    "LD (HL),E",
    "LD (HL),H",
    "LD (HL),L",
    "HALT",
    "LD (HL),A",
    "LD A,B",
    "LD A,C",
    "LD A,D",
    "LD A,E",
    "LD A,H",
    "LD A,L",
    "LD A,(HL)",
    "LD A,A",
    "ADD A,B",
    "ADD A,C",
    "ADD A,D",
    "ADD A,E",
    "ADD A,H",
    "ADD A,L",
    "ADD A,(HL)",
    "ADD A,A",
    "ADC A,B",
    "ADC A,C",
    "ADC A,D",
    "ADC A,E",
    "ADC A,H",
    "ADC A,L",
    "ADC A,(HL)",
    "ADC A",
    "SUB B",
    "SUB C",
    "SUB D",
    "SUB E",
    "SUB H",
    "SUB L",
    "SUB (HL)",
    "SUB A",
    "SBC A,B",
    "SBC A,C",
    "SBC A,D",
    "SBC A,E",
    "SBC A,H",
    "SBC A,L",
    "SBC A,(HL)",
    "SBC A,A",
    "AND B",
    "AND C",
    "AND D",
    "AND E",
    "AND H",
    "AND L",
    "AND (HL)",
    "AND A",
    "XOR B",
    "XOR C",
    "XOR D",
    "XOR E",
    "XOR H",
    "XOR L",
    "XOR (HL)",
    "XOR A",
    "OR B",
    "OR C",
    "OR D",
    "OR E",
    "OR H",
    "OR L",
    "OR (HL)",
    "OR A",
    "CP B",
    "CP C",
    "CP D",
    "CP E",
    "CP H",
    "CP L",
    "CP (HL)",
    "CP A",
    "RET NZ",
    "POP BC",
    "JP NZ,%w",
    "JP %w",
    "CALL NZ,%w",
    "PUSH BC",
    "ADD A,%b",
    "RST 0h",
    "RET Z",
    "RET",
    "JP Z,%w",
    NULL,
    "CALL Z,%w",
    "CALL %w",
    "ADC A,%b",
    "RST 8h",
    "RET NC",
    "POP DE",
    "JP NC,%w",
    NULL,
    "CALL NC,%w",
    "PUSH DE",
    "SUB %b",
    "RST 10h",
    "RET C",
    "RETI",
    "JP C,%w",
    NULL,
    "CALL C,%w",
    NULL,
    "SBC A,%b",
    "RST 18h",
    "LD (FF00+%b),A",
    "POP HL",
    "LD (FF00+C),A",
    NULL,
    NULL,
    "PUSH HL",
    "AND %b",
    "RST 20h",
    "ADD SP,%o",
    "JP HL",
    "LD (%w),A",
    NULL,
    NULL,
    NULL,
    "XOR %b",
    "RST 28h",
    "LD A,(FF00+%b)",
    "POP AF",
    "LD A,(FF00+C)",
    "DI",
    NULL,
    "PUSH AF",
    "OR %b",
    "RST 30h",
    "LD HL,SP%o",
    "LD SP,HL",
    "LD A,(%w)",
    "EI",
    NULL,
    NULL,
    "CP %b",
    "RST 38h"
};

static char *cb_mnemonic_table[256] =
{
    "RLC B",
    "RLC C",
    "RLC D",
    "RLC E",
    "RLC H",
    "RLC L",
    "RLC (HL)",
    "RLC A",
    "RRC B",
    "RRC C",
    "RRC D",
    "RRC E",
    "RRC H",
    "RRC L",
    "RRC (HL)",
    "RRC A",
    "RL B",
    "RL C",
    "RL D",
    "RL E",
    "RL H",
    "RL L",
    "RL (HL)",
    "RL A",
    "RR B",
    "RR C",
    "RR D",
    "RR E",
    "RR H",
    "RR L",
    "RR (HL)",
    "RR A",
    "SLA B",
    "SLA C",
    "SLA D",
    "SLA E",
    "SLA H",
    "SLA L",
    "SLA (HL)",
    "SLA A",
    "SRA B",
    "SRA C",
    "SRA D",
    "SRA E",
    "SRA H",
    "SRA L",
    "SRA (HL)",
    "SRA A",
    "SWAP B",
    "SWAP C",
    "SWAP D",
    "SWAP E",
    "SWAP H",
    "SWAP L",
    "SWAP (HL)",
    "SWAP A",
    "SRL B",
    "SRL C",
    "SRL D",
    "SRL E",
    "SRL H",
    "SRL L",
    "SRL (HL)",
    "SRL A",
    "BIT 0,B",
    "BIT 0,C",
    "BIT 0,D",
    "BIT 0,E",
    "BIT 0,H",
    "BIT 0,L",
    "BIT 0,(HL)",
    "BIT 0,A",
    "BIT 1,B",
    "BIT 1,C",
    "BIT 1,D",
    "BIT 1,E",
    "BIT 1,H",
    "BIT 1,L",
    "BIT 1,(HL)",
    "BIT 1,A",
    "BIT 2,B",
    "BIT 2,C",
    "BIT 2,D",
    "BIT 2,E",
    "BIT 2,H",
    "BIT 2,L",
    "BIT 2,(HL)",
    "BIT 2,A",
    "BIT 3,B",
    "BIT 3,C",
    "BIT 3,D",
    "BIT 3,E",
    "BIT 3,H",
    "BIT 3,L",
    "BIT 3,(HL)",
    "BIT 3,A",
    "BIT 4,B",
    "BIT 4,C",
    "BIT 4,D",
    "BIT 4,E",
    "BIT 4,H",
    "BIT 4,L",
    "BIT 4,(HL)",
    "BIT 4,A",
    "BIT 5,B",
    "BIT 5,C",
    "BIT 5,D",
    "BIT 5,E",
    "BIT 5,H",
    "BIT 5,L",
    "BIT 5,(HL)",
    "BIT 5,A",
    "BIT 6,B",
    "BIT 6,C",
    "BIT 6,D",
    "BIT 6,E",
    "BIT 6,H",
    "BIT 6,L",
    "BIT 6,(HL)",
    "BIT 6,A",
    "BIT 7,B",
    "BIT 7,C",
    "BIT 7,D",
    "BIT 7,E",
    "BIT 7,H",
    "BIT 7,L",
    "BIT 7,(HL)",
    "BIT 7,A",
    "RES 0,B",
    "RES 0,C",
    "RES 0,D",
    "RES 0,E",
    "RES 0,H",
    "RES 0,L",
    "RES 0,(HL)",
    "RES 0,A",
    "RES 1,B",
    "RES 1,C",
    "RES 1,D",
    "RES 1,E",
    "RES 1,H",
    "RES 1,L",
    "RES 1,(HL)",
    "RES 1,A",
    "RES 2,B",
    "RES 2,C",
    "RES 2,D",
    "RES 2,E",
    "RES 2,H",
    "RES 2,L",
    "RES 2,(HL)",
    "RES 2,A",
    "RES 3,B",
    "RES 3,C",
    "RES 3,D",
    "RES 3,E",
    "RES 3,H",
    "RES 3,L",
    "RES 3,(HL)",
    "RES 3,A",
    "RES 4,B",
    "RES 4,C",
    "RES 4,D",
    "RES 4,E",
    "RES 4,H",
    "RES 4,L",
    "RES 4,(HL)",
    "RES 4,A",
    "RES 5,B",
    "RES 5,C",
    "RES 5,D",
    "RES 5,E",
    "RES 5,H",
    "RES 5,L",
    "RES 5,(HL)",
    "RES 5,A",
    "RES 6,B",
    "RES 6,C",
    "RES 6,D",
    "RES 6,E",
    "RES 6,H",
    "RES 6,L",
    "RES 6,(HL)",
    "RES 6,A",
    "RES 7,B",
    "RES 7,C",
    "RES 7,D",
    "RES 7,E",
    "RES 7,H",
    "RES 7,L",
    "RES 7,(HL)",
    "RES 7,A",
    "SET 0,B",
    "SET 0,C",
    "SET 0,D",
    "SET 0,E",
    "SET 0,H",
    "SET 0,L",
    "SET 0,(HL)",
    "SET 0,A",
    "SET 1,B",
    "SET 1,C",
    "SET 1,D",
    "SET 1,E",
    "SET 1,H",
    "SET 1,L",
    "SET 1,(HL)",
    "SET 1,A",
    "SET 2,B",
    "SET 2,C",
    "SET 2,D",
    "SET 2,E",
    "SET 2,H",
    "SET 2,L",
    "SET 2,(HL)",
    "SET 2,A",
    "SET 3,B",
    "SET 3,C",
    "SET 3,D",
    "SET 3,E",
    "SET 3,H",
    "SET 3,L",
    "SET 3,(HL)",
    "SET 3,A",
    "SET 4,B",
    "SET 4,C",
    "SET 4,D",
    "SET 4,E",
    "SET 4,H",
    "SET 4,L",
    "SET 4,(HL)",
    "SET 4,A",
    "SET 5,B",
    "SET 5,C",
    "SET 5,D",
    "SET 5,E",
    "SET 5,H",
    "SET 5,L",
    "SET 5,(HL)",
    "SET 5,A",
    "SET 6,B",
    "SET 6,C",
    "SET 6,D",
    "SET 6,E",
    "SET 6,H",
    "SET 6,L",
    "SET 6,(HL)",
    "SET 6,A",
    "SET 7,B",
    "SET 7,C",
    "SET 7,D",
    "SET 7,E",
    "SET 7,H",
    "SET 7,L",
    "SET 7,(HL)",
    "SET 7,A"
};

static byte operand_count[256] =
{
    1, 3, 1, 1, 1, 1, 2, 1, 3, 1, 1, 1, 1, 1, 2, 1,
    1, 3, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1,
    2, 3, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1,
    2, 3, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 3, 3, 3, 1, 2, 1, 1, 1, 3, 2, 3, 3, 2, 1,
    1, 1, 3, 1, 3, 1, 2, 1, 1, 1, 3, 1, 3, 1, 2, 1,
    2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 3, 1, 1, 1, 2, 1,
    2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 3, 1, 1, 1, 2, 1
};


/* replace with a real interactive debugger eventually... */

int debug_trace = 0;

rcvar_t debug_exports[] =
{
    RCV_BOOL("trace", &debug_trace),
    RCV_END
};

void debug_disassemble(addr a, int c)
{
    static int i, j, k;
    static byte code;
    static byte ops[3];
    static int opaddr;
    static char mnemonic[256];
    static char *pattern;
    char ops_str[300];
    if(!debug_trace) return;

    while (c > 0)
    {
        k = 0;
        opaddr = a;
        code = ops[k++] = readb(a); a++;
        if (code != 0xCB)
        {
            pattern = mnemonic_table[code];
            if (!pattern)
                pattern = "***INVALID***";
        }
        else
        {
            code = ops[k++] = readb(a); a++;
            pattern = cb_mnemonic_table[code];
        }
        i = j = 0;
        while (pattern[i])
        {
            if (pattern[i] == '%')
            {
                switch (pattern[++i])
                {
                case 'B':
                case 'b':
                    ops[k] = readb(a); a++;
                    j += snprintf(mnemonic + j,255-j, "%02Xh", ops[k++]);
                    break;
                case 'W':
                case 'w':
                    ops[k] = readb(a); a++;
                    ops[k+1] = readb(a); a++;
                    j += snprintf(mnemonic + j, 255-j,"%04Xh",
                        ((ops[k+1] << 8) | ops[k]));
                    k += 2;
                    break;
                case 'O':
                case 'o':
                    ops[k] = readb(a); a++;
                    j += snprintf(mnemonic + j, 255-j,"%+d", (n8)(ops[k++]));
                    break;
                }
                i++;
            }
            else
            {
                mnemonic[j++] = pattern[i++];
            }
        }
        mnemonic[j] = 0;
        switch (operand_count[ops[0]]) {
        case 1:
            snprintf(ops_str,sizeof(ops_str),"%02X      ", ops[0]);
            break;
        case 2:
            snprintf(ops_str,sizeof(ops_str),"%02X %02X   ", ops[0], ops[1]);
            break;
        case 3:
            snprintf(ops_str,sizeof(ops_str),"%02X %02X %02X", ops[0], ops[1], ops[2]);
            break;
        }
        rb->lcd_putsxyf(0,0,"%04X %s %-16.16s", opaddr, ops_str, mnemonic);
        rb->lcd_update();        
        c--;
    }
}
