cheat-engine/Cheat Engine/disassemblerthumb.pas

5281 lines
125 KiB
ObjectPascal
Executable file

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}
{$ifdef darwin}
,macport, macportdefines
{$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';
else
m:='';
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 and $fffffffe), @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;
initialization
OutputDebugString('DisassemblerThumb init'); //runs
end.