/// <summary> /// Branch (1). /// </summary> private void Thumb_B() { sbyte Immediate = (sbyte)(Opcode & 0xff); ARMCondition Condition = (ARMCondition)((Opcode >> 8) & 0xf); if (IsConditionMet(Condition)) { Registers[15] = (uint)(Registers[15] + (Immediate << 1)); } }
public List<string> Disassemble(uint* ptr, int count) { List<string> instructions = new(); while (count --> 0) { uint cond = (*ptr & MASK_COND) >> RSHIFT_COND; if (cond >= 0b1111) instructions.Add($"NOP ; undefined behaviour in COND: 0x{*ptr:x8}"); else { string rn = get_register(ptr, ARMRegisterType.Rn); string rd = get_register(ptr, ARMRegisterType.Rd); string rs = get_register(ptr, ARMRegisterType.Rs); string rm = get_register(ptr, ARMRegisterType.Rm); string suffix = (ARMCondition)cond switch { ARMCondition.AL or ARMCondition.RV => "", ARMCondition c => c.ToString(), }; if ((matches(*ptr, MASK_DATA_PROCESSING, MATCH_DATA_PROCESSING) || matches(*ptr, MASK_MULTIPLY, MATCH_MULTIPLY) || matches(*ptr, MASK_MULTIPLY_LONG, MATCH_MULTIPLY_LONG)) && (*ptr & MASK_BIT_SL) != 0) suffix += 'S'; if (matches(*ptr, MASK_BRANCH, MATCH_BRANCH)) { string instr = get_bit(ptr, ARMInstructionBit.Link) ? "BL" : "B"; int offs = (int)((*ptr & MASK_BR_OFFSET) << 8); instructions.Add($"{instr}{suffix} 0x{offs >> 6:x8}"); } else if (matches(*ptr, MASK_DATA_PROCESSING, MATCH_DATA_PROCESSING)) { ARMDataProcessingOpCode opcode = (ARMDataProcessingOpCode)((*ptr & MASK_OPCODE) >> RSHIFT_OPCODE); string instr = $"{opcode}{suffix} {opcode switch { ARMDataProcessingOpCode.MOV or ARMDataProcessingOpCode.MVN => rd, ARMDataProcessingOpCode.CMP or ARMDataProcessingOpCode.CMN or ARMDataProcessingOpCode.TEQ or ARMDataProcessingOpCode.TST => rn, _ => $"{rd}, {rn}", }}, ";
/// <summary> /// Checks whenever the Condition of a Opcode matches the current Status Register, to see if the condition is true. /// </summary> /// <param name="Condition">The Condition of the Opcode</param> /// <returns>If the condition is true or not</returns> private bool IsConditionMet(ARMCondition Condition) { switch (Condition) { case ARMCondition.Equal: return(Registers.IsFlagSet(ARMFlag.Zero)); case ARMCondition.NotEqual: return(Registers.IsFlagClear(ARMFlag.Zero)); case ARMCondition.CarrySet: return(Registers.IsFlagSet(ARMFlag.Carry)); case ARMCondition.CarryClear: return(Registers.IsFlagClear(ARMFlag.Carry)); case ARMCondition.Minus: return(Registers.IsFlagSet(ARMFlag.Negative)); case ARMCondition.Plus: return(Registers.IsFlagClear(ARMFlag.Negative)); case ARMCondition.Overflow: return(Registers.IsFlagSet(ARMFlag.Overflow)); case ARMCondition.NoOverflow: return(Registers.IsFlagClear(ARMFlag.Overflow)); case ARMCondition.UnsignedHigher: return(ConditionHI()); case ARMCondition.UnsignedLowerOrSame: return(ConditionLS()); case ARMCondition.SignedGreaterThanOrEqual: return(ConditionGE()); case ARMCondition.SignedLessThan: return(ConditionLT()); case ARMCondition.SignedGreaterThan: return(Registers.IsFlagClear(ARMFlag.Zero) && ConditionGE()); case ARMCondition.SignedLessThanOrEqual: return(Registers.IsFlagSet(ARMFlag.Zero) || ConditionLT()); case ARMCondition.Always: return(true); } return(false); }
/// <summary> /// Executes a single instruction. /// </summary> public void Execute() { uint TruePC = Registers[15] - 4; if (Registers.IsFlagSet(ARMFlag.Thumb)) { Opcode = NextOpcode; NextOpcode = ReadUInt16(Registers[15]); Registers[15] += 2; Registers.PCChanged = false; switch ((Opcode >> 13) & 7) { case 0: switch ((Opcode >> 11) & 3) { case 0: Thumb_LSL(); break; case 1: Thumb_LSR(); break; case 2: Thumb_ASR(); break; case 3: if (IsOpcodeBitSet(9)) { if (IsOpcodeBitSet(10)) { Thumb_SUB(); } else { Thumb_SUB_3(); } } else { if (IsOpcodeBitSet(10)) { Thumb_ADD(); } else { Thumb_ADD_3(); } } break; } break; case 1: switch ((Opcode >> 11) & 3) { case 0: Thumb_MOV(); break; case 1: Thumb_CMP(); break; case 2: Thumb_ADD_2(); break; case 3: Thumb_SUB_2(); break; } break; case 2: if (IsOpcodeBitSet(12)) { switch ((Opcode >> 9) & 7) { case 0: Thumb_STR_2(); break; case 1: Thumb_STRH_2(); break; case 2: Thumb_STRB_2(); break; case 3: Thumb_LDRSB(); break; case 4: Thumb_LDR_2(); break; case 5: Thumb_LDRH_2(); break; case 6: Thumb_LDRB_2(); break; case 7: Thumb_LDRSH(); break; } } else { if (IsOpcodeBitSet(11)) { Thumb_LDR_3(); } else { if (IsOpcodeBitSet(10)) { switch ((Opcode >> 8) & 3) { case 0: Thumb_ADD_4(); break; case 1: Thumb_CMP_3(); break; case 2: Thumb_CPY(); break; case 3: if (IsOpcodeBitSet(7)) { Thumb_BLX_2(); } else { Thumb_BX(); } break; } } else //Data Processing { switch ((Opcode >> 6) & 0xf) { case 0: Thumb_AND(); break; case 1: Thumb_EOR(); break; case 2: Thumb_LSL_2(); break; case 3: Thumb_LSR_2(); break; case 4: Thumb_ASR_2(); break; case 5: Thumb_ADC(); break; case 6: Thumb_SBC(); break; case 7: Thumb_ROR(); break; case 8: Thumb_TST(); break; case 9: Thumb_NEG(); break; case 0xa: Thumb_CMP_2(); break; case 0xb: Thumb_CMN(); break; case 0xc: Thumb_ORR(); break; case 0xd: Thumb_MUL(); break; case 0xe: Thumb_BIC(); break; case 0xf: Thumb_MVN(); break; } } } } break; case 3: if (IsOpcodeBitSet(11)) { if (IsOpcodeBitSet(12)) { Thumb_LDRB(); } else { Thumb_LDR(); } } else { if (IsOpcodeBitSet(12)) { Thumb_STRB(); } else { Thumb_STR(); } } break; case 4: if (IsOpcodeBitSet(12)) { if (IsOpcodeBitSet(11)) { Thumb_LDR_4(); } else { Thumb_STR_3(); } } else { if (IsOpcodeBitSet(11)) { Thumb_LDRH(); } else { Thumb_STRH(); } } break; case 5: if (IsOpcodeBitSet(12)) { switch ((Opcode >> 9) & 3) { case 0: if (IsOpcodeBitSet(7)) { Thumb_SUB_4(); } else { Thumb_ADD_7(); } break; case 1: if (IsOpcodeBitSet(11)) { switch ((Opcode >> 6) & 3) { case 0: Thumb_REV(); break; case 1: Thumb_REV16(); break; case 3: Thumb_REVSH(); break; } } else { switch ((Opcode >> 6) & 3) { case 0: Thumb_SXTH(); break; case 1: Thumb_SXTB(); break; case 2: Thumb_UXTH(); break; case 3: Thumb_UXTB(); break; } } break; case 2: if (IsOpcodeBitSet(11)) { Thumb_POP(); } else { Thumb_PUSH(); } break; case 3: if (IsOpcodeBitSet(11)) { Thumb_BKPT(); } else { if (IsOpcodeBitSet(5)) { Thumb_CPS(); } else { Thumb_SETEND(); } } break; } } else { if (IsOpcodeBitSet(11)) { Thumb_ADD_6(); } else { Thumb_ADD_5(); } } break; case 6: if (IsOpcodeBitSet(12)) { if (((Opcode >> 8) & 0xf) == 0xf) { Thumb_SWI(); } else { Thumb_B(); } } else { if (IsOpcodeBitSet(11)) { Thumb_LDMIA(); } else { Thumb_STMIA(); } } break; case 7: if (((Opcode >> 11) & 3) == 0) { Thumb_B_2(); } else { Thumb_BLX(); } break; } } else { Opcode = NextOpcode; NextOpcode = ReadUInt32(Registers[15]); Registers[15] += 4; Registers.PCChanged = false; ARMCondition Condition = (ARMCondition)(Opcode >> 28); if (IsConditionMet(Condition)) { switch ((Opcode >> 25) & 7) { case 0: case 1: if (IsOpcodeBitSet(4) && IsOpcodeBitSet(7) && !IsOpcodeBitSet(25)) { if (((Opcode >> 5) & 3) > 0 || IsOpcodeBitSet(24)) { ARM_DecodeLoadAndStoreExtension(); } else { ARM_DecodeMultiplyExtension(); } } else { if (((Opcode >> 23) & 3) == 2 && !IsOpcodeBitSet(20)) { ARM_DecodeDSPExtension(); } else //Data Processing { switch ((Opcode >> 21) & 0xf) { case 0: ARM_AND(); break; case 1: ARM_EOR(); break; case 2: ARM_SUB(); break; case 3: ARM_RSB(); break; case 4: ARM_ADD(); break; case 5: ARM_ADC(); break; case 6: ARM_SBC(); break; case 7: ARM_RSC(); break; case 8: ARM_TST(); break; case 9: ARM_TEQ(); break; case 0xa: ARM_CMP(); break; case 0xb: ARM_CMN(); break; case 0xc: ARM_ORR(); break; case 0xd: ARM_MOV(); break; case 0xe: ARM_BIC(); break; case 0xf: ARM_MVN(); break; } } } break; case 2: case 3: if (IsOpcodeBitSet(4) && IsOpcodeBitSet(25)) { ARM_DecodeMediaExtension(); } else //Load/Store { if (IsOpcodeBitSet(20)) { if (IsOpcodeBitSet(22)) { ARM_LDRB(); } else { ARM_LDR(); } } else { if (IsOpcodeBitSet(22)) { ARM_STRB(); } else { ARM_STR(); } } } break; case 4: //Load/Store Multiple if (IsOpcodeBitSet(20)) { ARM_LDM(); } else { ARM_STM(); } break; case 5: ARM_B(); break; case 6: case 7: //Coprocessor if (IsOpcodeBitSet(25)) { if (IsOpcodeBitSet(24)) { ARM_SWI(); } else { if (IsOpcodeBitSet(4)) { if (IsOpcodeBitSet(20)) { ARM_MRC(); } else { ARM_MCR(); } } else { ARM_CDP(); } } } else { if (IsOpcodeBitSet(20)) { ARM_MRRC(); } else { ARM_MCRR(); } } break; } } else if (Condition == ARMCondition.Unconditional) { switch ((Opcode >> 26) & 3) { case 0: if (IsOpcodeBitSet(16)) { ARM_SETEND(); } else { ARM_CPS(); } break; case 1: ARM_PLD(); break; case 2: if (IsOpcodeBitSet(25)) { ARM_BLX(); } else { if (IsOpcodeBitSet(22)) { ARM_SRS(); } else { ARM_RFE(); } } break; case 3: if (IsOpcodeBitSet(25)) { if (IsOpcodeBitSet(20)) { ARM_MRC(); } else { ARM_MCR(); } } else { if (IsOpcodeBitSet(20)) { ARM_MRRC(); } else { ARM_MCRR(); } } break; } } } if (Registers.PCChanged) { ReloadPipeline(); } if (Debug) { string RVals = null; for (int i = 0; i < 15; i++) { RVals += "R" + i + " = " + Registers[i].ToString("X8") + " "; } System.Diagnostics.Debug.WriteLine(Opcode.ToString("X8") + " - " + TruePC.ToString("X8") + ": " + RVals + " CPSR: " + Registers.CPSR.ToString("X8")); } }