about summary refs log tree commit diff stats
path: root/src/miasm/arch
diff options
context:
space:
mode:
Diffstat (limited to 'src/miasm/arch')
-rw-r--r--src/miasm/arch/__init__.py1
-rw-r--r--src/miasm/arch/aarch64/__init__.py1
-rw-r--r--src/miasm/arch/aarch64/arch.py2309
-rw-r--r--src/miasm/arch/aarch64/disasm.py27
-rw-r--r--src/miasm/arch/aarch64/jit.py79
-rw-r--r--src/miasm/arch/aarch64/lifter_model_call.py50
-rw-r--r--src/miasm/arch/aarch64/regs.py251
-rw-r--r--src/miasm/arch/aarch64/sem.py2386
-rw-r--r--src/miasm/arch/arm/__init__.py1
-rw-r--r--src/miasm/arch/arm/arch.py3457
-rw-r--r--src/miasm/arch/arm/disasm.py61
-rw-r--r--src/miasm/arch/arm/jit.py144
-rw-r--r--src/miasm/arch/arm/lifter_model_call.py106
-rw-r--r--src/miasm/arch/arm/regs.py177
-rw-r--r--src/miasm/arch/arm/sem.py2305
-rw-r--r--src/miasm/arch/mep/__init__.py0
-rw-r--r--src/miasm/arch/mep/arch.py2080
-rw-r--r--src/miasm/arch/mep/disasm.py23
-rw-r--r--src/miasm/arch/mep/jit.py112
-rw-r--r--src/miasm/arch/mep/lifter_model_call.py45
-rw-r--r--src/miasm/arch/mep/regs.py91
-rw-r--r--src/miasm/arch/mep/sem.py1240
-rw-r--r--src/miasm/arch/mips32/__init__.py0
-rw-r--r--src/miasm/arch/mips32/arch.py838
-rw-r--r--src/miasm/arch/mips32/disasm.py16
-rw-r--r--src/miasm/arch/mips32/jit.py160
-rw-r--r--src/miasm/arch/mips32/lifter_model_call.py104
-rw-r--r--src/miasm/arch/mips32/regs.py101
-rw-r--r--src/miasm/arch/mips32/sem.py667
-rw-r--r--src/miasm/arch/msp430/__init__.py1
-rw-r--r--src/miasm/arch/msp430/arch.py610
-rw-r--r--src/miasm/arch/msp430/ctype.py68
-rw-r--r--src/miasm/arch/msp430/disasm.py8
-rw-r--r--src/miasm/arch/msp430/jit.py41
-rw-r--r--src/miasm/arch/msp430/lifter_model_call.py31
-rw-r--r--src/miasm/arch/msp430/regs.py116
-rw-r--r--src/miasm/arch/msp430/sem.py509
-rw-r--r--src/miasm/arch/ppc/__init__.py1
-rw-r--r--src/miasm/arch/ppc/arch.py826
-rw-r--r--src/miasm/arch/ppc/disasm.py7
-rw-r--r--src/miasm/arch/ppc/jit.py70
-rw-r--r--src/miasm/arch/ppc/lifter_model_call.py87
-rw-r--r--src/miasm/arch/ppc/regs.py77
-rw-r--r--src/miasm/arch/ppc/sem.py981
-rw-r--r--src/miasm/arch/sh4/__init__.py0
-rw-r--r--src/miasm/arch/sh4/arch.py998
-rw-r--r--src/miasm/arch/sh4/regs.py84
-rw-r--r--src/miasm/arch/x86/__init__.py1
-rw-r--r--src/miasm/arch/x86/arch.py4878
-rw-r--r--src/miasm/arch/x86/ctype.py137
-rw-r--r--src/miasm/arch/x86/disasm.py30
-rw-r--r--src/miasm/arch/x86/jit.py296
-rw-r--r--src/miasm/arch/x86/lifter_model_call.py80
-rw-r--r--src/miasm/arch/x86/regs.py454
-rw-r--r--src/miasm/arch/x86/sem.py6065
55 files changed, 33288 insertions, 0 deletions
diff --git a/src/miasm/arch/__init__.py b/src/miasm/arch/__init__.py
new file mode 100644
index 00000000..78e2dd3c
--- /dev/null
+++ b/src/miasm/arch/__init__.py
@@ -0,0 +1 @@
+"Architecture implementations"
diff --git a/src/miasm/arch/aarch64/__init__.py b/src/miasm/arch/aarch64/__init__.py
new file mode 100644
index 00000000..bbad893b
--- /dev/null
+++ b/src/miasm/arch/aarch64/__init__.py
@@ -0,0 +1 @@
+__all__ = ["arch", "disasm", "regs", "sem"]
diff --git a/src/miasm/arch/aarch64/arch.py b/src/miasm/arch/aarch64/arch.py
new file mode 100644
index 00000000..ab6b7528
--- /dev/null
+++ b/src/miasm/arch/aarch64/arch.py
@@ -0,0 +1,2309 @@
+#-*- coding:utf-8 -*-
+
+from builtins import range
+from future.utils import viewitems, viewvalues
+
+import logging
+from pyparsing import *
+from miasm.expression import expression as m2_expr
+from miasm.core.cpu import *
+from collections import defaultdict
+from miasm.core.bin_stream import bin_stream
+from miasm.arch.aarch64 import regs as regs_module
+from miasm.arch.aarch64.regs import *
+from miasm.core.cpu import log as log_cpu
+from miasm.core.modint import mod_size2int
+from miasm.core.asm_ast import AstInt, AstId, AstMem, AstOp
+from miasm.ir.ir import color_expr_html
+from miasm.core import utils
+from miasm.core.utils import BRACKET_O, BRACKET_C
+
+log = logging.getLogger("aarch64dis")
+console_handler = logging.StreamHandler()
+console_handler.setFormatter(logging.Formatter("[%(levelname)-8s]: %(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.ExprInt(0, 32),
+    XZR: m2_expr.ExprInt(0, 64),
+
+}
+
+
+
+
+shift2expr_dct = {'LSL': '<<', 'LSR': '>>', 'ASR': 'a>>', 'ROR': '>>>'}
+shift_str = ["LSL", "LSR", "ASR", "ROR"]
+shift_expr = ["<<", ">>", "a>>", '>>>']
+
+
+def cb_shift(tokens):
+    return shift2expr_dct[tokens[0]]
+
+
+def cb_extreg(tokens):
+    return tokens[0]
+
+
+def cb_shiftreg(tokens):
+    if len(tokens) == 1:
+        return tokens[0]
+    elif len(tokens) == 3:
+        result = AstOp(tokens[1], tokens[0], tokens[2])
+        return result
+    else:
+        raise ValueError('bad string')
+
+
+def cb_shift_sc(tokens):
+    if len(tokens) == 1:
+        return tokens[0]
+    elif len(tokens) == 3:
+        if tokens[1] != '<<':
+            raise ValueError('bad op')
+        result = AstOp("slice_at", tokens[0], tokens[2])
+        return result
+    else:
+        raise ValueError('bad string')
+
+
+def cb_extend(tokens):
+    if len(tokens) == 1:
+        return tokens[0]
+    result = AstOp(tokens[1], tokens[0], tokens[2])
+    return result
+
+
+def cb_deref_pc_off(tokens):
+    if len(tokens) == 2 and tokens[0] == "PC":
+        result = AstOp('preinc', AstId(ExprId('PC', 64)), tokens[1])
+        return result
+    raise ValueError('bad string')
+
+def cb_deref_pc_nooff(tokens):
+    if len(tokens) == 1 and tokens[0] == "PC":
+        result = AstOp('preinc', AstId(PC))
+        return result
+    raise ValueError('bad string')
+
+all_binaryop_lsl_t = literal_list(shift_str).setParseAction(cb_shift)
+
+all_binaryop_shiftleft_t = literal_list(["LSL"]).setParseAction(cb_shift)
+
+extend_lst = ['UXTB', 'UXTH', 'UXTW', 'UXTX', 'SXTB', 'SXTH', 'SXTW', 'SXTX']
+extend2_lst = ['UXTW', 'LSL', 'SXTW', 'SXTX']
+
+all_extend_t = literal_list(extend_lst).setParseAction(cb_extreg)
+all_extend2_t = literal_list(extend2_lst).setParseAction(cb_extreg)
+
+
+gpregz32_extend = (gpregsz32_info.parser + Optional(all_extend_t + base_expr)).setParseAction(cb_extend)
+gpregz64_extend = (gpregsz64_info.parser + Optional(all_extend_t + base_expr)).setParseAction(cb_extend)
+
+
+shift32_off = (gpregsz32_info.parser + Optional(all_binaryop_lsl_t + base_expr)).setParseAction(cb_shiftreg)
+shift64_off = (gpregsz64_info.parser + Optional(all_binaryop_lsl_t + base_expr)).setParseAction(cb_shiftreg)
+
+
+shiftimm_imm_sc = (base_expr + all_binaryop_shiftleft_t + base_expr).setParseAction(cb_shift_sc)
+
+shiftimm_off_sc = shiftimm_imm_sc | base_expr
+
+
+shift_off = (shift32_off | shift64_off)
+reg_ext_off = (gpregz32_extend | gpregz64_extend)
+
+gpregs_32_64 = (gpregs32_info.parser | gpregs64_info.parser)
+gpregsz_32_64 = (gpregsz32_info.parser | gpregsz64_info.parser | base_expr)
+
+gpregs_32_64_nosp = (gpregs32_nosp_info.parser | gpregs64_nosp_info.parser)
+
+
+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 | base_expr)
+
+
+gpregs_info = {32: gpregs32_info,
+               64: gpregs64_info}
+gpregsz_info = {32: gpregsz32_info,
+                64: gpregsz64_info}
+
+
+gpregs_nosp_info = {
+    32: gpregs32_nosp_info,
+    64: gpregs64_nosp_info
+}
+
+simds_info = {8: simd08_info,
+              16: simd16_info,
+              32: simd32_info,
+              64: simd64_info,
+              128: simd128_info}
+
+
+
+def cb_deref_nooff(t):
+    # XXX default
+    result = AstOp("preinc", t[0], AstInt(0))
+    return result
+
+
+def cb_deref_post(t):
+    assert len(t) == 2
+    if isinstance(t[1], AstId) and isinstance(t[1].name, ExprId):
+        return
+    result = AstOp("postinc", *t)
+    return result
+
+
+def cb_deref_pre(t):
+    assert len(t) == 2
+    if isinstance(t[1], AstId) and isinstance(t[1].name, ExprId):
+        return
+    result = AstOp("preinc", *t)
+    return result
+
+
+def cb_deref_pre_wb(t):
+    assert len(t) == 2
+    if isinstance(t[1], AstId) and isinstance(t[1].name, ExprId):
+        return
+    result = AstOp("preinc_wb", *t)
+    return result
+
+
+LBRACK = Suppress("[")
+RBRACK = Suppress("]")
+COMMA = Suppress(",")
+POSTINC = Suppress("!")
+
+deref_nooff = (LBRACK + gpregs64_info.parser + RBRACK).setParseAction(cb_deref_nooff)
+deref_off_post = (LBRACK + gpregs64_info.parser + RBRACK + COMMA + base_expr).setParseAction(cb_deref_post)
+deref_off_pre = (LBRACK + gpregs64_info.parser + COMMA + base_expr + RBRACK).setParseAction(cb_deref_pre)
+deref_off_pre_wb = (LBRACK + gpregs64_info.parser + COMMA + base_expr + RBRACK + POSTINC).setParseAction(cb_deref_pre_wb)
+
+deref = (deref_off_post | deref_off_pre_wb | deref_off_pre | deref_nooff)
+
+
+deref_pc_off = (LBRACK + Literal("PC") + COMMA + base_expr + RBRACK).setParseAction(cb_deref_pc_off)
+deref_pc_nooff = (LBRACK + Literal("PC") + RBRACK).setParseAction(cb_deref_pc_nooff)
+
+deref_pc = (deref_pc_off | deref_pc_nooff)
+
+def cb_deref_ext2op(t):
+    if len(t) == 4:
+        result = AstOp('segm', t[0], AstOp(t[2], t[1], t[3]))
+        return result
+    elif len(t) == 2:
+        result = AstOp('segm', *t)
+        return result
+
+    raise ValueError("cad deref")
+
+deref_ext2 = (LBRACK + gpregs_32_64 + COMMA + gpregs_32_64 + Optional(all_extend2_t + base_expr) + RBRACK).setParseAction(cb_deref_ext2op)
+
+
+class additional_info(object):
+
+    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 aarch64_arg(m_arg):
+    def asm_ast_to_expr(self, value, loc_db, size_hint=None, fixed_size=None):
+        if size_hint is None:
+            size_hint = 64
+        if fixed_size is None:
+            fixed_size = set()
+        if isinstance(value, AstId):
+            if value.name in all_regs_ids_byname:
+                reg = all_regs_ids_byname[value.name]
+                fixed_size.add(reg.size)
+                return reg
+            if isinstance(value.name, ExprId):
+                fixed_size.add(value.name.size)
+                return value.name
+            loc_key = loc_db.get_or_create_name_location(value.name)
+            return m2_expr.ExprLoc(loc_key, size_hint)
+        if isinstance(value, AstInt):
+            assert size_hint is not None
+            return m2_expr.ExprInt(value.value, size_hint)
+        if isinstance(value, AstOp):
+            if value.op == "segm":
+                segm = self.asm_ast_to_expr(value.args[0], loc_db)
+                ptr = self.asm_ast_to_expr(value.args[1], loc_db, None, fixed_size)
+                return m2_expr.ExprOp('segm', segm, ptr)
+
+            args = [self.asm_ast_to_expr(arg, loc_db, None, fixed_size) for arg in value.args]
+            if len(fixed_size) == 0:
+                # No fixed size
+                pass
+            elif len(fixed_size) == 1:
+                # One fixed size, regen all
+                size = list(fixed_size)[0]
+                args = [self.asm_ast_to_expr(arg, loc_db, size, fixed_size) for arg in value.args]
+            else:
+                raise ValueError("Size conflict")
+
+            return m2_expr.ExprOp(value.op, *args)
+        return None
+
+
+class instruction_aarch64(instruction):
+    __slots__ = []
+
+    def __init__(self, *args, **kargs):
+        super(instruction_aarch64, self).__init__(*args, **kargs)
+
+    @staticmethod
+    def arg2str(expr, index=None, loc_db=None):
+        wb = False
+        if expr.is_id() or expr.is_int():
+            return str(expr)
+        elif expr.is_loc():
+            if loc_db is not None:
+                return loc_db.pretty_str(expr.loc_key)
+            else:
+                return str(expr)
+        elif isinstance(expr, m2_expr.ExprOp) and expr.op in shift_expr:
+            op_str = shift_str[shift_expr.index(expr.op)]
+            return "%s %s %s" % (expr.args[0], op_str, expr.args[1])
+        elif isinstance(expr, m2_expr.ExprOp) and expr.op == "slice_at":
+            return "%s LSL %s" % (expr.args[0], expr.args[1])
+        elif isinstance(expr, m2_expr.ExprOp) and expr.op in extend_lst:
+            op_str = expr.op
+            return "%s %s %s" % (expr.args[0], op_str, expr.args[1])
+        elif isinstance(expr, m2_expr.ExprOp) and expr.op == "postinc":
+            if int(expr.args[1]) != 0:
+                return "[%s], %s" % (expr.args[0], expr.args[1])
+            else:
+                return "[%s]" % (expr.args[0])
+        elif isinstance(expr, m2_expr.ExprOp) and expr.op == "preinc_wb":
+            if int(expr.args[1]) != 0:
+                return "[%s, %s]!" % (expr.args[0], expr.args[1])
+            else:
+                return "[%s]" % (expr.args[0])
+        elif isinstance(expr, m2_expr.ExprOp) and expr.op == "preinc":
+            if len(expr.args) == 1:
+                return "[%s]" % (expr.args[0])
+            elif not isinstance(expr.args[1], m2_expr.ExprInt) or int(expr.args[1]) != 0:
+                return "[%s, %s]" % (expr.args[0], expr.args[1])
+            else:
+                return "[%s]" % (expr.args[0])
+        elif isinstance(expr, m2_expr.ExprOp) and expr.op == 'segm':
+            arg = expr.args[1]
+            if isinstance(arg, m2_expr.ExprId):
+                arg = str(arg)
+            elif arg.op == 'LSL' and int(arg.args[1]) == 0:
+                arg = str(arg.args[0])
+            else:
+                arg = "%s %s %s" % (arg.args[0], arg.op, arg.args[1])
+            return '[%s, %s]' % (expr.args[0], arg)
+
+        else:
+            raise NotImplementedError("bad op")
+
+    @staticmethod
+    def arg2html(expr, index=None, loc_db=None):
+        wb = False
+        if expr.is_id() or expr.is_int() or expr.is_loc():
+            return color_expr_html(expr, loc_db)
+        elif isinstance(expr, m2_expr.ExprOp) and expr.op in shift_expr:
+            op_str = shift_str[shift_expr.index(expr.op)]
+            return "%s %s %s" % (
+                color_expr_html(expr.args[0], loc_db),
+                utils.set_html_text_color(op_str, utils.COLOR_OP),
+                color_expr_html(expr.args[1], loc_db)
+            )
+        elif isinstance(expr, m2_expr.ExprOp) and expr.op == "slice_at":
+            return "%s LSL %s" % (
+                color_expr_html(expr.args[0], loc_db),
+                color_expr_html(expr.args[1], loc_db)
+            )
+        elif isinstance(expr, m2_expr.ExprOp) and expr.op in extend_lst:
+            op_str = expr.op
+            return "%s %s %s" % (
+                color_expr_html(expr.args[0], loc_db),
+                op_str,
+                color_expr_html(expr.args[1], loc_db)
+            )
+        elif isinstance(expr, m2_expr.ExprOp) and expr.op == "postinc":
+            if int(expr.args[1]) != 0:
+                return BRACKET_O + color_expr_html(expr.args[0], loc_db) + BRACKET_C + ", " + color_expr_html(expr.args[1], loc_db)
+            else:
+                return BRACKET_O + color_expr_html(expr.args[0], loc_db) + BRACKET_C
+        elif isinstance(expr, m2_expr.ExprOp) and expr.op == "preinc_wb":
+            if int(expr.args[1]) != 0:
+                return BRACKET_O + color_expr_html(expr.args[0], loc_db) + ", " + color_expr_html(expr.args[1], loc_db) + BRACKET_C + '!'
+            else:
+                return BRACKET_O + color_expr_html(expr.args[0], loc_db) + BRACKET_C
+        elif isinstance(expr, m2_expr.ExprOp) and expr.op == "preinc":
+            if len(expr.args) == 1:
+                return BRACKET_O + color_expr_html(expr.args[0], loc_db) + BRACKET_C
+            elif not isinstance(expr.args[1], m2_expr.ExprInt) or int(expr.args[1]) != 0:
+                return BRACKET_O + color_expr_html(expr.args[0], loc_db) + ", " + color_expr_html(expr.args[1], loc_db) + BRACKET_C
+            else:
+                return BRACKET_O + color_expr_html(expr.args[0], loc_db) + BRACKET_C
+        elif isinstance(expr, m2_expr.ExprOp) and expr.op == 'segm':
+            arg = expr.args[1]
+            if isinstance(arg, m2_expr.ExprId):
+                arg = str(arg)
+            elif arg.op == 'LSL' and int(arg.args[1]) == 0:
+                arg = str(arg.args[0])
+            else:
+                arg = "%s %s %s" % (
+                    color_expr_html(arg.args[0], loc_db),
+                    utils.set_html_text_color(arg.op, utils.COLOR_OP),
+                    color_expr_html(arg.args[1], loc_db)
+                )
+            return BRACKET_O + color_expr_html(expr.args[0], loc_db) + ', ' +  arg + BRACKET_C
+
+        else:
+            raise NotImplementedError("bad op")
+
+    def dstflow(self):
+        return self.name in BRCOND + ["B", "BL", "BR", "BLR"]
+
+    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, loc_db):
+        index = self.mnemo_flow_to_dst_index(self.name)
+        expr = self.args[index]
+        if not expr.is_int():
+            return
+        addr = (int(expr) + self.offset) & int(expr.mask)
+        loc_key = loc_db.get_or_create_offset_location(addr)
+        self.args[index] = m2_expr.ExprLoc(loc_key, expr.size)
+
+    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, loc_db):
+        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, loc_db):
+        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 = (int(e) - self.offset) & int(e.mask)
+        if int(off % 4):
+            raise ValueError('strange offset! %r' % off)
+        self.args[index] = m2_expr.ExprInt(int(off), 64)
+
+
+
+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 enough 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, loc_db, 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_gpreg_noarg_nosp(aarch64_gpreg_noarg):
+    parser = gpregs_32_64_nosp
+    gpregs_info = gpregs_nosp_info
+
+    def decode(self, v):
+        size = 64 if self.parent.sf.value else 32
+        if v >= len(self.gpregs_info[size].expr):
+            return False
+        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
+        if self.expr not 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, aarch64_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(0, size)
+            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, aarch64_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, aarch64_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, aarch64_arg):
+    parser = gpregsz_32_64
+    gpregs_info = gpregsz_info
+
+
+class aarch64_gpreg0(bsi, aarch64_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(0, size)
+        else:
+            self.expr = self.gpregs_info[size].expr[v]
+        return True
+
+    def encode(self):
+        if isinstance(self.expr, m2_expr.ExprInt):
+            if int(self.expr) == 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, aarch64_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, aarch64_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, aarch64_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, aarch64_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, aarch64_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, aarch64_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, aarch64_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, aarch64_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, aarch64_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, aarch64_arg):
+    reg_info = simd128_info
+    parser = reg_info.parser
+
+
+class aarch64_imm_32(imm_noarg, aarch64_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.ExprInt(
+        sign_ext(x, self.l, self.intsize), 64)
+
+
+class aarch64_uint64_noarg(imm_noarg):
+    parser = base_expr
+    intsize = 64
+    intmask = (1 << intsize) - 1
+    int2expr = lambda self, x: m2_expr.ExprInt(x, 64)
+
+
+class aarch64_uint64(aarch64_uint64_noarg, aarch64_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(int(expr), size)
+    else:
+        if int(expr) > (1 << size) - 1:
+            return None
+        expr = m2_expr.ExprInt(int(expr), size)
+    return expr
+
+
+class aarch64_imm_sf(imm_noarg):
+    parser = base_expr
+
+    def fromstring(self, text, loc_db, parser_result=None):
+        start, stop = super(aarch64_imm_sf, self).fromstring(text, loc_db, 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)
+        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(v, size)
+        return True
+
+
+class aarch64_imm_sft(aarch64_imm_sf, aarch64_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)
+        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(v, size)
+        elif self.parent.shift.value == 1:
+            self.expr = m2_expr.ExprInt(v << 12, size)
+        else:
+            return False
+        return True
+
+OPTION2SIZE = [32, 32, 32, 64,
+               32, 32, 32, 64]
+
+
+class aarch64_gpreg_ext(reg_noarg, aarch64_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 gpregsz_info[self.expr.size].expr:
+            return False
+        self.value = gpregsz_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)
+        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 = gpregsz_info[size].expr[v]
+
+        self.expr = m2_expr.ExprOp(extend_lst[self.parent.option.value],
+                           reg, m2_expr.ExprInt(self.parent.imm.value, reg.size))
+        return True
+
+EXT2_OP = {
+    0b010: 'UXTW',
+    0b011: 'LSL',
+    0b110: 'SXTW',
+    0b111: 'SXTX'
+}
+
+EXT2_OP_INV = dict((value, key) for key, value in viewitems(EXT2_OP))
+
+
+class aarch64_gpreg_ext2(reg_noarg, aarch64_arg):
+    parser = deref_ext2
+
+    def get_size(self):
+        return self.parent.size.value
+
+    def encode(self):
+        if not isinstance(self.expr, m2_expr.ExprOp):
+            return False
+        if len(self.expr.args) != 2:
+            return False
+        arg0, arg1 = self.expr.args
+        if (self.expr.is_op("preinc") and arg0.is_id() and arg1.is_id()):
+            self.parent.shift.value = 0
+            self.parent.rn.value = self.parent.rn.reg_info.expr.index(arg0)
+            self.value = gpregs_info[arg1.size].expr.index(arg1)
+            self.parent.option.value = 0b011
+            return True
+        if not (isinstance(self.expr, m2_expr.ExprOp) and self.expr.op == 'segm'):
+            return False
+        if not arg0 in self.parent.rn.reg_info.expr:
+            return False
+        self.parent.rn.value = self.parent.rn.reg_info.expr.index(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 viewvalues(EXT2_OP):
+            reg = arg1.args[0]
+        else:
+            return False
+        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
+        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 int(arg1.args[1]) == 0:
+            self.parent.shift.value = 0
+            return True
+
+        if int(arg1.args[1]) != self.get_size():
+            return False
+
+        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 = gpregsz32_info.expr
+        elif opt in [3, 7]:
+            reg_expr = gpregsz64_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(self.get_size(), arg.size))
+            else:
+                arg = m2_expr.ExprOp(EXT2_OP[opt], arg,
+                             m2_expr.ExprInt(0, arg.size))
+
+        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, aarch64_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])
+        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(amount, e.size))
+        self.expr = e
+        return True
+
+
+def ror(value, amount, size):
+    mask = (1 << size) - 1
+    return ((value >> amount) | (value << (size - amount))) & mask
+
+
+def rol(value, amount, size):
+    mask = (1 << size) - 1
+    return ((value << amount) | (value >> (size - amount)) & mask)
+
+# This implementation is inspired from ARM ISA v8.2
+# Exact Reference name:
+# "ARM Architecture Reference Manual ARMv8, for ARMv8-A architecture profile"
+
+class ReservedValue(Exception):
+    """Reserved Value, should not happen"""
+    pass
+
+class NotEncodable(Exception):
+    """Instruction is not encodable"""
+    pass
+
+class bits(object):
+    """Stand for ARM ASL 'bits' type, ie. a bit vector"""
+
+    __slots__ = ["size", "value"]
+
+    def __init__(self, size, value):
+        """Instantiate a bitvector of size @size with value @value"""
+        value = int(value)
+        self.size = int(size)
+        if value & self.mask != value:
+            raise ValueError(
+                "Value %r is too large for %r bits (mask %r)",
+                value,
+                size,
+                self.mask
+            )
+        self.value = value
+
+    def concat_left(self, other_bits):
+        """Return a new bits instance for @other_bits . self"""
+        return bits(self.size + other_bits.size,
+                    self.value | (other_bits.value << self.size))
+
+    @property
+    def mask(self):
+        return (1 << self.size) - 1
+
+    def __invert__(self):
+        return bits(self.size, self.value ^ self.mask)
+
+    def __int__(self):
+        return self.value
+
+    def __and__(self, other_bits):
+        assert other_bits.size == self.size
+        return bits(self.size, self.value & other_bits.value)
+
+    def __eq__(self, other_bits):
+        return all((self.size == other_bits.size,
+                    self.value == other_bits.value))
+
+    def __getitem__(self, info):
+        if isinstance(info, slice):
+            start = info.start if info.start else 0
+            stop = info.stop if info.stop else self.value
+            if info.step is not None:
+                raise RuntimeError("Not implemented")
+            mask = (1 << stop) - 1
+            return bits(stop - start,
+                        (self.value >> start) & mask)
+        else:
+            raise RuntimeError("Not implemented")
+
+    @property
+    def pop_count(self):
+        "Population count: number of bit set"
+        count = 0
+        value = self.value
+        while (value > 0):
+            if value & 1 == 1:
+                count += 1
+            value >>= 1
+        return count
+
+    def __str__(self):
+        return "'%s'" % "".join('1' if self.value & (1 << i) else '0'
+                                for i in reversed(range(self.size)))
+
+# From J1-6035
+def HighestSetBit(x):
+    for i in reversed(range(x.size)):
+        if x.value & (1 << i):
+            return i
+    return - 1
+
+# From J1-6037
+def Ones(N):
+    return bits(N, (1 << N) - 1)
+
+# From J1-6038
+def ROR(x, shift):
+    if shift == 0:
+        return x
+    return bits(x.size, ror(UInt(x), shift, x.size))
+
+# From J1-6038
+def Replicate(x, N):
+    assert N % x.size == 0
+    new = x
+    while new.size < N:
+        new = new.concat_left(x)
+    return new
+
+# From J1-6039
+def UInt(x):
+    return int(x)
+
+# From J1-6039
+def ZeroExtend(x, N):
+    assert N >= x.size
+    return bits(N, x.value)
+
+# From J1-5906
+def DecodeBitMasks(M, immN, imms, immr, immediate):
+    """
+    @M: 32 or 64
+    @immN: 1-bit
+    @imms: 6-bit
+    @immr: 6-bit
+    @immediate: boolean
+    """
+    len_ = HighestSetBit((~imms).concat_left(immN))
+    if len_ < 1:
+        raise ReservedValue()
+    assert M >= (1 << len_)
+
+    levels = ZeroExtend(Ones(len_), 6)
+
+    if immediate and (imms & levels) == levels:
+        raise ReservedValue()
+    S = UInt(imms & levels);
+    R = UInt(immr & levels);
+
+    esize = 1 << len_
+    welem = ZeroExtend(Ones(S + 1), esize)
+    wmask = Replicate(ROR(welem, R), M)
+
+    # For now, 'tmask' is unused:
+    #
+    # diff = S - R;
+    # d = UInt(bits(len_, diff))
+    # telem = ZeroExtend(Ones(d + 1), esize)
+    # tmask = Replicate(telem, M)
+
+    return wmask, None
+
+# EncodeBitMasks doesn't have any equivalent in ARM ASL shared functions
+# This implementation "reverses" DecodeBitMasks flow
+def EncodeBitMasks(wmask):
+    # Find replicate
+    M = wmask.size
+    for i in range(1, M + 1):
+        if M % i != 0:
+            continue
+        if wmask == Replicate(wmask[:i], M):
+            break
+    else:
+        raise NotEncodable
+
+    # Find ROR value: welem is only '1's
+    welem_after_ror = wmask[:i]
+    esize = welem_after_ror.size
+    S = welem_after_ror.pop_count - 1
+    welem = ZeroExtend(Ones(S + 1), esize)
+    for i in range(welem_after_ror.size):
+        if ROR(welem, i) == welem_after_ror:
+            break
+    else:
+        raise NotEncodable
+    R = i
+
+    # Find len value
+    for i in range(M):
+        if (1 << i) == esize:
+            break
+    else:
+        raise NotEncodable
+    len_ = i
+    levels = ZeroExtend(Ones(len_), 6)
+    levels = UInt(levels)
+
+    if len_ == 6:
+        # N = 1
+        immn = 1
+        imms = S
+    else:
+        # N = 0, NOT(imms) have to be considered
+        immn = 0
+        mask = (1 << ((6 - len_ - 1))) - 1
+        mask <<= (len_ + 1)
+        imms = S | mask
+    immr = R
+    return immr, imms, immn
+
+
+class aarch64_imm_nsr(aarch64_imm_sf, aarch64_arg):
+    parser = base_expr
+
+    def decode(self, v):
+        size = 64 if self.parent.sf.value else 32
+        bitmask, _ = DecodeBitMasks(size,
+                                    bits(1, self.parent.immn.value),
+                                    bits(6, v),
+                                    bits(6, self.parent.immr.value),
+                                    True
+        )
+        self.expr = m2_expr.ExprInt(UInt(bitmask),
+                                    size)
+        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 = int(self.expr)
+        if value == 0:
+            return False
+
+        try:
+            immr, imms, immn = EncodeBitMasks(bits(self.expr.size, value))
+        except NotEncodable:
+            return False
+        self.parent.immr.value = immr
+        self.parent.immn.value = immn
+        self.value = imms
+        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.ExprInt(v, 64)
+        return True
+
+    def encode(self):
+        v = int(self.expr)
+        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.ExprInt(v, 64)
+        return True
+
+    def encode(self):
+        v = int(self.expr)
+        if v & (1 << 63):
+            v &= (1 << 21) - 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(aarch64_arg):
+    parser = base_expr
+    shift_op = '<<'
+
+    def decode(self, v):
+        size = 64 if self.parent.sf.value else 32
+        self.expr = m2_expr.ExprInt(v << (16 * self.parent.hw.value), size)
+        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)
+        mask = (1 << size) - 1
+        for i in range(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(aarch64_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(v, size)
+        amount = m2_expr.ExprInt(16 * self.parent.hw.value, size)
+        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 int(self.expr) > 0xFFFF:
+                return False
+            self.value = int(self.expr)
+            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) 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, aarch64_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.ExprInt(v, 64)
+        return True
+
+    def encode(self):
+        if not isinstance(self.expr, m2_expr.ExprInt):
+            return False
+        v = int(self.expr)
+        if v & (1 << 63):
+            v &= (1 << (self.l + 2)) - 1
+        self.value = v >> 2
+        return True
+
+
+
+class aarch64_offs_pc(imm_noarg, aarch64_arg):
+    parser = deref_pc
+
+    def decode(self, v):
+        v = v & self.lmask
+        v = (v << 2)
+        v = sign_ext(v, (self.l + 2), 64)
+        self.expr = m2_expr.ExprOp("preinc", PC, m2_expr.ExprInt(v, 64))
+        return True
+
+    def encode(self):
+        if not self.expr.is_op('preinc'):
+            return False
+        if self.expr.args == (PC,):
+            v = 0
+        elif (len(self.expr.args) == 2 and
+              self.expr.args[0] == PC and
+              self.expr.args[1].is_int()):
+            v = int(self.expr.args[1])
+        else:
+            return None
+        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(aarch64_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 = int(self.parent.imm.expr)
+        op = self.get_postpre(self.parent)
+        off = self.decode_w_size(off)
+        self.expr = m2_expr.ExprOp(op, reg, m2_expr.ExprInt(off, 64))
+        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
+        if len(expr.args) != 2:
+            return False
+        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)
+        imm = self.encode_w_size(imm)
+        if imm is False:
+            return False
+        self.parent.imm.expr = m2_expr.ExprInt(imm, 64)
+        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 int(off) != 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, aarch64_arg):
+    reg_info = conds_info
+    parser = reg_info.parser
+
+
+class aarch64_cond_inv_arg(reg_noarg, aarch64_arg):
+    reg_info = conds_inv_info
+    parser = reg_info.parser
+
+
+class aarch64_b40(aarch64_arg):
+    parser = base_expr
+
+    def decode(self, v):
+        self.expr = m2_expr.ExprInt(
+            (self.parent.sf.value << self.l) | v, self.parent.rt.expr.size)
+        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)
+        self.value = value & self.lmask
+        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_gpregz,), fname="rt")
+rt2 = bs(l=5, cls=(aarch64_gpregz,), fname="rt2")
+rn0 = bs(l=5, cls=(aarch64_gpreg0,), fname="rn")
+
+rmz = bs(l=5, cls=(aarch64_gpregz,), fname="rm")
+rnz = bs(l=5, cls=(aarch64_gpregz,), fname="rn")
+rdz = bs(l=5, cls=(aarch64_gpregz,), fname="rd")
+
+rd_nosp = bs(l=5, cls=(aarch64_gpreg_noarg_nosp, aarch64_arg), fname="rd")
+
+
+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, aarch64_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, aarch64_arg), fname="nzcv", order=-1)
+uimm4 = bs(l=4, cls=(aarch64_uint64_noarg, aarch64_arg), fname="imm", order=-1)
+uimm5 = bs(l=5, cls=(aarch64_uint64_noarg, aarch64_arg), fname="imm", order=-1)
+uimm6 = bs(l=6, cls=(aarch64_uint64_noarg, aarch64_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, aarch64_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)
+
+class op0_value(aarch64_uint64):
+    def decode(self, v):
+        v = v & self.lmask
+        v = self.decodeval(v)
+        v += 2
+        e = self.int2expr(v)
+        if not e:
+            return False
+        self.expr = e
+        return True
+
+    def encode(self):
+        v = self.expr2int(self.expr)
+        if v is None:
+            return False
+        v -= 2
+        v = self.encodeval(v)
+        if v is False:
+            return False
+        self.value = v
+        return True
+
+op0 = bs(l=1, cls=(op0_value, aarch64_arg), fname="op0")
+op1 = bs(l=3, cls=(aarch64_uint64, aarch64_arg), fname="op1")
+op2 = bs(l=3, cls=(aarch64_uint64, aarch64_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, aarch64_arg), fname="imm1", order=-1)
+a_immr = bs(l=6, cls=(aarch64_imm_sf, aarch64_arg), fname="imm1", order=-1)
+
+
+
+adsu_name = {'ADD': 0, 'SUB': 1}
+bs_adsu_name = bs_name(l=1, name=adsu_name)
+
+
+adsus_name = {'ADDS': 0, 'SUBS': 1}
+bs_adsus_name = bs_name(l=1, name=adsus_name)
+
+
+offs19 = bs(l=19, cls=(aarch64_offs,), fname='off')
+offs19pc = bs(l=19, cls=(aarch64_offs_pc,), 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_nosp], [rd_nosp, rn, rm_sft])
+aarch64op("CMN", [sf, bs('0'), bs('1'), bs('01011'), shift, bs('0'), rm_sft, imm6, rn, bs('11111')], [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, bs('0'), bs('01011'), bs('00'), bs('1'), rm_ext, option, imm3, rn, rd], [rd, rn, rm_ext])
+aarch64op("addssubs", [sf, bs_adsus_name, bs('1'), bs('01011'), bs('00'), bs('1'), rm_ext, option, imm3, rn, rd_nosp], [rd_nosp, 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}
+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])
+# ANDS
+aarch64op("ands", [sf, bs('11'), bs('100100'), immn, immr, imms, rn0, rdz], [rdz, rn0, imms])
+aarch64op("tst",  [sf, bs('11'), bs('100100'), immn, immr, imms, rn0, bs('11111')], [rn0, imms], alias=True)
+
+
+# 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], alias=True)
+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'), rmz, bs('000000'), bs('11111'), rd], [rd, rmz], alias=True)
+
+
+aarch64op("adc", [sf, bs('00'), bs('11010000'), rm, bs('000000'), rn, rd], [rd, rn, rm])
+aarch64op("adcs", [sf, bs('01'), bs('11010000'), rm, bs('000000'), rn, rd], [rd, rn, rm])
+
+
+aarch64op("sbc", [sf, bs('10'), bs('11010000'), rm, bs('000000'), rn, rd], [rd, rn, rm])
+aarch64op("sbcs", [sf, bs('11'), bs('11010000'), rm, bs('000000'), rn, rd], [rd, rn, rm])
+
+
+
+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'), offs19pc, rt], [rt, offs19pc])
+aarch64op("ldrsw",  [bs('10'), bs('011'), bs('0'), bs('00'), offs19pc, rt64], [rt64, offs19pc])
+
+# load/store simd literal p.142
+aarch64op("ldr",  [sdsize, bs('011'), bs('1'), bs('00'), offs19pc, sd1], [sd1, offs19pc])
+
+
+# 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, simm7, 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, simm7, 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=list(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])
+
+# conversion 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'), rmz, cond_arg, bs('00'), rnz, rd], [rd, rnz, rmz, cond_arg])
+aarch64op("csinc", [sf, bs('0'), bs('0'), bs('11010100'), rmz, cond_arg, bs('01'), rnz, rd], [rd, rnz, rmz, cond_arg])
+aarch64op("csinv", [sf, bs('1'), bs('0'), bs('11010100'), rmz, cond_arg, bs('00'), rnz, rd], [rd, rnz, rmz, cond_arg])
+aarch64op("csneg", [sf, bs('1'), bs('0'), bs('11010100'), rmz, cond_arg, bs('01'), rnz, rd], [rd, rnz, rmz, 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("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, uimm6, rn, rd], [rd, rn, rm, uimm6])
+
+# 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'), op0, op1, crn, crm, op2, rt64], [rt64, op0, op1, crn, crm, op2])
+aarch64op("msr", [bs('1101010100'), bs('0'), bs('1'), op0, op1, crn, crm, op2, rt64], [op0, 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, rt32], [rt32, 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("stlr", [bs('1'), sf, bs('001000'), bs('1'), bs('0'), bs('0'), bs('11111'), bs('1'), bs('11111'), rn64_deref_nooff, rt], [rt, rn64_deref_nooff])
+aarch64op("stlrb",[bs('0'), bs('0'), bs('001000'), bs('1'), bs('0'), bs('0'), bs('11111'), bs('1'), bs('11111'), rn64_deref_nooff, rt32], [rt32, rn64_deref_nooff])
+aarch64op("stlrh",[bs('0'), bs('1'), bs('001000'), bs('1'), bs('0'), bs('0'), bs('11111'), bs('1'), bs('11111'), rn64_deref_nooff, rt32], [rt32, 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])
+aarch64op("ic",  [bs('1101010100'), bs('0'), bs('01'), op1, bs('0111'), crm, op2, rt64], [op1, crm, op2, rt64])
+aarch64op('clrex', [bs('1101010100'), bs('0'), bs('00'), bs('011'), bs('0011'), uimm4, bs('010'), bs('11111')], [uimm4])
+aarch64op("tlbi", [bs('1101010100'), bs('0'), bs('01'), op1, bs('1000'), crm, op2, rt64], [op1, crm, op2, rt64])
+aarch64op('yield', [bs('1101010100'), bs('0'), bs('00'), bs('011'), bs('0010'), bs('0000'), bs('001'), bs('11111')], [])
+
+
+stacctype = bs_mod_name(l=1, fname='order', mn_mod=['', 'L'])
+ltacctype = bs_mod_name(l=1, fname='order', mn_mod=['', 'A'])
+
+
+aarch64op("casp",   [bs('0'), sf, bs('001000'), bs('0'), ltacctype, bs('1'), rs, stacctype, bs('11111'), rn64_deref_nooff, rt], [rs, rt, rn64_deref_nooff])
+aarch64op("ldaxrb", [bs('00'),  bs('001000'), bs('0'), bs('1'), bs('0'), bs('11111'), bs('1'), bs('11111'), rn64_deref_nooff, rt32], [rt32, rn64_deref_nooff])
diff --git a/src/miasm/arch/aarch64/disasm.py b/src/miasm/arch/aarch64/disasm.py
new file mode 100644
index 00000000..c4ad9181
--- /dev/null
+++ b/src/miasm/arch/aarch64/disasm.py
@@ -0,0 +1,27 @@
+from miasm.core.asmblock import disasmEngine
+from miasm.arch.aarch64.arch import mn_aarch64
+
+cb_aarch64_funcs = []
+
+
+def cb_aarch64_disasm(*args, **kwargs):
+    for func in cb_aarch64_funcs:
+        func(*args, **kwargs)
+
+
+class dis_aarch64b(disasmEngine):
+    attrib = "b"
+    def __init__(self, bs=None, **kwargs):
+        super(dis_aarch64b, self).__init__(
+            mn_aarch64, self.attrib, bs,
+            dis_block_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_block_callback = cb_aarch64_disasm,
+            **kwargs)
diff --git a/src/miasm/arch/aarch64/jit.py b/src/miasm/arch/aarch64/jit.py
new file mode 100644
index 00000000..f71ecae4
--- /dev/null
+++ b/src/miasm/arch/aarch64/jit.py
@@ -0,0 +1,79 @@
+from builtins import range
+import logging
+
+from miasm.jitter.jitload import Jitter, named_arguments
+from miasm.core.utils import pck64, upck64
+from miasm.arch.aarch64.sem import Lifter_Aarch64b, Lifter_Aarch64l
+
+log = logging.getLogger('jit_aarch64')
+hnd = logging.StreamHandler()
+hnd.setFormatter(logging.Formatter("[%(levelname)-8s]: %(message)s"))
+log.addHandler(hnd)
+log.setLevel(logging.CRITICAL)
+
+class jitter_aarch64l(Jitter):
+    max_reg_arg = 8
+
+    def __init__(self, loc_db, *args, **kwargs):
+        Jitter.__init__(self, Lifter_Aarch64l(loc_db), *args, **kwargs)
+        self.vm.set_little_endian()
+
+    def push_uint64_t(self, value):
+        self.cpu.SP -= 8
+        self.vm.set_mem(self.cpu.SP, pck64(value))
+
+    def pop_uint64_t(self):
+        value = self.vm.get_u64(self.cpu.SP)
+        self.cpu.SP += 8
+        return value
+
+    def get_stack_arg(self, index):
+        return self.vm.get_u64(self.cpu.SP + 8 * index)
+
+    # calling conventions
+
+    @named_arguments
+    def func_args_stdcall(self, n_args):
+        args = []
+        for i in range(min(n_args, self.max_reg_arg)):
+            args.append(getattr(self.cpu, 'X%d' % i))
+        for i in range(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, index):
+        if index < self.max_reg_arg:
+            arg = self.cpu.get_gpreg()['X%d' % index]
+        else:
+            arg = self.get_stack_arg(index - self.max_reg_arg)
+        return arg
+
+    def func_prepare_stdcall(self, ret_addr, *args):
+        for index in range(min(len(args), 4)):
+            setattr(self.cpu, 'X%d' % index, args[index])
+        for index in range(4, len(args)):
+            self.vm.set_mem(self.cpu.SP + 8 * (index - 4), pck64(args[index]))
+        self.cpu.LR = ret_addr
+
+    func_args_systemv = func_args_stdcall
+    func_ret_systemv = func_ret_stdcall
+    get_arg_n_systemv = get_arg_n_stdcall
+    func_prepare_systemv = func_prepare_stdcall
+
+    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, loc_db, *args, **kwargs):
+        Jitter.__init__(self, Lifter_Aarch64b(loc_db), *args, **kwargs)
+        self.vm.set_big_endian()
diff --git a/src/miasm/arch/aarch64/lifter_model_call.py b/src/miasm/arch/aarch64/lifter_model_call.py
new file mode 100644
index 00000000..74f25969
--- /dev/null
+++ b/src/miasm/arch/aarch64/lifter_model_call.py
@@ -0,0 +1,50 @@
+#-*- coding:utf-8 -*-
+
+from miasm.ir.analysis import LifterModelCall
+from miasm.arch.aarch64.sem import Lifter_Aarch64l, Lifter_Aarch64b
+
+
+class LifterModelCallAarch64lBase(Lifter_Aarch64l, LifterModelCall):
+
+    def __init__(self, loc_db):
+        Lifter_Aarch64l.__init__(self, loc_db)
+        self.ret_reg = self.arch.regs.X0
+
+
+class LifterModelCallAarch64bBase(Lifter_Aarch64b, LifterModelCall):
+
+    def __init__(self, loc_db):
+        Lifter_Aarch64b.__init__(self, loc_db)
+        self.ret_reg = self.arch.regs.X0
+
+
+class LifterModelCallAarch64l(LifterModelCallAarch64lBase):
+
+    def __init__(self, loc_db):
+        LifterModelCallAarch64lBase.__init__(self, loc_db)
+        self.ret_reg = self.arch.regs.X0
+
+    def get_out_regs(self, _):
+        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 LifterModelCallAarch64b(LifterModelCallAarch64bBase, LifterModelCallAarch64l):
+
+    def __init__(self, loc_db):
+        LifterModelCallAarch64bBase.__init__(self, loc_db)
+        self.ret_reg = self.arch.regs.X0
diff --git a/src/miasm/arch/aarch64/regs.py b/src/miasm/arch/aarch64/regs.py
new file mode 100644
index 00000000..9dee726b
--- /dev/null
+++ b/src/miasm/arch/aarch64/regs.py
@@ -0,0 +1,251 @@
+#-*- coding:utf-8 -*-
+
+from builtins import range
+from miasm.expression.expression import ExprId
+from miasm.core.cpu import gen_reg, gen_regs, reg_info
+
+exception_flags = ExprId('exception_flags', 32)
+interrupt_num = ExprId('interrupt_num', 32)
+
+
+gpregs32_str = ["W%d" % i for i in range(0x1f)] + ["WSP"]
+gpregs32_expr, gpregs32_init, gpregs32_info = gen_regs(
+    gpregs32_str, globals(), 32)
+
+gpregs64_str = ["X%d" % i for i in range(0x1E)] + ["LR", "SP"]
+gpregs64_expr, gpregs64_init, gpregs64_info = gen_regs(
+    gpregs64_str, globals(), 64)
+
+
+gpregsz32_str = ["W%d" % i for i in range(0x1f)] + ["WZR"]
+gpregsz32_expr, gpregsz32_init, gpregsz32_info = gen_regs(
+    gpregsz32_str, globals(), 32)
+
+gpregsz64_str = ["X%d" % i for i in range(0x1e)] + ["LR", "XZR"]
+gpregsz64_expr, gpregsz64_init, gpregsz64_info = gen_regs(
+    gpregsz64_str, globals(), 64)
+
+gpregs32_nosp, _, gpregs32_nosp_info = gen_regs(gpregs32_str[:-1], globals(), 32)
+gpregs64_nosp, _, gpregs64_nosp_info = gen_regs(gpregs64_str[:-1], globals(), 64)
+
+
+cr_str = ["c%d" % i for i in range(0x10)]
+cr_expr, cr_init, cr_info = gen_regs(cr_str, globals(), 32)
+
+
+simd08_str = ["B%d" % i for i in range(0x20)]
+simd08_expr, simd08_init, simd08_info = gen_regs(simd08_str, globals(), 8)
+
+simd16_str = ["H%d" % i for i in range(0x20)]
+simd16_expr, simd16_init, simd16_info = gen_regs(simd16_str, globals(), 16)
+
+simd32_str = ["S%d" % i for i in range(0x20)]
+simd32_expr, simd32_init, simd32_info = gen_regs(simd32_str, globals(), 32)
+
+simd64_str = ["D%d" % i for i in range(0x20)]
+simd64_expr, simd64_init, simd64_info = gen_regs(simd64_str, globals(), 64)
+
+simd128_str = ["Q%d" % i for i in range(0x20)]
+simd128_expr, simd128_init, simd128_info = gen_regs(
+    simd128_str, globals(), 128)
+
+sysregs_str = ['ACTLR_EL1', 'ACTLR_EL2', 'ACTLR_EL3', 'AFSR0_EL1',
+    'AFSR0_EL2', 'AFSR0_EL3', 'AFSR1_EL1', 'AFSR1_EL2', 'AFSR1_EL3',
+    'AIDR_EL1', 'AMAIR_EL1', 'AMAIR_EL2', 'AMAIR_EL3', 'AMCFGR_EL0',
+    'AMCG1IDR_EL0', 'AMCGCR_EL0', 'AMCNTENCLR0_EL0', 'AMCNTENCLR1_EL0',
+    'AMCNTENSET0_EL0', 'AMCNTENSET1_EL0', 'AMCR_EL0'] + \
+    ['AMEVCNTR%d%d_EL0' % (i, j)     for i in range(2) for j in range(16)] + \
+    ['AMEVCNTVOFF%d%d_EL2' % (i, j)  for i in range(2) for j in range(16)] + \
+    ['AMEVTYPER%d%d_EL0' % (i, j)    for i in range(2) for j in range(16)] + \
+    ['AMUSERENR_EL0', 'APDAKeyHi_EL1', 'APDAKeyLo_EL1', 'APDBKeyHi_EL1',
+    'APDBKeyLo_EL1', 'APGAKeyHi_EL1', 'APGAKeyLo_EL1', 'APIAKeyHi_EL1',
+    'APIAKeyLo_EL1', 'APIBKeyHi_EL1', 'APIBKeyLo_EL1', 'CCSIDR2_EL1',
+    'CCSIDR_EL1', 'CLIDR_EL1', 'CNTFRQ_EL0', 'CNTHCTL_EL2',
+    'CNTHPS_CTL_EL2', 'CNTHPS_CVAL_EL2', 'CNTHPS_TVAL_EL2', 'CNTHP_CTL_EL2',
+    'CNTHP_CVAL_EL2', 'CNTHP_TVAL_EL2', 'CNTHVS_CTL_EL2', 'CNTHVS_CVAL_EL2',
+    'CNTHVS_TVAL_EL2', 'CNTHV_CTL_EL2', 'CNTHV_CVAL_EL2', 'CNTHV_TVAL_EL2',
+    'CNTKCTL_EL1', 'CNTPCTSS_EL0', 'CNTPCT_EL0', 'CNTPOFF_EL2',
+    'CNTPS_CTL_EL1', 'CNTPS_CVAL_EL1', 'CNTPS_TVAL_EL1', 'CNTP_CTL_EL0',
+    'CNTP_CVAL_EL0', 'CNTP_TVAL_EL0', 'CNTVCTSS_EL0', 'CNTVCT_EL0',
+    'CNTVOFF_EL2', 'CNTV_CTL_EL0', 'CNTV_CVAL_EL0', 'CNTV_TVAL_EL0',
+    'CONTEXTIDR_EL1', 'CONTEXTIDR_EL2', 'CPACR_EL1', 'CPTR_EL2',
+    'CPTR_EL3', 'CSSELR_EL1', 'CTR_EL0', 'DACR32_EL2', 'DBGAUTHSTATUS_EL1'] + \
+    ['DBGBCR%d_EL1' % i for i in range(16)] + \
+    ['DBGBVR%d_EL1' % i for i in range(16)] + \
+    ['DBGCLAIMCLR_EL1', 'DBGCLAIMSET_EL1', 'DBGDTRRX_EL0', 'DBGDTRTX_EL0',
+    'DBGDTR_EL0', 'DBGPRCR_EL1', 'DBGVCR32_EL2'] + \
+    ['DBGWCR%d_EL1' % i for i in range(16)] + \
+    ['DBGWVR%d_EL1' % i for i in range(16)] + \
+    ['DCZID_EL0', 'DISR_EL1', 'ELR_EL1', 'ERRIDR_EL1',
+    'ERRSELR_EL1','ERXADDR_EL1', 'ERXCTLR_EL1', 'ERXFR_EL1',
+    'ERXMISC0_EL1', 'ERXMISC1_EL1', 'ERXMISC2_EL1', 'ERXMISC3_EL1',
+    'ERXPFGCDN_EL1', 'ERXPFGCTL_EL1', 'ERXPFGF_EL1', 'ERXSTATUS_EL1',
+    'ESR_EL1', 'ESR_EL2', 'ESR_EL3', 'FAR_EL1',
+    'FAR_EL2', 'FAR_EL3', 'FPEXC32_EL2', 'HACR_EL2',
+    'HAFGRTR_EL2', 'HCR_EL2', 'HDFGRTR_EL2', 'HDFGWTR_EL2',
+    'HFGITR_EL2', 'HFGRTR_EL2', 'HFGWTR_EL2', 'HPFAR_EL2',
+    'HSTR_EL2', 'ICC_AP0R0_EL1', 'ICC_AP0R1_EL1', 'ICC_AP0R2_EL1', 
+    'ICC_AP0R3_EL1', 'ICC_AP1R0_EL1', 'ICC_AP1R1_EL1', 'ICC_AP1R2_EL1',
+    'ICC_AP1R3_EL1', 'ICC_ASGI1R_EL1', 'ICC_BPR0_EL1', 'ICC_BPR1_EL1',
+    'ICC_CTLR_EL1', 'ICC_CTLR_EL3', 'ICC_DIR_EL1', 'ICC_EOIR0_EL1',
+    'ICC_EOIR1_EL1', 'ICC_HPPIR0_EL1', 'ICC_HPPIR1_EL1', 'ICC_IAR0_EL1',
+    'ICC_IAR1_EL1', 'ICC_IGRPEN0_EL1', 'ICC_IGRPEN1_EL1', 'ICC_IGRPEN1_EL3',
+    'ICC_PMR_EL1', 'ICC_RPR_EL1', 'ICC_SGI0R_EL1', 'ICC_SGI1R_EL1',
+    'ICC_SRE_EL1', 'ICC_SRE_EL2', 'ICC_SRE_EL3', 'ICH_AP0R0_EL2',
+    'ICH_AP0R1_EL2', 'ICH_AP0R2_EL2', 'ICH_AP0R3_EL2', 'ICH_AP1R0_EL2',
+    'ICH_AP1R1_EL2', 'ICH_AP1R2_EL2', 'ICH_AP1R3_EL2', 'ICH_EISR_EL2',
+    'ICH_ELRSR_EL2', 'ICH_HCR_EL2'] + \
+    ['ICH_LR%d_EL2' % i for i in range(16)] + \
+    ['ICH_MISR_EL2', 'ICH_VMCR_EL2', 'ICH_VTR_EL2', 'ID_AA64AFR0_EL1',
+    'ID_AA64AFR1_EL1', 'ID_AA64DFR0_EL1', 'ID_AA64DFR1_EL1', 'ID_AA64ISAR0_EL1',
+    'ID_AA64ISAR1_EL1', 'ID_AA64MMFR0_EL1','ID_AA64MMFR1_EL1', 'ID_AA64MMFR2_EL1',
+    'ID_AA64PFR0_EL1', 'ID_AA64PFR1_EL1', 'ID_AA64ZFR0_EL1', 'ID_AFR0_EL1',
+    'ID_DFR0_EL1', 'ID_ISAR0_EL1', 'ID_ISAR1_EL1', 'ID_ISAR2_EL1',
+    'ID_ISAR3_EL1', 'ID_ISAR4_EL1', 'ID_ISAR5_EL1', 'ID_MMFR0_EL1',
+    'ID_MMFR1_EL1', 'ID_MMFR2_EL1', 'ID_MMFR3_EL1', 'ID_MMFR4_EL1',
+    'ID_MMFR5_EL1', 'ID_PFR0_EL1', 'ID_PFR1_EL1', 'ID_PFR2_EL1',
+    'IFSR32_EL2', 'ISR_EL1', 'LORC_EL1', 'LOREA_EL1',
+    'LORID_EL1', 'LORN_EL1', 'LORSA_EL1', 'MAIR_EL1',
+    'MAIR_EL2', 'MAIR_EL3', 'MDCCINT_EL1', 'MDCCSR_EL0',
+    'MDCR_EL2', 'MDCR_EL3', 'MDRAR_EL1', 'MDSCR_EL1',
+    'MIDR_EL1', 'MPIDR_EL1', 'MVFR0_EL1', 'MVFR1_EL1',
+    'MVFR2_EL1', 'OSDLR_EL1', 'OSDTRRX_EL1', 'OSDTRTX_EL1',
+    'OSECCR_EL1', 'OSLAR_EL1', 'OSLSR_EL1', 'PAR_EL1',
+    'PMBIDR_EL1', 'PMBLIMITR_EL1', 'PMBPTR_EL1', 'PMBSR_EL1',
+    'PMCCFILTR_EL0', 'PMCCNTR_EL0', 'PMCEID0_EL0', 'PMCEID1_EL0',
+    'PMCNTENCLR_EL0', 'PMCNTENSET_EL0', 'PMCR_EL0'] + \
+    ['PMEVCNTR%d_EL0' % i for i in range(32)] + \
+    ['PMEVTYPER%d_EL0' % i for i in range(32)] + \
+    ['PMINTENCLR_EL1', 'PMINTENSET_EL1', 'PMMIR_EL1', 'PMOVSCLR_EL0',
+    'PMOVSSET_EL0', 'PMSCR_EL1', 'PMSCR_EL2', 'PMSELR_EL0',
+    'PMSEVFR_EL1', 'PMSFCR_EL1', 'PMSICR_EL1', 'PMSIDR_EL1',
+    'PMSIRR_EL1', 'PMSLATFR_EL1', 'PMSWINC_EL0', 'PMUSERENR_EL0',
+    'PMXEVCNTR_EL0', 'PMXEVTYPER_EL0', 'REVIDR_EL1', 'RMR_EL1',
+    'RMR_EL2', 'RMR_EL3', 'RVBAR_EL1', 'RVBAR_EL2',
+    'RVBAR_EL3', 'SCRLR_EL1', 'SCR_EL3', 'SCTLR_EL1',
+    'SCTLR_EL2', 'SCTLR_EL3', 'SDER32_EL2', 'SDER32_EL3',
+    'SPSR_EL1', 'TCR_EL1', 'TCR_EL2', 'TCR_EL3',
+    'TPIDRRO_EL0', 'TPIDR_EL0', 'TPIDR_EL1', 'TPIDR_EL2',
+    'TPIDR_EL3', 'TRFCR_EL1', 'TRFCR_EL2', 'TTBR0_EL1',
+    'TTBR0_EL2', 'TTBR0_EL3', 'TTBR1_EL1', 'VBAR_EL1',
+    'VBAR_EL2', 'VBAR_EL3', 'VDISR_EL2', 'VMPIDR_EL2',
+    'VNCR_EL2', 'VPIDR_EL2', 'VSESR_EL2', 'VSTCR_EL2',
+    'VSTTBR_EL2', 'VTCR_EL2', 'VTTBR_EL2', 'ZCR_EL1',
+    'ZCR_EL2', 'ZCR_EL3', 'ELR_EL2', 'ELR_EL3', 
+    'FPCR', 'FPSR', 'SP_EL0', 'SP_EL1', 
+    'SP_EL2', 'SPSR_abt', 'SPSR_EL2',
+    'SPSR_EL3', 'SPSR_fiq', 'SPSR_irq', 'SPSR_und',
+    'DLR_EL0', 'DSPSR_EL0']
+sysregs_expr, sysregs_init, sysregs_info = gen_regs(sysregs_str, globals(), 64)
+
+PC, _ = gen_reg("PC", 64)
+WZR, _ = gen_reg("WZR", 32)
+XZR, _ = gen_reg("XZR", 64)
+
+PC_init = ExprId("PC_init", 64)
+WZR_init = ExprId("WZR_init", 32)
+XZR_init = ExprId("XZR_init", 64)
+
+reg_zf = 'zf'
+reg_nf = 'nf'
+reg_of = 'of'
+reg_cf = 'cf'
+
+reg_df = 'df'
+reg_af = 'af'
+reg_iff = 'if'
+reg_ff = 'ff'
+
+reg_cur_el = 'cur_el'
+reg_dit = 'dit'
+reg_pan = 'pan'
+reg_spsel = 'spsel'
+reg_ssbs = 'ssbs'
+reg_tco = 'tco'
+reg_uao = 'uao'
+
+zf = ExprId(reg_zf, size=1)
+nf = ExprId(reg_nf, size=1)
+of = ExprId(reg_of, size=1)
+cf = ExprId(reg_cf, size=1)
+
+df = ExprId(reg_df, size=1)
+af = ExprId(reg_af, size=1)
+iff = ExprId(reg_iff, size=1)
+ff = ExprId(reg_ff, size=1)
+
+cur_el = ExprId(reg_cur_el, size=2)
+dit = ExprId(reg_dit, size=1)
+pan = ExprId(reg_pan, size=1)
+spsel = ExprId(reg_spsel, size=1)
+ssbs = ExprId(reg_ssbs, size=1)
+tco = ExprId(reg_tco, size=1)
+uao = ExprId(reg_uao, 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)
+df_init = ExprId("df_init", size=1)
+af_init = ExprId("af_init", size=1)
+iff_init = ExprId("if_init", size=1)
+ff_init = ExprId("ff_init", size=1)
+cur_el_init = ExprId("cur_el_init", size=2)
+dit_init = ExprId("dit_init", size=1)
+pan_init = ExprId("pan_init", size=1)
+spsel_init = ExprId("spsel_init", size=1)
+ssbs_init = ExprId("ssbs_init", size=1)
+tco_init = ExprId("tco_init", size=1)
+uao_init = ExprId("uao_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,
+    interrupt_num,
+    PC,
+    WZR,
+    XZR,
+    zf, nf, of, cf,
+    df, af, iff, ff,
+    cur_el, dit, pan, spsel, ssbs, tco, uao,
+] + sysregs_expr 
+
+
+all_regs_ids_no_alias = all_regs_ids
+
+attrib_to_regs = {
+    'l': all_regs_ids_no_alias,
+    'b': all_regs_ids_no_alias,
+}
+
+all_regs_ids_byname = dict([(x.name, x) for x in all_regs_ids])
+
+all_regs_ids_init = [ExprId("%s_init" % x.name, x.size) for x in all_regs_ids]
+
+regs_init = {}
+for i, r in enumerate(all_regs_ids):
+    regs_init[r] = all_regs_ids_init[i]
+
+regs_flt_expr = []
diff --git a/src/miasm/arch/aarch64/sem.py b/src/miasm/arch/aarch64/sem.py
new file mode 100644
index 00000000..eaa01228
--- /dev/null
+++ b/src/miasm/arch/aarch64/sem.py
@@ -0,0 +1,2386 @@
+from builtins import range
+from future.utils import viewitems
+
+from miasm.expression.expression import ExprId, ExprInt, ExprLoc, ExprMem, \
+    ExprCond, ExprCompose, ExprOp, ExprAssign
+from miasm.ir.ir import Lifter, IRBlock, AssignBlock
+from miasm.arch.aarch64.arch import mn_aarch64, conds_expr, replace_regs
+from miasm.arch.aarch64.regs import *
+from miasm.core.sembuilder import SemBuilder
+from miasm.jitter.csts import EXCEPT_DIV_BY_ZERO, EXCEPT_INT_XX
+
+# System register for ARM64-A 8.6
+system_regs = {
+    # op0 op1 crn crm op2
+    (2, 0, 0, 0, 2): OSDTRRX_EL1,
+
+    (2, 0, 0, 2, 0): MDCCINT_EL1,
+    (2, 0, 0, 2, 2): MDSCR_EL1,
+
+    (2, 0, 0, 3, 2): OSDTRTX_EL1,
+
+    (2, 0, 0, 6, 2): OSECCR_EL1,
+
+    (2, 0, 0, 0, 4): DBGBVR0_EL1,
+    (2, 0, 0, 1, 4): DBGBVR1_EL1,
+    (2, 0, 0, 2, 4): DBGBVR2_EL1,
+    (2, 0, 0, 3, 4): DBGBVR3_EL1,
+    (2, 0, 0, 4, 4): DBGBVR4_EL1,
+    (2, 0, 0, 5, 4): DBGBVR5_EL1,
+    (2, 0, 0, 6, 4): DBGBVR6_EL1,
+    (2, 0, 0, 7, 4): DBGBVR7_EL1,
+    (2, 0, 0, 8, 4): DBGBVR8_EL1,
+    (2, 0, 0, 9, 4): DBGBVR9_EL1,
+    (2, 0, 0, 10, 4): DBGBVR10_EL1,
+    (2, 0, 0, 11, 4): DBGBVR11_EL1,
+    (2, 0, 0, 12, 4): DBGBVR12_EL1,
+    (2, 0, 0, 13, 4): DBGBVR13_EL1,
+    (2, 0, 0, 14, 4): DBGBVR14_EL1,
+    (2, 0, 0, 15, 4): DBGBVR15_EL1,
+
+    (2, 0, 0, 0, 5): DBGBCR0_EL1,
+    (2, 0, 0, 1, 5): DBGBCR1_EL1,
+    (2, 0, 0, 2, 5): DBGBCR2_EL1,
+    (2, 0, 0, 3, 5): DBGBCR3_EL1,
+    (2, 0, 0, 4, 5): DBGBCR4_EL1,
+    (2, 0, 0, 5, 5): DBGBCR5_EL1,
+    (2, 0, 0, 6, 5): DBGBCR6_EL1,
+    (2, 0, 0, 7, 5): DBGBCR7_EL1,
+    (2, 0, 0, 8, 5): DBGBCR8_EL1,
+    (2, 0, 0, 9, 5): DBGBCR9_EL1,
+    (2, 0, 0, 10, 5): DBGBCR10_EL1,
+    (2, 0, 0, 11, 5): DBGBCR11_EL1,
+    (2, 0, 0, 12, 5): DBGBCR12_EL1,
+    (2, 0, 0, 13, 5): DBGBCR13_EL1,
+    (2, 0, 0, 14, 5): DBGBCR14_EL1,
+    (2, 0, 0, 15, 5): DBGBCR15_EL1,
+
+    (2, 0, 0, 0, 6): DBGWVR0_EL1,
+    (2, 0, 0, 1, 6): DBGWVR1_EL1,
+    (2, 0, 0, 2, 6): DBGWVR2_EL1,
+    (2, 0, 0, 3, 6): DBGWVR3_EL1,
+    (2, 0, 0, 4, 6): DBGWVR4_EL1,
+    (2, 0, 0, 5, 6): DBGWVR5_EL1,
+    (2, 0, 0, 6, 6): DBGWVR6_EL1,
+    (2, 0, 0, 7, 6): DBGWVR7_EL1,
+    (2, 0, 0, 8, 6): DBGWVR8_EL1,
+    (2, 0, 0, 9, 6): DBGWVR9_EL1,
+    (2, 0, 0, 10, 6): DBGWVR10_EL1,
+    (2, 0, 0, 11, 6): DBGWVR11_EL1,
+    (2, 0, 0, 12, 6): DBGWVR12_EL1,
+    (2, 0, 0, 13, 6): DBGWVR13_EL1,
+    (2, 0, 0, 14, 6): DBGWVR14_EL1,
+    (2, 0, 0, 15, 6): DBGWVR15_EL1,
+
+    (2, 0, 0, 0, 7): DBGWCR0_EL1,
+    (2, 0, 0, 1, 7): DBGWCR1_EL1,
+    (2, 0, 0, 2, 7): DBGWCR2_EL1,
+    (2, 0, 0, 3, 7): DBGWCR3_EL1,
+    (2, 0, 0, 4, 7): DBGWCR4_EL1,
+    (2, 0, 0, 5, 7): DBGWCR5_EL1,
+    (2, 0, 0, 6, 7): DBGWCR6_EL1,
+    (2, 0, 0, 7, 7): DBGWCR7_EL1,
+    (2, 0, 0, 8, 7): DBGWCR8_EL1,
+    (2, 0, 0, 9, 7): DBGWCR9_EL1,
+    (2, 0, 0, 10, 7): DBGWCR10_EL1,
+    (2, 0, 0, 11, 7): DBGWCR11_EL1,
+    (2, 0, 0, 12, 7): DBGWCR12_EL1,
+    (2, 0, 0, 13, 7): DBGWCR13_EL1,
+    (2, 0, 0, 14, 7): DBGWCR14_EL1,
+    (2, 0, 0, 15, 7): DBGWCR15_EL1,
+
+    (2, 0, 1, 0, 0): MDRAR_EL1,
+    (2, 0, 1, 0, 4): OSLAR_EL1,
+
+    (2, 0, 1, 1, 4): OSLSR_EL1,
+
+    (2, 0, 1, 3, 4): OSDLR_EL1,
+
+    (2, 0, 1, 4, 4): DBGPRCR_EL1,
+
+    (2, 0, 7, 8, 6): DBGCLAIMSET_EL1,
+
+    (2, 0, 7, 9, 6): DBGCLAIMCLR_EL1,
+
+    (2, 0, 7, 14, 6): DBGAUTHSTATUS_EL1,
+
+    (2, 3, 0, 1, 0): MDCCSR_EL0,
+
+    (2, 3, 0, 4, 0): DBGDTR_EL0,
+
+    (2, 3, 0, 5, 0): DBGDTRRX_EL0,
+    (2, 3, 0, 5, 1): DBGDTRTX_EL0,
+
+    (2, 4, 0, 7, 0): DBGVCR32_EL2,
+
+    (3, 0, 0, 0, 0): MIDR_EL1,
+    (3, 0, 0, 0, 5): MPIDR_EL1,
+    (3, 0, 0, 0, 6): REVIDR_EL1,
+
+    (3, 0, 0, 1, 0): ID_PFR0_EL1,
+    (3, 0, 0, 1, 1): ID_PFR1_EL1,
+    (3, 0, 0, 1, 2): ID_DFR0_EL1,
+    (3, 0, 0, 1, 3): ID_AFR0_EL1,
+    (3, 0, 0, 1, 4): ID_MMFR0_EL1,
+    (3, 0, 0, 1, 5): ID_MMFR1_EL1,
+    (3, 0, 0, 1, 6): ID_MMFR2_EL1,
+    (3, 0, 0, 1, 7): ID_MMFR3_EL1,
+
+    (3, 0, 0, 2, 0): ID_ISAR0_EL1,
+    (3, 0, 0, 2, 1): ID_ISAR1_EL1,
+    (3, 0, 0, 2, 2): ID_ISAR2_EL1,
+    (3, 0, 0, 2, 3): ID_ISAR3_EL1,
+    (3, 0, 0, 2, 4): ID_ISAR4_EL1,
+    (3, 0, 0, 2, 5): ID_ISAR5_EL1,
+    (3, 0, 0, 2, 6): ID_MMFR4_EL1,
+
+    (3, 0, 0, 3, 0): MVFR0_EL1,
+    (3, 0, 0, 3, 1): MVFR1_EL1,
+    (3, 0, 0, 3, 2): MVFR2_EL1,
+    (3, 0, 0, 3, 4): ID_PFR2_EL1,
+    (3, 0, 0, 3, 6): ID_MMFR5_EL1,
+
+    (3, 0, 0, 4, 0): ID_AA64PFR0_EL1,
+    (3, 0, 0, 4, 1): ID_AA64PFR1_EL1,
+    (3, 0, 0, 4, 4): ID_AA64ZFR0_EL1,
+
+    (3, 0, 0, 5, 0): ID_AA64DFR0_EL1,
+    (3, 0, 0, 5, 1): ID_AA64DFR1_EL1,
+    (3, 0, 0, 5, 4): ID_AA64AFR0_EL1,
+    (3, 0, 0, 5, 5): ID_AA64AFR1_EL1,
+
+    (3, 0, 0, 6, 0): ID_AA64ISAR0_EL1,
+    (3, 0, 0, 6, 1): ID_AA64ISAR1_EL1,
+
+    (3, 0, 0, 7, 0): ID_AA64MMFR0_EL1,
+    (3, 0, 0, 7, 1): ID_AA64MMFR1_EL1,
+    (3, 0, 0, 7, 2): ID_AA64MMFR2_EL1,
+
+    (3, 0, 1, 0, 0): SCRLR_EL1,
+    (3, 0, 1, 0, 1): ACTLR_EL1,
+    (3, 0, 1, 0, 2): CPACR_EL1,
+
+    (3, 0, 1, 2, 0): ZCR_EL1,
+    (3, 0, 1, 2, 1): TRFCR_EL1,
+
+    (3, 0, 2, 0, 0): TTBR0_EL1,
+    (3, 0, 2, 0, 1): TTBR1_EL1,
+    (3, 0, 2, 0, 2): TCR_EL1,
+
+    (3, 0, 2, 1, 0): APIAKeyLo_EL1,
+    (3, 0, 2, 1, 1): APIAKeyHi_EL1,
+    (3, 0, 2, 1, 2): APIBKeyLo_EL1,
+    (3, 0, 2, 1, 3): APIBKeyHi_EL1,
+
+    (3, 0, 2, 2, 0): APDAKeyLo_EL1,
+    (3, 0, 2, 2, 1): APDAKeyHi_EL1,
+    (3, 0, 2, 2, 2): APDBKeyLo_EL1,
+    (3, 0, 2, 2, 3): APDBKeyHi_EL1,
+
+    (3, 0, 2, 3, 0): APGAKeyLo_EL1,
+    (3, 0, 2, 3, 1): APGAKeyHi_EL1,
+
+    (3, 0, 4, 1, 0): SP_EL0,
+    (3, 0, 4, 6, 0): ICC_PMR_EL1, # Alias ICV_PMR_EL1
+
+    (3, 0, 5, 1, 0): AFSR0_EL1,
+    (3, 0, 5, 1, 1): AFSR1_EL1,
+
+    (3, 0, 5, 2, 0): ESR_EL1,
+
+    (3, 0, 5, 3, 0): ERRIDR_EL1,
+    (3, 0, 5, 3, 1): ERRSELR_EL1,
+
+    (3, 0, 5, 4, 0): ERXFR_EL1,
+    (3, 0, 5, 4, 1): ERXCTLR_EL1,
+    (3, 0, 5, 4, 2): ERXSTATUS_EL1,
+    (3, 0, 5, 4, 3): ERXADDR_EL1,
+    (3, 0, 5, 4, 4): ERXPFGF_EL1,
+    (3, 0, 5, 4, 5): ERXPFGCTL_EL1,
+    (3, 0, 5, 4, 6): ERXPFGCDN_EL1,
+
+    (3, 0, 5, 5, 0): ERXMISC0_EL1,
+    (3, 0, 5, 5, 1): ERXMISC1_EL1,
+    (3, 0, 5, 5, 2): ERXMISC2_EL1,
+    (3, 0, 5, 5, 3): ERXMISC3_EL1,
+
+    (3, 0, 6, 0, 0): FAR_EL1,
+
+    (3, 0, 7, 4, 0): PAR_EL1,
+
+    (3, 0, 9, 9, 0): PMSCR_EL1,
+    (3, 0, 9, 9, 2): PMSICR_EL1,
+    (3, 0, 9, 9, 3): PMSIRR_EL1,
+    (3, 0, 9, 9, 4): PMSFCR_EL1,
+    (3, 0, 9, 9, 5): PMSEVFR_EL1,
+    (3, 0, 9, 9, 6): PMSLATFR_EL1,
+    (3, 0, 9, 9, 7): PMSIDR_EL1,
+
+    (3, 0, 9, 10, 0): PMBLIMITR_EL1,
+    (3, 0, 9, 10, 1): PMBPTR_EL1,
+    (3, 0, 9, 10, 3): PMBSR_EL1,
+    (3, 0, 9, 10, 7): PMBIDR_EL1,
+
+    (3, 0, 9, 14, 1): PMINTENSET_EL1,
+    (3, 0, 9, 14, 2): PMINTENCLR_EL1,
+    (3, 0, 9, 14, 6): PMMIR_EL1,
+
+    (3, 0, 10, 2, 0): MAIR_EL1,
+
+    (3, 0, 10, 3, 0): AMAIR_EL1,
+
+    (3, 0, 10, 4, 0): LORSA_EL1,
+    (3, 0, 10, 4, 1): LOREA_EL1,
+    (3, 0, 10, 4, 2): LORN_EL1,
+    (3, 0, 10, 4, 3): LORC_EL1,
+    (3, 0, 10, 4, 7): LORID_EL1,
+
+    (3, 0, 12, 0, 0): VBAR_EL1,
+    (3, 0, 12, 0, 1): RVBAR_EL1,
+    (3, 0, 12, 0, 2): RMR_EL1,
+
+    (3, 0, 12, 1, 0): ISR_EL1,
+    (3, 0, 12, 1, 1): DISR_EL1,
+
+    (3, 0, 12, 8, 0): ICC_IAR0_EL1,   # Alias ICV_IAR0_EL1
+    (3, 0, 12, 8, 1): ICC_EOIR0_EL1,  # Alias ICV_EOIR0_EL1
+    (3, 0, 12, 8, 2): ICC_HPPIR0_EL1, # Alias ICV_HPPIR0_EL1
+    (3, 0, 12, 8, 3): ICC_BPR0_EL1,   # Alias ICV_BPR0_EL1
+    (3, 0, 12, 8, 4): ICC_AP0R0_EL1,  # Alias ICV_AP0R0_EL1
+    (3, 0, 12, 8, 5): ICC_AP0R1_EL1,  # Alias ICV_AP0R1_EL1
+    (3, 0, 12, 8, 6): ICC_AP0R2_EL1,  # Alias ICV_AP0R2_EL1
+    (3, 0, 12, 8, 7): ICC_AP0R3_EL1,  # Alias ICV_AP0R3_EL1
+
+    (3, 0, 12, 9, 0): ICC_AP1R0_EL1,  # Alias ICV_AP1R0_EL1
+    (3, 0, 12, 9, 1): ICC_AP1R1_EL1,  # Alias ICV_AP1R1_EL1
+    (3, 0, 12, 9, 2): ICC_AP1R2_EL1,  # Alias ICV_AP1R2_EL1
+    (3, 0, 12, 9, 3): ICC_AP1R3_EL1,  # Alias ICV_AP1R3_EL1
+
+    (3, 0, 12, 11, 1): ICC_DIR_EL1,  # Alias ICV_DIR_EL1
+    (3, 0, 12, 11, 3): ICC_RPR_EL1,  # Alias ICV_RPR_EL1
+    (3, 0, 12, 11, 5): ICC_SGI1R_EL1,
+    (3, 0, 12, 11, 6): ICC_ASGI1R_EL1,
+    (3, 0, 12, 11, 7): ICC_SGI0R_EL1,
+
+    (3, 0, 12, 12, 0): ICC_IAR1_EL1,   # Alias ICV_IAR1_EL1
+    (3, 0, 12, 12, 1): ICC_EOIR1_EL1,  # Alias ICV_EOIR1_EL1
+    (3, 0, 12, 12, 2): ICC_HPPIR1_EL1, # Alias ICV_HPPIR1_EL1
+    (3, 0, 12, 12, 3): ICC_BPR1_EL1,   # Alias ICV_BPR1_EL1
+    (3, 0, 12, 12, 4): ICC_CTLR_EL1,   # Alias ICV_CTLR_EL1
+    (3, 0, 12, 12, 5): ICC_SRE_EL1,
+    (3, 0, 12, 12, 6): ICC_IGRPEN0_EL1,  # Alias ICV_IGRPEN0_EL1
+    (3, 0, 12, 12, 7): ICC_IGRPEN1_EL1,  # Alias ICV_IGRPEN1_EL1
+
+    (3, 0, 13, 0, 1): CONTEXTIDR_EL1,
+    (3, 0, 13, 0, 4): TPIDR_EL1,
+
+    (3, 0, 14, 1, 0): CNTKCTL_EL1,
+
+    (3, 1, 0, 0, 0): CCSIDR_EL1,
+    (3, 1, 0, 0, 1): CLIDR_EL1,
+    (3, 1, 0, 0, 2): CCSIDR2_EL1,
+    (3, 1, 0, 0, 7): AIDR_EL1,
+
+    (3, 2, 0, 0, 0): CSSELR_EL1,
+    (3, 0, 0, 0, 1): CTR_EL0,
+
+    (3, 3, 0, 0, 7): DCZID_EL0,
+
+    (3, 3, 4, 4, 0): FPCR,
+    (3, 3, 4, 4, 1): FPSR,
+
+    (3, 3, 4, 5, 0): DSPSR_EL0,
+    (3, 3, 4, 5, 1): DLR_EL0,
+
+    (3, 4, 4, 0, 0): SPSR_EL2,
+    (3, 4 ,4, 0, 1): ELR_EL2,
+
+    (3, 4, 4, 1, 0): SP_EL1,
+
+    (3, 4, 4, 3, 0): SPSR_irq,
+    (3, 4, 4, 3, 1): SPSR_abt,
+    (3, 4, 4, 3, 2): SPSR_und,
+    (3, 4, 4, 3, 3): SPSR_fiq,
+
+    (3, 3, 9, 12, 0): PMCR_EL0,
+    (3, 3, 9, 12, 1): PMCNTENSET_EL0,
+    (3, 3, 9, 12, 2): PMCNTENCLR_EL0,
+    (3, 3, 9, 12, 3): PMOVSCLR_EL0,
+    (3, 3, 9, 12, 4): PMSWINC_EL0,
+    (3, 3, 9, 12, 5): PMSELR_EL0,
+    (3, 3, 9, 12, 6): PMCEID0_EL0,
+    (3, 3, 9, 12, 7): PMCEID1_EL0,
+
+    (3, 3, 9, 13, 0): PMCCNTR_EL0,
+    (3, 3, 9, 13, 1): PMXEVTYPER_EL0,
+    (3, 3, 9, 13, 2): PMXEVCNTR_EL0,
+
+    (3, 3, 9, 14, 0): PMUSERENR_EL0,
+    (3, 3, 9, 14, 3): PMOVSSET_EL0,
+
+    (3, 3, 13, 0, 2): TPIDR_EL0,
+    (3, 3, 13, 0, 3): TPIDRRO_EL0,
+
+    (3, 3, 13, 2, 0): AMCR_EL0,
+    (3, 3, 13, 2, 1): AMCFGR_EL0,
+    (3, 3, 13, 2, 2): AMCGCR_EL0,
+    (3, 3, 13, 2, 3): AMUSERENR_EL0,
+    (3, 3, 13, 2, 4): AMCNTENCLR0_EL0,
+    (3, 3, 13, 2, 5): AMCNTENSET0_EL0,
+    (3, 3, 13, 2, 6): AMCG1IDR_EL0,
+
+    (3, 3, 13, 3, 0): AMCNTENCLR1_EL0,
+    (3, 3, 13, 3, 1): AMCNTENSET1_EL0,
+
+    (3, 3, 13, 4, 0): AMEVCNTR00_EL0,
+    (3, 3, 13, 4, 1): AMEVCNTR01_EL0,
+    (3, 3, 13, 4, 2): AMEVCNTR02_EL0,
+    (3, 3, 13, 4, 3): AMEVCNTR03_EL0,
+    (3, 3, 13, 4, 4): AMEVCNTR04_EL0,
+    (3, 3, 13, 4, 5): AMEVCNTR05_EL0,
+    (3, 3, 13, 4, 6): AMEVCNTR06_EL0,
+    (3, 3, 13, 4, 7): AMEVCNTR07_EL0,
+
+    (3, 3, 13, 5, 0): AMEVCNTR08_EL0,
+    (3, 3, 13, 5, 1): AMEVCNTR09_EL0,
+    (3, 3, 13, 5, 2): AMEVCNTR010_EL0,
+    (3, 3, 13, 5, 3): AMEVCNTR011_EL0,
+    (3, 3, 13, 5, 4): AMEVCNTR012_EL0,
+    (3, 3, 13, 5, 5): AMEVCNTR013_EL0,
+    (3, 3, 13, 5, 6): AMEVCNTR014_EL0,
+    (3, 3, 13, 5, 7): AMEVCNTR015_EL0,
+
+    (3, 3, 13, 6, 0): AMEVTYPER00_EL0,
+    (3, 3, 13, 6, 1): AMEVTYPER01_EL0,
+    (3, 3, 13, 6, 2): AMEVTYPER02_EL0,
+    (3, 3, 13, 6, 3): AMEVTYPER03_EL0,
+    (3, 3, 13, 6, 4): AMEVTYPER04_EL0,
+    (3, 3, 13, 6, 5): AMEVTYPER05_EL0,
+    (3, 3, 13, 6, 6): AMEVTYPER06_EL0,
+    (3, 3, 13, 6, 7): AMEVTYPER07_EL0,
+
+    (3, 3, 13, 7, 0): AMEVTYPER08_EL0,
+    (3, 3, 13, 7, 1): AMEVTYPER09_EL0,
+    (3, 3, 13, 7, 2): AMEVTYPER010_EL0,
+    (3, 3, 13, 7, 3): AMEVTYPER011_EL0,
+    (3, 3, 13, 7, 4): AMEVTYPER012_EL0,
+    (3, 3, 13, 7, 5): AMEVTYPER013_EL0,
+    (3, 3, 13, 7, 6): AMEVTYPER014_EL0,
+    (3, 3, 13, 7, 7): AMEVTYPER015_EL0,
+
+    (3, 3, 13, 12, 0): AMEVCNTR10_EL0,
+    (3, 3, 13, 12, 1): AMEVCNTR11_EL0,
+    (3, 3, 13, 12, 2): AMEVCNTR12_EL0,
+    (3, 3, 13, 12, 3): AMEVCNTR13_EL0,
+    (3, 3, 13, 12, 4): AMEVCNTR14_EL0,
+    (3, 3, 13, 12, 5): AMEVCNTR15_EL0,
+    (3, 3, 13, 12, 6): AMEVCNTR16_EL0,
+    (3, 3, 13, 12, 7): AMEVCNTR17_EL0,
+
+    (3, 3, 13, 13, 0): AMEVCNTR18_EL0,
+    (3, 3, 13, 13, 1): AMEVCNTR19_EL0,
+    (3, 3, 13, 13, 2): AMEVCNTR110_EL0,
+    (3, 3, 13, 13, 3): AMEVCNTR111_EL0,
+    (3, 3, 13, 13, 4): AMEVCNTR112_EL0,
+    (3, 3, 13, 13, 5): AMEVCNTR113_EL0,
+    (3, 3, 13, 13, 6): AMEVCNTR114_EL0,
+    (3, 3, 13, 13, 7): AMEVCNTR115_EL0,
+
+    (3, 3, 13, 14, 0): AMEVTYPER10_EL0,
+    (3, 3, 13, 14, 1): AMEVTYPER11_EL0,
+    (3, 3, 13, 14, 2): AMEVTYPER12_EL0,
+    (3, 3, 13, 14, 3): AMEVTYPER13_EL0,
+    (3, 3, 13, 14, 4): AMEVTYPER14_EL0,
+    (3, 3, 13, 14, 5): AMEVTYPER15_EL0,
+    (3, 3, 13, 14, 6): AMEVTYPER16_EL0,
+    (3, 3, 13, 14, 7): AMEVTYPER17_EL0,
+
+    (3, 3, 13, 15, 0): AMEVTYPER18_EL0,
+    (3, 3, 13, 15, 1): AMEVTYPER19_EL0,
+    (3, 3, 13, 15, 2): AMEVTYPER110_EL0,
+    (3, 3, 13, 15, 3): AMEVTYPER111_EL0,
+    (3, 3, 13, 15, 4): AMEVTYPER112_EL0,
+    (3, 3, 13, 15, 5): AMEVTYPER113_EL0,
+    (3, 3, 13, 15, 6): AMEVTYPER114_EL0,
+    (3, 3, 13, 15, 7): AMEVTYPER115_EL0,
+
+    (3, 3, 14, 0, 0): CNTFRQ_EL0,
+    (3, 3, 14, 0, 1): CNTPCT_EL0,
+    (3, 3, 14, 0, 2): CNTVCT_EL0,
+    (3, 3, 14, 0, 5): CNTPCTSS_EL0,
+    (3, 3, 14, 0, 6): CNTVCTSS_EL0,
+
+    (3, 3, 14, 2, 0): CNTP_TVAL_EL0,
+    (3, 3, 14, 2, 1): CNTP_CTL_EL0,
+    (3, 3, 14, 2, 2): CNTP_CVAL_EL0,
+
+    (3, 3, 14, 3, 0): CNTV_TVAL_EL0,
+    (3, 3, 14, 3, 1): CNTV_CTL_EL0,
+    (3, 3, 14, 3, 2): CNTV_CVAL_EL0,
+
+    (3, 3, 14, 8, 0): PMEVCNTR0_EL0,
+    (3, 3, 14, 8, 1): PMEVCNTR1_EL0,
+    (3, 3, 14, 8, 2): PMEVCNTR2_EL0,
+    (3, 3, 14, 8, 3): PMEVCNTR3_EL0,
+    (3, 3, 14, 8, 4): PMEVCNTR4_EL0,
+    (3, 3, 14, 8, 5): PMEVCNTR5_EL0,
+    (3, 3, 14, 8, 6): PMEVCNTR6_EL0,
+    (3, 3, 14, 8, 7): PMEVCNTR7_EL0,
+
+    (3, 3, 14, 9, 0): PMEVCNTR8_EL0,
+    (3, 3, 14, 9, 1): PMEVCNTR9_EL0,
+    (3, 3, 14, 9, 2): PMEVCNTR10_EL0,
+    (3, 3, 14, 9, 3): PMEVCNTR11_EL0,
+    (3, 3, 14, 9, 4): PMEVCNTR12_EL0,
+    (3, 3, 14, 9, 5): PMEVCNTR13_EL0,
+    (3, 3, 14, 9, 6): PMEVCNTR14_EL0,
+    (3, 3, 14, 9, 7): PMEVCNTR15_EL0,
+
+    (3, 3, 14, 10, 0): PMEVCNTR16_EL0,
+    (3, 3, 14, 10, 1): PMEVCNTR17_EL0,
+    (3, 3, 14, 10, 2): PMEVCNTR18_EL0,
+    (3, 3, 14, 10, 3): PMEVCNTR19_EL0,
+    (3, 3, 14, 10, 4): PMEVCNTR20_EL0,
+    (3, 3, 14, 10, 5): PMEVCNTR21_EL0,
+    (3, 3, 14, 10, 6): PMEVCNTR22_EL0,
+    (3, 3, 14, 10, 7): PMEVCNTR23_EL0,
+
+    (3, 3, 14, 11, 0): PMEVCNTR24_EL0,
+    (3, 3, 14, 11, 1): PMEVCNTR25_EL0,
+    (3, 3, 14, 11, 2): PMEVCNTR26_EL0,
+    (3, 3, 14, 11, 3): PMEVCNTR27_EL0,
+    (3, 3, 14, 11, 4): PMEVCNTR28_EL0,
+    (3, 3, 14, 11, 5): PMEVCNTR29_EL0,
+    (3, 3, 14, 11, 6): PMEVCNTR30_EL0,
+
+    (3, 3, 14, 12, 0): PMEVTYPER0_EL0,
+    (3, 3, 14, 12, 1): PMEVTYPER1_EL0,
+    (3, 3, 14, 12, 2): PMEVTYPER2_EL0,
+    (3, 3, 14, 12, 3): PMEVTYPER3_EL0,
+    (3, 3, 14, 12, 4): PMEVTYPER4_EL0,
+    (3, 3, 14, 12, 5): PMEVTYPER5_EL0,
+    (3, 3, 14, 12, 6): PMEVTYPER6_EL0,
+    (3, 3, 14, 12, 7): PMEVTYPER7_EL0,
+
+    (3, 3, 14, 13, 0): PMEVTYPER8_EL0,
+    (3, 3, 14, 13, 1): PMEVTYPER9_EL0,
+    (3, 3, 14, 13, 2): PMEVTYPER10_EL0,
+    (3, 3, 14, 13, 3): PMEVTYPER11_EL0,
+    (3, 3, 14, 13, 4): PMEVTYPER12_EL0,
+    (3, 3, 14, 13, 5): PMEVTYPER13_EL0,
+    (3, 3, 14, 13, 6): PMEVTYPER14_EL0,
+    (3, 3, 14, 13, 7): PMEVTYPER15_EL0,
+
+    (3, 3, 14, 14, 0): PMEVTYPER16_EL0,
+    (3, 3, 14, 14, 1): PMEVTYPER17_EL0,
+    (3, 3, 14, 14, 2): PMEVTYPER18_EL0,
+    (3, 3, 14, 14, 3): PMEVTYPER19_EL0,
+    (3, 3, 14, 14, 4): PMEVTYPER20_EL0,
+    (3, 3, 14, 14, 5): PMEVTYPER21_EL0,
+    (3, 3, 14, 14, 6): PMEVTYPER22_EL0,
+    (3, 3, 14, 14, 7): PMEVTYPER23_EL0,
+
+    (3, 3, 14, 15, 0): PMEVTYPER24_EL0,
+    (3, 3, 14, 15, 1): PMEVTYPER25_EL0,
+    (3, 3, 14, 15, 2): PMEVTYPER26_EL0,
+    (3, 3, 14, 15, 3): PMEVTYPER27_EL0,
+    (3, 3, 14, 15, 4): PMEVTYPER28_EL0,
+    (3, 3, 14, 15, 5): PMEVTYPER29_EL0,
+    (3, 3, 14, 15, 6): PMEVTYPER30_EL0,
+    (3, 3, 14, 15, 7): PMCCFILTR_EL0,
+
+    (3, 4, 0, 0, 0): VPIDR_EL2,
+    (3, 4, 0, 0, 5): VMPIDR_EL2,
+
+    (3, 4, 1, 0, 0): SCTLR_EL2,
+    (3, 4, 1, 0, 5): ACTLR_EL2,
+
+    (3, 4, 1, 1, 0): HCR_EL2,
+    (3, 4, 1, 1, 1): MDCR_EL2,
+    (3, 4, 1, 1, 2): CPTR_EL2,
+    (3, 4, 1, 1, 3): HSTR_EL2,
+    (3, 4, 1, 1, 4): HFGRTR_EL2,
+    (3, 4, 1, 1, 5): HFGWTR_EL2,
+    (3, 4, 1, 1, 6): HFGITR_EL2,
+    (3, 4, 1, 1, 7): HACR_EL2,
+
+    (3, 4, 1, 2, 0): ZCR_EL2,
+
+    (3, 4, 1, 2, 1): TRFCR_EL2,
+
+    (3, 4, 1, 3, 1): SDER32_EL2,
+
+    (3, 4, 2, 0, 0): TTBR0_EL2,
+    (3, 4, 2, 0, 2): TCR_EL2,
+
+    (3, 4, 2, 1, 0): VTTBR_EL2,
+    (3, 4, 2, 1, 2): VTCR_EL2,
+
+    (3, 4, 2, 2, 0): VNCR_EL2,
+
+    (3, 4, 2, 6, 0): VSTTBR_EL2,
+    (3, 4, 2, 6, 2): VSTCR_EL2,
+
+    (3, 4, 3, 0, 0): DACR32_EL2,
+
+    (3, 4, 3, 1, 4): HDFGRTR_EL2,
+    (3, 4, 3, 1, 5): HDFGWTR_EL2,
+    (3, 4, 3, 1, 6): HAFGRTR_EL2,
+
+    (3, 4, 5, 0, 1): IFSR32_EL2,
+
+    (3, 4, 5, 1, 0): AFSR0_EL2,
+    (3, 4, 5, 1, 1): AFSR1_EL2,
+
+    (3, 4, 5, 2, 0): ESR_EL2,
+    (3, 4, 5, 2, 3): VSESR_EL2,
+
+    (3, 4, 5, 3, 0): FPEXC32_EL2,
+
+    (3, 4, 6, 0, 0): FAR_EL2,
+    (3, 4, 6, 0, 4): HPFAR_EL2,
+
+    (3, 4, 9, 9, 0): PMSCR_EL2,
+
+    (3, 4, 10, 2, 0): MAIR_EL2,
+
+    (3, 4, 10, 3, 0): AMAIR_EL2,
+
+    (3, 4, 12, 0, 0): VBAR_EL2,
+    (3, 4, 12, 0, 1): RVBAR_EL2,
+    (3, 4, 12, 0, 2): RMR_EL2,
+
+    (3, 4, 12, 1, 1): VDISR_EL2,
+
+    (3, 4, 12, 8, 0): ICH_AP0R0_EL2,
+    (3, 4, 12, 8, 1): ICH_AP0R1_EL2,
+    (3, 4, 12, 8, 2): ICH_AP0R2_EL2,
+    (3, 4, 12, 8, 3): ICH_AP0R3_EL2,
+
+    (3, 4, 12, 9, 0): ICH_AP1R0_EL2,
+    (3, 4, 12, 9, 1): ICH_AP1R1_EL2,
+    (3, 4, 12, 9, 2): ICH_AP1R2_EL2,
+    (3, 4, 12, 9, 3): ICH_AP1R3_EL2,
+    (3, 4, 12, 9, 5): ICC_SRE_EL2,
+
+    (3, 4, 12, 11, 0): ICH_HCR_EL2,
+    (3, 4, 12, 11, 1): ICH_VTR_EL2,
+    (3, 4, 12, 11, 2): ICH_MISR_EL2,
+    (3, 4, 12, 11, 3): ICH_EISR_EL2,
+    (3, 4, 12, 11, 5): ICH_ELRSR_EL2,
+    (3, 4, 12, 11, 7): ICH_VMCR_EL2,
+
+    (3, 4, 12, 12, 0): ICH_LR0_EL2,
+    (3, 4, 12, 12, 1): ICH_LR1_EL2,
+    (3, 4, 12, 12, 2): ICH_LR2_EL2,
+    (3, 4, 12, 12, 3): ICH_LR3_EL2,
+    (3, 4, 12, 12, 4): ICH_LR4_EL2,
+    (3, 4, 12, 12, 5): ICH_LR5_EL2,
+    (3, 4, 12, 12, 6): ICH_LR6_EL2,
+    (3, 4, 12, 12, 7): ICH_LR7_EL2,
+
+    (3, 4, 12, 13, 0): ICH_LR8_EL2,
+    (3, 4, 12, 13, 1): ICH_LR9_EL2,
+    (3, 4, 12, 13, 2): ICH_LR10_EL2,
+    (3, 4, 12, 13, 3): ICH_LR11_EL2,
+    (3, 4, 12, 13, 4): ICH_LR12_EL2,
+    (3, 4, 12, 13, 5): ICH_LR13_EL2,
+    (3, 4, 12, 13, 6): ICH_LR14_EL2,
+    (3, 4, 12, 13, 7): ICH_LR15_EL2,
+
+    (3, 4, 13, 0, 1): CONTEXTIDR_EL2,
+    (3, 4, 13, 0, 2): TPIDR_EL2,
+
+    (3, 4, 13, 8, 0): AMEVCNTVOFF00_EL2,
+    (3, 4, 13, 8, 1): AMEVCNTVOFF01_EL2,
+    (3, 4, 13, 8, 2): AMEVCNTVOFF02_EL2,
+    (3, 4, 13, 8, 3): AMEVCNTVOFF03_EL2,
+    (3, 4, 13, 8, 4): AMEVCNTVOFF04_EL2,
+    (3, 4, 13, 8, 5): AMEVCNTVOFF05_EL2,
+    (3, 4, 13, 8, 6): AMEVCNTVOFF06_EL2,
+    (3, 4, 13, 8, 7): AMEVCNTVOFF07_EL2,
+
+    (3, 4, 13, 9, 0): AMEVCNTVOFF08_EL2,
+    (3, 4, 13, 9, 1): AMEVCNTVOFF09_EL2,
+    (3, 4, 13, 9, 2): AMEVCNTVOFF010_EL2,
+    (3, 4, 13, 9, 3): AMEVCNTVOFF011_EL2,
+    (3, 4, 13, 9, 4): AMEVCNTVOFF012_EL2,
+    (3, 4, 13, 9, 5): AMEVCNTVOFF013_EL2,
+    (3, 4, 13, 9, 6): AMEVCNTVOFF014_EL2,
+    (3, 4, 13, 9, 7): AMEVCNTVOFF015_EL2,
+
+    (3, 4, 13, 10, 0): AMEVCNTVOFF10_EL2,
+    (3, 4, 13, 10, 1): AMEVCNTVOFF11_EL2,
+    (3, 4, 13, 10, 2): AMEVCNTVOFF12_EL2,
+    (3, 4, 13, 10, 3): AMEVCNTVOFF13_EL2,
+    (3, 4, 13, 10, 4): AMEVCNTVOFF14_EL2,
+    (3, 4, 13, 10, 5): AMEVCNTVOFF15_EL2,
+    (3, 4, 13, 10, 6): AMEVCNTVOFF16_EL2,
+    (3, 4, 13, 10, 7): AMEVCNTVOFF17_EL2,
+
+    (3, 4, 13, 11, 0): AMEVCNTVOFF18_EL2,
+    (3, 4, 13, 11, 1): AMEVCNTVOFF19_EL2,
+    (3, 4, 13, 11, 2): AMEVCNTVOFF110_EL2,
+    (3, 4, 13, 11, 3): AMEVCNTVOFF111_EL2,
+    (3, 4, 13, 11, 4): AMEVCNTVOFF112_EL2,
+    (3, 4, 13, 11, 5): AMEVCNTVOFF113_EL2,
+    (3, 4, 13, 11, 6): AMEVCNTVOFF114_EL2,
+    (3, 4, 13, 11, 7): AMEVCNTVOFF115_EL2,
+
+    (3, 4, 14, 0, 3): CNTVOFF_EL2,
+    (3, 4, 14, 0, 6): CNTPOFF_EL2,
+
+    (3, 4, 14, 1, 0): CNTHCTL_EL2,
+
+    (3, 4, 14, 2, 0): CNTHP_TVAL_EL2,
+    (3, 4, 14, 2, 1): CNTHP_CTL_EL2,
+    (3, 4, 14, 2, 2): CNTHP_CVAL_EL2,
+
+    (3, 4, 14, 3, 0): CNTHV_TVAL_EL2,
+    (3, 4, 14, 3, 1): CNTHV_CTL_EL2,
+    (3, 4, 14, 3, 2): CNTHV_CVAL_EL2,
+
+    (3, 4, 14, 4, 0): CNTHVS_TVAL_EL2,
+    (3, 4, 14, 4, 1): CNTHVS_CTL_EL2,
+    (3, 4, 14, 4, 2): CNTHVS_CVAL_EL2,
+
+    (3, 4, 14, 5, 0): CNTHPS_TVAL_EL2,
+    (3, 4, 14, 5, 1): CNTHPS_CTL_EL2,
+    (3, 4, 14, 5, 2): CNTHPS_CVAL_EL2,
+
+    # Aliases for *_EL02 *_EL12
+    # see page 2864 of "Arm Architecture Reference Manual Armv8,
+    # for Armv8-A architecture profile" Release 31 March 2020
+    (3, 5, 1, 0, 0): SCTLR_EL1,
+    (3, 5, 1, 0, 2): CPACR_EL1,
+
+    (3, 5, 1, 2, 0): ZCR_EL1,
+    (3, 5, 1, 2, 1): TRFCR_EL1,
+
+    (3, 5, 2, 0, 0): TTBR0_EL1,
+    (3, 5, 2, 0, 1): TTBR1_EL1,
+    (3, 5, 2, 0, 2): TCR_EL1,
+
+    (3, 5, 4, 0, 0): SPSR_EL1,
+    (3, 5, 4, 0, 1): ELR_EL1,
+
+    (3, 5, 5, 1, 0): AFSR0_EL1,
+    (3, 5, 5, 1, 1): AFSR1_EL1,
+
+    (3, 5, 5, 2, 0): ESR_EL1,
+
+    (3, 5, 6, 0, 0): FAR_EL1,
+
+    (3, 5, 9, 9, 0): PMSCR_EL1,
+
+    (3, 5, 10, 2, 0): MAIR_EL1,
+
+    (3, 5, 10, 3, 0): AMAIR_EL1,
+
+    (3, 5, 12, 0, 0): VBAR_EL1,
+
+    (3, 5, 13, 0, 0): CONTEXTIDR_EL1,
+
+    (3, 5, 14, 1, 0): CNTKCTL_EL1,
+
+    (3, 5, 14, 2, 0): CNTP_TVAL_EL0,
+    (3, 5, 14, 2, 1): CNTP_CTL_EL0,
+    (3, 5, 14, 2, 2): CNTP_CVAL_EL0,
+
+    (3, 5, 14, 3, 0): CNTV_TVAL_EL0,
+    (3, 5, 14, 3, 1): CNTV_CTL_EL0,
+    (3, 5, 14, 3, 2): CNTV_CVAL_EL0,
+    # End of aliases
+
+    (3, 6, 1, 0, 0): SCTLR_EL3,
+    (3, 6, 1, 0, 1): ACTLR_EL3,
+
+    (3, 6, 1, 1, 0): SCR_EL3,
+    (3, 6, 1, 1, 1): SDER32_EL3,
+    (3, 6, 1, 1, 2): CPTR_EL3,
+
+    (3, 6, 1, 2, 0): ZCR_EL3,
+
+    (3, 6, 1, 3, 1): MDCR_EL3,
+
+    (3, 6, 2, 0, 0): TTBR0_EL3,
+    (3, 6, 2, 0, 2): TCR_EL3,
+
+    (3, 6, 4, 0, 0): SPSR_EL3,
+    (3, 6, 4, 0, 1): ELR_EL3,
+
+    (3, 6, 4, 1, 0): SP_EL2,
+
+    (3, 6, 5, 1, 0): AFSR0_EL3,
+    (3, 6, 5, 1, 1): AFSR1_EL3,
+
+    (3, 6, 5, 2, 0): ESR_EL3,
+
+    (3, 6, 6, 0, 0): FAR_EL3,
+
+    (3, 6, 10, 2, 0): MAIR_EL3,
+
+    (3, 6, 10, 3, 0): AMAIR_EL3,
+
+    (3, 6, 12, 0, 0): VBAR_EL3,
+    (3, 6, 12, 0, 1): RVBAR_EL3,
+    (3, 6, 12, 0, 2): RMR_EL3,
+
+    (3, 6, 12, 12, 4): ICC_CTLR_EL3,
+    (3, 6, 12, 12, 5): ICC_SRE_EL3,
+    (3, 6, 12, 12, 7): ICC_IGRPEN1_EL3,
+
+    (3, 6, 13, 0, 2): TPIDR_EL3,
+
+    (3, 7, 14, 2, 0): CNTPS_TVAL_EL1,
+    (3, 7, 14, 2, 1): CNTPS_CTL_EL1,
+    (3, 7, 14, 2, 2): CNTPS_CVAL_EL1,
+}
+
+# CPSR: N Z C V
+
+
+def update_flag_zf(a):
+    return [ExprAssign(zf, ExprOp("FLAG_EQ", a))]
+
+
+def update_flag_zf_eq(a, b):
+    return [ExprAssign(zf, ExprOp("FLAG_EQ_CMP", a, b))]
+
+
+def update_flag_nf(arg):
+    return [
+        ExprAssign(
+            nf,
+            ExprOp("FLAG_SIGN_SUB", arg, ExprInt(0, arg.size))
+        )
+    ]
+
+
+def update_flag_zn(a):
+    e = []
+    e += update_flag_zf(a)
+    e += update_flag_nf(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 update_flag_add_cf(op1, op2):
+    "Compute cf in @op1 + @op2"
+    return [ExprAssign(cf, ExprOp("FLAG_ADD_CF", op1, op2))]
+
+
+def update_flag_add_of(op1, op2):
+    "Compute of in @op1 + @op2"
+    return [ExprAssign(of, ExprOp("FLAG_ADD_OF", op1, op2))]
+
+
+def update_flag_sub_cf(op1, op2):
+    "Compote CF in @op1 - @op2"
+    return [ExprAssign(cf, ExprOp("FLAG_SUB_CF", op1, op2) ^ ExprInt(1, 1))]
+
+
+def update_flag_sub_of(op1, op2):
+    "Compote OF in @op1 - @op2"
+    return [ExprAssign(of, ExprOp("FLAG_SUB_OF", op1, op2))]
+
+
+def update_flag_arith_add_co(arg1, arg2):
+    e = []
+    e += update_flag_add_cf(arg1, arg2)
+    e += update_flag_add_of(arg1, arg2)
+    return e
+
+
+def update_flag_arith_add_zn(arg1, arg2):
+    """
+    Compute zf and nf flags for (arg1 + arg2)
+    """
+    e = []
+    e += update_flag_zf_eq(arg1, -arg2)
+    e += [ExprAssign(nf, ExprOp("FLAG_SIGN_SUB", arg1, -arg2))]
+    return e
+
+
+def update_flag_arith_sub_co(arg1, arg2):
+    """
+    Compute cf and of flags for (arg1 - arg2)
+    """
+    e = []
+    e += update_flag_sub_cf(arg1, arg2)
+    e += update_flag_sub_of(arg1, arg2)
+    return e
+
+
+def update_flag_arith_sub_zn(arg1, arg2):
+    """
+    Compute zf and nf flags for (arg1 - arg2)
+    """
+    e = []
+    e += update_flag_zf_eq(arg1, arg2)
+    e += [ExprAssign(nf, ExprOp("FLAG_SIGN_SUB", arg1, arg2))]
+    return e
+
+
+
+
+def update_flag_zfaddwc_eq(arg1, arg2, arg3):
+    return [ExprAssign(zf, ExprOp("FLAG_EQ_ADDWC", arg1, arg2, arg3))]
+
+def update_flag_zfsubwc_eq(arg1, arg2, arg3):
+    return [ExprAssign(zf, ExprOp("FLAG_EQ_SUBWC", arg1, arg2, arg3))]
+
+
+def update_flag_arith_addwc_zn(arg1, arg2, arg3):
+    """
+    Compute znp flags for (arg1 + arg2 + cf)
+    """
+    e = []
+    e += update_flag_zfaddwc_eq(arg1, arg2, arg3)
+    e += [ExprAssign(nf, ExprOp("FLAG_SIGN_ADDWC", arg1, arg2, arg3))]
+    return e
+
+
+def update_flag_arith_subwc_zn(arg1, arg2, arg3):
+    """
+    Compute znp flags for (arg1 - (arg2 + cf))
+    """
+    e = []
+    e += update_flag_zfsubwc_eq(arg1, arg2, arg3)
+    e += [ExprAssign(nf, ExprOp("FLAG_SIGN_SUBWC", arg1, arg2, arg3))]
+    return e
+
+
+def update_flag_addwc_cf(op1, op2, op3):
+    "Compute cf in @res = @op1 + @op2 + @op3"
+    return [ExprAssign(cf, ExprOp("FLAG_ADDWC_CF", op1, op2, op3))]
+
+
+def update_flag_addwc_of(op1, op2, op3):
+    "Compute of in @res = @op1 + @op2 + @op3"
+    return [ExprAssign(of, ExprOp("FLAG_ADDWC_OF", op1, op2, op3))]
+
+
+def update_flag_arith_addwc_co(arg1, arg2, arg3):
+    e = []
+    e += update_flag_addwc_cf(arg1, arg2, arg3)
+    e += update_flag_addwc_of(arg1, arg2, arg3)
+    return e
+
+
+
+def update_flag_subwc_cf(op1, op2, op3):
+    "Compute cf in @res = @op1 + @op2 + @op3"
+    return [ExprAssign(cf, ExprOp("FLAG_SUBWC_CF", op1, op2, op3) ^ ExprInt(1, 1))]
+
+
+def update_flag_subwc_of(op1, op2, op3):
+    "Compute of in @res = @op1 + @op2 + @op3"
+    return [ExprAssign(of, ExprOp("FLAG_SUBWC_OF", op1, op2, op3))]
+
+
+def update_flag_arith_subwc_co(arg1, arg2, arg3):
+    e = []
+    e += update_flag_subwc_cf(arg1, arg2, arg3)
+    e += update_flag_subwc_of(arg1, arg2, arg3)
+    return e
+
+
+cond2expr = {'EQ': ExprOp("CC_EQ", zf),
+             'NE': ExprOp("CC_NE", zf),
+             'CS': ExprOp("CC_U>=", cf ^ ExprInt(1, 1)), # inv cf
+             'CC': ExprOp("CC_U<", cf ^ ExprInt(1, 1)), # inv cf
+             'MI': ExprOp("CC_NEG", nf),
+             'PL': ExprOp("CC_POS", nf),
+             'VS': ExprOp("CC_sOVR", of),
+             'VC': ExprOp("CC_sNOOVR", of),
+             'HI': ExprOp("CC_U>", cf ^ ExprInt(1, 1), zf), # inv cf
+             'LS': ExprOp("CC_U<=", cf ^ ExprInt(1, 1), zf), # inv cf
+             'GE': ExprOp("CC_S>=", nf, of),
+             'LT': ExprOp("CC_S<", nf, of),
+             'GT': ExprOp("CC_S>", nf, of, zf),
+             'LE': ExprOp("CC_S<=", nf, of, zf),
+             'AL': ExprInt(1, 1),
+             'NV': ExprInt(0, 1)
+             }
+
+
+def extend_arg(dst, arg):
+    if not isinstance(arg, ExprOp):
+        return arg
+
+    op, (reg, shift) = arg.op, arg.args
+    if op == "SXTB":
+        base = reg[:8].signExtend(dst.size)
+        op = "<<"
+    elif op == "SXTH":
+        base = reg[:16].signExtend(dst.size)
+        op = "<<"
+    elif op == 'SXTW':
+        base = reg[:32].signExtend(dst.size)
+        op = "<<"
+    elif op == "SXTX":
+        base = reg.signExtend(dst.size)
+        op = "<<"
+
+    elif op == "UXTB":
+        base = reg[:8].zeroExtend(dst.size)
+        op = "<<"
+    elif op == "UXTH":
+        base = reg[:16].zeroExtend(dst.size)
+        op = "<<"
+    elif op == 'UXTW':
+        base = reg[:32].zeroExtend(dst.size)
+        op = "<<"
+    elif op == "UXTX":
+        base = reg.zeroExtend(dst.size)
+        op = "<<"
+
+    elif op in ['<<', '>>', '<<a', 'a>>', '<<<', '>>>']:
+        base = reg.zeroExtend(dst.size)
+    else:
+        raise NotImplementedError('Unknown shifter operator')
+
+    out = ExprOp(op, base, (shift.zeroExtend(dst.size)
+                            & ExprInt(dst.size - 1, dst.size)))
+    return out
+
+
+# SemBuilder context
+ctx = {"PC": PC,
+       "LR": LR,
+       "nf": nf,
+       "zf": zf,
+       "cf": cf,
+       "of": of,
+       "cond2expr": cond2expr,
+       "extend_arg": extend_arg,
+       "ExprId":ExprId,
+       "exception_flags": exception_flags,
+       "interrupt_num": interrupt_num,
+       "EXCEPT_DIV_BY_ZERO": EXCEPT_DIV_BY_ZERO,
+       "EXCEPT_INT_XX": EXCEPT_INT_XX,
+       }
+
+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))
+
+
+def bics(ir, instr, arg1, arg2, arg3):
+    e = []
+    tmp1, tmp2 = arg2, (~extend_arg(arg2, arg3))
+    res = tmp1 & tmp2
+
+    e += [ExprAssign(zf, ExprOp('FLAG_EQ_AND', tmp1, tmp2))]
+    e += update_flag_nf(res)
+
+    e.append(ExprAssign(arg1, res))
+    return e, []
+
+
+@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_add_zn(arg2, arg3)
+    e += update_flag_arith_add_co(arg2, arg3)
+
+    e.append(ExprAssign(arg1, res))
+
+    return e, []
+
+
+def subs(ir, instr, arg1, arg2, arg3):
+    e = []
+    arg3 = extend_arg(arg2, arg3)
+    res = arg2 - arg3
+
+
+    e += update_flag_arith_sub_zn(arg2, arg3)
+    e += update_flag_arith_sub_co(arg2, arg3)
+
+    e.append(ExprAssign(arg1, res))
+    return e, []
+
+
+def cmp(ir, instr, arg1, arg2):
+    e = []
+    arg2 = extend_arg(arg1, arg2)
+
+    e += update_flag_arith_sub_zn(arg1, arg2)
+    e += update_flag_arith_sub_co(arg1, arg2)
+
+    return e, []
+
+
+def cmn(ir, instr, arg1, arg2):
+    e = []
+    arg2 = extend_arg(arg1, arg2)
+
+    e += update_flag_arith_add_zn(arg1, arg2)
+    e += update_flag_arith_add_co(arg1, arg2)
+
+    return e, []
+
+
+def ands(ir, instr, arg1, arg2, arg3):
+    e = []
+    arg3 = extend_arg(arg2, arg3)
+    res = arg2 & arg3
+
+    e += [ExprAssign(zf, ExprOp('FLAG_EQ_AND', arg2, arg3))]
+    e += update_flag_nf(res)
+
+    e.append(ExprAssign(arg1, res))
+    return e, []
+
+def tst(ir, instr, arg1, arg2):
+    e = []
+    arg2 = extend_arg(arg1, arg2)
+    res = arg1 & arg2
+
+    e += [ExprAssign(zf, ExprOp('FLAG_EQ_AND', arg1, arg2))]
+    e += update_flag_nf(res)
+
+    return e, []
+
+
+@sbuild.parse
+def lsl(arg1, arg2, arg3):
+    arg1 = arg2 << (arg3 & ExprInt(arg3.size - 1, arg3.size))
+
+
+@sbuild.parse
+def lsr(arg1, arg2, arg3):
+    arg1 = arg2 >> (arg3 & ExprInt(arg3.size - 1, arg3.size))
+
+
+@sbuild.parse
+def asr(arg1, arg2, arg3):
+    arg1 = ExprOp(
+        'a>>', arg2, (arg3 & ExprInt(arg3.size - 1, arg3.size)))
+
+
+@sbuild.parse
+def mov(arg1, arg2):
+    arg1 = arg2
+
+
+def movk(ir, instr, arg1, arg2):
+    e = []
+    if isinstance(arg2, ExprOp):
+        assert(arg2.op == 'slice_at' and
+               isinstance(arg2.args[0], ExprInt) and
+               isinstance(arg2.args[1], ExprInt))
+        value, shift = int(arg2.args[0]), int(arg2.args[1])
+        e.append(
+            ExprAssign(arg1[shift:shift + 16], ExprInt(value, 16)))
+    else:
+        e.append(ExprAssign(arg1[:16], ExprInt(int(arg2), 16)))
+
+    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 = ExprInt(instr.offset + instr.l, 64)
+
+@sbuild.parse
+def csel(arg1, arg2, arg3, arg4):
+    cond_expr = cond2expr[arg4.name]
+    arg1 = arg2 if cond_expr else arg3
+
+def ccmp(ir, instr, arg1, arg2, arg3, arg4):
+    e = []
+    if(arg2.is_int()):
+        arg2=ExprInt(int(arg2),arg1.size)
+    default_nf = arg3[0:1]
+    default_zf = arg3[1:2]
+    default_cf = arg3[2:3]
+    default_of = arg3[3:4]
+    cond_expr = cond2expr[arg4.name]
+    res = arg1 - arg2
+    new_nf = nf
+    new_zf = update_flag_zf(res)[0].src
+    new_cf = update_flag_sub_cf(arg1, arg2)[0].src
+    new_of = update_flag_sub_of(arg1, arg2)[0].src
+
+    e.append(ExprAssign(nf, ExprCond(cond_expr,
+                                                    new_nf,
+                                                    default_nf)))
+    e.append(ExprAssign(zf, ExprCond(cond_expr,
+                                                    new_zf,
+                                                    default_zf)))
+    e.append(ExprAssign(cf, ExprCond(cond_expr,
+                                                    new_cf,
+                                                    default_cf)))
+    e.append(ExprAssign(of, ExprCond(cond_expr,
+                                                    new_of,
+                                                    default_of)))
+    return e, []
+
+
+def csinc(ir, instr, arg1, arg2, arg3, arg4):
+    e = []
+    cond_expr = cond2expr[arg4.name]
+    e.append(
+        ExprAssign(
+            arg1,
+            ExprCond(
+                cond_expr,
+                arg2,
+                arg3 + ExprInt(1, arg3.size)
+            )
+        )
+    )
+    return e, []
+
+
+def csinv(ir, instr, arg1, arg2, arg3, arg4):
+    e = []
+    cond_expr = cond2expr[arg4.name]
+    e.append(
+        ExprAssign(
+            arg1,
+            ExprCond(
+                cond_expr,
+                arg2,
+                ~arg3)
+        )
+    )
+    return e, []
+
+
+def csneg(ir, instr, arg1, arg2, arg3, arg4):
+    e = []
+    cond_expr = cond2expr[arg4.name]
+    e.append(
+        ExprAssign(
+            arg1,
+            ExprCond(
+                cond_expr,
+                arg2,
+                -arg3)
+        )
+    )
+    return e, []
+
+
+def cset(ir, instr, arg1, arg2):
+    e = []
+    cond_expr = cond2expr[arg2.name]
+    e.append(
+        ExprAssign(
+            arg1,
+            ExprCond(
+                cond_expr,
+                ExprInt(1, arg1.size),
+                ExprInt(0, arg1.size)
+            )
+        )
+    )
+    return e, []
+
+
+def csetm(ir, instr, arg1, arg2):
+    e = []
+    cond_expr = cond2expr[arg2.name]
+    e.append(
+        ExprAssign(
+            arg1,
+            ExprCond(
+                cond_expr,
+                ExprInt(-1, arg1.size),
+                ExprInt(0, arg1.size)
+            )
+        )
+    )
+    return e, []
+
+
+def get_mem_access(mem):
+    updt = None
+    if isinstance(mem, ExprOp):
+        if mem.op == 'preinc':
+            if len(mem.args) == 1:
+                addr = mem.args[0]
+            else:
+                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, ExprInt) and int(shift) == 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 = ExprAssign(addr, addr + off)
+        elif mem.op == "preinc_wb":
+            base, off = mem.args
+            addr = base + off
+            updt = ExprAssign(base, base + off)
+        else:
+            raise NotImplementedError('bad op')
+    else:
+        raise NotImplementedError('bad op')
+    return addr, updt
+
+
+
+def ldr(ir, instr, arg1, arg2):
+    e = []
+    addr, updt = get_mem_access(arg2)
+    e.append(ExprAssign(arg1, ExprMem(addr, arg1.size)))
+    if updt:
+        e.append(updt)
+    return e, []
+
+
+def ldr_size(ir, instr, arg1, arg2, size):
+    e = []
+    addr, updt = get_mem_access(arg2)
+    e.append(
+        ExprAssign(arg1, ExprMem(addr, size).zeroExtend(arg1.size)))
+    if updt:
+        e.append(updt)
+    return e, []
+
+
+def ldrb(ir, instr, arg1, arg2):
+    return ldr_size(ir, instr, arg1, arg2, 8)
+
+
+def ldrh(ir, instr, arg1, arg2):
+    return ldr_size(ir, instr, arg1, arg2, 16)
+
+
+def ldrs_size(ir, instr, arg1, arg2, size):
+    e = []
+    addr, updt = get_mem_access(arg2)
+    e.append(
+        ExprAssign(arg1, ExprMem(addr, size).signExtend(arg1.size)))
+    if updt:
+        e.append(updt)
+    return e, []
+
+
+def ldrsb(ir, instr, arg1, arg2):
+    return ldrs_size(ir, instr, arg1, arg2, 8)
+
+
+def ldrsh(ir, instr, arg1, arg2):
+    return ldrs_size(ir, instr, arg1, arg2, 16)
+
+
+def ldrsw(ir, instr, arg1, arg2):
+    return ldrs_size(ir, instr, arg1, arg2, 32)
+
+def ldaxrb(ir, instr, arg1, arg2):
+    # TODO XXX no memory lock implemented
+    assert arg2.is_op('preinc')
+    assert len(arg2.args) == 1
+    ptr = arg2.args[0]
+    e = []
+    e.append(ExprAssign(arg1, ExprMem(ptr, 8).zeroExtend(arg1.size)))
+    return e, []
+
+def ldxr(ir, instr, arg1, arg2):
+    # TODO XXX no memory lock implemented
+    assert arg2.is_op('preinc')
+    assert len(arg2.args) == 1
+    ptr = arg2.args[0]
+    e = []
+    e.append(ExprAssign(arg1, ExprMem(ptr, arg1.size).zeroExtend(arg1.size)))
+    return e, []
+
+def stlxr(ir, instr, arg1, arg2, arg3):
+    assert arg3.is_op('preinc')
+    assert len(arg3.args) == 1
+    ptr = arg3.args[0]
+    e = []
+    e.append(ExprAssign(ExprMem(ptr, arg2.size), arg2))
+    # TODO XXX here, force update success
+    e.append(ExprAssign(arg1, ExprInt(0, arg1.size)))
+    return e, []
+
+def stlxrb(ir, instr, arg1, arg2, arg3):
+    assert arg3.is_op('preinc')
+    assert len(arg3.args) == 1
+    ptr = arg3.args[0]
+    e = []
+    e.append(ExprAssign(ExprMem(ptr, 8), arg2[:8]))
+    # TODO XXX here, force update success
+    e.append(ExprAssign(arg1, ExprInt(0, arg1.size)))
+    return e, []
+
+def stlrb(ir, instr, arg1, arg2):
+    ptr = arg2.args[0]
+    e = []
+    e.append(ExprAssign(ExprMem(ptr, 8), arg1[:8]))
+    return e, []
+
+def l_str(ir, instr, arg1, arg2):
+    e = []
+    addr, updt = get_mem_access(arg2)
+    e.append(ExprAssign(ExprMem(addr, arg1.size), arg1))
+    if updt:
+        e.append(updt)
+    return e, []
+
+
+def strb(ir, instr, arg1, arg2):
+    e = []
+    addr, updt = get_mem_access(arg2)
+    e.append(ExprAssign(ExprMem(addr, 8), arg1[:8]))
+    if updt:
+        e.append(updt)
+    return e, []
+
+
+def strh(ir, instr, arg1, arg2):
+    e = []
+    addr, updt = get_mem_access(arg2)
+    e.append(ExprAssign(ExprMem(addr, 16), arg1[:16]))
+    if updt:
+        e.append(updt)
+    return e, []
+
+
+def stp(ir, instr, arg1, arg2, arg3):
+    e = []
+    addr, updt = get_mem_access(arg3)
+    e.append(ExprAssign(ExprMem(addr, arg1.size), arg1))
+    e.append(
+        ExprAssign(ExprMem(addr + ExprInt(arg1.size // 8, addr.size), 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(ExprAssign(arg1, ExprMem(addr, arg1.size)))
+    e.append(
+        ExprAssign(arg2, ExprMem(addr + ExprInt(arg1.size // 8, addr.size), arg2.size)))
+    if updt:
+        e.append(updt)
+    return e, []
+
+
+def sbfm(ir, instr, arg1, arg2, arg3, arg4):
+    e = []
+    rim, sim = int(arg3), int(arg4) + 1
+    if sim > rim:
+        res = arg2[rim:sim].signExtend(arg1.size)
+    else:
+        shift = ExprInt(arg2.size - rim, arg2.size)
+        res = (arg2[:sim].signExtend(arg1.size) << shift)
+    e.append(ExprAssign(arg1, res))
+    return e, []
+
+
+def ubfm(ir, instr, arg1, arg2, arg3, arg4):
+    e = []
+    rim, sim = int(arg3), int(arg4) + 1
+    if sim != arg1.size - 1 and rim == sim:
+        # Simple case: lsl
+        value = int(rim)
+        assert value < arg1.size
+        e.append(ExprAssign(arg1, arg2 << (ExprInt(arg1.size - value, arg2.size))))
+        return e, []
+    if sim == arg1.size:
+        # Simple case: lsr
+        value = int(rim)
+        assert value < arg1.size
+        e.append(ExprAssign(arg1, arg2 >> (ExprInt(value, arg2.size))))
+        return e, []
+
+    if sim > rim:
+        res = arg2[rim:sim].zeroExtend(arg1.size)
+    else:
+        shift = ExprInt(arg2.size - rim, arg2.size)
+        res = (arg2[:sim].zeroExtend(arg1.size) << shift)
+    e.append(ExprAssign(arg1, res))
+    return e, []
+
+def bfm(ir, instr, arg1, arg2, arg3, arg4):
+    e = []
+    rim, sim = int(arg3), int(arg4) + 1
+    if sim > rim:
+        res = arg2[rim:sim]
+        e.append(ExprAssign(arg1[:sim-rim], res))
+    else:
+        shift_i = arg2.size - rim
+        shift = ExprInt(shift_i, arg2.size)
+        res = arg2[:sim]
+        e.append(ExprAssign(arg1[shift_i:shift_i+sim], res))
+    return e, []
+
+
+
+def mrs(ir, insr, arg1, arg2, arg3, arg4, arg5, arg6):
+    e = []
+    if arg2.is_int(3) and arg3.is_int(3) and arg4.is_id("c4") and arg5.is_id("c2") and arg6.is_int(0):
+        out = []
+        out.append(ExprInt(0x0, 28))
+        out.append(of)
+        out.append(cf)
+        out.append(zf)
+        out.append(nf)
+        e.append(ExprAssign(arg1, ExprCompose(*out).zeroExtend(arg1.size)))
+
+    elif arg1.is_int(3) and arg2.is_int(3) and arg3.is_id("c4") and arg4.is_id("c2") and arg5.is_int(7):
+        out = []
+        out.append(ExprInt(0x0, 38))
+        out.append(tco)
+        e.append(ExprAssign(arg1, ExprCompose(*out).zeroExtend(arg1.size)))
+
+    elif arg1.is_int(3) and arg2.is_int(3) and arg3.is_id("c4") and arg4.is_id("c2") and arg5.is_int(0):
+        out = []
+        out.append(ExprInt(0x0, 39))
+        out.append(dit)
+        e.append(ExprAssign(arg1, ExprCompose(*out).zeroExtend(arg1.size)))
+
+    elif arg1.is_int(3) and arg2.is_int(0) and arg3.is_id("c4") and arg4.is_id("c2") and arg5.is_int(4):
+        out = []
+        out.append(ExprInt(0x0, 40))
+        out.append(uao)
+        e.append(ExprAssign(arg1, ExprCompose(*out).zeroExtend(arg1.size)))
+
+    elif arg1.is_int(3) and arg2.is_int(0) and arg3.is_id("c4") and arg4.is_id("c2") and arg5.is_int(3):
+        out = []
+        out.append(ExprInt(0x0, 41))
+        out.append(pan)
+        e.append(ExprAssign(arg1, ExprCompose(*out).zeroExtend(arg1.size)))
+
+    elif arg1.is_int(3) and arg2.is_int(3) and arg3.is_id("c4") and arg4.is_id("c2") and arg5.is_int(6):
+        out = []
+        out.append(ExprInt(0x0, 51))
+        out.append(ssbs)
+        e.append(ExprAssign(arg1, ExprCompose(*out).zeroExtend(arg1.size)))
+
+    elif arg1.is_int(3) and arg2.is_int(3) and arg3.is_id("c4") and arg4.is_id("c2") and arg5.is_int(1):
+        out = []
+        out.append(ExprInt(0x0, 54))
+        out.append(df)
+        out.append(af)
+        out.append(iff)
+        out.append(ff)
+        e.append(ExprAssign(arg1, ExprCompose(*out).zeroExtend(arg1.size)))
+
+    elif arg1.is_int(3) and arg2.is_int(0) and arg3.is_id("c4") and arg4.is_id("c2") and arg5.is_int(2):
+        out = []
+        out.append(ExprInt(0x0, 60))
+        out.append(cur_el)
+        e.append(ExprAssign(arg1, ExprCompose(*out).zeroExtend(arg1.size)))
+
+    elif arg1.is_int(3) and arg2.is_int(0) and arg3.is_id("c4") and arg4.is_id("c2") and arg5.is_int(0):
+        out = []
+        out.append(ExprInt(0x0, 63))
+        out.append(spsel)
+        e.append(ExprAssign(arg1, ExprCompose(*out).zeroExtend(arg1.size)))
+
+    else:
+        sreg = (int(arg2), int(arg3), int(str(arg4)[1:]), int(str(arg5)[1:]), int(arg6))
+        if sreg in system_regs:
+            e.append(ExprAssign(arg1, system_regs[sreg]))
+        else:
+            raise NotImplementedError("Unknown system register: %d %d %s %s %d" % (int(arg2), int(arg3), str(arg4), str(arg5), int(arg6)))
+
+    return e, []
+
+def msr(ir, instr, arg1, arg2, arg3, arg4, arg5, arg6):
+
+    e = []
+    if arg1.is_int(3) and arg2.is_int(3) and arg3.is_id("c4") and arg4.is_id("c2") and arg5.is_int(0):
+        e.append(ExprAssign(nf, arg6[31:32]))
+        e.append(ExprAssign(zf, arg6[30:31]))
+        e.append(ExprAssign(cf, arg6[29:30]))
+        e.append(ExprAssign(of, arg6[28:29]))
+
+    elif arg1.is_int(3) and arg2.is_int(3) and arg3.is_id("c4") and arg4.is_id("c2") and arg5.is_int(7):
+        e.append(ExprAssign(tco, arg6[25:26]))
+
+    elif arg1.is_int(3) and arg2.is_int(3) and arg3.is_id("c4") and arg4.is_id("c2") and arg5.is_int(0):
+        e.append(ExprAssign(dit, arg6[24:25]))
+
+    elif arg1.is_int(3) and arg2.is_int(0) and arg3.is_id("c4") and arg4.is_id("c2") and arg5.is_int(4):
+        e.append(ExprAssign(uao, arg6[23:24]))
+
+    elif arg1.is_int(3) and arg2.is_int(0) and arg3.is_id("c4") and arg4.is_id("c2") and arg5.is_int(3):
+        e.append(ExprAssign(pan, arg6[22:23]))
+
+    elif arg1.is_int(3) and arg2.is_int(3) and arg3.is_id("c4") and arg4.is_id("c2") and arg5.is_int(6):
+        e.append(ExprAssign(ssbs, arg6[12:13]))
+
+    elif arg1.is_int(3) and arg2.is_int(3) and arg3.is_id("c4") and arg4.is_id("c2") and arg5.is_int(1):
+        e.append(ExprAssign(df, arg6[9:10]))
+        e.append(ExprAssign(af, arg6[8:9]))
+        e.append(ExprAssign(iff, arg6[7:8]))
+        e.append(ExprAssign(ff, arg6[6:7]))
+
+    elif arg1.is_int(3) and arg2.is_int(0) and arg3.is_id("c4") and arg4.is_id("c2") and arg5.is_int(2):
+        e.append(ExprAssign(cur_el, arg6[2:4]))
+
+    elif arg1.is_int(3) and arg2.is_int(0) and arg3.is_id("c4") and arg4.is_id("c2") and arg5.is_int(0):
+        e.append(ExprAssign(spsel, arg6[0:1]))
+
+    else:
+        sreg = (int(arg1), int(arg2), int(str(arg3)[1:]), int(str(arg4)[1:]), int(arg5))
+        if sreg in system_regs:
+            e.append(ExprAssign(system_regs[sreg], arg6))
+        else:
+            raise NotImplementedError("Unknown system register: %d %d %s %s %d" % (int(arg1), int(arg2), str(arg3), str(arg4), int(arg5)))
+
+    return e, []
+
+
+
+def adc(ir, instr, arg1, arg2, arg3):
+    arg3 = extend_arg(arg2, arg3)
+    e = []
+    r = arg2 + arg3 + cf.zeroExtend(arg3.size)
+    e.append(ExprAssign(arg1, r))
+    return e, []
+
+
+def adcs(ir, instr, arg1, arg2, arg3):
+    arg3 = extend_arg(arg2, arg3)
+    e = []
+    r = arg2 + arg3 + cf.zeroExtend(arg3.size)
+    e.append(ExprAssign(arg1, r))
+    e += update_flag_arith_addwc_zn(arg2, arg3, cf)
+    e += update_flag_arith_addwc_co(arg2, arg3, cf)
+    return e, []
+
+
+def sbc(ir, instr, arg1, arg2, arg3):
+    arg3 = extend_arg(arg2, arg3)
+    e = []
+    r = arg2 - (arg3 + (~cf).zeroExtend(arg3.size))
+    e.append(ExprAssign(arg1, r))
+    return e, []
+
+
+def sbcs(ir, instr, arg1, arg2, arg3):
+    arg3 = extend_arg(arg2, arg3)
+    e = []
+    r = arg2 - (arg3 + (~cf).zeroExtend(arg3.size))
+    e.append(ExprAssign(arg1, r))
+    e += update_flag_arith_subwc_zn(arg2, arg3, ~cf)
+    e += update_flag_arith_subwc_co(arg2, arg3, ~cf)
+    return e, []
+
+
+@sbuild.parse
+def madd(arg1, arg2, arg3, arg4):
+    arg1 = arg2 * arg3 + arg4
+
+
+@sbuild.parse
+def msub(arg1, arg2, arg3, arg4):
+    arg1 = arg4 - (arg2 * arg3)
+
+
+@sbuild.parse
+def udiv(arg1, arg2, arg3):
+    if arg3:
+        arg1 = ExprOp('udiv', arg2, arg3)
+    else:
+        exception_flags = ExprInt(EXCEPT_DIV_BY_ZERO,
+                                          exception_flags.size)
+
+@sbuild.parse
+def sdiv(arg1, arg2, arg3):
+    if arg3:
+        arg1 = ExprOp('sdiv', arg2, arg3)
+    else:
+        exception_flags = ExprInt(EXCEPT_DIV_BY_ZERO,
+                                          exception_flags.size)
+
+
+
+@sbuild.parse
+def smaddl(arg1, arg2, arg3, arg4):
+    arg1 = arg2.signExtend(arg1.size) * arg3.signExtend(arg1.size) + arg4
+
+
+@sbuild.parse
+def cbz(arg1, arg2):
+    dst = ExprLoc(ir.get_next_loc_key(instr), 64) if arg1 else arg2
+    PC = dst
+    ir.IRDst = dst
+
+
+@sbuild.parse
+def cbnz(arg1, arg2):
+    dst = arg2 if arg1 else ExprLoc(ir.get_next_loc_key(instr), 64)
+    PC = dst
+    ir.IRDst = dst
+
+
+@sbuild.parse
+def tbz(arg1, arg2, arg3):
+    bitmask = ExprInt(1, arg1.size) << arg2
+    dst = ExprLoc(
+        ir.get_next_loc_key(instr),
+        64
+    ) if arg1 & bitmask else arg3
+    PC = dst
+    ir.IRDst = dst
+
+
+@sbuild.parse
+def tbnz(arg1, arg2, arg3):
+    bitmask = ExprInt(1, arg1.size) << arg2
+    dst = arg3 if arg1 & bitmask else ExprLoc(
+        ir.get_next_loc_key(instr),
+        64
+    )
+    PC = dst
+    ir.IRDst = dst
+
+
+@sbuild.parse
+def b_ne(arg1):
+    cond = cond2expr['NE']
+    dst = arg1 if cond else ExprLoc(ir.get_next_loc_key(instr), 64)
+    PC = dst
+    ir.IRDst = dst
+
+
+@sbuild.parse
+def b_eq(arg1):
+    cond = cond2expr['EQ']
+    dst = arg1 if cond else ExprLoc(ir.get_next_loc_key(instr), 64)
+    PC = dst
+    ir.IRDst = dst
+
+
+@sbuild.parse
+def b_ge(arg1):
+    cond = cond2expr['GE']
+    dst = arg1 if cond else ExprLoc(ir.get_next_loc_key(instr), 64)
+    PC = dst
+    ir.IRDst = dst
+
+
+@sbuild.parse
+def b_mi(arg1):
+    cond = cond2expr['MI']
+    dst = arg1 if cond else ExprLoc(ir.get_next_loc_key(instr), 64)
+    PC = dst
+    ir.IRDst = dst
+
+
+@sbuild.parse
+def b_pl(arg1):
+    cond = cond2expr['PL']
+    dst = arg1 if cond else ExprLoc(ir.get_next_loc_key(instr), 64)
+    PC = dst
+    ir.IRDst = dst
+
+
+@sbuild.parse
+def b_gt(arg1):
+    cond = cond2expr['GT']
+    dst = arg1 if cond else ExprLoc(ir.get_next_loc_key(instr), 64)
+    PC = dst
+    ir.IRDst = dst
+
+
+@sbuild.parse
+def b_cc(arg1):
+    cond = cond2expr['CC']
+    dst = arg1 if cond else ExprLoc(ir.get_next_loc_key(instr), 64)
+    PC = dst
+    ir.IRDst = dst
+
+
+@sbuild.parse
+def b_cs(arg1):
+    cond = cond2expr['CS']
+    dst = arg1 if cond else ExprLoc(ir.get_next_loc_key(instr), 64)
+    PC = dst
+    ir.IRDst = dst
+
+
+@sbuild.parse
+def b_hi(arg1):
+    cond = cond2expr['HI']
+    dst = arg1 if cond else ExprLoc(ir.get_next_loc_key(instr), 64)
+    PC = dst
+    ir.IRDst = dst
+
+
+@sbuild.parse
+def b_le(arg1):
+    cond = cond2expr['LE']
+    dst = arg1 if cond else ExprLoc(ir.get_next_loc_key(instr), 64)
+    PC = dst
+    ir.IRDst = dst
+
+
+@sbuild.parse
+def b_ls(arg1):
+    cond = cond2expr['LS']
+    dst = arg1 if cond else ExprLoc(ir.get_next_loc_key(instr), 64)
+    PC = dst
+    ir.IRDst = dst
+
+
+@sbuild.parse
+def b_lt(arg1):
+    cond = cond2expr['LT']
+    dst = arg1 if cond else ExprLoc(ir.get_next_loc_key(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 & ExprInt(0xfffffffffffff000, 64)) + arg2
+
+
+@sbuild.parse
+def adr(arg1, arg2):
+    arg1 = PC + arg2
+
+
+@sbuild.parse
+def b(arg1):
+    PC = arg1
+    ir.IRDst = arg1
+
+
+@sbuild.parse
+def br(arg1):
+    PC = arg1
+    ir.IRDst = arg1
+
+@sbuild.parse
+def blr(arg1):
+    PC = arg1
+    ir.IRDst = arg1
+    LR = ExprLoc(ir.get_next_loc_key(instr), 64)
+
+@sbuild.parse
+def nop():
+    """Do nothing"""
+
+
+@sbuild.parse
+def dsb(arg1):
+    """Data Synchronization Barrier"""
+
+@sbuild.parse
+def isb(arg1):
+    """Instruction Synchronization Barrier"""
+
+@sbuild.parse
+def dmb(arg1):
+    """Data Memory Barrier"""
+
+@sbuild.parse
+def tlbi(arg1, arg2, arg3, arg4):
+    """TLB invalidate operation"""
+
+@sbuild.parse
+def clrex(arg1):
+    """Clear the local monitor of the executing PE"""
+
+@sbuild.parse
+def ic(arg1, arg2, arg3, arg4):
+    """Instruction/Data cache operation"""
+
+
+def rev(ir, instr, arg1, arg2):
+    out = []
+    for i in range(0, arg2.size, 8):
+        out.append(arg2[i:i+8])
+    out.reverse()
+    e = []
+    result = ExprCompose(*out)
+    e.append(ExprAssign(arg1, result))
+    return e, []
+
+
+def rev16(ir, instr, arg1, arg2):
+    out = []
+    for i in range(0, arg2.size // 8):
+        index = (i & ~1) + (1 - (i & 1))
+        out.append(arg2[index * 8:(index + 1) * 8])
+    e = []
+    result = ExprCompose(*out)
+    e.append(ExprAssign(arg1, result))
+    return e, []
+
+
+@sbuild.parse
+def extr(arg1, arg2, arg3, arg4):
+    compose = ExprCompose(arg2, arg3)
+    arg1 = compose[int(arg4):int(arg4)+arg1.size]
+
+
+@sbuild.parse
+def svc(arg1):
+    exception_flags = ExprInt(EXCEPT_INT_XX, exception_flags.size)
+    interrupt_num = ExprInt(int(arg1), interrupt_num.size)
+
+
+def fmov(ir, instr, arg1, arg2):
+    if arg2.is_int():
+        # Transform int to signed floating-point constant with 3-bit exponent
+        # and normalized 4 bits of precision
+        # VFPExpandImm() of ARM Architecture Reference Manual
+        imm8 = int(arg2)
+        N = arg1.size
+        assert N in [32, 64]
+        E = 8 if N == 32 else 11
+        F = N - E - 1;
+        # sign = imm8<7>;
+        sign = (imm8 >> 7) & 1;
+        # exp = NOT(imm8<6>):Replicate(imm8<6>,E-3):imm8<5:4>;
+        exp = (((imm8 >> 6) & 1) ^ 1) << (E - 3 + 2)
+        if (imm8 >> 6) & 1:
+            tmp = (1 << (E - 3)) - 1
+        else:
+            tmp = 0
+        exp |= tmp << 2
+        exp |= (imm8 >> 4) & 3
+        # frac = imm8<3:0>:Zeros(F-4);
+        frac = (imm8 & 0xf) << (F - 4)
+        value = frac
+        value |= exp << (4 + F - 4)
+        value |= sign << (4 + F - 4  + 1 + E - 3 + 2)
+        arg2 = ExprInt(value, N)
+    e = [ExprAssign(arg1, arg2)]
+    return e, []
+
+
+def fadd(ir, instr, arg1, arg2, arg3):
+    e = []
+    e.append(ExprAssign(arg1, ExprOp('fadd', arg2, arg3)))
+    return e, []
+
+
+def fsub(ir, instr, arg1, arg2, arg3):
+    e = []
+    e.append(ExprAssign(arg1, ExprOp('fsub', arg2, arg3)))
+    return e, []
+
+
+def fmul(ir, instr, arg1, arg2, arg3):
+    e = []
+    e.append(ExprAssign(arg1, ExprOp('fmul', arg2, arg3)))
+    return e, []
+
+
+def fdiv(ir, instr, arg1, arg2, arg3):
+    e = []
+    e.append(ExprAssign(arg1, ExprOp('fdiv', arg2, arg3)))
+    return e, []
+
+
+def fabs(ir, instr, arg1, arg2):
+    e = []
+    e.append(ExprAssign(arg1, ExprOp('fabs', arg2)))
+    return e, []
+
+
+def fmadd(ir, instr, arg1, arg2, arg3, arg4):
+    e = []
+    e.append(
+        ExprAssign(
+            arg1,
+            ExprOp(
+                'fadd',
+                arg4,
+                ExprOp('fmul', arg2, arg3)
+            )
+        )
+    )
+    return e, []
+
+
+def fmsub(ir, instr, arg1, arg2, arg3, arg4):
+    e = []
+    e.append(
+        ExprAssign(
+            arg1,
+            ExprOp(
+                'fsub',
+                arg4,
+                ExprOp('fmul', arg2, arg3)
+            )
+        )
+    )
+    return e, []
+
+
+def fcvt(ir, instr, arg1, arg2):
+    # XXX TODO: rounding
+    e = []
+    src = ExprOp('fpconvert_fp%d' % arg1.size, arg2)
+    e.append(ExprAssign(arg1, src))
+    return e, []
+
+
+def scvtf(ir, instr, arg1, arg2):
+    # XXX TODO: rounding
+    e = []
+    src = ExprOp('sint_to_fp', arg2)
+    if arg1.size != src.size:
+        src = ExprOp('fpconvert_fp%d' % arg1.size, src)
+    e.append(ExprAssign(arg1, src))
+    return e, []
+
+
+def ucvtf(ir, instr, arg1, arg2):
+    # XXX TODO: rounding
+    e = []
+    src = ExprOp('uint_to_fp', arg2)
+    if arg1.size != src.size:
+        src = ExprOp('fpconvert_fp%d' % arg1.size, src)
+    e.append(ExprAssign(arg1, src))
+    return e, []
+
+
+def fcvtzs(ir, instr, arg1, arg2):
+    # XXX TODO: rounding
+    e = []
+    e.append(
+        ExprAssign(
+            arg1,
+            ExprOp('fp_to_sint%d' % arg1.size,
+                   ExprOp('fpround_towardszero', arg2)
+            )
+        )
+    )
+    return e, []
+
+
+def fcvtzu(ir, instr, arg1, arg2):
+    # XXX TODO: rounding
+    e = []
+    e.append(
+        ExprAssign(
+            arg1,
+            ExprOp('fp_to_uint%d' % arg1.size,
+                   ExprOp('fpround_towardszero', arg2)
+            )
+        )
+    )
+    return e, []
+
+
+def fcmpe(ir, instr, arg1, arg2):
+    e = []
+    e.append(
+        ExprAssign(
+            nf,
+            ExprOp('fcom_c0', arg1, arg2)
+        )
+    )
+    e.append(
+        ExprAssign(
+            cf,
+            ~ExprOp('fcom_c0', arg1, arg2)
+        )
+    )
+    e.append(
+        ExprAssign(
+            zf,
+            ExprOp('fcom_c3', arg1, arg2)
+        )
+    )
+    e.append(ExprAssign(of, ExprInt(0, 1)))
+    return e, []
+
+
+def clz(ir, instr, arg1, arg2):
+    e = []
+    e.append(ExprAssign(arg1, ExprOp('cntleadzeros', arg2)))
+    return e, []
+
+def casp(ir, instr, arg1, arg2, arg3):
+    # XXX TODO: memory barrier
+    e = []
+    if arg1.size == 32:
+        regs = gpregs32_expr
+    else:
+        regs = gpregs64_expr
+    index1 = regs.index(arg1)
+    index2 = regs.index(arg2)
+
+    # TODO endianness
+    comp_value = ExprCompose(regs[index1], regs[index1 + 1])
+    new_value = ExprCompose(regs[index2], regs[index2 + 1])
+    assert arg3.is_op('preinc')
+    ptr = arg3.args[0]
+    data = ExprMem(ptr, comp_value.size)
+
+    loc_store = ExprLoc(ir.loc_db.add_location(), ir.IRDst.size)
+    loc_do = ExprLoc(ir.loc_db.add_location(), ir.IRDst.size)
+    loc_next = ExprLoc(ir.get_next_loc_key(instr), ir.IRDst.size)
+
+    e.append(ExprAssign(ir.IRDst, ExprCond(ExprOp("FLAG_EQ_CMP", data, comp_value), loc_do, loc_store)))
+
+    e_store = []
+    e_store.append(ExprAssign(data, new_value))
+    e_store.append(ExprAssign(ir.IRDst, loc_do))
+    blk_store = IRBlock(ir.loc_db, loc_store.loc_key, [AssignBlock(e_store, instr)])
+
+    e_do = []
+    e_do.append(ExprAssign(regs[index1], data[:data.size // 2]))
+    e_do.append(ExprAssign(regs[index1 + 1], data[data.size // 2:]))
+    e_do.append(ExprAssign(ir.IRDst, loc_next))
+    blk_do = IRBlock(ir.loc_db, loc_do.loc_key, [AssignBlock(e_do, instr)])
+
+    return e, [blk_store, blk_do]
+
+
+@sbuild.parse
+def umaddl(arg1, arg2, arg3, arg4):
+    arg1 = arg2.zeroExtend(arg1.size) * arg3.zeroExtend(arg1.size) + arg4
+
+
+@sbuild.parse
+def umsubbl(arg1, arg2, arg3, arg4):
+    arg1 = arg2.zeroExtend(arg1.size) * arg3.zeroExtend(arg1.size) + arg4
+
+
+@sbuild.parse
+def umull(arg1, arg2, arg3):
+    arg1 = (arg2.zeroExtend(64) * arg3.zeroExtend(64))
+
+
+@sbuild.parse
+def umulh(arg1, arg2, arg3):
+    arg1 = (arg2.zeroExtend(128) * arg3.zeroExtend(128))[64:]
+
+
+@sbuild.parse
+def smulh(arg1, arg2, arg3):
+    arg1 = (arg2.signExtend(128) * arg3.signExtend(128))[64:]
+
+
+@sbuild.parse
+def smull(arg1, arg2, arg3):
+    arg1 = (arg2.signExtend(64) * arg3.signExtend(64))[64:]
+
+
+
+mnemo_func = sbuild.functions
+mnemo_func.update({
+    'and': and_l,
+    'adds': adds,
+    'ands': ands,
+    'tst': tst,
+    'subs': subs,
+    'cmp': cmp,
+    'cmn': cmn,
+    'movk': movk,
+    'ccmp': ccmp,
+    'csinc': csinc,
+    'csinv': csinv,
+    'csneg': csneg,
+    'cset': cset,
+    'csetm': csetm,
+
+    'b.ne': b_ne,
+    'b.eq': b_eq,
+    'b.ge': b_ge,
+    'b.mi': b_mi,
+    'b.pl': b_pl,
+    '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,
+
+    'bics': bics,
+
+    'ret': ret,
+    'stp': stp,
+    'ldp': ldp,
+
+    'ldr': ldr,
+    'ldrb': ldrb,
+    'ldrh': ldrh,
+
+    'ldur': ldr,
+    'ldurb': ldrb,
+    'ldursb': ldrsb,
+    'ldurh': ldrh,
+    'ldursh': ldrsh,
+    'ldursw': ldrsw,
+
+    'ldrsb': ldrsb,
+    'ldrsh': ldrsh,
+    'ldrsw': ldrsw,
+
+    'ldar': ldr, # TODO memory barrier
+    'ldarb': ldrb,
+
+    'ldaxrb': ldaxrb,
+    'stlxrb': stlxrb,
+
+    'stlr': l_str, # TODO memory barrier
+    'stlrb': stlrb,
+
+    'stlxr': stlxr,
+    'ldxr': ldxr,
+
+    'str': l_str,
+    'strb': strb,
+    'strh': strh,
+
+    'stur': l_str,
+    'sturb': strb,
+    'sturh': strh,
+
+
+    'bfm': bfm,
+    'sbfm': sbfm,
+    'ubfm': ubfm,
+
+    'extr': extr,
+    'rev': rev,
+    'rev16': rev16,
+
+    'msr': msr,
+    'mrs': mrs,
+
+    'adc': adc,
+    'adcs': adcs,
+    'sbc': sbc,
+    'sbcs': sbcs,
+
+    'fmov': fmov,
+    'fadd': fadd,
+    'fsub': fsub,
+    'fmul': fmul,
+    'fdiv': fdiv,
+    'fabs': fabs,
+    'fmadd': fmadd,
+    'fmsub': fmsub,
+    'fcvt': fcvt,
+    'scvtf': scvtf,
+    'ucvtf': ucvtf,
+    'fcvtzs': fcvtzs,
+    'fcvtzu': fcvtzu,
+    'fcmpe': fcmpe,
+    'clz': clz,
+
+    # XXX TODO: memory barrier
+    'casp':casp,
+    'caspl':casp,
+    'caspa':casp,
+    'caspal':casp,
+
+    'yield': nop,
+    'isb': isb,
+    'dsb': dsb,
+    'dmb': dmb,
+    'tlbi': tlbi,
+    'clrex': clrex,
+    'ic': ic
+})
+
+
+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(object):
+    mode = "aarch64"
+    # offset
+
+
+class Lifter_Aarch64l(Lifter):
+
+    def __init__(self, loc_db):
+        Lifter.__init__(self, mn_aarch64, "l", loc_db)
+        self.pc = PC
+        self.sp = SP
+        self.IRDst = ExprId('IRDst', 64)
+        self.addrsize = 64
+
+    def get_ir(self, instr):
+        args = instr.args
+        if len(args) and isinstance(args[-1], ExprOp):
+            if (args[-1].op in ['<<', '>>', '<<a', 'a>>', '<<<', '>>>'] and
+               isinstance(args[-1].args[-1], ExprId)):
+                args[-1] = 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)
+        self.mod_pc(instr, instr_ir, extra_ir)
+        instr_ir, extra_ir = self.del_dst_zr(instr, instr_ir, extra_ir)
+        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 ExprAssign(dst, src)
+
+    def irbloc_fix_regs_for_mode(self, irblock, mode=64):
+        irs = []
+        for assignblk in irblock:
+            new_assignblk = dict(assignblk)
+            for dst, src in viewitems(assignblk):
+                del(new_assignblk[dst])
+                # Special case for 64 bits:
+                # If destination is a 32 bit reg, zero extend the 64 bit reg
+                if (isinstance(dst, ExprId) and
+                    dst.size == 32 and
+                    dst in replace_regs):
+                    src = src.zeroExtend(64)
+                    dst = replace_regs[dst].arg
+
+                dst = self.expr_fix_regs_for_mode(dst)
+                src = self.expr_fix_regs_for_mode(src)
+                new_assignblk[dst] = src
+            irs.append(AssignBlock(new_assignblk, assignblk.instr))
+        return IRBlock(self.loc_db, irblock.loc_key, irs)
+
+    def mod_pc(self, instr, instr_ir, extra_ir):
+        "Replace PC by the instruction's offset"
+        cur_offset = ExprInt(instr.offset, 64)
+        pc_fixed = {self.pc: cur_offset}
+        for i, expr in enumerate(instr_ir):
+            dst, src = expr.dst, expr.src
+            if dst != self.pc:
+                dst = dst.replace_expr(pc_fixed)
+            src = src.replace_expr(pc_fixed)
+            instr_ir[i] = ExprAssign(dst, src)
+
+        for idx, irblock in enumerate(extra_ir):
+            extra_ir[idx] = irblock.modify_exprs(lambda expr: expr.replace_expr(pc_fixed) \
+                                                 if expr != self.pc else expr,
+                                                 lambda expr: expr.replace_expr(pc_fixed))
+
+
+    def del_dst_zr(self, instr, instr_ir, extra_ir):
+        "Writes to zero register are discarded"
+        regs_to_fix = [WZR, XZR]
+        instr_ir = [expr for expr in instr_ir if expr.dst not in regs_to_fix]
+
+        new_irblocks = []
+        for irblock in extra_ir:
+            irs = []
+            for assignblk in irblock:
+                new_dsts = {
+                    dst:src for dst, src in viewitems(assignblk)
+                    if dst not in regs_to_fix
+                }
+                irs.append(AssignBlock(new_dsts, assignblk.instr))
+            new_irblocks.append(IRBlock(self.loc_db, irblock.loc_key, irs))
+
+        return instr_ir, new_irblocks
+
+
+class Lifter_Aarch64b(Lifter_Aarch64l):
+
+    def __init__(self, loc_db):
+        Lifter.__init__(self, mn_aarch64, "b", loc_db)
+        self.pc = PC
+        self.sp = SP
+        self.IRDst = ExprId('IRDst', 64)
+        self.addrsize = 64
diff --git a/src/miasm/arch/arm/__init__.py b/src/miasm/arch/arm/__init__.py
new file mode 100644
index 00000000..bbad893b
--- /dev/null
+++ b/src/miasm/arch/arm/__init__.py
@@ -0,0 +1 @@
+__all__ = ["arch", "disasm", "regs", "sem"]
diff --git a/src/miasm/arch/arm/arch.py b/src/miasm/arch/arm/arch.py
new file mode 100644
index 00000000..10551515
--- /dev/null
+++ b/src/miasm/arch/arm/arch.py
@@ -0,0 +1,3457 @@
+#-*- coding:utf-8 -*-
+
+from builtins import range
+from future.utils import viewitems
+
+import logging
+from pyparsing import *
+from miasm.expression.expression import *
+from miasm.core.cpu import *
+from collections import defaultdict
+from miasm.core.bin_stream import bin_stream
+import miasm.arch.arm.regs as regs_module
+from miasm.arch.arm.regs import *
+from miasm.core.asm_ast import AstInt, AstId, AstMem, AstOp
+from miasm.ir.ir import color_expr_html
+from miasm.core import utils
+from miasm.core.utils import BRACKET_O, BRACKET_C
+
+# A1 encoding
+
+log = logging.getLogger("armdis")
+console_handler = logging.StreamHandler()
+console_handler.setFormatter(logging.Formatter("[%(levelname)-8s]: %(message)s"))
+log.addHandler(console_handler)
+log.setLevel(logging.DEBUG)
+
+# arm regs ##############
+reg_dum = ExprId('DumReg', 32)
+
+PC, _ = gen_reg('PC')
+
+# GP
+regs_str = ['R%d' % r for r in range(0x10)]
+regs_str[13] = 'SP'
+regs_str[14] = 'LR'
+regs_str[15] = 'PC'
+regs_expr = [ExprId(x, 32) for x in regs_str]
+
+gpregs = reg_info(regs_str, regs_expr)
+
+gpregs_pc = reg_info(regs_str[-1:], regs_expr[-1:])
+gpregs_sp = reg_info(regs_str[13:14], regs_expr[13:14])
+
+gpregs_nosppc = reg_info(regs_str[:13] + [str(reg_dum), regs_str[14]],
+                         regs_expr[:13] + [reg_dum, regs_expr[14]])
+
+gpregs_nopc = reg_info(regs_str[:14],
+                       regs_expr[:14])
+
+gpregs_nosp = reg_info(regs_str[:13] + [str(reg_dum), regs_str[14], regs_str[15]],
+                       regs_expr[:13] + [reg_dum, regs_expr[14], regs_expr[15]])
+
+
+# psr
+sr_flags = "cxsf"
+cpsr_regs_str = []
+spsr_regs_str = []
+for i in range(0x10):
+    o = ""
+    for j in range(4):
+        if i & (1 << j):
+            o += sr_flags[j]
+    cpsr_regs_str.append("CPSR_%s" % o)
+    spsr_regs_str.append("SPSR_%s" % o)
+
+# psr_regs_str = ['CPSR', 'SPSR']
+# psr_regs_expr = [ExprId(x, 32) for x in psr_regs_str]
+
+# psr_regs = reg_info(psr_regs_str, psr_regs_expr)
+
+cpsr_regs_expr = [ExprId(x, 32) for x in cpsr_regs_str]
+spsr_regs_expr = [ExprId(x, 32) for x in spsr_regs_str]
+
+cpsr_regs = reg_info(cpsr_regs_str, cpsr_regs_expr)
+spsr_regs = reg_info(spsr_regs_str, spsr_regs_expr)
+
+# CP
+cpregs_str = ['c%d' % r for r in range(0x10)]
+cpregs_expr = [ExprId(x, 32) for x in cpregs_str]
+
+cp_regs = reg_info(cpregs_str, cpregs_expr)
+
+# P
+pregs_str = ['p%d' % r for r in range(0x10)]
+pregs_expr = [ExprId(x, 32) for x in pregs_str]
+
+p_regs = reg_info(pregs_str, pregs_expr)
+
+conditional_branch = ["BEQ", "BNE", "BCS", "BCC", "BMI", "BPL", "BVS",
+                      "BVC", "BHI", "BLS", "BGE", "BLT", "BGT", "BLE"]
+
+unconditional_branch = ["B", "BX", "BL", "BLX"]
+
+barrier_expr = {
+    0b1111: ExprId("SY", 32),
+    0b1110: ExprId("ST", 32),
+    0b1101: ExprId("LD", 32),
+    0b1011: ExprId("ISH", 32),
+    0b1010: ExprId("ISHST", 32),
+    0b1001: ExprId("ISHLD", 32),
+    0b0111: ExprId("NSH", 32),
+    0b0110: ExprId("NSHST", 32),
+    0b0011: ExprId("OSH", 32),
+    0b0010: ExprId("OSHST", 32),
+    0b0001: ExprId("OSHLD", 32),
+}
+
+barrier_info = reg_info_dct(barrier_expr)
+
+
+
+# parser helper ###########
+
+def cb_tok_reg_duo(tokens):
+    tokens = tokens[0]
+    i1 = gpregs.expr.index(tokens[0].name)
+    i2 = gpregs.expr.index(tokens[1].name)
+    o = []
+    for i in range(i1, i2 + 1):
+        o.append(AstId(gpregs.expr[i]))
+    return o
+
+LPARENTHESIS = Literal("(")
+RPARENTHESIS = Literal(")")
+
+LACC = Suppress(Literal("{"))
+RACC = Suppress(Literal("}"))
+MINUS = Suppress(Literal("-"))
+CIRCUNFLEX = Literal("^")
+
+
+def check_bounds(left_bound, right_bound, value):
+    if left_bound <= value and value <= right_bound:
+        return AstInt(value)
+    else:
+        raise ValueError('shift operator immediate value out of bound')
+
+
+def check_values(values, value):
+    if value in values:
+        return AstInt(value)
+    else:
+        raise ValueError('shift operator immediate value out of bound')
+
+int_1_31 = str_int.copy().setParseAction(lambda v: check_bounds(1, 31, v[0]))
+int_1_32 = str_int.copy().setParseAction(lambda v: check_bounds(1, 32, v[0]))
+
+int_8_16_24 = str_int.copy().setParseAction(lambda v: check_values([8, 16, 24], v[0]))
+
+
+def cb_reglistparse(tokens):
+    tokens = tokens[0]
+    if tokens[-1] == "^":
+        return AstOp('sbit', AstOp('reglist', *tokens[:-1]))
+    return AstOp('reglist', *tokens)
+
+
+allshifts = ['<<', '>>', 'a>>', '>>>', 'rrx']
+allshifts_armt = ['<<', '>>', 'a>>', '>>>', 'rrx']
+
+shift2expr_dct = {'LSL': '<<', 'LSR': '>>', 'ASR': 'a>>',
+                  'ROR': ">>>", 'RRX': "rrx"}
+
+expr2shift_dct = dict((value, key) for key, value in viewitems(shift2expr_dct))
+
+
+def op_shift2expr(tokens):
+    return shift2expr_dct[tokens[0]]
+
+reg_duo = Group(gpregs.parser + MINUS +
+                gpregs.parser).setParseAction(cb_tok_reg_duo)
+reg_or_duo = reg_duo | gpregs.parser
+gpreg_list = Group(LACC + delimitedList(
+    reg_or_duo, delim=',') + RACC + Optional(CIRCUNFLEX))
+gpreg_list.setParseAction(cb_reglistparse)
+
+LBRACK = Suppress("[")
+RBRACK = Suppress("]")
+COMMA = Suppress(",")
+all_binaryop_1_31_shifts_t = literal_list(
+    ['LSL', 'ROR']).setParseAction(op_shift2expr)
+all_binaryop_1_32_shifts_t = literal_list(
+    ['LSR', 'ASR']).setParseAction(op_shift2expr)
+all_unaryop_shifts_t = literal_list(['RRX']).setParseAction(op_shift2expr)
+
+ror_shifts_t = literal_list(['ROR']).setParseAction(op_shift2expr)
+shl_shifts_t = literal_list(['SHL']).setParseAction(op_shift2expr)
+
+
+allshifts_t_armt = literal_list(
+    ['LSL', 'LSR', 'ASR', 'ROR', 'RRX']).setParseAction(op_shift2expr)
+
+gpreg_p = gpregs.parser
+
+psr_p = cpsr_regs.parser | spsr_regs.parser
+
+
+def cb_shift(tokens):
+    if len(tokens) == 1:
+        ret = tokens[0]
+    elif len(tokens) == 2:
+        ret = AstOp(tokens[1], tokens[0])
+    elif len(tokens) == 3:
+        ret = AstOp(tokens[1], tokens[0], tokens[2])
+    else:
+        raise ValueError("Bad arg")
+    return ret
+
+shift_off = (gpregs.parser + Optional(
+    (all_unaryop_shifts_t) |
+    (all_binaryop_1_31_shifts_t + (gpregs.parser | int_1_31)) |
+    (all_binaryop_1_32_shifts_t + (gpregs.parser | int_1_32))
+)).setParseAction(cb_shift)
+shift_off |= base_expr
+
+
+rot2_expr = (gpregs.parser + Optional(
+    (ror_shifts_t + (int_8_16_24))
+)).setParseAction(cb_shift)
+
+
+rot5_expr = shift_off
+
+OP_LSL = Suppress("LSL")
+
+def cb_deref_reg_reg(tokens):
+    if len(tokens) != 2:
+        raise ValueError("Bad mem format")
+    return AstMem(AstOp('+', tokens[0], tokens[1]), 8)
+
+def cb_deref_reg_reg_lsl_1(tokens):
+    if len(tokens) != 3:
+        raise ValueError("Bad mem format")
+    reg1, reg2, index = tokens
+    if not isinstance(index, AstInt) or index.value != 1:
+        raise ValueError("Bad index")
+    ret = AstMem(AstOp('+', reg1, AstOp('<<', reg2, index)), 16)
+    return ret
+
+
+deref_reg_reg = (LBRACK + gpregs.parser + COMMA + gpregs.parser + RBRACK).setParseAction(cb_deref_reg_reg)
+deref_reg_reg_lsl_1 = (LBRACK + gpregs.parser + COMMA + gpregs.parser + OP_LSL + base_expr + RBRACK).setParseAction(cb_deref_reg_reg_lsl_1)
+
+
+
+(gpregs.parser + Optional(
+    (ror_shifts_t + (int_8_16_24))
+)).setParseAction(cb_shift)
+
+
+
+reg_or_base = gpregs.parser | base_expr
+
+def deref2expr_nooff(tokens):
+    tokens = tokens[0]
+    # XXX default
+    return ExprOp("preinc", tokens[0], ExprInt(0, 32))
+
+
+def cb_deref_preinc(tokens):
+    tokens = tokens[0]
+    if len(tokens) == 1:
+        return AstOp("preinc", tokens[0], AstInt(0))
+    elif len(tokens) == 2:
+        return AstOp("preinc", tokens[0], tokens[1])
+    else:
+        raise NotImplementedError('len(tokens) > 2')
+
+
+def cb_deref_pre_mem(tokens):
+    tokens = tokens[0]
+    if len(tokens) == 1:
+        return AstMem(AstOp("preinc", tokens[0], AstInt(0)), 32)
+    elif len(tokens) == 2:
+        return AstMem(AstOp("preinc", tokens[0], tokens[1]), 32)
+    else:
+        raise NotImplementedError('len(tokens) > 2')
+
+
+def cb_deref_post(tokens):
+    tokens = tokens[0]
+    return AstOp("postinc", tokens[0], tokens[1])
+
+
+def cb_deref_wb(tokens):
+    tokens = tokens[0]
+    if tokens[-1] == '!':
+        return AstMem(AstOp('wback', *tokens[:-1]), 32)
+    return AstMem(tokens[0], 32)
+
+# shift_off.setParseAction(deref_off)
+deref_nooff = Group(
+    LBRACK + gpregs.parser + RBRACK).setParseAction(deref2expr_nooff)
+deref_pre = Group(LBRACK + gpregs.parser + Optional(
+    COMMA + shift_off) + RBRACK).setParseAction(cb_deref_preinc)
+deref_post = Group(LBRACK + gpregs.parser + RBRACK +
+                   COMMA + shift_off).setParseAction(cb_deref_post)
+deref = Group((deref_post | deref_pre | deref_nooff)
+              + Optional('!')).setParseAction(cb_deref_wb)
+
+
+def cb_gpreb_wb(tokens):
+    assert len(tokens) == 1
+    tokens = tokens[0]
+    if tokens[-1] == '!':
+        return AstOp('wback', *tokens[:-1])
+    return tokens[0]
+
+gpregs_wb = Group(gpregs.parser + Optional('!')).setParseAction(cb_gpreb_wb)
+
+
+cond_list_full = ['EQ', 'NE', 'CS', 'CC', 'MI', 'PL', 'VS', 'VC',
+                  'HI', 'LS', 'GE', 'LT', 'GT', 'LE', 'NV']
+
+
+cond_list = ['EQ', 'NE', 'CS', 'CC', 'MI', 'PL', 'VS', 'VC',
+             'HI', 'LS', 'GE', 'LT', 'GT', 'LE', '']  # , 'NV']
+cond_dct = dict([(x[1], x[0]) for x in enumerate(cond_list)])
+bm_cond = bs_mod_name(l=4, fname='cond', mn_mod=cond_list)
+
+
+
+cond_dct_barmt = dict([(x[0], x[1]) for x in enumerate(cond_list) if x[0] & 0b1110 != 0b1110])
+bm_cond_barmt = bs_mod_name(l=4, fname='cond', mn_mod=cond_dct_barmt)
+
+
+
+def permut_args(order, args):
+    l = []
+    for i, x in enumerate(order):
+        l.append((x.__class__, i))
+    l = dict(l)
+    out = [None for x in range(len(args))]
+    for a in args:
+        out[l[a.__class__]] = a
+    return out
+
+
+class additional_info(object):
+
+    def __init__(self):
+        self.except_on_instr = False
+        self.lnk = None
+        self.cond = None
+
+
+class instruction_arm(instruction):
+    __slots__ = []
+
+    def __init__(self, *args, **kargs):
+        super(instruction_arm, self).__init__(*args, **kargs)
+
+    @staticmethod
+    def arg2str(expr, index=None, loc_db=None):
+        wb = False
+        if expr.is_id() or expr.is_int():
+            return str(expr)
+        elif expr.is_loc():
+            if loc_db is not None:
+                return loc_db.pretty_str(expr.loc_key)
+            else:
+                return str(expr)
+        if isinstance(expr, ExprOp) and expr.op in expr2shift_dct:
+            if len(expr.args) == 1:
+                return '%s %s' % (expr.args[0], expr2shift_dct[expr.op])
+            elif len(expr.args) == 2:
+                return '%s %s %s' % (expr.args[0], expr2shift_dct[expr.op], expr.args[1])
+            else:
+                raise NotImplementedError('zarb arg2str')
+
+
+        sb = False
+        if isinstance(expr, ExprOp) and expr.op == "sbit":
+            sb = True
+            expr = expr.args[0]
+        if isinstance(expr, ExprOp) and expr.op == "reglist":
+            o = [gpregs.expr.index(x) for x in expr.args]
+            out = reglist2str(o)
+            if sb:
+                out += "^"
+            return out
+
+
+        if isinstance(expr, ExprOp) and expr.op == 'wback':
+            wb = True
+            expr = expr.args[0]
+        if isinstance(expr, ExprId):
+            out = str(expr)
+            if wb:
+                out += "!"
+            return out
+
+        if not isinstance(expr, ExprMem):
+            return str(expr)
+
+        expr = expr.ptr
+        if isinstance(expr, ExprOp) and expr.op == 'wback':
+            wb = True
+            expr = expr.args[0]
+
+
+        if isinstance(expr, ExprId):
+            r, s = expr, None
+        elif len(expr.args) == 1 and isinstance(expr.args[0], ExprId):
+            r, s = expr.args[0], None
+        elif isinstance(expr.args[0], ExprId):
+            r, s = expr.args[0], expr.args[1]
+        else:
+            r, s = expr.args[0].args
+        if isinstance(s, ExprOp) and s.op in expr2shift_dct:
+            s = ' '.join(
+                str(x)
+                for x in (s.args[0], expr2shift_dct[s.op], s.args[1])
+            )
+
+        if isinstance(expr, ExprOp) and expr.op == 'postinc':
+            o = '[' + str(r) + ']'
+            if s and not (isinstance(s, ExprInt) and int(s) == 0):
+                o += ', %s' % s
+        else:
+            if s and not (isinstance(s, ExprInt) and int(s) == 0):
+                o = '[' + ("%s, %s" % (r, s)) + ']'
+            else:
+                o = '[' + str(r) + ']'
+
+        if wb:
+            o += "!"
+        return o
+
+    @staticmethod
+    def arg2html(expr, index=None, loc_db=None):
+        wb = False
+        if expr.is_id() or expr.is_int() or expr.is_loc():
+            return color_expr_html(expr, loc_db)
+        if isinstance(expr, ExprOp) and expr.op in expr2shift_dct:
+            if len(expr.args) == 1:
+                return '%s %s' % (color_expr_html(expr.args[0], loc_db), expr2shift_dct[expr.op])
+            elif len(expr.args) == 2:
+                return '%s %s %s' % (color_expr_html(expr.args[0], loc_db), expr2shift_dct[expr.op], expr.args[1])
+            else:
+                raise NotImplementedError('zarb arg2str')
+
+
+        sb = False
+        if isinstance(expr, ExprOp) and expr.op == "sbit":
+            sb = True
+            expr = expr.args[0]
+        if isinstance(expr, ExprOp) and expr.op == "reglist":
+            o = [gpregs.expr.index(x) for x in expr.args]
+            out = reglist2html(o)
+            if sb:
+                out += "^"
+            return out
+
+
+        if isinstance(expr, ExprOp) and expr.op == 'wback':
+            wb = True
+            expr = expr.args[0]
+        if isinstance(expr, ExprId):
+            out = color_expr_html(expr, loc_db)
+            if wb:
+                out += "!"
+            return out
+
+        if not isinstance(expr, ExprMem):
+            return color_expr_html(expr, loc_db)
+
+        expr = expr.ptr
+        if isinstance(expr, ExprOp) and expr.op == 'wback':
+            wb = True
+            expr = expr.args[0]
+
+
+        if isinstance(expr, ExprId):
+            r, s = expr, None
+        elif len(expr.args) == 1 and isinstance(expr.args[0], ExprId):
+            r, s = expr.args[0], None
+        elif isinstance(expr.args[0], ExprId):
+            r, s = expr.args[0], expr.args[1]
+        else:
+            r, s = expr.args[0].args
+        if isinstance(s, ExprOp) and s.op in expr2shift_dct:
+            s_html = ' '.join(
+                str(x)
+                for x in (
+                        color_expr_html(s.args[0], loc_db),
+                        utils.set_html_text_color(expr2shift_dct[s.op], utils.COLOR_OP),
+                        color_expr_html(s.args[1], loc_db)
+                )
+            )
+        else:
+            s_html = color_expr_html(s, loc_db)
+
+        if isinstance(expr, ExprOp) and expr.op == 'postinc':
+            o = BRACKET_O + color_expr_html(r, loc_db) + BRACKET_C
+            if s and not (isinstance(s, ExprInt) and int(s) == 0):
+                o += ', %s' % s_html
+        else:
+            if s and not (isinstance(s, ExprInt) and int(s) == 0):
+                o = BRACKET_O + color_expr_html(r, loc_db) + ", " + s_html + BRACKET_C
+            else:
+                o = BRACKET_O + color_expr_html(r, loc_db) + BRACKET_C
+
+        if wb:
+            o += "!"
+        return o
+
+
+    def dstflow(self):
+        if self.is_subcall():
+            return True
+        return self.name in conditional_branch + unconditional_branch
+
+    def dstflow2label(self, loc_db):
+        expr = self.args[0]
+        if not isinstance(expr, ExprInt):
+            return
+        if self.name == 'BLX':
+            addr = (int(expr) + self.offset) & int(expr.mask)
+        else:
+            addr = (int(expr) + self.offset) & int(expr.mask)
+        loc_key = loc_db.get_or_create_offset_location(addr)
+        self.args[0] = ExprLoc(loc_key, expr.size)
+
+    def breakflow(self):
+        if self.is_subcall():
+            return True
+        if self.name in conditional_branch + unconditional_branch:
+            return True
+        if self.name.startswith("LDM") and PC in self.args[1].args:
+            return True
+        if self.args and PC in self.args[0].get_r():
+            return True
+        return False
+
+    def is_subcall(self):
+        if self.name == 'BLX':
+            return True
+        return self.additional_info.lnk
+
+    def getdstflow(self, loc_db):
+        return [self.args[0]]
+
+    def splitflow(self):
+        if self.additional_info.lnk:
+            return True
+        if self.name == 'BLX':
+            return True
+        if self.name == 'BX':
+            return False
+        return self.breakflow() and self.additional_info.cond != 14
+
+    def get_symbol_size(self, symbol, loc_db):
+        return 32
+
+    def fixDstOffset(self):
+        e = self.args[0]
+        if self.offset is None:
+            raise ValueError('symbol not resolved %s' % l)
+        if not isinstance(e, ExprInt):
+            log.debug('dyn dst %r', e)
+            return
+        off = (int(e) - self.offset) & int(e.mask)
+        if int(off % 4):
+            raise ValueError('strange offset! %r' % off)
+        self.args[0] = ExprInt(off, 32)
+
+    def get_args_expr(self):
+        args = [a for a in self.args]
+        return args
+
+    def get_asm_offset(self, expr):
+        # LDR XXX, [PC, offset] => PC is self.offset+8
+        return ExprInt(self.offset+8, expr.size)
+
+class instruction_armt(instruction_arm):
+    __slots__ = []
+
+    def __init__(self, *args, **kargs):
+        super(instruction_armt, self).__init__(*args, **kargs)
+
+    def dstflow(self):
+        if self.name in ["CBZ", "CBNZ"]:
+            return True
+        return self.name in conditional_branch + unconditional_branch
+
+    def dstflow2label(self, loc_db):
+        if self.name in ["CBZ", "CBNZ"]:
+            expr = self.args[1]
+        else:
+            expr = self.args[0]
+        if not isinstance(expr, ExprInt):
+            return
+        if self.name == 'BLX':
+            addr = (int(expr) + (self.offset & 0xfffffffc)) & int(expr.mask)
+        elif self.name == 'BL':
+            addr = (int(expr) + self.offset) & int(expr.mask)
+        elif self.name.startswith('BP'):
+            addr = (int(expr) + self.offset) & int(expr.mask)
+        elif self.name.startswith('CB'):
+            addr = (int(expr) + self.offset + self.l + 2) & int(expr.mask)
+        else:
+            addr = (int(expr) + self.offset) & int(expr.mask)
+
+        loc_key = loc_db.get_or_create_offset_location(addr)
+        dst = ExprLoc(loc_key, expr.size)
+
+        if self.name in ["CBZ", "CBNZ"]:
+            self.args[1] = dst
+        else:
+            self.args[0] = dst
+
+    def breakflow(self):
+        if self.name in conditional_branch + unconditional_branch +["CBZ", "CBNZ", 'TBB', 'TBH']:
+            return True
+        if self.name.startswith("LDM") and PC in self.args[1].args:
+            return True
+        if self.args and PC in self.args[0].get_r():
+            return True
+        return False
+
+    def getdstflow(self, loc_db):
+        if self.name in ['CBZ', 'CBNZ']:
+            return [self.args[1]]
+        return [self.args[0]]
+
+    def splitflow(self):
+        if self.name in conditional_branch + ['BL', 'BLX', 'CBZ', 'CBNZ']:
+            return True
+        return False
+
+    def is_subcall(self):
+        return self.name in ['BL', 'BLX']
+
+    def fixDstOffset(self):
+        e = self.args[0]
+        if self.offset is None:
+            raise ValueError('symbol not resolved %s' % l)
+        if not isinstance(e, ExprInt):
+            log.debug('dyn dst %r', e)
+            return
+        # The first +2 is to compensate instruction len, but strangely, 32 bits
+        # thumb2 instructions len is 2... For the second +2, didn't find it in
+        # the doc.
+        off = (int(e) - self.offset) & int(e.mask)
+        if int(off % 2):
+            raise ValueError('strange offset! %r' % off)
+        self.args[0] = ExprInt(off, 32)
+
+    def get_asm_offset(self, expr):
+        # ADR XXX, PC, imm => PC is 4 aligned + imm
+        new_offset = ((self.offset + self.l) // 4) * 4
+        return ExprInt(new_offset, expr.size)
+
+
+class mn_arm(cls_mn):
+    delayslot = 0
+    name = "arm"
+    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_arm
+    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
+        if hasattr(self, "cond"):
+            info.cond = self.cond.value
+        else:
+            info.cond = None
+        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 enough 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 [bm_cond] + 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_arm, 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, loc_db, mode):
+        return 32
+
+
+class mn_armt(cls_mn):
+    name = "armt"
+    regs = regs_module
+    delayslot = 0
+    bintree = {}
+    num = 0
+    all_mn = []
+    all_mn_mode = defaultdict(list)
+    all_mn_name = defaultdict(list)
+    all_mn_inst = defaultdict(list)
+    pc = PC
+    sp = SP
+    instruction = instruction_armt
+    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
+        info.cond = 14  # COND_ALWAYS
+        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 enough 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 & ~1) + 1 - offset % 2
+        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 in [16, 32], "len %r" % l
+
+    @classmethod
+    def getmn(cls, name):
+        return name.upper()
+
+    @classmethod
+    def mod_fields(cls, fields):
+        return list(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_armt, self).value(mode)
+        if mode == 'l':
+            out = []
+            for x in v:
+                if len(x) == 2:
+                    out.append(x[::-1])
+                elif len(x) == 4:
+                    out.append(x[:2][::-1] + x[2:4][::-1])
+            return out
+        elif mode == 'b':
+            return [x for x in v]
+        else:
+            raise NotImplementedError('bad attrib')
+
+    def get_args_expr(self):
+        args = [a.expr for a in self.args]
+        return args
+
+    def get_symbol_size(self, symbol, loc_db, mode):
+        return 32
+
+
+class arm_arg(m_arg):
+    def asm_ast_to_expr(self, arg, loc_db):
+        if isinstance(arg, AstId):
+            if isinstance(arg.name, ExprId):
+                return arg.name
+            if arg.name in gpregs.str:
+                return None
+            loc_key = loc_db.get_or_create_name_location(arg.name)
+            return ExprLoc(loc_key, 32)
+        if isinstance(arg, AstOp):
+            args = [self.asm_ast_to_expr(tmp, loc_db) for tmp in arg.args]
+            if None in args:
+                return None
+            if arg.op == "-":
+                assert len(args) == 2
+                return args[0] - args[1]
+            return ExprOp(arg.op, *args)
+        if isinstance(arg, AstInt):
+            return ExprInt(arg.value, 32)
+        if isinstance(arg, AstMem):
+            ptr = self.asm_ast_to_expr(arg.ptr, loc_db)
+            if ptr is None:
+                return None
+            return ExprMem(ptr, arg.size)
+        return None
+
+
+class arm_reg(reg_noarg, arm_arg):
+    pass
+
+
+class arm_gpreg_noarg(reg_noarg):
+    reg_info = gpregs
+    parser = reg_info.parser
+
+
+class arm_gpreg(arm_reg):
+    reg_info = gpregs
+    parser = reg_info.parser
+
+
+class arm_reg_wb(arm_reg):
+    reg_info = gpregs
+    parser = gpregs_wb
+
+    def decode(self, v):
+        v = v & self.lmask
+        e = self.reg_info.expr[v]
+        if self.parent.wback.value:
+            e = ExprOp('wback', e)
+        self.expr = e
+        return True
+
+    def encode(self):
+        e = self.expr
+        self.parent.wback.value = 0
+        if isinstance(e, ExprOp) and e.op == 'wback':
+            self.parent.wback.value = 1
+            e = e.args[0]
+        if isinstance(e, ExprId):
+            self.value = self.reg_info.expr.index(e)
+        else:
+            self.parent.wback.value = 1
+            self.value = self.reg_info.expr.index(e.args[0])
+        return True
+
+
+class arm_psr(arm_arg):
+    parser = psr_p
+
+    def decode(self, v):
+        v = v & self.lmask
+        if self.parent.psr.value == 0:
+            e = cpsr_regs.expr[v]
+        else:
+            e = spsr_regs.expr[v]
+        self.expr = e
+        return True
+
+    def encode(self):
+        e = self.expr
+        if e in spsr_regs.expr:
+            self.parent.psr.value = 1
+            v = spsr_regs.expr.index(e)
+        elif e in cpsr_regs.expr:
+            self.parent.psr.value = 0
+            v = cpsr_regs.expr.index(e)
+        else:
+            return False
+        self.value = v
+        return True
+
+
+class arm_cpreg(arm_reg):
+    reg_info = cp_regs
+    parser = reg_info.parser
+
+
+class arm_preg(arm_reg):
+    reg_info = p_regs
+    parser = reg_info.parser
+
+
+class arm_imm(imm_noarg, arm_arg):
+    parser = base_expr
+
+
+class arm_offs(arm_imm):
+    parser = base_expr
+
+    def int2expr(self, v):
+        if v & ~self.intmask != 0:
+            return None
+        return ExprInt(v, self.intsize)
+
+    def decodeval(self, v):
+        v <<= 2
+        # Add pipeline offset
+        v += 8
+        return v
+
+    def encodeval(self, v):
+        if v%4 != 0:
+            return False
+        # Remove pipeline offset
+        v -= 8
+        return v >> 2
+
+    def decode(self, v):
+        v = v & self.lmask
+        if (1 << (self.l - 1)) & v:
+            v |= ~0 ^ self.lmask
+        v = self.decodeval(v)
+        self.expr = ExprInt(v, 32)
+        return True
+
+    def encode(self):
+        if not isinstance(self.expr, ExprInt):
+            return False
+        v = int(self.expr)
+        if (1 << (self.l - 1)) & v:
+            v = -((0xffffffff ^ v) + 1)
+        v = self.encodeval(v)
+        if v is False:
+            return False
+        self.value = (v & 0xffffffff) & self.lmask
+        return True
+
+
+class arm_imm8_12(arm_arg):
+    parser = deref
+
+    def decode(self, v):
+        v = v & self.lmask
+        if self.parent.updown.value:
+            e = ExprInt(v << 2, 32)
+        else:
+            e = ExprInt(-v << 2, 32)
+        if self.parent.ppi.value:
+            e = ExprOp('preinc', self.parent.rn.expr, e)
+        else:
+            e = ExprOp('postinc', self.parent.rn.expr, e)
+        if self.parent.wback.value == 1:
+            e = ExprOp('wback', e)
+        self.expr = ExprMem(e, 32)
+        return True
+
+    def encode(self):
+        self.parent.updown.value = 1
+        e = self.expr
+        if not isinstance(e, ExprMem):
+            return False
+        e = e.ptr
+        if isinstance(e, ExprOp) and e.op == 'wback':
+            self.parent.wback.value = 1
+            e = e.args[0]
+        else:
+            self.parent.wback.value = 0
+        if e.op == "postinc":
+            self.parent.ppi.value = 0
+        elif e.op == "preinc":
+            self.parent.ppi.value = 1
+        else:
+            # XXX default
+            self.parent.ppi.value = 1
+        self.parent.rn.expr = e.args[0]
+        if len(e.args) == 1:
+            self.value = 0
+            return True
+        e = e.args[1]
+        if not isinstance(e, ExprInt):
+            log.debug('should be int %r', e)
+            return False
+        v = int(e)
+        if v < 0 or v & (1 << 31):
+            self.parent.updown.value = 0
+            v = -v & 0xFFFFFFFF
+        if v & 0x3:
+            log.debug('arg should be 4 aligned')
+            return False
+        v >>= 2
+        self.value = v
+        return True
+
+
+class arm_imm_4_12(arm_arg):
+    parser = reg_or_base
+
+    def decode(self, v):
+        v = v & self.lmask
+        imm = (self.parent.imm4.value << 12) | v
+        self.expr = ExprInt(imm, 32)
+        return True
+
+    def encode(self):
+        if not isinstance(self.expr, ExprInt):
+            return False
+        v = int(self.expr)
+        if v > 0xffff:
+            return False
+        self.parent.imm4.value = v >> 12
+        self.value = v & 0xfff
+        return True
+
+
+class arm_imm_12_4(arm_arg):
+    parser = base_expr
+
+    def decode(self, v):
+        v = v & self.lmask
+        imm =  (self.parent.imm.value << 4) | v
+        self.expr = ExprInt(imm, 32)
+        return True
+
+    def encode(self):
+        if not isinstance(self.expr, ExprInt):
+            return False
+        v = int(self.expr)
+        if v > 0xffff:
+            return False
+        self.parent.imm.value = (v >> 4) & 0xfff
+        self.value = v & 0xf
+        return True
+
+
+class arm_op2(arm_arg):
+    parser = shift_off
+
+    def str_to_imm_rot_form(self, s, neg=False):
+        if neg:
+            s = -s & 0xffffffff
+        for i in range(0, 32, 2):
+            v = myrol32(s, i)
+            if 0 <= v < 0x100:
+                return ((i // 2) << 8) | v
+        return None
+
+    def decode(self, v):
+        val = v & self.lmask
+        if self.parent.immop.value:
+            rot = val >> 8
+            imm = val & 0xff
+            imm = myror32(imm, rot * 2)
+            self.expr = ExprInt(imm, 32)
+            return True
+        rm = val & 0xf
+        shift = val >> 4
+        shift_kind = shift & 1
+        shift_type = (shift >> 1) & 3
+        shift >>= 3
+        if shift_kind:
+            # shift kind is reg
+            if shift & 1:
+                return False
+            rs = shift >> 1
+            if rs == 0xf:
+                return False
+            shift_op = regs_expr[rs]
+        else:
+            # shift kind is imm
+            amount = shift
+            shift_op = ExprInt(amount, 32)
+        a = regs_expr[rm]
+        if shift_op == ExprInt(0, 32):
+            #rrx
+            if shift_type == 3:
+                self.expr = ExprOp(allshifts[4], a)
+            #asr, lsr
+            elif shift_type == 1 or shift_type == 2:
+                self.expr = ExprOp(allshifts[shift_type], a, ExprInt(32, 32))
+            else:
+                self.expr = a
+        else:
+            self.expr = ExprOp(allshifts[shift_type], a, shift_op)
+        return True
+
+    def encode(self):
+        e = self.expr
+        # pure imm
+        if isinstance(e, ExprInt):
+            val = self.str_to_imm_rot_form(int(e))
+            if val is None:
+                return False
+            self.parent.immop.value = 1
+            self.value = val
+            return True
+
+        self.parent.immop.value = 0
+        # pure reg
+        if isinstance(e, ExprId):
+            rm = gpregs.expr.index(e)
+            shift_kind = 0
+            shift_type = 0
+            amount = 0
+            self.value = (
+                ((((amount << 2) | shift_type) << 1) | shift_kind) << 4) | rm
+            return True
+        # rot reg
+        if not isinstance(e, ExprOp):
+            log.debug('bad reg rot1 %r', e)
+            return False
+        rm = gpregs.expr.index(e.args[0])
+        shift_type = allshifts.index(e.op)
+        if e.op == 'rrx':
+            shift_kind = 0
+            amount = 0
+            shift_type = 3
+        elif isinstance(e.args[1], ExprInt):
+            shift_kind = 0
+            amount = int(e.args[1])
+            # LSR/ASR of 32 => 0
+            if amount == 32 and e.op in ['>>', 'a>>']:
+                amount = 0
+        else:
+            shift_kind = 1
+            amount = gpregs.expr.index(e.args[1]) << 1
+        self.value = (
+            ((((amount << 2) | shift_type) << 1) | shift_kind) << 4) | rm
+        return True
+
+# op2imm + rn
+
+
+class arm_op2imm(arm_imm8_12):
+    parser = deref
+
+    def str_to_imm_rot_form(self, s, neg=False):
+        if neg:
+            s = -s & 0xffffffff
+        if 0 <= s < (1 << 12):
+            return s
+        return None
+
+    def decode(self, v):
+        val = v & self.lmask
+        if self.parent.immop.value == 0:
+            imm = val
+            if self.parent.updown.value == 0:
+                imm = -imm
+            if self.parent.ppi.value:
+                e = ExprOp('preinc', self.parent.rn.expr, ExprInt(imm, 32))
+            else:
+                e = ExprOp('postinc', self.parent.rn.expr, ExprInt(imm, 32))
+            if self.parent.wback.value == 1:
+                e = ExprOp('wback', e)
+            self.expr = ExprMem(e, 32)
+            return True
+        rm = val & 0xf
+        shift = val >> 4
+        shift_kind = shift & 1
+        shift_type = (shift >> 1) & 3
+        shift >>= 3
+        # print self.parent.immop.value, hex(shift), hex(shift_kind),
+        # hex(shift_type)
+        if shift_kind:
+            # log.debug('error in disasm xx')
+            return False
+        else:
+            # shift kind is imm
+            amount = shift
+            shift_op = ExprInt(amount, 32)
+        a = regs_expr[rm]
+        if shift_op == ExprInt(0, 32):
+            pass
+        else:
+            a = ExprOp(allshifts[shift_type], a, shift_op)
+        if self.parent.ppi.value:
+            e = ExprOp('preinc', self.parent.rn.expr, a)
+        else:
+            e = ExprOp('postinc', self.parent.rn.expr, a)
+        if self.parent.wback.value == 1:
+            e = ExprOp('wback', e)
+        self.expr = ExprMem(e, 32)
+        return True
+
+    def encode(self):
+        self.parent.immop.value = 1
+        self.parent.updown.value = 1
+
+        e = self.expr
+        assert(isinstance(e, ExprMem))
+        e = e.ptr
+        if e.op == 'wback':
+            self.parent.wback.value = 1
+            e = e.args[0]
+        else:
+            self.parent.wback.value = 0
+        if e.op == "postinc":
+            self.parent.ppi.value = 0
+        elif e.op == "preinc":
+            self.parent.ppi.value = 1
+        else:
+            # XXX default
+            self.parent.ppi.value = 1
+
+        # if len(v) <1:
+        #    raise ValueError('cannot parse', s)
+        self.parent.rn.expr = e.args[0]
+        if len(e.args) == 1:
+            self.parent.immop.value = 0
+            self.value = 0
+            return True
+        # pure imm
+        if isinstance(e.args[1], ExprInt):
+            self.parent.immop.value = 0
+            val = self.str_to_imm_rot_form(int(e.args[1]))
+            if val is None:
+                val = self.str_to_imm_rot_form(int(e.args[1]), True)
+                if val is None:
+                    log.debug('cannot encode inm')
+                    return False
+                self.parent.updown.value = 0
+            self.value = val
+            return True
+        # pure reg
+        if isinstance(e.args[1], ExprId):
+            rm = gpregs.expr.index(e.args[1])
+            shift_kind = 0
+            shift_type = 0
+            amount = 0
+            self.value = (
+                ((((amount << 2) | shift_type) << 1) | shift_kind) << 4) | rm
+            return True
+        # rot reg
+        if not isinstance(e.args[1], ExprOp):
+            log.debug('bad reg rot2 %r', e)
+            return False
+        e = e.args[1]
+        rm = gpregs.expr.index(e.args[0])
+        shift_type = allshifts.index(e.op)
+        if isinstance(e.args[1], ExprInt):
+            shift_kind = 0
+            amount = int(e.args[1])
+        else:
+            shift_kind = 1
+            amount = gpregs.expr.index(e.args[1]) << 1
+        self.value = (
+            ((((amount << 2) | shift_type) << 1) | shift_kind) << 4) | rm
+        return True
+
+
+def reglist2str(rlist):
+    out = []
+    i = 0
+    while i < len(rlist):
+        j = i + 1
+        while j < len(rlist) and rlist[j] < 13 and rlist[j] == rlist[j - 1] + 1:
+            j += 1
+        j -= 1
+        if j < i + 2:
+            out.append(regs_str[rlist[i]])
+            i += 1
+        else:
+            out.append(regs_str[rlist[i]] + '-' + regs_str[rlist[j]])
+            i = j + 1
+    return "{" + ", ".join(out) + '}'
+
+def reglist2html(rlist):
+    out = []
+    i = 0
+    while i < len(rlist):
+        j = i + 1
+        while j < len(rlist) and rlist[j] < 13 and rlist[j] == rlist[j - 1] + 1:
+            j += 1
+        j -= 1
+        if j < i + 2:
+            out.append(color_expr_html(regs_expr[rlist[i]], None))
+            i += 1
+        else:
+            out.append(color_expr_html(regs_expr[rlist[i]], None) + '-' + color_expr_html(regs_expr[rlist[j]], None))
+            i = j + 1
+    out = utils.fix_html_chars("{") + ", ".join(out) + utils.fix_html_chars("}")
+    return out
+
+
+class arm_rlist(arm_arg):
+    parser = gpreg_list
+
+    def encode(self):
+        self.parent.sbit.value = 0
+        e = self.expr
+        if isinstance(e, ExprOp) and e.op == "sbit":
+            e = e.args[0]
+            self.parent.sbit.value = 1
+        rlist = [gpregs.expr.index(x) for x in e.args]
+        v = 0
+        for r in rlist:
+            v |= 1 << r
+        self.value = v
+        return True
+
+    def decode(self, v):
+        v = v & self.lmask
+        out = []
+        for i in range(0x10):
+            if 1 << i & v:
+                out.append(gpregs.expr[i])
+        if not out:
+            return False
+        e = ExprOp('reglist', *out)
+        if self.parent.sbit.value == 1:
+            e = ExprOp('sbit', e)
+        self.expr = e
+        return True
+
+
+class updown_b_nosp_mn(bs_mod_name):
+    mn_mod = ['D', 'I']
+
+    def modname(self, name, f_i):
+        return name + self.args['mn_mod'][f_i]
+
+
+class ppi_b_nosp_mn(bs_mod_name):
+    prio = 5
+    mn_mod = ['A', 'B']
+
+
+class updown_b_sp_mn(bs_mod_name):
+    mn_mod = ['A', 'D']
+
+    def modname(self, name, f_i):
+        if name.startswith("STM"):
+            f_i = [1, 0][f_i]
+        return name + self.args['mn_mod'][f_i]
+
+
+class ppi_b_sp_mn(bs_mod_name):
+    mn_mod = ['F', 'E']
+
+    def modname(self, name, f_i):
+        if name.startswith("STM"):
+            f_i = [1, 0][f_i]
+        return name + self.args['mn_mod'][f_i]
+
+
+class arm_reg_wb_nosp(arm_reg_wb):
+
+    def decode(self, v):
+        v = v & self.lmask
+        if v == 13:
+            return False
+        e = self.reg_info.expr[v]
+        if self.parent.wback.value:
+            e = ExprOp('wback', e)
+        self.expr = e
+        return True
+
+
+class arm_offs_blx(arm_imm):
+
+    def decode(self, v):
+        v = v & self.lmask
+        v = (v << 2) + (self.parent.lowb.value << 1)
+        v = sign_ext(v, 26, 32)
+        # Add pipeline offset
+        v += 8
+        self.expr = ExprInt(v, 32)
+        return True
+
+    def encode(self):
+        if not isinstance(self.expr, ExprInt):
+            return False
+        # Remove pipeline offset
+        v = (int(self.expr) - 8) & int(self.expr.mask)
+        if v & 0x80000000:
+            v &= (1 << 26) - 1
+        self.parent.lowb.value = (v >> 1) & 1
+        self.value = v >> 2
+        return True
+
+
+class bs_lnk(bs_mod_name):
+
+    def modname(self, name, i):
+        return name[:1] + self.args['mn_mod'][i] + name[1:]
+
+
+class armt_rm_cp(bsi):
+
+    def decode(self, v):
+        if v != gpregs.expr.index(self.parent.rm.expr):
+            return False
+        return True
+
+    def encode(self):
+        self.value = gpregs.expr.index(self.parent.rm.expr)
+        return True
+
+
+accum = bs(l=1)
+scc = bs_mod_name(l=1, fname='scc', mn_mod=['', 'S'])
+dumscc = bs("1")
+rd = bs(l=4, cls=(arm_gpreg,))
+rdl = bs(l=4, cls=(arm_gpreg,))
+
+rn = bs(l=4, cls=(arm_gpreg,), fname="rn")
+rs = bs(l=4, cls=(arm_gpreg,))
+rm = bs(l=4, cls=(arm_gpreg,), fname='rm')
+ra = bs(l=4, cls=(arm_gpreg,))
+rt = bs(l=4, cls=(arm_gpreg,), fname='rt')
+rt2 = bs(l=4, cls=(arm_gpreg,))
+
+rm_cp = bs(l=4, cls=(armt_rm_cp,))
+
+op2 = bs(l=12, cls=(arm_op2,))
+lnk = bs_lnk(l=1, fname='lnk', mn_mod=['', 'L'])
+offs = bs(l=24, cls=(arm_offs,), fname="offs")
+
+rn_noarg = bs(l=4, cls=(arm_gpreg_noarg,), fname="rn")
+rm_noarg = bs(l=4, cls=(arm_gpreg_noarg,), fname="rm", order = -1)
+
+immop = bs(l=1, fname='immop')
+dumr = bs(l=4, default_val="0000", fname="dumr")
+# psr = bs(l=1, cls=(arm_psr,), fname="psr")
+
+psr = bs(l=1, fname="psr")
+psr_field = bs(l=4, cls=(arm_psr,))
+
+ppi = bs(l=1, fname='ppi')
+updown = bs(l=1, fname='updown')
+trb = bs_mod_name(l=1, fname='trb', mn_mod=['', 'B'])
+wback = bs_mod_name(l=1, fname="wback", mn_mod=['', 'T'])
+wback_no_t = bs(l=1, fname="wback")
+
+op2imm = bs(l=12, cls=(arm_op2imm,))
+
+updown_b_nosp = updown_b_nosp_mn(l=1, mn_mod=['D', 'I'], fname='updown')
+ppi_b_nosp = ppi_b_nosp_mn(l=1, mn_mod=['A', 'B'], fname='ppi')
+updown_b_sp = updown_b_sp_mn(l=1, mn_mod=['A', 'D'], fname='updown')
+ppi_b_sp = ppi_b_sp_mn(l=1, mn_mod=['F', 'E'], fname='ppi')
+
+sbit = bs(l=1, fname="sbit")
+rn_sp = bs("1101", cls=(arm_reg_wb,), fname='rnsp')
+rn_wb = bs(l=4, cls=(arm_reg_wb_nosp,), fname='rn')
+rlist = bs(l=16, cls=(arm_rlist,), fname='rlist')
+
+swi_i = bs(l=24, cls=(arm_imm,), fname="swi_i")
+
+opc = bs(l=4, cls=(arm_imm, m_arg), fname='opc')
+crn = bs(l=4, cls=(arm_cpreg,), fname='crn')
+crd = bs(l=4, cls=(arm_cpreg,), fname='crd')
+crm = bs(l=4, cls=(arm_cpreg,), fname='crm')
+cpnum = bs(l=4, cls=(arm_preg,), fname='cpnum')
+cp = bs(l=3, cls=(arm_imm, m_arg), fname='cp')
+
+imm8_12 = bs(l=8, cls=(arm_imm8_12, m_arg), fname='imm')
+tl = bs_mod_name(l=1, fname="tl", mn_mod=['', 'L'])
+
+cpopc = bs(l=3, cls=(arm_imm, m_arg), fname='cpopc')
+imm20 = bs(l=20, cls=(arm_imm, m_arg))
+imm4 = bs(l=4, cls=(arm_imm, m_arg))
+imm12 = bs(l=12, cls=(arm_imm, m_arg))
+imm16 = bs(l=16, cls=(arm_imm, m_arg))
+
+imm12_off = bs(l=12, fname="imm")
+
+imm2_noarg = bs(l=2, fname="imm")
+imm4_noarg = bs(l=4, fname="imm4")
+
+
+imm_4_12 = bs(l=12, cls=(arm_imm_4_12,))
+
+imm12_noarg = bs(l=12, fname="imm")
+imm_12_4 = bs(l=4, cls=(arm_imm_12_4,))
+
+lowb = bs(l=1, fname='lowb')
+offs_blx = bs(l=24, cls=(arm_offs_blx,), fname="offs")
+
+fix_cond = bs("1111", fname="cond")
+
+class mul_part_x(bs_mod_name):
+    prio = 5
+    mn_mod = ['B', 'T']
+
+class mul_part_y(bs_mod_name):
+    prio = 6
+    mn_mod = ['B', 'T']
+
+mul_x = mul_part_x(l=1, fname='x', mn_mod=['B', 'T'])
+mul_y = mul_part_y(l=1, fname='y', mn_mod=['B', 'T'])
+
+class arm_immed(arm_arg):
+    parser = deref
+
+    def decode(self, v):
+        if self.parent.immop.value == 1:
+            imm = ExprInt((self.parent.immedH.value << 4) | v, 32)
+        else:
+            imm = gpregs.expr[v]
+        if self.parent.updown.value == 0:
+            imm = -imm
+        if self.parent.ppi.value:
+            e = ExprOp('preinc', self.parent.rn.expr, imm)
+        else:
+            e = ExprOp('postinc', self.parent.rn.expr, imm)
+        if self.parent.wback.value == 1:
+            e = ExprOp('wback', e)
+        self.expr = ExprMem(e, 32)
+
+        return True
+
+    def encode(self):
+        self.parent.immop.value = 1
+        self.parent.updown.value = 1
+        e = self.expr
+        if not isinstance(e, ExprMem):
+            return False
+        e = e.ptr
+        if isinstance(e, ExprOp) and e.op == 'wback':
+            self.parent.wback.value = 1
+            e = e.args[0]
+        else:
+            self.parent.wback.value = 0
+        if e.op == "postinc":
+            self.parent.ppi.value = 0
+        elif e.op == "preinc":
+            self.parent.ppi.value = 1
+        else:
+            # XXX default
+            self.parent.ppi.value = 1
+        self.parent.rn.expr = e.args[0]
+        if len(e.args) == 1:
+            self.value = 0
+            self.parent.immedH.value = 0
+            return True
+        e = e.args[1]
+        if isinstance(e, ExprInt):
+            v = int(e)
+            if v < 0 or v & (1 << 31):
+                self.parent.updown.value = 0
+                v = (-v) & 0xFFFFFFFF
+            if v > 0xff:
+                log.debug('cannot encode imm XXX')
+                return False
+            self.value = v & 0xF
+            self.parent.immedH.value = v >> 4
+            return True
+
+        self.parent.immop.value = 0
+        if isinstance(e, ExprOp) and len(e.args) == 1 and e.op == "-":
+            self.parent.updown.value = 0
+            e = e.args[0]
+        if e in gpregs.expr:
+            self.value = gpregs.expr.index(e)
+            self.parent.immedH.value = 0x0
+            return True
+        else:
+            raise ValueError('e should be int: %r' % e)
+
+immedH = bs(l=4, fname='immedH')
+immedL = bs(l=4, cls=(arm_immed, m_arg), fname='immedL')
+hb = bs(l=1)
+
+
+class armt2_rot_rm(arm_arg):
+    parser = shift_off
+    def decode(self, v):
+        r = self.parent.rm.expr
+        if v == 00:
+            e = r
+        else:
+            raise NotImplementedError('rotation')
+        self.expr = e
+        return True
+    def encode(self):
+        e = self.expr
+        if isinstance(e, ExprId):
+            self.value = 0
+        else:
+            raise NotImplementedError('rotation')
+        return True
+
+rot_rm = bs(l=2, cls=(armt2_rot_rm,), fname="rot_rm")
+
+
+class arm_mem_rn_imm(arm_arg):
+    parser = deref
+    def decode(self, v):
+        value = self.parent.imm.value
+        if self.parent.rw.value == 0:
+            value = -value
+        imm = ExprInt(value, 32)
+        reg = gpregs.expr[v]
+        if value:
+            expr = ExprMem(reg + imm, 32)
+        else:
+            expr = ExprMem(reg, 32)
+        self.expr = expr
+        return True
+
+    def encode(self):
+        self.parent.add_imm.value = 1
+        self.parent.imm.value = 0
+        expr = self.expr
+        if not isinstance(expr, ExprMem):
+            return False
+        ptr = expr.ptr
+        if ptr in gpregs.expr:
+            self.value = gpregs.expr.index(ptr)
+        elif (isinstance(ptr, ExprOp) and
+              len(ptr.args) == 2 and
+              ptr.op == 'preinc'):
+            reg, imm = ptr.args
+            if not reg in gpregs.expr:
+                return False
+            self.value = gpregs.expr.index(reg)
+            if not isinstance(imm, ExprInt):
+                return False
+            value = int(imm)
+            if value & 0x80000000:
+                value = -value
+                self.parent.add_imm.value = 0
+            self.parent.imm.value = value
+        else:
+            return False
+        return True
+
+mem_rn_imm = bs(l=4, cls=(arm_mem_rn_imm,), order=1)
+
+def armop(name, fields, args=None, alias=False):
+    dct = {"fields": fields}
+    dct["alias"] = alias
+    if args is not None:
+        dct['args'] = args
+    type(name, (mn_arm,), dct)
+
+
+def armtop(name, fields, args=None, alias=False):
+    dct = {"fields": fields}
+    dct["alias"] = alias
+    if args is not None:
+        dct['args'] = args
+    type(name, (mn_armt,), dct)
+
+
+op_list = ['AND', 'EOR', 'SUB', 'RSB', 'ADD', 'ADC', 'SBC', 'RSC',
+           'TST', 'TEQ', 'CMP', 'CMN', 'ORR', 'MOV', 'BIC', 'MVN']
+data_mov_name = {'MOV': 13, 'MVN': 15}
+data_test_name = {'TST': 8, 'TEQ': 9, 'CMP': 10, 'CMN': 11}
+
+data_name = {}
+for i, n in enumerate(op_list):
+    if n in list(data_mov_name) + list(data_test_name):
+        continue
+    data_name[n] = i
+bs_data_name = bs_name(l=4, name=data_name)
+
+bs_data_mov_name = bs_name(l=4, name=data_mov_name)
+
+bs_data_test_name = bs_name(l=4, name=data_test_name)
+
+
+transfer_name = {'STR': 0, 'LDR': 1}
+bs_transfer_name = bs_name(l=1, name=transfer_name)
+
+transferh_name = {'STRH': 0, 'LDRH': 1}
+bs_transferh_name = bs_name(l=1, name=transferh_name)
+
+
+transfer_ldr_name = {'LDRD': 0, 'LDRSB': 1}
+bs_transfer_ldr_name = bs_name(l=1, name=transfer_ldr_name)
+
+btransfer_name = {'STM': 0, 'LDM': 1}
+bs_btransfer_name = bs_name(l=1, name=btransfer_name)
+
+ctransfer_name = {'STC': 0, 'LDC': 1}
+bs_ctransfer_name = bs_name(l=1, name=ctransfer_name)
+
+mr_name = {'MCR': 0, 'MRC': 1}
+bs_mr_name = bs_name(l=1, name=mr_name)
+
+
+bs_addi = bs(l=1, fname="add_imm")
+bs_rw = bs_mod_name(l=1, fname='rw', mn_mod=['W', ''])
+
+class armt_barrier_option(reg_noarg, arm_arg):
+    reg_info = barrier_info
+    parser = reg_info.parser
+
+    def decode(self, v):
+        v = v & self.lmask
+        if v not in self.reg_info.dct_expr:
+            return False
+        self.expr = self.reg_info.dct_expr[v]
+        return True
+
+    def encode(self):
+        if not self.expr in self.reg_info.dct_expr_inv:
+            log.debug("cannot encode reg %r", self.expr)
+            return False
+        self.value = self.reg_info.dct_expr_inv[self.expr]
+        return True
+
+    def check_fbits(self, v):
+        return v & self.fmask == self.fbits
+
+barrier_option = bs(l=4, cls=(armt_barrier_option,))
+
+armop("mul", [bs('000000'), bs('0'), scc, rd, bs('0000'), rs, bs('1001'), rm], [rd, rm, rs])
+armop("umull", [bs('000010'), bs('0'), scc, rd, rdl, rs, bs('1001'), rm], [rdl, rd, rm, rs])
+armop("umlal", [bs('000010'), bs('1'), scc, rd, rdl, rs, bs('1001'), rm], [rdl, rd, rm, rs])
+armop("smull", [bs('000011'), bs('0'), scc, rd, rdl, rs, bs('1001'), rm], [rdl, rd, rm, rs])
+armop("smlal", [bs('000011'), bs('1'), scc, rd, rdl, rs, bs('1001'), rm], [rdl, rd, rm, rs])
+armop("mla", [bs('000000'), bs('1'), scc, rd, rn, rs, bs('1001'), rm], [rd, rm, rs, rn])
+armop("mrs", [bs('00010'), psr, bs('00'), psr_field, rd, bs('000000000000')], [rd, psr])
+armop("msr", [bs('00010'), psr, bs('10'), psr_field, bs('1111'), bs('0000'), bs('0000'), rm], [psr_field, rm])
+armop("data", [bs('00'), immop, bs_data_name, scc, rn, rd, op2], [rd, rn, op2])
+armop("data_mov", [bs('00'), immop, bs_data_mov_name, scc, bs('0000'), rd, op2], [rd, op2])
+armop("data_test", [bs('00'), immop, bs_data_test_name, dumscc, rn, dumr, op2])
+armop("b", [bs('101'), lnk, offs])
+
+armop("smul", [bs('00010110'), rd, bs('0000'), rs, bs('1'), mul_y, mul_x, bs('0'), rm], [rd, rm, rs])
+
+# TODO TEST
+#armop("und", [bs('011'), imm20, bs('1'), imm4])
+armop("transfer", [bs('01'), immop, ppi, updown, trb, wback_no_t, bs_transfer_name, rn_noarg, rd, op2imm], [rd, op2imm])
+armop("transferh", [bs('000'), ppi, updown, immop, wback_no_t, bs_transferh_name, rn_noarg, rd, immedH, bs('1011'), immedL], [rd, immedL])
+armop("ldrd", [bs('000'), ppi, updown, immop, wback_no_t, bs_transfer_ldr_name, rn_noarg, rd, immedH, bs('1101'), immedL], [rd, immedL])
+armop("ldrsh", [bs('000'),  ppi, updown, immop, wback_no_t, bs('1'), rn_noarg, rd, immedH, bs('1'), bs('1'), bs('1'), bs('1'), immedL], [rd, immedL])
+armop("strd", [bs('000'),  ppi, updown, immop, wback_no_t, bs('0'), rn_noarg, rd, immedH, bs('1'), bs('1'), bs('1'), bs('1'), immedL], [rd, immedL])
+armop("btransfersp", [bs('100'),  ppi_b_sp, updown_b_sp, sbit, wback_no_t, bs_btransfer_name, rn_sp, rlist])
+armop("btransfer", [bs('100'),  ppi_b_nosp, updown_b_nosp, sbit, wback_no_t, bs_btransfer_name, rn_wb, rlist])
+# TODO: TEST
+armop("swp", [bs('00010'), trb, bs('00'), rn, rd, bs('0000'), bs('1001'), rm])
+armop("svc", [bs('1111'), swi_i])
+armop("cdp", [bs('1110'), opc, crn, crd, cpnum, cp, bs('0'), crm], [cpnum, opc, crd, crn, crm, cp])
+armop("cdata", [bs('110'), ppi, updown, tl, wback_no_t, bs_ctransfer_name, rn_noarg, crd, cpnum, imm8_12], [cpnum, crd, imm8_12])
+armop("mr", [bs('1110'), cpopc, bs_mr_name, crn, rd, cpnum, cp, bs('1'), crm], [cpnum, cpopc, rd, crn, crm, cp])
+armop("bkpt", [bs('00010010'), imm12_noarg, bs('0111'), imm_12_4])
+armop("bx", [bs('000100101111111111110001'), rn])
+armop("mov", [bs('00110000'), imm4_noarg, rd, imm_4_12], [rd, imm_4_12])
+armop("movt", [bs('00110100'), imm4_noarg, rd, imm_4_12], [rd, imm_4_12])
+armop("blx", [bs('00010010'), bs('1111'), bs('1111'), bs('1111'), bs('0011'), rm], [rm])
+armop("blx", [fix_cond, bs('101'), lowb, offs_blx], [offs_blx])
+armop("clz", [bs('00010110'), bs('1111'), rd, bs('1111'), bs('0001'), rm], [rd, rm])
+armop("qadd", [bs('00010000'), rn, rd, bs('0000'), bs('0101'), rm], [rd, rm, rn])
+
+armop("uxtb", [bs('01101110'), bs('1111'), rd, rot_rm, bs('00'), bs('0111'), rm_noarg])
+armop("uxth", [bs('01101111'), bs('1111'), rd, rot_rm, bs('00'), bs('0111'), rm_noarg])
+armop("sxtb", [bs('01101010'), bs('1111'), rd, rot_rm, bs('00'), bs('0111'), rm_noarg])
+armop("sxth", [bs('01101011'), bs('1111'), rd, rot_rm, bs('00'), bs('0111'), rm_noarg])
+
+armop("rev", [bs('01101011'), bs('1111'), rd, bs('1111'), bs('0011'), rm])
+armop("rev16", [bs('01101011'), bs('1111'), rd, bs('1111'), bs('1011'), rm])
+
+armop("pld", [bs8(0xF5), bs_addi, bs_rw, bs('01'), mem_rn_imm, bs('1111'), imm12_off])
+
+armop("dsb", [bs('111101010111'), bs('1111'), bs('1111'), bs('0000'), bs('0100'), barrier_option])
+armop("isb", [bs('111101010111'), bs('1111'), bs('1111'), bs('0000'), bs('0110'), barrier_option])
+armop("nop", [bs8(0xE3), bs8(0x20), bs8(0xF0), bs8(0)])
+
+class arm_widthm1(arm_imm, m_arg):
+    def decode(self, v):
+        self.expr = ExprInt(v+1, 32)
+        return True
+
+    def encode(self):
+        if not isinstance(self.expr, ExprInt):
+            return False
+        v = int(self.expr) +  -1
+        self.value = v
+        return True
+
+
+class arm_rm_rot2(arm_arg):
+    parser = rot2_expr
+    def decode(self, v):
+        expr = gpregs.expr[v]
+        shift_value = self.parent.rot2.value
+        if shift_value:
+            expr = ExprOp(allshifts[3], expr, ExprInt(shift_value * 8, 32))
+        self.expr = expr
+        return True
+    def encode(self):
+        if self.expr in gpregs.expr:
+            self.value = gpregs.expr.index(self.expr)
+            self.parent.rot2.value = 0
+        elif (isinstance(self.expr, ExprOp) and
+              self.expr.op == allshifts[3]):
+            reg, value = self.expr.args
+            if reg not in gpregs.expr:
+                return False
+            self.value = gpregs.expr.index(reg)
+            if not isinstance(value, ExprInt):
+                return False
+            value = int(value)
+            if not value in [8, 16, 24]:
+                return False
+            self.parent.rot2.value = value // 8
+        return True
+
+
+
+class arm_rm_rot5_lsl(arm_arg):
+    parser = rot5_expr
+    index_op = 0
+    def decode(self, v):
+        expr = gpregs.expr[v]
+        shift_value = self.parent.rot5.value
+        if shift_value:
+            expr = ExprOp(allshifts[self.index_op], expr, ExprInt(shift_value, 32))
+        self.expr = expr
+        return True
+    def encode(self):
+        if self.expr in gpregs.expr:
+            self.value = gpregs.expr.index(self.expr)
+            self.parent.rot5.value = 0
+        elif (isinstance(self.expr, ExprOp) and
+              self.expr.op == allshifts[self.index_op]):
+            reg, value = self.expr.args
+            if reg not in gpregs.expr:
+                return False
+            self.value = gpregs.expr.index(reg)
+            if not isinstance(value, ExprInt):
+                return False
+            value = int(value)
+            if not 0 <= value < 32:
+                return False
+            self.parent.rot5.value = value
+        return True
+
+class arm_rm_rot5_asr(arm_rm_rot5_lsl):
+    parser = rot5_expr
+    index_op = 2
+    def decode(self, v):
+        expr = gpregs.expr[v]
+        shift_value = self.parent.rot5.value
+        if shift_value == 0:
+            expr = ExprOp(allshifts[self.index_op], expr, ExprInt(32, 32))
+        else:
+            expr = ExprOp(allshifts[self.index_op], expr, ExprInt(shift_value, 32))
+        self.expr = expr
+        return True
+    def encode(self):
+        if (isinstance(self.expr, ExprOp) and
+              self.expr.op == allshifts[self.index_op]):
+            reg, value = self.expr.args
+            if reg not in gpregs.expr:
+                return False
+            self.value = gpregs.expr.index(reg)
+            if not isinstance(value, ExprInt):
+                return False
+            value = int(value)
+            if not 0 < value <= 32:
+                return False
+            if value == 32:
+                value = 0
+            self.parent.rot5.value = value
+        else:
+            return False
+        return True
+
+
+class arm_gpreg_nopc(reg_noarg):
+    reg_info = gpregs_nopc
+    parser = reg_info.parser
+
+
+    def decode(self, v):
+        ret = super(arm_gpreg_nopc, self).decode(v)
+        if ret is False:
+            return False
+        if self.expr == reg_dum:
+            return False
+        return True
+
+
+class arm_gpreg_nosp(reg_noarg):
+    reg_info = gpregs_nosp
+    parser = reg_info.parser
+
+    def decode(self, v):
+        ret = super(arm_gpreg_nosp, self).decode(v)
+        if ret is False:
+            return False
+        if self.expr == reg_dum:
+            return False
+        return True
+
+
+rm_rot2 = bs(l=4, cls=(arm_rm_rot2,), fname="rm")
+rot2 = bs(l=2, fname="rot2")
+
+rm_rot5_lsl = bs(l=4, cls=(arm_rm_rot5_lsl,), fname="rm")
+rm_rot5_asr = bs(l=4, cls=(arm_rm_rot5_asr,), fname="rm")
+rot5 = bs(l=5, fname="rot5")
+
+widthm1 = bs(l=5, cls=(arm_widthm1, m_arg))
+lsb = bs(l=5, cls=(arm_imm, m_arg))
+
+rd_nopc = bs(l=4, cls=(arm_gpreg_nopc, arm_arg), fname="rd")
+rn_nopc = bs(l=4, cls=(arm_gpreg_nopc, arm_arg), fname="rn")
+ra_nopc = bs(l=4, cls=(arm_gpreg_nopc, arm_arg), fname="ra")
+rt_nopc = bs(l=4, cls=(arm_gpreg_nopc, arm_arg), fname="rt")
+
+rn_nosp = bs(l=4, cls=(arm_gpreg_nosp, arm_arg), fname="rn")
+
+rn_nopc_noarg = bs(l=4, cls=(arm_gpreg_nopc,), fname="rn")
+
+armop("ubfx", [bs('0111111'), widthm1, rd, lsb, bs('101'), rn], [rd, rn, lsb, widthm1])
+
+armop("bfc", [bs('0111110'), widthm1, rd, lsb, bs('001'), bs('1111')], [rd, lsb, widthm1])
+
+armop("uxtab", [bs('01101110'), rn_nopc, rd, rot2, bs('000111'), rm_rot2], [rd, rn_nopc, rm_rot2])
+
+armop("pkhbt", [bs('01101000'), rn, rd, rot5, bs('001'), rm_rot5_lsl], [rd, rn, rm_rot5_lsl])
+armop("pkhtb", [bs('01101000'), rn, rd, rot5, bs('101'), rm_rot5_asr], [rd, rn, rm_rot5_asr])
+
+
+
+#
+# thumnb #######################
+#
+# ARM7-TDMI-manual-pt3
+gpregs_l = reg_info(regs_str[:8], regs_expr[:8])
+gpregs_h = reg_info(regs_str[8:], regs_expr[8:])
+
+gpregs_sppc = reg_info(regs_str[-1:] + regs_str[13:14],
+                       regs_expr[-1:] + regs_expr[13:14])
+
+deref_reg_imm = Group(LBRACK + gpregs.parser + Optional(
+    COMMA + shift_off) + RBRACK).setParseAction(cb_deref_pre_mem)
+deref_low = Group(LBRACK + gpregs_l.parser + Optional(
+    COMMA + shift_off) + RBRACK).setParseAction(cb_deref_pre_mem)
+deref_pc = Group(LBRACK + gpregs_pc.parser + Optional(
+    COMMA + shift_off) + RBRACK).setParseAction(cb_deref_pre_mem)
+deref_sp = Group(LBRACK + gpregs_sp.parser + COMMA +
+                 shift_off + RBRACK).setParseAction(cb_deref_pre_mem)
+
+gpregs_l_wb = Group(
+    gpregs_l.parser + Optional('!')).setParseAction(cb_gpreb_wb)
+
+
+gpregs_l_13 = reg_info(regs_str[:13], regs_expr[:13])
+
+
+class arm_offreg(arm_arg):
+    parser = deref_pc
+
+    def decodeval(self, v):
+        return v
+
+    def encodeval(self, v):
+        return v
+
+    def decode(self, v):
+        v = v & self.lmask
+        v = self.decodeval(v)
+        if v:
+            self.expr = self.off_reg + ExprInt(v, 32)
+        else:
+            self.expr = self.off_reg
+
+        e = self.expr
+        if isinstance(e, ExprOp) and e.op == 'wback':
+            self.parent.wback.value = 1
+            e = e.args[0]
+        return True
+
+    def encode(self):
+        e = self.expr
+        if not (isinstance(e, ExprOp) and e.op == "preinc"):
+            log.debug('cannot encode %r', e)
+            return False
+        if e.args[0] != self.off_reg:
+            log.debug('cannot encode reg %r', e.args[0])
+            return False
+        v = int(e.args[1])
+        v = self.encodeval(v)
+        self.value = v
+        return True
+
+
+class arm_offpc(arm_offreg):
+    off_reg = regs_expr[15]
+
+    def decode(self, v):
+        v = v & self.lmask
+        v <<= 2
+        if v:
+            self.expr = ExprMem(self.off_reg + ExprInt(v, 32), 32)
+        else:
+            self.expr = ExprMem(self.off_reg, 32)
+
+        e = self.expr.ptr
+        if isinstance(e, ExprOp) and e.op == 'wback':
+            self.parent.wback.value = 1
+            e = e.args[0]
+        return True
+
+    def encode(self):
+        e = self.expr
+        if not isinstance(e, ExprMem):
+            return False
+        e = e.ptr
+        if not (isinstance(e, ExprOp) and e.op == "preinc"):
+            log.debug('cannot encode %r', e)
+            return False
+        if e.args[0] != self.off_reg:
+            log.debug('cannot encode reg %r', e.args[0])
+            return False
+        v = int(e.args[1])
+        if v & 3:
+            return False
+        v >>= 2
+        self.value = v
+        return True
+
+
+
+
+class arm_offsp(arm_offpc):
+    parser = deref_sp
+    off_reg = regs_expr[13]
+
+
+class arm_offspc(arm_offs):
+
+    def decodeval(self, v):
+        v = v << 1
+        # Add pipeline offset
+        v += 2 + 2
+        return v
+
+    def encodeval(self, v):
+        # Remove pipeline offset
+        v -= 2 + 2
+        if v % 2 != 0:
+            return False
+        if v > (1 << (self.l - 1)) - 1:
+            return False
+        return v >> 1
+
+
+class arm_off8sppc(arm_imm):
+
+    def decodeval(self, v):
+        return v << 2
+
+    def encodeval(self, v):
+        return v >> 2
+
+
+class arm_off7(arm_imm):
+
+    def decodeval(self, v):
+        return v << 2
+
+    def encodeval(self, v):
+        return v >> 2
+
+class arm_deref_reg_imm(arm_arg):
+    parser = deref_reg_imm
+
+    def decode(self, v):
+        v = v & self.lmask
+        rbase = regs_expr[v]
+        e = ExprOp('preinc', rbase, self.parent.off.expr)
+        self.expr = ExprMem(e, 32)
+        return True
+
+    def encode(self):
+        self.parent.off.expr = None
+        e = self.expr
+        if not isinstance(e, ExprMem):
+            return False
+        e = e.ptr
+        if not (isinstance(e, ExprOp) and e.op == 'preinc'):
+            log.debug('cannot encode %r', e)
+            return False
+        off = e.args[1]
+        if isinstance(off, ExprId):
+            self.parent.off.expr = off
+        elif isinstance(off, ExprInt):
+            self.parent.off.expr = off
+        else:
+            log.debug('cannot encode off %r', off)
+            return False
+        self.value = gpregs.expr.index(e.args[0])
+        if self.value >= 1 << self.l:
+            log.debug('cannot encode reg %r', off)
+            return False
+        return True
+
+class arm_derefl(arm_deref_reg_imm):
+    parser = deref_low
+
+
+class arm_offbw(imm_noarg):
+
+    def decode(self, v):
+        v = v & self.lmask
+        if self.parent.trb.value == 0:
+            v <<= 2
+        self.expr = ExprInt(v, 32)
+        return True
+
+    def encode(self):
+        if not isinstance(self.expr, ExprInt):
+            return False
+        v = int(self.expr)
+        if self.parent.trb.value == 0:
+            if v & 3:
+                log.debug('off must be aligned %r', v)
+                return False
+            v >>= 2
+        self.value = v
+        return True
+
+
+
+class arm_off(imm_noarg):
+
+    def decode(self, v):
+        v = v & self.lmask
+        self.expr = ExprInt(v, 32)
+        return True
+
+    def encode(self):
+        if not isinstance(self.expr, ExprInt):
+            return False
+        v = int(self.expr)
+        self.value = v
+        return True
+
+
+class arm_offh(imm_noarg):
+
+    def decode(self, v):
+        v = v & self.lmask
+        v <<= 1
+        self.expr = ExprInt(v, 32)
+        return True
+
+    def encode(self):
+        if not isinstance(self.expr, ExprInt):
+            return False
+        v = int(self.expr)
+        if v & 1:
+            log.debug('off must be aligned %r', v)
+            return False
+        v >>= 1
+        self.value = v
+        return True
+
+
+class armt_rlist(arm_arg):
+    parser = gpreg_list
+
+    def encode(self):
+        e = self.expr
+        rlist = [gpregs_l.expr.index(x) for x in e.args]
+        v = 0
+        for r in rlist:
+            v |= 1 << r
+        self.value = v
+        return True
+
+    def decode(self, v):
+        v = v & self.lmask
+        out = []
+        for i in range(0x10):
+            if 1 << i & v:
+                out.append(gpregs.expr[i])
+        if not out:
+            return False
+        e = ExprOp('reglist', *out)
+        self.expr = e
+        return True
+
+
+class armt_rlist13(armt_rlist):
+    parser = gpreg_list
+
+    def encode(self):
+        e = self.expr
+        rlist = []
+        reg_l = list(e.args)
+
+        self.parent.pclr.value = 0
+        if self.parent.name.startswith('PUSH'):
+            if regs_expr[14] in reg_l:
+                reg_l.remove(regs_expr[14])
+                self.parent.pclr.value = 1
+        else:
+            if regs_expr[15] in reg_l:
+                reg_l.remove(regs_expr[15])
+                self.parent.pclr.value = 1
+
+        for reg in reg_l:
+            if reg not in gpregs_l_13.expr:
+                return False
+            rlist.append(gpregs_l_13.expr.index(reg))
+        v = 0
+        for r in rlist:
+            v |= 1 << r
+        self.value = v
+        return True
+
+    def decode(self, v):
+        v = v & self.lmask
+        out = []
+        for i in range(13):
+            if 1 << i & v:
+                out.append(gpregs_l_13.expr[i])
+
+        if self.parent.pclr.value == 1:
+            if self.parent.name.startswith("PUSH"):
+                out += [regs_expr[14]]
+            else:
+                out += [regs_expr[15]]
+
+        if not out:
+            return False
+        e = ExprOp('reglist', *out)
+        self.expr = e
+        return True
+
+
+
+class armt_rlist13_pc_lr(armt_rlist):
+    parser = gpreg_list
+
+    def encode(self):
+        e = self.expr
+        rlist = []
+        reg_l = list(e.args)
+
+        self.parent.pc_in.value = 0
+        self.parent.lr_in.value = 0
+        if regs_expr[14] in reg_l:
+            reg_l.remove(regs_expr[14])
+            self.parent.lr_in.value = 1
+        if regs_expr[15] in reg_l:
+            reg_l.remove(regs_expr[15])
+            self.parent.pc_in.value = 1
+
+        for reg in reg_l:
+            if reg not in gpregs_l_13.expr:
+                return False
+            rlist.append(gpregs_l_13.expr.index(reg))
+        v = 0
+        for r in rlist:
+            v |= 1 << r
+        self.value = v
+        return True
+
+    def decode(self, v):
+        v = v & self.lmask
+        out = []
+        for i in range(13):
+            if 1 << i & v:
+                out.append(gpregs_l_13.expr[i])
+
+        if self.parent.lr_in.value == 1:
+            out += [regs_expr[14]]
+        if self.parent.pc_in.value == 1:
+            out += [regs_expr[15]]
+
+        if not out:
+            return False
+        e = ExprOp('reglist', *out)
+        self.expr = e
+        return True
+
+
+
+class armt_rlist_pclr(armt_rlist):
+
+    def encode(self):
+        e = self.expr
+        reg_l = list(e.args)
+        self.parent.pclr.value = 0
+        if self.parent.pp.value == 0:
+            if regs_expr[14] in reg_l:
+                reg_l.remove(regs_expr[14])
+                self.parent.pclr.value = 1
+        else:
+            if regs_expr[15] in reg_l:
+                reg_l.remove(regs_expr[15])
+                self.parent.pclr.value = 1
+        rlist = [gpregs.expr.index(x) for x in reg_l]
+        v = 0
+        for r in rlist:
+            v |= 1 << r
+        self.value = v
+        return True
+
+    def decode(self, v):
+        v = v & self.lmask
+        out = []
+        for i in range(0x10):
+            if 1 << i & v:
+                out.append(gpregs.expr[i])
+
+        if self.parent.pclr.value == 1:
+            if self.parent.pp.value == 0:
+                out += [regs_expr[14]]
+            else:
+                out += [regs_expr[15]]
+        if not out:
+            return False
+        e = ExprOp('reglist', *out)
+        self.expr = e
+        return True
+
+
+class armt_reg_wb(arm_reg_wb):
+    reg_info = gpregs_l
+    parser = gpregs_l_wb
+
+    def decode(self, v):
+        v = v & self.lmask
+        e = self.reg_info.expr[v]
+        if not e in self.parent.trlist.expr.args:
+            e = ExprOp('wback', e)
+        self.expr = e
+        return True
+
+    def encode(self):
+        e = self.expr
+        if isinstance(e, ExprOp):
+            if e.op != 'wback':
+                return False
+            e = e.args[0]
+        self.value = self.reg_info.expr.index(e)
+        return True
+
+
+class arm_gpreg_l(arm_reg):
+    reg_info = gpregs_l
+    parser = reg_info.parser
+
+
+class arm_gpreg_h(arm_reg):
+    reg_info = gpregs_h
+    parser = reg_info.parser
+
+
+class arm_gpreg_l_noarg(arm_gpreg_noarg):
+    reg_info = gpregs_l
+    parser = reg_info.parser
+
+
+class arm_sppc(arm_reg):
+    reg_info = gpregs_sppc
+    parser = reg_info.parser
+
+
+class arm_sp(arm_reg):
+    reg_info = gpregs_sp
+    parser = reg_info.parser
+
+off5 = bs(l=5, cls=(arm_imm,), fname="off")
+off3 = bs(l=3, cls=(arm_imm,), fname="off")
+off8 = bs(l=8, cls=(arm_imm,), fname="off")
+off7 = bs(l=7, cls=(arm_off7,), fname="off")
+
+rdl = bs(l=3, cls=(arm_gpreg_l,), fname="rd")
+rnl = bs(l=3, cls=(arm_gpreg_l,), fname="rn")
+rsl = bs(l=3, cls=(arm_gpreg_l,), fname="rs")
+rml = bs(l=3, cls=(arm_gpreg_l,), fname="rm")
+rol = bs(l=3, cls=(arm_gpreg_l,), fname="ro")
+rbl = bs(l=3, cls=(arm_gpreg_l,), fname="rb")
+rbl_deref = bs(l=3, cls=(arm_derefl,), fname="rb")
+dumrh = bs(l=3, default_val="000")
+
+rdh = bs(l=3, cls=(arm_gpreg_h,), fname="rd")
+rsh = bs(l=3, cls=(arm_gpreg_h,), fname="rs")
+
+offpc8 = bs(l=8, cls=(arm_offpc,), fname="offs")
+offsp8 = bs(l=8, cls=(arm_offsp,), fname="offs")
+rol_noarg = bs(l=3, cls=(arm_gpreg_l_noarg,), fname="off")
+
+off5bw = bs(l=5, cls=(arm_offbw,), fname="off")
+off5h = bs(l=5, cls=(arm_offh,), fname="off")
+sppc = bs(l=1, cls=(arm_sppc,))
+
+off12 = bs(l=12, cls=(arm_off,), fname="off", order=-1)
+rn_deref = bs(l=4, cls=(arm_deref_reg_imm,), fname="rt")
+
+
+
+pclr = bs(l=1, fname='pclr', order=-2)
+
+
+pc_in = bs(l=1, fname='pc_in', order=-2)
+lr_in = bs(l=1, fname='lr_in', order=-2)
+
+
+sp = bs(l=0, cls=(arm_sp,))
+
+
+off8s = bs(l=8, cls=(arm_offs,), fname="offs")
+trlistpclr = bs(l=8, cls=(armt_rlist_pclr,))
+trlist = bs(l=8, cls=(armt_rlist,), fname="trlist", order = -1)
+trlist13 = bs(l=13, cls=(armt_rlist13,), fname="trlist", order = -1)
+trlist13pclr = bs(l=13, cls=(armt_rlist13_pc_lr,), fname="trlist", order = -1)
+
+
+rbl_wb = bs(l=3, cls=(armt_reg_wb,), fname='rb')
+
+offs8 = bs(l=8, cls=(arm_offspc,), fname="offs")
+offs11 = bs(l=11, cls=(arm_offspc,), fname="offs")
+
+hl = bs(l=1, prio=default_prio + 1, fname='hl')
+off8sppc = bs(l=8, cls=(arm_off8sppc,), fname="off")
+
+imm8_d1 = bs(l=8, default_val="00000001")
+imm8 = bs(l=8, cls=(arm_imm,), default_val = "00000001")
+
+
+mshift_name = {'LSLS': 0, 'LSRS': 1, 'ASRS': 2}
+bs_mshift_name = bs_name(l=2, name=mshift_name)
+
+
+addsub_name = {'ADDS': 0, 'SUBS': 1}
+bs_addsub_name = bs_name(l=1, name=addsub_name)
+
+mov_cmp_add_sub_name = {'MOVS': 0, 'CMP': 1, 'ADDS': 2, 'SUBS': 3}
+bs_mov_cmp_add_sub_name = bs_name(l=2, name=mov_cmp_add_sub_name)
+
+alu_name = {'ANDS': 0, 'EORS': 1, 'LSLS': 2, 'LSRS': 3,
+            'ASRS': 4, 'ADCS': 5, 'SBCS': 6, 'RORS': 7,
+            'TST': 8, 'NEGS': 9, 'CMP': 10, 'CMN': 11,
+            'ORRS': 12, 'MULS': 13, 'BICS': 14, 'MVNS': 15}
+bs_alu_name = bs_name(l=4, name=alu_name)
+
+hiregop_name = {'ADDS': 0, 'CMP': 1, 'MOV': 2}
+bs_hiregop_name = bs_name(l=2, name=hiregop_name)
+
+ldr_str_name = {'STR': 0, 'LDR': 1}
+bs_ldr_str_name = bs_name(l=1, name=ldr_str_name)
+
+ldrh_strh_name = {'STRH': 0, 'LDRH': 1}
+bs_ldrh_strh_name = bs_name(l=1, name=ldrh_strh_name)
+
+ldstsp_name = {'STR': 0, 'LDR': 1}
+bs_ldstsp_name = bs_name(l=1, name=ldstsp_name)
+
+addsubsp_name = {'ADD': 0, 'SUB': 1}
+bs_addsubsp_name = bs_name(l=1, name=addsubsp_name)
+
+pushpop_name = {'PUSH': 0, 'POP': 1}
+bs_pushpop_name = bs_name(l=1, name=pushpop_name, fname='pp')
+
+tbtransfer_name = {'STMIA': 0, 'LDMIA': 1}
+bs_tbtransfer_name = bs_name(l=1, name=tbtransfer_name)
+
+br_name = {'BEQ': 0, 'BNE': 1, 'BCS': 2, 'BCC': 3, 'BMI': 4,
+           'BPL': 5, 'BVS': 6, 'BVC': 7, 'BHI': 8, 'BLS': 9,
+           'BGE': 10, 'BLT': 11, 'BGT': 12, 'BLE': 13}
+bs_br_name = bs_name(l=4, name=br_name)
+
+
+armtop("mshift", [bs('000'), bs_mshift_name, off5, rsl, rdl], [rdl, rsl, off5])
+armtop("addsubr", [bs('000110'),  bs_addsub_name, rnl, rsl, rdl], [rdl, rsl, rnl])
+armtop("addsubi", [bs('000111'),  bs_addsub_name, off3, rsl, rdl], [rdl, rsl, off3])
+armtop("mcas", [bs('001'), bs_mov_cmp_add_sub_name, rnl, off8])
+armtop("alu", [bs('010000'), bs_alu_name, rsl, rdl], [rdl, rsl])
+  # should not be used ??
+armtop("hiregop00", [bs('010001'), bs_hiregop_name, bs('00'), rsl, rdl], [rdl, rsl])
+armtop("hiregop01", [bs('010001'), bs_hiregop_name, bs('01'), rsh, rdl], [rdl, rsh])
+armtop("hiregop10", [bs('010001'), bs_hiregop_name, bs('10'), rsl, rdh], [rdh, rsl])
+armtop("hiregop11", [bs('010001'), bs_hiregop_name, bs('11'), rsh, rdh], [rdh, rsh])
+armtop("bx", [bs('010001'), bs('11'), bs('00'), rsl, dumrh])
+armtop("bx", [bs('010001'), bs('11'), bs('01'), rsh, dumrh])
+armtop("ldr", [bs('01001'),  rdl, offpc8])
+armtop("ldrstr", [bs('0101'), bs_ldr_str_name, trb, bs('0'), rol_noarg, rbl_deref, rdl], [rdl, rbl_deref])
+armtop("strh", [bs('0101'), bs('00'), bs('1'), rol_noarg, rbl_deref, rdl], [rdl, rbl_deref])
+armtop("ldrh", [bs('0101'), bs('10'), bs('1'), rol_noarg, rbl_deref, rdl], [rdl, rbl_deref])
+armtop("ldsb", [bs('0101'), bs('01'), bs('1'), rol_noarg, rbl_deref, rdl], [rdl, rbl_deref])
+armtop("ldsh", [bs('0101'), bs('11'), bs('1'), rol_noarg, rbl_deref, rdl], [rdl, rbl_deref])
+armtop("ldst", [bs('011'), trb, bs_ldr_str_name, off5bw, rbl_deref, rdl], [rdl, rbl_deref])
+armtop("ldhsth", [bs('1000'), bs_ldrh_strh_name, off5h, rbl_deref, rdl], [rdl, rbl_deref])
+armtop("ldstsp", [bs('1001'), bs_ldstsp_name, rdl, offsp8], [rdl, offsp8])
+armtop("add", [bs('1010'), sppc, rdl, off8sppc], [rdl, sppc, off8sppc])
+armtop("addsp", [bs('10110000'), bs_addsubsp_name, sp, off7], [sp, off7])
+armtop("pushpop", [bs('1011'), bs_pushpop_name, bs('10'), pclr, trlistpclr], [trlistpclr])
+armtop("btransfersp", [bs('1100'),  bs_tbtransfer_name, rbl_wb, trlist])
+armtop("br", [bs('1101'),  bs_br_name, offs8])
+armtop("blx", [bs("01000111"),  bs('1'), rm, bs('000')])
+armtop("svc", [bs('11011111'),  imm8])
+armtop("b", [bs('11100'),  offs11])
+armtop("und", [bs('1101'), bs('1110'), imm8_d1])
+
+armtop("rev",    [bs('10111010'), bs('00'), rsl, rdl], [rdl, rsl])
+armtop("rev16",  [bs('10111010'), bs('01'), rsl, rdl], [rdl, rsl])
+
+armtop("uxtb", [bs('10110010'), bs('11'), rml, rdl], [rdl, rml])
+armtop("uxth", [bs('10110010'), bs('10'), rml, rdl], [rdl, rml])
+armtop("sxtb", [bs('10110010'), bs('01'), rml, rdl], [rdl, rml])
+armtop("sxth", [bs('10110010'), bs('00'), rml, rdl], [rdl, rml])
+
+armtop("uxtab", [bs('111110100'), bs('101'), rn_nopc, bs('1111'), rd, bs('10'), rot2, rm_rot2], [rd, rn_nopc, rm_rot2])
+armtop("uxtah", [bs('111110100'), bs('001'), rn_nopc, bs('1111'), rd, bs('10'), rot2, rm_rot2], [rd, rn_nopc, rm_rot2])
+
+# thumb2 ######################
+#
+# ARM Architecture Reference Manual Thumb-2 Supplement
+
+armt_gpreg_shift_off = (gpregs_nosppc.parser + allshifts_t_armt + (gpregs.parser | int_1_31)).setParseAction(cb_shift)
+
+
+armt_gpreg_shift_off |= gpregs_nosppc.parser
+
+
+class arm_gpreg_nosppc(arm_reg):
+    reg_info = gpregs_nosppc
+    parser = reg_info.parser
+
+    def decode(self, v):
+        ret = super(arm_gpreg_nosppc, self).decode(v)
+        if ret is False:
+            return False
+        if self.expr == reg_dum:
+            return False
+        return True
+
+
+class armt_gpreg_rm_shift_off(arm_reg):
+    parser = armt_gpreg_shift_off
+
+    def decode(self, v):
+        v = v & self.lmask
+        if v >= len(gpregs_nosppc.expr):
+            return False
+        r = gpregs_nosppc.expr[v]
+        if r == reg_dum:
+            return False
+
+        i = int(self.parent.imm5_3.value) << 2
+        i |= int(self.parent.imm5_2.value)
+
+        if self.parent.stype.value < 3 or i != 0:
+            shift = allshifts_armt[self.parent.stype.value]
+        else:
+            shift = allshifts_armt[4]
+        self.expr = ExprOp(shift, r, ExprInt(i, 32))
+        return True
+
+    def encode(self):
+        e = self.expr
+        if isinstance(e, ExprId):
+            if e not in gpregs_nosppc.expr:
+                return False
+            self.value = gpregs_nosppc.expr.index(e)
+            self.parent.stype.value = 0
+            self.parent.imm5_3.value = 0
+            self.parent.imm5_2.value = 0
+            return True
+        if not e.is_op():
+            return False
+        shift = e.op
+        r = gpregs_nosppc.expr.index(e.args[0])
+        self.value = r
+        i = int(e.args[1])
+        if shift == 'rrx':
+            if i != 1:
+                log.debug('rrx shift must be 1')
+                return False
+            self.parent.imm5_3.value = 0
+            self.parent.imm5_2.value = 0
+            self.parent.stype.value = 3
+            return True
+        self.parent.stype.value = allshifts_armt.index(shift)
+        self.parent.imm5_2.value = i & 3
+        self.parent.imm5_3.value = i >> 2
+        return True
+
+rn_nosppc = bs(l=4, cls=(arm_gpreg_nosppc,), fname="rn")
+rd_nosppc = bs(l=4, cls=(arm_gpreg_nosppc,), fname="rd")
+rm_sh = bs(l=4, cls=(armt_gpreg_rm_shift_off,), fname="rm")
+
+
+class armt2_imm12(arm_imm):
+
+    def decode(self, v):
+        v = v & self.lmask
+        v |= int(self.parent.imm12_3.value) << 8
+        v |= int(self.parent.imm12_1.value) << 11
+
+        # simple encoding
+        if 0 <= v < 0x100:
+            self.expr = ExprInt(v, 32)
+            return True
+        # 00XY00XY form
+        if v >> 8 == 1:
+            v &= 0xFF
+            self.expr = ExprInt((v << 16) | v, 32)
+            return True
+        # XY00XY00 form
+        if v >> 8 == 2:
+            v &= 0xFF
+            self.expr = ExprInt((v << 24) | (v << 8), 32)
+            return True
+        # XYXYXYXY
+        if v >> 8 == 3:
+            v &= 0xFF
+            self.expr = ExprInt((v << 24) | (v << 16) | (v << 8) | v, 32)
+            return True
+        r = v >> 7
+        v = 0x80 | (v & 0x7F)
+        self.expr = ExprInt(myror32(v, r), 32)
+        return True
+
+    def encode(self):
+        if not self.expr.is_int():
+            return False
+        v = int(self.expr)
+        value = None
+        # simple encoding
+        if 0 <= v < 0x100:
+            value = v
+        elif v & 0xFF00FF00 == 0 and v & 0xFF == (v >> 16) & 0xff:
+            # 00XY00XY form
+            value = (1 << 8) | (v & 0xFF)
+        elif v & 0x00FF00FF == 0 and (v >> 8) & 0xff == (v >> 24) & 0xff:
+            # XY00XY00 form
+            value = (2 << 8) | ((v >> 8) & 0xff)
+        elif (v & 0xFF ==
+             (v >> 8)  & 0xFF ==
+             (v >> 16) & 0xFF ==
+             (v >> 24) & 0xFF):
+            # XYXYXYXY form
+            value = (3 << 8) | ((v >> 16) & 0xff)
+        else:
+            # rol encoding
+            for i in range(32):
+                o = myrol32(v, i)
+                if 0x80 <= o <= 0xFF:
+                    value = (i << 7) | (o & 0x7F)
+                    break
+        if value is None:
+            log.debug('cannot encode imm12')
+            return False
+        self.value = value & self.lmask
+        self.parent.imm12_3.value = (value >> 8) & self.parent.imm12_3.lmask
+        self.parent.imm12_1.value = (value >> 11) & self.parent.imm12_1.lmask
+        return True
+
+
+
+
+class armt4_imm12(arm_imm):
+
+    def decode(self, v):
+        v = v & self.lmask
+        v |= int(self.parent.imm12_3.value) << 8
+        v |= int(self.parent.imm12_1.value) << 11
+        self.expr = ExprInt(v, 32)
+        return True
+
+    def encode(self):
+        if not self.expr.is_int():
+            return False
+        value = int(self.expr)
+        if value >= (1 << 16):
+            return False
+        self.value = value & self.lmask
+        self.parent.imm12_3.value = (value >> 8) & self.parent.imm12_3.lmask
+        self.parent.imm12_1.value = (value >> 11) & self.parent.imm12_1.lmask
+        return True
+
+
+
+class armt2_imm16(arm_imm):
+
+    def decode(self, v):
+        v = v & self.lmask
+        v |= int(self.parent.imm16_3.value) << 8
+        v |= int(self.parent.imm16_1.value) << 11
+        v |= int(self.parent.imm16_4.value) << 12
+        self.expr = ExprInt(v, 32)
+        return True
+
+    def encode(self):
+        if not self.expr.is_int():
+            return False
+        value = int(self.expr)
+        if value >= (1 << 16):
+            return False
+        self.value = value & self.lmask
+        self.parent.imm16_3.value = (value >> 8) & self.parent.imm16_3.lmask
+        self.parent.imm16_1.value = (value >> 11) & self.parent.imm16_1.lmask
+        self.parent.imm16_4.value = (value >> 12) & self.parent.imm16_4.lmask
+        return True
+
+
+class armt2_lsb5(arm_imm):
+
+    def decode(self, v):
+        v = v & self.lmask
+        v |= int(self.parent.lsb5_3.value) << 2
+        self.expr = ExprInt(v, 32)
+        return True
+
+    def encode(self):
+        if not self.expr.is_int():
+            return False
+        value = int(self.expr)
+        self.value = value & self.lmask
+        self.parent.lsb5_3.value = (value >> 2) & self.parent.lsb5_3.lmask
+        return True
+
+
+class armt_widthm1(arm_imm):
+    parser = base_expr
+
+    def decodeval(self, v):
+        return v + 1
+
+    def encodeval(self, v):
+        if v <= 0:
+            return False
+        return v - 1
+
+
+
+
+class armt2_off20(arm_imm):
+
+    def decode(self, v):
+        v = v & self.lmask
+        v <<= 1
+        v |= int(self.parent.off20_6.value) << 12
+        v |= int(self.parent.off20_j1.value) << 18
+        v |= int(self.parent.off20_j2.value) << 19
+        v |= int(self.parent.off20_s.value) << 20
+        self.expr = ExprInt(v, 32)
+        return True
+
+    def encode(self):
+        if not self.expr.is_int():
+            return False
+        value = int(self.expr)
+        if value & 1:
+            return False
+        self.value = (value >> 1) & self.lmask
+        self.parent.off20_6.value = (value >> 12) & self.parent.off20_6.lmask
+        self.parent.off20_j1.value = (value >> 18) & self.parent.off20_j1.lmask
+        self.parent.off20_j2.value = (value >> 19) & self.parent.off20_j2.lmask
+        self.parent.off20_s.value = (value >> 20) & self.parent.off20_s.lmask
+        return True
+
+
+
+class armt2_imm10l(arm_imm):
+
+    def decode(self, v):
+        v = v & self.lmask
+        s = self.parent.sign.value
+        j1 = self.parent.j1.value
+        j2 = self.parent.j2.value
+        imm10h = self.parent.imm10h.value
+        imm10l = v
+
+        i1, i2 = j1 ^ s ^ 1, j2 ^ s ^ 1
+
+        v = (s << 24) | (i1 << 23) | (i2 << 22) | (imm10h << 12) | (imm10l << 2)
+        v = sign_ext(v, 25, 32)
+        self.expr = ExprInt(v, 32)
+        return True
+
+    def encode(self):
+        if not isinstance(self.expr, ExprInt):
+            return False
+        v = int(self.expr)
+        s = 0
+        if v & 0x80000000:
+            s = 1
+            v &= (1<<26) - 1
+        if v >= (1 << 26):
+            return False
+        i1, i2, imm10h, imm10l = (v >> 23) & 1, (v >> 22) & 1, (v >> 12) & 0x3ff, (v >> 2) & 0x3ff
+        j1, j2 = i1 ^ s ^ 1, i2 ^ s ^ 1
+        self.parent.sign.value = s
+        self.parent.j1.value = j1
+        self.parent.j2.value = j2
+        self.parent.imm10h.value = imm10h
+        self.value = imm10l
+        return True
+
+
+class armt2_imm11l(arm_imm):
+
+    def decode(self, v):
+        v = v & self.lmask
+        s = self.parent.sign.value
+        j1 = self.parent.j1.value
+        j2 = self.parent.j2.value
+        imm10h = self.parent.imm10h.value
+        imm11l = v
+
+        i1, i2 = j1 ^ s ^ 1, j2 ^ s ^ 1
+
+        v = (s << 24) | (i1 << 23) | (i2 << 22) | (imm10h << 12) | (imm11l << 1)
+        v = sign_ext(v, 25, 32)
+        self.expr = ExprInt(v + 4, 32)
+        return True
+
+    def encode(self):
+        if not isinstance(self.expr, ExprInt):
+            return False
+        v = (int(self.expr) - 4) & int(self.expr.mask)
+        s = 0
+        if v & 0x80000000:
+            s = 1
+            v &= (1<<26) - 1
+        if v >= (1 << 26):
+            return False
+        if v & 1:
+            return False
+        i1, i2, imm10h, imm11l = (v >> 23) & 1, (v >> 22) & 1, (v >> 12) & 0x3ff, (v >> 1) & 0x7ff
+        j1, j2 = i1 ^ s ^ 1, i2 ^ s ^ 1
+        self.parent.sign.value = s
+        self.parent.j1.value = j1
+        self.parent.j2.value = j2
+        self.parent.imm10h.value = imm10h
+        self.value = imm11l
+        return True
+
+
+
+class armt2_imm6_11l(arm_imm):
+
+    def decode(self, v):
+        v = v & self.lmask
+        s = self.parent.sign.value
+        j1 = self.parent.j1.value
+        j2 = self.parent.j2.value
+        imm6h = self.parent.imm6h.value
+        imm11l = v
+
+        v = (s << 20) | (j2 << 19) | (j1 << 18) | (imm6h << 12) | (imm11l << 1)
+        v = sign_ext(v, 21, 32)
+        self.expr = ExprInt(v + 4, 32)
+        return True
+
+    def encode(self):
+        if not isinstance(self.expr, ExprInt):
+            return False
+        v = (int(self.expr) - 4) & int(self.expr.mask)
+        s = 0
+        if v != sign_ext(v & ((1 << 22) - 1), 21, 32):
+            return False
+        if v & 0x80000000:
+            s = 1
+        v &= (1<<22) - 1
+        if v & 1:
+            return False
+        i2, i1, imm6h, imm11l = (v >> 19) & 1, (v >> 18) & 1, (v >> 12) & 0x3f, (v >> 1) & 0x7ff
+        self.parent.sign.value = s
+        self.parent.j1.value = i1
+        self.parent.j2.value = i2
+        self.parent.imm6h.value = imm6h
+        self.value = imm11l
+        return True
+
+
+
+imm12_1 = bs(l=1, fname="imm12_1", order=1)
+imm12_3 = bs(l=3, fname="imm12_3", order=1)
+imm12_8 = bs(l=8, cls=(armt2_imm12,), fname="imm", order=2)
+
+
+imm12_8_t4 = bs(l=8, cls=(armt4_imm12,), fname="imm", order=2)
+
+
+imm16_1 = bs(l=1, fname="imm16_1", order=1)
+imm16_3 = bs(l=3, fname="imm16_3", order=1)
+imm16_4 = bs(l=4, fname="imm16_4", order=1)
+imm16_8 = bs(l=8, cls=(armt2_imm16,), fname="imm", order=2)
+
+
+imm5_3 = bs(l=3, fname="imm5_3")
+imm5_2 = bs(l=2, fname="imm5_2")
+imm_stype = bs(l=2, fname="stype")
+
+imm_stype_00 = bs('00', fname="stype")
+imm_stype_01 = bs('01', fname="stype")
+imm_stype_11 = bs('11', fname="stype")
+
+
+imm1 = bs(l=1, fname="imm1")
+
+
+
+off20_6 = bs(l=6, fname="off20_6", order=1)
+off20_11 = bs(l=11, cls=(armt2_off20,), fname="imm", order=2)
+
+
+
+lsb5_3 = bs(l=3, fname="lsb5_3", order=1)
+lsb5_2 = bs(l=2, cls=(armt2_lsb5,), fname="imm", order=2)
+
+widthm1 = bs(l=5, cls=(armt_widthm1,), fname="imm", order=2)
+
+
+
+class armt_imm5_1(arm_imm):
+
+    def decode(self, v):
+        v = ((self.parent.imm1.value << 5) | v) << 1
+        self.expr = ExprInt(v, 32)
+        return True
+
+    def encode(self):
+        if not isinstance(self.expr, ExprInt):
+            return False
+        v = int(self.expr)
+        if v & 0x1:
+            return False
+        self.parent.imm1.value = (v >> 6) & 1
+        self.value = (v >> 1) & 0x1f
+        return True
+
+aif_str = ["X", "F", "I", "IF", "A", "AF", "AI", "AIF"]
+aif_expr = [ExprId(x, 32) if x != None else None for x in aif_str]
+
+aif_reg = reg_info(aif_str, aif_expr)
+
+class armt_aif(reg_noarg, arm_arg):
+    reg_info = aif_reg
+    parser = reg_info.parser
+
+    def decode(self, v):
+        if v == 0:
+            return False
+        return super(armt_aif, self).decode(v)
+
+    def encode(self):
+        ret = super(armt_aif, self).encode()
+        if not ret:
+            return ret
+        return self.value != 0
+
+    def fromstring(self, text, loc_db, parser_result=None):
+        start, stop = super(armt_aif, self).fromstring(text, loc_db, parser_result)
+        if self.expr.name == "X":
+            return None, None
+        return start, stop
+
+
+class armt_it_arg(arm_arg):
+    arg_E = ExprId('E', 1)
+    arg_NE = ExprId('NE', 1)
+
+    def decode(self, v):
+        if v:
+            return self.arg_E
+        else:
+            return self.arg_NE
+
+    def encode(self):
+        if self.expr == self.arg_E:
+            return 1
+        elif self.expr == self.arg_NE:
+            return 0
+
+class armt_itmask(bs_divert):
+    prio = 2
+
+    def divert(self, i, candidates):
+        out = []
+        for cls, _, bases, dct, fields in candidates:
+            for value in range(1, 0x10):
+                nfields = fields[:]
+                s = int2bin(value, self.args['l'])
+                args = dict(self.args)
+                args.update({'strbits': s})
+                f = bs(**args)
+                nfields[i] = f
+                inv = nfields[-2].value
+                ndct = dict(dct)
+                ndct['name'] = self.modname(ndct['name'], value, inv)
+                out.append((cls, ndct['name'], bases, ndct, nfields))
+        return out
+
+    def modname(self, name, value, inv):
+        count = 0
+        while value & (1 << count) == 0:
+            count += 1
+        out = []
+        values = ['E', 'T']
+        if inv== 1:
+            values.reverse()
+        for index in range(3 - count):
+            if value & (1 << (3 - index)):
+                out.append(values[0])
+            else:
+                out.append(values[1])
+        return name + "".join(out)
+
+
+
+class armt_cond_lsb(bs_divert):
+    prio = 2
+
+    def divert(self, i, candidates):
+        out = []
+        for cls, _, bases, dct, fields in candidates:
+            for value in range(2):
+                nfields = fields[:]
+                s = int2bin(value, self.args['l'])
+                args = dict(self.args)
+                args.update({'strbits': s})
+                f = bs(**args)
+                nfields[i] = f
+                ndct = dict(dct)
+                out.append((cls, ndct['name'], bases, ndct, nfields))
+        return out
+
+
+cond_expr = [ExprId(x, 32) for x in cond_list_full]
+cond_info = reg_info(cond_list_full, cond_expr)
+
+class armt_cond_arg(arm_arg):
+    parser = cond_info.parser
+
+    def decode(self, v):
+        v = (v << 1) | self.parent.condlsb.value
+        self.expr = ExprId(cond_list_full[v], 32)
+        return True
+
+    def encode(self):
+        index = cond_list_full.index(self.expr.name)
+        self.value = index >> 1
+        if index & 1 != self.parent.condlsb.value:
+            return False
+        return True
+
+
+class armt_op2imm(arm_imm8_12):
+    parser = deref
+
+    def str_to_imm_rot_form(self, s, neg=False):
+        if neg:
+            s = -s & 0xffffffff
+        if 0 <= s < (1 << 12):
+            return s
+        return None
+
+    def decodeval(self, v):
+        return v
+
+    def encodeval(self, v):
+        return v
+
+    def decode(self, v):
+        val = v & self.lmask
+        val = self.decodeval(val)
+        if val is False:
+            return False
+        imm = val
+        if self.parent.updown.value == 0:
+            imm = -imm
+        if self.parent.ppi.value == 0 and self.parent.wback.value == 0:
+            return False
+        if self.parent.ppi.value:
+            e = ExprOp('preinc', self.parent.rn.expr, ExprInt(imm, 32))
+            if self.parent.wback.value == 1:
+                e = ExprOp('wback', e)
+        else:
+            e = ExprOp('postinc', self.parent.rn.expr, ExprInt(imm, 32))
+        self.expr = ExprMem(e, 32)
+        return True
+
+    def encode(self):
+        self.parent.updown.value = 1
+        self.parent.wback.value = 0
+
+        e = self.expr
+        assert(isinstance(e, ExprMem))
+        e = e.ptr
+        if e.op == 'wback':
+            self.parent.wback.value = 1
+            e = e.args[0]
+        if e.op == "postinc":
+            self.parent.ppi.value = 0
+            self.parent.wback.value = 1
+        elif e.op == "preinc":
+            self.parent.ppi.value = 1
+        else:
+            # XXX default
+            self.parent.ppi.value = 1
+
+        self.parent.rn.expr = e.args[0]
+
+        if len(e.args) == 1:
+            self.value = 0
+            return True
+        # pure imm
+        if isinstance(e.args[1], ExprInt):
+            val = self.str_to_imm_rot_form(int(e.args[1]))
+            if val is None:
+                val = self.str_to_imm_rot_form(int(e.args[1]), True)
+                if val is None:
+                    log.debug('cannot encode inm')
+                    return False
+                self.parent.updown.value = 0
+            val = self.encodeval(val)
+            if val is False:
+                return False
+            self.value = val
+            return True
+        # pure reg
+        if isinstance(e.args[1], ExprId):
+            rm = gpregs.expr.index(e.args[1])
+            shift_kind = 0
+            shift_type = 0
+            amount = 0
+            val = (((((amount << 2) | shift_type) << 1) | shift_kind) << 4) | rm
+            val = self.encodeval(val)
+            if val is False:
+                return False
+            self.value = val
+            return True
+        return False
+
+
+class armt_op2imm00(armt_op2imm):
+
+    def decodeval(self, v):
+        return v << 2
+
+    def encodeval(self, v):
+        if v & 3:
+            return False
+        return v >> 2
+
+
+class armt_deref_reg(arm_imm8_12):
+    parser = deref
+
+    def decode(self, v):
+        base = self.parent.rn.expr
+        off = gpregs.expr[v]
+        if self.parent.imm.value != 0:
+            off = off << ExprInt(self.parent.imm.value, 32)
+        e = ExprMem(ExprOp('preinc', base, off), 8)
+        self.expr = e
+        return True
+
+    def encode(self):
+        if not isinstance(self.expr, ExprMem):
+            return False
+        ptr = self.expr.ptr
+        if not ptr.is_op('preinc'):
+            return False
+        if len(ptr.args) != 2:
+            return False
+        base, off = ptr.args
+        if base.is_id() and off.is_id():
+            self.parent.rn.expr = base
+            self.parent.imm.value = 0
+            self.value = gpregs.expr.index(off)
+        elif off.is_int():
+            return False
+        elif off.is_op('<<'):
+            if len(off.args) != 2:
+                return False
+            reg, off = off.args
+            self.parent.rn.expr = base
+            self.parent.imm.value = 0
+            self.value = gpregs.expr.index(reg)
+            off = int(off)
+            if off > self.parent.imm.lmask:
+                return False
+            self.parent.imm.value = off
+        return True
+
+
+class armt_deref_reg_reg(arm_arg):
+    parser = deref_reg_reg
+    reg_info = gpregs
+
+    def decode(self, v):
+        expr = self.reg_info.expr[v]
+        expr = ExprMem(self.parent.rn.expr + expr, 8)
+        self.expr = expr
+        return True
+
+    def encode(self):
+        expr = self.expr
+        if not expr.is_mem():
+            return False
+        ptr = expr.ptr
+        if not ptr.is_op('+') or len(ptr.args) != 2:
+            return False
+        reg1, reg2 = ptr.args
+        self.parent.rn.expr = reg1
+        self.value = self.reg_info.expr.index(reg2)
+        return True
+
+
+class armt_deref_reg_reg_lsl_1(arm_reg):
+    parser = deref_reg_reg_lsl_1
+    reg_info = gpregs
+
+    def decode(self, v):
+        expr = self.reg_info.expr[v]
+        expr = ExprMem(self.parent.rn.expr + (expr << ExprInt(1, 32)), 16)
+        self.expr = expr
+        return True
+
+    def encode(self):
+        expr = self.expr
+        if not expr.is_mem():
+            return False
+        ptr = expr.ptr
+        if not ptr.is_op('+') or len(ptr.args) != 2:
+            return False
+        reg1, reg_shift = ptr.args
+        self.parent.rn.expr = reg1
+        if not reg_shift.is_op('<<') or len(reg_shift.args) != 2:
+            return False
+        if reg_shift.args[1] != ExprInt(1, 32):
+            return False
+        self.value = self.reg_info.expr.index(reg_shift.args[0])
+        return True
+
+
+aif = bs(l=3, cls=(armt_aif,))
+
+
+imm5_off = bs(l=5, cls=(armt_imm5_1,), fname="imm5_off")
+
+tsign = bs(l=1, fname="sign")
+tj1 = bs(l=1, fname="j1")
+tj2 = bs(l=1, fname="j2")
+
+timm6h = bs(l=6, fname="imm6h")
+timm10H = bs(l=10, fname="imm10h")
+timm10L = bs(l=10, cls=(armt2_imm10l,), fname="imm10l")
+timm11L = bs(l=11, cls=(armt2_imm11l,), fname="imm11l")
+
+timm6h11l = bs(l=11, cls=(armt2_imm6_11l,), fname="imm6h11l")
+
+itcond = bs(l=4, fname="itcond")
+itmask = armt_itmask(l=4, fname="itmask")
+bs_cond_arg_msb = bs(l=3, cls=(armt_cond_arg,))
+
+
+condlsb = armt_cond_lsb(l=1, fname="condlsb")
+
+deref_immpuw = bs(l=8, cls=(armt_op2imm,))
+deref_immpuw00 = bs(l=8, cls=(armt_op2imm00,))
+
+
+rm_deref_reg = bs(l=4, cls=(armt_deref_reg,))
+
+bs_deref_reg_reg = bs(l=4, cls=(armt_deref_reg_reg,))
+bs_deref_reg_reg_lsl_1 = bs(l=4, cls=(armt_deref_reg_reg_lsl_1,))
+
+
+armtop("adc", [bs('11110'),  imm12_1, bs('0'), bs('1010'), scc, rn_nosppc, bs('0'), imm12_3, rd_nosppc, imm12_8])
+armtop("adc", [bs('11101'),  bs('01'), bs('1010'), scc, rn_nosppc, bs('0'), imm5_3, rd_nosppc, imm5_2, imm_stype, rm_sh])
+armtop("bl", [bs('11110'), tsign, timm10H, bs('11'), tj1, bs('1'), tj2, timm11L])
+armtop("blx", [bs('11110'), tsign, timm10H, bs('11'), tj1, bs('0'), tj2, timm10L, bs('0')])
+armtop("cbz", [bs('101100'), imm1, bs('1'), imm5_off, rnl], [rnl, imm5_off])
+armtop("cbnz", [bs('101110'), imm1, bs('1'), imm5_off, rnl], [rnl, imm5_off])
+
+armtop("bkpt", [bs('1011'), bs('1110'), imm8])
+
+
+armtop("it", [bs('10111111'), bs_cond_arg_msb, condlsb, itmask])
+
+
+armtop("nop", [bs8(0xBF),bs8(0x0)])
+armtop("wfi", [bs8(0xBF),bs8(0x30)])
+armtop("cpsid", [bs8(0xB6),bs('0111'), bs('0'), aif], [aif])
+armtop("cpsie", [bs8(0xB6),bs('0110'), bs('0'), aif], [aif])
+
+armtop("push", [bs('1110100'), bs('10'), bs('0'), bs('1'), bs('0'), bs('1101'), bs('0'), pclr, bs('0'), trlist13], [trlist13])
+armtop("pop",  [bs('1110100'), bs('01'), bs('0'), bs('1'), bs('1'), bs('1101'), pc_in, lr_in, bs('0'), trlist13pclr], [trlist13pclr])
+armtop("mov", [bs('11110'), imm12_1, bs('00010'), scc, bs('1111'), bs('0'), imm12_3, rd_nosppc, imm12_8])
+armtop("asr", [bs('11111010'), bs('0100'), rm, bs('1111'), rd, bs('0000'), rs], [rd, rm, rs])
+armtop("lsl", [bs('11111010'), bs('0000'), rm, bs('1111'), rd, bs('0000'), rs], [rd, rm, rs])
+armtop("sel", [bs('11111010'), bs('1010'), rm, bs('1111'), rd, bs('1000'), rs], [rd, rm, rs])
+armtop("rev", [bs('11111010'), bs('1001'), rm, bs('1111'), rd, bs('1000'), rm_cp], [rd, rm])
+armtop("uadd8", [bs('111110101000'), rn, bs('1111'), rd, bs('0100'), rm], [rd, rn, rm])
+armtop("mvn", [bs('11101010011'), scc, bs('11110'), imm5_3, rd_nosppc, imm5_2, imm_stype, rm_sh] )
+armtop("and", [bs('11101010000'), scc, rn_nosppc, bs('0'), imm5_3, rd_nosppc, imm5_2, imm_stype, rm_sh], [rd_nosppc, rn_nosppc, rm_sh] )
+armtop("orr", [bs('11101010010'), scc, rn_nosppc, bs('0'), imm5_3, rd_nosppc, imm5_2, imm_stype, rm_sh], [rd_nosppc, rn_nosppc, rm_sh] )
+armtop("bic", [bs('11101010001'), scc, rn_nosppc, bs('0'), imm5_3, rd_nosppc, imm5_2, imm_stype, rm_sh], [rd_nosppc, rn_nosppc, rm_sh] )
+armtop("add", [bs('11101011000'), scc, rn_nosppc, bs('0'), imm5_3, rd_nosppc, imm5_2, imm_stype, rm_sh], [rd_nosppc, rn_nosppc, rm_sh] )
+armtop("sub", [bs('11101011101'), scc, rn_nosppc, bs('0'), imm5_3, rd_nosppc, imm5_2, imm_stype, rm_sh], [rd_nosppc, rn_nosppc, rm_sh] )
+armtop("eor", [bs('11101010100'), scc, rn_nosppc, bs('0'), imm5_3, rd_nosppc, imm5_2, imm_stype, rm_sh], [rd_nosppc, rn_nosppc, rm_sh] )
+armtop("rsb", [bs('11101011110'), scc, rn, bs('0'), imm5_3, rd, imm5_2, imm_stype, rm_sh], [rd, rn, rm_sh] )
+armtop("orn", [bs('11101010011'), scc, rn_nopc, bs('0'), imm5_3, rd, imm5_2, imm_stype, rm_sh], [rd, rn_nopc, rm_sh] )
+# lsl
+armtop("mov", [bs('11101010010'), scc, bs('1111'), bs('0'), imm5_3, rd_nosppc, imm5_2, imm_stype_00, rm_sh], [rd_nosppc, rm_sh] )
+armtop("mov", [bs('11101010010'), scc, bs('1111'), bs('0'), imm5_3, rd_nosppc, imm5_2, imm_stype_01, rm_sh], [rd_nosppc, rm_sh] )
+armtop("mov", [bs('11101010010'), scc, bs('1111'), bs('0'), imm5_3, rd_nosppc, imm5_2, imm_stype_11, rm_sh], [rd_nosppc, rm_sh] )
+
+
+armtop("orr", [bs('11110'), imm12_1, bs('00010'), scc, rn_nosppc, bs('0'), imm12_3, rd, imm12_8] )
+armtop("add", [bs('11110'), imm12_1, bs('01000'), bs('0'), rn, bs('0'), imm12_3, rd_nopc, imm12_8], [rd_nopc, rn, imm12_8])
+armtop("adds",[bs('11110'), imm12_1, bs('01000'), bs('1'), rn, bs('0'), imm12_3, rd_nopc, imm12_8], [rd_nopc, rn, imm12_8])
+armtop("bic", [bs('11110'), imm12_1, bs('00001'), scc, rn_nosppc, bs('0'), imm12_3, rd, imm12_8], [rd, rn_nosppc, imm12_8])
+armtop("and", [bs('11110'), imm12_1, bs('00000'), scc, rn, bs('0'), imm12_3, rd_nopc, imm12_8], [rd_nopc, rn, imm12_8])
+armtop("sub", [bs('11110'), imm12_1, bs('01101'), scc, rn, bs('0'), imm12_3, rd_nopc, imm12_8], [rd_nopc, rn, imm12_8])
+armtop("eor", [bs('11110'), imm12_1, bs('00100'), scc, rn, bs('0'), imm12_3, rd_nopc, imm12_8], [rd_nopc, rn, imm12_8])
+armtop("add", [bs('11110'), imm12_1, bs('10000'), scc, rn_nosppc, bs('0'), imm12_3, rd, imm12_8_t4], [rd, rn_nosppc, imm12_8_t4])
+armtop("cmp", [bs('11110'), imm12_1, bs('01101'), bs('1'), rn, bs('0'), imm12_3, bs('1111'), imm12_8] )
+
+armtop("cmp", [bs('11101011101'), bs('1'), rn, bs('0'), imm5_3, bs('1111'), imm5_2, imm_stype, rm_sh], [rn, rm_sh] )
+
+armtop("cmn", [bs('11110'), imm12_1, bs('01000'), bs('1'), rn, bs('0'), imm12_3, bs('1111'), imm12_8], [rn, imm12_8])
+
+
+armtop("mvn", [bs('11110'), imm12_1, bs('00011'), scc, bs('1111'), bs('0'), imm12_3, rd, imm12_8])
+armtop("rsb", [bs('11110'), imm12_1, bs('01110'), scc, rn_nosppc, bs('0'), imm12_3, rd, imm12_8], [rd, rn_nosppc, imm12_8])
+armtop("sub", [bs('11110'), imm12_1, bs('101010'), rn_nosppc, bs('0'), imm12_3, rd, imm12_8_t4], [rd, rn_nosppc, imm12_8_t4])
+armtop("tst", [bs('11110'), imm12_1, bs('000001'), rn, bs('0'), imm12_3, bs('1111'), imm12_8], [rn, imm12_8])
+
+armtop("mov",  [bs('11110'), imm16_1, bs('100100'), imm16_4, bs('0'), imm16_3, rd, imm16_8] )
+armtop("movt", [bs('11110'), imm16_1, bs('101100'), imm16_4, bs('0'), imm16_3, rd, imm16_8] )
+
+armtop("sdiv", [bs('111110111001'), rn, bs('1111'), rd, bs('1111'), rm], [rd, rn, rm] )
+armtop("udiv", [bs('111110111011'), rn, bs('1111'), rd, bs('1111'), rm], [rd, rn, rm] )
+armtop("mls",  [bs('111110110000'), rn, ra, rd, bs('0001'), rm], [rd, rn, rm, ra] )
+armtop("mla",  [bs('111110110000'), rn, ra_nopc, rd, bs('0000'), rm], [rd, rn, rm, ra_nopc] )
+armtop("mul",  [bs('111110110000'), rn, bs('1111'), rd, bs('0000'), rm], [rd, rn, rm] )
+
+armtop("smlabb", [bs('111110110001'), rn, ra_nopc, rd, bs('00'), bs('00'), rm], [rd, rn, rm, ra_nopc])
+armtop("smlabt", [bs('111110110001'), rn, ra_nopc, rd, bs('00'), bs('01'), rm], [rd, rn, rm, ra_nopc])
+armtop("smlatb", [bs('111110110001'), rn, ra_nopc, rd, bs('00'), bs('10'), rm], [rd, rn, rm, ra_nopc])
+armtop("smlatt", [bs('111110110001'), rn, ra_nopc, rd, bs('00'), bs('11'), rm], [rd, rn, rm, ra_nopc])
+
+armtop("b", [bs('11110'), tsign, bm_cond_barmt, timm6h, bs('10'), tj1, bs('0'), tj2, timm6h11l], [timm6h11l])
+armtop("b", [bs('11110'), tsign, timm10H, bs('10'), tj1, bs('1'), tj2, timm11L], [timm11L])
+
+armtop("ubfx", [bs('111100111100'), rn, bs('0'), lsb5_3, rd, lsb5_2, bs('0'), widthm1], [rd, rn, lsb5_2, widthm1])
+armtop("uxth", [bs('111110100001'), bs('1111'), bs('1111'), rd, bs('10'), rot2, rm_rot2], [rd, rm_rot2])
+
+
+
+armtop("str",  [bs('111110001100'), rn_deref, rt, off12], [rt, rn_deref])
+armtop("str",  [bs('111110000100'), rn_noarg, rt, bs('000000'), imm2_noarg, rm_deref_reg], [rt, rm_deref_reg])
+armtop("str",  [bs('111110000100'), rn_noarg, rt, bs('1'), ppi, updown, wback_no_t, deref_immpuw], [rt, deref_immpuw])
+armtop("strb", [bs('111110001000'), rn_deref, rt, off12], [rt, rn_deref])
+armtop("strb", [bs('111110000000'), rn_noarg, rt, bs('1'), ppi, updown, wback_no_t, deref_immpuw], [rt, deref_immpuw])
+armtop("strh", [bs('111110001010'), rn_deref, rt, off12], [rt, rn_deref])
+armtop("strh", [bs('111110000010'), rn_noarg, rt, bs('1'), ppi, updown, wback_no_t, deref_immpuw], [rt, deref_immpuw])
+
+armtop("strd", [bs('1110100'), ppi, updown, bs('1'), wback_no_t, bs('0'), rn_nopc_noarg, rt, rt2, deref_immpuw00], [rt, rt2, deref_immpuw00])
+armtop("ldrd", [bs('1110100'), ppi, updown, bs('1'), wback_no_t, bs('1'), rn_nopc_noarg, rt, rt2, deref_immpuw00], [rt, rt2, deref_immpuw00])
+
+
+armtop("ldr",  [bs('111110001101'), rn_deref, rt, off12], [rt, rn_deref])
+armtop("ldr",  [bs('111110000101'), rn_noarg, rt, bs('1'), ppi, updown, wback_no_t, deref_immpuw], [rt, deref_immpuw])
+armtop("ldr",  [bs('111110000101'), rn_noarg, rt, bs('000000'), imm2_noarg, rm_deref_reg], [rt, rm_deref_reg])
+armtop("ldrb", [bs('111110000001'), rn_noarg, rt, bs('000000'), imm2_noarg, rm_deref_reg], [rt, rm_deref_reg])
+armtop("ldrb", [bs('111110000001'), rn_noarg, rt, bs('1'), ppi, updown, wback_no_t, deref_immpuw], [rt, deref_immpuw])
+armtop("ldrb", [bs('111110001001'), rn_deref, rt_nopc, off12], [rt_nopc, rn_deref])
+armtop("ldrsb",[bs('111110011001'), rn_deref, rt, off12], [rt, rn_deref])
+armtop("ldrsh",[bs('111110011011'), rn_deref, rt, off12], [rt, rn_deref])
+armtop("ldrh", [bs('111110001011'), rn_deref, rt, off12], [rt, rn_deref])
+armtop("ldrh", [bs('111110000011'), rn_noarg, rt, bs('1'), ppi, updown, wback_no_t, deref_immpuw], [rt, deref_immpuw])
+
+armtop("pld",  [bs('111110001001'), rn_deref, bs('1111'), off12], [rn_deref])
+armtop("pldw", [bs('111110001011'), rn_deref, bs('1111'), off12], [rn_deref])
+
+armtop("clz",  [bs('111110101011'), rm, bs('1111'), rd, bs('1000'), rm_cp], [rd, rm])
+armtop("tbb",  [bs('111010001101'), rn_noarg, bs('11110000000'), bs('0'), bs_deref_reg_reg], [bs_deref_reg_reg])
+armtop("tbh",  [bs('111010001101'), rn_noarg, bs('11110000000'), bs('1'), bs_deref_reg_reg_lsl_1], [bs_deref_reg_reg_lsl_1])
+armtop("dsb",  [bs('111100111011'), bs('1111'), bs('1000'), bs('1111'), bs('0100'), barrier_option])
+
+armtop("adr", [bs('11110'), imm12_1, bs('100000'), bs('1111'), bs('0'), imm12_3, rd, imm12_8_t4], [rd, imm12_8_t4])
diff --git a/src/miasm/arch/arm/disasm.py b/src/miasm/arch/arm/disasm.py
new file mode 100644
index 00000000..e84f617d
--- /dev/null
+++ b/src/miasm/arch/arm/disasm.py
@@ -0,0 +1,61 @@
+from future.utils import viewvalues
+
+from miasm.core.asmblock import AsmConstraint, disasmEngine
+from miasm.arch.arm.arch import mn_arm, mn_armt
+
+
+def cb_arm_fix_call(mdis, cur_block, offsets_to_dis):
+    """
+    for arm:
+    MOV        LR, PC
+    LDR        PC, [R5, 0x14]
+    * is a subcall *
+
+    """
+    if len(cur_block.lines) < 2:
+        return
+    l1 = cur_block.lines[-1]
+    l2 = cur_block.lines[-2]
+    if l1.name != "LDR":
+        return
+    if l2.name != "MOV":
+        return
+
+    values = viewvalues(mdis.arch.pc)
+    if not l1.args[0] in values:
+        return
+    if not l2.args[1] in values:
+        return
+    loc_key_cst = mdis.loc_db.get_or_create_offset_location(l1.offset + 4)
+    cur_block.add_cst(loc_key_cst, AsmConstraint.c_next)
+    offsets_to_dis.add(l1.offset + 4)
+
+cb_arm_funcs = [cb_arm_fix_call]
+
+
+def cb_arm_disasm(*args, **kwargs):
+    for func in cb_arm_funcs:
+        func(*args, **kwargs)
+
+
+class dis_armb(disasmEngine):
+    attrib = 'b'
+    def __init__(self, bs=None, **kwargs):
+        super(dis_armb, self).__init__(mn_arm, self.attrib, bs, **kwargs)
+        self.dis_block_callback = cb_arm_disasm
+
+class dis_arml(disasmEngine):
+    attrib = 'l'
+    def __init__(self, bs=None, **kwargs):
+        super(dis_arml, self).__init__(mn_arm, self.attrib, bs, **kwargs)
+        self.dis_block_callback = cb_arm_disasm
+
+class dis_armtb(disasmEngine):
+    attrib = 'b'
+    def __init__(self, bs=None, **kwargs):
+        super(dis_armtb, self).__init__(mn_armt, self.attrib, bs, **kwargs)
+
+class dis_armtl(disasmEngine):
+    attrib = 'l'
+    def __init__(self, bs=None, **kwargs):
+        super(dis_armtl, self).__init__(mn_armt, self.attrib, bs, **kwargs)
diff --git a/src/miasm/arch/arm/jit.py b/src/miasm/arch/arm/jit.py
new file mode 100644
index 00000000..27c26988
--- /dev/null
+++ b/src/miasm/arch/arm/jit.py
@@ -0,0 +1,144 @@
+from builtins import range
+import logging
+
+from miasm.jitter.jitload import Jitter, named_arguments
+from miasm.core.utils import pck32, upck32
+from miasm.arch.arm.sem import Lifter_Armb, Lifter_Arml, Lifter_Armtl, Lifter_Armtb, cond_dct_inv, tab_cond
+from miasm.jitter.codegen import CGen
+from miasm.expression.expression import ExprId, ExprAssign, ExprCond
+from miasm.ir.ir import IRBlock, AssignBlock
+from miasm.ir.translators.C import TranslatorC
+from miasm.expression.simplifications import expr_simp_high_to_explicit
+
+log = logging.getLogger('jit_arm')
+hnd = logging.StreamHandler()
+hnd.setFormatter(logging.Formatter("[%(levelname)-8s]: %(message)s"))
+log.addHandler(hnd)
+log.setLevel(logging.CRITICAL)
+
+
+
+class arm_CGen(CGen):
+
+    def block2assignblks(self, block):
+        """
+        Return the list of irblocks for a native @block
+        @block: AsmBlock
+        """
+        irblocks_list = []
+        index = -1
+        while index + 1 < len(block.lines):
+            index += 1
+            instr = block.lines[index]
+
+            if instr.name.startswith("IT"):
+                assignments = []
+                label = self.lifter.get_instr_label(instr)
+                irblocks = []
+                index, irblocks = self.lifter.do_it_block(label, index, block, assignments, True)
+                irblocks_list += irblocks
+                continue
+
+
+            assignblk_head, assignblks_extra = self.lifter.instr2ir(instr)
+            # Keep result in ordered list as first element is the assignblk head
+            # The remainings order is not really important
+            irblock_head = self.assignblk_to_irbloc(instr, assignblk_head)
+            irblocks = [irblock_head] + assignblks_extra
+
+
+            # Simplify high level operators
+            out = []
+            for irblock in irblocks:
+                new_irblock = irblock.simplify(expr_simp_high_to_explicit)[1]
+                out.append(new_irblock)
+            irblocks = out
+
+
+            for irblock in irblocks:
+                assert irblock.dst is not None
+            irblocks_list.append(irblocks)
+        return irblocks_list
+
+
+class jitter_arml(Jitter):
+    C_Gen = arm_CGen
+
+    def __init__(self, loc_db, *args, **kwargs):
+        Jitter.__init__(self, Lifter_Arml(loc_db), *args, **kwargs)
+        self.vm.set_little_endian()
+
+    def push_uint32_t(self, value):
+        self.cpu.SP -= 4
+        self.vm.set_mem(self.cpu.SP, pck32(value))
+
+    def pop_uint32_t(self):
+        value = self.vm.get_u32(self.cpu.SP)
+        self.cpu.SP += 4
+        return value
+
+    def get_stack_arg(self, index):
+        return self.vm.get_u32(self.cpu.SP + 4 * index)
+
+    # calling conventions
+
+    @named_arguments
+    def func_args_stdcall(self, n_args):
+        args = [self.get_arg_n_stdcall(i) for i in range(n_args)]
+        ret_ad = self.cpu.LR
+        return ret_ad, args
+
+    def func_ret_stdcall(self, ret_addr, ret_value1=None, ret_value2=None):
+        self.pc = self.cpu.PC = ret_addr
+        if ret_value1 is not None:
+            self.cpu.R0 = ret_value1
+        if ret_value2 is not None:
+            self.cpu.R1 = ret_value2
+        return True
+
+    def func_prepare_stdcall(self, ret_addr, *args):
+        for index in range(min(len(args), 4)):
+            setattr(self.cpu, 'R%d' % index, args[index])
+        for index in reversed(range(4, len(args))):
+            self.push_uint32_t(args[index])
+        self.cpu.LR = ret_addr
+
+    def get_arg_n_stdcall(self, index):
+        if index < 4:
+            arg = getattr(self.cpu, 'R%d' % index)
+        else:
+            arg = self.get_stack_arg(index-4)
+        return arg
+
+    func_args_systemv = func_args_stdcall
+    func_ret_systemv = func_ret_stdcall
+    func_prepare_systemv = func_prepare_stdcall
+    get_arg_n_systemv = get_arg_n_stdcall
+
+    def syscall_args_systemv(self, n_args):
+        args = [self.cpu.R0, self.cpu.R1, self.cpu.R2, self.cpu.R3,
+            self.cpu.R4, self.cpu.R5][:n_args]
+        return args
+
+    def syscall_ret_systemv(self, value):
+        self.cpu.R0 = value
+
+    def init_run(self, *args, **kwargs):
+        Jitter.init_run(self, *args, **kwargs)
+        self.cpu.PC = self.pc
+
+
+class jitter_armb(jitter_arml):
+    C_Gen = arm_CGen
+
+    def __init__(self, loc_db, *args, **kwargs):
+        Jitter.__init__(self, Lifter_Armb(loc_db), *args, **kwargs)
+        self.vm.set_big_endian()
+
+
+class jitter_armtl(jitter_arml):
+    C_Gen = arm_CGen
+
+    def __init__(self, loc_db, *args, **kwargs):
+        Jitter.__init__(self, Lifter_Armtl(loc_db), *args, **kwargs)
+        self.vm.set_little_endian()
diff --git a/src/miasm/arch/arm/lifter_model_call.py b/src/miasm/arch/arm/lifter_model_call.py
new file mode 100644
index 00000000..9aac74a4
--- /dev/null
+++ b/src/miasm/arch/arm/lifter_model_call.py
@@ -0,0 +1,106 @@
+#-*- coding:utf-8 -*-
+
+from miasm.ir.analysis import LifterModelCall
+from miasm.ir.ir import IRBlock
+from miasm.arch.arm.sem import Lifter_Arml, Lifter_Armtl, Lifter_Armb, Lifter_Armtb, tab_cond
+from miasm.expression.expression import ExprAssign, ExprOp, ExprLoc, ExprCond
+from miasm.ir.ir import AssignBlock
+
+class LifterModelCallArmlBase(Lifter_Arml, LifterModelCall):
+    def __init__(self, loc_db):
+        Lifter_Arml.__init__(self, loc_db)
+        self.ret_reg = self.arch.regs.R0
+
+class LifterModelCallArmbBase(Lifter_Armb, LifterModelCall):
+    def __init__(self, loc_db):
+        Lifter_Armb.__init__(self, loc_db)
+        self.ret_reg = self.arch.regs.R0
+
+
+class LifterModelCallArml(LifterModelCallArmlBase):
+
+    def __init__(self, loc_db):
+        LifterModelCallArmlBase.__init__(self, loc_db)
+        self.ret_reg = self.arch.regs.R0
+
+    def call_effects(self, ad, instr):
+        call_assignblk = AssignBlock(
+            [
+                ExprAssign(
+                    self.ret_reg,
+                    ExprOp(
+                        'call_func_ret',
+                        ad,
+                        self.arch.regs.R0,
+                        self.arch.regs.R1,
+                        self.arch.regs.R2,
+                        self.arch.regs.R3,
+                    )
+                ),
+                ExprAssign(
+                    self.sp,
+                    ExprOp('call_func_stack', ad, self.sp)
+                ),
+            ],
+            instr
+        )
+
+
+        cond = instr.additional_info.cond
+        if cond == 14: # COND_ALWAYS:
+            return [call_assignblk], []
+
+        # Call is a conditional instruction
+        cond = tab_cond[cond]
+
+        loc_next = self.get_next_loc_key(instr)
+        loc_next_expr = ExprLoc(loc_next, 32)
+        loc_do = self.loc_db.add_location()
+        loc_do_expr = ExprLoc(loc_do, 32)
+        dst_cond = ExprCond(cond, loc_do_expr, loc_next_expr)
+
+        call_assignblks = [
+            call_assignblk,
+            AssignBlock([ExprAssign(self.IRDst, loc_next_expr)], instr),
+        ]
+        e_do = IRBlock(self.loc_db, loc_do, call_assignblks)
+        assignblks_out = [
+            AssignBlock([ExprAssign(self.IRDst, dst_cond)], instr)
+        ]
+        return assignblks_out, [e_do]
+
+
+    def get_out_regs(self, _):
+        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 LifterModelCallArmb(LifterModelCallArmbBase, LifterModelCallArml):
+
+    def __init__(self, loc_db):
+        LifterModelCallArmbBase.__init__(self, loc_db)
+        self.ret_reg = self.arch.regs.R0
+
+
+class LifterModelCallArmtl(Lifter_Armtl, LifterModelCallArml):
+    def __init__(self, loc_db):
+        Lifter_Armtl.__init__(self, loc_db)
+        self.ret_reg = self.arch.regs.R0
+
+class LifterModelCallArmtb(LifterModelCallArmtl, Lifter_Armtb, LifterModelCallArmb):
+    def __init__(self, loc_db):
+        Lifter_Armtb.__init__(self, loc_db)
+        self.ret_reg = self.arch.regs.R0
diff --git a/src/miasm/arch/arm/regs.py b/src/miasm/arch/arm/regs.py
new file mode 100644
index 00000000..2b24b0d5
--- /dev/null
+++ b/src/miasm/arch/arm/regs.py
@@ -0,0 +1,177 @@
+#-*- coding:utf-8 -*-
+
+from builtins import range
+from miasm.expression.expression import *
+from miasm.core.cpu import gen_reg, gen_regs
+
+# GP
+
+regs32_str = ["R%d" % i for i in range(13)] + ["SP", "LR", "PC"]
+regs32_expr = [ExprId(x, 32) for x in regs32_str]
+
+exception_flags = ExprId('exception_flags', 32)
+interrupt_num = ExprId('interrupt_num', 32)
+bp_num = ExprId('bp_num', 32)
+
+
+R0 = regs32_expr[0]
+R1 = regs32_expr[1]
+R2 = regs32_expr[2]
+R3 = regs32_expr[3]
+R4 = regs32_expr[4]
+R5 = regs32_expr[5]
+R6 = regs32_expr[6]
+R7 = regs32_expr[7]
+R8 = regs32_expr[8]
+R9 = regs32_expr[9]
+R10 = regs32_expr[10]
+R11 = regs32_expr[11]
+R12 = regs32_expr[12]
+SP = regs32_expr[13]
+LR = regs32_expr[14]
+PC = regs32_expr[15]
+
+R0_init = ExprId("R0_init", 32)
+R1_init = ExprId("R1_init", 32)
+R2_init = ExprId("R2_init", 32)
+R3_init = ExprId("R3_init", 32)
+R4_init = ExprId("R4_init", 32)
+R5_init = ExprId("R5_init", 32)
+R6_init = ExprId("R6_init", 32)
+R7_init = ExprId("R7_init", 32)
+R8_init = ExprId("R8_init", 32)
+R9_init = ExprId("R9_init", 32)
+R10_init = ExprId("R10_init", 32)
+R11_init = ExprId("R11_init", 32)
+R12_init = ExprId("R12_init", 32)
+SP_init = ExprId("SP_init", 32)
+LR_init = ExprId("LR_init", 32)
+PC_init = ExprId("PC_init", 32)
+
+
+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)
+
+
+reg_ge0 = 'ge0'
+reg_ge1 = 'ge1'
+reg_ge2 = 'ge2'
+reg_ge3 = 'ge3'
+
+ge0 = ExprId(reg_ge0, size=1)
+ge1 = ExprId(reg_ge1, size=1)
+ge2 = ExprId(reg_ge2, size=1)
+ge3 = ExprId(reg_ge3, size=1)
+
+ge0_init = ExprId("ge0_init", size=1)
+ge1_init = ExprId("ge1_init", size=1)
+ge2_init = ExprId("ge2_init", size=1)
+ge3_init = ExprId("ge3_init", size=1)
+
+ge_regs = [ge0, ge1, ge2, ge3]
+
+all_regs_ids = [
+    R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, SP, LR, PC,
+    zf, nf, of, cf,
+    ge0, ge1, ge2, ge3,
+    exception_flags, interrupt_num, bp_num
+]
+
+all_regs_ids_no_alias = all_regs_ids
+
+attrib_to_regs = {
+    'l': all_regs_ids_no_alias,
+    'b': all_regs_ids_no_alias,
+}
+
+all_regs_ids_byname = dict([(x.name, x) for x in all_regs_ids])
+
+all_regs_ids_init = [R0_init, R1_init, R2_init, R3_init,
+                     R4_init, R5_init, R6_init, R7_init,
+                     R8_init, R9_init, R10_init, R11_init,
+                     R12_init, SP_init, LR_init, PC_init,
+                     zf_init, nf_init, of_init, cf_init,
+                     ge0_init, ge1_init, ge2_init, ge3_init,
+                     ExprInt(0, 32), ExprInt(0, 32), ExprInt(0, 32)
+                     ]
+
+regs_init = {}
+for i, r in enumerate(all_regs_ids):
+    regs_init[r] = all_regs_ids_init[i]
+
+coproc_reg_str = [
+                    "MIDR", "CTR", "TCMTR", "TLBTR", "MIDR", "MPIDR", "REVIDR",
+                    "ID_PFR0", "ID_PFR1", "ID_DFR0", "ID_AFR0", "ID_MMFR0", "ID_MMFR1", "ID_MMFR2", "ID_MMFR3",
+                    "ID_ISAR0", "ID_ISAR1", "ID_ISAR2", "ID_ISAR3", "ID_ISAR4", "ID_ISAR5",
+                    "CCSIDR", "CLIDR", "AIDR",
+                    "CSSELR",
+                    "VPIDR", "VMPIDR",
+                    "SCTLR", "ACTLR", "CPACR",
+                    "SCR", "SDER", "NSACR",
+                    "HSCTLR", "HACTLR",
+                    "HCR", "HDCR", "HCPTR", "HSTR", "HACR",
+                    "TTBR0", "TTBR1", "TTBCR",
+                    "HTCR", "VTCR",
+                    "DACR",
+                    "DFSR", "IFSR",
+                    "ADFSR", "AIFSR",
+                    "HADFSR", "HAIFSR",
+                    "HSR",
+                    "DFAR", "IFAR",
+                    "HDFAR", "HIFAR", "HPFAR",
+                    "ICIALLUIS", "BPIALLIS",
+                    "PAR",
+                    "ICIALLU", "ICIMVAU", "CP15ISB", "BPIALL", "BPIMVA",
+                    "DCIMVAC", "DCISW",
+                    "ATS1CPR", "ATS1CPW", "ATS1CUR", "ATS1CUW", "ATS12NSOPR", "ATS12NSOPW", "ATS12NSOUR", "ATS12NSOUW",
+                    "DCCMVAC", "DCCSW", "CP15DSB", "CP15DMB",
+                    "DCCMVAU",
+                    "DCCIMVAC", "DCCISW",
+                    "ATS1HR", "ATS1HW",
+                    "TLBIALLIS", "TLBIMVAIS", "TLBIASIDIS", "TLBIMVAAIS",
+                    "ITLBIALL", "ITLBIMVA", "ITLBIASID",
+                    "DTLBIALL", "DTLBIMVA", "DTLBIASID",
+                    "TLBIALL", "TLBIMVA", "TLBIASID", "TLBIMVAA",
+                    "TLBIALLHIS", "TLBIMVAHIS", "TLBIALLNSNHIS",
+                    "TLBIALLH", "TLBIMVAH", "TLBIALLNSNH",
+                    "PMCR", "PMCNTENSET", "PMCNTENCLR", "PMOVSR", "PMSWINC", "PMSELR", "PMCEID0", "PMCEID1",
+                    "PMCCNTR", "PMXEVTYPER", "PMXEVCNTR",
+                    "PMUSERENR", "PMINTENSET", "PMINTENCLR", "PMOVSSET", 
+                    "PRRR", "NMRR",
+                    "AMAIR0", "AMAIR1",
+                    "HMAIR0", "HMAIR1",
+                    "HAMAIR0", "HAMAIR1",
+                    "VBAR", "MVBAR",
+                    "ISR",
+                    "HVBAR",
+                    "FCSEIDR", "CONTEXTIDR", "TPIDRURW", "TPIDRURO", "TPIDRPRW",
+                    "HTPIDR",
+                    "CNTFRQ",
+                    "CNTKCTL",
+                    "CNTP_TVAL", "CNTP_CTL",
+                    "CNTV_TVAL", "CNTV_CTL",
+                    "CNTHCTL",
+                    "CNTHP_TVAL", "CNTHP_CTL"
+                ]
+coproc_reg_expr, coproc_reg_init, coproc_reg_info = gen_regs(coproc_reg_str, globals(), 32)
+
+all_regs_ids = all_regs_ids + coproc_reg_expr
+all_regs_ids_byname.update(dict([(x.name, x) for x in coproc_reg_expr]))
+all_regs_ids_init = all_regs_ids_init + coproc_reg_init
+
+for i, r in enumerate(coproc_reg_expr):
+    regs_init[r] = coproc_reg_init[i]
+
+regs_flt_expr = []
diff --git a/src/miasm/arch/arm/sem.py b/src/miasm/arch/arm/sem.py
new file mode 100644
index 00000000..a138ef91
--- /dev/null
+++ b/src/miasm/arch/arm/sem.py
@@ -0,0 +1,2305 @@
+from builtins import range
+from future.utils import viewitems, viewvalues
+
+from miasm.expression.expression import *
+from miasm.expression.simplifications import expr_simp
+from miasm.ir.ir import Lifter, IRBlock, AssignBlock
+from miasm.arch.arm.arch import mn_arm, mn_armt
+from miasm.arch.arm.regs import *
+
+from miasm.jitter.csts import EXCEPT_DIV_BY_ZERO, EXCEPT_INT_XX
+
+coproc_reg_dict = {
+        ("p15", "c0", 0, "c0", 0): MIDR,
+        ("p15", "c0", 0, "c0", 1): CTR,
+        ("p15", "c0", 0, "c0", 2): TCMTR,
+        ("p15", "c0", 0, "c0", 3): TLBTR,
+        ("p15", "c0", 0, "c0", 4): MIDR,
+        ("p15", "c0", 0, "c0", 5): MPIDR,
+        ("p15", "c0", 0, "c0", 6): REVIDR,
+        ("p15", "c0", 0, "c0", 7): MIDR,
+
+        ("p15", "c0", 0, "c1", 0): ID_PFR0,
+        ("p15", "c0", 0, "c1", 1): ID_PFR1,
+        ("p15", "c0", 0, "c1", 2): ID_DFR0,
+        ("p15", "c0", 0, "c1", 3): ID_AFR0,
+        ("p15", "c0", 0, "c1", 4): ID_MMFR0,
+        ("p15", "c0", 0, "c1", 5): ID_MMFR1,
+        ("p15", "c0", 0, "c1", 6): ID_MMFR2,
+        ("p15", "c0", 0, "c1", 7): ID_MMFR3,
+
+        ("p15", "c0", 0, "c2", 0): ID_ISAR0,
+        ("p15", "c0", 0, "c2", 1): ID_ISAR1,
+        ("p15", "c0", 0, "c2", 2): ID_ISAR2,
+        ("p15", "c0", 0, "c2", 3): ID_ISAR3,
+        ("p15", "c0", 0, "c2", 4): ID_ISAR4,
+        ("p15", "c0", 0, "c2", 5): ID_ISAR5,
+
+        ("p15", "c0", 1, "c0", 0): CCSIDR,
+        ("p15", "c0", 1, "c0", 1): CLIDR,
+        ("p15", "c0", 1, "c0", 7): AIDR,
+
+        ("p15", "c0", 2, "c0", 0): CSSELR,
+
+        ("p15", "c0", 4, "c0", 0): VPIDR,
+        ("p15", "c0", 4, "c0", 5): VMPIDR,
+
+        ("p15", "c1", 0, "c0", 0): SCTLR,
+        ("p15", "c1", 0, "c0", 1): ACTLR,
+        ("p15", "c1", 0, "c0", 2): CPACR,
+
+        ("p15", "c1", 0, "c1", 0): SCR,
+        ("p15", "c1", 0, "c1", 1): SDER,
+        ("p15", "c1", 0, "c1", 2): NSACR,
+
+        ("p15", "c1", 4, "c0", 0): HSCTLR,
+        ("p15", "c1", 4, "c0", 1): HACTLR,
+
+        ("p15", "c1", 4, "c1", 0): HCR,
+        ("p15", "c1", 4, "c1", 1): HDCR,
+        ("p15", "c1", 4, "c1", 2): HCPTR,
+        ("p15", "c1", 4, "c1", 3): HSTR,
+        ("p15", "c1", 4, "c1", 7): HACR,
+
+        # TODO: TTBRO/TTBR1 64-bit
+        ("p15", "c2", 0, "c0", 0): TTBR0,
+        ("p15", "c2", 0, "c0", 1): TTBR1,
+        ("p15", "c2", 0, "c0", 2): TTBCR,
+
+        ("p15", "c2", 4, "c0", 2): HTCR,
+
+        ("p15", "c2", 4, "c1", 2): VTCR,
+
+        # TODO: HTTBR, VTTBR
+
+        ("p15", "c3", 0, "c0", 0): DACR,
+
+        ("p15", "c5", 0, "c0", 0): DFSR,
+        ("p15", "c5", 0, "c0", 1): IFSR,
+
+        ("p15", "c5", 0, "c1", 0): ADFSR,
+        ("p15", "c5", 0, "c1", 1): AIFSR,
+
+        ("p15", "c5", 4, "c1", 0): HADFSR,
+        ("p15", "c5", 4, "c1", 1): HAIFSR,
+
+        ("p15", "c5", 4, "c2", 0): HSR,
+
+        ("p15", "c6", 0, "c1", 0): DFAR,
+        ("p15", "c6", 0, "c1", 2): IFAR,
+
+        ("p15", "c6", 4, "c0", 0): HDFAR,
+        ("p15", "c6", 4, "c0", 2): HIFAR,
+        ("p15", "c6", 4, "c0", 4): HPFAR,
+
+        ("p15", "c7", 0, "c1", 0): ICIALLUIS,
+        ("p15", "c7", 0, "c1", 6): BPIALLIS,
+
+        ("p15", "c7", 0, "c4", 0): PAR,
+
+        # TODO: PAR 64-bit
+
+        ("p15", "c7", 0, "c5", 0): ICIALLU,
+        ("p15", "c7", 0, "c5", 1): ICIMVAU,
+        ("p15", "c7", 0, "c5", 4): CP15ISB,
+        ("p15", "c7", 0, "c5", 6): BPIALL,
+        ("p15", "c7", 0, "c5", 7): BPIMVA,
+
+        ("p15", "c7", 0, "c6", 1): DCIMVAC,
+        ("p15", "c7", 0, "c6", 2): DCISW,
+
+        ("p15", "c7", 0, "c8", 0): ATS1CPR,
+        ("p15", "c7", 0, "c8", 1): ATS1CPW,
+        ("p15", "c7", 0, "c8", 2): ATS1CUR,
+        ("p15", "c7", 0, "c8", 3): ATS1CUW,
+        ("p15", "c7", 0, "c8", 4): ATS12NSOPR,
+        ("p15", "c7", 0, "c8", 5): ATS12NSOPW,
+        ("p15", "c7", 0, "c8", 6): ATS12NSOUR,
+        ("p15", "c7", 0, "c8", 7): ATS12NSOUW,
+
+        ("p15", "c7", 0, "c10", 1): DCCMVAC,
+        ("p15", "c7", 0, "c10", 2): DCCSW,
+        ("p15", "c7", 0, "c10", 4): CP15DSB,
+        ("p15", "c7", 0, "c10", 5): CP15DMB,
+
+        ("p15", "c7", 0, "c11", 1): DCCMVAU,
+
+        ("p15", "c7", 0, "c14", 1): DCCIMVAC,
+        ("p15", "c7", 0, "c14", 2): DCCISW,
+
+        ("p15", "c7", 4, "c8", 0): ATS1HR,
+        ("p15", "c7", 4, "c8", 1): ATS1HW,
+
+        ("p15", "c8", 0, "c3", 0): TLBIALLIS,
+        ("p15", "c8", 0, "c3", 1): TLBIMVAIS,
+        ("p15", "c8", 0, "c3", 2): TLBIASIDIS,
+        ("p15", "c8", 0, "c3", 3): TLBIMVAAIS,
+
+        ("p15", "c8", 0, "c5", 0): ITLBIALL,
+        ("p15", "c8", 0, "c5", 1): ITLBIMVA,
+        ("p15", "c8", 0, "c5", 2): ITLBIASID,
+
+        ("p15", "c8", 0, "c6", 0): DTLBIALL,
+        ("p15", "c8", 0, "c6", 1): DTLBIMVA,
+        ("p15", "c8", 0, "c6", 2): DTLBIASID,
+
+        ("p15", "c8", 0, "c7", 0): TLBIALL,
+        ("p15", "c8", 0, "c7", 1): TLBIMVA,
+        ("p15", "c8", 0, "c7", 2): TLBIASID,
+        ("p15", "c8", 0, "c7", 3): TLBIMVAA,
+
+        ("p15", "c8", 4, "c3", 0): TLBIALLHIS,
+        ("p15", "c8", 4, "c3", 1): TLBIMVAHIS,
+        ("p15", "c8", 4, "c3", 4): TLBIALLNSNHIS,
+
+        ("p15", "c8", 4, "c7", 0): TLBIALLH,
+        ("p15", "c8", 4, "c7", 1): TLBIMVAH,
+        ("p15", "c8", 4, "c7", 2): TLBIALLNSNH,
+
+        ("p15", "c9", 0, "c12", 0): PMCR,
+        ("p15", "c9", 0, "c12", 1): PMCNTENSET,
+        ("p15", "c9", 0, "c12", 2): PMCNTENCLR,
+        ("p15", "c9", 0, "c12", 3): PMOVSR,
+        ("p15", "c9", 0, "c12", 4): PMSWINC,
+        ("p15", "c9", 0, "c12", 5): PMSELR,
+        ("p15", "c9", 0, "c12", 6): PMCEID0,
+        ("p15", "c9", 0, "c12", 7): PMCEID1,
+
+        ("p15", "c9", 0, "c13", 0): PMCCNTR,
+        ("p15", "c9", 0, "c13", 1): PMXEVTYPER,
+        ("p15", "c9", 0, "c13", 2): PMXEVCNTR,
+
+        ("p15", "c9", 0, "c14", 0): PMUSERENR,
+        ("p15", "c9", 0, "c14", 1): PMINTENSET,
+        ("p15", "c9", 0, "c14", 2): PMINTENCLR,
+        ("p15", "c9", 0, "c14", 3): PMOVSSET,
+
+        ("p15", "c10", 0, "c2", 0): PRRR,   # ALIAS MAIR0
+        ("p15", "c10", 0, "c2", 1): NMRR,   # ALIAS MAIR1
+
+        ("p15", "c10", 0, "c3", 0): AMAIR0,
+        ("p15", "c10", 0, "c3", 1): AMAIR1,
+
+        ("p15", "c10", 4, "c2", 0): HMAIR0,
+        ("p15", "c10", 4, "c2", 1): HMAIR1,
+
+        ("p15", "c10", 4, "c3", 0): HAMAIR0,
+        ("p15", "c10", 4, "c3", 1): HAMAIR1,
+
+        ("p15", "c12", 0, "c0", 0): VBAR,
+        ("p15", "c12", 0, "c0", 1): MVBAR,
+
+        ("p15", "c12", 0, "c1", 0): ISR,
+
+        ("p15", "c12", 4, "c0", 0): HVBAR,
+
+        ("p15", "c13", 0, "c0", 0): FCSEIDR,
+        ("p15", "c13", 0, "c0", 1): CONTEXTIDR,
+        ("p15", "c13", 0, "c0", 2): TPIDRURW,
+        ("p15", "c13", 0, "c0", 3): TPIDRURO,
+        ("p15", "c13", 0, "c0", 4): TPIDRPRW,
+
+        ("p15", "c13", 4, "c0", 2): HTPIDR,
+
+        ("p15", "c14", 0, "c0", 0): CNTFRQ,
+        # TODO: CNTPCT 64-bit
+
+        ("p15", "c14", 0, "c1", 0): CNTKCTL,
+
+        ("p15", "c14", 0, "c2", 0): CNTP_TVAL,
+        ("p15", "c14", 0, "c2", 1): CNTP_CTL,
+
+        ("p15", "c14", 0, "c3", 0): CNTV_TVAL,
+        ("p15", "c14", 0, "c3", 1): CNTV_CTL,
+
+        # TODO: CNTVCT, CNTP_CVAL, CNTV_CVAL, CNTVOFF 64-bit
+
+        ("p15", "c14", 4, "c1", 0): CNTHCTL,
+
+        ("p15", "c14", 4, "c2", 0): CNTHP_TVAL,
+        ("p15", "c14", 4, "c2", 0): CNTHP_CTL
+
+        # TODO: CNTHP_CVAL 64-bit
+        }
+
+# liris.cnrs.fr/~mmrissa/lib/exe/fetch.php?media=armv7-a-r-manual.pdf
+EXCEPT_SOFT_BP = (1 << 1)
+
+EXCEPT_PRIV_INSN = (1 << 17)
+
+# CPSR: N Z C V
+
+
+def update_flag_zf(a):
+    return [ExprAssign(zf, ExprOp("FLAG_EQ", a))]
+
+
+def update_flag_zf_eq(a, b):
+    return [ExprAssign(zf, ExprOp("FLAG_EQ_CMP", a, b))]
+
+
+def update_flag_nf(arg):
+    return [
+        ExprAssign(
+            nf,
+            ExprOp("FLAG_SIGN_SUB", arg, ExprInt(0, arg.size))
+        )
+    ]
+
+
+def update_flag_zn(a):
+    e = []
+    e += update_flag_zf(a)
+    e += update_flag_nf(a)
+    return e
+
+
+# Instructions which use shifter's carry flag: ANDS, BICS, EORS, MOVS/RRX, MVNS, ORNS (TODO), ORRS, TEQ, TST
+def compute_rrx_carry(operation):
+    """
+    Returns a tuple (result, carry) corresponding to the RRX computation
+    @operation: The ExprOp operation
+    """
+    new_cf = operation.args[0][:1]
+    res = ExprCompose(operation.args[0][1:], cf)
+    return res, new_cf
+
+# XXX TODO: set cf if ROT imm in argument
+
+
+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 update_flag_add_cf(op1, op2):
+    "Compute cf in @op1 + @op2"
+    return [ExprAssign(cf, ExprOp("FLAG_ADD_CF", op1, op2))]
+
+
+def update_flag_add_of(op1, op2):
+    "Compute of in @op1 + @op2"
+    return [ExprAssign(of, ExprOp("FLAG_ADD_OF", op1, op2))]
+
+
+def update_flag_sub_cf(op1, op2):
+    "Compute CF in @op1 - @op2"
+    return [ExprAssign(cf, ExprOp("FLAG_SUB_CF", op1, op2) ^ ExprInt(1, 1))]
+
+
+def update_flag_sub_of(op1, op2):
+    "Compute OF in @op1 - @op2"
+    return [ExprAssign(of, ExprOp("FLAG_SUB_OF", op1, op2))]
+
+
+def update_flag_arith_add_co(arg1, arg2):
+    e = []
+    e += update_flag_add_cf(arg1, arg2)
+    e += update_flag_add_of(arg1, arg2)
+    return e
+
+
+def update_flag_arith_add_zn(arg1, arg2):
+    """
+    Compute zf and nf flags for (arg1 + arg2)
+    """
+    e = []
+    e += update_flag_zf_eq(arg1, -arg2)
+    e += [ExprAssign(nf, ExprOp("FLAG_SIGN_SUB", arg1, -arg2))]
+    return e
+
+
+def update_flag_arith_sub_co(arg1, arg2):
+    """
+    Compute cf and of flags for (arg1 - arg2)
+    """
+    e = []
+    e += update_flag_sub_cf(arg1, arg2)
+    e += update_flag_sub_of(arg1, arg2)
+    return e
+
+
+def update_flag_arith_sub_zn(arg1, arg2):
+    """
+    Compute zf and nf flags for (arg1 - arg2)
+    """
+    e = []
+    e += update_flag_zf_eq(arg1, arg2)
+    e += [ExprAssign(nf, ExprOp("FLAG_SIGN_SUB", arg1, arg2))]
+    return e
+
+
+
+
+def update_flag_zfaddwc_eq(arg1, arg2, arg3):
+    return [ExprAssign(zf, ExprOp("FLAG_EQ_ADDWC", arg1, arg2, arg3))]
+
+def update_flag_zfsubwc_eq(arg1, arg2, arg3):
+    return [ExprAssign(zf, ExprOp("FLAG_EQ_SUBWC", arg1, arg2, arg3))]
+
+
+def update_flag_arith_addwc_zn(arg1, arg2, arg3):
+    """
+    Compute znp flags for (arg1 + arg2 + cf)
+    """
+    e = []
+    e += update_flag_zfaddwc_eq(arg1, arg2, arg3)
+    e += [ExprAssign(nf, ExprOp("FLAG_SIGN_ADDWC", arg1, arg2, arg3))]
+    return e
+
+
+def update_flag_arith_subwc_zn(arg1, arg2, arg3):
+    """
+    Compute znp flags for (arg1 - (arg2 + cf))
+    """
+    e = []
+    e += update_flag_zfsubwc_eq(arg1, arg2, arg3)
+    e += [ExprAssign(nf, ExprOp("FLAG_SIGN_SUBWC", arg1, arg2, arg3))]
+    return e
+
+
+def update_flag_addwc_cf(op1, op2, op3):
+    "Compute cf in @res = @op1 + @op2 + @op3"
+    return [ExprAssign(cf, ExprOp("FLAG_ADDWC_CF", op1, op2, op3))]
+
+
+def update_flag_addwc_of(op1, op2, op3):
+    "Compute of in @res = @op1 + @op2 + @op3"
+    return [ExprAssign(of, ExprOp("FLAG_ADDWC_OF", op1, op2, op3))]
+
+
+def update_flag_arith_addwc_co(arg1, arg2, arg3):
+    e = []
+    e += update_flag_addwc_cf(arg1, arg2, arg3)
+    e += update_flag_addwc_of(arg1, arg2, arg3)
+    return e
+
+
+
+def update_flag_subwc_cf(op1, op2, op3):
+    "Compute cf in @res = @op1 + @op2 + @op3"
+    return [ExprAssign(cf, ExprOp("FLAG_SUBWC_CF", op1, op2, op3) ^ ExprInt(1, 1))]
+
+
+def update_flag_subwc_of(op1, op2, op3):
+    "Compute of in @res = @op1 + @op2 + @op3"
+    return [ExprAssign(of, ExprOp("FLAG_SUBWC_OF", op1, op2, op3))]
+
+
+def update_flag_arith_subwc_co(arg1, arg2, arg3):
+    e = []
+    e += update_flag_subwc_cf(arg1, arg2, arg3)
+    e += update_flag_subwc_of(arg1, arg2, arg3)
+    return e
+
+# Utility function for flag computation when it depends on the mode
+def isThumb(lifter):
+    return isinstance(lifter, (Lifter_Armtl, Lifter_Armtb))
+
+
+def get_dst(a):
+    if a == PC:
+        return PC
+    return None
+
+# instruction definition ##############
+
+
+def adc(ir, instr, a, b, c=None):
+    e = []
+    if c is None:
+        b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
+    arg1, arg2 = b, c
+    r = b + c + cf.zeroExtend(32)
+    if instr.name == 'ADCS' and a != PC:
+        e += update_flag_arith_addwc_zn(arg1, arg2, cf)
+        e += update_flag_arith_addwc_co(arg1, arg2, cf)
+    e.append(ExprAssign(a, r))
+    dst = get_dst(a)
+    if dst is not None:
+        e.append(ExprAssign(ir.IRDst, r))
+    return e, []
+
+
+def add(ir, instr, a, b, c=None):
+    e = []
+    if c is None:
+        b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
+    arg1, arg2 = b, c
+    r = b + c
+    if instr.name == 'ADDS' and a != PC:
+        e += update_flag_arith_add_zn(arg1, arg2)
+        e += update_flag_arith_add_co(arg1, arg2)
+    e.append(ExprAssign(a, r))
+    dst = get_dst(a)
+    if dst is not None:
+        e.append(ExprAssign(ir.IRDst, r))
+    return e, []
+
+
+def l_and(ir, instr, a, b, c=None):
+    setflags = (instr.name == 'ANDS') and a != PC
+    if c is None:
+        b, c = a, b
+    if c.is_op():
+        e, extra_ir = _shift_rotate_tpl(ir, instr, a, c, onlyCarry=setflags)
+        # get back the result
+        c = e.pop(0).src
+    else:
+        e = []
+        extra_ir = []
+    r = b & c
+    if setflags:
+        e += [ExprAssign(zf, ExprOp('FLAG_EQ_AND', b, c))]
+        e += update_flag_nf(r)
+
+    e.append(ExprAssign(a, r))
+    dst = get_dst(a)
+    if dst is not None:
+        e.append(ExprAssign(ir.IRDst, r))
+    return e, extra_ir
+
+def sub(ir, instr, a, b, c=None):
+    e = []
+    if c is None:
+        b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
+    r = b - c
+    e.append(ExprAssign(a, r))
+    dst = get_dst(a)
+    if dst is not None:
+        e.append(ExprAssign(ir.IRDst, r))
+    return e, []
+
+
+def subs(ir, instr, a, b, c=None):
+    e = []
+    if c is None:
+        b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
+    arg1, arg2 = b, c
+    r = b - c
+    e += update_flag_arith_sub_zn(arg1, arg2)
+    e += update_flag_arith_sub_co(arg1, arg2)
+    e.append(ExprAssign(a, r))
+    dst = get_dst(a)
+    if dst is not None:
+        e.append(ExprAssign(ir.IRDst, r))
+    return e, []
+
+
+def eor(ir, instr, a, b, c=None):
+    e = []
+    if c is None:
+        b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
+    r = b ^ c
+    e.append(ExprAssign(a, r))
+    dst = get_dst(a)
+    if dst is not None:
+        e.append(ExprAssign(ir.IRDst, r))
+    return e, []
+
+
+def eors(ir, instr, a, b, c=None):
+    setflags = a != PC
+    if c is None:
+        b, c = a, b
+    if c.is_op():
+        e, extra_ir = _shift_rotate_tpl(ir, instr, a, c, onlyCarry=setflags)
+        # get back the result
+        c = e.pop(0).src
+    else:
+        e = []
+        extra_ir = []
+    arg1, arg2 = b, c
+    r = arg1 ^ arg2
+
+    e += [ExprAssign(zf, ExprOp('FLAG_EQ_CMP', arg1, arg2))]
+    e += update_flag_nf(r)
+
+    e.append(ExprAssign(a, r))
+    dst = get_dst(a)
+    if dst is not None:
+        e.append(ExprAssign(ir.IRDst, r))
+    return e, extra_ir
+
+
+def rsb(ir, instr, a, b, c=None):
+    e = []
+    if c is None:
+        b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
+    arg1, arg2 = c, b
+    r = arg1 - arg2
+    e.append(ExprAssign(a, r))
+    dst = get_dst(a)
+    if dst is not None:
+        e.append(ExprAssign(ir.IRDst, r))
+    return e, []
+
+
+def rsbs(ir, instr, a, b, c=None):
+    e = []
+    if c is None:
+        b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
+    arg1, arg2 = c, b
+    r = arg1 - arg2
+    e += update_flag_arith_sub_zn(arg1, arg2)
+    e += update_flag_arith_sub_co(arg1, arg2)
+    e.append(ExprAssign(a, r))
+    dst = get_dst(a)
+    if dst is not None:
+        e.append(ExprAssign(ir.IRDst, r))
+    return e, []
+
+
+def sbc(ir, instr, a, b, c=None):
+    e = []
+    if c is None:
+        b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
+    arg1, arg2 = b, c
+    r = arg1 - (arg2 + (~cf).zeroExtend(32))
+    e.append(ExprAssign(a, r))
+    dst = get_dst(a)
+    if dst is not None:
+        e.append(ExprAssign(ir.IRDst, r))
+    return e, []
+
+
+def sbcs(ir, instr, a, b, c=None):
+    e = []
+    if c is None:
+        b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
+    arg1, arg2 = b, c
+    r = arg1 - (arg2 + (~cf).zeroExtend(32))
+
+    e += update_flag_arith_subwc_zn(arg1, arg2, ~cf)
+    e += update_flag_arith_subwc_co(arg1, arg2, ~cf)
+
+    e.append(ExprAssign(a, r))
+    dst = get_dst(a)
+    if dst is not None:
+        e.append(ExprAssign(ir.IRDst, r))
+    return e, []
+
+
+def rsc(ir, instr, a, b, c=None):
+    e = []
+    if c is None:
+        b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
+    arg1, arg2 = c, b
+    r = arg1 - (arg2 + (~cf).zeroExtend(32))
+    e.append(ExprAssign(a, r))
+    dst = get_dst(a)
+    if dst is not None:
+        e.append(ExprAssign(ir.IRDst, r))
+    return e, []
+
+
+def rscs(ir, instr, a, b, c=None):
+    e = []
+    if c is None:
+        b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
+    arg1, arg2 = c, b
+    r = arg1 - (arg2 + (~cf).zeroExtend(32))
+
+    e += update_flag_arith_subwc_zn(arg1, arg2, ~cf)
+    e += update_flag_arith_subwc_co(arg1, arg2, ~cf)
+
+    e.append(ExprAssign(a, r))
+
+    dst = get_dst(a)
+    if dst is not None:
+        e.append(ExprAssign(ir.IRDst, r))
+    return e, []
+
+
+def tst(ir, instr, a, b):
+    setflags = a != PC
+    if b.is_op():
+        e, extra_ir = _shift_rotate_tpl(ir, instr, a, b, onlyCarry=setflags)
+        # get back the result
+        b = e.pop(0).src
+    else:
+        e = []
+        extra_ir = []
+    arg1, arg2 = a, b
+    r = arg1 & arg2
+
+    e += [ExprAssign(zf, ExprOp('FLAG_EQ_AND', arg1, arg2))]
+    e += update_flag_nf(r)
+
+    return e, extra_ir
+
+
+def teq(ir, instr, a, b, c=None):
+    setflags = a != PC
+    if b.is_op():
+        e, extra_ir = _shift_rotate_tpl(ir, instr, a, b, onlyCarry=setflags)
+        # get back the result
+        b = e.pop(0).src
+    else:
+        e = []
+        extra_ir = []
+    if c is None:
+        b, c = a, b
+    arg1, arg2 = b, c
+    r = arg1 ^ arg2
+
+    e += [ExprAssign(zf, ExprOp('FLAG_EQ_CMP', arg1, arg2))]
+    e += update_flag_nf(r)
+
+    return e, extra_ir
+
+
+def l_cmp(ir, instr, a, b, c=None):
+    e = []
+    if c is None:
+        b, c = a, b
+    arg1, arg2 = b, c
+    e += update_flag_arith_sub_zn(arg1, arg2)
+    e += update_flag_arith_sub_co(arg1, arg2)
+    return e, []
+
+
+def cmn(ir, instr, a, b, c=None):
+    e = []
+    if c is None:
+        b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
+    arg1, arg2 = b, c
+    e += update_flag_arith_add_zn(arg1, arg2)
+    e += update_flag_arith_add_co(arg1, arg2)
+    return e, []
+
+
+def orr(ir, instr, a, b, c=None):
+    e = []
+    if c is None:
+        b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
+    r = b | c
+    e.append(ExprAssign(a, r))
+    dst = get_dst(a)
+    if dst is not None:
+        e.append(ExprAssign(ir.IRDst, r))
+    return e, []
+
+
+def orn(ir, instr, a, b, c=None):
+    e = []
+    if c is None:
+        b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
+    r = ~(b | c)
+    e.append(ExprAssign(a, r))
+    dst = get_dst(a)
+    if dst is not None:
+        e.append(ExprAssign(ir.IRDst, r))
+    return e, []
+
+
+def orrs(ir, instr, a, b, c=None):
+    setflags = a != PC
+    if c is None:
+        b, c = a, b
+    if c.is_op():
+        e, extra_ir = _shift_rotate_tpl(ir, instr, a, c, onlyCarry=setflags)
+        # get back the result
+        c = e.pop(0).src
+    else:
+        e = []
+        extra_ir = []
+    arg1, arg2 = b, c
+    r = arg1 | arg2
+
+    e += [ExprAssign(zf, ExprOp('FLAG_EQ', r))]
+    e += update_flag_nf(r)
+
+    e.append(ExprAssign(a, r))
+    dst = get_dst(a)
+    if dst is not None:
+        e.append(ExprAssign(ir.IRDst, r))
+    return e, extra_ir
+
+
+def mov(ir, instr, a, b):
+    if b.is_op():
+        return _shift_rotate_tpl(ir, instr, a, b, setflags=False)
+    # TODO handle cf
+    e = [ExprAssign(a, b)]
+    dst = get_dst(a)
+    if dst is not None:
+        e.append(ExprAssign(ir.IRDst, b))
+    return e, []
+
+
+def movt(ir, instr, a, b):
+    r = a | b << ExprInt(16, 32)
+    e = [ExprAssign(a, r)]
+    dst = get_dst(a)
+    if dst is not None:
+        e.append(ExprAssign(ir.IRDst, r))
+    return e, []
+
+
+def _shift_rotate_tpl(ir, instr, dst, shift_operation, setflags=False, is_not=False, onlyCarry=False):
+    """
+    Template to generate a shift/rotate
+    A temporary basic block is generated to handle 0-shift
+    @dst: destination
+    @shift_operation: the shift/rotate operation (ExprOp)
+    @setflags: (optional) if set, flags are updated (ZNC)
+    @onlyCarry: (optional) if set, Z and N flags won't be updated except if setflags is set.
+    @is_not: (optional) if set, behaves as MVN/MVNS
+    """
+    op = shift_operation.op
+    # Compute carry (+ result for rrx)
+    if op == 'rrx':
+        res, new_cf = compute_rrx_carry(shift_operation)
+        shifter = ExprInt(1, 8)
+    elif op in ['<<', '>>', 'a>>']:
+        shifter = shift_operation.args[1]
+        if setflags or onlyCarry:
+            new_cf = ExprOp(op, shift_operation.args[0], shifter - ExprInt(1, size=shifter.size))
+            left = op[-1] == '<'
+            new_cf = new_cf.msb() if left else new_cf[:1]
+        res = shift_operation
+    elif op == '>>>':
+        shifter = shift_operation.args[1]
+        if setflags or onlyCarry:
+            new_cf = shift_operation.msb()
+        res = shift_operation
+    else:
+        raise NotImplementedError(f"Unknown shift / rotate operation : {op}")
+
+    # NOT the result and use it for ZN flags computations
+    if is_not:
+        res ^= ExprInt(-1, res.size)
+    # Build basic blocks
+    e_do = []
+    e = [ExprAssign(dst, res)]
+    if setflags:
+        e += update_flag_zn(res)
+    if setflags or onlyCarry:
+        e_do += [ExprAssign(cf, expr_simp(new_cf))]
+    # Don't generate conditional shifter on constant
+    if shifter.is_int():
+        if shifter.is_int(0):
+            # assignement + flags if setflags except cf
+            return (e, [])
+        else:
+            # assignement + flags if setflags
+            return (e + e_do, [])
+
+    loc_do, loc_do_expr = ir.gen_loc_key_and_expr(ir.IRDst.size)
+    loc_skip = ir.get_next_loc_key(instr)
+    loc_skip_expr = ExprLoc(loc_skip, ir.IRDst.size)
+    isPC = get_dst(dst)
+    if isPC is not None:
+        # Not really a Loc in this case
+        loc_skip_expr = res
+    e_do.append(ExprAssign(ir.IRDst, loc_skip_expr))
+    e.append(ExprAssign(
+        ir.IRDst, ExprCond(shifter, loc_do_expr, loc_skip_expr)))
+    return (e, [IRBlock(ir.loc_db, loc_do, [AssignBlock(e_do, instr)])])
+
+
+
+def movs(ir, instr, a, b):
+    e = []
+    # handle shift / rotate
+    if b.is_op():
+        return _shift_rotate_tpl(ir, instr, a, b, setflags=a != PC)
+
+
+    e.append(ExprAssign(a, b))
+    # TODO handle cf
+    e += [ExprAssign(zf, ExprOp('FLAG_EQ', b))]
+    e += update_flag_nf(b)
+
+    dst = get_dst(a)
+    if dst is not None:
+        e.append(ExprAssign(ir.IRDst, b))
+    return e, []
+
+
+def mvn(ir, instr, a, b):
+    if b.is_op():
+        return _shift_rotate_tpl(ir, instr, a, b, setflags=False, is_not=True)
+    r = b ^ ExprInt(-1, 32)
+    # TODO handle cf
+    e = [ExprAssign(a, r)]
+    dst = get_dst(a)
+    if dst is not None:
+        e.append(ExprAssign(ir.IRDst, r))
+    return e, []
+
+
+def mvns(ir, instr, a, b):
+    if b.is_op():
+        return _shift_rotate_tpl(ir, instr, a, b, setflags= a != PC, is_not=True)
+    e = []
+    r = b ^ ExprInt(-1, 32)
+    e.append(ExprAssign(a, r))
+    # TODO handle cf
+    e += [ExprAssign(zf, ExprOp('FLAG_EQ', r))]
+    e += update_flag_nf(r)
+
+    dst = get_dst(a)
+    if dst is not None:
+        e.append(ExprAssign(ir.IRDst, r))
+    return e, []
+
+
+
+def mrs(ir, instr, a, b):
+    e = []
+    if b.is_id('CPSR_cxsf'):
+        out = []
+        out.append(ExprInt(0x10, 28))
+        out.append(of)
+        out.append(cf)
+        out.append(zf)
+        out.append(nf)
+        e.append(ExprAssign(a, ExprCompose(*out)))
+    else:
+        raise NotImplementedError("MRS not implemented")
+    return e, []
+
+def msr(ir, instr, a, b):
+    e = []
+    if a.is_id('CPSR_cf'):
+        e.append(ExprAssign(nf, b[31:32]))
+        e.append(ExprAssign(zf, b[30:31]))
+        e.append(ExprAssign(cf, b[29:30]))
+        e.append(ExprAssign(of, b[28:29]))
+    else:
+        raise NotImplementedError("MSR not implemented")
+    return e, []
+
+
+def neg(ir, instr, a, b):
+    e = []
+    r = - b
+    e.append(ExprAssign(a, r))
+    dst = get_dst(a)
+    if dst is not None:
+        e.append(ExprAssign(ir.IRDst, r))
+    return e, []
+
+def negs(ir, instr, a, b):
+    return subs(ir, instr, a, ExprInt(0, b.size), b)
+
+def bic(ir, instr, a, b, c=None):
+    e = []
+    if c is None:
+        b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
+    r = b & (c ^ ExprInt(-1, 32))
+    e.append(ExprAssign(a, r))
+    dst = get_dst(a)
+    if dst is not None:
+        e.append(ExprAssign(ir.IRDst, r))
+    return e, []
+
+
+def bics(ir, instr, a, b, c=None):
+    setflags = a != PC
+    if c is None:
+        b, c = a, b
+    if c.is_op():
+        e, extra_ir = _shift_rotate_tpl(ir, instr, a, c, onlyCarry=setflags)
+        # get back the result
+        c = e.pop(0).src
+    else:
+        e = []
+        extra_ir = []
+    tmp1, tmp2 = b, ~c
+    r = tmp1 & tmp2
+
+    e += [ExprAssign(zf, ExprOp('FLAG_EQ_AND', tmp1, tmp2))]
+    e += update_flag_nf(r)
+
+    e.append(ExprAssign(a, r))
+    dst = get_dst(a)
+    if dst is not None:
+        e.append(ExprAssign(ir.IRDst, r))
+    return e, extra_ir
+
+
+def sdiv(ir, instr, a, b, c=None):
+    e = []
+    if c is None:
+        b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
+
+    loc_div = ExprLoc(ir.loc_db.add_location(), ir.IRDst.size)
+    loc_except = ExprId(ir.loc_db.add_location(), ir.IRDst.size)
+    loc_next = ExprLoc(ir.get_next_loc_key(instr), ir.IRDst.size)
+
+    e.append(ExprAssign(ir.IRDst, ExprCond(c, loc_div, loc_except)))
+
+    do_except = []
+    do_except.append(ExprAssign(exception_flags, ExprInt(EXCEPT_DIV_BY_ZERO, exception_flags.size)))
+    do_except.append(ExprAssign(ir.IRDst, loc_next))
+    blk_except = IRBlock(ir.loc_db, loc_except.loc_key, [AssignBlock(do_except, instr)])
+
+
+
+    r = ExprOp("sdiv", b, c)
+    do_div = []
+    do_div.append(ExprAssign(a, r))
+    dst = get_dst(a)
+    if dst is not None:
+        do_div.append(ExprAssign(ir.IRDst, r))
+
+    do_div.append(ExprAssign(ir.IRDst, loc_next))
+    blk_div = IRBlock(ir.loc_db, loc_div.loc_key, [AssignBlock(do_div, instr)])
+
+    return e, [blk_div, blk_except]
+
+
+def udiv(ir, instr, a, b, c=None):
+    e = []
+    if c is None:
+        b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
+
+
+
+    loc_div = ExprLoc(ir.loc_db.add_location(), ir.IRDst.size)
+    loc_except = ExprLoc(ir.loc_db.add_location(), ir.IRDst.size)
+    loc_next = ExprLoc(ir.get_next_loc_key(instr), ir.IRDst.size)
+
+    e.append(ExprAssign(ir.IRDst, ExprCond(c, loc_div, loc_except)))
+
+    do_except = []
+    do_except.append(ExprAssign(exception_flags, ExprInt(EXCEPT_DIV_BY_ZERO, exception_flags.size)))
+    do_except.append(ExprAssign(ir.IRDst, loc_next))
+    blk_except = IRBlock(ir.loc_db, loc_except.loc_key, [AssignBlock(do_except, instr)])
+
+
+    r = ExprOp("udiv", b, c)
+    do_div = []
+    do_div.append(ExprAssign(a, r))
+    dst = get_dst(a)
+    if dst is not None:
+        do_div.append(ExprAssign(ir.IRDst, r))
+
+    do_div.append(ExprAssign(ir.IRDst, loc_next))
+    blk_div = IRBlock(ir.loc_db, loc_div.loc_key, [AssignBlock(do_div, instr)])
+
+    return e, [blk_div, blk_except]
+
+
+def mla(ir, instr, a, b, c, d):
+    e = []
+    r = (b * c) + d
+    e.append(ExprAssign(a, r))
+    dst = get_dst(a)
+    if dst is not None:
+        e.append(ExprAssign(ir.IRDst, r))
+    return e, []
+
+
+def mlas(ir, instr, a, b, c, d):
+    e = []
+    r = (b * c) + d
+    e += update_flag_zn(r)
+    e.append(ExprAssign(a, r))
+    dst = get_dst(a)
+    if dst is not None:
+        e.append(ExprAssign(ir.IRDst, r))
+    return e, []
+
+
+def mls(ir, instr, a, b, c, d):
+    e = []
+    r = d - (b * c)
+    e.append(ExprAssign(a, r))
+    dst = get_dst(a)
+    if dst is not None:
+        e.append(ExprAssign(ir.IRDst, r))
+    return e, []
+
+
+def mul(ir, instr, a, b, c=None):
+    e = []
+    if c is None:
+        b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
+    r = b * c
+    e.append(ExprAssign(a, r))
+    dst = get_dst(a)
+    if dst is not None:
+        e.append(ExprAssign(ir.IRDst, r))
+    return e, []
+
+
+def muls(ir, instr, a, b, c=None):
+    e = []
+    if c is None:
+        b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
+    r = b * c
+    e += update_flag_zn(r)
+    e.append(ExprAssign(a, r))
+    dst = get_dst(a)
+    if dst is not None:
+        e.append(ExprAssign(ir.IRDst, r))
+    return e, []
+
+def umull(ir, instr, a, b, c, d):
+    e = []
+    r = c.zeroExtend(64) * d.zeroExtend(64)
+    e.append(ExprAssign(a, r[0:32]))
+    e.append(ExprAssign(b, r[32:64]))
+    # r15/IRDst not allowed as output
+    return e, []
+
+def umlal(ir, instr, a, b, c, d):
+    e = []
+    r = c.zeroExtend(64) * d.zeroExtend(64) + ExprCompose(a, b)
+    e.append(ExprAssign(a, r[0:32]))
+    e.append(ExprAssign(b, r[32:64]))
+    # r15/IRDst not allowed as output
+    return e, []
+
+def smull(ir, instr, a, b, c, d):
+    e = []
+    r = c.signExtend(64) * d.signExtend(64)
+    e.append(ExprAssign(a, r[0:32]))
+    e.append(ExprAssign(b, r[32:64]))
+    # r15/IRDst not allowed as output
+    return e, []
+
+def smlal(ir, instr, a, b, c, d):
+    e = []
+    r = c.signExtend(64) * d.signExtend(64) + ExprCompose(a, b)
+    e.append(ExprAssign(a, r[0:32]))
+    e.append(ExprAssign(b, r[32:64]))
+    # r15/IRDst not allowed as output
+    return e, []
+
+def b(ir, instr, a):
+    e = []
+    e.append(ExprAssign(PC, a))
+    e.append(ExprAssign(ir.IRDst, a))
+    return e, []
+
+
+def bl(ir, instr, a):
+    e = []
+    l = ExprInt(instr.offset + instr.l, 32)
+    e.append(ExprAssign(PC, a))
+    e.append(ExprAssign(ir.IRDst, a))
+    e.append(ExprAssign(LR, l))
+    return e, []
+
+
+def bx(ir, instr, a):
+    e = []
+    e.append(ExprAssign(PC, a))
+    e.append(ExprAssign(ir.IRDst, a))
+    return e, []
+
+
+def blx(ir, instr, a):
+    e = []
+    l = ExprInt(instr.offset + instr.l, 32)
+    e.append(ExprAssign(PC, a))
+    e.append(ExprAssign(ir.IRDst, a))
+    e.append(ExprAssign(LR, l))
+    return e, []
+
+
+def st_ld_r(ir, instr, a, a2, b, store=False, size=32, s_ext=False, z_ext=False):
+    e = []
+    wb = False
+    postinc = False
+    b = b.ptr
+    if isinstance(b, ExprOp):
+        if b.op == "wback":
+            wb = True
+            b = b.args[0]
+        if b.op == "postinc":
+            postinc = True
+    if isinstance(b, ExprOp) and b.op in ["postinc", 'preinc']:
+        # XXX TODO CHECK
+        base, off = b.args[0],  b.args[1]  # ExprInt(size/8, 32)
+    else:
+        base, off = b, ExprInt(0, 32)
+    if postinc:
+        ad = base
+    else:
+        ad = base + off
+
+    # PC base lookup uses PC 4 byte alignment
+    ad = ad.replace_expr({PC: PC & ExprInt(0xFFFFFFFC, 32)})
+
+    dmem = False
+    if size in [8, 16]:
+        if store:
+            a = a[:size]
+            m = ExprMem(ad, size=size)
+        elif s_ext:
+            m = ExprMem(ad, size=size).signExtend(a.size)
+        elif z_ext:
+            m = ExprMem(ad, size=size).zeroExtend(a.size)
+        else:
+            raise ValueError('unhandled case')
+    elif size == 32:
+        m = ExprMem(ad, size=size)
+    elif size == 64:
+        assert a2 is not None
+        m = ExprMem(ad, size=32)
+        dmem = True
+        size = 32
+    else:
+        raise ValueError('the size DOES matter')
+    dst = None
+
+    if store:
+        e.append(ExprAssign(m, a))
+        if dmem:
+            e.append(ExprAssign(ExprMem(ad + ExprInt(4, 32), size=size), a2))
+    else:
+        if a == PC:
+            dst = PC
+            e.append(ExprAssign(ir.IRDst, m))
+        e.append(ExprAssign(a, m))
+        if dmem:
+            e.append(ExprAssign(a2, ExprMem(ad + ExprInt(4, 32), size=size)))
+
+    # XXX TODO check multiple write cause by wb
+    if wb or postinc:
+        e.append(ExprAssign(base, base + off))
+    return e, []
+
+
+def ldr(ir, instr, a, b):
+    return st_ld_r(ir, instr, a, None, b, store=False)
+
+
+def ldrd(ir, instr, a, b, c=None):
+    if c is None:
+        a2 = ir.arch.regs.all_regs_ids[ir.arch.regs.all_regs_ids.index(a) + 1]
+    else:
+        a2 = b
+        b = c
+    return st_ld_r(ir, instr, a, a2, b, store=False, size=64)
+
+
+def l_str(ir, instr, a, b):
+    return st_ld_r(ir, instr, a, None, b, store=True)
+
+
+def l_strd(ir, instr, a, b, c=None):
+    if c is None:
+        a2 = ir.arch.regs.all_regs_ids[ir.arch.regs.all_regs_ids.index(a) + 1]
+    else:
+        a2 = b
+        b = c
+    return st_ld_r(ir, instr, a, a2, b, store=True, size=64)
+
+def ldrb(ir, instr, a, b):
+    return st_ld_r(ir, instr, a, None, b, store=False, size=8, z_ext=True)
+
+def ldrsb(ir, instr, a, b):
+    return st_ld_r(ir, instr, a, None, b, store=False, size=8, s_ext=True, z_ext=False)
+
+def strb(ir, instr, a, b):
+    return st_ld_r(ir, instr, a, None, b, store=True, size=8)
+
+def ldrh(ir, instr, a, b):
+    return st_ld_r(ir, instr, a, None, b, store=False, size=16, z_ext=True)
+
+
+def strh(ir, instr, a, b):
+    return st_ld_r(ir, instr, a, None, b, store=True, size=16, z_ext=True)
+
+
+def ldrsh(ir, instr, a, b):
+    return st_ld_r(ir, instr, a, None, b, store=False, size=16, s_ext=True, z_ext=False)
+
+
+def st_ld_m(ir, instr, a, b, store=False, postinc=False, updown=False):
+    e = []
+    wb = False
+    dst = None
+    if isinstance(a, ExprOp) and a.op == 'wback':
+        wb = True
+        a = a.args[0]
+    if isinstance(b, ExprOp) and b.op == 'sbit':
+        b = b.args[0]
+    regs = b.args
+    base = a
+    if updown:
+        step = 4
+    else:
+        step = -4
+        regs = regs[::-1]
+    if postinc:
+        pass
+    else:
+        base += ExprInt(step, 32)
+    for i, r in enumerate(regs):
+        ad = base + ExprInt(i * step, 32)
+        if store:
+            e.append(ExprAssign(ExprMem(ad, 32), r))
+        else:
+            e.append(ExprAssign(r, ExprMem(ad, 32)))
+            if r == PC:
+                e.append(ExprAssign(ir.IRDst, ExprMem(ad, 32)))
+    # XXX TODO check multiple write cause by wb
+    if wb:
+        if postinc:
+            e.append(ExprAssign(a, base + ExprInt(len(regs) * step, 32)))
+        else:
+            e.append(ExprAssign(a, base + ExprInt((len(regs) - 1) * step, 32)))
+    if store:
+        pass
+    else:
+        assert(isinstance(b, ExprOp) and b.op == "reglist")
+
+    return e, []
+
+
+def ldmia(ir, instr, a, b):
+    return st_ld_m(ir, instr, a, b, store=False, postinc=True, updown=True)
+
+
+def ldmib(ir, instr, a, b):
+    return st_ld_m(ir, instr, a, b, store=False, postinc=False, updown=True)
+
+
+def ldmda(ir, instr, a, b):
+    return st_ld_m(ir, instr, a, b, store=False, postinc=True, updown=False)
+
+
+def ldmdb(ir, instr, a, b):
+    return st_ld_m(ir, instr, a, b, store=False, postinc=False, updown=False)
+
+
+def stmia(ir, instr, a, b):
+    return st_ld_m(ir, instr, a, b, store=True, postinc=True, updown=True)
+
+
+def stmib(ir, instr, a, b):
+    return st_ld_m(ir, instr, a, b, store=True, postinc=False, updown=True)
+
+
+def stmda(ir, instr, a, b):
+    return st_ld_m(ir, instr, a, b, store=True, postinc=True, updown=False)
+
+
+def stmdb(ir, instr, a, b):
+    return st_ld_m(ir, instr, a, b, store=True, postinc=False, updown=False)
+
+
+def svc(ir, instr, a):
+    e = []
+    except_int = EXCEPT_INT_XX
+    e.append(ExprAssign(exception_flags, ExprInt(except_int, 32)))
+    e.append(ExprAssign(interrupt_num, a))
+    return e, []
+
+
+def und(ir, instr, a, b):
+    # XXX TODO implement
+    e = []
+    return e, []
+
+def lsr(ir, instr, a, b, c=None):
+    e = []
+    if c is None:
+        b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
+    return _shift_rotate_tpl(ir, instr, a, b >> c, setflags=False)
+
+
+def lsrs(ir, instr, a, b, c=None):
+    e = []
+    if c is None:
+        b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
+    return _shift_rotate_tpl(ir, instr, a, b >> c, setflags= a != PC)
+
+def asr(ir, instr, a, b, c=None):
+    e = []
+    if c is None:
+        b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
+    r = ExprOp("a>>", b, c)
+    return _shift_rotate_tpl(ir, instr, a, r, setflags=False)
+
+def asrs(ir, instr, a, b, c=None):
+    e = []
+    if c is None:
+        b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
+    r = ExprOp("a>>", b, c)
+    return _shift_rotate_tpl(ir, instr, a, r, setflags= a != PC)
+
+def lsl(ir, instr, a, b, c=None):
+    e = []
+    if c is None:
+        b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
+    return _shift_rotate_tpl(ir, instr, a, b << c, setflags=False)
+
+
+
+def lsls(ir, instr, a, b, c=None):
+    e = []
+    if c is None:
+        b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
+    return _shift_rotate_tpl(ir, instr, a, b << c, setflags= a != PC)
+
+
+def rors(ir, instr, a, b):
+    e = []
+    r = ExprOp(">>>", a, b)
+    return _shift_rotate_tpl(ir, instr, a, r, setflags= a != PC)
+
+
+
+def push(ir, instr, a):
+    e = []
+    regs = list(a.args)
+    for i in range(len(regs)):
+        r = SP + ExprInt(-4 * len(regs) + 4 * i, 32)
+        e.append(ExprAssign(ExprMem(r, 32), regs[i]))
+    r = SP + ExprInt(-4 * len(regs), 32)
+    e.append(ExprAssign(SP, r))
+    return e, []
+
+
+def pop(ir, instr, a):
+    e = []
+    regs = list(a.args)
+    dst = None
+    for i in range(len(regs)):
+        r = SP + ExprInt(4 * i, 32)
+        e.append(ExprAssign(regs[i], ExprMem(r, 32)))
+        if regs[i] == ir.pc:
+            dst = ExprMem(r, 32)
+    r = SP + ExprInt(4 * len(regs), 32)
+    e.append(ExprAssign(SP, r))
+    if dst is not None:
+        e.append(ExprAssign(ir.IRDst, dst))
+    return e, []
+
+
+def cbz(ir, instr, a, b):
+    e = []
+    loc_next = ir.get_next_loc_key(instr)
+    loc_next_expr = ExprLoc(loc_next, 32)
+    e.append(ExprAssign(ir.IRDst, ExprCond(a, loc_next_expr, b)))
+    return e, []
+
+
+def cbnz(ir, instr, a, b):
+    e = []
+    loc_next = ir.get_next_loc_key(instr)
+    loc_next_expr = ExprLoc(loc_next, 32)
+    e.append(ExprAssign(ir.IRDst, ExprCond(a, b, loc_next_expr)))
+    return e, []
+
+
+def uxtb(ir, instr, a, b):
+    e = []
+    r = b[:8].zeroExtend(32)
+    e.append(ExprAssign(a, r))
+    dst = None
+    if PC in a.get_r():
+        dst = PC
+        e.append(ExprAssign(ir.IRDst, r))
+    return e, []
+
+def uxth(ir, instr, a, b):
+    e = []
+    r = b[:16].zeroExtend(32)
+    e.append(ExprAssign(a, r))
+    dst = None
+    if PC in a.get_r():
+        dst = PC
+        e.append(ExprAssign(ir.IRDst, r))
+    return e, []
+
+def sxtb(ir, instr, a, b):
+    e = []
+    r = b[:8].signExtend(32)
+    e.append(ExprAssign(a, r))
+    dst = None
+    if PC in a.get_r():
+        dst = PC
+        e.append(ExprAssign(ir.IRDst, r))
+    return e, []
+
+def sxth(ir, instr, a, b):
+    e = []
+    r = b[:16].signExtend(32)
+    e.append(ExprAssign(a, r))
+    dst = None
+    if PC in a.get_r():
+        dst = PC
+        e.append(ExprAssign(ir.IRDst, r))
+    return e, []
+
+
+def ubfx(ir, instr, a, b, c, d):
+    e = []
+    c = int(c)
+    d = int(d)
+    r = b[c:c+d].zeroExtend(32)
+    e.append(ExprAssign(a, r))
+    dst = None
+    if PC in a.get_r():
+        dst = PC
+        e.append(ExprAssign(ir.IRDst, r))
+    return e, []
+
+def bfc(ir, instr, a, b, c):
+    e = []
+    start = int(b)
+    stop = start + int(c)
+    out = []
+    last = 0
+    if start:
+        out.append(a[:start])
+        last = start
+    if stop - start:
+        out.append(ExprInt(0, 32)[last:stop])
+        last = stop
+    if last < 32:
+        out.append(a[last:])
+    r = ExprCompose(*out)
+    e.append(ExprAssign(a, r))
+    dst = None
+    if PC in a.get_r():
+        dst = PC
+        e.append(ExprAssign(ir.IRDst, r))
+    return e, []
+
+
+def pld(ir, instr, a):
+    e = []
+    return e, []
+
+
+def pldw(ir, instr, a):
+    e = []
+    return e, []
+
+
+def clz(ir, instr, a, b):
+    e = []
+    e.append(ExprAssign(a, ExprOp('cntleadzeros', b)))
+    return e, []
+
+def uxtab(ir, instr, a, b, c):
+    e = []
+    e.append(ExprAssign(a, b + (c & ExprInt(0xff, 32))))
+    return e, []
+
+
+def uxtah(ir, instr, a, b, c):
+    e = []
+    e.append(ExprAssign(a, b + (c & ExprInt(0xffff, 32))))
+    return e, []
+
+
+def bkpt(ir, instr, a):
+    e = []
+    e.append(ExprAssign(exception_flags, ExprInt(EXCEPT_SOFT_BP, 32)))
+    e.append(ExprAssign(bp_num, a))
+    return e, []
+
+
+def _extract_s16(arg, part):
+    if part == 'B': # bottom 16 bits
+        return arg[0:16]
+    elif part == 'T': # top 16 bits
+        return arg[16:32]
+
+
+def smul(ir, instr, a, b, c):
+    e = []
+    e.append(ExprAssign(a, _extract_s16(b, instr.name[4]).signExtend(32) * _extract_s16(c, instr.name[5]).signExtend(32)))
+    return e, []
+
+
+def smulw(ir, instr, a, b, c):
+    e = []
+    prod = b.signExtend(48) * _extract_s16(c, instr.name[5]).signExtend(48)
+    e.append(ExprAssign(a, prod[16:48]))
+    return e, [] # signed most significant 32 bits of the 48-bit result
+
+
+def tbb(ir, instr, a):
+    e = []
+    dst = PC + ExprInt(2, 32) * a.zeroExtend(32)
+    e.append(ExprAssign(PC, dst))
+    e.append(ExprAssign(ir.IRDst, dst))
+    return e, []
+
+
+def tbh(ir, instr, a):
+    e = []
+    dst = PC + ExprInt(2, 32) * a.zeroExtend(32)
+    e.append(ExprAssign(PC, dst))
+    e.append(ExprAssign(ir.IRDst, dst))
+    return e, []
+
+
+def smlabb(ir, instr, a, b, c, d):
+    e = []
+    result = (b[:16].signExtend(32) * c[:16].signExtend(32)) + d
+    e.append(ExprAssign(a, result))
+    return e, []
+
+
+def smlabt(ir, instr, a, b, c, d):
+    e = []
+    result = (b[:16].signExtend(32) * c[16:32].signExtend(32)) + d
+    e.append(ExprAssign(a, result))
+    return e, []
+
+
+def smlatb(ir, instr, a, b, c, d):
+    e = []
+    result = (b[16:32].signExtend(32) * c[:16].signExtend(32)) + d
+    e.append(ExprAssign(a, result))
+    return e, []
+
+
+def smlatt(ir, instr, a, b, c, d):
+    e = []
+    result = (b[16:32].signExtend(32) * c[16:32].signExtend(32)) + d
+    e.append(ExprAssign(a, result))
+    return e, []
+
+
+def uadd8(ir, instr, a, b, c):
+    e = []
+    sums = []
+    ges = []
+    for i in range(0, 32, 8):
+        sums.append(b[i:i+8] + c[i:i+8])
+        ges.append((b[i:i+8].zeroExtend(9) + c[i:i+8].zeroExtend(9))[8:9])
+
+    e.append(ExprAssign(a, ExprCompose(*sums)))
+
+    for i, value in enumerate(ges):
+        e.append(ExprAssign(ge_regs[i], value))
+    return e, []
+
+
+def sel(ir, instr, a, b, c):
+    e = []
+    cond = nf ^ of ^ ExprInt(1, 1)
+    parts = []
+    for i in range(4):
+        parts.append(ExprCond(ge_regs[i], b[i*8:(i+1)*8], c[i*8:(i+1)*8]))
+    result = ExprCompose(*parts)
+    e.append(ExprAssign(a, result))
+    return e, []
+
+
+def rev(ir, instr, a, b):
+    e = []
+    result = ExprCompose(b[24:32], b[16:24], b[8:16], b[:8])
+    e.append(ExprAssign(a, result))
+    return e, []
+
+
+def rev16(ir, instr, a, b):
+    e = []
+    result = ExprCompose(b[8:16], b[:8], b[24:32], b[16:24])
+    e.append(ExprAssign(a, result))
+    return e, []
+
+
+def nop(ir, instr):
+    e = []
+    return e, []
+
+
+def dsb(ir, instr, a):
+    # XXX TODO
+    e = []
+    return e, []
+
+def isb(ir, instr, a):
+    # XXX TODO
+    e = []
+    return e, []
+
+def cpsie(ir, instr, a):
+    # XXX TODO
+    e = []
+    return e, []
+
+
+def cpsid(ir, instr, a):
+    # XXX TODO
+    e = []
+    return e, []
+
+
+def wfe(ir, instr):
+    # XXX TODO
+    e = []
+    return e, []
+
+
+def wfi(ir, instr):
+    # XXX TODO
+    e = []
+    return e, []
+
+def adr(ir, instr, arg1, arg2):
+    e = []
+    e.append(ExprAssign(arg1, (PC & ExprInt(0xfffffffc, 32)) + arg2))
+    return e, []
+
+
+def pkhbt(ir, instr, arg1, arg2, arg3):
+    e = []
+    e.append(
+        ExprAssign(
+            arg1,
+            ExprCompose(
+                arg2[:16],
+                arg3[16:]
+            )
+        )
+    )
+    return e, []
+
+
+def pkhtb(ir, instr, arg1, arg2, arg3):
+    e = []
+    e.append(
+        ExprAssign(
+            arg1,
+            ExprCompose(
+                arg3[:16],
+                arg2[16:]
+            )
+        )
+    )
+    return e, []
+
+def mrc(ir, insr, arg1, arg2, arg3, arg4, arg5, arg6):
+    e = []
+    sreg = (str(arg1), str(arg4), int(arg2), str(arg5), int(arg6))
+    if sreg in coproc_reg_dict:
+        e.append(ExprAssign(arg3, coproc_reg_dict[sreg]))
+    else:
+        raise NotImplementedError("Unknown coprocessor register: %s %s %d %s %d" % (str(arg1), str(arg4), int(arg2), str(arg5), int(arg6)))
+
+    return e, []
+
+def mcr(ir, insr, arg1, arg2, arg3, arg4, arg5, arg6):
+    e = []
+    sreg = (str(arg1), str(arg4), int(arg2), str(arg5), int(arg6))
+    if sreg in coproc_reg_dict:
+        e.append(ExprAssign(coproc_reg_dict[sreg], arg3))
+    else:
+        raise NotImplementedError("Unknown coprocessor register: %s %s %d %s %d" % (str(arg1), str(arg4), int(arg2), str(arg5), int(arg6)))
+
+    return e, []
+
+COND_EQ = 0
+COND_NE = 1
+COND_CS = 2
+COND_CC = 3
+COND_MI = 4
+COND_PL = 5
+COND_VS = 6
+COND_VC = 7
+COND_HI = 8
+COND_LS = 9
+COND_GE = 10
+COND_LT = 11
+COND_GT = 12
+COND_LE = 13
+COND_AL = 14
+COND_NV = 15
+
+cond_dct = {
+    COND_EQ: "EQ",
+    COND_NE: "NE",
+    COND_CS: "CS",
+    COND_CC: "CC",
+    COND_MI: "MI",
+    COND_PL: "PL",
+    COND_VS: "VS",
+    COND_VC: "VC",
+    COND_HI: "HI",
+    COND_LS: "LS",
+    COND_GE: "GE",
+    COND_LT: "LT",
+    COND_GT: "GT",
+    COND_LE: "LE",
+    COND_AL: "AL",
+    # COND_NV: "NV",
+}
+
+cond_dct_inv = dict((name, num) for num, name in viewitems(cond_dct))
+
+
+"""
+Code            Meaning (for cmp or subs)                                  Flags Tested
+eq              Equal.                                                     Z==1
+ne              Not equal.                                                 Z==0
+cs or hs        Unsigned higher or same (or carry set).                    C==1
+cc or lo        Unsigned lower (or carry clear).                           C==0
+mi              Negative. The mnemonic stands for "minus".                 N==1
+pl              Positive or zero. The mnemonic stands for "plus".          N==0
+vs              Signed overflow. The mnemonic stands for "V set".          V==1
+vc              No signed overflow. The mnemonic stands for "V clear".     V==0
+hi              Unsigned higher.                                           (C==1) && (Z==0)
+ls              Unsigned lower or same.                                    (C==0) || (Z==1)
+ge              Signed greater than or equal.                              N==V
+lt              Signed less than.                                          N!=V
+gt              Signed greater than.                                       (Z==0) && (N==V)
+le              Signed less than or equal.                                 (Z==1) || (N!=V)
+al (or omitted) Always executed.        None tested.
+"""
+
+tab_cond = {COND_EQ: ExprOp("CC_EQ", zf),
+            COND_NE: ExprOp("CC_NE", zf),
+            COND_CS: ExprOp("CC_U>=", cf ^ ExprInt(1, 1)), # inv cf
+            COND_CC: ExprOp("CC_U<", cf ^ ExprInt(1, 1)), # inv cf
+            COND_MI: ExprOp("CC_NEG", nf),
+            COND_PL: ExprOp("CC_POS", nf),
+            COND_VS: ExprOp("CC_sOVR", of),
+            COND_VC: ExprOp("CC_sNOOVR", of),
+            COND_HI: ExprOp("CC_U>", cf ^ ExprInt(1, 1), zf), # inv cf
+            COND_LS: ExprOp("CC_U<=", cf ^ ExprInt(1, 1), zf), # inv cf
+            COND_GE: ExprOp("CC_S>=", nf, of),
+            COND_LT: ExprOp("CC_S<", nf, of),
+            COND_GT: ExprOp("CC_S>", nf, of, zf),
+            COND_LE: ExprOp("CC_S<=", nf, of, zf),
+            }
+
+
+
+
+
+def is_pc_written(ir, instr_ir):
+    all_pc = viewvalues(ir.mn.pc)
+    for ir in instr_ir:
+        if ir.dst in all_pc:
+            return True, ir.dst
+    return False, None
+
+
+def add_condition_expr(ir, instr, cond, instr_ir, extra_ir):
+    if cond == COND_AL:
+        return instr_ir, extra_ir
+    if not cond in tab_cond:
+        raise ValueError('unknown condition %r' % cond)
+    cond = tab_cond[cond]
+
+
+
+    loc_next = ir.get_next_loc_key(instr)
+    loc_next_expr = ExprLoc(loc_next, 32)
+    loc_do = ir.loc_db.add_location()
+    loc_do_expr = ExprLoc(loc_do, 32)
+
+    dst_cond = ExprCond(cond, loc_do_expr, loc_next_expr)
+    assert(isinstance(instr_ir, list))
+
+    has_irdst = False
+    for e in instr_ir:
+        if e.dst == ir.IRDst:
+            has_irdst = True
+            break
+    if not has_irdst:
+        instr_ir.append(ExprAssign(ir.IRDst, loc_next_expr))
+    e_do = IRBlock(ir.loc_db, loc_do, [AssignBlock(instr_ir, instr)])
+    e = [ExprAssign(ir.IRDst, dst_cond)]
+    return e, [e_do] + extra_ir
+
+mnemo_func = {}
+mnemo_func_cond = {}
+mnemo_condm0 = {'add': add,
+                'sub': sub,
+                'eor': eor,
+                'and': l_and,
+                'rsb': rsb,
+                'adc': adc,
+                'sbc': sbc,
+                'rsc': rsc,
+
+                'tst': tst,
+                'teq': teq,
+                'cmp': l_cmp,
+                'cmn': cmn,
+                'orr': orr,
+                'mov': mov,
+                'movt': movt,
+                'bic': bic,
+                'mvn': mvn,
+                'neg': neg,
+
+                'sdiv': sdiv,
+                'udiv': udiv,
+
+                'mrc': mrc,
+                'mcr': mcr,
+
+                'mul': mul,
+                'umull': umull,
+                'umlal': umlal,
+                'smull': smull,
+                'smlal': smlal,
+                'mla': mla,
+                'ldr': ldr,
+                'ldrd': ldrd,
+                'ldrsb': ldrsb,
+                'str': l_str,
+                'strd': l_strd,
+                'b': b,
+                'bl': bl,
+                'svc': svc,
+                'und': und,
+                'bx': bx,
+                'ldrh': ldrh,
+                'strh': strh,
+                'ldrsh': ldrsh,
+                'ldsh': ldrsh,
+                'uxtb': uxtb,
+                'uxth': uxth,
+                'sxtb': sxtb,
+                'sxth': sxth,
+                'ubfx': ubfx,
+                'bfc': bfc,
+                'rev': rev,
+                'rev16': rev16,
+                'clz': clz,
+                'uxtab': uxtab,
+                'uxtah': uxtah,
+                'bkpt': bkpt,
+                'smulbb': smul,
+                'smulbt': smul,
+                'smultb': smul,
+                'smultt': smul,
+                'smulwt': smulw,
+                'smulwb': smulw,
+
+                'pkhtb': pkhtb,
+                'pkhbt': pkhbt,
+
+                }
+
+mnemo_condm1 = {'adds': add,
+                'subs': subs,
+                'eors': eors,
+                'ands': l_and,
+                'rsbs': rsbs,
+                'adcs': adc,
+                'sbcs': sbcs,
+                'rscs': rscs,
+
+                'orrs': orrs,
+                'movs': movs,
+                'bics': bics,
+                'mvns': mvns,
+
+                'mrs': mrs,
+                'msr': msr,
+
+                'negs': negs,
+
+                'muls': muls,
+                'mls': mls,
+                'mlas': mlas,
+                'blx': blx,
+
+                'ldrb': ldrb,
+                'ldsb': ldrsb,
+                'strb': strb,
+                }
+
+mnemo_condm2 = {'ldmia': ldmia,
+                'ldmib': ldmib,
+                'ldmda': ldmda,
+                'ldmdb': ldmdb,
+
+                'ldmfa': ldmda,
+                'ldmfd': ldmia,
+                'ldmea': ldmdb,
+                'ldmed': ldmib,  # XXX
+
+
+                'stmia': stmia,
+                'stmib': stmib,
+                'stmda': stmda,
+                'stmdb': stmdb,
+
+                'stmfa': stmib,
+                'stmed': stmda,
+                'stmfd': stmdb,
+                'stmea': stmia,
+                }
+
+
+mnemo_nocond = {'lsr': lsr,
+                'lsrs': lsrs,
+                'lsl': lsl,
+                'lsls': lsls,
+                'rors': rors,
+                'push': push,
+                'pop': pop,
+                'asr': asr,
+                'asrs': asrs,
+                'cbz': cbz,
+                'cbnz': cbnz,
+                'pld': pld,
+                'pldw': pldw,
+                'tbb': tbb,
+                'tbh': tbh,
+                'nop': nop,
+                'dsb': dsb,
+                'isb': isb,
+                'cpsie': cpsie,
+                'cpsid': cpsid,
+                'wfe': wfe,
+                'wfi': wfi,
+                'adr': adr,
+                'orn': orn,
+                'smlabb': smlabb,
+                'smlabt': smlabt,
+                'smlatb': smlatb,
+                'smlatt': smlatt,
+                'uadd8': uadd8,
+                'sel': sel,
+                }
+
+mn_cond_x = [mnemo_condm0,
+             mnemo_condm1,
+             mnemo_condm2]
+
+for index, mn_base in enumerate(mn_cond_x):
+    for mn, mf in viewitems(mn_base):
+        for cond, cn in viewitems(cond_dct):
+            if cond == COND_AL:
+                cn = ""
+            cn = cn.lower()
+            if index == 0:
+                mn_mod = mn + cn
+            else:
+                mn_mod = mn[:-index] + cn + mn[-index:]
+            # print mn_mod
+            mnemo_func_cond[mn_mod] = cond, mf
+
+for name, mf in viewitems(mnemo_nocond):
+    mnemo_func_cond[name] = COND_AL, mf
+
+
+def split_expr_dst(ir, instr_ir):
+    out = []
+    dst = None
+    for i in instr_ir:
+        if i.dst == ir.pc:
+            out.append(i)
+            dst = ir.pc  # i.src
+        else:
+            out.append(i)
+    return out, dst
+
+
+def get_mnemo_expr(ir, instr, *args):
+    if not instr.name.lower() in mnemo_func_cond:
+        raise ValueError('unknown mnemo %s' % instr)
+    cond, mf = mnemo_func_cond[instr.name.lower()]
+    instr_ir, extra_ir = mf(ir, instr, *args)
+    instr, extra_ir = add_condition_expr(ir, instr, cond, instr_ir, extra_ir)
+    return instr, extra_ir
+
+get_arm_instr_expr = get_mnemo_expr
+
+
+class arminfo(object):
+    mode = "arm"
+    # offset
+
+
+class Lifter_Arml(Lifter):
+    def __init__(self, loc_db):
+        Lifter.__init__(self, mn_arm, "l", loc_db)
+        self.pc = PC
+        self.sp = SP
+        self.IRDst = ExprId('IRDst', 32)
+        self.addrsize = 32
+
+
+
+    def mod_pc(self, instr, instr_ir, extra_ir):
+        # fix PC (+8 for arm)
+        pc_fixed = {self.pc: ExprInt(instr.offset + 8, 32)}
+
+        for i, expr in enumerate(instr_ir):
+            dst, src = expr.dst, expr.src
+            if dst != self.pc:
+                dst = dst.replace_expr(pc_fixed)
+            src = src.replace_expr(pc_fixed)
+            instr_ir[i] = ExprAssign(dst, src)
+
+        for idx, irblock in enumerate(extra_ir):
+            extra_ir[idx] = irblock.modify_exprs(lambda expr: expr.replace_expr(pc_fixed) \
+                                                 if expr != self.pc else expr,
+                                                 lambda expr: expr.replace_expr(pc_fixed))
+
+    def get_ir(self, instr):
+        args = instr.args
+        # ir = get_mnemo_expr(self, self.name.lower(), *args)
+        if len(args) and isinstance(args[-1], ExprOp):
+            if (args[-1].op in ['<<', '>>', '<<a', 'a>>', '<<<', '>>>'] and
+                  isinstance(args[-1].args[-1], ExprId)):
+                args[-1] = 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)
+
+        self.mod_pc(instr, instr_ir, extra_ir)
+        return instr_ir, extra_ir
+
+    def parse_itt(self, instr):
+        name = instr.name
+        assert name.startswith('IT')
+        name = name[1:]
+        out = []
+        for hint in name:
+            if hint == 'T':
+                out.append(0)
+            elif hint == "E":
+                out.append(1)
+            else:
+                raise ValueError("IT name invalid %s" % instr)
+        return out, instr.args[0]
+
+    def do_it_block(self, loc, index, block, assignments, gen_pc_updt):
+        instr = block.lines[index]
+        it_hints, it_cond = self.parse_itt(instr)
+        cond_num = cond_dct_inv[it_cond.name]
+        cond_eq = tab_cond[cond_num]
+
+        if not index + len(it_hints) <= len(block.lines):
+            raise NotImplementedError("Split IT block non supported yet")
+
+        ir_blocks_all = []
+
+        # Gen dummy irblock for IT instr
+        loc_next = self.get_next_loc_key(instr)
+        dst = ExprAssign(self.IRDst, ExprLoc(loc_next, 32))
+        dst_blk = AssignBlock([dst], instr)
+        assignments.append(dst_blk)
+        irblock = IRBlock(self.loc_db, loc, assignments)
+        ir_blocks_all.append([irblock])
+
+        loc = loc_next
+        assignments = []
+        for hint in it_hints:
+            irblocks = []
+            index += 1
+            instr = block.lines[index]
+
+            # Add conditional jump to current irblock
+            loc_do = self.loc_db.add_location()
+            loc_next = self.get_next_loc_key(instr)
+
+            if hint:
+                local_cond = ~cond_eq
+            else:
+                local_cond = cond_eq
+            dst = ExprAssign(self.IRDst, ExprCond(local_cond, ExprLoc(loc_do, 32), ExprLoc(loc_next, 32)))
+            dst_blk = AssignBlock([dst], instr)
+            assignments.append(dst_blk)
+            irblock = IRBlock(self.loc_db, loc, assignments)
+
+            irblocks.append(irblock)
+
+            it_instr_irblocks = []
+            assignments = []
+            loc = loc_do
+
+            split = self.add_instr_to_current_state(
+                instr, block, assignments,
+                it_instr_irblocks, gen_pc_updt
+            )
+            if split:
+                raise NotImplementedError("Unsupported instr in IT block (%s)" % instr)
+
+            if it_instr_irblocks:
+                assert len(it_instr_irblocks) == 1
+                it_instr_irblocks = it_instr_irblocks.pop()
+            # Remove flags assignment if instr != [CMP, CMN, TST]
+            if instr.name not in ["CMP", "CMN", "TST"]:
+                # Fix assignments
+                out = []
+                for assignment in assignments:
+                    assignment = AssignBlock(
+                        {
+                            dst: src for (dst, src) in viewitems(assignment)
+                            if dst not in [zf, nf, of, cf]
+                        },
+                        assignment.instr
+                    )
+                    out.append(assignment)
+                assignments = out
+                # Fix extra irblocksx
+                new_irblocks = []
+                for irblock in it_instr_irblocks:
+                    out = []
+                    for tmp_assignment in irblock:
+                        assignment = AssignBlock(
+                            {
+                                dst: src for (dst, src) in viewitems(assignment)
+                                if dst not in [zf, nf, of, cf]
+                            },
+                            assignment.instr
+                        )
+                        out.append(assignment)
+                    new_irblock = IRBlock(self.loc_db, irblock.loc_key, out)
+                    new_irblocks.append(new_irblock)
+                it_instr_irblocks = new_irblocks
+
+            irblocks += it_instr_irblocks
+            dst = ExprAssign(self.IRDst, ExprLoc(loc_next, 32))
+            dst_blk = AssignBlock([dst], instr)
+            assignments.append(dst_blk)
+            irblock = IRBlock(self.loc_db, loc, assignments)
+            irblocks.append(irblock)
+            loc = loc_next
+            assignments = []
+            ir_blocks_all.append(irblocks)
+        return index, ir_blocks_all
+
+    def add_asmblock_to_ircfg(self, block, ircfg, gen_pc_updt=False):
+        """
+        Add a native block to the current IR
+        @block: native assembly block
+        @gen_pc_updt: insert PC update effects between instructions
+        """
+
+        it_hints = None
+        it_cond = None
+        label = block.loc_key
+        assignments = []
+        ir_blocks_all = []
+        index = -1
+        while index + 1 < len(block.lines):
+            index += 1
+            instr = block.lines[index]
+            if label is None:
+                assignments = []
+                label = self.get_loc_key_for_instr(instr)
+            if instr.name.startswith("IT"):
+                index, irblocks_it = self.do_it_block(label, index, block, assignments, gen_pc_updt)
+                for irblocks in irblocks_it:
+                    ir_blocks_all += irblocks
+                label = None
+                continue
+
+            split = self.add_instr_to_current_state(
+                instr, block, assignments,
+                ir_blocks_all, gen_pc_updt
+            )
+            if split:
+                ir_blocks_all.append(IRBlock(self.loc_db, label, assignments))
+                label = None
+                assignments = []
+        if label is not None:
+            ir_blocks_all.append(IRBlock(self.loc_db, label, assignments))
+
+        new_ir_blocks_all = self.post_add_asmblock_to_ircfg(block, ircfg, ir_blocks_all)
+        for irblock in new_ir_blocks_all:
+            ircfg.add_irblock(irblock)
+        return new_ir_blocks_all
+
+
+
+class Lifter_Armb(Lifter_Arml):
+    def __init__(self, loc_db):
+        Lifter.__init__(self, mn_arm, "b", loc_db)
+        self.pc = PC
+        self.sp = SP
+        self.IRDst = ExprId('IRDst', 32)
+        self.addrsize = 32
+
+
+class Lifter_Armtl(Lifter_Arml):
+    def __init__(self, loc_db):
+        Lifter.__init__(self, mn_armt, "l", loc_db)
+        self.pc = PC
+        self.sp = SP
+        self.IRDst = ExprId('IRDst', 32)
+        self.addrsize = 32
+
+
+    def mod_pc(self, instr, instr_ir, extra_ir):
+        # fix PC (+4 for thumb)
+        pc_fixed = {self.pc: ExprInt(instr.offset + 4, 32)}
+
+        for i, expr in enumerate(instr_ir):
+            dst, src = expr.dst, expr.src
+            if dst != self.pc:
+                dst = dst.replace_expr(pc_fixed)
+            src = src.replace_expr(pc_fixed)
+            instr_ir[i] = ExprAssign(dst, src)
+
+        for idx, irblock in enumerate(extra_ir):
+            extra_ir[idx] = irblock.modify_exprs(lambda expr: expr.replace_expr(pc_fixed) \
+                                                 if expr != self.pc else expr,
+                                                 lambda expr: expr.replace_expr(pc_fixed))
+
+
+class Lifter_Armtb(Lifter_Armtl):
+    def __init__(self, loc_db):
+        Lifter.__init__(self, mn_armt, "b", loc_db)
+        self.pc = PC
+        self.sp = SP
+        self.IRDst = ExprId('IRDst', 32)
+        self.addrsize = 32
+
diff --git a/src/miasm/arch/mep/__init__.py b/src/miasm/arch/mep/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/miasm/arch/mep/__init__.py
diff --git a/src/miasm/arch/mep/arch.py b/src/miasm/arch/mep/arch.py
new file mode 100644
index 00000000..ed7813ca
--- /dev/null
+++ b/src/miasm/arch/mep/arch.py
@@ -0,0 +1,2080 @@
+# Toshiba MeP-c4 - miasm architecture definition
+# Guillaume Valadon <guillaume@valadon.net>
+
+from builtins import range
+from miasm.core.cpu import *
+from miasm.core.utils import Disasm_Exception
+from miasm.expression.expression import ExprId, ExprInt, ExprLoc, \
+    ExprMem, ExprOp, is_expr
+from miasm.core.asm_ast import AstId, AstMem
+
+from miasm.arch.mep.regs import *
+import miasm.arch.mep.regs as mep_regs_module  # will be used to set mn_mep.regs
+from miasm.ir.ir import color_expr_html
+
+
+# Note: pyparsing is used to alter the way special operands are parsed
+from pyparsing import Literal, Group, Word, hexnums
+
+
+# These definitions will help parsing dereferencing instructions (i.e. that uses
+# parenthesis) with pyparsing
+LPARENTHESIS = Literal("(")
+RPARENTHESIS = Literal(")")
+PLUSSIGN = Literal("+")
+HEX_INTEGER = str_int_pos | str_int_neg
+
+
+def ExprInt2SignedString(expr, pos_fmt="%d", neg_fmt="%d", size=None, offset=0):
+    """Return the signed string corresponding to an ExprInt
+
+       Note: this function is only useful to mimic objdump output"""
+
+    # Apply a mask to the integer
+    if size is None:
+        mask_length = expr.size
+    else:
+        mask_length = size
+    mask = (1 << mask_length) - 1
+    value = int(expr) & mask
+
+    # Return a signed integer if necessary
+    if (value >> mask_length - 1) == 1:
+        value = offset - ((value ^ mask) + 1)
+        if value < 0:
+            return "-" + neg_fmt % -value
+    else:
+        value += offset
+
+    return pos_fmt % value
+
+
+class instruction_mep(instruction):
+    """Generic MeP-c4 instruction
+
+    Notes:
+        - this object is used to build internal miasm instructions based
+          on mnemonics
+        - it must be implemented !
+    """
+
+    @staticmethod
+    def arg2str(expr, pos=None, loc_db=None):
+        """Convert mnemonics arguments into readable strings according to the
+        MeP-c4 architecture manual and their internal types
+
+        Notes:
+            - it must be implemented ! However, a simple 'return str(expr)'
+              could do the trick.
+            - it is used to mimic objdump output
+
+        Args:
+            expr: argument as a miasm expression
+            pos: position index in the arguments list
+        """
+
+        if isinstance(expr, ExprId) or isinstance(expr, ExprInt):
+            return str(expr)
+
+        elif isinstance(expr, ExprLoc):
+            if loc_db is not None:
+                return loc_db.pretty_str(expr.loc_key)
+            else:
+                return str(expr)
+
+        elif isinstance(expr, ExprMem) and (isinstance(expr.ptr, ExprId) or isinstance(expr.ptr, ExprInt)):
+            return "(%s)" % expr.ptr
+
+        elif isinstance(expr, ExprMem) and isinstance(expr.ptr, ExprOp):
+            return "0x%X(%s)" % (int(expr.ptr.args[1]), expr.ptr.args[0])
+
+        # Raise an exception if the expression type was not processed
+        message = "instruction_mep.arg2str(): don't know what \
+                   to do with a '%s' instance." % type(expr)
+        raise Disasm_Exception(message)
+
+    @staticmethod
+    def arg2html(expr, pos=None, loc_db=None):
+        """Convert mnemonics arguments into readable html strings according to the
+        MeP-c4 architecture manual and their internal types
+
+        Notes:
+            - it must be implemented ! However, a simple 'return str(expr)'
+              could do the trick.
+            - it is used to mimic objdump output
+
+        Args:
+            expr: argument as a miasm expression
+            pos: position index in the arguments list
+        """
+
+        if isinstance(expr, ExprId) or isinstance(expr, ExprInt) or isinstance(expr, ExprLoc):
+            return color_expr_html(expr, loc_db)
+
+        elif isinstance(expr, ExprMem) and (isinstance(expr.ptr, ExprId) or isinstance(expr.ptr, ExprInt)):
+            return "(%s)" % color_expr_html(expr.ptr, loc_db)
+
+        elif isinstance(expr, ExprMem) and isinstance(expr.ptr, ExprOp):
+            return "%s(%s)" % (
+                color_expr_html(expr.ptr.args[1], loc_db),
+                color_expr_html(expr.ptr.args[0], loc_db)
+            )
+
+        # Raise an exception if the expression type was not processed
+        message = "instruction_mep.arg2str(): don't know what \
+                   to do with a '%s' instance." % type(expr)
+        raise Disasm_Exception(message)
+
+    def __str__(self):
+        """Return the mnemonic as a string.
+
+        Note:
+            - it is not mandatory as the instruction class already implement
+              it. It used to get rid of the padding between the opcode and the
+              arguments.
+            - most of this code is copied from miasm/core/cpu.py
+        """
+
+        o = "%s" % self.name
+
+        if self.name == "SSARB":
+            # The first operand is displayed in decimal, not in hex
+            o += " %d" % int(self.args[0])
+            o += self.arg2str(self.args[1])
+
+        elif self.name in ["MOV", "ADD"] and isinstance(self.args[1], ExprInt):
+            # The second operand is displayed in decimal, not in hex
+            o += " " + self.arg2str(self.args[0])
+            o += ", %s" % ExprInt2SignedString(self.args[1])
+
+        elif "CPI" in self.name:
+            # The second operand ends with the '+' sign
+            o += " " + self.arg2str(self.args[0])
+            deref_reg_str = self.arg2str(self.args[1])
+            o += ", %s+)" % deref_reg_str[:-1]  # GV: looks ugly
+
+        elif self.name[0] in ["S", "L"] and self.name[-3:] in ["CPA", "PM0", "PM1"]:
+            # The second operand ends with the '+' sign
+            o += " " + self.arg2str(self.args[0])
+            deref_reg_str = self.arg2str(self.args[1])
+            o += ", %s+)" % deref_reg_str[:-1]  # GV: looks ugly
+            # The third operand is displayed in decimal, not in hex
+            o += ", %s" % ExprInt2SignedString(self.args[2])
+
+        elif len(self.args) == 2 and self.name in ["SB", "SH", "LBU", "LB", "LH", "LW"] and \
+                isinstance(self.args[1], ExprMem) and isinstance(self.args[1].ptr, ExprOp):  # Major Opcodes #12
+            # The second operand is an offset to a register
+            o += " " + self.arg2str(self.args[0])
+            o += ", %s" % ExprInt2SignedString(self.args[1].ptr.args[1], "0x%X")
+            o += "(%s)" % self.arg2str(self.args[1].ptr.args[0])
+
+        elif len(self.args) == 2 and self.name in ["SWCP", "LWCP", "SMCP", "LMCP"] \
+                and isinstance(self.args[1], ExprMem) and isinstance(self.args[1].ptr, ExprOp):  # Major Opcodes #12
+            # The second operand is an offset to a register
+            o += " " + self.arg2str(self.args[0])
+            o += ", %s" % ExprInt2SignedString(self.args[1].ptr.args[1])
+            o += "(%s)" % self.arg2str(self.args[1].ptr.args[0])
+
+        elif self.name == "SLL" and isinstance(self.args[1], ExprInt):  # Major Opcodes #6
+            # The second operand is displayed in hex, not in decimal
+            o += " " + self.arg2str(self.args[0])
+            o += ", 0x%X" % int(self.args[1])
+
+        elif self.name in ["ADD3", "SLT3"] and isinstance(self.args[2], ExprInt):
+            o += " %s" % self.arg2str(self.args[0])
+            o += ", %s" % self.arg2str(self.args[1])
+            # The third operand is displayed in decimal, not in hex
+            o += ", %s" % ExprInt2SignedString(self.args[2], pos_fmt="0x%X")
+
+        elif self.name == "(RI)":
+            return o
+
+        else:
+            args = []
+            if self.args:
+                o += " "
+            for i, arg in enumerate(self.args):
+                if not is_expr(arg):
+                    raise ValueError('zarb arg type')
+                x = self.arg2str(arg, pos=i)
+                args.append(x)
+            o += self.gen_args(args)
+
+        return o
+
+    def breakflow(self):
+        """Instructions that stop a basic block."""
+
+        if self.name in ["BRA", "BEQZ", "BNEZ", "BEQI", "BNEI", "BLTI", "BGEI", "BEQ", "BNE", "BSR"]:
+            return True
+
+        if self.name in ["JMP", "JSR", "RET"]:
+            return True
+
+        if self.name in ["RETI", "HALT", "SLEEP"]:
+            return True
+
+        return False
+
+    def splitflow(self):
+        """Instructions that splits a basic block, i.e. the CPU can go somewhere else."""
+
+        if self.name in ["BEQZ", "BNEZ", "BEQI", "BNEI", "BLTI", "BGEI", "BEQ", "BNE", "BSR"]:
+            return True
+
+        return False
+
+    def dstflow(self):
+        """Instructions that explicitly provide the destination."""
+
+        if self.name in ["BRA", "BEQZ", "BNEZ", "BEQI", "BNEI", "BLTI", "BGEI", "BEQ", "BNE", "BSR"]:
+            return True
+
+        if self.name in ["JMP"]:
+            return True
+
+        return False
+
+    def dstflow2label(self, loc_db):
+        """Set the label for the current destination.
+
+           Note: it is used at disassembly"""
+
+        if self.name == "JMP" and isinstance(self.args[0], ExprId):
+            # 'JMP RM' does not provide the destination
+            return
+
+        # Compute the correct address
+        num = self.get_dst_num()
+        addr = int(self.args[num])
+        if not self.name == "JMP":
+            addr += self.offset
+
+        # Get a new label at the address
+        label = loc_db.get_or_create_offset_location(addr)
+
+        # Assign the label to the correct instruction argument
+        self.args[num] = ExprLoc(label, self.args[num].size)
+
+    def get_dst_num(self):
+        """Get the index of the argument that points to the instruction destination."""
+
+        if self.name[-1] == "Z":
+            num = 1
+        elif self.name in ["BEQI", "BNEI", "BLTI", "BGEI", "BEQ", "BNE"]:
+            num = 2
+        else:
+            num = 0
+
+        return num
+
+    def getdstflow(self, loc_db):
+        """Get the argument that points to the instruction destination."""
+
+        num = self.get_dst_num()
+        return [self.args[num]]
+
+    def is_subcall(self):
+        """Instructions used to call sub functions."""
+
+        return self.name in ["JSR", "BSR"]
+
+    def fixDstOffset(self):
+        """Fix/correct the instruction immediate according to the current offset
+
+           Note: - it is used at assembly
+                 - code inspired by miasm/arch/mips32/arch.py"""
+
+        if self.name == "JMP" and isinstance(self.args[0], ExprInt):
+            # 'JMP IMMEDIATE' does not need to be fixed
+            return
+
+        # Get the argument that needs to be fixed
+        if not len(self.args):
+            return
+        num = self.get_dst_num()
+        expr = self.args[num]
+
+        # Check that the argument can be fixed
+        if self.offset is None:
+            raise ValueError("Symbol not resolved %s" % self.l)
+        if not isinstance(expr, ExprInt):
+            return
+
+        # Adjust the immediate according to the current instruction offset
+        off = expr.arg - self.offset
+        if int(off % 2):
+            raise ValueError("Strange offset! %r" % off)
+        self.args[num] = ExprInt(off, 32)
+
+
+class mep_additional_info(object):
+    """Additional MeP instructions information
+    """
+
+    def __init__(self):
+        self.except_on_instr = False
+
+
+class mn_mep(cls_mn):
+    """Toshiba MeP-c4 disassembler & assembler
+    """
+
+    # Define variables that stores information used to disassemble & assemble
+    # Notes: - these variables are mandatory
+    #        - they could be moved to the cls_mn class
+
+    num = 0  # holds the number of mnemonics
+
+    all_mn = list()  # list of mnenomnics, converted to metamn objects
+
+    all_mn_mode = defaultdict(list)  # mneomnics, converted to metamn objects
+                                     # Note:
+                                     #   - the key is the mode # GV: what is it ?
+                                     #   - the data is a list of mnemonics
+
+    all_mn_name = defaultdict(list)  # mnenomnics strings
+                                     # Note:
+                                     #   - the key is the mnemonic string
+                                     #   - the data is the corresponding
+                                     #     metamn object
+
+    all_mn_inst = defaultdict(list)  # mnemonics objects
+                                     # Note:
+                                     #   - the key is the mnemonic Python class
+                                     #   - the data is an instantiated object
+
+    bintree = dict()  # Variable storing internal values used to guess a
+                      # mnemonic during disassembly
+
+    # Defines the instruction set that will be used
+    instruction = instruction_mep
+
+    # Python module that stores registers information
+    regs = mep_regs_module
+
+    # Default delay slot
+    # Note:
+    #   - mandatory for the miasm Machine
+    delayslot = 0
+
+    # Architecture name
+    name = "mep"
+
+    # PC name depending on architecture attributes (here, l or b)
+    pc = {'l': PC, 'b': PC}
+
+    def additional_info(self):
+        """Define instruction side effects # GV: not fully understood yet
+
+        When used, it must return an object that implements specific
+        variables, such as except_on_instr.
+
+        Notes:
+            - it must be implemented !
+            - it could be moved to the cls_mn class
+        """
+
+        return mep_additional_info()
+
+    @classmethod
+    def gen_modes(cls, subcls, name, bases, dct, fields):
+        """Ease populating internal variables used to disassemble & assemble, such
+        as self.all_mn_mode, self.all_mn_name and self.all_mn_inst
+
+        Notes:
+            - it must be implemented !
+            - it could be moved to the cls_mn class. All miasm architectures
+              use the same code
+
+        Args:
+            cls: ?
+            sublcs:
+            name: mnemonic name
+            bases: ?
+            dct: ?
+            fields: ?
+
+        Returns:
+            a list of ?
+
+        """
+
+        dct["mode"] = None
+        return [(subcls, name, bases, dct, fields)]
+
+    @classmethod
+    def getmn(cls, name):
+        """Get the mnemonic name
+
+        Notes:
+            - it must be implemented !
+            - it could be moved to the cls_mn class. Most miasm architectures
+              use the same code
+
+        Args:
+            cls:  the mnemonic class
+            name: the mnemonic string
+        """
+
+        return name.upper()
+
+    @classmethod
+    def getpc(cls, attrib=None):
+        """"Return the ExprId that represents the Program Counter.
+
+        Notes:
+            - mandatory for the symbolic execution
+            - PC is defined in regs.py
+
+        Args:
+           attrib: architecture dependent attributes (here, l or b)
+        """
+
+        return PC
+
+    @classmethod
+    def getsp(cls, attrib=None):
+        """"Return the ExprId that represents the Stack Pointer.
+
+        Notes:
+            - mandatory for the symbolic execution
+            - SP is defined in regs.py
+
+        Args:
+           attrib: architecture dependent attributes (here, l or b)
+        """
+
+        return SP
+
+    @classmethod
+    def getbits(cls, bitstream, attrib, start, n):
+        """Return an integer of n bits at the 'start' offset
+
+           Note: code from miasm/arch/mips32/arch.py
+        """
+
+        # Return zero if zero bits are requested
+        if not n:
+            return 0
+
+        o = 0  # the returned value
+        while n:
+            # Get a byte, the offset is adjusted according to the endianness
+            offset = start // 8  # the offset in bytes
+            n_offset = cls.endian_offset(attrib, offset)  # the adjusted offset
+            c = cls.getbytes(bitstream, n_offset, 1)
+            if not c:
+                raise IOError
+
+            # Extract the bits value
+            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):
+        """Adjust the byte offset according to the endianness"""
+
+        if attrib == "l":  # Little Endian
+            if offset % 2:
+                return offset - 1
+            else:
+                return offset + 1
+
+        elif attrib == "b":  # Big Endian
+            return offset
+
+        else:
+            raise NotImplementedError("Bad MeP endianness")
+
+    def value(self, mode):
+        """Adjust the assembled instruction based on the endianness
+
+           Note: code inspired by miasm/arch/mips32/arch.py
+        """
+
+        # Get the candidated
+        candidates = super(mn_mep, self).value(mode)
+
+        if mode == "l":
+            # Invert bytes per 16-bits
+            for i in range(len(candidates)):
+                tmp = candidates[i][1] + candidates[i][0]
+                if len(candidates[i]) == 4:
+                    tmp += candidates[i][3] + candidates[i][2]
+                candidates[i] = tmp
+            return candidates
+
+        elif mode == "b":
+            return candidates
+
+        else:
+            raise NotImplementedError("Bad MeP endianness (%s)" % mode)
+
+
+def addop(name, fields, args=None, alias=False):
+    """Dynamically create the "name" object
+
+    Notes:
+        - it could be moved to a generic function such as:
+          addop(name, fields, cls_mn, args=None, alias=False).
+        - most architectures use the same code
+
+    Args:
+        name:   the mnemonic name
+        fields: used to fill the object.__dict__'fields' attribute # GV: not understood yet
+        args:   used to fill the object.__dict__'fields' attribute # GV: not understood yet
+        alias:  used to fill the object.__dict__'fields' attribute # GV: not understood yet
+    """
+
+    namespace = {"fields": fields, "alias": alias}
+
+    if args is not None:
+        namespace["args"] = args
+
+    # Dynamically create the "name" object
+    type(name, (mn_mep,), namespace)
+
+
+# Define specific operand parsers & converters
+
+def deref2expr(s, l, parse_results):
+    """Convert a parsed dereferenced register to an ExprMem"""
+
+    # Only use the first results
+    parse_results = parse_results[0]
+
+    if type(parse_results[0]) == AstInt and isinstance(parse_results[2], AstId):
+        return AstMem(parse_results[2] + parse_results[0], 32)  # 1 == "(" and 3 == ")"
+
+    elif type(parse_results[0]) == int and isinstance(parse_results[2], AstId):
+        return AstMem(parse_results[2] + AstOp('-', AstInt(-parse_results[0])), 32)  # 1 == "(" and 3 == ")"
+
+    else:
+        return AstMem(parse_results[1], 32)  # 0 == "(" and 2 == ")"
+
+
+deref_reg_parser = Group(LPARENTHESIS + gpr_infos.parser + RPARENTHESIS).setParseAction(deref2expr)
+deref_inc_reg_parser = Group(LPARENTHESIS + gpr_infos.parser + PLUSSIGN + RPARENTHESIS).setParseAction(deref2expr)
+abs24_deref_parser = Group(LPARENTHESIS + HEX_INTEGER + RPARENTHESIS).setParseAction(deref2expr)
+offset_deref_reg_parser = Group(HEX_INTEGER + LPARENTHESIS + gpr_infos.parser + RPARENTHESIS).setParseAction(deref2expr)
+
+# Define registers decoders and encoders
+
+class mep_arg(m_arg):
+    def asm_ast_to_expr(self, arg, loc_db):
+        """Convert AST to expressions
+
+           Note: - code inspired by miasm/arch/mips32/arch.py"""
+
+        if isinstance(arg, AstId):
+            if isinstance(arg.name, ExprId):
+                return arg.name
+            if isinstance(arg.name, str) and arg.name in gpr_names:
+                return None  # GV: why?
+            loc_key = loc_db.get_or_create_name_location(arg.name)
+            return ExprLoc(loc_key, 32)
+
+        elif isinstance(arg, AstMem):
+            addr = self.asm_ast_to_expr(arg.ptr, loc_db)
+            if addr is None:
+                return None
+            return ExprMem(addr, 32)
+
+        elif isinstance(arg, AstInt):
+            return ExprInt(arg.value, 32)
+
+        elif isinstance(arg, AstOp):
+            args = [self.asm_ast_to_expr(tmp, loc_db) for tmp in arg.args]
+            if None in args:
+                return None
+            return ExprOp(arg.op, *args)
+
+        # Raise an exception if the argument was not processed
+        message = "mep_arg.asm_ast_to_expr(): don't know what \
+                   to do with a '%s' instance." % type(arg)
+        raise Exception(message)
+
+class mep_reg(reg_noarg, mep_arg):
+    """Generic Toshiba MeP-c4 register
+
+    Note:
+        - the register size will be set using bs()
+    """
+    reg_info = gpr_infos  # the list of MeP-c4 registers defined in regs.py
+    parser = reg_info.parser  # GV: not understood yet
+
+
+class mep_deref_reg(mep_arg):
+    """Generic Toshiba MeP-c4 dereferenced register
+
+    Note:
+        - the arg2str() method could be defined to change the output string
+    """
+    parser = deref_reg_parser
+
+    def decode(self, v):
+        """Transform the decoded value to a ExprMem(ExprId()) expression"""
+        r = gpr_infos.expr[v]  # get the ExprId, i.e. the register expression
+        self.expr = ExprMem(r, 32)
+        return True
+
+    def encode(self):
+        """Ensure that we have a ExprMem(ExprId()) expression, and return the
+        register value."""
+
+        if not isinstance(self.expr, ExprMem):
+            return False
+        if not isinstance(self.expr.ptr, ExprId):
+            return False
+
+        # Get the ExprId index, i.e. its value
+        self.value = gpr_exprs.index(self.expr.ptr)
+        return True
+
+
+class mep_reg_sp(mep_reg):
+    """Dummy Toshiba MeP-c4 register that represents SP. It is used in
+    instructions that implicitly use SP, such as ADD3.
+    """
+    implicit_reg = SP
+
+    def decode(self, v):
+        """Always return 'implicit_reg."""
+        self.expr = self.implicit_reg
+        return True
+
+    def encode(self):
+        """Do nothing"""
+        return True
+
+
+class mep_reg_tp(mep_reg_sp):
+    """Dummy Toshiba MeP-c4 register that represents TP.
+    """
+    implicit_reg = TP
+
+
+class mep_deref_reg_offset(mep_arg):
+    """Toshiba MeP-c4 dereferenced register that represents SP, plus an
+    offset.
+    """
+    parser = offset_deref_reg_parser
+
+    def decode(self, v):
+        """Modify the decoded value using the previously decoded
+        register id.
+        """
+
+        # Apply the immediate mask
+        se = sign_ext(v & 0xFFFF, 16, 32)  # GV: might not belong here
+        int_id = ExprInt(se, 32)
+
+        # Get the register expression
+        reg_id = gpr_infos.expr[self.parent.reg04_deref.value]
+
+        # Build the internal expression
+        self.expr = ExprMem(reg_id + int_id, 32)
+
+        return True
+
+    def encode(self):
+        """Modify the encoded value. One part is stored in this object, and
+        the other one in reg04_deref.
+        """
+
+        # Verify the expression
+        if not isinstance(self.expr, ExprMem):
+            return False
+        if not isinstance(self.expr.ptr, ExprOp):
+            return False
+
+        # Get the integer and check the upper bound
+        v = int(self.expr.ptr.args[1]) & 0xFFFF
+
+        # Encode the values
+        self.parent.reg04_deref.value = gpr_exprs.index(self.expr.ptr.args[0])
+        self.value = v & 0xFFFF
+        return True
+
+
+class mep_deref_sp_offset(mep_deref_reg):
+    """Dummy Toshiba MeP-c4 dereferenced register that represents SP, plus an
+    offset.
+    Note: it is as generic as possible to ease its use in different instructions
+    """
+    implicit_reg = SP
+    parser = offset_deref_reg_parser
+
+    def decode(self, v):
+        """Modify the decoded value using the previously decoded
+        immediate.
+        """
+
+        immediate = None
+        if getattr(self.parent, "imm7_align4", False):
+            # Apply the immediate mask
+            v = self.parent.imm7_align4.value & 0x1F
+
+            # Shift value such as:
+            #   imm7=iii_ii||00
+            immediate = v << 2
+
+        elif getattr(self.parent, "imm7", False):
+            # Apply the immediate mask
+            immediate = self.parent.imm7.value & 0x7F
+
+        elif getattr(self.parent, "disp7_align2", False):
+            # Apply the immediate mask
+            disp7_align2 = self.parent.disp7_align2.value & 0x3F
+
+            # Shift value such as:
+            #   disp7 = ddd_ddd||0
+            immediate = disp7_align2 << 1
+
+        if immediate is not None:
+            self.expr = ExprMem(self.implicit_reg + ExprInt(immediate, 32), 32)
+            return True
+        else:
+            return False
+
+    def encode(self):
+        """Modify the encoded value. One part is stored in this object, and
+        the other one in a parent immediate.
+        """
+
+        # Verify the expression
+        if not isinstance(self.expr, ExprMem):
+            return False
+        if not isinstance(self.expr.ptr, ExprOp):
+            return False
+        if self.expr.ptr.args[0] != self.implicit_reg:
+            return False
+
+        if getattr(self.parent, "imm7_align4", False):
+
+            # Get the integer and check the upper bound
+            v = int(self.expr.ptr.args[1].arg)
+            if v > 0x80:
+                return False
+
+            # Encode the value
+            self.parent.imm7_align4.value = v >> 2
+
+            return True
+
+        elif getattr(self.parent, "imm7", False):
+
+            # Get the integer and check the upper bound
+            v = int(self.expr.ptr.args[1].arg)
+            if v > 0x80:
+                return False
+
+            # Encode the value
+            self.parent.imm7.value = v
+
+            return True
+
+        elif getattr(self.parent, "disp7_align2", False):
+
+            # Get the integer and check the upper bound
+            v = int(self.expr.ptr.args[1].arg)
+            if v > 0x80:
+                return False
+
+            # Encode the value
+            self.parent.disp7_align2.value = v >> 1
+
+            return True
+
+        return False
+
+
+class mep_deref_tp_offset(mep_deref_sp_offset):
+    """Dummy Toshiba MeP-c4 dereferenced register that represents TP, plus an
+    offset.
+    """
+    implicit_reg = TP
+
+
+class mep_copro_reg(reg_noarg, mep_arg):
+    """Generic Toshiba MeP-c4 coprocessor register
+    """
+    reg_info = copro_gpr_infos  # the list of MeP-c4 coprocessor registers defined in regs.py
+    parser = reg_info.parser  # GV: not understood yet
+
+
+class mep_copro_reg_split(mep_copro_reg):
+    """Generic Toshiba MeP-c4 coprocessor register encode into different fields
+    """
+
+    def decode(self, v):
+        """Modify the decoded value using the previously decoded imm4_noarg.
+        """
+
+        # Apply the immediate mask
+        v = v & self.lmask
+
+        # Shift values such as:
+        #   CRn=NNnnnn
+        crn = (v << 4) + (self.parent.imm4.value & 0xF)
+
+        # Build the internal expression
+        self.expr = ExprId("C%d" % crn, 32)
+        return True
+
+    def encode(self):
+        """Modify the encoded value. One part is stored in this object, and
+        the other one in imm4_noarg.
+        """
+
+        if not isinstance(self.expr, ExprId):
+            return False
+
+        # Get the register and check the upper bound
+        reg_name = self.expr.name
+        if reg_name[0] != "C":
+            return False
+        reg_value = copro_gpr_names.index(reg_name)
+        if reg_value > 0x3f:
+            return False
+
+        # Encode the value into two parts
+        self.parent.imm4.value = (reg_value & 0xF)
+        self.value = (reg_value >> 4) & 0x3
+        return True
+
+
+class mep_deref_inc_reg(mep_deref_reg):
+    """Generic Toshiba MeP-c4 coprocess dereferenced & incremented register
+    """
+    parser = deref_inc_reg_parser
+
+
+# Immediate decoders and encoders
+
+class mep_int32_noarg(int32_noarg):
+    """Generic Toshiba MeP-c4 signed immediate
+
+       Note: encode() is copied from int32_noarg.encode() and modified to allow
+             small (< 32 bits) signed immediate to be manipulated.
+
+    """
+
+    def encode(self):
+        if not isinstance(self.expr, ExprInt):
+            return False
+        v = int(self.expr)
+        # Note: the following lines were commented on purpose
+        #if sign_ext(v & self.lmask, self.l, self.intsize) != v:
+        #    return False
+        v = self.encodeval(v & self.lmask)
+        self.value = v & self.lmask
+        return True
+
+
+class mep_imm(imm_noarg, mep_arg):
+    """Generic Toshiba MeP-c4 immediate
+
+    Note:
+        - the immediate size will be set using bs()
+    """
+    parser = base_expr
+
+
+class mep_imm6(mep_int32_noarg):
+    """Toshiba MeP-c4 signed 6 bits immediate."""
+    parser = base_expr
+    intsize = 6
+    intmask = (1 << intsize) - 1
+    int2expr = lambda self, x: ExprInt(sign_ext(x, self.l, 32), 32)
+
+
+class mep_imm8(mep_int32_noarg):
+    """Toshiba MeP-c4 signed 8 bits immediate."""
+    parser = base_expr
+    intsize = 8
+    intmask = (1 << intsize) - 1
+    int2expr = lambda self, x: ExprInt(sign_ext(x, self.l, 32), 32)
+
+
+class mep_imm16(mep_int32_noarg):
+    """Toshiba MeP-c4 16 bits immediate."""
+    parser = base_expr
+    intsize = 16
+    intmask = (1 << intsize) - 1
+    int2expr = lambda self, x: ExprInt(x, 32)
+
+
+class mep_imm16_signed(mep_int32_noarg):
+    """Toshiba MeP-c4 signed 16 bits immediate."""
+    parser = base_expr
+    intsize = 16
+    intmask = (1 << intsize) - 1
+    int2expr = lambda self, x: ExprInt(sign_ext(x, self.l, 32), 32)
+
+
+class mep_target24(mep_imm):
+    """Toshiba MeP-c4 target24 immediate, as used in JMP
+    """
+
+    def decode(self, v):
+        """Modify the decoded value using the previously decoded imm7.
+        """
+
+        # Apply the immediate mask
+        v = v & self.lmask
+
+        # Shift values such as:
+        #   target24=tttt_tttt_tttt_tttt||TTT_TTTT||0
+        target24 = (v << 8) + ((self.parent.imm7.value & 0x7F) << 1)
+
+        # Build the internal expression
+        self.expr = ExprInt(target24, 32)
+        return True
+
+    def encode(self):
+        """Modify the encoded value. One part is stored in this object, and
+        the other one in imm7.
+        """
+
+        if not isinstance(self.expr, ExprInt):
+            return False
+
+        # Get the integer and apply a mask
+        v = int(self.expr) & 0x00FFFFFF
+
+        # Encode the value into two parts
+        self.parent.imm7.value = (v & 0xFF) >> 1
+        self.value = v >> 8
+        return True
+
+
+class mep_target24_signed(mep_target24):
+    """Toshiba MeP-c4 target24 signed immediate, as used in BSR
+    """
+
+    def decode(self, v):
+        """Perform sign extension
+        """
+
+        mep_target24.decode(self, v)
+        v = int(self.expr)
+        self.expr = ExprInt(sign_ext(v, 24, 32), 32)
+
+        return True
+
+
+class mep_code20(mep_imm):
+    """Toshiba MeP-c4 code20 immediate, as used in DSP1
+    """
+
+    def decode(self, v):
+        """Modify the decoded value using the previously decoded imm4_noarg.
+        """
+
+        # Apply the immediate mask
+        v = v & self.lmask
+
+        # Shift values such as:
+        #   code20=mmmm_cccc_cccc_cccc_cccc
+        code20 = v + ((self.parent.imm4.value & 0xFF) << 16)
+
+        # Build the internal expression
+        self.expr = ExprInt(code20, 32)
+        return True
+
+    def encode(self):
+        """Modify the encoded value. One part is stored in this object, and
+        the other one in imm4_noarg.
+        """
+
+        if not isinstance(self.expr, ExprInt):
+            return False
+
+        # Get the integer and check the upper bound
+        v = int(self.expr.arg)
+        if v > 0xffffff:
+            return False
+
+        # Encode the value into two parts
+        self.parent.imm4 = ((v >> 16) & 0xFF)
+        self.value = v
+        return True
+
+
+class mep_code24(mep_imm):
+    """Toshiba MeP-c4 code24 immediate, as used in CP
+    """
+
+    def decode(self, v):
+        """Modify the decoded value using the previously decoded imm8_CCCC_CCCC.
+        """
+
+        # Shift values such as:
+        #   code24=CCCC_CCCC||cccc_cccc_cccc_cccc
+        code24 = v + ((self.parent.imm8_CCCC_CCCC.value & 0xFF) << 16)
+
+        # Build the internal expression
+        self.expr = ExprInt(code24, 32)
+        return True
+
+    def encode(self):
+        """Modify the encoded value. One part is stored in this object, and
+        the other one in imm8_CCCC_CCCC.
+        """
+
+        if not isinstance(self.expr, ExprInt):
+            return False
+
+        # Get the integer and check the upper bound
+        v = int(self.expr.arg)
+        if v > 0xFFFFFF:
+            return False
+
+        # Encode the value into two parts
+        self.parent.imm8_CCCC_CCCC.value = ((v >> 16) & 0xFF)
+        self.value = v & 0xFFFF
+        return True
+
+
+class mep_imm7_align4(mep_imm):
+    """Toshiba MeP-c4 imm7.align4 immediate, as used in Major #4 opcodes
+    """
+
+    def decode(self, v):
+        """Modify the decoded value.
+        """
+
+        # Apply the immediate mask
+        v = v & self.lmask
+
+        # Shift value such as:
+        #   imm7=iii_ii||00
+        imm7_align4 = v << 2
+
+        # Build the internal expression
+        self.expr = ExprInt(imm7_align4, 32)
+        return True
+
+    def encode(self):
+        """Modify the encoded value.
+        """
+
+        if not isinstance(self.expr, ExprInt):
+            return False
+
+        # Get the integer and check the upper bound
+        v = int(self.expr)
+        if v > 0x80:
+            return False
+
+        # Encode the value
+        self.value = v >> 2
+        return True
+
+
+class mep_imm5_Iiiii (mep_imm):
+    """Toshiba MeP-c4 imm5 immediate, as used in STC & LDC. It encodes a
+    control/special register.
+    """
+
+    reg_info = csr_infos  # the list of MeP-c4 control/special registers defined in regs.py
+    parser = reg_info.parser  # GV: not understood yet
+
+    def decode(self, v):
+        """Modify the decoded value using the previously decoded imm4_iiii
+        """
+
+        # Apply the immediate mask
+        I = v & self.lmask
+
+        # Shift values such as:
+        #   imm5=I||iiii
+        imm5 = (I << 4) + (self.parent.imm4_iiii.value & 0xF)
+
+        # Build the internal register expression
+        self.expr = ExprId(csr_names[imm5], 32)
+        return True
+
+    def encode(self):
+        """Modify the encoded value. One part is stored in this object, and
+        the other one in imm4_iiii.
+        """
+
+        if not isinstance(self.expr, ExprId):
+            return False
+
+        # Get the register number and check the upper bound
+        v = csr_names.index(self.expr.name)
+        if v > 0x1F:
+            return False
+
+        # Encode the value into two parts
+        self.parent.imm4_iiii.value = v & 0xF  # iiii
+        self.value = (v >> 4) & 0b1  # I
+        return True
+
+
+class mep_disp7_align2(mep_imm):
+    """Toshiba MeP-c4 disp7.align2 immediate, as used in Major #8 opcodes
+    """
+    upper_bound = 0x7F
+    bits_shift = 1
+
+    def decode(self, v):
+        """Modify the decoded value.
+        """
+
+        # Apply the immediate mask
+        v = v & self.lmask
+
+        # Shift value such as:
+        #   disp7 = ddd_ddd||0
+        disp7_align2 = (v << self.bits_shift)
+
+        # Sign extension
+        disp7_align2 = sign_ext(disp7_align2, self.l + self.bits_shift, 32)
+
+        # Build the internal expression
+        self.expr = ExprInt(disp7_align2, 32)
+        return True
+
+    def encode(self):
+        """Modify the encoded value.
+        """
+
+        if not isinstance(self.expr, ExprInt):
+            return False
+
+        # Get the integer
+        v = int(self.expr) & self.upper_bound
+
+        # Encode the value
+        self.value = (v >> self.bits_shift) & self.upper_bound
+        self.value = (v & self.upper_bound) >> self.bits_shift
+        return True
+
+
+class mep_disp8_align2(mep_disp7_align2):
+    upper_bound = 0xFF
+
+
+class mep_disp8_align4(mep_disp7_align2):
+    upper_bound = 0xFF
+    bits_shift = 2
+
+
+class mep_imm8_align8(mep_disp7_align2):
+    upper_bound = 0xFF
+    bits_shift = 3
+
+
+class mep_disp12_align2(mep_disp7_align2):
+    upper_bound = 0xFFF
+
+
+class mep_disp12_align2_signed(mep_disp12_align2):
+
+    def decode(self, v):
+        """Perform sign extension.
+        """
+        mep_disp12_align2.decode(self, v)
+        v = int(self.expr)
+
+        self.expr = ExprInt(sign_ext(v, 12, 32), 32)
+        return True
+
+
+class mep_disp17(mep_disp7_align2):
+    upper_bound = 0x1FFFF
+
+
+class mep_imm24(mep_imm):
+    """Toshiba MeP-c4 imm24 immediate, as used in MOVU
+    """
+
+    def decode(self, v):
+        """Modify the decoded value.
+        """
+
+        # Apply the immediate mask
+        v = v & self.lmask
+
+        # Shift values such as:
+        #   imm24=iiii_iiii_iiii_iiii||IIII_IIIII
+        imm24 = ((v & 0xFFFF) << 8) + ((v & 0xFF0000) >> 16)
+
+        # Build the internal expression
+        self.expr = ExprInt(imm24, 32)
+        return True
+
+    def encode(self):
+        """Modify the encoded value.
+        """
+
+        if not isinstance(self.expr, ExprInt):
+            return False
+
+        # Get the integer and check the upper bound
+        v = int(self.expr)
+        if v > 0xFFFFFF:
+            return False
+
+        # Encode the value
+        self.value = ((v & 0xFFFF00) >> 8) + ((v & 0xFF) << 16)
+        return True
+
+
+class mep_abs24(mep_imm):
+    """Toshiba MeP-c4 abs24 immediate
+    """
+    parser = abs24_deref_parser
+
+    def decode(self, v):
+        """Modify the decoded value using the previously decoded imm6.
+        """
+
+        # Apply the immediate mask
+        v = v & self.lmask
+
+        # Shift values such as:
+        #   abs24=dddd_dddd_dddd_dddd||DDDD_DD||00
+        abs24 = (v << 8) + ((self.parent.imm6.value & 0x3F) << 2)
+
+        # Build the internal expression
+        self.expr = ExprMem(ExprInt(abs24, 32), 32)
+        return True
+
+    def encode(self):
+        """Modify the encoded value. One part is stored in this object, and
+        the other one in imm6.
+        """
+
+        if not (isinstance(self.expr, ExprMem) and isinstance(self.expr.ptr, ExprInt)):
+            return False
+
+        # Get the integer and check the upper bound
+        v = int(self.expr.ptr)
+        if v > 0xffffff:
+            return False
+
+        # Encode the value into two parts
+        self.parent.imm6.value = (v & 0xFF) >> 2
+        self.value = v >> 8
+        return True
+
+
+# Define MeP-c4 assembly operands
+
+reg04 = bs(l=4,  # length in bits
+           cls=(mep_reg, ))  # class implementing decoding & encoding
+
+reg04_l = bs(l=4, cls=(mep_reg, ))
+
+reg04_m = bs(l=4, cls=(mep_reg, ))
+
+reg04_n = bs(l=4, cls=(mep_reg, ))
+
+reg00 = bs(l=0, cls=(mep_reg, ))
+
+reg00_sp = bs(l=0, cls=(mep_reg_sp, ))
+
+reg00_tp = bs(l=0, cls=(mep_reg_tp, ))
+
+reg00_deref_sp = bs(l=0, cls=(mep_deref_sp_offset, ))
+
+reg00_deref_tp = bs(l=0, cls=(mep_deref_tp_offset, ))
+
+reg03 = bs(l=3, cls=(mep_reg, ))
+
+reg04_deref = bs(l=4, cls=(mep_deref_reg,))
+
+reg04_deref_noarg = bs(l=4, fname="reg04_deref")
+
+reg04_inc_deref = bs(l=4, cls=(mep_deref_inc_reg,))
+
+copro_reg04 = bs(l=4, cls=(mep_copro_reg,))
+
+copro_reg05 = bs(l=1, cls=(mep_copro_reg_split,))
+
+copro_reg06 = bs(l=2, cls=(mep_copro_reg_split,))
+
+disp2 = bs(l=2, cls=(mep_imm, ))
+
+imm2 = disp2
+
+imm3 = bs(l=3, cls=(mep_imm, ))
+
+imm4 = bs(l=4, cls=(mep_imm, ))
+
+imm4_noarg = bs(l=4, fname="imm4")
+
+imm4_iiii_noarg = bs(l=4, fname="imm4_iiii")
+
+imm5 = bs(l=5, cls=(mep_imm, ))
+
+imm5_Iiiii = bs(l=1, cls=(mep_imm5_Iiiii, ))  # it is not an immediate, but a
+                                              # control/special register.
+
+imm6 = bs(l=6, cls=(mep_imm6, mep_arg))
+
+imm6_noarg = bs(l=6, fname="imm6")
+
+imm7 = bs(l=7, cls=(mep_imm, ))
+
+imm7_noarg = bs(l=7, fname="imm7")  # Note:
+                                    #   - will be decoded as a 7 bits immediate
+                                    #   - fname is used to set the operand name
+                                    #     used in mep_target24 to merge operands
+                                    #     values. By default, the bs class fills
+                                    #     fname with an hex string compute from
+                                    #     arguments passed to __init__
+
+imm7_align4 = bs(l=5, cls=(mep_imm7_align4,))
+
+imm7_align4_noarg = bs(l=5, fname="imm7_align4")
+
+disp7_align2 = bs(l=6, cls=(mep_disp7_align2,))
+
+disp7_align2_noarg = bs(l=6, fname="disp7_align2")
+
+imm8 = bs(l=8, cls=(mep_imm8, mep_arg))
+
+imm8_noarg = bs(l=8, fname="imm8_CCCC_CCCC")
+
+disp8 = bs(l=7, cls=(mep_disp8_align2, ))
+
+imm8_align2 = bs(l=7, cls=(mep_disp8_align2, ))
+
+imm8_align4 = bs(l=6, cls=(mep_disp8_align4, ))
+
+imm8_align8 = bs(l=5, cls=(mep_imm8_align8, ))
+
+imm12 = bs(l=12, cls=(mep_imm, ))
+
+disp12_signed = bs(l=11, cls=(mep_disp12_align2_signed, ))
+
+imm16 = bs(l=16, cls=(mep_imm16, mep_arg))
+imm16_signed = bs(l=16, cls=(mep_imm16_signed, mep_arg))
+
+disp16_reg_deref = bs(l=16, cls=(mep_deref_reg_offset,))
+
+disp17 = bs(l=16, cls=(mep_disp17, ))
+
+imm18 = bs(l=19, cls=(mep_imm, ))
+
+imm_code20 = bs(l=16, cls=(mep_code20, ))
+
+imm24 = bs(l=24, cls=(mep_imm24, ))
+
+imm_target24 = bs(l=16, cls=(mep_target24, ))
+imm_target24_signed = bs(l=16, cls=(mep_target24_signed, ))
+
+imm_code24 = bs(l=16, cls=(mep_code24, ))
+
+abs24 = bs(l=16, cls=(mep_abs24, ))
+
+
+# MeP-c4 mnemonics objects
+
+### <Major Opcode #0>
+
+# MOV Rn,Rm - 0000_nnnn_mmmm_0000
+addop("MOV", [bs("0000"), reg04, reg04, bs("0000")])
+
+# NEG Rn,Rm - 0000_nnnn_mmmm_0001
+addop("NEG", [bs("0000"), reg04, reg04, bs("0001")])
+
+# SLT3 R0,Rn,Rm - 0000_nnnn_mmmm_0010
+addop("SLT3", [bs("0000"), reg00, reg04, reg04, bs("0010")])
+
+# SLTU3 R0,Rn,Rm - 0000_nnnn_mmmm_0011
+addop("SLTU3", [bs("0000"), reg00, reg04, reg04, bs("0011")])
+
+# SUB Rn,Rm - 0000_nnnn_mmmm_0100
+addop("SUB", [bs("0000"), reg04, reg04, bs("0100")])
+
+# SBVCK3 R0,Rn,Rm - 0000_nnnn_mmmm_0101
+addop("SBVCK3", [bs("0000"), reg00, reg04, reg04, bs("0101")])
+
+# (RI) - 0000_xxxx_xxxx_0110
+addop("(RI)", [bs("0000"), reg04, reg04, bs("0110")])
+
+# ADVCK3 R0,Rn,Rm - 0000_nnnn_mmmm_0111
+addop("ADVCK3", [bs("0000"), reg00, reg04, reg04, bs("0111")])
+
+# SB Rn,(Rm) - 0000_nnnn_mmmm_1000
+addop("SB", [bs("0000"), reg04, reg04_deref, bs("1000")])
+
+# SH Rn,(Rm) - 0000_nnnn_mmmm_1001
+addop("SH", [bs("0000"), reg04, reg04_deref, bs("1001")])
+
+# SW Rn,(Rm) - 0000_nnnn_mmmm_1010
+addop("SW", [bs("0000"), reg04, reg04_deref, bs("1010")])
+
+# LBU Rn,(Rm) - 0000_nnnn_mmmm_1011
+addop("LBU", [bs("0000"), reg04, reg04_deref, bs("1011")])
+
+# LB Rn,(Rm) - 0000_nnnn_mmmm_1100
+addop("LB", [bs("0000"), reg04, reg04_deref, bs("1100")])
+
+# LH Rn,(Rm) - 0000_nnnn_mmmm_1101
+addop("LH", [bs("0000"), reg04, reg04_deref, bs("1101")])
+
+# LW Rn,(Rm) - 0000_nnnn_mmmm_1110
+addop("LW", [bs("0000"), reg04, reg04_deref, bs("1110")])
+
+# LHU Rn,(Rm) - 0000_nnnn_mmmm_1111
+addop("LHU", [bs("0000"), reg04, reg04_deref, bs("1111")])
+
+
+### <Major Opcode #1>
+
+# OR Rn,Rm - 0001_nnnn_mmmm_0000
+addop("OR", [bs("0001"), reg04, reg04, bs("0000")])
+
+# AND Rn,Rm - 0001_nnnn_mmmm_0001
+addop("AND", [bs("0001"), reg04, reg04, bs("0001")])
+
+# XOR Rn,Rm - 0001_nnnn_mmmm_0010
+addop("XOR", [bs("0001"), reg04, reg04, bs("0010")])
+
+# NOR Rn,Rm - 0001_nnnn_mmmm_0011
+addop("NOR", [bs("0001"), reg04, reg04, bs("0011")])
+
+# MUL Rn,Rm - 0001_nnnn_mmmm_0100
+addop("MUL", [bs("0001"), reg04, reg04, bs("0100")])
+
+# MULU Rn,Rm - 0001_nnnn_mmmm_0101
+addop("MULU", [bs("0001"), reg04, reg04, bs("0101")])
+
+# MULR Rn,Rm - 0001_nnnn_mmmm_0110
+addop("MULR", [bs("0001"), reg04, reg04, bs("0110")])
+
+# MULRU Rn,Rm - 0001_nnnn_mmmm_0111
+addop("MULRU", [bs("0001"), reg04, reg04, bs("0111")])
+
+# DIV Rn,Rm - 0001_nnnn_mmmm_1000
+addop("DIV", [bs("0001"), reg04, reg04, bs("1000")])
+
+# DIVU Rn,Rm - 0001_nnnn_mmmm_1001
+addop("DIVU", [bs("0001"), reg04, reg04, bs("1001")])
+
+# (RI) - 0001_xxxx_xxxx_1010
+addop("(RI)", [bs("0001"), reg04, reg04, bs("1010")])
+
+# (RI) - 0001_xxxx_xxxx_1011
+addop("(RI)", [bs("0001"), reg04, reg04, bs("1011")])
+
+# SSARB disp2(Rm) - 0001_00dd_mmmm_1100
+addop("SSARB", [bs("000100"), disp2, reg04_deref, bs("1100")])
+
+# EXTB Rn - 0001_nnnn_0000_1101
+addop("EXTB", [bs("0001"), reg04, bs("00001101")])
+
+# EXTH Rn - 0001_nnnn_0010_1101
+addop("EXTH", [bs("0001"), reg04, bs("00101101")])
+
+# EXTUB Rn - 0001_nnnn_1000_1101
+addop("EXTUB", [bs("0001"), reg04, bs("10001101")])
+
+# EXTUH Rn - 0001_nnnn_1010_1101
+addop("EXTUH", [bs("0001"), reg04, bs("10101101")])
+
+# JMP Rm - 0001_0000_mmmm_1110
+addop("JMP", [bs("00010000"), reg04, bs("1110")])
+
+# JSR Rm - 0001_0000_mmmm_1111
+addop("JSR", [bs("00010000"), reg04, bs("1111")])
+
+# JSRV Rm - 0001_1000_mmmm_1111
+addop("JSRV", [bs("00011000"), reg04, bs("1111")])
+
+
+### <Major Opcode #2>
+
+# BSETM (Rm),imm3 - 0010_0iii_mmmm_0000
+addop("BSETM", [bs("00100"), imm3, reg04_deref, bs("0000")], [reg04_deref, imm3])
+
+# BCLRM (Rn),imm3 - 0010_0iii_mmmm_0001
+addop("BCLRM", [bs("00100"), imm3, reg04_deref, bs("0001")], [reg04_deref, imm3])
+
+# BNOTM (Rm),imm3 - 0010_0iii_mmmm_0010
+addop("BNOTM", [bs("00100"), imm3, reg04_deref, bs("0010")], [reg04_deref, imm3])
+
+# BTSTM R0,(Rm),imm3 - 0010_0iii_mmmm_0011
+addop("BTSTM", [bs("00100"), reg00, imm3, reg04_deref, bs("0011")], [reg00, reg04_deref, imm3])
+
+# TAS Rn,(Rm) - 0010_nnnn_mmmm_0100
+addop("TAS", [bs("0010"), reg04, reg04_deref, bs("0100")])
+
+# (RI) - 0010_xxxx_xxxx_0101
+addop("(RI)", [bs("0010"), reg04, reg04, bs("0101")])
+
+# SL1AD3 R0,Rn,Rm - 0010_nnnn_mmmm_0110
+addop("SL1AD3", [bs("0010"), reg00, reg04, reg04, bs("0110")])
+
+# SL2AD3 R0,Rn,Rm - 0010_nnnn_mmmm_0111
+addop("SL2AD3", [bs("0010"), reg00, reg04, reg04, bs("0111")])
+
+# (RI) - 0010_xxxx_xxxx_1000
+addop("(RI)", [bs("0010"), reg04, reg04, bs("1000")])
+
+# (RI) - 0010_xxxx_xxxx_1001
+addop("(RI)", [bs("0010"), reg04, reg04, bs("1001")])
+
+# (RI) - 0010_xxxx_xxxx_1010
+addop("(RI)", [bs("0010"), reg04, reg04, bs("1010")])
+
+# (RI) - 0010_xxxx_xxxx_1011
+addop("(RI)", [bs("0010"), reg04, reg04, bs("1011")])
+
+# SRL Rn,Rm - 0010_nnnn_mmmm_1100
+addop("SRL", [bs("0010"), reg04, reg04, bs("1100")])
+
+# SRA Rn,Rm - 0010_nnnn_mmmm_1101
+addop("SRA", [bs("0010"), reg04, reg04, bs("1101")])
+
+# SLL Rn,Rm - 0010_nnnn_mmmm_1110
+addop("SLL", [bs("0010"), reg04, reg04, bs("1110")])
+
+# FSFT Rn,Rm - 0010_nnnn_mmmm_1111
+addop("FSFT", [bs("0010"), reg04, reg04, bs("1111")])
+
+
+### <Major Opcode #3>
+
+# SWCPI CRn,(Rm+) - 0011_nnnn_mmmm_0000
+addop("SWCPI", [bs("0011"), copro_reg04, reg04_inc_deref, bs("0000")])
+
+# LWCPI CRn,(Rm+) - 0011_nnnn_mmmm_0001
+addop("LWCPI", [bs("0011"), copro_reg04, reg04_inc_deref, bs("0001")])
+
+# SMCPI CRn,(Rm+) - 0011_nnnn_mmmm_0010
+addop("SMCPI", [bs("0011"), copro_reg04, reg04_inc_deref, bs("0010")])
+
+# LMCPI CRn,(Rm+) - 0011_nnnn_mmmm_0011
+addop("LMCPI", [bs("0011"), copro_reg04, reg04_inc_deref, bs("0011")])
+
+# SWCP CRn,(Rm) - 0011_nnnn_mmmm_1000
+addop("SWCP", [bs("0011"), copro_reg04, reg04_deref, bs("1000")])
+
+# LWCP CRn,(Rm) - 0011_nnnn_mmmm_1001
+addop("LWCP", [bs("0011"), copro_reg04, reg04_deref, bs("1001")])
+
+# SMCP CRn,(Rm) - 0011_nnnn_mmmm_1010
+addop("SMCP", [bs("0011"), copro_reg04, reg04_deref, bs("1010")])
+
+# LMCP CRn,(Rm) - 0011_nnnn_mmmm_1011
+addop("LMCP", [bs("0011"), copro_reg04, reg04_deref, bs("1011")])
+
+
+### <Major Opcode #4>
+
+# ADD3 Rn,SP,imm7.align4 - 0100_nnnn_0iii_ii00
+addop("ADD3", [bs("0100"), reg04, reg00_sp, bs("0"), imm7_align4, bs("00")])
+
+# SW Rn,disp7.align4(SP) - 0100_nnnn_0ddd_dd10
+# Note: disp7.align4 is the same as imm7.align4
+addop("SW", [bs("0100"), reg04, bs("0"), imm7_align4_noarg, reg00_deref_sp, bs("10")])
+
+# LW Rn,disp7.align4(SP) - 0100_nnnn_0ddd_dd11
+addop("LW", [bs("0100"), reg04, bs("0"), imm7_align4_noarg, reg00_deref_sp, bs("11")])
+
+# SW Rn[0-7],disp7.align4(TP) - 0100_0nnn_1ddd_dd10
+addop("SW", [bs("01000"), reg03, bs("1"), imm7_align4_noarg, reg00_deref_tp, bs("10")])
+
+# LW Rn[0-7],disp7.align4(TP) - 0100_0nnn_1ddd_dd11
+addop("LW", [bs("01000"), reg03, bs("1"), imm7_align4_noarg, reg00_deref_tp, bs("11")])
+
+# LBU Rn[0-7],disp7(TP) - 0100_1nnn_1ddd_dddd
+addop("LBU", [bs("01001"), reg03, bs("1"), imm7_noarg, reg00_deref_tp], [reg03, reg00_deref_tp])
+
+### <Major Opcode #5>
+
+# MOV Rn,imm8 - 0101_nnnn_iiii_iiii
+addop("MOV", [bs("0101"), reg04, imm8])
+
+
+### <Major Opcode #6>
+
+# ADD Rn,imm6 - 0110_nnnn_iiii_ii00
+addop("ADD",  # mnemonic name
+      [bs("0110"), reg04, imm6, bs("00")])  # mnemonic description
+
+# SLT3 R0,Rn,imm5 - 0110_nnnn_iiii_i001
+addop("SLT3", [bs("0110"), reg00, reg04, imm5, bs("001")])
+
+# SRL Rn,imm5 - 0110_nnnn_iiii_i010
+addop("SRL", [bs("0110"), reg04, imm5, bs("010")])
+
+# SRA Rn,imm5 - 0110_nnnn_iiii_i011
+addop("SRA", [bs("0110"), reg04, imm5, bs("011")])
+
+# SLTU3 R0,Rn,imm5 - 0110_nnnn_iiii_i101
+addop("SLTU3", [bs("0110"), reg00, reg04, imm5, bs("101")])
+
+# SLL Rn,imm5 - 0110_nnnn_iiii_i110
+addop("SLL", [bs("0110"), reg04, imm5, bs("110")])
+
+# SLL3 R0,Rn,imm5 - 0110_nnnn_iiii_i111
+addop("SLL3", [bs("0110"), reg00, reg04, imm5, bs("111")])
+
+
+### <Major Opcode #7>
+
+# DI - 0111_0000_0000_0000
+addop("DI", [bs("0111000000000000")])
+
+# EI - 0111_0000_0001_0000
+addop("EI", [bs("0111000000010000")])
+
+# SYNCM - 0111_0000_0001_0001
+addop("SYNCM", [bs("0111000000010001")])
+
+# SYNCCP - 0111_0000_0010_0001
+addop("SYNCCP", [bs("0111000000100001")])
+
+# RET - 0111_0000_0000_0010
+addop("RET", [bs("0111000000000010")])
+
+# RETI - 0111_0000_0001_0010
+addop("RETI", [bs("0111000000010010")])
+
+# HALT - 0111_0000_0010_0010
+addop("HALT", [bs("0111000000100010")])
+
+# BREAK - 0111_0000_0011_0010
+addop("BREAK", [bs("0111000000110010")])
+
+# SLEEP - 0111_0000_0110_0010
+addop("SLEEP", [bs("0111000001100010")])
+
+# DRET - 0111_0000_0001_0011
+addop("DRET", [bs("0111000000010011")])
+
+# DBREAK - 0111_0000_0011_0011
+addop("DBREAK", [bs("0111000000110011")])
+
+# CACHE imm4,(Rm) - 0111_iiii_mmmm_0100
+addop("CACHE", [bs("0111"), imm4, reg04_deref, bs("0100")])
+
+# (RI) - 0111_xxxx_xxxx_0101
+addop("(RI)", [bs("0111"), reg04, reg04, bs("0101")])
+
+# SWI imm2 - 0111_0000_00ii_0110
+addop("SWI", [bs("0111000000"), imm2, bs("0110")])
+
+# (RI) - 0111_xxxx_xxxx_0111
+addop("(RI)", [bs("0111"), reg04, reg04, bs("0111")])
+
+# STC Rn,imm5 - 0111_nnnn_iiii_100I
+addop("STC", [bs("0111"), reg04, imm4_iiii_noarg, bs("100"), imm5_Iiiii])
+
+# LDC Rn,imm5 - 0111_nnnn_iiii_101I
+addop("LDC", [bs("0111"), reg04, imm4_iiii_noarg, bs("101"), imm5_Iiiii])
+
+# (RI) - 0111_xxxx_xxxx_1100
+addop("(RI)", [bs("0111"), reg04, reg04, bs("1100")])
+
+# (RI) - 0111_xxxx_xxxx_1101
+addop("(RI)", [bs("0111"), reg04, reg04, bs("1101")])
+
+# (RI) - 0111_xxxx_xxxx_1110
+addop("(RI)", [bs("0111"), reg04, reg04, bs("1110")])
+
+# (RI) - 0111_xxxx_xxxx_1111
+addop("(RI)", [bs("0111"), reg04, reg04, bs("1111")])
+
+
+### <Major Opcode #8>
+
+# SB Rn[0-7],disp7(TP) - 1000_0nnn_0ddd_dddd
+addop("SB", [bs("10000"), reg03, bs("0"), imm7_noarg, reg00_deref_tp])
+
+# SH Rn[0-7],disp7.align2(TP) - 1000_0nnn_1ddd_ddd0
+# (disp7.align2 = ddd_ddd||0)
+addop("SH", [bs("10000"), reg03, bs("1"), disp7_align2_noarg, bs("0"), reg00_deref_tp])
+
+# LB Rn[0-7],disp7(TP) - 1000_1nnn_0ddd_dddd
+addop("LB", [bs("10001"), reg03, bs("0"), imm7_noarg, reg00_deref_tp])
+
+# LH Rn[0-7],disp7.align2(TP) - 1000_1nnn_1ddd_ddd0
+addop("LH", [bs("10001"), reg03, bs("1"), disp7_align2_noarg, bs("0"), reg00_deref_tp])
+
+# LHU Rn[0-7],disp7.align2(TP) - 1000_1nnn_1ddd_ddd1
+addop("LHU", [bs("10001"), reg03, bs("1"), disp7_align2_noarg, bs("1"), reg00_deref_tp])
+
+
+### <Major Opcode #9>
+
+# ADD3 Rl,Rn,Rm - 1001_nnnn_mmmm_llll
+addop("ADD3", [bs("1001"), reg04_n, reg04_m, reg04_l], [reg04_l, reg04_n, reg04_m])
+
+
+### <Major Opcode #10>
+
+# BEQZ Rn,disp8.align2 - 1010_nnnn_dddd_ddd0
+# (disp8=dddd_ddd||0)
+addop("BEQZ", [bs("1010"), reg04, disp8, bs("0")])
+
+# BNEZ Rn,disp8.align2 - 1010_nnnn_dddd_ddd1
+addop("BNEZ", [bs("1010"), reg04, disp8, bs("1")])
+
+
+### <Major Opcode #11>
+
+# BRA disp12.align2 - 1011_dddd_dddd_ddd0
+# (disp12=dddd_dddd_ddd||0)
+addop("BRA", [bs("1011"), disp12_signed, bs("0")])
+
+# BSR disp12.align2 - 1011_dddd_dddd_ddd1
+addop("BSR", [bs("1011"), disp12_signed, bs("1")])
+
+
+### <Major Opcode #12>
+
+# ADD3 Rn,Rm,imm16 - 1100_nnnn_mmmm_0000 iiii_iiii_iiii_iiii
+addop("ADD3", [bs("1100"), reg04, reg04, bs("0000"), imm16_signed])
+
+# MOV Rn,imm16 - 1100_nnnn_0000_0001 iiii_iiii_iiii_iiii
+addop("MOV", [bs("1100"), reg04, bs("00000001"), imm16])
+
+# MOVU Rn,imm16 - 1100_nnnn_0001_0001 iiii_iiii_iiii_iiii
+addop("MOVU", [bs("1100"), reg04, bs("00010001"), imm16])
+
+# MOVH Rn,imm16 - 1100_nnnn_0010_0001 iiii_iiii_iiii_iiii
+addop("MOVH", [bs("1100"), reg04, bs("00100001"), imm16])
+
+# SLT3 Rn,Rm,imm16 - 1100_nnnn_mmmm_0010 iiii_iiii_iiii_iiii
+addop("SLT3", [bs("1100"), reg04, reg04, bs("0010"), imm16_signed])
+
+# SLTU3 Rn,Rm,imm16 - 1100_nnnn_mmmm_0011 iiii_iiii_iiii_iiii
+addop("SLTU3", [bs("1100"), reg04, reg04, bs("0011"), imm16])
+
+# OR3 Rn,Rm,imm16 - 1100_nnnn_mmmm_0100 iiii_iiii_iiii_iiii
+addop("OR3", [bs("1100"), reg04, reg04, bs("0100"), imm16])
+
+# AND3 Rn,Rm,imm16 - 1100_nnnn_mmmm_0101 iiii_iiii_iiii_iiii
+addop("AND3", [bs("1100"), reg04, reg04, bs("0101"), imm16])
+
+# XOR3 Rn,Rm,imm16 - 1100_nnnn_mmmm_0110 iiii_iiii_iiii_iiii
+addop("XOR3", [bs("1100"), reg04, reg04, bs("0110"), imm16])
+
+# (RI) - 1100_xxxx_xxxx_0111 xxxx_xxxx_xxxx_xxxx
+addop("(RI)", [bs("1100"), imm8, bs("0111"), imm16])
+
+# SB Rn,disp16(Rm) - 1100_nnnn_mmmm_1000 dddd_dddd_dddd_dddd
+addop("SB", [bs("1100"), reg04, reg04_deref_noarg, bs("1000"), disp16_reg_deref], [reg04, disp16_reg_deref])
+
+# SH Rn,disp16(Rm) - 1100_nnnn_mmmm_1001 dddd_dddd_dddd_dddd
+addop("SH", [bs("1100"), reg04, reg04_deref_noarg, bs("1001"), disp16_reg_deref], [reg04, disp16_reg_deref])
+
+# SW Rn,disp16(Rm) - 1100_nnnn_mmmm_1010 dddd_dddd_dddd_dddd
+addop("SW", [bs("1100"), reg04, reg04_deref_noarg, bs("1010"), disp16_reg_deref], [reg04, disp16_reg_deref])
+
+# LBU Rn,disp16(Rm) - 1100_nnnn_mmmm_1011 dddd_dddd_dddd_dddd
+addop("LBU", [bs("1100"), reg04, reg04_deref_noarg, bs("1011"), disp16_reg_deref], [reg04, disp16_reg_deref])
+
+# LB Rn,disp16(Rm) - 1100_nnnn_mmmm_1100 dddd_dddd_dddd_dddd
+addop("LB", [bs("1100"), reg04, reg04_deref_noarg, bs("1100"), disp16_reg_deref], [reg04, disp16_reg_deref])
+
+# LH Rn,disp16(Rm) - 1100_nnnn_mmmm_1101 dddd_dddd_dddd_dddd
+addop("LH", [bs("1100"), reg04, reg04_deref_noarg, bs("1101"), disp16_reg_deref], [reg04, disp16_reg_deref])
+
+# LW Rn,disp16(Rm) - 1100_nnnn_mmmm_1110 dddd_dddd_dddd_dddd
+addop("LW", [bs("1100"), reg04, reg04_deref_noarg, bs("1110"), disp16_reg_deref], [reg04, disp16_reg_deref])
+
+# LHU Rn,disp16(Rm) - 1100_nnnn_mmmm_1111 dddd_dddd_dddd_dddd
+addop("LHU", [bs("1100"), reg04, reg04_deref_noarg, bs("1111"), disp16_reg_deref], [reg04, disp16_reg_deref])
+
+
+### <Major Opcode #13>
+
+# MOVU Rn[0-7],imm24 - 1101_0nnn_IIII_IIII iiii_iiii_iiii_iiii
+addop("MOVU", [bs("11010"), reg03, imm24])
+
+# BCPEQ cccc,disp17 - 1101_1000_cccc_0100 dddd_dddd_dddd_dddd
+addop("BCPEQ", [bs("11011000"), imm4, bs("0100"), disp17])
+
+# BCPNE cccc,disp17 - 1101_1000_cccc_0101 dddd_dddd_dddd_dddd
+addop("BCPNE", [bs("11011000"), imm4, bs("0101"), disp17])
+
+# BCPAT cccc,disp17 - 1101_1000_cccc_0110 dddd_dddd_dddd_dddd
+addop("BCPAT", [bs("11011000"), imm4, bs("0110"), disp17])
+
+# BCPAF cccc,disp17 - 1101_1000_cccc_0111 dddd_dddd_dddd_dddd
+addop("BCPAF", [bs("11011000"), imm4, bs("0111"), disp17])
+
+# JMP target24 - 1101_1TTT_TTTT_1000 tttt_tttt_tttt_tttt
+addop("JMP", [bs("11011"), imm7_noarg, bs("1000"), imm_target24],
+      [imm_target24])  # the only interesting operand is imm_target24
+
+# BSR disp24 - 1101_1DDD_DDDD_1001 dddd_dddd_dddd_dddd
+addop("BSR", [bs("11011"), imm7_noarg, bs("1001"), imm_target24_signed], [imm_target24_signed])
+
+# BSRV disp24 1101_1DDD_DDDD_1011 dddd_dddd_dddd_dddd
+addop("BSRV", [bs("11011"), imm7_noarg, bs("1011"), imm_target24], [imm_target24])
+
+
+### <Major Opcode #14>
+
+# BEQI Rn,imm4,disp17 - 1110_nnnn_iiii_0000 dddd_dddd_dddd_dddd
+addop("BEQI", [bs("1110"), reg04, imm4, bs("0000"), disp17])
+
+# BEQ Rn,Rm,disp17 - 1110_nnnn_mmmm_0001 dddd_dddd_dddd_dddd
+addop("BEQ", [bs("1110"), reg04, reg04, bs("0001"), disp17])
+
+# BNEI Rn,imm4,disp17 - 1110_nnnn_iiii_0100 dddd_dddd_dddd_dddd
+addop("BNEI", [bs("1110"), reg04, imm4, bs("0100"), disp17])
+
+# BNE Rn,Rm,disp17 - 1110_nnnn_mmmm_0101 dddd_dddd_dddd_dddd
+addop("BNE", [bs("1110"), reg04, reg04, bs("0101"), disp17])
+
+# BGEI Rn,imm4,disp17 - 1110_nnnn_iiii_1000 dddd_dddd_dddd_dddd
+addop("BGEI", [bs("1110"), reg04, imm4, bs("1000"), disp17])
+
+# REPEAT Rn,disp17 - 1110_nnnn_0000_1001 dddd_dddd_dddd_dddd
+addop("REPEAT", [bs("1110"), reg04, bs("00001001"), disp17])
+
+# EREPEAT disp17 - 1110_0000_0001_1001 dddd_dddd_dddd_dddd
+addop("EREPEAT", [bs("1110000000011001"), disp17])
+
+# BLTI Rn,imm4,disp17 - 1110_nnnn_iiii_1100 dddd_dddd_dddd_dddd
+addop("BLTI", [bs("1110"), reg04, imm4, bs("1100"), disp17])
+
+# (RI) - 1110_xxxx_xxxx_1101 xxxx_xxxx_xxxx_xxxx
+addop("(RI)", [bs("1110"), imm8, bs("1101"), imm16])
+
+# SW Rn,(abs24) - 1110_nnnn_DDDD_DD10 dddd_dddd_dddd_dddd
+addop("SW", [bs("1110"), reg04, imm6_noarg, bs("10"), abs24])
+
+# LW Rn,(abs24) - 1110_nnnn_DDDD_DD11 dddd_dddd_dddd_dddd
+addop("LW", [bs("1110"), reg04, imm6_noarg, bs("11"), abs24])
+
+
+### <Major Opcode #15>
+
+# DSP Rn,Rm,code16 - 1111_nnnn_mmmm_0000 cccc_cccc_cccc_cccc
+addop("DSP", [bs("1111"), reg04, reg04, bs("0000"), imm16])
+
+# Note: DSP, DSP0 & DSP1 look exactly the same. This is ambiguous, and prevent
+#       them for being correctly disassembled. DSP0 & DSP1 are arbitrarily
+#       disabled.
+
+# DSP0 code24 - 1111_nnnn_mmmm_0000 cccc_cccc_cccc_cccc
+#addop("DSP0", [bs("1111"), imm8_noarg, bs("0000"), imm_code24], [imm_code24])
+
+# DSP1 Rn,code20 - 1111_nnnn_mmmm_0000 cccc_cccc_cccc_cccc
+#addop("DSP1", [bs("1111"), reg04, imm4_noarg, bs("0000"), imm_code20])
+
+# LDZ Rn,Rm - 1111_nnnn_mmmm_0001 0000_0000_0000_0000
+addop("LDZ", [bs("1111"), reg04, reg04, bs("00010000000000000000")])
+
+# AVE Rn,Rm - 1111_nnnn_mmmm_0001 0000_0000_0000_0010
+addop("AVE", [bs("1111"), reg04, reg04, bs("00010000000000000010")])
+
+# ABS Rn,Rm - 1111_nnnn_mmmm_0001 0000_0000_0000_0011
+addop("ABS", [bs("1111"), reg04, reg04, bs("00010000000000000011")])
+
+# MIN Rn,Rm - 1111_nnnn_mmmm_0001 0000_0000_0000_0100
+addop("MIN", [bs("1111"), reg04, reg04, bs("00010000000000000100")])
+
+# MAX Rn,Rm - 1111_nnnn_mmmm_0001 0000_0000_0000_0101
+addop("MAX", [bs("1111"), reg04, reg04, bs("00010000000000000101")])
+
+# MINU Rn,Rm - 1111_nnnn_mmmm_0001 0000_0000_0000_0110
+addop("MINU", [bs("1111"), reg04, reg04, bs("00010000000000000110")])
+
+# MAXU Rn,Rm - 1111_nnnn_mmmm_0001 0000_0000_0000_0111
+addop("MAXU", [bs("1111"), reg04, reg04, bs("00010000000000000111")])
+
+# SADD Rn,Rm - 1111_nnnn_mmmm_0001 0000_0000_0000_1000
+addop("SADD", [bs("1111"), reg04, reg04, bs("00010000000000001000")])
+
+# SADDU Rn,Rm - 1111_nnnn_mmmm_0001 0000_0000_0000_1001
+addop("SADDU", [bs("1111"), reg04, reg04, bs("00010000000000001001")])
+
+# SSUB Rn,Rm - 1111_nnnn_mmmm_0001 0000_0000_0000_1010
+addop("SSUB", [bs("1111"), reg04, reg04, bs("00010000000000001010")])
+
+# SSUBU Rn,Rm - 1111_nnnn_mmmm_0001 0000_0000_0000_1011
+addop("SSUBU", [bs("1111"), reg04, reg04, bs("00010000000000001011")])
+
+# CLIP Rn,imm5 - 1111_nnnn_0000_0001 0001_0000_iiii_i000
+addop("CLIP", [bs("1111"), reg04, bs("0000000100010000"), imm5, bs("000")])
+
+# CLIPU Rn,imm5 - 1111_nnnn_0000_0001 0001_0000_iiii_i001
+addop("CLIPU", [bs("1111"), reg04, bs("0000000100010000"), imm5, bs("001")])
+
+# (RI) - 1111_xxxx_xxxx_0001 0010_xxxx_xxxx_xxxx
+addop("(RI)", [bs("1111"), imm8, bs("00010010"), imm12])
+
+# MADD Rn,Rm - 1111_nnnn_mmmm_0001 0011_0000_0000_0100
+addop("MADD", [bs("1111"), reg04, reg04, bs("00010011000000000100")])
+
+# MADDU Rn,Rm - 1111_nnnn_mmmm_0001 0011_0000_0000_0101
+addop("MADDU", [bs("1111"), reg04, reg04, bs("00010011000000000101")])
+
+# MADDR Rn,Rm - 1111_nnnn_mmmm_0001 0011_0000_0000_0110
+addop("MADDR", [bs("1111"), reg04, reg04, bs("00010011000000000110")])
+
+# MADDRU Rn,Rm - 1111_nnnn_mmmm_0001 0011_0000_0000_0111
+addop("MADDRU", [bs("1111"), reg04, reg04, bs("00010011000000000111")])
+
+# UCI Rn,Rm,code16 - 1111_nnnn_mmmm_0010 cccc_cccc_cccc_cccc
+addop("UCI", [bs("1111"), reg04, reg04, bs("0010"), imm16])
+
+# (RI) - 1111_xxxx_xxxx_0011 xxxx_xxxx_xxxx_xxxx
+addop("(RI)", [bs("1111"), imm8, bs("0011"), imm16])
+
+# STCB Rn,abs16 - 1111_nnnn_0000_0100 aaaa_aaaa_aaaa_aaaa
+addop("STCB", [bs("1111"), reg04, bs("00000100"), imm16])
+
+# LDCB Rn,abs16 - 1111_nnnn_0001_0100 aaaa_aaaa_aaaa_aaaa
+addop("LDCB", [bs("1111"), reg04, bs("00010100"), imm16])
+
+# SBCPA CRn,(Rm+),imm8 - 1111_nnnn_mmmm_0101 0000_0000_iiii_iiii
+addop("SBCPA", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010100000000"), imm8])
+
+# SHCPA CRn,(Rm+),imm8.align2 - 1111_nnnn_mmmm_0101 0001_0000_iiii_iii0
+addop("SHCPA", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010100010000"), imm8_align2, bs("0")])
+
+# SWCPA CRn,(Rm+),imm8.align4 - 1111_nnnn_mmmm_0101 0010_0000_iiii_ii00
+addop("SWCPA", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010100100000"), imm8_align4, bs("00")])
+
+# SMCPA CRn,(Rm+),imm8.align8 - 1111_nnnn_mmmm_0101 0011_0000_iiii_i000
+addop("SMCPA", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010100110000"), imm8_align8, bs("000")])
+
+# LBCPA CRn,(Rm+),imm8 - 1111_nnnn_mmmm_0101 0100_0000_iiii_iiii
+addop("LBCPA", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010101000000"), imm8])
+
+# LHCPA CRn,(Rm+),imm8.align2 - 1111_nnnn_mmmm_0101 0101_0000_iiii_iii0
+addop("LHCPA", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010101010000"), imm8_align2, bs("0")])
+
+# LWCPA CRn,(Rm+),imm8.align4 - 1111_nnnn_mmmm_0101 0110_0000_iiii_ii00
+addop("LWCPA", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010101100000"), imm8_align4, bs("00")])
+
+# LMCPA CRn,(Rm+),imm8.align8 - 1111_nnnn_mmmm_0101 0111_0000_iiii_i000
+addop("LMCPA", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010101110000"), imm8_align8, bs("000")])
+
+# SBCPM0 CRn,(Rm+),imm8 - 1111_nnnn_mmmm_0101 0000_1000_iiii_iiii
+addop("SBCPM0", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010100001000"), imm8])
+
+# SHCPM0 CRn,(Rm+),imm8.align2 - 1111_nnnn_mmmm_0101 0001_1000_iiii_iii0
+addop("SHCPM0", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010100011000"), imm8_align2, bs("0")])
+
+# SWCPM0 CRn,(Rm+),imm8.align4 - 1111_nnnn_mmmm_0101 0010_1000_iiii_ii00
+addop("SWCPM0", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010100101000"), imm8_align4, bs("00")])
+
+# SMCPM0 CRn,(Rm+),imm8.align8 - 1111_nnnn_mmmm_0101 0011_1000_iiii_i000
+addop("SMCPM0", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010100111000"), imm8_align8, bs("000")])
+
+# LBCPM0 CRn,(Rm+),imm8 - 1111_nnnn_mmmm_0101 0100_1000_iiii_iiii
+addop("LBCPM0", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010101001000"), imm8])
+
+# LHCPM0 CRn,(Rm+),imm8.align2 - 1111_nnnn_mmmm_0101 0101_1000_iiii_iii0
+addop("LHCPM0", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010101011000"), imm8_align2, bs("0")])
+
+# LWCPM0 CRn,(Rm+),imm8.align4 - 1111_nnnn_mmmm_0101 0110_1000_iiii_ii00
+addop("LWCPM0", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010101101000"), imm8_align4, bs("00")])
+
+# LMCPM0 CRn,(Rm+),imm8.align8 - 1111_nnnn_mmmm_0101 0111_1000_iiii_i000
+addop("LMCPM0", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010101111000"), imm8_align8, bs("000")])
+
+# SBCPM1 CRn,(Rm+),imm8 - 1111_nnnn_mmmm_0101 0000_1100_iiii_iiii
+addop("SBCPM1", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010100001100"), imm8])
+
+# SHCPM1 CRn,(Rm+),imm8.align2 - 1111_nnnn_mmmm_0101 0001_1100_iiii_iii0
+addop("SHCPM1", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010100011100"), imm8_align2, bs("0")])
+
+# SWCPM1 CRn,(Rm+),imm8.align4 - 1111_nnnn_mmmm_0101 0010_1100_iiii_ii00
+addop("SWCPM1", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010100101100"), imm8_align4, bs("00")])
+
+# SMCPM1 CRn,(Rm+),imm8.align8 - 1111_nnnn_mmmm_0101 0011_1100_iiii_i000
+addop("SMCPM1", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010100111100"), imm8_align8, bs("000")])
+
+# LBCPM1 CRn,(Rm+),imm8 - 1111_nnnn_mmmm_0101 0100_1100_iiii_iiii
+addop("LBCPM1", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010101001100"), imm8])
+
+# LHCPM1 CRn,(Rm+),imm8.align2 - 1111_nnnn_mmmm_0101 0101_1100_iiii_iii0
+addop("LHCPM1", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010101011100"), imm8_align2, bs("0")])
+
+# LWCPM1 CRn,(Rm+),imm8.align4 - 1111_nnnn_mmmm_0101 0110_1100_iiii_ii00
+addop("LWCPM1", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010101101100"), imm8_align4, bs("00")])
+
+# LMCPM1 CRn,(Rm+),imm8.align8 - 1111_nnnn_mmmm_0101 0111_1100_iiii_i000
+addop("LMCPM1", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010101111100"), imm8_align8, bs("000")])
+
+# (RI) - 1111_xxxx_xxxx_0110 xxxx_xxxx_xxxx_xxxx
+addop("(RI)", [bs("1111"), imm8, bs("0110"), imm16])
+
+# CP code24 - 1111_CCCC_CCCC_0111 cccc_cccc_cccc_cccc
+#addop("CP", [bs("1111"), imm8_noarg, bs("0111"), imm_code24], [imm_code24])
+# Note: CP & CMOV* look exactly the same. This is ambiguous, and prevent
+#       them for being correctly disassembled. CP was arbitrarily disabled.
+
+# CP code56 - 1111_CCCC_CCCC_0111 cccc_cccc_cccc_cccc cccc_cccc_cccc_cccc
+# 64-bit VLIW operation mode - not implemented
+
+# CMOV CRn,Rm - 1111_nnnn_mmmm_0111 1111_0000_0000_0000
+#addop("CMOV", [bs("1111"), copro_reg04, reg04, bs("01111111000000000000")])
+
+# CMOV Rm,CRn - 1111_nnnn_mmmm_0111 1111_0000_0000_0001
+#addop("CMOV", [bs("1111"), copro_reg04, reg04, bs("01111111000000000001")], [reg04, copro_reg04])
+
+# CMOVC CCRn,Rm - 1111_nnnn_mmmm_0111 1111_0000_0000_NN10
+# CRn=NNnnnn
+addop("CMOVC", [bs("1111"), imm4_noarg, reg04, bs("0111111100000000"), copro_reg06, bs("10")], [copro_reg06, reg04])
+
+# CMOVC Rm,CCRn - 1111_nnnn_mmmm_0111 1111_0000_0000_NN11
+# CRn=NNnnnn
+addop("CMOVC", [bs("1111"), imm4_noarg, reg04, bs("0111111100000000"), copro_reg06, bs("11")], [reg04, copro_reg06])
+
+# CMOVH CRn,Rm - 1111_nnnn_mmmm_0111 1111_0001_0000_0000
+#addop("CMOVH", [bs("1111"), copro_reg04, reg04, bs("01111111000100000000")])
+
+# CMOVH Rm,CRn - 1111_nnnn_mmmm_0111 1111_0001_0000_0001
+#addop("CMOVH", [bs("1111"), copro_reg04, reg04, bs("01111111000100000001")], [reg04, copro_reg04])
+
+# Note: the following CMOV* instructions are extensions used when the processor
+#       has more than 16 coprocessor general-purpose registers. They can be
+#       used to assemble and disassemble both CMOV* instructuons sets.
+
+# CMOV CRn,Rm - 1111_nnnn_mmmm_0111 1111_0000_0000_N000
+# CRn=Nnnnn
+addop("CMOV", [bs("1111"), imm4_noarg, reg04, bs("0111111100000000"), copro_reg05, bs("000")], [copro_reg05, reg04])
+
+# CMOV Rm,CRn - 1111_nnnn_mmmm_0111 1111_0000_0000_N001
+addop("CMOV", [bs("1111"), imm4_noarg, reg04, bs("0111111100000000"), copro_reg05, bs("001")], [reg04, copro_reg05])
+
+# CMOVH CRn,Rm - 1111_nnnn_mmmm_0111 1111_0001_0000_N000
+addop("CMOVH", [bs("1111"), imm4_noarg, reg04, bs("0111111100010000"), copro_reg05, bs("000")], [copro_reg05, reg04])
+
+# CMOVH Rm,CRn - 1111_nnnn_mmmm_0111 1111_0001_0000_N001
+addop("CMOVH", [bs("1111"), imm4_noarg, reg04, bs("0111111100010000"), copro_reg05, bs("001")], [reg04, copro_reg05])
+
+# (RI) - 1111_xxxx_xxxx_10xx xxxx_xxxx_xxxx_xxxx
+addop("(RI)", [bs("1111"), imm8, bs("10"), imm18])
+
+# SWCP CRn,disp16(Rm) - 1111_nnnn_mmmm_1100 dddd_dddd_dddd_dddd
+addop("SWCP", [bs("1111"), copro_reg04, reg04_deref_noarg, bs("1100"), disp16_reg_deref], [copro_reg04, disp16_reg_deref])
+
+# LWCP CRn,disp16(Rm) - 1111_nnnn_mmmm_1101 dddd_dddd_dddd_dddd
+addop("LWCP", [bs("1111"), copro_reg04, reg04_deref_noarg, bs("1101"), disp16_reg_deref], [copro_reg04, disp16_reg_deref, reg04_deref])
+
+# SMCP CRn,disp16(Rm) - 1111_nnnn_mmmm_1110 dddd_dddd_dddd_dddd
+addop("SMCP", [bs("1111"), copro_reg04, reg04_deref_noarg, bs("1110"), disp16_reg_deref], [copro_reg04, disp16_reg_deref, reg04_deref])
+
+# LMCP CRn,disp16(Rm) - 1111_nnnn_mmmm_1111 dddd_dddd_dddd_dddd
+addop("LMCP", [bs("1111"), copro_reg04, reg04_deref_noarg, bs("1111"), disp16_reg_deref], [copro_reg04, disp16_reg_deref])
diff --git a/src/miasm/arch/mep/disasm.py b/src/miasm/arch/mep/disasm.py
new file mode 100644
index 00000000..0260c01d
--- /dev/null
+++ b/src/miasm/arch/mep/disasm.py
@@ -0,0 +1,23 @@
+# Toshiba MeP-c4 - miasm disassembly engine
+# Guillaume Valadon <guillaume@valadon.net>
+
+from miasm.core.asmblock import disasmEngine
+from miasm.arch.mep.arch import mn_mep
+
+
+class dis_mepb(disasmEngine):
+    """MeP miasm disassembly engine - Big Endian
+
+       Notes:
+           - its is mandatory to call the miasm Machine
+    """
+
+    attrib = "b"
+
+    def __init__(self, bs=None, **kwargs):
+        super(dis_mepb, self).__init__(mn_mep, self.attrib, bs, **kwargs)
+
+
+class dis_mepl(dis_mepb):
+    """MeP miasm disassembly engine - Little Endian"""
+    attrib = "l"
diff --git a/src/miasm/arch/mep/jit.py b/src/miasm/arch/mep/jit.py
new file mode 100644
index 00000000..3fee2537
--- /dev/null
+++ b/src/miasm/arch/mep/jit.py
@@ -0,0 +1,112 @@
+# Toshiba MeP-c4 - miasm jitter
+# Guillaume Valadon <guillaume@valadon.net>
+# Note: inspiration from msp430/jit.py
+
+from miasm.jitter.jitload import Jitter
+from miasm.core.utils import *
+from miasm.jitter.codegen import CGen
+from miasm.ir.translators.C import TranslatorC
+from miasm.arch.mep.sem import Lifter_MEPl, Lifter_MEPb
+
+import logging
+
+log = logging.getLogger("jit_mep")
+hnd = logging.StreamHandler()
+hnd.setFormatter(logging.Formatter("[%(levelname)-8s]: %(message)s"))
+log.addHandler(hnd)
+log.setLevel(logging.CRITICAL)
+
+
+class mep_CGen(CGen):
+    """
+    Translate a block containing MeP instructions to C
+
+    Note: it is used to emulate the *REPEAT instructions
+    """
+
+    def __init__(self, lifter):
+        self.lifter = lifter
+        self.PC = self.lifter.arch.regs.PC
+        self.translator = TranslatorC(self.lifter.loc_db)
+        self.init_arch_C()
+
+    def gen_pre_code(self, attrib):
+        """Generate C code inserted before the current block"""
+
+        # Call the base class method
+        out = super(mep_CGen, self).gen_pre_code(attrib)
+
+        # Set the PC register value explicitly
+        out.append("mycpu->PC = 0x%X;" % attrib.instr.offset)
+        out.append("mycpu->last_addr = mycpu->PC;");
+
+        return out
+
+    def gen_post_code(self, attrib, pc_value):
+        """Generate C code inserted after the current block"""
+
+        # Call the base class method
+        out = super(mep_CGen, self).gen_post_code(attrib, pc_value)
+
+        # Implement the *REPEAT instructions logics
+        tmp = r"""
+        /* *REPEAT instructions logic */
+        {
+            uint32_t is_repeat_end = mycpu->is_repeat_end;
+            mycpu->is_repeat_end = !!(mycpu->last_addr == (mycpu->RPE&~0x1));
+
+            if (is_repeat_end && !mycpu->take_jmp &&
+                   (mycpu->in_erepeat || mycpu->RPC)) {
+                 if (mycpu->RPC)
+                       mycpu->RPC --;
+
+                 //printf("Go repeat  %X\n", mycpu->RPB);
+                 DST_value = mycpu->RPB;
+                 BlockDst->address = mycpu->RPB;
+                 return JIT_RET_NO_EXCEPTION;
+             }
+        }
+        """
+
+        out += tmp.split('`\n')
+        return out
+
+
+class jitter_mepl(Jitter):
+
+    C_Gen = mep_CGen
+
+    def __init__(self, loc_db, *args, **kwargs):
+        Jitter.__init__(self, Lifter_MEPl(loc_db), *args, **kwargs)
+        self.vm.set_little_endian()
+        self.lifter.jit_pc = self.lifter.arch.regs.PC
+
+    def push_uint16_t(self, v):
+        regs = self.cpu.get_gpreg()
+        regs["SP"] -= 2
+        self.cpu.set_gpreg(regs)
+        self.vm.set_mem(regs["SP"], pck16(v))
+
+    def pop_uint16_t(self):
+        regs = self.cpu.get_gpreg()
+        x = self.vm.get_u16(regs["SP"])
+        regs["SP"] += 2
+        self.cpu.set_gpreg(regs)
+        return x
+
+    def get_stack_arg(self, n):
+        regs = self.cpu.get_gpreg()
+        x = self.vm.get_u16(regs["SP"] + 2 * n)
+        return x
+
+    def init_run(self, *args, **kwargs):
+        Jitter.init_run(self, *args, **kwargs)
+        self.cpu.PC = self.pc
+
+
+class jitter_mepb(jitter_mepl):
+
+    def __init__(self, loc_db, *args, **kwargs):
+        Jitter.__init__(self, Lifter_MEPb(loc_db), *args, **kwargs)
+        self.vm.set_big_endian()
+        self.lifter.jit_pc = self.lifter.arch.regs.PC
diff --git a/src/miasm/arch/mep/lifter_model_call.py b/src/miasm/arch/mep/lifter_model_call.py
new file mode 100644
index 00000000..db729ba0
--- /dev/null
+++ b/src/miasm/arch/mep/lifter_model_call.py
@@ -0,0 +1,45 @@
+# Toshiba MeP-c4 - miasm IR analysis
+# Guillaume Valadon <guillaume@valadon.net>
+
+from miasm.arch.mep.sem import Lifter_MEPb, Lifter_MEPl
+from miasm.ir.analysis import LifterModelCall
+
+
+class LifterModelCallMepb(Lifter_MEPb, LifterModelCall):
+    """MeP high level IR manipulations - Big Endian
+
+    Notes:
+        - it is mandatory for symbolic execution.
+    """
+
+    def __init__(self, loc_db):
+        Lifter_MEPb.__init__(self, loc_db)
+        self.ret_reg = self.arch.regs.R0
+
+    # Note: the following are abstract method and must be implemented
+    def sizeof_char(self):
+        "Return the size of a char in bits"
+        return 8
+
+    def sizeof_short(self):
+        "Return the size of a short in bits"
+        return 16
+
+    def sizeof_int(self):
+        "Return the size of an int in bits"
+        return 32
+
+    def sizeof_long(self):
+        "Return the size of a long in bits"
+        return 32
+
+    def sizeof_pointer(self):
+        "Return the size of a void* in bits"
+        return 32
+
+
+class LifterModelCallMepl(Lifter_MEPl, LifterModelCallMepb):
+    """MeP high level IR manipulations - Little Endian"""
+
+    def __init__(self, loc_db):
+        LifterModelCallMepb.__init__(self, loc_db)
diff --git a/src/miasm/arch/mep/regs.py b/src/miasm/arch/mep/regs.py
new file mode 100644
index 00000000..be195b61
--- /dev/null
+++ b/src/miasm/arch/mep/regs.py
@@ -0,0 +1,91 @@
+# Toshiba MeP-c4 - miasm registers definition
+# Guillaume Valadon <guillaume@valadon.net>
+
+from builtins import range
+from miasm.expression.expression import ExprId
+from miasm.core.cpu import reg_info, gen_reg, gen_regs
+
+# Used by internal miasm exceptions
+exception_flags = ExprId("exception_flags", 32)
+exception_flags_init = ExprId("exception_flags_init", 32)
+
+is_repeat_end = ExprId("is_repeat_end", 32)
+is_repeat_end_init = ExprId("is_repeat_end_init", 32)
+last_addr = ExprId("last_addr", 32)
+last_addr_init = ExprId("last_addr_init", 32)
+take_jmp = ExprId("take_jmp", 32)
+take_jmp_init = ExprId("take_jmp_init", 32)
+in_erepeat = ExprId("in_erepeat", 32)
+in_erepeat_init = ExprId("take_jmp_init", 32)
+
+
+# General-purpose registers (R0 to R15) names
+gpr_names = ["R%d" % r for r in range(13)]  # register names
+gpr_names += ["TP", "GP", "SP"]  # according to the manual GP does not exist
+gpr_exprs, gpr_inits, gpr_infos = gen_regs(gpr_names, globals())  # sz=32 bits (default)
+
+# Notes:
+#     - gpr_exprs: register ExprIds on 32 bits.  The size is important for
+#       symbolic execution.
+#     - gpr_inits: register initial values.
+#     - gpr_infos: object that binds names & ExprIds
+
+# Define aliases to general-purpose registers
+TP = gpr_exprs[13]  # Tiny data area Pointer
+GP = gpr_exprs[14]  # Global Pointer
+SP = gpr_exprs[15]  # Stack Pointer
+
+
+# Control/special registers name
+csr_names = ["PC", "LP", "SAR", "S3", "RPB", "RPE", "RPC", "HI", "LO",
+             "S9", "S10", "S11", "MB0", "ME0", "MB1", "ME1", "PSW",
+             "ID", "TMP", "EPC", "EXC", "CFG", "S22", "NPC", "DBG",
+             "DEPC", "OPT", "RCFG", "CCFG", "S29", "S30", "S31", "S32"]
+csr_exprs, csr_inits, csr_infos = gen_regs(csr_names, globals())
+
+# Define aliases to control/special registers
+PC = csr_exprs[0]  # Program Counter. On MeP, it is the special register R0
+LP = csr_exprs[1]  # Link Pointer. On MeP, it is the special register R1
+SAR = csr_exprs[2]  # Shift Amount Register. On MeP, it is the special register R2
+RPB = csr_exprs[4]  # Repeat Begin. On MeP, it is the special register R4
+RPE = csr_exprs[5]  # Repeat End. On MeP, it is the special register R5
+RPC = csr_exprs[6]  # Repeat Counter. On MeP, it is the special register R6
+
+
+# Coprocesssor general-purpose registers (C0 to C15) names
+# Note: a processor extension allows up to 32 coprocessor general-purpose registers
+copro_gpr_names = ["C%d" % r for r in range(32)]  # register names
+copro_gpr_exprs, copro_gpr_inits, copro_gpr_infos = gen_regs(copro_gpr_names, globals())
+
+
+# Set registers initial values
+all_regs_ids = gpr_exprs + csr_exprs + copro_gpr_exprs + [
+    exception_flags, take_jmp, last_addr, is_repeat_end,
+    in_erepeat
+]
+
+all_regs_ids_init = gpr_inits + csr_inits + copro_gpr_inits + [
+    exception_flags_init, take_jmp_init, last_addr_init, is_repeat_end_init,
+    in_erepeat_init
+]
+
+all_regs_ids_no_alias = all_regs_ids[:]  # GV: not understood yet !
+all_regs_ids_byname = dict([(x.name, x) for x in all_regs_ids])
+
+
+float_st0 = ExprId("float_st0", 64)
+float_st1 = ExprId("float_st1", 64)
+float_st2 = ExprId("float_st2", 64)
+float_st3 = ExprId("float_st3", 64)
+float_st4 = ExprId("float_st4", 64)
+float_st5 = ExprId("float_st5", 64)
+float_st6 = ExprId("float_st6", 64)
+float_st7 = ExprId("float_st7", 64)
+
+regs_flt_expr = [float_st0, float_st1, float_st2, float_st3,
+                 float_st4, float_st5, float_st6, float_st7]
+
+
+regs_init = dict()  # mandatory name
+for i, r in enumerate(all_regs_ids):
+    regs_init[r] = all_regs_ids_init[i]
diff --git a/src/miasm/arch/mep/sem.py b/src/miasm/arch/mep/sem.py
new file mode 100644
index 00000000..0ac50c58
--- /dev/null
+++ b/src/miasm/arch/mep/sem.py
@@ -0,0 +1,1240 @@
+# Toshiba MeP-c4 - miasm instructions side effects
+# Guillaume Valadon <guillaume@valadon.net>
+
+from miasm.core.sembuilder import SemBuilder
+from miasm.ir.ir import Lifter
+from miasm.arch.mep.arch import mn_mep
+from miasm.arch.mep.regs import PC, SP, LP, SAR, TP, RPB, RPE, RPC, EPC, NPC, \
+    take_jmp, in_erepeat
+from miasm.arch.mep.regs import EXC, HI, LO, PSW, DEPC, DBG
+from miasm.expression.expression import ExprId, ExprInt, ExprOp, TOK_EQUAL
+from miasm.expression.expression import ExprAssign, ExprCond, ExprMem
+from miasm.core.cpu import sign_ext
+from miasm.jitter.csts import EXCEPT_DIV_BY_ZERO
+
+from miasm.arch.mep.regs import exception_flags
+
+
+def compute_s_inf(arg1, arg2):
+    """Signed comparison operator"""
+    return ((arg1 - arg2) ^ ((arg1 ^ arg2) & ((arg1 - arg2) ^ arg1))).msb()
+
+def compute_u_inf(x, y):
+    """Unsigned comparison operator"""
+    result = (((x - y) ^ ((x ^ y) & ((x - y) ^ x))) ^ x ^ y).msb()
+    return result
+
+def i8(value):
+    return ExprInt(value, 8)
+
+def i32(value):
+    return ExprInt(value, 32)
+
+
+# SemBuilder context
+ctx = {"PC": PC, "SP": SP, "LP": LP, "SAR": SAR, "TP": TP,
+       "RPB": RPB, "RPE": RPE, "RPC": RPC, "EPC": EPC, "NPC": NPC,
+       "EXC": EXC, "HI": HI, "LO": LO, "PSW": PSW, "DEPC": DEPC, "DBG": DBG,
+       "exception_flags": exception_flags, "compute_s_inf": compute_s_inf,
+       "compute_u_inf": compute_u_inf, "take_jmp": take_jmp,
+       "in_erepeat": in_erepeat, "EXCEPT_DIV_BY_ZERO": EXCEPT_DIV_BY_ZERO}
+sbuild = SemBuilder(ctx)
+
+
+# Functions used to get an instruction IR
+manual_functions = dict()
+
+
+@sbuild.parse
+def mep_nop():
+    """Dummy instruction"""
+
+
+@sbuild.parse
+def mep_nop_2_args(arg1, arg2):
+    """Dummy instruction with two arguments"""
+
+
+### Load/Store instructions
+
+# Register indirect addressing mode
+
+def sb(ir, instr, reg_src, deref_dst):
+    """SB - Store Byte into memory"""
+
+    # MemByte(Rm31..0) <- Rn7..0
+    # MemByte((ZeroExt(disp7)+TP)31..0)) <- Rn7..0
+    # MemByte((SignExt(disp16)+Rm)31..0) <- Rn7..0
+    e = []
+    e.append(ExprAssign(ExprMem(deref_dst.ptr, 8), reg_src[:8]))
+    return e, []
+
+manual_functions["sb"] = sb
+
+
+def sh(ir, instr, reg_src, deref_dst):
+    """SH - Store Halfword into memory"""
+
+    # MemHword(Rm31..1||0) <- Rn15..0
+    # MemHword((ZeroExt((disp7)6..1||0)+TP)31..1||0)) <- Rn15..0
+    # MemHword((SignExt(disp16)+Rm)31..1||0) <- Rn15..0
+    e = []
+    e.append(ExprAssign(ExprMem(deref_dst.ptr & i32(0xFFFFFFFE), 16), reg_src[:16]))
+    return e, []
+
+manual_functions["sh"] = sh
+
+
+def sw(ir, instr, reg_src, deref_dst):
+    """SW - Store Word into memory"""
+
+    # MemWord(Rm31..2||00) <- Rn31..0
+    # MemWord((ZeroExt((disp7)6..2||00)+SP)31..2||00)) <- Rn31..0
+    # MemWord((ZeroExt((disp7)6..2||00)+TP)31..2||00)) <- Rn31..0
+    # MemWord((SignExt(disp16)+Rm)31..2||00) <- Rn31..0
+    # MemWord(ZeroExt((abs24)23..2||00)) - Rn31..0
+    e = []
+    e.append(ExprAssign(ExprMem(deref_dst.ptr & i32(0xFFFFFFFC), 32), reg_src))
+    return e, []
+
+manual_functions["sw"] = sw
+
+# Without the sembuilder
+#def sw(ir, instr, reg_src, deref_reg_or_imm, deref_reg=None):
+#    """SW - store Word into memory.
+#
+#       Note: there are three variants to get the memory address:
+#            - from a register
+#            - relatively to SP
+#            - relatively to TP"""
+#
+#    if isinstance(deref_reg_or_imm, ExprMem):
+#        # MemWord(Rm31..2||00) <- Rn31..0
+#        dst = deref_reg_or_imm
+#
+#    elif isinstance(deref_reg_or_imm, ExprInt) and deref_reg:
+#        # MemWord((ZeroExt((disp7)6..2||00)+SP)31..2||00)) <- Rn31..0
+#        # MemWord((ZeroExt((disp7)6..2||00)+TP)31..2||00)) <- Rn31..0
+#
+#        imm = deref_reg_or_imm.zeroExtend(32)
+#        dst = ExprMem(ExprOp("+", imm, deref_reg.arg))
+#
+#    return [ExprAssign(dst, reg_src)], []
+
+
+def lb(ir, instr, reg_dst, deref_dst):
+    """LB - Load Byte from memory"""
+
+    # Rn <- SignExt(MemByte(Rm31..0))
+    # Rn <- SignExt(MemByte((ZeroExt(disp7)+TP)31..0))
+    # Rn <- SignExt(MemByte((SignExt(disp16)+Rm)31..0)
+    e = []
+    e.append(ExprAssign(reg_dst, ExprMem(deref_dst.ptr, 8).signExtend(32)))
+    return e, []
+
+manual_functions["lb"] = lb
+
+
+def lh(ir, instr, reg_dst, deref_dst):
+    """LH - Load Halfword from memory"""
+
+    # Rn <- SignExt(MemHword(Rm31..1||0))
+    # Rn <- SignExt(MemHword((ZeroExt((disp7)6..1||0)+TP)31..1||0)
+    # Rn <- SignExt(MemHword((SignExt(disp16)+Rm)31..1||0))
+    e = []
+    e.append(ExprAssign(reg_dst, ExprMem(deref_dst.ptr & i32(0xFFFFFFFE), 16).signExtend(32)))
+    return e, []
+
+manual_functions["lh"] = lh
+
+def lw(ir, instr, reg_dst, deref_dst):
+    """LW - Load Word from memory"""
+
+    # Rn <- MemWord(Rm31..2||00)
+    # Rn <- MemWord((ZeroExt((disp7)6..2||00)+TP)31..2||00)
+    # Rn <- MemWord((SignExt(disp16)+Rm)31..2||00)
+    # Rn <- MemWord(ZeroExt((abs24)23..2||00))
+    e = []
+    e.append(ExprAssign(reg_dst, ExprMem(deref_dst.ptr & i32(0xFFFFFFFC), 32)))
+    return e, []
+
+manual_functions["lw"] = lw
+
+
+def lbu(ir, instr, reg_dst, deref_dst):
+    """LBU - Load an unsigned Byte from memory"""
+
+    # Rn <- ZeroExt(MemByte(Rm31..0))
+    # Rn <- ZeroExt(MemByte((ZeroExt(disp7)+TP)31..0))
+    # Rn <- ZeroExt(MemByte((SignExt(disp16)+Rm)31..0))
+    e = []
+    e.append(ExprAssign(reg_dst, ExprMem(deref_dst.ptr, 8).zeroExtend(32)))
+    return e, []
+
+manual_functions["lbu"] = lbu
+
+
+def lhu(ir, instr, reg_dst, deref_dst):
+    """LHU - Load an unsigned Halfword from memory"""
+
+    # Rn <- ZeroExt(MemHword(Rm31..1||0))
+    # Rn <- ZeroExt(MemHword((SignExt(disp16)+Rm)31..1||0))
+    # Rn <- ZeroExt(MemHword((ZeroExt((disp7)6..1||0)+TP)31..1||0))
+    e = []
+    e.append(ExprAssign(reg_dst, ExprMem(deref_dst.ptr & i32(0xFFFFFFFE), 16).zeroExtend(32)))
+    return e, []
+
+manual_functions["lhu"] = lhu
+
+
+
+### Byte/Halfword extension instructions
+
+@sbuild.parse
+def extb(reg):
+    """EXTB - Sign extend a byte"""
+
+    # Rn <- SignExt(Rn7..0)
+    reg = reg[:8].signExtend(32)
+
+
+@sbuild.parse
+def exth(reg):
+    """EXTH - Sign extend a word"""
+
+    # Rn <- ZeroExt(Rn15..0)
+    reg = reg[:16].signExtend(32)
+
+
+@sbuild.parse
+def extub(reg):
+    """EXUTB - Zero extend a byte"""
+
+    # Rn <- SignExt(Rn7..0)
+    reg = reg[:8].zeroExtend(32)
+
+
+@sbuild.parse
+def extuh(reg):
+    """EXTUH - Zero extend a word"""
+
+    # Rn <- ZeroExt(Rn15..0)
+    reg = reg[:16].zeroExtend(32)
+
+
+### Shift amount manipulation instructions
+
+#@sbuild.parse
+#def ssarb(deref_reg):
+
+
+### Move instructions
+
+@sbuild.parse
+def mov(reg, value):
+    """MOV - Copy 'value' to a register. The three alternatives are handled."""
+
+    # Rn <- Rm
+    # Rn <- SignExt(imm8)
+    # Rn <- SignExt(imm16)
+    reg = value.signExtend(32)
+
+
+@sbuild.parse
+def movu(reg, value):
+    """MOV - Copy 'value' to a register. The two alternatives are handled."""
+
+    # Rn[0-7] <- ZeroExt(imm24)
+    # Rn <- ZeroExt(imm16)
+    reg = value.zeroExtend(32)
+
+
+@sbuild.parse
+def movh(reg, imm16):
+    """MOVH - Copy a shifted imm16 to a register."""
+
+    # Rn <- imm16 <<16
+    reg = imm16.zeroExtend(32) << i32(16)
+
+
+### Arithmetic instructions
+
+def add3(ir, instr, reg_dst, reg_src, reg_or_imm):
+    """ADD3 - Add two register and store the result to a register, or
+              add a register and an immediate and store the result to a register"""
+
+    if isinstance(reg_or_imm, ExprId):
+        # Rl <- Rn + Rm
+        result = ExprOp("+", reg_src, reg_or_imm)
+    else:
+        # Rn <- Rm + SignExt(imm16)
+        value = int(reg_or_imm)
+        result = ExprOp("+", reg_src, ExprInt(value, 32))
+
+    return [ExprAssign(reg_dst, result)], []
+
+manual_functions["add3"] = add3
+
+
+@sbuild.parse
+def add(arg1, arg2):
+    """ADD - Add a register and an immediate."""
+
+    # Rn <- Rn + SignExt(imm6)
+    arg1 = arg1 + arg2.signExtend(32)
+
+
+@sbuild.parse
+def advck3(r0, rn, rm):
+    """ADVCK3 - Check addition overflow."""
+
+    # if(Overflow(Rn+Rm)) R0<-1 else R0<-0 (Signed)
+    r0 = i32(1) if compute_u_inf(i64(0xFFFFFFFF), rn.zeroExtend(64) + rm.zeroExtend(64)) else i32(0)
+
+
+@sbuild.parse
+def sub(reg1, reg2):
+    """SUB - Subtract one register to another."""
+
+    # Rn <- Rn - Rm
+    reg1 = reg1 - reg2
+
+
+def sbvck3(ir, instr, r0, rn, rm):
+    """SBVCK3 - Check subtraction overflow"""
+
+    # if(Overflow(Rn-Rm)) R0<-1 else R0<-0 (Signed)
+
+    # Subtract registers
+    reg_sub = ExprOp("+", rn, rm)
+
+    # Get the register storing the highest value
+    max_rn_rm = ExprCond(ExprOp(">", rn, rm), rn, rm)
+
+    # Check for an overflow
+    overflow_test = ExprOp(">", reg_sub, max_rn_rm)
+
+    # Return the result
+    condition = ExprCond(overflow_test, ExprInt(1, 32), ExprInt(0, 32))
+    return [ExprAssign(r0, condition)], []
+
+manual_functions["sbvck3"] = sbvck3
+
+
+@sbuild.parse
+def neg(reg1, reg2):
+    """NEG - Negate one register."""
+
+    # Rn <- - Rm
+    reg1 = - reg2
+
+
+@sbuild.parse
+def slt3(r0, rn, rm_or_imm5):
+    """SLT3 - Set on less than (signed)."""
+
+    # if (Rn<Rm) R0<-1 else R0<-0 (Signed)
+    # if (Rn<ZeroExt(imm5)) R0<-1 else R0<-0(Signed)
+    r0 = i32(1) if compute_s_inf(rn, rm_or_imm5.signExtend(32)) else i32(0)
+
+if False:
+    rm_ext = rm_or_imm5
+
+    # Mask sign bits
+    sign_mask = i32(0x80000000)
+    sign_rn = rn & sign_mask
+    sign_rm = rm_ext & sign_mask
+
+    # Check if both numbers are positive or negative
+    are_both_neg = sign_rn & sign_rm
+    are_both_pos = ~(sign_rn & sign_rm) >> i32(31)
+
+    # rn is positive and rm negative, return 1
+    r0_mixed = i32(1) if sign_rn else i32(0)
+
+    # rn & rm are both positives, test and return 1 or 0
+    r0_pos = (i32(1) if "<"(rn, rm_ext) else i32(0)) if are_both_pos else r0_mixed
+
+    # rn & rm are both negatives, test and return 0 or 1
+    r0 = (i32(0) if "<"(rn, rm_ext) else i32(1)) if are_both_neg else r0_pos
+
+
+@sbuild.parse
+def sltu3(r0, rn, rm_or_imm5):
+    """SLTU3 - Set on less than (unsigned)."""
+
+    # if (Rn<Rm) R0<-1 else R0<-0 (Unsigned)
+    # if (Rn<ZeroExt(imm5)) R0<-1 else R0<-0(Unsigned)
+    r0 = i32(1) if compute_u_inf(rn, rm_or_imm5) else i32(0)
+
+
+@sbuild.parse
+def sl1ad3(r0, rn, rm):
+    """SL1AD3 - Shift a register one bit left, then add another one."""
+
+    # R0 <- (Rn<<1) + Rm
+    r0 = (rn << i32(1)) + rm
+
+
+@sbuild.parse
+def sl2ad3(r0, rn, rm):
+    """SL2AD3 - Shift a register two bits left, then add another one."""
+
+    # R0 <- (Rn<<2) + Rm
+    r0 = (rn << i32(2)) + rm
+
+
+### Logical instructions
+
+@sbuild.parse
+def logical_or(rn, rm):
+    """OR - Logical OR between two registers."""
+
+    # Rn <- Rn or Rm
+    rn = rn | rm
+
+manual_functions["or"] = logical_or
+
+
+@sbuild.parse
+def logical_and(rn, rm):
+    """AND - Logical AND between two registers."""
+
+    # Rn <- Rn and Rm
+    rn = rn & rm
+
+manual_functions["and"] = logical_and
+
+
+@sbuild.parse
+def xor(rn, rm):
+    """XOR - Logical XOR between two registers."""
+
+    # Rn <- Rn xor Rm
+    rn = rn ^ rm
+
+
+@sbuild.parse
+def nor(rn, rm):
+    """NOR - Logical NOR between two registers."""
+
+    # Rn <- Rn nor Rm
+    rn = ~ (rn | rm)
+
+
+@sbuild.parse
+def or3(rn, rm, imm16):
+    """OR3 - Logical OR between a register and an immediate"""
+
+    # Rn <- Rm or ZeroExt(imm16)
+    rn = rm | imm16
+
+
+@sbuild.parse
+def and3(rn, rm, imm16):
+    """AND3 - Logical AND between a register and an immediate"""
+
+    # Rn <- Rm and ZeroExt(imm16)
+    rn = rm & imm16
+
+
+@sbuild.parse
+def xor3(rn, rm, imm16):
+    """XOR3 - Logical XOR between a register and an immediate"""
+
+    # Rn <- Rm xor ZeroExt(imm16)
+    rn = rm ^ imm16
+
+
+### Shift instruction
+
+@sbuild.parse
+def sra(rn, rm_or_imm5):
+    """SRA - Shift Right signed"""
+
+    # Rn <- (Signed) Rn >> Rm4..0
+    # Rn <- (Signed) Rn >> imm5
+
+    # Unsigned result
+    shift_u = rn >> rm_or_imm5
+
+    # Signed result
+    shift_mask = i32(32) - rm_or_imm5
+    mask = (i32(0xFFFFFFFF) >> shift_mask) << shift_mask
+    shift_s = shift_u | mask
+
+    rn = shift_s if rn.msb() else shift_u
+
+
+@sbuild.parse
+def srl(rn, rm_or_imm5):
+    """SRL - Shift Right unsigned."""
+
+    # Rn <- (Unsigned) Rn >> Rm4..0
+    # Rn <- (Unsigned) Rn >> imm5
+    rn = rn >> rm_or_imm5
+
+
+@sbuild.parse
+def sll(rn, rm_or_imm5):
+    """SLL - Shift Left unsigned."""
+
+    # Rn <- (Unsigned) Rn >> Rm4..0
+    # Rn <- (Unsigned) Rn << imm5
+    rn = rn << rm_or_imm5
+
+
+@sbuild.parse
+def sll3(r0, rn, imm5):
+    """SLL3 - Shift Left unsigned, with 3 arguments."""
+
+    # R0 <- (Unsigned) Rn << imm5
+    r0 = rn << imm5
+
+
+@sbuild.parse
+def fsft(rn, rm):
+    """FSFT - Funnel shift."""
+
+    # Rn <- ((Rn||Rm)<<SAR5..0)63..32
+    # Note: lowest Rm bits are discarded
+
+    sar = SAR[:5].zeroExtend(32)
+    tmp_rn = rn << sar  # Shift Rn
+    tmp_rm = rm >> (i32(32) - sar)  # Shift Rm in the reverse order
+    rn = tmp_rn | tmp_rm  # Concatenate registers
+
+
+## Branch/Jump instructions
+
+@sbuild.parse
+def bra(disp12):
+    """BRA - Branch to an address."""
+
+    # PC <- PC + SignExt((disp12)11..1||0)
+    dst = disp12
+    PC = dst
+    take_jmp = ExprInt(1, 32)
+    ir.IRDst = dst
+
+
+@sbuild.parse
+def beqz(reg_test, disp8):
+    """BEQZ - Branch if the register stores zero."""
+
+    # if(Rn==0) PC <- PC +SignExt((disp8)7..1||0)
+    dst = ExprLoc(ir.get_next_break_loc_key(instr), 32) if reg_test else disp8
+    take_jmp = ExprInt(0, 32) if reg_test else ExprInt(1, 32)
+    PC = dst
+    ir.IRDst = dst
+
+
+@sbuild.parse
+def bnez(reg_test, disp8):
+    """BNEZ - Branch if the register does not store zero."""
+
+    # if(Rn!=0) PC <- PC + SignExt((disp8)7..1||0)
+    dst = disp8 if reg_test else ExprLoc(ir.get_next_break_loc_key(instr), 32)
+    take_jmp = ExprInt(1, 32) if reg_test else ExprInt(0, 32)
+    PC = dst
+    ir.IRDst = dst
+
+
+@sbuild.parse
+def beqi(reg_test, imm4, disp16):
+    """BEQI - Branch if the register stores imm4."""
+
+    # if(Rn==ZeroExt(imm4)) PC <- PC +SignExt((disp17)16..1||0)
+    dst = ExprLoc(ir.get_next_break_loc_key(instr), 32) if (reg_test - imm4) else disp16
+    take_jmp = ExprInt(0, 32) if (reg_test - imm4) else ExprInt(1, 32)
+    PC = dst
+    ir.IRDst = dst
+
+
+@sbuild.parse
+def bnei(reg_test, imm4, disp16):
+    """BNEI - Branch if the register does not store imm4."""
+
+    # if(Rn!=ZeroExt(imm4)) PC <- PC+SignExt((disp17)16..1||0)
+    dst = disp16 if (reg_test - imm4) else ExprLoc(ir.get_next_break_loc_key(instr), 32)
+    take_jmp = ExprInt(1, 32) if (reg_test - imm4) else ExprInt(0, 32)
+    PC = dst
+    ir.IRDst = dst
+
+
+@sbuild.parse
+def blti(reg_test, imm4, disp16):
+    """BLTI - Branch if the register is lower than imm4."""
+
+    # if(Rn< ZeroExt(imm4)) PC <- PC +SignExt((disp17)16..1||0) - (Signed comparison)
+    dst = disp16 if compute_s_inf(reg_test, imm4) else ExprLoc(ir.get_next_break_loc_key(instr), 32)
+    take_jmp = ExprInt(1, 32) if compute_s_inf(reg_test, imm4) else ExprInt(0, 32)
+    PC = dst
+    ir.IRDst = dst
+
+
+@sbuild.parse
+def bgei(reg_test, imm4, disp16):
+    """BGEI - Branch if the register is greater or equal to imm4."""
+
+    # if(Rn>=ZeroExt(imm4)) PC <- PC +SignExt((disp17)16..1||0) - (Signed comparison)
+    cond = i32(1) if ExprOp(TOK_EQUAL, reg_test, imm4) else compute_s_inf(imm4, reg_test).zeroExtend(32)
+    dst = disp16 if cond else ExprLoc(ir.get_next_break_loc_key(instr), 32)
+    take_jmp = ExprInt(1, 32) if cond else ExprInt(0, 32)
+    PC = dst
+    ir.IRDst = dst
+
+
+@sbuild.parse
+def beq(rn, rm, disp16):
+    """BEQ - Branch if the two registers are equal."""
+
+    # if(Rn==Rm) PC <- PC +SignExt((disp17)16..1||0)
+    dst = ExprLoc(ir.get_next_break_loc_key(instr), 32) if (rn - rm) else disp16
+    take_jmp = ExprInt(0, 32) if (rn - rm) else ExprInt(1, 32)
+    PC = dst
+    ir.IRDst = dst
+
+
+@sbuild.parse
+def bne(rn, rm, disp16):
+    """BNE - Branch if the two registers are not equal."""
+
+    # if(Rn!=Rm) PC <- PC +SignExt((disp17)16..1||0)
+    dst = disp16 if (rn - rm) else ExprLoc(ir.get_next_break_loc_key(instr), 32)
+    take_jmp = ExprInt(1, 32) if (rn - rm) else ExprInt(0, 32)
+    PC = dst
+    ir.IRDst = dst
+
+
+@sbuild.parse
+def bsr(disp):
+    """BSR - Branch to an address, and store the return address."""
+
+    # 16-bit variant: LP <- PC + 2; PC <- PC +SignExt((disp12)11..1||0)
+    # 32-bit variant: LP <- PC + 4; PC <- PC +SignExt((disp24)23..1||0)
+
+    # Set LP
+    LP = ExprLoc(ir.get_next_break_loc_key(instr), 32)
+    take_jmp = ExprInt(1, 32)
+
+    # Set PC according to the immediate size
+    dst = disp
+    PC = dst
+    ir.IRDst = dst
+
+
+def jmp(ir, instr, reg_or_imm):
+    """JMP - Change PC to a register content or an immediate.
+       Note: the behavior in VLIW mode is not implemented"""
+
+    take_jmp = ExprInt(1, 32)
+
+    if isinstance(reg_or_imm, ExprId):
+        # PC <- Rm31..1||0
+        new_PC = ExprAssign(PC, reg_or_imm)
+    else:
+        # PC <- PC31..28||0000||(target24)23..1||0
+        new_PC = ExprAssign(PC, ExprOp("+", ExprOp("&", PC, ExprInt(0xF0000000, 32)), reg_or_imm))
+
+    return [new_PC, ExprAssign(ir.IRDst, new_PC)], []
+
+manual_functions["jmp"] = jmp
+
+
+@sbuild.parse
+def jsr(reg):
+    """JSR - Jump to the register, and store the return address."""
+
+    # LP <- PC + 2; PC <- Rm31..1||0
+    LP = ExprLoc(ir.get_next_break_loc_key(instr), 32)
+    take_jmp = ExprInt(1, 32)
+    PC = reg
+    ir.IRDst = reg
+
+
+@sbuild.parse
+def ret():
+    """RET - Return from a function call.
+       Note: the behavior in VLIW mode is not implemented"""
+
+    # PC <- LP31..1||0
+    dst = LP
+    PC = dst
+    ir.IRDst = dst
+
+
+# Repeat instructions
+
+@sbuild.parse
+def repeat(rn, disp17):
+    """REPEAT - This instruction repeats an instruction block. It sets the RPB,
+       RPE and RPC control registers."""
+
+    # RPB <- pc+4 // Repeat Begin
+    RPB = PC + i32(4)
+    # RPE <- pc+SignExt((disp17)16..1||0)) // Repeat End
+    RPE = PC + i32(int(disp17) & 0xFFFFFFFE)
+    # RPC <- Rn
+    RPC = rn
+    in_erepeat = ExprInt(0, 32)
+
+
+@sbuild.parse
+def erepeat(disp17):
+    """EREPEAT - This instruction repeats an instruction block. It sets the RPB
+       and RPE control registers. To distinguish from the repeat instruction,
+       the least significant bit in the RPE register (ELR) is set to 1."""
+
+    # RPB <- pc+4 // Repeat Begin
+    RPB = PC + i32(4)
+    # RPE <- pc+SignExt((disp17)16..1||1)) (EREPEAT)
+    RPE = PC + i32(int(disp17) + 1)
+    # RPC <- undefined
+    in_erepeat = ExprInt(1, 32)
+
+
+## Control Instructions
+
+@sbuild.parse
+def stc(reg, control_reg):
+    """STC - Copy a general-purpose register into a control register."""
+
+    # ControlReg(imm5) <- Rn
+    control_reg = reg
+
+
+@sbuild.parse
+def ldc(reg, control_reg):
+    """LDC - Copy a control register into a general-purpose register."""
+
+    # Rn <- ControlReg(imm5)
+    reg = control_reg
+
+
+@sbuild.parse
+def di():
+    """DI - Disable Interrupt"""
+
+    # PSW.IEC<-0
+    PSW = PSW & i32(0xFFFFFFFE)  # PSW.IEC: bit 0
+
+
+@sbuild.parse
+def ei():
+    """EI - Enable Interrupt"""
+
+    # PSW.IEC<-1
+    PSW = PSW ^ i32(0b1)  # PSW.IEC: bit 0
+
+
+@sbuild.parse
+def reti():
+    """RETI - Return from the exception/interrupt handler.
+       Note: the behavior in VLIW mode is not implemented"""
+
+    #if (PSW.NMI==1) {
+    #   PC <- NPC31..1 || 0; PSW.NMI<-0;
+    #} else {
+    #   PC <- EPC31..1 || 0;
+    #   PSW.UMC <- PSW.UMP; PSW.IEC <- PSW.IEP
+    #}
+
+    # PSW.NMI == bit 9
+    NMI_mask = i32(1 << 9)
+
+    # PSW.UMP == bit 3
+    # PSW.IEP == bit 1
+    UMP_IEP_mask = i32((1 << 3) ^ (1 << 1))
+
+    # PSW.UMC == bit 2
+    # PSW.IEC == bit 0
+    UMC_IEC_mask = (PSW & UMP_IEP_mask) >> i32(1)
+
+    # Get PSW.NMI
+    PSW_NMI = (PSW & NMI_mask) >> i32(9)
+
+    # Set PC
+    dst = NPC & i32(0xFFFFFFFE) if PSW_NMI else EPC & i32(0xFFFFFFFE)
+    PC = dst
+
+    # Set flags
+    PSW = PSW ^ NMI_mask if PSW_NMI else PSW ^ UMC_IEC_mask
+
+    ir.IRDst = dst
+
+
+@sbuild.parse
+def swi(imm2):
+    """SWI - Software Interrupt"""
+
+    # if(imm2==0) EXC.SIP0 <- 1
+    # else if (imm2==1) EXC.SIP1 <- 1
+    # else if (imm2==2) EXC.SIP2 <- 1
+    # else if (imm2==3) EXC.SIP3 <- 1
+
+    # EXC.SIP0 == bit 4
+    # EXC.SIP1 == bit 5
+    # EXC.SIP2 == bit 6
+    # EXC.SIP3 == bit 7
+
+    EXC = EXC ^ (i32(1) << (i32(4) + imm2))
+
+
+# Note: the following instructions can't be implemented
+manual_functions["halt"] = mep_nop
+manual_functions["sleep"] = mep_nop
+manual_functions["break"] = mep_nop
+manual_functions["syncm"] = mep_nop
+manual_functions["stcb"] = mep_nop_2_args
+manual_functions["ldcb"] = mep_nop_2_args
+
+
+### Bit manipulation instruction option
+
+def bsetm(ir, instr, rm_deref, imm3):
+    """BSETM - Bit Set Memory"""
+
+    # MemByte(Rm) <- MemByte(Rm) or (1<<imm3)
+    e = []
+    e.append(ExprAssign(ExprMem(rm_deref.ptr, 8), ExprOp("|", ExprMem(rm_deref.ptr, 8), (i8(1) << imm3[:8]))))
+    return e, []
+
+manual_functions["bsetm"] = bsetm
+
+
+def bclrm(ir, instr, rm_deref, imm3):
+    """BCLRM - Bit Clear Memory"""
+
+    # MemByte(Rm) <- MemByte(Rm) and ~(1<<imm3)
+    e = []
+    shift = ExprOp("<<", i8(1), imm3[:8])
+    e.append(ExprAssign(ExprMem(rm_deref.ptr, 8), ExprOp("&", ExprMem(rm_deref.ptr, 8), shift.__invert__())))
+    return e, []
+
+manual_functions["bclrm"] = bclrm
+
+
+def bnotm(ir, instr, rm_deref, imm3):
+    """BNOTM - Bit Not Memory"""
+
+    # MemByte(Rm) <- MemByte(Rm) xor (1<<imm3)
+    e = []
+    e.append(ExprAssign(ExprMem(rm_deref.ptr, 8), ExprOp("^", ExprMem(rm_deref.ptr, 8), (i8(1) << imm3[:8]))))
+    return e, []
+
+manual_functions["bnotm"] = bnotm
+
+
+def btstm(ir, instr, r0, rm_deref, imm3):
+    """BTSTM - Bit Test Memory"""
+
+    # R0 <- ZeroExt( MemByte(Rm) and (1<<imm3) )
+    e = []
+    e.append(ExprAssign(r0, ExprOp("&", ExprMem(rm_deref.ptr, 8), i8(1) << imm3[:8]).zeroExtend(32)))
+    return e, []
+
+manual_functions["btstm"] = btstm
+
+
+def tas(ir, instr, rn, rm_deref):
+    """TAS - Load And Set"""
+
+    # temp <- Rm; Rn <- ZeroExt(MemByte(temp)); MemByte(temp) <- 1
+    e = []
+    temp = rm_deref
+    e.append(ExprAssign(rn, ExprMem(temp.ptr, 8).zeroExtend(32)))
+    e.append(ExprAssign(ExprMem(temp.ptr, 8),  i8(1)))
+    return e, []
+
+manual_functions["tas"] = tas
+
+
+### Data cache option
+
+# Note: the following instruction can't be implemented
+manual_functions["cache"] = mep_nop_2_args
+
+
+### 32-bit multiply instruction option
+
+@sbuild.parse
+def mul(rn, rm):
+    """MUL - Signed 32-bit multiplication"""
+
+    # HI||LO <- Rn * Rm (Signed)
+    result = rn.signExtend(64) * rm.signExtend(64)  # expand registers size
+    HI = result[32:64]
+    LO = result[:32]
+
+
+@sbuild.parse
+def mulu(rn, rm):
+    """MUL - Unsigned 32-bit multiplication"""
+
+    # HI||LO <- Rn * Rm (Unsigned)
+    result = rn.zeroExtend(64) * rm.zeroExtend(64)  # expand registers size
+    HI = result[32:64]
+    LO = result[0:32]
+
+
+@sbuild.parse
+def mulr(rn, rm):
+    """MULR - Signed 32-bit multiplication & store LO in Rn"""
+
+    # HI||LO <- Rn * Rm; Rn <- LO (Signed)
+    result = rn.signExtend(64) * rm.signExtend(64)  # expand registers size
+    HI = result[32:64]
+    LO = result[:32]
+    rn = result[:32]
+
+
+@sbuild.parse
+def mulru(rn, rm):
+    """MULRU - Unsigned 32-bit multiplication & store LO in Rn"""
+
+    # HI||LO <- Rn * Rm; Rn <- LO (Unsigned)
+    result = rn.zeroExtend(64) * rm.zeroExtend(64)  # expand registers size
+    HI = result[32:64]
+    LO = result[:32]
+    rn = result[:32]
+
+
+@sbuild.parse
+def madd(rn, rm):
+    """MADD - Signed 32-bit multiplication, adding results to HI & LO registers"""
+
+    # HI||LO <- HI||LO + Rn*Rm (Signed)
+    result = (HI << i32(32)).signExtend(64) + LO.signExtend(64) + rn.signExtend(64) * rm.signExtend(64)  # expand registers size
+    HI = result[32:64]
+    LO = result[:32]
+
+
+@sbuild.parse
+def maddu(rn, rm):
+    """MADDU - Unsigned 32-bit multiplication, adding results to HI & LO registers"""
+
+    # HI||LO <- HI||LO + Rn*Rm (Unsigned)
+    result = (HI << i32(32)).zeroExtend(64) + LO.zeroExtend(64) + rn.zeroExtend(64) * rm.zeroExtend(64)  # expand registers size
+    HI = result[32:64]
+    LO = result[:32]
+
+
+@sbuild.parse
+def maddr(rn, rm):
+    """MADDR - Signed 32-bit multiplication, adding results to HI & LO registers & storing LO in Rn"""
+
+    # HI||LO <- HI||LO + Rn*Rm; Rn <- LO (Signed)
+    result = (HI << i32(32)).signExtend(64) + LO.signExtend(64) + rn.signExtend(64) * rm.signExtend(64)  # expand registers size
+    HI = result[32:64]
+    LO = result[:32]
+    rn = result[:32]
+
+
+@sbuild.parse
+def maddru(rn, rm):
+    """MADDRU - Unsigned 32-bit multiplication, adding results to HI & LO registers & storing LO in Rn"""
+
+    # HI||LO <- HI||LO + Rn*Rm; Rn <- LO (Unsigned)
+    result = (HI << i32(32)).zeroExtend(64) + LO.zeroExtend(64) + rn.zeroExtend(64) * rm.zeroExtend(64)  # expand registers size
+    HI = result[32:64]
+    LO = result[:32]
+    rn = result[:32]
+
+
+### 32-bit divide instruction option
+
+@sbuild.parse
+def div(rn, rm):
+    """DIV - Signed division"""
+
+    # LO <- Rn / Rm, HI <- Rn % Rm (Signed)
+
+    # Mask sign bits
+    sign_mask = i32(0x80000000)
+    sign_rn = rn & sign_mask
+    sign_rm = rm & sign_mask
+
+    # Check if both numbers are positive or negative
+    are_both_neg = sign_rn & sign_rm
+    are_both_pos = ExprCond(
+        are_both_neg - sign_mask,
+        ExprInt(0, are_both_neg.size),
+        ExprInt(1, are_both_neg.size)
+    )
+
+
+    # Invert both numbers
+    rn_inv = ~rn + i32(1)
+    rm_inv = ~rm + i32(1)
+
+    # Used to delay the arithmetic computations
+    tmp_rm = rm if rm else i32(1)
+    tmp_rm_inv = rm_inv if rm_inv else i32(1)
+
+    # Results if only rn, or rm is negative
+    LO_rn_neg = (~(rn_inv // tmp_rm) + i32(1)) if sign_rn else (~(rn // tmp_rm_inv) + i32(1))
+    HI_rn_neg = (~(rn_inv % tmp_rm) + i32(1)) if sign_rn else (~(rn % tmp_rm_inv) + i32(1))
+
+    # Results if both numbers are positive
+    LO_pos = rn // tmp_rm if are_both_pos else LO_rn_neg
+    HI_pos = rn % tmp_rm if are_both_pos else HI_rn_neg
+
+    # Results if both numbers are negative
+    LO_neg = rn_inv // tmp_rm_inv if are_both_neg else LO_pos
+    HI_neg = rn_inv % tmp_rm_inv if are_both_neg else HI_pos
+
+    # Results if rm is equal to zero
+    LO = LO_neg if rm else LO
+    HI = HI_neg if rm else HI
+
+    exception_flags = i32(0) if rm else i32(EXCEPT_DIV_BY_ZERO)
+
+
+@sbuild.parse
+def divu(rn, rm):
+    """DIVU - Unsigned division"""
+
+    # LO <- Rn / Rm, HI <- Rn % Rm (Unsigned)
+
+    tmp_rm = rm if rm else i32(1)  # used to delay the arithmetic computations
+    LO = rn // tmp_rm if rm else LO
+    HI = rn % tmp_rm if rm else HI
+
+    exception_flags = i32(0) if rm else i32(EXCEPT_DIV_BY_ZERO)
+
+
+### Debug function option
+
+@sbuild.parse
+def dret():
+    """DRET - Debug Exception Return"""
+
+    # PC <- DEPC; DBG.DM <- 0
+    PC = DEPC
+    DBG = DBG & i32(0xFFFFBFFF)  # DBG.DM: bit 15
+
+
+@sbuild.parse
+def dbreak():
+    """DBREAK - Debug break"""
+
+    # The DBG.DBP bit becomes 1
+    DBG = DBG ^ i32(0b10)  # DBG.DBP: bit 2
+
+
+### Leading zero instruction option
+
+@sbuild.parse
+def ldz(rn, rm):
+    """LDZ - Count Leading Zeroes
+
+       Note: this implementation is readable, yet slow. Each bit are tested
+       individually, and the results are propagated to other bits.
+
+       Here is the commented implementation for 4-bit integers:
+       rm = 0b0001
+
+       # Invert the value
+       reversed_rm = ~rm
+      -> reversed_rm = 0b1110
+
+       # Test bits individually
+       b3 = (reversed_rm & i32(2**3)) >> i32(3) if reversed_rm else i32(0)
+      -> b3 = (0b1110 & 0b1000 >> 3) = 1
+
+       b2 = (reversed_rm & i32(2**2)) >> i32(2) if b3 else i32(0)
+      -> b2 = (0b1110 & 0b0100 >> 2) = 1
+
+       b1 = (reversed_rm & i32(2**1)) >> i32(1) if b2 else i32(0)
+      -> b1 = (0b1110 & 0b0010 >> 1) = 1
+
+       b0 = (reversed_rm & i32(2**0)) >> i32(0) if b1 else i32(0)
+      -> b0 = (0b1110 & 0b0001 >> 0) = 0
+
+       # Sum all partial results
+       rn = b3 + b2 + b1 + b0
+      -> rn = 1 + 1 + 1 + 0 = 3
+    """
+
+    # Rn <- LeadingZeroDetect(Rm)
+
+    # Invert the value
+    reversed_rm = ~rm
+
+    # Test bits individually
+    b31 = (reversed_rm & i32(2**31)) >> i32(31) if reversed_rm else i32(0)
+    b30 = (reversed_rm & i32(2**30)) >> i32(30) if b31 else i32(0)
+    b29 = (reversed_rm & i32(2**29)) >> i32(29) if b30 else i32(0)
+    b28 = (reversed_rm & i32(2**28)) >> i32(28) if b29 else i32(0)
+    b27 = (reversed_rm & i32(2**27)) >> i32(27) if b28 else i32(0)
+    b26 = (reversed_rm & i32(2**26)) >> i32(26) if b27 else i32(0)
+    b25 = (reversed_rm & i32(2**25)) >> i32(25) if b26 else i32(0)
+    b24 = (reversed_rm & i32(2**24)) >> i32(24) if b25 else i32(0)
+    b23 = (reversed_rm & i32(2**23)) >> i32(23) if b24 else i32(0)
+    b22 = (reversed_rm & i32(2**22)) >> i32(22) if b23 else i32(0)
+    b21 = (reversed_rm & i32(2**21)) >> i32(21) if b22 else i32(0)
+    b20 = (reversed_rm & i32(2**20)) >> i32(20) if b21 else i32(0)
+    b19 = (reversed_rm & i32(2**19)) >> i32(19) if b20 else i32(0)
+    b18 = (reversed_rm & i32(2**18)) >> i32(18) if b19 else i32(0)
+    b17 = (reversed_rm & i32(2**17)) >> i32(17) if b18 else i32(0)
+    b16 = (reversed_rm & i32(2**16)) >> i32(16) if b17 else i32(0)
+    b15 = (reversed_rm & i32(2**15)) >> i32(15) if b16 else i32(0)
+    b14 = (reversed_rm & i32(2**14)) >> i32(14) if b15 else i32(0)
+    b13 = (reversed_rm & i32(2**13)) >> i32(13) if b14 else i32(0)
+    b12 = (reversed_rm & i32(2**12)) >> i32(12) if b13 else i32(0)
+    b11 = (reversed_rm & i32(2**11)) >> i32(11) if b12 else i32(0)
+    b10 = (reversed_rm & i32(2**10)) >> i32(10) if b11 else i32(0)
+    b09 = (reversed_rm & i32(2 ** 9)) >> i32(9) if b10 else i32(0)
+    b08 = (reversed_rm & i32(2 ** 8)) >> i32(8) if b09 else i32(0)
+    b07 = (reversed_rm & i32(2 ** 7)) >> i32(7) if b08 else i32(0)
+    b06 = (reversed_rm & i32(2 ** 6)) >> i32(6) if b07 else i32(0)
+    b05 = (reversed_rm & i32(2 ** 5)) >> i32(5) if b06 else i32(0)
+    b04 = (reversed_rm & i32(2 ** 4)) >> i32(4) if b05 else i32(0)
+    b03 = (reversed_rm & i32(2 ** 3)) >> i32(3) if b04 else i32(0)
+    b02 = (reversed_rm & i32(2 ** 2)) >> i32(2) if b03 else i32(0)
+    b01 = (reversed_rm & i32(2 ** 1)) >> i32(1) if b02 else i32(0)
+    b00 = (reversed_rm & i32(2 ** 0)) >> i32(0) if b01 else i32(0)
+
+    # Sum all partial results
+    rn = b31 + b30 + b29 + b28 + b27 + b26 + b25 + b24 + b23 + b22 + b21 + b20 \
+        + b19 + b18 + b17 + b16 + b15 + b14 + b13 + b12 + b11 + b10 + b09 + b08 \
+        + b07 + b06 + b05 + b04 + b03 + b02 + b01 + b00
+
+
+### Coprocessor option
+
+# Note: these instructions are implemented when needed
+
+# SWCP - Store Word to memory from a coprocessor register
+#        MemWord(Rm31..2||00) <- CRn 31..0
+manual_functions["swcp"] = sw
+
+
+# LWCP - Load Word from memory to a coprocessor register
+#        CRn <- MemWord(Rm31..2||00)
+manual_functions["lwcp"] = lw
+
+
+def smcp(ir, instr, reg_src, deref_dst):
+    """SMCP - Store Word to memory from a coprocessor register"""
+
+    # MemDword(Rm31..3||000) <- CRn
+    e = []
+    e.append(ExprAssign(ExprMem(deref_dst.ptr & i32(0xFFFFFFF8), 32), reg_src))
+    return e, []
+
+manual_functions["smcp"] = smcp
+
+
+def lmcp(ir, instr, reg_dst, deref_src):
+    """LMCP - Load Word from memory to a coprocessor register"""
+
+    # CRn <- MemDword(Rm31..3||000)
+    e = []
+    e.append(ExprAssign(reg_dst, ExprMem(deref_src.ptr & i32(0xFFFFFFF8), 32)))
+    return e, []
+
+manual_functions["lmcp"] = lmcp
+
+
+def swcpi(ir, instr, reg_src, deref_dst):
+    """SWCPI - Store Word to memory, and increment the address"""
+
+    # MemWord(Rm31..2||00) <- CRn 31..0; Rm<-Rm+4
+    e = []
+    e.append(ExprAssign(ExprMem(deref_dst.ptr & i32(0xFFFFFFFC), 32), reg_src))
+    e.append(ExprAssign(deref_dst.ptr, deref_dst.ptr + i32(4)))
+    return e, []
+
+manual_functions["swcpi"] = swcpi
+
+
+def lwcpi(ir, instr, reg_dst, deref_src):
+    """LWCPI - Load Word from memory, and increment the address"""
+
+    # CRn <- MemWord(Rm31..2||00); Rm<-Rm+4
+    e = []
+    e.append(ExprAssign(reg_dst, ExprMem(deref_src.ptr & i32(0xFFFFFFFC), 32)))
+    e.append(ExprAssign(deref_src.ptr, deref_src.ptr + i32(4)))
+    return e, []
+
+manual_functions["lwcpi"] = lwcpi
+
+def smcpi(ir, instr, reg_src, deref_dst):
+    """SMCPI - Store Word to memory, and increment the address"""
+
+    # MemDword(Rm31..3||000) <- CRn; Rm<-Rm+8
+    e = []
+    e.append(ExprAssign(ExprMem(deref_dst.ptr & i32(0xFFFFFFF8), 32), reg_src))
+    e.append(ExprAssign(deref_dst.ptr, deref_dst.ptr + i32(8)))
+    return e, []
+
+manual_functions["smcpi"] = smcpi
+
+
+def lmcpi(ir, instr, reg_dst, deref_src):
+    """LMCPI - Load Word from memory, and increment the address"""
+
+    # CRn <- MemDword(Rm31..3||000); Rm<-Rm+8
+    e = []
+    e.append(ExprAssign(reg_dst, ExprMem(deref_src.ptr & i32(0xFFFFFFFC), 32)))
+    e.append(ExprAssign(deref_src.ptr, deref_src.ptr + i32(8)))
+    return e, []
+
+manual_functions["lmcpi"] = lmcpi
+
+
+### IR MeP definitions
+
+def get_mnemo_expr(ir, instr, *args):
+    """Simplify getting the IR from a miasm instruction."""
+
+    if instr.name.lower() in sbuild.functions:
+        mnemo_func = sbuild.functions[instr.name.lower()]
+    else:
+        mnemo_func = manual_functions[instr.name.lower()]
+
+    ir, extra_ir = mnemo_func(ir, instr, *args)
+    return ir, extra_ir
+
+
+class Lifter_MEPb(Lifter):
+    """Toshiba MeP miasm IR - Big Endian
+
+       It transforms an instructon into an IR.
+    """
+
+    addrsize = 32
+
+    def __init__(self, loc_db):
+        Lifter.__init__(self, mn_mep, "b", loc_db)
+        self.pc = mn_mep.getpc()
+        self.sp = mn_mep.getsp()
+        self.IRDst = ExprId("IRDst", 32)
+
+    def get_ir(self, instr):
+        """Get the IR from a miasm instruction."""
+
+        instr_ir, extra_ir = get_mnemo_expr(self, instr, *instr.args)
+
+        return instr_ir, extra_ir
+
+    def get_next_break_loc_key(self, instr):
+        """Returns a new label that identifies where the instruction is going.
+
+           Note: it eases linking IR blocks
+        """
+
+        l = self.loc_db.get_or_create_offset_location(instr.offset + instr.l)
+        return l
+
+
+class Lifter_MEPl(Lifter_MEPb):
+    """Toshiba MeP miasm IR - Little Endian"""
+
+    def __init__(self, loc_db):
+        Lifter.__init__(self, mn_mep, "l", loc_db)
+        self.pc = mn_mep.getpc()
+        self.sp = mn_mep.getsp()
+        self.IRDst = ExprId("IRDst", 32)
diff --git a/src/miasm/arch/mips32/__init__.py b/src/miasm/arch/mips32/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/miasm/arch/mips32/__init__.py
diff --git a/src/miasm/arch/mips32/arch.py b/src/miasm/arch/mips32/arch.py
new file mode 100644
index 00000000..76ebe730
--- /dev/null
+++ b/src/miasm/arch/mips32/arch.py
@@ -0,0 +1,838 @@
+#-*- coding:utf-8 -*-
+
+import logging
+from collections import defaultdict
+
+from pyparsing import Literal, Optional
+
+from miasm.expression.expression import ExprMem, ExprInt, ExprId, ExprOp, ExprLoc
+from miasm.core.bin_stream import bin_stream
+import miasm.arch.mips32.regs as regs
+import miasm.core.cpu as cpu
+from miasm.ir.ir import color_expr_html
+
+from miasm.core.asm_ast import AstInt, AstId, AstMem, AstOp
+
+log = logging.getLogger("mips32dis")
+console_handler = logging.StreamHandler()
+console_handler.setFormatter(logging.Formatter("[%(levelname)-8s]: %(message)s"))
+log.addHandler(console_handler)
+log.setLevel(logging.DEBUG)
+
+
+gpregs = cpu.reg_info(regs.regs32_str, regs.regs32_expr)
+
+
+LPARENTHESIS = Literal("(")
+RPARENTHESIS = Literal(")")
+
+def cb_deref(tokens):
+    if len(tokens) != 4:
+        raise NotImplementedError("TODO")
+    return AstMem(tokens[2] + tokens[0], 32)
+
+def cb_deref_nooff(tokens):
+    if len(tokens) != 3:
+        raise NotImplementedError("TODO")
+    return AstMem(tokens[1], 32)
+
+base_expr = cpu.base_expr
+
+deref_off = (Optional(base_expr) + LPARENTHESIS + gpregs.parser + RPARENTHESIS).setParseAction(cb_deref)
+deref_nooff = (LPARENTHESIS + gpregs.parser + RPARENTHESIS).setParseAction(cb_deref_nooff)
+deref = deref_off | deref_nooff
+
+
+class additional_info(object):
+    def __init__(self):
+        self.except_on_instr = False
+
+br_0 = ['B', 'J', 'JR', 'BAL', 'JAL', 'JALR']
+br_1 = ['BGEZ', 'BLTZ', 'BGTZ', 'BGTZL', 'BLEZ', 'BLEZL', 'BC1T', 'BC1TL', 'BC1F', 'BC1FL']
+br_2 = ['BEQ', 'BEQL', 'BNE', 'BNEL']
+
+
+class instruction_mips32(cpu.instruction):
+    __slots__ = []
+
+    def __init__(self, *args, **kargs):
+        super(instruction_mips32, self).__init__(*args, **kargs)
+        self.delayslot = 1
+
+
+    @staticmethod
+    def arg2str(expr, index=None, loc_db=None):
+        if expr.is_id() or expr.is_int():
+            return str(expr)
+        elif expr.is_loc():
+            if loc_db is not None:
+                return loc_db.pretty_str(expr.loc_key)
+            else:
+                return str(expr)
+        assert(isinstance(expr, ExprMem))
+        arg = expr.ptr
+        if isinstance(arg, ExprId):
+            return "(%s)"%arg
+        assert(len(arg.args) == 2 and arg.op == '+')
+        return "%s(%s)"%(arg.args[1], arg.args[0])
+
+    @staticmethod
+    def arg2html(expr, index=None, loc_db=None):
+        if expr.is_id() or expr.is_int() or expr.is_loc():
+            return color_expr_html(expr, loc_db)
+        assert(isinstance(expr, ExprMem))
+        arg = expr.ptr
+        if isinstance(arg, ExprId):
+            return "(%s)"%color_expr_html(arg, loc_db)
+        assert(len(arg.args) == 2 and arg.op == '+')
+        return "%s(%s)"%(
+            color_expr_html(arg.args[1], loc_db),
+            color_expr_html(arg.args[0], loc_db)
+        )
+
+    def dstflow(self):
+        if self.name == 'BREAK':
+            return False
+        if self.name in br_0 + br_1 + br_2:
+            return True
+        return False
+
+    def get_dst_num(self):
+        if self.name in br_0:
+            i = 0
+        elif self.name in br_1:
+            i = 1
+        elif self.name in br_2:
+            i = 2
+        else:
+            raise NotImplementedError("TODO %s"%self)
+        return i
+
+    def dstflow2label(self, loc_db):
+        if self.name in ["J", 'JAL']:
+            expr = self.args[0]
+            offset = int(expr)
+            addr = ((self.offset & (0xFFFFFFFF ^ ((1<< 28)-1))) + offset) & int(expr.mask)
+            loc_key = loc_db.get_or_create_offset_location(addr)
+            self.args[0] = ExprLoc(loc_key, expr.size)
+            return
+
+        ndx = self.get_dst_num()
+        expr = self.args[ndx]
+
+        if not isinstance(expr, ExprInt):
+            return
+        addr = (int(expr) + self.offset) & int(expr.mask)
+        loc_key = loc_db.get_or_create_offset_location(addr)
+        self.args[ndx] = ExprLoc(loc_key, expr.size)
+
+    def breakflow(self):
+        if self.name == 'BREAK':
+            return False
+        if self.name in br_0 + br_1 + br_2:
+            return True
+        return False
+
+    def is_subcall(self):
+        if self.name in ['JAL', 'JALR', 'BAL']:
+            return True
+        return False
+
+    def getdstflow(self, loc_db):
+        if self.name in br_0:
+            return [self.args[0]]
+        elif self.name in br_1:
+            return [self.args[1]]
+        elif self.name in br_2:
+            return [self.args[2]]
+        elif self.name in ['JAL', 'JALR', 'JR', 'J']:
+            return [self.args[0]]
+        else:
+            raise NotImplementedError("fix mnemo %s"%self.name)
+
+    def splitflow(self):
+        if self.name in ["B", 'JR', 'J']:
+            return False
+        if self.name in br_0:
+            return True
+        if self.name in br_1:
+            return True
+        if self.name in br_2:
+            return True
+        if self.name in ['JAL', 'JALR']:
+            return True
+        return False
+
+    def get_symbol_size(self, symbol, loc_db):
+        return 32
+
+    def fixDstOffset(self):
+        ndx = self.get_dst_num()
+        e = self.args[ndx]
+        if self.offset is None:
+            raise ValueError('symbol not resolved %s' % self.l)
+        if not isinstance(e, ExprInt):
+            return
+        off = (int(e) - self.offset) & int(e.mask)
+        if int(off % 4):
+            raise ValueError('strange offset! %r' % off)
+        self.args[ndx] = ExprInt(off, 32)
+
+    def get_args_expr(self):
+        args = [a for a in self.args]
+        return args
+
+
+class mn_mips32(cpu.cls_mn):
+    delayslot = 1
+    name = "mips32"
+    regs = regs
+    bintree = {}
+    num = 0
+    all_mn = []
+    all_mn_mode = defaultdict(list)
+    all_mn_name = defaultdict(list)
+    all_mn_inst = defaultdict(list)
+    pc = {'l':regs.PC, 'b':regs.PC}
+    sp = {'l':regs.SP, 'b':regs.SP}
+    instruction = instruction_mips32
+    max_instruction_len = 4
+
+    @classmethod
+    def getpc(cls, attrib = None):
+        return regs.PC
+
+    @classmethod
+    def getsp(cls, attrib = None):
+        return regs.SP
+
+    def additional_info(self):
+        info = additional_info()
+        return info
+
+    @classmethod
+    def getbits(cls, bitstream, attrib, start, n):
+        if not n:
+            return 0
+        o = 0
+        while n:
+            offset = start // 8
+            n_offset = cls.endian_offset(attrib, offset)
+            c = cls.getbytes(bitstream, 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 gen_modes(cls, subcls, name, bases, dct, fields):
+        dct['mode'] = None
+        return [(subcls, name, bases, dct, fields)]
+
+    def value(self, mode):
+        v = super(mn_mips32, 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 mips32op(name, fields, args=None, alias=False):
+    dct = {"fields": fields}
+    dct["alias"] = alias
+    if args is not None:
+        dct['args'] = args
+    type(name, (mn_mips32,), dct)
+    #type(name, (mn_mips32b,), dct)
+
+class mips32_arg(cpu.m_arg):
+    def asm_ast_to_expr(self, arg, loc_db):
+        if isinstance(arg, AstId):
+            if isinstance(arg.name, ExprId):
+                return arg.name
+            if arg.name in gpregs.str:
+                return None
+            loc_key = loc_db.get_or_create_name_location(arg.name)
+            return ExprLoc(loc_key, 32)
+        if isinstance(arg, AstOp):
+            args = [self.asm_ast_to_expr(tmp, loc_db) for tmp in arg.args]
+            if None in args:
+                return None
+            return ExprOp(arg.op, *args)
+        if isinstance(arg, AstInt):
+            return ExprInt(arg.value, 32)
+        if isinstance(arg, AstMem):
+            ptr = self.asm_ast_to_expr(arg.ptr, loc_db)
+            if ptr is None:
+                return None
+            return ExprMem(ptr, arg.size)
+        return None
+
+
+class mips32_reg(cpu.reg_noarg, mips32_arg):
+    pass
+
+class mips32_gpreg(mips32_reg):
+    reg_info = gpregs
+    parser = reg_info.parser
+
+class mips32_fltpreg(mips32_reg):
+    reg_info = regs.fltregs
+    parser = reg_info.parser
+
+
+class mips32_fccreg(mips32_reg):
+    reg_info = regs.fccregs
+    parser = reg_info.parser
+
+class mips32_imm(cpu.imm_noarg):
+    parser = base_expr
+
+
+class mips32_s16imm_noarg(mips32_imm):
+    def decode(self, v):
+        v = v & self.lmask
+        v = cpu.sign_ext(v, 16, 32)
+        self.expr = ExprInt(v, 32)
+        return True
+
+    def encode(self):
+        if not isinstance(self.expr, ExprInt):
+            return False
+        v = int(self.expr)
+        if v & 0x80000000:
+            nv = v & ((1 << 16) - 1)
+            assert( v == cpu.sign_ext(nv, 16, 32))
+            v = nv
+        self.value = v
+        return True
+
+
+class mips32_s09imm_noarg(mips32_imm):
+    def decode(self, v):
+        v = v & self.lmask
+        v = cpu.sign_ext(v, 9, 32)
+        self.expr = ExprInt(v, 32)
+        return True
+
+    def encode(self):
+        if not isinstance(self.expr, ExprInt):
+            return False
+        v = int(self.expr)
+        if v & 0x80000000:
+            nv = v & ((1 << 9) - 1)
+            assert( v == cpu.sign_ext(nv, 9, 32))
+            v = nv
+        self.value = v
+        return True
+
+
+class mips32_soff_noarg(mips32_imm):
+    def decode(self, v):
+        v = v & self.lmask
+        v <<= 2
+        v = cpu.sign_ext(v, 16+2, 32)
+        # Add pipeline offset
+        self.expr = ExprInt(v + 4, 32)
+        return True
+
+    def encode(self):
+        if not isinstance(self.expr, ExprInt):
+            return False
+        # Remove pipeline offset
+        v = (int(self.expr) - 4) & 0xFFFFFFFF
+        if v & 0x80000000:
+            nv = v & ((1 << 16+2) - 1)
+            assert( v == cpu.sign_ext(nv, 16+2, 32))
+            v = nv
+        self.value = v>>2
+        return True
+
+
+class mips32_s16imm(mips32_s16imm_noarg, mips32_arg):
+    pass
+
+class mips32_s09imm(mips32_s09imm_noarg, mips32_arg):
+    pass
+
+class mips32_soff(mips32_soff_noarg, mips32_arg):
+    pass
+
+
+class mips32_instr_index(mips32_imm, mips32_arg):
+    def decode(self, v):
+        v = v & self.lmask
+        self.expr = ExprInt(v<<2, 32)
+        return True
+
+    def encode(self):
+        if not isinstance(self.expr, ExprInt):
+            return False
+        v = int(self.expr)
+        if v & 3:
+            return False
+        v>>=2
+        if v > (1<<self.l):
+            return False
+        self.value = v
+        return True
+
+
+class mips32_u16imm(mips32_imm, mips32_arg):
+    def decode(self, v):
+        v = v & self.lmask
+        self.expr = ExprInt(v, 32)
+        return True
+
+    def encode(self):
+        if not isinstance(self.expr, ExprInt):
+            return False
+        v = int(self.expr)
+        assert(v < (1<<16))
+        self.value = v
+        return True
+
+class mips32_dreg_imm(mips32_arg):
+    parser = deref
+    def decode(self, v):
+        imm = self.parent.imm.expr
+        r = gpregs.expr[v]
+        self.expr = ExprMem(r+imm, 32)
+        return True
+
+    def encode(self):
+        e = self.expr
+        if not isinstance(e, ExprMem):
+            return False
+        ptr = e.ptr
+        if isinstance(ptr, ExprId):
+            self.parent.imm.expr = ExprInt(0, 32)
+            r = ptr
+        elif len(ptr.args) == 2 and ptr.op == "+":
+            self.parent.imm.expr = ptr.args[1]
+            r = ptr.args[0]
+        else:
+            return False
+        self.value = gpregs.expr.index(r)
+        return True
+
+    @staticmethod
+    def arg2str(expr, index=None):
+        assert(isinstance(expr, ExprMem))
+        ptr = expr.ptr
+        if isinstance(ptr, ExprId):
+            return "(%s)"%ptr
+        assert(len(ptr.args) == 2 and ptr.op == '+')
+        return "%s(%s)"%(ptr.args[1], ptr.args[0])
+
+class mips32_esize(mips32_imm, mips32_arg):
+    def decode(self, v):
+        v = v & self.lmask
+        self.expr = ExprInt(v+1, 32)
+        return True
+
+    def encode(self):
+        if not isinstance(self.expr, ExprInt):
+            return False
+        v = int(self.expr) -1
+        assert(v < (1<<16))
+        self.value = v
+        return True
+
+class mips32_eposh(mips32_imm, mips32_arg):
+    def decode(self, v):
+        self.expr = ExprInt(v-int(self.parent.epos.expr)+1, 32)
+        return True
+
+    def encode(self):
+        if not isinstance(self.expr, ExprInt):
+            return False
+        v = int(self.expr) + int(self.parent.epos.expr) -1
+        self.value = v
+        return True
+
+
+
+
+class mips32_cpr(mips32_arg):
+    parser = regs.regs_cpr0_info.parser
+    def decode(self, v):
+        index = int(self.parent.cpr0.expr) << 3
+        index += v
+        self.expr = regs.regs_cpr0_expr[index]
+        return True
+    def encode(self):
+        e = self.expr
+        if not e in regs.regs_cpr0_expr:
+            return False
+        index = regs.regs_cpr0_expr.index(e)
+        self.value = index & 7
+        index >>=2
+        self.parent.cpr0.value = index
+        return True
+
+rs = cpu.bs(l=5, cls=(mips32_gpreg,))
+rt = cpu.bs(l=5, cls=(mips32_gpreg,))
+rd = cpu.bs(l=5, cls=(mips32_gpreg,))
+ft = cpu.bs(l=5, cls=(mips32_fltpreg,))
+fs = cpu.bs(l=5, cls=(mips32_fltpreg,))
+fd = cpu.bs(l=5, cls=(mips32_fltpreg,))
+
+s16imm = cpu.bs(l=16, cls=(mips32_s16imm,))
+u16imm = cpu.bs(l=16, cls=(mips32_u16imm,))
+s09imm = cpu.bs(l=9, cls=(mips32_s09imm,))
+sa = cpu.bs(l=5, cls=(mips32_u16imm,))
+base = cpu.bs(l=5, cls=(mips32_dreg_imm,))
+soff = cpu.bs(l=16, cls=(mips32_soff,))
+oper = cpu.bs(l=5, cls=(mips32_u16imm,))
+
+cpr0 = cpu.bs(l=5, cls=(mips32_imm,), fname="cpr0")
+cpr =  cpu.bs(l=3, cls=(mips32_cpr,))
+
+stype = cpu.bs(l=5, cls=(mips32_u16imm,))
+hint_pref = cpu.bs(l=5, cls=(mips32_u16imm,))
+
+s16imm_noarg = cpu.bs(l=16, cls=(mips32_s16imm_noarg,), fname="imm",
+                  order=-1)
+s09imm_noarg = cpu.bs(l=9, cls=(mips32_s09imm_noarg,), fname="imm",
+                  order=-1)
+
+hint = cpu.bs(l=5, default_val="00000")
+fcc = cpu.bs(l=3, cls=(mips32_fccreg,))
+
+sel = cpu.bs(l=3, cls=(mips32_u16imm,))
+
+code = cpu.bs(l=20, cls=(mips32_u16imm,))
+
+esize = cpu.bs(l=5, cls=(mips32_esize,))
+epos = cpu.bs(l=5, cls=(mips32_u16imm,), fname="epos",
+          order=-1)
+
+eposh = cpu.bs(l=5, cls=(mips32_eposh,))
+
+instr_index = cpu.bs(l=26, cls=(mips32_instr_index,))
+bs_fmt = cpu.bs_mod_name(l=5, fname='fmt', mn_mod={0x10: '.S', 0x11: '.D',
+                                                   0x14: '.W', 0x15: '.L',
+                                                   0x16: '.PS'})
+class bs_cond(cpu.bs_mod_name):
+    mn_mod = ['.F', '.UN', '.EQ', '.UEQ',
+              '.OLT', '.ULT', '.OLE', '.ULE',
+              '.SF', '.NGLE', '.SEQ', '.NGL',
+              '.LT', '.NGE', '.LE', '.NGT'
+              ]
+
+    def modname(self, name, f_i):
+        raise NotImplementedError("Not implemented")
+
+
+class bs_cond_name(cpu.bs_divert):
+    prio = 2
+    mn_mod = [['.F', '.UN', '.EQ', '.UEQ',
+               '.OLT', '.ULT', '.OLE', '.ULE'],
+              ['.SF', '.NGLE', '.SEQ', '.NGL',
+               '.LT', '.NGE', '.LE', '.NGT']
+              ]
+
+    def divert(self, index, candidates):
+        out = []
+        for candidate in candidates:
+            cls, name, bases, dct, fields = candidate
+            cond1 = [f for f in fields if f.fname == "cond1"]
+            assert(len(cond1) == 1)
+            cond1 = cond1.pop()
+            mm = self.mn_mod[cond1.value]
+            for value, new_name in enumerate(mm):
+                nfields = fields[:]
+                s = cpu.int2bin(value, self.args['l'])
+                args = dict(self.args)
+                args.update({'strbits': s})
+                f = cpu.bs(**args)
+                nfields[index] = f
+                ndct = dict(dct)
+                ndct['name'] = name + new_name
+                out.append((cls, new_name, bases, ndct, nfields))
+        return out
+
+
+
+class bs_cond_mod(cpu.bs_mod_name):
+    prio = 1
+
+bs_cond = bs_cond_mod(l=4,
+                      mn_mod = ['.F', '.UN', '.EQ', '.UEQ',
+                                '.OLT', '.ULT', '.OLE', '.ULE',
+                                '.SF', '.NGLE', '.SEQ', '.NGL',
+                                '.LT', '.NGE', '.LE', '.NGT'])
+
+
+
+bs_arith = cpu.bs_name(l=6, name={'ADDU':0b100001,
+                                  'SUBU':0b100011,
+                                  'OR':0b100101,
+                                  'AND':0b100100,
+                                  'SLTU':0b101011,
+                                  'XOR':0b100110,
+                                  'SLT':0b101010,
+                                  'SUBU':0b100011,
+                                  'NOR':0b100111,
+                                  'MOVN':0b001011,
+                                  'MOVZ':0b001010,
+                                  })
+
+bs_shift = cpu.bs_name(l=6, name={'SLL':0b000000,
+                                  'SRL':0b000010,
+                                  'SRA':0b000011,
+                                  })
+
+bs_shift1 = cpu.bs_name(l=6, name={'SLLV':0b000100,
+                                   'SRLV':0b000110,
+                                   'SRAV':0b000111,
+                                   })
+
+
+bs_arithfmt = cpu.bs_name(l=6, name={'ADD':0b000000,
+                                     'SUB':0b000001,
+                                     'MUL':0b000010,
+                                     'DIV':0b000011,
+                                     })
+
+bs_s_l = cpu.bs_name(l=6, name = {"SW":    0b101011,
+                                  "SH":    0b101001,
+                                  "SB":    0b101000,
+                                  "LW":    0b100011,
+                                  "LH":    0b100001,
+                                  "LB":    0b100000,
+                                  "LHU":   0b100101,
+                                  "LBU":   0b100100,
+                                  "LWL":   0b100010,
+                                  "LWR":   0b100110,
+
+                                  "SWL":   0b101010,
+                                  "SWR":   0b101110,
+                                  })
+
+
+bs_oax = cpu.bs_name(l=6, name = {"ORI":    0b001101,
+                                  "ANDI":   0b001100,
+                                  "XORI":   0b001110,
+                                  })
+
+bs_bcc = cpu.bs_name(l=5, name = {"BGEZ":    0b00001,
+                                  "BGEZL":   0b00011,
+                                  "BGEZAL":  0b10001,
+                                  "BGEZALL": 0b10011,
+                                  "BLTZ":    0b00000,
+                                  "BLTZL":   0b00010,
+                                  "BLTZAL":  0b10000,
+                                  "BLTZALL": 0b10010,
+                                  })
+
+
+bs_code = cpu.bs(l=10)
+
+
+mips32op("addi",    [cpu.bs('001000'), rs, rt, s16imm], [rt, rs, s16imm])
+mips32op("addiu",   [cpu.bs('001001'), rs, rt, s16imm], [rt, rs, s16imm])
+mips32op("nop",     [cpu.bs('0'*32)], alias = True)
+mips32op("lui",     [cpu.bs('001111'), cpu.bs('00000'), rt, u16imm])
+mips32op("oax",     [bs_oax, rs, rt, u16imm], [rt, rs, u16imm])
+
+mips32op("arith",   [cpu.bs('000000'), rs, rt, rd, cpu.bs('00000'), bs_arith],
+         [rd, rs, rt])
+mips32op("shift1",  [cpu.bs('000000'), rs, rt, rd, cpu.bs('00000'), bs_shift1],
+         [rd, rt, rs])
+
+mips32op("shift",   [cpu.bs('000000'), cpu.bs('00000'), rt, rd, sa, bs_shift],
+         [rd, rt, sa])
+
+mips32op("rotr",    [cpu.bs('000000'), cpu.bs('00001'), rt, rd, sa,
+                     cpu.bs('000010')], [rd, rt, sa])
+
+mips32op("mul",     [cpu.bs('011100'), rs, rt, rd, cpu.bs('00000'),
+                     cpu.bs('000010')], [rd, rs, rt])
+mips32op("div",     [cpu.bs('000000'), rs, rt, cpu.bs('0000000000'),
+                     cpu.bs('011010')])
+
+mips32op("s_l",     [bs_s_l, base, rt, s16imm_noarg], [rt, base])
+
+#mips32op("mfc0",    [bs('010000'), bs('00000'), rt, rd, bs('00000000'), sel])
+mips32op("mfc0",    [cpu.bs('010000'), cpu.bs('00000'), rt, cpr0,
+                     cpu.bs('00000000'), cpr])
+mips32op("mfc1",    [cpu.bs('010001'), cpu.bs('00000'), rt, fs,
+                     cpu.bs('00000000000')])
+
+mips32op("ldc1",    [cpu.bs('110101'), base, ft, s16imm_noarg], [ft, base])
+
+mips32op("mov",     [cpu.bs('010001'), bs_fmt, cpu.bs('00000'), fs, fd,
+                     cpu.bs('000110')], [fd, fs])
+
+mips32op("add",     [cpu.bs('010001'), bs_fmt, ft, fs, fd, bs_arithfmt],
+         [fd, fs, ft])
+
+mips32op("divu",    [cpu.bs('000000'), rs, rt, cpu.bs('0000000000'),
+                     cpu.bs('011011')])
+mips32op("mult",    [cpu.bs('000000'), rs, rt, cpu.bs('0000000000'),
+                     cpu.bs('011000')])
+mips32op("multu",   [cpu.bs('000000'), rs, rt, cpu.bs('0000000000'),
+                     cpu.bs('011001')])
+mips32op("mflo",    [cpu.bs('000000'), cpu.bs('0000000000'), rd,
+                     cpu.bs('00000'), cpu.bs('010010')])
+mips32op("mfhi",    [cpu.bs('000000'), cpu.bs('0000000000'), rd,
+                     cpu.bs('00000'), cpu.bs('010000')])
+
+
+mips32op("b",       [cpu.bs('000100'), cpu.bs('00000'), cpu.bs('00000'), soff],
+         alias = True)
+mips32op("bne",     [cpu.bs('000101'), rs, rt, soff])
+mips32op("bnel",    [cpu.bs('010101'), rs, rt, soff])
+
+mips32op("beq",     [cpu.bs('000100'), rs, rt, soff])
+mips32op("beql",    [cpu.bs('010100'), rs, rt, soff])
+
+mips32op("blez",    [cpu.bs('000110'), rs, cpu.bs('00000'), soff])
+mips32op("blezl",   [cpu.bs('010110'), rs, cpu.bs('00000'), soff])
+
+mips32op("bcc",     [cpu.bs('000001'), rs, bs_bcc, soff])
+
+mips32op("bgtz",    [cpu.bs('000111'), rs, cpu.bs('00000'), soff])
+mips32op("bgtzl",   [cpu.bs('010111'), rs, cpu.bs('00000'), soff])
+mips32op("bal",     [cpu.bs('000001'), cpu.bs('00000'), cpu.bs('10001'), soff],
+         alias = True)
+
+
+mips32op("slti",    [cpu.bs('001010'), rs, rt, s16imm], [rt, rs, s16imm])
+mips32op("sltiu",   [cpu.bs('001011'), rs, rt, s16imm], [rt, rs, s16imm])
+
+
+mips32op("j",       [cpu.bs('000010'), instr_index])
+mips32op("jal",     [cpu.bs('000011'), instr_index])
+mips32op("jalr",    [cpu.bs('000000'), rs, cpu.bs('00000'), rd, hint,
+                     cpu.bs('001001')])
+mips32op("jr",      [cpu.bs('000000'), rs, cpu.bs('0000000000'), hint,
+                     cpu.bs('001000')])
+
+mips32op("lwc1",    [cpu.bs('110001'), base, ft, s16imm_noarg], [ft, base])
+
+#mips32op("mtc0",    [bs('010000'), bs('00100'), rt, rd, bs('00000000'), sel])
+mips32op("mtc0",    [cpu.bs('010000'), cpu.bs('00100'), rt, cpr0,
+                     cpu.bs('00000000'), cpr])
+mips32op("mtc1",    [cpu.bs('010001'), cpu.bs('00100'), rt, fs,
+                     cpu.bs('00000000000')])
+# XXXX TODO CFC1
+mips32op("cfc1",    [cpu.bs('010001'), cpu.bs('00010'), rt, fs,
+                     cpu.bs('00000000000')])
+# XXXX TODO CTC1
+mips32op("ctc1",    [cpu.bs('010001'), cpu.bs('00110'), rt, fs,
+                     cpu.bs('00000000000')])
+
+mips32op("break",   [cpu.bs('000000'), code, cpu.bs('001101')])
+mips32op("syscall", [cpu.bs('000000'), code, cpu.bs('001100')])
+
+
+mips32op("c",       [cpu.bs('010001'), bs_fmt, ft, fs, fcc, cpu.bs('0'),
+                     cpu.bs('0'), cpu.bs('11'), bs_cond], [fcc, fs, ft])
+
+
+mips32op("bc1t",    [cpu.bs('010001'), cpu.bs('01000'), fcc, cpu.bs('0'),
+                     cpu.bs('1'), soff])
+mips32op("bc1tl",    [cpu.bs('010001'), cpu.bs('01000'), fcc, cpu.bs('1'),
+                     cpu.bs('1'), soff])
+mips32op("bc1f",    [cpu.bs('010001'), cpu.bs('01000'), fcc, cpu.bs('0'),
+                     cpu.bs('0'), soff])
+mips32op("bc1fl",    [cpu.bs('010001'), cpu.bs('01000'), fcc, cpu.bs('1'),
+                     cpu.bs('0'), soff])
+
+mips32op("swc1",    [cpu.bs('111001'), base, ft, s16imm_noarg], [ft, base])
+
+mips32op("cvt.d",   [cpu.bs('010001'), bs_fmt, cpu.bs('00000'), fs, fd,
+                     cpu.bs('100001')], [fd, fs])
+mips32op("cvt.w",   [cpu.bs('010001'), bs_fmt, cpu.bs('00000'), fs, fd,
+                     cpu.bs('100100')], [fd, fs])
+mips32op("cvt.s",   [cpu.bs('010001'), bs_fmt, cpu.bs('00000'), fs, fd,
+                     cpu.bs('100000')], [fd, fs])
+
+mips32op("ext",     [cpu.bs('011111'), rs, rt, esize, epos, cpu.bs('000000')],
+         [rt, rs, epos, esize])
+mips32op("ins",     [cpu.bs('011111'), rs, rt, eposh, epos, cpu.bs('000100')],
+         [rt, rs, epos, eposh])
+
+mips32op("seb",     [cpu.bs('011111'), cpu.bs('00000'), rt, rd, cpu.bs('10000'),
+                     cpu.bs('100000')], [rd, rt])
+mips32op("seh",     [cpu.bs('011111'), cpu.bs('00000'), rt, rd, cpu.bs('11000'),
+                     cpu.bs('100000')], [rd, rt])
+mips32op("wsbh",    [cpu.bs('011111'), cpu.bs('00000'), rt, rd, cpu.bs('00010'),
+                     cpu.bs('100000')], [rd, rt])
+
+mips32op("di",      [cpu.bs('010000'), cpu.bs('01011'), rt, cpu.bs('01100'),
+                     cpu.bs('00000'), cpu.bs('0'), cpu.bs('00'), cpu.bs('000')])
+mips32op("ei",      [cpu.bs('010000'), cpu.bs('01011'), rt, cpu.bs('01100'),
+                     cpu.bs('00000'), cpu.bs('1'), cpu.bs('00'), cpu.bs('000')])
+
+
+mips32op("tlbp",    [cpu.bs('010000'), cpu.bs('1'), cpu.bs('0'*19),
+                     cpu.bs('001000')])
+mips32op("tlbwi",   [cpu.bs('010000'), cpu.bs('1'), cpu.bs('0'*19),
+                     cpu.bs('000010')])
+
+
+mips32op("teq",     [cpu.bs('000000'), rs, rt, bs_code, cpu.bs('110100')],
+         [rs, rt])
+mips32op("tne",     [cpu.bs('000000'), rs, rt, bs_code, cpu.bs('110110')],         
+         [rs, rt])
+
+mips32op("clz",     [cpu.bs('011100'), rs, rt, rd, cpu.bs('00000'), cpu.bs('100000')],
+        [rd, rs])
+mips32op("clz",     [cpu.bs('000000'), rs, cpu.bs('00000'), rd, cpu.bs('00001010000')],
+        [rd, rs])
+
+mips32op("ll",      [cpu.bs('110000'), base, rt, s16imm_noarg], [rt, base])
+mips32op("ll",      [cpu.bs('011111'), base, rt, s09imm_noarg, cpu.bs('0110110')], [rt, base])
+
+mips32op("sc",      [cpu.bs('111000'), base, rt, s16imm_noarg], [rt, base])
+mips32op("sc",      [cpu.bs('011111'), base, rt, s09imm_noarg, cpu.bs('0'), cpu.bs('100110')], [rt, base])
+
+mips32op("sync",    [cpu.bs('000000000000000000000'), stype, cpu.bs('001111')], [stype])
+
+mips32op("pref",    [cpu.bs('110011'), base, hint_pref, s16imm_noarg], [hint_pref, base])
+mips32op("pref",    [cpu.bs('011111'), base, hint_pref, s09imm_noarg, cpu.bs('0110101')], [hint_pref, base])
+
+mips32op("tlbwr",   [cpu.bs('01000010000000000000000000000110')], [])
+mips32op("tlbr",    [cpu.bs('01000010000000000000000000000001')], [])
+
+mips32op("cache",   [cpu.bs('101111'), base, oper, s16imm_noarg], [oper, base])
+mips32op("cache",   [cpu.bs('011111'), base, oper, s09imm_noarg, cpu.bs('0100101')], [oper, base])
+
+mips32op("eret",    [cpu.bs('01000010000000000000000000011000')], [])
+
+mips32op("mtlo",    [cpu.bs('000000'), rs, cpu.bs('000000000000000'), cpu.bs('010011')], [rs])
+mips32op("mthi",    [cpu.bs('000000'), rs, cpu.bs('000000000000000'), cpu.bs('010001')], [rs])
+
diff --git a/src/miasm/arch/mips32/disasm.py b/src/miasm/arch/mips32/disasm.py
new file mode 100644
index 00000000..b6c05cb7
--- /dev/null
+++ b/src/miasm/arch/mips32/disasm.py
@@ -0,0 +1,16 @@
+from miasm.core.asmblock import disasmEngine
+from miasm.arch.mips32.arch import mn_mips32
+
+
+
+class dis_mips32b(disasmEngine):
+    attrib = 'b'
+    def __init__(self, bs=None, **kwargs):
+        super(dis_mips32b, self).__init__(mn_mips32, self.attrib, bs, **kwargs)
+
+
+class dis_mips32l(disasmEngine):
+    attrib = "l"
+    def __init__(self, bs=None, **kwargs):
+        super(dis_mips32l, self).__init__(mn_mips32, self.attrib, bs, **kwargs)
+
diff --git a/src/miasm/arch/mips32/jit.py b/src/miasm/arch/mips32/jit.py
new file mode 100644
index 00000000..a4d8a193
--- /dev/null
+++ b/src/miasm/arch/mips32/jit.py
@@ -0,0 +1,160 @@
+from builtins import range
+import logging
+
+from miasm.jitter.jitload import Jitter, named_arguments
+from miasm.core.locationdb import LocationDB
+from miasm.core.utils import pck32, upck32
+from miasm.arch.mips32.sem import Lifter_Mips32l, Lifter_Mips32b
+from miasm.jitter.codegen import CGen
+from miasm.ir.ir import AssignBlock, IRBlock
+import miasm.expression.expression as m2_expr
+
+log = logging.getLogger('jit_mips32')
+hnd = logging.StreamHandler()
+hnd.setFormatter(logging.Formatter("[%(levelname)-8s]: %(message)s"))
+log.addHandler(hnd)
+log.setLevel(logging.CRITICAL)
+
+
+class mipsCGen(CGen):
+    CODE_INIT = CGen.CODE_INIT + r"""
+    unsigned int branch_dst_pc;
+    unsigned int branch_dst_irdst;
+    unsigned int branch_dst_set=0;
+    """
+
+    CODE_RETURN_NO_EXCEPTION = r"""
+    %s:
+    if (branch_dst_set) {
+        %s = %s;
+        BlockDst->address = %s;
+    } else {
+        BlockDst->address = %s;
+    }
+    return JIT_RET_NO_EXCEPTION;
+    """
+
+    def __init__(self, lifter):
+        super(mipsCGen, self).__init__(lifter)
+        self.delay_slot_dst = m2_expr.ExprId("branch_dst_irdst", 32)
+        self.delay_slot_set = m2_expr.ExprId("branch_dst_set", 32)
+
+    def block2assignblks(self, block):
+        irblocks_list = super(mipsCGen, self).block2assignblks(block)
+        for irblocks in irblocks_list:
+            for blk_idx, irblock in enumerate(irblocks):
+                has_breakflow = any(assignblock.instr.breakflow() for assignblock in irblock)
+                if not has_breakflow:
+                    continue
+
+                irs = []
+                for assignblock in irblock:
+                    if self.lifter.pc not in assignblock:
+                        irs.append(AssignBlock(assignments, assignblock.instr))
+                        continue
+                    assignments = dict(assignblock)
+                    # Add internal branch destination
+                    assignments[self.delay_slot_dst] = assignblock[
+                        self.lifter.pc]
+                    assignments[self.delay_slot_set] = m2_expr.ExprInt(1, 32)
+                    # Replace IRDst with next instruction
+                    dst_loc_key = self.lifter.get_next_instr(assignblock.instr)
+                    assignments[self.lifter.IRDst] = m2_expr.ExprLoc(dst_loc_key, 32)
+                    irs.append(AssignBlock(assignments, assignblock.instr))
+                irblocks[blk_idx] = IRBlock(irblock.loc_db, irblock.loc_key, irs)
+
+        return irblocks_list
+
+    def gen_finalize(self, block):
+        """
+        Generate the C code for the final block instruction
+        """
+
+        loc_key = self.get_block_post_label(block)
+        offset = self.lifter.loc_db.get_location_offset(loc_key)
+        out = (self.CODE_RETURN_NO_EXCEPTION % (loc_key,
+                                                self.C_PC,
+                                                m2_expr.ExprId('branch_dst_irdst', 32),
+                                                m2_expr.ExprId('branch_dst_irdst', 32),
+                                                self.id_to_c(m2_expr.ExprInt(offset, 32)))
+              ).split('\n')
+        return out
+
+
+class jitter_mips32l(Jitter):
+
+    C_Gen = mipsCGen
+
+    def __init__(self, loc_db, *args, **kwargs):
+        Jitter.__init__(self, Lifter_Mips32l(loc_db), *args, **kwargs)
+        self.vm.set_little_endian()
+
+    def push_uint32_t(self, value):
+        self.cpu.SP -= 4
+        self.vm.set_mem(self.cpu.SP, pck32(value))
+
+    def pop_uint32_t(self):
+        value = self.vm.get_u32(self.cpu.SP)
+        self.cpu.SP += 4
+        return value
+
+    def get_stack_arg(self, index):
+        return self.vm.get_u32(self.cpu.SP + 4 * index)
+
+    def init_run(self, *args, **kwargs):
+        Jitter.init_run(self, *args, **kwargs)
+        self.cpu.PC = self.pc
+
+    # calling conventions
+
+    @named_arguments
+    def func_args_stdcall(self, n_args):
+        args = [self.get_arg_n_stdcall(i) for i in range(n_args)]
+        ret_ad = self.cpu.RA
+        return ret_ad, args
+
+    def func_ret_stdcall(self, ret_addr, ret_value1=None, ret_value2=None):
+        self.pc = self.cpu.PC = ret_addr
+        if ret_value1 is not None:
+            self.cpu.V0 = ret_value1
+        if ret_value2 is not None:
+            self.cpu.V1 = ret_value2
+        return True
+
+    def func_prepare_stdcall(self, ret_addr, *args):
+        for index in range(min(len(args), 4)):
+            setattr(self.cpu, 'A%d' % index, args[index])
+        for index in range(4, len(args)):
+            self.vm.set_mem(self.cpu.SP + 4 * (index - 4), pck32(args[index]))
+        self.cpu.RA = ret_addr
+
+    def get_arg_n_stdcall(self, index):
+        if index < 4:
+            arg = getattr(self.cpu, 'A%d' % index)
+        else:
+            arg = self.get_stack_arg(index-4)
+        return arg
+
+    def syscall_args_systemv(self, n_args):
+        # Documentation: http://man7.org/linux/man-pages/man2/syscall.2.html
+        # mips/o32      a0    a1    a2    a3    stack
+        args = [self.get_arg_n_stdcall(i) for i in range(n_args)]
+        return args
+
+    def syscall_ret_systemv(self, value1, value2, error):
+        # Documentation: http://man7.org/linux/man-pages/man2/syscall.2.html
+        self.cpu.V0 = value1
+        self.cpu.V1 = value2
+        self.cpu.A3 = error  # 0 -> no error, -1 -> error
+
+    func_args_systemv = func_args_stdcall
+    func_ret_systemv = func_ret_stdcall
+    func_prepare_systemv = func_prepare_stdcall
+    get_arg_n_systemv = get_arg_n_stdcall
+
+
+class jitter_mips32b(jitter_mips32l):
+
+    def __init__(self, loc_db, *args, **kwargs):
+        Jitter.__init__(self, Lifter_Mips32b(loc_db), *args, **kwargs)
+        self.vm.set_big_endian()
diff --git a/src/miasm/arch/mips32/lifter_model_call.py b/src/miasm/arch/mips32/lifter_model_call.py
new file mode 100644
index 00000000..bd0e8506
--- /dev/null
+++ b/src/miasm/arch/mips32/lifter_model_call.py
@@ -0,0 +1,104 @@
+#-*- coding:utf-8 -*-
+
+from miasm.expression.expression import ExprAssign, ExprOp
+from miasm.ir.ir import IRBlock, AssignBlock
+from miasm.ir.analysis import LifterModelCall
+from miasm.arch.mips32.sem import Lifter_Mips32l, Lifter_Mips32b
+
+class LifterModelCallMips32l(Lifter_Mips32l, LifterModelCall):
+    def __init__(self, loc_db):
+        Lifter_Mips32l.__init__(self, loc_db)
+        self.ret_reg = self.arch.regs.V0
+
+    def call_effects(self, ad, instr):
+        call_assignblk = AssignBlock(
+            [
+                ExprAssign(
+                    self.ret_reg,
+                    ExprOp(
+                        'call_func_ret',
+                        ad,
+                        self.arch.regs.A0,
+                        self.arch.regs.A1,
+                        self.arch.regs.A2,
+                        self.arch.regs.A3,
+                    )
+                ),
+            ],
+            instr
+        )
+
+        return [call_assignblk], []
+
+
+    def add_asmblock_to_ircfg(self, block, ircfg, gen_pc_updt=False):
+        """
+        Add a native block to the current IR
+        @block: native assembly block
+        @ircfg: IRCFG instance
+        @gen_pc_updt: insert PC update effects between instructions
+        """
+        loc_key = block.loc_key
+        ir_blocks_all = []
+
+        assignments = []
+        for index, instr in enumerate(block.lines):
+            if loc_key is None:
+                assignments = []
+                loc_key = self.get_loc_key_for_instr(instr)
+            if instr.is_subcall():
+                assert index == len(block.lines) - 2
+
+                # Add last instruction first (before call)
+                split = self.add_instr_to_current_state(
+                    block.lines[-1], block, assignments,
+                    ir_blocks_all, gen_pc_updt
+                )
+                assert not split
+                # Add call effects after the delay splot
+                split = self.add_instr_to_current_state(
+                    instr, block, assignments,
+                    ir_blocks_all, gen_pc_updt
+                )
+                assert split
+                break
+            split = self.add_instr_to_current_state(
+                instr, block, assignments,
+                ir_blocks_all, gen_pc_updt
+            )
+            if split:
+                ir_blocks_all.append(IRBlock(self.loc_db, loc_key, assignments))
+                loc_key = None
+                assignments = []
+        if loc_key is not None:
+            ir_blocks_all.append(IRBlock(self.loc_db, loc_key, assignments))
+
+        new_ir_blocks_all = self.post_add_asmblock_to_ircfg(block, ircfg, ir_blocks_all)
+        for irblock in new_ir_blocks_all:
+            ircfg.add_irblock(irblock)
+        return new_ir_blocks_all
+
+    def get_out_regs(self, _):
+        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 LifterModelCallMips32b(Lifter_Mips32b, LifterModelCallMips32l):
+    def __init__(self, loc_db):
+        Lifter_Mips32b.__init__(self, loc_db)
+        self.ret_reg = self.arch.regs.V0
diff --git a/src/miasm/arch/mips32/regs.py b/src/miasm/arch/mips32/regs.py
new file mode 100644
index 00000000..967b7458
--- /dev/null
+++ b/src/miasm/arch/mips32/regs.py
@@ -0,0 +1,101 @@
+#-*- coding:utf-8 -*-
+
+from builtins import range
+from miasm.expression.expression import ExprId
+from miasm.core.cpu import gen_reg, gen_regs
+
+
+PC, _ = gen_reg('PC')
+PC_FETCH, _ = gen_reg('PC_FETCH')
+
+R_LO, _ = gen_reg('R_LO')
+R_HI, _ = gen_reg('R_HI')
+
+exception_flags = ExprId('exception_flags', 32)
+
+PC_init = ExprId("PC_init", 32)
+PC_FETCH_init = ExprId("PC_FETCH_init", 32)
+
+regs32_str = ["ZERO", 'AT', 'V0', 'V1'] +\
+    ['A%d'%i for i in range(4)] +\
+    ['T%d'%i for i in range(8)] +\
+    ['S%d'%i for i in range(8)] +\
+    ['T%d'%i for i in range(8, 10)] +\
+    ['K0', 'K1'] +\
+    ['GP', 'SP', 'FP', 'RA']
+
+regs32_expr = [ExprId(x, 32) for x in regs32_str]
+ZERO = regs32_expr[0]
+
+regs_flt_str = ['F%d'%i for i in range(0x20)]
+
+regs_fcc_str = ['FCC%d'%i for i in range(8)]
+
+R_LO = ExprId('R_LO', 32)
+R_HI = ExprId('R_HI', 32)
+
+R_LO_init = ExprId('R_LO_init', 32)
+R_HI_init = ExprId('R_HI_init', 32)
+
+
+cpr0_str = ["CPR0_%d"%x for x in range(0x100)]
+cpr0_str[0] = "INDEX"
+cpr0_str[8] = "RANDOM"
+cpr0_str[16] = "ENTRYLO0"
+cpr0_str[24] = "ENTRYLO1"
+cpr0_str[32] = "CONTEXT"
+cpr0_str[33] = "CONTEXTCONFIG"
+cpr0_str[40] = "PAGEMASK"
+cpr0_str[41] = "PAGEGRAIN"
+cpr0_str[42] = "SEGCTL0"
+cpr0_str[43] = "SEGCTL1"
+cpr0_str[44] = "SEGCTL2"
+cpr0_str[45] = "PWBASE"
+cpr0_str[46] = "PWFIELD"
+cpr0_str[47] = "PWSIZE"
+cpr0_str[48] = "WIRED"
+cpr0_str[54] = "PWCTL"
+cpr0_str[64] = "BADVADDR"
+cpr0_str[65] = "BADINSTR"
+cpr0_str[66] = "BADINSTRP"
+cpr0_str[72] = "COUNT"
+cpr0_str[80] = "ENTRYHI"
+cpr0_str[104] = "CAUSE"
+cpr0_str[112] = "EPC"
+cpr0_str[120] = "PRID"
+cpr0_str[121] = "EBASE"
+cpr0_str[128] = "CONFIG"
+cpr0_str[129] = "CONFIG1"
+cpr0_str[130] = "CONFIG2"
+cpr0_str[131] = "CONFIG3"
+cpr0_str[132] = "CONFIG4"
+cpr0_str[133] = "CONFIG5"
+cpr0_str[152] = "WATCHHI"
+cpr0_str[250] = "KSCRATCH"
+cpr0_str[251] = "KSCRATCH1"
+cpr0_str[252] = "KSCRATCH2"
+cpr0_str[253] = "KSCRATCH3"
+cpr0_str[254] = "KSCRATCH4"
+cpr0_str[255] = "KSCRATCH5"
+
+regs_cpr0_expr, regs_cpr0_init, regs_cpr0_info = gen_regs(cpr0_str, globals())
+
+gpregs_expr, gpregs_init, gpregs = gen_regs(regs32_str, globals())
+regs_flt_expr, regs_flt_init, fltregs = gen_regs(regs_flt_str, globals(), sz=64)
+regs_fcc_expr, regs_fcc_init, fccregs = gen_regs(regs_fcc_str, globals())
+
+
+all_regs_ids = [PC, PC_FETCH, R_LO, R_HI, exception_flags] + gpregs_expr + regs_flt_expr + \
+    regs_fcc_expr + regs_cpr0_expr
+all_regs_ids_byname = dict([(x.name, x) for x in all_regs_ids])
+all_regs_ids_init = [ExprId("%s_init" % reg.name, reg.size) for reg in all_regs_ids]
+all_regs_ids_no_alias = all_regs_ids[:]
+
+attrib_to_regs = {
+    'l': all_regs_ids_no_alias,
+    'b': all_regs_ids_no_alias,
+}
+
+regs_init = {}
+for i, r in enumerate(all_regs_ids):
+    regs_init[r] = all_regs_ids_init[i]
diff --git a/src/miasm/arch/mips32/sem.py b/src/miasm/arch/mips32/sem.py
new file mode 100644
index 00000000..649adcaa
--- /dev/null
+++ b/src/miasm/arch/mips32/sem.py
@@ -0,0 +1,667 @@
+import miasm.expression.expression as m2_expr
+from miasm.ir.ir import Lifter, IRBlock, AssignBlock
+from miasm.arch.mips32.arch import mn_mips32
+from miasm.arch.mips32.regs import R_LO, R_HI, PC, RA, ZERO, exception_flags
+from miasm.core.sembuilder import SemBuilder
+from miasm.jitter.csts import EXCEPT_DIV_BY_ZERO, EXCEPT_SOFT_BP, EXCEPT_SYSCALL
+
+
+# SemBuilder context
+ctx = {
+    "R_LO": R_LO,
+    "R_HI": R_HI,
+    "PC": PC,
+    "RA": RA,
+    "m2_expr": m2_expr
+}
+
+sbuild = SemBuilder(ctx)
+
+
+@sbuild.parse
+def addiu(arg1, arg2, arg3):
+    """Adds a register @arg3 and a sign-extended immediate value @arg2 and
+    stores the result in a register @arg1"""
+    arg1 = arg2 + arg3
+
+@sbuild.parse
+def lw(arg1, arg2):
+    "A word is loaded into a register @arg1 from the specified address @arg2."
+    arg1 = arg2
+
+@sbuild.parse
+def sw(arg1, arg2):
+    "The contents of @arg2 is stored at the specified address @arg1."
+    arg2 = arg1
+
+@sbuild.parse
+def jal(arg1):
+    "Jumps to the calculated address @arg1 and stores the return address in $RA"
+    PC = arg1
+    ir.IRDst = arg1
+    RA = m2_expr.ExprLoc(ir.get_next_break_loc_key(instr), RA.size)
+
+@sbuild.parse
+def jalr(arg1, arg2):
+    """Jump to an address stored in a register @arg1, and store the return
+    address in another register @arg2"""
+    PC = arg1
+    ir.IRDst = arg1
+    arg2 = m2_expr.ExprLoc(ir.get_next_break_loc_key(instr), arg2.size)
+
+@sbuild.parse
+def bal(arg1):
+    PC = arg1
+    ir.IRDst = arg1
+    RA = m2_expr.ExprLoc(ir.get_next_break_loc_key(instr), RA.size)
+
+@sbuild.parse
+def l_b(arg1):
+    PC = arg1
+    ir.IRDst = arg1
+
+@sbuild.parse
+def lbu(arg1, arg2):
+    """A byte is loaded (unsigned extended) into a register @arg1 from the
+    specified address @arg2."""
+    arg1 = m2_expr.ExprMem(arg2.ptr, 8).zeroExtend(32)
+
+@sbuild.parse
+def lh(arg1, arg2):
+    """A word is loaded into a register @arg1 from the
+    specified address @arg2."""
+    arg1 = m2_expr.ExprMem(arg2.ptr, 16).signExtend(32)
+
+@sbuild.parse
+def lhu(arg1, arg2):
+    """A word is loaded (unsigned extended) into a register @arg1 from the
+    specified address @arg2."""
+    arg1 = m2_expr.ExprMem(arg2.ptr, 16).zeroExtend(32)
+
+@sbuild.parse
+def lb(arg1, arg2):
+    "A byte is loaded into a register @arg1 from the specified address @arg2."
+    arg1 = m2_expr.ExprMem(arg2.ptr, 8).signExtend(32)
+
+@sbuild.parse
+def ll(arg1, arg2):
+    "To load a word from memory for an atomic read-modify-write"
+    arg1 = arg2
+
+@sbuild.parse
+def beq(arg1, arg2, arg3):
+    "Branches on @arg3 if the quantities of two registers @arg1, @arg2 are eq"
+    dst = arg3 if m2_expr.ExprOp(m2_expr.TOK_EQUAL, arg1, arg2) else m2_expr.ExprLoc(ir.get_next_break_loc_key(instr), ir.IRDst.size)
+    PC = dst
+    ir.IRDst = dst
+
+@sbuild.parse
+def beql(arg1, arg2, arg3):
+    "Branches on @arg3 if the quantities of two registers @arg1, @arg2 are eq"
+    dst = arg3 if m2_expr.ExprOp(m2_expr.TOK_EQUAL, arg1, arg2) else m2_expr.ExprLoc(ir.get_next_delay_loc_key(instr), ir.IRDst.size)
+    PC = dst
+    ir.IRDst = dst
+
+@sbuild.parse
+def bgez(arg1, arg2):
+    """Branches on @arg2 if the quantities of register @arg1 is greater than or
+    equal to zero"""
+    dst = m2_expr.ExprLoc(ir.get_next_break_loc_key(instr), ir.IRDst.size) if m2_expr.ExprOp(m2_expr.TOK_INF_SIGNED, arg1, m2_expr.ExprInt(0, arg1.size)) else arg2
+    PC = dst
+    ir.IRDst = dst
+
+@sbuild.parse
+def bgezl(arg1, arg2):
+    """Branches on @arg2 if the quantities of register @arg1 is greater than or
+    equal to zero"""
+    dst = m2_expr.ExprLoc(ir.get_next_delay_loc_key(instr), ir.IRDst.size) if m2_expr.ExprOp(m2_expr.TOK_INF_SIGNED, arg1, m2_expr.ExprInt(0, arg1.size)) else arg2
+    PC = dst
+    ir.IRDst = dst
+
+@sbuild.parse
+def bne(arg1, arg2, arg3):
+    """Branches on @arg3 if the quantities of two registers @arg1, @arg2 are NOT
+    equal"""
+    dst = m2_expr.ExprLoc(ir.get_next_break_loc_key(instr), ir.IRDst.size) if m2_expr.ExprOp(m2_expr.TOK_EQUAL, arg1, arg2) else arg3
+    PC = dst
+    ir.IRDst = dst
+
+@sbuild.parse
+def bnel(arg1, arg2, arg3):
+    """Branches on @arg3 if the quantities of two registers @arg1, @arg2 are NOT
+    equal"""
+    dst = m2_expr.ExprLoc(ir.get_next_delay_loc_key(instr), ir.IRDst.size) if m2_expr.ExprOp(m2_expr.TOK_EQUAL, arg1, arg2) else arg3
+    PC = dst
+    ir.IRDst = dst
+
+@sbuild.parse
+def lui(arg1, arg2):
+    """The immediate value @arg2 is shifted left 16 bits and stored in the
+    register @arg1. The lower 16 bits are zeroes."""
+    arg1 = m2_expr.ExprCompose(i16(0), arg2[:16])
+
+@sbuild.parse
+def nop():
+    """Do nothing"""
+
+@sbuild.parse
+def sync(arg1):
+    """Synchronize Shared Memory"""
+
+@sbuild.parse
+def pref(arg1, arg2):
+    """To move data between memory and cache"""
+
+@sbuild.parse
+def j(arg1):
+    """Jump to an address @arg1"""
+    PC = arg1
+    ir.IRDst = arg1
+
+@sbuild.parse
+def l_or(arg1, arg2, arg3):
+    """Bitwise logical ors two registers @arg2, @arg3 and stores the result in a
+    register @arg1"""
+    arg1 = arg2 | arg3
+
+@sbuild.parse
+def nor(arg1, arg2, arg3):
+    """Bitwise logical Nors two registers @arg2, @arg3 and stores the result in
+    a register @arg1"""
+    arg1 = (arg2 | arg3) ^ i32(-1)
+
+@sbuild.parse
+def l_and(arg1, arg2, arg3):
+    """Bitwise logical ands two registers @arg2, @arg3 and stores the result in
+    a register @arg1"""
+    arg1 = arg2 & arg3
+
+@sbuild.parse
+def ext(arg1, arg2, arg3, arg4):
+    pos = int(arg3)
+    size = int(arg4)
+    arg1 = arg2[pos:pos + size].zeroExtend(32)
+
+@sbuild.parse
+def mul(arg1, arg2, arg3):
+    """Multiplies @arg2 by $arg3 and stores the result in @arg1."""
+    arg1 = 'imul'(arg2, arg3)
+
+@sbuild.parse
+def sltu(arg1, arg2, arg3):
+    """If @arg2 is less than @arg3 (unsigned), @arg1 is set to one. It gets zero
+    otherwise."""
+    arg1 = m2_expr.ExprCond(
+        m2_expr.ExprOp(m2_expr.TOK_INF_UNSIGNED, arg2, arg3),
+        m2_expr.ExprInt(1, arg1.size),
+        m2_expr.ExprInt(0, arg1.size)
+    )
+
+@sbuild.parse
+def slt(arg1, arg2, arg3):
+    """If @arg2 is less than @arg3 (signed), @arg1 is set to one. It gets zero
+    otherwise."""
+    arg1 = m2_expr.ExprCond(
+        m2_expr.ExprOp(m2_expr.TOK_INF_SIGNED, arg2, arg3),
+        m2_expr.ExprInt(1, arg1.size),
+        m2_expr.ExprInt(0, arg1.size)
+    )
+
+
+@sbuild.parse
+def l_sub(arg1, arg2, arg3):
+    arg1 = arg2 - arg3
+
+def sb(ir, instr, arg1, arg2):
+    """The least significant byte of @arg1 is stored at the specified address
+    @arg2."""
+    e = []
+    e.append(m2_expr.ExprAssign(m2_expr.ExprMem(arg2.ptr, 8), arg1[:8]))
+    return e, []
+
+def sh(ir, instr, arg1, arg2):
+    e = []
+    e.append(m2_expr.ExprAssign(m2_expr.ExprMem(arg2.ptr, 16), arg1[:16]))
+    return e, []
+
+@sbuild.parse
+def movn(arg1, arg2, arg3):
+    if arg3:
+        arg1 = arg2
+
+@sbuild.parse
+def movz(arg1, arg2, arg3):
+    if not arg3:
+        arg1 = arg2
+
+@sbuild.parse
+def srl(arg1, arg2, arg3):
+    """Shifts arg1 register value @arg2 right by the shift amount @arg3 and
+    places the value in the destination register @arg1.
+    Zeroes are shifted in."""
+    arg1 = arg2 >> arg3
+
+@sbuild.parse
+def sra(arg1, arg2, arg3):
+    """Shifts arg1 register value @arg2 right by the shift amount @arg3 and
+    places the value in the destination register @arg1. The sign bit is shifted
+    in."""
+    arg1 = 'a>>'(arg2, arg3)
+
+@sbuild.parse
+def srav(arg1, arg2, arg3):
+    arg1 = 'a>>'(arg2, arg3 & i32(0x1F))
+
+@sbuild.parse
+def sll(arg1, arg2, arg3):
+    arg1 = arg2 << arg3
+
+@sbuild.parse
+def srlv(arg1, arg2, arg3):
+    """Shifts a register value @arg2 right by the amount specified in @arg3 and
+    places the value in the destination register @arg1.
+    Zeroes are shifted in."""
+    arg1 = arg2 >> (arg3 & i32(0x1F))
+
+@sbuild.parse
+def sllv(arg1, arg2, arg3):
+    """Shifts a register value @arg2 left by the amount specified in @arg3 and
+    places the value in the destination register @arg1.
+    Zeroes are shifted in."""
+    arg1 = arg2 << (arg3 & i32(0x1F))
+
+@sbuild.parse
+def l_xor(arg1, arg2, arg3):
+    """Exclusive ors two registers @arg2, @arg3 and stores the result in a
+    register @arg3"""
+    arg1 = arg2 ^ arg3
+
+@sbuild.parse
+def seb(arg1, arg2):
+    arg1 = arg2[:8].signExtend(32)
+
+@sbuild.parse
+def seh(arg1, arg2):
+    arg1 = arg2[:16].signExtend(32)
+
+@sbuild.parse
+def bltz(arg1, arg2):
+    """Branches on @arg2 if the register @arg1 is less than zero"""
+    dst_o = arg2 if m2_expr.ExprOp(m2_expr.TOK_INF_SIGNED, arg1, m2_expr.ExprInt(0, arg1.size)) else m2_expr.ExprLoc(ir.get_next_break_loc_key(instr), ir.IRDst.size)
+    PC = dst_o
+    ir.IRDst = dst_o
+
+@sbuild.parse
+def bltzl(arg1, arg2):
+    """Branches on @arg2 if the register @arg1 is less than zero"""
+    dst_o = arg2 if m2_expr.ExprOp(m2_expr.TOK_INF_SIGNED, arg1, m2_expr.ExprInt(0, arg1.size)) else m2_expr.ExprLoc(ir.get_next_delay_loc_key(instr), ir.IRDst.size)
+    PC = dst_o
+    ir.IRDst = dst_o
+
+@sbuild.parse
+def blez(arg1, arg2):
+    """Branches on @arg2 if the register @arg1 is less than or equal to zero"""
+    cond = m2_expr.ExprOp(m2_expr.TOK_INF_EQUAL_SIGNED, arg1, m2_expr.ExprInt(0, arg1.size))
+    dst_o = arg2 if cond else m2_expr.ExprLoc(ir.get_next_break_loc_key(instr), ir.IRDst.size)
+    PC = dst_o
+    ir.IRDst = dst_o
+
+@sbuild.parse
+def blezl(arg1, arg2):
+    """Branches on @arg2 if the register @arg1 is less than or equal to zero"""
+    cond = m2_expr.ExprOp(m2_expr.TOK_INF_EQUAL_SIGNED, arg1, m2_expr.ExprInt(0, arg1.size))
+    dst_o = arg2 if cond else m2_expr.ExprLoc(ir.get_next_delay_loc_key(instr), ir.IRDst.size)
+    PC = dst_o
+    ir.IRDst = dst_o
+
+@sbuild.parse
+def bgtz(arg1, arg2):
+    """Branches on @arg2 if the register @arg1 is greater than zero"""
+    cond =  m2_expr.ExprOp(m2_expr.TOK_INF_EQUAL_SIGNED, arg1, m2_expr.ExprInt(0, arg1.size))
+    dst_o = m2_expr.ExprLoc(ir.get_next_break_loc_key(instr), ir.IRDst.size) if cond else arg2
+    PC = dst_o
+    ir.IRDst = dst_o
+
+@sbuild.parse
+def bgtzl(arg1, arg2):
+    """Branches on @arg2 if the register @arg1 is greater than zero"""
+    cond =  m2_expr.ExprOp(m2_expr.TOK_INF_EQUAL_SIGNED, arg1, m2_expr.ExprInt(0, arg1.size))
+    dst_o = m2_expr.ExprLoc(ir.get_next_delay_loc_key(instr), ir.IRDst.size) if cond else arg2
+    PC = dst_o
+    ir.IRDst = dst_o
+
+@sbuild.parse
+def wsbh(arg1, arg2):
+    arg1 = m2_expr.ExprCompose(arg2[8:16], arg2[0:8], arg2[24:32], arg2[16:24])
+
+@sbuild.parse
+def rotr(arg1, arg2, arg3):
+    arg1 = '>>>'(arg2, arg3)
+
+@sbuild.parse
+def add_d(arg1, arg2, arg3):
+    # XXX TODO check
+    arg1 = 'fadd'(arg2, arg3)
+
+@sbuild.parse
+def sub_d(arg1, arg2, arg3):
+    # XXX TODO check
+    arg1 = 'fsub'(arg2, arg3)
+
+@sbuild.parse
+def div_d(arg1, arg2, arg3):
+    # XXX TODO check
+    arg1 = 'fdiv'(arg2, arg3)
+
+@sbuild.parse
+def mul_d(arg1, arg2, arg3):
+    # XXX TODO check
+    arg1 = 'fmul'(arg2, arg3)
+
+@sbuild.parse
+def mov_d(arg1, arg2):
+    # XXX TODO check
+    arg1 = arg2
+
+@sbuild.parse
+def mfc0(arg1, arg2):
+    arg1 = arg2
+
+@sbuild.parse
+def mfc1(arg1, arg2):
+    arg1 = arg2
+
+@sbuild.parse
+def mtc0(arg1, arg2):
+    arg2 = arg1
+
+@sbuild.parse
+def mtc1(arg1, arg2):
+    arg2 = arg1
+
+@sbuild.parse
+def tlbwi():
+    "TODO XXX"
+
+@sbuild.parse
+def tlbp():
+    "TODO XXX"
+
+@sbuild.parse
+def tlbwr():
+    "TODO XXX"
+
+@sbuild.parse
+def tlbr():
+    "TODO XXX"
+
+def break_(ir, instr):
+    e = []
+    e.append(m2_expr.ExprAssign(exception_flags, m2_expr.ExprInt(EXCEPT_SOFT_BP, 32)))
+    return e, []
+
+def syscall(ir, instr, code):
+    e = []
+    e.append(m2_expr.ExprAssign(exception_flags, m2_expr.ExprInt(EXCEPT_SYSCALL, 32)))
+    return e, []
+
+def ins(ir, instr, a, b, c, d):
+    e = []
+    pos = int(c)
+    l = int(d)
+
+    my_slices = []
+    if pos != 0:
+        my_slices.append(a[:pos])
+    if l != 0:
+        my_slices.append(b[:l])
+    if pos + l != 32:
+        my_slices.append(a[pos+l:])
+    r = m2_expr.ExprCompose(*my_slices)
+    e.append(m2_expr.ExprAssign(a, r))
+    return e, []
+
+
+@sbuild.parse
+def lwc1(arg1, arg2):
+    arg1 = ('mem_%.2d_to_single' % arg2.size)(arg2)
+
+@sbuild.parse
+def swc1(arg1, arg2):
+    arg2 = ('single_to_mem_%.2d' % arg1.size)(arg1)
+
+@sbuild.parse
+def c_lt_d(arg1, arg2, arg3):
+    arg1 = 'fcomp_lt'(arg2, arg3)
+
+@sbuild.parse
+def c_eq_d(arg1, arg2, arg3):
+    arg1 = 'fcomp_eq'(arg2, arg3)
+
+@sbuild.parse
+def c_le_d(arg1, arg2, arg3):
+    arg1 = 'fcomp_le'(arg2, arg3)
+
+@sbuild.parse
+def bc1t(arg1, arg2):
+    dst_o = arg2 if arg1 else m2_expr.ExprLoc(ir.get_next_break_loc_key(instr), ir.IRDst.size)
+    PC = dst_o
+    ir.IRDst = dst_o
+
+@sbuild.parse
+def bc1tl(arg1, arg2):
+    dst_o = arg2 if arg1 else m2_expr.ExprLoc(ir.get_next_delay_loc_key(instr), ir.IRDst.size)
+    PC = dst_o
+    ir.IRDst = dst_o
+
+@sbuild.parse
+def bc1f(arg1, arg2):
+    dst_o = m2_expr.ExprLoc(ir.get_next_break_loc_key(instr), ir.IRDst.size) if arg1 else arg2
+    PC = dst_o
+    ir.IRDst = dst_o
+
+@sbuild.parse
+def bc1fl(arg1, arg2):
+    dst_o = m2_expr.ExprLoc(ir.get_next_delay_loc_key(instr), ir.IRDst.size) if arg1 else arg2
+    PC = dst_o
+    ir.IRDst = dst_o
+
+@sbuild.parse
+def cvt_d_w(arg1, arg2):
+    # TODO XXX
+    arg1 = 'flt_d_w'(arg2)
+
+@sbuild.parse
+def mult(arg1, arg2):
+    """Multiplies (signed) @arg1 by @arg2 and stores the result in $R_HI:$R_LO"""
+    size = arg1.size
+    result = arg1.signExtend(size * 2) * arg2.signExtend(size * 2)
+    R_LO = result[:32]
+    R_HI = result[32:]
+
+@sbuild.parse
+def multu(arg1, arg2):
+    """Multiplies (unsigned) @arg1 by @arg2 and stores the result in $R_HI:$R_LO"""
+    size = arg1.size
+    result = arg1.zeroExtend(size * 2) * arg2.zeroExtend(size * 2)
+    R_LO = result[:32]
+    R_HI = result[32:]
+
+@sbuild.parse
+def div(arg1, arg2):
+    """Divide (signed) @arg1 by @arg2 and stores the remaining/result in $R_HI/$R_LO"""
+    R_LO = m2_expr.ExprOp('sdiv' ,arg1, arg2)
+    R_HI = m2_expr.ExprOp('smod', arg1, arg2)
+
+@sbuild.parse
+def divu(arg1, arg2):
+    """Divide (unsigned) @arg1 by @arg2 and stores the remaining/result in $R_HI/$R_LO"""
+    R_LO = m2_expr.ExprOp('udiv', arg1, arg2)
+    R_HI = m2_expr.ExprOp('umod', arg1, arg2)
+
+@sbuild.parse
+def mfhi(arg1):
+    "The contents of register $R_HI are moved to the specified register @arg1."
+    arg1 = R_HI
+
+@sbuild.parse
+def mflo(arg1):
+    "The contents of register R_LO are moved to the specified register @arg1."
+    arg1 = R_LO
+
+@sbuild.parse
+def di(arg1):
+    "NOP"
+
+@sbuild.parse
+def ei(arg1):
+    "NOP"
+
+@sbuild.parse
+def ehb(arg1):
+    "NOP"
+
+@sbuild.parse
+def sc(arg1, arg2):
+    arg2 = arg1;
+    arg1 = m2_expr.ExprInt(0x1, 32)
+
+@sbuild.parse
+def mthi(arg1):
+    R_HI = arg1
+
+@sbuild.parse
+def mtlo(arg1):
+    R_LOW = arg1
+
+def clz(ir, instr, rs, rd):
+    e = []
+    e.append(m2_expr.ExprAssign(rd, m2_expr.ExprOp('cntleadzeros', rs)))
+    return e, []
+
+def teq(ir, instr, arg1, arg2):
+    e = []
+
+    loc_except, loc_except_expr = ir.gen_loc_key_and_expr(ir.IRDst.size)
+    loc_next = ir.get_next_loc_key(instr)
+    loc_next_expr = m2_expr.ExprLoc(loc_next, ir.IRDst.size)
+
+    do_except = []
+    do_except.append(m2_expr.ExprAssign(exception_flags, m2_expr.ExprInt(
+        EXCEPT_DIV_BY_ZERO, exception_flags.size)))
+    do_except.append(m2_expr.ExprAssign(ir.IRDst, loc_next_expr))
+    blk_except = IRBlock(ir.loc_db, loc_except, [AssignBlock(do_except, instr)])
+
+    cond = arg1 - arg2
+
+
+    e = []
+    e.append(m2_expr.ExprAssign(ir.IRDst,
+                             m2_expr.ExprCond(cond, loc_next_expr, loc_except_expr)))
+
+    return e, [blk_except]
+
+def tne(ir, instr, arg1, arg2):
+    e = []
+
+    loc_except, loc_except_expr = ir.gen_loc_key_and_expr(ir.IRDst.size)
+    loc_next = ir.get_next_loc_key(instr)
+    loc_next_expr = m2_expr.ExprLoc(loc_next, ir.IRDst.size)
+
+    do_except = []
+    do_except.append(m2_expr.ExprAssign(exception_flags, m2_expr.ExprInt(
+        EXCEPT_DIV_BY_ZERO, exception_flags.size)))
+    do_except.append(m2_expr.ExprAssign(ir.IRDst, loc_next_expr))
+    blk_except = IRBlock(ir.loc_db, loc_except, [AssignBlock(do_except, instr)])
+
+    cond = arg1 ^ arg2
+
+
+    e = []
+    e.append(m2_expr.ExprAssign(ir.IRDst,
+                             m2_expr.ExprCond(cond, loc_next_expr, loc_except_expr)))
+
+    return e, [blk_except]
+
+
+mnemo_func = sbuild.functions
+mnemo_func.update(
+    {
+        'add.d': add_d,
+        'addu': addiu,
+        'addi': addiu,
+        'and': l_and,
+        'andi': l_and,
+        'b': l_b,
+        'c.eq.d': c_eq_d,
+        'c.le.d': c_le_d,
+        'c.lt.d': c_lt_d,
+        'cvt.d.w': cvt_d_w,
+        'div.d': div_d,
+        'ins': ins,
+        'jr': j,
+        'mov.d': mov_d,
+        'mul.d': mul_d,
+        'or': l_or,
+        'ori': l_or,
+        'slti': slt,
+        'sltiu': sltu,
+        'sub.d': sub_d,
+        'subu': l_sub,
+        'xor': l_xor,
+        'xori': l_xor,
+        'clz': clz,
+        'teq': teq,
+        'tne': tne,
+        'break': break_,
+        'sb': sb,
+        'sh': sh,
+        'syscall': syscall,
+    }
+)
+
+def get_mnemo_expr(ir, instr, *args):
+    instr, extra_ir = mnemo_func[instr.name.lower()](ir, instr, *args)
+    return instr, extra_ir
+
+class Lifter_Mips32l(Lifter):
+
+    def __init__(self, loc_db):
+        Lifter.__init__(self, mn_mips32, 'l', loc_db)
+        self.pc = mn_mips32.getpc()
+        self.sp = mn_mips32.getsp()
+        self.IRDst = m2_expr.ExprId('IRDst', 32)
+        self.addrsize = 32
+
+    def get_ir(self, instr):
+        args = instr.args
+        instr_ir, extra_ir = get_mnemo_expr(self, instr, *args)
+
+        fixed_regs = {
+            self.pc: m2_expr.ExprInt(instr.offset + 4, 32),
+            ZERO: m2_expr.ExprInt(0, 32)
+        }
+
+        instr_ir = [m2_expr.ExprAssign(expr.dst, expr.src.replace_expr(fixed_regs))
+                    for expr in instr_ir]
+
+        new_extra_ir = [irblock.modify_exprs(mod_src=lambda expr: expr.replace_expr(fixed_regs))
+                        for irblock in extra_ir]
+        return instr_ir, new_extra_ir
+
+    def get_next_instr(self, instr):
+        return self.loc_db.get_or_create_offset_location(instr.offset  + 4)
+
+    def get_next_break_loc_key(self, instr):
+        return self.loc_db.get_or_create_offset_location(instr.offset  + 8)
+
+    def get_next_delay_loc_key(self, instr):
+        return self.loc_db.get_or_create_offset_location(instr.offset + 16)
+
+class Lifter_Mips32b(Lifter_Mips32l):
+    def __init__(self, loc_db):
+        self.addrsize = 32
+        Lifter.__init__(self, mn_mips32, 'b', loc_db)
+        self.pc = mn_mips32.getpc()
+        self.sp = mn_mips32.getsp()
+        self.IRDst = m2_expr.ExprId('IRDst', 32)
diff --git a/src/miasm/arch/msp430/__init__.py b/src/miasm/arch/msp430/__init__.py
new file mode 100644
index 00000000..bbad893b
--- /dev/null
+++ b/src/miasm/arch/msp430/__init__.py
@@ -0,0 +1 @@
+__all__ = ["arch", "disasm", "regs", "sem"]
diff --git a/src/miasm/arch/msp430/arch.py b/src/miasm/arch/msp430/arch.py
new file mode 100644
index 00000000..417511fa
--- /dev/null
+++ b/src/miasm/arch/msp430/arch.py
@@ -0,0 +1,610 @@
+#-*- coding:utf-8 -*-
+
+from builtins import range
+
+import logging
+from pyparsing import *
+from miasm.expression.expression import *
+from miasm.core.cpu import *
+from collections import defaultdict
+from miasm.core.bin_stream import bin_stream
+import miasm.arch.msp430.regs as regs_module
+from miasm.arch.msp430.regs import *
+from miasm.core.asm_ast import AstInt, AstId, AstMem, AstOp
+from miasm.ir.ir import color_expr_html
+
+log = logging.getLogger("msp430dis")
+console_handler = logging.StreamHandler()
+console_handler.setFormatter(logging.Formatter("[%(levelname)-8s]: %(message)s"))
+log.addHandler(console_handler)
+log.setLevel(logging.DEBUG)
+
+conditional_branch = ['jnz', 'jz', 'jnc', 'jc',
+                      'jn', 'jge', 'jl']
+unconditional_branch = ['jmp']
+
+def cb_deref_nooff(tokens):
+    assert len(tokens) == 1
+    result = AstMem(tokens[0], 16)
+    return result
+
+
+def cb_deref_pinc(tokens):
+    assert len(tokens) == 1
+
+    result = AstOp('autoinc', *tokens)
+    return result
+
+
+def cb_deref_off(tokens):
+    assert len(tokens) == 2
+    result = AstMem(tokens[1] + tokens[0], 16)
+    return result
+
+
+def cb_expr(tokens):
+    assert(len(tokens) == 1)
+    result = tokens[0]
+    return result
+
+
+ARO = Suppress("@")
+LPARENT = Suppress("(")
+RPARENT = Suppress(")")
+
+PINC = Suppress("+")
+
+deref_nooff = (ARO + base_expr).setParseAction(cb_deref_nooff)
+deref_pinc = (ARO + base_expr + PINC).setParseAction(cb_deref_pinc)
+deref_off = (base_expr + LPARENT + gpregs.parser + RPARENT).setParseAction(cb_deref_off)
+sreg_p = (deref_pinc | deref_nooff | deref_off | base_expr).setParseAction(cb_expr)
+
+
+
+class msp430_arg(m_arg):
+    def asm_ast_to_expr(self, value, loc_db):
+        if isinstance(value, AstId):
+            name = value.name
+            if is_expr(name):
+                return name
+            assert isinstance(name, str)
+            if name in gpregs.str:
+                index = gpregs.str.index(name)
+                reg = gpregs.expr[index]
+                return reg
+            loc_key = loc_db.get_or_create_name_location(value.name)
+            return ExprLoc(loc_key, 16)
+        if isinstance(value, AstOp):
+            args = [self.asm_ast_to_expr(tmp, loc_db) for tmp in value.args]
+            if None in args:
+                return None
+            return ExprOp(value.op, *args)
+        if isinstance(value, AstInt):
+            return ExprInt(value.value, 16)
+        if isinstance(value, AstMem):
+            ptr = self.asm_ast_to_expr(value.ptr, loc_db)
+            if ptr is None:
+                return None
+            return ExprMem(ptr, value.size)
+        return None
+
+
+class additional_info(object):
+
+    def __init__(self):
+        self.except_on_instr = False
+
+
+class instruction_msp430(instruction):
+    __slots__ = []
+
+    def dstflow(self):
+        if self.name.startswith('j'):
+            return True
+        return self.name in ['call']
+
+    @staticmethod
+    def arg2str(expr, index=None, loc_db=None):
+        if isinstance(expr, ExprId):
+            o = str(expr)
+        elif isinstance(expr, ExprInt):
+            o = str(expr)
+        elif expr.is_loc():
+            if loc_db is not None:
+                return loc_db.pretty_str(expr.loc_key)
+            else:
+                return str(expr)
+        elif isinstance(expr, ExprOp) and expr.op == "autoinc":
+            o = "@%s+" % str(expr.args[0])
+        elif isinstance(expr, ExprMem):
+            if isinstance(expr.ptr, ExprId):
+                if index == 0:
+                    o = "@%s" % expr.ptr
+                else:
+                    o = "0x0(%s)" % expr.ptr
+            elif isinstance(expr.ptr, ExprInt):
+                o = "@%s" % expr.ptr
+            elif isinstance(expr.ptr, ExprOp):
+                o = "%s(%s)" % (expr.ptr.args[1], expr.ptr.args[0])
+        else:
+            raise NotImplementedError('unknown instance expr = %s' % type(expr))
+        return o
+
+    @staticmethod
+    def arg2html(expr, index=None, loc_db=None):
+        if isinstance(expr, ExprId) or isinstance(expr, ExprInt) or expr.is_loc():
+            return color_expr_html(expr, loc_db)
+        elif isinstance(expr, ExprOp) and expr.op == "autoinc":
+            o = "@%s+" % color_expr_html(expr.args[0], loc_db)
+        elif isinstance(expr, ExprMem):
+            if isinstance(expr.ptr, ExprId):
+                if index == 0:
+                    o = "@%s" % color_expr_html(expr.ptr, loc_db)
+                else:
+                    o = "0x0(%s)" % color_expr_html(expr.ptr, loc_db)
+            elif isinstance(expr.ptr, ExprInt):
+                o = "@%s" % color_expr_html(expr.ptr, loc_db)
+            elif isinstance(expr.ptr, ExprOp):
+                o = "%s(%s)" % (
+                    color_expr_html(expr.ptr.args[1], loc_db),
+                    color_expr_html(expr.ptr.args[0], loc_db)
+                )
+        else:
+            raise NotImplementedError('unknown instance expr = %s' % type(expr))
+        return o
+
+
+    def dstflow2label(self, loc_db):
+        expr = self.args[0]
+        if not isinstance(expr, ExprInt):
+            return
+        if self.name == "call":
+            addr = int(expr)
+        else:
+            addr = (int(expr) + int(self.offset))  & int(expr.mask)
+
+        loc_key = loc_db.get_or_create_offset_location(addr)
+        self.args[0] = ExprLoc(loc_key, expr.size)
+
+    def breakflow(self):
+        if self.name in conditional_branch + unconditional_branch:
+            return True
+        if self.name.startswith('ret'):
+            return True
+        if self.name.startswith('int'):
+            return True
+        if self.name.startswith('mov') and self.args[1] == PC:
+            return True
+        return self.name in ['call']
+
+    def splitflow(self):
+        if self.name in conditional_branch:
+            return True
+        if self.name in unconditional_branch:
+            return False
+        return self.name in ['call']
+
+    def setdstflow(self, a):
+        return
+
+    def is_subcall(self):
+        return self.name in ['call']
+
+    def getdstflow(self, loc_db):
+        return [self.args[0]]
+
+    def get_symbol_size(self, symbol, loc_db):
+        return 16
+
+    def fixDstOffset(self):
+        e = self.args[0]
+        if self.offset is None:
+            raise ValueError('symbol not resolved %s' % l)
+        if not isinstance(e, ExprInt):
+            # raise ValueError('dst must be int or label')
+            log.warning('dynamic dst %r', e)
+            return
+
+        # Call argument is an absolute offset
+        # Other offsets are relative to instruction offset
+        if self.name != "call":
+            self.args[0] =  ExprInt(int(e) - self.offset, 16)
+
+    def get_info(self, c):
+        pass
+
+    def __str__(self):
+        o = super(instruction_msp430, self).__str__()
+        return o
+
+    def get_args_expr(self):
+        args = []
+        for a in self.args:
+            args.append(a)
+        return args
+
+
+mode_msp430 = None
+
+
+class mn_msp430(cls_mn):
+    name = "msp430"
+    regs = regs_module
+    all_mn = []
+    bintree = {}
+    num = 0
+    delayslot = 0
+    pc = {None: PC}
+    sp = {None: SP}
+    all_mn_mode = defaultdict(list)
+    all_mn_name = defaultdict(list)
+    all_mn_inst = defaultdict(list)
+    instruction = instruction_msp430
+    max_instruction_len = 8
+
+    @classmethod
+    def getpc(cls, attrib):
+        return PC
+
+    @classmethod
+    def getsp(cls, attrib):
+        return SP
+
+    @classmethod
+    def check_mnemo(cls, fields):
+        l = sum([x.l for x in fields])
+        assert l % 16 == 00, "len %r" % l
+
+    @classmethod
+    def getbits(cls, bs, attrib, start, n):
+        if not n:
+            return 0
+        o = 0
+        if n > bs.getlen() * 8:
+            raise ValueError('not enough bits %r %r' % (n, len(bs.bin) * 8))
+        while n:
+            i = start // 8
+            c = cls.getbytes(bs, i)
+            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 getbytes(cls, bs, offset, l=1):
+        out = b""
+        for _ in range(l):
+            n_offset = (offset & ~1) + 1 - offset % 2
+            out += bs.getbytes(n_offset, 1)
+            offset += 1
+        return out
+
+    def decoded2bytes(self, result):
+        tmp = super(mn_msp430, self).decoded2bytes(result)
+        out = []
+        for x in tmp:
+            o = b""
+            while x:
+                o += x[:2][::-1]
+                x = x[2:]
+            out.append(o)
+        return out
+
+    @classmethod
+    def gen_modes(cls, subcls, name, bases, dct, fields):
+        dct['mode'] = None
+        return [(subcls, name, bases, dct, fields)]
+
+    def additional_info(self):
+        info = additional_info()
+        return info
+
+    @classmethod
+    def getmn(cls, name):
+        return name.upper()
+
+    def reset_class(self):
+        super(mn_msp430, self).reset_class()
+
+    def getnextflow(self, loc_db):
+        raise NotImplementedError('not fully functional')
+
+
+def addop(name, fields, args=None, alias=False):
+    dct = {"fields": fields}
+    dct["alias"] = alias
+    if args is not None:
+        dct['args'] = args
+    type(name, (mn_msp430,), dct)
+
+
+class bw_mn(bs_mod_name):
+    prio = 5
+    mn_mod = ['.w', '.b']
+
+
+class msp430_sreg_arg(reg_noarg, msp430_arg):
+    prio = default_prio + 1
+    reg_info = gpregs
+    parser = sreg_p
+
+    def decode(self, v):
+        size = 16
+        if hasattr(self.parent, 'size'):
+            size = [16, 8][self.parent.size.value]
+        v = v & self.lmask
+        e = self.reg_info.expr[v]
+        if self.parent.a_s.value == 0b00:
+            if e == R3:
+                self.expr = ExprInt(0, size)
+            else:
+                self.expr = e
+        elif self.parent.a_s.value == 0b01:
+            if e == SR:
+                self.expr = ExprMem(ExprInt(self.parent.off_s.value, 16), size)
+            elif e == R3:
+                self.expr = ExprInt(1, size)
+            else:
+                self.expr = ExprMem(
+                    e + ExprInt(self.parent.off_s.value, 16), size)
+        elif self.parent.a_s.value == 0b10:
+            if e == SR:
+                self.expr = ExprInt(4, size)
+            elif e == R3:
+                self.expr = ExprInt(2, size)
+            else:
+                self.expr = ExprMem(e, size)
+        elif self.parent.a_s.value == 0b11:
+            if e == SR:
+                self.expr = ExprInt(8, size)
+            elif e == R3:
+                if self.parent.size.value == 0:
+                    self.expr = ExprInt(0xffff, size)
+                else:
+                    self.expr = ExprInt(0xff, size)
+            elif e == PC:
+                self.expr = ExprInt(self.parent.off_s.value, size)
+            else:
+                self.expr = ExprOp('autoinc', e)
+        else:
+            raise NotImplementedError(
+                "unknown value self.parent.a_s.value = " +
+                "%d" % self.parent.a_s.value)
+        return True
+
+    def encode(self):
+        e = self.expr
+        if e in self.reg_info.expr:
+            self.parent.a_s.value = 0
+            self.value = self.reg_info.expr.index(e)
+        elif isinstance(e, ExprInt):
+            v = int(e)
+            if v == 0xffff and self.parent.size.value == 0:
+                self.parent.a_s.value = 0b11
+                self.value = 3
+            elif v == 0xff and self.parent.size.value == 1:
+                self.parent.a_s.value = 0b11
+                self.value = 3
+            elif v == 2:
+                self.parent.a_s.value = 0b10
+                self.value = 3
+            elif v == 1:
+                self.parent.a_s.value = 0b01
+                self.value = 3
+            elif v == 8:
+                self.parent.a_s.value = 0b11
+                self.value = 2
+            elif v == 4:
+                self.parent.a_s.value = 0b10
+                self.value = 2
+            elif v == 0:
+                self.parent.a_s.value = 0b00
+                self.value = 3
+            else:
+                self.parent.a_s.value = 0b11
+                self.value = 0
+                self.parent.off_s.value = v
+        elif isinstance(e, ExprMem):
+            if isinstance(e.ptr, ExprId):
+                self.parent.a_s.value = 0b10
+                self.value = self.reg_info.expr.index(e.ptr)
+            elif isinstance(e.ptr, ExprInt):
+                self.parent.a_s.value = 0b01
+                self.value = self.reg_info.expr.index(SR)
+                self.parent.off_s.value = int(e.ptr)
+            elif isinstance(e.ptr, ExprOp):
+                self.parent.a_s.value = 0b01
+                self.value = self.reg_info.expr.index(e.ptr.args[0])
+                self.parent.off_s.value = int(e.ptr.args[1])
+            else:
+                raise NotImplementedError(
+                    'unknown instance e.ptr = %s' % type(e.ptr))
+        elif isinstance(e, ExprOp) and e.op == "autoinc":
+            self.parent.a_s.value = 0b11
+            self.value = self.reg_info.expr.index(e.args[0])
+        else:
+            raise NotImplementedError('unknown instance e = %s' % type(e))
+        return True
+
+
+class msp430_dreg_arg(msp430_sreg_arg):
+    prio = default_prio + 1
+    reg_info = gpregs
+    parser = sreg_p
+
+    def decode(self, v):
+        if hasattr(self.parent, 'size'):
+            size = [16, 8][self.parent.size.value]
+        else:
+            size = 16
+
+        v = v & self.lmask
+        e = self.reg_info.expr[v]
+        if self.parent.a_d.value == 0:
+            self.expr = e
+        elif self.parent.a_d.value == 1:
+            if e == SR:
+                x = ExprInt(self.parent.off_d.value, 16)
+            else:
+                x = e + ExprInt(self.parent.off_d.value, 16)
+            self.expr = ExprMem(x, size)
+        else:
+            raise NotImplementedError(
+                "unknown value self.parent.a_d.value = " +
+                "%d" % self.parent.a_d.value)
+        return True
+
+    def encode(self):
+        e = self.expr
+        if e in self.reg_info.expr:
+            self.parent.a_d.value = 0
+            self.value = self.reg_info.expr.index(e)
+        elif isinstance(e, ExprMem):
+            if isinstance(e.ptr, ExprId):
+                r, i = e.ptr, ExprInt(0, 16)
+            elif isinstance(e.ptr, ExprOp):
+                r, i = e.ptr.args[0], e.ptr.args[1]
+            elif isinstance(e.ptr, ExprInt):
+                r, i = SR, e.ptr
+            else:
+                raise NotImplementedError(
+                    'unknown instance e.arg = %s' % type(e.ptr))
+            self.parent.a_d.value = 1
+            self.value = self.reg_info.expr.index(r)
+            self.parent.off_d.value = int(i)
+        else:
+            raise NotImplementedError('unknown instance e = %s' % type(e))
+        return True
+
+class bs_cond_off_s(bs_cond):
+
+    @classmethod
+    def flen(cls, mode, v):
+        if v['a_s'] == 0b00:
+            return None
+        elif v['a_s'] == 0b01:
+            if v['sreg'] in [3]:
+                return None
+            else:
+                return 16
+        elif v['a_s'] == 0b10:
+            return None
+        elif v['a_s'] == 0b11:
+            """
+            if v['sreg'] in [2, 3]:
+                return None
+            else:
+                return 16
+            """
+            if v['sreg'] in [0]:
+                return 16
+            else:
+                return None
+        else:
+            raise NotImplementedError("unknown value v[a_s] = %d" % v['a_s'])
+
+    def encode(self):
+        return super(bs_cond_off_s, self).encode()
+
+    def decode(self, v):
+        if self.l == 0:
+            self.value = None
+        self.value = v
+        return True
+
+
+class bs_cond_off_d(bs_cond_off_s):
+
+    @classmethod
+    def flen(cls, mode, v):
+        if v['a_d'] == 0:
+            return None
+        elif v['a_d'] == 1:
+            return 16
+        else:
+            raise NotImplementedError("unknown value v[a_d] = %d" % v['a_d'])
+
+
+class msp430_offs(imm_noarg, msp430_arg):
+    parser = base_expr
+
+    def int2expr(self, v):
+        if v & ~self.intmask != 0:
+            return None
+        return ExprInt(v, 16)
+
+    def decodeval(self, v):
+        v <<= 1
+        v += self.parent.l
+        return v
+
+    def encodeval(self, v):
+        plen = self.parent.l + self.l
+        assert(plen % 8 == 0)
+        v -= plen // 8
+        if v % 2 != 0:
+            return False
+        return v >> 1
+
+    def decode(self, v):
+        v = v & self.lmask
+        if (1 << (self.l - 1)) & v:
+            v |= ~0 ^ self.lmask
+        v = self.decodeval(v)
+        self.expr = ExprInt(v, 16)
+        return True
+
+    def encode(self):
+        if not isinstance(self.expr, ExprInt):
+            return False
+        v = int(self.expr)
+        if (1 << (self.l - 1)) & v:
+            v = -((0xffff ^ v) + 1)
+        v = self.encodeval(v)
+        self.value = (v & 0xffff) & self.lmask
+        return True
+
+
+off_s = bs(l=16, order=-10, cls=(bs_cond_off_s,), fname = "off_s")
+off_d = bs(l=16, order=-10, cls=(bs_cond_off_d,), fname = "off_d")
+
+a_s = bs(l=2, order=-4, fname='a_s')
+a_d = bs(l=1, order=-6, fname='a_d')
+
+a_d2 = bs(l=2, order=-2, fname='a_d')
+
+sreg = bs(l=4, order=-3, cls=(msp430_sreg_arg,), fname='sreg')
+dreg = bs(l=4, order=-5, cls=(msp430_dreg_arg,), fname='dreg')
+
+bw = bw_mn(l=1, order=-10, mn_mod=['.w', '.b'], fname='size')
+
+bs_f1 = bs_name(
+    l=4, name={
+        'mov': 4, 'add': 5, 'addc': 6, 'subc': 7, 'sub': 8, 'cmp': 9,
+        'dadd': 10, 'bit': 11, 'bic': 12, 'bis': 13, 'xor': 14, 'and': 15})
+addop("f1", [bs_f1, sreg, a_d, bw, a_s, dreg, off_s, off_d])
+
+bs_f2 = bs_name(l=3, name={'rrc': 0, 'rra': 2,
+                           'push': 4})
+addop("f2_1", [bs('000100'), bs_f2, bw, a_s, sreg, off_s])
+
+
+bs_f2_nobw = bs_name(l=3, name={'swpb': 1, 'sxt': 3,
+                                'call': 5})
+addop("f2_2", [bs('000100'), bs_f2_nobw, bs('0'), a_s, sreg, off_s])
+
+# Offset must be decoded in last position to have final instruction len
+offimm = bs(l=10, cls=(msp430_offs,), fname="offs", order=-1)
+
+bs_f2_jcc = bs_name(l=3, name={'jnz': 0, 'jz': 1, 'jnc': 2, 'jc': 3, 'jn': 4,
+                               'jge': 5, 'jl': 6, 'jmp': 7})
+addop("f2_3", [bs('001'), bs_f2_jcc, offimm])
+
diff --git a/src/miasm/arch/msp430/ctype.py b/src/miasm/arch/msp430/ctype.py
new file mode 100644
index 00000000..0e6562e8
--- /dev/null
+++ b/src/miasm/arch/msp430/ctype.py
@@ -0,0 +1,68 @@
+from miasm.core.objc import CLeafTypes, ObjCDecl, PADDING_TYPE_NAME
+from miasm.core.ctypesmngr import CTypeId, CTypePtr
+
+
+class CTypeMSP430_unk(CLeafTypes):
+    """Define C types sizes/alignment for msp430 architecture"""
+
+    obj_pad = ObjCDecl(PADDING_TYPE_NAME, 1, 1) # __padding__ is size 1/align 1
+
+    obj_char = ObjCDecl("char", 1, 1)
+    obj_short = ObjCDecl("short", 2, 2)
+    obj_int = ObjCDecl("int", 2, 2)
+    obj_long = ObjCDecl("long", 2, 2)
+
+    obj_uchar = ObjCDecl("uchar", 1, 1)
+    obj_ushort = ObjCDecl("ushort", 2, 2)
+    obj_uint = ObjCDecl("uint", 2, 2)
+    obj_ulong = ObjCDecl("ulong", 2, 2)
+
+    obj_void = ObjCDecl("void", 1, 1)
+
+    obj_enum = ObjCDecl("enum", 2, 2)
+
+    obj_float = ObjCDecl("float", 4, 4)
+    obj_double = ObjCDecl("double", 8, 8)
+    obj_ldouble = ObjCDecl("ldouble", 16, 16)
+
+    def __init__(self):
+        self.types = {
+            CTypeId(PADDING_TYPE_NAME): self.obj_pad,
+
+            CTypeId('char'): self.obj_char,
+            CTypeId('short'): self.obj_short,
+            CTypeId('int'): self.obj_int,
+            CTypeId('void'): self.obj_void,
+            CTypeId('long',): self.obj_long,
+            CTypeId('float'): self.obj_float,
+            CTypeId('double'): self.obj_double,
+
+            CTypeId('signed', 'char'): self.obj_char,
+            CTypeId('unsigned', 'char'): self.obj_uchar,
+
+            CTypeId('short', 'int'): self.obj_short,
+            CTypeId('signed', 'short'): self.obj_short,
+            CTypeId('signed', 'short', 'int'): self.obj_short,
+            CTypeId('unsigned', 'short'): self.obj_ushort,
+            CTypeId('unsigned', 'short', 'int'): self.obj_ushort,
+
+            CTypeId('unsigned', ): self.obj_uint,
+            CTypeId('unsigned', 'int'): self.obj_uint,
+            CTypeId('signed', 'int'): self.obj_int,
+
+            CTypeId('long', 'int'): self.obj_long,
+            CTypeId('long', 'long'): self.obj_long,
+            CTypeId('long', 'long', 'int'): self.obj_long,
+            CTypeId('signed', 'long', 'long'): self.obj_long,
+            CTypeId('unsigned', 'long', 'long'): self.obj_ulong,
+            CTypeId('signed', 'long', 'long', 'int'): self.obj_long,
+            CTypeId('unsigned', 'long', 'long', 'int'): self.obj_ulong,
+
+            CTypeId('signed', 'long'): self.obj_long,
+            CTypeId('unsigned', 'long'): self.obj_ulong,
+            CTypeId('signed', 'long', 'int'): self.obj_long,
+            CTypeId('unsigned', 'long', 'int'): self.obj_ulong,
+
+            CTypeId('long', 'double'): self.obj_ldouble,
+            CTypePtr(CTypeId('void')): self.obj_uint,
+        }
diff --git a/src/miasm/arch/msp430/disasm.py b/src/miasm/arch/msp430/disasm.py
new file mode 100644
index 00000000..eff77d2d
--- /dev/null
+++ b/src/miasm/arch/msp430/disasm.py
@@ -0,0 +1,8 @@
+from miasm.core.asmblock import disasmEngine
+from miasm.arch.msp430.arch import mn_msp430
+
+
+class dis_msp430(disasmEngine):
+
+    def __init__(self, bs=None, **kwargs):
+        super(dis_msp430, self).__init__(mn_msp430, None, bs, **kwargs)
diff --git a/src/miasm/arch/msp430/jit.py b/src/miasm/arch/msp430/jit.py
new file mode 100644
index 00000000..ad767588
--- /dev/null
+++ b/src/miasm/arch/msp430/jit.py
@@ -0,0 +1,41 @@
+from miasm.jitter.jitload import Jitter
+from miasm.core.locationdb import LocationDB
+from miasm.core.utils import pck16, upck16
+from miasm.arch.msp430.sem import Lifter_MSP430
+
+import logging
+
+log = logging.getLogger('jit_msp430')
+hnd = logging.StreamHandler()
+hnd.setFormatter(logging.Formatter("[%(levelname)-8s]: %(message)s"))
+log.addHandler(hnd)
+log.setLevel(logging.CRITICAL)
+
+class jitter_msp430(Jitter):
+
+    def __init__(self, loc_db, *args, **kwargs):
+        Jitter.__init__(self, Lifter_MSP430(loc_db), *args, **kwargs)
+        self.vm.set_little_endian()
+
+    def push_uint16_t(self, value):
+        regs = self.cpu.get_gpreg()
+        regs['SP'] -= 2
+        self.cpu.set_gpreg(regs)
+        self.vm.set_mem(regs['SP'], pck16(value))
+
+    def pop_uint16_t(self):
+        regs = self.cpu.get_gpreg()
+        value = self.vm.get_u16(regs['SP'])
+        regs['SP'] += 2
+        self.cpu.set_gpreg(regs)
+        return value
+
+    def get_stack_arg(self, index):
+        regs = self.cpu.get_gpreg()
+        value = self.vm.get_u16(regs['SP'] + 2 * index)
+        return value
+
+    def init_run(self, *args, **kwargs):
+        Jitter.init_run(self, *args, **kwargs)
+        self.cpu.PC = self.pc
+
diff --git a/src/miasm/arch/msp430/lifter_model_call.py b/src/miasm/arch/msp430/lifter_model_call.py
new file mode 100644
index 00000000..05f649e5
--- /dev/null
+++ b/src/miasm/arch/msp430/lifter_model_call.py
@@ -0,0 +1,31 @@
+#-*- coding:utf-8 -*-
+
+from miasm.ir.analysis import LifterModelCall
+from miasm.arch.msp430.sem import Lifter_MSP430
+from miasm.ir.ir import AssignBlock
+from miasm.expression.expression import *
+
+class LifterModelCallMsp430Base(Lifter_MSP430, LifterModelCall):
+
+    def __init__(self, loc_db):
+        Lifter_MSP430.__init__(self, loc_db)
+        self.ret_reg = self.arch.regs.R15
+
+    def call_effects(self, addr, instr):
+        call_assignblk = AssignBlock(
+            [
+                ExprAssign(self.ret_reg, ExprOp('call_func_ret', addr, self.sp, self.arch.regs.R15)),
+                ExprAssign(self.sp, ExprOp('call_func_stack', addr, self.sp))
+            ],
+            instr
+        )
+        return [call_assignblk], []
+
+class LifterModelCallMsp430(LifterModelCallMsp430Base):
+
+    def __init__(self, loc_db):
+        LifterModelCallMsp430Base.__init__(self, loc_db)
+
+    def get_out_regs(self, _):
+        return set([self.ret_reg, self.sp])
+
diff --git a/src/miasm/arch/msp430/regs.py b/src/miasm/arch/msp430/regs.py
new file mode 100644
index 00000000..2bcaa055
--- /dev/null
+++ b/src/miasm/arch/msp430/regs.py
@@ -0,0 +1,116 @@
+from builtins import range
+from miasm.expression.expression import *
+from miasm.core.cpu import reg_info
+
+
+# GP
+
+regs16_str = ["PC", "SP", "SR"] + ["R%d" % i for i in range(3, 16)]
+regs16_expr = [ExprId(x, 16) for x in regs16_str]
+
+exception_flags = ExprId('exception_flags', 32)
+
+gpregs = reg_info(regs16_str, regs16_expr)
+
+PC = regs16_expr[0]
+SP = regs16_expr[1]
+SR = regs16_expr[2]
+R3 = regs16_expr[3]
+R4 = regs16_expr[4]
+R5 = regs16_expr[5]
+R6 = regs16_expr[6]
+R7 = regs16_expr[7]
+R8 = regs16_expr[8]
+R9 = regs16_expr[9]
+R10 = regs16_expr[10]
+R11 = regs16_expr[11]
+R12 = regs16_expr[12]
+R13 = regs16_expr[13]
+R14 = regs16_expr[14]
+R15 = regs16_expr[15]
+
+PC_init = ExprId("PC_init", 16)
+SP_init = ExprId("SP_init", 16)
+SR_init = ExprId("SR_init", 16)
+R3_init = ExprId("R3_init", 16)
+R4_init = ExprId("R4_init", 16)
+R5_init = ExprId("R5_init", 16)
+R6_init = ExprId("R6_init", 16)
+R7_init = ExprId("R7_init", 16)
+R8_init = ExprId("R8_init", 16)
+R9_init = ExprId("R9_init", 16)
+R10_init = ExprId("R10_init", 16)
+R11_init = ExprId("R11_init", 16)
+R12_init = ExprId("R12_init", 16)
+R13_init = ExprId("R13_init", 16)
+R14_init = ExprId("R14_init", 16)
+R15_init = ExprId("R15_init", 16)
+
+
+reg_zf = 'zf'
+reg_nf = 'nf'
+reg_of = 'of'
+reg_cf = 'cf'
+reg_cpuoff = 'cpuoff'
+reg_gie = 'gie'
+reg_osc = 'osc'
+reg_scg0 = 'scg0'
+reg_scg1 = 'scg1'
+reg_res = 'res'
+
+zf = ExprId(reg_zf, size=1)
+nf = ExprId(reg_nf, size=1)
+of = ExprId(reg_of, size=1)
+cf = ExprId(reg_cf, size=1)
+
+cpuoff = ExprId(reg_cpuoff, size=1)
+gie = ExprId(reg_gie, size=1)
+osc = ExprId(reg_osc, size=1)
+scg0 = ExprId(reg_scg0, size=1)
+scg1 = ExprId(reg_scg1, size=1)
+res = ExprId(reg_res, size=7)
+
+
+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)
+
+
+cpuoff_init = ExprId("cpuoff_init", size=1)
+gie_init = ExprId("gie_init", size=1)
+osc_init = ExprId("osc_init", size=1)
+scg0_init = ExprId("scg0_init", size=1)
+scg1_init = ExprId("scg1_init", size=1)
+res_init = ExprId("res_init", size=7)
+
+
+all_regs_ids = [
+    PC, SP, SR, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15,
+    zf, nf, of, cf,
+    cpuoff, gie, osc, scg0, scg1, res,
+]
+
+all_regs_ids_no_alias = all_regs_ids
+
+attrib_to_regs = {
+    'l': all_regs_ids_no_alias,
+    'b': all_regs_ids_no_alias,
+}
+
+all_regs_ids_byname = dict([(x.name, x) for x in all_regs_ids])
+
+all_regs_ids_init = [PC_init, SP_init, SR_init, R3_init,
+                     R4_init, R5_init, R6_init, R7_init,
+                     R8_init, R9_init, R10_init, R11_init,
+                     R12_init, R13_init, R14_init, R15_init,
+                     zf_init, nf_init, of_init, cf_init,
+                     cpuoff_init, gie_init, osc_init,
+                     scg0_init, scg1_init, res_init,
+                     ]
+
+regs_init = {}
+for i, r in enumerate(all_regs_ids):
+    regs_init[r] = all_regs_ids_init[i]
+
+regs_flt_expr = []
diff --git a/src/miasm/arch/msp430/sem.py b/src/miasm/arch/msp430/sem.py
new file mode 100644
index 00000000..d4d3221b
--- /dev/null
+++ b/src/miasm/arch/msp430/sem.py
@@ -0,0 +1,509 @@
+#-*- coding:utf-8 -*-
+
+from miasm.expression.expression import *
+from miasm.arch.msp430.regs import *
+from miasm.arch.msp430.arch import mn_msp430
+from miasm.ir.ir import Lifter
+
+
+# Utils
+def hex2bcd(val):
+    "Return val as BCD"
+    try:
+        return int("%x" % val, 10)
+    except ValueError:
+        raise NotImplementedError("Not defined behaviour")
+
+
+def bcd2hex(val):
+    "Return the hex value of a BCD"
+    try:
+        return int("0x%d" % val, 16)
+    except ValueError:
+        raise NotImplementedError("Not defined behaviour")
+
+
+def reset_sr_res():
+    return [ExprAssign(res, ExprInt(0, 7))]
+
+
+def update_flag_cf_inv_zf(a):
+    return [ExprAssign(cf, ExprCond(a, ExprInt(1, 1), ExprInt(0, 1)))]
+
+
+def update_flag_zf_eq(a, b):
+    return [ExprAssign(zf, ExprOp("FLAG_EQ_CMP", a, b))]
+
+
+def update_flag_zf(a):
+    return [ExprAssign(zf, ExprOp("FLAG_EQ", a))]
+
+
+def update_flag_nf(arg):
+    return [
+        ExprAssign(
+            nf,
+            ExprOp("FLAG_SIGN_SUB", arg, ExprInt(0, arg.size))
+        )
+    ]
+
+
+def update_flag_add_cf(op1, op2, res):
+    "Compute cf in @res = @op1 + @op2"
+    return [ExprAssign(cf, ExprOp("FLAG_ADD_CF", op1, op2))]
+
+
+def update_flag_add_of(op1, op2, res):
+    "Compute of in @res = @op1 + @op2"
+    return [ExprAssign(of, ExprOp("FLAG_ADD_OF", op1, op2))]
+
+
+# checked: ok for sbb add because b & c before +cf
+def update_flag_sub_cf(op1, op2, res):
+    "Compote CF in @op1 - @op2"
+    return [ExprAssign(cf, ExprOp("FLAG_SUB_CF", op1, op2) ^ ExprInt(1, 1))]
+
+
+def update_flag_sub_of(op1, op2, res):
+    "Compote OF in @res = @op1 - @op2"
+    return [ExprAssign(of, ExprOp("FLAG_SUB_OF", op1, op2))]
+
+
+def update_flag_arith_sub_zn(arg1, arg2):
+    """
+    Compute znp flags for (arg1 - arg2)
+    """
+    e = []
+    e += update_flag_zf_eq(arg1, arg2)
+    e += [ExprAssign(nf, ExprOp("FLAG_SIGN_SUB", arg1, arg2))]
+    return e
+
+
+def update_flag_arith_add_zn(arg1, arg2):
+    """
+    Compute zf and nf flags for (arg1 + arg2)
+    """
+    e = []
+    e += update_flag_zf_eq(arg1, -arg2)
+    e += [ExprAssign(nf, ExprOp("FLAG_SIGN_SUB", arg1, -arg2))]
+    return e
+
+
+
+def mng_autoinc(a, b, size):
+    e = []
+    if not (isinstance(a, ExprOp) and a.op == "autoinc"):
+        return e, a, b
+
+    a_r = a.args[0]
+    e.append(ExprAssign(a_r, a_r + ExprInt(size // 8, a_r.size)))
+    a = ExprMem(a_r, size)
+    if isinstance(b, ExprMem) and a_r in b.arg:
+        b = ExprMem(b.arg + ExprInt(size // 8, 16), b.size)
+    return e, a, b
+
+# Mnemonics
+
+
+def mov_b(ir, instr, a, b):
+    e, a, b = mng_autoinc(a, b, 8)
+    if isinstance(b, ExprMem):
+        b = ExprMem(b.arg, 8)
+        a = a[:8]
+    else:
+        a = a[:8].zeroExtend(16)
+    e.append(ExprAssign(b, a))
+    return e, []
+
+
+def mov_w(ir, instr, a, b):
+    e, a, b = mng_autoinc(a, b, 16)
+    e.append(ExprAssign(b, a))
+    if b == ir.pc:
+        e.append(ExprAssign(ir.IRDst, a))
+    return e, []
+
+
+def and_b(ir, instr, a, b):
+    e, arg1, arg2 = mng_autoinc(a, b, 8)
+    arg1, arg2 = arg1[:8], arg2[:8]
+    res = arg1 & arg2
+    e.append(ExprAssign(b, res.zeroExtend(16)))
+
+    e += [ExprAssign(zf, ExprOp('FLAG_EQ_AND', arg1, arg2))]
+    e += [ExprAssign(nf, ExprOp("FLAG_SIGN_SUB", res, ExprInt(0, res.size)))]
+    e += reset_sr_res()
+    e += update_flag_cf_inv_zf(res)
+    e += [ExprAssign(of, ExprInt(0, 1))]
+
+    return e, []
+
+
+def and_w(ir, instr, a, b):
+    e, arg1, arg2 = mng_autoinc(a, b, 16)
+    res = arg1 & arg2
+    e.append(ExprAssign(arg2, res))
+
+    e += [ExprAssign(zf, ExprOp('FLAG_EQ_AND', arg1, arg2))]
+    e += [ExprAssign(nf, ExprOp("FLAG_SIGN_SUB", res, ExprInt(0, res.size)))]
+    e += reset_sr_res()
+    e += update_flag_cf_inv_zf(res)
+    e += [ExprAssign(of, ExprInt(0, 1))]
+
+    return e, []
+
+
+def bic_b(ir, instr, a, b):
+    e, a, b = mng_autoinc(a, b, 8)
+    c = (a[:8] ^ ExprInt(0xff, 8)) & b[:8]
+    c = c.zeroExtend(b.size)
+    e.append(ExprAssign(b, c))
+    return e, []
+
+
+def bic_w(ir, instr, a, b):
+    e, a, b = mng_autoinc(a, b, 16)
+    if b == SR:
+        # Special case
+        if a.is_int(1):
+            # cf
+            e.append(ExprAssign(cf, ExprInt(0, 1)))
+            return e, []
+    c = (a ^ ExprInt(0xffff, 16)) & b
+    e.append(ExprAssign(b, c))
+    return e, []
+
+
+def bis_w(ir, instr, a, b):
+    e, a, b = mng_autoinc(a, b, 16)
+    c = a | b
+    e.append(ExprAssign(b, c))
+    return e, []
+
+
+def bit_w(ir, instr, a, b):
+    e, arg1, arg2 = mng_autoinc(a, b, 16)
+    res = arg1 & arg2
+
+    e += [ExprAssign(zf, ExprOp('FLAG_EQ_AND', arg1, arg2))]
+    e += [ExprAssign(nf, ExprOp("FLAG_SIGN_SUB", res, ExprInt(0, res.size)))]
+    e += reset_sr_res()
+    e += update_flag_cf_inv_zf(res)
+    e += [ExprAssign(of, ExprInt(0, 1))]
+
+    return e, []
+
+
+def sub_w(ir, instr, a, b):
+    e, arg1, arg2 = mng_autoinc(a, b, 16)
+    res = arg2 - arg1
+
+    e.append(ExprAssign(b, res))
+
+    e += update_flag_arith_sub_zn(arg2, arg1)
+    e += update_flag_sub_cf(arg2, arg1, res)
+    e += update_flag_sub_of(arg2, arg1, res)
+    e += reset_sr_res()
+
+    # micrcorruption
+    # e += update_flag_sub_of(a, b, c)
+    # e += update_flag_sub_of(b, a, c)
+    return e, []
+
+
+def add_b(ir, instr, a, b):
+    e, arg1, arg2 = mng_autoinc(a, b, 8)
+    if isinstance(arg2, ExprMem):
+        arg2 = ExprMem(arg2.arg, 8)
+    else:
+        arg2 = arg2[:8]
+    arg1 = arg1[:8]
+    res = arg2 + arg1
+    e.append(ExprAssign(b, res))
+
+    e += update_flag_arith_add_zn(arg2, arg1)
+    e += update_flag_add_cf(arg2, arg1, res)
+    e += update_flag_add_of(arg2, arg1, res)
+    e += reset_sr_res()
+
+    return e, []
+
+
+def add_w(ir, instr, a, b):
+    e, arg1, arg2 = mng_autoinc(a, b, 16)
+    res = arg2 + arg1
+    e.append(ExprAssign(b, res))
+
+    e += update_flag_arith_add_zn(arg2, arg1)
+    e += update_flag_add_cf(arg2, arg1, res)
+    e += update_flag_add_of(arg2, arg1, res)
+    e += reset_sr_res()
+
+    return e, []
+
+
+def dadd_w(ir, instr, a, b):
+    e, a, b = mng_autoinc(a, b, 16)
+    # TODO: microcorruption no carryflag
+    c = ExprOp("bcdadd", b, a)  # +zeroExtend(cf, 16))
+
+    e.append(ExprAssign(b, c))
+
+    # micrcorruption
+    e += update_flag_zf(a)
+    # e += update_flag_nf(a)
+    e += reset_sr_res()
+
+    e.append(ExprAssign(cf, ExprOp("bcdadd_cf", b, a)))  # +zeroExtend(cf, 16))))
+
+    # of : undefined
+    return e, []
+
+
+def xor_w(ir, instr, a, b):
+    e, arg1, arg2 = mng_autoinc(a, b, 16)
+    res = arg2 ^ arg1
+    e.append(ExprAssign(b, res))
+
+    e += [ExprAssign(zf, ExprOp('FLAG_EQ_CMP', arg2, arg1))]
+    e += update_flag_nf(res)
+    e += reset_sr_res()
+    e += update_flag_cf_inv_zf(res)
+    e.append(ExprAssign(of, arg2.msb() & arg1.msb()))
+
+    return e, []
+
+
+def push_w(ir, instr, a):
+    e = []
+    e.append(ExprAssign(ExprMem(SP - ExprInt(2, 16), 16), a))
+    e.append(ExprAssign(SP, SP - ExprInt(2, 16)))
+    return e, []
+
+
+def call(ir, instr, a):
+    e, a, dummy = mng_autoinc(a, None, 16)
+
+    loc_next = ir.get_next_loc_key(instr)
+    loc_next_expr = ExprLoc(loc_next, 16)
+
+    e.append(ExprAssign(ExprMem(SP - ExprInt(2, 16), 16), loc_next_expr))
+    e.append(ExprAssign(SP, SP - ExprInt(2, 16)))
+    e.append(ExprAssign(PC, a))
+    e.append(ExprAssign(ir.IRDst, a))
+    return e, []
+
+
+def swpb(ir, instr, a):
+    e = []
+    x, y = a[:8], a[8:16]
+    e.append(ExprAssign(a, ExprCompose(y, x)))
+    return e, []
+
+
+def cmp_w(ir, instr, a, b):
+    e, arg1, arg2 = mng_autoinc(a, b, 16)
+    res = arg2 - arg1
+
+    e += update_flag_arith_sub_zn(arg2, arg1)
+    e += update_flag_sub_cf(arg2, arg1, res)
+    e += update_flag_sub_of(arg2, arg1, res)
+    e += reset_sr_res()
+
+    return e, []
+
+
+def cmp_b(ir, instr, a, b):
+    e, arg1, arg2 = mng_autoinc(a, b, 8)
+    arg1, arg2 = arg1[:8], arg2[:8]
+    res = arg2 - arg1
+
+    e += update_flag_arith_sub_zn(arg2, arg1)
+    e += update_flag_sub_cf(arg2, arg1, res)
+    e += update_flag_sub_of(arg2, arg1, res)
+    e += reset_sr_res()
+
+    return e, []
+
+
+def jz(ir, instr, a):
+    loc_next = ir.get_next_loc_key(instr)
+    loc_next_expr = ExprLoc(loc_next, 16)
+    e = []
+    e.append(ExprAssign(PC, ExprCond(ExprOp("CC_EQ", zf), a, loc_next_expr)))
+    e.append(ExprAssign(ir.IRDst, ExprCond(ExprOp("CC_EQ", zf), a, loc_next_expr)))
+    return e, []
+
+
+def jnz(ir, instr, a):
+    loc_next = ir.get_next_loc_key(instr)
+    loc_next_expr = ExprLoc(loc_next, 16)
+    e = []
+    e.append(ExprAssign(PC, ExprCond(ExprOp("CC_EQ", zf), loc_next_expr, a)))
+    e.append(ExprAssign(ir.IRDst, ExprCond(ExprOp("CC_EQ", zf), loc_next_expr, a)))
+    return e, []
+
+
+def jl(ir, instr, a):
+    loc_next = ir.get_next_loc_key(instr)
+    loc_next_expr = ExprLoc(loc_next, 16)
+    e = []
+    e.append(ExprAssign(PC, ExprCond(ExprOp("CC_S<", nf, of), a, loc_next_expr)))
+    e.append(ExprAssign(ir.IRDst, ExprCond(ExprOp("CC_S<", nf, of), a, loc_next_expr)))
+    return e, []
+
+
+def jc(ir, instr, a):
+    loc_next = ir.get_next_loc_key(instr)
+    loc_next_expr = ExprLoc(loc_next, 16)
+    e = []
+    e.append(ExprAssign(PC, ExprCond(ExprOp("CC_U>=", cf ^ ExprInt(1, 1)), a, loc_next_expr)))
+    e.append(ExprAssign(ir.IRDst, ExprCond(ExprOp("CC_U>=", cf ^ ExprInt(1, 1)), a, loc_next_expr)))
+    return e, []
+
+
+def jnc(ir, instr, a):
+    loc_next = ir.get_next_loc_key(instr)
+    loc_next_expr = ExprLoc(loc_next, 16)
+    e = []
+    e.append(ExprAssign(PC, ExprCond(ExprOp("CC_U>=", cf ^ ExprInt(1, 1)), loc_next_expr, a)))
+    e.append(ExprAssign(ir.IRDst, ExprCond(ExprOp("CC_U>=", cf ^ ExprInt(1, 1)), loc_next_expr, a)))
+    return e, []
+
+
+def jge(ir, instr, a):
+    loc_next = ir.get_next_loc_key(instr)
+    loc_next_expr = ExprLoc(loc_next, 16)
+    e = []
+    e.append(ExprAssign(PC, ExprCond(ExprOp("CC_S>=", nf, of), a, loc_next_expr)))
+    e.append(ExprAssign(ir.IRDst, ExprCond(ExprOp("CC_S>=", nf, of), a, loc_next_expr)))
+    return e, []
+
+
+def jmp(ir, instr, a):
+    e = []
+    e.append(ExprAssign(PC, a))
+    e.append(ExprAssign(ir.IRDst, a))
+    return e, []
+
+
+def rrc_w(ir, instr, a):
+    e = []
+    c = ExprCompose(a[1:16], cf)
+    e.append(ExprAssign(a, c))
+    e.append(ExprAssign(cf, a[:1]))
+
+    # micrcorruption
+    e += update_flag_zf(a)
+    # e += update_flag_nf(a)
+    e += reset_sr_res()
+
+    e.append(ExprAssign(of, ExprInt(0, 1)))
+    return e, []
+
+
+def rra_w(ir, instr, a):
+    e = []
+    c = ExprCompose(a[1:16], a[15:16])
+    e.append(ExprAssign(a, c))
+    # TODO: error in disasm microcorruption?
+    # e.append(ExprAssign(cf, a[:1]))
+
+    # micrcorruption
+    e += update_flag_zf(a)
+    # e += update_flag_nf(a)
+    e += reset_sr_res()
+
+    e.append(ExprAssign(of, ExprInt(0, 1)))
+    return e, []
+
+
+def sxt(ir, instr, a):
+    e = []
+    c = a[:8].signExtend(16)
+    e.append(ExprAssign(a, c))
+
+    e += update_flag_zf(a)
+    e += update_flag_nf(a)
+    e += reset_sr_res()
+    e += update_flag_cf_inv_zf(c)
+    e.append(ExprAssign(of, ExprInt(0, 1)))
+
+    return e, []
+
+mnemo_func = {
+    "mov.b": mov_b,
+    "mov.w": mov_w,
+    "and.b": and_b,
+    "and.w": and_w,
+    "bic.b": bic_b,
+    "bic.w": bic_w,
+    "bis.w": bis_w,
+    "bit.w": bit_w,
+    "sub.w": sub_w,
+    "add.b": add_b,
+    "add.w": add_w,
+    "push.w": push_w,
+    "dadd.w": dadd_w,
+    "xor.w": xor_w,
+    "call": call,
+    "swpb": swpb,
+    "cmp.w": cmp_w,
+    "cmp.b": cmp_b,
+    "jz": jz,
+    "jnz": jnz,
+    "jl": jl,
+    "jc": jc,
+    "jnc": jnc,
+    "jmp": jmp,
+    "jge": jge,
+    "rrc.w": rrc_w,
+    "rra.w": rra_w,
+    "sxt": sxt,
+}
+
+
+composed_sr = ExprCompose(cf, zf, nf, gie, cpuoff, osc, scg0, scg1, of, res)
+
+
+def ComposeExprAssign(dst, src):
+    e = []
+    for start, arg in dst.iter_args():
+        e.append(ExprAssign(arg, src[start:start+arg.size]))
+    return e
+
+
+class Lifter_MSP430(Lifter):
+
+    def __init__(self, loc_db):
+        Lifter.__init__(self, mn_msp430, None, loc_db)
+        self.pc = PC
+        self.sp = SP
+        self.IRDst = ExprId('IRDst', 16)
+        self.addrsize = 16
+
+    def mod_pc(self, instr, instr_ir, extra_ir):
+        pass
+
+    def get_ir(self, instr):
+        args = instr.args
+        instr_ir, extra_ir = mnemo_func[instr.name](self, instr, *args)
+        self.mod_sr(instr, instr_ir, extra_ir)
+
+        return instr_ir, extra_ir
+
+    def mod_sr(self, instr, instr_ir, extra_ir):
+        for i, x in enumerate(instr_ir):
+            x = ExprAssign(x.dst, x.src.replace_expr({SR: composed_sr}))
+            instr_ir[i] = x
+            if x.dst != SR:
+                continue
+            xx = ComposeExprAssign(composed_sr, x.src)
+            instr_ir[i:i+1] = xx
+        for i, x in enumerate(instr_ir):
+            x = ExprAssign(x.dst, x.src.replace_expr(
+                {self.pc: ExprInt(instr.offset + instr.l, 16)}))
+            instr_ir[i] = x
+
+        if extra_ir:
+            raise NotImplementedError('not fully functional')
diff --git a/src/miasm/arch/ppc/__init__.py b/src/miasm/arch/ppc/__init__.py
new file mode 100644
index 00000000..bbad893b
--- /dev/null
+++ b/src/miasm/arch/ppc/__init__.py
@@ -0,0 +1 @@
+__all__ = ["arch", "disasm", "regs", "sem"]
diff --git a/src/miasm/arch/ppc/arch.py b/src/miasm/arch/ppc/arch.py
new file mode 100644
index 00000000..a1bde2a6
--- /dev/null
+++ b/src/miasm/arch/ppc/arch.py
@@ -0,0 +1,826 @@
+from builtins import range
+
+import logging
+from pyparsing import *
+from miasm.expression.expression import *
+from miasm.core.cpu import *
+from collections import defaultdict
+from miasm.core.bin_stream import bin_stream
+import miasm.arch.ppc.regs as regs_module
+from miasm.arch.ppc.regs import *
+from miasm.core.asm_ast import AstInt, AstId, AstMem, AstOp
+from miasm.ir.ir import color_expr_html
+
+log = logging.getLogger("ppcdis")
+console_handler = logging.StreamHandler()
+console_handler.setFormatter(logging.Formatter("[%(levelname)-8s]: %(message)s"))
+log.addHandler(console_handler)
+log.setLevel(logging.DEBUG)
+
+LPARENTHESIS = Suppress(Literal("("))
+RPARENTHESIS = Suppress(Literal(")"))
+
+def cb_deref_imm_reg(tokens):
+    if len(tokens) == 1:
+        return AstMem(tokens[0], 32)
+    elif len(tokens) == 2:
+        return AstMem(tokens[1] + tokens[0], 32)
+    else:
+        raise NotImplementedError('len(tokens) > 2')
+
+
+deref_reg_disp = (Optional(base_expr) + LPARENTHESIS + gpregs.parser +  RPARENTHESIS).setParseAction(cb_deref_imm_reg)
+deref_reg = (LPARENTHESIS + gpregs.parser +  RPARENTHESIS).setParseAction(cb_deref_imm_reg)
+
+deref = deref_reg | deref_reg_disp
+
+
+class ppc_arg(m_arg):
+    def asm_ast_to_expr(self, arg, loc_db):
+        if isinstance(arg, AstId):
+            if isinstance(arg.name, ExprId):
+                return arg.name
+            if arg.name in gpregs.str:
+                return None
+            loc_key = loc_db.get_or_create_name_location(arg.name)
+            return ExprLoc(loc_key, 32)
+        if isinstance(arg, AstOp):
+            args = [self.asm_ast_to_expr(tmp, loc_db) for tmp in arg.args]
+            if None in args:
+                return None
+            return ExprOp(arg.op, *args)
+        if isinstance(arg, AstInt):
+            return ExprInt(arg.value, 32)
+        if isinstance(arg, AstMem):
+            ptr = self.asm_ast_to_expr(arg.ptr, loc_db)
+            if ptr is None:
+                return None
+            return ExprMem(ptr, arg.size)
+        return None
+
+
+class additional_info(object):
+
+    def __init__(self):
+        self.except_on_instr = False
+        self.bo_bi_are_defined = False
+        self.bi = 0
+        self.bo = 0
+
+
+class instruction_ppc(instruction):
+
+    def __init__(self, *args, **kargs):
+        super(instruction_ppc, self).__init__(*args, **kargs)
+
+    @staticmethod
+    def arg2str(e, pos = None, loc_db=None):
+        if isinstance(e, ExprId) or isinstance(e, ExprInt):
+            return str(e)
+        elif isinstance(e, ExprMem):
+            addr = e.ptr
+            if isinstance(addr, ExprInt) or isinstance(addr, ExprId):
+                out = '(%s)'%addr
+            elif isinstance(addr, ExprOp):
+                if len(addr.args) == 1:
+                    out = '(%s)'%addr
+                elif len(addr.args) == 2:
+                    out = '%s(%s)'%(addr.args[1], addr.args[0])
+                else:
+                    raise NotImplementedError('More than two args to ExprOp of address')
+            else:
+                raise NotImplementedError('Invalid memory expression')
+            return out
+
+        return str(e)
+
+
+    @staticmethod
+    def arg2html(e, pos = None, loc_db=None):
+        if isinstance(e, ExprId) or isinstance(e, ExprInt) or isinstance(e, ExprLoc):
+            return color_expr_html(e, loc_db)
+        elif isinstance(e, ExprMem):
+            addr = e.ptr
+            if isinstance(addr, ExprInt) or isinstance(addr, ExprId):
+                out = '(%s)'%color_expr_html(addr, loc_db)
+            elif isinstance(addr, ExprOp):
+                if len(addr.args) == 1:
+                    out = '(%s)'%color_expr_html(addr, loc_db)
+                elif len(addr.args) == 2:
+                    out = '%s(%s)'%(color_expr_html(addr.args[1], loc_db), color_expr_html(addr.args[0], loc_db))
+                else:
+                    raise NotImplementedError('More than two args to ExprOp of address')
+            else:
+                raise NotImplementedError('Invalid memory expression')
+            return out
+
+        return color_expr_html(e, loc_db)
+
+    @staticmethod
+    def is_conditional_jump(s):
+        return (s[0] == 'B' and
+                s[1:3] in { 'DN', 'DZ', 'LT', 'GT', 'EQ', 'SO',
+                            'GE', 'LE', 'NE', 'NS' })
+
+    def dstflow(self):
+        name = self.name
+        if name[-1] == '+' or name[-1] == '-':
+            name = name[:-1]
+        return (name[0] == 'B' and
+                name[-2:] != 'LR' and
+                name[-3:] != 'LRL' and
+                name[-3:] != 'CTR' and
+                name[-4:] != 'CTRL')
+
+    def dstflow2label(self, loc_db):
+        name = self.name
+        if name[-1] == '+' or name[-1] == '-':
+            name = name[:-1]
+
+        if name[-1] == 'L':
+            name = name[:-1]
+        elif name[-2:] == 'LA':
+            name = name[:-2] + 'A'
+
+        if name[-2:] != 'LR' and name[-3:] != 'CTR':
+            if len(self.args) == 2:
+                address_index = 1
+            else:
+                address_index = 0
+            e = self.args[address_index]
+            if not isinstance(e, ExprInt):
+                return
+            if name[-1] != 'A':
+                ad = (int(e) + self.offset) & 0xFFFFFFFF
+            else:
+                ad = int(e)
+            loc_key = loc_db.get_or_create_offset_location(ad)
+            s = ExprLoc(loc_key, e.size)
+            self.args[address_index] = s
+
+    def breakflow(self):
+        return self.name[0] == 'B'
+
+    def is_subcall(self):
+        name = self.name
+        if name[-1] == '+' or name[-1] == '-':
+            name = name[0:-1]
+        return name[0] == 'B' and (name[-1] == 'L' or name[-2:-1] == 'LA')
+
+    def getdstflow(self, loc_db):
+        if 'LR' in self.name:
+            return [ LR ]
+        elif 'CTR' in self.name:
+            return [ CTR ]
+        elif len(self.args) == 2:
+            address_index = 1
+        else:
+            address_index = 0
+        return [ self.args[address_index] ]
+
+    def splitflow(self):
+        ret = False
+        if self.is_conditional_jump(self.name):
+            if self.additional_info.bo & 0b10100 != 0b10100:
+                ret = True
+        ret = ret or self.is_subcall()
+        return ret
+
+    def get_symbol_size(self, symbol, loc_db):
+        return 32
+
+    def fixDstOffset(self):
+        e = self.args[0]
+        if not isinstance(e, ExprInt):
+            log.debug('Dynamic destination offset %r' % e)
+            return
+        if self.name[-1] != 'A':
+            if self.offset is None:
+                raise ValueError('symbol not resolved %s' % self.l)
+            off = (int(e) + 0x100000000 - (self.offset + self.l)) & 0xFFFFFFFF
+            if int(off % 4):
+                raise ValueError('Offset %r must be a multiple of four' % off)
+        else:
+            off = int(e)
+        self.args[0] = ExprInt(off, 32)
+
+    def get_args_expr(self):
+        args = [a for a in self.args]
+        return args
+
+    def get_asm_offset(self, x):
+        return ExprInt_from(x, self.offset)
+
+
+class mn_ppc(cls_mn):
+    delayslot = 0
+    name = "ppc32"
+    regs = regs_module
+    bintree = {}
+    num = 0
+    all_mn = []
+    all_mn_mode = defaultdict(list)
+    all_mn_name = defaultdict(list)
+    all_mn_inst = defaultdict(list)
+    instruction = instruction_ppc
+    max_instruction_len = 4
+
+    @classmethod
+    def getpc(cls, attrib = None):
+        return PC
+
+    @classmethod
+    def getsp(cls, attrib = None):
+        return R1
+
+    def additional_info(self):
+        info = additional_info()
+        info.bo_bi_are_defined = False
+        if hasattr(self, "bo"):
+            info.bo_bi_are_defined = True
+            info.bi = int(self.bi.strbits, 2)
+            info.bo = int(self.bo.strbits, 2)
+        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 enough 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 == "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])
+        return fields
+
+    @classmethod
+    def gen_modes(cls, subcls, name, bases, dct, fields):
+        dct['mode'] = None
+        return [(subcls, name, bases, dct, fields)]
+
+    def post_dis(self):
+        return self
+
+    def value(self, mode):
+        v = super(mn_ppc, self).value(mode)
+        if mode == 'b':
+            return [x for x in v]
+        else:
+            raise NotImplementedError("bad attrib")
+
+    def get_symbol_size(self, symbol, loc_db, mode):
+        return 32
+
+
+class ppc_reg(reg_noarg, ppc_arg):
+    pass
+
+
+class ppc_gpreg_noarg(reg_noarg):
+    reg_info = gpregs
+    parser = reg_info.parser
+
+class ppc_gpreg_or_0_noarg(reg_noarg):
+    reg_info = gpregs
+    parser = reg_info.parser
+
+    def decode(self, v):
+        ret = super(ppc_gpreg_or_0_noarg, self).decode(v)
+        if ret == False:
+            return False
+        reg = self.expr
+        if reg == R0:
+            self.expr = ExprInt(0, 32)
+        return ret
+
+class ppc_gpreg(ppc_reg):
+    reg_info = gpregs
+    parser = reg_info.parser
+
+class ppc_gpreg_or_0(ppc_reg):
+    reg_info = gpregs
+    parser = reg_info.parser
+
+    def decode(self, v):
+        ret = super(ppc_gpreg_or_0, self).decode(v)
+        if ret == False:
+            return False
+        reg = self.expr
+        if reg == R0:
+            self.expr = ExprInt(0, 32)
+        return ret
+
+class ppc_crfreg_noarg(reg_noarg):
+    reg_info = crfregs
+    parser = reg_info.parser
+
+class ppc_crfreg(ppc_reg):
+    reg_info = crfregs
+    parser = reg_info.parser
+
+class ppc_imm(imm_noarg, ppc_arg):
+    parser = base_expr
+
+class ppc_s14imm_branch(ppc_imm):
+
+    def decode(self, v):
+        v = sign_ext(v << 2, 16, 32)
+        self.expr = ExprInt(v, 32)
+        return True
+
+    def encode(self):
+        if not isinstance(self.expr, ExprInt):
+            return False
+        v = int(self.expr)
+        if v & 0x3:
+            return False
+        v = v >> 2
+        if sign_ext(v & self.lmask, 14, 32) != v:
+            return False
+        self.value = v & self.lmask
+        return True
+
+class ppc_s24imm_branch(ppc_imm):
+
+    def decode(self, v):
+        v = sign_ext(v << 2, 26, 32)
+        self.expr = ExprInt(v, 32)
+        return True
+
+    def encode(self):
+        if not isinstance(self.expr, ExprInt):
+            return False
+        v = int(self.expr)
+        if v & 0x3:
+            return False
+        v = v >> 2
+        if sign_ext(v & self.lmask, 24, 32) != v:
+            return False
+        self.value = v & self.lmask
+        return True
+
+class ppc_s16imm(ppc_imm):
+
+    def decode(self, v):
+        v = sign_ext(v, 16, 32)
+        self.expr = ExprInt(v, 32)
+        return True
+
+    def encode(self):
+        if not isinstance(self.expr, ExprInt):
+            return False
+        v = int(self.expr)
+        if sign_ext(v & self.lmask, 16, 32) != v:
+            return False
+        self.value = v & self.lmask
+        return True
+
+class ppc_u16imm(ppc_imm):
+
+    def decode(self, v):
+        if v & self.lmask != v:
+            return False
+        self.expr = ExprInt(v, 32)
+        return True
+
+    def encode(self):
+        if not isinstance(self.expr, ExprInt):
+            return False
+        v = int(self.expr)
+        if v & self.lmask != v:
+            return False
+        self.value = v & self.lmask
+        return True
+
+def ppc_swap_10(v):
+    return ((v & 0b11111) << 5) | ((v & 0b1111100000) >> 5)
+
+class ppc_spr(ppc_imm):
+
+    def decode(self, v):
+        self.expr = ExprInt(ppc_swap_10(v), 32)
+        return True
+
+    def encode(self, e):
+        if not isinstance(e, ExprInt):
+            return False
+        self.value = ppc_swap_10(int(e))
+        return True
+
+class ppc_tbr(ppc_imm):
+
+    def decode(self, v):
+        self.expr = ExprInt(ppc_swap_10(v), 32)
+        return True
+
+    def encode(self, e):
+        if not isinstance(e, ExprInt):
+            return False
+        self.value = ppc_swap_10(int(e))
+        return True
+
+class ppc_u08imm(ppc_u16imm):
+    pass
+
+class ppc_u05imm(ppc_u16imm):
+    pass
+
+class ppc_u04imm(ppc_u16imm):
+    pass
+
+class ppc_u02imm_noarg(imm_noarg):
+    pass
+
+class ppc_float(ppc_reg):
+    reg_info = floatregs
+    parser = reg_info.parser
+
+class ppc_vex(ppc_reg):
+    reg_info = vexregs
+    parser = reg_info.parser
+
+def ppc_bo_bi_to_mnemo(bo, bi, prefer_taken=True, default_taken=True):
+    bo2mnemo = { 0: 'DNZF', 2: 'DZF', 4: 'F', 8: 'DNZT',
+                 10: 'DZT', 12: 'T', 16: 'DNZ', 18: 'DZ',
+                 20: '' }
+    bi2cond = { 0b00: 'LT', 0b01: 'GT', 0b10: 'EQ', 0b11: 'SO' }
+    bi2ncond = { 0b00: 'GE', 0b01: 'LE', 0b10: 'NE', 0b11: 'NS' }
+    n = bo & 0b11110
+    if not n in bo2mnemo:
+        raise NotImplementedError("Unknown BO field")
+    mnem = 'B' + bo2mnemo[n]
+    if mnem[-1] == 'T':
+        mnem = mnem[:-1] + bi2cond[bi & 0b11]
+    if mnem[-1] == 'F':
+        mnem = mnem[:-1] + bi2ncond[bi & 0b11]
+
+    if prefer_taken != default_taken:
+        if prefer_taken:
+            mnem += '+'
+        else:
+            mnem += '-'
+
+    return mnem
+
+def ppc_all_bo_bi():
+    for bo in [0, 2, 4, 8, 10, 12, 16, 18, 20]:
+        for bi in range(4):
+            yield bo, bi
+
+class ppc_divert_conditional_branch(bs_divert):
+    prio=3
+    def divert(self, i, candidates):
+        out = []
+        for cls, _, bases, dct, fields in candidates:
+            bi_i = getfieldindexby_name(fields, 'bi')[1]
+            bo_i = getfieldindexby_name(fields, 'bo')[1]
+
+            for bo, bi in ppc_all_bo_bi():
+                nfields = fields[:]
+                nfields[bi_i] = bs(int2bin(bi, 2), fname="bi")
+                nfields[bo_i] = bs(int2bin(bo, 5), fname="bo")
+                ndct = dict(dct)
+                ndct['name'] = ppc_bo_bi_to_mnemo(bo, bi)
+                out.append((cls, ndct['name'], bases, ndct, nfields))
+
+                nfields = fields[:]
+                nfields[bi_i] = bs(int2bin(bi, 2), fname="bi")
+                nfields[bo_i] = bs(int2bin(bo+1, 5), fname="bo")
+                ndct = dict(dct)
+                ndct['name'] = ppc_bo_bi_to_mnemo(bo, bi)
+                out.append((cls, ndct['name'], bases, ndct, nfields))
+
+        return out
+
+class ppc_deref32(ppc_arg):
+    parser = deref
+
+    def decode(self, v):
+        v = sign_ext(v, 16, 32)
+        e = self.parent.ra.expr + ExprInt(v, 32)
+        self.expr = ExprMem(e, size=32)
+        return True
+
+    def encode(self):
+        e = self.expr
+        if not isinstance(e, ExprMem):
+            return False
+        addr = e.ptr
+        if isinstance(addr, ExprId) or isinstance(addr, ExprInt):
+            addr = addr + ExprInt(0, 32)
+        elif not isinstance(addr, ExprOp):
+            return False
+        if addr.op != '+':
+            return False
+        if len(addr.args) != 2:
+            return False
+        reg, disp = addr.args[0], addr.args[1]
+        v = int(disp)
+        if sign_ext(v & 0xFFFF, 16, 32) != v:
+            return False
+        v &= 0xFFFF
+        self.value = v
+        self.parent.ra.expr = reg
+        return True
+
+
+def ppcop(name, fields, args=None, alias=False):
+    dct = {"fields": fields}
+    dct["alias"] = alias
+    if args is not None:
+        dct['args'] = args
+    type(name, (mn_ppc,), dct)
+
+rd = bs(l=5, cls=(ppc_gpreg,))
+ra = bs(l=5, cls=(ppc_gpreg,))
+ra_or_0 = bs(l=5, cls=(ppc_gpreg_or_0,))
+rb = bs(l=5, cls=(ppc_gpreg,))
+rs = bs(l=5, cls=(ppc_gpreg,))
+crfd = bs(l=3, cls=(ppc_crfreg,))
+crfs = bs(l=3, cls=(ppc_crfreg,))
+sh = bs(l=5, cls=(ppc_u05imm,))
+mb = bs(l=5, cls=(ppc_u05imm,))
+me = bs(l=5, cls=(ppc_u05imm,))
+nb = bs(l=5, cls=(ppc_u05imm,))
+crm = bs(l=8, cls=(ppc_u08imm,))
+sr = bs(l=4, cls=(ppc_u04imm,))
+spr = bs(l=10, cls=(ppc_spr,))
+tbr = bs(l=10, cls=(ppc_tbr,))
+u05imm = bs(l=5, cls=(ppc_u05imm,))
+
+s24imm_branch = bs(l=24, cls=(ppc_s24imm_branch,), fname="imm")
+s14imm_branch = bs(l=14, cls=(ppc_s14imm_branch,), fname="imm")
+s16imm = bs(l=16, cls=(ppc_s16imm,), fname="imm")
+u16imm = bs(l=16, cls=(ppc_u16imm,), fname="imm")
+u08imm = bs(l=5, cls=(ppc_u08imm,), fname="imm")
+u02imm_noarg = bs(l=2, cls=(ppc_u02imm_noarg,), fname="imm")
+
+ra_noarg = bs(l=5, cls=(ppc_gpreg_noarg,), fname="ra")
+ra_or_0_noarg = bs(l=5, cls=(ppc_gpreg_or_0_noarg,), fname="ra")
+dregimm = bs(l=16, cls=(ppc_deref32,))
+
+rc_mod = bs_mod_name(l=1, mn_mod=['', '.'], fname='rc')
+
+frd = bs(l=5, cls=(ppc_float,))
+frb = bs(l=5, cls=(ppc_float,))
+frs = bs(l=5, cls=(ppc_float,))
+fm = bs(l=8, cls=(ppc_u08imm,))
+
+va = bs(l=5, cls=(ppc_vex,))
+vb = bs(l=5, cls=(ppc_vex,))
+vd = bs(l=5, cls=(ppc_vex,))
+rb_noarg = bs(l=5, cls=(ppc_gpreg_noarg,), fname="rb")
+
+arith1_name = {"MULLI": 0b000111, "SUBFIC": 0b001000, "ADDIC": 0b001100,
+               "ADDIC.": 0b001101 }
+
+logic2_name = {"ORI": 0b011000, "XORI": 0b011010, "ANDI.": 0b011100 }
+slogic2_name = {"ORIS": 0b011001, "XORIS": 0b011011, "ANDIS.": 0b011101 }
+
+arith3_name = {"SUBFC": 0b0000001000, "ADDC": 0b0000001010,
+               "MULHWU": 0b0000001011, "SUBF": 0b0000101000,
+               "MULHW": 0b0001001011, "SUBFE": 0b0010001000,
+               "ADDE": 0b0010001010, "MULLW": 0b0011101011,
+               "ADD": 0b0100001010, "DIVWU": 0b0111001011,
+               "DIVW": 0b0111101011, "SUBFCO": 0b1000001000,
+               "ADDCO": 0b1000001010, "SUBFO": 0b1000101000,
+               "SUBFEO": 0b1010001000, "ADDEO": 0b1010001010,
+               "MULLWO": 0b1011101011, "ADDO": 0b1100001010,
+               "DIVWUO": 0b1111001011, "DIVWO": 0b1111101011 }
+
+xor_name = { "EQV": 0b0100011100, "XOR": 0b0100111100 }
+
+arith4_name = {"NEG": 0b0001101000, "SUBFZE": 0b0011001000,
+               "ADDZE": 0b0011001010, "SUBFME": 0b0011101000,
+               "ADDME": 0b0011101010, "NEGO": 0b1001101000,
+               "SUBFZEO": 0b1011001000, "ADDZEO": 0b1011001010,
+               "SUBFMEO": 0b1011101000, "ADDMEO": 0b1011101010 }
+
+arith5_name = {"CNTLZW": 0b00000, "EXTSH": 0b11100, "EXTSB": 0b11101 }
+
+crlogic_name = {"CRAND": 0b1000, "CRANDC": 0b0100, "CREQV": 0b1001,
+                "CRNAND": 0b0111, "CRNOR": 0b0001, "CROR": 0b1110,
+                "CRORC": 0b1101, "CRXOR": 0b0110 }
+
+rotins_name = {"RLWIMI": 0b010100, "RLWINM": 0b010101 }
+
+bs_arith1_name = bs_name(l=6, name=arith1_name)
+
+load1_name = {"LWARX": 0b0000010100, "LWZX": 0b0000010111,
+              "LBZX": 0b0001010111, "LHZX": 0b0100010111,
+              "ECIWX": 0b0100110110, "LHAX": 0b0101010111,
+              "LSWX": 0b1000010101, "LWBRX": 0b1000010110,
+              "LHBRX": 0b1100010110 }
+
+load1_name_u = {"LWZUX": 0b0000110111, "LBZUX": 0b0001110111,
+                "LHZUX": 0b0100110111, "LHAUX": 0b0101110111 }
+
+load2_name = {"LWZ": 0b0000, "LBZ": 0b0010, "LHZ": 0b1000, "LHA": 0b1010,
+              "LMW": 0b1110 }
+
+load2_name_u = {"LWZU": 0b0001, "LBZU": 0b0011, "LHZU": 0b1001, "LHAU": 0b1011}
+
+store1_name = { "STWCX.": 0b00100101101, "STWX": 0b00100101110,
+                "STBX": 0b00110101110, "STHX": 0b01100101110,
+                "ECOWX": 0b01101101100, "STSWX": 0b10100101010,
+                "STWBRX": 0b10100101100, "STHBRX": 0b11100101100 }
+store1_name_u = { "STWUX": 0b00101101110, "STBUX": 0b00111101110,
+                  "STHUX": 0b01101101110 }
+
+store2_name = { "STW": 0b0100, "STB": 0b0110, "STH": 0b1100, "STMW": 0b1111 }
+store2_name_u = { "STWU": 0b0101, "STBU": 0b0111, "STHU": 0b1101 }
+
+logic1_name = {"SLW": 0b0000011000, "AND": 0b0000011100,
+               "ANDC": 0b0000111100, "NOR": 0b0001111100,
+               "ORC": 0b0110011100, "OR": 0b0110111100,
+               "NAND": 0b0111011100, "SRW": 0b1000011000,
+               "SRAW": 0b1100011000 }
+
+dcb_name = {"DCBST": 0b00001, "DCBF": 0b00010,
+            "DCBTST": 0b00111, "DCBT": 0b01000,
+            "DCBI": 0b01110, "DCBA": 0b10111,
+            "ICBI": 0b11110, "DCBZ": 0b11111 }
+
+
+load1_name_float = {"LFS": 0b110000, "LFD": 0b110010 }
+load1_name_float_u = {"LFSU": 0b110001, "LFDU": 0b110011 }
+store1_name_float = {"STFS": 0b110100, "STFD": 0b110110 }
+store1_name_float_u = {"STFSU": 0b110101, "STFDU": 0b110111 }
+
+load1_name_vex = {"LVEBX": 0b0000000111, "LVEHX": 0b0000100111,
+                  "LVEWX": 0b0001000111, "LVSL": 0b0000000110,
+                  "LVSR": 0b0000100110, "LVX": 0b0001100111,
+                  "LVXL": 0b0101100111 }
+
+class bs_mod_name_prio4(bs_mod_name):
+    prio = 4
+
+class bs_mod_name_prio5(bs_mod_name):
+    prio = 5
+
+class bs_mod_name_prio6(bs_mod_name):
+    prio = 6
+
+branch_to_reg = bs_mod_name_prio4(l=1, mn_mod=['LR', 'CTR'], fname='btoreg')
+branch_lk = bs_mod_name_prio5(l=1, mn_mod=['', 'L'], fname='lk')
+branch_aa = bs_mod_name_prio6(l=1, mn_mod=['', 'A'], fname='aa')
+
+ppcop("arith1", [bs_arith1_name, rd, ra, s16imm])
+ppcop("ADDIS", [bs('001111'), rd, ra_or_0, u16imm])
+ppcop("ADDI", [bs('001110'), rd, ra_or_0, s16imm])
+
+ppcop("logic2", [bs_name(l=6, name=logic2_name), rs, ra, u16imm],
+      [ra, rs, u16imm])
+ppcop("slogic2", [bs_name(l=6, name=slogic2_name), rs, ra, u16imm],
+      [ra, rs, u16imm])
+
+ppcop("store1", [bs('011111'), rs, ra_or_0, rb,
+                 bs_name(l=11, name=store1_name)])
+ppcop("store1u", [bs('011111'), rs, ra, rb,
+                  bs_name(l=11, name=store1_name_u)])
+
+ppcop("store2", [bs('10'), bs_name(l=4, name=store2_name), rs,
+                    ra_noarg, dregimm])
+ppcop("store2u", [bs('10'), bs_name(l=4, name=store2_name_u), rs,
+                    ra_or_0_noarg, dregimm])
+
+ppcop("arith3", [bs('011111'), rd, ra, rb, bs_name(l=10, name=arith3_name),
+                 rc_mod])
+
+ppcop("xor", [bs('011111'), rs, ra, rb, bs_name(l=10, name=xor_name),
+                 rc_mod], [ra, rs, rb])
+
+ppcop("arith4", [bs('011111'), rd, ra, bs('00000'),
+                 bs_name(l=10, name=arith4_name), rc_mod])
+
+ppcop("arith5", [bs('011111'), rs, ra, bs('00000'),
+                 bs_name(l=5, name=arith5_name),
+                 bs('11010'), rc_mod], [ra, rs])
+
+ppcop("load1", [bs('011111'), rd, ra_or_0, rb,
+                bs_name(l=10, name=load1_name), bs('0')])
+ppcop("load1u", [bs('011111'), rd, ra, rb,
+                 bs_name(l=10, name=load1_name_u), bs('0')])
+ppcop("load2", [bs('10'), bs_name(l=4, name=load2_name),
+                rd, ra_or_0_noarg, dregimm])
+ppcop("load2u", [bs('10'), bs_name(l=4, name=load2_name_u),
+                 rd, ra_noarg, dregimm])
+
+ppcop("logic1", [bs('011111'), rs, ra, rb, bs_name(l=10, name=logic1_name),
+                 rc_mod],
+      [ra, rs, rb])
+
+ppcop("TWI", [bs('000011'), u05imm, ra, s16imm])
+ppcop("TW", [bs('011111'), u05imm, ra, rb, bs('00000001000')])
+
+ppcop("CMPW", [bs('011111'), crfd, bs('00'), ra, rb, bs('00000000000')])
+ppcop("CMPLW", [bs('011111'), crfd, bs('00'), ra, rb, bs('00001000000')])
+ppcop("CMPLWI", [bs('001010'), crfd, bs('00'), ra, u16imm])
+ppcop("CMPWI", [bs('001011'), crfd, bs('00'), ra, s16imm])
+
+ppcop("BC", [bs('010000'), bs(l=5, cls=(ppc_u05imm,), fname='bo'),
+             crfs,
+             ppc_divert_conditional_branch(l=2, fname='bi'),
+             s14imm_branch, branch_aa, branch_lk])
+ppcop("SC", [bs('01000100000000000000000000000010')])
+ppcop("B", [bs('010010'), s24imm_branch, branch_aa, branch_lk])
+ppcop("MCRF", [bs('010011'), crfd, bs('00'), crfs, bs('000000000000000000')])
+
+ppcop("BCXXX", [bs('010011'), bs(l=5, cls=(ppc_u05imm,), fname='bo'),
+                crfs,
+                ppc_divert_conditional_branch(l=2, fname='bi'),
+                bs('00000'), branch_to_reg,
+                bs('000010000'), branch_lk])
+
+ppcop("crlogic", [bs('010011'),
+                  bs(l=5, cls=(ppc_u05imm,), fname='crbd'),
+                  bs(l=5, cls=(ppc_u05imm,), fname='crba'),
+                  bs(l=5, cls=(ppc_u05imm,), fname='crbb'),
+                  bs('0'),
+                  bs_name(l=4, name=crlogic_name),
+                  bs('000010')])
+
+ppcop("rotins", [bs_name(l=6, name=rotins_name),
+                 rs, ra, sh, mb, me, rc_mod],
+      [ ra, rs, sh, mb, me ])
+ppcop("RLWNM", [bs('010111'), rs, ra, rb, mb, me, rc_mod],
+      [ ra, rs, rb, mb, me ])
+ppcop("MFXXX", [bs('011111'), rd, bs('0000000000'),
+                bs('000'),
+                bs_name(l=1, name={'MFCR':0, 'MFMSR':1}),
+                bs('0100110')])
+
+ppcop("dcb", [bs('01111100000'), ra, rb, bs_name(l=5, name=dcb_name),
+              bs('101100')])
+
+ppcop("MTCRF", [bs('011111'), rs, bs('0'), crm, bs('000100100000')], [crm, rs])
+ppcop("MTMSR", [bs('011111'), rs, bs('0000000000'), bs('00100100100')])
+ppcop("MTSR", [bs('011111'), rs, bs('0'), sr, bs('0000000110100100')], [sr, rs])
+ppcop("MTSRIN", [bs('011111'), rs, bs('00000'), rb, bs('00111100100')])
+
+ppcop("TLBIE", [bs('011111'), bs('0000000000'), rb, bs('01001100100')])
+ppcop("MFSPR", [bs('011111'), rd, spr, bs('01010100110')])
+ppcop("TLBIA", [bs('01111100000000000000001011100100')])
+ppcop("MFTB", [bs('011111'), rd, tbr, bs('01011100110')])
+ppcop("RFI", [bs('01001100000000000000000001100100')])
+ppcop("ISYNC", [bs('01001100000000000000000100101100')])
+ppcop("MTSPR", [bs('011111'), rs, spr, bs('01110100110')], [spr, rs])
+ppcop("MCRXR", [bs('011111'), crfd, bs('000000000000'),
+                bs('10000000000')])
+ppcop("TLBSYNC", [bs('01111100000000000000010001101100')])
+ppcop("MFSR", [bs('011111'), rd, bs('0'), sr, bs('00000'), bs('10010100110')])
+ppcop("LSWI", [bs('011111'), rd, ra, nb, bs('10010101010')])
+ppcop("STSWI", [bs('011111'), rs, ra, nb, bs('10110101010')])
+ppcop("SYNC", [bs('011111'), bs('000000000000000'), bs('10010101100')])
+ppcop("MFSRIN", [bs('011111'), rd, bs('00000'), rb, bs('10100100110')])
+
+ppcop("SRAWI", [bs('011111'), rs, ra, sh, bs('1100111000'), rc_mod],
+      [ra, rs, sh])
+
+ppcop("EIEIO", [bs('011111'), bs('000000000000000'), bs('11010101100')])
+
+ppcop("load1f", [bs_name(l=6, name=load1_name_float), frd, ra_noarg, dregimm])
+ppcop("load1fu", [bs_name(l=6, name=load1_name_float_u), frd, ra_noarg, dregimm])
+ppcop("store1f", [bs_name(l=6, name=store1_name_float), frd, ra_noarg, dregimm])
+ppcop("store1fu", [bs_name(l=6, name=store1_name_float_u), frd, ra_noarg, dregimm])
+ppcop("MTFSF", [bs('111111'), bs('0'), fm, bs('0'), frb, bs('10110001110')])
+ppcop("MTFSF.", [bs('111111'), bs('0'), fm, bs('0'), frb, bs('10110001111')])
+ppcop("MFFS", [bs('111111'), frd, bs('00000000001001000111'), bs('0')])
+ppcop("MFFS.", [bs('111111'), frd, bs('00000000001001000111'), bs('1')])
+
+ppcop("load1vex", [bs('011111'), vd, ra, rb, bs_name(l=10, name=load1_name_vex), bs('0')])
+ppcop("mtvscr", [bs('0001000000000000'), vb, bs('11001000100')])
diff --git a/src/miasm/arch/ppc/disasm.py b/src/miasm/arch/ppc/disasm.py
new file mode 100644
index 00000000..b91d96bf
--- /dev/null
+++ b/src/miasm/arch/ppc/disasm.py
@@ -0,0 +1,7 @@
+from miasm.arch.ppc.arch import mn_ppc
+from miasm.core.asmblock import disasmEngine
+
+class dis_ppc32b(disasmEngine):
+    def __init__(self, bs=None, **kwargs):
+        super(dis_ppc32b, self).__init__(mn_ppc, None, bs, **kwargs)
+        self.attrib = 'b'
diff --git a/src/miasm/arch/ppc/jit.py b/src/miasm/arch/ppc/jit.py
new file mode 100644
index 00000000..dcaff82c
--- /dev/null
+++ b/src/miasm/arch/ppc/jit.py
@@ -0,0 +1,70 @@
+from builtins import range
+from miasm.jitter.jitload import Jitter, named_arguments
+from miasm.arch.ppc.sem import Lifter_PPC32b
+import struct
+
+import logging
+
+log = logging.getLogger('jit_ppc')
+hnd = logging.StreamHandler()
+hnd.setFormatter(logging.Formatter("[%(levelname)-8s]: %(message)s"))
+log.addHandler(hnd)
+log.setLevel(logging.CRITICAL)
+
+class jitter_ppc32b(Jitter):
+    max_reg_arg = 8
+
+    def __init__(self, loc_db, *args, **kwargs):
+        super(jitter_ppc32b, self).__init__(Lifter_PPC32b(loc_db),
+                                            *args, **kwargs)
+        self.vm.set_big_endian()
+
+    def push_uint32_t(self, v):
+        self.cpu.R1 -= 4
+        self.vm.set_mem(self.cpu.R1, struct.pack(">I", v))
+
+    def pop_uint32_t(self):
+        x = struct.unpack(">I", self.vm.get_mem(self.cpu.R1, 4))[0]
+        self.cpu.R1 += 4
+        return x
+
+    def get_stack_arg(self, n):
+        x = struct.unpack(">I", self.vm.get_mem(self.cpu.R1 + 8 + 4 * n, 4))[0]
+        return x
+
+    @named_arguments
+    def func_args_systemv(self, n_args):
+        args = [self.get_arg_n_systemv(i) for i in range(n_args)]
+        ret_ad = self.cpu.LR
+        return ret_ad, args
+
+    def func_ret_systemv(self, ret_addr, ret_value1=None, ret_value2=None):
+        self.pc = self.cpu.PC = ret_addr
+        if ret_value1 is not None:
+            self.cpu.R3 = ret_value1
+        if ret_value2 is not None:
+            self.cpu.R4 = ret_value2
+        return True
+
+    def func_prepare_systemv(self, ret_addr, *args):
+        for index in range(min(len(args), self.max_reg_arg)):
+            setattr(self.cpu, 'R%d' % (index + 3), args[index])
+        for index in range(len(args) - 1, self.max_reg_arg - 1, -1):
+            self.push_uint32_t(args[index])
+
+        # reserve room for LR save word and backchain
+        self.cpu.R1 -= 8
+
+        self.cpu.LR = ret_addr
+
+    def get_arg_n_systemv(self, index):
+        if index < self.max_reg_arg:
+            arg = getattr(self.cpu, 'R%d' % (index + 3))
+        else:
+            arg = self.get_stack_arg(index - self.max_reg_arg)
+        return arg
+
+
+    def init_run(self, *args, **kwargs):
+        Jitter.init_run(self, *args, **kwargs)
+        self.cpu.PC = self.pc
diff --git a/src/miasm/arch/ppc/lifter_model_call.py b/src/miasm/arch/ppc/lifter_model_call.py
new file mode 100644
index 00000000..06691190
--- /dev/null
+++ b/src/miasm/arch/ppc/lifter_model_call.py
@@ -0,0 +1,87 @@
+from miasm.expression.expression import ExprAssign, ExprOp
+from miasm.ir.ir import AssignBlock
+from miasm.ir.analysis import LifterModelCall
+from miasm.arch.ppc.sem import Lifter_PPC32b
+
+
+class LifterModelCallPpc32b(Lifter_PPC32b, LifterModelCall):
+
+    def __init__(self, loc_db, *args):
+        super(LifterModelCallPpc32b, self).__init__(loc_db, *args)
+        self.ret_reg = self.arch.regs.R3
+
+    # for test XXX TODO
+    def set_dead_regs(self, irblock):
+        pass
+
+    def get_out_regs(self, _):
+        return set([self.ret_reg, self.sp])
+
+    def add_unused_regs(self):
+        leaves = [self.blocks[label] for label in self.g.leafs()]
+        for irblock in leaves:
+            self.set_dead_regs(irblock)
+
+    def call_effects(self, ad, instr):
+        call_assignblks = AssignBlock(
+            [
+                ExprAssign(
+                    self.ret_reg,
+                    ExprOp(
+                        'call_func_ret',
+                        ad,
+                        self.sp,
+                        self.arch.regs.R3,
+                        self.arch.regs.R4,
+                        self.arch.regs.R5,
+                    )
+                ),
+                ExprAssign(self.sp, ExprOp('call_func_stack', ad, self.sp)),
+            ],
+            instr
+        )
+        return [call_assignblks], []
+
+    def add_instr_to_current_state(self, instr, block, assignments, ir_blocks_all, gen_pc_updt):
+        """
+        Add the IR effects of an instruction to the current state.
+
+        @instr: native instruction
+        @block: native block source
+        @assignments: list of current AssignBlocks
+        @ir_blocks_all: list of additional effects
+        @gen_pc_updt: insert PC update effects between instructions
+        """
+        if instr.is_subcall():
+            call_assignblks, extra_irblocks = self.call_effects(
+                instr.getdstflow(None)[0],
+                instr
+            )
+            assignments += call_assignblks
+            ir_blocks_all += extra_irblocks
+            return True
+
+        if gen_pc_updt is not False:
+            self.gen_pc_update(assignments, instr)
+
+        assignblk, ir_blocks_extra = self.instr2ir(instr)
+        assignments.append(assignblk)
+        ir_blocks_all += ir_blocks_extra
+        if ir_blocks_extra:
+            return True
+        return False
+
+    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
diff --git a/src/miasm/arch/ppc/regs.py b/src/miasm/arch/ppc/regs.py
new file mode 100644
index 00000000..00781d6a
--- /dev/null
+++ b/src/miasm/arch/ppc/regs.py
@@ -0,0 +1,77 @@
+
+from builtins import range
+from miasm.expression.expression import *
+from miasm.core.cpu import gen_reg, gen_regs
+
+exception_flags = ExprId('exception_flags', 32)
+spr_access = ExprId('spr_access', 32)
+
+reserve = ExprId('reserve', 1)
+reserve_address = ExprId('reserve_address', 32)
+
+SPR_ACCESS_IS_WRITE = 0x80000000
+SPR_ACCESS_SPR_MASK = 0x000003FF
+SPR_ACCESS_SPR_OFF  = 0
+SPR_ACCESS_GPR_MASK = 0x0001F000
+SPR_ACCESS_GPR_OFF  = 12
+
+gpregs_str = ["R%d" % i for i in range(32)]
+gpregs_expr, gpregs_init, gpregs = gen_regs(gpregs_str, globals(), 32)
+
+crfregs_str = ["CR%d" % i for i in range(8)]
+crfregs_expr, crfregs_init, crfregs = gen_regs(crfregs_str, globals(), 4)
+
+crfbitregs_str = ["CR%d_%s" % (i, flag) for i in range(8)
+                  for flag in ['LT', 'GT', 'EQ', 'SO'] ]
+crfbitregs_expr, crfbitregs_init, crfbitregs = gen_regs(crfbitregs_str,
+                                                        globals(), 1)
+
+xerbitregs_str = ["XER_%s" % field for field in ['SO', 'OV', 'CA'] ]
+xerbitregs_expr, xerbitregs_init, xerbitregs = gen_regs(xerbitregs_str,
+                                                        globals(), 1)
+
+xerbcreg_str = ["XER_BC"]
+xerbcreg_expr, xerbcreg_init, xerbcreg = gen_regs(xerbcreg_str,
+                                                  globals(), 7)
+
+
+otherregs_str = ["PC", "CTR", "LR", "FPSCR", "VRSAVE", "VSCR" ]
+otherregs_expr, otherregs_init, otherregs = gen_regs(otherregs_str,
+                                                     globals(), 32)
+
+superregs_str = (["SPRG%d" % i for i in range(4)] +
+                 ["SRR%d" % i for i in range(2)] +
+                 ["DAR", "DSISR", "MSR", "PIR", "PVR",
+                  "DEC", "TBL", "TBU"])
+superregs_expr, superregs_init, superregs = gen_regs(superregs_str,
+                                                     globals(), 32)
+
+mmuregs_str = (["SR%d" % i for i in range(16)] +
+               ["IBAT%dU" % i for i in range(4)] +
+               ["IBAT%dL" % i for i in range(4)] +
+               ["DBAT%dU" % i for i in range(4)] +
+               ["DBAT%dL" % i for i in range(4)] +
+               ["SDR1"])
+mmuregs_expr, mmuregs_init, mmuregs = gen_regs(mmuregs_str,
+                                               globals(), 32)
+
+floatregs_str = (["FPR%d" % i for i in range(32)])
+floatregs_expr, floatregs_init, floatregs = gen_regs(floatregs_str,
+                                                     globals(), 64)
+
+vexregs_str = (["VR%d" % i for i in range(32)])
+vexregs_expr, vexregs_init, vexregs = gen_regs(vexregs_str,
+                                              globals(), 128)
+
+regs_flt_expr = []
+
+all_regs_ids = (gpregs_expr + crfbitregs_expr + xerbitregs_expr +
+                xerbcreg_expr + otherregs_expr + superregs_expr + mmuregs_expr + floatregs_expr + vexregs_expr +
+                [ exception_flags, spr_access, reserve, reserve_address ])
+all_regs_ids_byname = dict([(x.name, x) for x in all_regs_ids])
+all_regs_ids_init = [ExprId("%s_init" % x.name, x.size) for x in all_regs_ids]
+all_regs_ids_no_alias = all_regs_ids[:]
+
+regs_init = {}
+for i, r in enumerate(all_regs_ids):
+    regs_init[r] = all_regs_ids_init[i]
diff --git a/src/miasm/arch/ppc/sem.py b/src/miasm/arch/ppc/sem.py
new file mode 100644
index 00000000..7fbf61e6
--- /dev/null
+++ b/src/miasm/arch/ppc/sem.py
@@ -0,0 +1,981 @@
+from __future__ import print_function
+from builtins import range
+
+import miasm.expression.expression as expr
+from miasm.ir.ir import AssignBlock, Lifter, IRBlock
+from miasm.arch.ppc.arch import mn_ppc
+from miasm.arch.ppc.regs import *
+from miasm.core.sembuilder import SemBuilder
+from miasm.jitter.csts import *
+
+spr_dict = {
+    8: LR, 9: CTR, 18: DSISR, 19: DAR,
+    22: DEC, 25: SDR1, 26: SRR0, 27: SRR1,
+    272: SPRG0, 273: SPRG0, 274: SPRG1, 275: SPRG2, 276: SPRG3,
+    284: TBL, 285: TBU, 287: PVR,
+    528: IBAT0U, 529: IBAT0L, 530: IBAT1U, 531: IBAT1L, 532: IBAT2U, 533: IBAT2L, 534: IBAT3U, 535: IBAT3L,
+    536: DBAT0U, 537: DBAT0L, 538: DBAT1U, 539: DBAT1L, 540: DBAT2U, 541: DBAT2L, 542: DBAT3U, 543: DBAT3L,
+    1023: PIR
+}
+
+sr_dict = {
+    0: SR0, 1: SR1, 2: SR2, 3: SR3,
+    4: SR4, 5: SR5, 6: SR6, 7: SR7,
+    8: SR8, 9: SR9, 10: SR10, 11: SR11,
+    12: SR12, 13: SR13, 14: SR14, 15: SR15
+}
+
+float_dict = {
+    0: FPR0, 1: FPR1, 2: FPR2, 3: FPR3, 4: FPR4, 5: FPR5, 6: FPR6, 7: FPR7, 8: FPR8,
+    9: FPR9, 10: FPR10, 11: FPR11, 12: FPR12, 13: FPR13, 14: FPR14, 15: FPR15, 16: FPR16,
+    17: FPR17, 18: FPR18, 19: FPR19, 20: FPR20, 21: FPR21, 22: FPR22, 23: FPR23, 24: FPR24,
+    25: FPR25, 26: FPR26, 27: FPR27, 28: FPR28, 29: FPR29, 30: FPR30, 31: FPR31
+}
+
+vex_dict = {
+    0: VR0, 1: VR1, 2: VR2, 3: VR3, 4: VR4, 5: VR5, 6: VR6, 7: VR7, 8: VR8,
+    9: VR9, 10: VR10, 11: VR11, 12: VR12, 13: VR13, 14: VR14, 15: VR15, 16: VR16,
+    17: VR17, 18: VR18, 19: VR19, 20: VR20, 21: VR21, 22: VR22, 23: VR23, 24: VR24,
+    25: VR25, 26: VR26, 27: VR27, 28: VR28, 29: VR29, 30: VR30, 31: VR31,
+}
+
+crf_dict = dict((ExprId("CR%d" % i, 4),
+                 dict( (bit, ExprId("CR%d_%s" % (i, bit), 1))
+                       for bit in ['LT', 'GT', 'EQ', 'SO' ] ))
+                for i in range(8) )
+
+ctx = {
+    'crf_dict': crf_dict,
+    'spr_dict': spr_dict,
+    'sr_dict': sr_dict,
+    'float_dict': float_dict,
+    'vex_dict': vex_dict,
+    'expr': expr,
+}
+
+ctx.update(all_regs_ids_byname)
+sbuild = SemBuilder(ctx)
+
+def mn_compute_flags(rvalue, overflow_expr=None):
+    ret = []
+    ret.append(ExprAssign(CR0_LT, rvalue.msb()))
+    ret.append(ExprAssign(CR0_GT, (ExprCond(rvalue, ExprInt(1, 1),
+                                         ExprInt(0, 1)) & ~rvalue.msb())))
+    ret.append(ExprAssign(CR0_EQ, ExprCond(rvalue, ExprInt(0, 1),
+                                        ExprInt(1, 1))))
+    if overflow_expr != None:
+        ret.append(ExprAssign(CR0_SO, XER_SO | overflow_expr))
+    else:
+        ret.append(ExprAssign(CR0_SO, XER_SO))
+
+    return ret
+
+def mn_do_add(ir, instr, arg1, arg2, arg3):
+    assert instr.name[0:3] == 'ADD'
+
+    flags_update = []
+
+    has_dot = False
+    has_c = False
+    has_e = False
+    has_o = False
+
+    for l in instr.name[3:]:
+        if l == '.':
+            has_dot = True
+        elif l == 'C':
+            has_c = True
+        elif l == 'E':
+            has_e = True
+        elif l == 'O':
+            has_o = True
+        elif l == 'I' or l == 'M' or l == 'S' or l == 'Z':
+            pass	# Taken care of earlier
+        else:
+            assert False
+
+    rvalue = arg2 + arg3
+
+    if has_e:
+        rvalue = rvalue + XER_CA.zeroExtend(32)
+
+    over_expr = None
+    if has_o:
+        msb1 = arg2.msb()
+        msb2 = arg3.msb()
+        msba = rvalue.msb()
+        over_expr = ~(msb1 ^ msb2) & (msb1 ^ msba)
+        flags_update.append(ExprAssign(XER_OV, over_expr))
+        flags_update.append(ExprAssign(XER_SO, XER_SO | over_expr))
+
+    if has_dot:
+        flags_update += mn_compute_flags(rvalue, over_expr)
+
+    if has_c or has_e:
+        carry_expr = (((arg2 ^ arg3) ^ rvalue) ^
+                      ((arg2 ^ rvalue) & (~(arg2 ^ arg3)))).msb()
+        flags_update.append(ExprAssign(XER_CA, carry_expr))
+
+    return ([ ExprAssign(arg1, rvalue) ] + flags_update), []
+
+def mn_do_and(ir, instr, ra, rs, arg2):
+    if len(instr.name) > 3 and instr.name[3] == 'C':
+        oarg = ~arg2
+    else:
+        oarg = arg2
+
+    rvalue = rs & oarg
+    ret = [ ExprAssign(ra, rvalue) ]
+
+    if instr.name[-1] == '.':
+        ret += mn_compute_flags(rvalue)
+
+    return ret, []
+
+def mn_do_cntlzw(ir, instr, ra, rs):
+    ret = [ ExprAssign(ra, ExprOp('cntleadzeros', rs)) ]
+
+    if instr.name[-1] == '.':
+        ret += mn_compute_flags(rvalue)
+
+    return ret, []
+
+def crbit_to_reg(bit):
+    bit = int(bit)
+    crid = bit // 4
+    bitname = [ 'LT', 'GT', 'EQ', 'SO' ][bit % 4]
+    return all_regs_ids_byname["CR%d_%s" % (crid, bitname)]
+
+def mn_do_cr(ir, instr, crd, cra, crb):
+    a = crbit_to_reg(cra)
+    b = crbit_to_reg(crb)
+    d = crbit_to_reg(crd)
+
+    op = instr.name[2:]
+
+    if op == 'AND':
+        r = a & b
+    elif op == 'ANDC':
+        r = a & ~b
+    elif op == 'EQV':
+        r = ~(a ^ b)
+    elif op == 'NAND':
+        r = ~(a & b)
+    elif op == 'NOR':
+        r = ~(a | b)
+    elif op == 'OR':
+        r = a | b
+    elif op == 'ORC':
+        r = a | ~b
+    elif op == 'XOR':
+        r = a ^ b
+    else:
+        raise RuntimeError("Unknown operation on CR")
+    return [ ExprAssign(d, r) ], []
+
+def mn_do_div(ir, instr, rd, ra, rb):
+    assert instr.name[0:4] == 'DIVW'
+
+    flags_update = []
+
+    has_dot = False
+    has_c = False
+    has_o = False
+    has_u = False
+
+    for l in instr.name[3:]:
+        if l == '.':
+            has_dot = True
+        elif l == 'C':
+            has_c = True
+        elif l == 'O':
+            has_o = True
+        elif l == 'U':
+            has_u = True
+        elif l == 'W':
+            pass
+        else:
+            assert False
+
+    if has_u:
+        op = 'udiv'
+    else:
+        op = 'sdiv'
+
+    rvalue = ExprOp(op, ra, rb)
+
+    over_expr = None
+    if has_o:
+        over_expr = ExprCond(rb, ExprInt(0, 1), ExprInt(1, 1))
+        if not has_u:
+            over_expr = over_expr | (ExprCond(ra ^ 0x80000000, ExprInt(0, 1),
+                                              ExprInt(1, 1)) &
+                                     ExprCond(rb ^ 0xFFFFFFFF, ExprInt(0, 1),
+                                              ExprInt(1, 1)))
+        flags_update.append(ExprAssign(XER_OV, over_expr))
+        flags_update.append(ExprAssign(XER_SO, XER_SO | over_expr))
+
+    if has_dot:
+        flags_update += mn_compute_flags(rvalue, over_expr)
+
+    return ([ ExprAssign(rd, rvalue) ] + flags_update), []
+
+
+def mn_do_eqv(ir, instr, ra, rs, rb):
+    rvalue = ~(rs ^ rb)
+    ret = [ ExprAssign(ra, rvalue) ]
+
+    if instr.name[-1] == '.':
+        ret += mn_compute_flags(rvalue)
+
+    return ret, []
+
+def mn_do_exts(ir, instr, ra, rs):
+    if instr.name[4] == 'B':
+        size = 8
+    elif instr.name[4] == 'H':
+        size = 16
+    else:
+        assert False
+
+    rvalue = rs[0:size].signExtend(32)
+    ret = [ ExprAssign(ra, rvalue) ]
+
+    if instr.name[-1] == '.':
+        ret += mn_compute_flags(rvalue)
+
+    return ret, []
+
+def byte_swap(expr):
+    nbytes = expr.size // 8
+    lbytes = [ expr[i*8:i*8+8] for i in range(nbytes - 1, -1, -1) ]
+    return ExprCompose(*lbytes)
+
+def mn_do_load(ir, instr, arg1, arg2, arg3=None):
+    assert instr.name[0] == 'L'
+
+    ret = []
+
+    if instr.name[1] == 'M':
+        return mn_do_lmw(ir, instr, arg1, arg2)
+    elif instr.name[1] == 'S':
+        raise RuntimeError("LSWI, and LSWX need implementing")
+    elif instr.name[1] == 'F':
+        print("Warning, instruction %s implemented as NOP" % instr)
+        return  [], []
+    elif instr.name[1] == 'V':
+        print("Warning, instruction %s implemented as NOP" % instr)
+        return [], []
+
+    size = {'B': 8, 'H': 16, 'W': 32}[instr.name[1]]
+
+    has_a = False
+    has_b = False
+    has_u = False
+    is_lwarx = False
+
+    for l in instr.name[2:]:
+        if l == 'A':
+            has_a = True
+        elif l == 'B':
+            has_b = True
+        elif l == 'U':
+            has_u = True
+        elif l == 'X' or l == 'Z':
+            pass	# Taken care of earlier
+        elif l == 'R' and not has_b:
+            is_lwarx = True
+        else:
+            assert False
+
+    if arg3 is None:
+        assert isinstance(arg2, ExprMem)
+
+        address = arg2.ptr
+    else:
+        address = arg2 + arg3
+
+    src = ExprMem(address, size)
+
+    if has_b:
+        src = byte_swap(src)
+
+    if has_a:
+        src = src.signExtend(32)
+    else:
+        src = src.zeroExtend(32)
+
+    ret.append(ExprAssign(arg1, src))
+    if has_u:
+        if arg3 is None:
+            ret.append(ExprAssign(arg2.ptr.args[0], address))
+        else:
+            ret.append(ExprAssign(arg2, address))
+
+    if is_lwarx:
+        ret.append(ExprAssign(reserve, ExprInt(1, 1)))
+        ret.append(ExprAssign(reserve_address, address))	# XXX should be the PA
+
+    return ret, []
+
+def mn_do_lmw(ir, instr, rd, src):
+    ret = []
+    address = src.ptr
+    ri = int(rd.name[1:],10)
+    i = 0
+    while ri <= 31:
+        ret.append(ExprAssign(all_regs_ids_byname["R%d" % ri],
+                           ExprMem(address + ExprInt(i, 32), 32)))
+        ri += 1
+        i += 4
+
+    return ret, []
+
+def mn_do_lswi(ir, instr, rd, ra, nb):
+    if nb == 0:
+        nb = 32
+    i = 32
+    raise RuntimeError("%r not implemented" % instr)
+
+def mn_do_lswx(ir, instr, rd, ra, nb):
+    raise RuntimeError("%r not implemented" % instr)
+
+def mn_do_mcrf(ir, instr, crfd, crfs):
+    ret = []
+
+    for bit in [ 'LT', 'GT', 'EQ', 'SO' ]:
+        d = all_regs_ids_byname["%s_%s" % (crfd, bit)]
+        s = all_regs_ids_byname["%s_%s" % (crfs, bit)]
+        ret.append(ExprAssign(d, s))
+
+    return ret, []
+
+def mn_do_mcrxr(ir, instr, crfd):
+    ret = []
+
+    for (bit, val) in [ ('LT', XER_SO), ('GT', XER_OV), ('EQ', XER_CA),
+                        ('SO', ExprInt(0, 1)) ]:
+        ret.append(ExprAssign(all_regs_ids_byname["%s_%s" % (crfd, bit)], val))
+
+    return ret, []
+
+def mn_do_mfcr(ir, instr, rd):
+    return ([ ExprAssign(rd, ExprCompose(*[ all_regs_ids_byname["CR%d_%s" % (i, b)]
+                                        for i in range(7, -1, -1)
+                                        for b in ['SO', 'EQ', 'GT', 'LT']]))],
+            [])
+
+@sbuild.parse
+def mn_mfmsr(rd):
+    rd = MSR
+
+def mn_mfspr(ir, instr, arg1, arg2):
+    sprid = int(arg2)
+    gprid = int(arg1.name[1:])
+    if sprid in spr_dict:
+        return [ ExprAssign(arg1, spr_dict[sprid]) ], []
+    elif sprid == 1:		# XER
+        return [ ExprAssign(arg1, ExprCompose(XER_BC, ExprInt(0, 22),
+                                           XER_CA, XER_OV, XER_SO)) ], []
+    else:
+        return [ ExprAssign(spr_access,
+                         ExprInt(((sprid << SPR_ACCESS_SPR_OFF) |
+                                    (gprid << SPR_ACCESS_GPR_OFF)), 32)),
+                 ExprAssign(exception_flags, ExprInt(EXCEPT_SPR_ACCESS, 32)) ], []
+
+def mn_mtcrf(ir, instr, crm, rs):
+    ret = []
+
+    for i in range(8):
+        if int(crm) & (1 << (7 - i)):
+            j = (28 - 4 * i) + 3
+            for b in ['LT', 'GT', 'EQ', 'SO']:
+                ret.append(ExprAssign(all_regs_ids_byname["CR%d_%s" % (i, b)],
+                                   rs[j:j+1]))
+                j -= 1
+
+    return ret, []
+
+def mn_mtmsr(ir, instr, rs):
+    print("%08x: MSR assigned" % instr.offset)
+    return [ ExprAssign(MSR, rs) ], []
+
+def mn_mtspr(ir, instr, arg1, arg2):
+    sprid = int(arg1)
+    gprid = int(arg2.name[1:])
+    if sprid in spr_dict:
+        return [ ExprAssign(spr_dict[sprid], arg2) ], []
+    elif sprid == 1:		# XER
+        return [ ExprAssign(XER_SO, arg2[31:32]),
+                 ExprAssign(XER_OV, arg2[30:31]),
+                 ExprAssign(XER_CA, arg2[29:30]),
+                 ExprAssign(XER_BC, arg2[0:7]) ], []
+    else:
+        return [ ExprAssign(spr_access,
+                         ExprInt(((sprid << SPR_ACCESS_SPR_OFF) |
+                                    (gprid << SPR_ACCESS_GPR_OFF) |
+                                    SPR_ACCESS_IS_WRITE), 32)),
+                 ExprAssign(exception_flags, ExprInt(EXCEPT_SPR_ACCESS, 32)) ], []
+
+def mn_mtsr(ir, instr, sr, rs):
+    srid = sr.arg
+    return [ ExprAssign(sr_dict[srid], rs) ], []
+
+# TODO
+#def mn_mtsrin(ir, instr, rs, rb):
+#    return [ ExprAssign(sr_dict[rb[0:3]], rs) ], []
+
+def mn_mfsr(ir, instr, rd, sr):
+    srid = sr.arg
+    return [ ExprAssign(rd, sr_dict[srid]) ], []
+
+# TODO
+#def mn_mfsrin(ir, instr, rd, rb):
+#    return [ ExprAssign(rd, sr_dict[rb[0:3]]) ], []
+
+def mn_do_mul(ir, instr, rd, ra, arg2):
+    variant = instr.name[3:]
+    if variant[-1] == '.':
+        variant = variant[:-2]
+
+    if variant == 'HW':
+        v1 = ra.signExtend(64)
+        v2 = arg2.signExtend(64)
+        shift = 32
+    elif variant == 'HWU':
+        v1 = ra.zeroExtend(64)
+        v2 = arg2.zeroExtend(64)
+        shift = 32
+    else:
+        v1 = ra
+        v2 = arg2
+        shift = 0
+
+    rvalue = ExprOp('*', v1, v2)
+    if shift != 0:
+        rvalue = rvalue[shift : shift + 32]
+
+    ret = [ ExprAssign(rd, rvalue) ]
+
+    over_expr = None
+    if variant[-1] == 'O':
+        over_expr = ExprCond((rvalue.signExtend(64) ^
+                              ExprOp('*', v1.signExtend(64),
+                                     v2.signExtend(64))),
+                             ExprInt(1, 1), ExprInt(0, 1))
+        ret.append(ExprAssign(XER_OV, over_expr))
+        ret.append(ExprAssign(XER_SO, XER_SO | over_expr))
+
+    if instr.name[-1] == '.':
+        ret += mn_compute_flags(rvalue, over_expr)
+
+    return ret, []
+
+def mn_do_nand(ir, instr, ra, rs, rb):
+    rvalue = ~(rs & rb)
+    ret = [ ExprAssign(ra, rvalue) ]
+
+    if instr.name[-1] == '.':
+        ret += mn_compute_flags(rvalue)
+
+    return ret, []
+
+def mn_do_neg(ir, instr, rd, ra):
+    rvalue = -ra
+    ret = [ ExprAssign(rd, rvalue) ]
+    has_o = False
+
+    over_expr = None
+    if instr.name[-1] == 'O' or instr.name[-2] == 'O':
+        has_o = True
+        over_expr = ExprCond(ra ^ ExprInt(0x80000000, 32),
+                             ExprInt(0, 1), ExprInt(1, 1))
+        ret.append(ExprAssign(XER_OV, over_expr))
+        ret.append(ExprAssign(XER_SO, XER_SO | over_expr))
+
+    if instr.name[-1] == '.':
+        ret += mn_compute_flags(rvalue, over_expr)
+
+    return ret, []
+
+def mn_do_nor(ir, instr, ra, rs, rb):
+
+    rvalue = ~(rs | rb)
+    ret = [ ExprAssign(ra, rvalue) ]
+
+    if instr.name[-1] == '.':
+        ret += mn_compute_flags(rvalue)
+
+    return ret, []
+
+def mn_do_or(ir, instr, ra, rs, arg2):
+    if len(instr.name) > 2 and instr.name[2] == 'C':
+        oarg = ~arg2
+    else:
+        oarg = arg2
+
+    rvalue = rs | oarg
+    ret = [ ExprAssign(ra, rvalue) ]
+
+    if instr.name[-1] == '.':
+        ret += mn_compute_flags(rvalue)
+
+    return ret, []
+
+def mn_do_rfi(ir, instr):
+    dest = ExprCompose(ExprInt(0, 2), SRR0[2:32])
+    ret = [ ExprAssign(MSR, (MSR &
+                          ~ExprInt(0b1111111101110011, 32) |
+                          ExprCompose(SRR1[0:2], ExprInt(0, 2),
+                                      SRR1[4:7], ExprInt(0, 1),
+                                      SRR1[8:16], ExprInt(0, 16)))),
+            ExprAssign(PC, dest),
+            ExprAssign(ir.IRDst, dest) ]
+    return ret, []
+
+def mn_do_rotate(ir, instr, ra, rs, shift, mb, me):
+    r = ExprOp('<<<', rs, shift)
+    if mb <= me:
+        m = ExprInt(((1 << (32 - mb)) - 1) & ~((1 << (32 - me - 1)) - 1), 32)
+    else:
+        m = ExprInt(((1 << (32 - mb)) - 1) | ~((1 << (32 - me - 1)) - 1), 32)
+    rvalue = r & m
+    if instr.name[0:6] == 'RLWIMI':
+        rvalue = rvalue | (ra & ~m)
+
+    ret = [ ExprAssign(ra, rvalue) ]
+
+    if instr.name[-1] == '.':
+        ret += mn_compute_flags(rvalue)
+
+    return ret, []
+
+def mn_do_slw(ir, instr, ra, rs, rb):
+
+    rvalue = ExprCond(rb[5:6], ExprInt(0, 32),
+                      ExprOp('<<', rs, rb & ExprInt(0b11111, 32)))
+    ret = [ ExprAssign(ra, rvalue) ]
+
+    if instr.name[-1] == '.':
+        ret += mn_compute_flags(rvalue)
+
+    return ret, []
+
+def mn_do_sraw(ir, instr, ra, rs, rb):
+    rvalue = ExprCond(rb[5:6], ExprInt(0xFFFFFFFF, 32),
+                      ExprOp('a>>', rs, rb & ExprInt(0b11111, 32)))
+    ret = [ ExprAssign(ra, rvalue) ]
+
+    if instr.name[-1] == '.':
+        ret += mn_compute_flags(rvalue)
+
+    mask = ExprCond(rb[5:6], ExprInt(0xFFFFFFFF, 32),
+                    (ExprInt(0xFFFFFFFF, 32) >>
+                     (ExprInt(32, 32) - (rb & ExprInt(0b11111, 32)))))
+    ret.append(ExprAssign(XER_CA, rs.msb() &
+                       ExprCond(rs & mask, ExprInt(1, 1), ExprInt(0, 1))))
+
+    return ret, []
+
+def mn_do_srawi(ir, instr, ra, rs, imm):
+    rvalue = ExprOp('a>>', rs, imm)
+    ret = [ ExprAssign(ra, rvalue) ]
+
+    if instr.name[-1] == '.':
+        ret += mn_compute_flags(rvalue)
+
+    mask = ExprInt(0xFFFFFFFF >> (32 - int(imm)), 32)
+
+    ret.append(ExprAssign(XER_CA, rs.msb() &
+                       ExprCond(rs & mask, ExprInt(1, 1), ExprInt(0, 1))))
+
+    return ret, []
+
+def mn_do_srw(ir, instr, ra, rs, rb):
+    rvalue = rs >> (rb & ExprInt(0b11111, 32))
+    ret = [ ExprAssign(ra, rvalue) ]
+
+    if instr.name[-1] == '.':
+        ret += mn_compute_flags(rvalue)
+
+    return ret, []
+
+def mn_do_stmw(ir, instr, rs, dest):
+    ret = []
+    address = dest.ptr
+    ri = int(rs.name[1:],10)
+    i = 0
+    while ri <= 31:
+        ret.append(ExprAssign(ExprMem(address + ExprInt(i,32), 32),
+                           all_regs_ids_byname["R%d" % ri]))
+        ri += 1
+        i += 4
+
+    return ret, []
+
+def mn_do_store(ir, instr, arg1, arg2, arg3=None):
+    assert instr.name[0:2] == 'ST'
+
+    ret = []
+    additional_ir = []
+
+    if instr.name[2] == 'S':
+        raise RuntimeError("STSWI, and STSWX need implementing")
+    elif instr.name[2] == 'F':
+        print("Warning, instruction %s implemented as NOP" % instr)
+        return  [], []
+
+    size = {'B': 8, 'H': 16, 'W': 32}[instr.name[2]]
+
+    has_b = False
+    has_u = False
+    is_stwcx = False
+
+    for l in instr.name[3:]:
+        if l == 'B' or l == 'R':
+            has_b = True
+        elif l == 'U':
+            has_u = True
+        elif l == 'X' or l == 'Z':
+            pass	# Taken care of earlier
+        elif l == 'C' or l == '.':
+            is_stwcx = True
+        else:
+            assert False
+
+    if arg3 is None:
+        assert isinstance(arg2, ExprMem)
+
+        address = arg2.ptr
+    else:
+        address = arg2 + arg3
+
+    dest = ExprMem(address, size)
+
+    src = arg1[0:size]
+    if has_b:
+        src = byte_swap(src)
+
+    ret.append(ExprAssign(dest, src))
+    if has_u:
+        if arg3 is None:
+            ret.append(ExprAssign(arg2.ptr.args[0], address))
+        else:
+            ret.append(ExprAssign(arg2, address))
+
+    if is_stwcx:
+        loc_do = ExprLoc(ir.loc_db.add_location(), ir.IRDst.size)
+        loc_dont = ExprLoc(ir.loc_db.add_location(), ir.IRDst.size)
+        loc_next = ExprLoc(ir.get_next_loc_key(instr), ir.IRDst.size)
+        flags = [ ExprAssign(CR0_LT, ExprInt(0,1)),
+                  ExprAssign(CR0_GT, ExprInt(0,1)),
+                  ExprAssign(CR0_SO, XER_SO)]
+        ret += flags
+        ret.append(ExprAssign(CR0_EQ, ExprInt(1,1)))
+        ret.append(ExprAssign(ir.IRDst, loc_next))
+        dont = flags + [ ExprAssign(CR0_EQ, ExprInt(0,1)),
+                         ExprAssign(ir.IRDst, loc_next) ]
+        additional_ir = [ IRBlock(ir.loc_db, loc_do.loc_key, [ AssignBlock(ret) ]),
+                          IRBlock(ir.loc_db, loc_dont.loc_key, [ AssignBlock(dont) ]) ]
+        ret = [ ExprAssign(reserve, ExprInt(0, 1)),
+                ExprAssign(ir.IRDst, ExprCond(reserve, loc_do, loc_dont)) ]
+
+    return ret, additional_ir
+
+def mn_do_sub(ir, instr, arg1, arg2, arg3):
+    assert instr.name[0:4] == 'SUBF'
+
+    flags_update = []
+
+    has_dot = False
+    has_c = False
+    has_e = False
+    has_o = False
+
+    for l in instr.name[4:]:
+        if l == '.':
+            has_dot = True
+        elif l == 'C':
+            has_c = True
+        elif l == 'E':
+            has_e = True
+        elif l == 'O':
+            has_o = True
+        elif l == 'I' or l == 'M' or l == 'S' or l == 'Z':
+            pass	# Taken care of earlier
+        else:
+            assert False
+
+    if has_e:
+        arg3 = arg3 + XER_CA.zeroExtend(32)
+        arg2 = arg2 + ExprInt(1, 32)
+
+    rvalue = arg3 - arg2
+
+    over_expr = None
+    if has_o:
+        msb1 = arg2.msb()
+        msb2 = arg3.msb()
+        msba = rvalue.msb()
+        over_expr = (msb1 ^ msb2) & (msb1 ^ msba)
+        flags_update.append(ExprAssign(XER_OV, over_expr))
+        flags_update.append(ExprAssign(XER_SO, XER_SO | over_expr))
+
+    if has_dot:
+        flags_update += mn_compute_flags(rvalue, over_expr)
+
+    if has_c or has_e:
+        carry_expr = ((((arg3 ^ arg2) ^ rvalue) ^
+                       ((arg3 ^ rvalue) & (arg3 ^ arg2))).msb())
+        flags_update.append(ExprAssign(XER_CA, ~carry_expr))
+
+    return ([ ExprAssign(arg1, rvalue) ] + flags_update), []
+
+def mn_do_xor(ir, instr, ra, rs, rb):
+    rvalue = rs ^ rb
+    ret = [ ExprAssign(ra, rvalue) ]
+
+    if instr.name[-1] == '.':
+        ret += mn_compute_flags(rvalue)
+
+    return ret, []
+
+def mn_b(ir, instr, arg1, arg2 = None):
+    if arg2 is not None:
+        arg1 = arg2
+    return [ ExprAssign(PC, arg1), ExprAssign(ir.IRDst, arg1) ], []
+
+def mn_bl(ir, instr, arg1, arg2 = None):
+    if arg2 is not None:
+        arg1 = arg2
+    dst = ir.get_next_instr(instr)
+    return [ ExprAssign(LR, ExprLoc(dst, 32)),
+             ExprAssign(PC, arg1),
+             ExprAssign(ir.IRDst, arg1) ], []
+
+def mn_get_condition(instr):
+    bit = instr.additional_info.bi & 0b11
+    cr = instr.args[0].name
+    return all_regs_ids_byname[cr + '_' + ['LT', 'GT', 'EQ', 'SO'][bit]]
+
+def mn_do_cond_branch(ir, instr, dest):
+    bo = instr.additional_info.bo
+    bi = instr.additional_info.bi
+    ret = []
+
+    if bo & 0b00100:
+        ctr_cond = True
+    else:
+        ret.append(ExprAssign(CTR, CTR - ExprInt(1, 32)))
+        ctr_cond = ExprCond(CTR ^ ExprInt(1, 32), ExprInt(1, 1), ExprInt(0, 1))
+        if bo & 0b00010:
+            ctr_cond = ~ctr_cond
+
+    if (bo & 0b10000):
+        cond_cond = True
+    else:
+        cond_cond = mn_get_condition(instr)
+        if not (bo & 0b01000):
+            cond_cond = ~cond_cond
+
+    if ctr_cond != True or cond_cond != True:
+        if ctr_cond != True:
+            condition = ctr_cond
+            if cond_cond != True:
+                condition = condition & cond_cond
+        else:
+            condition = cond_cond
+        dst = ir.get_next_instr(instr)
+        dest_expr = ExprCond(condition, dest,
+                             ExprLoc(dst, 32))
+    else:
+        dest_expr = dest
+
+    if instr.name[-1] == 'L' or instr.name[-2:-1] == 'LA':
+        dst = ir.get_next_instr(instr)
+        ret.append(ExprAssign(LR, ExprLoc(dst, 32)))
+
+    ret.append(ExprAssign(PC, dest_expr))
+    ret.append(ExprAssign(ir.IRDst, dest_expr))
+
+    return ret, []
+
+def mn_do_nop_warn(ir, instr, *args):
+    print("Warning, instruction %s implemented as NOP" % instr)
+    return [], []
+
+@sbuild.parse
+def mn_cmp_signed(arg1, arg2, arg3):
+    crf_dict[arg1]['LT'] = expr.ExprOp(expr.TOK_INF_SIGNED, arg2, arg3)
+    crf_dict[arg1]['GT'] = expr.ExprOp(expr.TOK_INF_SIGNED, arg3, arg2)
+    crf_dict[arg1]['EQ'] = expr.ExprOp(expr.TOK_EQUAL, arg2, arg3)
+    crf_dict[arg1]['SO'] = XER_SO
+
+@sbuild.parse
+def mn_cmp_unsigned(arg1, arg2, arg3):
+    crf_dict[arg1]['LT'] = expr.ExprOp(expr.TOK_INF_UNSIGNED, arg2, arg3)
+    crf_dict[arg1]['GT'] = expr.ExprOp(expr.TOK_INF_UNSIGNED, arg3, arg2)
+    crf_dict[arg1]['EQ'] = expr.ExprOp(expr.TOK_EQUAL, arg2, arg3)
+    crf_dict[arg1]['SO'] = XER_SO
+
+def mn_nop(ir, instr, *args):
+    return [], []
+
+@sbuild.parse
+def mn_or(arg1, arg2, arg3):
+    arg1 = arg2 | arg3
+
+@sbuild.parse
+def mn_assign(arg1, arg2):
+    arg2 = arg1
+
+def mn_stb(ir, instr, arg1, arg2):
+    dest = ExprMem(arg2.arg, 8)
+    return [ExprAssign(dest, ExprSlice(arg1, 0, 8))], []
+
+@sbuild.parse
+def mn_stwu(arg1, arg2):
+    arg2 = arg1
+    arg1 = arg2.arg
+
+sem_dir = {
+    'B': mn_b,
+    'BA': mn_b,
+    'BL': mn_bl,
+    'BLA': mn_bl,
+    'CMPLW': mn_cmp_unsigned,
+    'CMPLWI': mn_cmp_unsigned,
+    'CMPW': mn_cmp_signed,
+    'CMPWI': mn_cmp_signed,
+    'CNTLZW': mn_do_cntlzw,
+    'CNTLZW.': mn_do_cntlzw,
+    'ECIWX': mn_do_nop_warn,
+    'ECOWX': mn_do_nop_warn,
+    'EIEIO': mn_do_nop_warn,
+    'EQV': mn_do_eqv,
+    'EQV.': mn_do_eqv,
+    'ICBI': mn_do_nop_warn,
+    'ISYNC': mn_do_nop_warn,
+    'MCRF': mn_do_mcrf,
+    'MCRXR': mn_do_mcrxr,
+    'MFCR': mn_do_mfcr,
+    'MFFS': mn_do_nop_warn,
+    'MFFS.': mn_do_nop_warn,
+    'MFMSR': mn_mfmsr,
+    'MFSPR': mn_mfspr,
+    'MFSR': mn_mfsr,
+    'MFSRIN': mn_do_nop_warn,
+    'MTFSF': mn_do_nop_warn,
+    'MTFSF.': mn_do_nop_warn,
+    'MFTB': mn_mfspr,
+    'MTCRF': mn_mtcrf,
+    'MTMSR': mn_mtmsr,
+    'MTSPR': mn_mtspr,
+    'MTSR': mn_mtsr,
+    'MTSRIN': mn_do_nop_warn,
+    'MTVSCR': mn_do_nop_warn,
+    'NAND': mn_do_nand,
+    'NAND.': mn_do_nand,
+    'NOR': mn_do_nor,
+    'NOR.': mn_do_nor,
+    'RFI': mn_do_rfi,
+    'SC': mn_do_nop_warn,
+    'SLW': mn_do_slw,
+    'SLW.': mn_do_slw,
+    'SRAW': mn_do_sraw,
+    'SRAW.': mn_do_sraw,
+    'SRAWI': mn_do_srawi,
+    'SRAWI.': mn_do_srawi,
+    'SRW': mn_do_srw,
+    'SRW.': mn_do_srw,
+    'SYNC': mn_do_nop_warn,
+    'TLBIA': mn_do_nop_warn,
+    'TLBIE': mn_do_nop_warn,
+    'TLBSYNC': mn_do_nop_warn,
+    'TW': mn_do_nop_warn,
+    'TWI': mn_do_nop_warn,
+}
+
+
+class Lifter_PPC32b(Lifter):
+
+    def __init__(self, loc_db):
+        super(Lifter_PPC32b, self).__init__(mn_ppc, 'b', loc_db)
+        self.pc = mn_ppc.getpc()
+        self.sp = mn_ppc.getsp()
+        self.IRDst = expr.ExprId('IRDst', 32)
+        self.addrsize = 32
+
+    def get_ir(self, instr):
+        args = instr.args[:]
+        if instr.name[0:5] in [ 'ADDIS', 'ORIS', 'XORIS', 'ANDIS' ]:
+            args[2] = ExprInt(int(args[2]) << 16, 32)
+        if instr.name[0:3] == 'ADD':
+            if instr.name[0:4] == 'ADDZ':
+                last_arg = ExprInt(0, 32)
+            elif instr.name[0:4] == 'ADDM':
+                last_arg = ExprInt(0xFFFFFFFF, 32)
+            else:
+                last_arg = args[2]
+            instr_ir, extra_ir = mn_do_add(self, instr, args[0], args[1],
+                                           last_arg)
+        elif instr.name[0:3] == 'AND':
+            instr_ir, extra_ir = mn_do_and(self, instr, *args)
+        elif instr.additional_info.bo_bi_are_defined:
+            name = instr.name
+            if name[-1] == '+' or name[-1] == '-':
+                name = name[0:-1]
+            if name[-3:] == 'CTR' or name[-4:] == 'CTRL':
+                arg1 = ExprCompose(ExprInt(0, 2), CTR[2:32])
+            elif name[-2:] == 'LR' or name[-3:] == 'LRL':
+                arg1 = ExprCompose(ExprInt(0, 2), LR[2:32])
+            else:
+                arg1 = args[1]
+            instr_ir, extra_ir = mn_do_cond_branch(self, instr, arg1)
+        elif instr.name[0:2] == 'CR':
+            instr_ir, extra_ir = mn_do_cr(self, instr, *args)
+        elif instr.name[0:3] == 'DCB':
+            instr_ir, extra_ir = mn_do_nop_warn(self, instr, *args)
+        elif instr.name[0:3] == 'DIV':
+            instr_ir, extra_ir = mn_do_div(self, instr, *args)
+        elif instr.name[0:4] == 'EXTS':
+            instr_ir, extra_ir = mn_do_exts(self, instr, *args)
+        elif instr.name[0] == 'L':
+            instr_ir, extra_ir = mn_do_load(self, instr, *args)
+        elif instr.name[0:3] == 'MUL':
+            instr_ir, extra_ir = mn_do_mul(self, instr, *args)
+        elif instr.name[0:3] == 'NEG':
+            instr_ir, extra_ir = mn_do_neg(self, instr, *args)
+        elif instr.name[0:2] == 'OR':
+            instr_ir, extra_ir = mn_do_or(self, instr, *args)
+        elif instr.name[0:2] == 'RL':
+            instr_ir, extra_ir = mn_do_rotate(self, instr, args[0], args[1],
+                                              args[2], int(args[3]),
+                                              int(args[4]))
+        elif instr.name == 'STMW':
+            instr_ir, extra_ir = mn_do_stmw(self, instr, *args)
+        elif instr.name[0:2] == 'ST':
+            instr_ir, extra_ir = mn_do_store(self, instr, *args)
+        elif instr.name[0:4] == 'SUBF':
+            if instr.name[0:5] == 'SUBFZ':
+                last_arg = ExprInt(0, 32)
+            elif instr.name[0:5] == 'SUBFM':
+                last_arg = ExprInt(0xFFFFFFFF, 32)
+            else:
+                last_arg = args[2]
+            instr_ir, extra_ir = mn_do_sub(self, instr, args[0], args[1],
+                                           last_arg)
+        elif instr.name[0:3] == 'XOR':
+            instr_ir, extra_ir = mn_do_xor(self, instr, *args)
+        else:
+            instr_ir, extra_ir = sem_dir[instr.name](self, instr, *args)
+
+        return instr_ir, extra_ir
+
+    def get_next_instr(self, instr):
+        l = self.loc_db.get_or_create_offset_location(instr.offset  + 4)
+        return l
+
+    def get_next_break_loc_key(self, instr):
+        l = self.loc_db.get_or_create_offset_location(instr.offset  + 4)
+        return l
diff --git a/src/miasm/arch/sh4/__init__.py b/src/miasm/arch/sh4/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/miasm/arch/sh4/__init__.py
diff --git a/src/miasm/arch/sh4/arch.py b/src/miasm/arch/sh4/arch.py
new file mode 100644
index 00000000..76489aee
--- /dev/null
+++ b/src/miasm/arch/sh4/arch.py
@@ -0,0 +1,998 @@
+#-*- coding:utf-8 -*-
+
+from __future__ import print_function
+from builtins import range
+
+from pyparsing import *
+from miasm.core.cpu import *
+from miasm.expression.expression import *
+from collections import defaultdict
+import miasm.arch.sh4.regs as regs_module
+from miasm.arch.sh4.regs import *
+
+
+from miasm.core.asm_ast import AstInt, AstId, AstMem, AstOp
+
+jra = ExprId('jra', 32)
+jrb = ExprId('jrb', 32)
+jrc = ExprId('jrc', 32)
+
+
+# parser helper ###########
+PLUS = Suppress("+")
+MULT = Suppress("*")
+MINUS = Suppress("-")
+AND = Suppress("&")
+LBRACK = Suppress("[")
+RBRACK = Suppress("]")
+DEREF = Suppress("@")
+COMMA = Suppress(",")
+LPARENT = Suppress("(")
+RPARENT = Suppress(")")
+
+
+def cb_deref_pcimm(tokens):
+    return tokens[0] + tokens[1]
+
+
+def cb_pcandimmimm(tokens):
+    return (tokens[0] & tokens[1]) + tokens[2]
+
+
+
+ref_pc = (LPARENT + reg_info_pc.parser + COMMA + base_expr + RPARENT).setParseAction(cb_deref_pcimm)
+ref_pcandimm = (LPARENT + reg_info_pc.parser + AND + base_expr + COMMA + base_expr + RPARENT).setParseAction(cb_pcandimmimm)
+pcdisp = (reg_info_pc.parser + AND + base_expr + PLUS + base_expr).setParseAction(cb_pcandimmimm)
+
+PTR = Suppress('PTR')
+
+
+def cb_deref_mem(tokens):
+    assert len(tokens) == 1
+    result = AstMem(tokens[0], 32)
+    return result
+
+
+def cb_predec(tokens):
+    assert len(tokens) == 1
+    result = AstMem(AstOp('predec', tokens[0]), 32)
+    return result
+
+
+def cb_postinc(tokens):
+    assert len(tokens) == 1
+    result = AstMem(AstOp('postinc', tokens[0]), 32)
+    return result
+
+
+def cb_regdisp(tokens):
+    assert len(tokens) == 2
+    result = AstMem(tokens[0] + tokens[1], 32)
+    return result
+
+
+def cb_regreg(tokens):
+    assert len(tokens) == 2
+    result = AstMem(tokens[0] + tokens[1], 32)
+    return result
+
+
+deref_pc = (DEREF + ref_pc).setParseAction(cb_deref_mem)
+deref_pcimm = (DEREF + ref_pcandimm).setParseAction(cb_deref_mem)
+
+dgpregs_base = (DEREF + gpregs.parser).setParseAction(cb_deref_mem)
+dgpregs_predec = (DEREF + MINUS + gpregs.parser).setParseAction(cb_predec)
+dgpregs_postinc = (DEREF + gpregs.parser + PLUS).setParseAction(cb_postinc)
+
+dgpregs = dgpregs_base | dgpregs_predec | dgpregs_postinc
+
+d_gpreg_gpreg = (DEREF + LPARENT + gpregs.parser + COMMA + gpregs.parser + RPARENT).setParseAction(cb_regdisp)
+dgpregs_p = dgpregs_predec | dgpregs_postinc
+
+
+dgpregs_ir = (DEREF + LPARENT + gpregs.parser + COMMA + base_expr + RPARENT).setParseAction(cb_regdisp)
+dgpregs_ir |= d_gpreg_gpreg
+
+dgbr_imm = (DEREF + LPARENT + reg_info_gbr.parser + COMMA + base_expr + RPARENT).setParseAction(cb_regdisp)
+
+dgbr_reg = (DEREF + LPARENT + reg_info_gbr.parser + COMMA + gpregs.parser + RPARENT).setParseAction(cb_regreg)
+
+
+class sh4_arg(m_arg):
+    def asm_ast_to_expr(self, arg, loc_db):
+        if isinstance(arg, AstId):
+            if isinstance(arg.name, ExprId):
+                return arg.name
+            if arg.name in gpregs.str:
+                return None
+            loc_key = loc_db.get_or_create_name_location(arg.name)
+            return ExprLoc(loc_key, 32)
+        if isinstance(arg, AstOp):
+            args = [self.asm_ast_to_expr(tmp, loc_db) for tmp in arg.args]
+            if None in args:
+                return None
+            return ExprOp(arg.op, *args)
+        if isinstance(arg, AstInt):
+            return ExprInt(arg.value, 32)
+        if isinstance(arg, AstMem):
+            ptr = self.asm_ast_to_expr(arg.ptr, loc_db)
+            if ptr is None:
+                return None
+            return ExprMem(ptr, arg.size)
+        return None
+
+
+_, bs_pr = gen_reg_bs('PR', reg_info_pr, (m_reg, sh4_arg,))
+_, bs_r0 = gen_reg_bs('R0', reg_info_r0, (m_reg, sh4_arg,))
+_, bs_sr = gen_reg_bs('SR', reg_info_sr, (m_reg, sh4_arg,))
+_, bs_gbr = gen_reg_bs('GBR', reg_info_gbr, (m_reg, sh4_arg,))
+_, bs_vbr = gen_reg_bs('VBR', reg_info_vbr, (m_reg, sh4_arg,))
+_, bs_ssr = gen_reg_bs('SSR', reg_info_ssr, (m_reg, sh4_arg,))
+_, bs_spc = gen_reg_bs('SPC', reg_info_spc, (m_reg, sh4_arg,))
+_, bs_sgr = gen_reg_bs('SGR', reg_info_sgr, (m_reg, sh4_arg,))
+_, bs_dbr = gen_reg_bs('dbr', reg_info_dbr, (m_reg, sh4_arg,))
+_, bs_mach = gen_reg_bs('mach', reg_info_mach, (m_reg, sh4_arg,))
+_, bs_macl = gen_reg_bs('macl', reg_info_macl, (m_reg, sh4_arg,))
+_, bs_fpul = gen_reg_bs('fpul', reg_info_fpul, (m_reg, sh4_arg,))
+_, bs_fr0 = gen_reg_bs('fr0', reg_info_fr0, (m_reg, sh4_arg,))
+
+class sh4_reg(reg_noarg, sh4_arg):
+    pass
+
+
+class sh4_gpreg(sh4_reg):
+    reg_info = gpregs
+    parser = reg_info.parser
+
+
+class sh4_dr(sh4_reg):
+    reg_info = dregs
+    parser = reg_info.parser
+
+
+class sh4_bgpreg(sh4_reg):
+    reg_info = bgpregs
+    parser = reg_info.parser
+
+
+class sh4_gpreg_noarg(reg_noarg, ):
+    reg_info = gpregs
+    parser = reg_info.parser
+
+
+class sh4_freg(sh4_reg):
+    reg_info = fregs
+    parser = reg_info.parser
+
+
+class sh4_dgpreg(sh4_arg):
+    parser = dgpregs_base
+
+    def fromstring(self, text, loc_db, parser_result=None):
+        start, stop = super(sh4_dgpreg, self).fromstring(text, loc_db, parser_result)
+        if start is None or self.expr == [None]:
+            return start, stop
+        self.expr = ExprMem(self.expr.ptr, self.sz)
+        return start, stop
+
+    def decode(self, v):
+        r = gpregs.expr[v]
+        self.expr = ExprMem(r, self.sz)
+        return True
+
+    def encode(self):
+        e = self.expr
+        if not isinstance(e, ExprMem):
+            return False
+        if not isinstance(e.ptr, ExprId):
+            return False
+        v = gpregs.expr.index(e.ptr)
+        self.value = v
+        return True
+
+
+class sh4_dgpregpinc(sh4_arg):
+    parser = dgpregs_p
+
+    def fromstring(self, text, loc_db, parser_result=None):
+        start, stop = super(sh4_dgpregpinc, self).fromstring(text, loc_db, parser_result)
+        if self.expr == [None]:
+            return None, None
+        if not isinstance(self.expr.ptr, ExprOp):
+            return None, None
+        if self.expr.ptr.op != self.op:
+            return None, None
+        return start, stop
+
+    def decode(self, v):
+        r = gpregs.expr[v]
+        e = ExprOp(self.op, r)
+        self.expr = ExprMem(e, self.sz)
+        return True
+
+    def encode(self):
+        e = self.expr
+        if not isinstance(e, ExprMem):
+            return False
+        e = e.ptr
+        res = match_expr(e, ExprOp(self.op, jra), [jra])
+        if not res:
+            return False
+        r = res[jra]
+        if not r in gpregs.expr:
+            return False
+        v = gpregs.expr.index(r)
+        self.value = v
+        return True
+
+
+class sh4_dgpregpdec(sh4_arg):
+    parser = dgpregs_postinc
+    op = "preinc"
+
+
+class sh4_dgpreg_imm(sh4_dgpreg):
+    parser = dgpregs_ir
+
+    def decode(self, v):
+        p = self.parent
+        r = gpregs.expr[v]
+        s = self.sz
+        d = ExprInt((p.disp.value * s) // 8, 32)
+        e = ExprMem(r + d, s)
+        self.expr = e
+        return True
+
+    def encode(self):
+        e = self.expr
+        p = self.parent
+        s = self.sz
+        if not isinstance(e, ExprMem):
+            return False
+        if isinstance(e.ptr, ExprId):
+            v = gpregs.expr.index(e.ptr)
+            p.disp.value = 0
+        elif isinstance(e.ptr, ExprOp):
+            res = match_expr(e, ExprMem(jra + jrb, self.sz), [jra, jrb])
+            if not res:
+                return False
+            if not isinstance(res[jra], ExprId):
+                return False
+            if not isinstance(res[jrb], ExprInt):
+                return False
+            d = int(res[jrb])
+            p.disp.value = d // (s // 8)
+            if not res[jra] in gpregs.expr:
+                return False
+            v = gpregs.expr.index(res[jra])
+        else:
+            return False
+        self.value = v
+        return True
+
+
+class sh4_imm(imm_noarg, sh4_arg):
+    parser = base_expr
+    pass
+
+
+class sh4_simm(sh4_imm):
+    parser = base_expr
+
+    def decode(self, v):
+        v = sign_ext(v, self.l, 32)
+        v = self.decodeval(v)
+        self.expr = ExprInt(v, 32)
+        return True
+
+    def encode(self):
+        if not isinstance(self.expr, ExprInt):
+            return False
+        v = int(self.expr)
+        if (1 << (self.l - 1)) & v:
+            v = -((0xffffffff ^ v) + 1)
+        v = self.encodeval(v)
+        self.value = (v & 0xffffffff) & self.lmask
+        return True
+
+
+class sh4_dpc16imm(sh4_dgpreg):
+    parser = deref_pc
+
+    def decode(self, v):
+        self.expr = ExprMem(PC + ExprInt(v * 2 + 4, 32), 16)
+        return True
+
+    def calcdisp(self, v):
+        v = (int(v) - 4) // 2
+        if not 0 < v <= 0xff:
+            return None
+        return v
+
+    def encode(self):
+        res = match_expr(self.expr, ExprMem(PC + jra, 16), [jra])
+        if not res:
+            return False
+        if not isinstance(res[jra], ExprInt):
+            return False
+        v = self.calcdisp(res[jra])
+        if v is None:
+            return False
+        self.value = v
+        return True
+
+
+class sh4_dgbrimm8(sh4_dgpreg):
+    parser = dgbr_imm
+
+    def decode(self, v):
+        s = self.sz
+        self.expr = ExprMem(GBR + ExprInt((v * s) // 8, 32), s)
+        return True
+
+    def encode(self):
+        e = self.expr
+        s = self.sz
+        if e == ExprMem(GBR, 32):
+            self.value = 0
+            return True
+        res = match_expr(self.expr, ExprMem(GBR + jra, s), [jra])
+        if not res:
+            return False
+        if not isinstance(res[jra], ExprInt):
+            return False
+        self.value = int(res[jra]) // (s // 8)
+        return True
+
+
+class sh4_dpc32imm(sh4_dpc16imm):
+    parser = deref_pcimm
+
+    def decode(self, v):
+        self.expr = ExprMem(
+            (PC & ExprInt(0xfffffffc, 32)) + ExprInt(v * 4 + 4, 32), 32)
+        return True
+
+    def calcdisp(self, v):
+        v = (int(v) - 4) // 4
+        if not 0 < v <= 0xff:
+            return None
+        return v
+
+    def encode(self):
+        res = match_expr(
+            self.expr, ExprMem((PC & ExprInt(0xFFFFFFFC, 32)) + jra, 32), [jra])
+        if not res:
+            return False
+        if not isinstance(res[jra], ExprInt):
+            return False
+        v = self.calcdisp(res[jra])
+        if v is None:
+            return False
+        self.value = v
+        return True
+
+
+class sh4_pc32imm(sh4_arg):
+    parser = pcdisp
+
+    def decode(self, v):
+        self.expr = (PC & ExprInt(0xfffffffc, 32)) + ExprInt(v * 4 + 4, 32)
+        return True
+
+    def encode(self):
+        res = match_expr(self.expr, (PC & ExprInt(0xfffffffc, 32)) + jra, [jra])
+        if not res:
+            return False
+        if not isinstance(res[jra], ExprInt):
+            return False
+        v = (int(res[jra]) - 4) // 4
+        if v is None:
+            return False
+        self.value = v
+        return True
+
+class additional_info(object):
+
+    def __init__(self):
+        self.except_on_instr = False
+
+
+class instruction_sh4(instruction):
+    __slots__ = []
+
+    def __init__(self, *args, **kargs):
+        super(instruction_sh4, self).__init__(*args, **kargs)
+
+    def dstflow(self):
+        return self.name.startswith('J')
+
+    @staticmethod
+    def arg2str(expr, index=None, loc_db=None):
+        if isinstance(expr, ExprId) or isinstance(expr, ExprInt):
+            return str(expr)
+        elif expr.is_loc():
+            if loc_db is not None:
+                return loc_db.pretty_str(expr.loc_key)
+            else:
+                return str(expr)
+        assert(isinstance(expr, ExprMem))
+        ptr = expr.ptr
+
+        if isinstance(ptr, ExprOp):
+            if ptr.op == "predec":
+                s = '-%s' % ptr.args[0]
+            elif ptr.op == "postinc":
+                s = '%s+' % ptr.args[0]
+            else:
+                s = ','.join(
+                    str(x).replace('(', '').replace(')', '')
+                    for x in ptr.args
+                )
+                s = "(%s)"%s
+            s = "@%s" % s
+        elif isinstance(ptr, ExprId):
+            s = "@%s" % ptr
+        else:
+            raise NotImplementedError('zarb arg2str')
+        return s
+
+
+    """
+    def dstflow2label(self, loc_db):
+        e = self.args[0]
+        if not isinstance(e, ExprInt):
+            return
+        if self.name == 'BLX':
+            ad = e.arg+8+self.offset
+        else:
+            ad = e.arg+8+self.offset
+        l = loc_db.get_or_create_offset_location(ad)
+        s = ExprId(l, e.size)
+        self.args[0] = s
+    """
+
+    def breakflow(self):
+        if self.name.startswith('J'):
+            return True
+        return False
+
+    def is_subcall(self):
+        return self.name == 'JSR'
+
+    def getdstflow(self, loc_db):
+        return [self.args[0]]
+
+    def splitflow(self):
+        return self.name == 'JSR'
+
+    def get_symbol_size(self, symbol, loc_db):
+        return 32
+
+    def fixDstOffset(self):
+        e = self.args[0]
+        if self.offset is None:
+            raise ValueError('symbol not resolved %s' % l)
+        if not isinstance(e, ExprInt):
+            log.debug('dyn dst %r', e)
+            return
+        off = e.arg - (self.offset + 4 + self.l)
+        print(hex(off))
+        if int(off % 4):
+            raise ValueError('strange offset! %r' % off)
+        self.args[0] = ExprInt(off, 32)
+        print('final', self.args[0])
+
+    def get_args_expr(self):
+        args = [a for a in self.args]
+        return args
+
+
+class mn_sh4(cls_mn):
+    bintree = {}
+    regs = regs_module
+    num = 0
+    all_mn = []
+    all_mn_mode = defaultdict(list)
+    all_mn_name = defaultdict(list)
+    all_mn_inst = defaultdict(list)
+    pc = PC
+    # delayslot:
+    # http://resource.renesas.com/lib/eng/e_learnig/sh4/13/index.html
+    delayslot = 0  # unit is instruction instruction
+    instruction = instruction_sh4
+
+    def additional_info(self):
+        info = additional_info()
+        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 enough bits %r %r' % (n, len(bs.bin) * 8))
+        while n:
+            i = start // 8
+            c = cls.getbytes(bs, i)
+            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 getbytes(cls, bs, offset, l=1):
+        out = b""
+        for _ in range(l):
+            n_offset = (offset & ~1) + 1 - offset % 2
+            out += bs.getbytes(n_offset, 1)
+            offset += 1
+        return out
+
+    @classmethod
+    def check_mnemo(cls, fields):
+        l = sum([x.l for x in fields])
+        assert l == 16, "len %r" % l
+
+    @classmethod
+    def getmn(cls, name):
+        return name.upper().replace('_', '.')
+
+    @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_sh4, self).value(mode)
+        return [x[::-1] for x in v]
+
+
+class bs_dr0gbr(sh4_dgpreg):
+    parser = dgbr_reg
+
+    def decode(self, v):
+        self.expr = ExprMem(GBR + R0, 8)
+        return True
+
+    def encode(self):
+        return self.expr == ExprMem(GBR + R0, 8)
+
+
+class bs_dr0gp(sh4_dgpreg):
+    parser = d_gpreg_gpreg
+
+    def decode(self, v):
+        self.expr = ExprMem(gpregs.expr[v] + R0, self.sz)
+        return True
+
+    def encode(self):
+        res = match_expr(self.expr, ExprMem(R0 + jra, self.sz), [jra])
+        if not res:
+            return False
+        r = res[jra]
+        if not r in gpregs.expr:
+            return False
+        self.value = gpregs.expr.index(r)
+        return True
+
+
+class bs_dgpreg(sh4_dgpreg):
+    parser = dgpregs_base
+
+
+rn = bs(l=4, cls=(sh4_gpreg,), fname="rn")
+rm = bs(l=4, cls=(sh4_gpreg,), fname="rm")
+
+
+d08_rn = bs(l=4, cls=(sh4_dgpreg,), fname="rn", sz = 8)
+d16_rn = bs(l=4, cls=(sh4_dgpreg,), fname="rn", sz = 16)
+d32_rn = bs(l=4, cls=(sh4_dgpreg,), fname="rn", sz = 32)
+d08_rm = bs(l=4, cls=(sh4_dgpreg,), fname="rm", sz = 8)
+d16_rm = bs(l=4, cls=(sh4_dgpreg,), fname="rm", sz = 16)
+d32_rm = bs(l=4, cls=(sh4_dgpreg,), fname="rm", sz = 32)
+
+
+brm = bs(l=3, cls=(sh4_bgpreg,), fname="brm")
+brn = bs(l=3, cls=(sh4_bgpreg,), fname="brn")
+
+d08rnimm = bs(l=4, fname="rn", cls=(sh4_dgpreg_imm,), sz = 8)
+d16rnimm = bs(l=4, fname="rn", cls=(sh4_dgpreg_imm,), sz = 16)
+d32rnimm = bs(l=4, fname="rn", cls=(sh4_dgpreg_imm,), sz = 32)
+
+d08rmimm = bs(l=4, fname="rm", cls=(sh4_dgpreg_imm,), sz = 8)
+d16rmimm = bs(l=4, fname="rm", cls=(sh4_dgpreg_imm,), sz = 16)
+d32rmimm = bs(l=4, fname="rm", cls=(sh4_dgpreg_imm,), sz = 32)
+
+btype = bs(l=4, fname="btype", order=-1)
+
+s08imm = bs(l=8, cls=(sh4_simm,), fname="imm")
+s12imm = bs(l=12, cls=(sh4_simm,), fname="imm")
+dpc16imm = bs(l=8, cls=(sh4_dpc16imm,), fname="pcimm", sz=16)
+dpc32imm = bs(l=8, cls=(sh4_dpc32imm,), fname="pcimm", sz=32)
+dimm4 = bs(l=4, fname='disp', order=-1)
+d08gbrimm8 = bs(l=8, cls=(sh4_dgbrimm8,), fname='disp', sz=8)
+d16gbrimm8 = bs(l=8, cls=(sh4_dgbrimm8,), fname='disp', sz=16)
+d32gbrimm8 = bs(l=8, cls=(sh4_dgbrimm8,), fname='disp', sz=32)
+
+pc32imm = bs(l=8, cls=(sh4_pc32imm,), fname="pcimm")
+
+d08rnpinc = bs(l=4, cls=(sh4_dgpregpinc,), op='postinc', sz=8, fname="rn")
+d08rmpinc = bs(l=4, cls=(sh4_dgpregpinc,), op='postinc', sz=8, fname="rm")
+
+d16rnpinc = bs(l=4, cls=(sh4_dgpregpinc,), op='postinc', sz=16, fname="rn")
+d16rmpinc = bs(l=4, cls=(sh4_dgpregpinc,), op='postinc', sz=16, fname="rm")
+
+d32rnpinc = bs(l=4, cls=(sh4_dgpregpinc,), op='postinc', sz=32, fname="rn")
+d32rmpinc = bs(l=4, cls=(sh4_dgpregpinc,), op='postinc', sz=32, fname="rm")
+
+d08rnpdec = bs(l=4, cls=(sh4_dgpregpinc,), op='predec', sz=8, fname="rn")
+d08rmpdec = bs(l=4, cls=(sh4_dgpregpinc,), op='predec', sz=8, fname="rm")
+
+d16rnpdec = bs(l=4, cls=(sh4_dgpregpinc,), op='predec', sz=16, fname="rn")
+d16rmpdec = bs(l=4, cls=(sh4_dgpregpinc,), op='predec', sz=16, fname="rm")
+
+d32rnpdec = bs(l=4, cls=(sh4_dgpregpinc,), op='predec', sz=32, fname="rn")
+d32rmpdec = bs(l=4, cls=(sh4_dgpregpinc,), op='predec', sz=32, fname="rm")
+
+
+u08imm = bs(l=8, cls=(sh4_imm,), fname="imm")
+dr0gbr = bs(l=0, cls=(bs_dr0gbr,), sz=8)
+
+d08gpreg = bs(l=4, cls=(bs_dgpreg,), sz=8)
+d32gpreg = bs(l=4, cls=(bs_dgpreg,), sz=32)
+
+frn = bs(l=4, cls=(sh4_freg,), fname="frn")
+frm = bs(l=4, cls=(sh4_freg,), fname="frm")
+
+bd08r0gp = bs(l=4, cls=(bs_dr0gp,), sz=8)
+bd16r0gp = bs(l=4, cls=(bs_dr0gp,), sz=16)
+bd32r0gp = bs(l=4, cls=(bs_dr0gp,), sz=32)
+
+drn = bs(l=3, cls=(sh4_dr,), fname="drn")
+drm = bs(l=3, cls=(sh4_dr,), fname="drm")
+
+
+def addop(name, fields, args=None, alias=False):
+    dct = {"fields": fields}
+    dct["alias"] = alias
+    if args is not None:
+        dct['args'] = args
+    type(name, (mn_sh4,), dct)
+
+addop("mov", [bs('1110'), rn, s08imm], [s08imm, rn])
+addop("mov_w", [bs('1001'), rn, dpc16imm], [dpc16imm, rn])
+addop("mov_l", [bs('1101'), rn, dpc32imm], [dpc32imm, rn])
+addop("mov", [bs('0110', fname="opc"), rn, rm, bs('0011')], [rm, rn])
+addop("mov_b", [bs('0010', fname="opc"), d08_rn, rm, bs('0000')], [rm, d08_rn])
+addop("mov_w", [bs('0010', fname="opc"), d16_rn, rm, bs('0001')], [rm, d16_rn])
+addop("mov_l", [bs('0010', fname="opc"), d32_rn, rm, bs('0010')], [rm, d32_rn])
+addop("mov_b", [bs('0110', fname="opc"), rn, d08_rm, bs('0000')], [d08_rm, rn])
+addop("mov_w", [bs('0110', fname="opc"), rn, d16_rm, bs('0001')], [d16_rm, rn])
+addop("mov_l", [bs('0110', fname="opc"), rn, d32_rm, bs('0010')], [d32_rm, rn])
+addop("mov_b",
+      [bs('0010', fname="opc"), d08rnpdec, rm, bs('0100')], [rm, d08rnpdec])
+addop("mov_w",
+      [bs('0010', fname="opc"), d16rnpdec, rm, bs('0101')], [rm, d16rnpdec])
+addop("mov_l",
+      [bs('0010', fname="opc"), d32rnpdec, rm, bs('0110')], [rm, d32rnpdec])
+addop("mov_b",
+      [bs('0110', fname="opc"), rn, d08rmpinc, bs('0100')], [rm, d08rnpinc])
+addop("mov_w",
+      [bs('0110', fname="opc"), rn, d16rmpinc, bs('0101')], [d16rmpinc, rn])
+addop("mov_l",
+      [bs('0110', fname="opc"), rn, d32rmpinc, bs('0110')], [d32rmpinc, rn])
+addop("mov_b", [bs('10000000', fname='opc'), bs_r0, d08rnimm, dimm4])
+addop("mov_w", [bs('10000001', fname='opc'), bs_r0, d16rnimm, dimm4])
+addop("mov_l", [bs('0001', fname='opc'), d32rnimm, rm, dimm4], [rm, d32rnimm])
+addop("mov_b", [bs('10000100', fname='opc'), d08rmimm, dimm4, bs_r0])
+addop("mov_w", [bs('10000101', fname='opc'), d16rmimm, dimm4, bs_r0])
+addop("mov_l", [bs('0101', fname='opc'), rn, d32rmimm, dimm4], [d32rmimm, rn])
+addop("mov_b",
+      [bs('0000', fname='opc'), bd08r0gp, rm, bs('0100')], [rm, bd08r0gp])
+addop("mov_w",
+      [bs('0000', fname='opc'), bd16r0gp, rm, bs('0101')], [rm, bd16r0gp])
+addop("mov_l",
+      [bs('0000', fname='opc'), bd32r0gp, rm, bs('0110')], [rm, bd32r0gp])
+addop("mov_b",
+      [bs('0000', fname='opc'), rn, bd08r0gp, bs('1100')], [bd08r0gp, rn])
+addop("mov_w",
+      [bs('0000', fname='opc'), rn, bd16r0gp, bs('1101')], [bd16r0gp, rn])
+addop("mov_l",
+      [bs('0000', fname='opc'), rn, bd32r0gp, bs('1110')], [bd32r0gp, rn])
+
+addop("mov_b", [bs('11000000'), bs_r0, d08gbrimm8])
+addop("mov_w", [bs('11000001'), bs_r0, d16gbrimm8])
+addop("mov_l", [bs('11000010'), bs_r0, d32gbrimm8])
+
+addop("mov_b", [bs('11000100'), d08gbrimm8, bs_r0])
+addop("mov_w", [bs('11000101'), d16gbrimm8, bs_r0])
+addop("mov_l", [bs('11000110'), d32gbrimm8, bs_r0])
+
+addop("mov", [bs('11000111'), pc32imm, bs_r0])
+
+addop("swapb", [bs('0110'), rn, rm, bs('1000')], [rm, rn])
+addop("swapw", [bs('0110'), rn, rm, bs('1001')], [rm, rn])
+addop("xtrct", [bs('0010'), rn, rm, bs('1101')], [rm, rn])
+
+
+addop("add", [bs('0011'), rn, rm, bs('1100')], [rm, rn])
+addop("add", [bs('0111'), rn, s08imm], [s08imm, rn])
+addop("addc", [bs('0011'), rn, rm, bs('1110')], [rm, rn])
+addop("addv", [bs('0011'), rn, rm, bs('1111')], [rm, rn])
+
+
+addop("cmpeq", [bs('10001000'), s08imm, bs_r0])
+
+
+addop("cmpeq", [bs('0011'), rn, rm, bs('0000')], [rm, rn])
+addop("cmphs", [bs('0011'), rn, rm, bs('0010')], [rm, rn])
+addop("cmpge", [bs('0011'), rn, rm, bs('0011')], [rm, rn])
+addop("cmphi", [bs('0011'), rn, rm, bs('0110')], [rm, rn])
+addop("cmpgt", [bs('0011'), rn, rm, bs('0111')], [rm, rn])
+
+
+addop("cmppz", [bs('0100'), rn, bs('00010001')])
+addop("cmppl", [bs('0100'), rn, bs('00010101')])
+addop("cmpstr", [bs('0010'), rn, rm, bs('1100')], [rm, rn])
+
+
+addop("div1", [bs('0011'), rn, rm, bs('0100')], [rm, rn])
+
+addop("div0s", [bs('0010'), rn, rm, bs('0111')], [rm, rn])
+addop("div0u", [bs('0000000000011001')])
+
+addop("dmuls", [bs('0011'), rn, rm, bs('1101')], [rm, rn])
+addop("dmulu", [bs('0011'), rn, rm, bs('0101')], [rm, rn])
+
+addop("dt", [bs('0100'), rn, bs('00010000')])
+
+
+addop("extsb", [bs('0110'), rn, rm, bs('1110')], [rm, rn])
+addop("extsw", [bs('0110'), rn, rm, bs('1111')], [rm, rn])
+addop("extub", [bs('0110'), rn, rm, bs('1100')], [rm, rn])
+addop("extuw", [bs('0110'), rn, rm, bs('1101')], [rm, rn])
+
+addop("mac_l", [bs('0000', fname='opc'), d32rnpinc,
+      d32rmpinc, bs('1111')], [d32rmpinc, d32rnpinc])
+addop("mac_w", [bs('0100', fname='opc'), d16rnpinc,
+      d16rmpinc, bs('1111')], [d16rmpinc, d16rnpinc])
+
+addop("mull", [bs('0000'), rn, rm, bs('0111')], [rm, rn])
+addop("mulsw", [bs('0010'), rn, rm, bs('1111')], [rm, rn])
+addop("muluw", [bs('0010'), rn, rm, bs('1110')], [rm, rn])
+
+addop("neg", [bs('0110'), rn, rm, bs('1011')], [rm, rn])
+addop("negc", [bs('0110'), rn, rm, bs('1010')], [rm, rn])
+
+addop("sub", [bs('0011'), rn, rm, bs('1000')], [rm, rn])
+addop("subc", [bs('0011'), rn, rm, bs('1010')], [rm, rn])
+addop("subv", [bs('0011'), rn, rm, bs('1011')], [rm, rn])
+
+addop("and", [bs('0010'), rn, rm, bs('1001')], [rm, rn])
+addop("and", [bs('11001001'), u08imm, bs_r0])
+addop("and_b", [bs('11001101'), u08imm, dr0gbr])
+
+addop("not", [bs('0110'), rn, rm, bs('0111')], [rm, rn])
+
+addop("or", [bs('0010'), rn, rm, bs('1011')], [rm, rn])
+
+addop("or", [bs('11001011'), u08imm, bs_r0])
+addop("or_b", [bs('11001111'), u08imm, dr0gbr])
+
+addop("tas_b", [bs('0100'), d08gpreg, bs('00011011')])
+addop("tst", [bs('0010'), rn, rm, bs('1000')], [rm, rn])
+addop("tst", [bs('11001000'), u08imm, bs_r0])
+addop("tst_b", [bs('11001100'), u08imm, dr0gbr])
+
+
+addop("xor", [bs('0010'), rn, rm, bs('1010')], [rm, rn])
+addop("xor", [bs('11001010'), u08imm, bs_r0])
+addop("xor_b", [bs('11001110'), u08imm, dr0gbr])
+
+addop("rotl", [bs('0100'), rn, bs('00000100')])
+addop("rotr", [bs('0100'), rn, bs('00000101')])
+addop("rotcl", [bs('0100'), rn, bs('00100100')])
+addop("rotcr", [bs('0100'), rn, bs('00100101')])
+
+addop("shad", [bs('0100'), rn, rm, bs('1100')], [rm, rn])
+addop("shal", [bs('0100'), rn, bs('00100000')])
+addop("shar", [bs('0100'), rn, bs('00100001')])
+addop("shld", [bs('0100'), rn, rm, bs('1101')], [rm, rn])
+
+addop("shll", [bs('0100'), rn, bs('00000000')])
+addop("shlr", [bs('0100'), rn, bs('00000001')])
+addop("shll2", [bs('0100'), rn, bs('00001000')])
+addop("shlr2", [bs('0100'), rn, bs('00001001')])
+addop("shll8", [bs('0100'), rn, bs('00011000')])
+addop("shlr8", [bs('0100'), rn, bs('00011001')])
+addop("shll16", [bs('0100'), rn, bs('00101000')])
+addop("shlr16", [bs('0100'), rn, bs('00101001')])
+
+
+addop("bf", [bs('10001011'), s08imm])
+"""
+    def splitflow(self):
+        return True
+    def breakflow(self):
+        return True
+    def dstflow(self):
+        return True
+    def dstflow2label(self, loc_db):
+        e = self.args[0].expr
+        ad = e.arg*2+4+self.offset
+        l = loc_db.get_or_create_offset_location(ad)
+        s = ExprId(l, e.size)
+        self.args[0].expr = s
+"""
+
+addop("bfs", [bs('10001111'), s08imm])
+"""
+    delayslot = 1
+"""
+addop("bt", [bs('10001001'), s08imm])
+
+addop("bts", [bs('10001101'), s08imm])
+
+addop("bra", [bs('1010'), s12imm])
+"""
+    delayslot = 1
+    def breakflow(self):
+        return True
+    def dstflow(self):
+        return True
+    def dstflow2label(self, loc_db):
+        e = self.args[0].expr
+        ad = e.arg*2+4+self.offset
+        l = loc_db.get_or_create_offset_location(ad)
+        s = ExprId(l, e.size)
+        self.args[0].expr = s
+"""
+
+addop("braf", [bs('0000'), rn, bs('00100011')])
+"""
+    delayslot = 1
+    def breakflow(self):
+        return True
+    def dstflow(self):
+        return True
+"""
+addop("bsr", [bs('1011'), s12imm])
+
+addop("bsrf", [bs('0000'), rn, bs('00000011')])
+"""
+    delayslot = 1
+    def breakflow(self):
+        return True
+    def is_subcall(self):
+        return True
+    def splitflow(self):
+        return True
+"""
+
+addop("jmp_l", [bs('0100'), d32gpreg, bs('00101011')])
+"""
+    delayslot = 1
+    def breakflow(self):
+        return True
+"""
+
+addop("jsr_l", [bs('0100'), d32gpreg, bs('00001011')])
+"""
+    delayslot = 1
+    def breakflow(self):
+        return True
+    def is_subcall(self):
+        return True
+    def splitflow(self):
+        return True
+"""
+
+addop("rts", [bs('0000000000001011')])
+"""
+    delayslot = 1
+    def breakflow(self):
+        return True
+"""
+addop("clrmac", [bs('0000000000101000')])
+addop("clrs", [bs('0000000001001000')])
+addop("clrt", [bs('0000000000001000')])
+
+
+addop("ldc", [bs('0100'), rm, bs_sr, bs('00001110')])
+addop("ldc", [bs('0100'), rm, bs_gbr, bs('00011110')])
+addop("ldc", [bs('0100'), rm, bs_vbr, bs('00101110')])
+addop("ldc", [bs('0100'), rm, bs_ssr, bs('00111110')])
+addop("ldc", [bs('0100'), rm, bs_spc, bs('01001110')])
+addop("ldc", [bs('0100'), rm, bs_dbr, bs('11111010')])
+addop("ldc", [bs('0100'), rm, bs('1'), brn, bs('1110')], [rm, brn])
+addop("ldc_l", [bs('0100'), d32rmpinc, bs_sr,  bs('00000111')])
+addop("ldc_l", [bs('0100'), d32rmpinc, bs_gbr, bs('00010111')])
+addop("ldc_l", [bs('0100'), d32rmpinc, bs_vbr, bs('00100111')])
+addop("ldc_l", [bs('0100'), d32rmpinc, bs_ssr, bs('00110111')])
+addop("ldc_l", [bs('0100'), d32rmpinc, bs_spc, bs('01000111')])
+addop("ldc_l", [bs('0100'), d32rmpinc, bs_dbr, bs('11110110')])
+addop("ldc_l", [bs('0100'), d32rmpinc, bs('1'), brn, bs('0111')])
+addop("lds", [bs('0100'), rm, bs_mach, bs('00001010')])
+addop("lds", [bs('0100'), rm, bs_macl, bs('00011010')])
+addop("lds", [bs('0100'), rm, bs_pr, bs('00101010')])
+addop("lds_l", [bs('0100'), d32rmpinc, bs_mach, bs('00000110')])
+addop("lds_l", [bs('0100'), d32rmpinc, bs_macl, bs('00010110')])
+addop("lds_l", [bs('0100'), d32rmpinc, bs_pr, bs('00100110')])
+addop("ldtlb", [bs('0000000000111000')])
+
+addop("movca_l", [bs('0000'), bs_r0, d32gpreg, bs('11000011')])
+addop("nop", [bs('0000000000001001')])
+addop("ocbi_l", [bs('0000'), d32gpreg, bs('10010011')])
+addop("ocbp_l", [bs('0000'), d32gpreg, bs('10100011')])
+addop("ocbwb_l", [bs('0000'), d32gpreg, bs('10110011')])
+addop("pref_l", [bs('0000'), d32gpreg, bs('10000011')])
+
+
+addop("rte", [bs('0000000000101011')])
+addop("sets", [bs('0000000001011000')])
+addop("sett", [bs('0000000000011000')])
+addop("sleep", [bs('0000000000011011')])
+addop("stc", [bs('0000'), bs_sr,  rn, bs('00000010')])
+addop("stc", [bs('0000'), bs_gbr, rn, bs('00010010')])
+addop("stc", [bs('0000'), bs_vbr, rn, bs('00100010')])
+addop("stc", [bs('0000'), bs_ssr, rn, bs('00110010')])
+addop("stc", [bs('0000'), bs_spc, rn, bs('01000010')])
+addop("stc", [bs('0000'), bs_sgr, rn, bs('00111010')])
+addop("stc", [bs('0000'), bs_dbr, rn, bs('11111010')])
+addop("stc", [bs('0000'), rn, bs('1'), brm, bs('0010')], [brm, rn])
+
+addop("stc_l", [bs('0100'), bs_sr, d32rmpdec,  bs('00000011')])
+addop("stc_l", [bs('0100'), bs_gbr, d32rmpdec, bs('00010011')])
+addop("stc_l", [bs('0100'), bs_vbr, d32rmpdec, bs('00100011')])
+addop("stc_l", [bs('0100'), bs_ssr, d32rmpdec, bs('00110011')])
+addop("stc_l", [bs('0100'), bs_spc, d32rmpdec, bs('01000011')])
+addop("stc_l", [bs('0100'), bs_sgr, d32rmpdec, bs('00110010')])
+addop("stc_l", [bs('0100'), bs_dbr, d32rmpdec, bs('11110010')])
+addop("stc_l",
+      [bs('0100'), d32rnpdec, bs('1'), brm, bs('0011')], [brm, d32rnpdec])
+
+# float
+addop("sts", [bs('0000'), bs_mach, rm, bs('00001010')])
+addop("sts", [bs('0000'), bs_macl, rm, bs('00011010')])
+addop("sts", [bs('0000'), bs_pr, rm, bs('00101010')])
+addop("sts_l", [bs('0100'), bs_mach, d32rmpdec, bs('00000010')])
+addop("sts_l", [bs('0100'), bs_macl, d32rmpdec, bs('00010010')])
+addop("sts_l",
+      [bs('0100'), d32rnpdec, bs_pr, bs('00100010')], [bs_pr, d32rnpdec])
+addop("trapa", [bs('11000011'), u08imm])
+
+addop("fldi0", [bs('1111'), frn, bs('10001101')])
+addop("fldi1", [bs('1111'), frn, bs('10011101')])
+addop("fmov", [bs('1111'), frn, frm, bs('1100')], [frm, frn])
+addop("fmov_s", [bs('1111'), frn, d32gpreg, bs('1000')], [d32gpreg, frn])
+addop("fmov_s", [bs('1111'), frn, bd32r0gp, bs('0110')], [bd32r0gp, frn])
+addop("fmov_s", [bs('1111'), frn, d32rmpinc, bs('1001')], [d32rmpinc, frn])
+addop("fmov_s", [bs('1111'), d32gpreg, frm, bs('1010')], [frm, d32gpreg])
+addop("fmov_s", [bs('1111'), d32rnpdec, frm, bs('1011')], [frm, d32rnpdec])
+addop("fmov_s", [bs('1111'), bd32r0gp, frm, bs('0111')], [frm, bd32r0gp])
+
+addop("flds", [bs('1111'), frm, bs_fpul, bs('00011101')])
+addop("fsts", [bs('1111'), bs_fpul, frm, bs('00001101')])
+addop("fabs", [bs('1111'), frn, bs('01011101')])
+addop("fadd", [bs('1111'), frn, frm, bs('0000')], [frm, frn])
+addop("fcmpeq", [bs('1111'), frn, frm, bs('0100')], [frm, frn])
+addop("fcmpgt", [bs('1111'), frn, frm, bs('0101')], [frm, frn])
+addop("fdiv", [bs('1111'), frn, frm, bs('0011')], [frm, frn])
+
+addop("float", [bs('1111'), bs_fpul, frn, bs('00101101')])
+addop("fmac", [bs('1111'), bs_fr0, frn, frm, bs('1110')], [bs_fr0, frm, frn])
+addop("fmul", [bs('1111'), frn, frm, bs('0010')], [frm, frn])
+addop("fneg", [bs('1111'), frn, bs('01001101')])
+addop("fsqrt", [bs('1111'), frn, bs('01101101')])
+addop("fsub", [bs('1111'), frn, frm, bs('0001')], [frm, frn])
+addop("ftrc", [bs('1111'), frm, bs_fpul, bs('00111101')])
diff --git a/src/miasm/arch/sh4/regs.py b/src/miasm/arch/sh4/regs.py
new file mode 100644
index 00000000..8a7e1881
--- /dev/null
+++ b/src/miasm/arch/sh4/regs.py
@@ -0,0 +1,84 @@
+from builtins import range
+from miasm.expression.expression import *
+from miasm.core.cpu import reg_info, gen_reg
+
+# GP
+gpregs_str = ['R%d' % r for r in range(0x10)]
+gpregs_expr = [ExprId(x, 32) for x in gpregs_str]
+gpregs = reg_info(gpregs_str, gpregs_expr)
+
+bgpregs_str = ['R%d_BANK' % r for r in range(0x8)]
+bgpregs_expr = [ExprId(x, 32) for x in bgpregs_str]
+bgpregs = reg_info(bgpregs_str, bgpregs_expr)
+
+fregs_str = ['FR%d' % r for r in range(0x10)]
+fregs_expr = [ExprId(x, 32) for x in fregs_str]
+fregs = reg_info(fregs_str, fregs_expr)
+
+dregs_str = ['DR%d' % r for r in range(0x8)]
+dregs_expr = [ExprId(x, 32) for x in dregs_str]
+dregs = reg_info(dregs_str, dregs_expr)
+
+
+PC, reg_info_pc = gen_reg('PC')
+PR, reg_info_pr = gen_reg('PR')
+R0, reg_info_r0 = gen_reg('R0')
+GBR, reg_info_gbr = gen_reg('GBR')
+SR, reg_info_sr = gen_reg('SR')
+VBR, reg_info_vbr = gen_reg('VBR')
+SSR, reg_info_ssr = gen_reg('SSR')
+SPC, reg_info_spc = gen_reg('SPC')
+SGR, reg_info_sgr = gen_reg('SGR')
+DBR, reg_info_dbr = gen_reg('DBR')
+MACH, reg_info_mach = gen_reg('MACH')
+MACL, reg_info_macl = gen_reg('MACL')
+FPUL, reg_info_fpul = gen_reg('FPUL')
+FR0, reg_info_fr0 = gen_reg('FR0')
+
+R0 = gpregs_expr[0]
+R1 = gpregs_expr[1]
+R2 = gpregs_expr[2]
+R3 = gpregs_expr[3]
+R4 = gpregs_expr[4]
+R5 = gpregs_expr[5]
+R6 = gpregs_expr[6]
+R7 = gpregs_expr[7]
+R8 = gpregs_expr[8]
+R9 = gpregs_expr[9]
+R10 = gpregs_expr[10]
+R11 = gpregs_expr[11]
+R12 = gpregs_expr[12]
+R13 = gpregs_expr[13]
+R14 = gpregs_expr[14]
+R15 = gpregs_expr[15]
+
+
+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)
+
+
+all_regs_ids = [
+    R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15,
+    zf, nf, of, cf,
+
+    PC, PR, R0, GBR, SR, VBR, SSR, SPC,
+    SGR, DBR, MACH, MACL, FPUL, FR0]
+
+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 = [ExprId("%s_init" % x.name, x.size) for x in all_regs_ids]
+
+regs_init = {}
+for i, r in enumerate(all_regs_ids):
+    regs_init[r] = all_regs_ids_init[i]
+
+regs_flt_expr = []
diff --git a/src/miasm/arch/x86/__init__.py b/src/miasm/arch/x86/__init__.py
new file mode 100644
index 00000000..bbad893b
--- /dev/null
+++ b/src/miasm/arch/x86/__init__.py
@@ -0,0 +1 @@
+__all__ = ["arch", "disasm", "regs", "sem"]
diff --git a/src/miasm/arch/x86/arch.py b/src/miasm/arch/x86/arch.py
new file mode 100644
index 00000000..5464a779
--- /dev/null
+++ b/src/miasm/arch/x86/arch.py
@@ -0,0 +1,4878 @@
+#-*- coding:utf-8 -*-
+
+from __future__ import print_function
+from builtins import range
+import re
+
+from future.utils import viewitems
+
+from miasm.core import utils
+from miasm.expression.expression import *
+from pyparsing import *
+from miasm.core.cpu import *
+from collections import defaultdict
+import miasm.arch.x86.regs as regs_module
+from miasm.arch.x86.regs import *
+from miasm.core.asm_ast import AstNode, AstInt, AstId, AstMem, AstOp
+from miasm.ir.ir import color_expr_html
+from miasm.core.utils import BRACKET_O, BRACKET_C
+
+
+log = logging.getLogger("x86_arch")
+console_handler = logging.StreamHandler()
+console_handler.setFormatter(logging.Formatter("[%(levelname)-8s]: %(message)s"))
+log.addHandler(console_handler)
+log.setLevel(logging.WARN)
+
+conditional_branch = ["JO", "JNO", "JB", "JAE",
+                      "JZ", "JNZ", "JBE", "JA",
+                      "JS", "JNS", "JPE", "JNP",
+                      #"L", "NL", "NG", "G"]
+                      "JL", "JGE", "JLE", "JG",
+                      "JCXZ", "JECXZ", "JRCXZ"]
+
+unconditional_branch = ['JMP', 'JMPF']
+
+f_isad = "AD"
+f_s08 = "S08"
+f_u08 = "U08"
+f_s16 = "S16"
+f_u16 = "U16"
+f_s32 = "S32"
+f_u32 = "U32"
+f_s64 = "S64"
+f_u64 = "U64"
+f_imm = 'IMM'
+
+f_imm2size = {f_s08: 8, f_s16: 16, f_s32: 32, f_s64: 64,
+              f_u08: 8, f_u16: 16, f_u32: 32, f_u64: 64}
+
+
+size2gpregs = {8: gpregs08, 16: gpregs16,
+               32: gpregs32, 64: gpregs64}
+
+
+replace_regs64 = {
+    AL: RAX[:8], CL: RCX[:8], DL: RDX[:8], BL: RBX[:8],
+    AH: RAX[8:16], CH: RCX[8:16], DH: RDX[8:16], BH: RBX[8:16],
+    SPL: RSP[0:8], BPL: RBP[0:8], SIL: RSI[0:8], DIL: RDI[0:8],
+    R8B: R8[0:8], R9B: R9[0:8], R10B: R10[0:8], R11B: R11[0:8],
+    R12B: R12[0:8], R13B: R13[0:8], R14B: R14[0:8], R15B: R15[0:8],
+
+    AX: RAX[:16], CX: RCX[:16], DX: RDX[:16], BX: RBX[:16],
+    SP: RSP[:16], BP: RBP[:16], SI: RSI[:16], DI: RDI[:16],
+    R8W:  R8[:16], R9W:  R9[:16], R10W: R10[:16], R11W: R11[:16],
+    R12W: R12[:16], R13W: R13[:16], R14W: R14[:16], R15W: R15[:16],
+
+    EAX: RAX[:32], ECX: RCX[:32], EDX: RDX[:32], EBX: RBX[:32],
+    ESP: RSP[:32], EBP: RBP[:32], ESI: RSI[:32], EDI: RDI[:32],
+    R8D: R8[:32], R9D: R9[:32], R10D: R10[:32], R11D: R11[:32],
+    R12D: R12[:32], R13D: R13[:32], R14D: R14[:32], R15D: R15[:32],
+
+    IP: RIP[:16], EIP: RIP[:32],
+
+    ExprId("ST", 64): float_st0,
+    ExprId("ST(0)", 64): float_st0,
+    ExprId("ST(1)", 64): float_st1,
+    ExprId("ST(2)", 64): float_st2,
+    ExprId("ST(3)", 64): float_st3,
+    ExprId("ST(4)", 64): float_st4,
+    ExprId("ST(5)", 64): float_st5,
+    ExprId("ST(6)", 64): float_st6,
+    ExprId("ST(7)", 64): float_st7,
+
+}
+
+replace_regs32 = {
+    AL: EAX[:8],   CL: ECX[:8],   DL: EDX[:8],   BL: EBX[:8],
+    AH: EAX[8:16], CH: ECX[8:16], DH: EDX[8:16], BH: EBX[8:16],
+
+    AX: EAX[:16], CX: ECX[:16], DX: EDX[:16], BX: EBX[:16],
+    SP: ESP[:16], BP: EBP[:16], SI: ESI[:16], DI: EDI[:16],
+
+    IP: EIP[:16],
+
+
+    ExprId("ST", 64): float_st0,
+    ExprId("ST(0)", 64): float_st0,
+    ExprId("ST(1)", 64): float_st1,
+    ExprId("ST(2)", 64): float_st2,
+    ExprId("ST(3)", 64): float_st3,
+    ExprId("ST(4)", 64): float_st4,
+    ExprId("ST(5)", 64): float_st5,
+    ExprId("ST(6)", 64): float_st6,
+    ExprId("ST(7)", 64): float_st7,
+
+}
+
+replace_regs16 = {
+    AL: AX[:8],   CL: CX[:8],   DL: DX[:8],   BL: BX[:8],
+    AH: AX[8:16], CH: CX[8:16], DH: DX[8:16], BH: BX[8:16],
+
+    AX: AX[:16],  CX: CX[:16],  DX: DX[:16],  BX: BX[:16],
+    SP: SP[:16],  BP: BP[:16],  SI: SI[:16],  DI: DI[:16],
+
+
+    ExprId("ST", 64): float_st0,
+    ExprId("ST(0)", 64): float_st0,
+    ExprId("ST(1)", 64): float_st1,
+    ExprId("ST(2)", 64): float_st2,
+    ExprId("ST(3)", 64): float_st3,
+    ExprId("ST(4)", 64): float_st4,
+    ExprId("ST(5)", 64): float_st5,
+    ExprId("ST(6)", 64): float_st6,
+    ExprId("ST(7)", 64): float_st7,
+
+}
+
+replace_regs = {16: replace_regs16,
+                32: replace_regs32,
+                64: replace_regs64}
+
+
+segm2enc = {CS: 1, SS: 2, DS: 3, ES: 4, FS: 5, GS: 6}
+enc2segm = dict((value, key) for key, value in viewitems(segm2enc))
+
+segm_info = reg_info_dct(enc2segm)
+
+
+
+enc2crx = {
+    0: cr0,
+    1: cr1,
+    2: cr2,
+    3: cr3,
+    4: cr4,
+    5: cr5,
+    6: cr6,
+    7: cr7,
+}
+
+crx_info = reg_info_dct(enc2crx)
+
+
+enc2drx = {
+    0: dr0,
+    1: dr1,
+    2: dr2,
+    3: dr3,
+    4: dr4,
+    5: dr5,
+    6: dr6,
+    7: dr7,
+}
+
+drx_info = reg_info_dct(enc2drx)
+
+
+
+# parser helper ###########
+PLUS = Suppress("+")
+MULT = Suppress("*")
+
+COLON = Suppress(":")
+
+
+LBRACK = Suppress("[")
+RBRACK = Suppress("]")
+
+
+gpreg = (
+    gpregs08.parser |
+    gpregs08_64.parser |
+    gpregs16.parser |
+    gpregs32.parser |
+    gpregs64.parser |
+    gpregs_xmm.parser |
+    gpregs_mm.parser |
+    gpregs_bnd.parser
+)
+
+
+def is_op_segm(expr):
+    """Returns True if is ExprOp and op == 'segm'"""
+    return expr.is_op('segm')
+
+def is_mem_segm(expr):
+    """Returns True if is ExprMem and ptr is_op_segm"""
+    return expr.is_mem() and is_op_segm(expr.ptr)
+
+
+def cb_deref_segmoff(tokens):
+    assert len(tokens) == 2
+    return AstOp('segm', tokens[0], tokens[1])
+
+
+def cb_deref_base_expr(tokens):
+    tokens = tokens[0]
+    assert isinstance(tokens, AstNode)
+    addr = tokens
+    return addr
+
+
+deref_mem_ad = (LBRACK + base_expr + RBRACK).setParseAction(cb_deref_base_expr)
+
+deref_ptr = (base_expr + COLON + base_expr).setParseAction(cb_deref_segmoff)
+
+
+PTR = Suppress('PTR')
+
+FAR = Suppress('FAR')
+
+
+BYTE = Literal('BYTE')
+WORD = Literal('WORD')
+DWORD = Literal('DWORD')
+QWORD = Literal('QWORD')
+TBYTE = Literal('TBYTE')
+XMMWORD = Literal('XMMWORD')
+
+MEMPREFIX2SIZE = {'BYTE': 8, 'WORD': 16, 'DWORD': 32,
+                  'QWORD': 64, 'TBYTE': 80, 'XMMWORD': 128}
+
+SIZE2MEMPREFIX = dict((value, key) for key, value in viewitems(MEMPREFIX2SIZE))
+
+def cb_deref_mem(tokens):
+    if len(tokens) == 2:
+        s, ptr = tokens
+        assert isinstance(ptr, AstNode)
+        return AstMem(ptr, MEMPREFIX2SIZE[s])
+    elif len(tokens) == 3:
+        s, segm, ptr = tokens
+        return AstMem(AstOp('segm', segm, ptr), MEMPREFIX2SIZE[s])
+    raise ValueError('len(tokens) > 3')
+
+mem_size = (BYTE | DWORD | QWORD | WORD | TBYTE | XMMWORD)
+deref_mem = (mem_size + PTR + Optional((base_expr + COLON))+ deref_mem_ad).setParseAction(cb_deref_mem)
+
+
+rmarg = (
+    gpregs08.parser |
+    gpregs08_64.parser |
+    gpregs16.parser |
+    gpregs32.parser |
+    gpregs64.parser |
+    gpregs_mm.parser |
+    gpregs_xmm.parser |
+    gpregs_bnd.parser
+)
+
+rmarg |= deref_mem
+
+
+mem_far = FAR + deref_mem
+
+
+cl_or_imm = r08_ecx.parser
+cl_or_imm |= base_expr
+
+
+
+class x86_arg(m_arg):
+    def asm_ast_to_expr(self, value, loc_db, size_hint=None, fixed_size=None):
+        if size_hint is None:
+            size_hint = self.parent.mode
+        if fixed_size is None:
+            fixed_size = set()
+        if isinstance(value, AstId):
+            if value.name in all_regs_ids_byname:
+                reg = all_regs_ids_byname[value.name]
+                fixed_size.add(reg.size)
+                return reg
+            if isinstance(value.name, ExprId):
+                fixed_size.add(value.name.size)
+                return value.name
+            if value.name in MEMPREFIX2SIZE:
+                return None
+            if value.name in ["FAR"]:
+                return None
+
+            loc_key = loc_db.get_or_create_name_location(value.name)
+            return ExprLoc(loc_key, size_hint)
+        if isinstance(value, AstOp):
+            # First pass to retrieve fixed_size
+            if value.op == "segm":
+                segm = self.asm_ast_to_expr(value.args[0], loc_db)
+                ptr = self.asm_ast_to_expr(value.args[1], loc_db, None, fixed_size)
+                return ExprOp('segm', segm, ptr)
+            args = [self.asm_ast_to_expr(arg, loc_db, None, fixed_size) for arg in value.args]
+            if len(fixed_size) == 0:
+                # No fixed size
+                pass
+            elif len(fixed_size) == 1:
+                # One fixed size, regen all
+                size = list(fixed_size)[0]
+                args = [self.asm_ast_to_expr(arg, loc_db, size, fixed_size) for arg in value.args]
+            else:
+                raise ValueError("Size conflict")
+            if None in args:
+                return None
+            return ExprOp(value.op, *args)
+        if isinstance(value, AstInt):
+            if 1 << size_hint < value.value:
+                size_hint *= 2
+            return ExprInt(value.value, size_hint)
+        if isinstance(value, AstMem):
+            fixed_size.add(value.size)
+            ptr = self.asm_ast_to_expr(value.ptr, loc_db, None, set())
+            if ptr is None:
+                return None
+            return ExprMem(ptr, value.size)
+        return None
+
+class r_al(reg_noarg, x86_arg):
+    reg_info = r08_eax
+    parser = reg_info.parser
+
+
+class r_ax(reg_noarg, x86_arg):
+    reg_info = r16_eax
+    parser = reg_info.parser
+
+
+class r_dx(reg_noarg, x86_arg):
+    reg_info = r16_edx
+    parser = reg_info.parser
+
+
+class r_eax(reg_noarg, x86_arg):
+    reg_info = r32_eax
+    parser = reg_info.parser
+
+
+class r_rax(reg_noarg, x86_arg):
+    reg_info = r64_eax
+    parser = reg_info.parser
+
+
+class r_cl(reg_noarg, x86_arg):
+    reg_info = r08_ecx
+    parser = reg_info.parser
+
+
+invmode = {16: 32, 32: 16}
+
+
+def opmode_prefix(mode):
+    size, opmode, admode = mode
+    if size in [16, 32]:
+        if opmode:
+            return invmode[size]
+        else:
+            return size
+    elif size == 64:
+        if opmode:
+            return 16
+        else:
+            return 32
+    raise NotImplementedError('not fully functional')
+
+
+def admode_prefix(mode):
+    size, opmode, admode = mode
+    if size in [16, 32]:
+        if admode:
+            return invmode[size]
+        else:
+            return size
+    elif size == 64:
+        return 64
+    raise NotImplementedError('not fully functional')
+
+
+def v_opmode_info(size, opmode, rex_w, stk):
+    if size in [16, 32]:
+        if opmode:
+            return invmode[size]
+        else:
+            return size
+    elif size == 64:
+        # Rex has the maximum priority
+        # Then opmode
+        # Then stacker
+        if rex_w == 1:
+            return 64
+        elif opmode == 1:
+            return 16
+        elif stk:
+            return 64
+        else:
+            return 32
+
+
+def v_opmode(p):
+    stk = hasattr(p, 'stk')
+    return v_opmode_info(p.mode, p.opmode, p.rex_w.value, stk)
+
+
+def v_admode_info(size, admode):
+    if size in [16, 32]:
+        if admode:
+            return invmode[size]
+        else:
+            return size
+    elif size == 64:
+        if admode == 1:
+            return 32
+        return 64
+
+
+def v_admode(p):
+    return v_admode_info(p.mode, p.admode)
+
+
+def offsize(p):
+    if p.opmode:
+        return 16
+    else:
+        return p.mode
+
+
+def get_prefix(s):
+    g = re.search(r'(\S+)(\s+)', s)
+    if not g:
+        return None, s
+    prefix, b = g.groups()
+    return prefix, s[len(prefix) + len(b):]
+
+
+repeat_mn = ["INS", "OUTS",
+             "MOVSB", "MOVSW", "MOVSD", "MOVSQ",
+             "SCASB", "SCASW", "SCASD", "SCASQ",
+             "LODSB", "LODSW", "LODSD", "LODSQ",
+             "STOSB", "STOSW", "STOSD", "STOSQ",
+             "CMPSB", "CMPSW", "CMPSD", "CMPSQ",
+             ]
+
+
+class group(object):
+
+    def __init__(self):
+        self.value = None
+
+
+class additional_info(object):
+
+    def __init__(self):
+        self.except_on_instr = False
+        self.g1 = group()
+        self.g2 = group()
+        self.vopmode = None
+        self.stk = False
+        self.v_opmode = None
+        self.v_admode = None
+        self.prefixed = b''
+
+
+class instruction_x86(instruction):
+    __slots__ = []
+
+    def __init__(self, *args, **kargs):
+        super(instruction_x86, self).__init__(*args, **kargs)
+
+    def v_opmode(self):
+        return self.additional_info.v_opmode
+
+    def v_admode(self):
+        return self.additional_info.v_admode
+
+    def dstflow(self):
+        if self.name in conditional_branch + unconditional_branch:
+            return True
+        if self.name.startswith('LOOP'):
+            return True
+        return self.name in ['CALL']
+
+    def dstflow2label(self, loc_db):
+        if self.additional_info.g1.value & 14 and self.name in repeat_mn:
+            return
+        expr = self.args[0]
+        if not expr.is_int():
+            return
+        addr = (int(expr) + int(self.offset)) & int(expr.mask)
+        loc_key = loc_db.get_or_create_offset_location(addr)
+        self.args[0] = ExprLoc(loc_key, expr.size)
+
+    def breakflow(self):
+        if self.name in conditional_branch + unconditional_branch:
+            return True
+        if self.name.startswith('LOOP'):
+            return True
+        if self.name.startswith('RET'):
+            return True
+        if self.name.startswith('INT'):
+            return True
+        if self.name.startswith('SYS'):
+            return True
+        return self.name in ['CALL', 'HLT', 'IRET', 'IRETD', 'IRETQ', 'ICEBP', 'UD2']
+
+    def splitflow(self):
+        if self.name in conditional_branch:
+            return True
+        if self.name in unconditional_branch:
+            return False
+        if self.name.startswith('LOOP'):
+            return True
+        if self.name.startswith('INT'):
+            return True
+        if self.name.startswith('SYS'):
+            return True
+        return self.name in ['CALL']
+
+    def setdstflow(self, a):
+        return
+
+    def is_subcall(self):
+        return self.name in ['CALL']
+
+    def getdstflow(self, loc_db):
+        if self.additional_info.g1.value & 14 and self.name in repeat_mn:
+            addr = int(self.offset)
+            loc_key = loc_db.get_or_create_offset_location(addr)
+            return [ExprLoc(loc_key, self.v_opmode())]
+        return [self.args[0]]
+
+    def get_symbol_size(self, symbol, loc_db):
+        return self.mode
+
+    def fixDstOffset(self):
+        expr = self.args[0]
+        if self.offset is None:
+            raise ValueError('symbol not resolved %s' % l)
+        if not isinstance(expr, ExprInt):
+            log.warning('dynamic dst %r', expr)
+            return
+        self.args[0] = ExprInt(int(expr) - self.offset, self.mode)
+
+    def get_info(self, c):
+        self.additional_info.g1.value = c.g1.value
+        self.additional_info.g2.value = c.g2.value
+        self.additional_info.stk = hasattr(c, 'stk')
+        self.additional_info.v_opmode = c.v_opmode()
+        self.additional_info.v_admode = c.v_admode()
+        self.additional_info.prefix = c.prefix
+        self.additional_info.prefixed = getattr(c, "prefixed", b"")
+
+    def __str__(self):
+        return self.to_string()
+
+    def to_string(self, loc_db=None):
+        o = super(instruction_x86, self).to_string(loc_db)
+        if self.additional_info.g1.value & 1:
+            o = "LOCK %s" % o
+        if self.additional_info.g1.value & 2:
+            if getattr(self.additional_info.prefixed, 'default', b"") != b"\xF2":
+                o = "REPNE %s" % o
+        if self.additional_info.g1.value & 8:
+            if getattr(self.additional_info.prefixed, 'default', b"") != b"\xF3":
+                o = "REP %s" % o
+        elif self.additional_info.g1.value & 4:
+            if getattr(self.additional_info.prefixed, 'default', b"") != b"\xF3":
+                o = "REPE %s" % o
+        return o
+
+    def to_html(self, loc_db=None):
+        o = super(instruction_x86, self).to_html(loc_db)
+        if self.additional_info.g1.value & 1:
+            text =  utils.set_html_text_color("LOCK", utils.COLOR_MNEMO)
+            o = "%s %s" % (text, o)
+        if self.additional_info.g1.value & 2:
+            if getattr(self.additional_info.prefixed, 'default', b"") != b"\xF2":
+                text =  utils.set_html_text_color("REPNE", utils.COLOR_MNEMO)
+                o = "%s %s" % (text, o)
+        if self.additional_info.g1.value & 8:
+            if getattr(self.additional_info.prefixed, 'default', b"") != b"\xF3":
+                text =  utils.set_html_text_color("REP", utils.COLOR_MNEMO)
+                o = "%s %s" % (text, o)
+        elif self.additional_info.g1.value & 4:
+            if getattr(self.additional_info.prefixed, 'default', b"") != b"\xF3":
+                text =  utils.set_html_text_color("REPE", utils.COLOR_MNEMO)
+                o = "%s %s" % (text, o)
+        return o
+
+
+    def get_args_expr(self):
+        args = []
+        for a in self.args:
+            a = a.replace_expr(replace_regs[self.mode])
+            args.append(a)
+        return args
+
+    @staticmethod
+    def arg2str(expr, index=None, loc_db=None):
+        if expr.is_id() or expr.is_int():
+            o = str(expr)
+        elif expr.is_loc():
+            if loc_db is not None:
+                o = loc_db.pretty_str(expr.loc_key)
+            else:
+                o = str(expr)
+        elif ((isinstance(expr, ExprOp) and expr.op == 'far' and
+               isinstance(expr.args[0], ExprMem)) or
+              isinstance(expr, ExprMem)):
+            if isinstance(expr, ExprOp):
+                prefix, expr = "FAR ", expr.args[0]
+            else:
+                prefix = ""
+            sz = SIZE2MEMPREFIX[expr.size]
+            segm = ""
+            if is_mem_segm(expr):
+                segm = "%s:" % expr.ptr.args[0]
+                expr = expr.ptr.args[1]
+            else:
+                expr = expr.ptr
+            if isinstance(expr, ExprOp):
+                s = str(expr).replace('(', '').replace(')', '')
+            else:
+                s = str(expr)
+            o = prefix + sz + ' PTR ' + str(segm) + '[%s]' % s
+        elif isinstance(expr, ExprOp) and expr.op == 'segm':
+            o = "%s:%s" % (expr.args[0], expr.args[1])
+        else:
+            raise ValueError('check this %r' % expr)
+        return "%s" % o
+
+
+    @staticmethod
+    def arg2html(expr, index=None, loc_db=None):
+        if expr.is_id() or expr.is_int() or expr.is_loc():
+            o = color_expr_html(expr, loc_db)
+        elif ((isinstance(expr, ExprOp) and expr.op == 'far' and
+               isinstance(expr.args[0], ExprMem)) or
+              isinstance(expr, ExprMem)):
+            if isinstance(expr, ExprOp):
+                prefix, expr = "FAR ", expr.args[0]
+            else:
+                prefix = ""
+            sz = SIZE2MEMPREFIX[expr.size]
+            sz =  '<font color="%s">%s</font>' % (utils.COLOR_MEM, sz)
+            segm = ""
+            if is_mem_segm(expr):
+                segm = "%s:" % expr.ptr.args[0]
+                expr = expr.ptr.args[1]
+            else:
+                expr = expr.ptr
+            if isinstance(expr, ExprOp):
+                s = color_expr_html(expr, loc_db)#.replace('(', '').replace(')', '')
+            else:
+                s = color_expr_html(expr, loc_db)
+            o = prefix + sz + ' PTR ' + str(segm) + BRACKET_O + str(s) + BRACKET_C
+        elif isinstance(expr, ExprOp) and expr.op == 'segm':
+            o = "%s:%s" % (
+                color_expr_html(expr.args[0], loc_db),
+                color_expr_html(expr.args[1], loc_db)
+            )
+        else:
+            raise ValueError('check this %r' % expr)
+        return "%s" % o
+
+
+
+class mn_x86(cls_mn):
+    name = "x86"
+    prefix_op_size = False
+    prefix_ad_size = False
+    regs = regs_module
+    all_mn = []
+    all_mn_mode = defaultdict(list)
+    all_mn_name = defaultdict(list)
+    all_mn_inst = defaultdict(list)
+    bintree = {}
+    num = 0
+    delayslot = 0
+    pc = {16: IP, 32: EIP, 64: RIP}
+    sp = {16: SP, 32: ESP, 64: RSP}
+    instruction = instruction_x86
+    max_instruction_len = 15
+
+    @classmethod
+    def getpc(cls, attrib):
+        return cls.pc[attrib]
+
+    @classmethod
+    def getsp(cls, attrib):
+        return cls.sp[attrib]
+
+    def v_opmode(self):
+        if hasattr(self, 'stk'):
+            stk = 1
+        else:
+            stk = 0
+        return v_opmode_info(self.mode, self.opmode, self.rex_w.value, stk)
+
+    def v_admode(self):
+        size, opmode, admode = self.mode, self.opmode, self.admode
+        if size in [16, 32]:
+            if admode:
+                return invmode[size]
+            else:
+                return size
+        elif size == 64:
+            if admode == 1:
+                return 32
+            return 64
+
+    def additional_info(self):
+        info = additional_info()
+        info.g1.value = self.g1.value
+        info.g2.value = self.g2.value
+        info.stk = hasattr(self, 'stk')
+        info.v_opmode = self.v_opmode()
+        info.prefixed = b""
+        if hasattr(self, 'prefixed'):
+            info.prefixed = self.prefixed.default
+        return info
+
+    @classmethod
+    def check_mnemo(cls, fields):
+        pass
+
+    @classmethod
+    def getmn(cls, name):
+        return name.upper()
+
+    @classmethod
+    def mod_fields(cls, fields):
+        prefix = [d_g1, d_g2, d_rex_p, d_rex_w, d_rex_r, d_rex_x, d_rex_b, d_vex, d_vex_l, d_vex_p, d_vex_v, d_vex_m]
+        return prefix + fields
+
+    @classmethod
+    def gen_modes(cls, subcls, name, bases, dct, fields):
+        dct['mode'] = None
+        return [(subcls, name, bases, dct, fields)]
+
+    @classmethod
+    def fromstring(cls, text, loc_db, mode):
+        pref = 0
+        prefix, new_s = get_prefix(text)
+        if prefix == "LOCK":
+            pref |= 1
+            text = new_s
+        elif prefix == "REPNE" or prefix == "REPNZ":
+            pref |= 2
+            text = new_s
+        elif prefix == "REPE" or prefix == "REPZ":
+            pref |= 4
+            text = new_s
+        elif prefix == "REP":
+            pref |= 8
+            text = new_s
+        c = super(mn_x86, cls).fromstring(text, loc_db, mode)
+        c.additional_info.g1.value = pref
+        return c
+
+    @classmethod
+    def pre_dis(cls, v, mode, offset):
+        offset_o = offset
+        pre_dis_info = {'opmode': 0,
+                        'admode': 0,
+                        'g1': 0,
+                        'g2': 0,
+                        'rex_p': 0,
+                        'rex_w': 0,
+                        'rex_r': 0,
+                        'rex_x': 0,
+                        'rex_b': 0,
+                        'vex_l': 0,
+                        'vex_p': 0,
+                        'vex_v': 0,
+                        'vex_m': 0,
+                        'vex' : 0,
+                        'prefix': b"",
+                        'prefixed': b"",
+                        }
+        while True:
+            c = v.getbytes(offset)
+            if c == b'\x66':
+                pre_dis_info['opmode'] = 1
+            elif c == b'\x67':
+                pre_dis_info['admode'] = 1
+            elif c == b'\xf0':
+                pre_dis_info['g1'] = 1
+            elif c == b'\xf2':
+                pre_dis_info['g1'] = 2
+            elif c == b'\xf3':
+                pre_dis_info['g1'] = 12
+
+            elif c == b'\x2e':
+                pre_dis_info['g2'] = 1
+            elif c == b'\x36':
+                pre_dis_info['g2'] = 2
+            elif c == b'\x3e':
+                pre_dis_info['g2'] = 3
+            elif c == b'\x26':
+                pre_dis_info['g2'] = 4
+            elif c == b'\x64':
+                pre_dis_info['g2'] = 5
+            elif c == b'\x65':
+                pre_dis_info['g2'] = 6
+
+            else:
+                break
+            pre_dis_info['prefix'] += c
+            offset += 1
+        vex3_prefix = b'\xc4'
+        vex2_prefix = b'\xc5'
+        rex_prefixes = b'@ABCDEFGHIJKLMNO'
+        if mode == 64 and c in rex_prefixes:
+            while c in rex_prefixes:
+                # multiple REX prefixes case - use last REX prefix
+                x = ord(c)
+                offset += 1
+                c = v.getbytes(offset)
+            pre_dis_info['rex_p'] = 1
+            pre_dis_info['rex_w'] = (x >> 3) & 1
+            pre_dis_info['rex_r'] = (x >> 2) & 1
+            pre_dis_info['rex_x'] = (x >> 1) & 1
+            pre_dis_info['rex_b'] = (x >> 0) & 1
+        elif mode == 64 and c == vex3_prefix:
+            offset += 1
+            c = ord(v.getbytes(offset))
+            pre_dis_info['vex'] = 1
+            pre_dis_info['rex_r'] = ((c >> 7) ^ 1) & 1
+            pre_dis_info['rex_x'] = ((c >> 6) ^ 1) & 1
+            pre_dis_info['rex_b'] = ((c >> 5) ^ 1) & 1
+            pre_dis_info['vex_m'] = (c & int('0b11111', 2))
+
+            offset += 1
+            c = ord(v.getbytes(offset))
+            pre_dis_info['rex_w'] = (c >> 7) & 1
+            pre_dis_info['vex_v'] = ((c >> 3) ^ 15) & 15
+            pre_dis_info['vex_l'] = (c >> 2) & 1
+            pre_dis_info['vex_p'] = c & int('0b11', 2)
+            offset += 1
+
+            if pre_dis_info['vex_p'] == 1:
+                pre_dis_info['opmode'] = 1
+            elif pre_dis_info['vex_p'] == 3:
+                pre_dis_info['g1'] = 2
+            elif pre_dis_info['vex_p'] == 2:
+                pre_dis_info['g1'] = 12
+
+        elif mode == 64 and c == vex2_prefix and v.getlen() > 2:
+            offset += 1
+            c = ord(v.getbytes(offset))
+            pre_dis_info['vex'] = 1
+            pre_dis_info['rex_r'] = ((c >> 7) ^ 1) & 1
+            pre_dis_info['rex_x'] = 0
+            pre_dis_info['rex_b'] = 0
+            pre_dis_info['rex_w'] = 0
+            pre_dis_info['vex_l'] = (c >> 2) & 1
+            pre_dis_info['vex_p'] = c & int('0b11', 2)
+            offset += 1
+
+            if pre_dis_info['vex_p'] == 1:
+                pre_dis_info['opmode'] = 1
+            elif pre_dis_info['vex_p'] == 3:
+                pre_dis_info['g1'] = 2
+            elif pre_dis_info['vex_p'] == 2:
+                pre_dis_info['g1'] = 12
+
+        elif pre_dis_info.get('g1', None) == 12 and c in [b'\xa6', b'\xa7', b'\xae', b'\xaf']:
+            pre_dis_info['g1'] = 4
+        return pre_dis_info, v, mode, offset, offset - offset_o
+
+    @classmethod
+    def get_cls_instance(cls, cc, mode, infos=None):
+        for opmode in [0, 1]:
+            for admode in [0, 1]:
+                c = cc()
+                c.init_class()
+
+                c.reset_class()
+                c.add_pre_dis_info()
+                c.dup_info(infos)
+                c.mode = mode
+                c.opmode = opmode
+                c.admode = admode
+
+                if not hasattr(c, 'stk') and hasattr(c, "fopmode") and c.fopmode.mode == 64:
+                    c.rex_w.value = 1
+                yield c
+
+    def post_dis(self):
+        if self.g2.value:
+            for a in self.args:
+                if not isinstance(a.expr, ExprMem):
+                    continue
+                m = a.expr
+                a.expr = ExprMem(
+                    ExprOp('segm', enc2segm[self.g2.value], m.ptr), m.size)
+        return self
+
+    def dup_info(self, infos):
+        if infos is not None:
+            self.g1.value = infos.g1.value
+            self.g2.value = infos.g2.value
+
+    def reset_class(self):
+        super(mn_x86, self).reset_class()
+        if hasattr(self, "opmode"):
+            del(self.opmode)
+        if hasattr(self, "admode"):
+            del(self.admode)
+
+    def add_pre_dis_info(self, pre_dis_info=None):
+        if pre_dis_info is None:
+            return True
+        if hasattr(self, "prefixed") and self.prefixed.default == b"\x66":
+            pre_dis_info['opmode'] = 0
+        self.opmode = pre_dis_info['opmode']
+        self.admode = pre_dis_info['admode']
+
+        if hasattr(self, 'no_xmm_pref') and\
+                pre_dis_info['prefix'] and\
+                pre_dis_info['prefix'][-1] in b'\x66\xf2\xf3':
+            return False
+        if (hasattr(self, "prefixed") and
+            not pre_dis_info['prefix'].endswith(self.prefixed.default)):
+            return False
+        if (self.rex_w.value is not None and
+            self.rex_w.value != pre_dis_info['rex_w']):
+            return False
+        else:
+            self.rex_w.value = pre_dis_info['rex_w']
+        self.rex_r.value = pre_dis_info['rex_r']
+        self.rex_b.value = pre_dis_info['rex_b']
+        self.rex_x.value = pre_dis_info['rex_x']
+        self.rex_p.value = pre_dis_info['rex_p']
+
+        self.vex.value = pre_dis_info['vex']
+        self.vex_l.value = pre_dis_info['vex_l']
+        self.vex_p.value = pre_dis_info['vex_p']
+        self.vex_v.value = pre_dis_info['vex_v']
+        self.vex_m.value = pre_dis_info['vex_m']
+
+        if hasattr(self, 'no_rex') and\
+           (self.rex_r.value or self.rex_b.value or
+            self.rex_x.value or self.rex_p.value):
+            return False
+
+        if self.vex.value == 0 and (hasattr(self, 'pref_0f')
+                                    or hasattr(self, 'pref_0f38')
+                                    or hasattr(self, 'pref_0f3a')):
+            return False
+
+        if hasattr(self, 'no_rep') and b'\xf3' in pre_dis_info['prefix']:
+            return False
+
+        if self.vex_m.value == 1 and not hasattr(self, 'pref_0f'):
+            return False
+        if self.vex_m.value == 2 and not hasattr(self, 'pref_0f38'):
+            return False
+        if self.vex_m.value == 3 and not hasattr(self, 'pref_0f3a'):
+            return False
+
+        self.g1.value = pre_dis_info['g1']
+        self.g2.value = pre_dis_info['g2']
+        self.prefix = pre_dis_info['prefix']
+        return True
+
+    def post_asm(self, v):
+        return v
+
+
+    def gen_prefix(self):
+        v = b""
+        rex = 0x40
+        if self.g1.value is None:
+            self.g1.value = 0
+        if self.g2.value is None:
+            self.g2.value = 0
+
+        if self.rex_w.value:
+            rex |= 0x8
+        if self.rex_r.value:
+            rex |= 0x4
+        if self.rex_x.value:
+            rex |= 0x2
+        if self.rex_b.value:
+            rex |= 0x1
+        if (rex != 0x40 and not self.vex.value) or self.rex_p.value == 1:
+            v = utils.int_to_byte(rex) + v
+            if hasattr(self, 'no_rex'):
+                return None
+
+        vex_byte1 = 0xc4
+        vex_byte2 = 0x00
+        vex_byte3 = 0x00
+
+        m_prefix = [field.fname for field in self.fields_order if 'pref_0f' in field.fname]
+        if m_prefix:
+            if m_prefix[0] == 'pref_0f':
+                vex_byte2 |= 0x01
+            elif m_prefix[0] == 'pref_0f38':
+                vex_byte2 |= 0x02
+            elif m_prefix[0] == 'pref_0f3a':
+                vex_byte2 |= 0x03
+
+        # TODO: L and p 
+        if m_prefix and m_prefix[0] == 'pref_0f' and not self.rex_w.value and not self.rex_b.value and ((hasattr(self, 'mod') and self.mod.value == 3) or not self.rex_x.value): # VEX2
+            print("test")
+            vex_version = 2
+            vex_byte1 = 0x00
+            vex_byte2 = 0xc5
+
+            if not hasattr(self, 'reg') or not self.rex_r.value:
+                vex_byte3 |= 0x80
+
+        else:
+            vex_version = 3
+            if not hasattr(self, 'reg') or not self.rex_r.value:
+                vex_byte2 |= 0x80
+            if (hasattr(self, 'mod') and self.mod.value == 3) or not self.rex_x.value:
+                vex_byte2 |= 0x40
+            if not self.rex_b.value:
+                vex_byte2 |= 0x20
+
+            if self.rex_w.value:
+                vex_byte3 |= 0x80
+
+        if self.vex.value == 1:
+            vex_byte3 |= ((15 - self.vex_v.value) << 3)
+            vex = (vex_byte1 << 16) | (vex_byte2 << 8) | vex_byte3
+            v = vex.to_bytes(vex_version, 'big') + v
+
+        if hasattr(self, 'prefixed'):
+            v = self.prefixed.default + v
+
+        if self.g1.value & 1:
+            v = b"\xf0" + v
+        if self.g1.value & 2:
+            if hasattr(self, 'no_xmm_pref'):
+                return None
+            v = b"\xf2" + v
+        if self.g1.value & 12:
+            if hasattr(self, 'no_xmm_pref'):
+                return None
+            v = b"\xf3" + v
+        if self.g2.value:
+            v = {
+                1: b'\x2e',
+                2: b'\x36',
+                3: b'\x3e',
+                4: b'\x26',
+                5: b'\x64',
+                6: b'\x65'
+            }[self.g2.value] + v
+        # mode prefix
+        if hasattr(self, "admode") and self.admode:
+            v = b"\x67" + v
+
+        if hasattr(self, "opmode") and self.opmode:
+            if hasattr(self, 'no_xmm_pref'):
+                return None
+            v = b"\x66" + v
+        return v
+
+    def encodefields(self, decoded):
+        v = super(mn_x86, self).encodefields(decoded)
+        prefix = self.gen_prefix()
+        if prefix is None:
+            return None
+        return prefix + v
+
+    def getnextflow(self, loc_db):
+        raise NotImplementedError('not fully functional')
+
+    def ir_pre_instruction(self):
+        return [ExprAssign(mRIP[self.mode],
+            ExprInt(self.offset + self.l, mRIP[self.mode].size))]
+
+    @classmethod
+    def filter_asm_candidates(cls, instr, candidates):
+
+        cand_same_mode = []
+        cand_diff_mode = []
+        out = []
+        for c, v in candidates:
+            if (hasattr(c, 'no_xmm_pref') and
+                (c.g1.value & 2 or c.g1.value & 4 or c.g1.value & 8 or c.opmode)):
+                continue
+            if hasattr(c, "fopmode") and v_opmode(c) != c.fopmode.mode:
+                continue
+            if hasattr(c, "fadmode") and v_admode(c) != c.fadmode.mode:
+                continue
+            # relative dstflow must not have opmode set
+            # (assign IP instead of EIP for instance)
+            if (instr.dstflow() and
+                instr.name not in ["JCXZ", "JECXZ", "JRCXZ"] and
+                len(instr.args) == 1 and
+                    isinstance(instr.args[0], ExprInt) and c.opmode):
+                continue
+
+            out.append((c, v))
+        candidates = out
+        for c, v in candidates:
+            if v_opmode(c) == instr.mode:
+                cand_same_mode += v
+        for c, v in candidates:
+            if v_opmode(c) != instr.mode:
+                cand_diff_mode += v
+        cand_same_mode.sort(key=len)
+        cand_diff_mode.sort(key=len)
+        return cand_same_mode + cand_diff_mode
+
+
+class bs_modname_size(bs_divert):
+    prio = 1
+
+    def divert(self, i, candidates):
+        out = []
+        for candidate in candidates:
+            cls, name, bases, dct, fields = candidate
+            fopmode = opmode_prefix(
+                (dct['mode'], dct['opmode'], dct['admode']))
+            mode = dct['mode']
+            size, opmode, admode = dct['mode'], dct['opmode'], dct['admode']
+            # no mode64 exinstance in name means no 64bit version of mnemo
+            if mode == 64:
+                if mode in self.args['name']:
+                    nfields = fields[:]
+                    f, i = getfieldindexby_name(nfields, 'rex_w')
+                    f = bs("1", l=0, cls=(bs_fbit,), fname="rex_w")
+                    osize = v_opmode_info(size, opmode, 1, 0)
+                    nfields[i] = f
+                    nfields = nfields[:-1]
+                    ndct = dict(dct)
+                    if osize in self.args['name']:
+                        ndct['name'] = self.args['name'][osize]
+                        out.append((cls, ndct['name'], bases, ndct, nfields))
+
+                    nfields = fields[:]
+                    nfields = nfields[:-1]
+                    f, i = getfieldindexby_name(nfields, 'rex_w')
+                    f = bs("0", l=0, cls=(bs_fbit,), fname="rex_w")
+                    osize = v_opmode_info(size, opmode, 0, 0)
+                    nfields[i] = f
+                    ndct = dict(dct)
+                    if osize in self.args['name']:
+                        ndct['name'] = self.args['name'][osize]
+                        out.append((cls, ndct['name'], bases, ndct, nfields))
+            else:
+                l = opmode_prefix((dct['mode'], dct['opmode'], dct['admode']))
+                osize = v_opmode_info(size, opmode, None, 0)
+                nfields = fields[:-1]
+                ndct = dict(dct)
+                if osize in self.args['name']:
+                    ndct['name'] = self.args['name'][osize]
+                    out.append((cls, ndct['name'], bases, ndct, nfields))
+        return out
+
+
+class bs_modname_jecx(bs_divert):
+    prio = 1
+
+    def divert(self, i, candidates):
+        out = []
+        for candidate in candidates:
+            cls, name, bases, dct, fields = candidate
+            fopmode = opmode_prefix(
+                (dct['mode'], dct['opmode'], dct['admode']))
+            mode = dct['mode']
+            size, opmode, admode = dct['mode'], dct['opmode'], dct['admode']
+
+            nfields = fields[:]
+            nfields = nfields[:-1]
+            args = dict(self.args)
+            ndct = dict(dct)
+            if mode == 64:
+                if admode:
+                    ndct['name'] = "JECXZ"
+                else:
+                    ndct['name'] = "JRCXZ"
+            elif mode == 32:
+                if admode:
+                    ndct['name'] = "JCXZ"
+                else:
+                    ndct['name'] = "JECXZ"
+            elif mode == 16:
+                if admode:
+                    ndct['name'] = "JECXZ"
+                else:
+                    ndct['name'] = "JCXZ"
+            else:
+                raise ValueError('unhandled mode')
+            out.append((cls, ndct['name'], bases, ndct, nfields))
+        return out
+
+
+class bs_modname_mode(bs_divert):
+    prio = 1
+
+    def divert(self, i, candidates):
+        out = []
+        for candidate in candidates:
+            cls, name, bases, dct, fields = candidate
+            fopmode = opmode_prefix(
+                (dct['mode'], dct['opmode'], dct['admode']))
+            size, opmode, admode = dct['mode'], dct['opmode'], dct['admode']
+
+            mode = dct['mode']
+            l = opmode_prefix((dct['mode'], dct['opmode'], dct['admode']))
+            osize = v_opmode_info(size, opmode, None, 0)
+            nfields = fields[:-1]
+            args = dict(self.args)
+            ndct = dict(dct)
+            if mode == 64 or osize == 32:
+                ndct['name'] = self.args['name'][mode]
+            else:
+                ndct['name'] = self.args['name'][16]
+            out.append((cls, ndct['name'], bases, ndct, nfields))
+        return out
+
+
+class x86_imm(imm_noarg):
+    parser = base_expr
+
+    def decodeval(self, v):
+        return swap_uint(self.l, v)
+
+    def encodeval(self, v):
+        return swap_uint(self.l, v)
+
+
+class x86_imm_fix_08(imm_noarg):
+    parser = base_expr
+    intsize = 8
+    intmask = (1 << intsize) - 1
+
+    def decodeval(self, v):
+        return self.ival
+
+    def encode(self):
+        v = self.expr2int(self.expr)
+        if v != self.ival:
+            return False
+        self.value = 0
+        return True
+
+
+class x86_08(x86_imm):
+    intsize = 8
+    intmask = (1 << intsize) - 1
+
+
+class x86_16(x86_imm):
+    intsize = 16
+    intmask = (1 << intsize) - 1
+
+
+class x86_32(x86_imm):
+    intsize = 32
+    intmask = (1 << intsize) - 1
+
+
+class x86_64(x86_imm):
+    intsize = 64
+    intmask = (1 << intsize) - 1
+
+
+class x86_08_ne(x86_imm):
+    intsize = 8
+    intmask = (1 << intsize) - 1
+
+    def encode(self):
+        return True
+
+    def decode(self, v):
+        v = swap_uint(self.l, v)
+        p = self.parent
+        admode = p.v_admode()
+        value = sign_ext(v, self.intsize, admode)
+        self.expr = ExprInt(value, admode)
+        return True
+
+
+class x86_16_ne(x86_08_ne):
+    intsize = 16
+    intmask = (1 << intsize) - 1
+
+
+class x86_32_ne(x86_08_ne):
+    intsize = 32
+    intmask = (1 << intsize) - 1
+
+
+class x86_64_ne(x86_08_ne):
+    intsize = 64
+    intmask = (1 << intsize) - 1
+
+
+class x86_s08to16(x86_imm):
+    in_size = 8
+    out_size = 16
+
+    def myexpr(self, x):
+        return ExprInt(x, 16)
+
+    def int2expr(self, v):
+        return self.myexpr(v)
+
+    def expr2int(self, e):
+        if not isinstance(e, ExprInt):
+            return None
+        v = int(e)
+        if v & ~((1 << self.l) - 1) != 0:
+            return None
+        return v
+
+    def decode(self, v):
+        v = v & self.lmask
+        v = self.decodeval(v)
+        if self.parent.v_opmode() == 64:
+            self.expr = ExprInt(sign_ext(v, self.in_size, 64), 64)
+        else:
+            if (1 << (self.l - 1)) & v:
+                v = sign_ext(v, self.l, self.out_size)
+            self.expr = self.myexpr(v)
+        return True
+
+    def encode(self):
+        if not isinstance(self.expr, ExprInt):
+            return False
+        v = int(self.expr)
+        opmode = self.parent.v_opmode()
+
+        out_size = self.out_size
+        if opmode != self.out_size:
+            if opmode == 32 and self.out_size == 64:
+                out_size = opmode
+                if v == sign_ext(
+                    int(v & ((1 << self.in_size) - 1)), self.in_size, out_size):
+                    pass
+                else:
+                    # test with rex_w
+                    self.parent.rex_w.value = 1
+                    opmode = self.parent.v_opmode()
+                    out_size = opmode
+                    if (v != sign_ext(
+                        int(v & ((1 << self.in_size) - 1)),
+                        self.in_size, out_size)):
+                        return False
+        if v != sign_ext(
+            int(v & ((1 << self.in_size) - 1)), self.in_size, out_size):
+            return False
+        v = self.encodeval(v)
+        self.value = (v & 0xffffffff) & self.lmask
+        return True
+
+    def decodeval(self, v):
+        return swap_uint(self.l, v)
+
+    def encodeval(self, v):
+        return swap_sint(self.l, v)
+
+
+class x86_s08to32(x86_s08to16):
+    in_size = 8
+    out_size = 32
+
+    def myexpr(self, x):
+        return ExprInt(x, 32)
+
+    def decode(self, v):
+        v = v & self.lmask
+        v = self.decodeval(v)
+        if self.parent.rex_w.value == 1:
+            v = ExprInt(sign_ext(v, self.in_size, 64), 64)
+        else:
+            v = ExprInt(sign_ext(v, self.in_size, 32), 32)
+
+        self.expr = v
+        return True
+
+
+class x86_s08to64(x86_s08to32):
+    in_size = 8
+    out_size = 64
+
+    def myexpr(self, x):
+        return ExprInt(x, 64)
+
+
+class x86_s32to64(x86_s08to32):
+    in_size = 32
+    out_size = 64
+
+    def myexpr(self, x):
+        return ExprInt(x, 64)
+
+
+class bs_eax(x86_arg):
+    reg_info = r_eax_all
+    rindex = 0
+    parser = reg_info.parser
+
+    def decode(self, v):
+        p = self.parent
+        expr = None
+        if hasattr(p, 'w8') and p.w8.value == 0:
+            expr = regs08_expr[self.rindex]
+        else:
+            expr = size2gpregs[p.v_opmode()].expr[self.rindex]
+        self.expr = expr
+        return True
+
+    def encode(self):
+        self.value = 0
+        p = self.parent
+        expr = self.expr
+        osize = p.v_opmode()
+        if hasattr(p, 'w8'):
+            if p.w8.value is None:
+                # XXX TODO: priority in w8 erase?
+                if expr.size == 8:
+                    p.w8.value = 0
+                else:
+                    p.w8.value = 1
+        if hasattr(p, 'w8') and p.w8.value == 0:
+            return expr == regs08_expr[self.rindex]
+        elif p.mode in [16, 32]:
+            return expr == size2gpregs[osize].expr[self.rindex]
+        elif p.mode == 64:
+            if expr == size2gpregs[64].expr[self.rindex]:
+                p.rex_w.value = 1
+                return True
+            elif expr == size2gpregs[osize].expr[self.rindex]:
+                return True
+            return False
+        return False
+
+class bs_seg(x86_arg):
+    reg_info = r_eax_all
+    rindex = 0
+    parser = reg_info.parser
+
+    def decode(self, v):
+        self.expr = self.reg_info.expr[0]
+        return True
+
+    def encode(self):
+        self.value = 0
+        return self.expr == self.reg_info.expr[0]
+
+
+class bs_edx(bs_eax):
+    reg_info = r_edx_all
+    rindex = 2
+    parser = reg_info.parser
+
+
+class bs_st(bs_eax):
+    reg_info = r_st_all
+    rindex = 0
+    parser = reg_info.parser
+
+
+class bs_cs(bs_seg):
+    reg_info = r_cs_all
+    rindex = 0
+    parser = reg_info.parser
+
+
+class bs_ds(bs_seg):
+    reg_info = r_ds_all
+    rindex = 0
+    parser = reg_info.parser
+
+
+class bs_es(bs_seg):
+    reg_info = r_es_all
+    rindex = 0
+    parser = reg_info.parser
+
+
+class bs_ss(bs_seg):
+    reg_info = r_ss_all
+    rindex = 0
+    parser = reg_info.parser
+
+
+class bs_fs(bs_seg):
+    reg_info = r_fs_all
+    rindex = 0
+    parser = reg_info.parser
+
+
+class bs_gs(bs_seg):
+    reg_info = r_gs_all
+    rindex = 0
+    parser = reg_info.parser
+
+
+class x86_reg_st(reg_noarg, x86_arg):
+    reg_info = r_st_all
+    parser = reg_info.parser
+
+
+class bs_sib_scale(bs_divert):
+    bsname = "sib_scale"
+
+    def divert(self, i, candidates):
+        out = []
+        done = False
+        for cls, name, bases, dct, fields in candidates:
+            if (not (admode_prefix(
+                (dct['mode'], dct['opmode'], dct['admode'])) != 16 and
+                'rm' in dct and dct['rm'] == 0b100 and
+                'mod' in dct and dct['mod'] != 0b11)):
+                ndct = dict(dct)
+                nfields = fields[:]
+                nfields[i] = None
+                ndct[self.args['fname']] = None
+                out.append((cls, ndct['name'], bases, ndct, nfields))
+                continue
+
+            nfields = fields[:]
+            args = dict(self.args)
+            ndct = dict(dct)
+            f = bs(**args)
+            nfields[i] = f
+            ndct[self.args['fname']] = None
+            out.append((cls, ndct['name'], bases, ndct, nfields))
+        return out
+
+
+class bs_sib_index(bs_sib_scale):
+    pass
+
+
+class bs_sib_base(bs_sib_scale):
+    pass
+
+
+class bs_disp(bs_divert):
+
+    def divert(self, i, candidates):
+        out = []
+        done = False
+        for cls, name, bases, dct, fields in candidates:
+            ndct = dict(dct)
+            nfields = fields[:]
+            if (admode_prefix(
+                (dct['mode'], dct['opmode'], dct['admode'])) == 16):
+                if 'mod' in dct and dct['mod'] == 0b00 and \
+                        'rm' in dct and dct['rm'] == 0b110:
+                    nfields[i] = bs(
+                        l=16, cls=(x86_16_ne,), fname=self.args['fname'])
+                    ndct[self.args['fname']] = True
+                    out.append((cls, ndct['name'], bases, ndct, nfields))
+                    continue
+                elif 'mod' in dct and dct['mod'] == 0b01:
+                    nfields[i] = bs(
+                        l=8, cls=(x86_08_ne,), fname=self.args['fname'])
+                    ndct[self.args['fname']] = True
+                    out.append((cls, ndct['name'], bases, ndct, nfields))
+                    continue
+                elif 'mod' in dct and dct['mod'] == 0b10:
+                    nfields[i] = bs(
+                        l=16, cls=(x86_16_ne,), fname=self.args['fname'])
+                    ndct[self.args['fname']] = True
+                    out.append((cls, ndct['name'], bases, ndct, nfields))
+                    continue
+            else:
+                if 'mod' in dct and dct['mod'] == 0b00 and \
+                        'rm' in dct and dct['rm'] == 0b101:
+                    nfields[i] = bs(
+                        l=32, cls=(x86_32_ne,), fname=self.args['fname'])
+                    ndct[self.args['fname']] = True
+                    out.append((cls, ndct['name'], bases, ndct, nfields))
+                    continue
+                elif 'mod' in dct and dct['mod'] == 0b01:
+                    nfields[i] = bs(
+                        l=8, cls=(x86_08_ne,), fname=self.args['fname'])
+                    ndct[self.args['fname']] = True
+                    out.append((cls, ndct['name'], bases, ndct, nfields))
+                    continue
+                elif 'mod' in dct and dct['mod'] == 0b10:
+                    nfields[i] = bs(
+                        l=32, cls=(x86_32_ne,), fname=self.args['fname'])
+                    ndct[self.args['fname']] = True
+                    out.append((cls, ndct['name'], bases, ndct, nfields))
+                    continue
+
+            nfields[i] = None
+            ndct[self.args['fname']] = None
+            out.append((cls, ndct['name'], bases, ndct, nfields))
+        return out
+
+
+def getmodrm(c):
+    return (c >> 6) & 3, (c >> 3) & 7, c & 7
+
+
+def setmodrm(mod, re, rm):
+    return ((mod & 3) << 6) | ((re & 7) << 3) | (rm & 7)
+
+
+def sib(c):
+    return modrm(c)
+
+db_afs_64 = []
+sib_64_s08_ebp = []
+
+
+def gen_modrm_form():
+    global db_afs_64, sib_64_s08_ebp
+    ebp = 5
+
+    sib_s08_ebp = [{f_isad: True} for i in range(0x100)]
+    sib_u32_ebp = [{f_isad: True} for i in range(0x100)]
+    sib_u32 = [{f_isad: True} for i in range(0x100)]
+
+    sib_u64 = []
+    for rex_x in range(2):
+        o = []
+        for rex_b in range(2):
+            x = [{f_isad: True} for i in range(0x100)]
+            o.append(x)
+        sib_u64.append(o)
+
+    sib_u64_ebp = []
+    for rex_x in range(2):
+        o = []
+        for rex_b in range(2):
+            x = [{f_isad: True} for i in range(0x100)]
+            o.append(x)
+        sib_u64_ebp.append(o)
+
+    sib_64_s08_ebp = []
+    for rex_x in range(2):
+        o = []
+        for rex_b in range(2):
+            x = [{f_isad: True} for i in range(0x100)]
+            o.append(x)
+        sib_64_s08_ebp.append(o)
+
+    for sib_rez in [sib_s08_ebp,
+                    sib_u32_ebp,
+                    sib_u32,
+                    sib_64_s08_ebp,
+                    sib_u64_ebp,
+                    sib_u64,
+                    ]:
+        for index in range(0x100):
+            ss, i, b = getmodrm(index)
+
+            if b == 0b101:
+                if sib_rez == sib_s08_ebp:
+                    sib_rez[index][f_imm] = f_s08
+                    sib_rez[index][ebp] = 1
+                elif sib_rez == sib_u32_ebp:
+                    sib_rez[index][f_imm] = f_u32
+                    sib_rez[index][ebp] = 1
+                elif sib_rez == sib_u32:
+                    sib_rez[index][f_imm] = f_u32
+                elif sib_rez == sib_u64_ebp:
+                    for rex_b in range(2):
+                        for rex_x in range(2):
+                            sib_rez[rex_x][rex_b][index][f_imm] = f_u32
+                            sib_rez[rex_x][rex_b][index][ebp + 8 * rex_b] = 1
+                elif sib_rez == sib_u64:
+                    for rex_b in range(2):
+                        for rex_x in range(2):
+                            sib_rez[rex_x][rex_b][index][f_imm] = f_u32
+                elif sib_rez == sib_64_s08_ebp:
+                    for rex_b in range(2):
+                        for rex_x in range(2):
+                            sib_rez[rex_x][rex_b][index][f_imm] = f_s08
+                            sib_rez[rex_x][rex_b][index][ebp + 8 * rex_b] = 1
+
+            else:
+                if sib_rez == sib_s08_ebp:
+                    sib_rez[index][b] = 1
+                    sib_rez[index][f_imm] = f_s08
+                elif sib_rez == sib_u32_ebp:
+                    sib_rez[index][b] = 1
+                    sib_rez[index][f_imm] = f_u32
+                elif sib_rez == sib_u32:
+                    sib_rez[index][b] = 1
+                elif sib_rez == sib_u64_ebp:
+                    for rex_b in range(2):
+                        for rex_x in range(2):
+                            sib_rez[rex_x][rex_b][index][b + 8 * rex_b] = 1
+                            sib_rez[rex_x][rex_b][index][f_imm] = f_u32
+                elif sib_rez == sib_u64:
+                    for rex_b in range(2):
+                        for rex_x in range(2):
+                            sib_rez[rex_x][rex_b][index][b + 8 * rex_b] = 1
+                elif sib_rez == sib_64_s08_ebp:
+                    for rex_b in range(2):
+                        for rex_x in range(2):
+                            sib_rez[rex_x][rex_b][index][f_imm] = f_s08
+                            sib_rez[rex_x][rex_b][index][b + 8 * rex_b] = 1
+
+            if i == 0b100 and sib_rez in [sib_s08_ebp, sib_u32_ebp, sib_u32]:
+                continue
+
+            if sib_rez in [sib_s08_ebp, sib_u32_ebp, sib_u32]:
+                tmp = i
+                if not tmp in sib_rez[index]:
+                    sib_rez[index][tmp] = 0  # 1 << ss
+                sib_rez[index][tmp] += 1 << ss
+            else:
+                for rex_b in range(2):
+                    for rex_x in range(2):
+                        tmp = i + 8 * rex_x
+                        if i == 0b100 and rex_x == 0:
+                            continue
+                        if not tmp in sib_rez[rex_x][rex_b][index]:
+                            sib_rez[rex_x][rex_b][index][tmp] = 0  # 1 << ss
+                        sib_rez[rex_x][rex_b][index][tmp] += 1 << ss
+
+    # 32bit
+    db_afs_32 = [None for i in range(0x100)]
+    for i in range(0x100):
+        index = i
+        mod, re, rm = getmodrm(i)
+
+        if mod == 0b00:
+            if rm == 0b100:
+                db_afs_32[index] = sib_u32
+            elif rm == 0b101:
+                db_afs_32[index] = {f_isad: True, f_imm: f_u32}
+            else:
+                db_afs_32[index] = {f_isad: True, rm: 1}
+        elif mod == 0b01:
+            if rm == 0b100:
+                db_afs_32[index] = sib_s08_ebp
+                continue
+            tmp = {f_isad: True, rm: 1, f_imm: f_s08}
+            db_afs_32[index] = tmp
+
+        elif mod == 0b10:
+            if rm == 0b100:
+                db_afs_32[index] = sib_u32_ebp
+            else:
+                db_afs_32[index] = {f_isad: True, rm: 1, f_imm: f_u32}
+        elif mod == 0b11:
+            db_afs_32[index] = {f_isad: False, rm: 1}
+
+    # 64bit
+    db_afs_64 = [None for i in range(0x400)]
+    for i in range(0x400):
+        index = i
+        rex_x = (index >> 9) & 1
+        rex_b = (index >> 8) & 1
+        mod, re, rm = getmodrm(i & 0xff)
+
+        if mod == 0b00:
+            if rm == 0b100:
+                db_afs_64[i] = sib_u64[rex_x][rex_b]
+            elif rm == 0b101:
+                db_afs_64[i] = {f_isad: True, f_imm: f_u32, 16: 1}
+            else:
+                db_afs_64[i] = {f_isad: True, rm + 8 * rex_b: 1}
+        elif mod == 0b01:
+            if rm == 0b100:
+                db_afs_64[i] = sib_64_s08_ebp[rex_x][rex_b]
+                continue
+            tmp = {f_isad: True, rm + 8 * rex_b: 1, f_imm: f_s08}
+            db_afs_64[i] = tmp
+
+        elif mod == 0b10:
+            if rm == 0b100:
+                db_afs_64[i] = sib_u64_ebp[rex_x][rex_b]
+            else:
+                db_afs_64[i] = {f_isad: True, rm + 8 * rex_b: 1, f_imm: f_u32}
+        elif mod == 0b11:
+            db_afs_64[i] = {f_isad: False, rm + 8 * rex_b: 1}
+
+    # 16bit
+    db_afs_16 = [None for i in range(0x100)]
+    _si = 6
+    _di = 7
+    _bx = 3
+    _bp = 5
+    for i in range(0x100):
+        index = i
+        mod, re, rm = getmodrm(i)
+
+        if mod == 0b00:
+            if rm == 0b100:
+                db_afs_16[index] = {f_isad: True, _si: 1}
+            elif rm == 0b101:
+                db_afs_16[index] = {f_isad: True, _di: 1}
+            elif rm == 0b110:
+                db_afs_16[index] = {
+                    f_isad: True, f_imm: f_u16}  # {f_isad:True,_bp:1}
+            elif rm == 0b111:
+                db_afs_16[index] = {f_isad: True, _bx: 1}
+            else:
+                db_afs_16[index] = {f_isad: True,
+                         [_si, _di][rm % 2]: 1,
+                    [_bx, _bp][(rm >> 1) % 2]: 1}
+        elif mod in [0b01, 0b10]:
+            if mod == 0b01:
+                my_imm = f_s08
+            else:
+                my_imm = f_u16
+
+            if rm == 0b100:
+                db_afs_16[index] = {f_isad: True, _si: 1, f_imm: my_imm}
+            elif rm == 0b101:
+                db_afs_16[index] = {f_isad: True, _di: 1, f_imm: my_imm}
+            elif rm == 0b110:
+                db_afs_16[index] = {f_isad: True, _bp: 1, f_imm: my_imm}
+            elif rm == 0b111:
+                db_afs_16[index] = {f_isad: True, _bx: 1, f_imm: my_imm}
+            else:
+                db_afs_16[index] = {f_isad: True,
+                         [_si, _di][rm % 2]: 1,
+                    [_bx, _bp][(rm >> 1) % 2]: 1,
+                    f_imm: my_imm}
+
+        elif mod == 0b11:
+            db_afs_16[index] = {f_isad: False, rm: 1}
+
+    byte2modrm = {}
+    byte2modrm[16] = db_afs_16
+    byte2modrm[32] = db_afs_32
+    byte2modrm[64] = db_afs_64
+
+    modrm2byte = {16: defaultdict(list),
+                  32: defaultdict(list),
+                  64: defaultdict(list),
+                  }
+    for size, db_afs in viewitems(byte2modrm):
+        for i, modrm in enumerate(db_afs):
+            if not isinstance(modrm, list):
+                # We only need sort for determinism
+                modrm = tuple(sorted(viewitems(modrm), key=str))
+                modrm2byte[size][modrm].append(i)
+                continue
+            for j, modrm_f in enumerate(modrm):
+                # We only need sort for determinism
+                modrm_f = tuple(sorted(viewitems(modrm_f), key=str))
+                modrm2byte[size][modrm_f].append((i, j))
+
+    return byte2modrm, modrm2byte
+
+byte2modrm, modrm2byte = gen_modrm_form()
+
+
+# ret is modr; ret is displacement
+def exprfindmod(e, o=None):
+    if o is None:
+        o = {}
+    if isinstance(e, ExprInt):
+        return e
+    if isinstance(e, ExprId):
+        i = size2gpregs[e.size].expr.index(e)
+        o[i] = 1
+        return None
+    elif isinstance(e, ExprOp):
+        out = None
+        if e.op == '+':
+            for a in e.args:
+                r = exprfindmod(a, o)
+                if out and r:
+                    raise ValueError('multiple displacement!')
+                out = r
+            return out
+        elif e.op == "*":
+            mul = int(e.args[1])
+            a = e.args[0]
+            i = size2gpregs[a.size].expr.index(a)
+            o[i] = mul
+        else:
+            raise ValueError('bad op')
+    return None
+
+def test_addr_size(ptr, size):
+    if isinstance(ptr, ExprInt):
+        return int(ptr) < (1 << size)
+    else:
+        return ptr.size == size
+
+SIZE2XMMREG = {64:gpregs_mm,
+               128:gpregs_xmm}
+SIZE2BNDREG = {64:gpregs_mm,
+               128:gpregs_bnd}
+
+def parse_mem(expr, parent, w8, sx=0, xmm=0, mm=0, bnd=0):
+    dct_expr = {}
+    opmode = parent.v_opmode()
+    if is_mem_segm(expr) and expr.ptr.args[0].is_int():
+        return None, None, False
+
+    if is_mem_segm(expr):
+        segm = expr.ptr.args[0]
+        ptr = expr.ptr.args[1]
+    else:
+        segm = None
+        ptr = expr.ptr
+
+    dct_expr[f_isad] = True
+    ad_size = ptr.size
+    admode = parent.v_admode()
+    if not test_addr_size(ptr, admode):
+        return None, None, False
+
+    if (w8 == 1 and expr.size != opmode and not sx and
+        not (hasattr(parent, 'sd') or hasattr(parent, 'wd'))):
+        return None, None, False
+
+    if hasattr(parent, 'wd'):
+        if expr.size == 16:
+            parent.wd.value = 1
+        elif expr.size == 32:
+            pass
+        else:
+            return None, None, False
+
+    if (not isinstance(ptr, ExprInt) and
+        parent.mode == 64 and
+        ptr.size == 32 and
+        parent.admode != 1):
+        return None, None, False
+    dct_expr = {f_isad: True}
+    disp = exprfindmod(ptr, dct_expr)
+    out = []
+    if disp is None:
+        # add 0 disp
+        disp = ExprInt(0, 32)
+    if disp is not None:
+        for signed, encoding, cast_size in [(True, f_s08, 8),
+                                           (True, f_s16, 16),
+                                           (True, f_s32, 32),
+                                           (False, f_u08, 8),
+                                           (False, f_u16, 16),
+                                           (False, f_u32, 32)]:
+            value = ExprInt(int(disp), cast_size)
+            if admode < value.size:
+                if signed:
+                    if int(disp) != sign_ext(int(value), admode, disp.size):
+                        continue
+                else:
+                    if int(disp) != int(value):
+                        continue
+            else:
+                if int(disp) != sign_ext(int(value), value.size, admode):
+                    continue
+            x1 = dict(dct_expr)
+            x1[f_imm] = (encoding, value)
+            out.append(x1)
+    else:
+        out = [dct_expr]
+    return out, segm, True
+
+def expr2modrm(expr, parent, w8, sx=0, xmm=0, mm=0, bnd=0):
+    dct_expr = {f_isad : False}
+
+    if mm or xmm or bnd:
+        if mm and expr.size != 64:
+            return None, None, False
+        elif xmm and expr.size != 128:
+            return None, None, False
+        elif bnd and expr.size != 128:
+            return None, None, False
+
+        if isinstance(expr, ExprId):
+            if bnd:
+                size2reg = SIZE2BNDREG
+            else:
+                size2reg = SIZE2XMMREG
+            selreg = size2reg[expr.size]
+            if not expr in selreg.expr:
+                return None, None, False
+            i = selreg.expr.index(expr)
+            dct_expr[i] = 1
+            return [dct_expr], None, True
+        else:
+            return parse_mem(expr, parent, w8, sx, xmm, mm)
+
+    elif expr.size == 64 and expr not in gpregs_mm.expr:
+        if hasattr(parent, 'sd'):
+            parent.sd.value = 1
+        elif hasattr(parent, 'wd'):
+            pass
+        elif hasattr(parent, 'stk'):
+            pass
+        else:
+            parent.rex_w.value = 1
+    opmode = parent.v_opmode()
+    if sx == 1:
+        opmode = 16
+    if sx == 2:
+        opmode = 32
+    if expr.size == 8 and w8 != 0:
+        return None, None, False
+
+    if w8 == 0 and expr.size != 8:
+        return None, None, False
+
+    if not isinstance(expr, ExprMem):
+        dct_expr[f_isad] = False
+        if xmm:
+            if expr in gpregs_xmm.expr:
+                i = gpregs_xmm.expr.index(expr)
+                dct_expr[i] = 1
+                return [dct_expr], None, True
+            else:
+                return None, None, False
+        if bnd:
+            if expr in gpregs_bnd.expr:
+                i = gpregs_bnd.expr.index(expr)
+                dct_expr[i] = 1
+                return [dct_expr], None, True
+            else:
+                return None, None, False
+        if mm:
+            if expr in gpregs_mm.expr:
+                i = gpregs_mm.expr.index(expr)
+                dct_expr[i] = 1
+                return [dct_expr], None, True
+            else:
+                return None, None, False
+        if w8 == 0:
+            if parent.mode == 64 and expr in gpregs08_64.expr:
+                r = gpregs08_64
+                parent.rex_p.value = 1
+            else:
+                parent.rex_p.value = 0
+                parent.rex_x.value = 0
+                r = size2gpregs[8]
+            if not expr in r.expr:
+                return None, None, False
+            i = r.expr.index(expr)
+            dct_expr[i] = 1
+            return [dct_expr], None, True
+        if opmode != expr.size:
+            return None, None, False
+        if not expr in size2gpregs[opmode].expr:
+            return None, None, False
+        i = size2gpregs[opmode].expr.index(expr)
+        if i > 7:
+            if parent.mode != 64:
+                return None, None, False
+        dct_expr[i] = 1
+        return [dct_expr], None, True
+    return parse_mem(expr, parent, w8, sx, xmm, mm, bnd)
+
+def modrm2expr(modrm, parent, w8, sx=0, xmm=0, mm=0, bnd=0):
+    o = []
+    if not modrm[f_isad]:
+        modrm_k = [key for key, value in viewitems(modrm) if value == 1]
+        if len(modrm_k) != 1:
+            raise ValueError('strange reg encoding %r' % modrm)
+        modrm_k = modrm_k[0]
+        if w8 == 0:
+            opmode = 8
+        elif sx == 1:
+            opmode = 16
+        elif sx == 2:
+            opmode = 32
+        else:
+            opmode = parent.v_opmode()
+        if xmm:
+            expr = gpregs_xmm.expr[modrm_k]
+        elif mm:
+            expr = gpregs_mm.expr[modrm_k]
+        elif bnd:
+            expr = gpregs_bnd.expr[modrm_k]
+        elif opmode == 8 and (parent.v_opmode() == 64 or parent.rex_p.value == 1):
+            expr = gpregs08_64.expr[modrm_k]
+        else:
+            expr = size2gpregs[opmode].expr[modrm_k]
+        return expr
+    admode = parent.v_admode()
+    opmode = parent.v_opmode()
+    for modrm_k, scale in viewitems(modrm):
+        if isinstance(modrm_k, int):
+            expr = size2gpregs[admode].expr[modrm_k]
+            if scale != 1:
+                expr = ExprInt(scale, admode) * expr
+            o.append(expr)
+    if f_imm in modrm:
+        if parent.disp.value is None:
+            return None
+        o.append(ExprInt(int(parent.disp.expr), admode))
+    if len(o) == 1:
+        expr = o[0]
+    else:
+        expr = ExprOp('+', *o)
+    if w8 == 0:
+        opmode = 8
+    elif sx == 1:
+        opmode = 16
+    elif sx == 2:
+        opmode = 32
+    if xmm:
+        opmode = 128
+    elif mm:
+        opmode = 64
+    elif bnd:
+        opmode = 128
+
+    expr = ExprMem(expr, size=opmode)
+    return expr
+
+
+class x86_rm_arg(x86_arg):
+    parser = rmarg
+
+    def fromstring(self, text, loc_db, parser_result=None):
+        start, stop = super(x86_rm_arg, self).fromstring(text, loc_db, parser_result)
+        p = self.parent
+        if start is None:
+            return None, None
+        return start, stop
+
+    def get_modrm(self):
+        p = self.parent
+        admode = p.v_admode()
+
+        if not admode in [16, 32, 64]:
+            raise ValueError('strange admode %r', admode)
+        v = setmodrm(p.mod.value, 0, p.rm.value)
+        v |= p.rex_b.value << 8
+        v |= p.rex_x.value << 9
+        if p.mode == 64:
+            # XXXx to check
+            admode = 64
+
+        xx = byte2modrm[admode][v]
+        if isinstance(xx, list):
+            if not p.sib_scale:
+                return False
+            v = setmodrm(p.sib_scale.value,
+                         p.sib_index.value,
+                         p.sib_base.value)
+            xx = xx[v]
+        return xx
+
+    def decode(self, v):
+        p = self.parent
+        xx = self.get_modrm()
+        self.expr = modrm2expr(xx, p, 1)
+        return self.expr is not None
+
+    def gen_cand(self, v_cand, admode):
+        if not admode in modrm2byte:
+            # XXX TODO: 64bit
+            return
+        if not v_cand:
+            return
+
+        p = self.parent
+        o_rex_x = p.rex_x.value
+        o_rex_b = p.rex_b.value
+        # add candidate without 0 imm
+        new_v_cand = []
+        moddd = False
+        for v in v_cand:
+            new_v_cand.append(v)
+            if f_imm in v and int(v[f_imm][1]) == 0:
+                v = dict(v)
+                del(v[f_imm])
+                new_v_cand.append(v)
+                moddd = True
+
+        v_cand = new_v_cand
+
+        out_c = []
+        for v in v_cand:
+            disp = None
+            # patch value in modrm
+            if f_imm in v:
+                size, disp = v[f_imm]
+                disp = int(disp)
+
+                v[f_imm] = size
+            vo = v
+            # We only need sort for determinism
+            v = tuple(sorted(viewitems(v), key=str))
+            admode = 64 if p.mode == 64 else admode
+            if not v in modrm2byte[admode]:
+                continue
+            xx = modrm2byte[admode][v]
+
+            # default case
+            for x in xx:
+                if type(x) == tuple:
+                    modrm, sib = x
+                else:
+                    modrm = x
+                    sib = None
+
+                # 16 bit cannot have sib
+                if sib is not None and admode == 16:
+                    continue
+                rex = modrm >> 8  # 0# XXX HACK REM temporary REX modrm>>8
+                if rex and admode != 64:
+                    continue
+
+                p.rex_x.value = (rex >> 1) & 1
+                p.rex_b.value = rex & 1
+
+                if o_rex_x is not None and p.rex_x.value != o_rex_x:
+                    continue
+                if o_rex_b is not None and p.rex_b.value != o_rex_b:
+                    continue
+
+                mod, re, rm = getmodrm(modrm)
+                # check re on parent
+                if hasattr(p, 'reg') and re != p.reg.value:
+                    continue
+
+                if sib is not None:
+                    s_scale, s_index, s_base = getmodrm(sib)
+                else:
+                    s_scale, s_index, s_base = None, None, None
+
+                p.mod.value = mod
+                p.rm.value = rm
+                p.sib_scale.value = s_scale
+                p.sib_index.value = s_index
+                p.sib_base.value = s_base
+                p.disp.value = disp
+                if disp is not None:
+                    p.disp.l = f_imm2size[vo[f_imm]]
+
+                yield True
+
+        return
+
+    def encode(self):
+        if isinstance(self.expr, ExprInt):
+            return
+        p = self.parent
+        admode = p.v_admode()
+        mode = self.expr.size
+        v_cand, segm, ok = expr2modrm(self.expr, p, 1)
+        if segm:
+            p.g2.value = segm2enc[segm]
+        for x in self.gen_cand(v_cand, admode):
+            yield x
+
+class x86_rm_mem(x86_rm_arg):
+    def fromstring(self, text, loc_db, parser_result=None):
+        self.expr = None
+        start, stop = super(x86_rm_mem, self).fromstring(text, loc_db, parser_result)
+        if not isinstance(self.expr, ExprMem):
+            return None, None
+        return start, stop
+
+
+class x86_rm_mem_far(x86_rm_arg):
+    parser = mem_far
+    def fromstring(self, text, loc_db, parser_result=None):
+        self.expr = None
+        start, stop = super(x86_rm_mem_far, self).fromstring(text, loc_db, parser_result)
+        if not isinstance(self.expr, ExprMem):
+            return None, None
+        self.expr = ExprOp('far', self.expr)
+        return start, stop
+
+    def decode(self, v):
+        ret = super(x86_rm_mem_far, self).decode(v)
+        if not ret:
+            return ret
+        if isinstance(self.expr, m2_expr.ExprMem):
+            self.expr = ExprOp('far', self.expr)
+        return True
+
+    def encode(self):
+        if not (isinstance(self.expr, m2_expr.ExprOp) and
+                self.expr.op == 'far'):
+            return
+
+        expr = self.expr.args[0]
+        if isinstance(expr, ExprInt):
+            return
+        p = self.parent
+        admode = p.v_admode()
+        mode = expr.size
+        v_cand, segm, ok = expr2modrm(expr, p, 1)
+        if segm:
+            p.g2.value = segm2enc[segm]
+        for x in self.gen_cand(v_cand, admode):
+            yield x
+
+class x86_rm_w8(x86_rm_arg):
+
+    def decode(self, v):
+        p = self.parent
+        xx = self.get_modrm()
+        self.expr = modrm2expr(xx, p, p.w8.value)
+        return self.expr is not None
+
+    def encode(self):
+        if isinstance(self.expr, ExprInt):
+            return
+        p = self.parent
+        if p.w8.value is None:
+            if self.expr.size == 8:
+                p.w8.value = 0
+            else:
+                p.w8.value = 1
+
+        v_cand, segm, ok = expr2modrm(self.expr, p, p.w8.value)
+        if segm:
+            p.g2.value = segm2enc[segm]
+        for x in self.gen_cand(v_cand, p.v_admode()):
+            yield x
+
+
+class x86_rm_sx(x86_rm_arg):
+
+    def decode(self, v):
+        p = self.parent
+        xx = self.get_modrm()
+        self.expr = modrm2expr(xx, p, p.w8.value, 1)
+        return self.expr is not None
+
+    def encode(self):
+        if isinstance(self.expr, ExprInt):
+            return
+        p = self.parent
+        if p.w8.value is None:
+            if self.expr.size == 8:
+                p.w8.value = 0
+            else:
+                p.w8.value = 1
+        v_cand, segm, ok = expr2modrm(self.expr, p, p.w8.value, 1)
+        if segm:
+            p.g2.value = segm2enc[segm]
+        for x in self.gen_cand(v_cand, p.v_admode()):
+            yield x
+
+
+class x86_rm_sxd(x86_rm_arg):
+
+    def decode(self, v):
+        p = self.parent
+        xx = self.get_modrm()
+        self.expr = modrm2expr(xx, p, 1, 2)
+        return self.expr is not None
+
+    def encode(self):
+        if isinstance(self.expr, ExprInt):
+            return
+        p = self.parent
+        v_cand, segm, ok = expr2modrm(self.expr, p, 1, 2)
+        if segm:
+            p.g2.value = segm2enc[segm]
+        for x in self.gen_cand(v_cand, p.v_admode()):
+            yield x
+
+
+class x86_rm_sd(x86_rm_arg):
+    out_size = 64
+    def get_s_value(self):
+        return self.parent.sd.value
+    def set_s_value(self, value):
+        self.parent.sd.value = value
+
+    def decode(self, v):
+        p = self.parent
+        xx = self.get_modrm()
+        expr = modrm2expr(xx, p, 1)
+        if not isinstance(expr, ExprMem):
+            return False
+        if self.get_s_value() == 0:
+            expr = ExprMem(expr.ptr, 32)
+        else:
+            expr = ExprMem(expr.ptr, self.out_size)
+        self.expr = expr
+        return self.expr is not None
+
+    def encode(self):
+        if isinstance(self.expr, ExprInt):
+            return
+        p = self.parent
+        if not self.expr.size in [32, 64]:
+            return
+        self.set_s_value(0)
+        v_cand, segm, ok = expr2modrm(self.expr, p, 1)
+        for x in self.gen_cand(v_cand, p.v_admode()):
+            yield x
+
+
+class x86_rm_wd(x86_rm_sd):
+    out_size = 16
+    def get_s_value(self):
+        return self.parent.wd.value
+    def set_s_value(self, value):
+        self.parent.wd.value = value
+
+    def encode(self):
+        if isinstance(self.expr, ExprInt):
+            return
+        p = self.parent
+        p.wd.value = 0
+        v_cand, segm, ok = expr2modrm(self.expr, p, 1)
+        for x in self.gen_cand(v_cand, p.v_admode()):
+            yield x
+
+
+class x86_rm_08(x86_rm_arg):
+    msize = 8
+
+    def decode(self, v):
+        p = self.parent
+        xx = self.get_modrm()
+        expr = modrm2expr(xx, p, 0)
+        if not isinstance(expr, ExprMem):
+            self.expr = expr
+            return True
+        self.expr = ExprMem(expr.ptr, self.msize)
+        return self.expr is not None
+
+    def encode(self):
+        if isinstance(self.expr, ExprInt):
+            return
+        p = self.parent
+        v_cand, segm, ok = expr2modrm(self.expr, p, 0, 0, 0, 0)
+        for x in self.gen_cand(v_cand, p.v_admode()):
+            yield x
+
+class x86_rm_reg_m08(x86_rm_arg):
+    msize = 8
+
+    def decode(self, v):
+        ret = x86_rm_arg.decode(self, v)
+        if not ret:
+            return ret
+        if not isinstance(self.expr, ExprMem):
+            return True
+        self.expr = ExprMem(self.expr.ptr, self.msize)
+        return self.expr is not None
+
+    def encode(self):
+        if isinstance(self.expr, ExprInt):
+            return
+        p = self.parent
+        if isinstance(self.expr, ExprMem):
+            expr = ExprMem(self.expr.ptr, 32)
+        else:
+            expr = self.expr
+        v_cand, segm, ok = expr2modrm(expr, p, 1, 0, 0, 0)
+        for x in self.gen_cand(v_cand, p.v_admode()):
+            yield x
+
+class x86_rm_reg_m16(x86_rm_reg_m08):
+    msize = 16
+
+class x86_rm_m64(x86_rm_arg):
+    msize = 64
+
+    def decode(self, v):
+        p = self.parent
+        xx = self.get_modrm()
+        expr = modrm2expr(xx, p, 1)
+        if not isinstance(expr, ExprMem):
+            return False
+        self.expr = ExprMem(expr.ptr, self.msize)
+        return self.expr is not None
+
+    def encode(self):
+        if isinstance(self.expr, ExprInt):
+            return
+        p = self.parent
+        v_cand, segm, ok = expr2modrm(self.expr, p, 0, 0, 0, 1)
+        for x in self.gen_cand(v_cand, p.v_admode()):
+            yield x
+
+
+class x86_rm_m80(x86_rm_m64):
+    msize = 80
+
+    def encode(self):
+        if isinstance(self.expr, ExprInt):
+            return
+        if not isinstance(self.expr, ExprMem) or self.expr.size != self.msize:
+            return
+        p = self.parent
+        mode = p.mode
+        if mode == 64:
+            mode = 32
+        self.expr = ExprMem(self.expr.ptr, mode)
+        v_cand, segm, ok = expr2modrm(self.expr, p, 1)
+        for x in self.gen_cand(v_cand, p.v_admode()):
+            yield x
+
+
+class x86_rm_m08(x86_rm_arg):
+    msize = 8
+
+    def decode(self, v):
+        p = self.parent
+        xx = self.get_modrm()
+        self.expr = modrm2expr(xx, p, 0)
+        return self.expr is not None
+
+    def encode(self):
+        if self.expr.size != 8:
+            return
+        p = self.parent
+        mode = p.mode
+        v_cand, segm, ok = expr2modrm(self.expr, p, 0)
+        for x in self.gen_cand(v_cand, p.v_admode()):
+            yield x
+
+
+class x86_rm_m16(x86_rm_m80):
+    msize = 16
+
+
+class x86_rm_mm(x86_rm_m80):
+    msize = 64
+    is_mm = True
+    is_xmm = False
+    is_bnd = False
+
+    def decode(self, v):
+        p = self.parent
+        xx = self.get_modrm()
+        expr = modrm2expr(xx, p, 0, 0, self.is_xmm, self.is_mm, self.is_bnd)
+        if isinstance(expr, ExprMem):
+            if self.msize is None:
+                return False
+            if expr.size != self.msize:
+                expr = ExprMem(expr.ptr, self.msize)
+        self.expr = expr
+        return True
+
+
+    def encode(self):
+        expr = self.expr
+        if isinstance(expr, ExprInt):
+            return
+        if isinstance(expr, ExprMem) and expr.size != self.msize:
+            return
+        p = self.parent
+        mode = p.mode
+        if mode == 64:
+            mode = 32
+        if isinstance(expr, ExprMem):
+            if self.is_xmm:
+                expr = ExprMem(expr.ptr, 128)
+            elif self.is_mm:
+                expr = ExprMem(expr.ptr, 64)
+
+        v_cand, segm, ok = expr2modrm(expr, p, 0, 0, self.is_xmm, self.is_mm,
+                                      self.is_bnd)
+        for x in self.gen_cand(v_cand, p.v_admode()):
+            yield x
+
+
+class x86_rm_mm_m64(x86_rm_mm):
+    msize = 64
+    is_mm = True
+    is_xmm = False
+
+class x86_rm_xmm(x86_rm_mm):
+    msize = 128
+    is_mm = False
+    is_xmm = True
+
+
+class x86_rm_xmm_m32(x86_rm_mm):
+    msize = 32
+    is_mm = False
+    is_xmm = True
+
+class x86_rm_xmm_m64(x86_rm_mm):
+    msize = 64
+    is_mm = False
+    is_xmm = True
+
+class x86_rm_xmm_m128(x86_rm_mm):
+    msize = 128
+    is_mm = False
+    is_xmm = True
+
+
+class x86_rm_xmm_reg(x86_rm_mm):
+    msize = None
+    is_mm = False
+    is_xmm = True
+
+class x86_rm_mm_reg(x86_rm_mm):
+    msize = None
+    is_mm = True
+    is_xmm = False
+
+
+class x86_rm_bnd(x86_rm_mm):
+    msize = 128
+    is_mm = False
+    is_xmm = False
+    is_bnd = True
+
+
+class x86_rm_bnd_reg(x86_rm_mm):
+    msize = None
+    is_mm = False
+    is_xmm = False
+    is_bnd = True
+
+
+class x86_rm_bnd_m64(x86_rm_mm):
+    msize = 64
+    is_mm = False
+    is_xmm = False
+    is_bnd = True
+
+
+class x86_rm_bnd_m128(x86_rm_mm):
+    msize = 128
+    is_mm = False
+    is_xmm = False
+    is_bnd = True
+
+
+class x86_rm_reg_noarg(object):
+    prio = default_prio + 1
+
+    parser = gpreg
+
+    def fromstring(self, text, loc_db, parser_result=None):
+        if not hasattr(self.parent, 'sx') and hasattr(self.parent, "w8"):
+            self.parent.w8.value = 1
+        if parser_result:
+            result, start, stop = parser_result[self.parser]
+            if result == [None]:
+                return None, None
+            self.expr = result
+            if self.expr.size == 8:
+                if hasattr(self.parent, 'sx') or not hasattr(self.parent, 'w8'):
+                    return None, None
+                self.parent.w8.value = 0
+            return start, stop
+        try:
+            result, start, stop = next(self.parser.scanString(text))
+        except StopIteration:
+            return None, None
+        expr = self.asm_ast_to_expr(result[0], loc_db)
+        if expr is None:
+            return None, None
+
+        self.expr = expr
+        if self.expr.size == 0:
+            if hasattr(self.parent, 'sx') or not hasattr(self.parent, 'w8'):
+                return None, None
+            self.parent.w8.value = 0
+
+        return start, stop
+
+    def getrexsize(self):
+        return self.parent.rex_r.value
+
+    def setrexsize(self, v):
+        self.parent.rex_r.value = v
+
+    def decode(self, v):
+        v = v & self.lmask
+        p = self.parent
+        opmode = p.v_opmode()
+        if not hasattr(p, 'sx') and (hasattr(p, 'w8') and p.w8.value == 0):
+            opmode = 8
+        r = size2gpregs[opmode]
+        if p.mode == 64 and self.getrexsize():
+            v |= 0x8
+        if p.v_opmode() == 64 or p.rex_p.value == 1:
+            if not hasattr(p, 'sx') and (hasattr(p, 'w8') and p.w8.value == 0):
+                r = gpregs08_64
+            elif p.rex_r.value == 1:
+                v |= 8
+        self.expr = r.expr[v]
+        return True
+
+    def encode(self):
+        if not isinstance(self.expr, ExprId):
+            return False
+        if self.expr in gpregs64.expr and not hasattr(self.parent, 'stk'):
+            self.parent.rex_w.value = 1
+        opmode = self.parent.v_opmode()
+        if not hasattr(self.parent, 'sx') and hasattr(self.parent, 'w8'):
+            self.parent.w8.value = 1
+        if self.expr.size == 8:
+            if hasattr(self.parent, 'sx') or not hasattr(self.parent, 'w8'):
+                return False
+            self.parent.w8.value = 0
+            opmode = 8
+        r = size2gpregs[opmode]
+        if self.expr in r.expr:
+            i = r.expr.index(self.expr)
+        elif (opmode == 8 and self.parent.mode == 64 and
+            self.expr in gpregs08_64.expr):
+            i = gpregs08_64.expr.index(self.expr)
+            self.parent.rex_p.value = 1
+        else:
+            log.debug("cannot encode reg %r", self.expr)
+            return False
+        if self.parent.v_opmode() == 64:
+            if i > 7:
+                self.setrexsize(1)
+                i -= 8
+        elif self.parent.mode == 64 and i > 7:
+            i -= 8
+            self.setrexsize(1)
+        self.value = i
+        return True
+
+
+class x86_rm_reg_mm(x86_rm_reg_noarg, x86_arg):
+    selreg = gpregs_mm
+    def decode(self, v):
+        if self.parent.mode == 64 and self.getrexsize():
+            v |= 0x8
+        self.expr = self.selreg.expr[v]
+        return True
+
+    def encode(self):
+        if not isinstance(self.expr, ExprId):
+            return False
+        if self.expr not in self.selreg.expr:
+            return False
+        i = self.selreg.expr.index(self.expr)
+        if self.parent.mode == 64 and i > 7:
+            i -= 8
+            self.setrexsize(1)
+        self.value = i
+        return True
+
+class x86_rm_reg_xmm(x86_rm_reg_mm):
+    selreg = gpregs_xmm
+
+class x86_rm_reg_bnd(x86_rm_reg_mm):
+    selreg = gpregs_bnd
+
+class x86_rm_reg(x86_rm_reg_noarg, x86_arg):
+    pass
+
+
+class x86_reg(x86_rm_reg):
+
+    def getrexsize(self):
+        return self.parent.rex_b.value
+
+    def setrexsize(self, v):
+        self.parent.rex_b.value = v
+
+class x86_vex_reg(x86_rm_reg):
+    # self.lmask = 15
+
+    def decode(self, v):
+        p = self.parent
+        
+        self.expr = size2gpregs[v_opmode(p)].expr[p.vex_v.value]
+        
+        return self.expr is not None
+
+    def encode(self):
+        opmode = self.parent.mode
+        size = self.expr.size
+
+        if opmode == 64 and size == 64:
+            self.parent.rex_w.value = 1
+        else:
+            self.parent.rex_w.value = 0
+
+        r = size2gpregs[size]
+        if self.expr in r.expr:
+            i = r.expr.index(self.expr)
+
+        self.parent.vex_v.value = i
+        self.parent.vex.value = 1
+        return True
+
+
+class x86_reg_modrm(x86_rm_reg):
+
+    def getrexsize(self):
+        return self.parent.rex_r.value
+
+    def setrexsize(self, v):
+        self.parent.rex_r.value = v
+
+
+
+class x86_reg_noarg(x86_rm_reg_noarg):
+
+    def getrexsize(self):
+        return self.parent.rex_b.value
+
+    def setrexsize(self, v):
+        self.parent.rex_b.value = v
+
+
+class x86_rm_segm(reg_noarg, x86_arg):
+    prio = default_prio + 1
+    reg_info = segmreg
+    parser = reg_info.parser
+
+
+class x86_rm_cr(reg_noarg, x86_arg):
+    prio = default_prio + 1
+    reg_info = crregs
+    parser = reg_info.parser
+
+
+class x86_rm_dr(reg_noarg, x86_arg):
+    prio = default_prio + 1
+    reg_info = drregs
+    parser = reg_info.parser
+
+
+class x86_rm_flt(reg_noarg, x86_arg):
+    prio = default_prio + 1
+    reg_info = fltregs
+    parser = reg_info.parser
+
+
+class bs_fbit(bsi):
+
+    def decode(self, v):
+        # value already decoded in pre_dis_info
+        return True
+
+
+class bs_cl1(bsi, x86_arg):
+    parser = cl_or_imm
+
+    def decode(self, v):
+        if v == 1:
+            self.expr = regs08_expr[1]
+        else:
+            self.expr = ExprInt(1, 8)
+        return True
+
+    def encode(self):
+        if self.expr == regs08_expr[1]:
+            self.value = 1
+        elif isinstance(self.expr, ExprInt) and int(self.expr) == 1:
+            self.value = 0
+        else:
+            return False
+        return True
+
+
+def sib_cond(cls, mode, v):
+    if admode_prefix((mode, v["opmode"], v["admode"])) == 16:
+        return None
+    if v['mod'] == 0b11:
+        return None
+    elif v['rm'] == 0b100:
+        return cls.ll
+    else:
+        return None
+    return v['rm'] == 0b100
+
+
+class bs_cond_scale(bs_cond):
+    # cond must return field len
+    ll = 2
+
+    @classmethod
+    def flen(cls, mode, v):
+        return sib_cond(cls, mode, v)
+
+    def encode(self):
+        if self.value is None:
+            self.value = 0
+            self.l = 0
+            return True
+        return super(bs_cond_scale, self).encode()
+
+    def decode(self, v):
+        self.value = v
+        return True
+
+
+class bs_cond_index(bs_cond_scale):
+    ll = 3
+
+    @classmethod
+    def flen(cls, mode, v):
+        return sib_cond(cls, mode, v)
+
+
+class bs_cond_disp(bs_cond):
+    # cond must return field len
+
+    @classmethod
+    def flen(cls, mode, v):
+        if admode_prefix((mode, v['opmode'], v['admode'])) == 16:
+            if v['mod'] == 0b00:
+                if v['rm'] == 0b110:
+                    return 16
+                else:
+                    return None
+            elif v['mod'] == 0b01:
+                return 8
+            elif v['mod'] == 0b10:
+                return 16
+            return None
+        # 32, 64
+        if 'sib_base' in v and v['sib_base'] == 0b101:
+            if v['mod'] == 0b00:
+                return 32
+            elif v['mod'] == 0b01:
+                return 8
+            elif v['mod'] == 0b10:
+                return 32
+            else:
+                return None
+
+        if v['mod'] == 0b00:
+            if v['rm'] == 0b101:
+                return 32
+            else:
+                return None
+        elif v['mod'] == 0b01:
+            return 8
+        elif v['mod'] == 0b10:
+            return 32
+        else:
+            return None
+
+    def encode(self):
+        if self.value is None:
+            self.value = 0
+            self.l = 0
+            return True
+        self.value = swap_uint(self.l, self.value)
+        return True
+
+    def decode(self, v):
+        admode = self.parent.v_admode()
+        v = swap_uint(self.l, v)
+        self.value = v
+        v = sign_ext(v, self.l, admode)
+        v = ExprInt(v, admode)
+        self.expr = v
+        return True
+
+
+class bs_cond_imm(bs_cond_scale, x86_arg):
+    parser = base_expr
+    max_size = 32
+
+    def fromstring(self, text, loc_db, parser_result=None):
+        if parser_result:
+            expr, start, stop = parser_result[self.parser]
+        else:
+            try:
+                expr, start, stop = next(self.parser.scanString(text))
+            except StopIteration:
+                expr = None
+        self.expr = expr
+
+        if len(self.parent.args) > 1:
+            l = self.parent.args[0].expr.size
+        else:
+            l = self.parent.v_opmode()
+        if isinstance(self.expr, ExprInt):
+            v = int(self.expr)
+            mask = ((1 << l) - 1)
+            self.expr = ExprInt(v & mask, l)
+
+        if self.expr is None:
+            log.debug('cannot fromstring int %r', text)
+            return None, None
+        return start, stop
+
+    @classmethod
+    def flen(cls, mode, v):
+        if 'w8' not in v or v['w8'] == 1:
+            if 'se' in v and v['se'] == 1:
+                return 8
+            else:
+                osize = v_opmode_info(mode, v['opmode'], v['rex_w'], 0)
+                osize = min(osize, cls.max_size)
+                return osize
+        return 8
+
+    def getmaxlen(self):
+        return 32
+
+    def encode(self):
+        if not isinstance(self.expr, ExprInt):
+            return
+        arg0_expr = self.parent.args[0].expr
+        self.parent.rex_w.value = 0
+        # special case for push
+        if len(self.parent.args) == 1:
+            v = int(self.expr)
+            l = self.parent.v_opmode()
+            l = min(l, self.max_size)
+
+            self.l = l
+            mask = ((1 << self.l) - 1)
+            if v != sign_ext(v & mask, self.l, l):
+                return
+            self.value = swap_uint(self.l, v & ((1 << self.l) - 1))
+            yield True
+            return
+
+        # assume 2 args; use first arg to guess op size
+        if arg0_expr.size == 64:
+            self.parent.rex_w.value = 1
+
+        l = self.parent.v_opmode()
+        v = int(self.expr)
+        if arg0_expr.size == 8:
+            if not hasattr(self.parent, 'w8'):
+                return
+            self.parent.w8.value = 0
+            l = 8
+            if hasattr(self.parent, 'se'):
+                self.parent.se.value = 0
+        elif hasattr(self.parent, 'se'):
+            if hasattr(self.parent, 'w8'):
+                self.parent.w8.value = 1
+            # try to generate signed extended version
+            if v == sign_ext(v & 0xFF, 8, arg0_expr.size):
+                self.parent.se.value = 1
+                self.l = 8
+                self.value = v & 0xFF
+                yield True
+            self.parent.se.value = 0
+        else:
+            if hasattr(self.parent, 'w8'):
+                self.parent.w8.value = 1
+        if l == 64:
+            self.l = self.getmaxlen()
+        else:
+            self.l = l
+
+        mask = ((1 << self.l) - 1)
+        if v != sign_ext(v & mask, self.l, l):
+            return
+        self.value = swap_uint(self.l, v & ((1 << self.l) - 1))
+        yield True
+
+    def decode(self, v):
+        opmode = self.parent.v_opmode()
+        v = swap_uint(self.l, v)
+        self.value = v
+        l_out = opmode
+        if hasattr(self.parent, 'w8') and self.parent.w8.value == 0:
+            l_out = 8
+        v = sign_ext(v, self.l, l_out)
+        self.expr = ExprInt(v, l_out)
+        return True
+
+
+class bs_cond_imm64(bs_cond_imm):
+    max_size = 64
+
+    def getmaxlen(self):
+        return 64
+
+    @classmethod
+    def flen(cls, mode, v):
+        if 'w8' not in v or v['w8'] == 1:
+            if 'se' in v and v['se'] == 1:
+                return 8
+            else:
+                osize = v_opmode_info(mode, v['opmode'], v['rex_w'], 0)
+                return osize
+        else:
+            return 8
+
+
+class bs_rel_off(bs_cond_imm):
+    parser = base_expr
+
+    def fromstring(self, text, loc_db, parser_result=None):
+        if parser_result:
+            expr, start, stop = parser_result[self.parser]
+        else:
+            try:
+                expr, start, stop = next(self.parser.scanString(text))
+            except StopIteration:
+                expr = None
+        self.expr = expr
+        l = self.parent.mode
+        if isinstance(self.expr, ExprInt):
+            v = int(self.expr)
+            mask = ((1 << l) - 1)
+            self.expr = ExprInt(v & mask, l)
+        return start, stop
+
+    @classmethod
+    def flen(cls, mode, v):
+        osize = v_opmode_info(mode, v['opmode'], v['rex_w'], 0)
+        if osize == 16:
+            return 16
+        else:
+            return 32
+
+    def encode(self):
+        if not isinstance(self.expr, ExprInt):
+            return
+        arg0_expr = self.parent.args[0].expr
+        if self.l == 0:
+            l = self.parent.v_opmode()
+            self.l = l
+        l = offsize(self.parent)
+        prefix = self.parent.gen_prefix()
+        parent_len = len(prefix) * 8 + self.parent.l + self.l
+        assert(parent_len % 8 == 0)
+
+        v = int(self.expr) - parent_len // 8
+        if prefix is None:
+            return
+        mask = ((1 << self.l) - 1)
+        if self.l > l:
+            return
+        if v != sign_ext(v & mask, self.l, l):
+            return
+        self.value = swap_uint(self.l, v & ((1 << self.l) - 1))
+        yield True
+
+    def decode(self, v):
+        v = swap_uint(self.l, v)
+        size = offsize(self.parent)
+        v = sign_ext(v, self.l, size)
+        v += self.parent.l
+        self.expr = ExprInt(v, size)
+        return True
+
+class bs_s08(bs_rel_off):
+    parser = base_expr
+
+    @classmethod
+    def flen(cls, mode, v):
+        return 8
+
+    def encode(self):
+        if not isinstance(self.expr, ExprInt):
+            return
+        arg0_expr = self.parent.args[0].expr
+        if self.l != 0:
+            l = self.l
+        else:
+            l = self.parent.v_opmode()
+            self.l = l
+        l = offsize(self.parent)
+        v = int(self.expr)
+        mask = ((1 << self.l) - 1)
+        if self.l > l:
+            return
+        if v != sign_ext(v & mask, self.l, l):
+            return
+        self.value = swap_uint(self.l, v & ((1 << self.l) - 1))
+        yield True
+
+    def decode(self, v):
+        v = swap_uint(self.l, v)
+        size = offsize(self.parent)
+        v = sign_ext(v, self.l, size)
+        self.expr = ExprInt(v, size)
+        return True
+
+
+class bs_rel_off08(bs_rel_off):
+
+    @classmethod
+    def flen(cls, mode, v):
+        return 8
+
+
+class bs_moff(bsi):
+
+    @classmethod
+    def flen(cls, mode, v):
+        osize = v_opmode_info(mode, v['opmode'], v['rex_w'], 0)
+        if osize == 16:
+            return 16
+        else:
+            return 32
+
+    def encode(self):
+        if not hasattr(self.parent, "mseg"):
+            return
+        m = self.parent.mseg.expr
+        if not (isinstance(m, ExprOp) and m.op == 'segm'):
+            return
+        if not isinstance(m.args[1], ExprInt):
+            return
+        l = self.parent.v_opmode()
+        if l == 16:
+            self.l = 16
+        else:
+            self.l = 32
+        v = int(m.args[1])
+        mask = ((1 << self.l) - 1)
+        if v != sign_ext(v & mask, self.l, l):
+            return
+        self.value = swap_uint(self.l, v & ((1 << self.l) - 1))
+        yield True
+
+    def decode(self, v):
+        opmode = self.parent.v_opmode()
+        if opmode == 64:
+            return False
+        v = swap_uint(self.l, v)
+        self.value = v
+        v = sign_ext(v, self.l, opmode)
+        self.expr = ExprInt(v, opmode)
+        return True
+
+
+class bs_movoff(x86_arg):
+    parser = deref_mem
+
+    def fromstring(self, text, loc_db, parser_result=None):
+        if parser_result:
+            e, start, stop = parser_result[self.parser]
+            if e is None:
+                return None, None
+            if not isinstance(e, ExprMem):
+                return None, None
+            self.expr = e
+            if self.expr is None:
+                return None, None
+            return start, stop
+        try:
+            v, start, stop = next(self.parser.scanString(text))
+        except StopIteration:
+            return None, None
+        if not isinstance(e, ExprMem):
+            return None, None
+        self.expr = v[0]
+        if self.expr is None:
+            log.debug('cannot fromstring int %r', text)
+            return None, None
+        return start, stop
+
+    @classmethod
+    def flen(cls, mode, v):
+        if mode == 64:
+            if v['admode']:
+                return 32
+            else:
+                return 64
+        asize = v_admode_info(mode, v['admode'])
+        return asize
+
+    def encode(self):
+        p = self.parent
+        if not isinstance(self.expr, ExprMem) or not isinstance(self.expr.ptr, ExprInt):
+            return
+        self.l = p.v_admode()
+        v = int(self.expr.ptr)
+        mask = ((1 << self.l) - 1)
+        if v != mask & v:
+            return
+        self.value = swap_uint(self.l, v & ((1 << self.l) - 1))
+        yield True
+
+    def decode(self, v):
+        if self.parent.mode == 64:
+            if self.parent.admode == 1:
+                l = 32
+            else:
+                l = 64
+        else:
+            l = self.parent.v_admode()
+        v = swap_uint(self.l, v)
+        self.value = v
+        v = sign_ext(v, self.l, l)
+        v = ExprInt(v, l)
+        size = self.parent.v_opmode()
+        if self.parent.w8.value == 0:
+            size = 8
+        self.expr = ExprMem(v, size)
+        return True
+
+
+class bs_msegoff(x86_arg):
+    parser = deref_ptr
+
+    def fromstring(self, text, loc_db, parser_result=None):
+        if parser_result:
+            e, start, stop = parser_result[self.parser]
+            if e is None:
+                return None, None
+            self.expr = e
+            if self.expr is None:
+                return None, None
+            return start, stop
+        try:
+            v, start, stop = next(self.parser.scanString(text))
+        except StopIteration:
+            return None, None
+        self.expr = v[0]
+        if self.expr is None:
+            log.debug('cannot fromstring int %r', text)
+            return None, None
+        return start, stop
+
+    def encode(self):
+        if not (isinstance(self.expr, ExprOp) and self.expr.op == 'segm'):
+            return
+        if not isinstance(self.expr.args[0], ExprInt):
+            return
+        if not isinstance(self.expr.args[1], ExprInt):
+            return
+        l = self.parent.v_opmode()
+        v = int(self.expr.args[0])
+        mask = ((1 << self.l) - 1)
+        if v != sign_ext(v & mask, self.l, l):
+            return
+        self.value = swap_uint(self.l, v & ((1 << self.l) - 1))
+        yield True
+
+    def decode(self, v):
+        opmode = self.parent.v_opmode()
+        v = swap_uint(self.l, v)
+        self.value = v
+        v = ExprInt(v, 16)
+        self.expr = ExprOp('segm', v, self.parent.off.expr)
+        return True
+
+
+d_rex_p = bs(l=0, cls=(bs_fbit,), fname="rex_p")
+d_rex_w = bs(l=0, cls=(bs_fbit,), fname="rex_w")
+d_rex_r = bs(l=0, cls=(bs_fbit,), fname="rex_r")
+d_rex_x = bs(l=0, cls=(bs_fbit,), fname="rex_x")
+d_rex_b = bs(l=0, cls=(bs_fbit,), fname="rex_b")
+
+d_vex = bs(l=0, cls=(bs_fbit,), fname="vex")
+d_vex_l = bs(l=0, cls=(bs_fbit,), fname="vex_l")
+d_vex_p = bs(l=0, cls=(bs_fbit,), fname="vex_p")
+d_vex_v = bs(l=0, cls=(bs_fbit,), fname="vex_v")
+d_vex_m = bs(l=0, cls=(bs_fbit,), fname="vex_m")
+
+pref_0f = bs(l=0, fname="pref_0f")
+pref_0f38 = bs(l=0, fname="pref_0f38")
+pref_0f3a = bs(l=0, fname="pref_0f3a")
+
+d_g1 = bs(l=0, cls=(bs_fbit,), fname="g1")
+d_g2 = bs(l=0, cls=(bs_fbit,), fname="g2")
+
+
+d_cl1 = bs(l=1, cls=(bs_cl1,), fname="cl1")
+
+
+w8 = bs(l=1, fname="w8")
+se = bs(l=1, fname="se")
+
+sx = bs(l=0, fname="sx")
+sxd = bs(l=0, fname="sx")
+
+
+xmmreg = bs(l=0, fname="xmmreg")
+mmreg = bs(l=0, fname="mmreg")
+
+pref_f2 = bs(l=0, fname="prefixed", default=b"\xf2")
+pref_f3 = bs(l=0, fname="prefixed", default=b"\xf3")
+pref_66 = bs(l=0, fname="prefixed", default=b"\x66")
+no_xmm_pref = bs(l=0, fname="no_xmm_pref")
+
+no_rex = bs(l=0, fname="no_rex")
+no_rep = bs(l=0, fname="no_rep")
+
+sib_scale = bs(l=2, cls=(bs_cond_scale,), fname = "sib_scale")
+sib_index = bs(l=3, cls=(bs_cond_index,), fname = "sib_index")
+sib_base = bs(l=3, cls=(bs_cond_index,), fname = "sib_base")
+
+disp = bs(l=0, cls=(bs_cond_disp,), fname = "disp")
+
+s08 = bs(l=8, cls=(bs_s08, ))
+
+u08 = bs(l=8, cls=(x86_08, x86_arg))
+u07 = bs(l=7, cls=(x86_08, x86_arg))
+u16 = bs(l=16, cls=(x86_16, x86_arg))
+u32 = bs(l=32, cls=(x86_32, x86_arg))
+s3264 = bs(l=32, cls=(x86_s32to64, x86_arg))
+
+u08_3 = bs(l=0, cls=(x86_imm_fix_08, x86_arg), ival = 3)
+
+d0 = bs("000", fname='reg')
+d1 = bs("001", fname='reg')
+d2 = bs("010", fname='reg')
+d3 = bs("011", fname='reg')
+d4 = bs("100", fname='reg')
+d5 = bs("101", fname='reg')
+d6 = bs("110", fname='reg')
+d7 = bs("111", fname='reg')
+
+sd = bs(l=1, fname="sd")
+wd = bs(l=1, fname="wd")
+
+stk = bs(l=0, fname="stk")
+
+
+class field_size(object):
+    prio = default_prio
+
+    def __init__(self, d=None):
+        if d is None:
+            d = {}
+        self.d = d
+
+    def get(self, opm, adm=None):
+        return self.d[opm]
+
+class bs_mem(object):
+    def encode(self):
+        return self.value != 0b11
+
+    def decode(self, v):
+        self.value = v
+        return v != 0b11
+
+class bs_reg(object):
+    def encode(self):
+        return self.value == 0b11
+
+    def decode(self, v):
+        self.value = v
+        return v == 0b11
+
+d_imm64 = bs(l=0, fname="imm64")
+
+d_eax = bs(l=0, cls=(bs_eax, ), fname='eax')
+d_edx = bs(l=0, cls=(bs_edx, ), fname='edx')
+d_st = bs(l=0, cls=(x86_reg_st, ), fname='st')
+d_imm = bs(l=0, cls=(bs_cond_imm,), fname="imm")
+d_imm64 = bs(l=0, cls=(bs_cond_imm64,), fname="imm")
+d_ax = bs(l=0, cls=(r_ax, ), fname='ax')
+d_dx = bs(l=0, cls=(r_dx, ), fname='dx')
+d_cl = bs(l=0, cls=(r_cl, ), fname='cl')
+
+d_cs = bs(l=0, cls=(bs_cs, ), fname='cs')
+d_ds = bs(l=0, cls=(bs_ds, ), fname='ds')
+d_es = bs(l=0, cls=(bs_es, ), fname='es')
+d_ss = bs(l=0, cls=(bs_ss, ), fname='ss')
+d_fs = bs(l=0, cls=(bs_fs, ), fname='fs')
+d_gs = bs(l=0, cls=(bs_gs, ), fname='gs')
+
+# Offset must be decoded in last position to have final instruction len
+rel_off = bs(l=0, cls=(bs_rel_off,), fname="off", order=-1)
+# Offset must be decoded in last position to have final instruction len
+rel_off08 = bs(l=8, cls=(bs_rel_off08,), fname="off", order=-1)
+moff = bs(l=0, cls=(bs_moff,), fname="off")
+msegoff = bs(l=16, cls=(bs_msegoff,), fname="mseg")
+movoff = bs(l=0, cls=(bs_movoff,), fname="off")
+mod = bs(l=2, fname="mod")
+mod_mem = bs(l=2, cls=(bs_mem,), fname="mod")
+mod_reg = bs(l=2, cls=(bs_reg,), fname="mod")
+
+rmreg = bs(l=3, cls=(x86_rm_reg, ), order =1, fname = "reg")
+reg = bs(l=3, cls=(x86_reg, ), order =1, fname = "reg")
+
+reg_modrm = bs(l=3, cls=(x86_reg_modrm, ), order =1, fname = "reg")
+
+vex_reg = bs(l=0, cls=(x86_vex_reg, ), order =1, fname = "vex_reg")
+
+regnoarg = bs(l=3, default_val="000", order=1, fname="reg")
+segm = bs(l=3, cls=(x86_rm_segm, ), order =1, fname = "reg")
+crreg = bs(l=3, cls=(x86_rm_cr, ), order =1, fname = "reg")
+drreg = bs(l=3, cls=(x86_rm_dr, ), order =1, fname = "reg")
+
+
+mm_reg = bs(l=3, cls=(x86_rm_reg_mm, ), order =1, fname = "reg")
+xmm_reg = bs(l=3, cls=(x86_rm_reg_xmm, ), order =1, fname = "reg")
+bnd_reg = bs(l=3, cls=(x86_rm_reg_bnd, ), order =1, fname = "reg")
+
+
+fltreg = bs(l=3, cls=(x86_rm_flt, ), order =1, fname = "reg")
+
+rm = bs(l=3, fname="rm")
+
+rm_arg = bs(l=0, cls=(x86_rm_arg,), fname='rmarg')
+rm_arg_w8 = bs(l=0, cls=(x86_rm_w8,), fname='rmarg')
+rm_arg_sx = bs(l=0, cls=(x86_rm_sx,), fname='rmarg')
+rm_arg_sxd = bs(l=0, cls=(x86_rm_sxd,), fname='rmarg')
+rm_arg_sd = bs(l=0, cls=(x86_rm_sd,), fname='rmarg')
+rm_arg_wd = bs(l=0, cls=(x86_rm_wd,), fname='rmarg')
+rm_arg_08 = bs(l=0, cls=(x86_rm_08,), fname='rmarg')
+rm_arg_reg_m08 = bs(l=0, cls=(x86_rm_reg_m08,), fname='rmarg')
+rm_arg_reg_m16 = bs(l=0, cls=(x86_rm_reg_m16,), fname='rmarg')
+rm_arg_m08 = bs(l=0, cls=(x86_rm_m08,), fname='rmarg')
+rm_arg_m64 = bs(l=0, cls=(x86_rm_m64,), fname='rmarg')
+rm_arg_m80 = bs(l=0, cls=(x86_rm_m80,), fname='rmarg')
+rm_arg_m16 = bs(l=0, cls=(x86_rm_m16,), fname='rmarg')
+
+rm_mem = bs(l=0, cls=(x86_rm_mem,), fname='rmarg')
+rm_mem_far = bs(l=0, cls=(x86_rm_mem_far,), fname='rmarg')
+
+rm_arg_mm = bs(l=0, cls=(x86_rm_mm,), fname='rmarg')
+rm_arg_mm_m64 = bs(l=0, cls=(x86_rm_mm_m64,), fname='rmarg')
+rm_arg_mm_reg = bs(l=0, cls=(x86_rm_mm_reg,), fname='rmarg')
+
+rm_arg_xmm = bs(l=0, cls=(x86_rm_xmm,), fname='rmarg')
+rm_arg_xmm_m32 = bs(l=0, cls=(x86_rm_xmm_m32,), fname='rmarg')
+rm_arg_xmm_m64 = bs(l=0, cls=(x86_rm_xmm_m64,), fname='rmarg')
+rm_arg_xmm_m128 = bs(l=0, cls=(x86_rm_xmm_m128,), fname='rmarg')
+rm_arg_xmm_reg = bs(l=0, cls=(x86_rm_xmm_reg,), fname='rmarg')
+
+rm_arg_bnd = bs(l=0, cls=(x86_rm_bnd,), fname='rmarg')
+rm_arg_bnd_m64 = bs(l=0, cls=(x86_rm_bnd_m64,), fname='rmarg')
+rm_arg_bnd_m128 = bs(l=0, cls=(x86_rm_bnd_m128,), fname='rmarg')
+rm_arg_bnd_reg = bs(l=0, cls=(x86_rm_bnd_reg,), fname='rmarg')
+
+
+swapargs = bs_swapargs(l=1, fname="swap", mn_mod=list(range(1 << 1)))
+
+
+class bs_op_mode(bsi):
+
+    def decode(self, v):
+        opmode = self.parent.v_opmode()
+        return opmode == self.mode
+
+
+class bs_ad_mode(bsi):
+
+    def decode(self, v):
+        admode = self.parent.v_admode()
+        return admode == self.mode
+
+
+class bs_op_mode_no64(bsi):
+
+    def encode(self):
+        if self.parent.mode == 64:
+            return False
+        return super(bs_op_mode_no64, self).encode()
+
+    def decode(self, v):
+        if self.parent.mode == 64:
+            return False
+        opmode = self.parent.v_opmode()
+        return opmode == self.mode
+
+
+class bs_op_mode64(bsi):
+    def encode(self):
+        if self.parent.mode != 64:
+            return False
+        return super(bs_op_mode64, self).encode()
+
+    def decode(self, v):
+        if self.parent.mode != 64:
+            return False
+        return True
+
+class bs_op_modeno64(bsi):
+    def encode(self):
+        if self.parent.mode == 64:
+            return False
+        return super(bs_op_modeno64, self).encode()
+
+    def decode(self, v):
+        if self.parent.mode == 64:
+            return False
+        return True
+
+
+
+bs_opmode16 = bs(l=0, cls=(bs_op_mode,), mode = 16, fname="fopmode")
+bs_opmode32 = bs(l=0, cls=(bs_op_mode,), mode = 32, fname="fopmode")
+bs_opmode64 = bs(l=0, cls=(bs_op_mode,), mode = 64, fname="fopmode")
+
+
+bs_admode16 = bs(l=0, cls=(bs_ad_mode,), mode = 16, fname="fadmode")
+bs_admode32 = bs(l=0, cls=(bs_ad_mode,), mode = 32, fname="fadmode")
+bs_admode64 = bs(l=0, cls=(bs_ad_mode,), mode = 64, fname="fadmode")
+
+bs_opmode16_no64 = bs(l=0, cls=(bs_op_mode_no64,), mode = 16, fname="fopmode")
+bs_opmode32_no64 = bs(l=0, cls=(bs_op_mode_no64,), mode = 32, fname="fopmode")
+
+bs_mode64 = bs(l=0, cls=(bs_op_mode64,))
+bs_modeno64 = bs(l=0, cls=(bs_op_modeno64,))
+
+
+cond_list = ["O", "NO", "B", "AE",
+             "Z", "NZ", "BE", "A",
+             "S", "NS", "PE", "NP",
+             #"L", "NL", "NG", "G"]
+             "L", "GE", "LE", "G"]
+cond = bs_mod_name(l=4, fname='cond', mn_mod=cond_list)
+
+
+def rmmod(r, rm_arg_x=rm_arg, modrm=mod):
+    return [modrm, r, rm, sib_scale, sib_index, sib_base, disp, rm_arg_x]
+
+#
+# mode | reg | rm #
+#
+
+#
+# scale | index | base #
+#
+
+#
+# Prefix | REX prefix | Opcode | mod/rm | sib | displacement | immediate #
+#
+
+
+def addop(name, fields, args=None, alias=False):
+    dct = {"fields": fields}
+    dct["alias"] = alias
+    if args is not None:
+        dct['args'] = args
+    type(name, (mn_x86,), dct)
+"""
+class ia32_aaa(mn_x86):
+    fields = [bs8(0x37)]
+"""
+addop("aaa", [bs8(0x37)])
+addop("aas", [bs8(0x3F)])
+addop("aad", [bs8(0xd5), u08])
+addop("aam", [bs8(0xd4), u08])
+
+addop("adc", [bs("0001010"), w8, d_eax, d_imm])
+addop("adc", [bs("100000"), se, w8] + rmmod(d2, rm_arg_w8) + [d_imm])
+addop("adc", [bs("000100"), swapargs, w8] +
+      rmmod(rmreg, rm_arg_w8), [rm_arg_w8, rmreg])
+
+addop("add", [bs("0000010"), w8, d_eax, d_imm])
+addop("add", [bs("100000"), se, w8] + rmmod(d0, rm_arg_w8) + [d_imm])
+addop("add", [bs("000000"), swapargs, w8] +
+      rmmod(rmreg, rm_arg_w8), [rm_arg_w8, rmreg])
+
+addop("and", [bs("0010010"), w8, d_eax, d_imm])
+addop("and", [bs("100000"), se, w8] + rmmod(d4, rm_arg_w8) + [d_imm])
+addop("and", [bs("001000"), swapargs, w8] +
+      rmmod(rmreg, rm_arg_w8), [rm_arg_w8, rmreg])
+
+addop("bndmov", [bs8(0x0f), bs8(0x1a), pref_66, bs_modeno64] +
+      rmmod(bnd_reg, rm_arg_bnd_m64), [bnd_reg, rm_arg_bnd_m64])
+addop("bndmov", [bs8(0x0f), bs8(0x1a), pref_66, bs_mode64] +
+      rmmod(bnd_reg, rm_arg_bnd_m128), [bnd_reg, rm_arg_bnd_m128])
+addop("bndmov", [bs8(0x0f), bs8(0x1b), pref_66, bs_modeno64] +
+      rmmod(bnd_reg, rm_arg_bnd_m64), [rm_arg_bnd_m64, bnd_reg])
+addop("bndmov", [bs8(0x0f), bs8(0x1b), pref_66, bs_mode64] +
+      rmmod(bnd_reg, rm_arg_bnd_m128), [rm_arg_bnd_m128, bnd_reg])
+
+
+
+addop("bsf", [bs8(0x0f), bs8(0xbc), no_rep] + rmmod(rmreg))
+addop("bsr", [bs8(0x0f), bs8(0xbd), mod,
+    rmreg, rm, sib_scale, sib_index, sib_base, disp, rm_arg])
+
+addop("bswap", [bs8(0x0f), bs('11001'), reg])
+
+addop("bt", [bs8(0x0f), bs8(0xa3)] + rmmod(rmreg), [rm_arg, rmreg])
+addop("bt", [bs8(0x0f), bs8(0xba)] + rmmod(d4) + [u08])
+addop("btc", [bs8(0x0f), bs8(0xbb)] + rmmod(rmreg), [rm_arg, rmreg])
+addop("btc", [bs8(0x0f), bs8(0xba)] + rmmod(d7) + [u08])
+
+
+addop("btr", [bs8(0x0f), bs8(0xb3)] + rmmod(rmreg), [rm_arg, rmreg])
+addop("btr", [bs8(0x0f), bs8(0xba)] + rmmod(d6) + [u08])
+addop("bts", [bs8(0x0f), bs8(0xab)] + rmmod(rmreg), [rm_arg, rmreg])
+addop("bts", [bs8(0x0f), bs8(0xba)] + rmmod(d5) + [u08])
+
+addop("call", [bs8(0xe8), rel_off])
+addop("call", [bs8(0xff), stk] + rmmod(d2))
+addop("call", [bs8(0xff), stk] + rmmod(d3, rm_arg_x=rm_mem_far, modrm=mod_mem))
+addop("call", [bs8(0x9a), bs_modeno64, moff, msegoff])
+
+
+addop("cbw", [bs8(0x98), bs_opmode16])
+addop("cwde", [bs8(0x98), bs_opmode32])
+addop("cdqe", [bs8(0x98), bs_opmode64])
+
+addop("clc", [bs8(0xf8)])
+addop("cld", [bs8(0xfc)])
+addop("cli", [bs8(0xfa)])
+addop("clts", [bs8(0x0f), bs8(0x06)])
+addop("cmc", [bs8(0xf5)])
+
+addop("cmov", [bs8(0x0f), bs('0100'), cond] + rmmod(rmreg))
+
+addop("cmp", [bs("0011110"), w8, d_eax, d_imm])
+addop("cmp", [bs("100000"), se, w8] + rmmod(d7, rm_arg_w8) + [d_imm])
+addop("cmp", [bs("001110"), swapargs, w8] +
+      rmmod(rmreg, rm_arg_w8), [rm_arg_w8, rmreg])
+
+
+addop("cmpsb", [bs8(0xa6)])
+addop("cmpsw", [bs8(0xa7), bs_opmode16])
+addop("cmpsd", [bs8(0xa7), bs_opmode32])
+addop("cmpsq", [bs8(0xa7), bs_opmode64])
+
+addop("cmpxchg", [bs8(0x0f), bs('1011000'), w8]
+      + rmmod(rmreg, rm_arg_w8), [rm_arg_w8, rmreg])
+addop("cmpxchg8b", [bs8(0x0f), bs8(0xc7), bs_opmode16] + rmmod(d1, rm_arg_m64))
+addop("cmpxchg8b", [bs8(0x0f), bs8(0xc7), bs_opmode32] + rmmod(d1, rm_arg_m64))
+addop("cmpxchg16b", [bs8(0x0f), bs8(0xc7), bs_opmode64] + rmmod(d1, rm_arg_xmm_m128))
+
+# XXX TODO CMPXCHG8/16
+
+addop("comiss", [bs8(0x0f), bs8(0x2f), no_xmm_pref] +
+      rmmod(xmm_reg, rm_arg_xmm_m32), [xmm_reg, rm_arg_xmm_m32])
+addop("comisd", [bs8(0x0f), bs8(0x2f), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm_m64), [xmm_reg, rm_arg_xmm_m64])
+
+addop("cpuid", [bs8(0x0f), bs8(0xa2)])
+
+addop("cwd", [bs8(0x99), bs_opmode16])
+addop("cdq", [bs8(0x99), bs_opmode32])
+addop("cqo", [bs8(0x99), bs_opmode64])
+
+
+addop("daa", [bs8(0x27)])
+addop("das", [bs8(0x2f)])
+addop("dec", [bs('1111111'), w8] + rmmod(d1, rm_arg_w8))
+addop("dec", [bs('01001'), reg, bs_modeno64])
+addop("div", [bs('1111011'), w8] + rmmod(d6, rm_arg_w8))
+addop("enter", [bs8(0xc8), u16, u08])
+
+# float #####
+addop("fwait", [bs8(0x9b)])
+
+addop("f2xm1", [bs8(0xd9), bs8(0xf0)])
+addop("fabs", [bs8(0xd9), bs8(0xe1)])
+
+addop("fadd", [bs("11011"), sd, bs("00")] + rmmod(d0, rm_arg_sd))
+addop("fadd", [bs("11011"), swapargs, bs("00"),
+      bs("11000"), d_st, fltreg], [d_st, fltreg])
+addop("faddp", [bs8(0xde), bs("11000"), fltreg, d_st])
+addop("fiadd", [bs("11011"), wd, bs("10")] + rmmod(d0, rm_arg_wd))
+
+addop("fbld", [bs8(0xdf)] + rmmod(d4, rm_arg_m80))
+addop("fbldp", [bs8(0xdf)] + rmmod(d6, rm_arg_m80))
+addop("fchs", [bs8(0xd9), bs8(0xe0)])
+# addop("fclex", [bs8(0x9b), bs8(0xdb), bs8(0xe2)])
+addop("fnclex", [bs8(0xdb), bs8(0xe2)])
+
+addop("fcmovb", [bs8(0xda), bs("11000"), d_st, fltreg])
+addop("fcmove", [bs8(0xda), bs("11001"), d_st, fltreg])
+addop("fcmovbe", [bs8(0xda), bs("11010"), d_st, fltreg])
+addop("fcmovu", [bs8(0xda), bs("11011"), d_st, fltreg])
+addop("fcmovnb", [bs8(0xdb), bs("11000"), d_st, fltreg])
+addop("fcmovne", [bs8(0xdb), bs("11001"), d_st, fltreg])
+addop("fcmovnbe", [bs8(0xdb), bs("11010"), d_st, fltreg])
+addop("fcmovnu", [bs8(0xdb), bs("11011"), d_st, fltreg])
+
+addop("fcom", [bs("11011"), sd, bs("00")] + rmmod(d2, rm_arg_sd))
+addop("fcom", [bs("11011"), swapargs, bs("00"),
+      bs("11010"), d_st, fltreg], [d_st, fltreg])
+addop("fcomp", [bs("11011"), sd, bs("00")] + rmmod(d3, rm_arg_sd))
+addop("fcomp",
+      [bs("11011"), swapargs, bs("00"), bs("11011"),
+      d_st, fltreg], [d_st, fltreg])
+addop("fcompp", [bs8(0xde), bs8(0xd9)])
+
+addop("fcomi", [bs8(0xdb), bs("11110"), d_st, fltreg])
+addop("fcomip", [bs8(0xdf), bs("11110"), d_st, fltreg])
+addop("fucomi", [bs8(0xdb), bs("11101"), d_st, fltreg])
+addop("fucomip", [bs8(0xdf), bs("11101"), d_st, fltreg])
+
+addop("fcos", [bs8(0xd9), bs8(0xff)])
+addop("fdecstp", [bs8(0xd9), bs8(0xf6)])
+
+
+addop("fdiv", [bs("11011"), sd, bs("00")] + rmmod(d6, rm_arg_sd))
+addop("fdiv", [bs8(0xd8), bs("11110"), d_st, fltreg])
+addop("fdiv", [bs8(0xdc), bs("11111"), fltreg, d_st])
+addop("fdivp", [bs8(0xde), bs("11111"), fltreg, d_st])
+addop("fidiv", [bs("11011"), wd, bs("10")] + rmmod(d6, rm_arg_wd))
+
+addop("fdivr", [bs("11011"), sd, bs("00")] + rmmod(d7, rm_arg_sd))
+addop("fdivr", [bs8(0xd8), bs("11111"), d_st, fltreg])
+addop("fdivr", [bs8(0xdc), bs("11110"), fltreg, d_st])
+addop("fdivrp", [bs8(0xde), bs("11110"), fltreg, d_st])
+addop("fidivr", [bs("11011"), wd, bs("10")] + rmmod(d7, rm_arg_wd))
+
+addop("ffree", [bs8(0xdd), bs("11000"), fltreg])
+addop("ficom", [bs("11011"), wd, bs("10")] + rmmod(d2, rm_arg_wd))
+addop("ficomp", [bs("11011"), wd, bs("10")] + rmmod(d3, rm_arg_wd))
+addop("fild", [bs("11011"), wd, bs("11")] + rmmod(d0, rm_arg_wd))
+addop("fild", [bs8(0xdf)] + rmmod(d5, rm_arg_m64))
+
+addop("fincstp", [bs8(0xd9), bs8(0xf7)])
+
+addop("blsi", [pref_0f38, bs8(0xf3), vex_reg] + rmmod(bs("011"), rm_arg), [vex_reg, rm_arg])
+addop("andn", [pref_0f38, bs8(0xf2), vex_reg] + rmmod(rmreg, rm_arg), [rmreg, vex_reg, rm_arg])
+addop("bextr", [pref_0f38, bs8(0xf7), vex_reg] + rmmod(rmreg, rm_arg), [rmreg, rm_arg, vex_reg])
+addop("blsmsk", [pref_0f38, bs8(0xf3), vex_reg] + rmmod(bs("010"), rm_arg), [vex_reg, rm_arg])
+addop("blsr", [pref_0f38, bs8(0xf3), vex_reg] + rmmod(bs("001"), rm_arg), [vex_reg, rm_arg])
+addop("bzhi", [pref_0f38, bs8(0xf5), vex_reg] + rmmod(rmreg, rm_arg), [rmreg, rm_arg, vex_reg])
+addop("tzcnt", [bs8(0x0f), bs8(0xbc), pref_f3] + rmmod(rmreg, rm_arg), [rmreg, rm_arg])
+
+# addop("finit", [bs8(0x9b), bs8(0xdb), bs8(0xe3)])
+addop("fninit", [bs8(0xdb), bs8(0xe3)])
+
+addop("fist", [bs("11011"), wd, bs("11")] + rmmod(d2, rm_arg_wd))
+addop("fistp", [bs("11011"), wd, bs("11")] + rmmod(d3, rm_arg_wd))
+addop("fistp", [bs8(0xdf)] + rmmod(d7, rm_arg_m64))
+
+addop("fisttp", [bs("11011"), wd, bs("11")] + rmmod(d1, rm_arg_wd))
+addop("fisttp", [bs8(0xdd)] + rmmod(d1, rm_arg_m64))
+
+addop("fld", [bs("11011"), sd, bs("01")] + rmmod(d0, rm_arg_sd))
+addop("fld", [bs8(0xdb)] + rmmod(d5, rm_arg_m80))
+addop("fld", [bs8(0xd9), bs("11000"), fltreg])
+
+addop("fld1", [bs8(0xd9), bs8(0xe8)])
+addop("fldl2t", [bs8(0xd9), bs8(0xe9)])
+addop("fldl2e", [bs8(0xd9), bs8(0xea)])
+addop("fldpi", [bs8(0xd9), bs8(0xeb)])
+addop("fldlg2", [bs8(0xd9), bs8(0xec)])
+addop("fldln2", [bs8(0xd9), bs8(0xed)])
+addop("fldz", [bs8(0xd9), bs8(0xee)])
+
+addop("fldcw", [bs8(0xd9)] + rmmod(d5, rm_arg_m16))
+addop("fldenv", [bs8(0xd9)] + rmmod(d4, rm_arg_m80))  # XXX TODO: m14?
+
+addop("fmul", [bs("11011"), sd, bs("00")] + rmmod(d1, rm_arg_sd))
+addop("fmul", [bs("11011"), swapargs, bs("00"),
+      bs("11001"), d_st, fltreg], [d_st, fltreg])
+addop("fmulp", [bs8(0xde), bs("11001"), fltreg, d_st])
+addop("fimul", [bs("11011"), wd, bs("10")] + rmmod(d1, rm_arg_wd))
+
+addop("fnop", [bs8(0xd9), bs8(0xd0)])
+addop("fpatan", [bs8(0xd9), bs8(0xf3)])
+addop("fprem", [bs8(0xd9), bs8(0xf8)])
+addop("fprem1", [bs8(0xd9), bs8(0xf5)])
+addop("fptan", [bs8(0xd9), bs8(0xf2)])
+addop("frndint", [bs8(0xd9), bs8(0xfc)])
+addop("frstor", [bs8(0xdd)] + rmmod(d4, rm_arg_m80))  # XXX TODO: m94 ?
+# addop("fsave", [bs8(0x9b), bs8(0xdd)] + rmmod(d6, rm_arg_m80)) # XXX
+# TODO: m94 ?
+addop("fnsave", [bs8(0xdd)] + rmmod(d6, rm_arg_m80))  # XXX TODO: m94 ?
+
+addop("fscale", [bs8(0xd9), bs8(0xfd)])
+addop("fsin", [bs8(0xd9), bs8(0xfe)])
+addop("fsincos", [bs8(0xd9), bs8(0xfb)])
+addop("fsqrt", [bs8(0xd9), bs8(0xfa)])
+
+addop("fst", [bs("11011"), sd, bs("01")] + rmmod(d2, rm_arg_sd))
+addop("fst", [bs8(0xdd), bs("11010"), fltreg])
+addop("fstp", [bs("11011"), sd, bs("01")] + rmmod(d3, rm_arg_sd))
+addop("fstp", [bs8(0xdb)] + rmmod(d7, rm_arg_m80))
+addop("fstp", [bs8(0xdd), bs("11011"), fltreg])
+
+# addop("fstcw", [bs8(0x9b), bs8(0xd9)] + rmmod(d7, rm_arg_m16))
+addop("fnstcw", [bs8(0xd9)] + rmmod(d7, rm_arg_m16))
+# addop("fstenv", [bs8(0x9b), bs8(0xd9)] + rmmod(d6, rm_arg_m80)) # XXX
+# TODO: m14?
+addop("fnstenv", [bs8(0xd9)] + rmmod(d6, rm_arg_m80))  # XXX TODO: m14?
+# addop("fstsw", [bs8(0x9b), bs8(0xdd)] + rmmod(d7, rm_arg_m16))
+addop("fnstsw", [bs8(0xdd)] + rmmod(d7, rm_arg_m16))
+# addop("fstsw", [bs8(0x9b), bs8(0xdf), bs8(0xe0), d_ax])
+addop("fnstsw", [bs8(0xdf), bs8(0xe0), d_ax])
+
+addop("fsub", [bs("11011"), sd, bs("00")] + rmmod(d4, rm_arg_sd))
+addop("fsub", [bs8(0xd8), bs("11100"), d_st, fltreg])
+addop("fsub", [bs8(0xdc), bs("11101"), fltreg, d_st])
+addop("fsubp", [bs8(0xde), bs("11101"), fltreg, d_st])
+addop("fisub", [bs("11011"), wd, bs("10")] + rmmod(d4, rm_arg_wd))
+
+addop("fsubr", [bs("11011"), sd, bs("00")] + rmmod(d5, rm_arg_sd))
+addop("fsubr", [bs8(0xd8), bs("11101"), d_st, fltreg])
+addop("fsubr", [bs8(0xdc), bs("11100"), fltreg, d_st])
+addop("fsubrp", [bs8(0xde), bs("11100"), fltreg, d_st])
+addop("fisubr", [bs("11011"), wd, bs("10")] + rmmod(d5, rm_arg_wd))
+addop("ftst", [bs8(0xd9), bs8(0xe4)])
+
+
+addop("fucom", [bs8(0xdd), bs("11100"), fltreg])
+addop("fucomp", [bs8(0xdd), bs("11101"), fltreg])
+addop("fucompp", [bs8(0xda), bs8(0xe9)])
+
+addop("fxam", [bs8(0xd9), bs8(0xe5)])
+addop("fxch", [bs8(0xd9), bs("11001"), fltreg])
+addop("fxrstor", [bs8(0x0f), bs8(0xae)]
+      + rmmod(d1, rm_arg_m80))  # XXX TODO m512
+addop("fxsave", [bs8(0x0f), bs8(0xae)]
+      + rmmod(d0, rm_arg_m80))  # XXX TODO m512
+addop("stmxcsr", [bs8(0x0f), bs8(0xae)] + rmmod(d3))
+addop("ldmxcsr", [bs8(0x0f), bs8(0xae)] + rmmod(d2))
+
+addop("fxtract", [bs8(0xd9), bs8(0xf4)])
+addop("fyl2x", [bs8(0xd9), bs8(0xf1)])
+addop("fyl2xp1", [bs8(0xd9), bs8(0xf9)])
+
+addop("hlt", [bs8(0xf4)])
+addop("icebp", [bs8(0xf1)])
+
+addop("idiv", [bs('1111011'), w8] + rmmod(d7, rm_arg_w8))
+
+addop("imul", [bs('1111011'), w8] + rmmod(d5, rm_arg_w8))
+addop("imul", [bs8(0x0f), bs8(0xaf)] + rmmod(rmreg))
+
+addop("imul", [bs("011010"), se, bs('1')] + rmmod(rmreg) + [d_imm])
+
+addop("in", [bs("1110010"), w8, d_eax, u08])
+addop("in", [bs("1110110"), w8, d_eax, d_edx])
+
+addop("inc", [bs('1111111'), w8] + rmmod(d0, rm_arg_w8))
+addop("inc", [bs('01000'), reg, bs_modeno64])
+
+addop("insb", [bs8(0x6c)])
+addop("insw", [bs8(0x6d), bs_opmode16])
+addop("insd", [bs8(0x6d), bs_opmode32])
+addop("insd", [bs8(0x6d), bs_opmode64])
+
+addop("int", [bs8(0xcc), u08_3])
+addop("int", [bs8(0xcd), u08])
+addop("into", [bs8(0xce)])
+addop("invd", [bs8(0x0f), bs8(0x08)])
+addop("invlpg", [bs8(0x0f), bs8(0x01)] + rmmod(d7))
+
+addop("iret", [bs8(0xcf), bs_opmode16])
+addop("iretd", [bs8(0xcf), bs_opmode32])
+addop("iretq", [bs8(0xcf), bs_opmode64])
+
+addop("j", [bs('0111'), cond, rel_off08])
+
+addop("jcxz", [bs8(0xe3), rel_off08, bs_admode16])
+addop("jecxz", [bs8(0xe3), rel_off08, bs_admode32])
+addop("jrcxz", [bs8(0xe3), rel_off08, bs_admode64])
+
+addop("j", [bs8(0x0f), bs('1000'), cond, rel_off])
+addop("jmp", [bs8(0xeb), rel_off08])
+addop("jmp", [bs8(0xe9), rel_off])
+# TODO XXX replace stk force64?
+addop("jmp", [bs8(0xff), stk] + rmmod(d4))
+addop("jmp", [bs8(0xea), bs_modeno64, moff, msegoff])
+
+addop("jmp", [bs8(0xff)] + rmmod(d5, rm_arg_x=rm_mem_far, modrm=mod_mem))
+
+addop("lahf", [bs8(0x9f)])
+addop("lar", [bs8(0x0f), bs8(0x02)] + rmmod(rmreg))
+
+addop("lea", [bs8(0x8d)] + rmmod(rmreg, rm_arg_x=rm_mem, modrm=mod_mem))
+addop("les", [bs8(0xc4)] + rmmod(rmreg, rm_arg_x=rm_mem, modrm=mod_mem))
+addop("lds", [bs8(0xc5)] + rmmod(rmreg, rm_arg_x=rm_mem, modrm=mod_mem))
+addop("lss", [bs8(0x0f), bs8(0xb2)] + rmmod(rmreg, rm_arg_x=rm_mem, modrm=mod_mem))
+addop("lfs", [bs8(0x0f), bs8(0xb4)] + rmmod(rmreg, rm_arg_x=rm_mem, modrm=mod_mem))
+addop("lgs", [bs8(0x0f), bs8(0xb5)] + rmmod(rmreg, rm_arg_x=rm_mem, modrm=mod_mem))
+
+addop("lgdt", [bs8(0x0f), bs8(0x01)] + rmmod(d2, modrm=mod_mem))
+addop("lidt", [bs8(0x0f), bs8(0x01)] + rmmod(d3, modrm=mod_mem))
+
+addop("lfence", [bs8(0x0f), bs8(0xae), bs8(0xe8), no_xmm_pref])
+addop("mfence", [bs8(0x0f), bs8(0xae), bs8(0xf0)])
+addop("sfence", [bs8(0x0f), bs8(0xae), bs8(0xf8)])
+
+addop("leave", [bs8(0xc9), stk])
+
+addop("lodsb", [bs8(0xac)])
+addop("lodsw", [bs8(0xad), bs_opmode16])
+addop("lodsd", [bs8(0xad), bs_opmode32])
+addop("lodsq", [bs8(0xad), bs_opmode64])
+
+addop("loop", [bs8(0xe2), rel_off08])
+addop("loope", [bs8(0xe1), rel_off08])
+addop("loopne", [bs8(0xe0), rel_off08])
+addop("lsl", [bs8(0x0f), bs8(0x03)] + rmmod(rmreg))
+addop("monitor", [bs8(0x0f), bs8(0x01), bs8(0xc8)])
+
+addop("mov", [bs("100010"), swapargs, w8] +
+      rmmod(rmreg, rm_arg_w8), [rm_arg_w8, rmreg])
+addop("mov", [bs("100011"), swapargs, bs('0')] + rmmod(segm), [rm_arg, segm])
+addop("mov", [bs("101000"), swapargs, w8, d_eax, movoff], [d_eax, movoff])
+addop("mov", [bs("1011"), w8, reg, d_imm64])
+addop("mov", [bs("1100011"), w8] + rmmod(d0, rm_arg_w8) + [d_imm])
+addop("mov", [bs8(0x0f), bs("001000"), swapargs, bs('0')]
+      + rmmod(crreg), [rm_arg, crreg])
+addop("mov", [bs8(0x0f), bs("001000"), swapargs, bs('1')]
+      + rmmod(drreg), [rm_arg, drreg])
+addop("movsb", [bs8(0xa4)])
+addop("movsw", [bs8(0xa5), bs_opmode16])
+addop("movsd", [bs8(0xa5), bs_opmode32])
+addop("movsq", [bs8(0xa5), bs_opmode64])
+
+addop("movsx", [bs8(0x0f), bs("1011111"), w8, sx] + rmmod(rmreg, rm_arg_sx))
+addop("movsxd", [bs8(0x63), sxd, bs_mode64] + rmmod(rmreg, rm_arg_sxd))
+
+addop("movups", [bs8(0x0f), bs("0001000"), swapargs, no_xmm_pref] +
+      rmmod(xmm_reg, rm_arg_xmm), [xmm_reg, rm_arg_xmm])
+addop("movsd", [bs8(0x0f), bs("0001000"), swapargs, pref_f2]
+      + rmmod(xmm_reg, rm_arg_xmm_m64), [xmm_reg, rm_arg_xmm_m64])
+addop("movss", [bs8(0x0f), bs("0001000"), swapargs, pref_f3] +
+      rmmod(xmm_reg, rm_arg_xmm_m32), [xmm_reg, rm_arg_xmm_m32])
+addop("movupd", [bs8(0x0f), bs8(0x10), pref_66] + rmmod(xmm_reg, rm_arg_xmm), [xmm_reg, rm_arg_xmm])
+addop("movupd", [bs8(0x0f), bs8(0x11), pref_66] + rmmod(xmm_reg, rm_arg_xmm), [rm_arg_xmm, xmm_reg])
+
+
+addop("movd", [bs8(0x0f), bs('011'), swapargs, bs('1110'), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg), [mm_reg, rm_arg])
+addop("movd", [bs8(0x0f), bs('011'), swapargs, bs('1110'), pref_66, bs_opmode32] +
+      rmmod(xmm_reg, rm_arg), [xmm_reg, rm_arg])
+addop("movq", [bs8(0x0f), bs('011'), swapargs, bs('1110'), pref_66, bs_opmode64] +
+      rmmod(xmm_reg, rm_arg), [xmm_reg, rm_arg])
+
+addop("movq", [bs8(0x0f), bs('011'), swapargs, bs('1111'), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm_m64), [mm_reg, rm_arg_mm_m64])
+
+addop("movq", [bs8(0x0f), bs8(0x7e), pref_f3] +
+      rmmod(xmm_reg, rm_arg_xmm_m64), [xmm_reg, rm_arg_xmm_m64])
+addop("movq", [bs8(0x0f), bs8(0xd6), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm_m64), [rm_arg_xmm_m64, xmm_reg])
+
+addop("movmskps", [bs8(0x0f), bs8(0x50), no_xmm_pref] +
+      rmmod(reg_modrm, rm_arg_xmm_reg))
+addop("movmskpd", [bs8(0x0f), bs8(0x50), pref_66] +
+      rmmod(reg_modrm, rm_arg_xmm_reg))
+
+addop("movnti", [bs8(0x0f), bs8(0xc3)] + rmmod(rmreg), [rm_arg, rmreg])
+
+addop("addss", [bs8(0x0f), bs8(0x58), pref_f3] + rmmod(xmm_reg, rm_arg_xmm_m32))
+addop("addsd", [bs8(0x0f), bs8(0x58), pref_f2] + rmmod(xmm_reg, rm_arg_xmm_m64))
+
+addop("subss", [bs8(0x0f), bs8(0x5c), pref_f3] + rmmod(xmm_reg, rm_arg_xmm_m32))
+addop("subsd", [bs8(0x0f), bs8(0x5c), pref_f2] + rmmod(xmm_reg, rm_arg_xmm_m64))
+
+addop("mulss", [bs8(0x0f), bs8(0x59), pref_f3] + rmmod(xmm_reg, rm_arg_xmm_m32))
+addop("mulsd", [bs8(0x0f), bs8(0x59), pref_f2] + rmmod(xmm_reg, rm_arg_xmm_m64))
+
+addop("divss", [bs8(0x0f), bs8(0x5e), pref_f3] + rmmod(xmm_reg, rm_arg_xmm_m32))
+addop("divsd", [bs8(0x0f), bs8(0x5e), pref_f2] + rmmod(xmm_reg, rm_arg_xmm_m64))
+
+addop("roundss", [bs8(0x0f), bs8(0x3a), bs8(0x0a), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm_m32) + [u08])
+addop("roundsd", [bs8(0x0f), bs8(0x3a), bs8(0x0b), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm_m64) + [u08])
+
+addop("pminsw", [bs8(0x0f), bs8(0xea), no_xmm_pref] + rmmod(mm_reg, rm_arg_mm))
+addop("pminsw", [bs8(0x0f), bs8(0xea), pref_66] + rmmod(xmm_reg, rm_arg_xmm))
+
+addop("ucomiss", [bs8(0x0f), bs8(0x2e), no_xmm_pref] + rmmod(xmm_reg, rm_arg_xmm_m32))
+addop("ucomisd", [bs8(0x0f), bs8(0x2e), pref_66] + rmmod(xmm_reg, rm_arg_xmm_m64))
+
+
+addop("movzx", [bs8(0x0f), bs("1011011"), w8, sx] + rmmod(rmreg, rm_arg_sx))
+addop("mul", [bs('1111011'), w8] + rmmod(d4, rm_arg_w8))
+
+addop("neg", [bs('1111011'), w8] + rmmod(d3, rm_arg_w8))
+addop("nop", [bs8(0x0f), bs8(0x1f)] + rmmod(d0, rm_arg))  # XXX TODO m512
+addop("nop", [bs8(0x0f), bs8(0x1f)] + rmmod(d1, rm_arg))  # XXX TODO m512
+addop("nop", [bs8(0x0f), bs8(0x1f)] + rmmod(d2, rm_arg))  # XXX TODO m512
+addop("nop", [bs8(0x0f), bs8(0x1f)] + rmmod(d3, rm_arg))  # XXX TODO m512
+addop("nop", [bs8(0x0f), bs8(0x1f)] + rmmod(d4, rm_arg))  # XXX TODO m512
+addop("nop", [bs8(0x0f), bs8(0x1f)] + rmmod(d5, rm_arg))  # XXX TODO m512
+addop("nop", [bs8(0x0f), bs8(0x1f)] + rmmod(d6, rm_arg))  # XXX TODO m512
+addop("nop", [bs8(0x0f), bs8(0x1f)] + rmmod(d7, rm_arg))  # XXX TODO m512
+addop("not", [bs('1111011'), w8] + rmmod(d2, rm_arg_w8))
+addop("or", [bs("0000110"), w8, d_eax, d_imm])
+addop("or", [bs("100000"), se, w8] + rmmod(d1, rm_arg_w8) + [d_imm])
+addop("or", [bs("000010"), swapargs, w8] +
+      rmmod(rmreg, rm_arg_w8), [rm_arg_w8, rmreg])
+addop("out", [bs("1110011"), w8, u08, d_eax])
+addop("out", [bs("1110111"), w8, d_edx, d_eax])
+
+addop("outsb", [bs8(0x6e)])
+addop("outsw", [bs8(0x6f), bs_opmode16])
+addop("outsd", [bs8(0x6f), bs_opmode32])
+addop("outsd", [bs8(0x6f), bs_opmode64])
+
+addop("setalc", [bs8(0xD6)])
+
+# addop("pause", [bs8(0xf3), bs8(0x90)])
+
+addop("popw", [bs8(0x8f), stk, bs_opmode16] + rmmod(d0))
+addop("popw", [bs("01011"), stk, reg, bs_opmode16])
+addop("popw", [bs8(0x1f), stk, d_ds, bs_opmode16])
+addop("popw", [bs8(0x07), stk, d_es, bs_opmode16])
+addop("popw", [bs8(0x17), stk, d_ss, bs_opmode16])
+addop("popw", [bs8(0x0f), stk, bs8(0xa1), d_fs, bs_opmode16])
+addop("popw", [bs8(0x0f), stk, bs8(0xa9), d_gs, bs_opmode16])
+
+addop("pop", [bs8(0x8f), stk, bs_opmode32] + rmmod(d0))
+addop("pop", [bs("01011"), stk, reg, bs_opmode32])
+addop("pop", [bs8(0x1f), stk, d_ds, bs_opmode32])
+addop("pop", [bs8(0x07), stk, d_es, bs_opmode32])
+addop("pop", [bs8(0x17), stk, d_ss, bs_opmode32])
+addop("pop", [bs8(0x0f), stk, bs8(0xa1), d_fs, bs_opmode32])
+addop("pop", [bs8(0x0f), stk, bs8(0xa9), d_gs, bs_opmode32])
+
+addop("pop", [bs8(0x8f), stk, bs_opmode64] + rmmod(d0))
+addop("pop", [bs("01011"), stk, reg, bs_opmode64])
+addop("pop", [bs8(0x1f), stk, d_ds, bs_opmode64])
+addop("pop", [bs8(0x07), stk, d_es, bs_opmode64])
+addop("pop", [bs8(0x17), stk, d_ss, bs_opmode64])
+addop("pop", [bs8(0x0f), stk, bs8(0xa1), d_fs, bs_opmode64])
+addop("pop", [bs8(0x0f), stk, bs8(0xa9), d_gs, bs_opmode64])
+
+
+addop("popa", [bs8(0x61), stk, bs_opmode16])
+addop("popad", [bs8(0x61), stk, bs_opmode32])
+
+addop("popfw", [bs8(0x9d), stk, bs_opmode16])
+addop("popfd", [bs8(0x9d), stk, bs_opmode32])
+addop("popfq", [bs8(0x9d), stk, bs_opmode64])
+
+addop("prefetch0", [bs8(0x0f), bs8(0x18)] + rmmod(d1, rm_arg_m08))
+addop("prefetch1", [bs8(0x0f), bs8(0x18)] + rmmod(d2, rm_arg_m08))
+addop("prefetch2", [bs8(0x0f), bs8(0x18)] + rmmod(d3, rm_arg_m08))
+addop("prefetchnta", [bs8(0x0f), bs8(0x18)] + rmmod(d0, rm_arg_m08))
+addop("prefetchw", [bs8(0x0f), bs8(0x0d)] + rmmod(d1, rm_arg_m08))
+
+addop("pushw", [bs8(0xff), stk, bs_opmode16] + rmmod(d6))
+addop("pushw", [bs("01010"), stk, reg, bs_opmode16])
+addop("pushw", [bs8(0x6a), s08, stk, bs_opmode16])
+addop("pushw", [bs8(0x68), d_imm, stk, bs_opmode16])
+addop("pushw", [bs8(0x0e), stk, d_cs, bs_opmode16])
+addop("pushw", [bs8(0x16), stk, d_ss, bs_opmode16])
+addop("pushw", [bs8(0x1e), stk, d_ds, bs_opmode16])
+addop("pushw", [bs8(0x06), stk, d_es, bs_opmode16])
+addop("pushw", [bs8(0x0f), stk, bs8(0xa0), d_fs, bs_opmode16])
+addop("pushw", [bs8(0x0f), stk, bs8(0xa8), d_gs, bs_opmode16])
+
+addop("push", [bs8(0xff), stk, bs_opmode32] + rmmod(d6))
+addop("push", [bs("01010"), stk, reg, bs_opmode32])
+addop("push", [bs8(0x6a), s08, stk, bs_opmode32])
+addop("push", [bs8(0x68), d_imm, stk, bs_opmode32])
+addop("push", [bs8(0x0e), stk, d_cs, bs_opmode32])
+addop("push", [bs8(0x16), stk, d_ss, bs_opmode32])
+addop("push", [bs8(0x1e), stk, d_ds, bs_opmode32])
+addop("push", [bs8(0x06), stk, d_es, bs_opmode32])
+addop("push", [bs8(0x0f), stk, bs8(0xa0), d_fs, bs_opmode32])
+addop("push", [bs8(0x0f), stk, bs8(0xa8), d_gs, bs_opmode32])
+
+addop("push", [bs8(0xff), stk, bs_opmode64] + rmmod(d6))
+addop("push", [bs("01010"), stk, reg, bs_opmode64])
+addop("push", [bs8(0x6a), s08, stk, bs_opmode64])
+addop("push", [bs8(0x68), d_imm, stk, bs_opmode64])
+addop("push", [bs8(0x0e), stk, d_cs, bs_opmode64])
+addop("push", [bs8(0x16), stk, d_ss, bs_opmode64])
+addop("push", [bs8(0x1e), stk, d_ds, bs_opmode64])
+addop("push", [bs8(0x06), stk, d_es, bs_opmode64])
+addop("push", [bs8(0x0f), stk, bs8(0xa0), d_fs, bs_opmode64])
+addop("push", [bs8(0x0f), stk, bs8(0xa8), d_gs, bs_opmode64])
+
+addop("pusha", [bs8(0x60), stk, bs_opmode16_no64])
+addop("pushad", [bs8(0x60), stk, bs_opmode32_no64])
+
+
+addop("pushfw", [bs8(0x9c), stk, bs_opmode16])
+addop("pushfd", [bs8(0x9c), stk, bs_opmode32])
+addop("pushfq", [bs8(0x9c), stk, bs_opmode64])
+
+addop("rcl", [bs('110100'), d_cl1, w8] +
+      rmmod(d2, rm_arg_w8), [rm_arg_w8, d_cl1])
+addop("rcl", [bs('1100000'), w8] + rmmod(d2, rm_arg_w8) + [u08])
+addop("rcr", [bs('110100'), d_cl1, w8] +
+      rmmod(d3, rm_arg_w8), [rm_arg_w8, d_cl1])
+addop("rcr", [bs('1100000'), w8] + rmmod(d3, rm_arg_w8) + [u08])
+addop("rol", [bs('110100'), d_cl1, w8]
+      + rmmod(d0, rm_arg_w8), [rm_arg_w8, d_cl1])
+addop("rol", [bs('1100000'), w8] + rmmod(d0, rm_arg_w8) + [u08])
+addop("ror", [bs('110100'), d_cl1, w8]
+      + rmmod(d1, rm_arg_w8), [rm_arg_w8, d_cl1])
+addop("ror", [bs('1100000'), w8] + rmmod(d1, rm_arg_w8) + [u08])
+
+addop("rdmsr", [bs8(0x0f), bs8(0x32)])
+addop("rdpmc", [bs8(0x0f), bs8(0x33)])
+addop("rdtsc", [bs8(0x0f), bs8(0x31)])
+addop("ret", [bs8(0xc3), stk])
+addop("ret", [bs8(0xc2), stk, u16])
+addop("retf", [bs8(0xcb), stk])
+addop("retf", [bs8(0xca), stk, u16])
+
+addop("rsm", [bs8(0x0f), bs8(0xaa)])
+addop("sahf", [bs8(0x9e)])
+
+# XXX tipo in doc: /4 instead of /6
+addop("sal", [bs('110100'), d_cl1, w8] +
+      rmmod(d6, rm_arg_w8), [rm_arg_w8, d_cl1])
+addop("sal", [bs('1100000'), w8] + rmmod(d6, rm_arg_w8) + [u08])
+addop("sar", [bs('110100'), d_cl1, w8] +
+      rmmod(d7, rm_arg_w8), [rm_arg_w8, d_cl1])
+addop("sar", [bs('1100000'), w8] + rmmod(d7, rm_arg_w8) + [u08])
+
+addop("scasb", [bs8(0xae)])
+addop("scasw", [bs8(0xaf), bs_opmode16])
+addop("scasd", [bs8(0xaf), bs_opmode32])
+addop("scasq", [bs8(0xaf), bs_opmode64])
+
+addop("shl", [bs('110100'), d_cl1, w8]
+      + rmmod(d4, rm_arg_w8), [rm_arg_w8, d_cl1])
+addop("shl", [bs('1100000'), w8] + rmmod(d4, rm_arg_w8) + [u08])
+addop("shr", [bs('110100'), d_cl1, w8]
+      + rmmod(d5, rm_arg_w8), [rm_arg_w8, d_cl1])
+addop("shr", [bs('1100000'), w8] + rmmod(d5, rm_arg_w8) + [u08])
+
+addop("sbb", [bs("0001110"), w8, d_eax, d_imm])
+addop("sbb", [bs("100000"), se, w8] + rmmod(d3, rm_arg_w8) + [d_imm])
+addop("sbb", [bs("000110"), swapargs, w8] +
+      rmmod(rmreg, rm_arg_w8), [rm_arg_w8, rmreg])
+
+addop("set", [bs8(0x0f), bs('1001'), cond] + rmmod(regnoarg, rm_arg_08))
+addop("sgdt", [bs8(0x0f), bs8(0x01)] + rmmod(d0, modrm=mod_mem))
+addop("shld", [bs8(0x0f), bs8(0xa4)] +
+      rmmod(rmreg) + [u08], [rm_arg, rmreg, u08])
+addop("shld", [bs8(0x0f), bs8(0xa5)] +
+      rmmod(rmreg) + [d_cl], [rm_arg, rmreg, d_cl])
+addop("shrd", [bs8(0x0f), bs8(0xac)] +
+      rmmod(rmreg) + [u08], [rm_arg, rmreg, u08])
+addop("shrd", [bs8(0x0f), bs8(0xad)] +
+      rmmod(rmreg) + [d_cl], [rm_arg, rmreg, d_cl])
+addop("sidt", [bs8(0x0f), bs8(0x01)] + rmmod(d1, modrm=mod_mem))
+addop("sldt", [bs8(0x0f), bs8(0x00)] + rmmod(d0, rm_arg_x=rm_arg_reg_m16))
+addop("smsw", [bs8(0x0f), bs8(0x01)] + rmmod(d4))
+addop("stc", [bs8(0xf9)])
+addop("std", [bs8(0xfd)])
+addop("sti", [bs8(0xfb)])
+addop("stosb", [bs8(0xaa)])
+addop("stosw", [bs8(0xab), bs_opmode16])
+addop("stosd", [bs8(0xab), bs_opmode32])
+addop("stosq", [bs8(0xab), bs_opmode64])
+
+addop("str", [bs8(0x0f), bs8(0x00)] + rmmod(d1))
+
+addop("sub", [bs("0010110"), w8, d_eax, d_imm])
+addop("sub", [bs("100000"), se, w8] + rmmod(d5, rm_arg_w8) + [d_imm])
+addop("sub", [bs("001010"), swapargs, w8] +
+      rmmod(rmreg, rm_arg_w8), [rm_arg_w8, rmreg])
+
+addop("syscall", [bs8(0x0f), bs8(0x05)])
+addop("sysenter", [bs8(0x0f), bs8(0x34)])
+addop("sysexit", [bs8(0x0f), bs8(0x35)])
+addop("sysret", [bs8(0x0f), bs8(0x07)])
+addop("test", [bs("1010100"), w8, d_eax, d_imm])
+addop("test", [bs("1111011"), w8] + rmmod(d0, rm_arg_w8) + [d_imm])
+addop("test", [bs("1000010"), w8] +
+      rmmod(rmreg, rm_arg_w8), [rm_arg_w8, rmreg])
+addop("ud2", [bs8(0x0f), bs8(0x0b)])
+addop("verr", [bs8(0x0f), bs8(0x00)] + rmmod(d4))
+addop("verw", [bs8(0x0f), bs8(0x00)] + rmmod(d5))
+addop("wbinvd", [bs8(0x0f), bs8(0x09)])
+addop("wrmsr", [bs8(0x0f), bs8(0x30)])
+addop("xadd", [bs8(0x0f), bs("1100000"), w8]
+      + rmmod(rmreg, rm_arg_w8), [rm_arg_w8, rmreg])
+
+addop("nop", [bs8(0x90), no_rex], alias=True)
+
+addop("xchg", [bs('10010'), d_eax, reg])
+addop("xchg", [bs('1000011'), w8] +
+      rmmod(rmreg, rm_arg_w8), [rm_arg_w8, rmreg])
+addop("xlat", [bs8(0xd7)])
+
+
+addop("xor", [bs("0011010"), w8, d_eax, d_imm])
+addop("xor", [bs("100000"), se, w8] + rmmod(d6, rm_arg_w8) + [d_imm])
+addop("xor", [bs("001100"), swapargs, w8] +
+      rmmod(rmreg, rm_arg_w8), [rm_arg_w8, rmreg])
+
+
+addop("xgetbv", [bs8(0x0f), bs8(0x01), bs8(0xd0)])
+
+
+
+#### MMX/SSE/AVX operations
+#### Categories are the same than here: https://software.intel.com/sites/landingpage/IntrinsicsGuide/
+####
+
+### Arithmetic (integers)
+###
+
+## Move
+# SSE
+addop("movapd", [bs8(0x0f), bs("0010100"), swapargs]
+      + rmmod(xmm_reg, rm_arg_xmm) + [bs_opmode16], [xmm_reg, rm_arg_xmm])
+addop("movaps", [bs8(0x0f), bs("0010100"), swapargs]
+      + rmmod(xmm_reg, rm_arg_xmm_m128) + [bs_opmode32], [xmm_reg, rm_arg_xmm_m128])
+addop("movaps", [bs8(0x0f), bs("0010100"), swapargs]
+      + rmmod(xmm_reg, rm_arg_xmm_m128) + [bs_opmode64], [xmm_reg, rm_arg_xmm_m128])
+addop("movdqu", [bs8(0x0f), bs("011"), swapargs, bs("1111"), pref_f3]
+      + rmmod(xmm_reg, rm_arg_xmm), [xmm_reg, rm_arg_xmm])
+addop("movdqa", [bs8(0x0f), bs("011"), swapargs, bs("1111"), pref_66]
+      + rmmod(xmm_reg, rm_arg_xmm), [xmm_reg, rm_arg_xmm])
+
+addop("movhpd", [bs8(0x0f), bs("0001011"), swapargs, pref_66] +
+      rmmod(xmm_reg, rm_arg_m64), [xmm_reg, rm_arg_m64])
+addop("movhps", [bs8(0x0f), bs("0001011"), swapargs, no_xmm_pref] +
+      rmmod(xmm_reg, rm_arg_m64), [xmm_reg, rm_arg_m64])
+addop("movlpd", [bs8(0x0f), bs("0001001"), swapargs, pref_66] +
+      rmmod(xmm_reg, rm_arg_m64), [xmm_reg, rm_arg_m64])
+addop("movlps", [bs8(0x0f), bs("0001001"), swapargs, no_xmm_pref] +
+      rmmod(xmm_reg, rm_arg_m64), [xmm_reg, rm_arg_m64])
+
+addop("movhlps", [bs8(0x0f), bs8(0x12), no_xmm_pref] +
+      rmmod(xmm_reg, rm_arg_xmm_reg), [xmm_reg, rm_arg_xmm_reg])
+addop("movlhps", [bs8(0x0f), bs8(0x16), no_xmm_pref] +
+      rmmod(xmm_reg, rm_arg_xmm_reg), [xmm_reg, rm_arg_xmm_reg])
+
+addop("movdq2q", [bs8(0x0f), bs8(0xd6), pref_f2] +
+      rmmod(mm_reg, rm_arg_xmm_reg), [mm_reg, rm_arg_xmm_reg])
+addop("movq2dq", [bs8(0x0f), bs8(0xd6), pref_f3] +
+      rmmod(xmm_reg, rm_arg_mm))
+
+## Additions
+# SSE
+addop("paddb", [bs8(0x0f), bs8(0xfc), pref_66] + rmmod(xmm_reg, rm_arg_xmm))
+addop("paddw", [bs8(0x0f), bs8(0xfd), pref_66] + rmmod(xmm_reg, rm_arg_xmm))
+addop("paddd", [bs8(0x0f), bs8(0xfe), pref_66] + rmmod(xmm_reg, rm_arg_xmm))
+addop("paddq", [bs8(0x0f), bs8(0xd4), pref_66] + rmmod(xmm_reg, rm_arg_xmm))
+
+addop("paddb", [bs8(0x0f), bs8(0xfc), no_xmm_pref] + rmmod(mm_reg, rm_arg_mm))
+addop("paddw", [bs8(0x0f), bs8(0xfd), no_xmm_pref] + rmmod(mm_reg, rm_arg_mm))
+addop("paddd", [bs8(0x0f), bs8(0xfe), no_xmm_pref] + rmmod(mm_reg, rm_arg_mm))
+addop("paddq", [bs8(0x0f), bs8(0xd4), no_xmm_pref] + rmmod(mm_reg, rm_arg_mm))
+
+## Substractions
+# SSE
+addop("psubb", [bs8(0x0f), bs8(0xf8), pref_66] + rmmod(xmm_reg, rm_arg_xmm))
+addop("psubw", [bs8(0x0f), bs8(0xf9), pref_66] + rmmod(xmm_reg, rm_arg_xmm))
+addop("psubd", [bs8(0x0f), bs8(0xfa), pref_66] + rmmod(xmm_reg, rm_arg_xmm))
+addop("psubq", [bs8(0x0f), bs8(0xfb), pref_66] + rmmod(xmm_reg, rm_arg_xmm))
+
+addop("psubb", [bs8(0x0f), bs8(0xf8), no_xmm_pref] + rmmod(mm_reg, rm_arg_mm))
+addop("psubw", [bs8(0x0f), bs8(0xf9), no_xmm_pref] + rmmod(mm_reg, rm_arg_mm))
+addop("psubd", [bs8(0x0f), bs8(0xfa), no_xmm_pref] + rmmod(mm_reg, rm_arg_mm))
+addop("psubq", [bs8(0x0f), bs8(0xfb), no_xmm_pref] + rmmod(mm_reg, rm_arg_mm))
+
+### Arithmetic (floating-point)
+###
+
+## Additions
+# SSE
+addop("addps", [bs8(0x0f), bs8(0x58), no_xmm_pref] + rmmod(xmm_reg, rm_arg_xmm))
+addop("addpd", [bs8(0x0f), bs8(0x58), pref_66] + rmmod(xmm_reg, rm_arg_xmm))
+
+## Substractions
+# SSE
+addop("subps", [bs8(0x0f), bs8(0x5c), no_xmm_pref] + rmmod(xmm_reg, rm_arg_xmm))
+addop("subpd", [bs8(0x0f), bs8(0x5c), pref_66] + rmmod(xmm_reg, rm_arg_xmm))
+
+## Multiplications
+# SSE
+addop("mulps", [bs8(0x0f), bs8(0x59), no_xmm_pref] + rmmod(xmm_reg, rm_arg_xmm))
+addop("mulpd", [bs8(0x0f), bs8(0x59), pref_66] + rmmod(xmm_reg, rm_arg_xmm))
+
+## Divisions
+# SSE
+addop("divps", [bs8(0x0f), bs8(0x5e), no_xmm_pref] + rmmod(xmm_reg, rm_arg_xmm))
+addop("divpd", [bs8(0x0f), bs8(0x5e), pref_66] + rmmod(xmm_reg, rm_arg_xmm))
+
+### Logical (floating-point)
+###
+
+## XOR
+addop("xorps", [bs8(0x0f), bs8(0x57), no_xmm_pref] + rmmod(xmm_reg, rm_arg_xmm))
+addop("xorpd", [bs8(0x0f), bs8(0x57), pref_66] + rmmod(xmm_reg, rm_arg_xmm))
+
+## AND
+addop("andps", [bs8(0x0f), bs8(0x54), no_xmm_pref] + rmmod(xmm_reg, rm_arg_xmm))
+addop("andpd", [bs8(0x0f), bs8(0x54), pref_66] + rmmod(xmm_reg, rm_arg_xmm))
+
+addop("andnps", [bs8(0x0f), bs8(0x55), no_xmm_pref] + rmmod(xmm_reg, rm_arg_xmm))
+addop("andnpd", [bs8(0x0f), bs8(0x55), pref_66] + rmmod(xmm_reg, rm_arg_xmm))
+
+## OR
+addop("orps", [bs8(0x0f), bs8(0x56), no_xmm_pref] + rmmod(xmm_reg, rm_arg_xmm))
+addop("orpd", [bs8(0x0f), bs8(0x56), pref_66] + rmmod(xmm_reg, rm_arg_xmm))
+
+## AND
+# MMX
+addop("pand", [bs8(0x0f), bs8(0xdb), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm), [mm_reg, rm_arg_mm])
+# SSE
+addop("pand", [bs8(0x0f), bs8(0xdb), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm), [xmm_reg, rm_arg_xmm])
+
+## ANDN
+# MMX
+addop("pandn", [bs8(0x0f), bs8(0xdf), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm), [mm_reg, rm_arg_mm])
+# SSE
+addop("pandn", [bs8(0x0f), bs8(0xdf), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm), [xmm_reg, rm_arg_xmm])
+
+## OR
+# MMX
+addop("por", [bs8(0x0f), bs8(0xeb), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm), [mm_reg, rm_arg_mm])
+# SSE
+addop("por", [bs8(0x0f), bs8(0xeb), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm), [xmm_reg, rm_arg_xmm])
+
+## XOR
+# MMX
+addop("pxor", [bs8(0x0f), bs8(0xef), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm))
+# MMX
+addop("pxor", [bs8(0x0f), bs8(0xef), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm))
+
+### Comparisons (floating-point)
+###
+addop("minps", [bs8(0x0f), bs8(0x5d), no_xmm_pref] + rmmod(xmm_reg,
+                                                           rm_arg_xmm_m128))
+addop("minss", [bs8(0x0f), bs8(0x5d), pref_f3] + rmmod(xmm_reg,
+                                                       rm_arg_xmm_m32))
+addop("minpd", [bs8(0x0f), bs8(0x5d), pref_66] + rmmod(xmm_reg,
+                                                       rm_arg_xmm_m128))
+addop("minsd", [bs8(0x0f), bs8(0x5d), pref_f2] + rmmod(xmm_reg,
+                                                       rm_arg_xmm_m64))
+addop("maxps", [bs8(0x0f), bs8(0x5f), no_xmm_pref] + rmmod(xmm_reg,
+                                                           rm_arg_xmm_m128))
+addop("maxpd", [bs8(0x0f), bs8(0x5f), pref_66] + rmmod(xmm_reg,
+                                                       rm_arg_xmm_m128))
+addop("maxsd", [bs8(0x0f), bs8(0x5f), pref_f2] + rmmod(xmm_reg, rm_arg_xmm_m64))
+addop("maxss", [bs8(0x0f), bs8(0x5f), pref_f3] + rmmod(xmm_reg, rm_arg_xmm_m32))
+
+for cond_name, value in [
+        ("eq", 0x00),
+        ("lt", 0x01),
+        ("le", 0x02),
+        ("unord", 0x03),
+        ("neq", 0x04),
+        ("nlt", 0x05),
+        ("nle", 0x06),
+        ("ord", 0x07),
+]:
+    addop("cmp%sps" % cond_name, [bs8(0x0f), bs8(0xc2), no_xmm_pref] +
+          rmmod(xmm_reg, rm_arg_xmm_m64) + [bs8(value)])
+    addop("cmp%spd" % cond_name, [bs8(0x0f), bs8(0xc2), pref_66] +
+          rmmod(xmm_reg, rm_arg_xmm_m64) + [bs8(value)])
+    addop("cmp%sss" % cond_name, [bs8(0x0f), bs8(0xc2), pref_f3] +
+          rmmod(xmm_reg, rm_arg_xmm_m32) + [bs8(value)])
+    addop("cmp%ssd" % cond_name, [bs8(0x0f), bs8(0xc2), pref_f2] +
+          rmmod(xmm_reg, rm_arg_xmm_m32) + [bs8(value)])
+
+
+
+addop("pshufb", [bs8(0x0f), bs8(0x38), bs8(0x00), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm_m64))
+addop("pshufb", [bs8(0x0f), bs8(0x38), bs8(0x00), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm_m128))
+addop("pshufd", [bs8(0x0f), bs8(0x70), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm_m128) + [u08])
+addop("pshuflw", [bs8(0x0f), bs8(0x70), pref_f2] +
+      rmmod(xmm_reg, rm_arg_xmm_m128) + [u08])
+addop("pshufhw", [bs8(0x0f), bs8(0x70), pref_f3] +
+      rmmod(xmm_reg, rm_arg_xmm_m128) + [u08])
+
+
+### Convert
+### SS = single precision
+### SD = double precision
+###
+
+## SS -> SD
+##
+
+addop("cvtdq2pd", [bs8(0x0f), bs8(0xe6), pref_f3]
+      + rmmod(xmm_reg, rm_arg_xmm_m64))
+addop("cvtdq2ps", [bs8(0x0f), bs8(0x5b), no_xmm_pref]
+      + rmmod(xmm_reg, rm_arg_xmm))
+addop("cvtpd2dq", [bs8(0x0f), bs8(0xe6), pref_f2]
+      + rmmod(xmm_reg, rm_arg_xmm))
+addop("cvtpd2pi", [bs8(0x0f), bs8(0x2d), pref_66]
+      + rmmod(mm_reg, rm_arg_xmm))
+addop("cvtpd2ps", [bs8(0x0f), bs8(0x5a), pref_66]
+      + rmmod(xmm_reg, rm_arg_xmm))
+addop("cvtpi2pd", [bs8(0x0f), bs8(0x2a), pref_66]
+      + rmmod(xmm_reg, rm_arg_mm_m64))
+addop("cvtpi2ps", [bs8(0x0f), bs8(0x2a), no_xmm_pref]
+      + rmmod(xmm_reg, rm_arg_mm_m64))
+addop("cvtps2dq", [bs8(0x0f), bs8(0x5b), pref_66]
+      + rmmod(xmm_reg, rm_arg_xmm))
+addop("cvtps2pd", [bs8(0x0f), bs8(0x5a), no_xmm_pref]
+      + rmmod(xmm_reg, rm_arg_xmm_m64))
+addop("cvtps2pi", [bs8(0x0f), bs8(0x2d), no_xmm_pref]
+      + rmmod(mm_reg, rm_arg_xmm_m64))
+addop("cvtsd2si", [bs8(0x0f), bs8(0x2d), pref_f2]
+      + rmmod(reg, rm_arg_xmm_m64))
+addop("cvtsd2ss", [bs8(0x0f), bs8(0x5a), pref_f2]
+      + rmmod(xmm_reg, rm_arg_xmm_m64))
+addop("cvtsi2sd", [bs8(0x0f), bs8(0x2a), pref_f2]
+      + rmmod(xmm_reg, rm_arg))
+addop("cvtsi2ss", [bs8(0x0f), bs8(0x2a), xmmreg, pref_f3]
+      + rmmod(xmm_reg, rm_arg))
+addop("cvtss2sd", [bs8(0x0f), bs8(0x5a), pref_f3]
+      + rmmod(xmm_reg, rm_arg_xmm_m32))
+addop("cvtss2si", [bs8(0x0f), bs8(0x2d), pref_f3]
+      + rmmod(rmreg, rm_arg_xmm_m32))
+addop("cvttpd2pi",[bs8(0x0f), bs8(0x2c), pref_66]
+      + rmmod(mm_reg, rm_arg_xmm))
+addop("cvttpd2dq",[bs8(0x0f), bs8(0xe6), pref_66]
+      + rmmod(xmm_reg, rm_arg_xmm))
+addop("cvttps2dq",[bs8(0x0f), bs8(0x5b), pref_f3]
+      + rmmod(xmm_reg, rm_arg_xmm))
+addop("cvttps2pi",[bs8(0x0f), bs8(0x2c), no_xmm_pref]
+      + rmmod(mm_reg, rm_arg_xmm_m64))
+addop("cvttsd2si",[bs8(0x0f), bs8(0x2c), pref_f2]
+      + rmmod(reg, rm_arg_xmm_m64))
+addop("cvttss2si",[bs8(0x0f), bs8(0x2c), pref_f3]
+      + rmmod(reg, rm_arg_xmm_m32))
+
+addop("palignr", [bs8(0x0f), bs8(0x73), bs8(0x0f), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm_m64) + [u08], [mm_reg, rm_arg_mm_m64, u08])
+addop("palignr", [bs8(0x0f), bs8(0x3a), bs8(0x0f), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm_m128) + [u08], [xmm_reg, rm_arg_xmm_m128, u08])
+
+addop("psrlq", [bs8(0x0f), bs8(0x73), no_xmm_pref] +
+      rmmod(d2, rm_arg_mm) + [u08], [rm_arg_mm, u08])
+addop("psrlq", [bs8(0x0f), bs8(0x73), pref_66] +
+      rmmod(d2, rm_arg_xmm) + [u08], [rm_arg_xmm, u08])
+
+addop("psrlq", [bs8(0x0f), bs8(0xd3), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm), [mm_reg, rm_arg_mm])
+addop("psrlq", [bs8(0x0f), bs8(0xd3), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm), [xmm_reg, rm_arg_xmm])
+
+
+addop("psrld", [bs8(0x0f), bs8(0x72), no_xmm_pref] +
+      rmmod(d2, rm_arg_mm) + [u08], [rm_arg_mm, u08])
+addop("psrld", [bs8(0x0f), bs8(0x72), pref_66] +
+      rmmod(d2, rm_arg_xmm) + [u08], [rm_arg_xmm, u08])
+
+addop("psrld", [bs8(0x0f), bs8(0xd2), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm), [mm_reg, rm_arg_mm])
+addop("psrld", [bs8(0x0f), bs8(0xd2), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm), [xmm_reg, rm_arg_xmm])
+
+addop("psrldq", [bs8(0x0f), bs8(0x73), pref_66] +
+      rmmod(d3, rm_arg_xmm) + [u08], [rm_arg_xmm, u08])
+
+addop("psrlw", [bs8(0x0f), bs8(0x71), no_xmm_pref] +
+      rmmod(d2, rm_arg_mm) + [u08], [rm_arg_mm, u08])
+addop("psrlw", [bs8(0x0f), bs8(0x71), pref_66] +
+      rmmod(d2, rm_arg_xmm) + [u08], [rm_arg_xmm, u08])
+
+addop("psrlw", [bs8(0x0f), bs8(0xd1), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm_m64), [mm_reg, rm_arg_mm_m64])
+addop("psrlw", [bs8(0x0f), bs8(0xd1), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm_m128), [xmm_reg, rm_arg_xmm_m128])
+
+addop("psraw", [bs8(0x0f), bs8(0xe1), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm_m64), [mm_reg, rm_arg_mm_m64])
+addop("psraw", [bs8(0x0f), bs8(0xe1), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm_m128), [xmm_reg, rm_arg_xmm_m128])
+
+addop("psraw", [bs8(0x0f), bs8(0x71), no_xmm_pref] +
+      rmmod(d4, rm_arg_mm_m64) + [u08], [rm_arg_mm_m64, u08])
+addop("psraw", [bs8(0x0f), bs8(0x71), pref_66] +
+      rmmod(d4, rm_arg_xmm_m128) + [u08], [rm_arg_xmm_m128, u08])
+
+addop("psrad", [bs8(0x0f), bs8(0xe2), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm_m64), [mm_reg, rm_arg_mm_m64])
+addop("psrad", [bs8(0x0f), bs8(0xe2), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm_m128), [xmm_reg, rm_arg_xmm_m128])
+
+addop("psrad", [bs8(0x0f), bs8(0x72), no_xmm_pref] +
+      rmmod(d4, rm_arg_mm_m64) + [u08], [rm_arg_mm_m64, u08])
+addop("psrad", [bs8(0x0f), bs8(0x72), pref_66] +
+      rmmod(d4, rm_arg_xmm_m128) + [u08], [rm_arg_xmm_m128, u08])
+
+
+addop("psllq", [bs8(0x0f), bs8(0x73), no_xmm_pref] +
+      rmmod(d6, rm_arg_mm) + [u08], [rm_arg_mm, u08])
+addop("psllq", [bs8(0x0f), bs8(0x73), pref_66] +
+      rmmod(d6, rm_arg_xmm) + [u08], [rm_arg_xmm, u08])
+
+addop("psllq", [bs8(0x0f), bs8(0xf3), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm), [mm_reg, rm_arg_mm])
+addop("psllq", [bs8(0x0f), bs8(0xf3), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm), [xmm_reg, rm_arg_xmm])
+
+
+addop("pslld", [bs8(0x0f), bs8(0x72), no_xmm_pref] +
+      rmmod(d6, rm_arg_mm) + [u08], [rm_arg_mm, u08])
+addop("pslld", [bs8(0x0f), bs8(0x72), pref_66] +
+      rmmod(d6, rm_arg_xmm) + [u08], [rm_arg_xmm, u08])
+
+addop("pslld", [bs8(0x0f), bs8(0xf2), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm), [mm_reg, rm_arg_mm])
+addop("pslld", [bs8(0x0f), bs8(0xf2), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm), [xmm_reg, rm_arg_xmm])
+
+
+addop("psllw", [bs8(0x0f), bs8(0x71), no_xmm_pref] +
+      rmmod(d6, rm_arg_mm) + [u08], [rm_arg_mm, u08])
+addop("psllw", [bs8(0x0f), bs8(0x71), pref_66] +
+      rmmod(d6, rm_arg_xmm) + [u08], [rm_arg_xmm, u08])
+
+addop("psllw", [bs8(0x0f), bs8(0xf1), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm), [mm_reg, rm_arg_mm])
+addop("psllw", [bs8(0x0f), bs8(0xf1), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm), [xmm_reg, rm_arg_xmm])
+
+addop("pslldq", [bs8(0x0f), bs8(0x73), pref_66] +
+      rmmod(d7, rm_arg_xmm) + [u08], [rm_arg_xmm, u08])
+
+
+addop("pmaxub", [bs8(0x0f), bs8(0xde), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm))
+addop("pmaxub", [bs8(0x0f), bs8(0xde), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm))
+
+addop("pmaxuw", [bs8(0x0f), bs8(0x38), bs8(0x3e), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm))
+
+addop("pmaxud", [bs8(0x0f), bs8(0x38), bs8(0x3f), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm))
+
+addop("pmaxsw", [bs8(0x0f), bs8(0xee), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm_m64))
+addop("pmaxsw", [bs8(0x0f), bs8(0xee), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm_m128))
+
+addop("pminub", [bs8(0x0f), bs8(0xda), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm))
+addop("pminub", [bs8(0x0f), bs8(0xda), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm))
+
+addop("pminuw", [bs8(0x0f), bs8(0x38), bs8(0x3a), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm))
+
+addop("pminud", [bs8(0x0f), bs8(0x38), bs8(0x3b), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm))
+
+
+addop("pcmpeqb", [bs8(0x0f), bs8(0x74), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm))
+addop("pcmpeqb", [bs8(0x0f), bs8(0x74), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm))
+
+addop("pcmpeqw", [bs8(0x0f), bs8(0x75), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm))
+addop("pcmpeqw", [bs8(0x0f), bs8(0x75), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm))
+
+addop("pcmpeqd", [bs8(0x0f), bs8(0x76), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm))
+addop("pcmpeqd", [bs8(0x0f), bs8(0x76), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm))
+
+addop("pcmpgtb", [bs8(0x0f), bs8(0x64), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm))
+addop("pcmpgtb", [bs8(0x0f), bs8(0x64), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm))
+
+addop("pcmpgtw", [bs8(0x0f), bs8(0x65), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm))
+addop("pcmpgtw", [bs8(0x0f), bs8(0x65), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm))
+
+addop("pcmpgtd", [bs8(0x0f), bs8(0x66), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm))
+addop("pcmpgtd", [bs8(0x0f), bs8(0x66), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm))
+
+addop("pcmpeqq", [bs8(0x0f), bs8(0x38), bs8(0x29), pref_66] + rmmod(xmm_reg, rm_arg_xmm))
+addop("pcmpgtq", [bs8(0x0f), bs8(0x38), bs8(0x37), pref_66] + rmmod(xmm_reg, rm_arg_xmm))
+
+addop("punpckhbw", [bs8(0x0f), bs8(0x68), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm))
+addop("punpckhbw", [bs8(0x0f), bs8(0x68), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm))
+
+addop("punpckhwd", [bs8(0x0f), bs8(0x69), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm))
+addop("punpckhwd", [bs8(0x0f), bs8(0x69), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm))
+
+addop("punpckhdq", [bs8(0x0f), bs8(0x6a), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm))
+addop("punpckhdq", [bs8(0x0f), bs8(0x6a), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm))
+
+addop("punpckhqdq", [bs8(0x0f), bs8(0x6d), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm))
+
+
+
+addop("punpcklbw", [bs8(0x0f), bs8(0x60), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm))
+addop("punpcklbw", [bs8(0x0f), bs8(0x60), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm))
+
+addop("punpcklwd", [bs8(0x0f), bs8(0x61), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm))
+addop("punpcklwd", [bs8(0x0f), bs8(0x61), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm))
+
+addop("punpckldq", [bs8(0x0f), bs8(0x62), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm))
+addop("punpckldq", [bs8(0x0f), bs8(0x62), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm))
+
+addop("punpcklqdq", [bs8(0x0f), bs8(0x6c), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm))
+
+
+addop("unpckhps", [bs8(0x0f), bs8(0x15), no_xmm_pref] +
+      rmmod(xmm_reg, rm_arg_xmm))
+addop("unpckhpd", [bs8(0x0f), bs8(0x15), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm))
+
+
+addop("unpcklps", [bs8(0x0f), bs8(0x14), no_xmm_pref] +
+      rmmod(xmm_reg, rm_arg_xmm))
+addop("unpcklpd", [bs8(0x0f), bs8(0x14), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm))
+
+
+
+addop("pinsrb", [bs8(0x0f), bs8(0x3a), bs8(0x20), pref_66] +
+      rmmod(xmm_reg, rm_arg_reg_m08) + [u08])
+addop("pinsrd", [bs8(0x0f), bs8(0x3a), bs8(0x22), pref_66, bs_opmode32] +
+      rmmod(xmm_reg, rm_arg) + [u08])
+addop("pinsrq", [bs8(0x0f), bs8(0x3a), bs8(0x22), pref_66] +
+      rmmod(xmm_reg, rm_arg_m64) + [bs_opmode64] + [u08])
+
+addop("pinsrw", [bs8(0x0f), bs8(0xc4), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_reg_m16) + [u08])
+addop("pinsrw", [bs8(0x0f), bs8(0xc4), pref_66] +
+      rmmod(xmm_reg, rm_arg_reg_m16) + [u08])
+
+
+addop("pextrb", [bs8(0x0f), bs8(0x3a), bs8(0x14), pref_66] +
+      rmmod(xmm_reg, rm_arg_reg_m08) + [u08], [rm_arg_reg_m08, xmm_reg, u08])
+addop("pextrd", [bs8(0x0f), bs8(0x3a), bs8(0x16), pref_66, bs_opmode32] +
+      rmmod(xmm_reg, rm_arg) + [u08], [rm_arg, xmm_reg, u08])
+addop("pextrq", [bs8(0x0f), bs8(0x3a), bs8(0x16), pref_66] +
+      rmmod(xmm_reg, rm_arg_m64) + [bs_opmode64] + [u08], [rm_arg_m64, xmm_reg, u08])
+
+
+addop("pextrw", [bs8(0x0f), bs8(0x3a), bs8(0x15), pref_66] +
+      rmmod(xmm_reg, rm_arg_reg_m16) + [u08], [rm_arg_reg_m16, xmm_reg, u08])
+addop("pextrw", [bs8(0x0f), bs8(0xc5), no_xmm_pref] +
+      rmmod(rmreg, rm_arg_mm) + [u08], [rmreg, rm_arg_mm, u08])
+addop("pextrw", [bs8(0x0f), bs8(0xc5), pref_66] +
+      rmmod(rmreg, rm_arg_xmm) + [u08], [rmreg, rm_arg_xmm, u08])
+
+
+addop("sqrtpd", [bs8(0x0f), bs8(0x51), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm))
+addop("sqrtps", [bs8(0x0f), bs8(0x51), no_xmm_pref] +
+      rmmod(xmm_reg, rm_arg_xmm))
+addop("sqrtsd", [bs8(0x0f), bs8(0x51), pref_f2] +
+      rmmod(xmm_reg, rm_arg_xmm_m64))
+addop("sqrtss", [bs8(0x0f), bs8(0x51), pref_f3] +
+      rmmod(xmm_reg, rm_arg_xmm_m32))
+
+addop("pmovmskb", [bs8(0x0f), bs8(0xd7), no_xmm_pref] +
+      rmmod(reg_modrm, rm_arg_mm_reg))
+addop("pmovmskb", [bs8(0x0f), bs8(0xd7), pref_66] +
+      rmmod(reg_modrm, rm_arg_xmm_reg))
+
+addop("shufps", [bs8(0x0f), bs8(0xc6), no_xmm_pref] +
+      rmmod(xmm_reg, rm_arg_xmm) + [u08])
+addop("shufpd", [bs8(0x0f), bs8(0xc6), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm) + [u08])
+
+addop("aesenc", [bs8(0x0f), bs8(0x38), bs8(0xdc), pref_66] + rmmod(xmm_reg, rm_arg_xmm))
+addop("aesdec", [bs8(0x0f), bs8(0x38), bs8(0xde), pref_66] + rmmod(xmm_reg, rm_arg_xmm))
+
+addop("aesenclast", [bs8(0x0f), bs8(0x38), bs8(0xdd), pref_66] + rmmod(xmm_reg, rm_arg_xmm))
+addop("aesdeclast", [bs8(0x0f), bs8(0x38), bs8(0xdf), pref_66] + rmmod(xmm_reg, rm_arg_xmm))
+
+addop("packsswb", [bs8(0x0f), bs8(0x63), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm_m64))
+addop("packsswb", [bs8(0x0f), bs8(0x63), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm_m128))
+addop("packssdw", [bs8(0x0f), bs8(0x6b), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm_m64))
+addop("packssdw", [bs8(0x0f), bs8(0x6b), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm_m128))
+
+addop("packuswb", [bs8(0x0f), bs8(0x67), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm_m64))
+addop("packuswb", [bs8(0x0f), bs8(0x67), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm_m128))
+
+addop("pmullw", [bs8(0x0f), bs8(0xd5), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm_m64))
+addop("pmullw", [bs8(0x0f), bs8(0xd5), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm_m128))
+addop("pmulhuw", [bs8(0x0f), bs8(0xe4), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm_m64))
+addop("pmulhuw", [bs8(0x0f), bs8(0xe4), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm_m128))
+addop("pmulhw", [bs8(0x0f), bs8(0xe5), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm_m64))
+addop("pmulhw", [bs8(0x0f), bs8(0xe5), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm_m128))
+addop("pmuludq", [bs8(0x0f), bs8(0xf4), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm_m64))
+addop("pmuludq", [bs8(0x0f), bs8(0xf4), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm_m128))
+
+
+addop("psubusb", [bs8(0x0f), bs8(0xd8), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm_m64))
+addop("psubusb", [bs8(0x0f), bs8(0xd8), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm_m128))
+addop("psubusw", [bs8(0x0f), bs8(0xd9), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm_m64))
+addop("psubusw", [bs8(0x0f), bs8(0xd9), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm_m128))
+addop("psubsb", [bs8(0x0f), bs8(0xe8), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm_m64))
+addop("psubsb", [bs8(0x0f), bs8(0xe8), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm_m128))
+addop("psubsw", [bs8(0x0f), bs8(0xe9), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm_m64))
+addop("psubsw", [bs8(0x0f), bs8(0xe9), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm_m128))
+
+
+addop("paddusb", [bs8(0x0f), bs8(0xdc), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm_m64))
+addop("paddusb", [bs8(0x0f), bs8(0xdc), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm_m128))
+addop("paddusw", [bs8(0x0f), bs8(0xdd), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm_m64))
+addop("paddusw", [bs8(0x0f), bs8(0xdd), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm_m128))
+addop("paddsb", [bs8(0x0f), bs8(0xec), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm_m64))
+addop("paddsb", [bs8(0x0f), bs8(0xec), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm_m128))
+addop("paddsw", [bs8(0x0f), bs8(0xed), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm_m64))
+addop("paddsw", [bs8(0x0f), bs8(0xed), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm_m128))
+
+addop("pmaddwd", [bs8(0x0f), bs8(0xf5), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm_m64))
+addop("pmaddwd", [bs8(0x0f), bs8(0xf5), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm_m128))
+
+addop("psadbw", [bs8(0x0f), bs8(0xf6), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm_m64))
+addop("psadbw", [bs8(0x0f), bs8(0xf6), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm_m128))
+
+addop("pavgb", [bs8(0x0f), bs8(0xe0), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm_m64))
+addop("pavgb", [bs8(0x0f), bs8(0xe0), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm_m128))
+addop("pavgw", [bs8(0x0f), bs8(0xe3), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm_m64))
+addop("pavgw", [bs8(0x0f), bs8(0xe3), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm_m128))
+
+addop("maskmovq", [bs8(0x0f), bs8(0xf7), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm_reg))
+addop("maskmovdqu", [bs8(0x0f), bs8(0xf7), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm_reg))
+
+addop("emms", [bs8(0x0f), bs8(0x77)])
+
+addop("incssp", [pref_f3, bs8(0x0f), bs8(0xae)] + rmmod(d5))
+addop("rdssp", [pref_f3, bs8(0x0f), bs8(0x1e)] + rmmod(d1, modrm=mod_reg))
+addop("saveprevssp", [pref_f3, bs8(0x0f), bs8(0x01), bs8(0xea)])
+addop("rstorssp", [pref_f3, bs8(0x0f), bs8(0x01)] + rmmod(d5, rm_arg_xmm, modrm=mod_mem))
+addop("wrss", [bs8(0x0f), bs8(0x38), bs8(0xf6)] + rmmod(rmreg, rm_arg), [rm_arg, rmreg])
+addop("wruss", [pref_66, bs8(0x0f), bs8(0x38), bs8(0xf5)] + rmmod(rmreg, rm_arg), [rm_arg, rmreg])
+addop("setssbsy", [pref_f3, bs8(0x0f), bs8(0x01), bs8(0xe8)])
+addop("clrssbsy", [pref_f3, bs8(0x0f), bs8(0xae)] + rmmod(d6, rm_arg_xmm))
+addop("endbr64", [pref_f3, bs8(0x0f), bs8(0x1e), bs8(0xfa)])
+addop("endbr32", [pref_f3, bs8(0x0f), bs8(0x1e), bs8(0xfb)])
+
+mn_x86.bintree = factor_one_bit(mn_x86.bintree)
+# mn_x86.bintree = factor_fields_all(mn_x86.bintree)
+"""
+mod reg r/m
+ XX XXX XXX
+
+"""
+
+
+def print_size(e):
+    print(e, e.size)
+    return e
diff --git a/src/miasm/arch/x86/ctype.py b/src/miasm/arch/x86/ctype.py
new file mode 100644
index 00000000..2a61689a
--- /dev/null
+++ b/src/miasm/arch/x86/ctype.py
@@ -0,0 +1,137 @@
+from miasm.core.objc import CLeafTypes, ObjCDecl, PADDING_TYPE_NAME
+from miasm.core.ctypesmngr import CTypeId, CTypePtr
+
+
+class CTypeAMD64_unk(CLeafTypes):
+    """Define C types sizes/alignment for x86_64 architecture"""
+
+    obj_pad = ObjCDecl(PADDING_TYPE_NAME, 1, 1) # __padding__ is size 1/align 1
+
+    obj_char = ObjCDecl("char", 1, 1)
+    obj_short = ObjCDecl("short", 2, 2)
+    obj_int = ObjCDecl("int", 4, 4)
+    obj_long = ObjCDecl("long", 8, 8)
+
+    obj_uchar = ObjCDecl("uchar", 1, 1)
+    obj_ushort = ObjCDecl("ushort", 2, 2)
+    obj_uint = ObjCDecl("uint", 4, 4)
+    obj_ulong = ObjCDecl("ulong", 8, 8)
+
+    obj_void = ObjCDecl("void", 1, 1)
+
+    obj_enum = ObjCDecl("enum", 4, 4)
+
+    obj_float = ObjCDecl("float", 4, 4)
+    obj_double = ObjCDecl("double", 8, 8)
+    obj_ldouble = ObjCDecl("ldouble", 16, 16)
+
+    def __init__(self):
+        self.types = {
+            CTypeId(PADDING_TYPE_NAME): self.obj_pad,
+
+            CTypeId('char'): self.obj_char,
+            CTypeId('short'): self.obj_short,
+            CTypeId('int'): self.obj_int,
+            CTypeId('void'): self.obj_void,
+            CTypeId('long',): self.obj_long,
+            CTypeId('float'): self.obj_float,
+            CTypeId('double'): self.obj_double,
+
+            CTypeId('signed', 'char'): self.obj_char,
+            CTypeId('unsigned', 'char'): self.obj_uchar,
+
+            CTypeId('short', 'int'): self.obj_short,
+            CTypeId('signed', 'short'): self.obj_short,
+            CTypeId('signed', 'short', 'int'): self.obj_short,
+            CTypeId('unsigned', 'short'): self.obj_ushort,
+            CTypeId('unsigned', 'short', 'int'): self.obj_ushort,
+
+            CTypeId('unsigned', ): self.obj_uint,
+            CTypeId('unsigned', 'int'): self.obj_uint,
+            CTypeId('signed', 'int'): self.obj_int,
+
+            CTypeId('long', 'int'): self.obj_long,
+            CTypeId('long', 'long'): self.obj_long,
+            CTypeId('long', 'long', 'int'): self.obj_long,
+            CTypeId('signed', 'long', 'long'): self.obj_long,
+            CTypeId('unsigned', 'long', 'long'): self.obj_ulong,
+            CTypeId('signed', 'long', 'long', 'int'): self.obj_long,
+            CTypeId('unsigned', 'long', 'long', 'int'): self.obj_ulong,
+
+            CTypeId('signed', 'long'): self.obj_long,
+            CTypeId('unsigned', 'long'): self.obj_ulong,
+            CTypeId('signed', 'long', 'int'): self.obj_long,
+            CTypeId('unsigned', 'long', 'int'): self.obj_ulong,
+
+            CTypeId('long', 'double'): self.obj_ldouble,
+            CTypePtr(CTypeId('void')): self.obj_ulong,
+        }
+
+
+
+
+
+class CTypeX86_unk(CLeafTypes):
+    """Define C types sizes/alignment for x86_32 architecture"""
+
+    obj_pad = ObjCDecl(PADDING_TYPE_NAME, 1, 1) # __padding__ is size 1/align 1
+
+    obj_char = ObjCDecl("char", 1, 1)
+    obj_short = ObjCDecl("short", 2, 2)
+    obj_int = ObjCDecl("int", 4, 4)
+    obj_long = ObjCDecl("long", 4, 4)
+
+    obj_uchar = ObjCDecl("uchar", 1, 1)
+    obj_ushort = ObjCDecl("ushort", 2, 2)
+    obj_uint = ObjCDecl("uint", 4, 4)
+    obj_ulong = ObjCDecl("ulong", 4, 4)
+
+    obj_void = ObjCDecl("void", 1, 1)
+
+    obj_enum = ObjCDecl("enum", 4, 4)
+
+    obj_float = ObjCDecl("float", 4, 4)
+    obj_double = ObjCDecl("double", 8, 8)
+    obj_ldouble = ObjCDecl("ldouble", 16, 16)
+
+    def __init__(self):
+        self.types = {
+            CTypeId(PADDING_TYPE_NAME): self.obj_pad,
+
+            CTypeId('char'): self.obj_char,
+            CTypeId('short'): self.obj_short,
+            CTypeId('int'): self.obj_int,
+            CTypeId('void'): self.obj_void,
+            CTypeId('long',): self.obj_long,
+            CTypeId('float'): self.obj_float,
+            CTypeId('double'): self.obj_double,
+
+            CTypeId('signed', 'char'): self.obj_char,
+            CTypeId('unsigned', 'char'): self.obj_uchar,
+
+            CTypeId('short', 'int'): self.obj_short,
+            CTypeId('signed', 'short'): self.obj_short,
+            CTypeId('signed', 'short', 'int'): self.obj_short,
+            CTypeId('unsigned', 'short'): self.obj_ushort,
+            CTypeId('unsigned', 'short', 'int'): self.obj_ushort,
+
+            CTypeId('unsigned', ): self.obj_uint,
+            CTypeId('unsigned', 'int'): self.obj_uint,
+            CTypeId('signed', 'int'): self.obj_int,
+
+            CTypeId('long', 'int'): self.obj_long,
+            CTypeId('long', 'long'): self.obj_long,
+            CTypeId('long', 'long', 'int'): self.obj_long,
+            CTypeId('signed', 'long', 'long'): self.obj_long,
+            CTypeId('unsigned', 'long', 'long'): self.obj_ulong,
+            CTypeId('signed', 'long', 'long', 'int'): self.obj_long,
+            CTypeId('unsigned', 'long', 'long', 'int'): self.obj_ulong,
+
+            CTypeId('signed', 'long'): self.obj_long,
+            CTypeId('unsigned', 'long'): self.obj_ulong,
+            CTypeId('signed', 'long', 'int'): self.obj_long,
+            CTypeId('unsigned', 'long', 'int'): self.obj_ulong,
+
+            CTypeId('long', 'double'): self.obj_ldouble,
+            CTypePtr(CTypeId('void')): self.obj_uint,
+        }
diff --git a/src/miasm/arch/x86/disasm.py b/src/miasm/arch/x86/disasm.py
new file mode 100644
index 00000000..49b7158a
--- /dev/null
+++ b/src/miasm/arch/x86/disasm.py
@@ -0,0 +1,30 @@
+from miasm.core.asmblock import disasmEngine
+from miasm.arch.x86.arch import mn_x86
+
+
+cb_x86_funcs = []
+
+
+def cb_x86_disasm(mdis, cur_block, offset_to_dis):
+    for func in cb_x86_funcs:
+        func(mdis, cur_block, offset_to_dis)
+
+
+class dis_x86(disasmEngine):
+    attrib = None
+
+    def __init__(self, bs=None, **kwargs):
+        super(dis_x86, self).__init__(mn_x86, self.attrib, bs, **kwargs)
+        self.dis_block_callback = cb_x86_disasm
+
+
+class dis_x86_16(dis_x86):
+    attrib = 16
+
+
+class dis_x86_32(dis_x86):
+    attrib = 32
+
+
+class dis_x86_64(dis_x86):
+    attrib = 64
diff --git a/src/miasm/arch/x86/jit.py b/src/miasm/arch/x86/jit.py
new file mode 100644
index 00000000..a90dec07
--- /dev/null
+++ b/src/miasm/arch/x86/jit.py
@@ -0,0 +1,296 @@
+from builtins import range
+import logging
+
+from miasm.jitter.jitload import Jitter, named_arguments
+from miasm.arch.x86.sem import Lifter_X86_16, Lifter_X86_32, Lifter_X86_64
+from miasm.jitter.codegen import CGen
+from miasm.ir.translators.C import TranslatorC
+
+log = logging.getLogger('jit_x86')
+hnd = logging.StreamHandler()
+hnd.setFormatter(logging.Formatter("[%(levelname)-8s]: %(message)s"))
+log.addHandler(hnd)
+log.setLevel(logging.CRITICAL)
+
+
+class x86_32_CGen(CGen):
+    def __init__(self, lifter):
+        self.lifter = lifter
+        self.PC = self.lifter.arch.regs.RIP
+        self.translator = TranslatorC(self.lifter.loc_db)
+        self.init_arch_C()
+
+    def gen_post_code(self, attrib, pc_value):
+        out = []
+        if attrib.log_regs:
+            # Update PC for dump_gpregs
+            out.append("%s = %s;" % (self.C_PC, pc_value))
+            out.append('dump_gpregs_32(jitcpu->cpu);')
+        return out
+
+class x86_64_CGen(x86_32_CGen):
+    def gen_post_code(self, attrib, pc_value):
+        out = []
+        if attrib.log_regs:
+            # Update PC for dump_gpregs
+            out.append("%s = %s;" % (self.C_PC, pc_value))
+            out.append('dump_gpregs_64(jitcpu->cpu);')
+        return out
+
+class jitter_x86_16(Jitter):
+
+    C_Gen = x86_32_CGen
+
+    def __init__(self, loc_db, *args, **kwargs):
+        Jitter.__init__(self, Lifter_X86_16(loc_db), *args, **kwargs)
+        self.vm.set_little_endian()
+        self.lifter.do_stk_segm = False
+        self.orig_irbloc_fix_regs_for_mode = self.lifter.irbloc_fix_regs_for_mode
+        self.lifter.irbloc_fix_regs_for_mode = self.lifterbloc_fix_regs_for_mode
+
+    def lifterbloc_fix_regs_for_mode(self, irblock, attrib=64):
+        return self.orig_irbloc_fix_regs_for_mode(irblock, 64)
+
+    def push_uint16_t(self, value):
+        self.cpu.SP -= self.lifter.sp.size // 8
+        self.vm.set_u16(self.cpu.SP, value)
+
+    def pop_uint16_t(self):
+        value = self.vm.get_u16(self.cpu.SP)
+        self.cpu.SP += self.lifter.sp.size // 8
+        return value
+
+    def get_stack_arg(self, index):
+        return self.vm.get_u16(self.cpu.SP + 4 * index)
+
+    def init_run(self, *args, **kwargs):
+        Jitter.init_run(self, *args, **kwargs)
+        self.cpu.IP = self.pc
+
+
+class jitter_x86_32(Jitter):
+
+    C_Gen = x86_32_CGen
+
+    def __init__(self, loc_db, *args, **kwargs):
+        Jitter.__init__(self, Lifter_X86_32(loc_db), *args, **kwargs)
+        self.vm.set_little_endian()
+        self.lifter.do_stk_segm = False
+
+        self.orig_irbloc_fix_regs_for_mode = self.lifter.irbloc_fix_regs_for_mode
+        self.lifter.irbloc_fix_regs_for_mode = self.lifterbloc_fix_regs_for_mode
+
+    def lifterbloc_fix_regs_for_mode(self, irblock, attrib=64):
+        return self.orig_irbloc_fix_regs_for_mode(irblock, 64)
+
+    def push_uint16_t(self, value):
+        self.cpu.ESP -= self.lifter.sp.size // 8
+        self.vm.set_u16(self.cpu.ESP, value)
+
+    def pop_uint16_t(self):
+        value = self.vm.get_u16(self.cpu.ESP)
+        self.cpu.ESP += self.lifter.sp.size // 8
+        return value
+
+    def push_uint32_t(self, value):
+        self.cpu.ESP -= self.lifter.sp.size // 8
+        self.vm.set_u32(self.cpu.ESP, value)
+
+    def pop_uint32_t(self):
+        value = self.vm.get_u32(self.cpu.ESP)
+        self.cpu.ESP += self.lifter.sp.size // 8
+        return value
+
+    def get_stack_arg(self, index):
+        return self.vm.get_u32(self.cpu.ESP + 4 * index)
+
+    def init_run(self, *args, **kwargs):
+        Jitter.init_run(self, *args, **kwargs)
+        self.cpu.EIP = self.pc
+
+    # calling conventions
+
+    # stdcall
+    @named_arguments
+    def func_args_stdcall(self, n_args):
+        ret_ad = self.pop_uint32_t()
+        args = [self.pop_uint32_t() for _ in range(n_args)]
+        return ret_ad, args
+
+    def func_ret_stdcall(self, ret_addr, ret_value1=None, ret_value2=None):
+        self.pc = self.cpu.EIP = ret_addr
+        if ret_value1 is not None:
+            self.cpu.EAX = ret_value1
+        if ret_value2 is not None:
+            self.cpu.EDX = ret_value2
+
+    def func_prepare_stdcall(self, ret_addr, *args):
+        for arg in reversed(args):
+            self.push_uint32_t(arg)
+        self.push_uint32_t(ret_addr)
+
+    get_arg_n_stdcall = get_stack_arg
+
+    # cdecl
+    @named_arguments
+    def func_args_cdecl(self, n_args):
+        ret_ad = self.pop_uint32_t()
+        args = [self.get_stack_arg(i) for i in range(n_args)]
+        return ret_ad, args
+
+    def func_ret_cdecl(self, ret_addr, ret_value1=None, ret_value2=None):
+        self.pc = self.cpu.EIP = ret_addr
+        if ret_value1 is not None:
+            self.cpu.EAX = ret_value1
+        if ret_value2 is not None:
+            self.cpu.EDX = ret_value2
+
+    get_arg_n_cdecl = get_stack_arg
+
+    # System V
+    func_args_systemv = func_args_cdecl
+    func_ret_systemv = func_ret_cdecl
+    func_prepare_systemv = func_prepare_stdcall
+    get_arg_n_systemv = get_stack_arg
+
+
+    # fastcall
+    @named_arguments
+    def func_args_fastcall(self, n_args):
+        args_regs = ['ECX', 'EDX']
+        ret_ad = self.pop_uint32_t()
+        args = []
+        for i in range(n_args):
+            args.append(self.get_arg_n_fastcall(i))
+        return ret_ad, args
+
+    def func_prepare_fastcall(self, ret_addr, *args):
+        args_regs = ['ECX', 'EDX']
+        for i in range(min(len(args), len(args_regs))):
+            setattr(self.cpu, args_regs[i], args[i])
+        remaining_args = args[len(args_regs):]
+        for arg in reversed(remaining_args):
+            self.push_uint32_t(arg)
+        self.push_uint32_t(ret_addr)
+
+    def get_arg_n_fastcall(self, index):
+        args_regs = ['ECX', 'EDX']
+        if index < len(args_regs):
+            return getattr(self.cpu, args_regs[index])
+        return self.get_stack_arg(index - len(args_regs))
+
+    def syscall_args_systemv(self, n_args):
+        # Documentation: http://man7.org/linux/man-pages/man2/syscall.2.html
+        # args: 
+        #   i386          ebx   ecx   edx   esi   edi   ebp   -
+        args = [self.cpu.EBX, self.cpu.ECX, self.cpu.EDX, self.cpu.ESI,
+                self.cpu.EDI, self.cpu.EBP][:n_args]
+        return args
+
+    def syscall_ret_systemv(self, value):
+        # Documentation: http://man7.org/linux/man-pages/man2/syscall.2.html
+        self.cpu.EAX = value
+
+
+class jitter_x86_64(Jitter):
+
+    C_Gen = x86_64_CGen
+    args_regs_systemv = ['RDI', 'RSI', 'RDX', 'RCX', 'R8', 'R9']
+    args_regs_stdcall = ['RCX', 'RDX', 'R8', 'R9']
+
+    def __init__(self, loc_db, *args, **kwargs):
+        Jitter.__init__(self, Lifter_X86_64(loc_db), *args, **kwargs)
+        self.vm.set_little_endian()
+        self.lifter.do_stk_segm = False
+
+        self.orig_irbloc_fix_regs_for_mode = self.lifter.irbloc_fix_regs_for_mode
+        self.lifter.irbloc_fix_regs_for_mode = self.lifterbloc_fix_regs_for_mode
+
+    def lifterbloc_fix_regs_for_mode(self, irblock, attrib=64):
+        return self.orig_irbloc_fix_regs_for_mode(irblock, 64)
+
+    def push_uint64_t(self, value):
+        self.cpu.RSP -= self.lifter.sp.size // 8
+        self.vm.set_u64(self.cpu.RSP, value)
+
+    def pop_uint64_t(self):
+        value = self.vm.get_u64(self.cpu.RSP)
+        self.cpu.RSP += self.lifter.sp.size // 8
+        return value
+
+    def get_stack_arg(self, index):
+        return self.vm.get_u64(self.cpu.RSP + 8 * index)
+
+    def init_run(self, *args, **kwargs):
+        Jitter.init_run(self, *args, **kwargs)
+        self.cpu.RIP = self.pc
+
+    # calling conventions
+
+    # stdcall
+    @named_arguments
+    def func_args_stdcall(self, n_args):
+        args_regs = self.args_regs_stdcall
+        ret_ad = self.pop_uint64_t()
+        args = []
+        for i in range(min(n_args, 4)):
+            args.append(self.cpu.get_gpreg()[args_regs[i]])
+        for i in range(max(0, n_args - 4)):
+            # Take into account the shadow registers on the stack 
+            # (Microsoft 64bit stdcall ABI)
+            # => Skip the first 4 stack parameters
+            args.append(self.get_stack_arg(4 + i))
+        return ret_ad, args
+
+    def func_prepare_stdcall(self, ret_addr, *args):
+        args_regs = self.args_regs_stdcall
+        for i in range(min(len(args), len(args_regs))):
+            setattr(self.cpu, args_regs[i], args[i])
+        remaining_args = args[len(args_regs):]
+        for arg in reversed(remaining_args):
+            self.push_uint64_t(arg)
+        self.push_uint64_t(ret_addr)
+
+    def func_ret_stdcall(self, ret_addr, ret_value=None):
+        self.pc = self.cpu.RIP = ret_addr
+        if ret_value is not None:
+            self.cpu.RAX = ret_value
+        return True
+
+    # cdecl
+    func_args_cdecl = func_args_stdcall
+    func_ret_cdecl = func_ret_stdcall
+    func_prepare_cdecl = func_prepare_stdcall
+
+    # System V
+
+    def get_arg_n_systemv(self, index):
+        args_regs = self.args_regs_systemv
+        if index < len(args_regs):
+            return getattr(self.cpu, args_regs[index])
+        return self.get_stack_arg(index - len(args_regs))
+
+    @named_arguments
+    def func_args_systemv(self, n_args):
+        ret_ad = self.pop_uint64_t()
+        args = [self.get_arg_n_systemv(index) for index in range(n_args)]
+        return ret_ad, args
+
+    func_ret_systemv = func_ret_cdecl
+
+    def func_prepare_systemv(self, ret_addr, *args):
+        args_regs = self.args_regs_systemv
+        self.push_uint64_t(ret_addr)
+        for i in range(min(len(args), len(args_regs))):
+            setattr(self.cpu, args_regs[i], args[i])
+        remaining_args = args[len(args_regs):]
+        for arg in reversed(remaining_args):
+            self.push_uint64_t(arg)
+
+    def syscall_args_systemv(self, n_args):
+        args = [self.cpu.RDI, self.cpu.RSI, self.cpu.RDX, self.cpu.R10,
+                self.cpu.R8, self.cpu.R9][:n_args]
+        return args
+
+    def syscall_ret_systemv(self, value):
+        self.cpu.RAX = value
diff --git a/src/miasm/arch/x86/lifter_model_call.py b/src/miasm/arch/x86/lifter_model_call.py
new file mode 100644
index 00000000..e75f8c69
--- /dev/null
+++ b/src/miasm/arch/x86/lifter_model_call.py
@@ -0,0 +1,80 @@
+#-*- coding:utf-8 -*-
+
+from miasm.expression.expression import ExprAssign, ExprOp
+from miasm.ir.ir import AssignBlock
+from miasm.ir.analysis import LifterModelCall
+from miasm.arch.x86.sem import Lifter_X86_16, Lifter_X86_32, Lifter_X86_64
+
+
+class LifterModelCall_x86_16(Lifter_X86_16, LifterModelCall):
+
+    def __init__(self, loc_db):
+        Lifter_X86_16.__init__(self, loc_db)
+        self.ret_reg = self.arch.regs.AX
+
+    def get_out_regs(self, _):
+        return set([self.ret_reg, self.sp])
+
+class LifterModelCall_x86_32(Lifter_X86_32, LifterModelCall_x86_16):
+
+    def __init__(self, loc_db):
+        Lifter_X86_32.__init__(self, loc_db)
+        self.ret_reg = self.arch.regs.EAX
+
+    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 LifterModelCall_x86_64(Lifter_X86_64, LifterModelCall_x86_16):
+
+    def __init__(self, loc_db):
+        Lifter_X86_64.__init__(self, loc_db)
+        self.ret_reg = self.arch.regs.RAX
+
+    def call_effects(self, ad, instr):
+        call_assignblk = AssignBlock(
+            [
+                ExprAssign(
+                    self.ret_reg,
+                    ExprOp(
+                        'call_func_ret',
+                        ad,
+                        self.sp,
+                        self.arch.regs.RCX,
+                        self.arch.regs.RDX,
+                        self.arch.regs.R8,
+                        self.arch.regs.R9,
+                    )
+                ),
+                ExprAssign(self.sp, ExprOp('call_func_stack', ad, self.sp)),
+            ],
+            instr
+        )
+        return [call_assignblk], []
+
+    def sizeof_char(self):
+        return 8
+
+    def sizeof_short(self):
+        return 16
+
+    def sizeof_int(self):
+        return 32
+
+    def sizeof_long(self):
+        return 64
+
+    def sizeof_pointer(self):
+        return 64
diff --git a/src/miasm/arch/x86/regs.py b/src/miasm/arch/x86/regs.py
new file mode 100644
index 00000000..dc0b9264
--- /dev/null
+++ b/src/miasm/arch/x86/regs.py
@@ -0,0 +1,454 @@
+from builtins import range
+from miasm.expression.expression import ExprId
+from miasm.core.cpu import reg_info
+
+
+IP = ExprId('IP', 16)
+EIP = ExprId('EIP', 32)
+RIP = ExprId('RIP', 64)
+exception_flags = ExprId('exception_flags', 32)
+interrupt_num = ExprId('interrupt_num', 8)
+
+# GP
+
+
+regs08_str = ["AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH"] + \
+    ["R%dB" % (i + 8) for i in range(8)]
+regs08_expr = [ExprId(x, 8) for x in regs08_str]
+
+regs08_64_str = ["AL", "CL", "DL", "BL", "SPL", "BPL", "SIL", "DIL"] + \
+    ["R%dB" % (i + 8) for i in range(8)]
+regs08_64_expr = [ExprId(x, 8) for x in regs08_64_str]
+
+
+regs16_str = ["AX", "CX", "DX", "BX", "SP", "BP", "SI", "DI"] + \
+    ["R%dW" % (i + 8) for i in range(8)]
+regs16_expr = [ExprId(x, 16) for x in regs16_str]
+
+regs32_str = ["EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI"] + \
+    ["R%dD" % (i + 8) for i in range(8)] + ["EIP"]
+regs32_expr = [ExprId(x, 32) for x in regs32_str]
+
+regs64_str = ["RAX", "RCX", "RDX", "RBX", "RSP", "RBP", "RSI", "RDI",
+              "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15",
+              "RIP"]
+regs64_expr = [ExprId(x, 64) for x in regs64_str]
+
+
+regs_xmm_str = ["XMM%d" % i for i in range(16)]
+regs_xmm_expr = [ExprId(x, 128) for x in regs_xmm_str]
+
+regs_mm_str = ["MM%d" % i for i in range(16)]
+regs_mm_expr = [ExprId(x, 64) for x in regs_mm_str]
+
+regs_bnd_str = ["BND%d" % i for i in range(4)]
+regs_bnd_expr = [ExprId(x, 128) for x in regs_bnd_str]
+
+gpregs08 = reg_info(regs08_str, regs08_expr)
+gpregs08_64 = reg_info(regs08_64_str, regs08_64_expr)
+gpregs16 = reg_info(regs16_str, regs16_expr)
+gpregs32 = reg_info(regs32_str, regs32_expr)
+gpregs64 = reg_info(regs64_str, regs64_expr)
+
+gpregs_xmm = reg_info(regs_xmm_str, regs_xmm_expr)
+gpregs_mm = reg_info(regs_mm_str, regs_mm_expr)
+gpregs_bnd = reg_info(regs_bnd_str, regs_bnd_expr)
+
+r08_eax = reg_info([regs08_str[0]], [regs08_expr[0]])
+r16_eax = reg_info([regs16_str[0]], [regs16_expr[0]])
+r32_eax = reg_info([regs32_str[0]], [regs32_expr[0]])
+r64_eax = reg_info([regs64_str[0]], [regs64_expr[0]])
+
+r08_ecx = reg_info([regs08_str[1]], [regs08_expr[1]])
+
+r_eax_all = reg_info(
+    [regs08_str[0], regs16_str[0], regs32_str[0], regs64_str[0]],
+    [regs08_expr[0], regs16_expr[0], regs32_expr[0], regs64_expr[0]])
+r_edx_all = reg_info(
+    [regs08_str[2], regs16_str[2], regs32_str[2], regs64_str[2]],
+    [regs08_expr[2], regs16_expr[2], regs32_expr[2], regs64_expr[2]])
+
+r16_edx = reg_info([regs16_str[2]], [regs16_expr[2]])
+
+
+selectr_str = ["ES", "CS", "SS", "DS", "FS", "GS"]
+selectr_expr = [ExprId(x, 16) for x in selectr_str]
+segmreg = reg_info(selectr_str, selectr_expr)
+
+crregs32_str = ["CR%d" % i for i in range(8)]
+crregs32_expr = [ExprId(x, 32) for x in crregs32_str]
+crregs = reg_info(crregs32_str, crregs32_expr)
+
+
+drregs32_str = ["DR%d" % i for i in range(8)]
+drregs32_expr = [ExprId(x, 32) for x in drregs32_str]
+drregs = reg_info(drregs32_str, drregs32_expr)
+
+
+fltregs32_str = ["ST(%d)" % i for i in range(8)]
+fltregs32_expr = [ExprId(x, 64) for x in fltregs32_str]
+fltregs = reg_info(fltregs32_str, fltregs32_expr)
+
+r_st_all = reg_info(['ST'],
+                    [ExprId('ST', 64)])
+
+r_cs_all = reg_info(['CS'],
+                    [ExprId('CS', 16)])
+r_ds_all = reg_info(['DS'],
+                    [ExprId('DS', 16)])
+r_es_all = reg_info(['ES'],
+                    [ExprId('ES', 16)])
+r_ss_all = reg_info(['SS'],
+                    [ExprId('SS', 16)])
+r_fs_all = reg_info(['FS'],
+                    [ExprId('FS', 16)])
+r_gs_all = reg_info(['GS'],
+                    [ExprId('GS', 16)])
+
+
+AL = regs08_expr[0]
+CL = regs08_expr[1]
+DL = regs08_expr[2]
+BL = regs08_expr[3]
+AH = regs08_expr[4]
+CH = regs08_expr[5]
+DH = regs08_expr[6]
+BH = regs08_expr[7]
+R8B = regs08_expr[8]
+R9B = regs08_expr[9]
+R10B = regs08_expr[10]
+R11B = regs08_expr[11]
+R12B = regs08_expr[12]
+R13B = regs08_expr[13]
+R14B = regs08_expr[14]
+R15B = regs08_expr[15]
+
+SPL = regs08_64_expr[4]
+BPL = regs08_64_expr[5]
+SIL = regs08_64_expr[6]
+DIL = regs08_64_expr[7]
+
+
+AX = regs16_expr[0]
+CX = regs16_expr[1]
+DX = regs16_expr[2]
+BX = regs16_expr[3]
+SP = regs16_expr[4]
+BP = regs16_expr[5]
+SI = regs16_expr[6]
+DI = regs16_expr[7]
+R8W = regs16_expr[8]
+R9W = regs16_expr[9]
+R10W = regs16_expr[10]
+R11W = regs16_expr[11]
+R12W = regs16_expr[12]
+R13W = regs16_expr[13]
+R14W = regs16_expr[14]
+R15W = regs16_expr[15]
+
+
+EAX = regs32_expr[0]
+ECX = regs32_expr[1]
+EDX = regs32_expr[2]
+EBX = regs32_expr[3]
+ESP = regs32_expr[4]
+EBP = regs32_expr[5]
+ESI = regs32_expr[6]
+EDI = regs32_expr[7]
+R8D = regs32_expr[8]
+R9D = regs32_expr[9]
+R10D = regs32_expr[10]
+R11D = regs32_expr[11]
+R12D = regs32_expr[12]
+R13D = regs32_expr[13]
+R14D = regs32_expr[14]
+R15D = regs32_expr[15]
+
+
+RAX = regs64_expr[0]
+RCX = regs64_expr[1]
+RDX = regs64_expr[2]
+RBX = regs64_expr[3]
+RSP = regs64_expr[4]
+RBP = regs64_expr[5]
+RSI = regs64_expr[6]
+RDI = regs64_expr[7]
+R8 = regs64_expr[8]
+R9 = regs64_expr[9]
+R10 = regs64_expr[10]
+R11 = regs64_expr[11]
+R12 = regs64_expr[12]
+R13 = regs64_expr[13]
+R14 = regs64_expr[14]
+R15 = regs64_expr[15]
+
+
+reg_zf = 'zf'
+reg_nf = 'nf'
+reg_pf = 'pf'
+reg_of = 'of'
+reg_cf = 'cf'
+reg_tf = 'tf'
+reg_if = 'i_f'
+reg_df = 'df'
+reg_af = 'af'
+reg_iopl = 'iopl_f'
+reg_nt = 'nt'
+reg_rf = 'rf'
+reg_vm = 'vm'
+reg_ac = 'ac'
+reg_vif = 'vif'
+reg_vip = 'vip'
+reg_id = 'i_d'
+
+
+reg_es = "ES"
+reg_cs = "CS"
+reg_ss = "SS"
+reg_ds = "DS"
+reg_fs = "FS"
+reg_gs = "GS"
+
+reg_dr0 = 'DR0'
+reg_dr1 = 'DR1'
+reg_dr2 = 'DR2'
+reg_dr3 = 'DR3'
+reg_dr4 = 'DR4'
+reg_dr5 = 'DR5'
+reg_dr6 = 'DR6'
+reg_dr7 = 'DR7'
+
+reg_cr0 = 'CR0'
+reg_cr1 = 'CR1'
+reg_cr2 = 'CR2'
+reg_cr3 = 'CR3'
+reg_cr4 = 'CR4'
+reg_cr5 = 'CR5'
+reg_cr6 = 'CR6'
+reg_cr7 = 'CR7'
+
+reg_mm0 = 'MM0'
+reg_mm1 = 'MM1'
+reg_mm2 = 'MM2'
+reg_mm3 = 'MM3'
+reg_mm4 = 'MM4'
+reg_mm5 = 'MM5'
+reg_mm6 = 'MM6'
+reg_mm7 = 'MM7'
+
+reg_tsc = "tsc"
+
+reg_float_c0 = 'float_c0'
+reg_float_c1 = 'float_c1'
+reg_float_c2 = 'float_c2'
+reg_float_c3 = 'float_c3'
+reg_float_stack_ptr = "float_stack_ptr"
+reg_float_control = 'reg_float_control'
+reg_float_eip = 'reg_float_eip'
+reg_float_cs = 'reg_float_cs'
+reg_float_address = 'reg_float_address'
+reg_float_ds = 'reg_float_ds'
+
+
+dr0 = ExprId(reg_dr0, 32)
+dr1 = ExprId(reg_dr1, 32)
+dr2 = ExprId(reg_dr2, 32)
+dr3 = ExprId(reg_dr3, 32)
+dr4 = ExprId(reg_dr4, 32)
+dr5 = ExprId(reg_dr5, 32)
+dr6 = ExprId(reg_dr6, 32)
+dr7 = ExprId(reg_dr7, 32)
+
+cr0 = ExprId(reg_cr0, 32)
+cr1 = ExprId(reg_cr1, 32)
+cr2 = ExprId(reg_cr2, 32)
+cr3 = ExprId(reg_cr3, 32)
+cr4 = ExprId(reg_cr4, 32)
+cr5 = ExprId(reg_cr5, 32)
+cr6 = ExprId(reg_cr6, 32)
+cr7 = ExprId(reg_cr7, 32)
+
+mm0 = ExprId(reg_mm0, 64)
+mm1 = ExprId(reg_mm1, 64)
+mm2 = ExprId(reg_mm2, 64)
+mm3 = ExprId(reg_mm3, 64)
+mm4 = ExprId(reg_mm4, 64)
+mm5 = ExprId(reg_mm5, 64)
+mm6 = ExprId(reg_mm6, 64)
+mm7 = ExprId(reg_mm7, 64)
+
+XMM0 = regs_xmm_expr[0]
+XMM1 = regs_xmm_expr[1]
+XMM2 = regs_xmm_expr[2]
+XMM3 = regs_xmm_expr[3]
+XMM4 = regs_xmm_expr[4]
+XMM5 = regs_xmm_expr[5]
+XMM6 = regs_xmm_expr[6]
+XMM7 = regs_xmm_expr[7]
+XMM8 = regs_xmm_expr[8]
+XMM9 = regs_xmm_expr[9]
+XMM10 = regs_xmm_expr[10]
+XMM11 = regs_xmm_expr[11]
+XMM12 = regs_xmm_expr[12]
+XMM13 = regs_xmm_expr[13]
+XMM14 = regs_xmm_expr[14]
+XMM15 = regs_xmm_expr[15]
+
+# tmp1= ExprId(reg_tmp1)
+zf = ExprId(reg_zf, size=1)
+nf = ExprId(reg_nf, size=1)
+pf = ExprId(reg_pf, size=1)
+of = ExprId(reg_of, size=1)
+cf = ExprId(reg_cf, size=1)
+tf = ExprId(reg_tf, size=1)
+i_f = ExprId(reg_if, size=1)
+df = ExprId(reg_df, size=1)
+af = ExprId(reg_af, size=1)
+iopl = ExprId(reg_iopl, size=2)
+nt = ExprId(reg_nt, size=1)
+rf = ExprId(reg_rf, size=1)
+vm = ExprId(reg_vm, size=1)
+ac = ExprId(reg_ac, size=1)
+vif = ExprId(reg_vif, size=1)
+vip = ExprId(reg_vip, size=1)
+i_d = ExprId(reg_id, size=1)
+
+ES = ExprId(reg_es, size=16)
+CS = ExprId(reg_cs, size=16)
+SS = ExprId(reg_ss, size=16)
+DS = ExprId(reg_ds, size=16)
+FS = ExprId(reg_fs, size=16)
+GS = ExprId(reg_gs, size=16)
+
+tsc = ExprId(reg_tsc, size=64)
+
+float_c0 = ExprId(reg_float_c0, size=1)
+float_c1 = ExprId(reg_float_c1, size=1)
+float_c2 = ExprId(reg_float_c2, size=1)
+float_c3 = ExprId(reg_float_c3, size=1)
+float_stack_ptr = ExprId(reg_float_stack_ptr, size=3)
+float_control = ExprId(reg_float_control, 16)
+float_eip = ExprId(reg_float_eip, 32)
+float_cs = ExprId(reg_float_cs, size=16)
+float_address = ExprId(reg_float_address, 32)
+float_ds = ExprId(reg_float_ds, size=16)
+
+float_st0 = ExprId("float_st0", 64)
+float_st1 = ExprId("float_st1", 64)
+float_st2 = ExprId("float_st2", 64)
+float_st3 = ExprId("float_st3", 64)
+float_st4 = ExprId("float_st4", 64)
+float_st5 = ExprId("float_st5", 64)
+float_st6 = ExprId("float_st6", 64)
+float_st7 = ExprId("float_st7", 64)
+
+
+float_list = [float_st0, float_st1, float_st2, float_st3,
+              float_st4, float_st5, float_st6, float_st7]
+
+float_replace = {fltregs32_expr[i]: float_list[i] for i in range(8)}
+float_replace[r_st_all.expr[0]] = float_st0
+
+
+EAX_init = ExprId('EAX_init', 32)
+EBX_init = ExprId('EBX_init', 32)
+ECX_init = ExprId('ECX_init', 32)
+EDX_init = ExprId('EDX_init', 32)
+ESI_init = ExprId('ESI_init', 32)
+EDI_init = ExprId('EDI_init', 32)
+ESP_init = ExprId('ESP_init', 32)
+EBP_init = ExprId('EBP_init', 32)
+
+
+RAX_init = ExprId('RAX_init', 64)
+RBX_init = ExprId('RBX_init', 64)
+RCX_init = ExprId('RCX_init', 64)
+RDX_init = ExprId('RDX_init', 64)
+RSI_init = ExprId('RSI_init', 64)
+RDI_init = ExprId('RDI_init', 64)
+RSP_init = ExprId('RSP_init', 64)
+RBP_init = ExprId('RBP_init', 64)
+
+
+all_regs_ids = [
+    AL, CL, DL, BL, AH, CH, DH, BH,
+    R8B, R9B, R10B, R11B, R12B, R13B, R14B, R15B,
+    SPL, BPL, SIL, DIL,
+    AX, CX, DX, BX, SP, BP, SI, DI,
+    R8W, R9W, R10W, R11W, R12W, R13W, R14W, R15W,
+    IP,
+    EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI,
+    R8D, R9D, R10D, R11D, R12D, R13D, R14D, R15D,
+    EIP,
+
+    RAX, RBX, RCX, RDX, RSP, RBP, RIP, RSI, RDI,
+    R8, R9, R10, R11, R12, R13, R14, R15,
+    zf, nf, pf, of, cf, af, df,
+    tf, i_f, iopl, nt, rf, vm, ac, vif, vip, i_d,
+    float_control, float_eip, float_cs, float_address, float_ds,
+    tsc,
+    ES, CS, SS, DS, FS, GS,
+    float_st0, float_st1, float_st2, float_st3,
+    float_st4, float_st5, float_st6, float_st7,
+    float_c0, float_c1, float_c2, float_c3,
+    cr0, cr3,
+    dr0, dr1, dr2, dr3, dr4, dr5, dr6, dr7,
+    float_stack_ptr,
+    mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
+
+    XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7,
+    XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, XMM15,
+
+
+    exception_flags, interrupt_num,
+] + fltregs32_expr
+
+all_regs_ids_no_alias = [
+    RAX, RBX, RCX, RDX, RSP, RBP, RIP, RSI, RDI,
+    R8, R9, R10, R11, R12, R13, R14, R15,
+    zf, nf, pf, of, cf, af, df,
+    tf, i_f, iopl, nt, rf, vm, ac, vif, vip, i_d,
+    float_control, float_eip, float_cs, float_address, float_ds,
+    tsc,
+    ES, CS, SS, DS, FS, GS,
+    float_st0, float_st1, float_st2, float_st3,
+    float_st4, float_st5, float_st6, float_st7,
+    float_c0, float_c1, float_c2, float_c3,
+    cr0, cr3,
+    dr0, dr1, dr2, dr3, dr4, dr5, dr6, dr7,
+    float_stack_ptr,
+    mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
+    XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7,
+    XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, XMM15,
+
+
+    exception_flags, interrupt_num,
+] + fltregs32_expr
+
+attrib_to_regs = {
+    16: regs16_expr + all_regs_ids_no_alias[all_regs_ids_no_alias.index(zf):] + [IP],
+    32: regs32_expr + all_regs_ids_no_alias[all_regs_ids_no_alias.index(zf):] + [EIP],
+    64: all_regs_ids_no_alias,
+}
+
+all_regs_ids_byname = dict([(x.name, x) for x in all_regs_ids])
+
+all_regs_ids_init = [ExprId("%s_init" % x.name, x.size) for x in all_regs_ids]
+
+regs_init = {}
+for i, r in enumerate(all_regs_ids):
+    regs_init[r] = all_regs_ids_init[i]
+
+regs_flt_expr = [float_st0, float_st1, float_st2, float_st3,
+                 float_st4, float_st5, float_st6, float_st7,
+                 ]
+
+mRAX = {16: AX, 32: EAX, 64: RAX}
+mRBX = {16: BX, 32: EBX, 64: RBX}
+mRCX = {16: CX, 32: ECX, 64: RCX}
+mRDX = {16: DX, 32: EDX, 64: RDX}
+mRSI = {16: SI, 32: ESI, 64: RSI}
+mRDI = {16: DI, 32: EDI, 64: RDI}
+mRBP = {16: BP, 32: EBP, 64: RBP}
+mRSP = {16: SP, 32: ESP, 64: RSP}
+mRIP = {16: IP, 32: EIP, 64: RIP}
diff --git a/src/miasm/arch/x86/sem.py b/src/miasm/arch/x86/sem.py
new file mode 100644
index 00000000..d19290b6
--- /dev/null
+++ b/src/miasm/arch/x86/sem.py
@@ -0,0 +1,6065 @@
+#
+# Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+
+from builtins import range
+
+from future.utils import viewitems
+
+import logging
+import miasm.expression.expression as m2_expr
+from miasm.expression.simplifications import expr_simp
+from miasm.arch.x86.regs import *
+from miasm.arch.x86.arch import mn_x86, repeat_mn, replace_regs, is_mem_segm
+from miasm.ir.ir import Lifter, IRBlock, AssignBlock
+from miasm.core.sembuilder import SemBuilder
+from miasm.jitter.csts import EXCEPT_DIV_BY_ZERO, EXCEPT_ILLEGAL_INSN, \
+    EXCEPT_PRIV_INSN, EXCEPT_SOFT_BP, EXCEPT_INT_XX, EXCEPT_INT_1, \
+    EXCEPT_SYSCALL
+import math
+import struct
+
+
+LOG_X86_SEM = logging.getLogger("x86_sem")
+CONSOLE_HANDLER = logging.StreamHandler()
+CONSOLE_HANDLER.setFormatter(logging.Formatter("[%(levelname)-8s]: %(message)s"))
+LOG_X86_SEM.addHandler(CONSOLE_HANDLER)
+LOG_X86_SEM.setLevel(logging.WARNING)
+
+
+# SemBuilder context
+ctx = {'mRAX': mRAX,
+       'mRBX': mRBX,
+       'mRCX': mRCX,
+       'mRDX': mRDX,
+       'zf': zf,
+       }
+sbuild = SemBuilder(ctx)
+
+
+
+"""
+http://www.emulators.com/docs/nx11_flags.htm
+
+CF(A+B) = (((A XOR B) XOR D) < 0) XOR (((A XOR D) AND NOT (A XOR B)) < 0)
+CF(A-B) = (((A XOR B) XOR D) < 0) XOR (((A XOR D) AND (A XOR B)) < 0)
+
+OF(A+B) = ((A XOR D) AND NOT (A XOR B)) < 0
+OF(A-B) = ((A XOR D) AND (A XOR B)) < 0
+"""
+
+
+# XXX TODO make default check against 0 or not 0 (same eq as in C)
+def update_flag_zf_eq(a, b):
+    return [m2_expr.ExprAssign(zf, m2_expr.ExprOp("FLAG_EQ_CMP", a, b))]
+
+
+def update_flag_zf(a):
+    return [
+        m2_expr.ExprAssign(
+            zf,
+            m2_expr.ExprCond(
+                a,
+                m2_expr.ExprInt(0, zf.size),
+                m2_expr.ExprInt(1, zf.size)
+            )
+        )
+    ]
+
+
+def update_flag_nf(arg):
+    return [
+        m2_expr.ExprAssign(
+            nf,
+            m2_expr.ExprOp("FLAG_SIGN_SUB", arg, m2_expr.ExprInt(0, arg.size))
+        )
+    ]
+
+
+def update_flag_pf(a):
+    return [m2_expr.ExprAssign(pf,
+                            m2_expr.ExprOp('parity',
+                                           a & m2_expr.ExprInt(0xFF, a.size)))]
+
+
+def update_flag_af(op1, op2, res):
+    return [m2_expr.ExprAssign(af, (op1 ^ op2 ^ res)[4:5])]
+
+
+def update_flag_znp(a):
+    e = []
+    e += update_flag_zf(a)
+    e += update_flag_nf(a)
+    e += update_flag_pf(a)
+    return e
+
+
+def update_flag_np(result):
+    e = []
+    e += update_flag_nf(result)
+    e += update_flag_pf(result)
+    return e
+
+
+def null_flag_co():
+    e = []
+    e.append(m2_expr.ExprAssign(of, m2_expr.ExprInt(0, of.size)))
+    e.append(m2_expr.ExprAssign(cf, m2_expr.ExprInt(0, cf.size)))
+    return e
+
+
+def update_flag_arith(a):
+    e = []
+    e += update_flag_znp(a)
+    return e
+
+
+def update_flag_zfaddwc_eq(arg1, arg2, arg3):
+    return [m2_expr.ExprAssign(zf, m2_expr.ExprOp("FLAG_EQ_ADDWC", arg1, arg2, arg3))]
+
+def update_flag_zfsubwc_eq(arg1, arg2, arg3):
+    return [m2_expr.ExprAssign(zf, m2_expr.ExprOp("FLAG_EQ_SUBWC", arg1, arg2, arg3))]
+
+
+def update_flag_arith_add_znp(arg1, arg2):
+    """
+    Compute znp flags for (arg1 + arg2)
+    """
+    e = []
+    e += update_flag_zf_eq(arg1, -arg2)
+    e += [m2_expr.ExprAssign(nf, m2_expr.ExprOp("FLAG_SIGN_SUB", arg1, -arg2))]
+    e += update_flag_pf(arg1+arg2)
+    return e
+
+
+def update_flag_arith_addwc_znp(arg1, arg2, arg3):
+    """
+    Compute znp flags for (arg1 + arg2 + cf)
+    """
+    e = []
+    e += update_flag_zfaddwc_eq(arg1, arg2, arg3)
+    e += [m2_expr.ExprAssign(nf, m2_expr.ExprOp("FLAG_SIGN_ADDWC", arg1, arg2, arg3))]
+    e += update_flag_pf(arg1+arg2+arg3.zeroExtend(arg2.size))
+    return e
+
+
+
+
+def update_flag_arith_sub_znp(arg1, arg2):
+    """
+    Compute znp flags for (arg1 - arg2)
+    """
+    e = []
+    e += update_flag_zf_eq(arg1, arg2)
+    e += [m2_expr.ExprAssign(nf, m2_expr.ExprOp("FLAG_SIGN_SUB", arg1, arg2))]
+    e += update_flag_pf(arg1 - arg2)
+    return e
+
+
+def update_flag_arith_subwc_znp(arg1, arg2, arg3):
+    """
+    Compute znp flags for (arg1 - (arg2 + cf))
+    """
+    e = []
+    e += update_flag_zfsubwc_eq(arg1, arg2, arg3)
+    e += [m2_expr.ExprAssign(nf, m2_expr.ExprOp("FLAG_SIGN_SUBWC", arg1, arg2, arg3))]
+    e += update_flag_pf(arg1 - (arg2+arg3.zeroExtend(arg2.size)))
+    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.ExprAssign(cf, m2_expr.ExprOp("FLAG_SUB_CF", op1, -op2))]
+    return [m2_expr.ExprAssign(cf, m2_expr.ExprOp("FLAG_ADD_CF", op1, op2))]
+
+
+def update_flag_add_of(op1, op2, res):
+    "Compute of in @res = @op1 + @op2"
+    return [m2_expr.ExprAssign(of, m2_expr.ExprOp("FLAG_ADD_OF", op1, op2))]
+
+
+# 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.ExprAssign(cf, m2_expr.ExprOp("FLAG_SUB_CF", op1, op2))]
+
+
+def update_flag_sub_of(op1, op2, res):
+    "Compote OF in @res = @op1 - @op2"
+    return [m2_expr.ExprAssign(of, m2_expr.ExprOp("FLAG_SUB_OF", op1, op2))]
+
+
+def update_flag_addwc_cf(op1, op2, op3):
+    "Compute cf in @res = @op1 + @op2 + @op3"
+    return [m2_expr.ExprAssign(cf, m2_expr.ExprOp("FLAG_ADDWC_CF", op1, op2, op3))]
+
+
+def update_flag_addwc_of(op1, op2, op3):
+    "Compute of in @res = @op1 + @op2 + @op3"
+    return [m2_expr.ExprAssign(of, m2_expr.ExprOp("FLAG_ADDWC_OF", op1, op2, op3))]
+
+
+
+def update_flag_subwc_cf(op1, op2, op3):
+    "Compute cf in @res = @op1 + @op2 + @op3"
+    return [m2_expr.ExprAssign(cf, m2_expr.ExprOp("FLAG_SUBWC_CF", op1, op2, op3))]
+
+
+def update_flag_subwc_of(op1, op2, op3):
+    "Compute of in @res = @op1 + @op2 + @op3"
+    return [m2_expr.ExprAssign(of, m2_expr.ExprOp("FLAG_SUBWC_OF", op1, op2, op3))]
+
+
+
+
+def update_flag_arith_add_co(x, y, z):
+    e = []
+    e += update_flag_add_cf(x, y, z)
+    e += update_flag_add_of(x, y, z)
+    return e
+
+
+def update_flag_arith_sub_co(x, y, z):
+    e = []
+    e += update_flag_sub_cf(x, y, z)
+    e += update_flag_sub_of(x, y, z)
+    return e
+
+
+
+
+def update_flag_arith_addwc_co(arg1, arg2, arg3):
+    e = []
+    e += update_flag_addwc_cf(arg1, arg2, arg3)
+    e += update_flag_addwc_of(arg1, arg2, arg3)
+    return e
+
+
+def update_flag_arith_subwc_co(arg1, arg2, arg3):
+    e = []
+    e += update_flag_subwc_cf(arg1, arg2, arg3)
+    e += update_flag_subwc_of(arg1, arg2, arg3)
+    return e
+
+
+
+def set_float_cs_eip(instr):
+    e = []
+    # XXX TODO check float updt
+    e.append(m2_expr.ExprAssign(float_eip,
+                             m2_expr.ExprInt(instr.offset, float_eip.size)))
+    e.append(m2_expr.ExprAssign(float_cs, CS))
+    return e
+
+
+def mode2addrsize(mode):
+    """Returns the address size for a given @mode"""
+
+    mode2size = {16:32, 32:32, 64:64}
+    if mode not in mode2size:
+        raise RuntimeError("Unknown size %s", mode)
+    return mode2size[mode]
+
+
+def instr2addrsize(instr):
+    """Returns the address size for a given @instr"""
+
+    return mode2addrsize(instr.mode)
+
+
+def expraddr(mode, ptr):
+    """Returns memory address pointer with size according to current @mode"""
+    return ptr.zeroExtend(mode2addrsize(mode))
+
+
+def fix_mem_args_size(instr, *args):
+    out = []
+    for arg in args:
+        if not arg.is_mem():
+            out.append(arg)
+            continue
+        ptr = arg.ptr
+        size = arg.size
+        if ptr.is_op('segm'):
+            ptr = m2_expr.ExprOp(
+                'segm', ptr.args[0], expraddr(instr.mode, ptr.args[1]))
+        else:
+            ptr = expraddr(instr.mode, ptr)
+        out.append(m2_expr.ExprMem(ptr, size))
+    return out
+
+
+def mem2double(instr, arg):
+    """
+    Add float conversion if argument is an ExprMem
+    @arg: argument to transform
+    """
+    if isinstance(arg, m2_expr.ExprMem):
+        if arg.size > 64:
+            # TODO: move to 80 bits
+            arg = m2_expr.ExprMem(expraddr(instr.mode, arg.ptr), size=64)
+        return m2_expr.ExprOp('sint_to_fp', arg.signExtend(64))
+    else:
+        return arg
+
+
+def float_implicit_st0(arg1, arg2):
+    """
+    Generate full float operators if one argument is implicit (float_st0)
+    """
+    if arg2 is None:
+        arg2 = arg1
+        arg1 = float_st0
+    return arg1, arg2
+
+
+def gen_jcc(ir, instr, cond, dst, jmp_if):
+    """
+    Macro to generate jcc semantic
+    @ir: ir instance
+    @instr: instruction
+    @cond: condition of the jcc
+    @dst: the destination if jcc is taken
+    @jmp_if: jump if/notif cond
+    """
+
+    e = []
+    meip = mRIP[ir.IRDst.size]
+    loc_next = ir.get_next_loc_key(instr)
+    loc_next_expr = m2_expr.ExprLoc(loc_next, dst.size)
+
+    if jmp_if:
+        dstA, dstB = dst, loc_next_expr
+    else:
+        dstA, dstB = loc_next_expr, dst
+    mn_dst = m2_expr.ExprCond(cond,
+                              dstA.zeroExtend(ir.IRDst.size),
+                              dstB.zeroExtend(ir.IRDst.size))
+    e.append(m2_expr.ExprAssign(meip, mn_dst))
+    e.append(m2_expr.ExprAssign(ir.IRDst, mn_dst))
+    return e, []
+
+
+def gen_fcmov(ir, instr, cond, arg1, arg2, mov_if):
+    """Generate fcmov
+    @ir: ir instance
+    @instr: instruction instance
+    @cond: condition
+    @mov_if: invert condition if False"""
+
+    loc_do, loc_do_expr = ir.gen_loc_key_and_expr(ir.IRDst.size)
+    loc_skip = ir.get_next_loc_key(instr)
+    loc_skip_expr = m2_expr.ExprLoc(loc_skip, ir.IRDst.size)
+    if mov_if:
+        dstA, dstB = loc_do_expr, loc_skip_expr
+    else:
+        dstA, dstB = loc_skip_expr, loc_do_expr
+    e = []
+    e_do, extra_irs = [m2_expr.ExprAssign(arg1, arg2)], []
+    e_do.append(m2_expr.ExprAssign(ir.IRDst, loc_skip_expr))
+    e.append(m2_expr.ExprAssign(ir.IRDst, m2_expr.ExprCond(cond, dstA, dstB)))
+    return e, [IRBlock(ir.loc_db, loc_do, [AssignBlock(e_do, instr)])]
+
+
+def gen_cmov(ir, instr, cond, dst, src, mov_if):
+    """Generate cmov
+    @ir: ir instance
+    @instr: instruction instance
+    @cond: condition
+    @mov_if: invert condition if False"""
+
+    loc_do, loc_do_expr = ir.gen_loc_key_and_expr(ir.IRDst.size)
+    loc_skip = ir.get_next_loc_key(instr)
+    loc_skip_expr = m2_expr.ExprLoc(loc_skip, ir.IRDst.size)
+    if mov_if:
+        dstA, dstB = loc_do_expr, loc_skip_expr
+    else:
+        dstA, dstB = loc_skip_expr, loc_do_expr
+    e = []
+    if instr.mode == 64:
+        # Force destination set in order to zero high bit orders
+        # In 64 bit:
+        # cmovz eax, ebx
+        # if zf == 0 => high part of RAX is set to zero
+        e.append(m2_expr.ExprAssign(dst, dst))
+    e_do, extra_irs = mov(ir, instr, dst, src)
+    e_do.append(m2_expr.ExprAssign(ir.IRDst, loc_skip_expr))
+    e.append(m2_expr.ExprAssign(ir.IRDst, m2_expr.ExprCond(cond, dstA, dstB)))
+    return e, [IRBlock(ir.loc_db, loc_do, [AssignBlock(e_do, instr)])]
+
+
+def mov(_, instr, dst, src):
+    if dst in [ES, CS, SS, DS, FS, GS]:
+        src = src[:dst.size]
+    if src in [ES, CS, SS, DS, FS, GS]:
+        src = src.zeroExtend(dst.size)
+    e = [m2_expr.ExprAssign(dst, src)]
+    return e, []
+
+
+def movq(_, instr, dst, src):
+    src_final = (src.zeroExtend(dst.size)
+                 if dst.size >= src.size else
+                 src[:dst.size])
+    return [m2_expr.ExprAssign(dst, src_final)], []
+
+
+@sbuild.parse
+def xchg(arg1, arg2):
+    arg1 = arg2
+    arg2 = arg1
+
+
+
+def movzx(_, instr, dst, src):
+    e = [m2_expr.ExprAssign(dst, src.zeroExtend(dst.size))]
+    return e, []
+
+
+def movsx(_, instr, dst, src):
+    e = [m2_expr.ExprAssign(dst, src.signExtend(dst.size))]
+    return e, []
+
+
+def lea(_, instr, dst, src):
+    ptr = src.ptr
+    if is_mem_segm(src):
+        # Do not use segmentation here
+        ptr = ptr.args[1]
+
+    if ptr.size > dst.size:
+        ptr = ptr[:dst.size]
+    e = [m2_expr.ExprAssign(dst, ptr.zeroExtend(dst.size))]
+    return e, []
+
+
+def add(_, instr, dst, src):
+    e = []
+
+    result = dst + src
+
+    e += update_flag_arith_add_znp(dst, src)
+    e += update_flag_arith_add_co(dst, src, result)
+    e += update_flag_af(dst, src, result)
+    e.append(m2_expr.ExprAssign(dst, result))
+    return e, []
+
+
+def xadd(_, instr, dst, src):
+    e = []
+
+    result = dst + src
+    e += update_flag_arith_add_znp(dst, src)
+    e += update_flag_arith_add_co(src, dst, result)
+    e += update_flag_af(dst, src, result)
+    if dst != src:
+        e.append(m2_expr.ExprAssign(src, dst))
+    e.append(m2_expr.ExprAssign(dst, result))
+    return e, []
+
+
+def adc(_, instr, dst, src):
+    e = []
+
+    arg1 = dst
+    arg2 = src
+    result = arg1 + (arg2 + cf.zeroExtend(src.size))
+
+    e += update_flag_arith_addwc_znp(arg1, arg2, cf)
+    e += update_flag_arith_addwc_co(arg1, arg2, cf)
+    e += update_flag_af(arg1, arg2, result)
+    e.append(m2_expr.ExprAssign(dst, result))
+    return e, []
+
+
+def sub(_, instr, dst, src):
+    e = []
+    arg1, arg2 = dst, src
+    result = dst - src
+
+    e += update_flag_arith_sub_znp(arg1, arg2)
+    e += update_flag_arith_sub_co(arg1, arg2, result)
+    e += update_flag_af(dst, src, result)
+
+    e.append(m2_expr.ExprAssign(dst, result))
+    return e, []
+
+# a-(b+cf)
+
+
+def sbb(_, instr, dst, src):
+    e = []
+    arg1 = dst
+    arg2 = src
+    result = arg1 - (arg2 + cf.zeroExtend(src.size))
+
+    e += update_flag_arith_subwc_znp(arg1, arg2, cf)
+    e += update_flag_af(arg1, arg2, result)
+    e += update_flag_arith_subwc_co(arg1, arg2, cf)
+    e.append(m2_expr.ExprAssign(dst, result))
+    return e, []
+
+
+def neg(_, instr, src):
+    e = []
+    dst = m2_expr.ExprInt(0, src.size)
+    arg1, arg2 = dst, src
+    result = arg1 - arg2
+
+    e += update_flag_arith_sub_znp(arg1, arg2)
+    e += update_flag_arith_sub_co(arg1, arg2, result)
+    e += update_flag_af(arg1, arg2, result)
+    e.append(m2_expr.ExprAssign(src, result))
+    return (e, [])
+
+
+def l_not(_, instr, dst):
+    e = []
+    result = (~dst)
+    e.append(m2_expr.ExprAssign(dst, result))
+    return (e, [])
+
+
+def l_cmp(_, instr, dst, src):
+    e = []
+    arg1, arg2 = dst, src
+    result = dst - src
+
+    e += update_flag_arith_sub_znp(arg1, arg2)
+    e += update_flag_arith_sub_co(arg1, arg2, result)
+    e += update_flag_af(dst, src, result)
+    return (e, [])
+
+
+def xor(_, instr, dst, src):
+    e = []
+    result = dst ^ src
+    e += [m2_expr.ExprAssign(zf, m2_expr.ExprOp('FLAG_EQ_CMP', dst, src))]
+    e += update_flag_np(result)
+    e += null_flag_co()
+    e.append(m2_expr.ExprAssign(dst, result))
+    return (e, [])
+
+
+def pxor(_, instr, dst, src):
+    e = []
+    result = dst ^ src
+    e.append(m2_expr.ExprAssign(dst, result))
+    return (e, [])
+
+
+def l_or(_, instr, dst, src):
+    e = []
+    result = dst | src
+    e += [m2_expr.ExprAssign(zf, m2_expr.ExprOp('FLAG_EQ', dst | src))]
+    e += update_flag_np(result)
+    e += null_flag_co()
+    e.append(m2_expr.ExprAssign(dst, result))
+    return (e, [])
+
+
+def l_and(_, instr, dst, src):
+    e = []
+    result = dst & src
+    e += [m2_expr.ExprAssign(zf, m2_expr.ExprOp('FLAG_EQ_AND', dst, src))]
+    e += update_flag_np(result)
+    e += null_flag_co()
+
+    e.append(m2_expr.ExprAssign(dst, result))
+    return (e, [])
+
+
+def l_test(_, instr, dst, src):
+    e = []
+    result = dst & src
+
+    e += [m2_expr.ExprAssign(zf, m2_expr.ExprOp('FLAG_EQ_CMP', result, m2_expr.ExprInt(0, result.size)))]
+    e += [m2_expr.ExprAssign(nf, m2_expr.ExprOp("FLAG_SIGN_SUB", result, m2_expr.ExprInt(0, result.size)))]
+    e += update_flag_pf(result)
+    e += null_flag_co()
+
+    return (e, [])
+
+
+def get_shift(dst, src):
+    if isinstance(src, m2_expr.ExprInt):
+        src = m2_expr.ExprInt(int(src), dst.size)
+    else:
+        src = src.zeroExtend(dst.size)
+    if dst.size == 64:
+        shift = src & m2_expr.ExprInt(63, src.size)
+    else:
+        shift = src & m2_expr.ExprInt(31, src.size)
+    shift = expr_simp(shift)
+    return shift
+
+
+def _rotate_tpl(ir, instr, dst, src, op, left=False):
+    '''Template to generate a rotater with operation @op
+    A temporary basic block is generated to handle 0-rotate
+    @op: operation to execute
+    @left (optional): indicates a left rotate if set, default is False
+    '''
+    # Compute results
+    shifter = get_shift(dst, src)
+    res = m2_expr.ExprOp(op, dst, shifter)
+
+    # CF is computed with 1-less round than `res`
+    new_cf = m2_expr.ExprOp(
+        op, dst, shifter - m2_expr.ExprInt(1, size=shifter.size))
+    new_cf = new_cf.msb() if left else new_cf[:1]
+
+    # OF is defined only for @b == 1
+    new_of = m2_expr.ExprCond(src - m2_expr.ExprInt(1, size=src.size),
+                              m2_expr.ExprInt(0, size=of.size),
+                              res.msb() ^ new_cf if left else (dst ^ res).msb())
+
+    # Build basic blocks
+    e_do = [m2_expr.ExprAssign(cf, new_cf),
+            m2_expr.ExprAssign(of, new_of),
+            m2_expr.ExprAssign(dst, res)
+            ]
+    e = []
+    if instr.mode == 64:
+        # Force destination set in order to zero high bit orders
+        # In 64 bit:
+        # rol eax, cl
+        # if cl == 0 => high part of RAX is set to zero
+        e.append(m2_expr.ExprAssign(dst, dst))
+    # Don't generate conditional shifter on constant
+    if isinstance(shifter, m2_expr.ExprInt):
+        if int(shifter) != 0:
+            return (e_do, [])
+        else:
+            return (e, [])
+    loc_do, loc_do_expr = ir.gen_loc_key_and_expr(ir.IRDst.size)
+    loc_skip = ir.get_next_loc_key(instr)
+    loc_skip_expr = m2_expr.ExprLoc(loc_skip, ir.IRDst.size)
+    e_do.append(m2_expr.ExprAssign(ir.IRDst, loc_skip_expr))
+    e.append(m2_expr.ExprAssign(
+        ir.IRDst, m2_expr.ExprCond(shifter, loc_do_expr, loc_skip_expr)))
+    return (e, [IRBlock(ir.loc_db, loc_do, [AssignBlock(e_do, instr)])])
+
+
+def l_rol(ir, instr, dst, src):
+    return _rotate_tpl(ir, instr, dst, src, '<<<', left=True)
+
+
+def l_ror(ir, instr, dst, src):
+    return _rotate_tpl(ir, instr, dst, src, '>>>')
+
+
+def rotate_with_carry_tpl(ir, instr, op, dst, src):
+    # Compute results
+    shifter = get_shift(dst, src).zeroExtend(dst.size + 1)
+    result = m2_expr.ExprOp(op, m2_expr.ExprCompose(dst, cf), shifter)
+
+    new_cf = result[dst.size:dst.size +1]
+    new_dst = result[:dst.size]
+
+    result_trunc = result[:dst.size]
+    if op == '<<<':
+        of_value = result_trunc.msb() ^ new_cf
+    else:
+        of_value = (dst ^ result_trunc).msb()
+    # OF is defined only for @b == 1
+    new_of = m2_expr.ExprCond(src - m2_expr.ExprInt(1, size=src.size),
+                              m2_expr.ExprInt(0, size=of.size),
+                              of_value)
+
+
+    # Build basic blocks
+    e_do = [m2_expr.ExprAssign(cf, new_cf),
+            m2_expr.ExprAssign(of, new_of),
+            m2_expr.ExprAssign(dst, new_dst)
+            ]
+    e = [m2_expr.ExprAssign(dst, dst)]
+    # Don't generate conditional shifter on constant
+    if isinstance(shifter, m2_expr.ExprInt):
+        if int(shifter) != 0:
+            return (e_do, [])
+        else:
+            return (e, [])
+    loc_do, loc_do_expr = ir.gen_loc_key_and_expr(ir.IRDst.size)
+    loc_skip = ir.get_next_loc_key(instr)
+    loc_skip_expr = m2_expr.ExprLoc(loc_skip, ir.IRDst.size)
+    e_do.append(m2_expr.ExprAssign(ir.IRDst, loc_skip_expr))
+    e.append(m2_expr.ExprAssign(
+        ir.IRDst, m2_expr.ExprCond(shifter, loc_do_expr, loc_skip_expr)))
+    return (e, [IRBlock(ir.loc_db, loc_do, [AssignBlock(e_do, instr)])])
+
+def rcl(ir, instr, dst, src):
+    return rotate_with_carry_tpl(ir, instr, '<<<', dst, src)
+
+def rcr(ir, instr, dst, src):
+    return rotate_with_carry_tpl(ir, instr, '>>>', dst, src)
+
+
+def _shift_tpl(op, ir, instr, a, b, c=None, op_inv=None, left=False,
+               custom_of=None):
+    """Template to generate a shifter with operation @op
+    A temporary basic block is generated to handle 0-shift
+    @op: operation to execute
+    @c (optional): if set, instruction has a bit provider
+    @op_inv (optional): opposite operation of @op. Must be provided if @c
+    @left (optional): indicates a left shift if set, default is False
+    @custom_of (optional): if set, override the computed value of OF
+    """
+    if c is not None:
+        shifter = get_shift(a, c)
+    else:
+        shifter = get_shift(a, b)
+
+    res = m2_expr.ExprOp(op, a, shifter)
+    cf_from_dst = m2_expr.ExprOp(op, a,
+                                 (shifter - m2_expr.ExprInt(1, a.size)))
+    cf_from_dst = cf_from_dst.msb() if left else cf_from_dst[:1]
+
+    new_cf = cf_from_dst
+    i1 = m2_expr.ExprInt(1, size=a.size)
+    if c is not None:
+        # There is a source for new bits
+        isize = m2_expr.ExprInt(a.size, size=a.size)
+        mask = m2_expr.ExprOp(op_inv, i1, (isize - shifter)) - i1
+
+        # An overflow can occurred, emulate the 'undefined behavior'
+        # Overflow behavior if (shift / size % 2)
+        base_cond_overflow = shifter if left else (
+            shifter - m2_expr.ExprInt(1, size=shifter.size))
+        cond_overflow = base_cond_overflow & m2_expr.ExprInt(a.size, shifter.size)
+        if left:
+            # Overflow occurs one round before right
+            mask = m2_expr.ExprCond(cond_overflow, mask, ~mask)
+        else:
+            mask = m2_expr.ExprCond(cond_overflow, ~mask, mask)
+
+        # Build res with dst and src
+        res = ((m2_expr.ExprOp(op, a, shifter) & mask) |
+               (m2_expr.ExprOp(op_inv, b, (isize - shifter)) & ~mask))
+
+        # Overflow case: cf come from src (bit number shifter % size)
+        cf_from_src = m2_expr.ExprOp(op, b,
+                                     (shifter.zeroExtend(b.size) &
+                                      m2_expr.ExprInt(a.size - 1, b.size)) - i1)
+        cf_from_src = cf_from_src.msb() if left else cf_from_src[:1]
+        new_cf = m2_expr.ExprCond(cond_overflow, cf_from_src, cf_from_dst)
+
+    # Overflow flag, only occurred when shifter is equal to 1
+    if custom_of is None:
+        value_of = a.msb() ^ a[-2:-1] if left else b[:1] ^ a.msb()
+    else:
+        value_of = custom_of
+
+    # Build basic blocks
+    e_do = [
+        m2_expr.ExprAssign(cf, new_cf),
+        m2_expr.ExprAssign(of, m2_expr.ExprCond(shifter - i1,
+                                             m2_expr.ExprInt(0, of.size),
+                                             value_of)),
+        m2_expr.ExprAssign(a, res),
+    ]
+    e_do += update_flag_znp(res)
+    e = []
+    if instr.mode == 64:
+        # Force destination set in order to zero high bit orders
+        # In 64 bit:
+        # shr eax, cl
+        # if cl == 0 => high part of RAX is set to zero
+        e.append(m2_expr.ExprAssign(a, a))
+    # Don't generate conditional shifter on constant
+    if isinstance(shifter, m2_expr.ExprInt):
+        if int(shifter) != 0:
+            return (e_do, [])
+        else:
+            return (e, [])
+    loc_do, loc_do_expr = ir.gen_loc_key_and_expr(ir.IRDst.size)
+    loc_skip = ir.get_next_loc_key(instr)
+    loc_skip_expr = m2_expr.ExprLoc(loc_skip, ir.IRDst.size)
+    e_do.append(m2_expr.ExprAssign(ir.IRDst, loc_skip_expr))
+    e.append(m2_expr.ExprAssign(ir.IRDst, m2_expr.ExprCond(shifter, loc_do_expr,
+                                                        loc_skip_expr)))
+    return e, [IRBlock(ir.loc_db, loc_do, [AssignBlock(e_do, instr)])]
+
+
+def sar(ir, instr, dst, src):
+    # Fixup OF, always cleared if src != 0
+    i0 = m2_expr.ExprInt(0, size=of.size)
+    return _shift_tpl("a>>", ir, instr, dst, src, custom_of=i0)
+
+
+def shr(ir, instr, dst, src):
+    return _shift_tpl(">>", ir, instr, dst, src, custom_of=dst.msb())
+
+
+def shrd(ir, instr, dst, src1, src2):
+    return _shift_tpl(">>>", ir, instr, dst, src1, src2, "<<<")
+
+
+def shl(ir, instr, dst, src):
+    return _shift_tpl("<<", ir, instr, dst, src, left=True)
+
+
+def shld(ir, instr, dst, src1, src2):
+    return _shift_tpl("<<<", ir, instr, dst, src1, src2, ">>>", left=True)
+
+
+# XXX todo ###
+def cmc(_, instr):
+    e = [m2_expr.ExprAssign(cf, m2_expr.ExprCond(cf, m2_expr.ExprInt(0, cf.size),
+                                              m2_expr.ExprInt(1, cf.size)))]
+    return e, []
+
+
+def clc(_, instr):
+    e = [m2_expr.ExprAssign(cf, m2_expr.ExprInt(0, cf.size))]
+    return e, []
+
+
+def stc(_, instr):
+    e = [m2_expr.ExprAssign(cf, m2_expr.ExprInt(1, cf.size))]
+    return e, []
+
+
+def cld(_, instr):
+    e = [m2_expr.ExprAssign(df, m2_expr.ExprInt(0, df.size))]
+    return e, []
+
+
+def std(_, instr):
+    e = [m2_expr.ExprAssign(df, m2_expr.ExprInt(1, df.size))]
+    return e, []
+
+
+def cli(_, instr):
+    e = [m2_expr.ExprAssign(i_f, m2_expr.ExprInt(0, i_f.size))]
+    return e, []
+
+
+def sti(_, instr):
+    e = [m2_expr.ExprAssign(exception_flags, m2_expr.ExprInt(EXCEPT_PRIV_INSN, 32))]
+    return e, []
+
+
+def inc(_, instr, dst):
+    e = []
+    src = m2_expr.ExprInt(1, dst.size)
+    arg1, arg2 = dst, src
+    result = dst + src
+
+    e += update_flag_arith_add_znp(arg1, arg2)
+    e += update_flag_af(arg1, arg2, result)
+    e += update_flag_add_of(arg1, arg2, result)
+
+    e.append(m2_expr.ExprAssign(dst, result))
+    return e, []
+
+
+def dec(_, instr, dst):
+    e = []
+    src = m2_expr.ExprInt(1, dst.size)
+    arg1, arg2 = dst, src
+    result = dst - src
+
+    e += update_flag_arith_sub_znp(arg1, arg2)
+    e += update_flag_af(arg1, arg2, result)
+    e += update_flag_sub_of(arg1, arg2, result)
+
+    e.append(m2_expr.ExprAssign(dst, result))
+    return e, []
+
+
+def push_gen(ir, instr, src, size):
+    e = []
+    if not size in [16, 32, 64]:
+        raise ValueError('bad size stacker!')
+    if src.size < size:
+        src = src.zeroExtend(size)
+    off_size = src.size
+
+    sp = mRSP[instr.mode]
+    new_sp = sp - m2_expr.ExprInt(off_size // 8, sp.size)
+    e.append(m2_expr.ExprAssign(sp, new_sp))
+    if ir.do_stk_segm:
+        new_sp = ir.gen_segm_expr(SS, new_sp)
+    e.append(m2_expr.ExprAssign(ir.ExprMem(new_sp, off_size),
+                             src))
+    return e, []
+
+
+def push(ir, instr, src):
+    return push_gen(ir, instr, src, instr.mode)
+
+
+def pushw(ir, instr, src):
+    return push_gen(ir, instr, src, 16)
+
+
+def pop_gen(ir, instr, src, size):
+    e = []
+    if not size in [16, 32, 64]:
+        raise ValueError('bad size stacker!')
+
+    sp = mRSP[instr.mode]
+    new_sp = sp + m2_expr.ExprInt(src.size // 8, sp.size)
+    # Don't generate SP/ESP/RSP incrementation on POP SP/ESP/RSP
+    if not (src in mRSP.values()):
+        e.append(m2_expr.ExprAssign(sp, new_sp))
+    # XXX FIX XXX for pop [esp]
+    if isinstance(src, m2_expr.ExprMem):
+        src = expr_simp(src.replace_expr({sp: new_sp}))
+    result = sp
+    if ir.do_stk_segm:
+        result = ir.gen_segm_expr(SS, result)
+
+    e.append(m2_expr.ExprAssign(src, ir.ExprMem(result, src.size)))
+    return e, []
+
+
+def pop(ir, instr, src):
+    return pop_gen(ir, instr, src, instr.mode)
+
+
+def popw(ir, instr, src):
+    return pop_gen(ir, instr, src, 16)
+
+
+def sete(_, instr, dst):
+    e = []
+    e.append(
+        m2_expr.ExprAssign(
+            dst,
+            m2_expr.ExprOp("CC_EQ", zf).zeroExtend(dst.size),
+        )
+    )
+    return e, []
+
+
+def setnz(_, instr, dst):
+    e = []
+    e.append(
+        m2_expr.ExprAssign(
+            dst,
+            m2_expr.ExprOp("CC_EQ", ~zf).zeroExtend(dst.size),
+        )
+    )
+    return e, []
+
+
+def setl(_, instr, dst):
+    e = []
+    e.append(
+        m2_expr.ExprAssign(
+            dst,
+            m2_expr.ExprOp("CC_S<", nf, of).zeroExtend(dst.size),
+        )
+    )
+    return e, []
+
+
+def setg(_, instr, dst):
+    e = []
+    e.append(
+        m2_expr.ExprAssign(
+            dst,
+            m2_expr.ExprOp("CC_S>", nf, of, zf).zeroExtend(dst.size),
+        )
+    )
+    return e, []
+
+
+def setge(_, instr, dst):
+    e = []
+    e.append(
+        m2_expr.ExprAssign(
+            dst,
+            m2_expr.ExprOp("CC_S>=", nf, of).zeroExtend(dst.size),
+        )
+    )
+    return e, []
+
+
+def seta(_, instr, dst):
+    e = []
+    e.append(
+        m2_expr.ExprAssign(
+            dst,
+            m2_expr.ExprOp("CC_U>", cf, zf).zeroExtend(dst.size),
+        )
+    )
+    return e, []
+
+
+def setae(_, instr, dst):
+    e = []
+    e.append(
+        m2_expr.ExprAssign(
+            dst,
+            m2_expr.ExprOp("CC_U>=", cf).zeroExtend(dst.size),
+        )
+    )
+    return e, []
+
+
+def setb(_, instr, dst):
+    e = []
+    e.append(
+        m2_expr.ExprAssign(
+            dst,
+            m2_expr.ExprOp("CC_U<", cf).zeroExtend(dst.size),
+        )
+    )
+    return e, []
+
+
+def setbe(_, instr, dst):
+    e = []
+    e.append(
+        m2_expr.ExprAssign(
+            dst,
+            m2_expr.ExprOp("CC_U<=", cf, zf).zeroExtend(dst.size),
+        )
+    )
+    return e, []
+
+
+def setns(_, instr, dst):
+    e = []
+    e.append(
+        m2_expr.ExprAssign(
+            dst,
+            m2_expr.ExprOp("CC_NEG", ~nf).zeroExtend(dst.size),
+        )
+    )
+    return e, []
+
+
+def sets(_, instr, dst):
+    e = []
+    e.append(
+        m2_expr.ExprAssign(
+            dst,
+            m2_expr.ExprOp("CC_NEG", nf).zeroExtend(dst.size),
+        )
+    )
+    return e, []
+
+
+def seto(_, instr, dst):
+    e = []
+    e.append(
+        m2_expr.ExprAssign(
+            dst,
+            of.zeroExtend(dst.size)
+        )
+    )
+    return e, []
+
+
+def setp(_, instr, dst):
+    e = []
+    e.append(
+        m2_expr.ExprAssign(
+            dst,
+            pf.zeroExtend(dst.size)
+        )
+    )
+    return e, []
+
+
+def setnp(_, instr, dst):
+    e = []
+    e.append(
+        m2_expr.ExprAssign(
+            dst,
+            m2_expr.ExprCond(
+                pf,
+                m2_expr.ExprInt(0, dst.size),
+                m2_expr.ExprInt(1, dst.size)
+            )
+        )
+    )
+    return e, []
+
+
+def setle(_, instr, dst):
+    e = []
+    e.append(
+        m2_expr.ExprAssign(
+            dst,
+            m2_expr.ExprOp("CC_S<=", nf, of, zf).zeroExtend(dst.size),
+        )
+    )
+    return e, []
+
+
+def setna(_, instr, dst):
+    e = []
+    e.append(
+        m2_expr.ExprAssign(
+            dst,
+            m2_expr.ExprOp("CC_U<=", cf, zf).zeroExtend(dst.size),
+        )
+    )
+    return e, []
+
+
+def setnbe(_, instr, dst):
+    e = []
+    e.append(
+        m2_expr.ExprAssign(
+            dst,
+            m2_expr.ExprOp("CC_U>", cf, zf).zeroExtend(dst.size),
+        )
+    )
+    return e, []
+
+
+def setno(_, instr, dst):
+    e = []
+    e.append(
+        m2_expr.ExprAssign(
+            dst,
+            m2_expr.ExprCond(
+                of,
+                m2_expr.ExprInt(0, dst.size),
+                m2_expr.ExprInt(1, dst.size)
+            )
+        )
+    )
+    return e, []
+
+
+def setnb(_, instr, dst):
+    e = []
+    e.append(
+        m2_expr.ExprAssign(
+            dst,
+            m2_expr.ExprOp("CC_U>=", cf).zeroExtend(dst.size),
+        )
+    )
+    return e, []
+
+
+def setalc(_, instr):
+    dst = mRAX[instr.mode][0:8]
+    e = []
+    e.append(
+        m2_expr.ExprAssign(dst, m2_expr.ExprCond(cf, m2_expr.ExprInt(0xff, dst.size),
+                                              m2_expr.ExprInt(0, dst.size))))
+    return e, []
+
+
+def bswap(_, instr, dst):
+    e = []
+    if dst.size == 16:
+        # BSWAP referencing a 16-bit register is undefined
+        # Seems to return 0 actually
+        result = m2_expr.ExprInt(0, 16)
+    elif dst.size == 32:
+        result = m2_expr.ExprCompose(
+            dst[24:32], dst[16:24], dst[8:16], dst[:8])
+    elif dst.size == 64:
+        result = m2_expr.ExprCompose(dst[56:64], dst[48:56], dst[40:48], dst[32:40],
+                                     dst[24:32], dst[16:24], dst[8:16], dst[:8])
+    else:
+        raise ValueError('the size DOES matter')
+    e.append(m2_expr.ExprAssign(dst, result))
+    return e, []
+
+
+def cmps(ir, instr, size):
+    loc_df_0, loc_df_0_expr = ir.gen_loc_key_and_expr(ir.IRDst.size)
+    loc_df_1, loc_df_1_expr = ir.gen_loc_key_and_expr(ir.IRDst.size)
+    loc_next_expr = m2_expr.ExprLoc(ir.get_next_loc_key(instr), ir.IRDst.size)
+
+    src1 = mRSI[instr.mode][:instr.v_admode()]
+    src2 = mRDI[instr.mode][:instr.v_admode()]
+
+    if ir.do_str_segm:
+        if instr.additional_info.g2.value:
+            raise NotImplementedError("add segm support")
+        src1_sgm = ir.gen_segm_expr(DS, src1)
+        src2_sgm = ir.gen_segm_expr(ES, src2)
+    else:
+        src1_sgm = src1
+        src2_sgm = src2
+
+    offset = m2_expr.ExprInt(size // 8, src1.size)
+
+    e, _ = l_cmp(ir, instr,
+                 ir.ExprMem(src1_sgm, size),
+                 ir.ExprMem(src2_sgm, size))
+
+
+    e0 = []
+    e0.append(m2_expr.ExprAssign(src1, src1 + offset))
+    e0.append(m2_expr.ExprAssign(src2, src2 + offset))
+    e0.append(m2_expr.ExprAssign(ir.IRDst, loc_next_expr))
+    e0 = IRBlock(ir.loc_db, loc_df_0, [AssignBlock(e0, instr)])
+
+    e1 = []
+    e1.append(m2_expr.ExprAssign(src1, src1 - offset))
+    e1.append(m2_expr.ExprAssign(src2, src2 - offset))
+    e1.append(m2_expr.ExprAssign(ir.IRDst, loc_next_expr))
+    e1 = IRBlock(ir.loc_db, loc_df_1, [AssignBlock(e1, instr)])
+
+    e.append(m2_expr.ExprAssign(ir.IRDst,
+                             m2_expr.ExprCond(df, loc_df_1_expr, loc_df_0_expr)))
+    return e, [e0, e1]
+
+
+def scas(ir, instr, size):
+    loc_df_0, loc_df_0_expr = ir.gen_loc_key_and_expr(ir.IRDst.size)
+    loc_df_1, loc_df_1_expr = ir.gen_loc_key_and_expr(ir.IRDst.size)
+    loc_next_expr = m2_expr.ExprLoc(ir.get_next_loc_key(instr), ir.IRDst.size)
+
+    src = mRDI[instr.mode][:instr.v_admode()]
+
+    if ir.do_str_segm:
+        if instr.additional_info.g2.value:
+            raise NotImplementedError("add segm support")
+        src_sgm = ir.gen_segm_expr(ES, src)
+
+    else:
+        src_sgm = src
+
+    offset = m2_expr.ExprInt(size // 8, src.size)
+    e, extra = l_cmp(ir, instr,
+                     mRAX[instr.mode][:size],
+                     ir.ExprMem(src_sgm, size))
+
+    e0 = []
+    e0.append(m2_expr.ExprAssign(src, src + offset))
+
+    e0.append(m2_expr.ExprAssign(ir.IRDst, loc_next_expr))
+    e0 = IRBlock(ir.loc_db, loc_df_0, [AssignBlock(e0, instr)])
+
+    e1 = []
+    e1.append(m2_expr.ExprAssign(src, src - offset))
+    e1.append(m2_expr.ExprAssign(ir.IRDst, loc_next_expr))
+    e1 = IRBlock(ir.loc_db, loc_df_1, [AssignBlock(e1, instr)])
+
+    e.append(m2_expr.ExprAssign(ir.IRDst,
+                             m2_expr.ExprCond(df, loc_df_1_expr, loc_df_0_expr)))
+
+    return e, [e0, e1]
+
+
+def compose_eflag(s=32):
+    args = []
+
+    args = [cf, m2_expr.ExprInt(1, 1), pf, m2_expr.ExprInt(0, 1), af,
+            m2_expr.ExprInt(0, 1), zf, nf, tf, i_f, df, of, iopl]
+
+    if s == 32:
+        args += [nt, m2_expr.ExprInt(0, 1), rf, vm, ac, vif, vip, i_d]
+    elif s == 16:
+        args += [nt, m2_expr.ExprInt(0, 1)]
+    else:
+        raise ValueError('unk size')
+    if s == 32:
+        args.append(m2_expr.ExprInt(0, 10))
+    return m2_expr.ExprCompose(*args)
+
+
+def pushfd(ir, instr):
+    return push(ir, instr, compose_eflag())
+
+
+def pushfq(ir, instr):
+    return push(ir, instr, compose_eflag().zeroExtend(64))
+
+
+def pushfw(ir, instr):
+    return pushw(ir, instr, compose_eflag(16))
+
+
+def popfd(ir, instr):
+    tmp = ir.ExprMem(mRSP[instr.mode], 32)
+    e = []
+    e.append(m2_expr.ExprAssign(cf, m2_expr.ExprSlice(tmp, 0, 1)))
+    e.append(m2_expr.ExprAssign(pf, m2_expr.ExprSlice(tmp, 2, 3)))
+    e.append(m2_expr.ExprAssign(af, m2_expr.ExprSlice(tmp, 4, 5)))
+    e.append(m2_expr.ExprAssign(zf, m2_expr.ExprSlice(tmp, 6, 7)))
+    e.append(m2_expr.ExprAssign(nf, m2_expr.ExprSlice(tmp, 7, 8)))
+    e.append(m2_expr.ExprAssign(tf, m2_expr.ExprSlice(tmp, 8, 9)))
+    e.append(m2_expr.ExprAssign(i_f, m2_expr.ExprSlice(tmp, 9, 10)))
+    e.append(m2_expr.ExprAssign(df, m2_expr.ExprSlice(tmp, 10, 11)))
+    e.append(m2_expr.ExprAssign(of, m2_expr.ExprSlice(tmp, 11, 12)))
+    e.append(m2_expr.ExprAssign(iopl, m2_expr.ExprSlice(tmp, 12, 14)))
+    e.append(m2_expr.ExprAssign(nt, m2_expr.ExprSlice(tmp, 14, 15)))
+    e.append(m2_expr.ExprAssign(rf, m2_expr.ExprSlice(tmp, 16, 17)))
+    e.append(m2_expr.ExprAssign(vm, m2_expr.ExprSlice(tmp, 17, 18)))
+    e.append(m2_expr.ExprAssign(ac, m2_expr.ExprSlice(tmp, 18, 19)))
+    e.append(m2_expr.ExprAssign(vif, m2_expr.ExprSlice(tmp, 19, 20)))
+    e.append(m2_expr.ExprAssign(vip, m2_expr.ExprSlice(tmp, 20, 21)))
+    e.append(m2_expr.ExprAssign(i_d, m2_expr.ExprSlice(tmp, 21, 22)))
+    e.append(m2_expr.ExprAssign(mRSP[instr.mode],
+                             mRSP[instr.mode] + m2_expr.ExprInt(instr.mode // 8, mRSP[instr.mode].size)))
+    e.append(m2_expr.ExprAssign(exception_flags,
+                             m2_expr.ExprCond(m2_expr.ExprSlice(tmp, 8, 9),
+                                              m2_expr.ExprInt(
+                                                  EXCEPT_SOFT_BP, 32),
+                                              exception_flags
+                                              )
+                             )
+             )
+    return e, []
+
+
+def _tpl_eflags(tmp):
+    """Extract eflags from @tmp
+    @tmp: Expr instance with a size >= 16
+    """
+    return [m2_expr.ExprAssign(dest, tmp[base:base + dest.size])
+            for base, dest in ((0, cf), (2, pf), (4, af), (6, zf), (7, nf),
+                               (8, tf), (9, i_f), (10, df), (11, of),
+                               (12, iopl), (14, nt))]
+
+
+def popfw(ir, instr):
+    tmp = ir.ExprMem(mRSP[instr.mode], 16)
+    e = _tpl_eflags(tmp)
+    e.append(
+        m2_expr.ExprAssign(mRSP[instr.mode], mRSP[instr.mode] + m2_expr.ExprInt(2, mRSP[instr.mode].size)))
+    return e, []
+
+pa_regs = [
+    mRAX, mRCX,
+    mRDX, mRBX,
+    mRSP, mRBP,
+    mRSI, mRDI
+]
+
+
+def pusha_gen(ir, instr, size):
+    e = []
+    cur_sp = mRSP[instr.mode]
+    for i, reg in enumerate(pa_regs):
+        stk_ptr = cur_sp + m2_expr.ExprInt(-(size // 8) * (i + 1), instr.mode)
+        e.append(m2_expr.ExprAssign(ir.ExprMem(stk_ptr, size), reg[size]))
+    e.append(m2_expr.ExprAssign(cur_sp, stk_ptr))
+    return e, []
+
+
+def pusha(ir, instr):
+    return pusha_gen(ir, instr, 16)
+
+
+def pushad(ir, instr):
+    return pusha_gen(ir, instr, 32)
+
+
+def popa_gen(ir, instr, size):
+    e = []
+    cur_sp = mRSP[instr.mode]
+    for i, reg in enumerate(reversed(pa_regs)):
+        if reg == mRSP:
+            continue
+        stk_ptr = cur_sp + m2_expr.ExprInt((size // 8) * i, instr.mode)
+        e.append(m2_expr.ExprAssign(reg[size], ir.ExprMem(stk_ptr, size)))
+
+    stk_ptr = cur_sp + m2_expr.ExprInt((size // 8) * (i + 1), instr.mode)
+    e.append(m2_expr.ExprAssign(cur_sp, stk_ptr))
+
+    return e, []
+
+
+def popa(ir, instr):
+    return popa_gen(ir, instr, 16)
+
+
+def popad(ir, instr):
+    return popa_gen(ir, instr, 32)
+
+
+def call(ir, instr, dst):
+    e = []
+    # opmode, admode = instr.opmode, instr.admode
+    s = dst.size
+    meip = mRIP[ir.IRDst.size]
+    opmode, admode = s, instr.v_admode()
+    myesp = mRSP[instr.mode][:opmode]
+    n = m2_expr.ExprLoc(ir.get_next_loc_key(instr), ir.IRDst.size)
+
+    if isinstance(dst, m2_expr.ExprOp):
+        if dst.op == "segm":
+            # Far call segm:addr
+            if instr.mode not in [16, 32]:
+                raise RuntimeError('not supported')
+            segm = dst.args[0]
+            base = dst.args[1]
+            m1 = segm.zeroExtend(CS.size)
+            m2 = base.zeroExtend(meip.size)
+        elif dst.op == "far":
+            # Far call far [eax]
+            addr = dst.args[0].ptr
+            m1 = ir.ExprMem(addr, CS.size)
+            m2 = ir.ExprMem(addr + m2_expr.ExprInt(2, addr.size), meip.size)
+        else:
+            raise RuntimeError("bad call operator")
+
+        e.append(m2_expr.ExprAssign(CS, m1))
+        e.append(m2_expr.ExprAssign(meip, m2))
+
+        e.append(m2_expr.ExprAssign(ir.IRDst, m2))
+
+        c = myesp + m2_expr.ExprInt(-s // 8, s)
+        e.append(m2_expr.ExprAssign(ir.ExprMem(c, size=s).zeroExtend(s),
+                                 CS.zeroExtend(s)))
+
+        c = myesp + m2_expr.ExprInt((-2 * s) // 8, s)
+        e.append(m2_expr.ExprAssign(ir.ExprMem(c, size=s).zeroExtend(s),
+                                 meip.zeroExtend(s)))
+
+        c = myesp + m2_expr.ExprInt((-2 * s) // 8, s)
+        e.append(m2_expr.ExprAssign(myesp, c))
+        return e, []
+
+    c = myesp + m2_expr.ExprInt(-s // 8, s)
+    e.append(m2_expr.ExprAssign(myesp, c))
+    if ir.do_stk_segm:
+        c = ir.gen_segm_expr(SS, c)
+
+    e.append(m2_expr.ExprAssign(ir.ExprMem(c, size=s), n))
+    e.append(m2_expr.ExprAssign(meip, dst.zeroExtend(ir.IRDst.size)))
+    e.append(m2_expr.ExprAssign(ir.IRDst, dst.zeroExtend(ir.IRDst.size)))
+    return e, []
+
+
+def ret(ir, instr, src=None):
+    e = []
+    meip = mRIP[ir.IRDst.size]
+    size, admode = instr.v_opmode(), instr.v_admode()
+    myesp = mRSP[instr.mode][:size]
+
+    if src is None:
+        value = (myesp + (m2_expr.ExprInt(size // 8, size)))
+    else:
+        src = m2_expr.ExprInt(int(src), size)
+        value = (myesp + (m2_expr.ExprInt(size // 8, size) + src))
+
+    e.append(m2_expr.ExprAssign(myesp, value))
+    result = myesp
+    if ir.do_stk_segm:
+        result = ir.gen_segm_expr(SS, result)
+
+    e.append(m2_expr.ExprAssign(meip, ir.ExprMem(
+        result, size=size).zeroExtend(size)))
+    e.append(m2_expr.ExprAssign(ir.IRDst,
+                             ir.ExprMem(result, size=size).zeroExtend(size)))
+    return e, []
+
+
+def retf(ir, instr, src=None):
+    e = []
+    meip = mRIP[ir.IRDst.size]
+    size, admode = instr.v_opmode(), instr.v_admode()
+    if src is None:
+        src = m2_expr.ExprInt(0, instr.mode)
+    myesp = mRSP[instr.mode][:size]
+
+    src = src.zeroExtend(size)
+
+    result = myesp
+    if ir.do_stk_segm:
+        result = ir.gen_segm_expr(SS, result)
+
+    e.append(m2_expr.ExprAssign(meip, ir.ExprMem(
+        result, size=size).zeroExtend(size)))
+    e.append(m2_expr.ExprAssign(ir.IRDst,
+                             ir.ExprMem(result, size=size).zeroExtend(size)))
+    # e.append(m2_expr.ExprAssign(meip, ir.ExprMem(c, size = s)))
+    result = myesp + m2_expr.ExprInt(size // 8, size)
+    if ir.do_stk_segm:
+        result = ir.gen_segm_expr(SS, result)
+
+    e.append(m2_expr.ExprAssign(CS, ir.ExprMem(result, size=16)))
+
+    value = myesp + (m2_expr.ExprInt((2 * size) // 8, size) + src)
+    e.append(m2_expr.ExprAssign(myesp, value))
+    return e, []
+
+
+def leave(ir, instr):
+    size = instr.mode
+    myesp = mRSP[size]
+    e = []
+    e.append(m2_expr.ExprAssign(mRBP[size], ir.ExprMem(mRBP[size], size=size)))
+    e.append(m2_expr.ExprAssign(myesp,
+                             m2_expr.ExprInt(size // 8, size) + mRBP[size]))
+    return e, []
+
+
+def enter(ir, instr, src1, src2):
+    size, admode = instr.v_opmode(), instr.v_admode()
+    myesp = mRSP[instr.mode][:size]
+    myebp = mRBP[instr.mode][:size]
+
+    src1 = src1.zeroExtend(size)
+
+    e = []
+    esp_tmp = myesp - m2_expr.ExprInt(size // 8, size)
+    e.append(m2_expr.ExprAssign(ir.ExprMem(esp_tmp, size=size),
+                             myebp))
+    e.append(m2_expr.ExprAssign(myebp, esp_tmp))
+    e.append(m2_expr.ExprAssign(myesp,
+                             myesp - (src1 + m2_expr.ExprInt(size // 8, size))))
+    return e, []
+
+
+def jmp(ir, instr, dst):
+    e = []
+    meip = mRIP[ir.IRDst.size]
+
+    if isinstance(dst, m2_expr.ExprOp):
+        if dst.op == "segm":
+            # Far jmp segm:addr
+            segm = dst.args[0]
+            base = dst.args[1]
+            m1 = segm.zeroExtend(CS.size)
+            m2 = base.zeroExtend(meip.size)
+        elif dst.op == "far":
+            # Far jmp far [eax]
+            addr = dst.args[0].ptr
+            m1 = ir.ExprMem(addr, CS.size)
+            m2 = ir.ExprMem(addr + m2_expr.ExprInt(2, addr.size), meip.size)
+        else:
+            raise RuntimeError("bad jmp operator")
+
+        e.append(m2_expr.ExprAssign(CS, m1))
+        e.append(m2_expr.ExprAssign(meip, m2))
+        e.append(m2_expr.ExprAssign(ir.IRDst, m2))
+
+    else:
+        # Classic jmp
+        e.append(m2_expr.ExprAssign(meip, dst))
+        e.append(m2_expr.ExprAssign(ir.IRDst, dst))
+
+        if isinstance(dst, m2_expr.ExprMem):
+            dst = meip
+    return e, []
+
+
+def jz(ir, instr, dst):
+    #return gen_jcc(ir, instr, zf, dst, True)
+    return gen_jcc(ir, instr, m2_expr.ExprOp("CC_EQ", zf), dst, True)
+
+
+def jcxz(ir, instr, dst):
+    return gen_jcc(ir, instr, mRCX[instr.mode][:16], dst, False)
+
+
+def jecxz(ir, instr, dst):
+    return gen_jcc(ir, instr, mRCX[instr.mode][:32], dst, False)
+
+
+def jrcxz(ir, instr, dst):
+    return gen_jcc(ir, instr, mRCX[instr.mode], dst, False)
+
+
+def jnz(ir, instr, dst):
+    #return gen_jcc(ir, instr, zf, dst, False)
+    return gen_jcc(ir, instr, m2_expr.ExprOp("CC_EQ", zf), dst, False)
+
+
+
+def jp(ir, instr, dst):
+    return gen_jcc(ir, instr, pf, dst, True)
+
+
+def jnp(ir, instr, dst):
+    return gen_jcc(ir, instr, pf, dst, False)
+
+
+def ja(ir, instr, dst):
+    #return gen_jcc(ir, instr, cf | zf, dst, False)
+    return gen_jcc(ir, instr, m2_expr.ExprOp("CC_U>", cf, zf), dst, True)
+
+
+def jae(ir, instr, dst):
+    #return gen_jcc(ir, instr, cf, dst, False)
+    return gen_jcc(ir, instr, m2_expr.ExprOp("CC_U>=", cf), dst, True)
+
+
+def jb(ir, instr, dst):
+    #return gen_jcc(ir, instr, cf, dst, True)
+    return gen_jcc(ir, instr, m2_expr.ExprOp("CC_U<", cf), dst, True)
+
+
+def jbe(ir, instr, dst):
+    #return gen_jcc(ir, instr, cf | zf, dst, True)
+    return gen_jcc(ir, instr, m2_expr.ExprOp("CC_U<=", cf, zf), dst, True)
+
+
+def jge(ir, instr, dst):
+    #return gen_jcc(ir, instr, nf - of, dst, False)
+    return gen_jcc(ir, instr, m2_expr.ExprOp("CC_S>=", nf, of), dst, True)
+
+
+def jg(ir, instr, dst):
+    #return gen_jcc(ir, instr, zf | (nf - of), dst, False)
+    return gen_jcc(ir, instr, m2_expr.ExprOp("CC_S>", nf, of, zf), dst, True)
+
+
+def jl(ir, instr, dst):
+    #return gen_jcc(ir, instr, nf - of, dst, True)
+    return gen_jcc(ir, instr, m2_expr.ExprOp("CC_S<", nf, of), dst, True)
+
+
+def jle(ir, instr, dst):
+    #return gen_jcc(ir, instr, zf | (nf - of), dst, True)
+    return gen_jcc(ir, instr, m2_expr.ExprOp("CC_S<=", nf, of, zf), dst, True)
+
+
+
+def js(ir, instr, dst):
+    #return gen_jcc(ir, instr, nf, dst, True)
+    return gen_jcc(ir, instr, m2_expr.ExprOp("CC_NEG", nf), dst, True)
+
+
+
+def jns(ir, instr, dst):
+    #return gen_jcc(ir, instr, nf, dst, False)
+    return gen_jcc(ir, instr, m2_expr.ExprOp("CC_NEG", nf), dst, False)
+
+
+def jo(ir, instr, dst):
+    return gen_jcc(ir, instr, of, dst, True)
+
+
+def jno(ir, instr, dst):
+    return gen_jcc(ir, instr, of, dst, False)
+
+
+def loop(ir, instr, dst):
+    e = []
+    meip = mRIP[ir.IRDst.size]
+    admode = instr.v_admode()
+    myecx = mRCX[instr.mode][:admode]
+
+    n = m2_expr.ExprLoc(ir.get_next_loc_key(instr), ir.IRDst.size)
+    c = myecx - m2_expr.ExprInt(1, myecx.size)
+    dst_o = m2_expr.ExprCond(c,
+                             dst.zeroExtend(ir.IRDst.size),
+                             n.zeroExtend(ir.IRDst.size))
+    e.append(m2_expr.ExprAssign(myecx, c))
+    e.append(m2_expr.ExprAssign(meip, dst_o))
+    e.append(m2_expr.ExprAssign(ir.IRDst, dst_o))
+    return e, []
+
+
+def loopne(ir, instr, dst):
+    e = []
+    meip = mRIP[ir.IRDst.size]
+    admode = instr.v_admode()
+    myecx = mRCX[instr.mode][:admode]
+
+    n = m2_expr.ExprLoc(ir.get_next_loc_key(instr), ir.IRDst.size)
+
+    c = m2_expr.ExprCond(myecx - m2_expr.ExprInt(1, size=myecx.size),
+                         m2_expr.ExprInt(1, 1),
+                         m2_expr.ExprInt(0, 1))
+    c &= zf ^ m2_expr.ExprInt(1, 1)
+
+    e.append(m2_expr.ExprAssign(myecx, myecx - m2_expr.ExprInt(1, myecx.size)))
+    dst_o = m2_expr.ExprCond(c,
+                             dst.zeroExtend(ir.IRDst.size),
+                             n.zeroExtend(ir.IRDst.size))
+    e.append(m2_expr.ExprAssign(meip, dst_o))
+    e.append(m2_expr.ExprAssign(ir.IRDst, dst_o))
+    return e, []
+
+
+def loope(ir, instr, dst):
+    e = []
+    meip = mRIP[ir.IRDst.size]
+    admode = instr.v_admode()
+    myecx = mRCX[instr.mode][:admode]
+
+    n = m2_expr.ExprLoc(ir.get_next_loc_key(instr), ir.IRDst.size)
+    c = m2_expr.ExprCond(myecx - m2_expr.ExprInt(1, size=myecx.size),
+                         m2_expr.ExprInt(1, 1),
+                         m2_expr.ExprInt(0, 1))
+    c &= zf
+    e.append(m2_expr.ExprAssign(myecx, myecx - m2_expr.ExprInt(1, myecx.size)))
+    dst_o = m2_expr.ExprCond(c,
+                             dst.zeroExtend(ir.IRDst.size),
+                             n.zeroExtend(ir.IRDst.size))
+    e.append(m2_expr.ExprAssign(meip, dst_o))
+    e.append(m2_expr.ExprAssign(ir.IRDst, dst_o))
+    return e, []
+
+# XXX size to do; eflag
+
+
+def div(ir, instr, src1):
+    e = []
+    size = src1.size
+    if size == 8:
+        src2 = mRAX[instr.mode][:16]
+    elif size in [16, 32, 64]:
+        s1, s2 = mRDX[size], mRAX[size]
+        src2 = m2_expr.ExprCompose(s2, s1)
+    else:
+        raise ValueError('div arg not impl', src1)
+
+    c_d = m2_expr.ExprOp('udiv', src2, src1.zeroExtend(src2.size))
+    c_r = m2_expr.ExprOp('umod', src2, src1.zeroExtend(src2.size))
+
+    # if 8 bit div, only ax is assigned
+    if size == 8:
+        e.append(m2_expr.ExprAssign(src2, m2_expr.ExprCompose(c_d[:8], c_r[:8])))
+    else:
+        e.append(m2_expr.ExprAssign(s1, c_r[:size]))
+        e.append(m2_expr.ExprAssign(s2, c_d[:size]))
+
+    loc_div, loc_div_expr = ir.gen_loc_key_and_expr(ir.IRDst.size)
+    loc_except, loc_except_expr = ir.gen_loc_key_and_expr(ir.IRDst.size)
+    loc_next = ir.get_next_loc_key(instr)
+    loc_next_expr = m2_expr.ExprLoc(loc_next, ir.IRDst.size)
+
+    do_div = []
+    do_div += e
+    do_div.append(m2_expr.ExprAssign(ir.IRDst, loc_next_expr))
+    blk_div = IRBlock(ir.loc_db, loc_div, [AssignBlock(do_div, instr)])
+
+    do_except = []
+    do_except.append(m2_expr.ExprAssign(exception_flags, m2_expr.ExprInt(
+        EXCEPT_DIV_BY_ZERO, exception_flags.size)))
+    do_except.append(m2_expr.ExprAssign(ir.IRDst, loc_next_expr))
+    blk_except = IRBlock(ir.loc_db, loc_except, [AssignBlock(do_except, instr)])
+
+    e = []
+    e.append(m2_expr.ExprAssign(ir.IRDst,
+                             m2_expr.ExprCond(src1, loc_div_expr, loc_except_expr)))
+
+    return e, [blk_div, blk_except]
+
+
+# XXX size to do; eflag
+
+def idiv(ir, instr, src1):
+    e = []
+    size = src1.size
+
+    if size == 8:
+        src2 = mRAX[instr.mode][:16]
+    elif size in [16, 32, 64]:
+        s1, s2 = mRDX[size], mRAX[size]
+        src2 = m2_expr.ExprCompose(s2, s1)
+    else:
+        raise ValueError('div arg not impl', src1)
+
+    c_d = m2_expr.ExprOp('sdiv', src2, src1.signExtend(src2.size))
+    c_r = m2_expr.ExprOp('smod', src2, src1.signExtend(src2.size))
+
+    # if 8 bit div, only ax is assigned
+    if size == 8:
+        e.append(m2_expr.ExprAssign(src2, m2_expr.ExprCompose(c_d[:8], c_r[:8])))
+    else:
+        e.append(m2_expr.ExprAssign(s1, c_r[:size]))
+        e.append(m2_expr.ExprAssign(s2, c_d[:size]))
+
+    loc_div, loc_div_expr = ir.gen_loc_key_and_expr(ir.IRDst.size)
+    loc_except, loc_except_expr = ir.gen_loc_key_and_expr(ir.IRDst.size)
+    loc_next = ir.get_next_loc_key(instr)
+    loc_next_expr = m2_expr.ExprLoc(loc_next, ir.IRDst.size)
+
+    do_div = []
+    do_div += e
+    do_div.append(m2_expr.ExprAssign(ir.IRDst, loc_next_expr))
+    blk_div = IRBlock(ir.loc_db, loc_div, [AssignBlock(do_div, instr)])
+
+    do_except = []
+    do_except.append(m2_expr.ExprAssign(exception_flags, m2_expr.ExprInt(
+        EXCEPT_DIV_BY_ZERO, exception_flags.size)))
+    do_except.append(m2_expr.ExprAssign(ir.IRDst, loc_next_expr))
+    blk_except = IRBlock(ir.loc_db, loc_except, [AssignBlock(do_except, instr)])
+
+    e = []
+    e.append(m2_expr.ExprAssign(ir.IRDst,
+                             m2_expr.ExprCond(src1, loc_div_expr, loc_except_expr)))
+
+    return e, [blk_div, blk_except]
+
+
+# XXX size to do; eflag
+
+
+def mul(_, instr, src1):
+    e = []
+    size = src1.size
+    if src1.size in [16, 32, 64]:
+        result = m2_expr.ExprOp('*',
+                                mRAX[size].zeroExtend(size * 2),
+                                src1.zeroExtend(size * 2))
+        e.append(m2_expr.ExprAssign(mRAX[size], result[:size]))
+        e.append(m2_expr.ExprAssign(mRDX[size], result[size:size * 2]))
+
+    elif src1.size == 8:
+        result = m2_expr.ExprOp('*',
+                                mRAX[instr.mode][:8].zeroExtend(16),
+                                src1.zeroExtend(16))
+        e.append(m2_expr.ExprAssign(mRAX[instr.mode][:16], result))
+    else:
+        raise ValueError('unknow size')
+
+    e.append(m2_expr.ExprAssign(of, m2_expr.ExprCond(result[size:size * 2],
+                                                  m2_expr.ExprInt(1, 1),
+                                                  m2_expr.ExprInt(0, 1))))
+    e.append(m2_expr.ExprAssign(cf, m2_expr.ExprCond(result[size:size * 2],
+                                                  m2_expr.ExprInt(1, 1),
+                                                  m2_expr.ExprInt(0, 1))))
+
+    return e, []
+
+
+def imul(_, instr, src1, src2=None, src3=None):
+    e = []
+    size = src1.size
+    if src2 is None:
+        if size in [16, 32, 64]:
+            result = m2_expr.ExprOp('*',
+                                    mRAX[size].signExtend(size * 2),
+                                    src1.signExtend(size * 2))
+            e.append(m2_expr.ExprAssign(mRAX[size], result[:size]))
+            e.append(m2_expr.ExprAssign(mRDX[size], result[size:size * 2]))
+        elif size == 8:
+            dst = mRAX[instr.mode][:16]
+            result = m2_expr.ExprOp('*',
+                                    mRAX[instr.mode][:8].signExtend(16),
+                                    src1.signExtend(16))
+
+            e.append(m2_expr.ExprAssign(dst, result))
+        value = m2_expr.ExprCond(result - result[:size].signExtend(size * 2),
+                                 m2_expr.ExprInt(1, 1),
+                                 m2_expr.ExprInt(0, 1))
+        e.append(m2_expr.ExprAssign(cf, value))
+        value = m2_expr.ExprCond(result - result[:size].signExtend(size * 2),
+                                 m2_expr.ExprInt(1, 1),
+                                 m2_expr.ExprInt(0, 1))
+        e.append(m2_expr.ExprAssign(of, value))
+
+    else:
+        if src3 is None:
+            src3 = src2
+            src2 = src1
+        result = m2_expr.ExprOp('*',
+                                src2.signExtend(size * 2),
+                                src3.signExtend(size * 2))
+        e.append(m2_expr.ExprAssign(src1, result[:size]))
+
+        value = m2_expr.ExprCond(result - result[:size].signExtend(size * 2),
+                                 m2_expr.ExprInt(1, 1),
+                                 m2_expr.ExprInt(0, 1))
+        e.append(m2_expr.ExprAssign(cf, value))
+        value = m2_expr.ExprCond(result - result[:size].signExtend(size * 2),
+                                 m2_expr.ExprInt(1, 1),
+                                 m2_expr.ExprInt(0, 1))
+        e.append(m2_expr.ExprAssign(of, value))
+    return e, []
+
+
+def cbw(_, instr):
+    # Only in 16 bit
+    e = []
+    tempAL = mRAX[instr.v_opmode()][:8]
+    tempAX = mRAX[instr.v_opmode()][:16]
+    e.append(m2_expr.ExprAssign(tempAX, tempAL.signExtend(16)))
+    return e, []
+
+
+def cwde(_, instr):
+    # Only in 32/64 bit
+    e = []
+    tempAX = mRAX[instr.v_opmode()][:16]
+    tempEAX = mRAX[instr.v_opmode()][:32]
+    e.append(m2_expr.ExprAssign(tempEAX, tempAX.signExtend(32)))
+    return e, []
+
+
+def cdqe(_, instr):
+    # Only in 64 bit
+    e = []
+    tempEAX = mRAX[instr.mode][:32]
+    tempRAX = mRAX[instr.mode][:64]
+    e.append(m2_expr.ExprAssign(tempRAX, tempEAX.signExtend(64)))
+    return e, []
+
+
+def cwd(_, instr):
+    # Only in 16 bit
+    e = []
+    tempAX = mRAX[instr.mode][:16]
+    tempDX = mRDX[instr.mode][:16]
+    result = tempAX.signExtend(32)
+    e.append(m2_expr.ExprAssign(tempAX, result[:16]))
+    e.append(m2_expr.ExprAssign(tempDX, result[16:32]))
+    return e, []
+
+
+def cdq(_, instr):
+    # Only in 32/64 bit
+    e = []
+    tempEAX = mRAX[instr.v_opmode()]
+    tempEDX = mRDX[instr.v_opmode()]
+    result = tempEAX.signExtend(64)
+    e.append(m2_expr.ExprAssign(tempEDX, result[32:64]))
+    return e, []
+
+
+def cqo(_, instr):
+    # Only in 64 bit
+    e = []
+    tempRAX = mRAX[instr.mode][:64]
+    tempRDX = mRDX[instr.mode][:64]
+    result = tempRAX.signExtend(128)
+    e.append(m2_expr.ExprAssign(tempRAX, result[:64]))
+    e.append(m2_expr.ExprAssign(tempRDX, result[64:128]))
+    return e, []
+
+
+def stos(ir, instr, size):
+    loc_df_0, loc_df_0_expr = ir.gen_loc_key_and_expr(ir.IRDst.size)
+    loc_df_1, loc_df_1_expr = ir.gen_loc_key_and_expr(ir.IRDst.size)
+    loc_next_expr = m2_expr.ExprLoc(ir.get_next_loc_key(instr), ir.IRDst.size)
+
+    addr_o = mRDI[instr.mode][:instr.v_admode()]
+    addr = addr_o
+    addr_p = addr + m2_expr.ExprInt(size // 8, addr.size)
+    addr_m = addr - m2_expr.ExprInt(size // 8, addr.size)
+    if ir.do_str_segm:
+        mss = ES
+        if instr.additional_info.g2.value:
+            raise NotImplementedError("add segm support")
+        addr = ir.gen_segm_expr(mss, addr)
+
+
+    b = mRAX[instr.mode][:size]
+
+    e0 = []
+    e0.append(m2_expr.ExprAssign(addr_o, addr_p))
+    e0.append(m2_expr.ExprAssign(ir.IRDst, loc_next_expr))
+    e0 = IRBlock(ir.loc_db, loc_df_0, [AssignBlock(e0, instr)])
+
+    e1 = []
+    e1.append(m2_expr.ExprAssign(addr_o, addr_m))
+    e1.append(m2_expr.ExprAssign(ir.IRDst, loc_next_expr))
+    e1 = IRBlock(ir.loc_db, loc_df_1, [AssignBlock(e1, instr)])
+
+    e = []
+    e.append(m2_expr.ExprAssign(ir.ExprMem(addr, size), b))
+    e.append(m2_expr.ExprAssign(ir.IRDst,
+                             m2_expr.ExprCond(df, loc_df_1_expr, loc_df_0_expr)))
+    return e, [e0, e1]
+
+
+def lods(ir, instr, size):
+    loc_df_0, loc_df_0_expr = ir.gen_loc_key_and_expr(ir.IRDst.size)
+    loc_df_1, loc_df_1_expr = ir.gen_loc_key_and_expr(ir.IRDst.size)
+    loc_next_expr = m2_expr.ExprLoc(ir.get_next_loc_key(instr), ir.IRDst.size)
+    e = []
+
+    addr_o = mRSI[instr.mode][:instr.v_admode()]
+    addr = addr_o
+    addr_p = addr + m2_expr.ExprInt(size // 8, addr.size)
+    addr_m = addr - m2_expr.ExprInt(size // 8, addr.size)
+    if ir.do_str_segm:
+        mss = DS
+        if instr.additional_info.g2.value:
+            raise NotImplementedError("add segm support")
+        addr = ir.gen_segm_expr(mss, addr)
+
+
+    b = mRAX[instr.mode][:size]
+
+    e0 = []
+    e0.append(m2_expr.ExprAssign(addr_o, addr_p))
+    e0.append(m2_expr.ExprAssign(ir.IRDst, loc_next_expr))
+    e0 = IRBlock(ir.loc_db, loc_df_0, [AssignBlock(e0, instr)])
+
+    e1 = []
+    e1.append(m2_expr.ExprAssign(addr_o, addr_m))
+    e1.append(m2_expr.ExprAssign(ir.IRDst, loc_next_expr))
+    e1 = IRBlock(ir.loc_db, loc_df_1, [AssignBlock(e1, instr)])
+
+    e = []
+    if instr.mode == 64 and b.size == 32:
+        e.append(m2_expr.ExprAssign(mRAX[instr.mode],
+                                 ir.ExprMem(addr, size).zeroExtend(64)))
+    else:
+        e.append(m2_expr.ExprAssign(b, ir.ExprMem(addr, size)))
+
+    e.append(m2_expr.ExprAssign(ir.IRDst,
+                             m2_expr.ExprCond(df, loc_df_1_expr, loc_df_0_expr)))
+    return e, [e0, e1]
+
+
+def movs(ir, instr, size):
+    loc_df_0, loc_df_0_expr = ir.gen_loc_key_and_expr(ir.IRDst.size)
+    loc_df_1, loc_df_1_expr = ir.gen_loc_key_and_expr(ir.IRDst.size)
+    loc_next_expr = m2_expr.ExprLoc(ir.get_next_loc_key(instr), ir.IRDst.size)
+
+    dst = mRDI[instr.mode][:instr.v_admode()]
+    src = mRSI[instr.mode][:instr.v_admode()]
+
+    e = []
+    if ir.do_str_segm:
+        if instr.additional_info.g2.value:
+            raise NotImplementedError("add segm support")
+        src_sgm = ir.gen_segm_expr(DS, src)
+        dst_sgm = ir.gen_segm_expr(ES, dst)
+
+    else:
+        src_sgm = src
+        dst_sgm = dst
+
+    offset = m2_expr.ExprInt(size // 8, src.size)
+
+    e.append(m2_expr.ExprAssign(ir.ExprMem(dst_sgm, size),
+                             ir.ExprMem(src_sgm, size)))
+
+    e0 = []
+    e0.append(m2_expr.ExprAssign(src, src + offset))
+    e0.append(m2_expr.ExprAssign(dst, dst + offset))
+    e0.append(m2_expr.ExprAssign(ir.IRDst, loc_next_expr))
+    e0 = IRBlock(ir.loc_db, loc_df_0, [AssignBlock(e0, instr)])
+
+    e1 = []
+    e1.append(m2_expr.ExprAssign(src, src - offset))
+    e1.append(m2_expr.ExprAssign(dst, dst - offset))
+    e1.append(m2_expr.ExprAssign(ir.IRDst, loc_next_expr))
+    e1 = IRBlock(ir.loc_db, loc_df_1, [AssignBlock(e1, instr)])
+
+    e.append(m2_expr.ExprAssign(ir.IRDst,
+                             m2_expr.ExprCond(df, loc_df_1_expr, loc_df_0_expr)))
+    return e, [e0, e1]
+
+
+def movsd(_, instr, dst, src):
+    # 64 bits access
+    if dst.is_id() and src.is_id():
+        src = src[:64]
+        dst = dst[:64]
+    elif dst.is_mem() and src.is_id():
+        dst = m2_expr.ExprMem(dst.ptr, 64)
+        src = src[:64]
+    else:
+        src = m2_expr.ExprMem(src.ptr, 64)
+        # Erase dst high bits
+        src = src.zeroExtend(dst.size)
+    return [m2_expr.ExprAssign(dst, src)], []
+
+
+def movsd_dispatch(ir, instr, dst=None, src=None):
+    if dst is None and src is None:
+        return movs(ir, instr, 32)
+    else:
+        return movsd(ir, instr, dst, src)
+
+
+def float_prev(flt, popcount=1):
+    if not flt in float_list:
+        return None
+    i = float_list.index(flt)
+    if i < popcount:
+        # Drop value (ex: FSTP ST(0))
+        return None
+    flt = float_list[i - popcount]
+    return flt
+
+
+def float_pop(avoid_flt=None, popcount=1):
+    """
+    Generate floatpop semantic (@popcount times), avoiding the avoid_flt@ float
+    @avoid_flt: float avoided in the generated semantic
+    @popcount: pop count
+    """
+    avoid_flt = float_prev(avoid_flt, popcount)
+    e = []
+    for i in range(8 - popcount):
+        if avoid_flt != float_list[i]:
+            e.append(m2_expr.ExprAssign(float_list[i],
+                                     float_list[i + popcount]))
+    fill_value = m2_expr.ExprOp("sint_to_fp", m2_expr.ExprInt(0, 64))
+    for i in range(8 - popcount, 8):
+        e.append(m2_expr.ExprAssign(float_list[i],
+                                 fill_value))
+    e.append(
+        m2_expr.ExprAssign(float_stack_ptr,
+                        float_stack_ptr - m2_expr.ExprInt(popcount, 3)))
+    return e
+
+# XXX TODO
+
+
+def fcom(_, instr, dst=None, src=None):
+
+    if dst is None and src is None:
+        dst, src = float_st0, float_st1
+    elif src is None:
+        src = mem2double(instr, dst)
+        dst = float_st0
+
+    e = []
+
+    e.append(m2_expr.ExprAssign(float_c0, m2_expr.ExprOp('fcom_c0', dst, src)))
+    e.append(m2_expr.ExprAssign(float_c1, m2_expr.ExprOp('fcom_c1', dst, src)))
+    e.append(m2_expr.ExprAssign(float_c2, m2_expr.ExprOp('fcom_c2', dst, src)))
+    e.append(m2_expr.ExprAssign(float_c3, m2_expr.ExprOp('fcom_c3', dst, src)))
+
+    e += set_float_cs_eip(instr)
+    return e, []
+
+
+def ftst(_, instr):
+    dst = float_st0
+
+    e = []
+    src = m2_expr.ExprOp('sint_to_fp', m2_expr.ExprInt(0, 64))
+    e.append(m2_expr.ExprAssign(float_c0, m2_expr.ExprOp('fcom_c0', dst, src)))
+    e.append(m2_expr.ExprAssign(float_c1, m2_expr.ExprOp('fcom_c1', dst, src)))
+    e.append(m2_expr.ExprAssign(float_c2, m2_expr.ExprOp('fcom_c2', dst, src)))
+    e.append(m2_expr.ExprAssign(float_c3, m2_expr.ExprOp('fcom_c3', dst, src)))
+
+    e += set_float_cs_eip(instr)
+    return e, []
+
+
+def fxam(ir, instr):
+    """
+    NaN:
+        C3, C2, C0 = 001;
+    Normal:
+        C3, C2, C0 = 010;
+    Infinity:
+        C3, C2, C0 = 011;
+    Zero:
+        C3, C2, C0 = 100;
+    Empty:
+        C3, C2, C0 = 101;
+    Denormal:
+        C3, C2, C0 = 110;
+
+    C1 = sign bit of ST; (* 0 for positive, 1 for negative *)
+    """
+    dst = float_st0
+
+    # Empty not handled
+    locs = {}
+    for name in ["NaN", "Normal", "Infinity", "Zero", "Denormal"]:
+        locs[name] = ir.gen_loc_key_and_expr(ir.IRDst.size)
+    loc_next = ir.get_next_loc_key(instr)
+    loc_next_expr = m2_expr.ExprLoc(loc_next, ir.IRDst.size)
+
+    # if Denormal:
+    #     if zero:
+    #         do_zero
+    #     else:
+    #         do_denormal
+    # else:
+    #     if Nan:
+    #         do_nan
+    #     else:
+    #         if infinity:
+    #             do_infinity
+    #         else:
+    #             do_normal
+
+    irdst = m2_expr.ExprCond(
+        m2_expr.expr_is_IEEE754_denormal(dst),
+        m2_expr.ExprCond(m2_expr.expr_is_IEEE754_zero(dst),
+                 locs["Zero"][1],
+                 locs["Denormal"][1],
+        ),
+        m2_expr.ExprCond(m2_expr.expr_is_NaN(dst),
+                 locs["NaN"][1],
+                 m2_expr.ExprCond(m2_expr.expr_is_infinite(dst),
+                          locs["Infinity"][1],
+                          locs["Normal"][1],
+                 )
+        )
+    )
+    base = [m2_expr.ExprAssign(ir.IRDst, irdst),
+         m2_expr.ExprAssign(float_c1, dst.msb())
+    ]
+    base += set_float_cs_eip(instr)
+
+    out = [
+        IRBlock(ir.loc_db, locs["Zero"][0], [AssignBlock({
+            float_c0: m2_expr.ExprInt(0, float_c0.size),
+            float_c2: m2_expr.ExprInt(0, float_c2.size),
+            float_c3: m2_expr.ExprInt(1, float_c3.size),
+            ir.IRDst: loc_next_expr,
+        }, instr)]),
+        IRBlock(ir.loc_db, locs["Denormal"][0], [AssignBlock({
+            float_c0: m2_expr.ExprInt(0, float_c0.size),
+            float_c2: m2_expr.ExprInt(1, float_c2.size),
+            float_c3: m2_expr.ExprInt(1, float_c3.size),
+            ir.IRDst: loc_next_expr,
+        }, instr)]),
+        IRBlock(ir.loc_db, locs["NaN"][0], [AssignBlock({
+            float_c0: m2_expr.ExprInt(1, float_c0.size),
+            float_c2: m2_expr.ExprInt(0, float_c2.size),
+            float_c3: m2_expr.ExprInt(0, float_c3.size),
+            ir.IRDst: loc_next_expr,
+        }, instr)]),
+        IRBlock(ir.loc_db, locs["Infinity"][0], [AssignBlock({
+            float_c0: m2_expr.ExprInt(1, float_c0.size),
+            float_c2: m2_expr.ExprInt(1, float_c2.size),
+            float_c3: m2_expr.ExprInt(0, float_c3.size),
+            ir.IRDst: loc_next_expr,
+        }, instr)]),
+        IRBlock(ir.loc_db, locs["Normal"][0], [AssignBlock({
+            float_c0: m2_expr.ExprInt(0, float_c0.size),
+            float_c2: m2_expr.ExprInt(1, float_c2.size),
+            float_c3: m2_expr.ExprInt(0, float_c3.size),
+            ir.IRDst: loc_next_expr,
+        }, instr)]),
+    ]
+    return base, out
+
+
+def ficom(_, instr, dst, src=None):
+
+    dst, src = float_implicit_st0(dst, src)
+
+    e = []
+
+    e.append(m2_expr.ExprAssign(float_c0,
+                             m2_expr.ExprOp('fcom_c0', dst,
+                                            src.zeroExtend(dst.size))))
+    e.append(m2_expr.ExprAssign(float_c1,
+                             m2_expr.ExprOp('fcom_c1', dst,
+                                            src.zeroExtend(dst.size))))
+    e.append(m2_expr.ExprAssign(float_c2,
+                             m2_expr.ExprOp('fcom_c2', dst,
+                                            src.zeroExtend(dst.size))))
+    e.append(m2_expr.ExprAssign(float_c3,
+                             m2_expr.ExprOp('fcom_c3', dst,
+                                            src.zeroExtend(dst.size))))
+
+    e += set_float_cs_eip(instr)
+    return e, []
+
+
+def fcomi(_, instr, dst=None, src=None):
+    # TODO unordered float
+    if dst is None and src is None:
+        dst, src = float_st0, float_st1
+    elif src is None:
+        src = dst
+        dst = float_st0
+
+    e = []
+
+    e.append(m2_expr.ExprAssign(cf, m2_expr.ExprOp('fcom_c0', dst, src)))
+    e.append(m2_expr.ExprAssign(pf, m2_expr.ExprOp('fcom_c2', dst, src)))
+    e.append(m2_expr.ExprAssign(zf, m2_expr.ExprOp('fcom_c3', dst, src)))
+
+    e.append(m2_expr.ExprAssign(of, m2_expr.ExprInt(0, 1)))
+    e.append(m2_expr.ExprAssign(nf, m2_expr.ExprInt(0, 1)))
+    e.append(m2_expr.ExprAssign(af, m2_expr.ExprInt(0, 1)))
+
+    e += set_float_cs_eip(instr)
+    return e, []
+
+
+def fcomip(ir, instr, dst=None, src=None):
+    e, extra = fcomi(ir, instr, dst, src)
+    e += float_pop()
+    e += set_float_cs_eip(instr)
+    return e, extra
+
+
+def fucomi(ir, instr, dst=None, src=None):
+    # TODO unordered float
+    return fcomi(ir, instr, dst, src)
+
+
+def fucomip(ir, instr, dst=None, src=None):
+    # TODO unordered float
+    return fcomip(ir, instr, dst, src)
+
+
+def fcomp(ir, instr, dst=None, src=None):
+    e, extra = fcom(ir, instr, dst, src)
+    e += float_pop()
+    e += set_float_cs_eip(instr)
+    return e, extra
+
+
+def fcompp(ir, instr, dst=None, src=None):
+    e, extra = fcom(ir, instr, dst, src)
+    e += float_pop(popcount=2)
+    e += set_float_cs_eip(instr)
+    return e, extra
+
+
+def ficomp(ir, instr, dst, src=None):
+    e, extra = ficom(ir, instr, dst, src)
+    e += float_pop()
+    e += set_float_cs_eip(instr)
+    return e, extra
+
+
+def fucom(ir, instr, dst=None, src=None):
+    # TODO unordered float
+    return fcom(ir, instr, dst, src)
+
+
+def fucomp(ir, instr, dst=None, src=None):
+    # TODO unordered float
+    return fcomp(ir, instr, dst, src)
+
+
+def fucompp(ir, instr, dst=None, src=None):
+    # TODO unordered float
+    return fcompp(ir, instr, dst, src)
+
+
+def comiss(_, instr, dst, src):
+    # TODO unordered float
+
+    e = []
+
+    dst = m2_expr.ExprOp('sint_to_fp', dst[:32])
+    src = m2_expr.ExprOp('sint_to_fp', src[:32])
+
+    e.append(m2_expr.ExprAssign(cf, m2_expr.ExprOp('fcom_c0', dst, src)))
+    e.append(m2_expr.ExprAssign(pf, m2_expr.ExprOp('fcom_c2', dst, src)))
+    e.append(m2_expr.ExprAssign(zf, m2_expr.ExprOp('fcom_c3', dst, src)))
+
+    e.append(m2_expr.ExprAssign(of, m2_expr.ExprInt(0, 1)))
+    e.append(m2_expr.ExprAssign(nf, m2_expr.ExprInt(0, 1)))
+    e.append(m2_expr.ExprAssign(af, m2_expr.ExprInt(0, 1)))
+
+    e += set_float_cs_eip(instr)
+    return e, []
+
+
+def comisd(_, instr, dst, src):
+    # TODO unordered float
+
+    e = []
+
+    dst = m2_expr.ExprOp('sint_to_fp', dst[:64])
+    src = m2_expr.ExprOp('sint_to_fp', src[:64])
+
+    e.append(m2_expr.ExprAssign(cf, m2_expr.ExprOp('fcom_c0', dst, src)))
+    e.append(m2_expr.ExprAssign(pf, m2_expr.ExprOp('fcom_c2', dst, src)))
+    e.append(m2_expr.ExprAssign(zf, m2_expr.ExprOp('fcom_c3', dst, src)))
+
+    e.append(m2_expr.ExprAssign(of, m2_expr.ExprInt(0, 1)))
+    e.append(m2_expr.ExprAssign(nf, m2_expr.ExprInt(0, 1)))
+    e.append(m2_expr.ExprAssign(af, m2_expr.ExprInt(0, 1)))
+
+    e += set_float_cs_eip(instr)
+    return e, []
+
+
+def fld(_, instr, src):
+
+    if src.size == 32:
+        src = m2_expr.ExprOp("fpconvert_fp64", src)
+    if isinstance(src, m2_expr.ExprMem) and src.size > 64:
+        raise NotImplementedError('convert from 80bits')
+
+    e = []
+    e.append(m2_expr.ExprAssign(float_st7, float_st6))
+    e.append(m2_expr.ExprAssign(float_st6, float_st5))
+    e.append(m2_expr.ExprAssign(float_st5, float_st4))
+    e.append(m2_expr.ExprAssign(float_st4, float_st3))
+    e.append(m2_expr.ExprAssign(float_st3, float_st2))
+    e.append(m2_expr.ExprAssign(float_st2, float_st1))
+    e.append(m2_expr.ExprAssign(float_st1, float_st0))
+    e.append(m2_expr.ExprAssign(float_st0, src))
+    e.append(
+        m2_expr.ExprAssign(float_stack_ptr,
+                        float_stack_ptr + m2_expr.ExprInt(1, 3)))
+
+    e += set_float_cs_eip(instr)
+    return e, []
+
+
+def fst(_, instr, dst):
+    e = []
+
+    if isinstance(dst, m2_expr.ExprMem) and dst.size > 64:
+        raise NotImplementedError('convert to 80bits')
+    src = float_st0
+
+    if dst.size == 32:
+        src = m2_expr.ExprOp("fpconvert_fp32", src)
+    e.append(m2_expr.ExprAssign(dst, src))
+    e += set_float_cs_eip(instr)
+    return e, []
+
+
+def fstp(ir, instr, dst):
+    e = []
+
+    if isinstance(dst, m2_expr.ExprMem) and dst.size > 64:
+        raise NotImplementedError('convert to 80bits')
+
+    if isinstance(dst, m2_expr.ExprMem):
+        src = float_st0
+        if dst.size == 32:
+            src = m2_expr.ExprOp("fpconvert_fp32", src)
+        e.append(m2_expr.ExprAssign(dst, src))
+    else:
+        src = float_st0
+        if float_list.index(dst) > 1:
+            # a = st0 -> st0 is dropped
+            # a = st1 -> st0 = st0, useless
+            e.append(m2_expr.ExprAssign(float_prev(dst), src))
+
+    e += set_float_cs_eip(instr)
+    e += float_pop(dst)
+    return e, []
+
+
+def fist(_, instr, dst):
+    e = []
+    e.append(m2_expr.ExprAssign(dst, m2_expr.ExprOp('fp_to_sint%d' % dst.size,
+                                                 float_st0)))
+
+    e += set_float_cs_eip(instr)
+    return e, []
+
+
+def fistp(ir, instr, dst):
+    e, extra = fist(ir, instr, dst)
+    e += float_pop(dst)
+    return e, extra
+
+
+def fisttp(_, instr, dst):
+    e = []
+    e.append(m2_expr.ExprAssign(
+        dst,
+        m2_expr.ExprOp('fp_to_sint%d' % dst.size,
+                       m2_expr.ExprOp('fpround_towardszero', float_st0)
+        )))
+
+    e += set_float_cs_eip(instr)
+    e += float_pop(dst)
+    return e, []
+
+
+def fild(ir, instr, src):
+    # XXXXX
+    src = m2_expr.ExprOp('sint_to_fp', src.signExtend(64))
+    e = []
+    e += set_float_cs_eip(instr)
+    e_fld, extra = fld(ir, instr, src)
+    e += e_fld
+    return e, extra
+
+
+def fldz(ir, instr):
+    return fld(ir, instr, m2_expr.ExprOp('sint_to_fp', m2_expr.ExprInt(0, 64)))
+
+
+def fld1(ir, instr):
+    return fld(ir, instr, m2_expr.ExprOp('sint_to_fp', m2_expr.ExprInt(1, 64)))
+
+
+def fldl2t(ir, instr):
+    value_f = math.log(10) / math.log(2)
+    value = struct.unpack('Q', struct.pack('d', value_f))[0]
+    return fld(ir, instr, m2_expr.ExprOp(
+        'sint_to_fp',
+        m2_expr.ExprInt(value, 64)
+    ))
+
+
+def fldpi(ir, instr):
+    value_f = math.pi
+    value = struct.unpack('Q', struct.pack('d', value_f))[0]
+    return fld(ir, instr, m2_expr.ExprOp(
+        'sint_to_fp',
+        m2_expr.ExprInt(value, 64)
+    ))
+
+
+def fldln2(ir, instr):
+    value_f = math.log(2)
+    value = struct.unpack('Q', struct.pack('d', value_f))[0]
+    return fld(ir, instr, m2_expr.ExprOp('mem_64_to_double',
+                                         m2_expr.ExprInt(value, 64)))
+
+
+def fldl2e(ir, instr):
+    x = struct.pack('d', 1 / math.log(2))
+    x = struct.unpack('Q', x)[0]
+    return fld(ir, instr, m2_expr.ExprOp('mem_64_to_double',
+                                         m2_expr.ExprInt(x, 64)))
+
+
+def fldlg2(ir, instr):
+    x = struct.pack('d', math.log10(2))
+    x = struct.unpack('Q', x)[0]
+    return fld(ir, instr, m2_expr.ExprOp('mem_64_to_double',
+                                         m2_expr.ExprInt(x, 64)))
+
+
+def fadd(_, instr, dst, src=None):
+    dst, src = float_implicit_st0(dst, src)
+    e = []
+    src = mem2double(instr, src)
+    e.append(m2_expr.ExprAssign(dst, m2_expr.ExprOp('fadd', dst, src)))
+
+    e += set_float_cs_eip(instr)
+    return e, []
+
+
+def fiadd(_, instr, dst, src=None):
+    dst, src = float_implicit_st0(dst, src)
+    e = []
+    src = mem2double(instr, src)
+    e.append(m2_expr.ExprAssign(dst, m2_expr.ExprOp('fiadd', dst, src)))
+    e += set_float_cs_eip(instr)
+    return e, []
+
+
+def fisub(_, instr, dst, src=None):
+    dst, src = float_implicit_st0(dst, src)
+    e = []
+    src = mem2double(instr, src)
+    e.append(m2_expr.ExprAssign(dst, m2_expr.ExprOp('fisub', dst, src)))
+    e += set_float_cs_eip(instr)
+    return e, []
+
+
+def fisubr(_, instr, dst, src=None):
+    dst, src = float_implicit_st0(dst, src)
+    e = []
+    src = mem2double(instr, src)
+    e.append(m2_expr.ExprAssign(dst, m2_expr.ExprOp('fisub', src, dst)))
+    e += set_float_cs_eip(instr)
+    return e, []
+
+
+def fpatan(_, instr):
+    e = []
+    a = float_st1
+    e.append(m2_expr.ExprAssign(float_prev(a),
+                             m2_expr.ExprOp('fpatan', float_st0, float_st1)))
+    e += set_float_cs_eip(instr)
+    e += float_pop(a)
+    return e, []
+
+
+def fprem(_, instr):
+    e = []
+    e.append(
+        m2_expr.ExprAssign(float_st0, m2_expr.ExprOp('fprem', float_st0, float_st1)))
+    # Remaining bits (ex: used in argument reduction in tan)
+    quotient = m2_expr.ExprOp('fp_to_sint32', m2_expr.ExprOp('fpround_towardszero', m2_expr.ExprOp('fdiv', float_st0, float_st1)))
+    e += [m2_expr.ExprAssign(float_c0, quotient[2:3]),
+          m2_expr.ExprAssign(float_c3, quotient[1:2]),
+          m2_expr.ExprAssign(float_c1, quotient[0:1]),
+          # Consider the reduction is always completed
+          m2_expr.ExprAssign(float_c2, m2_expr.ExprInt(0, 1)),
+          ]
+    e += set_float_cs_eip(instr)
+    return e, []
+
+
+def fprem1(_, instr):
+    e = []
+    e.append(
+        m2_expr.ExprAssign(float_st0, m2_expr.ExprOp('fprem1', float_st0, float_st1)))
+    e += set_float_cs_eip(instr)
+    return e, []
+
+
+def faddp(_, instr, dst, src=None):
+    dst, src = float_implicit_st0(dst, src)
+    e = []
+    src = mem2double(instr, src)
+    e.append(m2_expr.ExprAssign(float_prev(dst), m2_expr.ExprOp('fadd', dst, src)))
+    e += set_float_cs_eip(instr)
+    e += float_pop(dst)
+    return e, []
+
+
+def fninit(_, instr):
+    e = []
+    e += set_float_cs_eip(instr)
+    return e, []
+
+
+def fyl2x(_, instr):
+    e = []
+    a = float_st1
+    e.append(
+        m2_expr.ExprAssign(float_prev(a), m2_expr.ExprOp('fyl2x', float_st0, float_st1)))
+    e += set_float_cs_eip(instr)
+    e += float_pop(a)
+    return e, []
+
+
+def fnstenv(ir, instr, dst):
+    e = []
+    # XXX TODO tag word, ...
+    status_word = m2_expr.ExprCompose(m2_expr.ExprInt(0, 8),
+                                      float_c0, float_c1, float_c2,
+                                      float_stack_ptr, float_c3,
+                                      m2_expr.ExprInt(0, 1))
+
+    s = instr.mode
+    # The behaviour in 64bit is identical to 32 bit
+    # This will truncate addresses
+    size = min(32, s)
+    ad = ir.ExprMem(dst.ptr, size=16)
+    e.append(m2_expr.ExprAssign(ad, float_control))
+    ad = ir.ExprMem(
+        dst.ptr + m2_expr.ExprInt(
+            (size // 8) * 1,
+            dst.ptr.size
+        ),
+        size=16
+    )
+    e.append(m2_expr.ExprAssign(ad, status_word))
+    ad = ir.ExprMem(
+        dst.ptr + m2_expr.ExprInt(
+            (size // 8) * 3,
+            dst.ptr.size
+        ),
+        size=size
+    )
+    e.append(m2_expr.ExprAssign(ad, float_eip[:size]))
+    ad = ir.ExprMem(
+        dst.ptr + m2_expr.ExprInt(
+            (size // 8) * 4,
+            dst.ptr.size
+        ),
+        size=16
+    )
+    e.append(m2_expr.ExprAssign(ad, float_cs))
+    ad = ir.ExprMem(
+        dst.ptr + m2_expr.ExprInt(
+            (size // 8) * 5,
+            dst.ptr.size
+        ),
+        size=size
+    )
+    e.append(m2_expr.ExprAssign(ad, float_address[:size]))
+    ad = ir.ExprMem(
+        dst.ptr + m2_expr.ExprInt(
+            (size // 8) * 6,
+            dst.ptr.size
+        ),
+        size=16
+    )
+    e.append(m2_expr.ExprAssign(ad, float_ds))
+    return e, []
+
+
+def fldenv(ir, instr, src):
+    e = []
+    # Inspired from fnstenv (same TODOs / issues)
+
+    s = instr.mode
+    # The behaviour in 64bit is identical to 32 bit
+    # This will truncate addresses
+    size = min(32, s)
+
+    # Float control
+    ad = ir.ExprMem(src.ptr, size=16)
+    e.append(m2_expr.ExprAssign(float_control, ad))
+
+    # Status word
+    ad = ir.ExprMem(
+        src.ptr + m2_expr.ExprInt(
+            size // (8 * 1),
+            size=src.ptr.size
+        ),
+        size=16
+    )
+    e += [
+        m2_expr.ExprAssign(x, y) for x, y in ((float_c0, ad[8:9]),
+                                              (float_c1, ad[9:10]),
+                                              (float_c2, ad[10:11]),
+                                              (float_stack_ptr, ad[11:14]),
+                                              (float_c3, ad[14:15]))
+    ]
+
+    # EIP, CS, Address, DS
+    for offset, target in (
+            (3, float_eip[:size]),
+            (4, float_cs),
+            (5, float_address[:size]),
+            (6, float_ds)
+    ):
+        ad = ir.ExprMem(
+            src.ptr + m2_expr.ExprInt(
+                size // ( 8 * offset),
+                size=src.ptr.size
+            ),
+            size=target.size
+        )
+        e.append(m2_expr.ExprAssign(target, ad))
+
+    return e, []
+
+
+def fsub(_, instr, dst, src=None):
+    dst, src = float_implicit_st0(dst, src)
+    e = []
+    src = mem2double(instr, src)
+    e.append(m2_expr.ExprAssign(dst, m2_expr.ExprOp('fsub', dst, src)))
+    e += set_float_cs_eip(instr)
+    return e, []
+
+
+def fsubp(_, instr, dst, src=None):
+    dst, src = float_implicit_st0(dst, src)
+    e = []
+    src = mem2double(instr, src)
+    e.append(m2_expr.ExprAssign(float_prev(dst), m2_expr.ExprOp('fsub', dst, src)))
+    e += set_float_cs_eip(instr)
+    e += float_pop(dst)
+    return e, []
+
+
+def fsubr(_, instr, dst, src=None):
+    dst, src = float_implicit_st0(dst, src)
+    e = []
+    src = mem2double(instr, src)
+    e.append(m2_expr.ExprAssign(dst, m2_expr.ExprOp('fsub', src, dst)))
+    e += set_float_cs_eip(instr)
+    return e, []
+
+
+def fsubrp(_, instr, dst, src=None):
+    dst, src = float_implicit_st0(dst, src)
+    e = []
+    src = mem2double(instr, src)
+    e.append(m2_expr.ExprAssign(float_prev(dst), m2_expr.ExprOp('fsub', src, dst)))
+    e += set_float_cs_eip(instr)
+    e += float_pop(dst)
+    return e, []
+
+
+def fmul(_, instr, dst, src=None):
+    dst, src = float_implicit_st0(dst, src)
+    e = []
+    src = mem2double(instr, src)
+    e.append(m2_expr.ExprAssign(dst, m2_expr.ExprOp('fmul', dst, src)))
+    e += set_float_cs_eip(instr)
+    return e, []
+
+
+def fimul(_, instr, dst, src=None):
+    dst, src = float_implicit_st0(dst, src)
+    e = []
+    src = mem2double(instr, src)
+    e.append(m2_expr.ExprAssign(dst, m2_expr.ExprOp('fimul', dst, src)))
+    e += set_float_cs_eip(instr)
+    return e, []
+
+
+def fdiv(_, instr, dst, src=None):
+    dst, src = float_implicit_st0(dst, src)
+    e = []
+    src = mem2double(instr, src)
+    e.append(m2_expr.ExprAssign(dst, m2_expr.ExprOp('fdiv', dst, src)))
+    e += set_float_cs_eip(instr)
+    return e, []
+
+
+def fdivr(_, instr, dst, src=None):
+    dst, src = float_implicit_st0(dst, src)
+    e = []
+    src = mem2double(instr, src)
+    e.append(m2_expr.ExprAssign(dst, m2_expr.ExprOp('fdiv', src, dst)))
+    e += set_float_cs_eip(instr)
+    return e, []
+
+
+def fdivrp(_, instr, dst, src=None):
+    dst, src = float_implicit_st0(dst, src)
+    e = []
+    src = mem2double(instr, src)
+    e.append(m2_expr.ExprAssign(float_prev(dst), m2_expr.ExprOp('fdiv', src, dst)))
+    e += set_float_cs_eip(instr)
+    e += float_pop(dst)
+    return e, []
+
+
+def fidiv(_, instr, dst, src=None):
+    dst, src = float_implicit_st0(dst, src)
+    e = []
+    src = mem2double(instr, src)
+    e.append(m2_expr.ExprAssign(dst, m2_expr.ExprOp('fidiv', dst, src)))
+    e += set_float_cs_eip(instr)
+    return e, []
+
+
+def fidivr(_, instr, dst, src=None):
+    dst, src = float_implicit_st0(dst, src)
+    e = []
+    src = mem2double(instr, src)
+    e.append(m2_expr.ExprAssign(dst, m2_expr.ExprOp('fidiv', src, dst)))
+    e += set_float_cs_eip(instr)
+    return e, []
+
+
+def fdivp(_, instr, dst, src=None):
+    # Invalid emulation
+    dst, src = float_implicit_st0(dst, src)
+    e = []
+    src = mem2double(instr, src)
+    e.append(m2_expr.ExprAssign(float_prev(dst), m2_expr.ExprOp('fdiv', dst, src)))
+    e += set_float_cs_eip(instr)
+    e += float_pop(dst)
+    return e, []
+
+
+def fmulp(_, instr, dst, src=None):
+    # Invalid emulation
+    dst, src = float_implicit_st0(dst, src)
+    e = []
+    src = mem2double(instr, src)
+    e.append(m2_expr.ExprAssign(float_prev(dst), m2_expr.ExprOp('fmul', dst, src)))
+    e += set_float_cs_eip(instr)
+    e += float_pop(dst)
+    return e, []
+
+
+def ftan(_, instr, src):
+    e = []
+    src = mem2double(instr, src)
+    e.append(m2_expr.ExprAssign(float_st0, m2_expr.ExprOp('ftan', src)))
+    e += set_float_cs_eip(instr)
+    return e, []
+
+
+def fxch(_, instr, src):
+    e = []
+    src = mem2double(instr, src)
+    e.append(m2_expr.ExprAssign(float_st0, src))
+    e.append(m2_expr.ExprAssign(src, float_st0))
+    e += set_float_cs_eip(instr)
+    return e, []
+
+
+def fptan(_, instr):
+    e = []
+    e.append(m2_expr.ExprAssign(float_st7, float_st6))
+    e.append(m2_expr.ExprAssign(float_st6, float_st5))
+    e.append(m2_expr.ExprAssign(float_st5, float_st4))
+    e.append(m2_expr.ExprAssign(float_st4, float_st3))
+    e.append(m2_expr.ExprAssign(float_st3, float_st2))
+    e.append(m2_expr.ExprAssign(float_st2, float_st1))
+    e.append(m2_expr.ExprAssign(float_st1, m2_expr.ExprOp('ftan', float_st0)))
+    e.append(
+        m2_expr.ExprAssign(
+            float_st0,
+            m2_expr.ExprOp(
+                'sint_to_fp',
+                m2_expr.ExprInt(1, 64)
+            )
+        )
+    )
+    e.append(
+        m2_expr.ExprAssign(float_stack_ptr,
+                        float_stack_ptr + m2_expr.ExprInt(1, 3)))
+    return e, []
+
+
+def frndint(_, instr):
+    e = []
+    e.append(m2_expr.ExprAssign(float_st0, m2_expr.ExprOp('frndint', float_st0)))
+    e += set_float_cs_eip(instr)
+    return e, []
+
+
+def fsin(_, instr):
+    e = []
+    e.append(m2_expr.ExprAssign(float_st0, m2_expr.ExprOp('fsin', float_st0)))
+    e += set_float_cs_eip(instr)
+    return e, []
+
+
+def fcos(_, instr):
+    e = []
+    e.append(m2_expr.ExprAssign(float_st0, m2_expr.ExprOp('fcos', float_st0)))
+    e += set_float_cs_eip(instr)
+    return e, []
+
+
+def fsincos(_, instr):
+    e = []
+    e.append(m2_expr.ExprAssign(float_st7, float_st6))
+    e.append(m2_expr.ExprAssign(float_st6, float_st5))
+    e.append(m2_expr.ExprAssign(float_st5, float_st4))
+    e.append(m2_expr.ExprAssign(float_st4, float_st3))
+    e.append(m2_expr.ExprAssign(float_st3, float_st2))
+    e.append(m2_expr.ExprAssign(float_st2, float_st1))
+    e.append(m2_expr.ExprAssign(float_st1, m2_expr.ExprOp('fsin', float_st0)))
+    e.append(m2_expr.ExprAssign(float_st0, m2_expr.ExprOp('fcos', float_st0)))
+    e.append(
+        m2_expr.ExprAssign(float_stack_ptr,
+                        float_stack_ptr + m2_expr.ExprInt(1, 3)))
+    return e, []
+
+
+def fscale(_, instr):
+    e = []
+    e.append(m2_expr.ExprAssign(float_st0, m2_expr.ExprOp('fscale', float_st0,
+                                                       float_st1)))
+    e += set_float_cs_eip(instr)
+    return e, []
+
+
+def f2xm1(_, instr):
+    e = []
+    e.append(m2_expr.ExprAssign(float_st0, m2_expr.ExprOp('f2xm1', float_st0)))
+    e += set_float_cs_eip(instr)
+    return e, []
+
+
+def fchs(_, instr):
+    e = []
+    e.append(m2_expr.ExprAssign(float_st0, m2_expr.ExprOp('fchs', float_st0)))
+    e += set_float_cs_eip(instr)
+    return e, []
+
+
+def fsqrt(_, instr):
+    e = []
+    e.append(m2_expr.ExprAssign(float_st0, m2_expr.ExprOp('fsqrt', float_st0)))
+    e += set_float_cs_eip(instr)
+    return e, []
+
+
+def fabs(_, instr):
+    e = []
+    e.append(m2_expr.ExprAssign(float_st0, m2_expr.ExprOp('fabs', float_st0)))
+    e += set_float_cs_eip(instr)
+    return e, []
+
+
+def fnstsw(_, instr, dst):
+    args = [
+        # Exceptions -> 0
+        m2_expr.ExprInt(0, 8),
+        float_c0,
+        float_c1,
+        float_c2,
+        float_stack_ptr,
+        float_c3,
+        # B: FPU is not busy -> 0
+        m2_expr.ExprInt(0, 1)]
+    e = [m2_expr.ExprAssign(dst, m2_expr.ExprCompose(*args))]
+    return e, []
+
+
+def fnstcw(_, instr, dst):
+    e = []
+    e.append(m2_expr.ExprAssign(dst, float_control))
+    return e, []
+
+
+def fldcw(_, instr, src):
+    e = []
+    e.append(m2_expr.ExprAssign(float_control, src))
+    return e, []
+
+
+def fwait(_, instr):
+    return [], []
+
+
+def fcmovb(ir, instr, arg1, arg2):
+    return gen_fcmov(ir, instr, cf, arg1, arg2, True)
+
+
+def fcmove(ir, instr, arg1, arg2):
+    return gen_fcmov(ir, instr, zf, arg1, arg2, True)
+
+
+def fcmovbe(ir, instr, arg1, arg2):
+    return gen_fcmov(ir, instr, cf | zf, arg1, arg2, True)
+
+
+def fcmovu(ir, instr, arg1, arg2):
+    return gen_fcmov(ir, instr, pf, arg1, arg2, True)
+
+
+def fcmovnb(ir, instr, arg1, arg2):
+    return gen_fcmov(ir, instr, cf, arg1, arg2, False)
+
+
+def fcmovne(ir, instr, arg1, arg2):
+    return gen_fcmov(ir, instr, zf, arg1, arg2, False)
+
+
+def fcmovnbe(ir, instr, arg1, arg2):
+    return gen_fcmov(ir, instr, cf | zf, arg1, arg2, False)
+
+
+def fcmovnu(ir, instr, arg1, arg2):
+    return gen_fcmov(ir, instr, pf, arg1, arg2, False)
+
+
+def nop(_, instr, a=None):
+    return [], []
+
+
+def prefetch0(_, instr, src=None):
+    # see 4-198 on this documentation
+    # https://www-ssl.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf
+    return [], []
+
+
+def prefetch1(_, instr, src=None):
+    # see 4-198 on this documentation
+    # https://www-ssl.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf
+    return [], []
+
+
+def prefetch2(_, instr, src=None):
+    # see 4-198 on this documentation
+    # https://www-ssl.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf
+    return [], []
+
+
+def prefetchw(_, instr, src=None):
+    # see 4-201 on this documentation
+    # https://www-ssl.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf
+    return [], []
+
+def prefetchnta(_, instr, src=None):
+    # see 4-201 on this documentation
+    # https://www-ssl.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf
+    return [], []
+
+
+def lfence(_, instr, src=None):
+    # see 3-485 on this documentation
+    # https://www-ssl.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf
+    return [], []
+
+
+def mfence(_, instr, src=None):
+    # see 3-516 on this documentation
+    # https://www-ssl.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf
+    return [], []
+
+
+def sfence(_, instr, src=None):
+    # see 3-356 on this documentation
+    # https://www-ssl.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf
+    return [], []
+
+
+def ud2(_, instr, src=None):
+    e = [m2_expr.ExprAssign(exception_flags, m2_expr.ExprInt(
+        EXCEPT_ILLEGAL_INSN, exception_flags.size))]
+    return e, []
+
+
+def hlt(_, instr):
+    e = []
+    except_int = EXCEPT_PRIV_INSN
+    e.append(m2_expr.ExprAssign(exception_flags, m2_expr.ExprInt(except_int, 32)))
+    return e, []
+
+
+def rdtsc(_, instr):
+    e = []
+    e.append(m2_expr.ExprAssign(tsc, tsc + m2_expr.ExprInt(1, 64)))
+    e.append(m2_expr.ExprAssign(mRAX[32], tsc[:32]))
+    e.append(m2_expr.ExprAssign(mRDX[32], tsc[32:]))
+    return e, []
+
+
+def daa(_, instr):
+    e = []
+    r_al = mRAX[instr.mode][:8]
+
+    cond1 = m2_expr.expr_is_unsigned_greater(r_al[:4], m2_expr.ExprInt(0x9, 4)) | af
+    e.append(m2_expr.ExprAssign(af, cond1))
+
+    cond2 = m2_expr.expr_is_unsigned_greater(m2_expr.ExprInt(6, 8), r_al)
+    cond3 = m2_expr.expr_is_unsigned_greater(r_al, m2_expr.ExprInt(0x99, 8)) | cf
+
+    cf_c1 = m2_expr.ExprCond(cond1,
+                             cf | (cond2),
+                             m2_expr.ExprInt(0, 1))
+    new_cf = m2_expr.ExprCond(cond3,
+                              m2_expr.ExprInt(1, 1),
+                              m2_expr.ExprInt(0, 1))
+    e.append(m2_expr.ExprAssign(cf, new_cf))
+
+    al_c1 = m2_expr.ExprCond(cond1,
+                             r_al + m2_expr.ExprInt(6, 8),
+                             r_al)
+
+    new_al = m2_expr.ExprCond(cond3,
+                              al_c1 + m2_expr.ExprInt(0x60, 8),
+                              al_c1)
+    e.append(m2_expr.ExprAssign(r_al, new_al))
+    e += update_flag_znp(new_al)
+    return e, []
+
+
+def das(_, instr):
+    e = []
+    r_al = mRAX[instr.mode][:8]
+
+    cond1 = m2_expr.expr_is_unsigned_greater(r_al[:4], m2_expr.ExprInt(0x9, 4)) | af
+    e.append(m2_expr.ExprAssign(af, cond1))
+
+    cond2 = m2_expr.expr_is_unsigned_greater(m2_expr.ExprInt(6, 8), r_al)
+    cond3 = m2_expr.expr_is_unsigned_greater(r_al, m2_expr.ExprInt(0x99, 8)) | cf
+
+    cf_c1 = m2_expr.ExprCond(cond1,
+                             cf | (cond2),
+                             m2_expr.ExprInt(0, 1))
+    new_cf = m2_expr.ExprCond(cond3,
+                              m2_expr.ExprInt(1, 1),
+                              cf_c1)
+    e.append(m2_expr.ExprAssign(cf, new_cf))
+
+    al_c1 = m2_expr.ExprCond(cond1,
+                             r_al - m2_expr.ExprInt(6, 8),
+                             r_al)
+
+    new_al = m2_expr.ExprCond(cond3,
+                              al_c1 - m2_expr.ExprInt(0x60, 8),
+                              al_c1)
+    e.append(m2_expr.ExprAssign(r_al, new_al))
+    e += update_flag_znp(new_al)
+    return e, []
+
+
+def aam(ir, instr, src):
+    e = []
+    assert src.is_int()
+
+    value = int(src)
+    if value:
+        tempAL = mRAX[instr.mode][0:8]
+        newEAX = m2_expr.ExprCompose(
+            m2_expr.ExprOp("umod", tempAL, src),
+            m2_expr.ExprOp("udiv", tempAL, src),
+            mRAX[instr.mode][16:]
+        )
+        e += [m2_expr.ExprAssign(mRAX[instr.mode], newEAX)]
+        e += update_flag_arith(newEAX)
+        e.append(m2_expr.ExprAssign(af, m2_expr.ExprInt(0, 1)))
+    else:
+        e.append(
+            m2_expr.ExprAssign(
+                exception_flags,
+                m2_expr.ExprInt(EXCEPT_DIV_BY_ZERO, exception_flags.size)
+            )
+        )
+    return e, []
+
+
+def aad(_, instr, src):
+    e = []
+    tempAL = mRAX[instr.mode][0:8]
+    tempAH = mRAX[instr.mode][8:16]
+    newEAX = m2_expr.ExprCompose((tempAL + (tempAH * src)) & m2_expr.ExprInt(0xFF, 8),
+                                 m2_expr.ExprInt(0, 8),
+                                 mRAX[instr.mode][16:])
+    e += [m2_expr.ExprAssign(mRAX[instr.mode], newEAX)]
+    e += update_flag_arith(newEAX)
+    e.append(m2_expr.ExprAssign(af, m2_expr.ExprInt(0, 1)))
+    return e, []
+
+
+def _tpl_aaa(_, instr, op):
+    """Templating for aaa, aas with operation @op
+    @op: operation to apply
+    """
+    e = []
+    r_al = mRAX[instr.mode][:8]
+    r_ah = mRAX[instr.mode][8:16]
+    r_ax = mRAX[instr.mode][:16]
+    i0 = m2_expr.ExprInt(0, 1)
+    i1 = m2_expr.ExprInt(1, 1)
+    # cond: if (al & 0xf) > 9 OR af == 1
+    cond = (r_al & m2_expr.ExprInt(0xf, 8)) - m2_expr.ExprInt(9, 8)
+    cond = ~cond.msb() & m2_expr.ExprCond(cond, i1, i0)
+    cond |= af & i1
+
+    to_add = m2_expr.ExprInt(0x106, size=r_ax.size)
+    if op == "-":
+        # Avoid ExprOp("-", A, B), should be ExprOp("+", A, ExprOp("-", B))
+        first_part = r_ax - to_add
+    else:
+        first_part = m2_expr.ExprOp(op, r_ax, to_add)
+    new_ax = first_part & m2_expr.ExprInt(0xff0f,
+                                          size=r_ax.size)
+    # set AL
+    e.append(m2_expr.ExprAssign(r_ax, m2_expr.ExprCond(cond, new_ax, r_ax)))
+    e.append(m2_expr.ExprAssign(af, cond))
+    e.append(m2_expr.ExprAssign(cf, cond))
+    return e, []
+
+
+def aaa(ir, instr):
+    return _tpl_aaa(ir, instr, "+")
+
+
+def aas(ir, instr):
+    return _tpl_aaa(ir, instr, "-")
+
+
+def bsr_bsf(ir, instr, dst, src, op_func):
+    """
+    IF SRC == 0
+        ZF = 1
+        DEST is left unchanged
+    ELSE
+        ZF = 0
+        DEST = @op_func(SRC)
+    """
+    loc_src_null, loc_src_null_expr = ir.gen_loc_key_and_expr(ir.IRDst.size)
+    loc_src_not_null, loc_src_not_null_expr = ir.gen_loc_key_and_expr(ir.IRDst.size)
+    loc_next = ir.get_next_loc_key(instr)
+    loc_next_expr = m2_expr.ExprLoc(loc_next, ir.IRDst.size)
+
+    aff_dst = m2_expr.ExprAssign(ir.IRDst, loc_next_expr)
+    e = [m2_expr.ExprAssign(ir.IRDst, m2_expr.ExprCond(src,
+                                                    loc_src_not_null_expr,
+                                                    loc_src_null_expr))]
+    e_src_null = []
+    e_src_null.append(m2_expr.ExprAssign(zf, m2_expr.ExprInt(1, zf.size)))
+    # XXX destination is undefined
+    e_src_null.append(aff_dst)
+
+    e_src_not_null = []
+    e_src_not_null.append(m2_expr.ExprAssign(zf, m2_expr.ExprInt(0, zf.size)))
+    e_src_not_null.append(m2_expr.ExprAssign(dst, op_func(src)))
+    e_src_not_null.append(aff_dst)
+
+    return e, [IRBlock(ir.loc_db, loc_src_null, [AssignBlock(e_src_null, instr)]),
+               IRBlock(ir.loc_db, loc_src_not_null, [AssignBlock(e_src_not_null, instr)])]
+
+
+def bsf(ir, instr, dst, src):
+    return bsr_bsf(ir, instr, dst, src,
+                   lambda src: m2_expr.ExprOp("cnttrailzeros", src))
+
+
+def bsr(ir, instr, dst, src):
+    return bsr_bsf(
+        ir, instr, dst, src,
+        lambda src: m2_expr.ExprInt(src.size - 1, src.size) - m2_expr.ExprOp("cntleadzeros", src)
+    )
+
+
+def arpl(_, instr, dst, src):
+    e = []
+    e.append(m2_expr.ExprAssign(exception_flags, m2_expr.ExprInt(1 << 7, 32)))
+    return e, []
+
+
+def ins(_, instr, size):
+    e = []
+    e.append(m2_expr.ExprAssign(exception_flags, m2_expr.ExprInt(1 << 7, 32)))
+    return e, []
+
+
+def sidt(ir, instr, dst):
+    e = []
+    if not isinstance(dst, m2_expr.ExprMem) or dst.size != 32:
+        raise ValueError('not exprmem 32bit instance!!')
+    ptr = dst.ptr
+    LOG_X86_SEM.warning("DEFAULT SIDT ADDRESS %s!!", dst)
+    e.append(m2_expr.ExprAssign(ir.ExprMem(ptr, 32),
+                             m2_expr.ExprInt(0xe40007ff, 32)))
+    e.append(
+        m2_expr.ExprAssign(ir.ExprMem(ptr + m2_expr.ExprInt(4, ptr.size), 16),
+                        m2_expr.ExprInt(0x8245, 16)))
+    return e, []
+
+
+def sldt(_, instr, dst):
+    LOG_X86_SEM.warning("DEFAULT SLDT ADDRESS %s!!", dst)
+    e = [m2_expr.ExprAssign(dst, m2_expr.ExprInt(0, dst.size))]
+    return e, []
+
+
+def cmovz(ir, instr, dst, src):
+    #return gen_cmov(ir, instr, zf, dst, src, True)
+    return gen_cmov(ir, instr, m2_expr.ExprOp("CC_EQ", zf), dst, src, True)
+
+
+def cmovnz(ir, instr, dst, src):
+    #return gen_cmov(ir, instr, zf, dst, src, False)
+    return gen_cmov(ir, instr, m2_expr.ExprOp("CC_EQ", zf), dst, src, False)
+
+
+def cmovpe(ir, instr, dst, src):
+    return gen_cmov(ir, instr, pf, dst, src, True)
+
+
+def cmovnp(ir, instr, dst, src):
+    return gen_cmov(ir, instr, pf, dst, src, False)
+
+
+def cmovge(ir, instr, dst, src):
+    #return gen_cmov(ir, instr, nf ^ of, dst, src, False)
+    return gen_cmov(ir, instr, m2_expr.ExprOp("CC_S>=", nf, of), dst, src, True)
+
+
+def cmovg(ir, instr, dst, src):
+    #return gen_cmov(ir, instr, zf | (nf ^ of), dst, src, False)
+    return gen_cmov(ir, instr, m2_expr.ExprOp("CC_S>", nf, of, zf), dst, src, True)
+
+
+def cmovl(ir, instr, dst, src):
+    #return gen_cmov(ir, instr, nf ^ of, dst, src, True)
+    return gen_cmov(ir, instr, m2_expr.ExprOp("CC_S<", nf, of), dst, src, True)
+
+
+def cmovle(ir, instr, dst, src):
+    #return gen_cmov(ir, instr, zf | (nf ^ of), dst, src, True)
+    return gen_cmov(ir, instr, m2_expr.ExprOp("CC_S<=", nf, of, zf), dst, src, True)
+
+
+def cmova(ir, instr, dst, src):
+    #return gen_cmov(ir, instr, cf | zf, dst, src, False)
+    return gen_cmov(ir, instr, m2_expr.ExprOp("CC_U>", cf, zf), dst, src, True)
+
+
+def cmovae(ir, instr, dst, src):
+    #return gen_cmov(ir, instr, cf, dst, src, False)
+    return gen_cmov(ir, instr, m2_expr.ExprOp("CC_U>=", cf), dst, src, True)
+
+
+def cmovbe(ir, instr, dst, src):
+    #return gen_cmov(ir, instr, cf | zf, dst, src, True)
+    return gen_cmov(ir, instr, m2_expr.ExprOp("CC_U<=", cf, zf), dst, src, True)
+
+
+def cmovb(ir, instr, dst, src):
+    #return gen_cmov(ir, instr, cf, dst, src, True)
+    return gen_cmov(ir, instr, m2_expr.ExprOp("CC_U<", cf), dst, src, True)
+
+
+def cmovo(ir, instr, dst, src):
+    return gen_cmov(ir, instr, of, dst, src, True)
+
+
+def cmovno(ir, instr, dst, src):
+    return gen_cmov(ir, instr, of, dst, src, False)
+
+
+def cmovs(ir, instr, dst, src):
+    #return gen_cmov(ir, instr, nf, dst, src, True)
+    return gen_cmov(ir, instr, m2_expr.ExprOp("CC_NEG", nf), dst, src, True)
+
+
+def cmovns(ir, instr, dst, src):
+    #return gen_cmov(ir, instr, nf, dst, src, False)
+    return gen_cmov(ir, instr, m2_expr.ExprOp("CC_NEG", nf), dst, src, False)
+
+
+def icebp(_, instr):
+    e = []
+    e.append(m2_expr.ExprAssign(exception_flags,
+                             m2_expr.ExprInt(EXCEPT_SOFT_BP, 32)))
+    return e, []
+# XXX
+
+
+def l_int(_, instr, src):
+    e = []
+    # XXX
+    assert src.is_int()
+    value = int(src)
+    if value == 1:
+        except_int = EXCEPT_INT_1
+    elif value == 3:
+        except_int = EXCEPT_SOFT_BP
+    else:
+        except_int = EXCEPT_INT_XX
+    e.append(m2_expr.ExprAssign(exception_flags,
+                             m2_expr.ExprInt(except_int, 32)))
+    e.append(m2_expr.ExprAssign(interrupt_num, src))
+    return e, []
+
+
+def l_sysenter(_, instr):
+    e = []
+    e.append(m2_expr.ExprAssign(exception_flags,
+                             m2_expr.ExprInt(EXCEPT_PRIV_INSN, 32)))
+    return e, []
+
+
+def l_syscall(_, instr):
+    e = []
+    e.append(m2_expr.ExprAssign(exception_flags,
+                             m2_expr.ExprInt(EXCEPT_SYSCALL, 32)))
+    return e, []
+
+# XXX
+
+
+def l_out(_, instr, src1, src2):
+    e = []
+    e.append(m2_expr.ExprAssign(exception_flags,
+                             m2_expr.ExprInt(EXCEPT_PRIV_INSN, 32)))
+    return e, []
+
+# XXX
+
+
+def l_outs(_, instr, size):
+    e = []
+    e.append(m2_expr.ExprAssign(exception_flags,
+                             m2_expr.ExprInt(EXCEPT_PRIV_INSN, 32)))
+    return e, []
+
+# XXX actually, xlat performs al = (ds:[e]bx + ZeroExtend(al))
+
+
+def xlat(ir, instr):
+    e = []
+    ptr = mRAX[instr.mode][0:8].zeroExtend(mRBX[instr.mode].size)
+    src = ir.ExprMem(mRBX[instr.mode] + ptr, 8)
+    e.append(m2_expr.ExprAssign(mRAX[instr.mode][0:8], src))
+    return e, []
+
+
+def cpuid(_, instr):
+    e = []
+    e.append(
+        m2_expr.ExprAssign(mRAX[instr.mode],
+                        m2_expr.ExprOp('x86_cpuid', mRAX[instr.mode], m2_expr.ExprInt(0, instr.mode))))
+    e.append(
+        m2_expr.ExprAssign(mRBX[instr.mode],
+                        m2_expr.ExprOp('x86_cpuid', mRAX[instr.mode], m2_expr.ExprInt(1, instr.mode))))
+    e.append(
+        m2_expr.ExprAssign(mRCX[instr.mode],
+                        m2_expr.ExprOp('x86_cpuid', mRAX[instr.mode], m2_expr.ExprInt(2, instr.mode))))
+    e.append(
+        m2_expr.ExprAssign(mRDX[instr.mode],
+                        m2_expr.ExprOp('x86_cpuid', mRAX[instr.mode], m2_expr.ExprInt(3, instr.mode))))
+    return e, []
+
+
+def bittest_get(ir, instr, src, index):
+    index = index.zeroExtend(src.size)
+    if isinstance(src, m2_expr.ExprMem):
+        b_mask = {16: 4, 32: 5, 64: 6}
+        b_decal = {16: 1, 32: 3, 64: 7}
+        ptr = src.ptr
+        segm = is_mem_segm(src)
+        if segm:
+            ptr = ptr.args[1]
+
+        off_bit = index.zeroExtend(
+            src.size) & m2_expr.ExprInt((1 << b_mask[src.size]) - 1,
+                                        src.size)
+        off_byte = ((index.zeroExtend(ptr.size) >> m2_expr.ExprInt(3, ptr.size)) &
+                    m2_expr.ExprInt(((1 << src.size) - 1) ^ b_decal[src.size], ptr.size))
+
+        addr = ptr + off_byte
+        if segm:
+            addr = ir.gen_segm_expr(src.ptr.args[0], addr)
+
+        d = ir.ExprMem(addr, src.size)
+    else:
+        off_bit = m2_expr.ExprOp(
+            '&', index, m2_expr.ExprInt(src.size - 1, src.size))
+        d = src
+    return d, off_bit
+
+
+def bt(ir, instr, src, index):
+    e = []
+    index = index.zeroExtend(src.size)
+    d, off_bit = bittest_get(ir, instr, src, index)
+    d = d >> off_bit
+    e.append(m2_expr.ExprAssign(cf, d[:1]))
+    return e, []
+
+
+def btc(ir, instr, src, index):
+    e = []
+    d, off_bit = bittest_get(ir, instr, src, index)
+    e.append(m2_expr.ExprAssign(cf, (d >> off_bit)[:1]))
+
+    m = m2_expr.ExprInt(1, src.size) << off_bit
+    e.append(m2_expr.ExprAssign(d, d ^ m))
+
+    return e, []
+
+
+def bts(ir, instr, src, index):
+    e = []
+    d, off_bit = bittest_get(ir, instr, src, index)
+    e.append(m2_expr.ExprAssign(cf, (d >> off_bit)[:1]))
+    m = m2_expr.ExprInt(1, src.size) << off_bit
+    e.append(m2_expr.ExprAssign(d, d | m))
+
+    return e, []
+
+
+def btr(ir, instr, src, index):
+    e = []
+    d, off_bit = bittest_get(ir, instr, src, index)
+    e.append(m2_expr.ExprAssign(cf, (d >> off_bit)[:1]))
+    m = ~(m2_expr.ExprInt(1, src.size) << off_bit)
+    e.append(m2_expr.ExprAssign(d, d & m))
+
+    return e, []
+
+
+def into(_, instr):
+    return [], []
+
+
+def l_in(_, instr, src1, src2):
+    e = []
+    e.append(m2_expr.ExprAssign(exception_flags,
+                             m2_expr.ExprInt(EXCEPT_PRIV_INSN, 32)))
+    return e, []
+
+
+@sbuild.parse
+def cmpxchg(arg1, arg2):
+    accumulator = mRAX[instr.v_opmode()][:arg1.size]
+    if (accumulator - arg1):
+        zf = i1(0)
+        accumulator = arg1
+    else:
+        zf = i1(1)
+        arg1 = arg2
+
+
+@sbuild.parse
+def cmpxchg8b(arg1):
+    accumulator = {mRAX[32], mRDX[32]}
+    if accumulator - arg1:
+        zf = i1(0)
+        mRAX[32] = arg1[:32]
+        mRDX[32] = arg1[32:]
+    else:
+        zf = i1(1)
+        arg1 = {mRBX[32], mRCX[32]}
+
+
+@sbuild.parse
+def cmpxchg16b(arg1):
+    accumulator = {mRAX[64], mRDX[64]}
+    if accumulator - arg1:
+        zf = i1(0)
+        mRAX[64] = arg1[:64]
+        mRDX[64] = arg1[64:]
+    else:
+        zf = i1(1)
+        arg1 = {mRBX[64], mRCX[64]}
+
+
+def lds(ir, instr, dst, src):
+    e = []
+    e.append(m2_expr.ExprAssign(dst, ir.ExprMem(src.ptr, size=dst.size)))
+    DS_value = ir.ExprMem(src.ptr + m2_expr.ExprInt(dst.size // 8, src.ptr.size),
+                          size=16)
+    e.append(m2_expr.ExprAssign(DS, DS_value))
+    return e, []
+
+
+def les(ir, instr, dst, src):
+    e = []
+    e.append(m2_expr.ExprAssign(dst, ir.ExprMem(src.ptr, size=dst.size)))
+    ES_value = ir.ExprMem(src.ptr + m2_expr.ExprInt(dst.size // 8, src.ptr.size),
+                          size=16)
+    e.append(m2_expr.ExprAssign(ES, ES_value))
+    return e, []
+
+
+def lss(ir, instr, dst, src):
+    e = []
+    e.append(m2_expr.ExprAssign(dst, ir.ExprMem(src.ptr, size=dst.size)))
+    SS_value = ir.ExprMem(src.ptr + m2_expr.ExprInt(dst.size // 8, src.ptr.size),
+                          size=16)
+    e.append(m2_expr.ExprAssign(SS, SS_value))
+    return e, []
+
+
+def lfs(ir, instr, dst, src):
+    e = []
+    e.append(m2_expr.ExprAssign(dst, ir.ExprMem(src.ptr, size=dst.size)))
+    FS_value = ir.ExprMem(src.ptr + m2_expr.ExprInt(dst.size // 8, src.ptr.size),
+                          size=16)
+    e.append(m2_expr.ExprAssign(FS, FS_value))
+    return e, []
+
+
+def lgs(ir, instr, dst, src):
+    e = []
+    e.append(m2_expr.ExprAssign(dst, ir.ExprMem(src.ptr, size=dst.size)))
+    GS_value = ir.ExprMem(src.ptr + m2_expr.ExprInt(dst.size // 8, src.ptr.size),
+                          size=16)
+    e.append(m2_expr.ExprAssign(GS, GS_value))
+    return e, []
+
+
+def lahf(_, instr):
+    e = []
+    args = [cf, m2_expr.ExprInt(1, 1), pf, m2_expr.ExprInt(0, 1), af,
+            m2_expr.ExprInt(0, 1), zf, nf]
+    e.append(
+        m2_expr.ExprAssign(mRAX[instr.mode][8:16], m2_expr.ExprCompose(*args)))
+    return e, []
+
+
+def sahf(_, instr):
+    tmp = mRAX[instr.mode][8:16]
+    e = []
+    e.append(m2_expr.ExprAssign(cf, tmp[0:1]))
+    e.append(m2_expr.ExprAssign(pf, tmp[2:3]))
+    e.append(m2_expr.ExprAssign(af, tmp[4:5]))
+    e.append(m2_expr.ExprAssign(zf, tmp[6:7]))
+    e.append(m2_expr.ExprAssign(nf, tmp[7:8]))
+    return e, []
+
+
+def lar(_, instr, dst, src):
+    e = []
+    e.append(m2_expr.ExprAssign(dst, m2_expr.ExprOp('access_segment', src)))
+    e.append(m2_expr.ExprAssign(zf, m2_expr.ExprOp('access_segment_ok', src)))
+    return e, []
+
+
+def lsl(_, instr, dst, src):
+    e = []
+    e.append(m2_expr.ExprAssign(dst, m2_expr.ExprOp('load_segment_limit', src)))
+    e.append(m2_expr.ExprAssign(zf, m2_expr.ExprOp('load_segment_limit_ok', src)))
+    return e, []
+
+
+def fclex(_, instr):
+    # XXX TODO
+    return [], []
+
+
+def fnclex(_, instr):
+    # XXX TODO
+    return [], []
+
+
+def l_str(_, instr, dst):
+    e = []
+    e.append(m2_expr.ExprAssign(dst, m2_expr.ExprOp('load_tr_segment_selector',
+                                                 m2_expr.ExprInt(0, 32))))
+    return e, []
+
+
+def movd(_, instr, dst, src):
+    e = []
+    if dst in regs_mm_expr:
+        e.append(m2_expr.ExprAssign(
+            dst, m2_expr.ExprCompose(src, m2_expr.ExprInt(0, 32))))
+    elif dst in regs_xmm_expr:
+        e.append(m2_expr.ExprAssign(
+            dst, m2_expr.ExprCompose(src, m2_expr.ExprInt(0, 96))))
+    else:
+        e.append(m2_expr.ExprAssign(dst, src[:32]))
+    return e, []
+
+
+def movdqu(_, instr, dst, src):
+    # XXX TODO alignment check
+    return [m2_expr.ExprAssign(dst, src)], []
+
+
+def movapd(_, instr, dst, src):
+    # XXX TODO alignment check
+    return [m2_expr.ExprAssign(dst, src)], []
+
+
+def andps(_, instr, dst, src):
+    e = []
+    e.append(m2_expr.ExprAssign(dst, m2_expr.ExprOp('&', dst, src)))
+    return e, []
+
+
+def andnps(_, instr, dst, src):
+    e = []
+    e.append(m2_expr.ExprAssign(dst, m2_expr.ExprOp('&', dst ^ dst.mask, src)))
+    return e, []
+
+
+def orps(_, instr, dst, src):
+    e = []
+    e.append(m2_expr.ExprAssign(dst, m2_expr.ExprOp('|', dst, src)))
+    return e, []
+
+
+def xorps(_, instr, dst, src):
+    e = []
+    e.append(m2_expr.ExprAssign(dst, m2_expr.ExprOp('^', dst, src)))
+    return e, []
+
+
+def rdmsr(ir, instr):
+    e = [m2_expr.ExprAssign(exception_flags,m2_expr.ExprInt(EXCEPT_PRIV_INSN, 32))]
+    return e, []
+
+
+def wrmsr(ir, instr):
+    e = [m2_expr.ExprAssign(exception_flags,m2_expr.ExprInt(EXCEPT_PRIV_INSN, 32))]
+    return e, []
+
+# MMX/SSE/AVX operations
+#
+
+def vec_op_clip(op, size, callback=None):
+    """
+    Generate simd operations
+    @op: the operator
+    @size: size of an element
+    """
+    def vec_op_clip_instr(ir, instr, dst, src):
+        if op == '-':
+            result = dst[:size] - src[:size]
+        else:
+            result = m2_expr.ExprOp(op, dst[:size], src[:size])
+        if callback is not None:
+            result = callback(result)
+        return [m2_expr.ExprAssign(dst[:size], result)], []
+    return vec_op_clip_instr
+
+# Generic vertical operation
+
+
+def vec_vertical_sem(op, elt_size, reg_size, dst, src, apply_on_output):
+    assert reg_size % elt_size == 0
+    n = reg_size // elt_size
+    if op == '-':
+        ops = [
+            apply_on_output((dst[i * elt_size:(i + 1) * elt_size]
+                             - src[i * elt_size:(i + 1) * elt_size]))
+            for i in range(0, n)
+        ]
+    else:
+        ops = [
+            apply_on_output(m2_expr.ExprOp(op, dst[i * elt_size:(i + 1) * elt_size],
+                                           src[i * elt_size:(i + 1) * elt_size]))
+            for i in range(0, n)
+        ]
+
+    return m2_expr.ExprCompose(*ops)
+
+
+def __vec_vertical_instr_gen(op, elt_size, sem, apply_on_output):
+    def vec_instr(ir, instr, dst, src):
+        e = []
+        if isinstance(src, m2_expr.ExprMem):
+            src = ir.ExprMem(src.ptr, dst.size)
+        reg_size = dst.size
+        e.append(m2_expr.ExprAssign(dst, sem(op, elt_size, reg_size, dst, src,
+                                          apply_on_output)))
+        return e, []
+    return vec_instr
+
+
+def vec_vertical_instr(op, elt_size, apply_on_output=lambda x: x):
+    return __vec_vertical_instr_gen(op, elt_size, vec_vertical_sem,
+                                    apply_on_output)
+
+
+def _keep_mul_high(expr, signed=False):
+    assert expr.is_op("*") and len(expr.args) == 2
+
+    if signed:
+        arg1 = expr.args[0].signExtend(expr.size * 2)
+        arg2 = expr.args[1].signExtend(expr.size * 2)
+    else:
+        arg1 = expr.args[0].zeroExtend(expr.size * 2)
+        arg2 = expr.args[1].zeroExtend(expr.size * 2)
+    return m2_expr.ExprOp("*", arg1, arg2)[expr.size:]
+
+# Op, signed => associated comparison
+_min_max_func = {
+    ("min", False): m2_expr.expr_is_unsigned_lower,
+    ("min", True): m2_expr.expr_is_signed_lower,
+    ("max", False): m2_expr.expr_is_unsigned_greater,
+    ("max", True): m2_expr.expr_is_signed_greater,
+}
+def _min_max(expr, signed):
+    assert (expr.is_op("min") or expr.is_op("max")) and len(expr.args) == 2
+    return m2_expr.ExprCond(
+        _min_max_func[(expr.op, signed)](expr.args[1], expr.args[0]),
+        expr.args[1],
+        expr.args[0],
+    )
+
+def _float_min_max(expr):
+    assert (expr.is_op("fmin") or expr.is_op("fmax")) and len(expr.args) == 2
+    src1 = expr.args[0]
+    src2 = expr.args[1]
+    if expr.is_op("fmin"):
+        comp = m2_expr.expr_is_float_lower(src1, src2)
+    elif expr.is_op("fmax"):
+        comp = m2_expr.expr_is_float_lower(src2, src1)
+
+    # x86 documentation (for MIN):
+    # IF ((SRC1 = 0.0) and (SRC2 = 0.0)) THEN DEST <-SRC2;
+    # ELSE IF (SRC1 = SNaN) THEN DEST <-SRC2; FI;
+    # ELSE IF (SRC2 = SNaN) THEN DEST <-SRC2; FI;
+    # ELSE IF (SRC1 < SRC2) THEN DEST <-SRC1;
+    # ELSE DEST<-SRC2;
+    #
+    # But this includes the NaN output of "SRC1 < SRC2"
+    # Associated text is more detailed, and this is the version impl here
+    return m2_expr.ExprCond(
+        m2_expr.expr_is_sNaN(src2), src2,
+        m2_expr.ExprCond(
+            m2_expr.expr_is_NaN(src2) | m2_expr.expr_is_NaN(src1), src2,
+            m2_expr.ExprCond(comp, src1, src2)
+        )
+    )
+
+
+# Integer arithmetic
+#
+
+# Additions
+#
+
+# SSE
+paddb = vec_vertical_instr('+', 8)
+paddw = vec_vertical_instr('+', 16)
+paddd = vec_vertical_instr('+', 32)
+paddq = vec_vertical_instr('+', 64)
+
+# Substractions
+#
+
+# SSE
+psubb = vec_vertical_instr('-', 8)
+psubw = vec_vertical_instr('-', 16)
+psubd = vec_vertical_instr('-', 32)
+psubq = vec_vertical_instr('-', 64)
+
+# Multiplications
+#
+
+# SSE
+pmullb = vec_vertical_instr('*', 8)
+pmullw = vec_vertical_instr('*', 16)
+pmulld = vec_vertical_instr('*', 32)
+pmullq = vec_vertical_instr('*', 64)
+pmulhub = vec_vertical_instr('*', 8, _keep_mul_high)
+pmulhuw = vec_vertical_instr('*', 16, _keep_mul_high)
+pmulhud = vec_vertical_instr('*', 32, _keep_mul_high)
+pmulhuq = vec_vertical_instr('*', 64, _keep_mul_high)
+pmulhb = vec_vertical_instr('*', 8, lambda x: _keep_mul_high(x, signed=True))
+pmulhw = vec_vertical_instr('*', 16, lambda x: _keep_mul_high(x, signed=True))
+pmulhd = vec_vertical_instr('*', 32, lambda x: _keep_mul_high(x, signed=True))
+pmulhq = vec_vertical_instr('*', 64, lambda x: _keep_mul_high(x, signed=True))
+
+def pmuludq(ir, instr, dst, src):
+    e = []
+    if dst.size == 64:
+        e.append(m2_expr.ExprAssign(
+            dst,
+            src[:32].zeroExtend(64) * dst[:32].zeroExtend(64)
+        ))
+    elif dst.size == 128:
+        e.append(m2_expr.ExprAssign(
+            dst[:64],
+            src[:32].zeroExtend(64) * dst[:32].zeroExtend(64)
+        ))
+        e.append(m2_expr.ExprAssign(
+            dst[64:],
+            src[64:96].zeroExtend(64) * dst[64:96].zeroExtend(64)
+        ))
+    else:
+        raise RuntimeError("Unsupported size %d" % dst.size)
+    return e, []
+
+# Mix
+#
+
+# SSE
+def pmaddwd(ir, instr, dst, src):
+    sizedst = 32
+    sizesrc = 16
+    out = []
+    for start in range(0, dst.size, sizedst):
+        base = start
+        mul1 = src[base: base + sizesrc].signExtend(sizedst) * dst[base: base + sizesrc].signExtend(sizedst)
+        base += sizesrc
+        mul2 = src[base: base + sizesrc].signExtend(sizedst) * dst[base: base + sizesrc].signExtend(sizedst)
+        out.append(mul1 + mul2)
+    return [m2_expr.ExprAssign(dst, m2_expr.ExprCompose(*out))], []
+
+
+def _absolute(expr):
+    """Return abs(@expr)"""
+    signed = expr.msb()
+    value_unsigned = (expr ^ expr.mask) + m2_expr.ExprInt(1, expr.size)
+    return m2_expr.ExprCond(signed, value_unsigned, expr)
+
+
+def psadbw(ir, instr, dst, src):
+    sizedst = 16
+    sizesrc = 8
+    out_dst = []
+    for start in range(0, dst.size, 64):
+        out = []
+        for src_start in range(0, 64, sizesrc):
+            beg = start + src_start
+            end = beg + sizesrc
+            # Not clear in the doc equations, but in the text, src and dst are:
+            # "8 unsigned byte integers"
+            out.append(_absolute(dst[beg: end].zeroExtend(sizedst) - src[beg: end].zeroExtend(sizedst)))
+        out_dst.append(m2_expr.ExprOp("+", *out))
+        out_dst.append(m2_expr.ExprInt(0, 64 - sizedst))
+
+    return [m2_expr.ExprAssign(dst, m2_expr.ExprCompose(*out_dst))], []
+
+def _average(expr):
+    assert expr.is_op("avg") and len(expr.args) == 2
+
+    arg1 = expr.args[0].zeroExtend(expr.size * 2)
+    arg2 = expr.args[1].zeroExtend(expr.size * 2)
+    one = m2_expr.ExprInt(1, arg1.size)
+    # avg(unsigned) = (a + b + 1) >> 1, addition being at least on one more bit
+    return ((arg1 + arg2 + one) >> one)[:expr.size]
+
+pavgb = vec_vertical_instr('avg', 8, _average)
+pavgw = vec_vertical_instr('avg', 16, _average)
+
+# Comparisons
+#
+
+# SSE
+pminsw = vec_vertical_instr('min', 16, lambda x: _min_max(x, signed=True))
+pminub = vec_vertical_instr('min', 8, lambda x: _min_max(x, signed=False))
+pminuw = vec_vertical_instr('min', 16, lambda x: _min_max(x, signed=False))
+pminud = vec_vertical_instr('min', 32, lambda x: _min_max(x, signed=False))
+pmaxub = vec_vertical_instr('max', 8, lambda x: _min_max(x, signed=False))
+pmaxuw = vec_vertical_instr('max', 16, lambda x: _min_max(x, signed=False))
+pmaxud = vec_vertical_instr('max', 32, lambda x: _min_max(x, signed=False))
+pmaxsw = vec_vertical_instr('max', 16, lambda x: _min_max(x, signed=True))
+
+# Floating-point arithmetic
+#
+
+# SSE
+addss = vec_op_clip('fadd', 32)
+addsd = vec_op_clip('fadd', 64)
+addps = vec_vertical_instr('fadd', 32)
+addpd = vec_vertical_instr('fadd', 64)
+subss = vec_op_clip('fsub', 32)
+subsd = vec_op_clip('fsub', 64)
+subps = vec_vertical_instr('fsub', 32)
+subpd = vec_vertical_instr('fsub', 64)
+mulss = vec_op_clip('fmul', 32)
+mulsd = vec_op_clip('fmul', 64)
+mulps = vec_vertical_instr('fmul', 32)
+mulpd = vec_vertical_instr('fmul', 64)
+divss = vec_op_clip('fdiv', 32)
+divsd = vec_op_clip('fdiv', 64)
+divps = vec_vertical_instr('fdiv', 32)
+divpd = vec_vertical_instr('fdiv', 64)
+
+# Comparisons (floating-point)
+
+minps = vec_vertical_instr('fmin', 32, _float_min_max)
+minpd = vec_vertical_instr('fmin', 64, _float_min_max)
+minss = vec_op_clip('fmin', 32, _float_min_max)
+minsd = vec_op_clip('fmin', 64, _float_min_max)
+maxps = vec_vertical_instr('fmax', 32, _float_min_max)
+maxpd = vec_vertical_instr('fmax', 64, _float_min_max)
+maxss = vec_op_clip('fmax', 32, _float_min_max)
+maxsd = vec_op_clip('fmax', 64, _float_min_max)
+
+def _float_compare_to_mask(expr):
+    if expr.op == 'unord':
+        to_ext = m2_expr.expr_is_NaN(expr.args[0]) | m2_expr.expr_is_NaN(expr.args[1])
+    elif expr.op == 'ord':
+        to_ext = ~m2_expr.expr_is_NaN(expr.args[0]) & ~m2_expr.expr_is_NaN(expr.args[1])
+    else:
+        if expr.op == '==fu':
+            to_ext = m2_expr.expr_is_float_equal(expr.args[0], expr.args[1])
+            on_NaN = m2_expr.ExprInt(0, 1)
+        elif expr.op == '<fu':
+            to_ext = m2_expr.expr_is_float_lower(expr.args[0], expr.args[1])
+            on_NaN = m2_expr.ExprInt(0, 1)
+        elif expr.op == '<=fu':
+            to_ext = (m2_expr.expr_is_float_equal(expr.args[0], expr.args[1]) |
+                      m2_expr.expr_is_float_lower(expr.args[0], expr.args[1]))
+            on_NaN = m2_expr.ExprInt(0, 1)
+        elif expr.op == '!=fu':
+            to_ext = ~m2_expr.expr_is_float_equal(expr.args[0], expr.args[1])
+            on_NaN = m2_expr.ExprInt(1, 1)
+        elif expr.op == '!<fu':
+            to_ext = ~m2_expr.expr_is_float_lower(expr.args[0], expr.args[1])
+            on_NaN = m2_expr.ExprInt(1, 1)
+        elif expr.op == '!<=fu':
+            to_ext = ~(m2_expr.expr_is_float_equal(expr.args[0], expr.args[1]) |
+                      m2_expr.expr_is_float_lower(expr.args[0], expr.args[1]))
+            on_NaN = m2_expr.ExprInt(1, 1)
+
+        to_ext = m2_expr.ExprCond(
+            m2_expr.expr_is_NaN(expr.args[0]) | m2_expr.expr_is_NaN(expr.args[1]),
+            on_NaN,
+            to_ext
+        )
+    return to_ext.signExtend(expr.size)
+
+cmpeqps = vec_vertical_instr('==fu', 32, lambda x: _float_compare_to_mask(x))
+cmpeqpd = vec_vertical_instr('==fu', 64, lambda x: _float_compare_to_mask(x))
+cmpeqss = vec_op_clip('==fu', 32, lambda x: _float_compare_to_mask(x))
+cmpeqsd = vec_op_clip('==fu', 64, lambda x: _float_compare_to_mask(x))
+cmpltps = vec_vertical_instr('<fu', 32, lambda x: _float_compare_to_mask(x))
+cmpltpd = vec_vertical_instr('<fu', 64, lambda x: _float_compare_to_mask(x))
+cmpltss = vec_op_clip('<fu', 32, lambda x: _float_compare_to_mask(x))
+cmpltsd = vec_op_clip('<fu', 64, lambda x: _float_compare_to_mask(x))
+cmpleps = vec_vertical_instr('<=fu', 32, lambda x: _float_compare_to_mask(x))
+cmplepd = vec_vertical_instr('<=fu', 64, lambda x: _float_compare_to_mask(x))
+cmpless = vec_op_clip('<=fu', 32, lambda x: _float_compare_to_mask(x))
+cmplesd = vec_op_clip('<=fu', 64, lambda x: _float_compare_to_mask(x))
+cmpunordps = vec_vertical_instr('unord', 32, lambda x: _float_compare_to_mask(x))
+cmpunordpd = vec_vertical_instr('unord', 64, lambda x: _float_compare_to_mask(x))
+cmpunordss = vec_op_clip('unord', 32, lambda x: _float_compare_to_mask(x))
+cmpunordsd = vec_op_clip('unord', 64, lambda x: _float_compare_to_mask(x))
+cmpneqps = vec_vertical_instr('!=fu', 32, lambda x: _float_compare_to_mask(x))
+cmpneqpd = vec_vertical_instr('!=fu', 64, lambda x: _float_compare_to_mask(x))
+cmpneqss = vec_op_clip('!=fu', 32, lambda x: _float_compare_to_mask(x))
+cmpneqsd = vec_op_clip('!=fu', 64, lambda x: _float_compare_to_mask(x))
+cmpnltps = vec_vertical_instr('!<fu', 32, lambda x: _float_compare_to_mask(x))
+cmpnltpd = vec_vertical_instr('!<fu', 64, lambda x: _float_compare_to_mask(x))
+cmpnltss = vec_op_clip('!<fu', 32, lambda x: _float_compare_to_mask(x))
+cmpnltsd = vec_op_clip('!<fu', 64, lambda x: _float_compare_to_mask(x))
+cmpnleps = vec_vertical_instr('!<=fu', 32, lambda x: _float_compare_to_mask(x))
+cmpnlepd = vec_vertical_instr('!<=fu', 64, lambda x: _float_compare_to_mask(x))
+cmpnless = vec_op_clip('!<=fu', 32, lambda x: _float_compare_to_mask(x))
+cmpnlesd = vec_op_clip('!<=fu', 64, lambda x: _float_compare_to_mask(x))
+cmpordps = vec_vertical_instr('ord', 32, lambda x: _float_compare_to_mask(x))
+cmpordpd = vec_vertical_instr('ord', 64, lambda x: _float_compare_to_mask(x))
+cmpordss = vec_op_clip('ord', 32, lambda x: _float_compare_to_mask(x))
+cmpordsd = vec_op_clip('ord', 64, lambda x: _float_compare_to_mask(x))
+
+# Logical (floating-point)
+#
+
+# MMX/SSE/AVX
+
+
+def pand(_, instr, dst, src):
+    e = []
+    result = dst & src
+    # No flag assigned
+    e.append(m2_expr.ExprAssign(dst, result))
+    return e, []
+
+
+def pandn(_, instr, dst, src):
+    e = []
+    result = (dst ^ dst.mask) & src
+    # No flag assigned
+    e.append(m2_expr.ExprAssign(dst, result))
+    return e, []
+
+
+def por(_, instr, dst, src):
+    e = []
+    result = dst | src
+    e.append(m2_expr.ExprAssign(dst, result))
+    return e, []
+
+
+def cvtdq2pd(_, instr, dst, src):
+    e = []
+    e.append(
+        m2_expr.ExprAssign(
+            dst[:64],
+            m2_expr.ExprOp(
+                'sint_to_fp',
+                src[:32].signExtend(64)
+            )
+        )
+    )
+    e.append(
+        m2_expr.ExprAssign(
+            dst[64:128],
+            m2_expr.ExprOp(
+                'sint_to_fp',
+                src[32:64].signExtend(64)
+            )
+        )
+    )
+    return e, []
+
+
+def cvtdq2ps(_, instr, dst, src):
+    e = []
+    e.append(
+        m2_expr.ExprAssign(dst[:32], m2_expr.ExprOp('sint_to_fp', src[:32])))
+    e.append(
+        m2_expr.ExprAssign(dst[32:64], m2_expr.ExprOp('sint_to_fp', src[32:64])))
+    e.append(
+        m2_expr.ExprAssign(dst[64:96], m2_expr.ExprOp('sint_to_fp', src[64:96])))
+    e.append(
+        m2_expr.ExprAssign(dst[96:128], m2_expr.ExprOp('sint_to_fp', src[96:128])))
+    return e, []
+
+
+def cvtpd2dq(_, instr, dst, src):
+    e = []
+    e.append(
+        m2_expr.ExprAssign(dst[:32], m2_expr.ExprOp('fp_to_sint32', src[:64])))
+    e.append(
+        m2_expr.ExprAssign(dst[32:64], m2_expr.ExprOp('fp_to_sint32', src[64:128])))
+    e.append(m2_expr.ExprAssign(dst[64:128], m2_expr.ExprInt(0, 64)))
+    return e, []
+
+
+def cvtpd2pi(_, instr, dst, src):
+    e = []
+    e.append(
+        m2_expr.ExprAssign(dst[:32], m2_expr.ExprOp('fp_to_sint32', src[:64])))
+    e.append(
+        m2_expr.ExprAssign(dst[32:64], m2_expr.ExprOp('fp_to_sint32', src[64:128])))
+    return e, []
+
+
+def cvtpd2ps(_, instr, dst, src):
+    e = []
+    e.append(
+        m2_expr.ExprAssign(dst[:32], m2_expr.ExprOp('fpconvert_fp32', src[:64])))
+    e.append(
+        m2_expr.ExprAssign(dst[32:64], m2_expr.ExprOp('fpconvert_fp32', src[64:128])))
+    e.append(m2_expr.ExprAssign(dst[64:128], m2_expr.ExprInt(0, 64)))
+    return e, []
+
+
+def cvtpi2pd(_, instr, dst, src):
+    e = []
+    e.append(
+        m2_expr.ExprAssign(
+            dst[:64],
+            m2_expr.ExprOp(
+                'sint_to_fp',
+                src[:32].signExtend(64)
+            )
+        )
+    )
+    e.append(
+        m2_expr.ExprAssign(
+            dst[64:128],
+            m2_expr.ExprOp(
+                'sint_to_fp',
+                src[32:64].signExtend(64))
+        )
+    )
+    return e, []
+
+
+def cvtpi2ps(_, instr, dst, src):
+    e = []
+    e.append(
+        m2_expr.ExprAssign(dst[:32], m2_expr.ExprOp('sint_to_fp', src[:32])))
+    e.append(
+        m2_expr.ExprAssign(dst[32:64], m2_expr.ExprOp('sint_to_fp', src[32:64])))
+    return e, []
+
+
+def cvtps2dq(_, instr, dst, src):
+    e = []
+    e.append(
+        m2_expr.ExprAssign(dst[:32], m2_expr.ExprOp('fp_to_sint32', src[:32])))
+    e.append(
+        m2_expr.ExprAssign(dst[32:64], m2_expr.ExprOp('fp_to_sint32', src[32:64])))
+    e.append(
+        m2_expr.ExprAssign(dst[64:96], m2_expr.ExprOp('fp_to_sint32', src[64:96])))
+    e.append(
+        m2_expr.ExprAssign(dst[96:128], m2_expr.ExprOp('fp_to_sint32', src[96:128])))
+    return e, []
+
+
+def cvtps2pd(_, instr, dst, src):
+    e = []
+    e.append(
+        m2_expr.ExprAssign(dst[:64], m2_expr.ExprOp('fpconvert_fp64', src[:32])))
+    e.append(
+        m2_expr.ExprAssign(dst[64:128], m2_expr.ExprOp('fpconvert_fp64', src[32:64])))
+    return e, []
+
+
+def cvtps2pi(_, instr, dst, src):
+    e = []
+    e.append(
+        m2_expr.ExprAssign(dst[:32], m2_expr.ExprOp('fp_to_sint32', src[:32])))
+    e.append(
+        m2_expr.ExprAssign(dst[32:64], m2_expr.ExprOp('fp_to_sint32', src[32:64])))
+    return e, []
+
+
+def cvtsd2si(_, instr, dst, src):
+    e = []
+    e.append(
+        m2_expr.ExprAssign(dst[:32], m2_expr.ExprOp('fp_to_sint32', src[:64])))
+    return e, []
+
+
+def cvtsd2ss(_, instr, dst, src):
+    e = []
+    e.append(
+        m2_expr.ExprAssign(dst[:32], m2_expr.ExprOp('fpconvert_fp32', src[:64])))
+    return e, []
+
+
+def cvtsi2sd(_, instr, dst, src):
+    e = []
+    e.append(
+        m2_expr.ExprAssign(
+            dst[:64],
+            m2_expr.ExprOp(
+                'sint_to_fp',
+                src[:32].signExtend(64)
+            )
+        )
+    )
+    return e, []
+
+
+def cvtsi2ss(_, instr, dst, src):
+    e = []
+    e.append(
+        m2_expr.ExprAssign(dst[:32], m2_expr.ExprOp('sint_to_fp', src[:32])))
+    return e, []
+
+
+def cvtss2sd(_, instr, dst, src):
+    e = []
+    e.append(
+        m2_expr.ExprAssign(dst[:64], m2_expr.ExprOp('fpconvert_fp64', src[:32])))
+    return e, []
+
+
+def cvtss2si(_, instr, dst, src):
+    e = []
+    e.append(
+        m2_expr.ExprAssign(dst[:32], m2_expr.ExprOp('fp_to_sint32', src[:32])))
+    return e, []
+
+
+def _cvtt_tpl(dst, src, numbers, double):
+    e = []
+    for i in numbers:
+        # For CVTT*D2* (Convert with Truncation ... Double-Precision) to work,
+        # a first conversion fp64 -> fp32 is needed
+        if double:
+            tmp_src = m2_expr.ExprOp('fpconvert_fp32', src[i*64:i*64 + 64])
+        else:
+            tmp_src = src[i*32:i*32 + 32]
+
+        e.append(m2_expr.ExprAssign(
+            dst[i*32:i*32 + 32],
+            m2_expr.ExprOp('fp_to_sint32', m2_expr.ExprOp(
+                'fpround_towardszero',
+                tmp_src
+            ))))
+    return e
+
+def cvttpd2pi(_, instr, dst, src):
+    return _cvtt_tpl(dst, src, [0, 1], double=True), []
+
+def cvttpd2dq(_, instr, dst, src):
+    e = _cvtt_tpl(dst, src, [0, 1], double=True)
+    e.append(m2_expr.ExprAssign(dst[64:128], m2_expr.ExprInt(0, 64)))
+    return e, []
+
+def cvttsd2si(_, instr, dst, src):
+    return _cvtt_tpl(dst, src, [0], double=True), []
+
+def cvttps2dq(_, instr, dst, src):
+    return _cvtt_tpl(dst, src, [0, 1, 2, 3], double=False), []
+
+def cvttps2pi(_, instr, dst, src):
+    return _cvtt_tpl(dst, src, [0, 1], double=False), []
+
+def cvttss2si(_, instr, dst, src):
+    return _cvtt_tpl(dst, src, [0], double=False), []
+
+def movss(_, instr, dst, src):
+    e = []
+    if not isinstance(dst, m2_expr.ExprMem) and not isinstance(src, m2_expr.ExprMem):
+        # Source and Destination xmm
+        e.append(m2_expr.ExprAssign(dst[:32], src[:32]))
+    elif not isinstance(src, m2_expr.ExprMem) and isinstance(dst, m2_expr.ExprMem):
+        # Source XMM Destination Mem
+        e.append(m2_expr.ExprAssign(dst, src[:32]))
+    else:
+        # Source Mem Destination XMM
+        e.append(m2_expr.ExprAssign(
+            dst, m2_expr.ExprCompose(src, m2_expr.ExprInt(0, 96))))
+    return e, []
+
+
+def ucomiss(_, instr, src1, src2):
+    e = []
+    e.append(m2_expr.ExprAssign(zf, m2_expr.ExprOp(
+        'ucomiss_zf', src1[:32], src2[:32])))
+    e.append(m2_expr.ExprAssign(pf, m2_expr.ExprOp(
+        'ucomiss_pf', src1[:32], src2[:32])))
+    e.append(m2_expr.ExprAssign(cf, m2_expr.ExprOp(
+        'ucomiss_cf', src1[:32], src2[:32])))
+
+    e.append(m2_expr.ExprAssign(of, m2_expr.ExprInt(0, 1)))
+    e.append(m2_expr.ExprAssign(af, m2_expr.ExprInt(0, 1)))
+    e.append(m2_expr.ExprAssign(nf, m2_expr.ExprInt(0, 1)))
+
+    return e, []
+
+def ucomisd(_, instr, src1, src2):
+    e = []
+    e.append(m2_expr.ExprAssign(zf, m2_expr.ExprOp(
+        'ucomisd_zf', src1[:64], src2[:64])))
+    e.append(m2_expr.ExprAssign(pf, m2_expr.ExprOp(
+        'ucomisd_pf', src1[:64], src2[:64])))
+    e.append(m2_expr.ExprAssign(cf, m2_expr.ExprOp(
+        'ucomisd_cf', src1[:64], src2[:64])))
+
+    e.append(m2_expr.ExprAssign(of, m2_expr.ExprInt(0, 1)))
+    e.append(m2_expr.ExprAssign(af, m2_expr.ExprInt(0, 1)))
+    e.append(m2_expr.ExprAssign(nf, m2_expr.ExprInt(0, 1)))
+
+    return e, []
+
+def blsi(_, instr, dst, src):
+    e = []
+
+    arg1 = m2_expr.ExprInt(0, src.size)
+    neg_src = arg1 - src
+    result = neg_src & src
+
+    e += update_flag_zf(result)
+    e += update_flag_nf(result)
+    e.append(m2_expr.ExprAssign(of, m2_expr.ExprInt(0, of.size)))
+
+    e.append(m2_expr.ExprAssign(cf, m2_expr.ExprCond(src,
+                                                     m2_expr.ExprInt(1, 1),
+                                                     m2_expr.ExprInt(0, 1))))
+
+    e.append(m2_expr.ExprAssign(dst, result))
+    return e, []
+
+def andn(_, instr, dst, src1, src2):
+    e = []
+
+    arg1 = m2_expr.ExprInt(0, src1.size)
+    neg_src1 = arg1 - src1
+    result = neg_src1 & src2
+
+    e += update_flag_zf(result)
+    e += update_flag_nf(result)
+    e.append(m2_expr.ExprAssign(of, m2_expr.ExprInt(0, of.size)))
+    e.append(m2_expr.ExprAssign(cf, m2_expr.ExprInt(0, cf.size)))
+
+    e.append(m2_expr.ExprAssign(dst, result))
+    return e, []
+
+def bextr(_, instr, dst, src1, src2):
+    e = []
+
+    # TODO: change zero extension to 512 bits when AVX is supported
+    start = (src2 & m2_expr.ExprInt(0xFF, src2.size)).zeroExtend(256)
+    length = ((src2 & m2_expr.ExprInt(0xFF00, src2.size)) >> m2_expr.ExprInt(8, src2.size)).zeroExtend(256)
+
+    tmp = src1.zeroExtend(256) >> start
+    mask = m2_expr.ExprInt(0, 256).mask >> (m2_expr.ExprInt(256, 256) - length)
+
+    tmp = tmp & mask
+    result = tmp[:dst.size]
+
+    e.append(m2_expr.ExprAssign(dst, result))
+    return e, []
+
+def blsmsk(_, instr, dst, src):
+    e = []
+
+    tmp = src - m2_expr.ExprInt(1, src.size)
+    result = src ^ tmp
+
+    e += update_flag_nf(result)
+    e.append(m2_expr.ExprAssign(of, m2_expr.ExprInt(0, of.size)))
+    e.append(m2_expr.ExprAssign(zf, m2_expr.ExprInt(0, zf.size)))
+
+    e.append(m2_expr.ExprAssign(cf, m2_expr.ExprCond(src,
+                                                     m2_expr.ExprInt(0, 1),
+                                                     m2_expr.ExprInt(1, 1))))
+
+    e.append(m2_expr.ExprAssign(dst, result))
+    return e, []
+
+def blsr(_, instr, dst, src):
+    e = []
+
+    tmp = src - m2_expr.ExprInt(1, src.size)
+    result = tmp & src
+
+    e += update_flag_zf(result)
+    e += update_flag_nf(result)
+    e.append(m2_expr.ExprAssign(of, m2_expr.ExprInt(0, of.size)))
+
+    e.append(m2_expr.ExprAssign(cf, m2_expr.ExprCond(src,
+                                                     m2_expr.ExprInt(0, 1),
+                                                     m2_expr.ExprInt(1, 1))))
+
+    e.append(m2_expr.ExprAssign(dst, result))
+    return e, []
+
+def tzcnt(ir, instr, dst, src):
+    e = []
+
+    operand_size = m2_expr.ExprInt(dst.size, dst.size)
+
+    result = m2_expr.ExprCond(src, m2_expr.ExprOp("cnttrailzeros", src), operand_size)
+
+    e.append(m2_expr.ExprAssign(cf, m2_expr.ExprCond(m2_expr.ExprOp("FLAG_EQ_CMP", result, operand_size),
+                                                     m2_expr.ExprInt(1, 1),
+                                                     m2_expr.ExprInt(0, 1))))
+
+    e += update_flag_zf(result)
+    e.append(m2_expr.ExprAssign(dst, result))
+    return e, []
+
+def bzhi(_, instr, dst, src1, src2):
+    e = []
+
+    operand_size = m2_expr.ExprInt(dst.size, dst.size)
+    index = src2[:7].zeroExtend(dst.size)
+    mask = m2_expr.ExprInt(0, dst.size).mask >> (operand_size
+                                                 - index
+                                                 - m2_expr.ExprInt(1, dst.size))
+
+    result = m2_expr.ExprCond(m2_expr.ExprOp("FLAG_SIGN_SUB", index, operand_size),
+                              src1 & mask, src1)
+
+
+    operand_size_dec = operand_size - m2_expr.ExprInt(1, dst.size)
+    e.append(m2_expr.ExprAssign(cf, m2_expr.ExprCond(m2_expr.ExprOp("FLAG_SIGN_SUB", operand_size_dec, index),
+                                                     m2_expr.ExprInt(1, 1),
+                                                     m2_expr.ExprInt(0, 1))))
+
+    e += update_flag_zf(result)
+    e += update_flag_nf(result)
+    e.append(m2_expr.ExprAssign(of, m2_expr.ExprInt(0, of.size)))
+    e.append(m2_expr.ExprAssign(dst, result))
+    return e, []
+
+def pshufb(_, instr, dst, src):
+    e = []
+    if dst.size == 64:
+        bit_l = 3
+    elif dst.size == 128:
+        bit_l = 4
+    else:
+        raise NotImplementedError("bad size")
+    for i in range(0, src.size, 8):
+        index = src[
+            i:i + bit_l].zeroExtend(dst.size) << m2_expr.ExprInt(3, dst.size)
+        value = (dst >> index)[:8]
+        e.append(m2_expr.ExprAssign(dst[i:i + 8],
+                                 m2_expr.ExprCond(src[i + 7:i + 8],
+                                                  m2_expr.ExprInt(0, 8),
+                                                  value)))
+    return e, []
+
+
+def pshufd(_, instr, dst, src, imm):
+    control = int(imm)
+    out = []
+    for i in range(4):
+        shift = ((control >> (i * 2)) & 3) * 32
+        # shift is 2 bits long, expr.size is 128
+        # => shift + 32 <= src.size
+        out.append(src[shift: shift + 32])
+    return [m2_expr.ExprAssign(dst, m2_expr.ExprCompose(*out))], []
+
+
+def pshuflw(_, instr, dst, src, imm):
+    control = int(imm)
+    out = []
+    for i in range(4):
+        shift = ((control >> (i * 2)) & 3) * 16
+        out.append(src[shift: shift + 16])
+    out.append(src[64:])
+    return [m2_expr.ExprAssign(dst, m2_expr.ExprCompose(*out))], []
+
+
+def pshufhw(_, instr, dst, src, imm):
+    control = int(imm)
+    out = [src[:64]]
+    for i in range(4):
+        shift = ((control >> (i * 2)) & 3) * 16
+        out.append(src[shift + 64: shift + 16 + 64])
+    return [m2_expr.ExprAssign(dst, m2_expr.ExprCompose(*out))], []
+
+
+def ps_rl_ll(ir, instr, dst, src, op, size):
+    mask = {16: 0xF,
+            32: 0x1F,
+            64: 0x3F}[size]
+    mask = m2_expr.ExprInt(mask, dst.size)
+
+    # Saturate the counter to 2**size
+    count = src.zeroExtend(dst.size)
+    count = m2_expr.ExprCond(count & expr_simp(~mask),
+                             m2_expr.ExprInt(size, dst.size), # saturation
+                             count, # count < 2**size
+    )
+    count = count[:size]
+    if src.is_int():
+        count = expr_simp(count)
+
+    out = []
+    for i in range(0, dst.size, size):
+        out.append(m2_expr.ExprOp(op, dst[i:i + size], count))
+    return [m2_expr.ExprAssign(dst, m2_expr.ExprCompose(*out))], []
+
+
+def psrlw(ir, instr, dst, src):
+    return ps_rl_ll(ir, instr, dst, src, ">>", 16)
+
+
+def psrld(ir, instr, dst, src):
+    return ps_rl_ll(ir, instr, dst, src, ">>", 32)
+
+
+def psrlq(ir, instr, dst, src):
+    return ps_rl_ll(ir, instr, dst, src, ">>", 64)
+
+
+def psllw(ir, instr, dst, src):
+    return ps_rl_ll(ir, instr, dst, src, "<<", 16)
+
+
+def pslld(ir, instr, dst, src):
+    return ps_rl_ll(ir, instr, dst, src, "<<",  32)
+
+
+def psllq(ir, instr, dst, src):
+    return ps_rl_ll(ir, instr, dst, src, "<<",  64)
+
+
+def psraw(ir, instr, dst, src):
+    return ps_rl_ll(ir, instr, dst, src, "a>>", 16)
+
+
+def psrad(ir, instr, dst, src):
+    return ps_rl_ll(ir, instr, dst, src, "a>>", 32)
+
+
+def pslldq(_, instr, dst, src):
+    assert src.is_int()
+    e = []
+    count = int(src)
+    if count > 15:
+        return [m2_expr.ExprAssign(dst, m2_expr.ExprInt(0, dst.size))], []
+    else:
+        return [m2_expr.ExprAssign(dst, dst << m2_expr.ExprInt(8 * count, dst.size))], []
+
+
+def psrldq(_, instr, dst, src):
+    assert src.is_int()
+    count = int(src)
+    if count > 15:
+        return [m2_expr.ExprAssign(dst, m2_expr.ExprInt(0, dst.size))], []
+    else:
+        return [m2_expr.ExprAssign(dst, dst >> m2_expr.ExprInt(8 * count, dst.size))], []
+
+
+def iret(ir, instr):
+    """IRET implementation
+    XXX: only support "no-privilege change"
+    """
+    size = instr.v_opmode()
+    exprs, _ = retf(ir, instr, m2_expr.ExprInt(size // 8, size=size))
+    tmp = mRSP[instr.mode][:size] + m2_expr.ExprInt((2 * size) // 8, size=size)
+    exprs += _tpl_eflags(tmp)
+    return exprs, []
+
+
+def pcmpeq(_, instr, dst, src, size):
+    e = []
+    for i in range(0, dst.size, size):
+        test = m2_expr.expr_is_equal(dst[i:i + size], src[i:i + size])
+        e.append(m2_expr.ExprAssign(dst[i:i + size],
+                                 m2_expr.ExprCond(test,
+                                                  m2_expr.ExprInt(-1, size),
+                                                  m2_expr.ExprInt(0, size))))
+    return e, []
+
+
+def pcmpgt(_, instr, dst, src, size):
+    e = []
+    for i in range(0, dst.size, size):
+        test = m2_expr.expr_is_signed_greater(dst[i:i + size], src[i:i + size])
+        e.append(m2_expr.ExprAssign(dst[i:i + size],
+                                 m2_expr.ExprCond(test,
+                                                  m2_expr.ExprInt(-1, size),
+                                                  m2_expr.ExprInt(0, size))))
+    return e, []
+
+
+def pcmpeqb(ir, instr, dst, src):
+    return pcmpeq(ir, instr, dst, src, 8)
+
+def pcmpeqw(ir, instr, dst, src):
+    return pcmpeq(ir, instr, dst, src, 16)
+
+def pcmpeqd(ir, instr, dst, src):
+    return pcmpeq(ir, instr, dst, src, 32)
+
+def pcmpeqq(ir, instr, dst, src):
+    return pcmpeq(ir, instr, dst, src, 64)
+
+
+
+
+def pcmpgtb(ir, instr, dst, src):
+    return pcmpgt(ir, instr, dst, src, 8)
+
+def pcmpgtw(ir, instr, dst, src):
+    return pcmpgt(ir, instr, dst, src, 16)
+
+def pcmpgtd(ir, instr, dst, src):
+    return pcmpgt(ir, instr, dst, src, 32)
+
+def pcmpgtq(ir, instr, dst, src):
+    return pcmpgt(ir, instr, dst, src, 64)
+
+
+
+def punpck(_, instr, dst, src, size, off):
+    e = []
+    slices = []
+    for i in range(dst.size // (2 * size)):
+        slices.append(dst[size * i + off: size * i + off + size])
+        slices.append(src[size * i + off: size * i + off + size])
+    e.append(m2_expr.ExprAssign(dst, m2_expr.ExprCompose(*slices)))
+    return e, []
+
+
+def punpckhbw(ir, instr, dst, src):
+    return punpck(ir, instr, dst, src, 8, dst.size // 2)
+
+
+def punpckhwd(ir, instr, dst, src):
+    return punpck(ir, instr, dst, src, 16, dst.size // 2)
+
+
+def punpckhdq(ir, instr, dst, src):
+    return punpck(ir, instr, dst, src, 32, dst.size // 2)
+
+
+def punpckhqdq(ir, instr, dst, src):
+    return punpck(ir, instr, dst, src, 64, dst.size // 2)
+
+
+def punpcklbw(ir, instr, dst, src):
+    return punpck(ir, instr, dst, src, 8, 0)
+
+
+def punpcklwd(ir, instr, dst, src):
+    return punpck(ir, instr, dst, src, 16, 0)
+
+
+def punpckldq(ir, instr, dst, src):
+    return punpck(ir, instr, dst, src, 32, 0)
+
+
+def punpcklqdq(ir, instr, dst, src):
+    return punpck(ir, instr, dst, src, 64, 0)
+
+
+def pinsr(_, instr, dst, src, imm, size):
+    e = []
+
+    mask = {8: 0xF,
+            16: 0x7,
+            32: 0x3,
+            64: 0x1}[size]
+
+    sel = (int(imm) & mask) * size
+    e.append(m2_expr.ExprAssign(dst[sel:sel + size], src[:size]))
+
+    return e, []
+
+
+def pinsrb(ir, instr, dst, src, imm):
+    return pinsr(ir, instr, dst, src, imm, 8)
+
+
+def pinsrw(ir, instr, dst, src, imm):
+    return pinsr(ir, instr, dst, src, imm, 16)
+
+
+def pinsrd(ir, instr, dst, src, imm):
+    return pinsr(ir, instr, dst, src, imm, 32)
+
+
+def pinsrq(ir, instr, dst, src, imm):
+    return pinsr(ir, instr, dst, src, imm, 64)
+
+
+def pextr(_, instr, dst, src, imm, size):
+    e = []
+
+    mask = {8: 0xF,
+            16: 0x7,
+            32: 0x3,
+            64: 0x1}[size]
+
+    sel = (int(imm) & mask) * size
+    e.append(m2_expr.ExprAssign(dst, src[sel:sel + size].zeroExtend(dst.size)))
+
+    return e, []
+
+
+def pextrb(ir, instr, dst, src, imm):
+    return pextr(ir, instr, dst, src, imm, 8)
+
+
+def pextrw(ir, instr, dst, src, imm):
+    return pextr(ir, instr, dst, src, imm, 16)
+
+
+def pextrd(ir, instr, dst, src, imm):
+    return pextr(ir, instr, dst, src, imm, 32)
+
+
+def pextrq(ir, instr, dst, src, imm):
+    return pextr(ir, instr, dst, src, imm, 64)
+
+
+def unpckhps(_, instr, dst, src):
+    e = []
+    src = m2_expr.ExprCompose(dst[64:96], src[64:96], dst[96:128], src[96:128])
+    e.append(m2_expr.ExprAssign(dst, src))
+    return e, []
+
+
+def unpckhpd(_, instr, dst, src):
+    e = []
+    src = m2_expr.ExprCompose(dst[64:128], src[64:128])
+    e.append(m2_expr.ExprAssign(dst, src))
+    return e, []
+
+
+def unpcklps(_, instr, dst, src):
+    e = []
+    src = m2_expr.ExprCompose(dst[0:32], src[0:32], dst[32:64], src[32:64])
+    e.append(m2_expr.ExprAssign(dst, src))
+    return e, []
+
+
+def unpcklpd(_, instr, dst, src):
+    e = []
+    src = m2_expr.ExprCompose(dst[0:64], src[0:64])
+    e.append(m2_expr.ExprAssign(dst, src))
+    return e, []
+
+
+def movlpd(_, instr, dst, src):
+    e = []
+    e.append(m2_expr.ExprAssign(dst[:64], src[:64]))
+    return e, []
+
+
+def movlps(_, instr, dst, src):
+    e = []
+    e.append(m2_expr.ExprAssign(dst[:64], src[:64]))
+    return e, []
+
+
+def movhpd(_, instr, dst, src):
+    e = []
+    if src.size == 64:
+        e.append(m2_expr.ExprAssign(dst[64:128], src))
+    elif dst.size == 64:
+        e.append(m2_expr.ExprAssign(dst, src[64:128]))
+    else:
+        raise RuntimeError("bad encoding!")
+    return e, []
+
+
+def movlhps(_, instr, dst, src):
+    e = []
+    e.append(m2_expr.ExprAssign(dst[64:128], src[:64]))
+    return e, []
+
+
+def movhlps(_, instr, dst, src):
+    e = []
+    e.append(m2_expr.ExprAssign(dst[:64], src[64:128]))
+    return e, []
+
+
+def movdq2q(_, instr, dst, src):
+    e = []
+    e.append(m2_expr.ExprAssign(dst, src[:64]))
+    return e, []
+
+
+def movq2dq(_, instr, dst, src):
+    e = []
+    e.append(m2_expr.ExprAssign(dst, src[:64].zeroExtend(dst.size)))
+    return e, []
+
+
+def sqrt_gen(_, instr, dst, src, size):
+    e = []
+    out = []
+    for i in range(src.size // size):
+        out.append(m2_expr.ExprOp('fsqrt',
+                                  src[i * size: (i + 1) * size]))
+    src = m2_expr.ExprCompose(*out)
+    e.append(m2_expr.ExprAssign(dst, src))
+    return e, []
+
+
+def sqrtpd(ir, instr, dst, src):
+    return sqrt_gen(ir, instr, dst, src, 64)
+
+
+def sqrtps(ir, instr, dst, src):
+    return sqrt_gen(ir, instr, dst, src, 32)
+
+
+def sqrtsd(_, instr, dst, src):
+    e = []
+    e.append(m2_expr.ExprAssign(dst[:64],
+                             m2_expr.ExprOp('fsqrt',
+                                            src[:64])))
+    return e, []
+
+
+def sqrtss(_, instr, dst, src):
+    e = []
+    e.append(m2_expr.ExprAssign(dst[:32],
+                             m2_expr.ExprOp('fsqrt',
+                                            src[:32])))
+    return e, []
+
+
+def pmovmskb(_, instr, dst, src):
+    e = []
+    out = []
+    for i in range(src.size // 8):
+        out.append(src[8 * i + 7:8 * (i + 1)])
+    src = m2_expr.ExprCompose(*out)
+    e.append(m2_expr.ExprAssign(dst, src.zeroExtend(dst.size)))
+    return e, []
+
+
+def smsw(ir, instr, dst):
+    e = []
+    LOG_X86_SEM.warning("DEFAULT SMSW %s!!", str(dst))
+    e.append(m2_expr.ExprAssign(dst, m2_expr.ExprInt(0x80050033, 32)[:dst.size]))
+    return e, []
+
+
+def bndmov(ir, instr, dst, src):
+    # Implemented as a NOP, because BND side effects are not yet supported
+    return [], []
+
+def palignr(ir, instr, dst, src, imm):
+    # dst.src >> imm * 8 [:dst.size]
+
+    shift = int(imm) * 8
+    if shift == 0:
+        result = src
+    elif shift == src.size:
+        result = dst
+    elif shift > src.size:
+        result = dst >> m2_expr.ExprInt(shift - src.size, dst.size)
+    else:
+        # shift < src.size
+        result = m2_expr.ExprCompose(
+            src[shift:],
+            dst[:shift],
+        )
+
+    return [m2_expr.ExprAssign(dst, result)], []
+
+
+def _signed_to_signed_saturation(expr, dst_size):
+    """Saturate the expr @expr for @dst_size bit
+    Signed saturation return MAX_INT / MIN_INT or value depending on the value
+    """
+    assert expr.size > dst_size
+
+    median = 1 << (dst_size - 1)
+
+    min_int = m2_expr.ExprInt(- median, dst_size)
+    max_int = m2_expr.ExprInt(median - 1, dst_size)
+
+    test_min_int = min_int.signExtend(expr.size)
+    test_max_int = max_int.signExtend(expr.size)
+
+    value = expr[:dst_size]
+
+    return m2_expr.ExprCond(
+        m2_expr.ExprOp(
+            m2_expr.TOK_INF_EQUAL_SIGNED,
+            expr,
+            test_min_int
+        ),
+        min_int,
+        m2_expr.ExprCond(
+            m2_expr.ExprOp(
+                m2_expr.TOK_INF_SIGNED,
+                expr,
+                test_max_int
+            ),
+            value,
+            max_int
+        )
+    )
+
+
+def _signed_to_unsigned_saturation(expr, dst_size):
+    """Saturate the expr @expr for @dst_size bit
+    Unsigned saturation return MAX_INT or value depending on the value
+    """
+    assert expr.size > dst_size
+
+    zero = m2_expr.ExprInt(0, dst_size)
+    test_zero = m2_expr.ExprInt(0, expr.size)
+
+    max_int = m2_expr.ExprInt(-1, dst_size)
+    test_max_int = max_int.zeroExtend(expr.size)
+
+    value = expr[:dst_size]
+
+    return m2_expr.ExprCond(
+        m2_expr.ExprOp(
+            m2_expr.TOK_INF_EQUAL_SIGNED,
+            expr,
+            test_zero
+        ),
+        zero,
+        m2_expr.ExprCond(
+            m2_expr.ExprOp(
+                m2_expr.TOK_INF_SIGNED,
+                expr,
+                test_max_int
+            ),
+            value,
+            max_int
+        )
+    )
+
+
+
+def packsswb(ir, instr, dst, src):
+    out = []
+    for source in [dst, src]:
+        for start in range(0, dst.size, 16):
+            out.append(_signed_to_signed_saturation(source[start:start + 16], 8))
+    return [m2_expr.ExprAssign(dst, m2_expr.ExprCompose(*out))], []
+
+
+def packssdw(ir, instr, dst, src):
+    out = []
+    for source in [dst, src]:
+        for start in range(0, dst.size, 32):
+            out.append(_signed_to_signed_saturation(source[start:start + 32], 16))
+    return [m2_expr.ExprAssign(dst, m2_expr.ExprCompose(*out))], []
+
+
+def packuswb(ir, instr, dst, src):
+    out = []
+    for source in [dst, src]:
+        for start in range(0, dst.size, 16):
+            out.append(_signed_to_unsigned_saturation(source[start:start + 16], 8))
+    return [m2_expr.ExprAssign(dst, m2_expr.ExprCompose(*out))], []
+
+
+def _saturation_sub_unsigned(expr):
+    assert expr.is_op("+") and len(expr.args) == 2 and expr.args[-1].is_op("-")
+
+    # Compute the soustraction on one more bit to be able to distinguish cases:
+    # 0x48 - 0xd7 in 8 bit, should saturate
+    arg1 = expr.args[0].zeroExtend(expr.size + 1)
+    arg2 = expr.args[1].args[0].zeroExtend(expr.size + 1)
+    return _signed_to_unsigned_saturation(arg1 - arg2, expr.size)
+
+def _saturation_sub_signed(expr):
+    assert expr.is_op("+") and len(expr.args) == 2 and expr.args[-1].is_op("-")
+
+    # Compute the subtraction on two more bits, see _saturation_sub_unsigned
+    arg1 = expr.args[0].signExtend(expr.size + 2)
+    arg2 = expr.args[1].args[0].signExtend(expr.size + 2)
+    return _signed_to_signed_saturation(arg1 - arg2, expr.size)
+
+def _saturation_add(expr):
+    assert expr.is_op("+") and len(expr.args) == 2
+
+    # Compute the addition on one more bit to be able to distinguish cases:
+    # 0x48 + 0xd7 in 8 bit, should saturate
+
+    arg1 = expr.args[0].zeroExtend(expr.size + 1)
+    arg2 = expr.args[1].zeroExtend(expr.size + 1)
+
+    # We can also use _signed_to_unsigned_saturation with two additional bits (to
+    # distinguish minus and overflow case)
+    # The resulting expression being more complicated with an impossible case
+    # (signed=True), we rewrite the rule here
+
+    return m2_expr.ExprCond((arg1 + arg2).msb(), m2_expr.ExprInt(-1, expr.size),
+                            expr)
+
+def _saturation_add_signed(expr):
+    assert expr.is_op("+") and len(expr.args) == 2
+
+    # Compute the subtraction on two more bits, see _saturation_add_unsigned
+
+    arg1 = expr.args[0].signExtend(expr.size + 2)
+    arg2 = expr.args[1].signExtend(expr.size + 2)
+
+    return _signed_to_signed_saturation(arg1 + arg2, expr.size)
+
+
+# Saturate SSE operations
+
+psubusb = vec_vertical_instr('-', 8, _saturation_sub_unsigned)
+psubusw = vec_vertical_instr('-', 16, _saturation_sub_unsigned)
+paddusb = vec_vertical_instr('+', 8, _saturation_add)
+paddusw = vec_vertical_instr('+', 16, _saturation_add)
+psubsb = vec_vertical_instr('-', 8, _saturation_sub_signed)
+psubsw = vec_vertical_instr('-', 16, _saturation_sub_signed)
+paddsb = vec_vertical_instr('+', 8, _saturation_add_signed)
+paddsw = vec_vertical_instr('+', 16, _saturation_add_signed)
+
+
+# Others SSE operations
+
+def maskmovq(ir, instr, src, mask):
+    loc_next = ir.get_next_loc_key(instr)
+    loc_next_expr = m2_expr.ExprLoc(loc_next, ir.IRDst.size)
+    blks = []
+
+    # For each possibility, check if a write is necessary
+    check_labels = [m2_expr.ExprLoc(ir.loc_db.add_location(), ir.IRDst.size)
+                    for _ in range(0, mask.size, 8)]
+    # If the write has to be done, do it (otherwise, nothing happen)
+    write_labels = [m2_expr.ExprLoc(ir.loc_db.add_location(), ir.IRDst.size)
+                    for _ in range(0, mask.size, 8)]
+
+    # Build check blocks
+    for i, start in enumerate(range(0, mask.size, 8)):
+        bit = mask[start + 7: start + 8]
+        cur_label = check_labels[i]
+        next_check_label = check_labels[i + 1] if (i + 1) < len(check_labels) else loc_next_expr
+        write_label = write_labels[i]
+        check = m2_expr.ExprAssign(ir.IRDst,
+                                m2_expr.ExprCond(bit,
+                                                 write_label,
+                                                 next_check_label))
+        blks.append(IRBlock(ir.loc_db, cur_label.loc_key, [AssignBlock([check], instr)]))
+
+    # Build write blocks
+    dst_addr = mRDI[instr.mode]
+    for i, start in enumerate(range(0, mask.size, 8)):
+        cur_label = write_labels[i]
+        next_check_label = check_labels[i + 1] if (i + 1) < len(check_labels) else loc_next_expr
+        write_addr = dst_addr + m2_expr.ExprInt(i, dst_addr.size)
+
+        # @8[DI/EDI/RDI + i] = src[byte i]
+        write_mem = m2_expr.ExprAssign(m2_expr.ExprMem(write_addr, 8),
+                                    src[start: start + 8])
+        jump = m2_expr.ExprAssign(ir.IRDst, next_check_label)
+        blks.append(IRBlock(ir.loc_db, cur_label.loc_key, [AssignBlock([write_mem, jump], instr)]))
+
+    # If mask is null, bypass all
+    e = [m2_expr.ExprAssign(ir.IRDst, m2_expr.ExprCond(mask,
+                                                    check_labels[0],
+                                                    loc_next_expr))]
+    return e, blks
+
+
+def emms(ir, instr):
+    # Implemented as a NOP
+    return [], []
+
+def incssp(ir, instr, dst):
+    # Implemented as a NOP
+    return [], []
+
+def rdssp(ir, instr, dst):
+    # Implemented as a NOP
+    return [], []
+
+def saveprevssp(ir, instr):
+    # Implemented as a NOP
+    return [], []
+
+def rstorssp(ir, instr, dst):
+    # Implemented as a NOP
+    return [], []
+
+def wrss(ir, instr, src, dst):
+    # Implemented as a NOP
+    return [], []
+
+def wruss(ir, instr, src, dst):
+    # Implemented as a NOP
+    return [], []
+
+def setssbsy(ir, instr):
+    # Implemented as a NOP
+    return [], []
+
+def clrssbsy(ir, instr, dst):
+    # Implemented as a NOP
+    return [], []
+
+def endbr64(ir, instr):
+    # Implemented as a NOP
+    return [], []
+
+def endbr32(ir, instr):
+    # Implemented as a NOP
+    return [], []
+
+# Common value without too many option, 0x1fa0
+STMXCSR_VALUE = 0x1fa0
+def stmxcsr(ir, instr, dst):
+    return [m2_expr.ExprAssign(dst, m2_expr.ExprInt(STMXCSR_VALUE, dst.size))], []
+
+def ldmxcsr(ir, instr, dst):
+    # Implemented as a NOP
+    return [], []
+
+
+def _select4(src, control):
+    # Implementation inspired from Intel Intrinsics Guide
+    # @control is already resolved (was an immediate)
+
+    if control == 0:
+        return src[:32] # 0
+    elif control == 1:
+        return src[32:64]
+    elif control == 2:
+        return src[64:96]
+    elif control == 3:
+        return src[96:]
+    else:
+        raise ValueError("Control must be on 2 bits")
+
+
+def shufps(ir, instr, dst, src, imm8):
+    out = []
+    control = int(imm8)
+    for i in range(4):
+        if i < 2:
+            source = dst
+        else:
+            source = src
+        out.append(_select4(source, (control >> (i * 2)) & 3))
+    return [m2_expr.ExprAssign(dst, m2_expr.ExprCompose(*out))], []
+
+
+def shufpd(ir, instr, dst, src, imm8):
+    out = []
+    control = int(imm8)
+    out.append(dst[64:] if control & 1 else dst[:64])
+    out.append(src[64:] if control & 2 else src[:64])
+    return [m2_expr.ExprAssign(dst, m2_expr.ExprCompose(*out))], []
+
+def movmskps(ir, instr, dst, src):
+    out = []
+    for i in range(4):
+        out.append(src[(32 * i) + 31:(32 * i) + 32])
+    return [m2_expr.ExprAssign(dst, m2_expr.ExprCompose(*out).zeroExtend(dst.size))], []
+
+def movmskpd(ir, instr, dst, src):
+    out = []
+    for i in range(2):
+        out.append(src[(64 * i) + 63:(64 * i) + 64])
+    return [m2_expr.ExprAssign(dst, m2_expr.ExprCompose(*out).zeroExtend(dst.size))], []
+
+def _roundscalar(ir, inst, dst, src, imm8, double):
+    res = None
+    ctl = int(imm8)
+    dst_expr = dst[:64] if double else dst[:32]
+    src_expr = src[:64] if double else src[:32]
+    if ctl & 0x4 != 0:
+        # Use MXCSR rounding config
+        # TODO: here we assume it's round to nearest, ties to even
+        res = m2_expr.ExprOp('fpround_towardsnearest', src_expr)
+    else:
+        # Use encoded rounding mechanism
+        rounding_mechanism = ctl & 0x3
+        ROUNDING_MODE = {
+            0x0: 'fpround_towardsnearest',
+            0x1: 'fpround_down',
+            0x2: 'fpround_up',
+            0x3: 'fpround_towardszero'
+        }
+        res = m2_expr.ExprOp(ROUNDING_MODE[rounding_mechanism], src_expr)
+    return [m2_expr.ExprAssign(dst_expr, res)], []
+
+def roundss(ir, inst, dst, src, imm8):
+    return _roundscalar(ir, inst, dst, src, imm8, False)
+
+def roundsd(ir, inst, dst, src, imm8):
+    return _roundscalar(ir, inst, dst, src, imm8, True)
+
+def fxsave(_ir, _instr, _src):
+    # Implemented as a NOP for now
+    return [], []
+
+def fxrstor(_ir, _instr, _dst):
+    # Implemented as a NOP for now
+    return [], []
+
+
+mnemo_func = {'mov': mov,
+              'xchg': xchg,
+              'movzx': movzx,
+              'movsx': movsx,
+              'movsxd': movsx,
+              'lea': lea,
+              'add': add,
+              'xadd': xadd,
+              'adc': adc,
+              'sub': sub,
+              'sbb': sbb,
+              'neg': neg,
+              'not': l_not,
+              'cmp': l_cmp,
+              'xor': xor,
+              'pxor': pxor,
+              'or': l_or,
+              'and': l_and,
+              'test': l_test,
+              'rol': l_rol,
+              'ror': l_ror,
+              'rcl': rcl,
+              'rcr': rcr,
+              'sar': sar,
+              'shr': shr,
+              'sal': shl,
+              'shl': shl,
+              'shld': shld,
+              'cmc': cmc,
+              'clc': clc,
+              'stc': stc,
+              'cld': cld,
+              'std': std,
+              'cli': cli,
+              'sti': sti,
+              'bsf': bsf,
+              'bsr': bsr,
+              'inc': inc,
+              'dec': dec,
+              'push': push,
+              'pushw': pushw,
+              'pop': pop,
+              'popw': popw,
+              'sete': sete,
+              'setnz': setnz,
+              'setl': setl,
+              'setg': setg,
+              'setge': setge,
+              'seta': seta,
+              'setae': setae,
+              'setb': setb,
+              'setbe': setbe,
+              'setns': setns,
+              'sets': sets,
+              'seto': seto,
+              'setp': setp,
+              'setpe': setp,
+              'setnp': setnp,
+              'setpo': setnp,
+              'setle': setle,
+              'setng': setle,
+              'setna': setna,
+              'setnbe': setnbe,
+              'setno': setno,
+              'setnc': setnb,
+              'setz': sete,
+              'setne': setnz,
+              'setnb': setae,
+              'setnae': setb,
+              'setc': setb,
+              'setnge': setl,
+              'setnl': setge,
+              'setnle': setg,
+              'setalc': setalc,
+              'bswap': bswap,
+              'cmpsb': lambda ir, instr: cmps(ir, instr, 8),
+              'cmpsw': lambda ir, instr: cmps(ir, instr, 16),
+              'cmpsd': lambda ir, instr: cmps(ir, instr, 32),
+              'cmpsq': lambda ir, instr: cmps(ir, instr, 64),
+              'scasb': lambda ir, instr: scas(ir, instr, 8),
+              'scasw': lambda ir, instr: scas(ir, instr, 16),
+              'scasd': lambda ir, instr: scas(ir, instr, 32),
+              'scasq': lambda ir, instr: scas(ir, instr, 64),
+              'pushfd': pushfd,
+              'pushfq': pushfq,
+              'pushfw': pushfw,
+              'popfd': popfd,
+              'popfq': popfd,
+              'popfw': popfw,
+              'pusha': pusha,
+              'pushad': pushad,
+              'popad': popad,
+              'popa': popa,
+              'call': call,
+              'ret': ret,
+              'retf': retf,
+              'iret': iret,
+              'iretd': iret,
+              'leave': leave,
+              'enter': enter,
+              'jmp': jmp,
+              'jz': jz,
+              'je': jz,
+              'jcxz': jcxz,
+              'jecxz': jecxz,
+              'jrcxz': jrcxz,
+              'jnz': jnz,
+              'jp': jp,
+              'jpe': jp,
+              'jnp': jnp,
+              'ja': ja,
+              'jae': jae,
+              'jb': jb,
+              'jbe': jbe,
+              'jg': jg,
+              'jge': jge,
+              'jl': jl,
+              'jle': jle,
+              'js': js,
+              'jns': jns,
+              'jo': jo,
+              'jno': jno,
+              'loop': loop,
+              'loopne': loopne,
+              'loope': loope,
+              'div': div,
+              'mul': mul,
+              'imul': imul,
+              'idiv': idiv,
+
+              'cbw': cbw,
+              'cwde': cwde,
+              'cdqe': cdqe,
+
+              'cwd': cwd,
+              'cdq': cdq,
+              'cqo': cqo,
+
+              'daa': daa,
+              'das': das,
+              'aam': aam,
+              'aad': aad,
+              'aaa': aaa,
+              'aas': aas,
+              'shrd': shrd,
+              'stosb': lambda ir, instr: stos(ir, instr, 8),
+              'stosw': lambda ir, instr: stos(ir, instr, 16),
+              'stosd': lambda ir, instr: stos(ir, instr, 32),
+              'stosq': lambda ir, instr: stos(ir, instr, 64),
+
+              'lodsb': lambda ir, instr: lods(ir, instr, 8),
+              'lodsw': lambda ir, instr: lods(ir, instr, 16),
+              'lodsd': lambda ir, instr: lods(ir, instr, 32),
+              'lodsq': lambda ir, instr: lods(ir, instr, 64),
+
+              'movsb': lambda ir, instr: movs(ir, instr, 8),
+              'movsw': lambda ir, instr: movs(ir, instr, 16),
+              'movsd': movsd_dispatch,
+              'movsq': lambda ir, instr: movs(ir, instr, 64),
+              'fcomp': fcomp,
+              'fcompp': fcompp,
+              'ficomp': ficomp,
+              'fucom': fucom,
+              'fucomp': fucomp,
+              'fucompp': fucompp,
+              'comiss': comiss,
+              'comisd': comisd,
+              'nop': nop,
+              'ud2': ud2,
+              'prefetch0': prefetch0,
+              'prefetch1': prefetch1,
+              'prefetch2': prefetch2,
+              'prefetchw': prefetchw,
+              'prefetchnta': prefetchnta,
+              'lfence': lfence,
+              'mfence': mfence,
+              'sfence': sfence,
+              'fnop': nop,  # XXX
+              'hlt': hlt,
+              'rdtsc': rdtsc,
+              'fst': fst,
+              'fstp': fstp,
+              'fist': fist,
+              'fistp': fistp,
+              'fisttp': fisttp,
+              'fld': fld,
+              'fldz': fldz,
+              'fld1': fld1,
+              'fldl2t': fldl2t,
+              'fldpi': fldpi,
+              'fldln2': fldln2,
+              'fldl2e': fldl2e,
+              'fldlg2': fldlg2,
+              'fild': fild,
+              'fadd': fadd,
+              'fiadd': fiadd,
+              'fisub': fisub,
+              'fisubr': fisubr,
+              'fpatan': fpatan,
+              'fprem': fprem,
+              'fprem1': fprem1,
+              'fninit': fninit,
+              'fyl2x': fyl2x,
+              'faddp': faddp,
+              'fsub': fsub,
+              'fsubp': fsubp,
+              'fsubr': fsubr,
+              'fsubrp': fsubrp,
+              'fmul': fmul,
+              'fimul': fimul,
+              'fmulp': fmulp,
+              'fdiv': fdiv,
+              'fdivr': fdivr,
+              'fdivrp': fdivrp,
+              'fidiv': fidiv,
+              'fidivr': fidivr,
+              'fdivp': fdivp,
+              'fxch': fxch,
+              'fptan': fptan,
+              'frndint': frndint,
+              'fsin': fsin,
+              'fcos': fcos,
+              'fsincos': fsincos,
+              'fscale': fscale,
+              'f2xm1': f2xm1,
+              'fchs': fchs,
+              'fsqrt': fsqrt,
+              'fabs': fabs,
+              'fnstsw': fnstsw,
+              'fnstcw': fnstcw,
+              'fldcw': fldcw,
+              'fwait': fwait,
+              'fcmovb':   fcmovb,
+              'fcmove':   fcmove,
+              'fcmovbe':  fcmovbe,
+              'fcmovu':   fcmovu,
+              'fcmovnb':  fcmovnb,
+              'fcmovne':  fcmovne,
+              'fcmovnbe': fcmovnbe,
+              'fcmovnu':  fcmovnu,
+              'fnstenv': fnstenv,
+              'fldenv': fldenv,
+              'sidt': sidt,
+              'sldt': sldt,
+              'arpl': arpl,
+              'cmovz': cmovz,
+              'cmove': cmovz,
+              'cmovnz': cmovnz,
+              'cmovpe': cmovpe,
+              'cmovnp': cmovnp,
+              'cmovge': cmovge,
+              'cmovnl': cmovge,
+              'cmovg': cmovg,
+              'cmovl': cmovl,
+              'cmova': cmova,
+              'cmovae': cmovae,
+              'cmovbe': cmovbe,
+              'cmovb': cmovb,
+              'cmovnge': cmovl,
+              'cmovle': cmovle,
+              'cmovng': cmovle,
+              'cmovo': cmovo,
+              'cmovno': cmovno,
+              'cmovs': cmovs,
+              'cmovns': cmovns,
+              'icebp': icebp,
+              'int': l_int,
+              'xlat': xlat,
+              'bt': bt,
+              'cpuid': cpuid,
+              'fcom': fcom,
+              'ftst': ftst,
+              'fxam': fxam,
+              'ficom': ficom,
+              'fcomi': fcomi,
+              'fcomip': fcomip,
+              'fucomi': fucomi,
+              'fucomip': fucomip,
+              'insb': lambda ir, instr: ins(ir, instr, 8),
+              'insw': lambda ir, instr: ins(ir, instr, 16),
+              'insd': lambda ir, instr: ins(ir, instr, 32),
+              'btc': btc,
+              'bts': bts,
+              'btr': btr,
+              'into': into,
+              'in': l_in,
+              'outsb': lambda ir, instr: l_outs(ir, instr, 8),
+              'outsw': lambda ir, instr: l_outs(ir, instr, 16),
+              'outsd': lambda ir, instr: l_outs(ir, instr, 32),
+
+              'out': l_out,
+              "sysenter": l_sysenter,
+              "syscall": l_syscall,
+              "cmpxchg": cmpxchg,
+              "cmpxchg8b": cmpxchg8b,
+              "lds": lds,
+              "les": les,
+              "lss": lss,
+              "lfs": lfs,
+              "lgs": lgs,
+              "lahf": lahf,
+              "sahf": sahf,
+              "lar": lar,
+              "lsl": lsl,
+              "fclex": fclex,
+              "fnclex": fnclex,
+              "str": l_str,
+              "movd": movd,
+              "movdqu": movdqu,
+              "movdqa": movdqu,
+              "movapd": movapd,  # XXX TODO alignment check
+              "movupd": movapd,  # XXX TODO alignment check
+              "movaps": movapd,  # XXX TODO alignment check
+              "movups": movapd,  # XXX TODO alignment check
+              "andps": andps,
+              "andpd": andps,
+              "andnps": andnps,
+              "andnpd": andnps,
+              "orps": orps,
+              "orpd": orps,
+              "xorps": xorps,
+              "xorpd": xorps,
+
+              "movq": movq,
+
+              "pminsw": pminsw,
+              "cvtdq2pd": cvtdq2pd,
+              "cvtdq2ps": cvtdq2ps,
+              "cvtpd2dq": cvtpd2dq,
+              "cvtpd2pi": cvtpd2pi,
+              "cvtpd2ps": cvtpd2ps,
+              "cvtpi2pd": cvtpi2pd,
+              "cvtpi2ps": cvtpi2ps,
+              "cvtps2dq": cvtps2dq,
+              "cvtps2pd": cvtps2pd,
+              "cvtps2pi": cvtps2pi,
+              "cvtsd2si": cvtsd2si,
+              "cvtsd2ss": cvtsd2ss,
+              "cvtsi2sd": cvtsi2sd,
+              "cvtsi2ss": cvtsi2ss,
+              "cvtss2sd": cvtss2sd,
+              "cvtss2si": cvtss2si,
+              "cvttpd2pi": cvttpd2pi,
+              "cvttpd2dq": cvttpd2dq,
+              "cvttps2dq": cvttps2dq,
+              "cvttps2pi": cvttps2pi,
+              "cvttsd2si": cvttsd2si,
+              "cvttss2si": cvttss2si,
+
+
+              "bndmov": bndmov,
+
+
+
+
+              "movss": movss,
+
+              "ucomiss": ucomiss,
+              "ucomisd": ucomisd,
+
+              # BMI operations
+              "blsi": blsi,
+              "andn": andn,
+              "bextr": bextr,
+              "blsmsk": blsmsk,
+              "blsr": blsr,
+              "tzcnt": tzcnt,
+              "bzhi": bzhi,
+
+              #
+              # MMX/AVX/SSE operations
+
+              # Arithmetic (integers)
+              #
+
+              # Additions
+              # SSE
+              "paddb": paddb,
+              "paddw": paddw,
+              "paddd": paddd,
+              "paddq": paddq,
+
+              # Substractions
+              # SSE
+              "psubb": psubb,
+              "psubw": psubw,
+              "psubd": psubd,
+              "psubq": psubq,
+
+              # Multiplications
+              # SSE
+              "pmullb": pmullb,
+              "pmullw": pmullw,
+              "pmulld": pmulld,
+              "pmullq": pmullq,
+              "pmulhub": pmulhub,
+              "pmulhuw": pmulhuw,
+              "pmulhud": pmulhud,
+              "pmulhuq": pmulhuq,
+              "pmulhb": pmulhb,
+              "pmulhw": pmulhw,
+              "pmulhd": pmulhd,
+              "pmulhq": pmulhq,
+              "pmuludq": pmuludq,
+
+              # Mix
+              # SSE
+              "pmaddwd": pmaddwd,
+              "psadbw": psadbw,
+              "pavgb": pavgb,
+              "pavgw": pavgw,
+
+              # Arithmetic (floating-point)
+              #
+
+              # Additions
+              # SSE
+              "addss": addss,
+              "addsd": addsd,
+              "addps": addps,
+              "addpd": addpd,
+
+              # Substractions
+              # SSE
+              "subss": subss,
+              "subsd": subsd,
+              "subps": subps,
+              "subpd": subpd,
+
+              # Multiplications
+              # SSE
+              "mulss": mulss,
+              "mulsd": mulsd,
+              "mulps": mulps,
+              "mulpd": mulpd,
+
+              # Divisions
+              # SSE
+              "divss": divss,
+              "divsd": divsd,
+              "divps": divps,
+              "divpd": divpd,
+
+              # Rounding
+              "roundss": roundss,
+              "roundsd": roundsd,
+
+              # Comparisons (floating-point)
+              #
+              "minps": minps,
+              "minpd": minpd,
+              "minss": minss,
+              "minsd": minsd,
+              "maxps": maxps,
+              "maxpd": maxpd,
+              "maxss": maxss,
+              "maxsd": maxsd,
+              "cmpeqps": cmpeqps,
+              "cmpeqpd": cmpeqpd,
+              "cmpeqss": cmpeqss,
+              "cmpeqsd": cmpeqsd,
+              "cmpltps": cmpltps,
+              "cmpltpd": cmpltpd,
+              "cmpltss": cmpltss,
+              "cmpltsd": cmpltsd,
+              "cmpleps": cmpleps,
+              "cmplepd": cmplepd,
+              "cmpless": cmpless,
+              "cmplesd": cmplesd,
+              "cmpunordps": cmpunordps,
+              "cmpunordpd": cmpunordpd,
+              "cmpunordss": cmpunordss,
+              "cmpunordsd": cmpunordsd,
+              "cmpneqps": cmpneqps,
+              "cmpneqpd": cmpneqpd,
+              "cmpneqss": cmpneqss,
+              "cmpneqsd": cmpneqsd,
+              "cmpnltps": cmpnltps,
+              "cmpnltpd": cmpnltpd,
+              "cmpnltss": cmpnltss,
+              "cmpnltsd": cmpnltsd,
+              "cmpnleps": cmpnleps,
+              "cmpnlepd": cmpnlepd,
+              "cmpnless": cmpnless,
+              "cmpnlesd": cmpnlesd,
+              "cmpordps": cmpordps,
+              "cmpordpd": cmpordpd,
+              "cmpordss": cmpordss,
+              "cmpordsd": cmpordsd,
+
+              # Logical (floating-point)
+              #
+
+              "pand": pand,
+              "pandn": pandn,
+              "por": por,
+
+              "rdmsr": rdmsr,
+              "wrmsr": wrmsr,
+              "pshufb": pshufb,
+              "pshufd": pshufd,
+              "pshuflw": pshuflw,
+              "pshufhw": pshufhw,
+
+              "psrlw": psrlw,
+              "psrld": psrld,
+              "psrlq": psrlq,
+              "psllw": psllw,
+              "pslld": pslld,
+              "psllq": psllq,
+              "pslldq": pslldq,
+              "psrldq": psrldq,
+              "psraw": psraw,
+              "psrad": psrad,
+
+              "palignr": palignr,
+
+              "pmaxub": pmaxub,
+              "pmaxuw": pmaxuw,
+              "pmaxud": pmaxud,
+              "pmaxsw": pmaxsw,
+
+              "pminub": pminub,
+              "pminuw": pminuw,
+              "pminud": pminud,
+
+              "pcmpeqb": pcmpeqb,
+              "pcmpeqw": pcmpeqw,
+              "pcmpeqd": pcmpeqd,
+              "pcmpeqq": pcmpeqq,
+
+              "pcmpgtb": pcmpgtb,
+              "pcmpgtw": pcmpgtw,
+              "pcmpgtd": pcmpgtd,
+              "pcmpgtq": pcmpgtq,
+
+              "punpckhbw": punpckhbw,
+              "punpckhwd": punpckhwd,
+              "punpckhdq": punpckhdq,
+              "punpckhqdq": punpckhqdq,
+
+
+              "punpcklbw": punpcklbw,
+              "punpcklwd": punpcklwd,
+              "punpckldq": punpckldq,
+              "punpcklqdq": punpcklqdq,
+
+              "pinsrb": pinsrb,
+              "pinsrw": pinsrw,
+              "pinsrd": pinsrd,
+              "pinsrq": pinsrq,
+
+              "pextrb": pextrb,
+              "pextrw": pextrw,
+              "pextrd": pextrd,
+              "pextrq": pextrq,
+
+              "unpckhps": unpckhps,
+              "unpckhpd": unpckhpd,
+              "unpcklps": unpcklps,
+              "unpcklpd": unpcklpd,
+
+              "movlpd": movlpd,
+              "movlps": movlps,
+              "movhpd": movhpd,
+              "movhps": movhpd,
+              "movlhps": movlhps,
+              "movhlps": movhlps,
+              "movdq2q": movdq2q,
+              "movq2dq": movq2dq,
+
+              "sqrtpd": sqrtpd,
+              "sqrtps": sqrtps,
+              "sqrtsd": sqrtsd,
+              "sqrtss": sqrtss,
+
+              "pmovmskb": pmovmskb,
+
+              "packsswb": packsswb,
+              "packssdw": packssdw,
+              "packuswb": packuswb,
+
+              "psubusb": psubusb,
+              "psubusw": psubusw,
+              "paddusb": paddusb,
+              "paddusw": paddusw,
+              "psubsb": psubsb,
+              "psubsw": psubsw,
+              "paddsb": paddsb,
+              "paddsw": paddsw,
+
+              "smsw": smsw,
+              "maskmovq": maskmovq,
+              "maskmovdqu": maskmovq,
+              "emms": emms,
+              "shufps": shufps,
+              "shufpd": shufpd,
+              "movmskps": movmskps,
+              "movmskpd": movmskpd,
+              "stmxcsr": stmxcsr,
+              "ldmxcsr": ldmxcsr,
+
+              # CET (Control-flow Enforcement Technology)
+              "incssp": incssp,
+              "rdssp": rdssp,
+              "saveprevssp": saveprevssp,
+              "rstorssp": rstorssp,
+              "wrss": wrss,
+              "wruss": wruss,
+              "setssbsy": setssbsy,
+              "clrssbsy": clrssbsy,
+              "endbr64": endbr64,
+              "endbr32": endbr32,
+              "fxsave": fxsave,
+              "fxrstor": fxrstor,
+              }
+
+
+class Lifter_X86_16(Lifter):
+
+    def __init__(self, loc_db):
+        Lifter.__init__(self, mn_x86, 16, loc_db)
+        self.do_stk_segm = False
+        self.do_ds_segm = False
+        self.do_str_segm = False
+        self.do_all_segm = False
+        self.pc = IP
+        self.sp = SP
+        self.IRDst = m2_expr.ExprId('IRDst', 16)
+        # Size of memory pointer access in IR
+        # 16 bit mode memory accesses may be greater than 16 bits
+        # 32 bit size may be enough
+        self.addrsize = 32
+
+    def mod_pc(self, instr, instr_ir, extra_ir):
+        pass
+
+    def ExprMem(self, ptr, size):
+        """Generate a memory access to @ptr
+        The ptr is resized to a fixed size self.addrsize
+
+        @ptr: Expr instance to the memory address
+        @size: size of the memory"""
+
+        return m2_expr.ExprMem(expraddr(self.addrsize, ptr), size)
+
+    def gen_segm_expr(self, selector, addr):
+        ptr = m2_expr.ExprOp(
+            'segm',
+            selector,
+            addr.zeroExtend(self.addrsize)
+        )
+
+        return ptr
+
+    def get_ir(self, instr):
+        args = instr.args[:]
+        args = [arg.replace_expr(float_replace) for arg in args]
+        args = fix_mem_args_size(instr, *args)
+        my_ss = None
+        if self.do_ds_segm:
+            my_ss = DS
+        if self.do_all_segm and instr.additional_info.g2.value:
+            my_ss = {1: CS, 2: SS, 3: DS, 4: ES, 5: FS, 6: GS}[
+                instr.additional_info.g2.value]
+        if my_ss is not None:
+            for i, a in enumerate(args):
+                if a.is_mem() and not is_mem_segm(a):
+                    args[i] = self.ExprMem(m2_expr.ExprOp('segm', my_ss,
+                                                          a.ptr), a.size)
+
+        if not instr.name.lower() in mnemo_func:
+            raise NotImplementedError(
+                "Mnemonic %s not implemented" % instr.name)
+
+        instr_ir, extra_ir = mnemo_func[
+            instr.name.lower()](self, instr, *args)
+        self.mod_pc(instr, instr_ir, extra_ir)
+        instr.additional_info.except_on_instr = False
+        if instr.additional_info.g1.value & 14 == 0 or \
+                not instr.name in repeat_mn:
+            return instr_ir, extra_ir
+        if instr.name == "MOVSD" and len(instr.args) == 2:
+            return instr_ir, extra_ir
+
+        instr.additional_info.except_on_instr = True
+        admode = instr.v_admode()
+        c_reg = mRCX[instr.mode][:admode]
+
+        zf_val = None
+        # set if zf is tested (cmps, scas)
+        for e in instr_ir:  # +[updt_c]:
+            if e.dst == zf:
+                zf_val = e.src
+
+        cond_dec = m2_expr.ExprCond(c_reg - m2_expr.ExprInt(1, c_reg.size),
+                                    m2_expr.ExprInt(0, 1), m2_expr.ExprInt(1, 1))
+        # end condition
+        if zf_val is None:
+            c_cond = cond_dec
+        elif instr.additional_info.g1.value & 2:  # REPNE and REPNZ
+            c_cond = cond_dec | zf
+        elif instr.additional_info.g1.value & 12:  # REPE, REP and REPZ
+            c_cond = cond_dec | (zf ^ m2_expr.ExprInt(1, 1))
+
+        # gen while
+        loc_do, loc_do_expr = self.gen_loc_key_and_expr(self.IRDst.size)
+        loc_end, loc_end_expr = self.gen_loc_key_and_expr(self.IRDst.size)
+        loc_skip = self.get_next_loc_key(instr)
+        loc_skip_expr = m2_expr.ExprLoc(loc_skip, self.IRDst.size)
+        loc_next = self.get_next_loc_key(instr)
+        loc_next_expr = m2_expr.ExprLoc(loc_next, self.IRDst.size)
+
+        fix_next_loc = {loc_next_expr: loc_end_expr}
+        new_extra_ir = [irblock.modify_exprs(mod_src=lambda expr: expr.replace_expr(fix_next_loc))
+                        for irblock in extra_ir]
+
+        cond_bloc = []
+        cond_bloc.append(m2_expr.ExprAssign(c_reg,
+                                         c_reg - m2_expr.ExprInt(1,
+                                                                 c_reg.size)))
+        cond_bloc.append(m2_expr.ExprAssign(self.IRDst, m2_expr.ExprCond(c_cond,
+                                                                      loc_skip_expr,
+                                                                      loc_do_expr)))
+        cond_bloc = IRBlock(self.loc_db, loc_end, [AssignBlock(cond_bloc, instr)])
+        e_do = instr_ir
+
+        c = IRBlock(self.loc_db, loc_do, [AssignBlock(e_do, instr)])
+        e_n = [m2_expr.ExprAssign(self.IRDst, m2_expr.ExprCond(c_reg, loc_do_expr,
+                                                            loc_skip_expr))]
+        return e_n, [cond_bloc, c] + new_extra_ir
+
+    def expr_fix_regs_for_mode(self, e, mode=64):
+        return e.replace_expr(replace_regs[mode])
+
+    def expraff_fix_regs_for_mode(self, e, mode=64):
+        dst = self.expr_fix_regs_for_mode(e.dst, mode)
+        src = self.expr_fix_regs_for_mode(e.src, mode)
+        return m2_expr.ExprAssign(dst, src)
+
+    def irbloc_fix_regs_for_mode(self, irblock, mode=64):
+        irs = []
+        for assignblk in irblock:
+            new_assignblk = dict(assignblk)
+            for dst, src in viewitems(assignblk):
+                del new_assignblk[dst]
+                # Special case for 64 bits:
+                # If destination is a 32 bit reg, zero extend the 64 bit reg
+                if mode == 64:
+                    if (isinstance(dst, m2_expr.ExprId) and
+                            dst.size == 32 and
+                            dst in replace_regs[64]):
+                        src = src.zeroExtend(64)
+                        dst = replace_regs[64][dst].arg
+                dst = self.expr_fix_regs_for_mode(dst, mode)
+                src = self.expr_fix_regs_for_mode(src, mode)
+                new_assignblk[dst] = src
+            irs.append(AssignBlock(new_assignblk, assignblk.instr))
+        return IRBlock(self.loc_db, irblock.loc_key, irs)
+
+
+class Lifter_X86_32(Lifter_X86_16):
+
+    def __init__(self, loc_db):
+        Lifter.__init__(self, mn_x86, 32, loc_db)
+        self.do_stk_segm = False
+        self.do_ds_segm = False
+        self.do_str_segm = False
+        self.do_all_segm = False
+        self.pc = EIP
+        self.sp = ESP
+        self.IRDst = m2_expr.ExprId('IRDst', 32)
+        self.addrsize = 32
+
+
+class Lifter_X86_64(Lifter_X86_16):
+
+    def __init__(self, loc_db):
+        Lifter.__init__(self, mn_x86, 64, loc_db)
+        self.do_stk_segm = False
+        self.do_ds_segm = False
+        self.do_str_segm = False
+        self.do_all_segm = False
+        self.pc = RIP
+        self.sp = RSP
+        self.IRDst = m2_expr.ExprId('IRDst', 64)
+        self.addrsize = 64
+
+    def mod_pc(self, instr, instr_ir, extra_ir):
+        # fix RIP for 64 bit
+        pc_fixed = {self.pc: m2_expr.ExprInt(instr.offset + instr.l, 64)}
+
+        for i, expr in enumerate(instr_ir):
+            dst, src = expr.dst, expr.src
+            if dst != self.pc:
+                dst = dst.replace_expr(pc_fixed)
+            src = src.replace_expr(pc_fixed)
+            instr_ir[i] = m2_expr.ExprAssign(dst, src)
+
+        for idx, irblock in enumerate(extra_ir):
+            extra_ir[idx] = irblock.modify_exprs(lambda expr: expr.replace_expr(pc_fixed) \
+                                                 if expr != self.pc else expr,
+                                                 lambda expr: expr.replace_expr(pc_fixed))