unit DisassemblerArm; {$mode objfpc}{$H+} interface {$ifdef JNI} uses unixporthelper, classes, sysutils, NewKernelHandler, LastDisassembleData, DisassemblerThumb; {$endif} {$ifdef windows} uses windows, Classes, SysUtils{$ifndef ARMDEV}, newkernelhandler, cefuncproc{$endif}, LastDisassembleData, DisassemblerThumb; {$endif} const ArmConditions: array [0..15] of string=('EQ','NE','CS', 'CC', 'MI', 'PL', 'VS', 'VC', 'HI', 'LS', 'GE', 'LT', 'GT', 'LE', '','NV'); const DataProcessingOpcodes: array [0..15] of string=('AND','EOR','SUB', 'RSB', 'ADD', 'ADC', 'SBC', 'RSC', 'TST', 'TEQ', 'CMP', 'CMN', 'ORR', 'MOV', 'BIC','MVN'); const ArmRegisters : array [0..15] of string=('R0','R1','R2','R3','R4','R5','R6','R7','R8','R9','R10','FP','IP','SP','LR','PC'); const ArmRegistersNoName : array [0..15] of string=('R0','R1','R2','R3','R4','R5','R6','R7','R8','R9','R10','R11','R12','R13','R14','R15'); function SignExtend(value: int32; mostSignificantBit: integer): int32; type TArmDisassembler=object private opcode: uint32; function Condition: string; procedure Branch; procedure BX; procedure DataProcessing; procedure MRS; procedure MSR; procedure MSR_flg; procedure Mul; procedure SingleDataTransfer; procedure LDM_STM; procedure SWP; procedure SWI; procedure CDP; public LastDisassembleData: TLastDisassembleData; function disassemble(var address: ptrUint): string; end; implementation {$ifndef ARMDEV} uses processhandlerunit; {$endif} function SignExtend(value: int32; mostSignificantBit: integer): int32; { Signextends a given offset. mostSignificant bit defines what bit determines if it should be sign extended or not } begin if (value shr mostSignificantBit)=1 then //needs to be sign extended begin //set bits 31 to mostSignificantBit to 1 result:=value or ($fffffff shl mostSignificantBit); end else result:=value; end; function TArmDisassembler.Condition: string; begin result:=ArmConditions[opcode shr 28]; end; procedure TArmDisassembler.Branch; var offset: int32; _condition: string; begin _condition:=condition; if (opcode shr 24) and 1=1 then //Link bit set begin LastDisassembleData.opcode:='BL'+Condition; LastDisassembleData.iscall:=true; end else begin LastDisassembleData.opcode:='B'+Condition; LastDisassembleData.isjump:=true; LastDisassembleData.isconditionaljump:=_condition<>''; end; offset:=signextend(opcode and $FFFFFF, 23) shl 2; LastDisassembleData.parameters:=inttohex(dword(LastDisassembleData.address+8+offset),8); end; procedure TArmDisassembler.BX; var Rn: integer; _Rn: string; _condition: string; begin _condition:=condition; LastDisassembleData.opcode:='BX'+Condition; LastDisassembleData.isjump:=true; LastDisassembleData.isconditionaljump:=_condition<>''; Rn:=opcode and $F; _Rn:=ArmRegisters[Rn]; LastDisassembleData.parameters:=_Rn; end; procedure TArmDisassembler.DataProcessing; var ImmediateOperand: integer; OpcodeIndex: integer; SetCondition: integer; Operand1: integer; Destination: integer; Operand2: integer; shift: integer; rm: integer; Rotate: integer; Imm: integer; shiftformat: integer; shiftType: integer; shiftammount: integer; shiftRegister: integer; shiftname: string; _shift: string; _opcode: string; _cond: string; _S: string; _Rd: string; _Rn: string; _rm: string; _rs: string; _op2: string; begin _opcode:=''; _cond:=''; _S:=''; _Rd:=''; _Rn:=''; _op2:=''; ImmediateOperand:=(opcode shr 25) and 1; OpcodeIndex:=(opcode shr 21) and $f; SetCondition:=(opcode shr 20) and 1; Operand1:=(opcode shr 16) and $f; Destination:=(opcode shr 12) and $f; Operand2:=opcode and $fff; _opcode:=DataProcessingOpcodes[OpcodeIndex]; _cond:=Condition; if SetCondition=1 then _s:='S'; _Rn:=ArmRegisters[Operand1]; _Rd:=ArmRegisters[Destination]; //build _op2 if ImmediateOperand=0 then //operand2 is a register begin shift:=Operand2 shr 4; rm:=operand2 and $f; _rm:=ArmRegisters[rm]; shiftformat:=shift and 1; shiftType:=(shift shr 1) and 3; case shifttype of 0: shiftname:='LSL'; 1: shiftname:='LSR'; 2: shiftname:='ASR'; 3: shiftname:='ROR'; end; _shift:=shiftname; if shiftformat=0 then begin shiftAmmount:=(shift shr (7-4)) and $1f; //7-4 because the doc describes the shift field starting from bit 4 if shiftAmmount>0 then _shift:=_shift+' '+inttohex(shiftammount,1) else _shift:=''; end else begin shiftregister:=(shift shr (8-4)) and $f; _rs:=ArmRegisters[shiftregister]; _shift:=_shift+' '+_rs; end; if _shift<>'' then _op2:=_rm+','+_shift else _op2:=_rm; end else begin //operand2 is an immediate value rotate:=Operand2 shr 8; imm:=Operand2 and $ff; _op2:=inttohex(RorDWord(imm, rotate*2),1); end; if _op2<>'' then _op2:=','+_op2; case OpcodeIndex of 13,15: begin LastDisassembleData.opcode:=_opcode+_cond+_S; LastDisassembleData.parameters:=_Rd+_op2; end; 8,9,10,11: begin LastDisassembleData.opcode:=_opcode+_cond; LastDisassembleData.parameters:=_Rn+_op2; end else begin LastDisassembleData.opcode:=_opcode+_cond+_S; LastDisassembleData.parameters:=_Rd+','+_Rn+_op2; end; end; end; procedure TArmDisassembler.MRS; var _cond: string; _rd: string; _psr: string; Ps: integer; Rd: integer; begin _cond:=Condition; Ps:=(opcode shr 22) and 1; if (Ps=0) then _psr:='CPSR' else _psr:='SPSR'; Rd:=(opcode shr 12) and $F; _rd:=ArmRegisters[rd]; LastDisassembleData.opcode:='MRS'+_cond; LastDisassembleData.parameters:=_Rd+','+_psr; end; procedure TArmDisassembler.MSR; var _cond: string; _psr: string; _Rm: string; Pd: integer; Rm: integer; I: integer; imm, rotate: integer; begin _cond:=Condition; Pd:=(opcode shr 22) and 1; if (Pd=0) then _psr:='CPSR' else _psr:='SPSR'; Rm:=opcode and $F; _rm:=ArmRegisters[rm]; LastDisassembleData.opcode:='MSR'+_cond; LastDisassembleData.parameters:=_psr+'_all,'+_Rm; end; procedure TArmDisassembler.MSR_flg; var _cond: string; _psr: string; _Rm: string; Pd: integer; Rm: integer; I: integer; imm, rotate: integer; begin _cond:=Condition; Pd:=(opcode shr 22) and 1; if (Pd=0) then _psr:='CPSR' else _psr:='SPSR'; i:=(opcode shr 25) and 1; if i=0 then begin Rm:=opcode and $F; _rm:=ArmRegisters[rm]; LastDisassembleData.opcode:='MSR'+_cond; LastDisassembleData.parameters:=_psr+'_flg,'+_Rm; end else begin rotate:=(opcode and $fff) shr 8; imm:=(opcode and $fff) and $ff; LastDisassembleData.opcode:='MSR'+_cond; LastDisassembleData.parameters:=_psr+'_flg,'+inttohex(RorDWord(imm, rotate*2),1); end; end; procedure TArmDisassembler.Mul; var _cond: string; _S: string; _rd: string; _rm: string; _rs: string; _rn: string; begin if (opcode shl 20) and 1=1 then _S:='S' else _S:=''; _cond:=Condition; _rd:=ArmRegisters[opcode shl 16 and $f]; _rn:=ArmRegisters[opcode shl 12 and $f]; _rs:=ArmRegisters[opcode shl 8 and $f]; _rm:=ArmRegisters[opcode and $f]; if (opcode shl 21) and 1=1 then begin LastDisassembleData.opcode:='MLA'+_cond+_S; LastDisassembleData.parameters:=_Rd+','+_Rm+','+_Rs+','+_Rn end else begin LastDisassembleData.opcode:='MUL'+_cond+_S; LastDisassembleData.parameters:=_Rd+','+_Rm+','+_Rs; end; end; procedure TArmDisassembler.SingleDataTransfer; var _cond: string; _opcode: string; _B: string; _T: string; _Rd: string; _Rn: string; _Rm: string; _shift: string; _U: string; I: integer; P: integer; U: integer; B: integer; W: integer; L: integer; Rn: integer; Rd: integer; Rm: integer; Offset: integer; shift: integer; shifttype: integer; _shiftname: string; _shiftAmount: string; shiftamount: integer; _address: string; begin I:=(opcode shr 25) and 1; P:=(opcode shr 24) and 1; U:=(opcode shr 23) and 1; B:=(opcode shr 22) and 1; W:=(opcode shr 21) and 1; L:=(opcode shr 20) and 1; Rn:=(opcode shr 16) and $f; Rd:=(opcode shr 12) and $f; offset:=opcode and $fff; if L=1 then _opcode:='LDR' else _opcode:='STR'; if u=0 then _U:='-' else _U:=''; _cond:=Condition; if b=1 then _B:='B' else _B:=''; if (W=1) and (p=0) then //w is set and p=0 (post indexed) _T:='T' else _T:=''; _Rd:=ArmRegisters[Rd]; _Rn:=ArmRegisters[Rn]; if i=0 then begin //offset is an immediate value if Rn=15 then //pc begin if u=0 then //decrease _address:='['+inttohex(dword(LastDisassembleData.address-offset+8),8)+']' else _address:='['+inttohex(dword(LastDisassembleData.address+offset+8),8)+']' end else begin if offset=0 then _address:='['+_Rn+']' else _address:='['+_Rn+','+_U+inttohex(dword(offset),8)+']'; end; end else begin //offset is a register Rm:=offset and $f; Shift:=offset shr 4; _Rm:=ArmRegisters[Rm]; shiftType:=(shift shr 1) and 3; case shifttype of 0: _shiftname:='LSL'; 1: _shiftname:='LSR'; 2: _shiftname:='ASR'; 3: _shiftname:='ROR'; end; shiftAmount:=(shift shr (7-4)) and $1f; if shiftAmount>0 then begin _shiftAmount:=inttohex(shiftamount,1); _shift:=', '+_U+_Rm+' '+_shiftname+' '+_shiftamount; end else begin _shiftAmount:=''; _shift:=', '+_Rm; end; if p=0 then //post index _address:='['+_Rn+']'+_shift else //preindexed _address:='['+_Rn+_shift+']'; end; if (w=1) and (p=1) then _address:=_address+'!'; LastDisassembleData.opcode:=_opcode+_cond+_B+_T; LastDisassembleData.parameters:=_Rd+','+_Address; end; procedure TArmDisassembler.LDM_STM; var P: integer; U: integer; S: integer; W: integer; L: integer; Rn: integer; RegisterList: integer; _opcode: string; _cond: string; _addressingmode: string; _rn: string; _ex: string; _exp: string; _rlist: string; i: integer; rcount: integer; begin _cond:=Condition; p:=(opcode shr 24) and 1; u:=(opcode shr 23) and 1; s:=(opcode shr 22) and 1; w:=(opcode shr 21) and 1; l:=(opcode shr 20) and 1; Rn:=(opcode shr 16) and $f; RegisterList:=opcode and $ffff; _rlist:='{'; rcount:=0; for i:=0 to 15 do begin if (RegisterList 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+'}'; if L=0 then _opcode:='STM' else _opcode:='LDM'; _rn:=ArmRegisters[Rn]; if w=1 then _ex:='!' else _ex:=''; if s=1 then _exp:='^' else _exp:=''; _addressingmode:=''; if (L=1) and (P=1) and (U=1) then begin if rn=13 then _addressingmode:='ED' else _addressingmode:='IB'; end; if (L=1) and (P=0) and (U=1) then begin if rn=13 then _addressingmode:='FD' else _addressingmode:='IA'; end; if (L=1) and (P=1) and (U=0) then begin if rn=13 then _addressingmode:='EA' else _addressingmode:='DB'; end; if (L=1) and (P=0) and (U=0) then begin if rn=13 then _addressingmode:='FA' else _addressingmode:='DA'; end; if (L=0) and (P=1) and (U=1) then begin if rn=13 then _addressingmode:='FA' else _addressingmode:='IB'; end; if (L=0) and (P=0) and (U=1) then begin if rn=13 then _addressingmode:='EA' else _addressingmode:='IA'; end; if (L=0) and (P=1) and (U=0) then begin if rn=13 then _addressingmode:='FD' else _addressingmode:='DB'; end; if (L=0) and (P=0) and (U=0) then begin if rn=13 then _addressingmode:='ED' else _addressingmode:='DA'; end; LastDisassembleData.opcode:=_opcode+_cond+_addressingmode; LastDisassembleData.parameters:=_rn+_ex+','+_rlist+_exp; end; procedure TArmDisassembler.SWP; var _cond: string; _B: string; _rd: string; _rm: string; _rn: string; begin _cond:=Condition; if (opcode shr 22) and 1=1 then _B:='1' else _B:=''; _rd:=ArmRegisters[(opcode shr 12) and $f]; _rm:=ArmRegisters[opcode and $f]; _rn:=ArmRegisters[(opcode shr 16) and $f]; LastDisassembleData.opcode:='SWP'+_cond+_B; LastDisassembleData.parameters:=_rd+','+_rm+',['+_rn+']'; end; procedure TArmDisassembler.SWI; begin LastDisassembleData.opcode:='SWI'+Condition; LastDisassembleData.parameters:=inttohex(opcode and $FFFFFF,1); end; procedure FloatingPointDataInstruction(var LastDisassembleData: TLastDisassembleData); var opcode: dword; cond: byte; t: byte; opc1, opc2, opc3, opc4: byte; condition: string; D, Vn, Vd, sz, N, M, Vm: byte; cc: byte; begin opcode:=pdword(LastDisassembleData.Bytes)^; if lastdisassembledata.Disassembler=dcArm then begin cond:=(opcode shr 28) and $f; if (cond=$f) then t:=1 else t:=0; condition:=ArmConditions[cond]; end else begin opcode:=(opcode shr 16) or (opcode shl 16); t:=(opcode shr 28) and 1; pdword(@lastdisassembledata.Bytes[0])^:=opcode; condition:=''; end; opc1:=(opcode shr 20) and $f; opc2:=(opcode shr 16) and $f; opc3:=(opcode shr 6) and 3; opc4:=opcode and $f; sz:=(opcode shr 8) and 1; D:=(opcode shr 22) and 1; Vn:=(opcode shr 16) and $f; Vd:=(opcode shr 12) and $f; N:=(opcode shr 7) and 1; M:=(opcode shr 5) and 1; Vm:=opcode and $f; if sz=0 then begin Vn:=(Vn shl 1) or N; Vm:=(Vm shl 1) or M; Vd:=(Vd shl 1) or D; LastDisassembleData.parameters:='S'+inttostr(vd)+', S'+inttostr(vn)+', S'+inttostr(Vm); end else begin Vn:=(N shl 4) or Vn; Vm:=(M shl 4) or Vm; Vd:=(D shl 4) or Vd; LastDisassembleData.parameters:='D'+inttostr(vd)+', D'+inttostr(vn)+', D'+inttostr(Vm); end; case (t shl 4) or opc1 of 0,4: if (opc3 and 1)=1 then LastDisassembleData.opcode:='VMLS' else LastDisassembleData.opcode:='VMLA'; 1,5: if (opc3 and 1)=1 then LastDisassembleData.opcode:='VNMLA' else LastDisassembleData.opcode:='VNMLS'; 2,6: if (opc3 and 1)=1 then LastDisassembleData.opcode:='VNMUL' else LastDisassembleData.opcode:='VMUL'; 3,7: if (opc3 and 1)=1 then LastDisassembleData.opcode:='VADD' else LastDisassembleData.opcode:='VSUB'; 8,12: if (opc3 and 1)=0 then LastDisassembleData.opcode:='VDIV'; 9,13: if (opc3 and 1)=1 then LastDisassembleData.opcode:='VFNMA' else LastDisassembleData.opcode:='VFNMS'; 10,14: if (opc3 and 1)=1 then LastDisassembleData.opcode:='VFMS' else LastDisassembleData.opcode:='VFMA'; 16..23: begin case (opcode shr 20) and 3 of 0: LastDisassembleData.opcode:='VSELEQ'; 1: LastDisassembleData.opcode:='VSELVS'; 2: LastDisassembleData.opcode:='VSELGE'; 3: LastDisassembleData.opcode:='VSELGT'; end; end; 24,28: if (opc3 and 1)=1 then LastDisassembleData.opcode:='VMINNM' else LastDisassembleData.opcode:='VMAXNM'; 11,15, 27, 31: begin //other: exit; end; end; if sz=0 then LastDisassembleData.opcode:=LastDisassembleData.opcode+condition+'.F32' else LastDisassembleData.opcode:=LastDisassembleData.opcode+condition+'.F64'; if lastdisassembledata.Disassembler=dcThumb then //undo the wordswap begin opcode:=(opcode shr 16) or (opcode shl 16); pdword(@lastdisassembledata.Bytes[0])^:=opcode; end; end; procedure TArmDisassembler.CDP; var CP_Opc: integer; CRn: integer; CRd: integer; CPn: integer; CP: integer; CRm: integer; _pn: string; _cd,_cn,_cm: string; _expression1,_expression2: string; begin CP_Opc:=(opcode shr 20) and $f; // CRd:=(opcode shr 12) and $f; // CRn:=(opcode shr 16) and $f; // CRm:=opcode and $f; // CPn:=(opcode shr 8) and $f; CP:=(opcode shr 5) and $7; // if (CPn in [10,11]) and ((opcode and $10)=$10) then begin FloatingPointDataInstruction(LastDisassembleData); exit; end; _expression1:=inttohex(CP_OPC,1); if cp<>0 then _expression2:=inttohex(CP,1) else _expression2:=''; _pn:=inttohex(cp,1); _cd:='c'+inttostr(CRd); _cn:='c'+inttostr(CRn); _cm:='c'+inttostr(CRm); //CDP{cond} p#,,cd,cn,cm{,} LastDisassembleData.opcode:='CDP'+Condition; LastDisassembleData.parameters:=_pn+','+_expression1+','+_cd+','+_cn+','+_cm+_expression2; end; procedure ASIMD_3RegSL(var LastDisassembleData: TLastDisassembleData); var opcode: dword; u,c,a,b: byte; d: byte; size: byte; Vn, Vd, op, N, Q, M, Vm: byte; _datatype: string; begin opcode:=pdword(LastDisassembleData.Bytes[0])^; if LastDisassembleData.Disassembler=dcThumb then u:=(opcode shr 28) and 1 else u:=(opcode shr 24) and 1; a:=(opcode shr 8) and $f; b:=(opcode shr 4) and 1; c:=(opcode shr 20) and 3; D:=(opcode shr 22) and 1; size:=(opcode shr 20) and 3; Vn:=(opcode shr 16) and $f; Vd:=(opcode shr 12) and $f; op:=(opcode shr 9) and 1; N:=(opcode shr 7) and 1; Q:=(opcode shr 6) and 1; M:=(opcode shr 5) and 1; Vm:=opcode and $f; Vn:=(N shl 4) or Vn; Vm:=(M shl 4) or Vm; Vd:=(D shl 4) or Vd; if u=0 then _datatype:='S' else _datatype:='U'; case size of 0: _datatype:=_datatype+'8'; 1: _datatype:=_datatype+'16'; 2: _datatype:=_datatype+'32'; 3: _datatype:=_datatype+'64'; //? end; if q=1 then LastDisassembleData.parameters:='.'+_datatype+' '+'D'+inttostr(vd)+', D'+inttostr(vn)+', D'+inttostr(Vm) else LastDisassembleData.parameters:='.'+_datatype+' '+'Q'+inttostr(vd)+', Q'+inttostr(vn)+', Q'+inttostr(Vm); case a of 0: if b=0 then LastDisassembleData.opcode:='VHADD' else LastDisassembleData.opcode:='VQADD'; 1: begin if b=0 then LastDisassembleData.opcode:='VRHADD' else begin case (u shl 2) or c of 0: LastDisassembleData.opcode:='VAND'; 1: LastDisassembleData.opcode:='VBIC'; 2: LastDisassembleData.opcode:='VORR'; 3: LastDisassembleData.opcode:='VORN'; 4: LastDisassembleData.opcode:='VEOR'; 5: LastDisassembleData.opcode:='VBSL'; 6: LastDisassembleData.opcode:='VBIT'; 7: LastDisassembleData.opcode:='VBIF'; end; end; end; 2: if b=0 then LastDisassembleData.opcode:='VHSUB' else LastDisassembleData.opcode:='VQSUB'; 3: if b=0 then LastDisassembleData.opcode:='VCGT' else LastDisassembleData.opcode:='VCGE'; 4: if b=0 then LastDisassembleData.opcode:='VSHL' else LastDisassembleData.opcode:='VQSHL'; 5: if b=0 then LastDisassembleData.opcode:='VRSHL' else LastDisassembleData.opcode:='VQRSHL'; 6: if b=0 then LastDisassembleData.opcode:='VMAX' else LastDisassembleData.opcode:='VMIN'; 7: if b=0 then LastDisassembleData.opcode:='VABD' else LastDisassembleData.opcode:='VABA'; 8: if b=0 then begin if u=0 then LastDisassembleData.opcode:='VADD' else LastDisassembleData.opcode:='VSUB'; end else begin if u=0 then LastDisassembleData.opcode:='VTST' else LastDisassembleData.opcode:='VCEQ'; end; 9: if b=0 then begin if u=0 then LastDisassembleData.opcode:='VMLA' else LastDisassembleData.opcode:='VMLS'; end else LastDisassembleData.opcode:='VMUL'; 10: if b=0 then LastDisassembleData.opcode:='VPMAX' else LastDisassembleData.opcode:='VPMIN'; 11: if b=0 then begin if u=0 then LastDisassembleData.opcode:='VQDMULH' else LastDisassembleData.opcode:='VQRDMULH'; end else LastDisassembleData.opcode:='VPADD'; 12: case (b shl 3) or (u shl 2) or c of 0: LastDisassembleData.opcode:='SHA1C'; 1: LastDisassembleData.opcode:='SHA1P'; 2: LastDisassembleData.opcode:='SHA1M'; 3: LastDisassembleData.opcode:='SHA1SU0'; 4: LastDisassembleData.opcode:='SHA256H'; 5: LastDisassembleData.opcode:='SHA256H2'; 6: LastDisassembleData.opcode:='SHA256SU1'; 8: LastDisassembleData.opcode:='VFMA'; 10:LastDisassembleData.opcode:='VFMS'; end; 13: case (b shl 3) or (u shl 2) or c of 0,1: LastDisassembleData.opcode:='VADD'; 2,3: LastDisassembleData.opcode:='VSUB'; 4,5: LastDisassembleData.opcode:='VPADD'; 6,7: LastDisassembleData.opcode:='VABD'; 8: LastDisassembleData.opcode:='VMLA'; 10: LastDisassembleData.opcode:='VMLS'; 12,13: LastDisassembleData.opcode:='VMUL'; end; 14: case (b shl 3) or (u shl 2) or c of 0,1: LastDisassembleData.opcode:='VCEQ'; 4,5: LastDisassembleData.opcode:='VCGE'; 6,7: LastDisassembleData.opcode:='VCGT'; 12: LastDisassembleData.opcode:='VACGE'; 14: LastDisassembleData.opcode:='VACGT'; end; 15: case (b shl 3) or (u shl 2) or c of 0: LastDisassembleData.opcode:='VMAX'; 2: LastDisassembleData.opcode:='VMIN'; 4: LastDisassembleData.opcode:='VPMAX'; 6: LastDisassembleData.opcode:='VPMIN'; 8,9: LastDisassembleData.opcode:='VRECPS'; 10,11: LastDisassembleData.opcode:='VRSQRTS'; 12: LastDisassembleData.opcode:='VMAXNM'; 14: LastDisassembleData.opcode:='VMINNM'; end; end; end; procedure ASIMD_1Reg_ModImm(var LastDisassembleData: TLastDisassembleData); var opcode: dword; a,b,c,d,cmode,op,e,f,g,h: byte; b2: byte; q: byte; Vd: byte; abcdefgh: byte; constant: qword; _dt: string; a32: dword; begin opcode:=pdword(LastDisassembleData.Bytes[0])^; if LastDisassembleData.Disassembler=dcThumb then a:=(opcode shr 28) and 1 else a:=(opcode shr 24) and 1; b:=(opcode shr 18) and 1; c:=(opcode shr 17) and 1; d:=(opcode shr 16) and 1; cmode:=(opcode shr 8) and $f; Q:=(opcode shr 6) and 1; op:=(opcode shr 5) and 1; e:=(opcode shr 3) and 1; f:=(opcode shr 2) and 1; g:=(opcode shr 1) and 1; h:=opcode and 1; Vd:=((opcode shr (22-4)) and $1) or (opcode shr 12) and $f; abcdefgh:=(a shl 7) or (b shl 6) or (c shl 5) or (d shl 4) or (e shl 3) or (f shl 2) or (g shl 1) or h; constant:=0; case cmode of 0: begin constant:=(qword(abcdefgh) shl 32) or abcdefgh; _dt:='I32'; end; 2: begin constant:=(qword(abcdefgh) shl 40) or (qword(abcdefgh) shl 8); _dt:='I32'; end; 4: begin constant:=(qword(abcdefgh) shl 48) or (qword(abcdefgh) shl 16); _dt:='I32'; end; 6: begin constant:=(qword(abcdefgh) shl 56) or (qword(abcdefgh) shl 24); _dt:='I32'; end; 8: begin constant:=(qword(abcdefgh) shl 48) or (qword(abcdefgh) shl 32) or (qword(abcdefgh) shl 16) or abcdefgh; _dt:='I16'; end; 10: begin constant:=(qword(abcdefgh) shl 56) or (qword(abcdefgh) shl 40) or (qword(abcdefgh) shl 24) or (abcdefgh shl 8); _dt:='I16'; end; 12: begin constant:=(qword(abcdefgh) shl 40) or (qword($ff) shl 32) or (qword(abcdefgh) shl 8) or ($ff); _dt:='I32'; end; 13: begin constant:=(qword(abcdefgh) shl 48) or (qword($ff) shl 40) or (qword($ff) shl 32) or (qword(abcdefgh) shl 16) or (qword($ff) shl 8) or ($ff); _dt:='I32'; end; 14: begin if op=0 then begin constant:=(qword(abcdefgh) shl 56) or (qword(abcdefgh) shl 48) or (qword(abcdefgh) shl 40) or (qword(abcdefgh) shl 32) or (qword(abcdefgh) shl 24) or (abcdefgh shl 16) or (abcdefgh shl 8); _dt:='I8'; end else begin a:=(a shl 7) or (a shl 6) or (a shl 5) or (a shl 4) or (a shl 3) or (a shl 2) or (a shl 1) or a; b:=(b shl 7) or (b shl 6) or (b shl 5) or (b shl 4) or (b shl 3) or (b shl 2) or (b shl 1) or b; c:=(c shl 7) or (c shl 6) or (c shl 5) or (c shl 4) or (c shl 3) or (c shl 2) or (c shl 1) or c; d:=(d shl 7) or (d shl 6) or (d shl 5) or (d shl 4) or (d shl 3) or (d shl 2) or (d shl 1) or d; e:=(e shl 7) or (e shl 6) or (e shl 5) or (e shl 4) or (e shl 3) or (e shl 2) or (e shl 1) or e; f:=(f shl 7) or (f shl 6) or (f shl 5) or (f shl 4) or (f shl 3) or (f shl 2) or (f shl 1) or f; g:=(g shl 7) or (g shl 6) or (g shl 5) or (g shl 4) or (g shl 3) or (g shl 2) or (g shl 1) or g; h:=(h shl 7) or (h shl 6) or (h shl 5) or (h shl 4) or (h shl 3) or (h shl 2) or (h shl 1) or h; constant:=(qword(a) shl 56) or (qword(b) shl 48) or (qword(c) shl 40) or (qword(d) shl 32) or (qword(e) shl 24) or (qword(f) shl 16) or (qword(g) shl 16) or qword(h); _dt:='I64'; end; end; 15: begin if op=0 then begin b2:=(not b) and 1; a32:=0; a32:=(a shl 31) or (b2 shl 30) or (b shl 29) or (b shl 28) or (b shl 27) or (b shl 26) or (b shl 25) or (c shl 24) or (d shl 23) or (e shl 22) or (e shl 21) or (f shl 20) or (g shl 19) or (h shl 18); constant:=(qword(a32) shl 32) or a32; end else begin constant:=qword($BADBADBADBADBAD) end; end; end; case (op shl 4) or cmode of 0,2,4,6: LastDisassembleData.opcode:='VMOV.'+_dt; 1,3,5,7: LastDisassembleData.opcode:='VORR.'+_dt; 8,10: LastDisassembleData.opcode:='VMOV.'+_dt; 9,11: LastDisassembleData.opcode:='VORR.'+_dt; 12,13,14,15: LastDisassembleData.opcode:='VMOV.'+_dt; 16,18,20,22: LastDisassembleData.opcode:='VMVN.'+_dt; 17,19,21,23: LastDisassembleData.opcode:='VBIC.'+_dt; 24,26: LastDisassembleData.opcode:='VMVN.'+_dt; 25,27: LastDisassembleData.opcode:='VBIC.'+_dt; 28,29: LastDisassembleData.opcode:='VMVN.'+_dt; 30: LastDisassembleData.opcode:='VMOV.'+_dt; end; if Q=0 then LastDisassembleData.parameters:='D'+inttostr(vd)+', '+inttohex(constant,1) else LastDisassembleData.parameters:='Q'+inttostr(vd)+', '+inttohex(constant,1); end; procedure ASIMD_2Reg_Shift(var LastDisassembleData: TLastDisassembleData); var opcode: dword; u: byte; imm3, imm6: byte; M, D,A,L,B,Q: byte; Vd, Vm: byte; size: integer; _type, _size: string; limm3: byte; imm: byte; esize: byte; elements: byte; op: byte; _dt1,_dt2: string; begin opcode:=pdword(LastDisassembleData.Bytes[0])^; imm:=0; if LastDisassembleData.Disassembler=dcThumb then u:=(opcode shr 28) and 1 else u:=(opcode shr 24) and 1; d:=(opcode shr 22) and 1; imm3:=(opcode shr 19) and $7; imm6:=(opcode shr 16) and $3f; Vd:=(opcode shr 12) and $f; a:=(opcode shr 8) and $f; op:=(opcode shr 8) and 1; l:=(opcode shr 7) and 1; b:=(opcode shr 6) and 1; q:=b; m:=(opcode shr 5) and 1; Vm:=opcode and $f; Vm:=(m shl 4) or vm; Vd:=(d shl 4) or vd; limm3:=(l shl 3) or imm3; if (limm3=0) then ASIMD_1Reg_ModImm(LastDisassembleData); _type:=''; //size: size:=8; if (limm3 and 1)=1 then size:=8 else if (limm3 and 2)=2 then size:=16 else if (limm3 and 4)=4 then size:=32 else if (limm3 and 8)=8 then size:=64; esize:=size; _size:=inttostr(size); //imm: if a in [0,1,2,3,4] then begin if size=32 then size:=64; imm:=size-imm6; end; if a in [5,6,7] then begin case size of 8: imm:=imm6-8; 16: imm:=imm6-16; 32: imm:=imm6-32; 64: imm:=imm6; end; end; //_type: if u=0 then _type:='S' else _type:='U'; if Q=0 then LastDisassembleData.parameters:='D'+inttostr(vd)+', D'+inttostr(vm)+', '+inttohex(imm,1) else LastDisassembleData.parameters:='Q'+inttostr(vd)+', Q'+inttostr(vm)+', '+inttohex(imm,1); //instruction: case A of 0: LastDisassembleData.opcode:='VSHR'+_type+_size; 1: LastDisassembleData.opcode:='VSRA'+_type+_size; 2: LastDisassembleData.opcode:='VRSHR'+_type+_size; 3: LastDisassembleData.opcode:='VRSRA'+_type+_size; 4: if u=1 then LastDisassembleData.opcode:='VSRI'+_size; 5: if u=0 then LastDisassembleData.opcode:='VSHL.I'+_size else LastDisassembleData.opcode:='VSLI'+_type+_size; 6: LastDisassembleData.opcode:='VQSHLU'+_type+_size; 7: LastDisassembleData.opcode:='VQSHL'+_type+_size; 8: begin size:=size*2; _size:=inttostr(size); imm:=size-imm6; LastDisassembleData.parameters:='D'+inttostr(vd)+', Q'+inttostr(vm)+', '+inttohex(imm,1); case (u shl 3) or (b shl 2) or l of 0: LastDisassembleData.opcode:='VSHRN.I'+_size; 2: LastDisassembleData.opcode:='VRSHRN.I'+_size; 4: LastDisassembleData.opcode:='VQSHRUN.I'+_type+_size; 6: LastDisassembleData.opcode:='VQRSHRUN.I'+_type+_size; end; end; 9: begin size:=size*2; _size:=inttostr(size); imm:=size-imm6; LastDisassembleData.parameters:='D'+inttostr(vd)+', Q'+inttostr(vm)+', '+inttohex(imm,1); case (b shl 2) or l of 0: LastDisassembleData.opcode:='VSHRN.I'+_size; 2: LastDisassembleData.opcode:='VRSHRN.I'+_size; end; end; 10: begin if (b=0) and (l=0) then begin imm:=imm6-esize; if imm=0 then begin LastDisassembleData.parameters:='D'+inttostr(vd)+', Q'+inttostr(vm); LastDisassembleData.opcode:='VMOVL'; end else begin LastDisassembleData.parameters:='D'+inttostr(vd)+', Q'+inttostr(vm)+', '+inttohex(imm,1); LastDisassembleData.opcode:='VSHLL'+_type+_size; end; end; end; 14,15: begin case (op shl 1) or U of 0: begin _dt1:='F32'; _dt2:='S32'; end; 1: begin _dt1:='F32'; _dt2:='U32'; end; 2: begin _dt1:='S32'; _dt2:='F32'; end; 3: begin _dt1:='U32'; _dt2:='F32'; end; end; LastDisassembleData.opcode:='VCVT.'+_dt1+'.'+_dt2; if Q=0 then LastDisassembleData.parameters:='D'+inttostr(vd)+', D'+inttostr(vm)+', '+inttohex(64-imm6,1) else LastDisassembleData.parameters:='Q'+inttostr(vd)+', Q'+inttostr(vm)+', '+inttohex(64-imm6,1) end; end; end; procedure ASIMD_3Reg_DL(var LastDisassembleData: TLastDisassembleData); var opcode: dword; u,b,a: byte; d, size, Vn, Vd, op, N,M, Vm: byte; _datatype: string; begin opcode:=pdword(LastDisassembleData.Bytes[0])^; if LastDisassembleData.Disassembler=dcThumb then u:=(opcode shr 28) and 1 else u:=(opcode shr 24) and 1; b:=(opcode shr 20) and 3; a:=(opcode shr 8) and $f; D:=(opcode shr 22) and 1; size:=(opcode shr 20) and 3; Vn:=(opcode shr 16) and $f; Vd:=(opcode shr 12) and $f; op:=(opcode shr 9) and 1; N:=(opcode shr 7) and 1; M:=(opcode shr 5) and 1; Vm:=opcode and $f; Vn:=(N shl 4) or Vn; Vm:=(M shl 4) or Vm; Vd:=(D shl 4) or Vd; if u=0 then _datatype:='S' else _datatype:='U'; case size of 0: _datatype:=_datatype+'8'; 1: _datatype:=_datatype+'16'; 2: _datatype:=_datatype+'32'; 3: _datatype:=_datatype+'64'; //? end; LastDisassembleData.parameters:='.'+_datatype+' '+'Q'+inttostr(vd)+', D'+inttostr(vn)+', D'+inttostr(Vm); case a of 0: LastDisassembleData.opcode:='VADDL'; 1: begin LastDisassembleData.opcode:='VADDW'; LastDisassembleData.parameters:='.'+_datatype+' '+'Q'+inttostr(vd)+', Q'+inttostr(vn)+', D'+inttostr(Vm); end; 2: LastDisassembleData.opcode:='VSUBL'; 3: begin LastDisassembleData.opcode:='VSUBL'; LastDisassembleData.parameters:='.'+_datatype+' '+'Q'+inttostr(vd)+', Q'+inttostr(vn)+', D'+inttostr(Vm); end; 4: if u=0 then LastDisassembleData.opcode:='VADDHN' else LastDisassembleData.opcode:='VRADDHN'; 5: LastDisassembleData.opcode:='VABAL'; 6: if u=0 then LastDisassembleData.opcode:='VSUBHN' else LastDisassembleData.opcode:='VRSUBHN'; 7: LastDisassembleData.opcode:='VABDL'; 8: LastDisassembleData.opcode:='VMLAL'; 9: if u=0 then LastDisassembleData.opcode:='VQDMLAL'; 10: LastDisassembleData.opcode:='VMLSL'; 11: LastDisassembleData.opcode:='VQDMLSL'; 12,14: LastDisassembleData.opcode:='VMULL'; 13: LastDisassembleData.opcode:='VQDMULL'; end; end; procedure ASIMD_2Reg_Scalar(var LastDisassembleData: TLastDisassembleData); var opcode: dword; q,u,b,a: byte; d, size, Vn, Vd, op, F,N,M, Vm: byte; _datatype: string; begin opcode:=pdword(LastDisassembleData.Bytes[0])^; if LastDisassembleData.Disassembler=dcThumb then u:=(opcode shr 28) and 1 else u:=(opcode shr 24) and 1; q:=u; b:=(opcode shr 20) and 3; a:=(opcode shr 8) and $f; D:=(opcode shr 22) and 1; size:=(opcode shr 20) and 3; Vn:=(opcode shr 16) and $f; Vd:=(opcode shr 12) and $f; op:=(opcode shr 9) and 1; F:=(opcode shr 8) and 1; N:=(opcode shr 7) and 1; M:=(opcode shr 5) and 1; Vm:=opcode and $f; Vn:=(N shl 4) or Vn; Vm:=(M shl 4) or Vm; Vd:=(D shl 4) or Vd; case size of 0: _datatype:='8'; 1: _datatype:='16'; 2: _datatype:='32'; 3: _datatype:='64'; //? end; case a of 0,1: begin if F=0 then _datatype:='I'+_datatype else _datatype:='F'+_datatype; LastDisassembleData.parameters:='.'+_datatype+' '+'Q'+inttostr(vd)+', D'+inttostr(vn)+', D'+inttostr(Vm); LastDisassembleData.opcode:='VMLA'; end; 2: begin if U=0 then _datatype:='S'+_datatype else _datatype:='U'+_datatype; LastDisassembleData.parameters:='.'+_datatype+' '+'Q'+inttostr(vd)+', D'+inttostr(vn)+', D'+inttostr(Vm); LastDisassembleData.opcode:='VMLAL'; end; 3: begin _datatype:='S'+_datatype; LastDisassembleData.parameters:='.'+_datatype+' '+'Q'+inttostr(vd)+', D'+inttostr(vn)+', D'+inttostr(Vm); LastDisassembleData.opcode:='VQDMLAL'; end; 4,5: begin if F=0 then _datatype:='I'+_datatype else _datatype:='F'+_datatype; LastDisassembleData.parameters:='.'+_datatype+' '+'Q'+inttostr(vd)+', D'+inttostr(vn)+', D'+inttostr(Vm); LastDisassembleData.opcode:='VMLA'; end; 6: begin if U=0 then _datatype:='S'+_datatype else _datatype:='U'+_datatype; LastDisassembleData.parameters:='.'+_datatype+' '+'Q'+inttostr(vd)+', D'+inttostr(vn)+', D'+inttostr(Vm); LastDisassembleData.opcode:='VMLSL'; end; 7: begin _datatype:='S'+_datatype; LastDisassembleData.parameters:='.'+_datatype+' '+'Q'+inttostr(vd)+', D'+inttostr(vn)+', D'+inttostr(Vm); LastDisassembleData.opcode:='VQDMLSL'; end; 8,9: begin if F=0 then _datatype:='I'+_datatype else _datatype:='F'+_datatype; if q=1 then LastDisassembleData.parameters:='.'+_datatype+' '+'D'+inttostr(vd)+', D'+inttostr(vn)+', D'+inttostr(Vm) else LastDisassembleData.parameters:='.'+_datatype+' '+'Q'+inttostr(vd)+', Q'+inttostr(vn)+', D'+inttostr(Vm); LastDisassembleData.opcode:='VMUL'; end; 10: begin if U=0 then _datatype:='S'+_datatype else _datatype:='U'+_datatype; LastDisassembleData.parameters:='.'+_datatype+' '+'Q'+inttostr(vd)+', D'+inttostr(vn)+', D'+inttostr(Vm); LastDisassembleData.opcode:='VMULL'; end; 11: begin _datatype:='S'+_datatype; LastDisassembleData.parameters:='.'+_datatype+' '+'Q'+inttostr(vd)+', D'+inttostr(vn)+', D'+inttostr(Vm); LastDisassembleData.opcode:='VQDMULL'; end; 12: begin _datatype:='S'+_datatype; if q=1 then LastDisassembleData.parameters:='.'+_datatype+' '+'D'+inttostr(vd)+', D'+inttostr(vn)+', D'+inttostr(Vm) else LastDisassembleData.parameters:='.'+_datatype+' '+'Q'+inttostr(vd)+', Q'+inttostr(vn)+', D'+inttostr(Vm); LastDisassembleData.opcode:='VQDMULH'; end; 13: begin _datatype:='S'+_datatype; if q=1 then LastDisassembleData.parameters:='.'+_datatype+' '+'D'+inttostr(vd)+', D'+inttostr(vn)+', D'+inttostr(Vm) else LastDisassembleData.parameters:='.'+_datatype+' '+'Q'+inttostr(vd)+', Q'+inttostr(vn)+', D'+inttostr(Vm); LastDisassembleData.opcode:='VQRDMULH'; end; end; end; procedure VEXT(var LastDisassembleData: TLastDisassembleData); var opcode: dword; D, Vn, Vd, imm4, N, Q, M, Vm: byte; begin opcode:=pdword(LastDisassembleData.Bytes[0])^; D:=(opcode shr 22) and 1; Vn:=(opcode shr 16) and $f; Vd:=(opcode shr 12) and $f; imm4:=(opcode shr 8) and $f; N:=(opcode shr 7) and 1; Q:=(opcode shr 6) and 1; M:=(opcode shr 5) and 1; Vm:=opcode and $f; Vn:=(N shl 4) or Vn; Vm:=(M shl 4) or Vm; Vd:=(D shl 4) or Vd; if q=0 then LastDisassembleData.parameters:='D'+inttostr(vd)+', D'+inttostr(Vn)+', D'+inttostr(Vm)+' '+inttohex(imm4,1) else LastDisassembleData.parameters:='D'+inttostr(vd)+', D'+inttostr(Vn)+', D'+inttostr(Vm)+' '+inttohex(imm4,1); LastDisassembleData.opcode:='VEXT.8'; end; procedure ASIMD_2Reg_Misc(var LastDisassembleData: TLastDisassembleData); var opcode: dword; u,b,a: byte; q,d, size, Vn, Vd, op, F,N,M, Vm: byte; sz: byte; _dt, _dt2: string; _sU, _sf: string; begin opcode:=pdword(LastDisassembleData.Bytes[0])^; if LastDisassembleData.Disassembler=dcThumb then u:=(opcode shr 28) and 1 else u:=(opcode shr 24) and 1; b:=(opcode shr 6) and $1f; a:=(opcode shr 16) and $3; D:=(opcode shr 22) and 1; size:=(opcode shr 18) and 3; Vn:=(opcode shr 16) and $f; Vd:=(opcode shr 12) and $f; op:=(opcode shr 7) and 1; F:=(opcode shr 10) and 1; N:=(opcode shr 7) and 1; Q:=(opcode shr 6) and 1; M:=(opcode shr 5) and 1; Vm:=opcode and $f; Vn:=(N shl 4) or Vn; Vm:=(M shl 4) or Vm; Vd:=(D shl 4) or Vd; case size of 0: _dt:='8'; 1: _dt:='16'; 2: _dt:='32'; 3: _dt:='64'; end; case size of 0: _dt2:='16'; 1: _dt2:='32'; 2: _dt2:='64'; end; if op=0 then _SU:='S' else _sU:='U'; if f=0 then _sf:='S' else _sf:='F'; case a of 0: begin case b of 0..11, 16..31: if q=0 then LastDisassembleData.parameters:='D'+inttostr(vd)+', D'+inttostr(Vm) else LastDisassembleData.parameters:='Q'+inttostr(vd)+', Q'+inttostr(Vm); 12..15: LastDisassembleData.parameters:='Q'+inttostr(vd)+', Q'+inttostr(Vm); end; case b of 0,1: LastDisassembleData.opcode:='VREV64.'+_dt; 2,3: LastDisassembleData.opcode:='VREV32.'+_dt; 4,5: LastDisassembleData.opcode:='VREV16.'+_dt; 8..11: LastDisassembleData.opcode:='VPADDL.'+_sU+_dt; 12: LastDisassembleData.opcode:='AESE.'+_dt; 13: LastDisassembleData.opcode:='AESD.'+_dt; 14: LastDisassembleData.opcode:='AESMC.'+_dt; 15: LastDisassembleData.opcode:='AESIMC.'+_dt; 16,17: LastDisassembleData.opcode:='VCLS.S'+_dt; 18,19: LastDisassembleData.opcode:='VCLZ.I'+_dt; 20,21: LastDisassembleData.opcode:='VCNT.8'; 22,23: LastDisassembleData.opcode:='VMVN'; 24,27: LastDisassembleData.opcode:='VPADAL.'+_sU+_dt; 28,29: LastDisassembleData.opcode:='VQABS.S'+_dt; 30,31: LastDisassembleData.opcode:='VQNEG.S'+_dt; end; end; 1: begin case (b shr 1) and 7 of 0..4: if q=0 then LastDisassembleData.parameters:='D'+inttostr(vd)+', D'+inttostr(Vm)+', 0' else LastDisassembleData.parameters:='Q'+inttostr(vd)+', Q'+inttostr(Vm)+', 0'; 5: LastDisassembleData.parameters:='Q'+inttostr(vd)+', Q'+inttostr(Vm); 6,7: if q=0 then LastDisassembleData.parameters:='D'+inttostr(vd)+', D'+inttostr(Vm) else LastDisassembleData.parameters:='Q'+inttostr(vd)+', Q'+inttostr(Vm); end; case (b shr 1) and 7 of 0: LastDisassembleData.opcode:='VCGT.'+_sf+_dt; 1: LastDisassembleData.opcode:='VCGE.'+_sf+_dt; 2: LastDisassembleData.opcode:='VCEQ.'+_sf+_dt; 3: LastDisassembleData.opcode:='VCLE.'+_sf+_dt; 4: LastDisassembleData.opcode:='VCLT.'+_sf+_dt; 5: LastDisassembleData.opcode:='SHA1H.32'; 6: LastDisassembleData.opcode:='VABS'+_sf+_dt; 7: LastDisassembleData.opcode:='VNEG.'+_sf+_dt; end; end; 2: begin if q=0 then LastDisassembleData.parameters:='D'+inttostr(vd)+', D'+inttostr(Vm) else LastDisassembleData.parameters:='Q'+inttostr(vd)+', Q'+inttostr(Vm); case b of 0,1: LastDisassembleData.opcode:='VSWP'; 2,3: LastDisassembleData.opcode:='VTRN.'+_dt; 4,5: LastDisassembleData.opcode:='VUZP.'+_dt; 6,7: LastDisassembleData.opcode:='VZIP.'+_dt; 8: begin LastDisassembleData.opcode:='VMOVN.I'+_dt; LastDisassembleData.parameters:='D'+inttostr(vd)+', Q'+inttostr(Vm); end; 9: begin LastDisassembleData.opcode:='VQMOVUN.S'+_dt2; LastDisassembleData.parameters:='D'+inttostr(vd)+', Q'+inttostr(Vm); end; 10: begin LastDisassembleData.opcode:='VQMOVN.S'+_dt2; LastDisassembleData.parameters:='D'+inttostr(vd)+', Q'+inttostr(Vm); end; 11: begin if size=0 then _dt:='8'; LastDisassembleData.opcode:='VQMOVN.U'+_dt2; LastDisassembleData.parameters:='D'+inttostr(vd)+', Q'+inttostr(Vm); end; 12: begin LastDisassembleData.opcode:='VSHLL'; LastDisassembleData.parameters:='Q'+inttostr(vd)+', D'+inttostr(Vm)+', '+inttohex(size,1); end; 14: begin LastDisassembleData.opcode:='SHA1SU1.32'; LastDisassembleData.parameters:='Q'+inttostr(vd)+', Q'+inttostr(Vm); end; 15: begin LastDisassembleData.opcode:='SHA1SU0.32'; LastDisassembleData.parameters:='Q'+inttostr(vd)+', Q'+inttostr(vn)+', Q'+inttostr(Vm); end; 16, 17: LastDisassembleData.opcode:='VRINTN.F32.F32'; 18, 19: LastDisassembleData.opcode:='VRINTX.F32.F32'; 20, 21: LastDisassembleData.opcode:='VRINTA.F32.F32'; 22, 23: LastDisassembleData.opcode:='VRINTZ.F32.F32'; 26, 27: LastDisassembleData.opcode:='VRINTM.F32.F32'; 30, 31: LastDisassembleData.opcode:='VRINTP.F32.F32'; 24: begin LastDisassembleData.opcode:='VCVT.F16.F32'; LastDisassembleData.parameters:='D'+inttostr(vd)+', Q'+inttostr(Vm); end; 28: begin LastDisassembleData.opcode:='VCVT.F32.F16'; LastDisassembleData.parameters:='Q'+inttostr(vd)+', D'+inttostr(Vm); end; end; end; 3: begin if q=0 then LastDisassembleData.parameters:='D'+inttostr(vd)+', D'+inttostr(Vm) else LastDisassembleData.parameters:='Q'+inttostr(vd)+', Q'+inttostr(Vm); case b shr 2 of 0: LastDisassembleData.opcode:='VCVTA.F32'; 1: LastDisassembleData.opcode:='VCVTN.F32'; 2: LastDisassembleData.opcode:='VCVTP.F32'; 3: LastDisassembleData.opcode:='VCVTN.F32'; 4,5: begin if ((b shr 1) and 1)=0 then LastDisassembleData.opcode:='VRECPE' else LastDisassembleData.opcode:='VRSQRTE'; if f=1 then LastDisassembleData.opcode:=LastDisassembleData.opcode+'F32' else LastDisassembleData.opcode:=LastDisassembleData.opcode+'S32'; end; 6,7: begin case (opcode shr 7) and 3 of 0: LastDisassembleData.opcode:='VCVT.F32.S32'; 1: LastDisassembleData.opcode:='VCVT.F32.U32'; 2: LastDisassembleData.opcode:='VCVT.S32.F32'; 3: LastDisassembleData.opcode:='VCVT.U32.F32'; end; end; end; end; end; end; procedure VTBL_VTBLX(var LastDisassembleData: TLastDisassembleData); var opcode: dword; D, Vn, Vd, len, N, op, M, Vm: byte; _list: string; i: integer; begin opcode:=pdword(LastDisassembleData.Bytes[0])^; D:=(opcode shr 22) and 1; Vn:=(opcode shr 16) and $f; Vd:=(opcode shr 12) and $f; len:=(opcode shr 8) and 3; N:=(opcode shr 7) and 1; op:=(opcode shr 6) and 1; M:=(opcode shr 5) and 1; Vm:=opcode and $f; Vn:=(N shl 4) or Vn; Vm:=(M shl 4) or Vm; Vd:=(D shl 4) or Vd; for i:=0 to len-1 do begin _list:=_list+'D'+inttostr(Vn+i); if i9) then DataProcessing else if (opcode shr 26) and 3=1 then SingleDataTransfer else if (opcode shr 25) and 7=4 then LDM_STM else if ((opcode shr 23) and $1f=2) and ((opcode shr 20) and $3=0) and ((opcode shr 4) and $ff=9) then SWP else if (opcode shr 24) and $F=$F then SWI else if (((opcode shr 24) and $F)=$E) and (((opcode shr 4) and 1)=1) then CDP else if (opcode shr 25) and $7f=$79 then Advanced_SIMD_Data_Processing(LastDisassembleData); //if (((opcode shr 24) and $f)=$E) and ((opcode shr 9) and $3=5) and ((opcode shr 4) and 1) = 1 end else LastDisassembleData.opcode:='??'; result:=inttohex(LastDisassembleData.address,8); 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,4); end; end.