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

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

# import expressions:
from amoco.cas.expressions import reg, slc, cst, top, bit1
from amoco.cas.expressions import is_reg_flags, is_reg_stack, is_reg_pc

# import all (other) expressions as interface
from amoco.cas.expressions import *  # noqa: F403

# reference documentation:
# "ARM Architecture Reference Manual ARMv8, for ARMv8-A architecture profile, Errata markup (DDI0487A.a_errata_2013_Q3)

# registers (application level, see B1.3.2) :
# -------------------------------------------

r0 = reg("X0", 64)
r1 = reg("X1", 64)
r2 = reg("X2", 64)
r3 = reg("X3", 64)
r4 = reg("X4", 64)
r5 = reg("X5", 64)
r6 = reg("X6", 64)
r7 = reg("X7", 64)
r8 = reg("X8", 64)
r9 = reg("X9", 64)
r10 = reg("X10", 64)
r11 = reg("X11", 64)
r12 = reg("X12", 64)
r13 = reg("X13", 64)
r14 = reg("X14", 64)
r15 = reg("X15", 64)
r16 = reg("X16", 64)
r17 = reg("X17", 64)
r18 = reg("X18", 64)
r19 = reg("X19", 64)
r20 = reg("X20", 64)
r21 = reg("X21", 64)
r22 = reg("X22", 64)
r23 = reg("X23", 64)
r24 = reg("X24", 64)
r25 = reg("X25", 64)
r26 = reg("X26", 64)
r27 = reg("X27", 64)
r28 = reg("X28", 64)
r29 = reg("X29", 64)
r30 = reg("X30", 64)

w0 = slc(r0, 0, 32, ref="W0")
w1 = slc(r1, 0, 32, ref="W1")
w2 = slc(r2, 0, 32, ref="W2")
w3 = slc(r3, 0, 32, ref="W3")
w4 = slc(r4, 0, 32, ref="W4")
w5 = slc(r5, 0, 32, ref="W5")
w6 = slc(r6, 0, 32, ref="W6")
w7 = slc(r7, 0, 32, ref="W7")
w8 = slc(r8, 0, 32, ref="W8")
w9 = slc(r9, 0, 32, ref="W9")
w10 = slc(r10, 0, 32, ref="W10")
w11 = slc(r11, 0, 32, ref="W11")
w12 = slc(r12, 0, 32, ref="W12")
w13 = slc(r13, 0, 32, ref="W13")
w14 = slc(r14, 0, 32, ref="W14")
w15 = slc(r15, 0, 32, ref="W15")
w16 = slc(r16, 0, 32, ref="W16")
w17 = slc(r17, 0, 32, ref="W17")
w18 = slc(r18, 0, 32, ref="W18")
w19 = slc(r19, 0, 32, ref="W19")
w20 = slc(r20, 0, 32, ref="W20")
w21 = slc(r21, 0, 32, ref="W21")
w22 = slc(r22, 0, 32, ref="W22")
w23 = slc(r23, 0, 32, ref="W23")
w24 = slc(r24, 0, 32, ref="W24")
w25 = slc(r25, 0, 32, ref="W25")
w26 = slc(r26, 0, 32, ref="W26")
w27 = slc(r27, 0, 32, ref="W27")
w28 = slc(r28, 0, 32, ref="W28")
w29 = slc(r29, 0, 32, ref="W29")
w30 = slc(r30, 0, 32, ref="W30")

xzr = cst(0, 64)
wzr = cst(0, 32)

sp = reg("SP", 64)
wsp = slc(sp, 0, 32, ref="WSP")

# lr = r30 ; lr.ref='LR'    # link register (return address)

pc = reg("PC", 64)

pstate = reg("pstate", 64)  # in current program status register

N = slc(pstate, 31, 1, ref="N")   # negative result from ALU
Z = slc(pstate, 30, 1, ref="Z")   # zero flag
C = slc(pstate, 29, 1, ref="C")   # carry flag
V = slc(pstate, 28, 1, ref="V")   # overflow flag

SS    = slc(pstate, 21, 1, ref="SS") # software step
IL    = slc(pstate, 20, 1, ref="IL") # illegal execution state
SPSel = slc(pstate, 12, 1, ref="SPSel")

