about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--miasm2/arch/aarch64/__init__.py1
-rw-r--r--miasm2/arch/aarch64/arch.py1944
-rw-r--r--miasm2/arch/aarch64/disasm.py27
-rw-r--r--miasm2/arch/aarch64/ira.py95
-rw-r--r--miasm2/arch/aarch64/jit.py73
-rw-r--r--miasm2/arch/aarch64/regs.py124
-rw-r--r--miasm2/arch/aarch64/sem.py740
-rw-r--r--miasm2/jitter/arch/JitCore_aarch64.c699
-rw-r--r--miasm2/jitter/arch/JitCore_aarch64.h196
9 files changed, 3899 insertions, 0 deletions
diff --git a/miasm2/arch/aarch64/__init__.py b/miasm2/arch/aarch64/__init__.py
new file mode 100644
index 00000000..bbad893b
--- /dev/null
+++ b/miasm2/arch/aarch64/__init__.py
@@ -0,0 +1 @@
+__all__ = ["arch", "disasm", "regs", "sem"]
diff --git a/miasm2/arch/aarch64/arch.py b/miasm2/arch/aarch64/arch.py
new file mode 100644
index 00000000..b991fe81
--- /dev/null
+++ b/miasm2/arch/aarch64/arch.py
@@ -0,0 +1,1944 @@
+#!/usr/bin/env python
+#-*- coding:utf-8 -*-
+
+import logging
+from pyparsing import *
+from miasm2.expression import expression as m2_expr
+from miasm2.core.cpu import *
+from collections import defaultdict
+from miasm2.core.bin_stream import bin_stream
+import regs as regs_module
+from regs import *
+from miasm2.core.asmbloc import asm_label
+from miasm2.core.cpu import log as log_cpu
+from miasm2.expression.modint import uint32, uint64
+import math
+
+log = logging.getLogger("aarch64dis")
+console_handler = logging.StreamHandler()
+console_handler.setFormatter(logging.Formatter("%(levelname)-5s: %(message)s"))
+log.addHandler(console_handler)
+log.setLevel(logging.DEBUG)
+
+# refs from A_e_armv8_arm.pdf
+
+# log_cpu.setLevel(logging.DEBUG)
+
+
+replace_regs = {
+    W0: X0[:32],
+    W1: X1[:32],
+    W2: X2[:32],
+    W3: X3[:32],
+    W4: X4[:32],
+    W5: X5[:32],
+    W6: X6[:32],
+    W7: X7[:32],
+    W8: X8[:32],
+    W9: X9[:32],
+
+    W10: X10[:32],
+    W11: X11[:32],
+    W12: X12[:32],
+    W13: X13[:32],
+    W14: X14[:32],
+    W15: X15[:32],
+    W16: X16[:32],
+    W17: X17[:32],
+    W18: X18[:32],
+    W19: X19[:32],
+
+    W20: X20[:32],
+    W21: X21[:32],
+    W22: X22[:32],
+    W23: X23[:32],
+    W24: X24[:32],
+    W25: X25[:32],
+    W26: X26[:32],
+    W27: X27[:32],
+    W28: X28[:32],
+    W29: X29[:32],
+
+    W30: LR[:32],
+
+    WSP: SP[:32],
+
+    WZR: m2_expr.ExprInt32(0),
+    XZR: m2_expr.ExprInt64(0),
+
+}
+
+
+variable, operand, base_expr = gen_base_expr()
+_, _, base_expr32 = gen_base_expr()
+_, _, base_expr64 = gen_base_expr()
+
+
+def ast_id2expr32(t):
+    if not t in mn_aarch64.regs.all_regs_ids_byname:
+        r = m2_expr.ExprId(asm_label(t))
+    else:
+        r = mn_aarch64.regs.all_regs_ids_byname[t]
+    if not r.size == 32:
+        raise StopIteration
+    return r
+
+
+def ast_int2expr32(a):
+    return m2_expr.ExprInt32(a)
+
+
+def ast_id2expr64(t):
+    if not t in mn_aarch64.regs.all_regs_ids_byname:
+        r = m2_expr.ExprId(asm_label(t))
+    else:
+        r = mn_aarch64.regs.all_regs_ids_byname[t]
+    if not r.size == 64:
+        raise StopIteration
+    return r
+
+
+def ast_int2expr64(a):
+    return m2_expr.ExprInt64(a)
+
+my_var_parser32 = parse_ast(ast_id2expr32, ast_int2expr32)
+my_var_parser64 = parse_ast(ast_id2expr64, ast_int2expr64)
+
+base_expr32.setParseAction(my_var_parser32)
+base_expr64.setParseAction(my_var_parser64)
+
+
+int_or_expr = base_expr
+int_or_expr32 = base_expr32
+int_or_expr64 = base_expr64
+
+
+shift2expr_dct = {'LSL': '<<', 'LSR': '>>', 'ASR': 'a>>', 'ROR': '>>>'}
+shift_str = ["LSL", "LSR", "ASR", "ROR"]
+shift_expr = ["<<", ">>", "a>>", '>>>']
+
+
+def op_shift2expr(s, l, t):
+    return shift2expr_dct[t[0]]
+
+
+def op_shift2expr_slice_at(s, l, t):
+    return "slice_at"
+
+
+def op_ext_reg(s, l, t):
+    return t[0]
+
+
+def shift2expr(t):
+    if len(t) == 1:
+        return t[0]
+    elif len(t) == 3:
+        if t[0].size == 32 and isinstance(t[2], m2_expr.ExprInt):
+            t[2] = m2_expr.ExprInt32(t[2].arg)
+        return m2_expr.ExprOp(t[1], t[0], t[2])
+    else:
+        raise ValueError('bad string')
+
+
+def shift2expr_sc(t):
+    if len(t) == 1:
+        return t[0]
+    elif len(t) == 3:
+        if t[0].size == 32 and isinstance(t[2], m2_expr.ExprInt):
+            t[2] = m2_expr.ExprInt32(t[2].arg)
+        if t[1] != '<<':
+            raise ValueError('bad op')
+        return m2_expr.ExprOp("slice_at", t[0], t[2])
+    else:
+        raise ValueError('bad string')
+
+
+def extend2expr(t):
+    if len(t) == 1:
+        return t[0]
+    return m2_expr.ExprOp(t[1], t[0], t[2])
+
+
+def shiftext2expr(t):
+    if len(t) == 1:
+        return t[0]
+    else:
+        return m2_expr.ExprOp(t[1], t[0], t[2])
+
+all_binaryop_lsl_t = literal_list(
+    shift_str).setParseAction(op_shift2expr)
+
+all_binaryop_shiftleft_t = literal_list(
+    ["LSL"]).setParseAction(op_shift2expr)
+
+extend_lst = ['UXTB', 'UXTH', 'UXTW', 'UXTX', 'SXTB', 'SXTH', 'SXTW', 'SXTX']
+extend2_lst = ['UXTW', 'LSL', 'SXTW', 'SXTX']
+
+all_extend_t = literal_list(extend_lst).setParseAction(op_ext_reg)
+all_extend2_t = literal_list(extend2_lst).setParseAction(op_ext_reg)
+
+
+gpreg32_extend = (gpregs32_info.parser + Optional(
+    all_extend_t + int_or_expr32)).setParseAction(extend2expr)
+gpreg64_extend = (gpregs64_info.parser + Optional(
+    all_extend_t + int_or_expr64)).setParseAction(extend2expr)
+
+
+shift32_off = (gpregsz32_info.parser + Optional(all_binaryop_lsl_t +
+               (gpregs32_info.parser | int_or_expr))).setParseAction(shift2expr)
+shift64_off = (gpregsz64_info.parser + Optional(all_binaryop_lsl_t +
+               (gpregs64_info.parser | int_or_expr))).setParseAction(shift2expr)
+
+
+shiftimm_imm_sc = (int_or_expr + all_binaryop_shiftleft_t +
+                   int_or_expr).setParseAction(shift2expr_sc)
+
+shiftimm_off_sc = shiftimm_imm_sc | int_or_expr
+
+
+shift_off = (shift32_off | shift64_off)
+reg_ext_off = (gpreg32_extend | gpreg64_extend)
+
+gpregs_32_64 = (gpregs32_info.parser | gpregs64_info.parser)
+gpregsz_32_64 = (gpregsz32_info.parser | gpregsz64_info.parser | int_or_expr)
+
+simdregs = (simd08_info.parser | simd16_info.parser |
+            simd32_info.parser | simd64_info.parser)
+simdregs_h = (simd32_info.parser | simd64_info.parser | simd128_info.parser)
+
+simdregs_h_zero = (simd32_info.parser |
+                   simd64_info.parser | simd128_info.parser | int_or_expr)
+
+
+def ast_id2expr(t):
+    if not t in mn_aarch64.regs.all_regs_ids_byname:
+        r = m2_expr.ExprId(asm_label(t))
+    else:
+        r = mn_aarch64.regs.all_regs_ids_byname[t]
+    return r
+
+
+def ast_int2expr(a):
+    return m2_expr.ExprInt64(a)
+
+gpregs_info = {32: gpregs32_info,
+               64: gpregs64_info}
+gpregsz_info = {32: gpregsz32_info,
+                64: gpregsz64_info}
+
+
+simds_info = {8: simd08_info,
+              16: simd16_info,
+              32: simd32_info,
+              64: simd64_info,
+              128: simd128_info}
+
+
+my_var_parser = parse_ast(ast_id2expr, ast_int2expr)
+base_expr.setParseAction(my_var_parser)
+
+
+def deref2expr_nooff(t):
+    t = t[0]
+    # XXX default
+    return m2_expr.ExprOp("preinc", t[0], m2_expr.ExprInt64(0))
+
+
+def deref2expr_post(t):
+    t = t[0]
+    if t[1] in regs_module.all_regs_ids:
+        raise StopIteration
+    return m2_expr.ExprOp("postinc", t[0], t[1])
+
+
+def deref2expr_pre(t):
+    t = t[0]
+    if t[1] in regs_module.all_regs_ids:
+        raise StopIteration
+    return m2_expr.ExprOp("preinc", t[0], t[1])
+
+
+def deref2expr_pre_wb(t):
+    t = t[0]
+    if t[1] in regs_module.all_regs_ids:
+        raise StopIteration
+    return m2_expr.ExprOp("preinc_wb", t[0], t[1])
+
+LBRACK = Suppress("[")
+RBRACK = Suppress("]")
+COMMA = Suppress(",")
+POSTINC = Suppress("!")
+
+deref_nooff = Group(
+    LBRACK + gpregs64_info.parser + RBRACK).setParseAction(deref2expr_nooff)
+deref_off_post = Group(LBRACK + gpregs64_info.parser +
+                       RBRACK + COMMA + int_or_expr64).setParseAction(deref2expr_post)
+deref_off_pre = Group(LBRACK + gpregs64_info.parser +
+                      COMMA + int_or_expr64 + RBRACK).setParseAction(deref2expr_pre)
+deref_off_pre_wb = Group(LBRACK + gpregs64_info.parser + COMMA +
+                         int_or_expr64 + RBRACK + POSTINC).setParseAction(deref2expr_pre_wb)
+
+deref = (deref_off_post | deref_off_pre_wb | deref_off_pre | deref_nooff)
+
+
+def deref_ext2op(t):
+    t = t[0]
+    if len(t) == 4:
+        expr = set_imm_to_size(t[1].size, t[3])
+        if expr is None:
+            raise StopIteration
+        return m2_expr.ExprOp('segm', t[0], m2_expr.ExprOp(t[2], t[1], expr))
+    elif len(t) == 2:
+        return m2_expr.ExprOp('segm', t[0], t[1])
+
+    raise ValueError("cad deref")
+
+deref_ext2 = Group(LBRACK + gpregs_32_64 + COMMA + gpregs_32_64 +
+                   Optional(all_extend2_t + int_or_expr) + RBRACK).setParseAction(deref_ext2op)
+
+
+class additional_info:
+
+    def __init__(self):
+        self.except_on_instr = False
+        self.lnk = None
+        self.cond = None
+
+CONDS = [
+    'EQ', 'NE', 'CS', 'CC',
+    'MI', 'PL', 'VS', 'VC',
+    'HI', 'LS', 'GE', 'LT',
+    'GT', 'LE', 'AL', 'NV']
+
+CONDS_INV = [
+    'NE', 'EQ', 'CC', 'CS',
+    'PL', 'MI', 'VC', 'VS',
+    'LS', 'HI', 'LT', 'GE',
+    'LE', 'GT', 'NV', 'AL']
+
+BRCOND = ['B.' + cond for cond in CONDS] + ['CBZ', 'CBNZ', 'TBZ', 'TBNZ']
+
+# for conditional selec
+conds_expr, _, conds_info = gen_regs(CONDS, {})
+conds_inv_expr, _, conds_inv_info = gen_regs(CONDS_INV, {})
+
+
+class instruction_aarch64(instruction):
+    delayslot = 0
+
+    def __init__(self, *args, **kargs):
+        super(instruction_aarch64, self).__init__(*args, **kargs)
+
+    @staticmethod
+    def arg2str(e, pos=None):
+        wb = False
+        if isinstance(e, m2_expr.ExprId) or isinstance(e, m2_expr.ExprInt):
+            return str(e)
+        elif isinstance(e, m2_expr.ExprOp) and e.op in shift_expr:
+            op_str = shift_str[shift_expr.index(e.op)]
+            return "%s %s %s" % (e.args[0], op_str, e.args[1])
+        elif isinstance(e, m2_expr.ExprOp) and e.op == "slice_at":
+            return "%s LSL %s" % (e.args[0], e.args[1])
+        elif isinstance(e, m2_expr.ExprOp) and e.op in extend_lst:
+            op_str = e.op
+            return "%s %s %s" % (e.args[0], op_str, e.args[1])
+        elif isinstance(e, m2_expr.ExprOp) and e.op == "postinc":
+            if e.args[1].arg != 0:
+                return "[%s], %s" % (e.args[0], e.args[1])
+            else:
+                return "[%s]" % (e.args[0])
+        elif isinstance(e, m2_expr.ExprOp) and e.op == "preinc_wb":
+            if e.args[1].arg != 0:
+                return "[%s, %s]!" % (e.args[0], e.args[1])
+            else:
+                return "[%s]" % (e.args[0])
+        elif isinstance(e, m2_expr.ExprOp) and e.op == "preinc":
+            if len(e.args) == 1:
+                return "[%s]" % (e.args[0])
+            elif not isinstance(e.args[1], m2_expr.ExprInt) or e.args[1].arg != 0:
+                return "[%s, %s]" % (e.args[0], e.args[1])
+            else:
+                return "[%s]" % (e.args[0])
+        elif isinstance(e, m2_expr.ExprOp) and e.op == 'segm':
+            arg = e.args[1]
+            if isinstance(arg, m2_expr.ExprId):
+                arg = str(arg)
+            elif arg.op == 'LSL' and arg.args[1].arg == 0:
+                arg = str(arg.args[0])
+            else:
+                arg = "%s %s %s" % (arg.args[0], arg.op, arg.args[1])
+            return '[%s, %s]' % (e.args[0], arg)
+
+        else:
+            raise NotImplementedError("bad op")
+
+    def dstflow(self):
+        return self.name in self.name in BRCOND + ["B", "BL"]
+
+    def mnemo_flow_to_dst_index(self, name):
+        if self.name in ['CBZ', 'CBNZ']:
+            return 1
+        elif self.name in ['TBZ', 'TBNZ']:
+            return 2
+        else:
+            return 0
+
+    def dstflow2label(self, symbol_pool):
+        index = self.mnemo_flow_to_dst_index(self.name)
+        e = self.args[index]
+        if not isinstance(e, m2_expr.ExprInt):
+            return
+        ad = e.arg + self.offset
+        l = symbol_pool.getby_offset_create(ad)
+        s = m2_expr.ExprId(l, e.size)
+        self.args[index] = s
+
+    def breakflow(self):
+        return self.name in BRCOND + ["BR", "BLR", "RET", "ERET", "DRPS", "B", "BL"]
+
+    def is_subcall(self):
+        return self.name in ["BLR", "BL"]
+
+    def getdstflow(self, symbol_pool):
+        index = self.mnemo_flow_to_dst_index(self.name)
+        return [self.args[index]]
+
+    def splitflow(self):
+        return self.name in BRCOND + ["BLR", "BL"]
+
+    def get_symbol_size(self, symbol, symbol_pool):
+        return 64
+
+    def fixDstOffset(self):
+        index = self.mnemo_flow_to_dst_index(self.name)
+        e = self.args[index]
+        if self.offset is None:
+            raise ValueError('symbol not resolved %s' % l)
+        if not isinstance(e, m2_expr.ExprInt):
+            log.debug('dyn dst %r', e)
+            return
+        off = e.arg - self.offset
+        if int(off % 4):
+            raise ValueError('strange offset! %r' % off)
+        self.args[index] = m2_expr.ExprInt32(off)
+
+
+
+class mn_aarch64(cls_mn):
+    delayslot = 0
+    name = "aarch64"
+    regs = regs_module
+    bintree = {}
+    num = 0
+    all_mn = []
+    all_mn_mode = defaultdict(list)
+    all_mn_name = defaultdict(list)
+    all_mn_inst = defaultdict(list)
+    pc = {'l': PC, 'b': PC}
+    sp = {'l': SP, 'b': SP}
+    instruction = instruction_aarch64
+    max_instruction_len = 4
+    alignment = 4
+
+    @classmethod
+    def getpc(cls, attrib=None):
+        return PC
+
+    @classmethod
+    def getsp(cls, attrib=None):
+        return SP
+
+    def additional_info(self):
+        info = additional_info()
+        info.lnk = False
+        if hasattr(self, "lnk"):
+            info.lnk = self.lnk.value != 0
+        return info
+
+    @classmethod
+    def getbits(cls, bs, attrib, start, n):
+        if not n:
+            return 0
+        o = 0
+        if n > bs.getlen() * 8:
+            raise ValueError('not enought bits %r %r' % (n, len(bs.bin) * 8))
+        while n:
+            offset = start / 8
+            n_offset = cls.endian_offset(attrib, offset)
+            c = cls.getbytes(bs, n_offset, 1)
+            if not c:
+                raise IOError
+            c = ord(c)
+            r = 8 - start % 8
+            c &= (1 << r) - 1
+            l = min(r, n)
+            c >>= (r - l)
+            o <<= l
+            o |= c
+            n -= l
+            start += l
+        return o
+
+    @classmethod
+    def endian_offset(cls, attrib, offset):
+        if attrib == "l":
+            return (offset & ~3) + 3 - offset % 4
+        elif attrib == "b":
+            return offset
+        else:
+            raise NotImplementedError('bad attrib')
+
+    @classmethod
+    def check_mnemo(cls, fields):
+        l = sum([x.l for x in fields])
+        assert l == 32, "len %r" % l
+
+    @classmethod
+    def getmn(cls, name):
+        return name.upper()
+
+    @classmethod
+    def mod_fields(cls, fields):
+        l = sum([x.l for x in fields])
+        if l == 32:
+            return fields
+        return fields
+
+    @classmethod
+    def gen_modes(cls, subcls, name, bases, dct, fields):
+        dct['mode'] = None
+        return [(subcls, name, bases, dct, fields)]
+
+    def value(self, mode):
+        v = super(mn_aarch64, self).value(mode)
+        if mode == 'l':
+            return [x[::-1] for x in v]
+        elif mode == 'b':
+            return [x for x in v]
+        else:
+            raise NotImplementedError('bad attrib')
+
+    def get_symbol_size(self, symbol, symbol_pool, mode):
+        return 32
+
+    def reset_class(self):
+        super(mn_aarch64, self).reset_class()
+        if hasattr(self, "sf"):
+            self.sf.value = None
+
+
+def aarch64op(name, fields, args=None, alias=False):
+    dct = {"fields": fields, "alias":alias}
+    if args is not None:
+        dct['args'] = args
+    type(name, (mn_aarch64,), dct)
+
+
+class aarch64_gpreg_noarg(reg_noarg):
+    parser = gpregs_32_64
+    gpregs_info = gpregs_info
+
+    def decode(self, v):
+        size = 64 if self.parent.sf.value else 32
+        self.expr = self.gpregs_info[size].expr[v]
+        return True
+
+    def encode(self):
+        if not test_set_sf(self.parent, self.expr.size):
+            return False
+        if not self.expr.size in self.gpregs_info:
+            return False
+        if not self.expr in self.gpregs_info[self.expr.size].expr:
+            return False
+        self.value = self.gpregs_info[self.expr.size].expr.index(self.expr)
+        return True
+
+
+class aarch64_simdreg(reg_noarg, m_arg):
+    parser = simdregs
+    simd_size = [8, 16, 32, 64]
+
+    def decode(self, v):
+        if self.parent.size.value > len(self.simd_size):
+            return False
+        size = self.simd_size[self.parent.size.value]
+        self.expr = simds_info[size].expr[v]
+        return True
+
+    def encode(self):
+        if not self.expr.size in self.simd_size:
+            return False
+        if not self.expr in simds_info[self.expr.size].expr:
+            return False
+        self.value = simds_info[self.expr.size].expr.index(self.expr)
+        self.parent.size.value = self.simd_size.index(self.expr.size)
+        return True
+
+
+class aarch64_simdreg_h(aarch64_simdreg):
+    parser = simdregs_h
+    simd_size = [32, 64, 128]
+
+
+class aarch64_simdreg_32_64(aarch64_simdreg):
+    parser = simdregs_h
+    simd_size = [32, 64]
+
+
+class aarch64_simdreg_32_64_zero(aarch64_simdreg_32_64):
+    parser = simdregs_h_zero
+
+    def decode(self, v):
+        if v == 0 and self.parent.opc.value == 1:
+            size = 64 if self.parent.size.value else 32
+            self.expr = m2_expr.ExprInt_fromsize(size, 0)
+            return True
+        else:
+            return super(aarch64_simdreg_32_64_zero, self).decode(v)
+
+    def encode(self):
+        if isinstance(self.expr, m2_expr.ExprInt):
+            self.parent.opc.value = 1
+            self.value = 0
+            return True
+        else:
+            self.parent.opc.value = 0
+            return super(aarch64_simdreg_32_64_zero, self).encode()
+
+
+class aarch64_gpreg_isf(reg_noarg, m_arg):
+    parser = gpregs_32_64
+
+    def decode(self, v):
+        size = 32 if self.parent.sf.value else 64
+        self.expr = gpregs_info[size].expr[v]
+        return True
+
+    def encode(self):
+        if not self.expr in gpregs_info[self.expr.size].expr:
+            return False
+        self.value = gpregs_info[self.expr.size].expr.index(self.expr)
+        self.parent.sf.value = 1 if self.expr.size == 32 else 0
+        return True
+
+
+class aarch64_gpreg(aarch64_gpreg_noarg, m_arg):
+    pass
+
+
+class aarch64_gpreg_n1(aarch64_gpreg):
+
+    def decode(self, v):
+        if v == 0b11111:
+            return False
+        return super(aarch64_gpreg_n1, self).decode(v)
+
+    def encode(self):
+        super(aarch64_gpreg_n1, self).encode()
+        return self.value != 0b11111
+
+
+class aarch64_gpregz(aarch64_gpreg_noarg, m_arg):
+    parser = gpregsz_32_64
+    gpregs_info = gpregsz_info
+
+
+class aarch64_gpreg0(bsi, m_arg):
+    parser = gpregsz_32_64
+    gpregs_info = gpregsz_info
+
+    def decode(self, v):
+        size = 64 if self.parent.sf.value else 32
+        if v == 0x1F:
+            self.expr = m2_expr.ExprInt_fromsize(size, 0)
+        else:
+            self.expr = self.gpregs_info[size].expr[v]
+        return True
+
+    def encode(self):
+        if isinstance(self.expr, m2_expr.ExprInt):
+            if self.expr.arg == 0:
+                self.value = 0x1F
+                return True
+            return False
+        if not self.expr.size in self.gpregs_info:
+            return False
+        if not test_set_sf(self.parent, self.expr.size):
+            return False
+        if not self.expr in self.gpregs_info[self.expr.size].expr:
+            return False
+        self.value = self.gpregs_info[self.expr.size].expr.index(self.expr)
+        return True
+
+
+class aarch64_crreg(reg_noarg, m_arg):
+    reg_info = cr_info
+    parser = reg_info.parser
+
+
+class aarch64_gpreg32_nodec(bsi):
+    reg_info = gpregs32_info
+
+
+class aarch64_gpreg64_nodec(bsi):
+    reg_info = gpregs64_info
+
+
+class aarch64_gpreg32_noarg(reg_noarg):
+    reg_info = gpregs32_info
+    parser = reg_info.parser
+
+
+class aarch64_gpreg32(aarch64_gpreg32_noarg, m_arg):
+    reg_info = gpregs32_info
+    parser = reg_info.parser
+
+
+class aarch64_gpreg64_noarg(reg_noarg):
+    reg_info = gpregs64_info
+    parser = reg_info.parser
+
+
+class aarch64_gpreg64(reg_noarg, m_arg):
+    reg_info = gpregs64_info
+    parser = reg_info.parser
+
+
+class aarch64_gpregz32_noarg(reg_noarg):
+    reg_info = gpregsz32_info
+    parser = reg_info.parser
+
+
+class aarch64_gpregz32(aarch64_gpreg32_noarg, m_arg):
+    reg_info = gpregsz32_info
+    parser = reg_info.parser
+
+
+class aarch64_gpregz64_noarg(reg_noarg):
+    reg_info = gpregsz64_info
+    parser = reg_info.parser
+
+
+class aarch64_gpregz64(reg_noarg, m_arg):
+    reg_info = gpregsz64_info
+    parser = reg_info.parser
+
+
+class aarch64_simd08_noarg(reg_noarg):
+    reg_info = simd08_info
+    parser = reg_info.parser
+
+
+class aarch64_simd08(aarch64_simd08_noarg, m_arg):
+    reg_info = simd08_info
+    parser = reg_info.parser
+
+
+class aarch64_simd16_noarg(reg_noarg):
+    reg_info = simd16_info
+    parser = reg_info.parser
+
+
+class aarch64_simd16(aarch64_simd16_noarg, m_arg):
+    reg_info = simd16_info
+    parser = reg_info.parser
+
+
+class aarch64_simd32_noarg(reg_noarg):
+    reg_info = simd32_info
+    parser = reg_info.parser
+
+
+class aarch64_simd32(aarch64_simd32_noarg, m_arg):
+    reg_info = simd32_info
+    parser = reg_info.parser
+
+
+class aarch64_simd64_noarg(reg_noarg):
+    reg_info = simd64_info
+    parser = reg_info.parser
+
+
+class aarch64_simd64(aarch64_simd64_noarg, m_arg):
+    reg_info = simd64_info
+    parser = reg_info.parser
+
+
+class aarch64_simd128_noarg(reg_noarg):
+    reg_info = simd128_info
+    parser = reg_info.parser
+
+
+class aarch64_simd128(aarch64_simd128_noarg, m_arg):
+    reg_info = simd128_info
+    parser = reg_info.parser
+
+
+class aarch64_imm_32(imm_noarg, m_arg):
+    parser = base_expr
+
+
+class aarch64_imm_64(aarch64_imm_32):
+    parser = base_expr
+
+
+class aarch64_int64_noarg(int32_noarg):
+    parser = base_expr
+    intsize = 64
+    intmask = (1 << intsize) - 1
+    int2expr = lambda self, x: m2_expr.ExprInt64(
+        sign_ext(x, self.l, self.intsize))
+
+
+class aarch64_uint64_noarg(imm_noarg):
+    parser = base_expr
+    intsize = 64
+    intmask = (1 << intsize) - 1
+    int2expr = lambda self, x: m2_expr.ExprInt64(x)
+
+
+class aarch64_uint64(aarch64_uint64_noarg, m_arg):
+    parser = base_expr
+
+
+def set_imm_to_size(size, expr):
+    if size == expr.size:
+        return expr
+    if size > expr.size:
+        expr = m2_expr.ExprInt_fromsize(size, expr.arg)
+    else:
+        if expr.arg > (1 << size) - 1:
+            return None
+        expr = m2_expr.ExprInt_fromsize(size, expr.arg)
+    return expr
+
+
+class aarch64_imm_sf(imm_noarg):
+    parser = base_expr
+
+    def fromstring(self, s, parser_result=None):
+        start, stop = super(aarch64_imm_sf, self).fromstring(s, parser_result)
+        if start is None:
+            return start, stop
+        size = self.parent.args[0].expr.size
+        if self.expr in gpregs64_info.expr + gpregs32_info.expr:
+            return None, None
+        if isinstance(self.expr, m2_expr.ExprOp):
+            return False
+        expr = set_imm_to_size(size, self.expr)
+        if expr is None:
+            return None, None
+        self.expr = expr
+        return start, stop
+
+    def encode(self):
+        if not isinstance(self.expr, m2_expr.ExprInt):
+            return False
+        if not test_set_sf(self.parent, self.expr.size):
+            return False
+        value = int(self.expr.arg)
+        if value >= 1 << self.l:
+            return False
+        self.value = value
+        return True
+
+    def decode(self, v):
+        size = 64 if self.parent.sf.value else 32
+        self.expr = m2_expr.ExprInt_fromsize(size, v)
+        return True
+
+
+class aarch64_imm_sft(aarch64_imm_sf, m_arg):
+
+    def encode(self):
+        if not isinstance(self.expr, m2_expr.ExprInt):
+            return False
+        if not test_set_sf(self.parent, self.expr.size):
+            return False
+        value = int(self.expr.arg)
+        if value < 1 << self.l:
+            self.parent.shift.value = 0
+        else:
+            if value & 0xFFF:
+                return False
+            value >>= 12
+            if value >= 1 << self.l:
+                return False
+            self.parent.shift.value = 1
+        self.value = value
+        return True
+
+    def decode(self, v):
+        size = 64 if self.parent.sf.value else 32
+        if self.parent.shift.value == 0:
+            self.expr = m2_expr.ExprInt_fromsize(size, v)
+        elif self.parent.shift.value == 1:
+            self.expr = m2_expr.ExprInt_fromsize(size, v << 12)
+        else:
+            return False
+        return True
+
+OPTION2SIZE = [32, 32, 32, 64,
+               32, 32, 32, 64]
+
+
+class aarch64_gpreg_ext(reg_noarg, m_arg):
+    parser = reg_ext_off
+
+    def encode(self):
+        if not isinstance(self.expr, m2_expr.ExprOp):
+            return False
+        if self.expr.op not in extend_lst:
+            return False
+        reg, amount = self.expr.args
+
+        if not reg in gpregs_info[self.expr.size].expr:
+            return False
+        self.value = gpregs_info[self.expr.size].expr.index(reg)
+        option = extend_lst.index(self.expr.op)
+        if self.expr.size != OPTION2SIZE[option]:
+            if not test_set_sf(self.parent, self.expr.size):
+                return False
+        self.parent.option.value = option
+        self.parent.imm.value = int(amount.arg)
+        return True
+
+    def decode(self, v):
+        if self.parent.sf.value == 0:
+            size = 64 if self.parent.sf.value else 32
+        else:
+            size = OPTION2SIZE[self.parent.option.value]
+        reg = gpregs_info[size].expr[v]
+
+        self.expr = m2_expr.ExprOp(extend_lst[self.parent.option.value],
+                           reg, m2_expr.ExprInt_from(reg, self.parent.imm.value))
+        return True
+
+EXT2_OP = {0b010: 'UXTW',
+           0b011: 'LSL',
+           0b110: 'SXTW',
+           0b111: 'SXTX'}
+EXT2_OP_INV = dict([(items[1], items[0]) for items in EXT2_OP.items()])
+
+
+class aarch64_gpreg_ext2(reg_noarg, m_arg):
+    parser = deref_ext2
+
+    def get_size(self):
+        return self.parent.size.value
+
+    def encode(self):
+        print "DECODE", self.expr
+        if not isinstance(self.expr, m2_expr.ExprOp):
+            return False
+        arg0, arg1 = self.expr.args
+        if not (isinstance(self.expr, m2_expr.ExprOp) and self.expr.op == 'segm'):
+            return False
+        print 'OKI'
+        if not arg0 in self.parent.rn.reg_info.expr:
+            return False
+        self.parent.rn.value = self.parent.rn.reg_info.expr.index(arg0)
+        print 'tt', arg0
+        is_reg = False
+        self.parent.shift.value = 0
+        if isinstance(arg1, m2_expr.ExprId):
+            reg = arg1
+            self.parent.option.value = 0b011
+            is_reg = True
+        elif isinstance(arg1, m2_expr.ExprOp) and arg1.op in EXT2_OP.values():
+            reg = arg1.args[0]
+        else:
+            return False
+        print 'ISR', is_reg
+        if not (reg.size in gpregs_info and
+                reg in gpregs_info[reg.size].expr):
+            return False
+        self.value = gpregs_info[reg.size].expr.index(reg)
+        if is_reg:
+            return True
+        print 'test int', arg1.args
+        if not (isinstance(arg1.args[1], m2_expr.ExprInt)):
+            return False
+        if arg1.op not in EXT2_OP_INV:
+            return False
+        self.parent.option.value = EXT2_OP_INV[arg1.op]
+        if arg1.args[1].arg == 0:
+            self.parent.shift.value = 0
+            return True
+
+        if arg1.args[1].arg != self.get_size():
+            return False
+        print "RR", arg1.args[1].arg
+
+        self.parent.shift.value = 1
+
+        return True
+
+    def decode(self, v):
+        opt = self.parent.option.value
+        if opt in [0, 1, 4, 5]:
+            return False
+        elif opt in [2, 6]:
+            reg_expr = gpregs32_info.expr
+        elif opt in [3, 7]:
+            reg_expr = gpregs64_info.expr
+        arg = reg_expr[v]
+
+        if opt in EXT2_OP:
+            if self.parent.shift.value == 1:
+                arg = m2_expr.ExprOp(EXT2_OP[opt], arg,
+                             m2_expr.ExprInt_from(arg, self.get_size()))
+            else:
+                arg = m2_expr.ExprOp(EXT2_OP[opt], arg,
+                             m2_expr.ExprInt_from(arg, 0))
+
+        reg = self.parent.rn.reg_info.expr[self.parent.rn.value]
+        self.expr = m2_expr.ExprOp('segm', reg, arg)
+        return True
+
+
+class aarch64_gpreg_ext2_128(aarch64_gpreg_ext2):
+
+    def get_size(self):
+        return 4
+
+
+def test_set_sf(parent, size):
+    if not hasattr(parent, 'sf'):
+        return False
+    if parent.sf.value == None:
+        parent.sf.value = 1 if size == 64 else 0
+        return True
+    psize = 64 if parent.sf.value else 32
+    return psize == size
+
+
+class aarch64_gpreg_sftimm(reg_noarg, m_arg):
+    reg_info = gpregsz_info
+    parser = shift_off
+
+    def encode(self):
+        size = self.expr.size
+        if not test_set_sf(self.parent, size):
+            return False
+        if isinstance(self.expr, m2_expr.ExprId):
+            if not size in gpregs_info:
+                return False
+            if not self.expr in self.reg_info[size].expr:
+                return False
+            self.parent.shift.value = 0
+            self.parent.imm.value = 0
+            self.value = self.reg_info[size].expr.index(self.expr)
+            return True
+
+        if not isinstance(self.expr, m2_expr.ExprOp):
+            return False
+        if not self.expr.op in shift_expr:
+            return False
+        args = self.expr.args
+        if not args[0] in self.reg_info[size].expr:
+            return False
+        if not isinstance(args[1], m2_expr.ExprInt):
+            return False
+        self.parent.shift.value = shift_expr.index(self.expr.op)
+        self.parent.imm.value = int(args[1].arg)
+        self.value = self.reg_info[size].expr.index(args[0])
+        return True
+
+    def decode(self, v):
+        size = 64 if self.parent.sf.value else 32
+        e = self.reg_info[size].expr[v]
+        amount = self.parent.imm.value
+        if amount != 0:
+            e = m2_expr.ExprOp(
+                shift_expr[self.parent.shift.value], e, m2_expr.ExprInt_from(e, amount))
+        self.expr = e
+        return True
+
+
+def ror(value, amount, size):
+    return (value >> amount) | (value << (size - amount))
+
+
+def rol(value, amount, size):
+    return (value << amount) | (value >> (size - amount))
+
+UINTS = {32: uint32, 64: uint64}
+
+
+def imm_to_imm_rot_form(value, size):
+    for i in xrange(0, size):
+        mod_value = int(rol(value, i, size))
+        if (mod_value + 1) & mod_value == 0:
+            return i
+    return None
+
+
+class aarch64_imm_nsr(aarch64_imm_sf, m_arg):
+    parser = base_expr
+
+    def decode(self, v):
+        size = 64 if self.parent.sf.value else 32
+        mask = UINTS[size]((1 << (v + 1)) - 1)
+        mask = ror(mask, self.parent.immr.value, size)
+        self.expr = m2_expr.ExprInt_fromsize(size, mask)
+        return True
+
+    def encode(self):
+        if not isinstance(self.expr, m2_expr.ExprInt):
+            return False
+        if not test_set_sf(self.parent, self.expr.size):
+            return False
+        value = self.expr.arg
+        if value == 0:
+            return False
+
+        index = imm_to_imm_rot_form(value, self.expr.size)
+        if index == None:
+            return False
+        power = int(rol(value, index, self.expr.size)) + 1
+        length = None
+        for i in xrange(self.expr.size):
+            if 1 << i == power:
+                length = i
+                break
+        if length is None:
+            return False
+        self.parent.immr.value = index
+        self.value = length - 1
+        self.parent.immn.value = 1 if self.expr.size == 64 else 0
+        return True
+
+
+class aarch64_pcoff(aarch64_imm_32):
+    parser = base_expr
+
+
+class aarch64_immhip_page(aarch64_imm_32):
+    parser = base_expr
+
+    def decode(self, v):
+        v = ((v << 2) | self.parent.immlo.value) << 12
+        v = sign_ext(v, 33, 64)
+        self.expr = m2_expr.ExprInt64(v)
+        return True
+
+    def encode(self):
+        v = int(self.expr.arg)
+        if v & (1 << 63):
+            v &= (1 << 33) - 1
+        if v & 0xfff:
+            return False
+        v >>= 12
+        self.parent.immlo.value = v & 3
+        v >>= 2
+        self.value = v
+        return True
+
+
+class aarch64_immhi_page(aarch64_imm_32):
+    parser = base_expr
+
+    def decode(self, v):
+        v = ((v << 2) | self.parent.immlo.value)
+        v = sign_ext(v, 21, 64)
+        self.expr = m2_expr.ExprInt64(v)
+        return True
+
+    def encode(self):
+        v = int(self.expr.arg)
+        if v & (1 << 63):
+            v &= (1 << 33) - 1
+        self.parent.immlo.value = v & 3
+        v >>= 2
+        if v > (1 << 19) - 1:
+            return False
+        self.value = v & ((1 << 19) - 1)
+        return True
+
+
+class aarch64_imm_hw(m_arg):
+    parser = base_expr
+    shift_op = '<<'
+
+    def decode(self, v):
+        size = 64 if self.parent.sf.value else 32
+        self.expr = m2_expr.ExprInt_fromsize(size, v << (16 * self.parent.hw.value))
+        return True
+
+    def encode(self):
+        if not isinstance(self.expr, m2_expr.ExprInt):
+            return False
+        size = self.parent.args[0].expr.size
+        if set_imm_to_size(size, self.expr) is None:
+            return False
+        value = int(self.expr.arg)
+        mask = (1 << size) - 1
+        for i in xrange(size / 16):
+            if ((0xffff << (i * 16)) ^ mask) & value:
+                continue
+            self.parent.hw.value = i
+            self.value = value >> (i * 16)
+            return True
+        return False
+
+
+class aarch64_imm_hw_sc(m_arg):
+    parser = shiftimm_off_sc
+    shift_op = 'slice_at'
+
+    def decode(self, v):
+        size = 64 if self.parent.sf.value else 32
+        expr = m2_expr.ExprInt_fromsize(size, v)
+        amount = m2_expr.ExprInt_fromsize(size, 16 * self.parent.hw.value)
+        if self.parent.hw.value:
+            self.expr = m2_expr.ExprOp(self.shift_op, expr,  amount)
+        else:
+            self.expr = expr
+        return True
+
+    def encode(self):
+        if isinstance(self.expr, m2_expr.ExprInt):
+            if self.expr.arg > 0xFFFF:
+                return False
+            self.value = int(self.expr.arg)
+            self.parent.hw.value = 0
+            return True
+
+        if not (isinstance(self.expr, m2_expr.ExprOp) and
+                self.expr.op == self.shift_op and
+                len(self.expr.args) == 2 and
+                isinstance(self.expr.args[0], m2_expr.ExprInt) and
+                isinstance(self.expr.args[1], m2_expr.ExprInt)):
+            return False
+        if set_imm_to_size(self.parent.args[0].expr.size, self.expr.args[0]) is None:
+            return False
+        if set_imm_to_size(self.parent.args[0].expr.size, self.expr.args[1]) is None:
+            return False
+        arg, amount = [int(arg.arg) for arg in self.expr.args]
+        if arg > 0xFFFF:
+            return False
+        if amount % 16 or amount / 16 > 4:
+            return False
+        self.value = arg
+        self.parent.hw.value = amount / 16
+        return True
+
+
+class aarch64_offs(imm_noarg, m_arg):
+    parser = base_expr
+
+    def decode(self, v):
+        v = v & self.lmask
+        v = (v << 2)
+        v = sign_ext(v, (self.l + 2), 64)
+        self.expr = m2_expr.ExprInt64(v)
+        return True
+
+    def encode(self):
+        if not isinstance(self.expr, m2_expr.ExprInt):
+            return False
+        v = int(self.expr.arg)
+        if v & (1 << 63):
+            v &= (1 << (self.l + 2)) - 1
+        self.value = v >> 2
+        return True
+
+
+def set_mem_off(parent, imm):
+    if hasattr(parent, 'simm'):
+        mask = (1 << parent.simm.l) - 1
+        if imm != sign_ext(imm & mask, parent.simm.l, 64):
+            return False
+        parent.simm.value = imm & mask
+    elif hasattr(parent, 'uimm'):
+        mask = (1 << parent.uimm.l) - 1
+        if imm > mask:
+            return False
+        parent.uimm.value = imm
+    else:
+        raise ValueError('unknown imm')
+    return True
+
+
+def get_size(parent):
+    if not hasattr(parent, "size"):
+        return 0
+    if hasattr(parent.size, "amount"):
+        size = parent.size.amount
+    else:
+        size = parent.size.value
+    return size
+
+
+class aarch64_deref(m_arg):
+    parser = deref
+
+    def decode_w_size(self, off):
+        return off
+
+    def encode_w_size(self, off):
+        return off
+
+    def get_postpre(self, parent):
+        if hasattr(self.parent, "postpre"):
+            if self.parent.postpre.value == 0:
+                op = 'postinc'
+            else:
+                op = 'preinc_wb'
+        else:
+            op = 'preinc'
+        return op
+
+    def decode(self, v):
+        reg = gpregs64_info.expr[v]
+        off = self.parent.imm.expr.arg
+        op = self.get_postpre(self.parent)
+        off = self.decode_w_size(off)
+        self.expr = m2_expr.ExprOp(op, reg, m2_expr.ExprInt64(off))
+        return True
+
+    def encode(self):
+        expr = self.expr
+        if not isinstance(expr, m2_expr.ExprOp):
+            return False
+        if not expr.op in ['postinc', 'preinc_wb', 'preinc']:
+            return False
+        if hasattr(self.parent, "postpre"):
+            if expr.op == 'postinc':
+                self.parent.postpre.value = 0
+            else:
+                self.parent.postpre.value = 1
+        reg, off = expr.args
+        if not reg in gpregs64_info.expr:
+            return False
+        if not isinstance(off, m2_expr.ExprInt):
+            return False
+        imm = int(off.arg)
+        imm = self.encode_w_size(imm)
+        if imm is False:
+            return False
+        self.parent.imm.expr = m2_expr.ExprInt64(imm)
+        if not self.parent.imm.encode():
+            return False
+        self.value = gpregs64_info.expr.index(reg)
+        return True
+
+
+class aarch64_deref_size(aarch64_deref):
+
+    def decode_w_size(self, off):
+        size = get_size(self.parent)
+        return off << size
+
+    def encode_w_size(self, off):
+        size = get_size(self.parent)
+        if size:
+            if off & ((1 << size) - 1):
+                return False
+            off >>= size
+        return off
+
+
+class aarch64_deref_nooff(aarch64_deref):
+    parser = deref_nooff
+
+    def decode(self, v):
+        reg = gpregs64_info.expr[v]
+        self.expr = m2_expr.ExprOp('preinc', reg)
+        return True
+
+    def encode(self):
+        expr = self.expr
+        if not isinstance(expr, m2_expr.ExprOp):
+            return False
+        if expr.op != 'preinc':
+            return False
+        if len(expr.args) == 1:
+            reg = expr.args[0]
+        elif len(expr.args) == 2:
+            reg, off = expr.args
+            if not isinstance(off, m2_expr.ExprInt):
+                return False
+            if off.arg != 0:
+                return False
+        else:
+            return False
+
+        if not reg in gpregs64_info.expr:
+            return False
+        self.value = gpregs64_info.expr.index(reg)
+        return True
+
+
+class aarch64_sf_scale(aarch64_deref):
+    size2scale = {32: 2, 64: 3}
+
+    def decode_w_size(self, off):
+        size = 2 + self.parent.sf.value
+        return off << size
+
+    def encode_w_size(self, off):
+        size = self.parent.args[0].expr.size
+        if not size in self.size2scale:
+            return False
+        scale = self.size2scale[size]
+        off = int(mod_size2int[size](off) >> scale)
+        return off
+
+
+class aarch64_sd_scale(aarch64_sf_scale):
+    size2scale = {32: 2, 64: 3, 128: 4}
+
+    def decode_w_size(self, off):
+        size = 2 + self.parent.size.value
+        return off << size
+
+
+class aarch64_eq(bsi):
+
+    def decode(self, v):
+        return getattr(self.parent, self.ref).value == v
+
+    def encode(self):
+        self.value = getattr(self.parent, self.ref).value
+        return True
+modf = bs_mod_name(l=1, fname='modf', mn_mod=['', 'S'])
+sf = bs(l=1, fname='sf', order=-1)
+
+
+class aarch64_cond_arg(reg_noarg, m_arg):
+    reg_info = conds_info
+    parser = reg_info.parser
+
+
+class aarch64_cond_inv_arg(reg_noarg, m_arg):
+    reg_info = conds_inv_info
+    parser = reg_info.parser
+
+
+class aarch64_b40(m_arg):
+    parser = base_expr
+
+    def decode(self, v):
+        self.expr = m2_expr.ExprInt_from(
+            self.parent.rt.expr, (self.parent.sf.value << self.l) | v)
+        return True
+
+    def encode(self):
+        if not isinstance(self.expr, m2_expr.ExprInt):
+            return False
+        size = self.parent.args[0].expr.size
+        value = int(self.expr.arg)
+        self.value = value & self.lmask
+        print 'TT', hex(value)
+        if self.parent.sf.value is None:
+            self.parent.sf.value = value >> self.l
+            return True
+        else:
+            return value >> self.l == self.parent.sf.value
+
+
+shift = bs(l=2, fname='shift')
+
+shiftb = bs(l=1, fname='shift', order=-1)
+
+
+rn64_v = bs(l=5, cls=(aarch64_gpreg64_nodec,), fname='rn', order=-1)
+
+rn = bs(l=5, cls=(aarch64_gpreg,), fname="rn")
+rs = bs(l=5, cls=(aarch64_gpreg,), fname="rs")
+rm = bs(l=5, cls=(aarch64_gpreg,), fname="rm")
+rd = bs(l=5, cls=(aarch64_gpreg,), fname="rd")
+ra = bs(l=5, cls=(aarch64_gpregz,), fname="ra")
+rt = bs(l=5, cls=(aarch64_gpreg,), fname="rt")
+rt2 = bs(l=5, cls=(aarch64_gpreg,), fname="rt2")
+rn0 = bs(l=5, cls=(aarch64_gpreg0,), fname="rn")
+
+
+rn_n1 = bs(l=5, cls=(aarch64_gpreg_n1,), fname="rn")
+rm_n1 = bs(l=5, cls=(aarch64_gpreg_n1,), fname="rm")
+
+
+rn_na = bs(l=5, cls=(aarch64_gpreg_noarg,), fname="rn", order=-1)
+rn32_na = bs(l=5, cls=(aarch64_gpreg32_noarg,), fname="rn", order=-1)
+rn64_na = bs(l=5, cls=(aarch64_gpreg64_noarg,), fname="rn", order=-1)
+
+sd1 = bs(l=5, cls=(aarch64_simdreg_h,), fname="rt")
+sd2 = bs(l=5, cls=(aarch64_simdreg_h,), fname="rt2")
+
+sdn_32_64 = bs(l=5, cls=(aarch64_simdreg_32_64,), fname="rn")
+sdd_32_64 = bs(l=5, cls=(aarch64_simdreg_32_64,), fname="rd")
+sdm_32_64 = bs(l=5, cls=(aarch64_simdreg_32_64,), fname="rm")
+sda_32_64 = bs(l=5, cls=(aarch64_simdreg_32_64,), fname="ra")
+
+
+sdm_32_64_zero = bs(l=5, cls=(aarch64_simdreg_32_64_zero,), fname="rm")
+
+crn = bs(l=4, cls=(aarch64_crreg,), fname="crn")
+crm = bs(l=4, cls=(aarch64_crreg,), fname="crm")
+
+
+rn64 = bs(l=5, cls=(aarch64_gpreg64,), fname="rn")
+rs64 = bs(l=5, cls=(aarch64_gpreg64,), fname="rs")
+rm64 = bs(l=5, cls=(aarch64_gpreg64,), fname="rm")
+rd64 = bs(l=5, cls=(aarch64_gpreg64,), fname="rd")
+rt64 = bs(l=5, cls=(aarch64_gpregz64,), fname="rt")
+ra64 = bs(l=5, cls=(aarch64_gpregz64,), fname="ra")
+
+rn32 = bs(l=5, cls=(aarch64_gpreg32,), fname="rn")
+rm32 = bs(l=5, cls=(aarch64_gpreg32,), fname="rm")
+rd32 = bs(l=5, cls=(aarch64_gpreg32,), fname="rd")
+rs32 = bs(l=5, cls=(aarch64_gpreg32,), fname="rs")
+
+sd08 = bs(l=5, cls=(aarch64_simd08,), fname="rd")
+sd16 = bs(l=5, cls=(aarch64_simd16,), fname="rd")
+sd32 = bs(l=5, cls=(aarch64_simd32,), fname="rd")
+sd64 = bs(l=5, cls=(aarch64_simd64,), fname="rd")
+sd128 = bs(l=5, cls=(aarch64_simd128,), fname="rd")
+
+sn08 = bs(l=5, cls=(aarch64_simd08,), fname="rn")
+sn16 = bs(l=5, cls=(aarch64_simd16,), fname="rn")
+sn32 = bs(l=5, cls=(aarch64_simd32,), fname="rn")
+sn64 = bs(l=5, cls=(aarch64_simd64,), fname="rn")
+sn128 = bs(l=5, cls=(aarch64_simd128,), fname="rn")
+
+
+rt32 = bs(l=5, cls=(aarch64_gpregz32,), fname="rt")
+
+rt_isf = bs(l=5, cls=(aarch64_gpreg_isf,), fname="rt")
+
+rn64_deref = bs(l=5, cls=(aarch64_deref,), fname="rn")
+rn64_deref_sz = bs(l=5, cls=(aarch64_deref_size,), fname="rn")
+rn64_deref_sf = bs(l=5, cls=(aarch64_sf_scale,), fname="rn")
+rn64_deref_sd = bs(l=5, cls=(aarch64_sd_scale,), fname="rn")
+
+rn64_deref_nooff = bs(l=5, cls=(aarch64_deref_nooff,), fname="rn")
+
+imm_sft_12 = bs(l=12, cls=(aarch64_imm_sft,))
+
+# imm32_3 = bs(l=3, cls=(aarch64_imm_32,))
+imm32_3 = bs(l=3, fname="imm")
+imm6 = bs(l=6, fname="imm", order=-1)
+imm3 = bs(l=3, fname="imm", order=-1)
+simm6 = bs(l=6, cls=(aarch64_int64_noarg, m_arg), fname="imm", order=-1)
+simm9 = bs(l=9, cls=(aarch64_int64_noarg,), fname="imm", order=-1)
+simm7 = bs(l=7, cls=(aarch64_int64_noarg,), fname="imm", order=-1)
+nzcv = bs(l=4, cls=(aarch64_uint64_noarg, m_arg), fname="nzcv", order=-1)
+uimm5 = bs(l=5, cls=(aarch64_uint64_noarg, m_arg), fname="imm", order=-1)
+uimm12 = bs(l=12, cls=(aarch64_uint64_noarg,), fname="imm", order=-1)
+uimm16 = bs(l=16, cls=(aarch64_uint64_noarg, m_arg), fname="imm", order=-1)
+uimm7 = bs(l=7, cls=(aarch64_uint64_noarg,), fname="imm", order=-1)
+
+uimm8 = bs(l=8, cls=(aarch64_uint64,), fname="imm", order=-1)
+
+op1 = bs(l=3, cls=(aarch64_uint64, m_arg), fname="op1")
+op2 = bs(l=3, cls=(aarch64_uint64, m_arg), fname="op2")
+
+
+imm16 = bs(l=16, fname="imm", order=-1)
+
+
+immlo = bs(l=2, fname='immlo')
+immhip = bs(l=19, cls=(aarch64_immhip_page,))
+immhi = bs(l=19, cls=(aarch64_immhi_page,))
+
+option = bs(l=3, fname='option', order=-1)
+
+
+rm_ext = bs(l=5, cls=(aarch64_gpreg_ext,), fname="rm")
+rm_sft = bs(l=5, cls=(aarch64_gpreg_sftimm,), fname="rm")
+
+rm_ext2 = bs(l=5, cls=(aarch64_gpreg_ext2,), fname="rm")
+rm_ext2_128 = bs(l=5, cls=(aarch64_gpreg_ext2_128,), fname="rm")
+
+
+imms = bs(l=6, cls=(aarch64_imm_nsr,), fname='imms')
+immr = bs(l=6, fname='immr')
+immn = bs(l=1, fname='immn')
+
+
+imm16_hw = bs(l=16, cls=(aarch64_imm_hw,), fname='imm')
+imm16_hw_sc = bs(l=16, cls=(aarch64_imm_hw_sc,), fname='imm')
+hw = bs(l=2, fname='hw')
+
+
+a_imms = bs(l=6, cls=(aarch64_imm_sf, m_arg), fname="imm1", order=-1)
+a_immr = bs(l=6, cls=(aarch64_imm_sf, m_arg), fname="imm1", order=-1)
+
+
+
+adsu_name = {'ADD': 0, 'SUB': 1}
+bs_adsu_name = bs_name(l=1, name=adsu_name)
+
+
+offs19 = bs(l=19, cls=(aarch64_offs,), fname='off')
+offs26 = bs(l=26, cls=(aarch64_offs,), fname='off')
+offs14 = bs(l=14, cls=(aarch64_offs,), fname='off')
+
+b40 = bs(l=5, cls=(aarch64_b40,), fname='b40', order=1)
+
+sdsize1 = bs(l=1, fname="size")
+
+sdsize = bs(l=2, fname="size")
+opsize = bs(l=2, fname="size")
+sd = bs(l=5, cls=(aarch64_simdreg,), fname='sd')
+
+opc = bs(l=1, fname='opc', order=-1)
+
+# add/sub (imm)
+aarch64op("addsub", [sf, bs_adsu_name, modf, bs('10001'), shift, imm_sft_12, rn, rd], [rd, rn, imm_sft_12])
+aarch64op("cmp", [sf, bs('1'), bs('1'), bs('10001'), shift, imm_sft_12, rn, bs('11111')], [rn, imm_sft_12], alias=True)
+aarch64op("cmn", [sf, bs('0'), bs('1'), bs('10001'), shift, imm_sft_12, rn, bs('11111')], [rn, imm_sft_12], alias=True)
+
+aarch64op("adrp", [bs('1'), immlo, bs('10000'), immhip, rd64], [rd64, immhip])
+aarch64op("adr",  [bs('0'), immlo, bs('10000'), immhi, rd64], [rd64, immhi])
+
+# add/sub (reg shift)
+aarch64op("addsub", [sf, bs_adsu_name, modf, bs('01011'), shift, bs('0'), rm_sft, imm6, rn, rd], [rd, rn, rm_sft])
+aarch64op("cmp", [sf, bs('1'), bs('1'), bs('01011'), shift, bs('0'), rm_sft, imm6, rn, bs('11111')], [rn, rm_sft], alias=True)
+# add/sub (reg ext)
+aarch64op("addsub", [sf, bs_adsu_name, modf, bs('01011'), bs('00'), bs('1'), rm_ext, option, imm3, rn, rd], [rd, rn, rm_ext])
+#aarch64op("cmp",    [sf, bs('1'), bs('1'), bs('01011'), bs('00'), bs('1'), rm_ext, option, imm3, rn, bs('11111')], [rn, rm_ext], alias=True)
+
+
+aarch64op("neg", [sf, bs('1'), modf, bs('01011'), shift, bs('0'), rm_sft, imm6, bs('11111'), rd], [rd, rm_sft], alias=True)
+
+
+logic_name = {'AND': 0, 'ORR': 1, 'EOR': 2, 'ANDS': 3}
+bs_logic_name = bs_name(l=2, name=logic_name)
+# logical (imm)
+aarch64op("logic", [sf, bs_logic_name, bs('100100'), immn, immr, imms, rn0, rd], [rd, rn0, imms])
+
+# bitfield move p.149
+logicbf_name = {'SBFM': 0b00, 'BFM': 0b01, 'UBFM': 0b10}
+bs_logicbf_name = bs_name(l=2, name=logicbf_name)
+aarch64op("logic", [sf, bs_logicbf_name, bs('100110'), bs(l=1, cls=(aarch64_eq,), ref="sf"), a_immr, a_imms, rn, rd], [rd, rn, a_immr, a_imms])
+
+
+# logical (reg shift)
+aarch64op("and",  [sf, bs('00'), bs('01010'), shift, bs('0'), rm_sft, imm6, rn, rd], [rd, rn, rm_sft])
+aarch64op("bic",  [sf, bs('00'), bs('01010'), shift, bs('1'), rm_sft, imm6, rn, rd], [rd, rn, rm_sft])
+aarch64op("orr",  [sf, bs('01'), bs('01010'), shift, bs('0'), rm_sft, imm6, rn, rd], [rd, rn, rm_sft])
+aarch64op("orn",  [sf, bs('01'), bs('01010'), shift, bs('1'), rm_sft, imm6, rn, rd], [rd, rn, rm_sft])
+aarch64op("mvn",  [sf, bs('01'), bs('01010'), shift, bs('1'), rm_sft, imm6, bs('11111'), rd], [rd, rm_sft], alias=True)
+aarch64op("eor",  [sf, bs('10'), bs('01010'), shift, bs('0'), rm_sft, imm6, rn, rd], [rd, rn, rm_sft])
+aarch64op("eon",  [sf, bs('10'), bs('01010'), shift, bs('1'), rm_sft, imm6, rn, rd], [rd, rn, rm_sft])
+aarch64op("ands", [sf, bs('11'), bs('01010'), shift, bs('0'), rm_sft, imm6, rn, rd], [rd, rn, rm_sft])
+aarch64op("tst",  [sf, bs('11'), bs('01010'), shift, bs('0'), rm_sft, imm6, rn, bs('11111')], [rn, rm_sft])
+aarch64op("bics", [sf, bs('11'), bs('01010'), shift, bs('1'), rm_sft, imm6, rn, rd], [rd, rn, rm_sft])
+
+# move reg
+aarch64op("mov",  [sf, bs('01'), bs('01010'), bs('00'), bs('0'), rm, bs('000000'), bs('11111'), rd], [rd, rm], alias=True)
+
+
+
+bcond = bs_mod_name(l=4, fname='cond', mn_mod=['EQ', 'NE', 'CS', 'CC',
+                                               'MI', 'PL', 'VS', 'VC',
+                                               'HI', 'LS', 'GE', 'LT',
+                                               'GT', 'LE', 'AL', 'NV'])
+
+cond_arg = bs(l=4, cls=(aarch64_cond_arg,), fname=cond)
+cond_inv_arg = bs(l=4, cls=(aarch64_cond_inv_arg,), fname=cond)
+# unconditional branch (ret)
+aarch64op("br", [bs('1101011'), bs('0000'), bs('11111'), bs('000000'), rn64, bs('00000')], [rn64])
+aarch64op("blr", [bs('1101011'), bs('0001'), bs('11111'), bs('000000'), rn64, bs('00000')], [rn64])
+aarch64op("ret", [bs('1101011'), bs('0010'), bs('11111'), bs('000000'), rn64, bs('00000')], [rn64])
+aarch64op("eret", [bs('1101011'), bs('0100'), bs('11111'), bs('000000'), bs('11111'), bs('00000')])
+aarch64op("drps", [bs('1101011'), bs('0101'), bs('11111'), bs('000000'), bs('11111'), bs('00000')])
+
+# unconditional branch (imm)
+aarch64op("b",  [bs('0'), bs('00101'), offs26], [offs26])
+aarch64op("bl", [bs('1'), bs('00101'), offs26], [offs26])
+
+
+post_pre = bs(l=1, order=-1, fname='postpre')
+
+# conditional compare (imm) p.158
+ccmp_name = {'CCMN': 0, 'CCMP': 1}
+bs_ccmp_name = bs_name(l=1, name=ccmp_name)
+aarch64op("condcmp", [sf, bs_ccmp_name, bs('1'), bs('11010010'), uimm5, cond_arg, bs('1'), bs('0'), rn, bs('0'), nzcv], [rn, uimm5, nzcv, cond_arg])
+aarch64op("condcmp", [sf, bs_ccmp_name, bs('1'), bs('11010010'), rm, cond_arg, bs('0'), bs('0'), rn, bs('0'), nzcv], [rn, rm, nzcv, cond_arg])
+
+ldst_b_name = {'STRB': 0, 'LDRB': 1}
+bs_ldst_b_name = bs_name(l=1, name=ldst_b_name)
+ldst_name = {'STR': 0, 'LDR': 1}
+bs_ldst_name = bs_name(l=1, name=ldst_name)
+ldst_h_name = {'STRH': 0, 'LDRH': 1}
+bs_ldst_h_name = bs_name(l=1, name=ldst_h_name)
+
+ldst_tb_name = {'STTRB': 0, 'LDTRB': 1}
+bs_ldst_tb_name = bs_name(l=1, name=ldst_tb_name)
+
+ldst_th_name = {'STTRH': 0, 'LDTRH': 1}
+bs_ldst_th_name = bs_name(l=1, name=ldst_th_name)
+
+ldst_ub_name = {'STURB': 0, 'LDURB': 1}
+bs_ldst_ub_name = bs_name(l=1, name=ldst_ub_name)
+ldst_u_name = {'STUR': 0, 'LDUR': 1}
+bs_ldst_u_name = bs_name(l=1, name=ldst_u_name)
+
+ldst_t_name = {'STTR': 0, 'LDTR': 1}
+bs_ldst_st_name = bs_name(l=1, name=ldst_t_name)
+
+ldst_1u_name = {'STUR': 0b0, 'LDUR': 0b1}
+bs_ldst_1u_name = bs_name(l=1, name=ldst_1u_name)
+
+ldst_uh_name = {'STURH': 0, 'LDURH': 1}
+bs_ldst_uh_name = bs_name(l=1, name=ldst_uh_name)
+
+
+ldst_sw_name = {'STRSW': 0, 'LDRSW': 1}
+bs_ldst_sw_name = bs_name(l=1, name=ldst_sw_name)
+
+# load/store register (imm post index)
+aarch64op("ldst",   [bs('00'), bs('111'), bs('0'), bs('00'), bs('0'), bs_ldst_b_name, bs('0'), simm9, post_pre, bs('1'), rn64_deref, rt32], [rt32, rn64_deref ])
+aarch64op("ldrsb",  [bs('00'), bs('111'), bs('0'), bs('00'), bs('1'), sf, bs('0'), simm9, post_pre, bs('1'), rn64_deref, rt_isf], [rt_isf, rn64_deref ])
+aarch64op("ldrsh",  [bs('01'), bs('111'), bs('0'), bs('00'), bs('1'), sf, bs('0'), simm9, post_pre, bs('1'), rn64_deref, rt_isf], [rt_isf, rn64_deref ])
+aarch64op("ldst",   [bs('01'), bs('111'), bs('0'), bs('00'), bs('0'), bs_ldst_h_name, bs('0'), simm9, post_pre, bs('1'), rn64_deref, rt32], [rt32, rn64_deref ])
+aarch64op("ldst",   [bs('10'), bs('111'), bs('0'), bs('00'), bs('0'), bs_ldst_name, bs('0'), simm9, post_pre, bs('1'), rn64_deref, rt32], [rt32, rn64_deref ])
+aarch64op("ldrsw",  [bs('10'), bs('111'), bs('0'), bs('00'), bs('10'), bs('0'), simm9, post_pre, bs('1'), rn64_deref, rt64], [rt64, rn64_deref ])
+aarch64op("ldst",   [bs('11'), bs('111'), bs('0'), bs('00'), bs('0'), bs_ldst_name, bs('0'), simm9, post_pre, bs('1'), rn64_deref, rt64], [rt64, rn64_deref ])
+
+aarch64op("ldst",   [sdsize, bs('111'), bs('1'), bs('00'), bs('0'), bs_ldst_name, bs('0'), simm9, post_pre, bs('1'), rn64_deref, sd], [sd, rn64_deref ])
+aarch64op("ldst",   [bs('00'), bs('111'), bs('1'), bs('00'), bs('1'), bs_ldst_name, bs('0'), simm9, post_pre, bs('1'), rn64_deref, sd128], [sd128, rn64_deref ])
+
+# load/store register (unsigned imm)
+aarch64op("ldst",   [bs('00', fname="size"), bs('111'), bs('0'), bs('01'), bs('0'), bs_ldst_b_name, uimm12, rn64_deref_sz, rt32], [rt32, rn64_deref_sz ])
+aarch64op("ldrsb",  [bs('00', fname="size"), bs('111'), bs('0'), bs('01'), bs('1'), sf, uimm12, rn64_deref_sz, rt_isf], [rt_isf, rn64_deref_sz ])
+aarch64op("ldrsh",  [bs('01', fname="size"), bs('111'), bs('0'), bs('01'), bs('1'), sf, uimm12, rn64_deref_sz, rt_isf], [rt_isf, rn64_deref_sz ])
+aarch64op("ldst",   [bs('01', fname="size"), bs('111'), bs('0'), bs('01'), bs('0'), bs_ldst_h_name, uimm12, rn64_deref_sz, rt32], [rt32, rn64_deref_sz ])
+aarch64op("ldst",   [bs('10', fname="size"), bs('111'), bs('0'), bs('01'), bs('0'), bs_ldst_name, uimm12, rn64_deref_sz, rt32], [rt32, rn64_deref_sz ])
+aarch64op("ldrsw",  [bs('10', fname="size"), bs('111'), bs('0'), bs('01'), bs('10'), uimm12, rn64_deref_sz, rt64], [rt64, rn64_deref_sz ])
+aarch64op("ldst",   [bs('11', fname="size"), bs('111'), bs('0'), bs('01'), bs('0'), bs_ldst_name, uimm12, rn64_deref_sz, rt64], [rt64, rn64_deref_sz ])
+
+aarch64op("ldst",   [sdsize, bs('111'), bs('1'), bs('01'), bs('0'), bs_ldst_name, uimm12, rn64_deref_sz, sd], [sd, rn64_deref_sz ])
+aarch64op("ldst",   [bs('00'), bs('111'), bs('1'), bs('01'), bs('1', fname='size', amount=4), bs_ldst_name, uimm12, rn64_deref_sz, sd128], [sd128, rn64_deref_sz ])
+
+# load/store register (unp)
+aarch64op("ldst",   [bs('00'), bs('111'), bs('0'), bs('00'), bs('0'), bs_ldst_tb_name, bs('0'), simm9, bs('10'), rn64_deref, rt32], [rt32, rn64_deref ])
+aarch64op("ldtrsb", [bs('00'), bs('111'), bs('0'), bs('00'), bs('1'), sf, bs('0'), simm9, bs('10'), rn64_deref, rt_isf], [rt_isf, rn64_deref ])
+aarch64op("ldtrsh", [bs('01'), bs('111'), bs('0'), bs('00'), bs('1'), sf, bs('0'), simm9, bs('10'), rn64_deref, rt_isf], [rt_isf, rn64_deref ])
+aarch64op("ldsttrh",[bs('01'), bs('111'), bs('0'), bs('00'), bs('0'), bs_ldst_th_name, bs('0'), simm9, bs('10'), rn64_deref, rt32], [rt32, rn64_deref ])
+aarch64op("ldtrsw", [bs('10'), bs('111'), bs('0'), bs('00'), bs('10'), bs('0'), simm9, bs('10'), rn64_deref, rt64], [rt64, rn64_deref ])
+aarch64op("ldstt",  [bs('1'), sf, bs('111'), bs('0'), bs('00'), bs('0'), bs_ldst_st_name, bs('0'), simm9, bs('10'), rn64_deref, rt], [rt, rn64_deref ])
+
+aarch64op("ldstt",  [sdsize, bs('111'), bs('1'), bs('00'), bs('0'), bs_ldst_st_name, bs('0'), simm9, bs('10'), rn64_deref, sd], [sd, rn64_deref ])
+aarch64op("ldst",   [bs('00'), bs('111'), bs('1'), bs('00'), bs('1'), bs_ldst_st_name, bs('0'), simm9, bs('10'), rn64_deref, sd128], [sd128, rn64_deref ])
+
+# load/store register (unscaled imm)
+aarch64op("ldst",   [bs('00'), bs('111'), bs('0'), bs('00'), bs('0'), bs_ldst_ub_name, bs('0'), simm9, bs('00'), rn64_deref, rt32], [rt32, rn64_deref ])
+aarch64op("ldursb", [bs('00'), bs('111'), bs('0'), bs('00'), bs('1'), sf, bs('0'), simm9, bs('00'), rn64_deref, rt_isf], [rt_isf, rn64_deref ])
+aarch64op("ldstuh", [bs('01'), bs('111'), bs('0'), bs('00'), bs('0'), bs_ldst_uh_name, bs('0'), simm9, bs('00'), rn64_deref, rt32], [rt32, rn64_deref ])
+aarch64op("ldursh", [bs('01'), bs('111'), bs('0'), bs('00'), bs('1'), sf, bs('0'), simm9, bs('00'), rn64_deref, rt_isf], [rt_isf, rn64_deref ])
+aarch64op("ldursw", [bs('10'), bs('111'), bs('0'), bs('00'), bs('10'), bs('0'), simm9, bs('00'), rn64_deref, rt64], [rt64, rn64_deref ])
+aarch64op("ldst",   [bs('1'), sf, bs('111'), bs('0'), bs('00'), bs('0'), bs_ldst_u_name, bs('0'), simm9, bs('00'), rn64_deref, rt], [rt, rn64_deref ])
+
+aarch64op("ldstu",  [sdsize, bs('111'), bs('1'), bs('00'), bs('0'), bs_ldst_u_name, bs('0'), simm9, bs('00'), rn64_deref, sd], [sd, rn64_deref ])
+aarch64op("ldst",   [bs('00'), bs('111'), bs('1'), bs('00'), bs('1'), bs_ldst_1u_name, bs('0'), simm9, bs('00'), rn64_deref, sd128], [sd128, rn64_deref ])
+
+# load/store (register) p.728
+
+aarch64op("ldstrb",[bs('00', fname="size"), bs('111'), bs('0'), bs('00'), bs('0'), bs_ldst_b_name, bs('1'), rm_ext2, option, shiftb, bs('10'), rn64_v, rt32], [rt32, rm_ext2])
+
+aarch64op("ldstrh",[bs('01', fname="size"), bs('111'), bs('0'), bs('00'), bs('0'), bs_ldst_h_name, bs('1'), rm_ext2, option, shiftb, bs('10'), rn64_v, rt32], [rt32, rm_ext2])
+
+aarch64op("ldrsb", [bs('00', fname="size"), bs('111'), bs('0'), bs('00'), bs('1'), sf, bs('1'), rm_ext2, option, shiftb, bs('10'), rn64_v, rt_isf], [rt_isf, rm_ext2])
+
+aarch64op("ldrsh", [bs('01', fname="size"), bs('111'), bs('0'), bs('00'), bs('1'), sf, bs('1'), rm_ext2, option, shiftb, bs('10'), rn64_v, rt_isf], [rt_isf, rm_ext2])
+
+aarch64op("ldst",  [sdsize, bs('111'), bs('1'), bs('00'), bs('0'), bs_ldst_name, bs('1'), rm_ext2, option, shiftb, bs('10'), rn64_v, sd], [sd, rm_ext2])
+aarch64op("ldst",  [bs('00', fname="size"), bs('111'), bs('1'), bs('00'), bs('1'), bs_ldst_name, bs('1'), rm_ext2_128, option, shiftb, bs('10'), rn64_v, sd128], [sd128, rm_ext2_128])
+
+aarch64op("str",   [bs('10', fname="size"), bs('111'), bs('0'), bs('00'), bs('0'), bs_ldst_name, bs('1'), rm_ext2, option, shiftb, bs('10'), rn64_v, rt32], [rt32, rm_ext2])
+
+aarch64op("ldrsw", [bs('10', fname="size"), bs('111'), bs('0'), bs('00'), bs('10'), bs('1'), rm_ext2, option, shiftb, bs('10'), rn64_v, rt64], [rt64, rm_ext2])
+
+aarch64op("ldst",  [bs('11', fname="size"), bs('111'), bs('0'), bs('00'), bs('0'), bs_ldst_name, bs('1'), rm_ext2, option, shiftb, bs('10'), rn64_v, rt64], [rt64, rm_ext2])
+
+# load/store literal p.137
+aarch64op("ldr",  [bs('0'), sf, bs('011'), bs('0'), bs('00'), offs19, rt], [rt, offs19])
+aarch64op("ldr",  [bs('10'), bs('011'), bs('0'), bs('00'), offs19, rt64], [rt64, offs19])
+
+# load/store simd literal p.142
+aarch64op("ldr",  [sdsize, bs('011'), bs('1'), bs('00'), offs19, sd1], [sd1, offs19])
+
+
+# move wide p.203
+movwide_name = {'MOVN': 0b00, 'MOVZ': 0b10}
+bs_movwide_name = bs_name(l=2, name=movwide_name)
+# mov wide (imm)
+aarch64op("mov", [sf, bs_movwide_name, bs('100101'), hw, imm16_hw, rd], [rd, imm16_hw])
+aarch64op("movk", [sf, bs('11'), bs('100101'), hw, imm16_hw_sc, rd], [rd, imm16_hw_sc])
+
+# stp/ldp p.139
+ldstp_name = {'STP': 0b0, 'LDP': 0b1}
+bs_ldstp_name = bs_name(l=1, name=ldstp_name)
+aarch64op("ldstp", [sf, bs('0'), bs('101'), bs('0'), bs('0'), post_pre, bs('1'), bs_ldstp_name, simm7, rt2, rn64_deref_sf, rt], [rt, rt2, rn64_deref_sf])
+#aarch64op("ldstp", [sf, bs('0'), bs('101'), bs('0'), bs('0'), bs('1'), bs('0'), bs_ldstp_name, simm7, rt2, rn64_deref_sf, rt], [rt, rt2, rn64_deref_sf])
+
+aarch64op("ldstp", [sdsize, bs('101'), bs('1'), bs('0'), post_pre, bs('1'), bs_ldstp_name, uimm7, sd2, rn64_deref_sd, sd1], [sd1, sd2, rn64_deref_sd])
+aarch64op("ldstp", [sdsize, bs('101'), bs('1'), bs('0'), bs('1'), bs('0'), bs_ldstp_name, uimm7, sd2, rn64_deref_sd, sd1], [sd1, sd2, rn64_deref_sd])
+
+
+# data process p.207
+datap0_name = {'RBIT': 0b000000, 'REV16': 0b000001,
+              'REV': 0b000010,
+              'CLZ': 0b000100, 'CLS': 0b000101}
+bs_datap0_name = bs_name(l=6, name=datap0_name)
+aarch64op("ldstp", [bs('0', fname='sf'), bs('1'), modf, bs('11010110'), bs('00000'), bs_datap0_name, rn, rd])
+datap1_name = {'RBIT': 0b000000, 'REV16': 0b000001,
+               'REV32': 0b000010, 'REV': 0b000011,
+              'CLZ': 0b000100, 'CLS': 0b000101}
+bs_datap1_name = bs_name(l=6, name=datap1_name)
+aarch64op("ldstp", [bs('1', fname='sf'), bs('1'), modf, bs('11010110'), bs('00000'), bs_datap1_name, rn, rd])
+
+
+# conditional branch p.132
+aarch64op("b.",   [bs('0101010'), bs('0'), offs19, bs('0'), bcond], [offs19])
+aarch64op("cbnz", [sf, bs('011010'), bs('1'), offs19, rt], [rt, offs19])
+aarch64op("cbz",  [sf, bs('011010'), bs('0'), offs19, rt], [rt, offs19])
+aarch64op("tbnz", [sf, bs('011011'), bs('1'), b40, offs14, rt], [rt, b40, offs14])
+aarch64op("tbz",  [sf, bs('011011'), bs('0'), b40, offs14, rt], [rt, b40, offs14])
+
+
+# fmov register p.160
+aarch64op("fmov",  [bs('000'), bs('11110'), bs('0'), sdsize1, bs('1'), bs('0000'), bs('00'), bs('10000'), sdn_32_64, sdd_32_64], [sdd_32_64, sdn_32_64])
+# fmov scalar imm p.160
+aarch64op("fmov",  [bs('000'), bs('11110'), bs('0'), sdsize1, bs('1'), uimm8, bs('100'), bs('00000'), sdd_32_64], [sdd_32_64, uimm8])
+# floating point comparison p.164
+aarch64op("fcmp",  [bs('000'), bs('11110'), bs('0'), sdsize1, bs('1'), sdm_32_64_zero, bs('00'), bs('1000'), sdn_32_64, bs('0'), opc, bs('000')], [sdn_32_64, sdm_32_64_zero])
+aarch64op("fcmpe", [bs('000'), bs('11110'), bs('0'), sdsize1, bs('1'), sdm_32_64_zero, bs('00'), bs('1000'), sdn_32_64, bs('1'), opc, bs('000')], [sdn_32_64, sdm_32_64_zero])
+# floating point convert p.161
+aarch64op("fcvtas",[sf, bs('00'), bs('11110'), bs('0'), sdsize1, bs('1'), bs('00'), bs('100'), bs('000000'), sdn_32_64, rd], [rd, sdn_32_64])
+aarch64op("fcvtzu",[sf, bs('00'), bs('11110'), bs('0'), sdsize1, bs('1'), bs('11'), bs('001'), bs('000000'), sdn_32_64, rd], [rd, sdn_32_64])
+aarch64op("fcvtzs",[sf, bs('00'), bs('11110'), bs('0'), sdsize1, bs('1'), bs('11'), bs('000'), bs('000000'), sdn_32_64, rd], [rd, sdn_32_64])
+
+aarch64op("fcvt",  [bs('000'), bs('11110'), bs('11'), bs('1'), bs('0001'), bs('00'), bs('10000'), sn16, sd32], [sd32, sn16])
+aarch64op("fcvt",  [bs('000'), bs('11110'), bs('11'), bs('1'), bs('0001'), bs('01'), bs('10000'), sn16, sd64], [sd64, sn16])
+aarch64op("fcvt",  [bs('000'), bs('11110'), bs('00'), bs('1'), bs('0001'), bs('11'), bs('10000'), sn32, sd16], [sd16, sn32])
+aarch64op("fcvt",  [bs('000'), bs('11110'), bs('00'), bs('1'), bs('0001'), bs('01'), bs('10000'), sn32, sd64], [sd64, sn32])
+aarch64op("fcvt",  [bs('000'), bs('11110'), bs('01'), bs('1'), bs('0001'), bs('11'), bs('10000'), sn64, sd16], [sd16, sn64])
+aarch64op("fcvt",  [bs('000'), bs('11110'), bs('01'), bs('1'), bs('0001'), bs('00'), bs('10000'), sn64, sd32], [sd32, sn64])
+
+
+
+swapargs = bs_swapargs(l=1, fname="swap", mn_mod=range(1 << 1))
+
+aarch64op("fmov",  [bs('0'), bs('00'), bs('11110'), bs('00'), bs('1'), bs('00'), bs('110'), bs('000000'), sn32, rd32], [rd32, sn32])
+aarch64op("fmov",  [bs('0'), bs('00'), bs('11110'), bs('00'), bs('1'), bs('00'), bs('111'), bs('000000'), rn32, sd32], [sd32, rn32])
+aarch64op("fmov",  [bs('1'), bs('00'), bs('11110'), bs('00'), bs('1'), bs('00'), bs('110'), bs('000000'), sd32, rd32], [rd32, sd32])
+aarch64op("fmov",  [bs('1'), bs('00'), bs('11110'), bs('01'), bs('1'), bs('00'), bs('111'), bs('000000'), rd64, sd64], [sd64, rd64])
+aarch64op("fmov",  [bs('1'), bs('00'), bs('11110'), bs('01'), bs('1'), bs('00'), bs('110'), bs('000000'), sd64, rd64], [rd64, sd64])
+
+
+
+# floating point arith p.163
+aarch64op("fsub",  [bs('0'), bs('00'), bs('11110'), bs('0'), sdsize1, bs('1'), sdm_32_64, bs('001'), bs('1'), bs('10'), sdn_32_64, sdd_32_64], [sdd_32_64, sdn_32_64, sdm_32_64])
+aarch64op("fadd",  [bs('0'), bs('00'), bs('11110'), bs('0'), sdsize1, bs('1'), sdm_32_64, bs('001'), bs('0'), bs('10'), sdn_32_64, sdd_32_64], [sdd_32_64, sdn_32_64, sdm_32_64])
+aarch64op("fdiv",  [bs('0'), bs('00'), bs('11110'), bs('0'), sdsize1, bs('1'), sdm_32_64, bs('000'), bs('1'), bs('10'), sdn_32_64, sdd_32_64], [sdd_32_64, sdn_32_64, sdm_32_64])
+aarch64op("fmul",  [bs('0'), bs('00'), bs('11110'), bs('0'), sdsize1, bs('1'), sdm_32_64, bs('000'), bs('0'), bs('10'), sdn_32_64, sdd_32_64], [sdd_32_64, sdn_32_64, sdm_32_64])
+aarch64op("fnmul", [bs('0'), bs('00'), bs('11110'), bs('0'), sdsize1, bs('1'), sdm_32_64, bs('100'), bs('0'), bs('10'), sdn_32_64, sdd_32_64], [sdd_32_64, sdn_32_64, sdm_32_64])
+
+aarch64op("fabs",  [bs('0'), bs('00'), bs('11110'), bs('0'), sdsize1, bs('1'), bs('0000'), bs('01'), bs('10000'), sdn_32_64, sdd_32_64], [sdd_32_64, sdn_32_64])
+aarch64op("fneg",  [bs('0'), bs('00'), bs('11110'), bs('0'), sdsize1, bs('1'), bs('0000'), bs('10'), bs('10000'), sdn_32_64, sdd_32_64], [sdd_32_64, sdn_32_64])
+aarch64op("fsqrt", [bs('0'), bs('00'), bs('11110'), bs('0'), sdsize1, bs('1'), bs('0000'), bs('11'), bs('10000'), sdn_32_64, sdd_32_64], [sdd_32_64, sdn_32_64])
+
+
+# floating point multiply add p.163
+aarch64op("fmadd", [bs('0'), bs('00'), bs('11111'), bs('0'), sdsize1, bs('0'), sdm_32_64, bs('0'), sda_32_64, sdn_32_64, sdd_32_64], [sdd_32_64, sdn_32_64, sdm_32_64, sda_32_64])
+aarch64op("fmsub", [bs('0'), bs('00'), bs('11111'), bs('0'), sdsize1, bs('0'), sdm_32_64, bs('1'), sda_32_64, sdn_32_64, sdd_32_64], [sdd_32_64, sdn_32_64, sdm_32_64, sda_32_64])
+aarch64op("fnmadd",[bs('0'), bs('00'), bs('11111'), bs('0'), sdsize1, bs('1'), sdm_32_64, bs('0'), sda_32_64, sdn_32_64, sdd_32_64], [sdd_32_64, sdn_32_64, sdm_32_64, sda_32_64])
+aarch64op("fnmsub",[bs('0'), bs('00'), bs('11111'), bs('0'), sdsize1, bs('1'), sdm_32_64, bs('1'), sda_32_64, sdn_32_64, sdd_32_64], [sdd_32_64, sdn_32_64, sdm_32_64, sda_32_64])
+
+# convertion float integer p.235
+aarch64op("scvtf", [sf, bs('0'), bs('0'), bs('11110'), bs('0'), sdsize1, bs('1'), bs('00'), bs('010'), bs('000000'), rn, sdd_32_64], [sdd_32_64, rn])
+aarch64op("ucvtf", [sf, bs('0'), bs('0'), bs('11110'), bs('0'), sdsize1, bs('1'), bs('00'), bs('011'), bs('000000'), rn, sdd_32_64], [sdd_32_64, rn])
+
+
+
+# conditional select p.158
+aarch64op("csel",  [sf, bs('0'), bs('0'), bs('11010100'), rm, cond_arg, bs('00'), rn, rd], [rd, rn, rm, cond_arg])
+aarch64op("csinc", [sf, bs('0'), bs('0'), bs('11010100'), rm, cond_arg, bs('01'), rn, rd], [rd, rn, rm, cond_arg])
+aarch64op("csinv", [sf, bs('1'), bs('0'), bs('11010100'), rm, cond_arg, bs('00'), rn, rd], [rd, rn, rm, cond_arg])
+aarch64op("csneg", [sf, bs('1'), bs('0'), bs('11010100'), rm, cond_arg, bs('01'), rn, rd], [rd, rn, rm, cond_arg])
+aarch64op("cset",  [sf, bs('0'), bs('0'), bs('11010100'), bs('11111'), cond_inv_arg, bs('01'), bs('11111'), rd], [rd, cond_inv_arg], alias=True)
+aarch64op("csetm", [sf, bs('1'), bs('0'), bs('11010100'), bs('11111'), cond_inv_arg, bs('00'), bs('11111'), rd], [rd, cond_inv_arg], alias=True)
+
+
+# multiply p.156
+aarch64op("madd",  [sf, bs('00'), bs('11011'), bs('000'), rm, bs('0'), ra, rn, rd], [rd, rn, rm, ra])
+aarch64op("msub",  [sf, bs('00'), bs('11011'), bs('000'), rm, bs('1'), ra, rn, rd], [rd, rn, rm, ra])
+
+aarch64op("umulh", [bs('1'), bs('00'), bs('11011'), bs('110'), rm64, bs('0'), bs('11111'), rn64, rd64], [rd64, rn64, rm64])
+aarch64op("smulh", [bs('1'), bs('00'), bs('11011'), bs('010'), rm64, bs('0'), bs('11111'), rn64, rd64], [rd64, rn64, rm64])
+aarch64op("umsubh",[bs('1'), bs('00'), bs('11011'), bs('101'), rm32, bs('1'), ra64, rn32, rd64], [rd64, rn32, rm32, ra64])
+
+
+aarch64op("smaddl",[bs('1'), bs('00'), bs('11011'), bs('001'), rm32, bs('0'), ra64, rn32, rd64], [rd64, rn32, rm32, ra64])
+aarch64op("umaddl",[bs('1'), bs('00'), bs('11011'), bs('101'), rm32, bs('0'), ra64, rn32, rd64], [rd64, rn32, rm32, ra64])
+
+aarch64op("smsubl",[bs('1'), bs('00'), bs('11011'), bs('001'), rm32, bs('1'), ra64, rn32, rd64], [rd64, rn32, rm32, ra64])
+aarch64op("umsubl",[bs('1'), bs('00'), bs('11011'), bs('101'), rm32, bs('1'), ra64, rn32, rd64], [rd64, rn32, rm32, ra64])
+
+# division p.156
+aarch64op("sdiv", [sf, bs('0'), bs('0'), bs('11010110'), rm, bs('00001'), bs('1'), rn, rd], [rd, rn, rm])
+aarch64op("udiv", [sf, bs('0'), bs('0'), bs('11010110'), rm, bs('00001'), bs('0'), rn, rd], [rd, rn, rm])
+
+
+# extract register p.150
+aarch64op("extr", [sf, bs('00100111'), bs(l=1, cls=(aarch64_eq,), ref="sf"), bs('0'), rm, simm6, rn, rd], [rd, rn, rm, simm6])
+
+# shift reg p.155
+shiftr_name = {'LSL': 0b00, 'LSR': 0b01, 'ASR': 0b10, 'ROR': 0b11}
+bs_shiftr_name = bs_name(l=2, name=shiftr_name)
+
+aarch64op("shiftr", [sf, bs('0'), bs('0'), bs('11010110'), rm, bs('0010'), bs_shiftr_name, rn, rd], [rd, rn, rm])
+
+#
+aarch64op("NOP", [bs('11010101000000110010000000011111')])
+
+# exception p.133
+aarch64op("brk", [bs('11010100'), bs('001'), uimm16, bs('000'), bs('00')], [uimm16])
+aarch64op("hlt", [bs('11010100'), bs('010'), uimm16, bs('000'), bs('00')], [uimm16])
+aarch64op("svc", [bs('11010100'), bs('000'), uimm16, bs('000'), bs('01')], [uimm16])
+aarch64op("hvc", [bs('11010100'), bs('000'), uimm16, bs('000'), bs('10')], [uimm16])
+aarch64op("smc", [bs('11010100'), bs('000'), uimm16, bs('000'), bs('11')], [uimm16])
+
+# msr p.631
+msr_name = {'MSR': 0b0, 'MRS': 0b1}
+bs_msr_name = bs_name(l=1, name=msr_name)
+aarch64op("mrs", [bs('1101010100'), bs('1'), bs('1'), bs('1'), op1, crn, crm, op2, rt64], [rt64, op1, crn, crm, op2])
+aarch64op("msr", [bs('1101010100'), bs('0'), bs('1'), bs('1'), op1, crn, crm, op2, rt64], [op1, crn, crm, op2, rt64])
+
+# load/store exclusive p.140
+aarch64op("stxr", [bs('1'), sf, bs('001000'), bs('0'), bs('0'), bs('0'), rs32, bs('0'), bs('11111'), rn64_deref_nooff, rt], [rs32, rt, rn64_deref_nooff])
+aarch64op("ldxr", [bs('1'), sf, bs('001000'), bs('0'), bs('1'), bs('0'), bs('11111'), bs('0'), bs('11111'), rn64_deref_nooff, rt], [rt, rn64_deref_nooff])
+
+
+aarch64op("stxrb", [bs('0'), bs('0'), bs('001000'), bs('0'), bs('0'), bs('0'), rs32, bs('0'), bs('11111'), rn64_deref_nooff, rt32], [rs32, rt32, rn64_deref_nooff])
+aarch64op("ldxrb", [bs('0'), bs('0'), bs('001000'), bs('0'), bs('1'), bs('0'), bs('11111'), bs('0'), bs('11111'), rn64_deref_nooff, rt32], [rt32, rn64_deref_nooff])
+
+aarch64op("stxrb", [bs('0'), bs('1'), bs('001000'), bs('0'), bs('0'), bs('0'), rs32, bs('0'), bs('11111'), rn64_deref_nooff, rt32], [rs32, rt32, rn64_deref_nooff])
+aarch64op("ldxrh", [bs('0'), bs('1'), bs('001000'), bs('0'), bs('1'), bs('0'), bs('11111'), bs('0'), bs('11111'), rn64_deref_nooff, rt32], [rt32, rn64_deref_nooff])
+
+aarch64op("stxp", [bs('1'), sf, bs('001000'), bs('0'), bs('0'), bs('1'), rs32, bs('0'), rt2, rn64_deref_nooff, rt], [rs32, rt, rt2, rn64_deref_nooff])
+aarch64op("ldxp", [bs('1'), sf, bs('001000'), bs('0'), bs('1'), bs('1'), bs('11111'), bs('0'), rt2, rn64_deref_nooff, rt], [rt, rt2, rn64_deref_nooff])
+
+# load acquire/store release p.141
+aarch64op("ldar", [bs('1'), sf, bs('001000'), bs('1'), bs('1'), bs('0'), bs('11111'), bs('1'), bs('11111'), rn64_deref_nooff, rt], [rt, rn64_deref_nooff])
+aarch64op("ldarb",[bs('0'), bs('0'), bs('001000'), bs('1'), bs('1'), bs('0'), bs('11111'), bs('1'), bs('11111'), rn64_deref_nooff, rt], [rt, rn64_deref_nooff])
+aarch64op("ldarh",[bs('0'), bs('1'), bs('001000'), bs('0'), bs('1'), bs('0'), bs('11111'), bs('1'), bs('11111'), rn64_deref_nooff, rt], [rt, rn64_deref_nooff])
+aarch64op("ldaxp",[bs('1'), sf, bs('001000'), bs('0'), bs('1'), bs('1'), bs('11111'), bs('1'), bs('11111'), rn64_deref_nooff, rt], [rt, rn64_deref_nooff])
+aarch64op("ldaxr",[bs('1'), sf, bs('001000'), bs('0'), bs('1'), bs('0'), bs('11111'), bs('1'), bs('11111'), rn64_deref_nooff, rt], [rt, rn64_deref_nooff])
+
+aarch64op("stlxr", [bs('1'), sf, bs('001000'), bs('0'), bs('0'), bs('0'), rs32, bs('1'), bs('11111'), rn64_deref_nooff, rt], [rs32, rt, rn64_deref_nooff])
+aarch64op("stlxrb",[bs('0'), bs('0'), bs('001000'), bs('0'), bs('0'), bs('0'), rs32, bs('1'), bs('11111'), rn64_deref_nooff, rt32], [rs32, rt32, rn64_deref_nooff])
+aarch64op("stlxrh",[bs('0'), bs('1'), bs('001000'), bs('0'), bs('0'), bs('0'), rs32, bs('1'), bs('11111'), rn64_deref_nooff, rt32], [rs32, rt32, rn64_deref_nooff])
+aarch64op("stlxp", [bs('1'), sf, bs('001000'), bs('0'), bs('0'), bs('1'), rs32, bs('1'), rt2, rn64_deref_nooff, rt], [rs32, rt, rt2, rn64_deref_nooff])
+
+# barriers p.135
+aarch64op("dsb", [bs('1101010100'), bs('0000110011'), crm, bs('1'), bs('00'), bs('11111')], [crm])
+aarch64op("dmb", [bs('1101010100'), bs('0000110011'), crm, bs('1'), bs('01'), bs('11111')], [crm])
+aarch64op("isb", [bs('1101010100'), bs('0000110011'), crm, bs('1'), bs('10'), bs('11111')], [crm])
diff --git a/miasm2/arch/aarch64/disasm.py b/miasm2/arch/aarch64/disasm.py
new file mode 100644
index 00000000..1fc19d07
--- /dev/null
+++ b/miasm2/arch/aarch64/disasm.py
@@ -0,0 +1,27 @@
+from miasm2.core.asmbloc import asm_constraint, disasmEngine
+from miasm2.arch.aarch64.arch import mn_aarch64
+
+cb_aarch64_funcs = []
+
+
+def cb_aarch64_disasm(mn, attrib, pool_bin, cur_bloc, offsets_to_dis, symbol_pool):
+    for func in cb_aarch64_funcs:
+        func(mn, attrib, pool_bin, cur_bloc, offsets_to_dis, symbol_pool)
+
+
+class dis_aarch64b(disasmEngine):
+    attrib = "b"
+    def __init__(self, bs=None, **kwargs):
+        super(dis_aarch64b, self).__init__(
+            mn_aarch64, self.attrib, bs,
+            dis_bloc_callback = cb_aarch64_disasm,
+            **kwargs)
+
+
+class dis_aarch64l(disasmEngine):
+    attrib = "l"
+    def __init__(self, bs=None, **kwargs):
+        super(dis_aarch64l, self).__init__(
+            mn_aarch64, self.attrib, bs,
+            dis_bloc_callback = cb_aarch64_disasm,
+            **kwargs)
diff --git a/miasm2/arch/aarch64/ira.py b/miasm2/arch/aarch64/ira.py
new file mode 100644
index 00000000..cf44f42c
--- /dev/null
+++ b/miasm2/arch/aarch64/ira.py
@@ -0,0 +1,95 @@
+#!/usr/bin/env python
+#-*- coding:utf-8 -*-
+
+from miasm2.expression.expression import *
+from miasm2.ir.ir import ir, irbloc
+from miasm2.ir.analysis import ira
+from miasm2.arch.aarch64.sem import ir_aarch64l, ir_aarch64b
+from miasm2.arch.aarch64.regs import *
+
+
+class ir_a_aarch64l_base(ir_aarch64l, ira):
+
+    def __init__(self, symbol_pool=None):
+        ir_aarch64l.__init__(self, symbol_pool)
+        self.ret_reg = self.arch.regs.X0
+
+
+class ir_a_aarch64b_base(ir_aarch64b, ira):
+
+    def __init__(self, symbol_pool=None):
+        ir_aarch64b.__init__(self, symbol_pool)
+        self.ret_reg = self.arch.regs.X0
+
+
+class ir_a_aarch64l(ir_a_aarch64l_base):
+
+    def __init__(self, symbol_pool=None):
+        ir_a_aarch64l_base.__init__(self, symbol_pool)
+        self.ret_reg = self.arch.regs.X0
+
+    # for test XXX TODO
+    def set_dead_regs(self, b):
+        b.rw[-1][1].add(self.arch.regs.zf)
+        b.rw[-1][1].add(self.arch.regs.nf)
+        b.rw[-1][1].add(self.arch.regs.of)
+        b.rw[-1][1].add(self.arch.regs.cf)
+
+    def call_effects(self, ad):
+        irs = [[ExprAff(self.ret_reg, ExprOp('call_func_ret', ad, self.sp)),
+                ExprAff(self.sp, ExprOp('call_func_stack', ad, self.sp)),
+                ]]
+        return irs
+
+    def post_add_bloc(self, bloc, ir_blocs):
+        ir.post_add_bloc(self, bloc, ir_blocs)
+        for irb in ir_blocs:
+            pc_val = None
+            lr_val = None
+            for exprs in irb.irs:
+                for e in exprs:
+                    if e.dst == PC:
+                        pc_val = e.src
+                    if e.dst == LR:
+                        lr_val = e.src
+            if pc_val is None or lr_val is None:
+                continue
+            if not isinstance(lr_val, ExprInt):
+                continue
+
+            l = bloc.lines[-1]
+            if lr_val.arg != l.offset + l.l:
+                continue
+            lbl = bloc.get_next()
+            new_lbl = self.gen_label()
+            irs = self.call_effects(pc_val)
+            irs.append([ExprAff(self.IRDst, ExprId(lbl, size=self.pc.size))])
+            nbloc = irbloc(new_lbl, irs)
+            nbloc.lines = [l] * len(irs)
+            self.blocs[new_lbl] = nbloc
+            irb.dst = ExprId(new_lbl, size=self.pc.size)
+
+    def get_out_regs(self, b):
+        return set([self.ret_reg, self.sp])
+
+    def sizeof_char(self):
+        return 8
+
+    def sizeof_short(self):
+        return 16
+
+    def sizeof_int(self):
+        return 32
+
+    def sizeof_long(self):
+        return 32
+
+    def sizeof_pointer(self):
+        return 32
+
+
+class ir_a_aarch64b(ir_a_aarch64b_base, ir_a_aarch64l):
+
+    def __init__(self, symbol_pool=None):
+        ir_a_aarch64b_base.__init__(self, symbol_pool)
+        self.ret_reg = self.arch.regs.X0
diff --git a/miasm2/arch/aarch64/jit.py b/miasm2/arch/aarch64/jit.py
new file mode 100644
index 00000000..44b0609f
--- /dev/null
+++ b/miasm2/arch/aarch64/jit.py
@@ -0,0 +1,73 @@
+import logging
+
+from miasm2.jitter.jitload import jitter, named_arguments
+from miasm2.core import asmbloc
+from miasm2.core.utils import *
+from miasm2.arch.aarch64.sem import ir_aarch64b, ir_aarch64l
+
+log = logging.getLogger('jit_aarch64')
+hnd = logging.StreamHandler()
+hnd.setFormatter(logging.Formatter("[%(levelname)s]: %(message)s"))
+log.addHandler(hnd)
+log.setLevel(logging.CRITICAL)
+
+
+class jitter_aarch64l(jitter):
+    max_reg_arg = 8
+
+    def __init__(self, *args, **kwargs):
+        sp = asmbloc.asm_symbol_pool()
+        jitter.__init__(self, ir_aarch64l(sp), *args, **kwargs)
+        self.vm.set_little_endian()
+        self.ir_arch.jit_pc = self.ir_arch.arch.regs.PC
+
+    def push_uint64_t(self, v):
+        self.cpu.SP -= 8
+        self.vm.set_mem(self.cpu.SP, pck64(v))
+
+    def pop_uint64_t(self):
+        x = upck32(self.vm.get_mem(self.cpu.SP, 8))
+        self.cpu.SP += 8
+        return x
+
+    def get_stack_arg(self, n):
+        x = upck64(self.vm.get_mem(self.cpu.SP + 8 * n, 8))
+        return x
+
+    # calling conventions
+
+    @named_arguments
+    def func_args_stdcall(self, n_args):
+        args = []
+        for i in xrange(min(n_args, self.max_reg_arg)):
+            args.append(self.cpu.get_gpreg()['X%d' % i])
+        for i in xrange(max(0, n_args - self.max_reg_arg)):
+            args.append(self.get_stack_arg(i))
+        ret_ad = self.cpu.LR
+        return ret_ad, args
+
+    def func_ret_stdcall(self, ret_addr, ret_value=None):
+        self.pc = self.cpu.PC = ret_addr
+        if ret_value is not None:
+            self.cpu.X0 = ret_value
+        return True
+
+    def get_arg_n_stdcall(self, n):
+        if n < self.max_reg_arg:
+            arg = self.cpu.get_gpreg()['X%d' % n]
+        else:
+            arg = self.get_stack_arg(n - self.max_reg_arg)
+        return arg
+
+    def init_run(self, *args, **kwargs):
+        jitter.init_run(self, *args, **kwargs)
+        self.cpu.PC = self.pc
+
+
+class jitter_aarch64b(jitter_aarch64l):
+
+    def __init__(self, *args, **kwargs):
+        sp = asmbloc.asm_symbol_pool()
+        jitter.__init__(self, ir_aarch64b(sp), *args, **kwargs)
+        self.vm.set_big_endian()
+        self.ir_arch.jit_pc = self.ir_arch.arch.regs.PC
diff --git a/miasm2/arch/aarch64/regs.py b/miasm2/arch/aarch64/regs.py
new file mode 100644
index 00000000..6130d075
--- /dev/null
+++ b/miasm2/arch/aarch64/regs.py
@@ -0,0 +1,124 @@
+#!/usr/bin/env python
+#-*- coding:utf-8 -*-
+
+from miasm2.expression.expression import *
+from miasm2.core.cpu import gen_reg, gen_regs
+
+exception_flags = ExprId('exception_flags', 32)
+
+
+gpregs32_str = ["W%d" % i for i in xrange(0x1f)] + ["WSP"]
+gpregs32_expr, gpregs32_init, gpregs32_info = gen_regs(
+    gpregs32_str, globals(), 32)
+
+gpregs64_str = ["X%d" % i for i in xrange(0x1E)] + ["LR", "SP"]
+gpregs64_expr, gpregs64_init, gpregs64_info = gen_regs(
+    gpregs64_str, globals(), 64)
+
+
+gpregsz32_str = ["W%d" % i for i in xrange(0x1f)] + ["WZR"]
+gpregsz32_expr, gpregsz32_init, gpregsz32_info = gen_regs(
+    gpregsz32_str, globals(), 32)
+
+gpregsz64_str = ["X%d" % i for i in xrange(0x1e)] + ["LR", "XZR"]
+gpregsz64_expr, gpregsz64_init, gpregsz64_info = gen_regs(
+    gpregsz64_str, globals(), 64)
+
+cr_str = ["c%d" % i for i in xrange(0xf)]
+cr_expr, cr_init, cr_info = gen_regs(cr_str, globals(), 32)
+
+
+simd08_str = ["B%d" % i for i in xrange(0x20)]
+simd08_expr, simd08_init, simd08_info = gen_regs(simd08_str, globals(), 8)
+
+simd16_str = ["H%d" % i for i in xrange(0x20)]
+simd16_expr, simd16_init, simd16_info = gen_regs(simd16_str, globals(), 16)
+
+simd32_str = ["S%d" % i for i in xrange(0x20)]
+simd32_expr, simd32_init, simd32_info = gen_regs(simd32_str, globals(), 32)
+
+simd64_str = ["D%d" % i for i in xrange(0x20)]
+simd64_expr, simd64_init, simd64_info = gen_regs(simd64_str, globals(), 64)
+
+simd128_str = ["Q%d" % i for i in xrange(0x20)]
+simd128_expr, simd128_init, simd128_info = gen_regs(
+    simd128_str, globals(), 128)
+
+
+PC, PC_init = gen_reg("PC", globals(), 64)
+WZR, WZR_init = gen_reg("WZR", globals(), 32)
+XZR, XZR_init = gen_reg("XZR", globals(), 64)
+
+reg_zf = 'zf'
+reg_nf = 'nf'
+reg_of = 'of'
+reg_cf = 'cf'
+
+zf = ExprId(reg_zf, size=1)
+nf = ExprId(reg_nf, size=1)
+of = ExprId(reg_of, size=1)
+cf = ExprId(reg_cf, size=1)
+
+zf_init = ExprId("zf_init", size=1)
+nf_init = ExprId("nf_init", size=1)
+of_init = ExprId("of_init", size=1)
+cf_init = ExprId("cf_init", size=1)
+
+
+all_regs_ids = [
+    B0, B1, B2, B3, B4, B5, B6, B7, B8, B9, B10, B11, B12, B13, B14, B15, B16,
+    B17, B18, B19, B20, B21, B22, B23, B24, B25, B26, B27, B28, B29, B30, B31,
+
+    H0, H1, H2, H3, H4, H5, H6, H7, H8, H9, H10, H11, H12, H13, H14, H15, H16,
+    H17, H18, H19, H20, H21, H22, H23, H24, H25, H26, H27, H28, H29, H30, H31,
+
+    S0, S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, S12, S13, S14, S15, S16,
+    S17, S18, S19, S20, S21, S22, S23, S24, S25, S26, S27, S28, S29, S30, S31,
+
+    D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11, D12, D13, D14, D15, D16,
+    D17, D18, D19, D20, D21, D22, D23, D24, D25, D26, D27, D28, D29, D30, D31,
+
+    Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, Q10, Q11, Q12, Q13, Q14, Q15, Q16,
+    Q17, Q18, Q19, Q20, Q21, Q22, Q23, Q24, Q25, Q26, Q27, Q28, Q29, Q30, Q31,
+
+    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,
+
+    X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X12, X13, X14, X15, X16,
+    X17, X18, X19, X20, X21, X22, X23, X24, X25, X26, X27, X28, X29, LR, SP,
+
+    exception_flags,
+    PC,
+    WZR, WZR,
+    zf, nf, of, cf,
+    XZR, WZR,
+
+]
+
+
+all_regs_ids_no_alias = all_regs_ids
+
+all_regs_ids_byname = dict([(x.name, x) for x in all_regs_ids])
+
+all_regs_ids_init = (simd08_init +
+                     simd16_init +
+                     simd32_init +
+                     simd64_init +
+                     simd128_init +
+                     gpregs32_init +
+                     gpregs64_init +
+                     [
+                         ExprInt32(0),
+                         PC_init,
+                         WZR_init,
+                         XZR_init,
+                         zf_init, nf_init, of_init, cf_init,
+                         ExprInt64(0), ExprInt32(0),
+                     ]
+                     )
+
+regs_init = {}
+for i, r in enumerate(all_regs_ids):
+    regs_init[r] = all_regs_ids_init[i]
+
+regs_flt_expr = []
diff --git a/miasm2/arch/aarch64/sem.py b/miasm2/arch/aarch64/sem.py
new file mode 100644
index 00000000..800cc677
--- /dev/null
+++ b/miasm2/arch/aarch64/sem.py
@@ -0,0 +1,740 @@
+from miasm2.expression import expression as m2_expr
+from miasm2.ir.ir import ir, irbloc
+from miasm2.arch.aarch64.arch import mn_aarch64, conds_expr, replace_regs
+from miasm2.arch.aarch64.regs import *
+from miasm2.core.sembuilder import SemBuilder
+
+EXCEPT_PRIV_INSN = (1 << 17)
+
+# CPSR: N Z C V
+
+
+def update_flag_zf(a):
+    return [m2_expr.ExprAff(zf, m2_expr.ExprCond(a, m2_expr.ExprInt1(0), m2_expr.ExprInt1(1)))]
+
+
+def update_flag_nf(a):
+    return [m2_expr.ExprAff(nf, a.msb())]
+
+
+def update_flag_zn(a):
+    e = []
+    e += update_flag_zf(a)
+    e += update_flag_nf(a)
+    return e
+
+
+def update_flag_logic(a):
+    e = []
+    e += update_flag_zn(a)
+    # XXX TODO: set cf if ROT imm in argument
+    # e.append(m2_expr.ExprAff(cf, m2_expr.ExprInt1(0)))
+    return e
+
+
+def update_flag_arith(a):
+    e = []
+    e += update_flag_zn(a)
+    return e
+
+
+def check_ops_msb(a, b, c):
+    if not a or not b or not c or a != b or a != c:
+        raise ValueError('bad ops size %s %s %s' % (a, b, c))
+
+
+def arith_flag(a, b, c):
+    a_s, b_s, c_s = a.size, b.size, c.size
+    check_ops_msb(a_s, b_s, c_s)
+    a_s, b_s, c_s = a.msb(), b.msb(), c.msb()
+    return a_s, b_s, c_s
+
+# checked: ok for adc add because b & c before +cf
+
+
+def update_flag_add_cf(op1, op2, res):
+    "Compute cf in @res = @op1 + @op2"
+    return m2_expr.ExprAff(cf, (((op1 ^ op2) ^ res) ^ ((op1 ^ res) & (~(op1 ^ op2)))).msb())
+
+
+def update_flag_add_of(op1, op2, res):
+    "Compute of in @res = @op1 + @op2"
+    return m2_expr.ExprAff(of, (((op1 ^ res) & (~(op1 ^ op2)))).msb())
+
+
+# checked: ok for sbb add because b & c before +cf
+def update_flag_sub_cf(op1, op2, res):
+    "Compote CF in @res = @op1 - @op2"
+    return m2_expr.ExprAff(cf,
+                           ((((op1 ^ op2) ^ res) ^ ((op1 ^ res) & (op1 ^ op2))).msb()) ^ m2_expr.ExprInt1(1))
+
+
+def update_flag_sub_of(op1, op2, res):
+    "Compote OF in @res = @op1 - @op2"
+    return m2_expr.ExprAff(of, (((op1 ^ res) & (op1 ^ op2))).msb())
+
+# z = x+y (+cf?)
+
+
+def update_flag_add(x, y, z):
+    e = []
+    e.append(update_flag_add_cf(x, y, z))
+    e.append(update_flag_add_of(x, y, z))
+    return e
+
+# z = x-y (+cf?)
+
+
+def update_flag_sub(x, y, z):
+    e = []
+    e.append(update_flag_sub_cf(x, y, z))
+    e.append(update_flag_sub_of(x, y, z))
+    return e
+
+
+cond2expr = {'EQ': zf,
+             'NE': zf ^ m2_expr.ExprInt1(1),
+             'CS': cf,
+             'CC': cf ^ m2_expr.ExprInt1(1),
+             'MI': nf,
+             'PL': nf ^ m2_expr.ExprInt1(1),
+             'VS': of,
+             'VC': of ^ m2_expr.ExprInt1(1),
+             'HI': cf & (zf ^ m2_expr.ExprInt1(1)),
+             'LS': (cf ^ m2_expr.ExprInt1(1)) | zf,
+             'GE': nf ^ of ^ m2_expr.ExprInt1(1),
+             'LT': nf ^ of,
+             'GT': ((zf ^ m2_expr.ExprInt1(1)) &
+                    (nf ^ of ^ m2_expr.ExprInt1(1))),
+             'LE': zf | (nf ^ of),
+             'AL': m2_expr.ExprInt1(1),
+             'NV': m2_expr.ExprInt1(0)
+             }
+
+
+def extend_arg(dst, arg):
+    if not isinstance(arg, m2_expr.ExprOp):
+        return arg
+
+    op, (reg, shift) = arg.op, arg.args
+    if op == 'SXTW':
+        base = reg.signExtend(dst.size)
+    else:
+        base = reg.zeroExtend(dst.size)
+
+    out = base << (shift.zeroExtend(dst.size)
+                   & m2_expr.ExprInt_from(dst, dst.size - 1))
+    return out
+
+
+# SemBuilder context
+ctx = {"PC": PC,
+       "LR": LR,
+       "nf": nf,
+       "zf": zf,
+       "cf": cf,
+       "of": of,
+       "cond2expr": cond2expr,
+       "extend_arg": extend_arg,
+       "m2_expr":m2_expr
+       }
+
+sbuild = SemBuilder(ctx)
+
+
+# instruction definition ##############
+
+@sbuild.parse
+def add(arg1, arg2, arg3):
+    arg1 = arg2 + extend_arg(arg2, arg3)
+
+
+@sbuild.parse
+def sub(arg1, arg2, arg3):
+    arg1 = arg2 - extend_arg(arg2, arg3)
+
+
+@sbuild.parse
+def neg(arg1, arg2):
+    arg1 = - arg2
+
+
+@sbuild.parse
+def and_l(arg1, arg2, arg3):
+    arg1 = arg2 & extend_arg(arg2, arg3)
+
+
+@sbuild.parse
+def eor(arg1, arg2, arg3):
+    arg1 = arg2 ^ extend_arg(arg2, arg3)
+
+
+@sbuild.parse
+def eon(arg1, arg2, arg3):
+    arg1 = arg2 ^ (~extend_arg(arg2, arg3))
+
+
+@sbuild.parse
+def orr(arg1, arg2, arg3):
+    arg1 = arg2 | extend_arg(arg2, arg3)
+
+
+@sbuild.parse
+def orn(arg1, arg2, arg3):
+    arg1 = arg2 | (~extend_arg(arg2, arg3))
+
+
+@sbuild.parse
+def bic(arg1, arg2, arg3):
+    arg1 = arg2 & (~extend_arg(arg2, arg3))
+
+
+@sbuild.parse
+def mvn(arg1, arg2):
+    arg1 = (~extend_arg(arg1, arg2))
+
+
+def adds(ir, instr, arg1, arg2, arg3):
+    e = []
+    arg3 = extend_arg(arg2, arg3)
+    res = arg2 + arg3
+    e += update_flag_arith(res)
+    e += update_flag_add(arg2, arg3, res)
+    e.append(m2_expr.ExprAff(arg1, res))
+    return e, []
+
+
+def subs(ir, instr, arg1, arg2, arg3):
+    e = []
+    arg3 = extend_arg(arg2, arg3)
+    res = arg2 - arg3
+    e += update_flag_arith(res)
+    e += update_flag_sub(arg2, arg3, res)
+    e.append(m2_expr.ExprAff(arg1, res))
+    return e, []
+
+
+def cmp(ir, instr, arg1, arg2):
+    e = []
+    arg2 = extend_arg(arg1, arg2)
+    res = arg1 - arg2
+    e += update_flag_arith(res)
+    e += update_flag_sub(arg1, arg2, res)
+    return e, []
+
+
+def cmn(ir, instr, arg1, arg2):
+    e = []
+    arg2 = extend_arg(arg1, arg2)
+    res = arg1 + arg2
+    e += update_flag_arith(res)
+    e += update_flag_add(arg1, arg2, res)
+    return e, []
+
+
+def ands(ir, instr, arg1, arg2, arg3):
+    e = []
+    arg3 = extend_arg(arg2, arg3)
+    res = arg2 & arg3
+    e += update_flag_logic(res)
+    e.append(m2_expr.ExprAff(arg1, res))
+    return e, []
+
+
+@sbuild.parse
+def lsl(arg1, arg2, arg3):
+    arg1 = arg2 << (arg3 & m2_expr.ExprInt_from(arg3, arg3.size - 1))
+
+
+@sbuild.parse
+def lsr(arg1, arg2, arg3):
+    arg1 = arg2 >> (arg3 & m2_expr.ExprInt_from(arg3, arg3.size - 1))
+
+
+@sbuild.parse
+def asr(arg1, arg2, arg3):
+    arg1 = m2_expr.ExprOp(
+        'a>>', arg2, (arg3 & m2_expr.ExprInt_from(arg3, arg3.size - 1)))
+
+
+@sbuild.parse
+def mov(arg1, arg2):
+    arg1 = arg2
+
+
+def movk(ir, instr, arg1, arg2):
+    e = []
+    if isinstance(arg2, m2_expr.ExprOp):
+        assert(arg2.op == 'slice_at' and
+               isinstance(arg2.args[0], m2_expr.ExprInt) and
+               isinstance(arg2.args[1], m2_expr.ExprInt))
+        value, shift = int(arg2.args[0].arg), int(arg2.args[1].arg)
+        e.append(
+            m2_expr.ExprAff(arg1[shift:shift + 16], m2_expr.ExprInt16(value)))
+    else:
+        e.append(m2_expr.ExprAff(arg1[:16], m2_expr.ExprInt16(int(arg2.arg))))
+
+    return e, []
+
+
+@sbuild.parse
+def movz(arg1, arg2):
+    arg1 = arg2
+
+
+@sbuild.parse
+def movn(arg1, arg2):
+    arg1 = ~arg2
+
+
+@sbuild.parse
+def bl(arg1):
+    PC = arg1
+    ir.IRDst = arg1
+    LR = m2_expr.ExprInt64(instr.offset + instr.l)
+
+@sbuild.parse
+def csel(arg1, arg2, arg3, arg4):
+    cond_expr = cond2expr[arg4.name]
+    arg1 = arg2 if cond_expr else arg3
+
+
+def csinc(ir, instr, arg1, arg2, arg3, arg4):
+    e = []
+    cond_expr = cond2expr[arg4.name]
+    e.append(m2_expr.ExprAff(arg1, m2_expr.ExprCond(cond_expr,
+                                                    arg2,
+                                                    arg3 + m2_expr.ExprInt_from(arg3, 1))))
+    return e, []
+
+
+def csinv(ir, instr, arg1, arg2, arg3, arg4):
+    e = []
+    cond_expr = cond2expr[arg4.name]
+    e.append(m2_expr.ExprAff(arg1, m2_expr.ExprCond(cond_expr,
+                                                    arg2,
+                                                    ~arg3)))
+    return e, []
+
+
+def csneg(ir, instr, arg1, arg2, arg3, arg4):
+    e = []
+    cond_expr = cond2expr[arg4.name]
+    e.append(m2_expr.ExprAff(arg1, m2_expr.ExprCond(cond_expr,
+                                                    arg2,
+                                                    -arg3)))
+    return e, []
+
+
+def cset(ir, instr, arg1, arg2):
+    e = []
+    cond_expr = cond2expr[arg2.name]
+    e.append(m2_expr.ExprAff(arg1, m2_expr.ExprCond(cond_expr,
+                                                    m2_expr.ExprInt_from(
+                                                        arg1, 1),
+                                                    m2_expr.ExprInt_from(arg1, 0))))
+    return e, []
+
+
+def csetm(ir, instr, arg1, arg2):
+    e = []
+    cond_expr = cond2expr[arg2.name]
+    e.append(m2_expr.ExprAff(arg1, m2_expr.ExprCond(cond_expr,
+                                                    m2_expr.ExprInt_from(
+                                                        arg1, -1),
+                                                    m2_expr.ExprInt_from(arg1, 0))))
+    return e, []
+
+
+def get_mem_access(mem):
+    updt = None
+    if isinstance(mem, m2_expr.ExprOp):
+        if mem.op == 'preinc':
+            addr = mem.args[0] + mem.args[1]
+        elif mem.op == 'segm':
+            base = mem.args[0]
+            op, (reg, shift) = mem.args[1].op, mem.args[1].args
+            if op == 'SXTW':
+                off = reg.signExtend(base.size) << shift.zeroExtend(base.size)
+                addr = base + off
+            elif op == 'UXTW':
+                off = reg.zeroExtend(base.size) << shift.zeroExtend(base.size)
+                addr = base + off
+            elif op == 'LSL':
+                if isinstance(shift, m2_expr.ExprInt) and int(shift.arg) == 0:
+                    addr = base + reg.zeroExtend(base.size)
+                else:
+                    addr = base + \
+                        (reg.zeroExtend(base.size)
+                         << shift.zeroExtend(base.size))
+            else:
+                raise NotImplementedError('bad op')
+        elif mem.op == "postinc":
+            addr, off = mem.args
+            updt = m2_expr.ExprAff(addr, addr + off)
+        elif mem.op == "preinc_wb":
+            base, off = mem.args
+            addr = base + off
+            updt = m2_expr.ExprAff(base, base + off)
+        else:
+            raise NotImplementedError('bad op')
+    else:
+        raise NotImplementedError('bad op')
+    return addr, updt
+
+
+def strb(ir, instr, arg1, arg2):
+    e = []
+    addr, updt = get_mem_access(arg2)
+    e.append(m2_expr.ExprAff(m2_expr.ExprMem(addr, 8), arg1[:8]))
+    if updt:
+        e.append(updt)
+    return e, []
+
+
+def ldrb(ir, instr, arg1, arg2):
+    e = []
+    addr, updt = get_mem_access(arg2)
+    e.append(
+        m2_expr.ExprAff(arg1, m2_expr.ExprMem(addr, 8).zeroExtend(arg1.size)))
+    if updt:
+        e.append(updt)
+    return e, []
+
+
+def str(ir, instr, arg1, arg2):
+    e = []
+    addr, updt = get_mem_access(arg2)
+    e.append(m2_expr.ExprAff(m2_expr.ExprMem(addr, arg1.size), arg1))
+    if updt:
+        e.append(updt)
+    return e, []
+
+
+def ldr(ir, instr, arg1, arg2):
+    e = []
+    addr, updt = get_mem_access(arg2)
+    e.append(m2_expr.ExprAff(arg1, m2_expr.ExprMem(addr, arg1.size)))
+    if updt:
+        e.append(updt)
+    return e, []
+
+
+def stp(ir, instr, arg1, arg2, arg3):
+    e = []
+    addr, updt = get_mem_access(arg3)
+    e.append(m2_expr.ExprAff(m2_expr.ExprMem(addr, arg1.size), arg1))
+    e.append(
+        m2_expr.ExprAff(m2_expr.ExprMem(addr + m2_expr.ExprInt_from(addr, arg1.size / 8), arg2.size), arg2))
+    if updt:
+        e.append(updt)
+    return e, []
+
+
+def ldp(ir, instr, arg1, arg2, arg3):
+    e = []
+    addr, updt = get_mem_access(arg3)
+    e.append(m2_expr.ExprAff(arg1, m2_expr.ExprMem(addr, arg1.size)))
+    e.append(
+        m2_expr.ExprAff(arg2, m2_expr.ExprMem(addr + m2_expr.ExprInt_from(addr, arg1.size / 8), arg2.size)))
+    if updt:
+        e.append(updt)
+    return e, []
+
+
+def ldrsw(ir, instr, arg1, arg2):
+    e = []
+    addr, updt = get_mem_access(arg2)
+    e.append(
+        m2_expr.ExprAff(arg1, m2_expr.ExprMem(addr, 32).signExtend(arg1.size)))
+    if updt:
+        e.append(updt)
+    return e, []
+
+
+def sbfm(ir, instr, arg1, arg2, arg3, arg4):
+    e = []
+    rim, sim = int(arg3.arg), int(arg4.arg) + 1
+    if sim > rim:
+        res = arg2[rim:sim].signExtend(arg1.size)
+    else:
+        shift = m2_expr.ExprInt_from(arg2, arg2.size - rim)
+        res = (arg2[:sim].signExtend(arg1.size) << shift)
+    e.append(m2_expr.ExprAff(arg1, res))
+    return e, []
+
+
+def ubfm(ir, instr, arg1, arg2, arg3, arg4):
+    e = []
+    rim, sim = int(arg3.arg), int(arg4.arg) + 1
+    if sim > rim:
+        res = arg2[rim:sim].zeroExtend(arg1.size)
+    else:
+        shift = m2_expr.ExprInt_from(arg2, arg2.size - rim)
+        res = (arg2[:sim].zeroExtend(arg1.size) << shift)
+    e.append(m2_expr.ExprAff(arg1, res))
+    return e, []
+
+
+@sbuild.parse
+def madd(arg1, arg2, arg3, arg4):
+    arg1 = arg2 * arg3 + arg4
+
+
+@sbuild.parse
+def udiv(arg1, arg2, arg3):
+    arg1 = m2_expr.ExprOp('udiv', arg2, arg3)
+
+
+@sbuild.parse
+def cbz(arg1, arg2):
+    dst = m2_expr.ExprId(ir.get_next_label(instr), 64) if arg1 else arg2
+    PC = dst
+    ir.IRDst = dst
+
+
+@sbuild.parse
+def cbnz(arg1, arg2):
+    dst = arg2 if arg1 else m2_expr.ExprId(ir.get_next_label(instr), 64)
+    PC = dst
+    ir.IRDst = dst
+
+
+@sbuild.parse
+def tbz(arg1, arg2, arg3):
+    bitmask = m2_expr.ExprInt_from(arg1, 1) << arg2
+    dst = m2_expr.ExprId(
+        ir.get_next_label(instr), 64) if arg1 & bitmask else arg3
+    PC = dst
+    ir.IRDst = dst
+
+
+@sbuild.parse
+def tbnz(arg1, arg2, arg3):
+    bitmask = m2_expr.ExprInt_from(arg1, 1) << arg2
+    dst = arg3 if arg1 & bitmask else m2_expr.ExprId(
+        ir.get_next_label(instr), 64)
+    PC = dst
+    ir.IRDst = dst
+
+
+@sbuild.parse
+def b_ne(arg1):
+    dst = m2_expr.ExprId(ir.get_next_label(instr), 64) if zf else arg1
+    PC = dst
+    ir.IRDst = dst
+
+
+@sbuild.parse
+def b_eq(arg1):
+    dst = arg1 if zf else m2_expr.ExprId(ir.get_next_label(instr), 64)
+    PC = dst
+    ir.IRDst = dst
+
+
+@sbuild.parse
+def b_ge(arg1):
+    cond = cond2expr['GE']
+    dst = arg1 if cond else m2_expr.ExprId(ir.get_next_label(instr), 64)
+    PC = dst
+    ir.IRDst = dst
+
+
+@sbuild.parse
+def b_gt(arg1):
+    cond = cond2expr['GT']
+    dst = arg1 if cond else m2_expr.ExprId(ir.get_next_label(instr), 64)
+    PC = dst
+    ir.IRDst = dst
+
+
+@sbuild.parse
+def b_cc(arg1):
+    cond = cond2expr['CC']
+    dst = arg1 if cond else m2_expr.ExprId(ir.get_next_label(instr), 64)
+    PC = dst
+    ir.IRDst = dst
+
+
+@sbuild.parse
+def b_cs(arg1):
+    cond = cond2expr['CS']
+    dst = arg1 if cond else m2_expr.ExprId(ir.get_next_label(instr), 64)
+    PC = dst
+    ir.IRDst = dst
+
+
+@sbuild.parse
+def b_hi(arg1):
+    cond = cond2expr['HI']
+    dst = arg1 if cond else m2_expr.ExprId(ir.get_next_label(instr), 64)
+    PC = dst
+    ir.IRDst = dst
+
+
+@sbuild.parse
+def b_le(arg1):
+    cond = cond2expr['LE']
+    dst = arg1 if cond else m2_expr.ExprId(ir.get_next_label(instr), 64)
+    PC = dst
+    ir.IRDst = dst
+
+
+@sbuild.parse
+def b_ls(arg1):
+    cond = cond2expr['LS']
+    dst = arg1 if cond else m2_expr.ExprId(ir.get_next_label(instr), 64)
+    PC = dst
+    ir.IRDst = dst
+
+
+@sbuild.parse
+def b_lt(arg1):
+    cond = cond2expr['LT']
+    dst = arg1 if cond else m2_expr.ExprId(ir.get_next_label(instr), 64)
+    PC = dst
+    ir.IRDst = dst
+
+
+@sbuild.parse
+def ret(arg1):
+    PC = arg1
+    ir.IRDst = arg1
+
+
+@sbuild.parse
+def adrp(arg1, arg2):
+    arg1 = (PC & m2_expr.ExprInt64(0xfffffffffffff000)) + arg2
+
+
+@sbuild.parse
+def b(arg1):
+    PC = arg1
+    ir.IRDst = arg1
+
+
+@sbuild.parse
+def br(arg1):
+    PC = arg1
+    ir.IRDst = arg1
+
+
+@sbuild.parse
+def nop():
+    """Do nothing"""
+
+mnemo_func = sbuild.functions
+mnemo_func.update({
+    'and': and_l,
+    'adds': adds,
+    'ands': ands,
+    'subs': subs,
+    'cmp': cmp,
+    'cmn': cmn,
+    'movk': movk,
+    'csinc': csinc,
+    'csinv': csinv,
+    'csneg': csneg,
+    'cset': cset,
+    'csetm': csetm,
+
+    'b.ne': b_ne,
+    'b.eq': b_eq,
+    'b.ge': b_ge,
+    'b.gt': b_gt,
+    'b.cc': b_cc,
+    'b.cs': b_cs,
+    'b.hi': b_hi,
+    'b.le': b_le,
+    'b.ls': b_ls,
+    'b.lt': b_lt,
+
+    'ret': ret,
+    'stp': stp,
+    'ldp': ldp,
+
+    'str': str,
+    'ldr': ldr,
+
+    'ldur': ldr,  # XXXX CHECK
+
+    'ldrsw': ldrsw,
+
+    'strb': strb,
+    'ldrb': ldrb,
+
+    'sbfm': sbfm,
+    'ubfm': ubfm,
+
+})
+
+
+def get_mnemo_expr(ir, instr, *args):
+    if not instr.name.lower() in mnemo_func:
+        raise NotImplementedError('unknown mnemo %s' % instr)
+    instr, extra_ir = mnemo_func[instr.name.lower()](ir, instr, *args)
+    return instr, extra_ir
+
+
+class aarch64info:
+    mode = "aarch64"
+    # offset
+
+
+class ir_aarch64l(ir):
+
+    def __init__(self, symbol_pool=None):
+        ir.__init__(self, mn_aarch64, "l", symbol_pool)
+        self.pc = PC
+        self.sp = SP
+        self.IRDst = m2_expr.ExprId('IRDst', 64)
+
+    def get_ir(self, instr):
+        args = instr.args
+        if len(args) and isinstance(args[-1], m2_expr.ExprOp):
+            if (args[-1].op in ['<<', '>>', '<<a', 'a>>', '<<<', '>>>'] and
+               isinstance(args[-1].args[-1], m2_expr.ExprId)):
+                args[-1] = m2_expr.ExprOp(args[-1].op,
+                                          args[-1].args[0],
+                                          args[-1].args[-1][:8].zeroExtend(32))
+        instr_ir, extra_ir = get_mnemo_expr(self, instr, *args)
+        # for i, expr in enumerate(instr_ir):
+        #    instr_ir[i] = self.expraff_fix_regs_for_mode(expr)
+        # for b in extra_ir:
+        #    for irs in b.irs:
+        #        for i, expr in enumerate(irs):
+        #            irs[i] = self.expraff_fix_regs_for_mode(expr)
+        return instr_ir, extra_ir
+
+    def expr_fix_regs_for_mode(self, e):
+        return e.replace_expr(replace_regs)
+
+    def expraff_fix_regs_for_mode(self, e):
+        dst = self.expr_fix_regs_for_mode(e.dst)
+        src = self.expr_fix_regs_for_mode(e.src)
+        return m2_expr.ExprAff(dst, src)
+
+    def irbloc_fix_regs_for_mode(self, irbloc, mode=64):
+        for irs in irbloc.irs:
+            for i, e in enumerate(irs):
+                """
+                special case for 64 bits:
+                if destination is a 32 bit reg, zero extend the 64 bit reg
+                """
+                if (isinstance(e.dst, m2_expr.ExprId) and
+                        e.dst.size == 32 and
+                        e.dst in replace_regs):
+                    src = self.expr_fix_regs_for_mode(e.src)
+                    dst = replace_regs[e.dst].arg
+                    e = m2_expr.ExprAff(dst, src.zeroExtend(64))
+                irs[i] = self.expr_fix_regs_for_mode(e)
+        irbloc.dst = self.expr_fix_regs_for_mode(irbloc.dst)
+
+
+class ir_aarch64b(ir_aarch64l):
+
+    def __init__(self, symbol_pool=None):
+        ir.__init__(self, mn_aarch64, "b", symbol_pool)
+        self.pc = PC
+        self.sp = SP
+        self.IRDst = m2_expr.ExprId('IRDst', 64)
diff --git a/miasm2/jitter/arch/JitCore_aarch64.c b/miasm2/jitter/arch/JitCore_aarch64.c
new file mode 100644
index 00000000..28661bfe
--- /dev/null
+++ b/miasm2/jitter/arch/JitCore_aarch64.c
@@ -0,0 +1,699 @@
+#include <Python.h>
+#include "../JitCore.h"
+#include "structmember.h"
+#include <stdint.h>
+#include <inttypes.h>
+#include "../queue.h"
+#include "../vm_mngr.h"
+#include "../vm_mngr_py.h"
+#include "JitCore_aarch64.h"
+
+
+
+reg_dict gpreg_dict[] = {
+	{.name = "X0", .offset = offsetof(vm_cpu_t, X0)},
+	{.name = "X1", .offset = offsetof(vm_cpu_t, X1)},
+	{.name = "X2", .offset = offsetof(vm_cpu_t, X2)},
+	{.name = "X3", .offset = offsetof(vm_cpu_t, X3)},
+	{.name = "X4", .offset = offsetof(vm_cpu_t, X4)},
+	{.name = "X5", .offset = offsetof(vm_cpu_t, X5)},
+	{.name = "X6", .offset = offsetof(vm_cpu_t, X6)},
+	{.name = "X7", .offset = offsetof(vm_cpu_t, X7)},
+	{.name = "X8", .offset = offsetof(vm_cpu_t, X8)},
+	{.name = "X9", .offset = offsetof(vm_cpu_t, X9)},
+	{.name = "X10", .offset = offsetof(vm_cpu_t, X10)},
+	{.name = "X11", .offset = offsetof(vm_cpu_t, X11)},
+	{.name = "X12", .offset = offsetof(vm_cpu_t, X12)},
+	{.name = "X13", .offset = offsetof(vm_cpu_t, X13)},
+	{.name = "X14", .offset = offsetof(vm_cpu_t, X14)},
+	{.name = "X15", .offset = offsetof(vm_cpu_t, X15)},
+	{.name = "X16", .offset = offsetof(vm_cpu_t, X16)},
+	{.name = "X17", .offset = offsetof(vm_cpu_t, X17)},
+	{.name = "X18", .offset = offsetof(vm_cpu_t, X18)},
+	{.name = "X19", .offset = offsetof(vm_cpu_t, X19)},
+	{.name = "X20", .offset = offsetof(vm_cpu_t, X20)},
+	{.name = "X21", .offset = offsetof(vm_cpu_t, X21)},
+	{.name = "X22", .offset = offsetof(vm_cpu_t, X22)},
+	{.name = "X23", .offset = offsetof(vm_cpu_t, X23)},
+	{.name = "X24", .offset = offsetof(vm_cpu_t, X24)},
+	{.name = "X25", .offset = offsetof(vm_cpu_t, X25)},
+	{.name = "X26", .offset = offsetof(vm_cpu_t, X26)},
+	{.name = "X27", .offset = offsetof(vm_cpu_t, X27)},
+	{.name = "X28", .offset = offsetof(vm_cpu_t, X28)},
+	{.name = "X29", .offset = offsetof(vm_cpu_t, X29)},
+	{.name = "LR", .offset = offsetof(vm_cpu_t, LR)},
+
+	{.name = "SP", .offset = offsetof(vm_cpu_t, SP)},
+	{.name = "PC", .offset = offsetof(vm_cpu_t, PC)},
+
+	{.name = "zf", .offset = offsetof(vm_cpu_t, zf)},
+	{.name = "nf", .offset = offsetof(vm_cpu_t, nf)},
+	{.name = "of", .offset = offsetof(vm_cpu_t, of)},
+	{.name = "cf", .offset = offsetof(vm_cpu_t, cf)},
+};
+
+/************************** JitCpu object **************************/
+
+
+
+
+PyObject* cpu_get_gpreg(JitCpu* self)
+{
+    PyObject *dict = PyDict_New();
+    PyObject *o;
+
+    get_reg(X0);
+    get_reg(X1);
+    get_reg(X2);
+    get_reg(X3);
+    get_reg(X4);
+    get_reg(X5);
+    get_reg(X6);
+    get_reg(X7);
+    get_reg(X8);
+    get_reg(X9);
+    get_reg(X10);
+    get_reg(X11);
+    get_reg(X12);
+    get_reg(X13);
+    get_reg(X14);
+    get_reg(X15);
+    get_reg(X16);
+    get_reg(X17);
+    get_reg(X18);
+    get_reg(X19);
+    get_reg(X20);
+    get_reg(X21);
+    get_reg(X22);
+    get_reg(X23);
+    get_reg(X24);
+    get_reg(X25);
+    get_reg(X26);
+    get_reg(X27);
+    get_reg(X28);
+    get_reg(X29);
+    get_reg(LR);
+    get_reg(SP);
+    get_reg(PC);
+
+    get_reg(zf);
+    get_reg(nf);
+    get_reg(of);
+    get_reg(cf);
+
+    return dict;
+}
+
+
+
+PyObject* cpu_set_gpreg(JitCpu* self, PyObject *args)
+{
+    PyObject* dict;
+    PyObject *d_key, *d_value = NULL;
+    Py_ssize_t pos = 0;
+    uint64_t val;
+    unsigned int i, found;
+
+    if (!PyArg_ParseTuple(args, "O", &dict))
+	    return NULL;
+    if(!PyDict_Check(dict))
+	    RAISE(PyExc_TypeError, "arg must be dict");
+    while(PyDict_Next(dict, &pos, &d_key, &d_value)){
+	    if(!PyString_Check(d_key))
+		    RAISE(PyExc_TypeError, "key must be str");
+
+	    PyGetInt(d_value, val);
+
+	    found = 0;
+	    for (i=0; i < sizeof(gpreg_dict)/sizeof(reg_dict); i++){
+		    if (strcmp(PyString_AsString(d_key), gpreg_dict[i].name))
+			    continue;
+		    *((uint32_t*)(((char*)(self->cpu)) + gpreg_dict[i].offset)) = val;
+		    found = 1;
+		    break;
+	    }
+
+	    if (found)
+		    continue;
+	    fprintf(stderr, "unkown key: %s\n", PyString_AsString(d_key));
+	    RAISE(PyExc_ValueError, "unkown reg");
+    }
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+
+PyObject * cpu_init_regs(JitCpu* self)
+{
+	memset(self->cpu, 0, sizeof(vm_cpu_t));
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+void dump_gpregs(vm_cpu_t* vmcpu)
+{
+	printf("X0  %.16"PRIX64" X1  %.16"PRIX64" X2  %.16"PRIX64" X3  %.16"PRIX64" "\
+	       "X4  %.16"PRIX64" X5  %.16"PRIX64" X6  %.16"PRIX64" X7  %.16"PRIX64"\n",
+	       vmcpu->X0, vmcpu->X1, vmcpu->X2, vmcpu->X3, vmcpu->X4, vmcpu->X5, vmcpu->X6, vmcpu->X7);
+	printf("X8  %.16"PRIX64" X9  %.16"PRIX64" X10 %.16"PRIX64" X11 %.16"PRIX64" "\
+	       "X12 %.16"PRIX64" X13 %.16"PRIX64" X14 %.16"PRIX64" X15 %.16"PRIX64"\n",
+	       vmcpu->X8, vmcpu->X9, vmcpu->X10, vmcpu->X11,
+	       vmcpu->X12, vmcpu->X13, vmcpu->X14, vmcpu->X15);
+	printf("X16 %.16"PRIX64" X17 %.16"PRIX64" X18 %.16"PRIX64" X19 %.16"PRIX64" "\
+	       "X20 %.16"PRIX64" X21 %.16"PRIX64" X22 %.16"PRIX64" X23 %.16"PRIX64"\n",
+	       vmcpu->X16, vmcpu->X17, vmcpu->X18, vmcpu->X19,
+	       vmcpu->X20, vmcpu->X21, vmcpu->X22, vmcpu->X23);
+	printf("X24 %.16"PRIX64" X25 %.16"PRIX64" X26 %.16"PRIX64" X27 %.16"PRIX64" "\
+	       "X28 %.16"PRIX64" X29 %.16"PRIX64" LR  %.16"PRIX64"\n",
+	       vmcpu->X24, vmcpu->X25, vmcpu->X26, vmcpu->X27,
+	       vmcpu->X28, vmcpu->X29, vmcpu->LR);
+
+
+	printf("SP  %.16"PRIX64" PC  %.16"PRIX64" "\
+	       "zf  %.16"PRIX32" nf  %.16"PRIX32" of  %.16"PRIX32" cf  %.16"PRIX32"\n",
+	       vmcpu->SP, vmcpu->PC,
+	       vmcpu->zf, vmcpu->nf, vmcpu->of, vmcpu->cf);
+}
+
+
+PyObject * cpu_dump_gpregs(JitCpu* self, PyObject* args)
+{
+	vm_cpu_t* vmcpu;
+
+	vmcpu = self->cpu;
+	dump_gpregs(vmcpu);
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+
+PyObject* cpu_set_exception(JitCpu* self, PyObject* args)
+{
+	PyObject *item1;
+	uint64_t i;
+
+	if (!PyArg_ParseTuple(args, "O", &item1))
+		return NULL;
+
+	PyGetInt(item1, i);
+
+	((vm_cpu_t*)self->cpu)->exception_flags = i;
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+PyObject* cpu_get_exception(JitCpu* self, PyObject* args)
+{
+	return PyLong_FromUnsignedLongLong((uint64_t)(((vm_cpu_t*)self->cpu)->exception_flags));
+}
+
+
+
+
+
+void check_automod(JitCpu* jitcpu, uint64_t addr, uint64_t size)
+{
+	PyObject *result;
+
+	if (!(((VmMngr*)jitcpu->pyvm)->vm_mngr.exception_flags & EXCEPT_CODE_AUTOMOD))
+		return;
+	result = PyObject_CallMethod(jitcpu->jitter, "automod_cb", "LL", addr, size);
+	Py_DECREF(result);
+
+}
+
+void MEM_WRITE_08(JitCpu* jitcpu, uint64_t addr, uint8_t src)
+{
+	vm_MEM_WRITE_08(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src);
+	check_automod(jitcpu, addr, 8);
+}
+
+void MEM_WRITE_16(JitCpu* jitcpu, uint64_t addr, uint16_t src)
+{
+	vm_MEM_WRITE_16(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src);
+	check_automod(jitcpu, addr, 16);
+}
+
+void MEM_WRITE_32(JitCpu* jitcpu, uint64_t addr, uint32_t src)
+{
+	vm_MEM_WRITE_32(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src);
+	check_automod(jitcpu, addr, 32);
+}
+
+void MEM_WRITE_64(JitCpu* jitcpu, uint64_t addr, uint64_t src)
+{
+	vm_MEM_WRITE_64(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src);
+	check_automod(jitcpu, addr, 64);
+}
+
+
+
+
+
+
+PyObject* vm_set_mem(JitCpu *self, PyObject* args)
+{
+       PyObject *py_addr;
+       PyObject *py_buffer;
+       Py_ssize_t py_length;
+
+       char * buffer;
+       uint64_t size;
+       uint64_t addr;
+       int ret = 0x1337;
+
+       if (!PyArg_ParseTuple(args, "OO", &py_addr, &py_buffer))
+	       return NULL;
+
+       PyGetInt(py_addr, addr);
+
+       if(!PyString_Check(py_buffer))
+	       RAISE(PyExc_TypeError,"arg must be str");
+
+       size = PyString_Size(py_buffer);
+       PyString_AsStringAndSize(py_buffer, &buffer, &py_length);
+
+       ret = vm_write_mem(&(((VmMngr*)self->pyvm)->vm_mngr), addr, buffer, size);
+       if (ret < 0)
+	       RAISE(PyExc_TypeError,"arg must be str");
+       check_automod(self, addr, size*8);
+
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
+
+UDIV(16)
+UDIV(32)
+UDIV(64)
+
+UMOD(16)
+UMOD(32)
+UMOD(64)
+
+
+IDIV(16)
+IDIV(32)
+IDIV(64)
+
+IMOD(16)
+IMOD(32)
+IMOD(64)
+
+
+static PyMemberDef JitCpu_members[] = {
+    {NULL}  /* Sentinel */
+};
+
+static PyMethodDef JitCpu_methods[] = {
+	{"init_regs", (PyCFunction)cpu_init_regs, METH_NOARGS,
+	 "X"},
+	{"dump_gpregs", (PyCFunction)cpu_dump_gpregs, METH_NOARGS,
+	 "X"},
+	{"get_gpreg", (PyCFunction)cpu_get_gpreg, METH_NOARGS,
+	 "X"},
+	{"set_gpreg", (PyCFunction)cpu_set_gpreg, METH_VARARGS,
+	 "X"},
+	{"get_exception", (PyCFunction)cpu_get_exception, METH_VARARGS,
+	 "X"},
+	{"set_exception", (PyCFunction)cpu_set_exception, METH_VARARGS,
+	 "X"},
+	{"set_mem", (PyCFunction)vm_set_mem, METH_VARARGS,
+	 "X"},
+	{"get_mem", (PyCFunction)vm_get_mem, METH_VARARGS,
+	 "X"},
+	{NULL}  /* Sentinel */
+};
+
+static int
+JitCpu_init(JitCpu *self, PyObject *args, PyObject *kwds)
+{
+	self->cpu = malloc(sizeof(vm_cpu_t));
+	if (self->cpu == NULL) {
+		fprintf(stderr, "cannot alloc vm_cpu_t\n");
+		exit(0);
+	}
+	return 0;
+}
+
+
+
+getset_reg_u64(X0);
+getset_reg_u64(X1);
+getset_reg_u64(X2);
+getset_reg_u64(X3);
+getset_reg_u64(X4);
+getset_reg_u64(X5);
+getset_reg_u64(X6);
+getset_reg_u64(X7);
+getset_reg_u64(X8);
+getset_reg_u64(X9);
+getset_reg_u64(X10);
+getset_reg_u64(X11);
+getset_reg_u64(X12);
+getset_reg_u64(X13);
+getset_reg_u64(X14);
+getset_reg_u64(X15);
+getset_reg_u64(X16);
+getset_reg_u64(X17);
+getset_reg_u64(X18);
+getset_reg_u64(X19);
+getset_reg_u64(X20);
+getset_reg_u64(X21);
+getset_reg_u64(X22);
+getset_reg_u64(X23);
+getset_reg_u64(X24);
+getset_reg_u64(X25);
+getset_reg_u64(X26);
+getset_reg_u64(X27);
+getset_reg_u64(X28);
+getset_reg_u64(X29);
+getset_reg_u64(LR);
+getset_reg_u64(SP);
+getset_reg_u64(PC);
+
+getset_reg_u32(zf);
+getset_reg_u32(nf);
+getset_reg_u32(of);
+getset_reg_u32(cf);
+
+
+
+PyObject* get_gpreg_offset_all(void)
+{
+    PyObject *dict = PyDict_New();
+    PyObject *o;
+
+    get_reg_off(exception_flags);
+    get_reg_off(exception_flags_new);
+
+    get_reg_off(X0);
+    get_reg_off(X1);
+    get_reg_off(X2);
+    get_reg_off(X3);
+    get_reg_off(X4);
+    get_reg_off(X5);
+    get_reg_off(X6);
+    get_reg_off(X7);
+    get_reg_off(X8);
+    get_reg_off(X9);
+    get_reg_off(X10);
+    get_reg_off(X11);
+    get_reg_off(X12);
+    get_reg_off(X13);
+    get_reg_off(X14);
+    get_reg_off(X15);
+    get_reg_off(X16);
+    get_reg_off(X17);
+    get_reg_off(X18);
+    get_reg_off(X19);
+    get_reg_off(X20);
+    get_reg_off(X21);
+    get_reg_off(X22);
+    get_reg_off(X23);
+    get_reg_off(X24);
+    get_reg_off(X25);
+    get_reg_off(X26);
+    get_reg_off(X27);
+    get_reg_off(X28);
+    get_reg_off(X29);
+    get_reg_off(LR);
+    get_reg_off(SP);
+    get_reg_off(PC);
+
+
+    get_reg_off(X0_new);
+    get_reg_off(X1_new);
+    get_reg_off(X2_new);
+    get_reg_off(X3_new);
+    get_reg_off(X4_new);
+    get_reg_off(X5_new);
+    get_reg_off(X6_new);
+    get_reg_off(X7_new);
+    get_reg_off(X8_new);
+    get_reg_off(X9_new);
+    get_reg_off(X10_new);
+    get_reg_off(X11_new);
+    get_reg_off(X12_new);
+    get_reg_off(X13_new);
+    get_reg_off(X14_new);
+    get_reg_off(X15_new);
+    get_reg_off(X16_new);
+    get_reg_off(X17_new);
+    get_reg_off(X18_new);
+    get_reg_off(X19_new);
+    get_reg_off(X20_new);
+    get_reg_off(X21_new);
+    get_reg_off(X22_new);
+    get_reg_off(X23_new);
+    get_reg_off(X24_new);
+    get_reg_off(X25_new);
+    get_reg_off(X26_new);
+    get_reg_off(X27_new);
+    get_reg_off(X28_new);
+    get_reg_off(X29_new);
+    get_reg_off(LR_new);
+    get_reg_off(SP_new);
+    get_reg_off(PC_new);
+
+
+
+    /* eflag */
+    get_reg_off(zf);
+    get_reg_off(nf);
+    get_reg_off(of);
+    get_reg_off(cf);
+
+    get_reg_off(zf_new);
+    get_reg_off(nf_new);
+    get_reg_off(of_new);
+    get_reg_off(cf_new);
+
+
+    get_reg_off(pfmem08_0);
+    get_reg_off(pfmem08_1);
+    get_reg_off(pfmem08_2);
+    get_reg_off(pfmem08_3);
+    get_reg_off(pfmem08_4);
+    get_reg_off(pfmem08_5);
+    get_reg_off(pfmem08_6);
+    get_reg_off(pfmem08_7);
+    get_reg_off(pfmem08_8);
+    get_reg_off(pfmem08_9);
+    get_reg_off(pfmem08_10);
+    get_reg_off(pfmem08_11);
+    get_reg_off(pfmem08_12);
+    get_reg_off(pfmem08_13);
+    get_reg_off(pfmem08_14);
+    get_reg_off(pfmem08_15);
+    get_reg_off(pfmem08_16);
+    get_reg_off(pfmem08_17);
+    get_reg_off(pfmem08_18);
+    get_reg_off(pfmem08_19);
+
+
+    get_reg_off(pfmem16_0);
+    get_reg_off(pfmem16_1);
+    get_reg_off(pfmem16_2);
+    get_reg_off(pfmem16_3);
+    get_reg_off(pfmem16_4);
+    get_reg_off(pfmem16_5);
+    get_reg_off(pfmem16_6);
+    get_reg_off(pfmem16_7);
+    get_reg_off(pfmem16_8);
+    get_reg_off(pfmem16_9);
+    get_reg_off(pfmem16_10);
+    get_reg_off(pfmem16_11);
+    get_reg_off(pfmem16_12);
+    get_reg_off(pfmem16_13);
+    get_reg_off(pfmem16_14);
+    get_reg_off(pfmem16_15);
+    get_reg_off(pfmem16_16);
+    get_reg_off(pfmem16_17);
+    get_reg_off(pfmem16_18);
+    get_reg_off(pfmem16_19);
+
+
+    get_reg_off(pfmem32_0);
+    get_reg_off(pfmem32_1);
+    get_reg_off(pfmem32_2);
+    get_reg_off(pfmem32_3);
+    get_reg_off(pfmem32_4);
+    get_reg_off(pfmem32_5);
+    get_reg_off(pfmem32_6);
+    get_reg_off(pfmem32_7);
+    get_reg_off(pfmem32_8);
+    get_reg_off(pfmem32_9);
+    get_reg_off(pfmem32_10);
+    get_reg_off(pfmem32_11);
+    get_reg_off(pfmem32_12);
+    get_reg_off(pfmem32_13);
+    get_reg_off(pfmem32_14);
+    get_reg_off(pfmem32_15);
+    get_reg_off(pfmem32_16);
+    get_reg_off(pfmem32_17);
+    get_reg_off(pfmem32_18);
+    get_reg_off(pfmem32_19);
+
+
+    get_reg_off(pfmem64_0);
+    get_reg_off(pfmem64_1);
+    get_reg_off(pfmem64_2);
+    get_reg_off(pfmem64_3);
+    get_reg_off(pfmem64_4);
+    get_reg_off(pfmem64_5);
+    get_reg_off(pfmem64_6);
+    get_reg_off(pfmem64_7);
+    get_reg_off(pfmem64_8);
+    get_reg_off(pfmem64_9);
+    get_reg_off(pfmem64_10);
+    get_reg_off(pfmem64_11);
+    get_reg_off(pfmem64_12);
+    get_reg_off(pfmem64_13);
+    get_reg_off(pfmem64_14);
+    get_reg_off(pfmem64_15);
+    get_reg_off(pfmem64_16);
+    get_reg_off(pfmem64_17);
+    get_reg_off(pfmem64_18);
+    get_reg_off(pfmem64_19);
+
+    return dict;
+}
+
+
+static PyGetSetDef JitCpu_getseters[] = {
+    {"vmmngr",
+     (getter)JitCpu_get_vmmngr, (setter)JitCpu_set_vmmngr,
+     "vmmngr",
+     NULL},
+
+    {"jitter",
+     (getter)JitCpu_get_jitter, (setter)JitCpu_set_jitter,
+     "jitter",
+     NULL},
+
+
+
+    {"X0" , (getter)JitCpu_get_X0 , (setter)JitCpu_set_X0 , "X0" , NULL},
+    {"X1" , (getter)JitCpu_get_X1 , (setter)JitCpu_set_X1 , "X1" , NULL},
+    {"X2" , (getter)JitCpu_get_X2 , (setter)JitCpu_set_X2 , "X2" , NULL},
+    {"X3" , (getter)JitCpu_get_X3 , (setter)JitCpu_set_X3 , "X3" , NULL},
+    {"X4" , (getter)JitCpu_get_X4 , (setter)JitCpu_set_X4 , "X4" , NULL},
+    {"X5" , (getter)JitCpu_get_X5 , (setter)JitCpu_set_X5 , "X5" , NULL},
+    {"X6" , (getter)JitCpu_get_X6 , (setter)JitCpu_set_X6 , "X6" , NULL},
+    {"X7" , (getter)JitCpu_get_X7 , (setter)JitCpu_set_X7 , "X7" , NULL},
+    {"X8" , (getter)JitCpu_get_X8 , (setter)JitCpu_set_X8 , "X8" , NULL},
+    {"X9" , (getter)JitCpu_get_X9 , (setter)JitCpu_set_X9 , "X9" , NULL},
+
+    {"X10" , (getter)JitCpu_get_X10 , (setter)JitCpu_set_X10 , "X10" , NULL},
+    {"X11" , (getter)JitCpu_get_X11 , (setter)JitCpu_set_X11 , "X11" , NULL},
+    {"X12" , (getter)JitCpu_get_X12 , (setter)JitCpu_set_X12 , "X12" , NULL},
+    {"X13" , (getter)JitCpu_get_X13 , (setter)JitCpu_set_X13 , "X13" , NULL},
+    {"X14" , (getter)JitCpu_get_X14 , (setter)JitCpu_set_X14 , "X14" , NULL},
+    {"X15" , (getter)JitCpu_get_X15 , (setter)JitCpu_set_X15 , "X15" , NULL},
+    {"X16" , (getter)JitCpu_get_X16 , (setter)JitCpu_set_X16 , "X16" , NULL},
+    {"X17" , (getter)JitCpu_get_X17 , (setter)JitCpu_set_X17 , "X17" , NULL},
+    {"X18" , (getter)JitCpu_get_X18 , (setter)JitCpu_set_X18 , "X18" , NULL},
+    {"X19" , (getter)JitCpu_get_X19 , (setter)JitCpu_set_X19 , "X19" , NULL},
+
+    {"X20" , (getter)JitCpu_get_X20 , (setter)JitCpu_set_X20 , "X20" , NULL},
+    {"X21" , (getter)JitCpu_get_X21 , (setter)JitCpu_set_X21 , "X21" , NULL},
+    {"X22" , (getter)JitCpu_get_X22 , (setter)JitCpu_set_X22 , "X22" , NULL},
+    {"X23" , (getter)JitCpu_get_X23 , (setter)JitCpu_set_X23 , "X23" , NULL},
+    {"X24" , (getter)JitCpu_get_X24 , (setter)JitCpu_set_X24 , "X24" , NULL},
+    {"X25" , (getter)JitCpu_get_X25 , (setter)JitCpu_set_X25 , "X25" , NULL},
+    {"X26" , (getter)JitCpu_get_X26 , (setter)JitCpu_set_X26 , "X26" , NULL},
+    {"X27" , (getter)JitCpu_get_X27 , (setter)JitCpu_set_X27 , "X27" , NULL},
+    {"X28" , (getter)JitCpu_get_X28 , (setter)JitCpu_set_X28 , "X28" , NULL},
+    {"X29" , (getter)JitCpu_get_X29 , (setter)JitCpu_set_X29 , "X29" , NULL},
+
+    {"LR" , (getter)JitCpu_get_LR , (setter)JitCpu_set_LR , "LR" , NULL},
+
+
+
+    {"SP" , (getter)JitCpu_get_SP , (setter)JitCpu_set_SP , "SP" , NULL},
+    {"PC" , (getter)JitCpu_get_PC , (setter)JitCpu_set_PC , "PC" , NULL},
+
+    {"zf", (getter)JitCpu_get_zf, (setter)JitCpu_set_zf, "zf", NULL},
+    {"nf", (getter)JitCpu_get_nf, (setter)JitCpu_set_nf, "nf", NULL},
+    {"of", (getter)JitCpu_get_of, (setter)JitCpu_set_of, "of", NULL},
+    {"cf", (getter)JitCpu_get_cf, (setter)JitCpu_set_cf, "cf", NULL},
+
+    {NULL}  /* Sentinel */
+};
+
+
+static PyTypeObject JitCpuType = {
+    PyObject_HEAD_INIT(NULL)
+    0,                         /*ob_size*/
+    "JitCore_aarch64.JitCpu",      /*tp_name*/
+    sizeof(JitCpu),            /*tp_basicsize*/
+    0,                         /*tp_itemsize*/
+    (destructor)JitCpu_dealloc,/*tp_dealloc*/
+    0,                         /*tp_print*/
+    0,                         /*tp_getattr*/
+    0,                         /*tp_setattr*/
+    0,                         /*tp_compare*/
+    0,                         /*tp_repr*/
+    0,                         /*tp_as_number*/
+    0,                         /*tp_as_sequence*/
+    0,                         /*tp_as_mapping*/
+    0,                         /*tp_hash */
+    0,                         /*tp_call*/
+    0,                         /*tp_str*/
+    0,                         /*tp_getattro*/
+    0,                         /*tp_setattro*/
+    0,                         /*tp_as_buffer*/
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+    "JitCpu objects",          /* tp_doc */
+    0,			       /* tp_traverse */
+    0,			       /* tp_clear */
+    0,			       /* tp_richcompare */
+    0,			       /* tp_weaklistoffset */
+    0,			       /* tp_iter */
+    0,			       /* tp_iternext */
+    JitCpu_methods,            /* tp_methods */
+    JitCpu_members,            /* tp_members */
+    JitCpu_getseters,          /* tp_getset */
+    0,                         /* tp_base */
+    0,                         /* tp_dict */
+    0,                         /* tp_descr_get */
+    0,                         /* tp_descr_set */
+    0,                         /* tp_dictoffset */
+    (initproc)JitCpu_init,     /* tp_init */
+    0,                         /* tp_alloc */
+    JitCpu_new,                /* tp_new */
+};
+
+
+
+static PyMethodDef JitCore_aarch64_Methods[] = {
+	{"get_gpreg_offset_all", (PyCFunction)get_gpreg_offset_all, METH_NOARGS},
+	{NULL, NULL, 0, NULL}        /* Sentinel */
+
+};
+
+static PyObject *JitCore_aarch64_Error;
+
+PyMODINIT_FUNC
+initJitCore_aarch64(void)
+{
+    PyObject *m;
+
+    if (PyType_Ready(&JitCpuType) < 0)
+	return;
+
+    m = Py_InitModule("JitCore_aarch64", JitCore_aarch64_Methods);
+    if (m == NULL)
+	    return;
+
+    JitCore_aarch64_Error = PyErr_NewException("JitCore_aarch64.error", NULL, NULL);
+    Py_INCREF(JitCore_aarch64_Error);
+    PyModule_AddObject(m, "error", JitCore_aarch64_Error);
+
+    Py_INCREF(&JitCpuType);
+    PyModule_AddObject(m, "JitCpu", (PyObject *)&JitCpuType);
+
+}
+
diff --git a/miasm2/jitter/arch/JitCore_aarch64.h b/miasm2/jitter/arch/JitCore_aarch64.h
new file mode 100644
index 00000000..e1708541
--- /dev/null
+++ b/miasm2/jitter/arch/JitCore_aarch64.h
@@ -0,0 +1,196 @@
+
+typedef struct {
+	uint32_t exception_flags;
+	uint32_t exception_flags_new;
+
+	/* gpregs */
+
+	uint64_t X0;
+	uint64_t X1;
+	uint64_t X2;
+	uint64_t X3;
+	uint64_t X4;
+	uint64_t X5;
+	uint64_t X6;
+	uint64_t X7;
+	uint64_t X8;
+	uint64_t X9;
+	uint64_t X10;
+	uint64_t X11;
+	uint64_t X12;
+	uint64_t X13;
+	uint64_t X14;
+	uint64_t X15;
+	uint64_t X16;
+	uint64_t X17;
+	uint64_t X18;
+	uint64_t X19;
+	uint64_t X20;
+	uint64_t X21;
+	uint64_t X22;
+	uint64_t X23;
+	uint64_t X24;
+	uint64_t X25;
+	uint64_t X26;
+	uint64_t X27;
+	uint64_t X28;
+	uint64_t X29;
+	uint64_t LR;
+	uint64_t SP;
+
+	uint64_t PC;
+
+
+	uint64_t X0_new;
+	uint64_t X1_new;
+	uint64_t X2_new;
+	uint64_t X3_new;
+	uint64_t X4_new;
+	uint64_t X5_new;
+	uint64_t X6_new;
+	uint64_t X7_new;
+	uint64_t X8_new;
+	uint64_t X9_new;
+	uint64_t X10_new;
+	uint64_t X11_new;
+	uint64_t X12_new;
+	uint64_t X13_new;
+	uint64_t X14_new;
+	uint64_t X15_new;
+	uint64_t X16_new;
+	uint64_t X17_new;
+	uint64_t X18_new;
+	uint64_t X19_new;
+	uint64_t X20_new;
+	uint64_t X21_new;
+	uint64_t X22_new;
+	uint64_t X23_new;
+	uint64_t X24_new;
+	uint64_t X25_new;
+	uint64_t X26_new;
+	uint64_t X27_new;
+	uint64_t X28_new;
+	uint64_t X29_new;
+	uint64_t LR_new;
+	uint64_t SP_new;
+
+	uint64_t PC_new;
+
+	/* eflag */
+	uint32_t zf;
+	uint32_t nf;
+	uint32_t of;
+	uint32_t cf;
+
+	uint32_t zf_new;
+	uint32_t nf_new;
+	uint32_t of_new;
+	uint32_t cf_new;
+
+
+	uint8_t pfmem08_0;
+	uint8_t pfmem08_1;
+	uint8_t pfmem08_2;
+	uint8_t pfmem08_3;
+	uint8_t pfmem08_4;
+	uint8_t pfmem08_5;
+	uint8_t pfmem08_6;
+	uint8_t pfmem08_7;
+	uint8_t pfmem08_8;
+	uint8_t pfmem08_9;
+	uint8_t pfmem08_10;
+	uint8_t pfmem08_11;
+	uint8_t pfmem08_12;
+	uint8_t pfmem08_13;
+	uint8_t pfmem08_14;
+	uint8_t pfmem08_15;
+	uint8_t pfmem08_16;
+	uint8_t pfmem08_17;
+	uint8_t pfmem08_18;
+	uint8_t pfmem08_19;
+
+
+	uint16_t pfmem16_0;
+	uint16_t pfmem16_1;
+	uint16_t pfmem16_2;
+	uint16_t pfmem16_3;
+	uint16_t pfmem16_4;
+	uint16_t pfmem16_5;
+	uint16_t pfmem16_6;
+	uint16_t pfmem16_7;
+	uint16_t pfmem16_8;
+	uint16_t pfmem16_9;
+	uint16_t pfmem16_10;
+	uint16_t pfmem16_11;
+	uint16_t pfmem16_12;
+	uint16_t pfmem16_13;
+	uint16_t pfmem16_14;
+	uint16_t pfmem16_15;
+	uint16_t pfmem16_16;
+	uint16_t pfmem16_17;
+	uint16_t pfmem16_18;
+	uint16_t pfmem16_19;
+
+
+	uint32_t pfmem32_0;
+	uint32_t pfmem32_1;
+	uint32_t pfmem32_2;
+	uint32_t pfmem32_3;
+	uint32_t pfmem32_4;
+	uint32_t pfmem32_5;
+	uint32_t pfmem32_6;
+	uint32_t pfmem32_7;
+	uint32_t pfmem32_8;
+	uint32_t pfmem32_9;
+	uint32_t pfmem32_10;
+	uint32_t pfmem32_11;
+	uint32_t pfmem32_12;
+	uint32_t pfmem32_13;
+	uint32_t pfmem32_14;
+	uint32_t pfmem32_15;
+	uint32_t pfmem32_16;
+	uint32_t pfmem32_17;
+	uint32_t pfmem32_18;
+	uint32_t pfmem32_19;
+
+
+	uint64_t pfmem64_0;
+	uint64_t pfmem64_1;
+	uint64_t pfmem64_2;
+	uint64_t pfmem64_3;
+	uint64_t pfmem64_4;
+	uint64_t pfmem64_5;
+	uint64_t pfmem64_6;
+	uint64_t pfmem64_7;
+	uint64_t pfmem64_8;
+	uint64_t pfmem64_9;
+	uint64_t pfmem64_10;
+	uint64_t pfmem64_11;
+	uint64_t pfmem64_12;
+	uint64_t pfmem64_13;
+	uint64_t pfmem64_14;
+	uint64_t pfmem64_15;
+	uint64_t pfmem64_16;
+	uint64_t pfmem64_17;
+	uint64_t pfmem64_18;
+	uint64_t pfmem64_19;
+
+}vm_cpu_t;
+
+
+uint64_t udiv64(vm_cpu_t* vmcpu, uint64_t a, uint64_t b);
+uint64_t umod64(vm_cpu_t* vmcpu, uint64_t a, uint64_t b);
+int64_t idiv64(vm_cpu_t* vmcpu, int64_t a, int64_t b);
+int64_t imod64(vm_cpu_t* vmcpu, int64_t a, int64_t b);
+
+uint32_t udiv32(vm_cpu_t* vmcpu, uint32_t a, uint32_t b);
+uint32_t umod32(vm_cpu_t* vmcpu, uint32_t a, uint32_t b);
+int32_t idiv32(vm_cpu_t* vmcpu, int32_t a, int32_t b);
+int32_t imod32(vm_cpu_t* vmcpu, int32_t a, int32_t b);
+
+uint16_t udiv16(vm_cpu_t* vmcpu, uint16_t a, uint16_t b);
+uint16_t umod16(vm_cpu_t* vmcpu, uint16_t a, uint16_t b);
+int16_t idiv16(vm_cpu_t* vmcpu, int16_t a, int16_t b);
+int16_t imod16(vm_cpu_t* vmcpu, int16_t a, int16_t b);
+
+#define RETURN_PC return BlockDst;