//http://www.zophar.net/fileuploads/2/10819kouzv/z80undoc.html

//TODO: ex. (IX+00h) could be turned into (IX)

//usage:
//VgMuseum.Z80.Disassembler disasm = new Disassembler();
//ushort pc = RegPC.Word;
//string str = disasm.Disassemble(() => ReadMemory(pc++));
//Console.WriteLine(str);

//please note that however much youre tempted to, timings can't be put in a table here because they depend on how the instruction executes at runtime

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace cpu.z80
{
    public class Disassembler
    {
        public static sbyte[,] opcodeSizes = new sbyte[9, 256];

        public static void GenerateOpcodeSizes()
        {
            Disassembler disasm = new Disassembler();

            for (int i = 0; i < 256; i++)
            {
                int pc = 0;
                byte[] opcode = { (byte)i, 0, 0, 0 };
                disasm.Disassemble(() => opcode[pc++]);
                opcodeSizes[0, i] = (sbyte)pc;
            }

            opcodeSizes[0, 0xCB] = -1;
            opcodeSizes[0, 0xED] = -2;
            opcodeSizes[0, 0xDD] = -3;
            opcodeSizes[0, 0xFD] = -4;

            for (int i = 0; i < 256; i++)
            {
                int pc = 0;
                byte[] opcode = { 0xCB, (byte)i, 0, 0, 0 };
                disasm.Disassemble(() => opcode[pc++]);
                opcodeSizes[1, i] = (sbyte)pc;
            }

            for (int i = 0; i < 256; i++)
            {
                int pc = 0;
                byte[] opcode = { 0xED, (byte)i, 0, 0, 0 };
                disasm.Disassemble(() => opcode[pc++]);
                opcodeSizes[2, i] = (sbyte)pc;
            }

            for (int i = 0; i < 256; i++)
            {
                int pc = 0;
                byte[] opcode = { 0xDD, (byte)i, 0, 0, 0 };
                disasm.Disassemble(() => opcode[pc++]);
                opcodeSizes[3, i] = (sbyte)pc;
            }

            opcodeSizes[3, 0xCB] = -5;
            opcodeSizes[3, 0xED] = -2;

            for (int i = 0; i < 256; i++)
            {
                int pc = 0;
                byte[] opcode = { 0xFD, (byte)i, 0, 0, 0 };
                disasm.Disassemble(() => opcode[pc++]);
                opcodeSizes[4, i] = (sbyte)pc;
            }

            opcodeSizes[4, 0xCB] = -6;
            opcodeSizes[4, 0xED] = -2;


            for (int i = 0; i < 256; i++)
            {
                int pc = 0;
                byte[] opcode = { 0xDD, 0xCB, (byte)i, 0, 0, 0 };
                disasm.Disassemble(() => opcode[pc++]);
                opcodeSizes[5, i] = (sbyte)pc;
            }

            for (int i = 0; i < 256; i++)
            {
                int pc = 0;
                byte[] opcode = { 0xFD, 0xCB, (byte)i, 0, 0, 0 };
                disasm.Disassemble(() => opcode[pc++]);
                opcodeSizes[6, i] = (sbyte)pc;
            }

            for (int i = 0; i < 256; i++)
            {
                int pc = 0;
                byte[] opcode = { 0xDD, 0xED, (byte)i, 0, 0, 0 };
                disasm.Disassemble(() => opcode[pc++]);
                opcodeSizes[7, i] = (sbyte)pc;
            }

            for (int i = 0; i < 256; i++)
            {
                int pc = 0;
                byte[] opcode = { 0xFD, 0xED, (byte)i, 0, 0, 0 };
                disasm.Disassemble(() => opcode[pc++]);
                opcodeSizes[8, i] = (sbyte)pc;
            }
        }

        static string Result(string format, Func<byte> read)
        {
            //d immediately succeeds the opcode
            //n immediate succeeds the opcode and the displacement (if present)
            //nn immediately succeeds the opcode and the displacement (if present)
            if (format.IndexOf("nn") != -1)
            {
                byte B = read();
                byte C = read();
                format = format.Replace("nn", string.Format("{0:X4}h", B + C * 256));
            }

            if (format.IndexOf("n") != -1)
            {
                byte B = read();
                format = format.Replace("n", string.Format("{0:X2}h", B));
            }

            if (format.IndexOf("+d") != -1) format = format.Replace("+d", "d");

            if (format.IndexOf("d") != -1)
            {
                byte B = read();
                bool neg = ((B & 0x80) != 0);
                char sign = neg ? '-' : '+';
                int val = neg ? 256 - B : B;
                format = format.Replace("d", string.Format("{0}{1:X2}h", sign, val));
            }

            return format;
        }

        readonly static string[] mnemonics = new string[]
		{
		  	"NOP", "LD BC, nn", "LD (BC), A", "INC BC", //0x04
			"INC B", "DEC B", "LD B, n", "RLCA", //0x08
			"EX AF, AF'", "ADD HL, BC", "LD A, (BC)", "DEC BC", //0x0C
			"INC C", "DEC C", "LD C, n", "RRCA", //0x10
			"DJNZ d", "LD DE, nn", "LD (DE), A", "INC DE", //0x14
			"INC D", "DEC D", "LD D, n", "RLA", //0x18
			"JR d", "ADD HL, DE", "LD A, (DE)", "DEC DE", //0x1C
			"INC E", "DEC E", "LD E, n", "RRA", //0x20
			"JR NZ, d", "LD HL, nn", "LD (nn), HL", "INC HL", //0x24
			"INC H", "DEC H", "LD H, n", "DAA", //0x28
			"JR Z, d", "ADD HL, HL", "LD HL, (nn)", "DEC HL", //0x2C
			"INC L", "DEC L", "LD L, n", "CPL", //0x30
			"JR NC, d", "LD SP, nn", "LD (nn), A", "INC SP", //0x34
			"INC (HL)", "DEC (HL)", "LD (HL), n", "SCF", //0x38
			"JR C, d", "ADD HL, SP", "LD A, (nn)", "DEC SP", //0x3C
			"INC A", "DEC A", "LD A, n", "CCF", //0x40
			"LD B, B", "LD B, C", "LD B, D", "LD B, E", //0x44
			"LD B, H", "LD B, L", "LD B, (HL)", "LD B, A", //0x48
			"LD C, B", "LD C, C", "LD C, D", "LD C, E", //0x4C
			"LD C, H", "LD C, L", "LD C, (HL)", "LD C, A", //0x50
			"LD D, B", "LD D, C", "LD D, D", "LD D, E", //0x54
			"LD D, H", "LD D, L", "LD D, (HL)", "LD D, A", //0x58
			"LD E, B", "LD E, C", "LD E, D", "LD E, E", //0x5C
			"LD E, H", "LD E, L", "LD E, (HL)", "LD E, A", //0x60
			"LD H, B", "LD H, C", "LD H, D", "LD H, E", //0x64
			"LD H, H", "LD H, L", "LD H, (HL)", "LD H, A", //0x68
			"LD L, B", "LD L, B", "LD L, D", "LD L, E", //0x6C
			"LD L, H", "LD L, L", "LD L, (HL)", "LD L, A", //0x70
			"LD (HL), B", "LD (HL), C", "LD (HL), D", "LD (HL), E", //0x74
			"LD (HL), H", "LD (HL), L", "HALT", "LD (HL), A", //0x78
			"LD A, B", "LD A, C", "LD A, D", "LD A, E", //0x7C
			"LD A, H", "LD A, L", "LD A, (HL)", "LD A, A", //0x80
			"ADD A, B", "ADD A, C", "ADD A, D", "ADD A, E", //0x84
			"ADD A, H", "ADD A, L", "ADD A, (HL)", "ADD A, A", //0x88
			"ADC A, B", "ADC A, C", "ADC A, D", "ADC A, E", //0x8C
			"ADC A, H", "ADC A, L", "ADC A, (HL)", "ADC A, A", //0x90
			"SUB A, B", "SUB A, C", "SUB A, D", "SUB A, E", //0x94
			"SUB A, H", "SUB A, L", "SUB A, (HL)", "SUB A, A", //0x98
			"SBC A, B", "SBC A, C", "SBC A, D", "SBC A, E", //0x9C
			"SBC A, H", "SBC A, L", "SBC A, (HL)", "SBC A, A", //0xA0
			"AND B", "AND C", "AND D", "AND E", //0xA4
			"AND H", "AND L", "AND (HL)", "AND A", //0xA8
			"XOR B", "XOR C", "XOR D", "XOR E", //0xAC
			"XOR H", "XOR L", "XOR (HL)", "XOR A", //0xB0
			"OR B", "OR C", "OR D", "OR E", //0xB4
			"OR H", "OR L", "OR (HL)", "OR A", //0xB8
			"CP B", "CP C", "CP D", "CP E", //0xBC
			"CP H", "CP L", "CP (HL)", "CP A", //0xC0
			"RET NZ", "POP BC", "JP NZ, nn", "JP nn", //0xC4
			"CALL NZ, nn", "PUSH BC", "ADD A, n", "RST $00", //0xC8
			"RET Z", "RET", "JP Z, nn", "[CB]", //0xCC
			"CALL Z, nn", "CALL nn", "ADC A, n", "RST $08", //0xD0
			"RET NC", "POP DE", "JP NC, nn", "OUT n, A", //0xD4
			"CALL NC, nn", "PUSH DE", "SUB n", "RST $10", //0xD8
			"RET C", "EXX", "JP C, nn", "IN A, n", //0xDC
			"CALL C, nn", "[DD]", "SBC A, n", "RST $18", //0xE0
			"RET PO", "POP HL", "JP PO, nn", "EX (SP), HL", //0xE4
			"CALL C, nn", "PUSH HL", "AND n", "RST $20", //0xE8
			"RET PE", "JP HL", "JP PE, nn", "EX DE, HL", //0xEC
			"CALL PE, nn", "[ED]", "XOR n", "RST $28", //0xF0
			"RET P", "POP AF", "JP P, nn", "DI", //0xF4
			"CALL P, nn", "PUSH AF", "OR n", "RST $30", //0xF8
			"RET M", "LD SP, HL", "JP M, nn", "EI", //0xFC
			"CALL M, nn", "[FD]", "CP n", "RST $38", //0x100
		};

        readonly static string[] mnemonicsDD = new string[]
		{
			"NOP", "LD BC, nn", "LD (BC), A", "INC BC", //0x04
			"INC B", "DEC B", "LD B, n", "RLCA", //0x08
			"EX AF, AF'", "ADD IX, BC", "LD A, (BC)", "DEC BC", //0x0C
			"INC C", "DEC C", "LD C, n", "RRCA", //0x10
			"DJNZ d", "LD DE, nn", "LD (DE), A", "INC DE", //0x14
			"INC D", "DEC D", "LD D, n", "RLA", //0x18
			"JR d", "ADD IX, DE", "LD A, (DE)", "DEC DE", //0x1C
			"INC E", "DEC E", "LD E, n", "RRA", //0x20
			"JR NZ, d", "LD IX, nn", "LD (nn), IX", "INC IX", //0x24
			"INC IXH", "DEC IXH", "LD IXH, n", "DAA", //0x28
			"JR Z, d", "ADD IX, IX", "LD IX, (nn)", "DEC IX", //0x2C
			"INC IXL", "DEC IXL", "LD IXL, n", "CPL", //0x30
			"JR NC, d", "LD SP, nn", "LD (nn), A", "INC SP", //0x34
			"INC (IX+d)", "DEC (IX+d)", "LD (IX+d), n", "SCF", //0x38
			"JR C, d", "ADD IX, SP", "LD A, (nn)", "DEC SP", //0x3C
			"INC A", "DEC A", "LD A, n", "CCF", //0x40
			"LD B, B", "LD B, C", "LD B, D", "LD B, E", //0x44
			"LD B, IXH", "LD B, IXL", "LD B, (IX+d)", "LD B, A", //0x48
			"LD C, B", "LD C, C", "LD C, D", "LD C, E", //0x4C
			"LD C, IXH", "LD C, IXL", "LD C, (IX+d)", "LD C, A", //0x50
			"LD D, B", "LD D, C", "LD D, D", "LD D, E", //0x54
			"LD D, IXH", "LD D, IXL", "LD D, (IX+d)", "LD D, A", //0x58
			"LD E, B", "LD E, C", "LD E, D", "LD E, E", //0x5C
			"LD E, IXH", "LD E, IXL", "LD E, (IX+d)", "LD E, A", //0x60
			"LD IXH, B", "LD IXH, C", "LD IXH, D", "LD IXH, E", //0x64
			"LD IXH, IXH", "LD IXH, IXL", "LD H, (IX+d)", "LD IXH, A", //0x68
			"LD IXL, B", "LD IXL, C", "LD IXL, D", "LD IXL, E", //0x6C
			"LD IXL, IXH", "LD IXL, IXL", "LD L, (IX+d)", "LD IXL, A", //0x70
			"LD (IX+d), B", "LD (IX+d), C", "LD (IX+d), D", "LD (IX+d), E", //0x74
			"LD (IX+d), H", "LD (IX+d), L", "HALT", "LD (IX+d), A", //0x78
			"LD A, B", "LD A, C", "LD A, D", "LD A, E", //0x7C
			"LD A, IXH", "LD A, IXL", "LD A, (IX+d)", "LD A, A", //0x80
			"ADD A, B", "ADD A, C", "ADD A, D", "ADD A, E", //0x84
			"ADD A, IXH", "ADD A, IXL", "ADD A, (IX+d)", "ADD A, A", //0x88
			"ADC A, B", "ADC A, C", "ADC A, D", "ADC A, E", //0x8C
			"ADC A, IXH", "ADC A, IXL", "ADC A, (IX+d)", "ADC A, A", //0x90
			"SUB A, B", "SUB A, C", "SUB A, D", "SUB A, E", //0x94
			"SUB A, IXH", "SUB A, IXL", "SUB A, (IX+d)", "SUB A, A", //0x98
			"SBC A, B", "SBC A, C", "SBC A, D", "SBC A, E", //0x9C
			"SBC A, IXH", "SBC A, IXL", "SBC A, (IX+d)", "SBC A, A", //0xA0
			"AND B", "AND C", "AND D", "AND E", //0xA4
			"AND IXH", "AND IXL", "AND (IX+d)", "AND A", //0xA8
			"XOR B", "XOR C", "XOR D", "XOR E", //0xAC
			"XOR IXH", "XOR IXL", "XOR (IX+d)", "XOR A", //0xB0
			"OR B", "OR C", "OR D", "OR E", //0xB4
			"OR IXH", "OR IXL", "OR (IX+d)", "OR A", //0xB8
			"CP B", "CP C", "CP D", "CP E", //0xBC
			"CP IXH", "CP IXL", "CP (IX+d)", "CP A", //0xC0
			"RET NZ", "POP BC", "JP NZ, nn", "JP nn", //0xC4
			"CALL NZ, nn", "PUSH BC", "ADD A, n", "RST $00", //0xC8
			"RET Z", "RET", "JP Z, nn", "[DD CB]", //0xCC
			"CALL Z, nn", "CALL nn", "ADC A, n", "RST $08", //0xD0
			"RET NC", "POP DE", "JP NC, nn", "OUT n, A", //0xD4
			"CALL NC, nn", "PUSH DE", "SUB n", "RST $10", //0xD8
			"RET C", "EXX", "JP C, nn", "IN A, n", //0xDC
			"CALL C, nn", "[!DD DD!]", "SBC A, n", "RST $18", //0xE0
			"RET PO", "POP IX", "JP PO, nn", "EX (SP), IX", //0xE4
			"CALL C, nn", "PUSH IX", "AND n", "RST $20", //0xE8
			"RET PE", "JP IX", "JP PE, nn", "EX DE, HL", //0xEC
			"CALL PE, nn", "[DD ED]", "XOR n", "RST $28", //0xF0
			"RET P", "POP AF", "JP P, nn", "DI", //0xF4
			"CALL P, nn", "PUSH AF", "OR n", "RST $30", //0xF8
			"RET M", "LD SP, IX", "JP M, nn", "EI", //0xFC
			"CALL M, nn", "[!!DD FD!!]", "CP n", "RST $38", //0x100
		};

        readonly static string[] mnemonicsFD = new string[]
		{
			"NOP", "LD BC, nn", "LD (BC), A", "INC BC", //0x04
			"INC B", "DEC B", "LD B, n", "RLCA", //0x08
			"EX AF, AF'", "ADD IY, BC", "LD A, (BC)", "DEC BC", //0x0C
			"INC C", "DEC C", "LD C, n", "RRCA", //0x10
			"DJNZ d", "LD DE, nn", "LD (DE), A", "INC DE", //0x14
			"INC D", "DEC D", "LD D, n", "RLA", //0x18
			"JR d", "ADD IY, DE", "LD A, (DE)", "DEC DE", //0x1C
			"INC E", "DEC E", "LD E, n", "RRA", //0x20
			"JR NZ, d", "LD IY, nn", "LD (nn), IY", "INC IY", //0x24
			"INC IYH", "DEC IYH", "LD IYH, n", "DAA", //0x28
			"JR Z, d", "ADD IY, IY", "LD IY, (nn)", "DEC IY", //0x2C
			"INC IYL", "DEC IYL", "LD IYL, n", "CPL", //0x30
			"JR NC, d", "LD SP, nn", "LD (nn), A", "INC SP", //0x34
			"INC (IY+d)", "DEC (IY+d)", "LD (IY+d), n", "SCF", //0x38
			"JR C, d", "ADD IY, SP", "LD A, (nn)", "DEC SP", //0x3C
			"INC A", "DEC A", "LD A, n", "CCF", //0x40
			"LD B, B", "LD B, C", "LD B, D", "LD B, E", //0x44
			"LD B, IYH", "LD B, IYL", "LD B, (IY+d)", "LD B, A", //0x48
			"LD C, B", "LD C, C", "LD C, D", "LD C, E", //0x4C
			"LD C, IYH", "LD C, IYL", "LD C, (IY+d)", "LD C, A", //0x50
			"LD D, B", "LD D, C", "LD D, D", "LD D, E", //0x54
			"LD D, IYH", "LD D, IYL", "LD D, (IY+d)", "LD D, A", //0x58
			"LD E, B", "LD E, C", "LD E, D", "LD E, E", //0x5C
			"LD E, IYH", "LD E, IYL", "LD E, (IY+d)", "LD E, A", //0x60
			"LD IYH, B", "LD IYH, C", "LD IYH, D", "LD IYH, E", //0x64
			"LD IYH, IYH", "LD IYH, IYL", "LD H, (IY+d)", "LD IYH, A", //0x68
			"LD IYL, B", "LD IYL, C", "LD IYL, D", "LD IYL, E", //0x6C
			"LD IYL, IYH", "LD IYL, IYL", "LD L, (IY+d)", "LD IYL, A", //0x70
			"LD (IY+d), B", "LD (IY+d), C", "LD (IY+d), D", "LD (IY+d), E", //0x74
			"LD (IY+d), H", "LD (IY+d), L", "HALT", "LD (IY+d), A", //0x78
			"LD A, B", "LD A, C", "LD A, D", "LD A, E", //0x7C
			"LD A, IYH", "LD A, IYL", "LD A, (IY+d)", "LD A, A", //0x80
			"ADD A, B", "ADD A, C", "ADD A, D", "ADD A, E", //0x84
			"ADD A, IYH", "ADD A, IYL", "ADD A, (IY+d)", "ADD A, A", //0x88
			"ADC A, B", "ADC A, C", "ADC A, D", "ADC A, E", //0x8C
			"ADC A, IYH", "ADC A, IYL", "ADC A, (IY+d)", "ADC A, A", //0x90
			"SUB A, B", "SUB A, C", "SUB A, D", "SUB A, E", //0x94
			"SUB A, IYH", "SUB A, IYL", "SUB A, (IY+d)", "SUB A, A", //0x98
			"SBC A, B", "SBC A, C", "SBC A, D", "SBC A, E", //0x9C
			"SBC A, IYH", "SBC A, IYL", "SBC A, (IY+d)", "SBC A, A", //0xA0
			"AND B", "AND C", "AND D", "AND E", //0xA4
			"AND IYH", "AND IYL", "AND (IY+d)", "AND A", //0xA8
			"XOR B", "XOR C", "XOR D", "XOR E", //0xAC
			"XOR IYH", "XOR IYL", "XOR (IY+d)", "XOR A", //0xB0
			"OR B", "OR C", "OR D", "OR E", //0xB4
			"OR IYH", "OR IYL", "OR (IY+d)", "OR A", //0xB8
			"CP B", "CP C", "CP D", "CP E", //0xBC
			"CP IYH", "CP IYL", "CP (IY+d)", "CP A", //0xC0
			"RET NZ", "POP BC", "JP NZ, nn", "JP nn", //0xC4
			"CALL NZ, nn", "PUSH BC", "ADD A, n", "RST $00", //0xC8
			"RET Z", "RET", "JP Z, nn", "[DD CB]", //0xCC
			"CALL Z, nn", "CALL nn", "ADC A, n", "RST $08", //0xD0
			"RET NC", "POP DE", "JP NC, nn", "OUT n, A", //0xD4
			"CALL NC, nn", "PUSH DE", "SUB n", "RST $10", //0xD8
			"RET C", "EXX", "JP C, nn", "IN A, n", //0xDC
			"CALL C, nn", "[!FD DD!]", "SBC A, n", "RST $18", //0xE0
			"RET PO", "POP IY", "JP PO, nn", "EX (SP), IY", //0xE4
			"CALL C, nn", "PUSH IY", "AND n", "RST $20", //0xE8
			"RET PE", "JP IY", "JP PE, nn", "EX DE, HL", //0xEC
			"CALL PE, nn", "[FD ED]", "XOR n", "RST $28", //0xF0
			"RET P", "POP AF", "JP P, nn", "DI", //0xF4
			"CALL P, nn", "PUSH AF", "OR n", "RST $30", //0xF8
			"RET M", "LD SP, IY", "JP M, nn", "EI", //0xFC
			"CALL M, nn", "[!FD FD!]", "CP n", "RST $38", //0x100
		};

        readonly static string[] mnemonicsDDCB = new string[]
		{
			"RLC (IX+d)->B", "RLC (IX+d)->C", "RLC (IX+d)->D", "RLC (IX+d)->E", "RLC (IX+d)->H", "RLC (IX+d)->L", "RLC (IX+d)", "RLC (IX+d)->A", 
			"RRC (IX+d)->B", "RRC (IX+d)->C", "RRC (IX+d)->D", "RRC (IX+d)->E", "RRC (IX+d)->H", "RRC (IX+d)->L", "RRC (IX+d)", "RRC (IX+d)->A", 
			"RL (IX+d)->B", "RL (IX+d)->C", "RL (IX+d)->D", "RL (IX+d)->E", "RL (IX+d)->H", "RL (IX+d)->L", "RL (IX+d)", "RL (IX+d)->A", 
			"RR (IX+d)->B", "RR (IX+d)->C", "RR (IX+d)->D", "RR (IX+d)->E", "RR (IX+d)->H", "RR (IX+d)->L", "RR (IX+d)", "RR (IX+d)->A", 
			"SLA (IX+d)->B", "SLA (IX+d)->C", "SLA (IX+d)->D", "SLA (IX+d)->E", "SLA (IX+d)->H", "SLA (IX+d)->L", "SLA (IX+d)", "SLA (IX+d)->A", 
			"SRA (IX+d)->B", "SRA (IX+d)->C", "SRA (IX+d)->D", "SRA (IX+d)->E", "SRA (IX+d)->H", "SRA (IX+d)->L", "SRA (IX+d)", "SRA (IX+d)->A", 
			"SL1 (IX+d)->B", "SL1 (IX+d)->C", "SL1 (IX+d)->D", "SL1 (IX+d)->E", "SL1 (IX+d)->H", "SL1 (IX+d)->L", "SL1 (IX+d)", "SL1 (IX+d)->A", 
			"SRL (IX+d)->B", "SRL (IX+d)->C", "SRL (IX+d)->D", "SRL (IX+d)->E", "SRL (IX+d)->H", "SRL (IX+d)->L", "SRL (IX+d)", "SRL (IX+d)->A", 
			"BIT 0, (IX+d)", "BIT 0, (IX+d)", "BIT 0, (IX+d)", "BIT 0, (IX+d)", "BIT 0, (IX+d)", "BIT 0, (IX+d)", "BIT 0, (IX+d)", "BIT 0, (IX+d)", 
			"BIT 1, (IX+d)", "BIT 1, (IX+d)", "BIT 1, (IX+d)", "BIT 1, (IX+d)", "BIT 1, (IX+d)", "BIT 1, (IX+d)", "BIT 1, (IX+d)", "BIT 1, (IX+d)", 
			"BIT 2, (IX+d)", "BIT 2, (IX+d)", "BIT 2, (IX+d)", "BIT 2, (IX+d)", "BIT 2, (IX+d)", "BIT 2, (IX+d)", "BIT 2, (IX+d)", "BIT 2, (IX+d)", 
			"BIT 3, (IX+d)", "BIT 3, (IX+d)", "BIT 3, (IX+d)", "BIT 3, (IX+d)", "BIT 3, (IX+d)", "BIT 3, (IX+d)", "BIT 3, (IX+d)", "BIT 3, (IX+d)", 
			"BIT 4, (IX+d)", "BIT 4, (IX+d)", "BIT 4, (IX+d)", "BIT 4, (IX+d)", "BIT 4, (IX+d)", "BIT 4, (IX+d)", "BIT 4, (IX+d)", "BIT 4, (IX+d)", 
			"BIT 5, (IX+d)", "BIT 5, (IX+d)", "BIT 5, (IX+d)", "BIT 5, (IX+d)", "BIT 5, (IX+d)", "BIT 5, (IX+d)", "BIT 5, (IX+d)", "BIT 5, (IX+d)", 
			"BIT 6, (IX+d)", "BIT 6, (IX+d)", "BIT 6, (IX+d)", "BIT 6, (IX+d)", "BIT 6, (IX+d)", "BIT 6, (IX+d)", "BIT 6, (IX+d)", "BIT 6, (IX+d)", 
			"BIT 7, (IX+d)", "BIT 7, (IX+d)", "BIT 7, (IX+d)", "BIT 7, (IX+d)", "BIT 7, (IX+d)", "BIT 7, (IX+d)", "BIT 7, (IX+d)", "BIT 7, (IX+d)", 
			"RES 0 (IX+d)->B", "RES 0 (IX+d)->C", "RES 0 (IX+d)->D", "RES 0 (IX+d)->E", "RES 0 (IX+d)->H", "RES 0 (IX+d)->L", "RES 0 (IX+d)", "RES 0 (IX+d)->A", 
			"RES 1 (IX+d)->B", "RES 1 (IX+d)->C", "RES 1 (IX+d)->D", "RES 1 (IX+d)->E", "RES 1 (IX+d)->H", "RES 1 (IX+d)->L", "RES 1 (IX+d)", "RES 1 (IX+d)->A", 
			"RES 2 (IX+d)->B", "RES 2 (IX+d)->C", "RES 2 (IX+d)->D", "RES 2 (IX+d)->E", "RES 2 (IX+d)->H", "RES 2 (IX+d)->L", "RES 2 (IX+d)", "RES 2 (IX+d)->A", 
			"RES 3 (IX+d)->B", "RES 3 (IX+d)->C", "RES 3 (IX+d)->D", "RES 3 (IX+d)->E", "RES 3 (IX+d)->H", "RES 3 (IX+d)->L", "RES 3 (IX+d)", "RES 3 (IX+d)->A", 
			"RES 4 (IX+d)->B", "RES 4 (IX+d)->C", "RES 4 (IX+d)->D", "RES 4 (IX+d)->E", "RES 4 (IX+d)->H", "RES 4 (IX+d)->L", "RES 4 (IX+d)", "RES 4 (IX+d)->A", 
			"RES 5 (IX+d)->B", "RES 5 (IX+d)->C", "RES 5 (IX+d)->D", "RES 5 (IX+d)->E", "RES 5 (IX+d)->H", "RES 5 (IX+d)->L", "RES 5 (IX+d)", "RES 5 (IX+d)->A", 
			"RES 6 (IX+d)->B", "RES 6 (IX+d)->C", "RES 6 (IX+d)->D", "RES 6 (IX+d)->E", "RES 6 (IX+d)->H", "RES 6 (IX+d)->L", "RES 6 (IX+d)", "RES 6 (IX+d)->A", 
			"RES 7 (IX+d)->B", "RES 7 (IX+d)->C", "RES 7 (IX+d)->D", "RES 7 (IX+d)->E", "RES 7 (IX+d)->H", "RES 7 (IX+d)->L", "RES 7 (IX+d)", "RES 7 (IX+d)->A", 
			"SET 0 (IX+d)->B", "SET 0 (IX+d)->C", "SET 0 (IX+d)->D", "SET 0 (IX+d)->E", "SET 0 (IX+d)->H", "SET 0 (IX+d)->L", "SET 0 (IX+d)", "SET 0 (IX+d)->A", 
			"SET 1 (IX+d)->B", "SET 1 (IX+d)->C", "SET 1 (IX+d)->D", "SET 1 (IX+d)->E", "SET 1 (IX+d)->H", "SET 1 (IX+d)->L", "SET 1 (IX+d)", "SET 1 (IX+d)->A", 
			"SET 2 (IX+d)->B", "SET 2 (IX+d)->C", "SET 2 (IX+d)->D", "SET 2 (IX+d)->E", "SET 2 (IX+d)->H", "SET 2 (IX+d)->L", "SET 2 (IX+d)", "SET 2 (IX+d)->A", 
			"SET 3 (IX+d)->B", "SET 3 (IX+d)->C", "SET 3 (IX+d)->D", "SET 3 (IX+d)->E", "SET 3 (IX+d)->H", "SET 3 (IX+d)->L", "SET 3 (IX+d)", "SET 3 (IX+d)->A", 
			"SET 4 (IX+d)->B", "SET 4 (IX+d)->C", "SET 4 (IX+d)->D", "SET 4 (IX+d)->E", "SET 4 (IX+d)->H", "SET 4 (IX+d)->L", "SET 4 (IX+d)", "SET 4 (IX+d)->A", 
			"SET 5 (IX+d)->B", "SET 5 (IX+d)->C", "SET 5 (IX+d)->D", "SET 5 (IX+d)->E", "SET 5 (IX+d)->H", "SET 5 (IX+d)->L", "SET 5 (IX+d)", "SET 5 (IX+d)->A", 
			"SET 6 (IX+d)->B", "SET 6 (IX+d)->C", "SET 6 (IX+d)->D", "SET 6 (IX+d)->E", "SET 6 (IX+d)->H", "SET 6 (IX+d)->L", "SET 6 (IX+d)", "SET 6 (IX+d)->A", 
			"SET 7 (IX+d)->B", "SET 7 (IX+d)->C", "SET 7 (IX+d)->D", "SET 7 (IX+d)->E", "SET 7 (IX+d)->H", "SET 7 (IX+d)->L", "SET 7 (IX+d)", "SET 7 (IX+d)->A", 
		};

        readonly static string[] mnemonicsFDCB = new string[]
		{
			"RLC (IY+d)->B", "RLC (IY+d)->C", "RLC (IY+d)->D", "RLC (IY+d)->E", "RLC (IY+d)->H", "RLC (IY+d)->L", "RLC (IY+d)", "RLC (IY+d)->A", 
			"RRC (IY+d)->B", "RRC (IY+d)->C", "RRC (IY+d)->D", "RRC (IY+d)->E", "RRC (IY+d)->H", "RRC (IY+d)->L", "RRC (IY+d)", "RRC (IY+d)->A", 
			"RL (IY+d)->B", "RL (IY+d)->C", "RL (IY+d)->D", "RL (IY+d)->E", "RL (IY+d)->H", "RL (IY+d)->L", "RL (IY+d)", "RL (IY+d)->A", 
			"RR (IY+d)->B", "RR (IY+d)->C", "RR (IY+d)->D", "RR (IY+d)->E", "RR (IY+d)->H", "RR (IY+d)->L", "RR (IY+d)", "RR (IY+d)->A", 
			"SLA (IY+d)->B", "SLA (IY+d)->C", "SLA (IY+d)->D", "SLA (IY+d)->E", "SLA (IY+d)->H", "SLA (IY+d)->L", "SLA (IY+d)", "SLA (IY+d)->A", 
			"SRA (IY+d)->B", "SRA (IY+d)->C", "SRA (IY+d)->D", "SRA (IY+d)->E", "SRA (IY+d)->H", "SRA (IY+d)->L", "SRA (IY+d)", "SRA (IY+d)->A", 
			"SL1 (IY+d)->B", "SL1 (IY+d)->C", "SL1 (IY+d)->D", "SL1 (IY+d)->E", "SL1 (IY+d)->H", "SL1 (IY+d)->L", "SL1 (IY+d)", "SL1 (IY+d)->A", 
			"SRL (IY+d)->B", "SRL (IY+d)->C", "SRL (IY+d)->D", "SRL (IY+d)->E", "SRL (IY+d)->H", "SRL (IY+d)->L", "SRL (IY+d)", "SRL (IY+d)->A", 
			"BIT 0, (IY+d)", "BIT 0, (IY+d)", "BIT 0, (IY+d)", "BIT 0, (IY+d)", "BIT 0, (IY+d)", "BIT 0, (IY+d)", "BIT 0, (IY+d)", "BIT 0, (IY+d)", 
			"BIT 1, (IY+d)", "BIT 1, (IY+d)", "BIT 1, (IY+d)", "BIT 1, (IY+d)", "BIT 1, (IY+d)", "BIT 1, (IY+d)", "BIT 1, (IY+d)", "BIT 1, (IY+d)", 
			"BIT 2, (IY+d)", "BIT 2, (IY+d)", "BIT 2, (IY+d)", "BIT 2, (IY+d)", "BIT 2, (IY+d)", "BIT 2, (IY+d)", "BIT 2, (IY+d)", "BIT 2, (IY+d)", 
			"BIT 3, (IY+d)", "BIT 3, (IY+d)", "BIT 3, (IY+d)", "BIT 3, (IY+d)", "BIT 3, (IY+d)", "BIT 3, (IY+d)", "BIT 3, (IY+d)", "BIT 3, (IY+d)", 
			"BIT 4, (IY+d)", "BIT 4, (IY+d)", "BIT 4, (IY+d)", "BIT 4, (IY+d)", "BIT 4, (IY+d)", "BIT 4, (IY+d)", "BIT 4, (IY+d)", "BIT 4, (IY+d)", 
			"BIT 5, (IY+d)", "BIT 5, (IY+d)", "BIT 5, (IY+d)", "BIT 5, (IY+d)", "BIT 5, (IY+d)", "BIT 5, (IY+d)", "BIT 5, (IY+d)", "BIT 5, (IY+d)", 
			"BIT 6, (IY+d)", "BIT 6, (IY+d)", "BIT 6, (IY+d)", "BIT 6, (IY+d)", "BIT 6, (IY+d)", "BIT 6, (IY+d)", "BIT 6, (IY+d)", "BIT 6, (IY+d)", 
			"BIT 7, (IY+d)", "BIT 7, (IY+d)", "BIT 7, (IY+d)", "BIT 7, (IY+d)", "BIT 7, (IY+d)", "BIT 7, (IY+d)", "BIT 7, (IY+d)", "BIT 7, (IY+d)", 
			"RES 0 (IY+d)->B", "RES 0 (IY+d)->C", "RES 0 (IY+d)->D", "RES 0 (IY+d)->E", "RES 0 (IY+d)->H", "RES 0 (IY+d)->L", "RES 0 (IY+d)", "RES 0 (IY+d)->A", 
			"RES 1 (IY+d)->B", "RES 1 (IY+d)->C", "RES 1 (IY+d)->D", "RES 1 (IY+d)->E", "RES 1 (IY+d)->H", "RES 1 (IY+d)->L", "RES 1 (IY+d)", "RES 1 (IY+d)->A", 
			"RES 2 (IY+d)->B", "RES 2 (IY+d)->C", "RES 2 (IY+d)->D", "RES 2 (IY+d)->E", "RES 2 (IY+d)->H", "RES 2 (IY+d)->L", "RES 2 (IY+d)", "RES 2 (IY+d)->A", 
			"RES 3 (IY+d)->B", "RES 3 (IY+d)->C", "RES 3 (IY+d)->D", "RES 3 (IY+d)->E", "RES 3 (IY+d)->H", "RES 3 (IY+d)->L", "RES 3 (IY+d)", "RES 3 (IY+d)->A", 
			"RES 4 (IY+d)->B", "RES 4 (IY+d)->C", "RES 4 (IY+d)->D", "RES 4 (IY+d)->E", "RES 4 (IY+d)->H", "RES 4 (IY+d)->L", "RES 4 (IY+d)", "RES 4 (IY+d)->A", 
			"RES 5 (IY+d)->B", "RES 5 (IY+d)->C", "RES 5 (IY+d)->D", "RES 5 (IY+d)->E", "RES 5 (IY+d)->H", "RES 5 (IY+d)->L", "RES 5 (IY+d)", "RES 5 (IY+d)->A", 
			"RES 6 (IY+d)->B", "RES 6 (IY+d)->C", "RES 6 (IY+d)->D", "RES 6 (IY+d)->E", "RES 6 (IY+d)->H", "RES 6 (IY+d)->L", "RES 6 (IY+d)", "RES 6 (IY+d)->A", 
			"RES 7 (IY+d)->B", "RES 7 (IY+d)->C", "RES 7 (IY+d)->D", "RES 7 (IY+d)->E", "RES 7 (IY+d)->H", "RES 7 (IY+d)->L", "RES 7 (IY+d)", "RES 7 (IY+d)->A", 
			"SET 0 (IY+d)->B", "SET 0 (IY+d)->C", "SET 0 (IY+d)->D", "SET 0 (IY+d)->E", "SET 0 (IY+d)->H", "SET 0 (IY+d)->L", "SET 0 (IY+d)", "SET 0 (IY+d)->A", 
			"SET 1 (IY+d)->B", "SET 1 (IY+d)->C", "SET 1 (IY+d)->D", "SET 1 (IY+d)->E", "SET 1 (IY+d)->H", "SET 1 (IY+d)->L", "SET 1 (IY+d)", "SET 1 (IY+d)->A", 
			"SET 2 (IY+d)->B", "SET 2 (IY+d)->C", "SET 2 (IY+d)->D", "SET 2 (IY+d)->E", "SET 2 (IY+d)->H", "SET 2 (IY+d)->L", "SET 2 (IY+d)", "SET 2 (IY+d)->A", 
			"SET 3 (IY+d)->B", "SET 3 (IY+d)->C", "SET 3 (IY+d)->D", "SET 3 (IY+d)->E", "SET 3 (IY+d)->H", "SET 3 (IY+d)->L", "SET 3 (IY+d)", "SET 3 (IY+d)->A", 
			"SET 4 (IY+d)->B", "SET 4 (IY+d)->C", "SET 4 (IY+d)->D", "SET 4 (IY+d)->E", "SET 4 (IY+d)->H", "SET 4 (IY+d)->L", "SET 4 (IY+d)", "SET 4 (IY+d)->A", 
			"SET 5 (IY+d)->B", "SET 5 (IY+d)->C", "SET 5 (IY+d)->D", "SET 5 (IY+d)->E", "SET 5 (IY+d)->H", "SET 5 (IY+d)->L", "SET 5 (IY+d)", "SET 5 (IY+d)->A", 
			"SET 6 (IY+d)->B", "SET 6 (IY+d)->C", "SET 6 (IY+d)->D", "SET 6 (IY+d)->E", "SET 6 (IY+d)->H", "SET 6 (IY+d)->L", "SET 6 (IY+d)", "SET 6 (IY+d)->A", 
			"SET 7 (IY+d)->B", "SET 7 (IY+d)->C", "SET 7 (IY+d)->D", "SET 7 (IY+d)->E", "SET 7 (IY+d)->H", "SET 7 (IY+d)->L", "SET 7 (IY+d)", "SET 7 (IY+d)->A", 
		};

        readonly static string[] mnemonicsCB = new string[]
		{
			"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",
			"SL1 B", "SL1 C", "SL1 D", "SL1 E", "SL1 H", "SL1 L", "SL1 (HL)", "SL1 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",
		};

        readonly static string[] mnemonicsED = new string[]
		{
			"NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", 
			"NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", 
			"NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", 
			"NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", 
			
			"IN B, C", "OUT C, B", "SBC HL, BC", "LD (nn), BC", //0x44
			"NEG", "RETN", "IM $0", "LD I, A", //0x48
			"IN C, C", "OUT C, C", "ADC HL, BC", "LD BC, (nn)", //0x4C
			"NEG", "RETI", "IM $0", "LD R, A", //0x50
			"IN D, C", "OUT C, D", "SBC HL, DE", "LD (nn), DE", //0x54
			"NEG", "RETN", "IM $1", "LD A, I", //0x58
			"IN E, C", "OUT C, E", "ADC HL, DE", "LD DE, (nn)", //0x5C
			"NEG", "RETI", "IM $2", "LD A, R", //0x60
			
			"IN H, C", "OUT C, H", "SBC HL, HL", "LD (nn), HL", //0x64
			"NEG", "RETN", "IM $0", "RRD", //0x68
			"IN L, C", "OUT C, L", "ADC HL, HL", "LD HL, (nn)", //0x6C
			"NEG", "RETI", "IM $0", "RLD", //0x70
			"IN 0, C", "OUT C, 0", "SBC HL, SP", "LD (nn), SP", //0x74
			"NEG", "RETN", "IM $1", "NOP", //0x78
			"IN A, C", "OUT C, A", "ADC HL, SP", "LD SP, (nn)", //0x7C
			"NEG", "RETI", "IM $2", "NOP", //0x80

			"NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", //0x90
			"NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", //0xA0
			"LDI", "CPI", "INI", "OUTI", //0xA4
			"NOP", "NOP", "NOP", "NOP", //0xA8
			"LDD", "CPD", "IND", "OUTD", //0xAC
			"NOP", "NOP", "NOP", "NOP", //0xB0
			"LDIR", "CPIR", "INIR", "OTIR", //0xB4
			"NOP", "NOP", "NOP", "NOP", //0xB8
			"LDDR", "CPDR", "INDR", "OTDR", //0xBC
			"NOP", "NOP", "NOP", "NOP", //0xC0

			"NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", //0xD0
			"NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", //0xE0
			"NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", //0xF0
			"NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", //0x100
		};

        string DisassembleInternal(Func<byte> read)
        {
            byte A = read();
            string format;
            switch (A)
            {
                case 0xCB:
                    A = read();
                    format = mnemonicsCB[A];
                    break;
                case 0xDD:
                    A = read();
                    switch (A)
                    {
                        case 0xCB: format = mnemonicsDDCB[A]; break;
                        case 0xED: format = mnemonicsED[A]; break;
                        default: format = mnemonicsDD[A]; break;
                    }
                    break;
                case 0xED:
                    A = read();
                    format = mnemonicsED[A];
                    break;
                case 0xFD:
                    A = read();
                    switch (A)
                    {
                        case 0xCB: format = mnemonicsFDCB[A]; break;
                        case 0xED: format = mnemonicsED[A]; break;
                        default: format = mnemonicsFD[A]; break;
                    }
                    break;
                default: format = mnemonics[A]; break;
            }
            return format;
        }

        public string Disassemble(Func<byte> read)
        {
            return Result(DisassembleInternal(read), read);
        }
        public string DisassembleInternal2(byte[] code)
        {
            byte A = code[0];
            string format;
            switch (A)
            {
                case 0xCB:
                    A = code[1];
                    format = mnemonicsCB[A];
                    break;
                case 0xDD:
                    A = code[1];
                    switch (A)
                    {
                        case 0xCB: format = mnemonicsDDCB[A]; break;
                        case 0xED: format = mnemonicsED[A]; break;
                        default: format = mnemonicsDD[A]; break;
                    }
                    break;
                case 0xED:
                    A = code[1];
                    format = mnemonicsED[A];
                    break;
                case 0xFD:
                    A = code[1];
                    switch (A)
                    {
                        case 0xCB: format = mnemonicsFDCB[A]; break;
                        case 0xED: format = mnemonicsED[A]; break;
                        default: format = mnemonicsFD[A]; break;
                    }
                    break;
                default: format = mnemonics[A]; break;
            }
            return format;
        }
        static string Result2(string format, byte[] code, int offset)
        {
            //d immediately succeeds the opcode
            //n immediate succeeds the opcode and the displacement (if present)
            //nn immediately succeeds the opcode and the displacement (if present)
            if (format.IndexOf("nn") != -1)
            {
                byte B = code[offset];
                byte C = code[offset + 1];
                format = format.Replace("nn", string.Format("{0:X4}h", B + C * 256));
            }

            if (format.IndexOf("n") != -1)
            {
                byte B = code[offset];
                format = format.Replace("n", string.Format("{0:X2}h", B));
            }

            if (format.IndexOf("+d") != -1) format = format.Replace("+d", "d");

            if (format.IndexOf("d") != -1)
            {
                byte B = code[offset];
                bool neg = ((B & 0x80) != 0);
                char sign = neg ? '-' : '+';
                int val = neg ? 256 - B : B;
                format = format.Replace("d", string.Format("{0}{1:X2}h", sign, val));
            }

            return format;
        }
        public string Disassemble2(byte[] code,int offset)
        {
            return Result2(DisassembleInternal2(code), code, offset);
        }
        public string GetDisassembleInfo(ushort ushort1)
        {
            byte[] opcode = null, opcode2 = null;
            byte byte1, byte2, byte3;
            string s1 = "", s2;
            int i, length = 0, offset = 0;
            string sDisassemble;
            byte1 = Z80A.zz1[0].ReadOp(ushort1);
            if (byte1 != 0xCB && byte1 != 0xED && byte1 != 0xDD && byte1 != 0xFD)
            {
                opcode2 = new byte[] { byte1, Z80A.zz1[0].ReadOpArg((ushort)(ushort1 + 1)), Z80A.zz1[0].ReadOpArg((ushort)(ushort1 + 2)), Z80A.zz1[0].ReadOpArg((ushort)(ushort1 + 3)) };
                length = Disassembler.opcodeSizes[0, byte1];
                offset = 1;
            }
            else if (byte1 == 0xCB)
            {
                opcode2 = new byte[] { byte1, Z80A.zz1[0].ReadOp((ushort)(ushort1 + 1)), Z80A.zz1[0].ReadOpArg((ushort)(ushort1 + 2)), Z80A.zz1[0].ReadOpArg((ushort)(ushort1 + 3)), Z80A.zz1[0].ReadOpArg((ushort)(ushort1 + 4)) };
                length = Disassembler.opcodeSizes[1, byte1];
                offset = 2;
            }
            else if (byte1 == 0xED)
            {
                opcode2 = new byte[] { byte1, Z80A.zz1[0].ReadOp((ushort)(ushort1 + 1)), Z80A.zz1[0].ReadOpArg((ushort)(ushort1 + 2)), Z80A.zz1[0].ReadOpArg((ushort)(ushort1 + 3)), Z80A.zz1[0].ReadOpArg((ushort)(ushort1 + 4)) };
                length = Disassembler.opcodeSizes[2, byte1];
                offset = 2;
            }
            else if (byte1 == 0xDD)
            {
                byte2 = Z80A.zz1[0].ReadOp((ushort)(ushort1 + 1));
                if (byte2 != 0xCB && byte2 != 0xED)
                {
                    opcode2 = new byte[] { byte1, byte2, Z80A.zz1[0].ReadOpArg((ushort)(ushort1 + 2)), Z80A.zz1[0].ReadOpArg((ushort)(ushort1 + 3)), Z80A.zz1[0].ReadOpArg((ushort)(ushort1 + 4)) };
                    length = Disassembler.opcodeSizes[3, byte2];
                    offset = 2;
                }
                else if (byte2 == 0xCB)
                {
                    byte3 = Z80A.zz1[0].ReadOpArg((ushort)(ushort1 + 2));
                    opcode2 = new byte[] { byte1, byte2, byte3, Z80A.zz1[0].ReadOpArg((ushort)(ushort1 + 3)), Z80A.zz1[0].ReadOpArg((ushort)(ushort1 + 4)), Z80A.zz1[0].ReadOpArg((ushort)(ushort1 + 5)) };
                    length = Disassembler.opcodeSizes[5, byte3];
                    offset = 2;
                }
                else if (byte2 == 0xED)
                {
                    byte3 = Z80A.zz1[0].ReadOp((ushort)(ushort1 + 2));
                    opcode2 = new byte[] { byte1, byte2, byte3, Z80A.zz1[0].ReadOpArg((ushort)(ushort1 + 3)), Z80A.zz1[0].ReadOpArg((ushort)(ushort1 + 4)), Z80A.zz1[0].ReadOpArg((ushort)(ushort1 + 5)) };
                    length = Disassembler.opcodeSizes[7, byte3];
                    offset = 2;
                }
            }
            else if (byte1 == 0xFD)
            {
                byte2 = Z80A.zz1[0].ReadOp((ushort)(ushort1 + 1));
                if (byte2 != 0xCB && byte2 != 0xED)
                {
                    opcode2 = new byte[] { byte1, byte2, Z80A.zz1[0].ReadOpArg((ushort)(ushort1 + 2)), Z80A.zz1[0].ReadOpArg((ushort)(ushort1 + 3)), Z80A.zz1[0].ReadOpArg((ushort)(ushort1 + 4)) };
                    length = Disassembler.opcodeSizes[4, byte2];
                    offset = 2;
                }
                else if (byte2 == 0xCB)
                {
                    byte3 = Z80A.zz1[0].ReadOpArg((ushort)(ushort1 + 2));
                    opcode2 = new byte[] { byte1, byte2, byte3, Z80A.zz1[0].ReadOpArg((ushort)(ushort1 + 3)), Z80A.zz1[0].ReadOpArg((ushort)(ushort1 + 4)), Z80A.zz1[0].ReadOpArg((ushort)(ushort1 + 5)) };
                    length = Disassembler.opcodeSizes[6, byte3];
                    offset = 2;
                }
                else if (byte2 == 0xED)
                {
                    byte3 = Z80A.zz1[0].ReadOp((ushort)(ushort1 + 2));
                    opcode2 = new byte[] { byte1, byte2, byte3, Z80A.zz1[0].ReadOpArg((ushort)(ushort1 + 3)), Z80A.zz1[0].ReadOpArg((ushort)(ushort1 + 4)), Z80A.zz1[0].ReadOpArg((ushort)(ushort1 + 5)) };
                    length = Disassembler.opcodeSizes[8, byte3];
                    offset = 2;
                }
            }
            opcode = new byte[length];
            Array.Copy(opcode2, opcode, length);
            s2 = Disassemble2(opcode, offset);
            for (i = 0; i < length; i++)
            {
                s1 += opcode[i].ToString("X2") + " ";
            }
            sDisassemble = s1.PadRight(20, ' ') + s2;
            return sDisassemble;
        }
    }
}