D = slc(pstate,  9, 1, ref="D")   # debug mask
A = slc(pstate,  8, 1, ref="A")   # SError mask
I = slc(pstate,  7, 1, ref="I")   # IRQ mask
F = slc(pstate,  6, 1, ref="F")   # FIQ mask
M = slc(pstate,  0, 5, ref="M")   # execution mode

is_reg_flags(pstate)
is_reg_stack(sp)
is_reg_pc(pc)

#exception-specific special regs:
sp_el0 = reg("SP_EL0", 64)
sp_el1 = reg("SP_EL1", 64)
sp_el2 = reg("SP_EL2", 64)
sp_el3 = reg("SP_EL3", 64)
elr_el1 = reg("ELR_EL1", 64)
elr_el2 = reg("ELR_EL2", 64)
elr_el3 = reg("ELR_EL3", 64)
spsr_el1 = reg("SPSR_EL1", 64)
spsr_el2 = reg("SPSR_EL2", 64)
spsr_el3 = reg("SPSR_EL3", 64)

Xregs = [
    r0,
    r1,
    r2,
    r3,
    r4,
    r5,
    r6,
    r7,
    r8,
    r9,
    r10,
    r11,
    r12,
    r13,
    r14,
    r15,
    r16,
    r17,
    r18,
    r19,
    r20,
    r21,
    r22,
    r23,
    r24,
    r25,
    r26,
    r27,
    r28,
    r29,
    r30,
    sp,
]
Wregs = [
    w0,
    w1,
    w2,
    w3,
    w4,
    w5,
    w6,
    w7,
    w8,
    w9,
    w10,
    w11,
    w12,
    w13,
    w14,
    w15,
    w16,
    w17,
    w18,
    w19,
    w20,
    w21,
    w22,
    w23,
    w24,
    w25,
    w26,
    w27,
    w28,
    w29,
    w30,
    wsp,
]

CONDITION_EQ = 0x0  # ==
CONDITION_NE = 0x1  # !=
CONDITION_CS = 0x2  # >= (unsigned)
CONDITION_CC = 0x3  # <  (unsigned)
CONDITION_MI = 0x4  # <0
CONDITION_PL = 0x5  # >=0
CONDITION_VS = 0x6  # overflow
CONDITION_VC = 0x7  # no overflow
CONDITION_HI = 0x8  # >  (unsigned)
CONDITION_LS = 0x9  # <= (unsigned)
CONDITION_GE = 0xA  # >= (signed)
CONDITION_LT = 0xB  # <  (signed)
CONDITION_GT = 0xC  # >  (signed)
CONDITION_LE = 0xD  # <= (signed)
CONDITION_AL = 0xE  # always
CONDITION_UNDEFINED = 0xF

CONDITION = {
    CONDITION_EQ: ("eq", Z == 1),  # ==
    CONDITION_NE: ("ne", Z == 0),  # !=
    CONDITION_CS: ("cs", C == 1),  # >= (unsigned)
    CONDITION_CC: ("cc", C == 0),  # <  (unsigned)
    CONDITION_MI: ("mi", N == 1),  # <0
    CONDITION_PL: ("pl", N == 0),  # >=0
    CONDITION_VS: ("vs", V == 1),  # overflow
    CONDITION_VC: ("vc", V == 0),  # no overflow
    CONDITION_HI: ("hi", (C == 1) & (Z == 0)),  # >  (unsigned)
    CONDITION_LS: ("ls", (C == 0) | (Z == 1)),  # <= (unsigned)
    CONDITION_GE: ("ge", (N == V)),  # >= (signed)
    CONDITION_LT: ("lt", (N != V)),  # <  (signed)
    CONDITION_GT: ("gt", (Z == 0) & (N == V)),  # >  (signed)
    CONDITION_LE: ("le", (Z == 1) | (N != V)),  # <= (signed)
    CONDITION_AL: ("  ", bit1),  # always
    CONDITION_UNDEFINED: ("??", top(1)),
}


# internal states not exposed to symbolic interpreter:
# -----------------------------------------------------
internals = {  # states MUST be in a mutable object !
    "endianstate": 0,  # 0: little-endian, 1: big-endian
    "ibigend": 0,  # instruction endianess: 0:LE, 1:BE
}

# SIMD and VFP (floating point) extensions:

Vregs = [reg("V%d"%i,128) for i in range(32)]

# Coprocessor (CPxx) support:
# NOT IMPLEMENTED

registers = Xregs + [sp, pc, pstate]
