# -*- coding: utf-8 -*-

# This code is part of Amoco
# Copyright (C) 2006-2011 Axel Tillequin (bdcht3@gmail.com)
# published under GPLv2 license

# import expressions:
from amoco.cas.expressions import reg, slc
from amoco.cas.expressions import is_reg_pc, is_reg_flags, is_reg_other, is_reg_stack
from amoco.cas.expressions import *  # noqa: F403

# 64bits registers :
# -------------------

rax = reg("rax", 64)  # accumulator for operands and results data
rbx = reg("rbx", 64)  # pointer to data in the DS segment
rcx = reg("rcx", 64)  # counter for string and loop operations
rdx = reg("rdx", 64)  # I/O pointer
rbp = reg("rbp", 64)  # pointer to data in the stack (SS segment)
rsp = reg("rsp", 64)  # stack pointer (SS segment)
rsi = reg("rsi", 64)  # ptr to data in segment pointed by DS; src ptr for strings
rdi = reg("rdi", 64)  # ptr to data in segment pointed by ES; dst ptr for strings
rip = reg("rip", 64)  # instruction pointer in 64 bit mode
rflags = reg("rflags", 64)

is_reg_pc(rip)
is_reg_flags(rflags)
is_reg_stack(rsp)
is_reg_stack(rbp)

# 32bits registers :
# -------------------

eax = slc(rax, 0, 32, "eax")
ebx = slc(rbx, 0, 32, "ebx")
ecx = slc(rcx, 0, 32, "ecx")
edx = slc(rdx, 0, 32, "edx")
ebp = slc(rbp, 0, 32, "ebp")
esp = slc(rsp, 0, 32, "esp")
esi = slc(rsi, 0, 32, "esi")
edi = slc(rdi, 0, 32, "edi")
eflags = slc(rflags, 0, 32, "eflags")
is_reg_flags(eflags)
ax = slc(rax, 0, 16, "ax")
bx = slc(rbx, 0, 16, "bx")
cx = slc(rcx, 0, 16, "cx")
dx = slc(rdx, 0, 16, "dx")
bp = slc(rbp, 0, 16, "bp")
sp = slc(rsp, 0, 16, "sp")
si = slc(rsi, 0, 16, "si")
di = slc(rdi, 0, 16, "di")

al = slc(rax, 0, 8, "al")
bl = slc(rbx, 0, 8, "bl")
cl = slc(rcx, 0, 8, "cl")
dl = slc(rdx, 0, 8, "dl")

spl = slc(rsp, 0, 8, "spl")
bpl = slc(rbp, 0, 8, "bpl")
sil = slc(rsi, 0, 8, "sil")
dil = slc(rdi, 0, 8, "dil")

ah = slc(rax, 8, 8, "ah")
bh = slc(rbx, 8, 8, "bh")
ch = slc(rcx, 8, 8, "ch")
dh = slc(rdx, 8, 8, "dh")

cf = slc(rflags, 0, 1, "cf")  # carry/borrow flag
pf = slc(rflags, 2, 1, "pf")  # parity flag
af = slc(rflags, 4, 1, "af")  # aux carry flag
zf = slc(rflags, 6, 1, "zf")  # zero flag
sf = slc(rflags, 7, 1, "sf")  # sign flag
df = slc(rflags, 10, 1, "df")  # direction flag
of = slc(rflags, 11, 1, "of")  # overflow flag

with is_reg_other:
    # segment registers & other mappings:
    cs = reg("cs", 16)  # segment selector for the code segment
    ds = reg("ds", 16)  # segment selector to a data segment
    ss = reg("ss", 16)  # segment selector to the stack segment
    es = reg("es", 16)  # (data)
    fs = reg("fs", 16)  # (data)
    gs = reg("gs", 16)  # (data)
    mmregs = [reg("mm%d" % n, 64) for n in range(16)]
    xmmregs = [reg("xmm%d" % n, 128) for n in range(16)]
    ymmregs = [reg("ymm%d" % n, 256) for n in range(16)]

r8 = reg("r8", 64)
r8d = slc(r8, 0, 32, "r8d")
r8w = slc(r8, 0, 16, "r8w")
r8l = slc(r8, 0, 8, "r8l")
r9 = reg("r9", 64)
r9d = slc(r9, 0, 32, "r9d")
r9w = slc(r9, 0, 16, "r9w")
r9l = slc(r9, 0, 8, "r9l")
r10 = reg("r10", 64)
r10d = slc(r10, 0, 32, "r10d")
r10w = slc(r10, 0, 16, "r10w")
r10l = slc(r10, 0, 8, "r10l")
r11 = reg("r11", 64)
r11d = slc(r11, 0, 32, "r11d")
r11w = slc(r11, 0, 16, "r11w")
r11l = slc(r11, 0, 8, "r11l")
r12 = reg("r12", 64)
r12d = slc(r12, 0, 32, "r12d")
r12w = slc(r12, 0, 16, "r12w")
r12l = slc(r12, 0, 8, "r12l")
r13 = reg("r13", 64)
r13d = slc(r13, 0, 32, "r13d")
r13w = slc(r13, 0, 16, "r13w")
r13l = slc(r13, 0, 8, "r13l")
r14 = reg("r14", 64)
r14d = slc(r14, 0, 32, "r14d")
r14w = slc(r14, 0, 16, "r14w")
r14l = slc(r14, 0, 8, "r14l")
r15 = reg("r15", 64)
r15d = slc(r15, 0, 32, "r15d")
r15w = slc(r15, 0, 16, "r15w")
r15l = slc(r15, 0, 8, "r15l")


# return R/M register (see ModR/M Byte encoding) :
def getreg(i, size=32):
    return {
        8: (
            al,
            cl,
            dl,
            bl,
            spl,
            bpl,
            sil,
            dil,
            r8l,
            r9l,
            r10l,
            r11l,
            r12l,
            r13l,
            r14l,
            r15l,
        ),
        16: (
            ax,
            cx,
            dx,
            bx,
            sp,
            bp,
            si,
            di,
            r8w,
            r9w,
            r10w,
            r11w,
            r12w,
            r13w,
            r14w,
            r15w,
        ),
        32: (
            eax,
            ecx,
            edx,
            ebx,
            esp,
            ebp,
            esi,
            edi,
            r8d,
            r9d,
            r10d,
            r11d,
            r12d,
            r13d,
            r14d,
            r15d,
        ),
        64: (
            rax,
            rcx,
            rdx,
            rbx,
            rsp,
            rbp,
            rsi,
            rdi,
            r8,
            r9,
            r10,
            r11,
            r12,
            r13,
            r14,
            r15,
        ),
        "mm": mmregs,
        128: xmmregs,
        256: ymmregs,
    }[size][i]


# fpu registers (80 bits holds double extended floats see Intel Vol1--4.4.2):
def st(num):
    return is_reg_other(reg("st%d" % num, 80))


# fpu state
fpu_control = reg("fpu_control", 16)
fpu_status = reg("fpu_status", 16)


def cr(num):
    return is_reg_other(reg("cr%d" % num, 64))


def dr(num):
    return is_reg_other(reg("dr%d" % num, 64))


internals = {"mode": 64}

registers = [
    rax,
    rcx,
    rdx,
    rbx,
    rsp,
    rbp,
    rsi,
    rdi,
    r8,
    r9,
    r10,
    r11,
    r12,
    r13,
    r14,
    r15,
    rip,
    eflags,
    cs,
    ss,
    ds,
    es,
    fs,
    gs,
]
