//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#pragma once

//
// Contains constants and tables used by the encoder.
//
#include "AssemblyStep.h"

// THUMB2 specific decl
typedef unsigned int ENCODE_32;
// THUMB1 specific decl.
typedef unsigned short ENCODE_16;
typedef unsigned char ENCODE_8;

#define MaxCondBranchOffset ((1 << 20) - 2)

#define RETURN_REG          RegR0
#define FIRST_INT_ARG_REG   RegR0
#define LAST_INT_ARG_REG    RegR3
#define NUM_INT_ARG_REGS\
    ((LAST_INT_ARG_REG - FIRST_INT_ARG_REG) + 1)
#define FIRST_CALLEE_SAVED_GP_REG RegR4
#define LAST_CALLEE_SAVED_GP_REG  RegR10
#define SCRATCH_REG         RegR12
#define ALT_LOCALS_PTR      RegR7
#define EH_STACK_SAVE_REG   RegR6
#define SP_ALLOC_SCRATCH_REG RegR4
#define CATCH_OBJ_REG       RegR1

#define RETURN_DBL_REG      RegD0
#define FIRST_CALLEE_SAVED_DBL_REG RegD8
#define LAST_CALLEE_SAVED_DBL_REG  RegD15
#define FIRST_CALLEE_SAVED_DBL_REG_NUM 8
#define LAST_CALLEE_SAVED_DBL_REG_NUM 15
#define CALLEE_SAVED_DOUBLE_REG_COUNT 8

// See comment in LowerEntryInstr: even in a global function, we'll home r0 and r1
#define MIN_HOMED_PARAM_REGS 2
// THUMB Specific
#define MAX_INT_REGISTERS_LOW     8
#define LOW_INT_REGISTERS_MASK    0x7

#define FRAME_REG           RegR11

#define DMOVE              0x0001
#define DLOAD              0x0002
#define DSTORE             0x0003
#define DMASK              0x0007
#define DHALFORSB          0x0020    // halfword or signed byte
#define DCONDEXE           0x0040    // safe for conditional execution
#define DSUPDATE           0x0100
#define DSSUB              0x0200
#define DSPOST             0x0400
#define DSBIT              0x0800
#define DQBR               0x1000 // Qualcomm buggy branch instructions see macro SOFTWARE_FIXFOR_HARDWARE_BUGWIN8_502326

#define D____              (0)
#define D___C              (DCONDEXE)
#define DQ__C              (DQBR | DCONDEXE)
#define D__SC              (DSBIT)
#define DM___              (DMOVE)
#define DM__C              (DMOVE | DCONDEXE)
#define DL___              (DLOAD)
#define DL__C              (DLOAD | DCONDEXE)
#define DLH__              (DLOAD | DHALFORSB)
#define DLH_C              (DLOAD | DHALFORSB | DCONDEXE)
#define DS___              (DSTORE)
#define DS__C              (DSTORE | DCONDEXE)
#define DSH__              (DSTORE | DHALFORSB)
#define DSH_C              (DSTORE | DHALFORSB | DCONDEXE)
#define DLUP_C             (DLOAD | DSUPDATE | DSPOST)
#define DLUPQC             (DLOAD | DSUPDATE | DSPOST | DQBR)
#define DSUS_C             (DSTORE | DSUPDATE | DSSUB)

#define ISMOVE(o)          ((EncoderMD::GetOpdope(o) & DMASK) == DMOVE)
#define ISLOAD(o)          ((EncoderMD::GetOpdope(o) & DMASK) == DLOAD)
#define ISSTORE(o)         ((EncoderMD::GetOpdope(o) & DMASK) == DSTORE)

#define ISSHIFTERUPDATE(o) ((EncoderMD::GetOpdope(o) & DSUPDATE) != 0)
#define ISSHIFTERSUB(o)    ((EncoderMD::GetOpdope(o) & DSSUB) != 0)
#define ISSHIFTERPOST(o)   ((EncoderMD::GetOpdope(o) & DSPOST) != 0)

#define SETS_SBIT(o)       ((EncoderMD::GetOpdope(o) & DSBIT) != 0)
#define ISQBUGGYBR(o)      ((EncoderMD::GetOpdope(o) & DQBR) != 0)

static const uint32 Opdope[] =
{
#define MACRO(name, jnLayout, attrib, byte2, form, opbyte, dope, ...) dope,
#include "MdOpCodes.h"
#undef MACRO
};

static const BYTE RegEncode[] =
{
#define REGDAT(Name, Listing, Encoding, ...) Encoding,
#include "RegList.h"
#undef REGDAT
};

#define REGBIT(reg)             (1 << RegEncode[reg])
#define TESTREGBIT(mask, reg)   (((mask) & REGBIT(reg)) != 0)
#define SETREGBIT(mask, reg)    ((mask) |= REGBIT(reg))
#define CLEARREGBIT(mask, reg)  ((mask) &= ~REGBIT(reg))
#define ZEROREGMASK(mask)       ((mask) = 0)
#define REGMASKEMPTY(mask)      ((mask) == 0)

#define CO_UIMMED8(intConst)        ((intConst) & 0xff) // 8 bit unsigned immediate

// Used by GenerateInstrs
#define CASE_OPCODES_ALWAYS_THUMB2      \
    case Js::OpCode::ADDW:              \
    case Js::OpCode::LDRRET:            \
    case Js::OpCode::MLS:               \
    case Js::OpCode::MOVT:              \
    case Js::OpCode::MOVW:              \
    case Js::OpCode::MOV_W:             \
    case Js::OpCode::NOP_W:             \
    case Js::OpCode::SDIV:              \
    case Js::OpCode::SUBW:              \
    case Js::OpCode::TIOFLW:            \
    case Js::OpCode::CLRSIGN:           \
    case Js::OpCode::SBCMPLNT:          \
    case Js::OpCode::PLD:               \
    case Js::OpCode::CLZ:


#define CASE_OPCODES_NEVER_THUMB2           \
    case Js::OpCode::DEBUGBREAK:            \
    case Js::OpCode::NOP:                   \
    case Js::OpCode::BLX:                   \
    case Js::OpCode::BX:                    \
    case Js::OpCode::RET:


#define IS_LOWREG(RegNum) (RegNum < RegR8)

#define IS_CONST_00000007(x) (((x) & ~0x00000007) == 0)
#define IS_CONST_0000001F(x) (((x) & ~0x0000001f) == 0)
#define IS_CONST_0000007F(x) (((x) & ~0x0000007f) == 0)
#define IS_CONST_000000FF(x) (((x) & ~0x000000ff) == 0)
#define IS_CONST_000003FF(x) (((x) & ~0x000003ff) == 0)
#define IS_CONST_00000FFF(x) (((x) & ~0x00000fff) == 0)
#define IS_CONST_0000FFFF(x) (((x) & ~0x0000ffff) == 0)
#define IS_CONST_000FFFFF(x) (((x) & ~0x000fffff) == 0)
#define IS_CONST_007FFFFF(x) (((x) & ~0x007fffff) == 0)

#define IS_CONST_NEG_8(x)    (((x) & ~0x0000007f) == ~0x0000007f)
#define IS_CONST_NEG_12(x)   (((x) & ~0x000007ff) == ~0x000007ff)
#define IS_CONST_NEG_21(x)   (((x) & ~0x000fffff) == ~0x000fffff)
#define IS_CONST_NEG_24(x)   (((x) & ~0x007fffff) == ~0x007fffff)

#define IS_CONST_INT8(x)     (IS_CONST_0000007F(x) || IS_CONST_NEG_8(x))
#define IS_CONST_INT12(x)    (IS_CONST_00000FFF(x) || IS_CONST_NEG_12(x))
#define IS_CONST_INT21(x)    (IS_CONST_000FFFFF(x) || IS_CONST_NEG_21(x))
#define IS_CONST_INT24(x)    (IS_CONST_007FFFFF(x) || IS_CONST_NEG_24(x))

#define IS_CONST_UINT3(x)    IS_CONST_00000007(x)
#define IS_CONST_UINT5(x)    IS_CONST_0000001F(x)
#define IS_CONST_UINT7(x)    IS_CONST_0000007F(x)
#define IS_CONST_UINT8(x)    IS_CONST_000000FF(x)
#define IS_CONST_UINT10(x)   IS_CONST_000003FF(x)
#define IS_CONST_UINT12(x)   IS_CONST_00000FFF(x)
#define IS_CONST_UINT16(x)   IS_CONST_0000FFFF(x)


