//This step is only used by the Word/Byte versions
        void BuildLoadStore_WordAndByte(LoadStoreBuilder b)
        {
            //Phase 0 - Choose memory size (word/byte)
            string originalName = b.name;

            b.opcode &= ~loadstore_byte_bit;
            //Case 1: Word
            b.memorySize = ARMPluginInterfaces.MemorySize.Word;
            BuildLoadStore_Offset(b);

            //Case 2: Byte
            b.name      += "B";
            b.opcode    |= loadstore_byte_bit;
            b.memorySize = ARMPluginInterfaces.MemorySize.Byte;
            BuildLoadStore_Offset(b);

            b.name    = originalName;
            b.opcode &= ~loadstore_byte_bit;
        }
        //This version applies to Word or Byte versions
        void BuildLoadStore_Offset(LoadStoreBuilder b)
        {
            //Phase 1 - Set operand type (register/immediate)

            //Clear register flag
            b.opcode &= ~loadstore_register_bit;

            //Immediate Offset (register flag 0)
            b.ComputeOffset = ComputeOffsetImmediate;
            BuildLoadStore_OffsetAddress(b);

            //Register Offset (register flag 1)
            b.opcode       |= loadstore_register_bit;
            b.ComputeOffset = ComputeOffsetRegister;
            BuildLoadStore_OffsetAddress(b);

            //Clear register flag
            b.opcode &= ~loadstore_register_bit;
        }
        void BuildLoadStore_OffsetAddress(LoadStoreBuilder b)
        {
            //Phase 2 - Set add/subtract behavior (i.e. is offset_address = "address + offset" or "address - offset"

            //Clear add/subtract flag (U bit)
            b.opcode &= ~offset_add_bit;

            //Subtract (U bit = 0)
            b.ComputeOffsetAddress = ComputeOffsetAddressSubtract;
            BuildLoadStore_IndexWriteBack(b);

            //Add (U bit = 1)
            b.opcode |= offset_add_bit;
            b.ComputeOffsetAddress = ComputeOffsetAddressAdd;
            BuildLoadStore_IndexWriteBack(b);

            //Clear add/subtract flag
            b.opcode &= ~offset_add_bit;
        }
        //This version applies to Halfword/Signed Halfword/Signed Byte versions
        void BuildLoadStore_Offset_SignedByte_HalfWord(LoadStoreBuilder b)
        {
            //Phase 1 - Set operand type (register/immediate)

            //Clear register flag
            b.opcode &= ~loadstore_immediate_bit_hw;


            //Register Offset (immediate flag 0)
            b.ComputeOffset = ComputeOffsetRegisterHW;
            BuildLoadStore_OffsetAddress(b);

            //Immediate Offset (immediate flag 1)
            b.opcode       |= loadstore_immediate_bit_hw;
            b.ComputeOffset = ComputeOffsetImmediateHW;
            BuildLoadStore_OffsetAddress(b);

            //Clear register flag
            b.opcode &= ~loadstore_immediate_bit_hw;
        }
        void BuildLoadStore_IndexWriteBack(LoadStoreBuilder b)
        {
            //Phase 3 - Set indexing (pre or post) and writeback behavior
            //Even though these are theoretically independent options, there is a special case
            //So we handle them all here.

            //Clear relevant flags:
            b.opcode &= ~(loadstore_preindex_bit | writeback_bit);

            //Case 1: Post-indexing (index_bit = 0) with writeback (by default) and writeback_bit = 0
            //Note that post-indexing is supposed to always have writeback, so the correct
            //protocol is for W = 0 when index_bit = 0.
            b.ComputeFinalAddress = ComputeAddressPostIndex;
            b.WritebackAddress    = WritebackAddressEnabled;
            FinishBuildingLoadStoreOp(b);
            b.opcode &= ~(loadstore_preindex_bit | writeback_bit);

            //Case 2: Post-indexing (index_bit = 0) with writeback (by default) and writeback_bit = 1
            //This actually corresponds to a special type of instruction with a T suffix (e.g. STRT)
            //cf. ARMv7 A8.8.92
            //For now, we ignore it.
            //TODO stop ignoring it.


            //Case 3: Pre-indexing (index_bit = 1) with no writeback (writeback_bit = 0)
            b.opcode |= loadstore_preindex_bit;
            b.ComputeFinalAddress = ComputeAddressPreIndex;
            b.WritebackAddress    = WritebackAddressDisabled;
            FinishBuildingLoadStoreOp(b);
            b.opcode &= ~(loadstore_preindex_bit | writeback_bit);

            //Case 3: Pre-indexing (index_bit = 1) with writeback (writeback_bit = 1)
            b.opcode |= loadstore_preindex_bit | writeback_bit;
            b.ComputeFinalAddress = ComputeAddressPreIndex;
            b.WritebackAddress    = WritebackAddressEnabled;
            FinishBuildingLoadStoreOp(b);

            //Clear relevant flags:
            b.opcode &= ~(loadstore_preindex_bit | writeback_bit);
        }
        internal void RegisterARMLoadStoreOps()
        {
            uint             base_opcode;
            uint             wildcard_mask; //The values of bits 20-27 vary between branches. The bit B (bit 4) in the specification is irrelevant here.
            LoadStoreBuilder b = new LoadStoreBuilder();

            //Create variants of STR and STRB
            base_opcode       = 0x04000000;
            wildcard_mask     = 0xf00fffff;         //The values of bits 20-27 vary between branches. The bit B (bit 4) in the specification is irrelevant here.
            b.name            = "STR";
            b.opcode          = base_opcode;
            b.wildcard_mask   = wildcard_mask;
            b.LoadStoreMemory = StoreMemory;
            BuildLoadStore_WordAndByte(b);

            //Create variants of LDR and LDRB
            base_opcode       = 0x04100000;
            wildcard_mask     = 0xf00fffff;
            b.name            = "LDR";
            b.opcode          = base_opcode;
            b.wildcard_mask   = wildcard_mask;
            b.LoadStoreMemory = LoadMemory;
            BuildLoadStore_WordAndByte(b);

            //Create variants of STRH
            base_opcode       = 0x000000b0;
            wildcard_mask     = 0xf00fff0f;
            b.name            = "STRH";
            b.opcode          = base_opcode;
            b.wildcard_mask   = wildcard_mask;
            b.LoadStoreMemory = StoreMemory;
            b.memorySize      = ARMPluginInterfaces.MemorySize.HalfWord;
            BuildLoadStore_Offset_SignedByte_HalfWord(b);

            //Create variants of LDRH
            base_opcode       = 0x001000b0;
            wildcard_mask     = 0xf00fff0f;
            b.name            = "LDRH";
            b.opcode          = base_opcode;
            b.wildcard_mask   = wildcard_mask;
            b.LoadStoreMemory = LoadMemory;
            b.memorySize      = ARMPluginInterfaces.MemorySize.HalfWord;
            BuildLoadStore_Offset_SignedByte_HalfWord(b);

            //Create variants of LDRSB (signed byte)
            base_opcode       = 0x001000d0;
            wildcard_mask     = 0xf00fff0f;
            b.name            = "LDRSB";
            b.opcode          = base_opcode;
            b.wildcard_mask   = wildcard_mask;
            b.LoadStoreMemory = LoadMemorySignedByte;
            b.memorySize      = ARMPluginInterfaces.MemorySize.Byte;
            BuildLoadStore_Offset_SignedByte_HalfWord(b);

            //Create variants of LDRSH (signed halfword)
            base_opcode       = 0x001000f0;
            wildcard_mask     = 0xf00fff0f;
            b.name            = "LDRSB";
            b.opcode          = base_opcode;
            b.wildcard_mask   = wildcard_mask;
            b.LoadStoreMemory = LoadMemorySignedHalfword;
            b.memorySize      = ARMPluginInterfaces.MemorySize.HalfWord;
            BuildLoadStore_Offset_SignedByte_HalfWord(b);


            //LDRD and STRD are load/store "dual" instructions which load or store two
            //adjacent words to two registers.

            //LDRD is v5TE only
            //RegisterOpcode(0x000000d0, 0xf1afff0f, null, "LDRD"); //LDRD (Register)
            //RegisterOpcode(0x004000d0, 0xf1afff0f, null, "LDRD"); //LDRD (immediate)
            //STRD is v5 and up only
            //RegisterOpcode(0x000000f0, 0xf1afff0f, null, "STRD"); //STRD (Register)
            //RegisterOpcode(0x004000f0, 0xf1afff0f, null, "STRD"); //STRD (immediate)
        }
        internal void FinishBuildingLoadStoreOp(LoadStoreBuilder b)
        {
            InstructionFunc handler = GenerateLoadStoreInstruction(b.ComputeOffset, b.ComputeOffsetAddress, b.ComputeFinalAddress, b.WritebackAddress, b.memorySize, b.LoadStoreMemory);

            RegisterOpcode(b.opcode, b.wildcard_mask, handler, b.name);
        }