#include "thumb.hpp" namespace ARM { DecodedThumbInstr DecodeThumb(ARM::ThumbInstr instr) { if (instr.opcode_upper5 == 0b00000) { // LSL (1) - Logical Shift Left ARM::ARMInstr arm_instr; arm_instr.raw = ((0b1110'0001'1011'0000ul) << 16) | (uint32_t { instr.idx_rd_low } << 12) | (uint32_t { instr.immed_mid_5 } << 7) | instr.idx_rm; return { arm_instr }; } else if (instr.opcode_upper5 == 0b00010) { // ASR (1) - Arithmetic Shift Right ARM::ARMInstr arm_instr; // arm_instr.raw = (0b1110'0001'1011'0000ul << 16) // | (uint32_t { instr.idx_rd_low } << 12) // | (uint32_t { instr.immed_mid_5 } << 7) // | (0b100ul << 3) // | instr.idx_rm; arm_instr.raw = (0b1110'0001'1011'0000ul << 16) | (uint32_t { instr.idx_rd_low } << 12) | (uint32_t { instr.immed_mid_5 } << 7) | (0b100ul << 4) | instr.idx_rm; // arm_instr.raw = (0b1110'0001'1011'0000'0000'1111'1010'0000ul); // shift_imm = 31, shift = 1 return { arm_instr }; } else if (instr.opcode_upper10 == 0b0100'0000'00) { // AND ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'0000'0001ul << 20) | (uint32_t { instr.idx_rd_low } << 16) | (uint32_t { instr.idx_rd_low } << 12) | instr.idx_rm; return { arm_instr }; } else if (instr.opcode_upper10 == 0b0100'0001'01) { // ADC ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'0000'1011ul << 20) | (uint32_t { instr.idx_rd_low } << 16) | (uint32_t { instr.idx_rd_low } << 12) | instr.idx_rm; return { arm_instr }; } else if (instr.opcode_upper7 == 0b0001110) { // ADD (1) ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'0010'1001ul << 20) | (uint32_t { instr.idx_rm } << 16) | (uint32_t { instr.idx_rd_low } << 12) | instr.immed_mid_5_lower3; return { arm_instr }; } else if (instr.opcode_upper5 == 0b00110) { // ADD (2) ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'0010'1001ul << 20) | (uint32_t { instr.idx_rd_high } << 16) | (uint32_t { instr.idx_rd_high } << 12) | instr.immed_low_8; return { arm_instr }; } else if (instr.opcode_upper7 == 0b0001100) { // ADD (3) ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'0000'1001ul << 20) | (uint32_t { instr.idx_rm } << 16) | (uint32_t { instr.idx_rd_low } << 12) | instr.idx_rn; return { arm_instr }; } else if (instr.opcode_upper8 == 0b01000100) { // ADD (4) ARM::ARMInstr arm_instr; auto idx_rd = uint32_t { instr.idx_rd_low } | (uint32_t { instr.idx_rd_upperbit } << 3); auto idx_rm = uint32_t { instr.idx_rm } | (uint32_t { instr.idx_rm_upperbit } << 3); arm_instr.raw = (0b1110'0000'1000ul << 20) | (idx_rd << 16) | (idx_rd << 12) | idx_rm; auto ret = DecodedThumbInstr { arm_instr }.SetMayReadPC(); if (idx_rd == 15) { ret.SetMayModifyPC(); } return ret; // } else if (instr.opcode_upper5 == 0b10100) { // // ADD (5) // ARM::ARMInstr arm_instr; // arm_instr.raw = (0b1110'0010'1000'1111ul << 16) // | (uint32_t { instr.idx_rd_high } << 12) // | (0b1111ul << 8) // | instr.immed_low_8; // return DecodedThumbInstr { arm_instr }.SetMayReadPC(); } else if (instr.opcode_upper5 == 0b10101) { // ADD (6) ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'0010'1000'1101ul << 16) | (uint32_t { instr.idx_rd_high } << 12) | (0b1111ul << 8) | instr.immed_low_8; return { arm_instr }; } else if (instr.opcode_upper9 == 0b1011'0000'0) { // ADD (7) ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110001010001101110111110ul << 7) | instr.immed_low_7; return { arm_instr }; } else if (instr.opcode_upper10 == 0b0100'0011'10) { // BIC ARM::ARMInstr arm_instr; arm_instr.raw = (0b111000011101ul << 20) | (uint32_t { instr.idx_rd_low } << 16) | (uint32_t { instr.idx_rd_low } << 12) | instr.idx_rm; return { arm_instr }; } else if (instr.opcode_upper10 == 0b0100'0010'00) { // TST ARM::ARMInstr arm_instr; arm_instr.raw = (0b111000010001ul << 20) | (uint32_t { instr.idx_rd_low } << 16) | instr.idx_rm; return { arm_instr }; } else if (instr.opcode_upper7 == 0b0001'111) { // SUB (1) ARM::ARMInstr arm_instr; arm_instr.raw = (0b111000100101ul << 20) | (uint32_t { instr.idx_rm } << 16) | (uint32_t { instr.idx_rd_low } << 12) | instr.immed_mid_5_lower3; return { arm_instr }; } else if (instr.opcode_upper5 == 0b00111) { // SUB (2) ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'0010'0101ul << 20) | (uint32_t { instr.idx_rd_high } << 16) | (uint32_t { instr.idx_rd_high } << 12) | instr.immed_low_8; return { arm_instr }; } else if (instr.opcode_upper7 == 0b0001'101) { // SUB (3) ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'0000'0101ul << 20) | (uint32_t { instr.idx_rm } << 16) | (uint32_t { instr.idx_rd_low } << 12) | instr.idx_rn; return { arm_instr }; } else if (instr.opcode_upper9 == 0b1011'0000'1) { // SUB (4) ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'0010'0100'1101'1101'1111'0ul << 7) | instr.immed_low_7; return { arm_instr }; } else if (instr.opcode_upper10 == 0b0100'0001'10) { // SBC ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'0000'1101ul << 20) | (uint32_t { instr.idx_rd_low } << 16) | (uint32_t { instr.idx_rd_low } << 12) | instr.idx_rm; return { arm_instr }; } else if (instr.opcode_upper10 == 0b0100'0011'00) { // ORR ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'0001'1001ul << 20) | (uint32_t { instr.idx_rd_low } << 16) | (uint32_t { instr.idx_rd_low } << 12) | instr.idx_rm; return { arm_instr }; } else if (instr.opcode_upper10 == 0b0100'0000'01) { // EOR ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'0000'0011ul << 20) | (uint32_t { instr.idx_rd_low } << 16) | (uint32_t { instr.idx_rd_low } << 12) | instr.idx_rm; return { arm_instr }; } else if (instr.opcode_upper5 == 0b00100) { // MOV (1) ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'0011'1011'0000ul << 16) | (uint32_t { instr.idx_rd_high } << 12) | instr.immed_low_8; return { arm_instr }; } else if (instr.opcode_upper8 == 0b0100'0110) { // MOV (3) ARM::ARMInstr arm_instr; auto idx_rd = uint32_t { instr.idx_rd_low } | (uint32_t { instr.idx_rd_upperbit } << 3); auto idx_rm = uint32_t { instr.idx_rm } | (uint32_t { instr.idx_rm_upperbit } << 3); arm_instr.raw = (0b1110'0001'1010ul << 20) | (idx_rd << 12) | idx_rm; auto ret = DecodedThumbInstr { arm_instr }.SetMayReadPC(); if (idx_rd == 15) { ret.SetMayModifyPC(); } return ret; } else if (instr.opcode_upper10 == 0b0100'0011'11) { // MVN ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'0001'1111'0000ul << 16) | (uint32_t { instr.idx_rd_low } << 12) | instr.idx_rm; return { arm_instr }; } else if (instr.opcode_upper5 == 0b00000) { // LSL (1) ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'0001'1011'0000ul << 16) | (uint32_t { instr.idx_rd_low } << 12) | (uint32_t { instr.immed_mid_5 } << 7) | instr.idx_rm; return { arm_instr }; } else if (instr.opcode_upper10 == 0b0100'0000'10) { // LSL (2) ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'0001'1011'0000ul << 16) | (uint32_t { instr.idx_rd_low } << 12) | (uint32_t { instr.idx_rm } << 8) | 0b1'0000 | instr.idx_rd_low; return { arm_instr }; } else if (instr.opcode_upper5 == 0b00001) { // LSR (1) ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'0001'1011'0000ul << 16) | (uint32_t { instr.idx_rd_low } << 12) | (uint32_t { instr.immed_mid_5 } << 7) | 0b10'0000 | instr.idx_rm; return { arm_instr }; } else if (instr.opcode_upper10 == 0b0100'0000'11) { // LSR (2) ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'0001'1011'0000ul << 16) | (uint32_t { instr.idx_rd_low } << 12) | (uint32_t { instr.idx_rm } << 8) | 0b11'0000 | instr.idx_rd_low; return { arm_instr }; } else if (instr.opcode_upper10 == 0b0100'0010'01) { // NEG ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'0010'0111ul << 20) | (uint32_t { instr.idx_rm } << 16) | (uint32_t { instr.idx_rd_low } << 12); return { arm_instr }; } else if (instr.opcode_upper10 == 0b0100'0011'01) { // MUL ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'0000'0001ul << 20) | (uint32_t { instr.idx_rd_low } << 16) | (uint32_t { instr.idx_rd_low } << 8) | (0b1001ul << 4) | instr.idx_rm; return { arm_instr }; } else if (instr.opcode_upper10 == 0b1011'1010'00) { // REV ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'0110'1011'1111ul << 16) | (uint32_t { instr.idx_rd_low } << 12) | (0b1111'0011ul << 4) | instr.idx_rm; return { arm_instr }; } else if (instr.opcode_upper10 == 0b0100'0001'11) { // ROR ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'0001'1011'0000ul << 16) | (uint32_t { instr.idx_rd_low } << 12) | (uint32_t { instr.idx_rm } << 8) | (0b0111ul << 4) | instr.idx_rd_low; return { arm_instr }; } else if (instr.opcode_upper10 == 0b1011'0010'01) { // SXTB ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'0110'1010'1111ul << 16) | (uint32_t { instr.idx_rd_low } << 12) | (0b0111ul << 4) | instr.idx_rm; return { arm_instr }; } else if (instr.opcode_upper10 == 0b1011'0010'00) { // SXTH ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'0110'1011'1111ul << 16) | (uint32_t { instr.idx_rd_low } << 12) | (0b0111ul << 4) | instr.idx_rm; return { arm_instr }; } else if (instr.opcode_upper10 == 0b1011'0010'10) { // UXTH ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'0110'1111'1111ul << 16) | (uint32_t { instr.idx_rd_low } << 12) | (0b0111ul << 4) | instr.idx_rm; return { arm_instr }; } else if (instr.opcode_upper10 == 0b1011'0010'11) { // UXTB ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'0110'1110'1111ul << 16) | (uint32_t { instr.idx_rd_low } << 12) | (0b0111ul << 4) | instr.idx_rm; return { arm_instr }; } else if (instr.opcode_upper5 == 0b11001) { // LDMIA ARM::ARMInstr arm_instr; uint32_t has_rd = (instr.register_list >> instr.idx_rd_high) & 1; arm_instr.raw = (0b1110'1000'1001ul << 20) | (uint32_t { !has_rd } << 21) | (uint32_t { instr.idx_rd_high } << 16) | instr.register_list; return { arm_instr }; } else if (instr.opcode_upper5 == 0b01101) { // LDR (1) ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'0101'1001ul << 20) | (uint32_t { instr.idx_rm } << 16) | (uint32_t { instr.idx_rd_low } << 12) | (uint32_t { instr.immed_mid_5 } << 2); return { arm_instr }; } else if (instr.opcode_upper7 == 0b0101'100) { // LDR (2) ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'0111'1001ul << 20) | (uint32_t { instr.idx_rm } << 16) | (uint32_t { instr.idx_rd_low } << 12) | instr.idx_rn; return { arm_instr }; } else if (instr.opcode_upper5 == 0b10011) { // LDR (4) ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'0101'1001'1101ul << 16) | (uint32_t { instr.idx_rd_high } << 12) | (uint32_t { instr.immed_low_8 } << 2); return { arm_instr }; } else if (instr.opcode_upper5 == 0b01111) { // LDRB (1) ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'0101'1101ul << 20) | (uint32_t { instr.idx_rm } << 16) | (uint32_t { instr.idx_rd_low } << 12) | instr.immed_mid_5; return { arm_instr }; } else if (instr.opcode_upper7 == 0b0101110) { // LDRB (2) ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'0111'1101ul << 20) | (uint32_t { instr.idx_rm } << 16) | (uint32_t { instr.idx_rd_low } << 12) | instr.idx_rn; return { arm_instr }; } else if (instr.opcode_upper7 == 0b0101011) { // LDRSB ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'0001'1001ul << 20) | (uint32_t { instr.idx_rm } << 16) | (uint32_t { instr.idx_rd_low } << 12) | (0b1101ul << 4) | instr.idx_rn; return { arm_instr }; } else if (instr.opcode_upper7 == 0b0101111) { // LDRSH ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'0001'1001ul << 20) | (uint32_t { instr.idx_rm } << 16) | (uint32_t { instr.idx_rd_low } << 12) | (0b1111ul << 4) | instr.idx_rn; return { arm_instr }; } else if (instr.opcode_upper5 == 0b10001) { // LDRH (1) ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'0001'1101ul<< 20) | (uint32_t { instr.idx_rm } << 16) | (uint32_t { instr.idx_rd_low } << 12) | (uint32_t { instr.immed_mid_5_upper2 } << 8) | (0b1011ul << 4) | (uint32_t { instr.immed_mid_5_lower3 } << 1); return { arm_instr }; } else if (instr.opcode_upper7 == 0b0101'101) { // LDRH (2) ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'0001'1001ul<< 20) | (uint32_t { instr.idx_rm } << 16) | (uint32_t { instr.idx_rd_low } << 12) | (0b1011ul << 4) | instr.idx_rn; return { arm_instr }; } else if (instr.opcode_upper5 == 0b00101) { // CMP (1) - Compare ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'0011'0101ul << 20) | (uint32_t { instr.idx_rd_high } << 16) | (instr.immed_low_8); return { arm_instr }; } else if (instr.opcode_upper10 == 0b0100'0010'10) { // CMP (2) - Compare ARM::ARMInstr arm_instr; arm_instr.raw = (0b111000010101ul << 20) | (uint32_t { instr.idx_rd_low } << 16) | instr.idx_rm; return { arm_instr }; } else if (instr.opcode_upper8 == 0b0100'0101) { // CMP (3) - Compare ARM::ARMInstr arm_instr; arm_instr.raw = (0b111000010101ul << 20) | (uint32_t { instr.idx_rd_low } << 16) | instr.idx_rm; return { arm_instr }; } else if (instr.opcode_upper5 == 0b11000) { // STMIA ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'1000'1010ul << 20) | (uint32_t { instr.idx_rd_high } << 16) | instr.register_list; return { arm_instr }; } else if (instr.opcode_upper5 == 0b01100) { // STR (1) ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'0101'1000ul << 20) | (uint32_t { instr.idx_rm } << 16) | (uint32_t { instr.idx_rd_low } << 12) | (uint32_t { instr.immed_mid_5 } << 2); return { arm_instr }; } else if (instr.opcode_upper7 == 0b0101000) { // STR (2) ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'0111'1000ul << 20) | (uint32_t { instr.idx_rm } << 16) | (uint32_t { instr.idx_rd_low } << 12) | instr.idx_rn; return { arm_instr }; } else if (instr.opcode_upper5 == 0b10010) { // STR (3) ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'0101'1000'1101ul << 16) | (uint32_t { instr.idx_rd_high } << 12) | (uint32_t { instr.immed_low_8 } << 2); return { arm_instr }; } else if (instr.opcode_upper5 == 0b01110) { // STRB (1) ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'0101'1100ul << 20) | (uint32_t { instr.idx_rm } << 16) | (uint32_t { instr.idx_rd_low } << 12) | instr.immed_mid_5; return { arm_instr }; } else if (instr.opcode_upper7 == 0b0101'010) { // STRB (2) ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'0111'1100ul << 20) | (uint32_t { instr.idx_rm } << 16) | (uint32_t { instr.idx_rd_low } << 12) | instr.idx_rn; return { arm_instr }; } else if (instr.opcode_upper5 == 0b10000) { // STRH (1) - Store Register Halfword ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'0001'1100ul << 20) | (uint32_t { instr.idx_rm } << 16) | (uint32_t { instr.idx_rd_low } << 12) | (uint32_t { instr.immed_mid_5_upper2 } << 8) | (0b1011 << 4) | (uint32_t { instr.immed_mid_5_lower3 } << 1); return { arm_instr }; } else if (instr.opcode_upper7 == 0b0101001) { // STRH (2) - Store Register Halfword ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'0001'1000ul << 20) | (uint32_t { instr.idx_rm } << 16) | (uint32_t { instr.idx_rd_low } << 12) | (0b1011 << 4) | instr.idx_rn; return { arm_instr }; } else if (instr.opcode_upper7 == 0b1011'010) { // PUSH - Push Multiple Registers ARM::ARMInstr arm_instr; arm_instr.raw = (0b1110'1001'0010'1101ul << 16) | ((uint32_t { instr.raw } & 0x100) << 6) // bit8 denotes whether to push LR | instr.register_list; return { arm_instr }; } else { // Instruction has no ARM equivalent, let the caller handle it manually return { }; } } } // namespace ARM