typedef struct _FormTable
{
    int form;
    ENCODE_32 inst;
    const AssemblyStep * steps;
} FormTable;

#define FDST(_form)         (FORM_ ## _form)
#define FSET(_form, _bits)  (FORM_ ## _form << _bits)
#define FSRC(_form,_opnum)  (FORM_ ## _form << ((_opnum) * FORM_BITS_PER_OPN))
#define FDST2(_form,_opnum) (FORM_ ## _form << ((_opnum) * FORM_BITS_PER_OPN))
#define FTHUMB2             (FORM_ ## THUMB2 << 28)
#define FTHUMB              (FORM_ ## THUMB << 28)

#define THUMB2_THUMB1_FORM(FTP,IFORM) \
        ( (FTP) == (((IFORM) & 0x0FFFFFFF) | FTHUMB))

// NOTE if we end up with a form with more than six operands the IFORM
// encoding needs to be reworked.  (runs out of bits)
typedef enum tagIFORM
{
    IFORM_A       = 1,  // This is used in mdtupdat.h, and must be IFORM type

    // CONSIDER: we seem to have some collisions here
    //  (is there a way to cleanup this? we'd need more than 16 values)

    FORM_REG      = 1,
    FORM_SREG     = 2,  // VFP single precision register
    FORM_DREG     = 3,  // VFP double precision register
    FORM_XREG     = 7,
    FORM_WREG     = 8,  // maps to "wR"
    FORM_WCREG    = 9,  // maps to "wC"
    FORM_CONST    = 4,
    FORM_INDIR    = 5,

    FORM_LABEL    = 6,
    FORM_CODE     = 7,

    FORM_PC       = 6,
    FORM_SP       = 7,
    FORM_CC       = 10,

    FORM_HREG     = 2,
    FORM_ACC      = 3,
    FORM_SR       = 5,

    FORM_NREG     = 11, // NEON 64bit register
    FORM_QREG     = 12, // NEON 128bit register

    FORM_THUMB    = 2,
    FORM_THUMB2   = 8,
    FORM_ARM      = 4,

    FORM_BITS_PER_OPN  = 4,

    FORM__________  = 0,
    FORM_2________  = FTHUMB2,
    FORM_T________  = FTHUMB,

    FORM_Trrc_____  = FTHUMB | FDST(REG) | FSRC(REG,1) | FSRC(CONST,2),
    FORM_Trc______  = FTHUMB | FDST(REG) | FSRC(CONST, 1),
    FORM_TrcC_____  = FTHUMB | FDST(REG) | FSRC(CONST, 1) | FSRC(CC,2),
    FORM_Trrr_____  = FTHUMB | FDST(REG) | FSRC(REG,1) | FSRC(REG,2),
    FORM_Trr______  = FTHUMB | FDST(REG) | FSRC(REG,1),
    FORM_TrC_____   = FTHUMB | FDST(REG) | FSRC(CC,1),
    FORM_TrrC_____  = FTHUMB | FDST(REG) | FSRC(REG,1) | FSRC(CC,2),
    FORM_Tr_______  = FTHUMB | FDST(REG),
    FORM_T_r______  = FTHUMB | FSRC(REG,1),
    FORM_T_rc_____  = FTHUMB | FSRC(REG,1) | FSRC(CONST, 2),
    FORM_T_rr_____  = FTHUMB | FSRC(REG,1) | FSRC(REG,2),
    FORM_Thr______  = FTHUMB | FSET(REG,28) | FSRC(REG,1),
    FORM_Th_r_____  = FTHUMB | FSET(REG,28) | FDST(REG),
    FORM_Th_rr____  = FTHUMB | FSET(REG,28) | FSRC(REG,1) | FSRC(REG,2),
    FORM_T_spr____  = FTHUMB | FSRC(SP,1) | FSRC(REG,2),
    FORM_Th_spr___  = FTHUMB | FSET(REG,28) | FSRC(SP,1) | FSRC(REG,2),

    // Thumb2
    FORM_2rrrcc___  = FTHUMB2 | FDST(REG) | FSRC(REG,1) | FSRC(REG,2) | FSRC(CONST,3) | FSRC(CONST,4),
    FORM_2rrrccC__  = FTHUMB2 | FDST(REG) | FSRC(REG,1) | FSRC(REG,2) | FSRC(CONST,3) | FSRC(CONST,4) | FSRC(CC,5),
    FORM_2rrc_____  = FTHUMB2 | FDST(REG) | FSRC(REG, 1) | FSRC(CONST, 2),
    FORM_2rrr_____  = FTHUMB2 | FDST(REG) | FSRC(REG,1) | FSRC(REG,2),
    FORM_2rrrc____  = FTHUMB2 | FDST(REG) | FSRC(REG,1) | FSRC(REG,2) | FSRC(CONST, 3),
    FORM_2rc______  = FTHUMB2 | FDST(REG) | FSRC(CONST, 1),
    FORM_2rcc_____  = FTHUMB2 | FDST(REG) | FSRC(CONST, 1) | FSRC(CONST, 2),
    FORM_2rrcc____  = FTHUMB2 | FDST(REG) | FSRC(REG,1) | FSRC(CONST, 2) | FSRC(CONST, 3),
    FORM_2rrcC____  = FTHUMB2 | FDST(REG) | FSRC(REG,1) | FSRC(CONST, 2) | FSRC(CC, 3),
    FORM_2rr______  = FTHUMB2 | FDST(REG) | FSRC(REG,1),
    FORM_2ipcc____  = FTHUMB2 | FDST(INDIR) | FSRC(PC,1) | FSRC(CONST,2),
    FORM_2ispc____  = FTHUMB2 | FDST(INDIR) | FSRC(SP,1) | FSRC(CONST,2),
    FORM_2risp____  = FTHUMB2 | FDST(REG) | FSRC(INDIR,1) | FSRC(SP,2),
    FORM_2rrC_____  = FTHUMB2 | FDST(REG) | FSRC(REG,1) | FSRC(CC,2),
    FORM_ThrC_____  = FTHUMB | FSET(REG,28) | FDST(REG) | FSRC(CC,1),
    FORM_ThrrC____  = FTHUMB | FSET(REG,28) | FDST(REG) | FSRC(REG,1) | FSRC(CC,2),
    FORM_TrhrC____  = FTHUMB | FDST(REG) | FSET(REG,28) |FSRC(REG,1) | FSRC(CC,2),
    FORM_ThrhrC___  = FTHUMB | FDST(REG) | FSET(REG,28) |FSRC(REG,1) | FSRC(CC,2),
    FORM_Tspsp____  = FTHUMB | FDST(SP) | FSRC(SP,1),

    FORM_2irr_____  = FTHUMB2 | FDST(INDIR) | FSRC(REG,1) | FSRC(REG,2),
    FORM_2ircrr___  = FTHUMB2 | FDST(INDIR) | FSRC(REG,1) | FSRC(CONST,2) | FSRC(REG,3) | FSRC(REG,4),
    FORM_2ispcrr__  = FTHUMB2 | FDST(INDIR) | FSRC(SP,1) | FSRC(CONST,2) | FSRC(REG,3) | FSRC(REG,4),

    // MOVW with relocation
    FORM_2rlsp____  = FTHUMB2 | FDST(REG) | FSRC(LABEL,1) | FSRC(SP,2),
    FORM_2re______  = FTHUMB2 | FDST(REG) | FSRC(CODE,1),
    FORM_2rl______  = FTHUMB2 | FDST(REG) | FSRC(LABEL,1),
    // MOVW with PAIR relocation
    FORM_2rlspc___  = FTHUMB2 | FDST(REG) | FSRC(LABEL,1) | FSRC(SP,2) | FSRC(CONST, 3),

    // MOVT with relocation
    FORM_2rlspr___  = FTHUMB2 | FDST(REG) | FSRC(LABEL,1) | FSRC(SP,2) | FSRC(REG,3),
    FORM_2rer_____  = FTHUMB2 | FDST(REG) | FSRC(CODE,1) | FSRC(REG,2),
    FORM_2rlr_____  = FTHUMB2 | FDST(REG) | FSRC(LABEL,1) | FSRC(REG,2),
    FORM_2rlsprc__  = FTHUMB2 | FDST(REG) | FSRC(LABEL,1) | FSRC(SP,2) | FSRC(REG,3) | FSRC(CONST, 4),

    //ADD
    FORM_Trpcc____  = FTHUMB | FDST(REG) | FSRC(PC,1) | FSRC(CONST,2),
    FORM_Trspc____  = FTHUMB | FDST(REG) | FSRC(SP,1) | FSRC(CONST,2),
    FORM_2rspc____  = FTHUMB2 | FDST(REG) | FSRC(SP,1) | FSRC(CONST,2),
    FORM_2sprc____  = FTHUMB2 | FDST(SP) | FSRC(REG,1) | FSRC(CONST,2),
    FORM_Tsphr____  = FTHUMB | FDST(SP) | FSET(REG, 28) | FSRC(REG,1),
    FORM_Trpc_____  = FTHUMB | FDST(REG) | FSRC(PC,1),
    //ADD, MOVH
    FORM_Trsp_____ = FTHUMB | FDST(REG) | FSRC(SP,1),
    FORM_Thrsp____ = FTHUMB | FSET(REG,28) |FDST(REG) | FSRC(SP,1),

    // ADD, SUB sp,sp,#imm
    FORM_2spspc___  = FTHUMB2 | FDST(SP) | FSRC(SP,1) | FSRC(CONST,2),
    FORM_2rrrC____  = FTHUMB2 | FDST(REG) | FSRC(REG,1) | FSRC(REG,2) | FSRC(CC,3),

    FORM_Tspspc___  = FTHUMB | FDST(SP) | FSRC(SP,1) | FSRC(CONST,2),
    FORM_Tspspr___  = FTHUMB | FDST(SP) | FSRC(SP,1) | FSRC(REG,2),
    FORM_Tspsphr__  = FTHUMB | FDST(SP) | FSET(REG, 28) | FSRC(SP,1) | FSRC(REG,2),
    FORM_Tpcpcr___  = FTHUMB | FDST(PC) | FSRC(PC,1) | FSRC(REG,2),

    //CMP
    FORM_2_r______ = FTHUMB2 | FSRC(REG,1),
    FORM_2_rr_____ = FTHUMB2 | FSRC(REG,1) |FSRC(REG,2),
    FORM_2_rc_____ = FTHUMB2 | FSRC(REG,1) |FSRC(CONST,2),

    //TBB, TBH
    FORM_2_irr____ = FTHUMB2 | FSRC(INDIR,1) | FSRC(REG,2) | FSRC(REG,3),
    FORM_2_irrc___ = FTHUMB2 | FSRC(INDIR,1) | FSRC(REG,2) | FSRC(REG,3) | FSRC(CONST,4),
    FORM_2_ipcr___ = FTHUMB2 | FSRC(INDIR,1) | FSRC(PC,2) | FSRC(REG,3),
    FORM_2_ipcrc__ = FTHUMB2 | FSRC(INDIR,1) | FSRC(PC,2) | FSRC(REG,3) | FSRC(CONST,4),

    //PLD
    FORM_2_irc____ = FTHUMB2 | FSRC(INDIR,1) | FSRC(REG,2) | FSRC(CONST,3),

    //B,BL,BCALL,BBL
    FORM_2l_______ = FTHUMB2 | FSRC(LABEL,1),
    FORM_2lC______ = FTHUMB2 | FSRC(LABEL,1) | FSRC(CC,2),
    FORM_2e_______ = FTHUMB2 | FSRC(CODE,1),
    FORM_Tl_______ = FTHUMB | FSRC(LABEL,1),
    FORM_TlC______ = FTHUMB | FSRC(LABEL,1) | FSRC(CC,2),
    FORM_Te_______ = FTHUMB | FSRC(CODE,1),

    //MULL, UMULL
    FORM_2rrrr____ = FTHUMB2 | FDST(REG) | FSRC(REG,1) | FSRC(REG,2) | FSRC(REG,3),

    //SMLAL, UMLAL
    FORM_2rrrrr___ = FTHUMB2 | FDST(REG) | FSRC(REG,1) | FSRC(REG,2) | FSRC(REG,3) | FSRC(REG,4),

    //LDRRET
    FORM_2pcispc__ = FTHUMB2 | FDST(PC) | FSRC(INDIR,1) | FSRC(SP,2) | FSRC(CONST,3),

    //LDR
    FORM_2rirc____ = FTHUMB2 | FDST(REG) | FSRC(INDIR,1) | FSRC(REG,2) | FSRC(CONST,3),
    FORM_2rispc___ = FTHUMB2 | FDST(REG) | FSRC(INDIR,1) | FSRC(SP,2) | FSRC(CONST,3),
    FORM_2ripcc___ = FTHUMB2 | FDST(REG) | FSRC(INDIR,1) | FSRC(PC,2) | FSRC(CONST,3),
    FORM_2rirr____ = FTHUMB2 | FDST(REG) | FSRC(INDIR,1) | FSRC(REG,2) | FSRC(REG,3),
    FORM_2rispr___ = FTHUMB2 | FDST(REG) | FSRC(INDIR,1) | FSRC(SP,2) | FSRC(REG,3),
    FORM_2rirrc___ = FTHUMB2 | FDST(REG) | FSRC(INDIR,1) | FSRC(REG,2) | FSRC(REG,3) | FSRC(CONST,4),

    FORM_Trirc____ = FTHUMB | FDST(REG) | FSRC(INDIR,1) | FSRC(REG,2) | FSRC(CONST,3),
    FORM_Trirr____ = FTHUMB | FDST(REG) | FSRC(INDIR,1) | FSRC(REG,2) | FSRC(REG,3),
    FORM_Tripcc___ = FTHUMB | FDST(REG) | FSRC(INDIR,1) | FSRC(PC,2) | FSRC(CONST,3),
    FORM_Trispc___ = FTHUMB | FDST(REG) | FSRC(INDIR,1) | FSRC(SP,2) | FSRC(CONST,3),
    //LDR SYM
    FORM_2ri______ = FTHUMB2 | FDST(REG) | FSRC(INDIR,1),
    FORM_2ripc____ = FTHUMB2 | FDST(REG) | FSRC(INDIR,1) | FSRC(PC,2),
    FORM_Tri______ = FTHUMB | FDST(REG) | FSRC(INDIR,1),
    FORM_Trisp____ = FTHUMB | FDST(REG) | FSRC(INDIR,1) | FSRC(SP,2),
    FORM_Tripc____ = FTHUMB | FDST(REG) | FSRC(INDIR,1) | FSRC(PC,2),

    //STR
    FORM_2ircr____ = FTHUMB2 | FDST(INDIR) | FSRC(REG,1) | FSRC(CONST,2) | FSRC(REG,3),
    FORM_2ispcr___ = FTHUMB2 | FDST(INDIR) | FSRC(SP,1) | FSRC(CONST,2) | FSRC(REG,3),
    FORM_2irrr____ = FTHUMB2 | FDST(INDIR) | FSRC(REG,1) | FSRC(REG,2) | FSRC(REG,3),
    FORM_2irrrc___ = FTHUMB2 | FDST(INDIR) | FSRC(REG,1) | FSRC(REG,2) | FSRC(REG,3) | FSRC(CONST,4),
    FORM_2isprr___ = FTHUMB2 | FDST(INDIR) | FSRC(SP,1) | FSRC(REG,2) | FSRC(REG,3),
    FORM_2ispr____ = FTHUMB2 | FDST(INDIR) | FSRC(SP,1) | FSRC(REG,2),
    FORM_2ir______ = FTHUMB2 | FDST(INDIR) | FSRC(REG,1),
    FORM_2irsp____ = FTHUMB2 | FDST(INDIR) | FSRC(REG,1) | FSRC(SP,2),

    FORM_Tircr____ = FTHUMB | FSRC(INDIR,0) | FSRC(REG,1) | FSRC(CONST,2) | FSRC(REG,3),
    FORM_Tirrr____ = FTHUMB | FDST(INDIR) | FSRC(REG,1) | FSRC(REG,2) | FSRC(REG,3),
    FORM_Tispcr___ = FTHUMB | FDST(INDIR) | FSRC(SP,1) | FSRC(CONST,2) | FSRC(REG,3),
    FORM_Tir______ = FTHUMB | FDST(INDIR) | FSRC(REG,1),
    FORM_Tispr____ = FTHUMB | FDST(INDIR) | FSRC(SP,1) | FSRC(REG,2),
    FORM_Tipcr____ = FTHUMB | FDST(INDIR) | FSRC(PC,1) | FSRC(REG,2),
    FORM_Tirsp____ = FTHUMB | FDST(INDIR) | FSRC(REG,1) | FSRC(SP,2),


    //STM/LDM
    FORM_Tispc____ = FTHUMB | FDST(INDIR) | FSRC(SP,1) | FSRC(CONST,2),
    FORM_Tirc_____ = FTHUMB | FDST(INDIR) | FSRC(REG,1) | FSRC(CONST,2),
    FORM_2pirc____ = FTHUMB2 | FSRC(INDIR,1) | FSRC(REG,2) | FSRC(CONST,3),
    FORM_2pirr____ = FTHUMB2 | FSRC(INDIR,1) | FSRC(REG,2) | FSRC(REG,3),
    FORM_2pirrc___ = FTHUMB2 | FSRC(INDIR,1) | FSRC(REG,2) | FSRC(REG,3) | FSRC(CONST,4),
    FORM_2irc_____ = FTHUMB2 | FDST(INDIR) | FSRC(REG,1) | FSRC(CONST,2),

    //LDMRET
    FORM_Tspispc__ = FTHUMB | FDST(SP) | FSRC(INDIR,1) | FSRC(SP,2) | FSRC(CONST,3),

    //MOVH
    FORM_Tspr_____ = FTHUMB | FDST(SP) | FSRC(REG,1),
    FORM_Thrr_____ = FTHUMB | FSET(REG,28) | FDST(REG) | FSRC(REG,1),
    FORM_2sphr____ = FTHUMB2 | FSET(REG,28) |FDST(SP) | FSRC(REG,1),
    FORM_2hrpc____ = FTHUMB2 | FSET(REG,28) | FDST(REG) | FSRC(PC,1),
    FORM_2rpc_____ = FTHUMB2 | FDST(REG) | FSRC(PC,1),

    //LDM
    FORM_Tric_____ = FTHUMB | FDST(REG) | FSRC(INDIR,1) | FSRC(CONST,1),
    FORM_Ticr_____ = FTHUMB | FDST(INDIR) | FSRC(CONST,1) | FSRC(REG,2),

    // CBZ
    FORM_2lr______ = FTHUMB2 | FSRC(LABEL,1) | FSRC(REG,2),
    FORM_2er______ = FTHUMB2 | FSRC(CODE,1) | FSRC(REG,2),

    //LEA
    FORM_Trl______ = FTHUMB | FDST(REG) | FSRC(LABEL,1),
    FORM_Trlsp____ = FTHUMB | FDST(REG) | FSRC(LABEL,1) | FSRC(SP,2),
    FORM_Tspl_____ = FTHUMB | FDST(SP) | FSRC(LABEL,1),

    //RET pc, r
    FORM_Tpchr____ = FTHUMB | FDST(PC) | FSET(REG,28) | FSRC(REG,1),
    FORM_Tpcr_____ = FTHUMB | FDST(PC) | FSRC(REG,1),
    FORM_Tpcriw___ = FTHUMB | FDST(PC) | FSRC(REG,1) | FSRC(REG,2),
    FORM_Tpchriw__ = FTHUMB | FDST(PC) | FSET(REG,28) | FSRC(REG,1) | FSRC(REG,2),

    //DCD
    FORM_Tlsp_____ = FTHUMB | FSRC(LABEL,1) | FSRC(SP,2),
    FORM_Tc_______ = FTHUMB | FSRC(CONST,1),
    FORM_2r_______ = FTHUMB2 | FDST(REG),
    FORM_2c_______ = FTHUMB2 | FSRC(CONST,1),
    FORM_Tcll_____ = FTHUMB | FSRC(CONST,1) | FSRC(LABEL,2) | FSRC(LABEL,3),
    FORM_Tcee_____ = FTHUMB | FSRC(CONST,1) | FSRC(CODE,2) | FSRC(CODE,3),


    FORM_2rrcrc___ = FTHUMB2 | FDST(REG) | FSRC(REG,1) | FSRC(CONST,2) | FSRC(REG,3) | FSRC(CONST,4),
    FORM_2rrrrcrc_ = FTHUMB2 | FDST(REG) | FSRC(REG,1) | FSRC(REG,2) | FSRC(REG,3) | FSRC(CONST,4) | FSRC(REG,5) | FSRC(CONST,6),

    // MRS, MSR
    FORM_2rsrc____ = FTHUMB2 | FDST(REG) | FSRC(SR,1) | FSRC(CONST, 2),
    FORM_2srrcc___ = FTHUMB2 | FDST(SR) | FSRC(REG,1) | FSRC(CONST, 2) | FSRC(CONST, 3),

    // MCRR, MRRC
    FORM_2cprr____ = FTHUMB2 | FSRC(CONST,1) | FSRC(REG,2) | FSRC(REG,3),
    FORM_2rcp_____ = FTHUMB2 | FDST(REG) | FSRC(CONST,1),

    // MAR, MRA
    FORM_2acprr___ = FTHUMB2 | FDST(ACC) | FSRC(CONST,1) | FSRC(REG,2) | FSRC(REG,3),
    FORM_2rcpa____ = FTHUMB2 | FDST(REG) | FSRC(CONST,1) | FSRC(ACC,2),

    // MCR, MRC
    FORM_2crcccc__ = FTHUMB2 | FSRC(CONST,1) | FSRC(REG,2) | FSRC(CONST, 3) | FSRC(CONST,4) | FSRC(CONST,5) | FSRC(CONST,6),
    FORM_2rccccc__ = FTHUMB2 | FDST(REG) | FSRC(CONST,1) | FSRC(CONST, 2) | FSRC(CONST,3) | FSRC(CONST,4) | FSRC(CONST,5),

    // WLDR
    FORM_2rcr_____ = FTHUMB2 | FDST(REG) | FSRC(CONST,1) | FSRC(REG,2),
    FORM_2rcrr____ = FTHUMB2 | FDST(REG) | FSRC(CONST,1) | FSRC(REG,2) | FSRC(REG,3),
    FORM_2rcrrr___ = FTHUMB2 | FDST(REG) | FSRC(CONST,1) | FSRC(REG,2) | FSRC(REG,3) | FSRC(REG,4),
    FORM_2rcrrrr__ = FTHUMB2 | FDST(REG) | FSRC(CONST,1) | FSRC(REG,2) | FSRC(REG,3) | FSRC(REG,4) | FSRC(REG,5),

    //FLOAT Forms
    FORM_2dd______ = FTHUMB2 | FDST(DREG) | FSRC(DREG,1),
    FORM_2ddd_____ = FTHUMB2 | FDST(DREG) | FSRC(DREG,1) | FSRC(DREG,2),
    FORM_2_dd_____ = FTHUMB2 | FSRC(DREG,1) | FSRC(DREG,2),
    FORM_2dr______ = FTHUMB2 | FDST(DREG) | FSRC(REG,1),
    FORM_2rd______ = FTHUMB2 | FDST(REG)  | FSRC(DREG,1),
    FORM_2dirc____ = FTHUMB2 | FDST(DREG) | FSRC(INDIR,1) | FSRC(REG,2) | FSRC(CONST,3),
    FORM_2disp____ = FTHUMB2 | FDST(DREG) | FSRC(INDIR,1) | FSRC(SP,2),
    FORM_2dispc___ = FTHUMB2 | FDST(DREG) | FSRC(INDIR,1) | FSRC(SP,2) | FSRC(CONST,3),
    FORM_2ircd____ = FTHUMB2 | FDST(INDIR) | FSRC(REG,1) | FSRC(CONST,2) | FSRC(DREG,3),
    FORM_2ispd____ = FTHUMB2 | FDST(INDIR) | FSRC(SP,1) | FSRC(DREG,2),

    FORM_NOMORE     = -1
}IFORM;

