unit DisassemblerThumb; {$mode objfpc}{$H+} { This disassembler is build based on the information in chapter F of the ARM DDI 0487A.e ID121714 Documentation it's main purpose is to give an basic overview of what is going on. And yes, this can require a bit of refactoring } interface uses Classes, SysUtils, LastDisassembleData, strutils; type TThumbDisassembler=object private a: ptruint; opcode: uint16; opcode2: uint16; //for 32-bit thumb2 procedure ADC_R_T1; procedure ADC_R_T2; procedure AND_R_T1; procedure AND_R_T2; procedure EOR_R_T1; procedure EOR_R_T2; procedure SBC_R_T1; procedure SBC_R_T2; procedure TST_R_T1; procedure TST_R_T2; procedure RSB_I_T1; procedure RSB_R_T1; procedure CMP_R_T1; procedure CMP_R_T2; procedure CMP_R_T3; procedure CMN_R_T1; procedure CMN_R_T2; procedure ORR_R_T1; procedure ORR_R_T2; procedure ORN_R_T1; procedure MUL_R_T1; procedure BIC_R_T1; procedure BIC_R_T2; procedure MVN_R_T1; procedure MVN_R_T2; procedure MOV_R_T1; procedure MOV_R_T2; procedure MOV_R_T3; procedure MOV_RSR_T1; procedure MOV_RSR_T2; procedure PKHBT_T1; procedure ADD_SP_R_T1; procedure ADD_SP_R_T2; procedure ADD_R_T1; procedure ADD_R_T2; procedure ADD_R_T3; procedure SUB_R_T1; procedure SUB_R_T2; procedure ADD_I_T1; procedure ADD_I_T2; procedure ADD_I_T4; procedure ADR_T2; procedure ADR_T3; procedure SUB_I_T1; procedure SUB_I_T2; procedure SUB_I_T4; procedure SUB_I_T5; procedure TEQ_R_T1; procedure SSAT_T1; procedure SSAT16_T1; procedure USAT_T1; procedure USAT16_T1; procedure SBFX_T1; procedure UBFX_T1; procedure BFI_T1; procedure BFC_T1; procedure MOV_I_T1; procedure MOV_I_T3; procedure MOVT_T1; procedure CMP_I_T1; procedure B_T1; procedure B_T2; procedure B_T3; procedure B_T4; procedure BL_X_T1; procedure BL_X_T2; procedure BX_T1; procedure BLX_R_T1; procedure BXJ_T1; procedure LDR_L_T1; procedure LDR_L_T2; procedure STR_R_T1; procedure STR_R_T2; procedure STRH_R_T1; procedure STRH_R_T2; procedure STRHT_T1; procedure STRB_R_T1; procedure STRB_R_T2; procedure STRBT_T1; procedure STRT_T1; procedure LDRSB_R_T1; procedure LDRSB_R_T2; procedure LDRSB_L_T1; procedure LDR_R_T1; procedure LDR_R_T2; procedure LDRH_R_T1; procedure LDRH_R_T2; procedure LDRB_R_T1; procedure LDRB_R_T2; procedure LDRSH_R_T1; procedure LDRSH_R_T2; procedure STR_I_T1; procedure LDR_I_T1; procedure STR_I_T2; procedure LDR_I_T2; procedure STR_I_T3; procedure STR_I_T4; procedure LDR_I_T4; procedure STRB_I_T1; procedure STRB_I_T2; procedure STRB_I_T3; procedure LDRB_I_T1; procedure LDRB_I_T2; procedure LDRB_I_T3; procedure STRH_I_T1; procedure STRH_I_T2; procedure STRH_I_T3; procedure LDRH_I_T1; procedure LDRSH_I_T1; procedure LDRSH_I_T2; procedure LDRSB_I_T1; procedure LDRSB_I_T2; procedure ADR_T1; procedure ADD_SP_I_T1; procedure ADD_SP_I_T2; procedure SUB_SP_I_T1; procedure CBZ_CBNZ; procedure SXTH_T1; procedure SXTH_T2; procedure SXTAH_T1; procedure SXTB_T1; procedure SXTB_T2; procedure SXTAB_T1; procedure SXTB16_T1; procedure SXTAB16_T1; procedure UXTB16_T1; procedure UXTAB_T1; procedure UXTAB16_T1; procedure UXTH_T1; procedure UXTH_T2; procedure UXTAH_T1; procedure UXTB_T1; procedure UXTB_T2; procedure PUSH_T1; procedure POP_T1; procedure SETEND_T1; procedure CPS_T1; procedure CPS_T2; procedure REV_T1; procedure REV16_T1; procedure REVSH_T1; procedure DBG_T1; procedure HLT_T1; procedure BKPT_T1; procedure UDF_T1; procedure SVC_T1; procedure IT_T1; procedure STM_T1; procedure STM_T2; procedure LDM_T1; procedure LDM_T2; procedure STMDB_T1; procedure LDMDB_T1; procedure MSR_BR_T1; procedure MSR_R_T1; procedure MRS_BR_T1; procedure MRS_R_T1; procedure SRS_T1; procedure SRS_T2; procedure RFE_T1; procedure RFE_T2; procedure STREX_T1; procedure LDREX_T1; procedure STRD_I_T1; procedure LDRD_I_T1; procedure LDRD_L_T1; procedure LDRH_L_T1; procedure LDRSH_L_T1; procedure LDRBT_T1; procedure LDRHT_T1; procedure LDRSHT_T1; procedure LDRSBT_T1; procedure PLD_L_T1; procedure PLD_R_T1; procedure PLD_I_T1; procedure PLD_I_T2; procedure PLI_IL_T1; procedure PLI_IL_T2; procedure PLI_IL_T3; procedure PLI_R_T1; procedure NOP_T32; //T32: procedure T32; procedure T32_DataProcessing_Reg; procedure T32_DataProcessing_Shifted_Reg; procedure T32_DataProcessing_Modified_Immediate; procedure T32_DataProcessing_Plain_Binary_Immediate; procedure T32_Branches_And_Miscellaneous_Control; procedure T32_LoadStore_Multiple; procedure T32_STR_LDR_STL; procedure T32_LoadWord; procedure T32_LoadHalfWord_MemoryHints; procedure T32_LoadByte_MemoryHints; procedure T32_StoreSingleDataItem; procedure T32_Multiply_MultiplyAccumulate_AbsoluteDiff; procedure T32_LongMultiply_LongMultiplyAccumulate_Divide; public LastDisassembleData: TLastDisassembleData; function disassemble(var address: ptrUint): string; end; implementation uses DisassemblerArm {$ifndef armdev} ,ProcessHandlerUnit, NewKernelHandler {$endif} ; procedure TThumbDisassembler.T32_LongMultiply_LongMultiplyAccumulate_Divide; var op1, rn, RdLo, RdHi, op2, Rm: byte; x: byte; begin op1:=(opcode shr 4) and 7; rn:=opcode and $f; RdLo:=(opcode2 shr 12) and $f; RdHi:=(opcode2 shr 8) and $f; op2:=(opcode2 shr 4) and $f; Rm:=opcode2 and $f; x:=(op1 shl 4) or op2; if op2=15 then LastDisassembleData.parameters:=ArmRegisters[RdHi]+','+ArmRegisters[Rn]+','+ArmRegisters[Rm] else LastDisassembleData.parameters:=ArmRegisters[RdLo]+','+ArmRegisters[RdHi]+','+ArmRegisters[Rn]+','+ArmRegisters[Rm]; case x of 0: LastDisassembleData.opcode:='SMULL'; $1f: LastDisassembleData.opcode:='SDIV'; $20: LastDisassembleData.opcode:='UMUL'; $3f: LastDisassembleData.opcode:='UDIV'; $40: LastDisassembleData.opcode:='SMLAL'; $48: LastDisassembleData.opcode:='SMLALBB'; $49: LastDisassembleData.opcode:='SMLALTB'; $4a: LastDisassembleData.opcode:='SMLALBT'; $4b: LastDisassembleData.opcode:='SMLALTT'; $4c: LastDisassembleData.opcode:='SMLALD'; $4d: LastDisassembleData.opcode:='SMLALDX'; $5c: LastDisassembleData.opcode:='SMLSLD'; $5d: LastDisassembleData.opcode:='SMLSLDX'; $60: LastDisassembleData.opcode:='UMLAL'; $66: LastDisassembleData.opcode:='UMAAL'; end; end; procedure TThumbDisassembler.T32_Multiply_MultiplyAccumulate_AbsoluteDiff; var op1, rn, Ra, rd, rm, op2: byte; x: byte; _ra: string; begin op1:=(opcode shr 4) and $7; rn:=opcode and $f; Ra:=(opcode2 shr 12) and $f; rd:=(opcode2 shr 8) and $f; op2:=(opcode2 shr 4) and 3; rm:=opcode2 and $f; x:=(op1 shl 2) or op2; if ra=15 then _ra:='' else _ra:=','+ArmRegisters[ra]; LastDisassembleData.parameters:=ArmRegisters[Rd]+','+ArmRegisters[Rn]+','+ArmRegisters[Rm]+_ra; case op1 of 0: if ra=15 then LastDisassembleData.opcode:='MUL' else LastDisassembleData.opcode:='MLA'; 1: LastDisassembleData.opcode:='MLS'; $4: if ra=15 then LastDisassembleData.opcode:='SMULBB' else LastDisassembleData.opcode:='SMLABB'; $5: if ra=15 then LastDisassembleData.opcode:='SMULTB' else LastDisassembleData.opcode:='SMLATB'; $6: if ra=15 then LastDisassembleData.opcode:='SMULBT' else LastDisassembleData.opcode:='SMLABT'; $7: if ra=15 then LastDisassembleData.opcode:='SMULTT' else LastDisassembleData.opcode:='SMLATT'; $8: if ra=15 then LastDisassembleData.opcode:='SMUAD' else LastDisassembleData.opcode:='SMLAD'; $9: if ra=15 then LastDisassembleData.opcode:='SMUADX' else LastDisassembleData.opcode:='SMLADX'; $C: if ra=15 then LastDisassembleData.opcode:='SMULWB' else LastDisassembleData.opcode:='SMLAWB'; $d: if ra=15 then LastDisassembleData.opcode:='SMULWT' else LastDisassembleData.opcode:='SMLAWT'; $10: if ra=15 then LastDisassembleData.opcode:='SMUSD' else LastDisassembleData.opcode:='SMLSD'; $11: if ra=15 then LastDisassembleData.opcode:='SMUSDX' else LastDisassembleData.opcode:='SMLSDX'; $14: if ra=15 then LastDisassembleData.opcode:='SMMUL' else LastDisassembleData.opcode:='SMMLA'; $15: if ra=15 then LastDisassembleData.opcode:='SMMULR' else LastDisassembleData.opcode:='SMMLAR'; $18: LastDisassembleData.opcode:='SMMLS'; $19: LastDisassembleData.opcode:='SMMLSR'; $1c: if ra=15 then LastDisassembleData.opcode:='USAD8' else LastDisassembleData.opcode:='USADA8'; end; end; procedure TThumbDisassembler.T32_DataProcessing_Reg; var op1, rd, rn, rm, op2,x: byte; begin op1:=(opcode shr 4) and $f; rn:=opcode and $f; rd:=(opcode2 shr 8) and $f; op2:=(opcode shr 4) and $f; rm:=opcode2 and $f; if (op2=0) and (op1 shr 1=1) then begin MOV_RSR_T2; end else if (op1 shr 3=1) then begin case op2 shr 2 of 0: begin //Parallel Addition and subtraction, signed op1:=(opcode shr 4) and 7; op2:=(opcode shr 4) and 3; x:=(op2 shl 3) or op1; LastDisassembleData.parameters:=ArmRegisters[Rd]+','+ArmRegisters[Rn]+','+ArmRegisters[Rm]; case x of 0: LastDisassembleData.opcode:='SADD8'; 1: LastDisassembleData.opcode:='SADD16'; 2: LastDisassembleData.opcode:='SASX'; 4: LastDisassembleData.opcode:='SSUB8'; 5: LastDisassembleData.opcode:='SSUB16'; 6: LastDisassembleData.opcode:='SSAX'; $8+0: LastDisassembleData.opcode:='QADD8'; $8+1: LastDisassembleData.opcode:='QADD16'; $8+2: LastDisassembleData.opcode:='QASX'; $8+4: LastDisassembleData.opcode:='QSUB8'; $8+5: LastDisassembleData.opcode:='QSUB16'; $8+6: LastDisassembleData.opcode:='QSAX'; $10+0: LastDisassembleData.opcode:='SHADD8'; $10+1: LastDisassembleData.opcode:='SHADD16'; $10+2: LastDisassembleData.opcode:='SHASX'; $10+4: LastDisassembleData.opcode:='SHSUB8'; $10+5: LastDisassembleData.opcode:='SHSUB16'; $10+6: LastDisassembleData.opcode:='SHSAX'; end; end; 1: begin //Parallel addition and subtraction, unsigned op1:=(opcode shr 4) and 7; op2:=(opcode shr 4) and 3; x:=(op2 shl 3) or op1; LastDisassembleData.parameters:=ArmRegisters[Rd]+','+ArmRegisters[Rn]+','+ArmRegisters[Rm]; case x of 0: LastDisassembleData.opcode:='UADD8'; 1: LastDisassembleData.opcode:='UADD16'; 2: LastDisassembleData.opcode:='UASX'; 4: LastDisassembleData.opcode:='USUB8'; 5: LastDisassembleData.opcode:='USUB16'; 6: LastDisassembleData.opcode:='USAX'; $8+0: LastDisassembleData.opcode:='UQADD8'; $8+1: LastDisassembleData.opcode:='UQADD16'; $8+2: LastDisassembleData.opcode:='UQASX'; $8+4: LastDisassembleData.opcode:='UQSUB8'; $8+5: LastDisassembleData.opcode:='UQSUB16'; $8+6: LastDisassembleData.opcode:='UQSAX'; $10+0: LastDisassembleData.opcode:='UHADD8'; $10+1: LastDisassembleData.opcode:='UHADD16'; $10+2: LastDisassembleData.opcode:='UHASX'; $10+4: LastDisassembleData.opcode:='UHSUB8'; $10+5: LastDisassembleData.opcode:='UHSUB16'; $10+6: LastDisassembleData.opcode:='UHSAX'; end; end; 2: begin //miscelanious operations op1:=(opcode shr 4) and 7; op2:=(opcode shr 4) and 3; x:=(op1 shl 2) or op2; LastDisassembleData.parameters:=ArmRegisters[Rd]+','+ArmRegisters[Rn]+','+ArmRegisters[Rm]; case x of 0: LastDisassembleData.opcode:='QADD'; 1: LastDisassembleData.opcode:='QDADD'; 2: LastDisassembleData.opcode:='QSUB'; 3: LastDisassembleData.opcode:='QDSUB'; $4+0: LastDisassembleData.opcode:='REV'; $4+1: LastDisassembleData.opcode:='REV16'; $4+2: LastDisassembleData.opcode:='RBIT'; $4+3: LastDisassembleData.opcode:='REVSH'; $8: LastDisassembleData.opcode:='SEL'; $c: LastDisassembleData.opcode:='CLZ'; $10: LastDisassembleData.opcode:='CRC32B'; $11: LastDisassembleData.opcode:='CRC32H'; $12: LastDisassembleData.opcode:='CRC32W'; $14: LastDisassembleData.opcode:='CRC32CB'; $15: LastDisassembleData.opcode:='CRC32CH'; $16: LastDisassembleData.opcode:='CRC32CW'; end; end; end; end else begin if op2 shr 3=1 then begin case op1 of 0: if rn=15 then SXTH_T2 else SXTAH_T1; 1: if rn=15 then UXTH_T2 else UXTAH_T1; 2: if rn=15 then SXTB16_T1 else SXTAB16_T1; 3: if rn=15 then UXTB16_T1 else UXTAB16_T1; 4: if rn=15 then SXTB_T2 else SXTAB_T1; 5: if rn=15 then UXTB_T2 else UXTAB_T1; end; end; end; end; procedure TThumbDisassembler.T32_DataProcessing_Shifted_Reg; var op, s, rn, rd: byte; rds: byte; begin op:=(opcode shr 5) and $f; s:=(opcode shr 4) and 1; rn:=opcode and $f; rd:=(opcode2 shr 8) and $f; rds:=(rd shl 1) or s; case op of 0: if rds=31 then AND_R_T2 else TST_R_T2; 1: BIC_R_T2; 2: if rn=15 then MOV_R_T3 else ORR_R_T2; 3: if rn=15 then MVN_R_T2 else ORN_R_T1; 4: if rds=31 then TEQ_R_T1 else EOR_R_T2; 6: PKHBT_T1; 8: if rds=31 then CMN_R_T2 else ADD_R_T3; 10: ADC_R_T2; 11: SBC_R_T2; 13: if RDS =31 then CMP_R_T3 else SUB_R_T2; 14: RSB_R_T1; end; end; procedure TThumbDisassembler.T32_StoreSingleDataItem; var op1, op2: byte; begin op1:=(opcode shr 5) and 7; op2:=(opcode shr 6) and $3f; case op1 of 4: STRB_I_T2; 5: STRH_I_T2; 6: STR_I_T3; else begin if (op2=0) then begin case op1 of 0: STRB_R_T2; 1: STRH_R_T2; 2: STR_R_T2; end; end else if (op2 and $24=$24) or ((op2 shr 2)=12) then begin case op1 of 0: STRB_I_T3; 1: STRH_I_T3; 2: STR_I_T4; end; end else if (op2 shr 2)=13 then begin case op1 of 0: STRBT_T1; 1: STRHT_T1; 2: STRT_T1; end; end; end; end; end; procedure TThumbDisassembler.T32_LoadByte_MemoryHints; var op1, rn, rt, op2: byte; begin op1:=(opcode shr 7) and 3; rn:=opcode and $f; rt:=(opcode2 shr 12) and $f; op2:=(opcode shr 6) and $3f; if (rn=15) then begin if (op1 shr 1)=1 then begin //1* if rt<>15 then begin LDRSB_L_T1; end else begin //rn=1111 rt=1111 PLI_IL_T3; end; end else begin //0* if rt<>15 then begin if op1=0 then LDRB_I_T3 else LDRB_I_T2 end else begin PLD_L_T1; end; end; end else //rn<>15 case op1 of 0: begin if (op2 and $24=$24) or ((op2 shr 2 = 12) and (rt<>15) ) then begin LDRB_I_T3; end else begin if op2=0 then begin if rt=15 then begin PLD_R_T1; end else begin LDRB_R_T2; end; end else begin //op2<>0 case op2 shr 2 of 12: begin if rt=15 then begin //op1=00 op2=1100xx rn<>1111 rt=1111 //1111100 0 0 0 0 1 xxxx 1111 1100xxxxxxxx PLD_I_T2; end; end; 14: begin //LDRBT //op1=00 op2=1110xx rn<>1111 rt=1111 //1111100 0 0 0 0 1 xxxx 1111 1100xxxxxxxx LDRBT_T1; end; end; end; end; end; 1: begin if rt=15 then begin PLD_I_T1; end else begin LDRB_I_T2; end; end; 2: begin if (op2 and $24=$24) or ((op2 shr 2 = 12) and (rt<>15) ) then begin LDRSB_I_T2; end else begin if op2=0 then begin if rt=15 then begin PLI_R_T1; end else begin LDRSB_R_T2; end; end else begin //op2<>0 case op2 shr 2 of 12: begin if rt=15 then begin PLI_IL_T2; end; end; 14: begin LDRSBT_T1; end; end; end; end; end; 3: begin if (rt=15) then begin PLI_IL_T1; end else begin LDRSB_I_T1; end; end; end; end; procedure TThumbDisassembler.T32_LoadHalfWord_MemoryHints; var op1, rn, rt, op2: byte; begin op1:=(opcode shr 7) and 3; rn:=opcode and $f; rt:=(opcode2 shr 12) and $f; op2:=(opcode shr 6) and $3f; if (rn=15) then begin if (op1 shr 1)=1 then begin if rt<>15 then begin LDRSH_L_T1; end else begin NOP_T32; end; end else begin if rt<>15 then begin LDRH_L_T1; end else begin PLD_L_T1; end; end; end else //rn<>15 case op1 of 0: begin if (op2 and $24=$24) or ((op2 shr 2 = 12) and (rt<>15) ) then begin LDRH_L_T1; end else begin if op2=0 then begin if rt=15 then begin PLD_R_T1; //00 000000 xxxx 1111 end else begin LDRH_R_T2; end; end else begin //op2<>0 case op2 shr 2 of 12: begin if rt=15 then begin PLD_I_T1; end; end; 14: begin LDRHT_T1; end; end; end; end; end; 1: begin if rt=15 then begin PLD_R_T1; end else begin LDRH_I_T1; end; end; 2: begin if (op2 and $24=$24) or ((op2 shr 2 = 12) and (rt<>15) ) then begin LDRSH_I_T2; end else begin if op2=0 then begin if rt=15 then begin NOP_T32; end else begin LDRSH_R_T2; end; end else begin //op2<>0 case op2 shr 2 of 12: begin if rt=15 then begin NOP_T32; end; end; 14: begin LDRSHT_T1; end; end; end; end; end; 3: begin if (rt=15) then NOP_T32 else LDRSH_I_T1; end; end; end; procedure TThumbDisassembler.T32_LoadWord; var op1, Rn, op2: byte; begin op1:=(opcode shr 7) and 3; Rn:=opcode and $f; op2:=(opcode shr 6) and $3f; if (rn=15) then begin if (op1<=1) then LDR_L_T2; end else begin if (op1=1) then begin LDR_I_T4; end else begin if (op2=0) then begin LDR_R_T2; end else begin if ((op2 shr 2)=12) or ((op2 and $24)=$24 ) then begin LDR_I_T4; end; end; end; end; end; procedure TThumbDisassembler.T32_STR_LDR_STL; var op1, op2, Rn, op3, rt, rt2, rd,rm: byte; _h: string; begin op1:=(opcode shr 7) and 3; op2:=(opcode shr 4) and 3; Rn:=opcode and $f; op3:=(opcode2 shr 4) and $f; rt:=(opcode2 shr 12) and $f; rt2:=(opcode2 shr 8) and $f; rd:=(opcode2 and $f); rm:=rd; case (op1 shl 2) or op2 of 0: STREX_T1; 1: LDREX_T1; 2,6,8,10,12,14: STRD_I_T1; 3, 7,9,11,13,15: if rn<>15 then LDRD_I_T1 else LDRD_L_T1; // else LDRD_Immediate; 4: begin case op3 of 4: begin LastDisassembleData.opcode:='STREXB'; LastDisassembleData.parameters:=ArmRegisters[Rd]+','+ArmRegisters[Rt]+'['+ArmRegisters[Rn]+']'; end; 5: begin LastDisassembleData.opcode:='STREXH'; LastDisassembleData.parameters:=ArmRegisters[Rd]+','+ArmRegisters[Rt]+'['+ArmRegisters[Rn]+']'; end; 7: begin LastDisassembleData.opcode:='STREXD'; LastDisassembleData.parameters:=ArmRegisters[Rd]+','+ArmRegisters[Rt]+','+ArmRegisters[Rt2]+'['+ArmRegisters[Rn]+']'; end; 8: begin LastDisassembleData.opcode:='STLB'; LastDisassembleData.parameters:=ArmRegisters[Rt]+',['+ArmRegisters[Rn]+']'; end; 9: begin LastDisassembleData.opcode:='STLH'; LastDisassembleData.parameters:=ArmRegisters[Rt]+',['+ArmRegisters[Rn]+']'; end; 10: begin LastDisassembleData.opcode:='STL'; LastDisassembleData.parameters:=ArmRegisters[Rt]+',['+ArmRegisters[Rn]+']'; end; 12: begin LastDisassembleData.opcode:='SLTEXB'; LastDisassembleData.parameters:=ArmRegisters[Rd]+','+ArmRegisters[Rt]+'['+ArmRegisters[Rn]+']'; end; 13: begin LastDisassembleData.opcode:='STLEXH'; LastDisassembleData.parameters:=ArmRegisters[Rd]+','+ArmRegisters[Rt]+'['+ArmRegisters[Rn]+']'; end; 14: begin LastDisassembleData.opcode:='STLEX'; LastDisassembleData.parameters:=ArmRegisters[Rd]+','+ArmRegisters[Rt]+'['+ArmRegisters[Rn]+']'; end; 15: begin LastDisassembleData.opcode:='STLEXD'; LastDisassembleData.parameters:=ArmRegisters[Rd]+','+ArmRegisters[Rt]+','+ArmRegisters[Rt2]+'['+ArmRegisters[Rn]+']'; end; end; end; 5: begin case op3 of 0: begin LastDisassembleData.opcode:='TBB'; LastDisassembleData.parameters:='['+ArmRegisters[Rn]+','+ArmRegisters[Rm]+']'; end; 1: begin LastDisassembleData.opcode:='TBH'; LastDisassembleData.parameters:='['+ArmRegisters[Rn]+','+ArmRegisters[Rm]+', LSL 1]'; end; 4: begin LastDisassembleData.opcode:='LDREXB'; LastDisassembleData.parameters:=ArmRegisters[Rt]+',['+ArmRegisters[Rn]+']'; end; 5: begin LastDisassembleData.opcode:='LDREXH'; LastDisassembleData.parameters:=ArmRegisters[Rt]+',['+ArmRegisters[Rn]+']'; end; 7: begin LastDisassembleData.opcode:='LDREXD'; LastDisassembleData.parameters:=ArmRegisters[Rt]+','+ArmRegisters[Rt2]+',['+ArmRegisters[Rn]+']'; end; 8: begin LastDisassembleData.opcode:='LDAB'; LastDisassembleData.parameters:=ArmRegisters[Rt]+',['+ArmRegisters[Rn]+']'; end; 9: begin LastDisassembleData.opcode:='LDAH'; LastDisassembleData.parameters:=ArmRegisters[Rt]+',['+ArmRegisters[Rn]+']'; end; 10: begin LastDisassembleData.opcode:='LDA'; LastDisassembleData.parameters:=ArmRegisters[Rt]+',['+ArmRegisters[Rn]+']'; end; 12: begin LastDisassembleData.opcode:='LDAEXB'; LastDisassembleData.parameters:=ArmRegisters[Rt]+',['+ArmRegisters[Rn]+']'; end; 13: begin LastDisassembleData.opcode:='LDAEXH'; LastDisassembleData.parameters:=ArmRegisters[Rt]+',['+ArmRegisters[Rn]+']'; end; 14: begin LastDisassembleData.opcode:='LDAEX'; LastDisassembleData.parameters:=ArmRegisters[Rt]+',['+ArmRegisters[Rn]+']'; end; 15: begin LastDisassembleData.opcode:='LDAEXD'; LastDisassembleData.parameters:=ArmRegisters[Rt]+','+ArmRegisters[Rt2]+',['+ArmRegisters[Rn]+']'; end; end; end; end; end; procedure TThumbDisassembler.T32_LoadStore_Multiple; var op, W,L,Rn: byte; WRn: byte; begin op:=(opcode shr 7) and 3; w:=(opcode shr 5) and 1; l:=(opcode shr 4) and 1; Rn:=opcode and $f; WRn:=(W shl 4) or Rn; case op of 0: begin case L of 0: SRS_T1; //SRS 1: RFE_T1; end; end; 1: begin case L of 0: STM_T2; 1: LDM_T2; ////not W_Rn: $1D end; end; 2: begin case L of 0: STMDB_T1; //not W_Rn: $1D 1: LDMDB_T1; end; end; 3: begin case L of 0: SRS_T2; 1: RFE_T2; end; end; end; end; procedure TThumbDisassembler.T32_Branches_And_Miscellaneous_Control; var op, op1, op2, op3, imm8: byte; begin op:=(opcode shr 4) and $7f; op3:=opcode and $f; op1:=(opcode2 shr 12) and 7; op2:=(opcode2 shr 8) and $f; imm8:=opcode2 and $ff; case op1 of 0,2: begin if (((op shr 3) and 7)<>7) then begin B_T3; end else begin case op of $38,$39: begin if (imm8 shr 5) and 1=1 then begin MSR_BR_T1; end else begin MSR_R_T1; end; end; $3a: begin //Change PE_State_and_Hints if ((opcode2 shl 8) and 7)<>0 then begin CPS_T2; end else begin case (opcode2 and $ff) of 0: LastDisassembleData.opcode:='NOP'; 1: LastDisassembleData.opcode:='YIELD'; 2: LastDisassembleData.opcode:='WFE'; 3: LastDisassembleData.opcode:='WFI'; 4: LastDisassembleData.opcode:='SEV'; 5: LastDisassembleData.opcode:='SEVL'; $f0..$ff: DBG_T1; end; end; end; $3b: begin //Misc_Control_instructions case ((opcode2 shr 4) and $f) of 2: LastDisassembleData.opcode:='CLREX'; 4: begin LastDisassembleData.opcode:='DSB'; LastDisassembleData.parameters:=inttohex(opcode2 and $f,1); end; 5: begin LastDisassembleData.opcode:='DMB'; LastDisassembleData.parameters:=inttohex(opcode2 and $f,1); end; 6: begin LastDisassembleData.opcode:='ISB'; LastDisassembleData.parameters:=inttohex(opcode2 and $f,1); end; end; end; $3c: BXJ_T1; //BXJ $3d: begin if imm8=0 then begin LastDisassembleData.opcode:='ERET'; end else begin SUB_I_T5; end; end; $3e, $3f: begin if (imm8 shr 5) and 1=1 then begin MRS_BR_T1; end else begin MRS_R_T1; end; end; $78: begin if (op1=0) and (op2=0) and (op3=15) and ((imm8 shr 2)=0) then LastDisassembleData.opcode:='DCPS'+inttostr(imm8 and 3); end; $7e: begin if (op1=0) and ((imm8 shr 2)=0) then begin LastDisassembleData.opcode:='HVC'; LastDisassembleData.parameters:=inttohex(((opcode and $f) shl 12) or (opcode2 and $fff),1); end; end; $7f: begin if (op1=0) and ((imm8 shr 2)=0) then begin LastDisassembleData.opcode:='SMC'; LastDisassembleData.parameters:=inttohex(opcode and $f,1); end; if (op1=2) then begin LastDisassembleData.opcode:='UDF'; LastDisassembleData.parameters:=inttohex(((opcode and $f) shl 12) or (opcode2 and $fff),1); end; end; end; end; end; 1,3: begin //B B_T4; end; 4,6: BL_X_T2; 5,7: BL_X_T1; end; end; procedure TThumbDisassembler.T32_DataProcessing_Plain_Binary_Immediate; var op, Rn: byte; begin op:=(opcode shr 4) and $1f; Rn:=opcode and $f; case op of 0: if rn<>15 then ADD_I_T4 else ADR_T3; 4: MOV_I_T3; 10: if rn<>15 then SUB_I_T4 else ADR_T2; 14: MOVT_T1; 16: SSAT_T1; 18: if (((opcode2 shr 6) and 3)=0) and (((opcode2 shr 12) and 7)=0) then SSAT16_T1 else SSAT_T1; 20: SBFX_T1; 22: if rn<>15 then BFI_T1 else BFC_T1; 24: USAT_T1; 26: if (((opcode2 shr 6) and 3)=0) and (((opcode2 shr 12) and 7)=0) then USAT16_T1 else USAT_T1; 28: UBFX_T1; end; end; procedure TThumbDisassembler.T32_DataProcessing_Modified_Immediate; var op: byte; S: byte; Rn: byte; Rd: byte; a1: boolean; i: Byte; imm3: byte; v: byte; imm12: word; imm32: dword; begin op:=(opcode shr 5) and $f; s:=(opcode shr 4) and 1; Rn:=opcode and $f; Rd:=(opcode2 shr 8) and $f; i:=(opcode shr 10) and 1; imm3:=(opcode2 shr 12) and 7; v:=opcode2 and $ff; a1:=(S=1) and (Rd=$F); imm12:=(i shl 12) or (imm3 shl 8) or v; imm32:=0; if (imm12 shr 10)=0 then begin case (imm12 shr 8) and 3 of 0: imm32:=v; 1: imm32:=(v shl 16) or v; 2: imm32:=(v shl 24) or (v shl 8); 3: imm32:=(v shl 24) or (v shl 16) or (v shl 8) or v; end; end else begin //rotate (explained on page 2530/2531) imm32:=(1 shl 7) or (imm12 and $3f); //no, not a mistake, the 8th bit gets replaced by a 1 imm32:=RorDWord(imm32, imm12 shr 7); end; case op of 0: if a1 then begin LastDisassembleData.opcode:='TST'; LastDisassembleData.parameters:=ArmRegisters[Rn]+','+inttohex(imm32,1); end else begin if (s=1) and (rd<>15) then LastDisassembleData.opcode:='ANDS' else LastDisassembleData.opcode:='AND'; LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[Rn]+','+inttohex(imm32,1); end; 1: begin if (s=1) and (rd<>15) then LastDisassembleData.opcode:='BIC' else LastDisassembleData.opcode:='BICS'; LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[Rn]+','+inttohex(imm32,1); end; 2: if rn=15 then begin if (s=1) and (rd<>15) then LastDisassembleData.opcode:='MOV' else LastDisassembleData.opcode:='MOVS'; LastDisassembleData.parameters:=ArmRegisters[rd]+','+inttohex(imm32,1); end else begin if (s=1) and (rd<>15) then LastDisassembleData.opcode:='ORR' else LastDisassembleData.opcode:='ORRS'; LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[Rn]+','+inttohex(imm32,1); end; 3: if rn=15 then begin if (s=1) then LastDisassembleData.opcode:='MVN' else LastDisassembleData.opcode:='MVNS'; LastDisassembleData.parameters:=ArmRegisters[rd]+','+inttohex(imm32,1); end else begin if (s=1) then LastDisassembleData.opcode:='ORN' else LastDisassembleData.opcode:='ORNS'; LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[Rn]+','+inttohex(imm32,1); end; 4: if a1 then begin LastDisassembleData.opcode:='TEQ'; LastDisassembleData.parameters:=ArmRegisters[Rn]+','+inttohex(imm32,1); end else begin if (s=1) and (rd<>15) then LastDisassembleData.opcode:='EOR' else LastDisassembleData.opcode:='EORS'; LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[Rn]+','+inttohex(imm32,1); end; 8: if a1 then begin LastDisassembleData.opcode:='CMN'; LastDisassembleData.parameters:=ArmRegisters[Rn]+','+inttohex(imm32,1); end else begin if (s=1) and (rd<>15) then LastDisassembleData.opcode:='ADDS' else LastDisassembleData.opcode:='ADD'; LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[Rn]+','+inttohex(imm32,1); end; 10: begin if (s=1) then LastDisassembleData.opcode:='ADCS' else LastDisassembleData.opcode:='ADC'; LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[Rn]+','+inttohex(imm32,1); end; 11: begin if (s=1) then LastDisassembleData.opcode:='SBC' else LastDisassembleData.opcode:='SBCS'; LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[Rn]+','+inttohex(imm32,1); end; 13: if a1 then begin LastDisassembleData.opcode:='CMP'; LastDisassembleData.parameters:=ArmRegisters[Rn]+','+inttohex(imm32,1); end else begin if (s=1) and (rd<>15) then LastDisassembleData.opcode:='SUBS' else LastDisassembleData.opcode:='SUB'; LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[Rn]+','+inttohex(imm32,1); end; 14: begin if (s=1) then LastDisassembleData.opcode:='RSB' else LastDisassembleData.opcode:='RSBS'; LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[Rn]+','+inttohex(imm32,1); end; end; end; procedure TThumbDisassembler.t32; var x: ptruint; op1, op2, op: byte; begin //read opcode2 {$ifdef armdev} opcode2:=pword(a+2)^; setlength(LastDisassembleData.Bytes,4); pword(@LastDisassembleData.Bytes[2])^:=opcode2; {$else} if readprocessmemory(processhandle, pointer(ptruint(a)-1+2), @opcode2, sizeof(opcode2), x) then begin setlength(LastDisassembleData.Bytes,4); puint16(@LastDisassembleData.Bytes[2])^:=opcode2; end; {$endif} op1:=(opcode shr 11) and 3; op2:=(opcode shr 4) and $7f; op:=(opcode2 shr 15) and 1; case op1 of 1: begin if (op2 shr 5)=0 then begin if (op2 shr 2) and 1 = 0 then begin //LoadStore multiple T32_LoadStore_Multiple; end else begin //LoadStore-Exclusive, load acquire/store release table branch T32_STR_LDR_STL; end; end else if (op2 shr 5)=1 then begin //Data-processing (shifted reg) T32_DataProcessing_Shifted_Reg; end else begin //CoProcessor, Advanced SIMD, floating point instr... //todo: perhaps in the future end; end; 2: begin if op=0 then begin if (op2 shr 5) and 1=0 then begin //Data processing (modified immediate) T32_DataProcessing_Modified_Immediate; end else begin //Data processing (plain binary immediate) T32_DataProcessing_Plain_Binary_Immediate; end; end else begin //Branches and miscellaneous T32_Branches_And_Miscellaneous_Control; end; end; 3: begin if (op2 shr 4=0) and ((op2 and 1)=0) then begin //Store single data Item T32_StoreSingleDataItem; end else if (op2 shr 5=0) then //00xxxxx begin case (op2 and 7) of 1: T32_LoadByte_MemoryHints; //LoadByte, memory hints 3: T32_LoadHalfWord_MemoryHints;//Load halfword, memory hints 5: T32_LoadWord;//Load word 7: ;//undefined else begin if ((op2 shr 4) and 1=1) and ((op2 and 1)=0) then begin //Advanced SIMD element or structure load/store end; end; end; end else if (op2 shr 4)=2 then begin //data processing (register) T32_DataProcessing_Reg; end else if (op2 shr 3)=6 then begin //Multiply, multiple accumulate, and absolute difference T32_Multiply_MultiplyAccumulate_AbsoluteDiff; end else if (op2 shr 3)=7 then begin //Long multiple, long multiple accumulate, and divide T32_LongMultiply_LongMultiplyAccumulate_Divide; end else if (op2 shr 6)=1 then begin //CoProcessor, Advanced SIMD, and floating point instructions end; end; end; //todo: implement me end; procedure TThumbDisassembler.STM_T1; var i: integer; rn: byte; reglist: word; rcount: integer; m: byte; _rlist: string; begin reglist:=opcode and $ff; rn:=(opcode shr 8) and 7; _rlist:='{'; rcount:=0; for i:=0 to 7 do begin if (reglist shr i) and 1=1 then begin if rcount=0 then _rlist:=_rlist+ArmRegisters[i] else _rlist:=_rlist+', '+ArmRegisters[i]; inc(rcount); end; end; _rlist:=_rlist+'}'; LastDisassembleData.opcode:='STM'; LastDisassembleData.parameters:=ArmRegisters[rn]+','+_rlist; end; procedure TThumbDisassembler.STM_T2; var w: byte; rn: byte; m: byte; reglist: word; i: integer; rcount: integer; _rlist: string; _w: string; begin w:=(opcode shr 5) and 1; rn:=opcode and $f; reglist:=opcode2 and $ffff; if w=1 then _w:='!' else _w:=''; _rlist:='{'; rcount:=0; for i:=0 to 15 do begin if (reglist shr i) and 1=1 then begin if rcount=0 then _rlist:=_rlist+ArmRegisters[i] else _rlist:=_rlist+', '+ArmRegisters[i]; inc(rcount); end; end; _rlist:=_rlist+'}'; LastDisassembleData.opcode:='STM'; LastDisassembleData.parameters:=ArmRegisters[rn]+_W+','+_rlist; end; procedure TThumbDisassembler.LDM_T1; var i: integer; rn: byte; reglist: word; rcount: integer; m: byte; _rlist: string; begin reglist:=opcode and $ff; rn:=(opcode shr 8) and 7; _rlist:='{'; rcount:=0; for i:=0 to 7 do begin if (reglist shr i) and 1=1 then begin if rcount=0 then _rlist:=_rlist+ArmRegisters[i] else _rlist:=_rlist+', '+ArmRegisters[i]; inc(rcount); end; end; _rlist:=_rlist+'}'; LastDisassembleData.opcode:='LDM'; LastDisassembleData.parameters:=ArmRegisters[rn]+','+_rlist; end; procedure TThumbDisassembler.LDM_T2; var w: byte; rn: byte; reglist: word; i: integer; rcount: integer; _rlist: string; _w: string; begin w:=(opcode shr 5) and 1; rn:=opcode and $f; reglist:=opcode2; if w=1 then _w:='!' else _w:=''; _rlist:='{'; rcount:=0; for i:=0 to 15 do begin if (reglist shr i) and 1=1 then begin if rcount=0 then _rlist:=_rlist+ArmRegisters[i] else _rlist:=_rlist+', '+ArmRegisters[i]; inc(rcount); end; end; _rlist:=_rlist+'}'; LastDisassembleData.opcode:='LDM'; LastDisassembleData.parameters:=ArmRegisters[rn]+_W+','+_rlist; end; procedure TThumbDisassembler.STMDB_T1; var w: byte; rn: byte; reglist: word; i: integer; rcount: integer; _rlist: string; _w: string; begin w:=(opcode shr 5) and 1; rn:=opcode and $f; reglist:=opcode2 and $ffff; if w=1 then _w:='!' else _w:=''; _rlist:='{'; rcount:=0; for i:=0 to 15 do begin if (reglist shr i) and 1=1 then begin if rcount=0 then _rlist:=_rlist+ArmRegisters[i] else _rlist:=_rlist+', '+ArmRegisters[i]; inc(rcount); end; end; _rlist:=_rlist+'}'; LastDisassembleData.opcode:='STMDB'; LastDisassembleData.parameters:=ArmRegisters[rn]+_W+','+_rlist; end; procedure TThumbDisassembler.LDMDB_T1; var w: byte; rn: byte; reglist: word; i: integer; rcount: integer; _rlist: string; _w: string; begin w:=(opcode shr 5) and 1; rn:=opcode and $f; reglist:=opcode2; if w=1 then _w:='!' else _w:=''; _rlist:='{'; rcount:=0; for i:=0 to 15 do begin if (reglist shr i) and 1=1 then begin if rcount=0 then _rlist:=_rlist+ArmRegisters[i] else _rlist:=_rlist+', '+ArmRegisters[i]; inc(rcount); end; end; _rlist:=_rlist+'}'; LastDisassembleData.opcode:='LDMDB'; LastDisassembleData.parameters:=ArmRegisters[rn]+_W+','+_rlist; end; procedure TThumbDisassembler.REVSH_T1; var rd, rs: byte; begin rd:=opcode and 7; rs:=(opcode shr 3) and 7; LastDisassembleData.opcode:='REVSH'; LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rs]; end; procedure TThumbDisassembler.IT_T1; var firstcond: byte; mask: byte; c: string; i: integer; m: string; begin firstcond:=(opcode shr 4) and $f; mask:=opcode and $f; c:=ArmConditions[firstcond]; case mask of 1: m:='TTT'; 2: m:='TT'; 3: m:='TTE'; 4: m:='T'; 5: m:='TET'; 6: m:='TE'; 7: m:='TEE'; 8: m:=''; 9: m:='ETT'; 10: m:='ET'; 11: m:='ETE'; 12: m:='E'; 13: m:='EET'; 14: m:='EE'; 15: m:='EEE'; end; LastDisassembleData.opcode:='IT'+m; LastDisassembleData.parameters:=c; end; procedure TThumbDisassembler.UDF_T1; var imm8: byte; begin imm8:=opcode and $ff; LastDisassembleData.opcode:='UDF'; LastDisassembleData.parameters:=inttohex(imm8,1); end; procedure TThumbDisassembler.SVC_T1; var imm8: byte; begin imm8:=opcode and $ff; LastDisassembleData.opcode:='SVC'; LastDisassembleData.parameters:=inttohex(imm8,1); end; procedure TThumbDisassembler.DBG_T1; var opt: byte; begin opt:=opcode and $f; LastDisassembleData.opcode:='DBG'; LastDisassembleData.parameters:=inttohex(opt,1); end; procedure TThumbDisassembler.BKPT_T1; var imm8: byte; begin imm8:=opcode and $ff; LastDisassembleData.opcode:='BKPT'; LastDisassembleData.parameters:=inttohex(imm8,1); end; procedure TThumbDisassembler.HLT_T1; var imm6: byte; begin imm6:=opcode and $3f; LastDisassembleData.opcode:='HLT'; LastDisassembleData.parameters:=inttohex(imm6,1); end; procedure TThumbDisassembler.REV_T1; var rd, rs: byte; begin rd:=opcode and 7; rs:=(opcode shr 3) and 7; LastDisassembleData.opcode:='REV'; LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rs]; end; procedure TThumbDisassembler.REV16_T1; var rd, rs: byte; begin rd:=opcode and 7; rs:=(opcode shr 3) and 7; LastDisassembleData.opcode:='REV16'; LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rs]; end; procedure TThumbDisassembler.CPS_T1; var _F,_I,_A, IM: byte; p: string; begin _f:=opcode and 1; _i:=(opcode shr 1) and 1; _a:=(opcode shr 2) and 1; im:=(opcode shr 4) and 1; if im=1 then LastDisassembleData.opcode:='CPSID' else LastDisassembleData.opcode:='CPSIE'; p:=''; if _a<>0 then p:='a'; if _i<>0 then p:=p+'i'; if _f<>0 then p:=p+'f'; LastDisassembleData.parameters:=p; end; procedure TThumbDisassembler.CPS_T2; var _F,_I,_A, IM,M, mode: byte; p: string; begin im:=(opcode2 shr 9) and 3; m:=(opcode2 shr 8) and 1; _a:=(opcode shr 7) and 1; _i:=(opcode shr 6) and 1; _f:=(opcode2 shr 5) and 1; mode:=opcode2 and $f; p:=''; if _a<>0 then p:='a'; if _i<>0 then p:=p+'i'; if _f<>0 then p:=p+'f'; case (im shl 1) or m of 1: begin LastDisassembleData.opcode:='CPS'; LastDisassembleData.parameters:=inttohex(mode,1); end; 4: begin LastDisassembleData.opcode:='CPSIE'; LastDisassembleData.parameters:=p; end; 5: begin LastDisassembleData.opcode:='CPSIE'; LastDisassembleData.parameters:=p+','+inttohex(mode,1); end; 6: begin LastDisassembleData.opcode:='CPSID'; LastDisassembleData.parameters:=p; end; 7: begin LastDisassembleData.opcode:='CPSID'; LastDisassembleData.parameters:=p+','+inttohex(mode,1); end; end; end; procedure TThumbDisassembler.SETEND_T1; begin LastDisassembleData.opcode:='SETEND'; if (opcode shr 3) and 1 =0 then LastDisassembleData.parameters:='LE' else LastDisassembleData.parameters:='BE'; end; procedure TThumbDisassembler.PUSH_T1; var i: integer; reglist: word; rcount: integer; m: byte; _rlist: string; begin reglist:=opcode and $ff; m:=(opcode shr 8) and 1; if m=1 then begin _rlist:='{'+ArmRegisters[14]; rcount:=1; end else begin _rlist:='{'; rcount:=0; end; for i:=0 to 7 do begin if (reglist shr i) and 1=1 then begin if rcount=0 then _rlist:=_rlist+ArmRegisters[i] else _rlist:=_rlist+', '+ArmRegisters[i]; inc(rcount); end; end; _rlist:=_rlist+'}'; LastDisassembleData.opcode:='PUSH'; LastDisassembleData.parameters:=_rlist; end; procedure TThumbDisassembler.POP_T1; var i: integer; reglist: word; rcount: integer; p: byte; _rlist: string; begin reglist:=opcode and $ff; p:=(opcode shr 8) and 1; if p=1 then begin _rlist:='{'+ArmRegisters[15]; rcount:=1; end else begin _rlist:='{'; rcount:=0; end; for i:=0 to 7 do begin if (reglist shr i) and 1=1 then begin if rcount=0 then _rlist:=_rlist+ArmRegisters[i] else _rlist:=_rlist+', '+ArmRegisters[i]; inc(rcount); end; end; _rlist:=_rlist+'}'; LastDisassembleData.opcode:='PUSH'; LastDisassembleData.parameters:=_rlist; end; procedure TThumbDisassembler.SXTH_T1; var rd, rs: byte; begin rd:=opcode and 7; rs:=(opcode shr 3) and 7; LastDisassembleData.opcode:='SXTH'; LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rs]; end; procedure TThumbDisassembler.SXTH_T2; var rd, rotate, rm: byte; begin rd:=(opcode2 shr 8) and $f; rotate:=(opcode2 shr 4) and 3; rm:=opcode2 and $f; LastDisassembleData.opcode:='SXTH'; if (rotate=0) then LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rm] else LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rm]+' ROR '+inttohex(rotate shr 3,1); end; procedure TThumbDisassembler.UXTH_T2; var rd, rotate, rm: byte; begin rd:=(opcode2 shr 8) and $f; rotate:=(opcode2 shr 4) and 3; rm:=opcode2 and $f; LastDisassembleData.opcode:='UXTH'; if (rotate=0) then LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rm] else LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rm]+' ROR '+inttohex(rotate shr 3,1); end; procedure TThumbDisassembler.SXTAH_T1; var rn, rd, rotate, rm: byte; begin rn:=opcode and $f; rd:=(opcode2 shr 8) and $f; rotate:=(opcode2 shr 4) and 3; rm:=opcode2 and $f; LastDisassembleData.opcode:='SXTAH'; if (rotate=0) then LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+ArmRegisters[rm] else LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+ArmRegisters[rm]+' ROR '+inttohex(rotate shr 3,1); end; procedure TThumbDisassembler.UXTAH_T1; var rn, rd, rotate, rm: byte; begin rn:=opcode and $f; rd:=(opcode2 shr 8) and $f; rotate:=(opcode2 shr 4) and 3; rm:=opcode2 and $f; LastDisassembleData.opcode:='UXTAH'; if (rotate=0) then LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+ArmRegisters[rm] else LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+ArmRegisters[rm]+' ROR '+inttohex(rotate shr 3,1); end; procedure TThumbDisassembler.SXTB_T1; var rd, rs: byte; begin rd:=opcode and 7; rs:=(opcode shr 3) and 7; LastDisassembleData.opcode:='SXTB'; LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rs]; end; procedure TThumbDisassembler.SXTB_T2; var rd, rotate, rm: byte; begin rd:=(opcode2 shr 8) and $f; rotate:=(opcode2 shr 4) and 3; rm:=opcode2 and $f; LastDisassembleData.opcode:='SXTB'; if (rotate=0) then LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rm] else LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rm]+' ROR '+inttohex(rotate shr 3,1); end; procedure TThumbDisassembler.SXTAB_T1; var rn, rd, rotate, rm: byte; begin rn:=opcode and $f; rd:=(opcode2 shr 8) and $f; rotate:=(opcode2 shr 4) and 3; rm:=opcode2 and $f; LastDisassembleData.opcode:='SXTAB'; if (rotate=0) then LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+ArmRegisters[rm] else LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+ArmRegisters[rm]+' ROR '+inttohex(rotate shr 3,1); end; procedure TThumbDisassembler.SXTB16_T1; var rn, rd, rotate, rm: byte; begin rd:=(opcode2 shr 8) and $f; rotate:=(opcode2 shr 4) and 3; rm:=opcode2 and $f; LastDisassembleData.opcode:='SXTB16'; if (rotate=0) then LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rm] else LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rm]+' ROR '+inttohex(rotate shr 3,1); end; procedure TThumbDisassembler.SXTAB16_T1; var rn, rd, rotate, rm: byte; begin rn:=opcode and $f; rd:=(opcode2 shr 8) and $f; rotate:=(opcode2 shr 4) and 3; rm:=opcode2 and $f; LastDisassembleData.opcode:='SXTAB16'; if (rotate=0) then LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+ArmRegisters[rm] else LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+ArmRegisters[rm]+' ROR '+inttohex(rotate shr 3,1); end; procedure TThumbDisassembler.UXTB16_T1; var rn, rd, rotate, rm: byte; begin rd:=(opcode2 shr 8) and $f; rotate:=(opcode2 shr 4) and 3; rm:=opcode2 and $f; LastDisassembleData.opcode:='UXTB16'; if (rotate=0) then LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rm] else LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rm]+' ROR '+inttohex(rotate shr 3,1); end; procedure TThumbDisassembler.UXTAB_T1; var rn, rd, rotate, rm: byte; begin rn:=opcode and $f; rd:=(opcode2 shr 8) and $f; rotate:=(opcode2 shr 4) and 3; rm:=opcode2 and $f; LastDisassembleData.opcode:='UXTAB'; if (rotate=0) then LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+ArmRegisters[rm] else LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+ArmRegisters[rm]+' ROR '+inttohex(rotate shr 3,1); end; procedure TThumbDisassembler.UXTAB16_T1; var rn, rd, rotate, rm: byte; begin rn:=opcode and $f; rd:=(opcode2 shr 8) and $f; rotate:=(opcode2 shr 4) and 3; rm:=opcode2 and $f; LastDisassembleData.opcode:='UXTAB16'; if (rotate=0) then LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+ArmRegisters[rm] else LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+ArmRegisters[rm]+' ROR '+inttohex(rotate shr 3,1); end; procedure TThumbDisassembler.UXTH_T1; var rd, rs: byte; begin rd:=opcode and 7; rs:=(opcode shr 3) and 7; LastDisassembleData.opcode:='UXTH'; LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rs]; end; procedure TThumbDisassembler.UXTB_T1; var rd, rs: byte; begin rd:=opcode and 7; rs:=(opcode shr 3) and 7; LastDisassembleData.opcode:='UXTB'; LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rs]; end; procedure TThumbDisassembler.UXTB_T2; var rd, rotate, rm: byte; begin rd:=(opcode2 shr 8) and $f; rotate:=(opcode2 shr 4) and 3; rm:=opcode2 and $f; LastDisassembleData.opcode:='UXTB'; if (rotate=0) then LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rm] else LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rm]+' ROR '+inttohex(rotate shr 3,1); end; procedure TThumbDisassembler.CBZ_CBNZ; var rs, imm5, i, op: byte; imm32: dword; begin rs:=opcode and $7; imm5:=(opcode shr 3) and $1f; i:=(opcode shr 9) and 1; op:=(opcode shr 11) and 1; if (op=0) then LastDisassembleData.opcode:='CBZ' else LastDisassembleData.opcode:='CBNZ'; imm32:=((i shl 6) or imm5) * 2; LastDisassembleData.parameters:=ArmRegisters[rs]+','+inttohex(a+2+imm32,1); end; procedure TThumbDisassembler.ADD_SP_I_T1; var rd, imm8: byte; begin rd:=(opcode shr 8) and 7; imm8:=opcode and $ff; LastDisassembleData.opcode:='ADD'; LastDisassembleData.parameters:=ArmRegisters[rd]+',SP,'+inttohex(imm8*4,1); end; procedure TThumbDisassembler.ADD_SP_I_T2; var imm7: byte; begin imm7:=opcode and $7f; LastDisassembleData.opcode:='ADD'; LastDisassembleData.parameters:='SP,'+inttohex(imm7*4,1); end; procedure TThumbDisassembler.SUB_SP_I_T1; var imm7: byte; begin imm7:=opcode and $7f; LastDisassembleData.opcode:='SUB'; LastDisassembleData.parameters:='SP,'+inttohex(imm7*4,1); end; procedure TThumbDisassembler.ADR_T1; var rd, imm8: byte; begin rd:=(opcode shr 8) and 7; imm8:=opcode and $ff; LastDisassembleData.opcode:='ADR'; LastDisassembleData.parameters:=ArmRegisters[rd]+','+inttohex(Align(a+2,4)+imm8*4,1); end; procedure TThumbDisassembler.STR_I_T1; var rt, rb, imm5: byte; _imm: string; begin rt:=opcode and 7; rb:=(opcode shr 3) and 7; imm5:=(opcode shr 6) and $1f; if imm5<>0 then _imm:=','+inttohex(imm5*4,1) else _imm:=''; LastDisassembleData.opcode:='STR'; LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rb]+_imm+']'; end; procedure TThumbDisassembler.LDR_I_T1; var rt, rb, imm5: byte; _imm: string; begin rt:=opcode and 7; rb:=(opcode shr 3) and 7; imm5:=(opcode shr 6) and $1f; if imm5<>0 then _imm:=','+inttohex(imm5*4,1) else _imm:=''; LastDisassembleData.opcode:='LDR'; LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rb]+_imm+']'; end; procedure TThumbDisassembler.STR_I_T2; var rt, imm8: byte; _imm: string; begin rt:=(opcode shr 8) and 7; imm8:=opcode and $ff; if imm8<>0 then _imm:=','+inttohex(imm8*4,1) else _imm:=''; LastDisassembleData.opcode:='STR'; LastDisassembleData.parameters:=ArmRegisters[rt]+',[SP'+_imm+']'; end; procedure TThumbDisassembler.STR_I_T3; var rn, rt: byte; imm12: word; _imm: string; begin rn:=opcode and $f; rt:=(opcode2 shr 12) and $f; imm12:=opcode2 and $fff; if imm12=0 then _imm:='' else _imm:=','+inttohex(imm12,1); LastDisassembleData.opcode:='STR'; LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+_imm+']' end; procedure TThumbDisassembler.STR_I_T4; var rn, rt, p, u, w, imm8: byte; _imm: string; begin rn:=opcode and $f; rt:=(opcode2 shr 12) and $f; p:=(opcode2 shr 10) and 1; u:=(opcode2 shr 9) and 1; w:=(opcode2 shr 8) and 1; imm8:=opcode2 and $ff; if imm8=0 then _imm:='' else begin if u=0 then _imm:=',-'+inttohex(imm8,1) else _imm:=','+inttohex(imm8,1); end; LastDisassembleData.opcode:='STR'; if (p=1) and (u=0) and (w=0) then LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+_imm+']' else if (p=0) and (w=1) then LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+']'+_imm else if (p=1) and (w=1) then LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+_imm+']!'; end; procedure TThumbDisassembler.LDR_I_T2; var rt, imm8: byte; _imm: string; begin rt:=(opcode shr 8) and 7; imm8:=opcode and $ff; if imm8<>0 then _imm:=','+inttohex(imm8*4,1) else _imm:=''; LastDisassembleData.opcode:='LDR'; LastDisassembleData.parameters:=ArmRegisters[rt]+',[SP'+_imm+']'; end; procedure TThumbDisassembler.LDR_I_T4; var rn, rt, p, u, w, imm8: byte; _imm: string; begin rn:=opcode and $f; rt:=(opcode2 shr 12) and $f; p:=(opcode2 shr 10) and 1; u:=(opcode2 shr 9) and 1; w:=(opcode2 shr 8) and 1; imm8:=opcode2 and $ff; if imm8=0 then _imm:='' else begin if u=0 then _imm:=',-'+inttohex(imm8,1) else _imm:=','+inttohex(imm8,1); end; LastDisassembleData.opcode:='LDR'; if (p=1) and (u=0) and (w=0) then LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+_imm+']' else if (p=0) and (w=1) then LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+']'+_imm else if (p=1) and (w=1) then LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+_imm+']!'; end; procedure TThumbDisassembler.LDRSB_I_T1; var rn, rt: byte; imm12: word; _imm: string; begin rn:=opcode and $f; rt:=(opcode2 shr 12) and $f; imm12:=opcode2 and $fff; if imm12=0 then _imm:='' else _imm:=','+inttohex(imm12,1); LastDisassembleData.opcode:='LDRSB'; LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+_imm+']' end; procedure TThumbDisassembler.LDRSB_I_T2; var rn, rt, p, u, w, imm8: byte; _imm: string; begin rn:=opcode and $f; rt:=(opcode2 shr 12) and $f; p:=(opcode2 shr 10) and 1; u:=(opcode2 shr 9) and 1; w:=(opcode2 shr 8) and 1; imm8:=opcode2 and $ff; if imm8=0 then _imm:='' else begin if u=0 then _imm:=',-'+inttohex(imm8,1) else _imm:=','+inttohex(imm8,1); end; LastDisassembleData.opcode:='LDRSB'; if (p=1) and (u=0) and (w=0) then LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+_imm+']' else if (p=0) and (w=1) then LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+']'+_imm else if (p=1) and (w=1) then LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+_imm+']!'; end; procedure TThumbDisassembler.LDRSH_I_T1; var rn, rt: byte; imm12: word; _imm: string; begin rn:=opcode and $f; rt:=(opcode2 shr 12) and $f; imm12:=opcode2 and $fff; if imm12=0 then _imm:='' else _imm:=','+inttohex(imm12,1); LastDisassembleData.opcode:='LDRSH'; LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+_imm+']' end; procedure TThumbDisassembler.LDRSH_I_T2; var rn, rt, p, u, w, imm8: byte; _imm: string; begin rn:=opcode and $f; rt:=(opcode2 shr 12) and $f; p:=(opcode2 shr 10) and 1; u:=(opcode2 shr 9) and 1; w:=(opcode2 shr 8) and 1; imm8:=opcode2 and $ff; if imm8=0 then _imm:='' else begin if u=0 then _imm:=',-'+inttohex(imm8,1) else _imm:=','+inttohex(imm8,1); end; LastDisassembleData.opcode:='LDRSH'; if (p=1) and (u=0) and (w=0) then LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+_imm+']' else if (p=0) and (w=1) then LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+']'+_imm else if (p=1) and (w=1) then LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+_imm+']!'; end; procedure TThumbDisassembler.STRB_I_T1; var rt, rb, imm5: byte; _imm: string; begin rt:=opcode and 7; rb:=(opcode shr 3) and 7; imm5:=(opcode shr 6) and $1f; if imm5<>0 then _imm:=','+inttohex(imm5*4,1) else _imm:=''; LastDisassembleData.opcode:='STRB'; LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rb]+_imm+']'; end; procedure TThumbDisassembler.STRB_I_T2; var rn, rt: byte; imm12: word; _imm: string; begin rn:=opcode and $f; rt:=(opcode2 shr 12) and $f; imm12:=opcode2 and $fff; if imm12=0 then _imm:='' else _imm:=','+inttohex(imm12,1); LastDisassembleData.opcode:='STRB'; LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+_imm+']' end; procedure TThumbDisassembler.STRB_I_T3; var rn, rt, p, u, w, imm8: byte; _imm: string; begin rn:=opcode and $f; rt:=(opcode2 shr 12) and $f; p:=(opcode2 shr 10) and 1; u:=(opcode2 shr 9) and 1; w:=(opcode2 shr 8) and 1; imm8:=opcode2 and $ff; if imm8=0 then _imm:='' else begin if u=0 then _imm:=',-'+inttohex(imm8,1) else _imm:=','+inttohex(imm8,1); end; LastDisassembleData.opcode:='STRB'; if (p=1) and (u=0) and (w=0) then LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+_imm+']' else if (p=0) and (w=1) then LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+']'+_imm else if (p=1) and (w=1) then LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+_imm+']!'; end; procedure TThumbDisassembler.LDRB_I_T1; var rt, rb, imm5: byte; _imm: string; begin rt:=opcode and 7; rb:=(opcode shr 3) and 7; imm5:=(opcode shr 6) and $1f; if imm5<>0 then _imm:=','+inttohex(imm5*4,1) else _imm:=''; LastDisassembleData.opcode:='LDRB'; LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rb]+_imm+']'; end; procedure TThumbDisassembler.LDRB_I_T2; var rn, rt: byte; imm12: word; _imm: string; begin rn:=opcode and $f; rt:=(opcode2 shr 12) and $f; imm12:=opcode2 and $fff; if imm12=0 then _imm:='' else _imm:=','+inttohex(imm12,1); LastDisassembleData.opcode:='LDRB'; LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+_imm+']' end; procedure TThumbDisassembler.LDRB_I_T3; var rn, rt, p, u, w, imm8: byte; _imm: string; begin rn:=opcode and $f; rt:=(opcode2 shr 12) and $f; p:=(opcode2 shr 10) and 1; u:=(opcode2 shr 9) and 1; w:=(opcode2 shr 8) and 1; imm8:=opcode2 and $ff; if imm8=0 then _imm:='' else begin if u=0 then _imm:=',-'+inttohex(imm8,1) else _imm:=','+inttohex(imm8,1); end; LastDisassembleData.opcode:='LDRB'; if (p=1) and (u=0) and (w=0) then LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+_imm+']' else if (p=0) and (w=1) then LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+']'+_imm else if (p=1) and (w=1) then LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+_imm+']!'; end; procedure TThumbDisassembler.STRH_I_T1; var rt, rb, imm5: byte; _imm: string; begin rt:=opcode and 7; rb:=(opcode shr 3) and 7; imm5:=(opcode shr 6) and $1f; if imm5<>0 then _imm:=','+inttohex(imm5*4,1) else _imm:=''; LastDisassembleData.opcode:='STRH'; LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rb]+_imm+']'; end; procedure TThumbDisassembler.STRH_I_T2; var rn, rt: byte; imm12: word; _imm: string; begin rn:=opcode and $f; rt:=(opcode2 shr 12) and $f; imm12:=opcode2 and $fff; if imm12=0 then _imm:='' else _imm:=','+inttohex(imm12,1); LastDisassembleData.opcode:='STRH'; LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+_imm+']' end; procedure TThumbDisassembler.STRH_I_T3; var rn, rt, p, u, w, imm8: byte; _imm: string; begin rn:=opcode and $f; rt:=(opcode2 shr 12) and $f; p:=(opcode2 shr 10) and 1; u:=(opcode2 shr 9) and 1; w:=(opcode2 shr 8) and 1; imm8:=opcode2 and $ff; if imm8=0 then _imm:='' else begin if u=0 then _imm:=',-'+inttohex(imm8,1) else _imm:=','+inttohex(imm8,1); end; LastDisassembleData.opcode:='STRH'; if (p=1) and (u=0) and (w=0) then LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+_imm+']' else if (p=0) and (w=1) then LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+']'+_imm else if (p=1) and (w=1) then LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+_imm+']!'; end; procedure TThumbDisassembler.LDRH_I_T1; var rt, rb, imm5: byte; _imm: string; begin rt:=opcode and 7; rb:=(opcode shr 3) and 7; imm5:=(opcode shr 6) and $1f; if imm5<>0 then _imm:=','+inttohex(imm5*4,1) else _imm:=''; LastDisassembleData.opcode:='LDRH'; LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rb]+_imm+']'; end; procedure TThumbDisassembler.STR_R_T1; var rt, rn, rm: byte; begin rt:=opcode and 7; rn:=(opcode shr 3) and 7; rm:=(opcode shr 6) and 7; LastDisassembleData.opcode:='STR'; LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+','+ArmRegisters[rm]+']'; end; procedure TThumbDisassembler.STR_R_T2; var rn, rt, imm2, rm: byte; begin rn:=opcode and $f; rt:=(opcode2 shr 12) and $f; imm2:=(opcode2 shr 4) and 3; rm:=(opcode2 and $f); LastDisassembleData.opcode:='STR'; if imm2=0 then LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+','+ArmRegisters[rm]+']' else LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+','+ArmRegisters[rm]+', LSL '+inttohex(imm2,1)+']'; end; procedure TThumbDisassembler.STRH_R_T1; var rt, rn, rm: byte; begin rt:=opcode and 7; rn:=(opcode shr 3) and 7; rm:=(opcode shr 6) and 7; LastDisassembleData.opcode:='STRH'; LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+','+ArmRegisters[rm]+']'; end; procedure TThumbDisassembler.STRH_R_T2; var rn, rt, imm2, rm: byte; begin rn:=opcode and $f; rt:=(opcode2 shr 12) and $f; imm2:=(opcode2 shr 4) and 3; rm:=(opcode2 and $f); LastDisassembleData.opcode:='STRH'; if imm2=0 then LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+','+ArmRegisters[rm]+']' else LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+','+ArmRegisters[rm]+', LSL '+inttohex(imm2,1)+']'; end; procedure TThumbDisassembler.STRHT_T1; var rn, rt, imm8: byte; begin rn:=opcode and $f; rt:=(opcode2 shr 12) and $f; imm8:=opcode2 and $ff; LastDisassembleData.opcode:='STRHT'; LastDisassembleData.parameters:=ArmRegisters[Rt]+',['+ArmRegisters[rn]+','+inttohex(imm8,1)+']'; end; procedure TThumbDisassembler.STRB_R_T1; var rt, rn, rm: byte; begin rt:=opcode and 7; rn:=(opcode shr 3) and 7; rm:=(opcode shr 6) and 7; LastDisassembleData.opcode:='STRB'; LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+','+ArmRegisters[rm]+']'; end; procedure TThumbDisassembler.STRB_R_T2; var rn, rt, imm2, rm: byte; begin rn:=opcode and $f; rt:=(opcode2 shr 12) and $f; imm2:=(opcode2 shr 4) and 3; rm:=(opcode2 and $f); LastDisassembleData.opcode:='STRB'; if imm2=0 then LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+','+ArmRegisters[rm]+']' else LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+','+ArmRegisters[rm]+', LSL '+inttohex(imm2,1)+']'; end; procedure TThumbDisassembler.STRBT_T1; var rn, rt, imm8: byte; begin rn:=opcode and $f; rt:=(opcode2 shr 12) and $f; imm8:=opcode2 and $ff; LastDisassembleData.opcode:='STRBT'; LastDisassembleData.parameters:=ArmRegisters[Rt]+',['+ArmRegisters[rn]+','+inttohex(imm8,1)+']'; end; procedure TThumbDisassembler.STRT_T1; var rn, rt, imm8: byte; begin rn:=opcode and $f; rt:=(opcode2 shr 12) and $f; imm8:=opcode2 and $ff; LastDisassembleData.opcode:='STRT'; LastDisassembleData.parameters:=ArmRegisters[Rt]+',['+ArmRegisters[rn]+','+inttohex(imm8,1)+']'; end; procedure TThumbDisassembler.LDRSB_R_T1; var rt, rn, rm: byte; begin rt:=opcode and 7; rn:=(opcode shr 3) and 7; rm:=(opcode shr 6) and 7; LastDisassembleData.opcode:='LDRSB'; LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+','+ArmRegisters[rm]+']'; end; procedure TThumbDisassembler.LDRSB_R_T2; var rn, rt, imm2, rm: byte; begin rn:=opcode and $f; rt:=(opcode2 shr 12) and $f; imm2:=(opcode2 shr 4) and 3; rm:=(opcode2 and $f); LastDisassembleData.opcode:='LDRSB'; if imm2=0 then LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+','+ArmRegisters[rm]+']' else LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+','+ArmRegisters[rm]+', LSL '+inttohex(imm2,1)+']'; end; procedure TThumbDisassembler.LDR_R_T1; var rt, rn, rm: byte; begin rt:=opcode and 7; rn:=(opcode shr 3) and 7; rm:=(opcode shr 6) and 7; LastDisassembleData.opcode:='LDR'; LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+','+ArmRegisters[rm]+']'; end; procedure TThumbDisassembler.LDR_R_T2; var rn, rt, imm2, rm: byte; begin rn:=opcode and $f; rt:=(opcode2 shr 12) and $f; imm2:=(opcode2 shr 4) and 3; rm:=opcode2 and $f; LastDisassembleData.opcode:='LDR'; if imm2=0 then LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+','+ArmRegisters[rm]+']' else LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+','+ArmRegisters[rm]+', LSL '+inttohex(imm2,1)+']'; end; procedure TThumbDisassembler.LDRH_R_T1; var rt, rn, rm: byte; begin rt:=opcode and 7; rn:=(opcode shr 3) and 7; rm:=(opcode shr 6) and 7; LastDisassembleData.opcode:='LDRH'; LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+','+ArmRegisters[rm]+']'; end; procedure TThumbDisassembler.LDRH_R_T2; var rn, rt, imm2, rm: byte; begin rn:=opcode and $f; rt:=(opcode2 shr 12) and $f; imm2:=(opcode2 shr 4) and 3; rm:=(opcode2 and $f); LastDisassembleData.opcode:='LDRH'; if imm2=0 then LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+','+ArmRegisters[rm]+']' else LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+','+ArmRegisters[rm]+', LSL '+inttohex(imm2,1)+']'; end; procedure TThumbDisassembler.LDRB_R_T1; var rt, rn, rm: byte; begin rt:=opcode and 7; rn:=(opcode shr 3) and 7; rm:=(opcode shr 6) and 7; LastDisassembleData.opcode:='LDRB'; LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+','+ArmRegisters[rm]+']'; end; procedure TThumbDisassembler.LDRB_R_T2; var rn, rt, imm2, rm: byte; begin rn:=opcode and $f; rt:=(opcode2 shr 12) and $f; imm2:=(opcode2 shr 4) and 3; rm:=(opcode2 and $f); LastDisassembleData.opcode:='LDRB'; if imm2=0 then LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+','+ArmRegisters[rm]+']' else LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+','+ArmRegisters[rm]+', LSL '+inttohex(imm2,1)+']'; end; procedure TThumbDisassembler.LDRSH_R_T1; var rt, rn, rm: byte; begin rt:=opcode and 7; rn:=(opcode shr 3) and 7; rm:=(opcode shr 6) and 7; LastDisassembleData.opcode:='LDRSH'; LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+','+ArmRegisters[rm]+']'; end; procedure TThumbDisassembler.LDRSH_R_T2; var rn, rt, imm2, rm: byte; begin rn:=opcode and $f; rt:=(opcode2 shr 12) and $f; imm2:=(opcode2 shr 4) and 3; rm:=(opcode2 and $f); LastDisassembleData.opcode:='LDRSH'; if imm2=0 then LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+','+ArmRegisters[rm]+']' else LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+','+ArmRegisters[rm]+', LSL '+inttohex(imm2,1)+']'; end; procedure TThumbDisassembler.LDR_L_T1; var rt, imm8: byte; begin rt:=(opcode shr 8) and $7; imm8:=opcode and $ff; LastDisassembleData.opcode:='LDR'; LastDisassembleData.parameters:=ArmRegisters[rt]+',['+inttohex(align(a+2,4)+imm8*4,1)+']'; end; procedure TThumbDisassembler.LDR_L_T2; var u, rt: byte; imm12: word; imm32: ptruint; begin u:=(opcode shr 7) and 1; rt:=(opcode2 shr 12) and $f; imm12:=opcode2 and $fff; imm32:=imm12; if u=0 then imm32:=-imm32; LastDisassembleData.opcode:='LDR'; LastDisassembleData.parameters:=ArmRegisters[rt]+',['+inttohex(align(a+4,4)+imm32,1)+']'; end; procedure TThumbDisassembler.B_T1; var cond:byte; imm8: ShortInt; begin cond:=(opcode shr 8) and $7; imm8:=opcode and $ff; LastDisassembleData.opcode:='B'+ArmConditions[cond]; LastDisassembleData.parameters:=inttohex(dword(a+2+imm8*2),1); end; procedure TThumbDisassembler.B_T2; var imm11: smallint; begin imm11:=opcode and $7ff; LastDisassembleData.opcode:='B'; imm11:=SignExtend(imm11, 10); LastDisassembleData.parameters:=inttohex(dword(a+2+imm11*2),1); end; procedure TThumbDisassembler.B_T3; var s, cond, imm6, j1, j2: byte; imm11: smallint; imm32: integer; begin s:=(opcode shr 10) and 1; cond:=(opcode shr 6) and $f; imm6:=opcode and $7f; j1:=(opcode2 shr 13) and 1; j2:=(opcode2 shr 11) and 1; imm11:=opcode2 and $7ff; //S:J2:J1:imm6:imm11:'0' imm32:=(j2 shl 18) or (j1 shl 17) or (imm6 shl 11) or imm11; imm32:=imm32 shl 1; if s=1 then imm32:=SignExtend(imm32, 19); LastDisassembleData.opcode:='B'+ArmConditions[cond]; LastDisassembleData.parameters:=inttohex(dword(a+4+imm32),8); end; procedure TThumbDisassembler.B_T4; var s, j1, j2: byte; imm10, imm11: smallint; imm32: integer; i1, i2: byte; begin s:=(opcode shr 10) and 1; imm10:=opcode and $3ff; j1:=(opcode2 shr 13) and 1; j2:=(opcode2 shr 11) and 1; imm11:=opcode2 and $7ff; i1:=(not (j1 xor s)) and $1; i2:=(not (j2 xor s)) and $1; //S:J2:J1:imm10:imm11:'0' imm32:=imm11; imm32:=imm32 or (imm10 shl 11); imm32:=imm32 or (i2 shl 21); imm32:=imm32 or (i1 shl 22); imm32:=imm32 or (s shl 23); imm32:=imm32 shl 1; imm32:=signextend(imm32, 24); //S is bit 24 after the shl 1 LastDisassembleData.opcode:='B'; LastDisassembleData.parameters:=inttohex(dword(a+4+imm32),8); end; procedure TThumbDisassembler.BL_X_T1; var s, j1, j2: byte; imm10: word; imm11: word; i1, i2: byte; imm32: integer; begin s:=(opcode shr 10) and 1; imm10:=opcode and $3ff; j1:=(opcode2 shr 13) and 1; j2:=(opcode2 shr 11) and 1; imm11:=opcode2 and $7ff; i1:=(not (j1 xor s)) and 1; i2:=(not (j2 xor s)) and 1; //S:J2:J1:imm10:imm11:'0' imm32:=(s shl 23) or (i1 shl 22) or (i2 shl 21) or (imm10 shl 11) or imm11; imm32:=imm32 shl 1; imm32:=signextend(imm32, 24); LastDisassembleData.opcode:='BL'; LastDisassembleData.parameters:=inttohex(dword(a+4+imm32),8); end; procedure TThumbDisassembler.BL_X_T2; var s, j1, j2: byte; imm10h: word; imm10l: word; i1, i2: byte; imm32: integer; begin s:=(opcode shr 10) and 1; imm10h:=opcode and $3ff; j1:=(opcode2 shr 13) and 1; j2:=(opcode2 shr 11) and 1; imm10l:=(opcode2 shr 1) and $3ff; i1:=not (j1 xor s); i2:=not (j2 xor s); //S:i1:i2:imm10h:imm10l:'00' imm32:=(s shl 22) or (i1 shl 21) or (i2 shl 20) or (imm10h shl 10) or imm10l; imm32:=imm32 shl 2; imm32:=signextend(imm32, 24); LastDisassembleData.opcode:='BLX'; LastDisassembleData.parameters:=inttohex(dword(a+4+imm32),8); end; procedure TThumbDisassembler.BX_T1; var rm: byte; begin rm:=(opcode shr 3) and $f; LastDisassembleData.opcode:='BX'; LastDisassembleData.parameters:=ArmRegisters[rm]; end; procedure TThumbDisassembler.BLX_R_T1; var rm: byte; begin rm:=(opcode shr 3) and $f; LastDisassembleData.opcode:='BLX'; LastDisassembleData.parameters:=ArmRegisters[rm]; end; procedure TThumbDisassembler.BXJ_T1; var rn: byte; begin rn:=opcode and $f; LastDisassembleData.opcode:='BXJ'; LastDisassembleData.parameters:=ArmRegisters[rn]; end; procedure TThumbDisassembler.ADD_I_T1; var imm3: byte; rn: byte; rd: byte; begin imm3:=(opcode shr 6) and 7; rn:=(opcode shr 3) and 7; rd:=opcode and 7; LastDisassembleData.opcode:='ADDS'; LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+IntToHex(imm3,1); end; procedure TThumbDisassembler.ADD_I_T2; var imm8: byte; rdn: byte; begin imm8:=opcode and $ff; rdn:=(opcode shr 8) and 7; LastDisassembleData.opcode:='ADDS'; LastDisassembleData.parameters:=ArmRegisters[rdn]+','+IntToHex(imm8,1); end; procedure TThumbDisassembler.ADD_I_T4; var i, rn, imm3, rd, imm8: byte; imm12: word; begin i:=(opcode shr 10) and 1; rn:=opcode and $f; imm3:=(opcode2 shr 12) and $7; rd:=(opcode2 shr 12) and $7; imm8:=opcode2 and $ff; imm12:=(i shr 11) or (imm3 shr 8) or (imm8); LastDisassembleData.opcode:='ADD'; LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+IntToHex(imm12,1); end; procedure TThumbDisassembler.ADR_T2; var i, imm3, rd, imm8: byte; imm12: word; begin i:=(opcode shr 10) and 1; imm3:=(opcode2 shr 12) and $7; rd:=(opcode2 shr 12) and $7; imm8:=opcode2 and $ff; imm12:=(i shr 11) or (imm3 shr 8) or (imm8); LastDisassembleData.opcode:='ADR'; LastDisassembleData.parameters:=ArmRegisters[rd]+','+IntToHex(imm12,1); end; procedure TThumbDisassembler.ADR_T3; var i, imm3, rd, imm8: byte; imm12: word; begin i:=(opcode shr 10) and 1; imm3:=(opcode2 shr 12) and $7; rd:=(opcode2 shr 12) and $7; imm8:=opcode2 and $ff; imm12:=(i shr 11) or (imm3 shr 8) or (imm8); LastDisassembleData.opcode:='ADR'; LastDisassembleData.parameters:=ArmRegisters[rd]+','+IntToHex(imm12,1); end; procedure TThumbDisassembler.SUB_I_T1; var imm3: byte; rn: byte; rd: byte; begin imm3:=(opcode shr 6) and 7; rn:=(opcode shr 3) and 7; rd:=opcode and 7; LastDisassembleData.opcode:='SUBS'; LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+IntToHex(imm3,1); end; procedure TThumbDisassembler.SUB_I_T2; var imm8: byte; rdn: byte; begin imm8:=opcode and $ff; rdn:=(opcode shr 8) and 7; LastDisassembleData.opcode:='SUBS'; LastDisassembleData.parameters:=ArmRegisters[rdn]+','+IntToHex(imm8,1); end; procedure TThumbDisassembler.SUB_I_T4; var i, rn, imm3, rd, imm8: byte; imm12: word; begin i:=(opcode shr 10) and 1; rn:=opcode and $f; imm3:=(opcode2 shr 12) and $7; rd:=(opcode2 shr 12) and $7; imm8:=opcode2 and $ff; imm12:=(i shr 11) or (imm3 shr 8) or (imm8); LastDisassembleData.opcode:='SUB'; LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+IntToHex(imm12,1); end; procedure TThumbDisassembler.SUB_I_T5; var imm8: byte; begin imm8:=opcode2 and $ff; LastDisassembleData.opcode:='SUBS'; LastDisassembleData.parameters:='PC,LR,'+ IntToHex(imm8,1); end; procedure TThumbDisassembler.TEQ_R_T1; var rn, imm3, imm2, _type, Rm: byte; v: byte; shift_s: string; begin rn:=opcode and $f; imm3:=(opcode2 shr 12) and 3; imm2:=(opcode2 shr 6) and $3; _type:=(opcode2 shr 4) and $3; rm:=opcode2 and $f; v:=(imm3 shl 2) or imm2; case _type of 0: shift_s:='LSL '; 1: shift_s:='LSR '; 2: shift_s:='ASR '; 3: shift_s:='ROR '; end; LastDisassembleData.opcode:='TEQ'; if (v=0) and (_type=3) then LastDisassembleData.parameters:=ArmRegisters[rn]+','+ArmRegisters[rm]+',RRX' else LastDisassembleData.parameters:=ArmRegisters[rn]+','+ArmRegisters[rm]+' '+shift_s+inttohex(_type,1); end; procedure TThumbDisassembler.SSAT_T1; var sh, rn, imm3, rd, imm2, sat_imm: byte; begin sh:=(opcode shr 5) and 1; rn:=opcode and $f; imm3:=(opcode2 shr 12) and $7; rd:=(opcode2 shr 8) and $f; imm2:=(opcode2 shr 6) and $3; sat_imm:=opcode2 and $f; LastDisassembleData.opcode:='SSAT'; if (sh=1) and not ((imm3=0) and (imm2=0)) then LastDisassembleData.parameters:=ArmRegisters[rd]+','+IntToHex(sat_imm+1,1)+','+ArmRegisters[rn]+', ASR '+inttoHex((imm3 shl 2) or imm2,1) else LastDisassembleData.parameters:=ArmRegisters[rd]+','+IntToHex(sat_imm+1,1)+','+ArmRegisters[rn]+', LSL '+inttoHex((imm3 shl 2) or imm2,1); end; procedure TThumbDisassembler.SSAT16_T1; var rn, rd, sat_imm: byte; begin rn:=opcode and $f; rd:=(opcode2 shr 8) and $f; sat_imm:=opcode2 and $f; LastDisassembleData.opcode:='SSAT16'; LastDisassembleData.parameters:=ArmRegisters[rd]+','+IntToHex(sat_imm+1,1)+','+ArmRegisters[rn]; end; procedure TThumbDisassembler.USAT_T1; var sh, rn, imm3, rd, imm2, sat_imm: byte; begin sh:=(opcode shr 5) and 1; rn:=opcode and $f; imm3:=(opcode2 shr 12) and $7; rd:=(opcode2 shr 8) and $f; imm2:=(opcode2 shr 6) and $3; sat_imm:=opcode2 and $f; LastDisassembleData.opcode:='USAT'; if (sh=1) and not ((imm3=0) and (imm2=0)) then LastDisassembleData.parameters:=ArmRegisters[rd]+','+IntToHex(sat_imm,1)+','+ArmRegisters[rn]+', ASR '+inttoHex((imm3 shl 2) or imm2,1) else LastDisassembleData.parameters:=ArmRegisters[rd]+','+IntToHex(sat_imm,1)+','+ArmRegisters[rn]+', LSL '+inttoHex((imm3 shl 2) or imm2,1); end; procedure TThumbDisassembler.USAT16_T1; var rn, rd, sat_imm: byte; begin rn:=opcode and $f; rd:=(opcode2 shr 8) and $f; sat_imm:=opcode2 and $f; LastDisassembleData.opcode:='USAT16'; LastDisassembleData.parameters:=ArmRegisters[rd]+','+IntToHex(sat_imm,1)+','+ArmRegisters[rn]; end; procedure TThumbDisassembler.SBFX_T1; var rn, imm3, rd, imm2, widthm1: byte; begin rn:=opcode and $f; imm3:=(opcode2 shr 12) and $7; rd:=(opcode2 shr 8) and $f; imm2:=(opcode2 shr 6) and $3; widthm1:=opcode2 and $f; LastDisassembleData.opcode:='SBFX'; LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+inttohex((imm3 shl 2) or imm2, 1)+','+inttohex(widthm1+1,1); end; procedure TThumbDisassembler.UBFX_T1; var rn, imm3, rd, imm2, widthm1: byte; begin rn:=opcode and $f; imm3:=(opcode2 shr 12) and $7; rd:=(opcode2 shr 8) and $f; imm2:=(opcode2 shr 6) and $3; widthm1:=opcode2 and $f; LastDisassembleData.opcode:='UBFX'; LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+inttohex((imm3 shl 2) or imm2, 1)+','+inttohex(widthm1+1,1); end; procedure TThumbDisassembler.BFI_T1; var rn, imm3, rd, imm2, msb: byte; lsb: byte; begin rn:=opcode and $f; imm3:=(opcode2 shr 12) and $7; rd:=(opcode2 shr 8) and $f; imm2:=(opcode2 shr 6) and $3; msb:=opcode2 and $f; lsb:=(imm3 shl 2) or imm2; LastDisassembleData.opcode:='BFI'; LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+inttohex(lsb, 1)+','+inttohex(msb+1-lsb,1); end; procedure TThumbDisassembler.BFC_T1; var rn, imm3, rd, imm2, msb: byte; lsb: byte; begin imm3:=(opcode2 shr 12) and $7; rd:=(opcode2 shr 8) and $f; imm2:=(opcode2 shr 6) and $3; msb:=opcode2 and $f; lsb:=(imm3 shl 2) or imm2; LastDisassembleData.opcode:='BFI'; LastDisassembleData.parameters:=ArmRegisters[rd]+','+inttohex(lsb, 1)+','+inttohex(msb+1-lsb,1); end; procedure TThumbDisassembler.MOV_I_T1; var imm8, rd: byte; begin rd:=(opcode shr 8) and 7; imm8:=opcode and $ff; LastDisassembleData.opcode:='MOVS'; LastDisassembleData.parameters:=ArmRegisters[rd]+','+IntToHex(imm8,1); end; procedure TThumbDisassembler.MOV_I_T3; var i, imm4, imm3, rd, imm8, imm16: byte; begin i:=(opcode shr 10) and 1; imm4:=opcode and $f; imm3:=(opcode2 shr 12) and $7; rd:=(opcode2 shr 12) and $7; imm8:=opcode2 and $ff; imm16:=(imm4 shr 12) or (i shr 11) or (imm3 shr 8) or (imm8); LastDisassembleData.opcode:='MOV'; LastDisassembleData.parameters:=ArmRegisters[rd]+','+IntToHex(imm16,1); end; procedure TThumbDisassembler.MOVT_T1; var i, imm4, imm3, rd, imm8, imm16: byte; begin i:=(opcode shr 10) and 1; imm4:=opcode and $f; imm3:=(opcode2 shr 12) and $7; rd:=(opcode2 shr 12) and $7; imm8:=opcode2 and $ff; imm16:=(imm4 shr 12) or (i shr 11) or (imm3 shr 8) or (imm8); LastDisassembleData.opcode:='MOVT'; LastDisassembleData.parameters:=ArmRegisters[rd]+','+IntToHex(imm16,1); end; procedure TThumbDisassembler.CMP_I_T1; var imm8, rn: byte; begin rn:=(opcode shr 8) and 7; imm8:=opcode and $ff; LastDisassembleData.opcode:='CMP'; LastDisassembleData.parameters:=ArmRegisters[rn]+','+IntToHex(imm8,1); end; procedure TThumbDisassembler.ADD_SP_R_T1; var dm: byte; rdm: byte; begin dm:=(opcode shr 7) and 1; rdm:=opcode and 7; rdm:=(dm shl 4) or rdm; LastDisassembleData.opcode:='ADD'; LastDisassembleData.parameters:='SP,'+ArmRegisters[rdm]; end; procedure TThumbDisassembler.ADD_SP_R_T2; var rm: byte; begin rm:=(opcode shr 3) and $f; LastDisassembleData.opcode:='ADD'; LastDisassembleData.parameters:='SP,'+ArmRegisters[rm]; end; procedure TThumbDisassembler.ADD_R_T1; var rd, rn, rm: byte; begin rd:=opcode and 7; rn:=(opcode shr 3) and 7; rm:=(opcode shr 6) and 7; LastDisassembleData.opcode:='ADDS'; LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+ArmRegisters[rm]; end; procedure TThumbDisassembler.ADD_R_T2; var rdn, rm,dn: byte; begin rdn:=opcode and 7; rm:=(opcode shr 3) and $f; dn:=(opcode shr 7) and 1; rdn:=(dn shl 4) or rdn; LastDisassembleData.opcode:='ADD'; LastDisassembleData.parameters:=ArmRegisters[rdn]+','+ArmRegisters[rm]; end; procedure TThumbDisassembler.ADD_R_T3; var s, rn, imm3, rd, imm2, _type, Rm: byte; v: byte; shift_s: string; begin s:=(opcode shr 4) and 1; rn:=opcode and $f; imm3:=(opcode2 shr 12) and 3; rd:=(opcode2 shr 8) and $f; imm2:=(opcode2 shr 6) and $3; _type:=(opcode2 shr 4) and $3; rm:=opcode2 and $f; v:=(imm3 shl 2) or imm2; case _type of 0: shift_s:='LSL '; 1: shift_s:='LSR '; 2: shift_s:='ASR '; 3: shift_s:='ROR '; end; if (s=0) then LastDisassembleData.opcode:='ADD' else LastDisassembleData.opcode:='ADDS'; if (v=0) and (_type=3) then LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+ArmRegisters[rm]+',RRX' else LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+ArmRegisters[rm]+' '+shift_s+inttohex(_type,1); end; procedure TThumbDisassembler.SUB_R_T1; var rd, rn, rm: byte; begin rd:=opcode and 7; rn:=(opcode shr 3) and 7; rm:=(opcode shr 6) and 7; LastDisassembleData.opcode:='SUBS'; LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+ArmRegisters[rm]; end; procedure TThumbDisassembler.SUB_R_T2; var s, rn, imm3, rd, imm2, _type, Rm: byte; v: byte; shift_s: string; begin s:=(opcode shr 4) and 1; rn:=opcode and $f; imm3:=(opcode2 shr 12) and 3; rd:=(opcode2 shr 8) and $f; imm2:=(opcode2 shr 6) and $3; _type:=(opcode2 shr 4) and $3; rm:=opcode2 and $f; v:=(imm3 shl 2) or imm2; case _type of 0: shift_s:='LSL '; 1: shift_s:='LSR '; 2: shift_s:='ASR '; 3: shift_s:='ROR '; end; if (s=0) then LastDisassembleData.opcode:='SUB' else LastDisassembleData.opcode:='SUBS'; if (v=0) and (_type=3) then LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+ArmRegisters[rm]+',RRX' else LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+ArmRegisters[rm]+' '+shift_s+inttohex(_type,1); end; procedure TThumbDisassembler.ADC_R_T1; var rdn,rm: byte; begin rm:=(opcode shr 3) and 7; rdn:=opcode and 7; LastDisassembleData.opcode:='ADCS'; LastDisassembleData.parameters:=ArmRegisters[rdn]+','+ArmRegisters[rm]; end; procedure TThumbDisassembler.ADC_R_T2; var s, rn, imm3, rd, imm2, _type, Rm: byte; v: byte; shift_s: string; begin s:=(opcode shr 4) and 1; rn:=opcode and $f; imm3:=(opcode2 shr 12) and 3; rd:=(opcode2 shr 8) and $f; imm2:=(opcode2 shr 6) and $3; _type:=(opcode2 shr 4) and $3; rm:=opcode2 and $f; v:=(imm3 shl 2) or imm2; case _type of 0: shift_s:='LSL '; 1: shift_s:='LSR '; 2: shift_s:='ASR '; 3: shift_s:='ROR '; end; if (s=0) then LastDisassembleData.opcode:='ADC' else LastDisassembleData.opcode:='ADCS'; if (v=0) and (_type=3) then LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+ArmRegisters[rm]+',RRX' else LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+ArmRegisters[rm]+' '+shift_s+inttohex(_type,1); end; procedure TThumbDisassembler.AND_R_T1; var rdn,rm: byte; begin rm:=(opcode shr 3) and 7; rdn:=opcode and 7; LastDisassembleData.opcode:='ANDS'; LastDisassembleData.parameters:=ArmRegisters[rdn]+','+ArmRegisters[rm]; end; procedure TThumbDisassembler.AND_R_T2; var s, rn, imm3, rd, imm2, _type, Rm: byte; v: byte; shift_s: string; begin s:=(opcode shr 4) and 1; rn:=opcode and $f; imm3:=(opcode2 shr 12) and 3; rd:=(opcode2 shr 8) and $f; imm2:=(opcode2 shr 6) and $3; _type:=(opcode2 shr 4) and $3; rm:=opcode2 and $f; v:=(imm3 shl 2) or imm2; case _type of 0: shift_s:='LSL '; 1: shift_s:='LSR '; 2: shift_s:='ASR '; 3: shift_s:='ROR '; end; if (s=0) then LastDisassembleData.opcode:='AND' else LastDisassembleData.opcode:='ANDS'; if (v=0) and (_type=3) then LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+ArmRegisters[rm]+',RRX' else LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+ArmRegisters[rm]+' '+shift_s+inttohex(_type,1); end; procedure TThumbDisassembler.EOR_R_T1; var rdn,rm: byte; begin rm:=(opcode shr 3) and 7; rdn:=opcode and 7; LastDisassembleData.opcode:='EORS'; LastDisassembleData.parameters:=ArmRegisters[rdn]+','+ArmRegisters[rm]; end; procedure TThumbDisassembler.EOR_R_T2; var s, rn, imm3, rd, imm2, _type, Rm: byte; v: byte; shift_s: string; begin s:=(opcode shr 4) and 1; rn:=opcode and $f; imm3:=(opcode2 shr 12) and 3; rd:=(opcode2 shr 8) and $f; imm2:=(opcode2 shr 6) and $3; _type:=(opcode2 shr 4) and $3; rm:=opcode2 and $f; v:=(imm3 shl 2) or imm2; case _type of 0: shift_s:='LSL '; 1: shift_s:='LSR '; 2: shift_s:='ASR '; 3: shift_s:='ROR '; end; if (s=0) then LastDisassembleData.opcode:='EOR' else LastDisassembleData.opcode:='EORS'; if (v=0) and (_type=3) then LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+ArmRegisters[rm]+',RRX' else LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+ArmRegisters[rm]+' '+shift_s+inttohex(_type,1); end; procedure TThumbDisassembler.SBC_R_T1; var rdn,rm: byte; begin rm:=(opcode shr 3) and 7; rdn:=opcode and 7; LastDisassembleData.opcode:='SBCS'; LastDisassembleData.parameters:=ArmRegisters[rdn]+','+ArmRegisters[rm]; end; procedure TThumbDisassembler.SBC_R_T2; var s, rn, imm3, rd, imm2, _type, Rm: byte; v: byte; shift_s: string; begin s:=(opcode shr 4) and 1; rn:=opcode and $f; imm3:=(opcode2 shr 12) and 3; rd:=(opcode2 shr 8) and $f; imm2:=(opcode2 shr 6) and $3; _type:=(opcode2 shr 4) and $3; rm:=opcode2 and $f; v:=(imm3 shl 2) or imm2; case _type of 0: shift_s:='LSL '; 1: shift_s:='LSR '; 2: shift_s:='ASR '; 3: shift_s:='ROR '; end; if (s=0) then LastDisassembleData.opcode:='ADC' else LastDisassembleData.opcode:='ADCS'; if (v=0) and (_type=3) then LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+ArmRegisters[rm]+',RRX' else LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+ArmRegisters[rm]+' '+shift_s+inttohex(_type,1); end; procedure TThumbDisassembler.TST_R_T1; var rdn,rm: byte; begin rm:=(opcode shr 3) and 7; rdn:=opcode and 7; LastDisassembleData.opcode:='TST'; LastDisassembleData.parameters:=ArmRegisters[rdn]+','+ArmRegisters[rm]; end; procedure TThumbDisassembler.TST_R_T2; var rn, imm3, imm2, _type, Rm: byte; v: byte; shift_s: string; begin rn:=opcode and $f; imm3:=(opcode2 shr 12) and 3; imm2:=(opcode2 shr 6) and $3; _type:=(opcode2 shr 4) and $3; rm:=opcode2 and $f; v:=(imm3 shl 2) or imm2; case _type of 0: shift_s:='LSL '; 1: shift_s:='LSR '; 2: shift_s:='ASR '; 3: shift_s:='ROR '; end; LastDisassembleData.opcode:='TST'; if (v=0) and (_type=3) then LastDisassembleData.parameters:=ArmRegisters[rn]+','+ArmRegisters[rm]+',RRX' else LastDisassembleData.parameters:=ArmRegisters[rn]+','+ArmRegisters[rm]+' '+shift_s+inttohex(_type,1); end; procedure TThumbDisassembler.RSB_I_T1; var rd,rn: byte; begin rn:=(opcode shr 3) and 7; rd:=opcode and 7; LastDisassembleData.opcode:='RSBS'; LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+',0'; end; procedure TThumbDisassembler.RSB_R_T1; var s, rn, imm3, rd, imm2, _type, Rm: byte; v: byte; shift_s: string; begin s:=(opcode shr 4) and 1; rn:=opcode and $f; imm3:=(opcode2 shr 12) and 3; rd:=(opcode2 shr 8) and $f; imm2:=(opcode2 shr 6) and $3; _type:=(opcode2 shr 4) and $3; rm:=opcode2 and $f; v:=(imm3 shl 2) or imm2; case _type of 0: shift_s:='LSL '; 1: shift_s:='LSR '; 2: shift_s:='ASR '; 3: shift_s:='ROR '; end; if (s=0) then LastDisassembleData.opcode:='RSB' else LastDisassembleData.opcode:='RSBS'; if (v=0) and (_type=3) then LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+ArmRegisters[rm]+',RRX' else LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+ArmRegisters[rm]+' '+shift_s+inttohex(_type,1); end; procedure TThumbDisassembler.CMP_R_T1; var rn,rm: byte; begin rm:=(opcode shr 3) and 7; rn:=opcode and 7; LastDisassembleData.opcode:='CMP'; LastDisassembleData.parameters:=ArmRegisters[rn]+','+ArmRegisters[rm]; end; procedure TThumbDisassembler.CMP_R_T2; var rn,rm,N: byte; begin rm:=(opcode shr 3) and $f; rn:=opcode and 7; n:=(opcode shr 7) and 1; rn:=(n shl 4) or rn; LastDisassembleData.opcode:='CMP'; LastDisassembleData.parameters:=ArmRegisters[rn]+','+ArmRegisters[rm]; end; procedure TThumbDisassembler.CMP_R_T3; var rn, imm3, imm2, _type, Rm: byte; v: byte; shift_s: string; begin rn:=opcode and $f; imm3:=(opcode2 shr 12) and 3; imm2:=(opcode2 shr 6) and $3; _type:=(opcode2 shr 4) and $3; rm:=opcode2 and $f; v:=(imm3 shl 2) or imm2; case _type of 0: shift_s:='LSL '; 1: shift_s:='LSR '; 2: shift_s:='ASR '; 3: shift_s:='ROR '; end; LastDisassembleData.opcode:='CMP'; if (v=0) and (_type=3) then LastDisassembleData.parameters:=ArmRegisters[rn]+','+ArmRegisters[rm]+',RRX' else LastDisassembleData.parameters:=ArmRegisters[rn]+','+ArmRegisters[rm]+' '+shift_s+inttohex(_type,1); end; procedure TThumbDisassembler.CMN_R_T1; var rn,rm: byte; begin rm:=(opcode shr 3) and 7; rn:=opcode and 7; LastDisassembleData.opcode:='CMN'; LastDisassembleData.parameters:=ArmRegisters[rn]+','+ArmRegisters[rm]; end; procedure TThumbDisassembler.CMN_R_T2; var rn, imm3, imm2, _type, Rm: byte; v: byte; shift_s: string; begin rn:=opcode and $f; imm3:=(opcode2 shr 12) and 3; imm2:=(opcode2 shr 6) and $3; _type:=(opcode2 shr 4) and $3; rm:=opcode2 and $f; v:=(imm3 shl 2) or imm2; case _type of 0: shift_s:='LSL '; 1: shift_s:='LSR '; 2: shift_s:='ASR '; 3: shift_s:='ROR '; end; LastDisassembleData.opcode:='CMN'; if (v=0) and (_type=3) then LastDisassembleData.parameters:=ArmRegisters[rn]+','+ArmRegisters[rm]+',RRX' else LastDisassembleData.parameters:=ArmRegisters[rn]+','+ArmRegisters[rm]+' '+shift_s+inttohex(_type,1); end; procedure TThumbDisassembler.ORR_R_T1; var rdn,rm: byte; begin rm:=(opcode shr 3) and 7; rdn:=opcode and 7; LastDisassembleData.opcode:='ORRS'; LastDisassembleData.parameters:=ArmRegisters[rdn]+','+ArmRegisters[rm]; end; procedure TThumbDisassembler.ORR_R_T2; var s, rn, imm3, rd, imm2, _type, Rm: byte; v: byte; shift_s: string; begin s:=(opcode shr 4) and 1; rn:=opcode and $f; imm3:=(opcode2 shr 12) and 3; rd:=(opcode2 shr 8) and $f; imm2:=(opcode2 shr 6) and $3; _type:=(opcode2 shr 4) and $3; rm:=opcode2 and $f; v:=(imm3 shl 2) or imm2; case _type of 0: shift_s:='LSL '; 1: shift_s:='LSR '; 2: shift_s:='ASR '; 3: shift_s:='ROR '; end; if (s=0) then LastDisassembleData.opcode:='ORR' else LastDisassembleData.opcode:='ORRS'; if (v=0) and (_type=3) then LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+ArmRegisters[rm]+',RRX' else LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+ArmRegisters[rm]+' '+shift_s+inttohex(_type,1); end; procedure TThumbDisassembler.ORN_R_T1; var s, rn, imm3, rd, imm2, _type, Rm: byte; v: byte; shift_s: string; begin s:=(opcode shr 4) and 1; rn:=opcode and $f; imm3:=(opcode2 shr 12) and 3; rd:=(opcode2 shr 8) and $f; imm2:=(opcode2 shr 6) and $3; _type:=(opcode2 shr 4) and $3; rm:=opcode2 and $f; v:=(imm3 shl 2) or imm2; case _type of 0: shift_s:='LSL '; 1: shift_s:='LSR '; 2: shift_s:='ASR '; 3: shift_s:='ROR '; end; if (s=0) then LastDisassembleData.opcode:='ORN' else LastDisassembleData.opcode:='ORNS'; if (v=0) and (_type=3) then LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+ArmRegisters[rm]+',RRX' else LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+ArmRegisters[rm]+' '+shift_s+inttohex(_type,1); end; procedure TThumbDisassembler.MUL_R_T1; var rdm,rn: byte; begin rn:=(opcode shr 3) and 7; rdm:=opcode and 7; LastDisassembleData.opcode:='MULS'; LastDisassembleData.parameters:=ArmRegisters[rdm]+','+ArmRegisters[rn]; end; procedure TThumbDisassembler.BIC_R_T1; var rdn,rm: byte; begin rm:=(opcode shr 3) and 7; rdn:=opcode and 7; LastDisassembleData.opcode:='BICS'; LastDisassembleData.parameters:=ArmRegisters[rdn]+','+ArmRegisters[rm]; end; procedure TThumbDisassembler.BIC_R_T2; var s, rn, imm3, rd, imm2, _type, Rm: byte; v: byte; shift_s: string; begin s:=(opcode shr 4) and 1; rn:=opcode and $f; imm3:=(opcode2 shr 12) and 3; rd:=(opcode2 shr 8) and $f; imm2:=(opcode2 shr 6) and $3; _type:=(opcode2 shr 4) and $3; rm:=opcode2 and $f; v:=(imm3 shl 2) or imm2; case _type of 0: shift_s:='LSL '; 1: shift_s:='LSR '; 2: shift_s:='ASR '; 3: shift_s:='ROR '; end; if (s=0) then LastDisassembleData.opcode:='BIC' else LastDisassembleData.opcode:='BICS'; if (v=0) and (_type=3) then LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+ArmRegisters[rm]+',RRX' else LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+ArmRegisters[rm]+' '+shift_s+inttohex(_type,1); end; procedure TThumbDisassembler.MVN_R_T1; var rd,rm: byte; begin rm:=(opcode shr 3) and 7; rd:=opcode and 7; LastDisassembleData.opcode:='MVN'; LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rm]; end; procedure TThumbDisassembler.MVN_R_T2; var s, rn, imm3, rd, imm2, _type, Rm: byte; v: byte; shift_s: string; begin s:=(opcode shr 4) and 1; rn:=opcode and $f; imm3:=(opcode2 shr 12) and 3; rd:=(opcode2 shr 8) and $f; imm2:=(opcode2 shr 6) and $3; _type:=(opcode2 shr 4) and $3; rm:=opcode2 and $f; v:=(imm3 shl 2) or imm2; case _type of 0: shift_s:='LSL '; 1: shift_s:='LSR '; 2: shift_s:='ASR '; 3: shift_s:='ROR '; end; if (s=0) then LastDisassembleData.opcode:='MVN' else LastDisassembleData.opcode:='MVNS'; if (v=0) and (_type=3) then LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+ArmRegisters[rm]+',RRX' else LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+ArmRegisters[rm]+' '+shift_s+inttohex(_type,1); end; procedure TThumbDisassembler.MOV_R_T1; var rd,rm,D: byte; begin rd:=(opcode and 7); rm:=(opcode shr 3) and $f; d:=(opcode shr 7) and 1; rd:=(d shl 4) or rd; LastDisassembleData.opcode:='MOV'; LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rm]; end; procedure TThumbDisassembler.MOV_RSR_T1; var op: byte; rs,rdm: byte; shiftname: string; begin op:=(opcode shr 6) and 3; rs:=(opcode shr 3) and 7; rdm:=opcode and 7; case op of 2: shiftname:='LSL'; 3: shiftname:='LSR'; 4: shiftname:='ASR'; 7: shiftname:='ROR'; end; LastDisassembleData.opcode:='MOVS'; LastDisassembleData.parameters:=ArmRegisters[rdm]+','+ArmRegisters[rdm]+','+shiftname+' '+ArmRegisters[rs]; end; procedure TThumbDisassembler.MOV_RSR_T2; var _type, s, rm, rd, rs: byte; shift_s: string; begin _type:=(opcode shr 5) and $f; s:=(opcode shr 4) and 1; rm:=opcode and $f; rd:=(opcode2 shr 8) and $f; rs:=opcode2 and $f; case _type of 0: shift_s:='LSL '; 1: shift_s:='LSR '; 2: shift_s:='ASR '; 3: shift_s:='ROR '; end; if (s=1) then LastDisassembleData.opcode:='MOVS' else LastDisassembleData.opcode:='MOV'; LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rm]+','+shift_s+ArmRegisters[rs]; end; procedure TThumbDisassembler.PKHBT_T1; var rn, imm3, rd, imm2, _type, Rm: byte; v: byte; shift_s: string; begin rn:=opcode and $f; imm3:=(opcode2 shr 12) and 3; rd:=(opcode2 shr 8) and $f; imm2:=(opcode2 shr 6) and $3; _type:=(opcode2 shr 4) and $3; rm:=opcode2 and $f; v:=(imm3 shl 2) or imm2; case _type of 0: shift_s:='LSL '; 1: shift_s:='LSR '; 2: shift_s:='ASR '; 3: shift_s:='ROR '; end; LastDisassembleData.opcode:='PKHBT'; LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+ArmRegisters[rm]+' '+shift_s+inttohex(_type,1); end; procedure TThumbDisassembler.MOV_R_T2; var op: byte; rn,rd: byte; imm5: byte; shiftname: string; begin if ((opcode shr 13)=0) and (((opcode shr 11) and 3)<>3) then begin op:=(opcode shr 11) and 3; imm5:=(opcode shr 6) and $1f; rn:=(opcode shr 3) and 7; rd:=opcode and 7; if imm5>0 then begin case op of 0: shiftname:='LSL'; 1: shiftname:='LSR'; 2: shiftname:='ASR'; 3: shiftname:='ROR'; end; shiftname:=','+shiftname+' '+inttohex(imm5,1); end else shiftname:=''; LastDisassembleData.opcode:='MOVS'; LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+shiftname; end; end; procedure TThumbDisassembler.MOV_R_T3; var s, rn, imm3, rd, imm2, _type, Rm: byte; v: byte; shift_s: string; begin s:=(opcode shr 4) and 1; rn:=opcode and $f; imm3:=(opcode2 shr 12) and 3; rd:=(opcode2 shr 8) and $f; imm2:=(opcode2 shr 6) and $3; _type:=(opcode2 shr 4) and $3; rm:=opcode2 and $f; v:=(imm3 shl 2) or imm2; case _type of 0: shift_s:='LSL '; 1: shift_s:='LSR '; 2: shift_s:='ASR '; 3: shift_s:='ROR '; end; if (s=0) then LastDisassembleData.opcode:='MOV' else LastDisassembleData.opcode:='MOVS'; if (v=0) and (_type=3) then LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+ArmRegisters[rm]+',RRX' else LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rn]+','+ArmRegisters[rm]+' '+shift_s+inttohex(_type,1); end; procedure TThumbDisassembler.MSR_BR_T1; var R, Rn, M1, m: byte; bankedreg: string; begin r:=(opcode shr 4) and 1; rn:=opcode and $f; m1:=(opcode2 shr 8) and $f; m:=(opcode2 shr 4) and 1; LastDisassembleData.opcode:='MSR'; case r of 0: begin case m of 0: case m1 of 0: bankedreg:='R8_usr'; 1: bankedreg:='R9_usr'; 2: bankedreg:='R10_usr'; 3: bankedreg:='R11_usr'; 4: bankedreg:='R12_usr'; 5: bankedreg:='SP_usr'; 6: bankedreg:='LR_usr'; 8: bankedreg:='R8_fiq'; 9: bankedreg:='R9_fiq'; 10: bankedreg:='R10_fiq'; 11: bankedreg:='R11_fiq'; 12: bankedreg:='R12_fiq'; 13: bankedreg:='SP_fiq'; 14: bankedreg:='LR_fiq'; end; 1: case m1 of 0: bankedreg:='LR_irq'; 1: bankedreg:='SP_irq'; 2: bankedreg:='LR_svc'; 3: bankedreg:='SP_svc'; 4: bankedreg:='LR_abt'; 5: bankedreg:='SP_abt'; 6: bankedreg:='LR_und'; 7: bankedreg:='SP_und'; 12: bankedreg:='LR_mon'; 13: bankedreg:='SP_mon'; 14: bankedreg:='ELR_hyp'; 15: bankedreg:='SP_hyp'; end; end; end; 1: begin case m of 0: case m1 of 14: bankedreg:='SPSR_fiq'; end; 1: case m1 of 0: bankedreg:='SPSR_irq'; 2: bankedreg:='SPSR_svc'; 4: bankedreg:='SPSR_abt'; 6: bankedreg:='SPSR_und'; 12: bankedreg:='SPSR_mon'; 14: bankedreg:='SPSR_hyp'; end; end; end; end; LastDisassembleData.parameters:=bankedreg+','+ArmRegisters[rn]; end; procedure TThumbDisassembler.MSR_R_T1; var r, rn, mask: byte; spec_reg: string; begin r:=(opcode shr 4) and 1; rn:=opcode and $f; mask:=(opcode shr 8) and $f; LastDisassembleData.opcode:='MSR'; if R=0 then LastDisassembleData.parameters:='CPSR('+intToBin(mask,4)+'),'+ArmRegisters[rn] else LastDisassembleData.parameters:='SPSR('+intToBin(mask,4)+'),'+ArmRegisters[rn]; end; procedure TThumbDisassembler.MRS_BR_T1; var R, M1, Rd, m: byte; bankedreg: string; begin r:=(opcode shr 4) and 1; m1:=(opcode2 shr 8) and $f; rd:=(opcode shr 8) and $f; m:=(opcode2 shr 4) and 1; LastDisassembleData.opcode:='MRS'; case r of 0: begin case m of 0: case m1 of 0: bankedreg:='R8_usr'; 1: bankedreg:='R9_usr'; 2: bankedreg:='R10_usr'; 3: bankedreg:='R11_usr'; 4: bankedreg:='R12_usr'; 5: bankedreg:='SP_usr'; 6: bankedreg:='LR_usr'; 8: bankedreg:='R8_fiq'; 9: bankedreg:='R9_fiq'; 10: bankedreg:='R10_fiq'; 11: bankedreg:='R11_fiq'; 12: bankedreg:='R12_fiq'; 13: bankedreg:='SP_fiq'; 14: bankedreg:='LR_fiq'; end; 1: case m1 of 0: bankedreg:='LR_irq'; 1: bankedreg:='SP_irq'; 2: bankedreg:='LR_svc'; 3: bankedreg:='SP_svc'; 4: bankedreg:='LR_abt'; 5: bankedreg:='SP_abt'; 6: bankedreg:='LR_und'; 7: bankedreg:='SP_und'; 12: bankedreg:='LR_mon'; 13: bankedreg:='SP_mon'; 14: bankedreg:='ELR_hyp'; 15: bankedreg:='SP_hyp'; end; end; end; 1: begin case m of 0: case m1 of 14: bankedreg:='SPSR_fiq'; end; 1: case m1 of 0: bankedreg:='SPSR_irq'; 2: bankedreg:='SPSR_svc'; 4: bankedreg:='SPSR_abt'; 6: bankedreg:='SPSR_und'; 12: bankedreg:='SPSR_mon'; 14: bankedreg:='SPSR_hyp'; end; end; end; end; LastDisassembleData.parameters:=ArmRegisters[rd]+','+bankedreg; end; procedure TThumbDisassembler.MRS_R_T1; var r, rd: byte; begin //todo: someday... r:=(opcode shr 4) and 1; rd:=(opcode shr 8) and $f; LastDisassembleData.opcode:='MRS'; if R=0 then LastDisassembleData.parameters:=ArmRegisters[rd]+',CPSR' else LastDisassembleData.parameters:=ArmRegisters[rd]+',APSR' end; procedure TThumbDisassembler.SRS_T1; var w,mode: byte; _w: string; begin w:=(opcode shr 5) and 1; if w=1 then _w:='!' else _w:=''; mode:=opcode2 and $f; LastDisassembleData.opcode:='SRS'; LastDisassembleData.parameters:='SP'+_w+','+inttohex(mode,1) end; procedure TThumbDisassembler.SRS_T2; var w,mode: byte; _w: string; begin w:=(opcode shr 5) and 1; if w=1 then _w:='!' else _w:=''; mode:=opcode2 and $f; LastDisassembleData.opcode:='SRSDB'; LastDisassembleData.parameters:='SP'+_w+','+inttohex(mode,1) end; procedure TThumbDisassembler.RFE_T1; var w,rn: byte; _w: string; begin w:=(opcode shr 5) and 1; if w=1 then _w:='!' else _w:=''; rn:=opcode and $f; LastDisassembleData.opcode:='RFEDB'; LastDisassembleData.parameters:=ArmRegisters[rn]+_w; end; procedure TThumbDisassembler.RFE_T2; var w,rn: byte; _w: string; begin w:=(opcode shr 5) and 1; if w=1 then _w:='!' else _w:=''; rn:=opcode and $f; LastDisassembleData.opcode:='RFE'; LastDisassembleData.parameters:=ArmRegisters[rn]+_w; end; procedure TThumbDisassembler.STREX_T1; var rn, rt, rd, imm8: byte; begin rn:=opcode and $f; rt:=(opcode2 shr 12) and $f; rd:=(opcode2 shr 8) and $f; imm8:=opcode2 and $ff; LastDisassembleData.opcode:='STREX'; if imm8=0 then LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rt]+',['+ArmRegisters[rn]+']' else LastDisassembleData.parameters:=ArmRegisters[rd]+','+ArmRegisters[rt]+',['+ArmRegisters[rn]+','+inttohex(imm8 shl 2,1)+']' end; procedure TThumbDisassembler.LDREX_T1; var rn, rt, imm8: byte; begin rn:=opcode and $f; rt:=(opcode2 shr 12) and $f; imm8:=opcode2 and $ff; LastDisassembleData.opcode:='LDREX'; if imm8=0 then LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+']' else LastDisassembleData.parameters:=ArmRegisters[rt]+',['+ArmRegisters[rn]+','+inttohex(imm8 shl 2,1)+']' end; procedure TThumbDisassembler.STRD_I_T1; var p,u,w,rn, rt, rt2, imm8: byte; _imm: string; begin p:=(opcode shr 8) and 1; u:=(opcode shr 7) and 1; w:=(opcode shr 5) and 1; rn:=opcode and $f; rt:=(opcode2 shr 12) and $f; rt2:=(opcode2 shr 8) and $f; imm8:=opcode2 and $ff; LastDisassembleData.opcode:='STRD'; if imm8=0 then _imm:='' else begin if u=0 then _imm:=',-'+inttohex(imm8 shl 2,1) else _imm:=','+inttohex(imm8 shl 2,1); end; if (p=1) and (w=0) then LastDisassembleData.parameters:=ArmRegisters[rt]+','+ArmRegisters[rt2]+',['+ArmRegisters[rn]+_imm+']' else if (p=0) and (w=1) then LastDisassembleData.parameters:=ArmRegisters[rt]+','+ArmRegisters[rt2]+',['+ArmRegisters[rn]+']'+_imm else if (p=1) and (w=1) then LastDisassembleData.parameters:=ArmRegisters[rt]+','+ArmRegisters[rt2]+',['+ArmRegisters[rn]+_imm+']!'; end; procedure TThumbDisassembler.LDRD_I_T1; var p,u,w,rn, rt, rt2, imm8: byte; _imm: string; begin p:=(opcode shr 8) and 1; u:=(opcode shr 7) and 1; w:=(opcode shr 5) and 1; rn:=opcode and $f; rt:=(opcode2 shr 12) and $f; rt2:=(opcode2 shr 8) and $f; imm8:=opcode2 and $ff; LastDisassembleData.opcode:='LDRD'; if imm8=0 then _imm:='' else begin if u=0 then _imm:=',-'+inttohex(imm8 shl 2,1) else _imm:=','+inttohex(imm8 shl 2,1); end; if (p=1) and (w=0) then LastDisassembleData.parameters:=ArmRegisters[rt]+','+ArmRegisters[rt2]+',['+ArmRegisters[rn]+_imm+']' else if (p=0) and (w=1) then LastDisassembleData.parameters:=ArmRegisters[rt]+','+ArmRegisters[rt2]+',['+ArmRegisters[rn]+']'+_imm else if (p=1) and (w=1) then LastDisassembleData.parameters:=ArmRegisters[rt]+','+ArmRegisters[rt2]+',['+ArmRegisters[rn]+_imm+']!'; end; procedure TThumbDisassembler.LDRD_L_T1; var p,u,w, rt, rt2, imm8: byte; _imm: string; imm32: ptruint; begin p:=(opcode shr 8) and 1; u:=(opcode shr 7) and 1; w:=(opcode shr 5) and 1; rt:=(opcode2 shr 12) and $f; rt2:=(opcode2 shr 8) and $f; imm8:=opcode2 and $ff; LastDisassembleData.opcode:='LDRD'; imm32:=imm8 shl 2; if u=0 then imm32:=-imm32; imm32:=Align(a+4,4)+imm32; if not ((p=0) and (w=0)) then LastDisassembleData.parameters:=ArmRegisters[rt]+','+ArmRegisters[rt2]+','+inttohex(imm32,1); end; procedure TThumbDisassembler.LDRH_L_T1; var u, rt: byte; imm12: word; imm32: ptruint; begin u:=(opcode shr 7) and 1; rt:=(opcode2 shr 12) and $f; imm12:=opcode2 and $ff; imm32:=imm12; if u=0 then imm32:=-imm32; LastDisassembleData.opcode:='LDRH'; LastDisassembleData.parameters:=inttohex(Align(a+4,4)+imm32,1); end; procedure TThumbDisassembler.LDRSH_L_T1; var u, rt: byte; imm12: word; imm32: ptruint; begin u:=(opcode shr 7) and 1; rt:=(opcode2 shr 12) and $f; imm12:=opcode2 and $ff; imm32:=imm12; if u=0 then imm32:=-imm32; LastDisassembleData.opcode:='LDRSH'; LastDisassembleData.parameters:=inttohex(Align(a+4,4)+imm32,1); end; procedure TThumbDisassembler.LDRSB_L_T1; var u, rt: byte; imm12: word; imm32: ptruint; begin u:=(opcode shr 7) and 1; rt:=(opcode2 shr 12) and $f; imm12:=opcode2 and $ff; imm32:=imm12; if u=0 then imm32:=-imm32; LastDisassembleData.opcode:='LDRSB'; LastDisassembleData.parameters:=inttohex(Align(a+4,4)+imm32,1); end; procedure TThumbDisassembler.PLD_L_T1; var u: byte; imm12: word; imm32: ptruint; begin u:=(opcode shr 7) and 1; imm12:=opcode2 and $ff; imm32:=imm12; if u=0 then imm32:=-imm32; LastDisassembleData.opcode:='PLD'; LastDisassembleData.parameters:=inttohex(Align(a+4,4)+imm32,1); end; procedure TThumbDisassembler.PLD_R_T1; var w,rn,imm2, rm: byte; begin w:=(opcode shr 5) and 1; rn:=(opcode and $f); imm2:=(opcode2 shr 4) and 3; rm:=opcode and $f; if (w=1) then LastDisassembleData.opcode:='PLDW' else LastDisassembleData.opcode:='PLD'; LastDisassembleData.parameters:='['+ArmRegisters[Rn]+','+ArmRegisters[Rm]+',LSL '+inttohex(imm2,1)+']'; end; procedure TThumbDisassembler.PLD_I_T1; var w,rn: byte; imm12: word; begin w:=(opcode shr 5) and 1; rn:=(opcode and $f); imm12:=opcode2 and $fff; if (w=1) then LastDisassembleData.opcode:='PLDW' else LastDisassembleData.opcode:='PLD'; LastDisassembleData.parameters:='['+ArmRegisters[Rn]+','+inttohex(imm12,1)+']'; end; procedure TThumbDisassembler.PLD_I_T2; var w,rn: byte; imm8: word; begin w:=(opcode shr 5) and 1; rn:=(opcode and $f); imm8:=opcode2 and $ff; if (w=1) then LastDisassembleData.opcode:='PLDW' else LastDisassembleData.opcode:='PLD'; LastDisassembleData.parameters:='['+ArmRegisters[Rn]+',-'+inttohex(imm8,1)+']'; end; procedure TThumbDisassembler.PLI_IL_T1; var rn: byte; imm12: word; begin rn:=(opcode and $f); imm12:=opcode2 and $fff; LastDisassembleData.opcode:='PLI'; LastDisassembleData.parameters:='['+ArmRegisters[Rn]+','+inttohex(imm12,1)+']'; end; procedure TThumbDisassembler.PLI_IL_T2; var rn: byte; imm8: word; begin rn:=(opcode and $f); imm8:=opcode2 and $ff; LastDisassembleData.opcode:='PLI'; LastDisassembleData.parameters:='['+ArmRegisters[Rn]+',-'+inttohex(imm8,1)+']'; end; procedure TThumbDisassembler.PLI_IL_T3; var u: byte; imm12: word; begin u:=(opcode shr 7) and $1; imm12:=opcode2 and $fff; LastDisassembleData.opcode:='PLI'; if u=0 then LastDisassembleData.parameters:='['+inttohex(align(a+4,4)-imm12,1)+']' else LastDisassembleData.parameters:='['+inttohex(align(a+4,4)+imm12,1)+']' end; procedure TThumbDisassembler.PLI_R_T1; var rn,imm2, rm: byte; begin rn:=(opcode and $f); imm2:=(opcode2 shr 4) and 3; rm:=opcode and $f; LastDisassembleData.opcode:='PLI'; LastDisassembleData.parameters:='['+ArmRegisters[Rn]+','+ArmRegisters[Rm]+',LSL '+inttohex(imm2,1)+']'; end; procedure TThumbDisassembler.LDRBT_T1; var rn, rt, imm8: byte; begin rn:=opcode and $f; rt:=(opcode2 shr 12) and $f; imm8:=opcode2 and $ff; LastDisassembleData.opcode:='LDRBT'; LastDisassembleData.parameters:=ArmRegisters[Rt]+',['+ArmRegisters[rn]+','+inttohex(imm8,1)+']'; end; procedure TThumbDisassembler.LDRHT_T1; var rn, rt, imm8: byte; begin rn:=opcode and $f; rt:=(opcode2 shr 12) and $f; imm8:=opcode2 and $ff; LastDisassembleData.opcode:='LDRHT'; LastDisassembleData.parameters:=ArmRegisters[Rt]+',['+ArmRegisters[rn]+','+inttohex(imm8,1)+']'; end; procedure TThumbDisassembler.LDRSHT_T1; var rn, rt, imm8: byte; begin rn:=opcode and $f; rt:=(opcode2 shr 12) and $f; imm8:=opcode2 and $ff; LastDisassembleData.opcode:='LDRSHT'; LastDisassembleData.parameters:=ArmRegisters[Rt]+',['+ArmRegisters[rn]+','+inttohex(imm8,1)+']'; end; procedure TThumbDisassembler.LDRSBT_T1; var rn, rt, imm8: byte; begin rn:=opcode and $f; rt:=(opcode2 shr 12) and $f; imm8:=opcode2 and $ff; LastDisassembleData.opcode:='LDRSBT'; LastDisassembleData.parameters:=ArmRegisters[Rt]+',['+ArmRegisters[rn]+','+inttohex(imm8,1)+']'; end; procedure TThumbDisassembler.NOP_T32; begin LastDisassembleData.opcode:='NOP'; LastDisassembleData.parameters:=''; end; function TThumbDisassembler.disassemble(var address: ptruint): string; var x: ptruint; i: integer; begin a:=address; setlength(LastDisassembleData.Bytes,2); {$ifdef armdev} opcode:=pword(address)^; pword(@LastDisassembleData.Bytes[0])^:=opcode; {$else} x:=0; if readprocessmemory(processhandle, pointer(address-1), @opcode, sizeof(opcode), x) then puint16(@LastDisassembleData.Bytes[0])^:=opcode; {$endif} LastDisassembleData.address:=a; LastDisassembleData.SeperatorCount:=0; LastDisassembleData.prefix:=''; LastDisassembleData.PrefixSize:=0; LastDisassembleData.opcode:=''; LastDisassembleData.parameters:=''; lastdisassembledata.isjump:=false; lastdisassembledata.iscall:=false; lastdisassembledata.isret:=false; lastdisassembledata.isconditionaljump:=false; lastdisassembledata.modrmValueType:=dvtNone; lastdisassembledata.parameterValueType:=dvtNone; lastdisassembledata.Disassembler:=dcThumb; case (opcode shr 10) of $00..$0f: begin //Shift, Add, Subtract, Move and Compare case (opcode shr 9) and $1f of $0..$b: MOV_R_T2; //000 0x xx - 000 10 xx $c: ADD_R_T1; $d: SUB_R_T1; $e: ADD_I_T1; $f: SUB_I_T1; $10..$13: MOV_I_T1; $14..$17: CMP_I_T1; $18..$1b: ADD_I_T2; $1c..$1f: SUB_I_T2; end; end; $10: begin //data Processing 010000 case (opcode shr 6) and $f of //4 bits (bit 6-9) 0: AND_R_T1; //0100000000****** 1: EOR_R_T1; 2,3,4,7: MOV_RSR_T1; //010000001x - 0100000100 - 0100000111 5: ADC_R_T1; 6: SBC_R_T1; 8: TST_R_T1; 9: RSB_I_T1; 10: CMP_R_T1; 11: CMN_R_T1; 12: ORR_R_T1; 13: MUL_R_T1; 14: BIC_R_T1; 15: MVN_R_T1; end; end; $11: begin //special Data Instructions And Branch And Exchange; case (opcode shr 6) and $f of 0..3: begin case (opcode shr 3) and $f of $D: ADD_SP_R_T1; 0,1,2,3,4,6,7: begin if ((opcode shr 7) and 1)=0 then ADD_R_T2 else begin if (opcode and 7)=5 then ADD_SP_R_T2 else ADD_R_T2; end; end; 8,9,$a,$b,$c,$e,$f: begin if ((opcode shr 7) and 1)=0 then ADD_R_T2 else begin if (opcode and 7)=5 then ADD_SP_R_T2 else ADD_R_T2; end; end; end; end; 4..7: CMP_R_T2; 8..11: MOV_R_T1; 12..13: BX_T1; 14..15: BLX_R_T1; end; end; $12..$13: LDR_L_T1; $14..$27: begin //Load Store Single Data Item; case (opcode shr 9) and $7f of $28: STR_R_T1; $29: STRH_R_T1; $2a: STRB_R_T1; $2b: LDRSB_R_T1; $2c: LDR_R_T1; $2d: LDRH_R_T1; $2e: LDRB_R_T1; $2f: LDRSH_R_T1; $30..$33: STR_I_T1; $34..$37: LDR_I_T1; $38..$3b: STRB_I_T1; $3c..$3f: LDRB_I_T1; $40..$43: STRH_I_T1; $44..$47: LDRH_I_T1; $48..$4b: STR_I_T2; $4c..$4f: LDR_I_T2; end; end; $28..$29: ADR_T1; $2a..$2b: ADD_SP_I_T1; $2c..$2f: begin //misc16 case (opcode shr 5) and $7f of $0..$3: ADD_SP_I_T2; $4..$7: SUB_SP_I_T1; $8..$f: CBZ_CBNZ; $10..$11: SXTH_T1; $12..$13: SXTB_T1; $14..$15: UXTH_T1; $16..$17: UXTB_T1; $18..$1f: CBZ_CBNZ; $20..$2f: PUSH_T1; $32: SETEND_T1; $33: CPS_T1; $48..$4f: CBZ_CBNZ; $50..$51: REV_T1; $52..$53: REV16_T1; $54..$55: HLT_T1; $56..$57: REVSH_T1; $58..$5f: CBZ_CBNZ; $60..$6f: POP_T1; $70..$77: BKPT_T1; $78..$7f: begin if (opcode and $f)<>0 then IT_T1 else case ((opcode shr 4) and $7) of 0: LastDisassembleData.opcode:='NOP'; 1: LastDisassembleData.opcode:='YIELD'; 2: LastDisassembleData.opcode:='WFE'; 3: LastDisassembleData.opcode:='WFI'; 4: LastDisassembleData.opcode:='SEV'; 5: LastDisassembleData.opcode:='SEVL'; end; end; end; end; $30..$31: STM_T1; $32..$33: LDM_T1; $34..$37: begin case (opcode shr 8) and $7 of $e: UDF_T1; $f: SVC_T1; else B_T1; end; end; $38..$39: B_T2; $3a..$3f: T32; end; result:=inttohex(LastDisassembleData.address,8)+' (THUMB)'; result:=result+' - '; if x>0 then begin for i:=0 to length(LastDisassembleData.bytes)-1 do result:=result+inttohex(LastDisassembleData.Bytes[i],2)+' '; end else begin for i:=0 to length(LastDisassembleData.bytes)-1 do result:=result+'?? '; end; result:=result+' - '; result:=result+LastDisassembleData.opcode; result:=result+' '; result:=result+LastDisassembleData.parameters; inc(address, length(LastDisassembleData.Bytes)); end; end.