import typing

from .... import platforms
from .machdef import GhidraMachineDef


class AMD64MachineDef(GhidraMachineDef):
    arch: platforms.Architecture = platforms.Architecture.X86_64
    byteorder: platforms.Byteorder = platforms.Byteorder.LITTLE
    language_id: str = "x86:LE:64:default"

    _registers: typing.Dict[str, typing.Optional[str]] = {
        # *** General Purpose Registers ***
        "rax": "rax",
        "eax": "eax",
        "ax": "ax",
        "al": "al",
        "ah": "ah",
        "rbx": "rbx",
        "ebx": "ebx",
        "bx": "bx",
        "bl": "bl",
        "bh": "bh",
        "rcx": "rcx",
        "ecx": "ecx",
        "cx": "cx",
        "cl": "cl",
        "ch": "ch",
        "rdx": "rdx",
        "edx": "edx",
        "dx": "dx",
        "dl": "dl",
        "dh": "dh",
        "r8": "r8",
        "r8d": "r8d",
        "r8w": "r8w",
        "r8b": "r8b",
        "r9": "r9",
        "r9d": "r9d",
        "r9w": "r9w",
        "r9b": "r9b",
        "r10": "r10",
        "r10d": "r10d",
        "r10w": "r10w",
        "r10b": "r10b",
        "r11": "r11",
        "r11d": "r11d",
        "r11w": "r11w",
        "r11b": "r11b",
        "r12": "r12",
        "r12d": "r12d",
        "r12w": "r12w",
        "r12b": "r12b",
        "r13": "r13",
        "r13d": "r13d",
        "r13w": "r13w",
        "r13b": "r13b",
        "r14": "r14",
        "r14d": "r14d",
        "r14w": "r14w",
        "r14b": "r14b",
        "r15": "r15",
        "r15d": "r15d",
        "r15w": "r15w",
        "r15b": "r15b",
        "rsi": "rsi",
        "esi": "esi",
        "si": "si",
        "sil": "sil",
        "rdi": "rdi",
        "edi": "edi",
        "di": "di",
        "dil": "dil",
        "rbp": "rbp",
        "ebp": "ebp",
        "bp": "bp",
        "bpl": "bpl",
        "rsp": "rsp",
        "esp": "esp",
        "sp": "sp",
        "spl": "spl",
        # *** Instruction Pointer ***
        "rip": "rip",
        "eip": "eip",
        "ip": "ip",
        # *** Segment Registers ***
        "cs": "cs",
        "ds": "ds",
        "es": "es",
        "fs": "fs",
        "gs": "gs",
        "ss": "ss",
        # *** Flags Register ***
        "rflags": "rflags",
        "eflags": "eflags",
        "flags": "flags",
        # *** Control Registers ***
        # NOTE: Ghidra happily supports up to cr15
        "cr0": "cr0",
        "cr1": "cr1",
        "cr2": "cr2",
        "cr3": "cr3",
        "cr4": "cr4",
        "cr8": "cr8",
        # *** Debug Registers ***
        "dr0": "dr0",
        "dr1": "dr1",
        "dr2": "dr2",
        "dr3": "dr3",
        "dr6": "dr6",
        "dr7": "dr7",
        "dr8": "dr8",
        "dr9": "dr9",
        "dr10": "dr10",
        "dr11": "dr11",
        "dr12": "dr12",
        "dr13": "dr13",
        "dr14": "dr14",
        "dr15": "dr15",
        # *** Descriptor Table Registers ***
        "gdtr": "gdtr",
        "idtr": "idtr",
        "ldtr": "ldtr",
        # *** Task Register ***
        "tr": "tr",
        # *** x87 Registers ***
        # TODO: Ghidra appears to support x87, but I have no idea how it works
        "fpr0": None,
        "fpr1": None,
        "fpr2": None,
        "fpr3": None,
        "fpr4": None,
        "fpr5": None,
        "fpr6": None,
        "fpr7": None,
        "fctrl": None,
        "fstat": None,
        "ftag": None,
        "fip": None,
        "fdp": None,
        "fop": None,
        # *** MMX Registers ***
        # TODO: Ghidra appears to support mmx, but I have no idea how it works.
        "mm0": None,
        "mm1": None,
        "mm2": None,
        "mm3": None,
        "mm4": None,
        "mm5": None,
        "mm6": None,
        "mm7": None,
        # SSE/AVX registers
        "ymm0": "ymm0",
        "xmm0": "xmm0",
        "ymm1": "ymm1",
        "xmm1": "xmm1",
        "ymm2": "ymm2",
        "xmm2": "xmm2",
        "ymm3": "ymm3",
        "xmm3": "xmm3",
        "ymm4": "ymm4",
        "xmm4": "xmm4",
        "ymm5": "ymm5",
        "xmm5": "xmm5",
        "ymm6": "ymm6",
        "xmm6": "xmm6",
        "ymm7": "ymm7",
        "xmm7": "xmm7",
        "ymm8": "ymm8",
        "xmm8": "xmm8",
        "ymm9": "ymm9",
        "xmm9": "xmm9",
        "ymm10": "ymm10",
        "xmm10": "xmm10",
        "ymm11": "ymm11",
        "xmm11": "xmm11",
        "ymm12": "ymm12",
        "xmm12": "xmm12",
        "ymm13": "ymm13",
        "xmm13": "xmm13",
        "ymm14": "ymm14",
        "xmm14": "xmm14",
        "ymm15": "ymm15",
        "xmm15": "xmm15",
    }