#define FT(_form, _inst, _steps)  { FORM_ ## _form, _inst, _steps }

static const FormTable Forms_ADD [] =
{
    FT (2rrc_____, 0x0000F100, Steps_T2_ALU_dn_modc12),
    FT (2rrrcc___, 0x0000EB00, Steps_T2_ALU_dnm_Shift_c),
    FT (2rrrccC__, 0x0000EB40, Steps_T2_ALU_dnm_Shift_c),
    FT (2rrr_____, 0x0000EB00, Steps_T2_ALU_dnm),
    FT (2rrcC____, 0x0000F140, Steps_T2_ALU_dn_modc12),
    FT (2rrrC____, 0x0000EB40, Steps_T2_ALU_dnm),
    FT (2rrC_____, 0x0000EB40, Steps_T2_ALU_ddm),

    // Thumb2 and Thumb1 ADD(4)
    FT (ThrC_____, 0x4140, Steps_T_ALU_dm),         // ADC rd, rd, rm
    FT (TrhrC____, 0x4140, Steps_T_ALU_dm),         // ADC rd, rd, rm
    FT (ThrrC____, 0x4140, Steps_T_ALU_dm),         // ADC rd, rd, rm
    FT (ThrhrC___, 0x4140, Steps_T_ALU_dm),         // ADC rd, rd, rm

    FT (Trrc_____, 0x1c00, Steps_T_Add_Sub_dnc),    // ADD rd, rn #<3_bit_immd>

    FT (Trc______, 0x3000, Steps_T_Add_Sub_ddc),    // ADD rd, #<8_bit_immd>
    FT (Tr_______, 0x1800, Steps_T_Add_Sub_dnm),    // ADD rd, rd, rm
    FT (Trr______, 0x1800, Steps_T_Add_Sub_dnm),    // ADD rd, rd, rm
    FT (Trrr_____, 0x1800, Steps_T_Add_Sub_dnm),    // ADD rd, rn, rm
    FT (Tpcpcr___, 0x4400, Steps_T_Add_High_dm),    // ADD pc, rm, h1,h2
    FT (Tspspr___, 0x4400, Steps_T_Add_High_dm),    // ADD sp, rm, h1,h2
    FT (Tspsphr__, 0x4400, Steps_T_Add_High_dm),    // ADD sp, rm, h1,h2
    FT (Thrr_____, 0x4400, Steps_T_Add_High_dm),    // ADD rd, rm, h1,h2
    FT (Thrsp____, 0x4400, Steps_T_Add_High_dm),    // ADD rd, sp, h1
    FT (Trpc_____, 0x4400, Steps_T_Add_High_dm),    // ADD rd, rm, h1, h2
    FT (Trsp_____, 0x4400, Steps_T_Add_High_dm),    // ADD rd, rm, h1, h2
    FT (Tpchr____, 0x4400, Steps_T_Add_High_dm),    // ADD rd, rm, h1, h2
    FT (Trpcc____, 0xa000, Steps_T_Add_SP_or_PC),   // ADD rd, PC, #<8_bit_immd>
    FT (Trspc____, 0xa800, Steps_T_Add_SP_or_PC),   // ADD rd, SP, #<8_bit_immd>
    FT (Tspspc___, 0xb000, Steps_T_Add_Sub_SP),     // ADD SP, SP, #<7_bit_immd>
    FT (TrC_____,  0x4140, Steps_T_ALU_dm),         // ADC rd, rd, rm
    FT (TrrC_____, 0x4140, Steps_T_ALU_dm),         // ADC rd, rd, rm

    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_ADDW [] =
{
    FT (2rrc_____, 0x0000F200, Steps_T2_ALU_dn_imm12),
    FT (2rspc____, 0x0000F200, Steps_T2_ALU_dn_imm12),
    FT (2spspc___, 0x0000F200, Steps_T2_ALU_dn_imm12),
    FT (2sprc____, 0x0000F200, Steps_T2_ALU_dn_imm12),
    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_ASR [] =
{
    FT (2rrc_____, 0x0020ea4f, Steps_T2_Shift_dmc),
    FT (2rrr_____, 0xF000FA40, Steps_T2_ALU_dnm),

    FT (Trc______, 0x1000, Steps_T_Shift_dmc),
    FT (Trrc_____, 0x1000, Steps_T_Shift_dmc),
    FT (Trr______, 0x4100, Steps_T_Shift_ds),
    FT (Tr_______, 0x4100, Steps_T_Shift_ds),

    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_BX [] =
{
    FT (Tr_______, 0x4700, Steps_T_BX),
    FT (T_r______, 0x4700, Steps_T_BX),
    FT (Thr______, 0x4700, Steps_T_BX),
    FT (NOMORE,   0x0,   0),
};


static const FormTable Forms_B [] =
{
    FT (2l_______, 0x9000F000, Steps_T2_BranchUncond),
//    FT (2l_______, 0x9000F000, Steps_T2_Branch),
//    FT (2lC______, 0x8000F000, Steps_T2_Branch),
//    FT (Tl_______, 0xe000, Steps_T_Branch),
//    FT (TlC______, 0xd000, Steps_T_Branch),
    FT (NOMORE,   0x0,   0),
};

// B<C> explicit ///////////////////////////////////
static const FormTable Forms_BEQ [] =
{
    //FT (2l_______, 0x9000F000, Steps_T2_Branch),
    FT (2l_______, 0x8000F000, Steps_T2_BranchCond),
    //FT (Tl_______, 0xe000, Steps_T_Branch),
    //FT (TlC______, 0xd000, Steps_T_Branch),
    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_BNE [] =
{
    FT (2l_______, 0x8000F040, Steps_T2_BranchCond),
    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_BLT [] =
{
    FT (2l_______, 0x8000F2C0, Steps_T2_BranchCond),
    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_BGT [] =
{
    FT (2l_______, 0x8000F300, Steps_T2_BranchCond),
    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_BLE [] =
{
    FT (2l_______, 0x8000F340, Steps_T2_BranchCond),
    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_BGE [] =
{
    FT (2l_______, 0x8000F280, Steps_T2_BranchCond),
    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_BCS [] =
{
    FT (2l_______, 0x8000F080, Steps_T2_BranchCond),
    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_BCC [] =
{
    FT (2l_______, 0x8000F0C0, Steps_T2_BranchCond),
    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_BHI [] =
{
    FT (2l_______, 0x8000F200, Steps_T2_BranchCond),
    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_BLS [] =
{
    FT (2l_______, 0x8000F240, Steps_T2_BranchCond),
    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_BMI [] =
{
    FT (2l_______, 0x8000F100, Steps_T2_BranchCond),
    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_BPL [] =
{
    FT (2l_______, 0x8000F140, Steps_T2_BranchCond),
    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_BVS [] =
{
    FT (2l_______, 0x8000F180, Steps_T2_BranchCond),
    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_BVC [] =
{
    FT (2l_______, 0x8000F1C0, Steps_T2_BranchCond),
    FT (NOMORE,   0x0,   0),
};
// End B<C> explicit ///////////////////////////////////


static const FormTable Forms_BL [] =
{
    FT (2e_______, 0xF800F000, Steps_T2_BL),

    FT (Tl_______, 0xf800f000, Steps_T_BL),
    FT (Te_______, 0xf800f000, Steps_T_BL),

    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_BLX [] =
{
    FT (2e_______, 0xE800F000, Steps_T2_BLX),

    FT (Te_______, 0xf400e400, Steps_T_BLX),
    FT (T_r______, 0x4780, Steps_T_BX),
    FT (Tr_______, 0x4780, Steps_T_BX), //same src, dst
    FT (Thr______, 0x4780, Steps_T_BX),
    FT (Th_r_____, 0x4780, Steps_T_BX),

    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_CMP [] =
{
    FT (2_rc_____, 0x0F00F1B0, Steps_T2_n_modc12),
    FT (2_rr_____, 0x0F00EBB0, Steps_T2_ALU_nm),
    //FT (2rrcc____, 0x0F00EBB0, Steps_T2_ALU_nm_Shift_c),

    FT (T_rc_____, 0x2800, Steps_T_RR_dc),
    FT (T_rr_____, 0x4280, Steps_T_RR_ds),
    FT (T_r______, 0x4280, Steps_T_RR_ds),
    FT (Th_rr____, 0x4500, Steps_T_HRR_ds),
    FT (T_spr____, 0x4500, Steps_T_HRR_ds),
    FT (Th_spr___, 0x4500, Steps_T_HRR_ds),

    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_CMP_ASR31 [] =
{
    // CMP.W Rn, Rm, ASR #31
    // T3 .im3 1111 i2ty Rm__ 1110 1011 1011 Rn__, ty = 10, im3:i2 = 31
    // -> .111 1111 1110 Rm__ 1110 1011 1011 Rn__
    FT (2_rr_____, 0x7FE0EBB0, Steps_T2_ALU_nm),
    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_CLZ [] =
{
    FT(2rr______, 0xF080FAB0, Steps_T2_ALU_dnn),
    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_CMN [] =
{
    FT (2_rc_____, 0x0F00F110, Steps_T2_n_modc12),
    FT (2_rr_____, 0x0F00EB10, Steps_T2_ALU_nm),
    //FT (2rrcc____, 0x0F00EB10, Steps_T2_ALU_nm_Shift_c),

    FT (T_rr_____, 0x42c0, Steps_T_RR_ds),
    FT (T_r______, 0x42c0, Steps_T_RR_ds),

    FT (NOMORE,   0x0,   0),
};


static const FormTable Forms_EOR [] =
{
    FT (2rrc_____, 0x0000F080, Steps_T2_ALU_dn_modc12),
    FT (2rrrcc___, 0x0000EA80, Steps_T2_ALU_dnm_Shift_c),
    FT (2rrr_____, 0x0000EA80, Steps_T2_ALU_dnm),
    FT (2rr______, 0x0000EA80, Steps_T2_ALU_dnm),

    FT (Trr______, 0x4040, Steps_T_ALU_dm),
    FT (Tr_______, 0x4040, Steps_T_ALU_dm),

    FT (NOMORE,    0x0,   0),
};

static const FormTable Forms_EOR_ASR31 [] =
{
    // EOR.W Rd, Rn, Rm, ASR #31
    // T2 0im3 Rd__ i2ty Rm__ 1110 1010 100S Rn__, ty = 10, im3:i2=31=11111
    // -> 0111 0000 1110 Rm__ 1110 1010 1000 Rn__
    FT (2rrr_____, 0x70E0EA80, Steps_T2_ALU_dnm),
    FT (NOMORE,    0x0,   0),
};

static const FormTable Forms_CLRSIGN [] =
{
    FT (2rr______, 0x70E0EA80, Steps_T2_ALU_dnn),
    FT (NOMORE,    0x0,   0),
};

static const FormTable Forms_LDM [] =
{
    FT (2ipcc____, 0x0000E810, Steps_T2_LDM),
    FT (2irc_____, 0x0000E810, Steps_T2_LDM),
    FT (2ispc____, 0x0000E810, Steps_T2_LDM),
    FT (2rispc___, 0x0B04F85D, Steps_T2_LDM_ONE),

    FT (Tispc____, 0xbc00, Steps_T_LDM_rspx),
    FT (Tirc_____, 0xc800, Steps_T_LDM_rrx),

    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_LDIMM [] =
{
    FT (Trc______, 0x2000, Steps_T_ALU_rc),

    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_LEA [] =
{
    // Treat this as a Thumb2 add: r = ADDW sp,offset
    FT (2risp____, 0x0000F200, Steps_T2_LEA_rrd),

//    FT (Trl______, 0xa800, Steps_T_LEA_rrd),
//    FT (Trlsp____, 0xa800, Steps_T_LEA_rspd),
//    FT (Tspl_____, 0xa800, Steps_T_LEA_rspd),

    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_STM [] =
{
    FT (2ispc____, 0x0000E800, Steps_T2_STM_rrx),
    FT (2irc_____, 0x0000E800, Steps_T2_STM_rrx),
    FT (2ispcr___, 0x0D04F84D, Steps_T2_STM_rsp_ONE),

    FT (Tispc____, 0xb400, Steps_T_STM_rspx),
    FT (Tirc_____, 0xc000, Steps_T_STM_rrx),
    FT (Tric_____, 0xc000, Steps_T_STM_rrx),

    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_LDRN [] =
{
    FT (Trirc____, 0x0000, Steps_T_LDRN_rcr),                   //LDR rd, [rn, #5_bit_off]
    FT (Trirr____, 0x0000, Steps_T_LDRN_rrr),                   //LDR rd, [rn, rm]
    FT (Tripcc___, 0x4800, Steps_T_LDRN_PC_or_SP),              //LDR rd, [PC, #8_bit_off]
    FT (Trispc___, 0x9800, Steps_T_LDRN_PC_or_SP),              //LDR rd, [SP, #8_bit_off]
    FT (Trisp____, 0x9800, Steps_T_LDRN_PC_or_SP),              //LDR rd, [rn, #5_bit_off]
    FT (Tripc____, 0x4800, Steps_T_LDRN_PC_or_SP),              //LDR rd, [PC, #8_bit_off]
    FT (Tri______, 0x6838, Steps_T_LDRN_ri),                    //LDR rd, [rn, #5_bit_off]

    FT (NOMORE, 0x0, 0),
};

// Thumb2        LDR.W
static const FormTable Forms_LDR_W [] =
{
    FT (2rirc____, 0x0000F810, Steps_T2_LDR_OFF),
    FT (2risp____, 0x0000F810, Steps_T2_LDR_Stack),
    FT (2ripc____, 0x0100F810, Steps_T2_LDR_Stack),
    FT (2ri______, 0x0000F810, Steps_T2_LDR_Stack),
    FT (2rispc___, 0x0000F810, Steps_T2_LDR_OFF),
    FT (2ripcc___, 0x0000F810, Steps_T2_LDR_OFF),
    FT (2rispr___, 0x0000F810, Steps_T2_LDR_RegIndir),
    FT (2rirr____, 0x0000F810, Steps_T2_LDR_RegIndir),
    FT (2rirrc___, 0x0000F810, Steps_T2_LDR_RegIndir),
    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_LDRRET [] =
{
    FT (2pcispc__, 0xf000f85d, Steps_T2_LDRRET),                // LDR PC, [SP], #imm
    FT (NOMORE, 0x0, 0),
};

static const FormTable Forms_MOV [] =
{
    FT (Trc______, 0x2000, Steps_T_ALU_rc),
    FT (Trr______, 0x4600, Steps_T_MovHigh_rr),
    FT (Tr_______, 0x4600, Steps_T_MovHigh_rr),

    FT (Thrsp____, 0x4600, Steps_T_MovHigh_rr),
    FT (Tsphr____, 0x4600, Steps_T_MovHigh_rr),
    FT (Th_r_____, 0x4600, Steps_T_MovHigh_rr),

    FT (Trsp_____, 0x4600, Steps_T_MovHigh_rr),
    FT (Tpchr____, 0x4600, Steps_T_MovHigh_rr),
    FT (Thrr_____, 0x4600, Steps_T_MovHigh_rr),
    FT (Tspr_____, 0x4600, Steps_T_MovHigh_rr),
    FT (Tspsp____, 0x4600, Steps_T_MovHigh_rr),

    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_MOV_W [] =
{
    FT (2rc______, 0x0000F04F, Steps_T2_ALU_r_modc12),
    FT (2rr______, 0x0000EA4F, Steps_T2_ALU_dm),
    FT (NOMORE,   0x0,   0),
};


static const FormTable Forms_MOVW [] =
{
    FT (2rc______, 0x0000F240, Steps_T2_ALU_r_imm16),
    FT (2rl______, 0x0000F240, Steps_T2_MOVW_reloc),

    FT (NOMORE,   0x0,   0),
};

// Thumb2 & ARMv7
static const FormTable Forms_MOVT [] =
{
    //UTC - FT (2rrc_____, 0x0000F2C0, Steps_T2_ALU_r_imm16),
    FT (2rc______, 0x0000F2C0, Steps_T2_ALU_r_imm16),
    FT (2rl______, 0x0000F2C0, Steps_T2_MOVT_reloc),

    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_RET [] =
{
    FT (Tpcr_____, 0x4600, Steps_T_Ret_rr),
    FT (Tpchr____, 0x4600, Steps_T_Ret_rr),
    FT (Tpcriw___, 0x4700, Steps_T_IWRET_dm),
    FT (Tpchriw__, 0x4700, Steps_T_IWRET_dm),

    FT (NOMORE,   0x0,   0),
};

// initializing it similar to SDIV. won't be used as we split REM into SDIV and MLS
static const FormTable Forms_REM [] =
{
    FT (2rrr_____, 0xF0F0FB90, Steps_T2_ALU_dnm_no_sbit),

    FT (NOMORE,    0x0,   0),
};

// Thumb2        SUBW rd, rn #<12_bit_immediate>
static const FormTable Forms_SUBW [] =
{
    FT (2rrc_____, 0x0000F2A0, Steps_T2_ALU_dn_imm12),
    FT (2rspc____, 0x0000F2A0, Steps_T2_ALU_dn_imm12),
    FT (2spspc___, 0x0000F2A0, Steps_T2_ALU_dn_imm12),
    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_SUB [] =
{
    FT (2rrc_____, 0x0000F1A0, Steps_T2_ALU_dn_modc12),
    //FT (2rrcc____, 0x0000EBA0, Steps_T2_ALU_ddm_Shift_c), //3rd operand Shifter operand not supported yet
    //FT (2rrrcc___, 0x0000EBA0, Steps_T2_ALU_dnm_Shift_c),
    //FT (2rrrccC__, 0x0000EB60, Steps_T2_ALU_dnm_Shift_c),
    FT (2rrr_____, 0x0000EBA0, Steps_T2_ALU_dnm),
    FT (2rrrC____, 0x0000EB60, Steps_T2_ALU_dnm),       // SBC
    FT (2rrcC____, 0x0000F160, Steps_T2_ALU_dn_modc12), // SBC

    FT (Trrc_____, 0x1e00, Steps_T_Add_Sub_dnc),        // SUB rd, rn #<3_bit_immd>
    FT (Trc______, 0x3800, Steps_T_Add_Sub_ddc),        // SUB rd, #<8_bit_immd>
    FT (Tr_______, 0x1a00, Steps_T_Add_Sub_dnm),        // ADD rd, rd, rm
    FT (Trr______, 0x1a00, Steps_T_Add_Sub_dnm),        // SUB rd, rd, rm
    FT (Trrr_____, 0x1a00, Steps_T_Add_Sub_dnm),        // SUB rd, rn, rm
    FT (Tspspc___, 0xb080, Steps_T_Add_Sub_SP),         // SUB SP, SP, #<7_bit_immd>
    FT (TrrC_____, 0x4180, Steps_T_ALU_dm),             // SBC

    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_SBCMPLNT [] =
{
    FT (2rrr_____, 0x70E0EBA0, Steps_T2_ALU_dnm),
    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_STRN[] =
{
    FT (Tircr____, 0x0000, Steps_T_STRN_rcr),           // STR rd, [rn, #off]
    FT (Tirrr____, 0x0000, Steps_T_STRN_rrr),           // STR rd, [rn, rm]
    FT (Tir______, 0x6038, Steps_T_STRN_ri),            // STR rd, [rn, #8_bit_off]
    FT (Tispr____, 0x9000, Steps_T_STRN_spcr),          // STR rd, [SP, #8_bit_off]
    FT (Tispcr___, 0x9000, Steps_T_STRN_spcr),          // STR rd, [SP, #8_bit_off]
    FT (Tipcr____, 0x6000, Steps_T_STRN_spcr),          // STR rd, [PC, #8_bit_off]
    FT (Tirsp____, 0x9000, Steps_T_STRN_spcr),          // STR rd, [SP, #8_bit_off]

    FT (NOMORE, 0x0, 0),
};

static const FormTable Forms_STR_W [] =
{
    FT (2ircr____, 0x0000F800, Steps_T2_STR_OFF),
    FT (2ispcr___, 0x0000F800, Steps_T2_STR_OFF),
    FT (2ispr____, 0x0000F800, Steps_T2_STR_Stack),
    FT (2irrr____, 0x0000F800, Steps_T2_STR_RegIndir),
    FT (2isprr___, 0x0000F800, Steps_T2_STR_RegIndir),
    FT (2irrrc___, 0x0000F800, Steps_T2_STR_RegIndir),
    FT (2ir______, 0x0000F800, Steps_T2_STR_Stack),
    FT (2irsp____, 0x0000F800, Steps_T2_STR_Stack),
    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_AND [] =
{
    FT (2rrc_____, 0x0000F000, Steps_T2_ALU_dn_modc12),
    FT (2rrr_____, 0x0000EA00, Steps_T2_ALU_dnm),
/*
    FT (2rrrcc___, 0x0000EA00, Steps_T2_ALU_dnm_Shift_c),
    FT (2rr______, 0x0000EA00, Steps_T2_ALU_dnm),
*/
    FT (Trr______, 0x4000, Steps_T_ALU_dm),
    FT (Tr_______, 0x4000, Steps_T_ALU_dm),

    FT (NOMORE,    0x0,   0),
};


static const FormTable Forms_LSL [] =
{
    FT (2rrc_____, 0x0000ea4f, Steps_T2_Shift_dmc),
    FT (2rrr_____, 0xF000FA00, Steps_T2_ALU_dnm),

    FT (Trc______, 0x0000, Steps_T_Shift_dmc),
    FT (Trrc_____, 0x0000, Steps_T_Shift_dmc),
    FT (Trr______, 0x4080, Steps_T_Shift_ds),
    FT (Tr_______, 0x4080, Steps_T_Shift_ds),

    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_LSR [] =
{
    FT (2rrc_____, 0x0010ea4f, Steps_T2_Shift_dmc),
    FT (2rrr_____, 0xF000FA20, Steps_T2_ALU_dnm),

    FT (Trc______, 0x0800, Steps_T_Shift_dmc),
    FT (Trrc_____, 0x0800, Steps_T_Shift_dmc),
    FT (Trr______, 0x40c0, Steps_T_Shift_ds),
    FT (Tr_______, 0x40c0, Steps_T_Shift_ds),

    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_MUL [] =
{
    FT (2rrrr____, 0x0000FB00, Steps_T2_MULA_dnsm),
    FT (2rrr_____, 0xF000FB00, Steps_T2_ALU_dnm_no_sbit),
    FT (2rr______, 0xF000FB00, Steps_T2_ALU_dnm_no_sbit),

    FT (Trr______, 0x4340, Steps_T_ALU_dm),

    FT (NOMORE,    0x0,   0),
};

static const FormTable Forms_SMLAL [] =
{
    // SMLAL RdLo, RdHi, Rn, Rm. We always use r12 as RdHi, as we don't currently support instructions with 4 operands.
    // RdLo RdHi 0000 Rm__ | 1111 1011 1100 Rn__
    FT (2rrr_____, 0x0000FBC0, Steps_T2_ALU_mull_no_sbit),
    FT (NOMORE,    0x0,   0),
};

static const FormTable Forms_SMULL [] =
{
    // SMULL<c> RdLo, RdHi, Rn, Rm. We always use r12 as RdHi, as we don't currently support instructions with 4 operands.
    // RdLo RdHi 0000 Rm__ | 1111 1011 1000 Rn__
    FT (2rrr_____, 0x0000FB80, Steps_T2_ALU_mull_no_sbit),
    FT (NOMORE,    0x0,   0),
};

static const FormTable Forms_MLS [] =
{
    FT (2rrr_____, 0x0010FB00, Steps_T2_mls_dnma),

    FT (NOMORE,    0x0,   0),
};

static const FormTable Forms_MVN [] =
{
    FT (2rc______, 0x0000F06F, Steps_T2_ALU_r_modc12),
    FT (2rrcc____, 0x0000EA6F, Steps_T2_ALU_dm_Shift_c),
    FT (2rr______, 0x0000EA6F, Steps_T2_ALU_dm),

    FT (Tr_______, 0x43c0, Steps_T_Neg_Mvn_dm),
    FT (Trr______, 0x43c0, Steps_T_Neg_Mvn_dm),

    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_ORR [] =
{
    FT (2rrc_____, 0x0000F040, Steps_T2_ALU_dn_modc12),
    FT (2rrrcc___, 0x0000EA40, Steps_T2_ALU_dnm_Shift_c),
    FT (2rrr_____, 0x0000EA40, Steps_T2_ALU_dnm),
    FT (2rr______, 0x0000EA40, Steps_T2_ALU_dnm),

    FT (Trr______, 0x4300, Steps_T_ALU_dm),
    FT (Tr_______, 0x4300, Steps_T_ALU_dm),

    FT (NOMORE,    0x0,   0),
};

static const FormTable Forms_RSB [] =
{
    FT (2rrc_____, 0x0000F1C0, Steps_T2_ALU_dn_modc12),
    FT (2rrrcc___, 0x0000EBC0, Steps_T2_ALU_dnm_Shift_c),
    FT (2rrr_____, 0x0000EBC0, Steps_T2_ALU_dnm),

    FT (Tr_______, 0x4240, Steps_T_Neg_Mvn_dm),
    FT (Trr______, 0x4240, Steps_T_Neg_Mvn_dm),

    FT (NOMORE,    0x0,   0),
};

static const FormTable Forms_SDIV [] =
{
    FT (2rrr_____, 0xF0F0FB90, Steps_T2_ALU_dnm_no_sbit),

    FT (NOMORE,    0x0,   0),
};

static const FormTable Forms_TST [] =
{
    FT (2_rr_____, 0x0F00EA10, Steps_T2_ALU_nm),
    FT (2_rc_____, 0x0F00F010, Steps_T2_n_modc12),
    FT (2rrcc____, 0x0F00EA10, Steps_T2_ALU_nm_Shift_c),

    FT (T_rr_____, 0x4200, Steps_T_RR_ds),
    FT (T_r______, 0x4200, Steps_T_RR_ds),

    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_TIOFLW [] =
{
    FT (2_r______, 0x0F40EA90, Steps_T2_ALU_nn),

    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_DBGBRK [] =
{
    FT (T________, 0xdefe, Steps_T_Dbg),
    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_NOP [] =
{
    FT (T________, 0x046c0, Steps_NOP),
    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_NOP_W [] =
{
    FT (2________, 0x8000F3AF, Steps_NOP),
    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_VABS [] =
{
    FT (2dd______, 0x0bc0eeb0, Steps_DBL_Unary_dm),
    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_VSQRT [] =
{
    // VSQRT.F64 <Dd>, <Dm>
    //   s = sz = double precision
    //   D = register selector for dest = sz ? D:Vd : Vd:D
    //   M = register selector for src  = sz ? M:Vm : Vm:M
    // T1/A1 Vd__ 101s 11M0 Vm__ | 1110 1110 1D11 0001 (flipped low and hi 2 bytes from as it's in the manual)
    //    -> 0000 1011 1100 0000 | 1110 1110 1011 0001
    // Note: using 2dd form as for Thumb2, although the manual says there is only T1/A1 form --
    //       the instr is essentially same as in Thumb2 (4 bytes).
    FT (2dd______, 0x0bc0eeb1, Steps_DBL_Unary_dm),
    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_VADDF64 [] =
{
    FT (2ddd_____, 0x0b00ee30, Steps_DBL_ALU_dnm),
    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_VSUBF64 [] =
{
    FT (2ddd_____, 0x0b40ee30, Steps_DBL_ALU_dnm),
    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_VMULF64 [] =
{
    FT (2ddd_____, 0x0b00ee20, Steps_DBL_ALU_dnm),
    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_VDIVF64 [] =
{
    FT (2ddd_____, 0x0b00ee80, Steps_DBL_ALU_dnm),
    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_VCMPF64 [] =
{
    FT (2_dd_____, 0x0b40eeb4, Steps_DBL_Cmp_dm),
    FT (NOMORE,   0x0,   0),
};

// This always moves FPSCR to ARM Status register.
// APSR_nzcv is encoded as Rt = '1111', and the instruction transfers the FPSCR N, Z, C, and
// V flags to the APSR N, Z, C, and V flags.
static const FormTable Forms_VMRS [] =
{
    FT (2________, 0xfa10eef1, Steps_FLT_FMRS_flags),
    FT (NOMORE, 0x0, 0),
};

static const FormTable Forms_VMRSR [] =
{
    FT (2r_______, 0x0a10eef1, Steps_FLT_FMRSR_flags),
    FT (NOMORE, 0x0, 0),
};

static const FormTable Forms_VMSR [] =
{
    FT (2_r______, 0x0a10eee1, Steps_FLT_FMRSR_flags),
    FT (NOMORE, 0x0, 0),
};

static const FormTable Forms_VNEGF64 [] =
{
    FT (2dd______, 0x0b40eeb1, Steps_DBL_Unary_dm),
    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_VLDR [] =
{
    FT (2dirc____, 0x0b00ec10, Steps_A_LDRN_DBL_Am_rcr),        //VLDR rd,[rn,#off]
    FT (2disp____, 0x0b00ec10, Steps_A_LDRN_DBL_Am_rcr),        //VLDR rd,[SP,#off]
    FT (NOMORE, 0x0, 0),
};

static const FormTable Forms_VLDR32 [] =
{
    FT (2dirc____, 0x0a00ec10, Steps_A_LDRN_FLT_Am_rcr),        //FLDS rd,[rn,#off]
    FT (2disp____, 0x0a00ec10, Steps_A_LDRN_FLT_Am_rcr),        //FLDS rd,[SP,#off]
    FT (NOMORE, 0x0, 0),
};

// used by floating point STRs
static const FormTable Forms_VSTR[] =
{
    FT (2ircd____, 0x0b00ec00, Steps_A_DBL_STRN_Am_rcr),        //VSTR dd, [rn, #off]
    FT (2ispd____, 0x0b00ec00, Steps_A_DBL_STRN_Am_rcr),        //VSTR dd, [SP, #off]
    FT (NOMORE, 0x0, 0),
};

// used by floating point STRs
static const FormTable Forms_VSTR32[] =
{
    FT (2ircd____, 0x0a00ec00, Steps_A_FLT_STRN_Am_rcr),        //FSTS sd, [rn, #off]
    FT (2ispd____, 0x0a00ec00, Steps_A_FLT_STRN_Am_rcr),        //FSTS sd, [SP, #off]
    FT (NOMORE, 0x0, 0),
};

static const FormTable Forms_VMOV[] =
{
    FT (2dd______, 0x0b40eeb0, Steps_DBL_Unary_dm),
    FT (NOMORE,   0x0,   0),
};

// This moves data between ARM core registers & VFP registers.
static const FormTable Forms_VMOVARMVFP[] =
{
    FT (2dr______, 0x0a10ee00, Steps_FLT_FMSR_sr),
    FT (2rd______, 0x0a10ee10, Steps_FLT_FMRS_rs),
    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_VCVTF64F32 [] =
{
    FT (2dd______, 0x0ac0eeb7, Steps_FCVTDS_ds),
    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_VCVTF32F64 [] =
{
    FT (2dd______, 0x0bc0eeb7, Steps_FCVTSD_sd),
    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_VCVTF64S32 [] =
{
    FT (2dd______, 0x0bc0eeb8, Steps_FITOD_ds),
    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_VCVTF64U32 [] =
{
    FT (2dd______, 0x0b40eeb8, Steps_FITOD_ds),
    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_VCVTS32F64 [] =
{
    FT (2dd______, 0x0bc0eebd, Steps_FDTOI_sd),
    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_VCVTRS32F64 [] =
{
    FT (2dd______, 0x0b40eebd, Steps_FDTOI_sd),
    FT (NOMORE,   0x0,   0),
};

static const FormTable Forms_PLD [] =
{
    FT (2_irc____, 0xF000F810, Steps_T2_PLD_offset),
    FT (2_irr____, 0xF000F810, Steps_T2_PLD_RegIndir),
    FT (NOMORE,   0x0,   0),
} ;

// used by floating point LDMs
static const FormTable Forms_VPOP[] =
{
    FT (2irc_____, 0x0b00ec10, Steps_A_DBL_LDM),                //FLDMD rn, {dreg list}
    FT (2ispc____, 0x0b00ec10, Steps_A_DBL_LDM),                //FLDMD SP, {dreg list}
    FT (2rirc____, 0x0b00ec10, Steps_A_DBL_LDM),                //FLDMD rn, {single register}
    FT (2rispc___, 0x0b00ec10, Steps_A_DBL_LDM),                //FLDMD SP, {single register}

    FT (NOMORE, 0x0, 0),
};

// used by floating point STMs
static const FormTable Forms_VPUSH[] =
{
    FT (2irc_____, 0x0b00ec00, Steps_A_DBL_STM),                //FSTMD rn, {dreg list}
    FT (2ispc____, 0x0b00ec00, Steps_A_DBL_STM),                //FSTMD SP, {dreg list}
    FT (2ircr____, 0x0b00ec00, Steps_A_DBL_STM),                //FSTMD rn, {single register}
    FT (2ispcr___, 0x0b00ec00, Steps_A_DBL_STM),                //FSTMD SP, {single register}

    FT (NOMORE, 0x0, 0),
};

static const FormTable Forms_BIC [] =
{
    FT (2rrc_____, 0x0000F020, Steps_T2_ALU_dn_modc12),
    FT (2rrrcc___, 0x0000EA20, Steps_T2_ALU_dnm_Shift_c),
    FT (2rrr_____, 0x0000EA20, Steps_T2_ALU_dnm),
    FT (2rr______, 0x0000EA20, Steps_T2_ALU_dnm),

    FT (Trr______, 0x4380, Steps_T_ALU_dm),
    FT (Tr_______, 0x4380, Steps_T_ALU_dm),

    FT (NOMORE,    0x0,   0),
};
