lazarus/components/fpdebug/fpdbgdisasxtensa.pas
2025-03-02 11:23:28 +01:00

1089 lines
48 KiB
ObjectPascal

{ $Id$ }
{
---------------------------------------------------------------------------
fpdbgdisasxtensa.pp - Native Freepascal debugger - xtensa Disassembler
---------------------------------------------------------------------------
This unit contains an xtensa disassembler for the Native Freepascal debugger
---------------------------------------------------------------------------
@created(Thu Sep 2nd 2021)
@lastmod($Date$)
@author()
***************************************************************************
* *
* This source is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This code is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* General Public License for more details. *
* *
* A copy of the GNU General Public License is available on the World *
* Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also *
* obtain it by writing to the Free Software Foundation, *
* Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA. *
* *
***************************************************************************
}
unit FpDbgDisasXtensa;
{$mode objfpc}{$H+}
interface
uses
SysUtils,
FpDbgUtil, FpDbgInfo, DbgIntfBaseTypes, FpdMemoryTools, {$ifdef FORCE_LAZLOGGER_DUMMY} LazLoggerDummy {$else} LazLoggerBase {$endif},
FpDbgClasses;
type
//The function Disassemble decodes the instruction at the given address.
//Unrecognized instructions are assumed to be data statements [dw XXXX]
TXtensaAsmDecoder = class;
TXtensaOpCode = (
A_ABS, A_ADD, A_ADDI, A_ADDMI, A_ADDX2, A_ADDX4, A_ADDX8, A_ALL4, A_ALL8,
A_AND, A_ANDB, A_ANDBC, A_ANY4, A_ANY8, A_B, A_BREAK, A_CALL0, A_CALL4,
A_CALL8, A_CALL12, A_CALLX0, A_CALLX4, A_CALLX8, A_CALLX12, A_CEIL,
A_CLAMPS, A_DHI, A_DHU, A_DHWB, A_DHWBI, A_DII, A_DIU, A_DIWB, A_DIWBI,
A_DPFL, A_DPFR, A_DPFRO, A_DPW, A_DPWO, A_DSYNC, A_ENTRY, A_ESYNC, A_EXCW,
A_EXTUI, A_EXTW, A_FLOAT, A_FLOOR, A_IDTLB, A_IHI, A_IHU, A_III, A_IITLB,
A_IIU, A_ILL, A_IPF, A_IPFL, A_ISYNC, A_J, A_JX, A_L8UI, A_L16SI, A_L16UI,
A_L32AI, A_L32E, A_L32I, A_L32R, A_LDCT, A_LDDEC, A_LDINC, A_LICT, A_LICW,
A_LOOP, A_LOOPGTZ, A_LOOPNEZ, A_LSI, A_LSIU, A_LSX, A_LSXU, A_MADD, A_MAX,
A_MAXU, A_MEMW, A_MIN, A_MINU, A_MOV, A_MOVEQZ, A_MOVF, A_MOVGEZ, A_MOVI,
A_MOVLTZ, A_MOVNEZ, A_MOVSP, A_MOVT, A_MSUB, A_MUL, A_MUL16, A_MULA, A_MULL,
A_MULS, A_MULSH, A_MULUH, A_NEG, A_NOP, A_NSA, A_NSAU, A_OEQ, A_OLE, A_OLT,
A_OR, A_ORB, A_ORBC, A_PDTLB, A_PITLB, A_QUOS, A_QUOU, A_RDTLB0, A_RDTLB1,
A_REMS, A_REMU, A_RET, A_RETW, A_RFDD, A_RFDE, A_RFE, A_RFI, A_RFME, A_RFR,
A_RFUE, A_RFWO, A_RFWU, A_RITLB0, A_RITLB1, A_ROTW, A_ROUND, A_RSIL, A_RSR,
A_RUR, A_S8I, A_S16I, A_S32C1I, A_S32E, A_S32I, A_S32RI, A_SDCT, A_SEXT,
A_SICT, A_SICW, A_SIMCALL, A_SLL, A_SLLI, A_SRA, A_SRAI, A_SRC, A_SRL,
A_SRLI, A_SSA8B, A_SSA8L, A_SSAI, A_SSI, A_SSIU, A_SSL, A_SSR, A_SSX,
A_SSXU, A_SUB, A_SUBX2, A_SUBX4, A_SUBX8, A_SYSCALL, A_TRUNC, A_UEQ,
A_UFLOAT, A_ULE, A_ULT, A_UMUL, A_UN, A_UTRUNC, A_WAITI, A_WDTLB, A_WER,
A_WFR, A_WITLB, A_WSR, A_WUR, A_XOR, A_XORB, A_XSR, A_INVALID);
TAVRInstruction = record
OpCode: TXtensaOpCode;
OpCodeMod: integer; // Use as index to general opcode modifiers, typically in range 0..7
Size: integer;
Oper: array[1..2] of integer;
end;
{ TXtensaAsmInstruction }
TXtensaAsmInstruction = class(TDbgAsmInstruction)
private const
INSTR_CODEBIN_LEN = 4;
private
FAsmDecoder: TXtensaAsmDecoder;
FAddress: TDBGPtr;
FCodeBin: array[0..INSTR_CODEBIN_LEN-1] of byte;
FFlags: set of (diCodeRead, diCodeReadError);
protected
procedure ReadCode; inline;
public
constructor Create(AAsmDecoder: TXtensaAsmDecoder);
procedure SetAddress(AnAddress: TDBGPtr);
function IsCallInstruction: boolean; override;
function IsReturnInstruction: boolean; override;
function IsLeaveStackFrame: boolean; override;
function InstructionLength: Integer; override;
end;
{ TXtensaAsmDecoder }
TXtensaAsmDecoder = class(TDbgAsmDecoder)
public type
TCallType = (ctCall0, ctCall4, ctCall8, ctCall12, ct_CallUnknown);
private const
MaxPrologueSize = 63; // Bytes, so ~22 instructions
MaxEpilogueSize = MaxPrologueSize; // Perhaps a bit smaller, since the locals/parameters do not have to be initialized
MAX_CODEBIN_LEN = MaxPrologueSize; // About 22 instructions
private
FProcess: TDbgProcess;
FLastErrWasMem: Boolean;
FCodeBin: array[0..MAX_CODEBIN_LEN-1] of byte;
FLastInstr: TXtensaAsmInstruction;
function FParsePrologue(AnAddress, AStartPC, AEndPC: TDBGPtr; ACallType: TCallType; out
returnAddressOffset: word; out AnIsOutsideFrame: Boolean): Boolean;
function FParseEpilogue(AnAddress, AStartPC, AEndPC: TDBGPtr; out
returnAddressOffset: word; out AnIsOutsideFrame: Boolean): Boolean;
protected
function GetLastErrorWasMemReadErr: Boolean; override;
function GetMaxInstrSize: integer; override;
function GetMinInstrSize: integer; override;
function GetCanReverseDisassemble: boolean; override;
function ReadCodeAt(AnAddress: TDBGPtr; var ALen: Cardinal): Boolean; inline;
public
procedure Disassemble(var AAddress: Pointer; out ACodeBytes: String; out ACode: String); override;
function GetInstructionInfo(AnAddress: TDBGPtr): TDbgAsmInstruction; override;
// Rather use GetFunctionFrameReturnAddress
function GetFunctionFrameInfo(AnAddress: TDBGPtr; out
AnIsOutsideFrame: Boolean): Boolean; override;
function GetBreakInstruction(const ALocation: TDBGPtr; out
BreakInstructionLength: Integer): QWord;
function BreakInstructionOffset: Int8;
// AStartPC & AEndPC indicates proc limits to help with scanning for prologue/epilogue
function GetFunctionFrameReturnAddress(AnAddress, AStartPC, AEndPC: TDBGPtr; ACallType: TCallType; out
returnAddressOffset: word; out AnIsOutsideFrame: Boolean): Boolean;
constructor Create(AProcess: TDbgProcess); override;
destructor Destroy;
end;
implementation
uses
StrUtils, LazClasses, Math;
var
DBG_WARNINGS: PLazLoggerLogGroup;
const
op = '%s';
op_a1 = '%s a%d';
op_c1 = '%s %d';
op_x1 = '%s %x';
op_a1a2 = '%s a%d, a%d';
op_a1b2 = '%s a%d, b%d';
op_a1c2 = '%s a%d, %d';
op_a1f2 = '%s a%d, f%d';
op_a1m2 = '%s a%d, m%d';
op_a1x2 = '%s a%d, %x';
op_b1b2 = '%s b%d, b%d';
op_b1c2 = '%s b%d, %d';
op_c1c2 = '%s %d, %d';
op_f1f2 = '%s f%d, f%d';
op_f1a2 = '%s f%d, a%d';
op_f1c2 = '%s f%d, %d';
op_m1m2 = '%s m%d, m%d';
op_m1a2 = '%s m%d, a%d';
op_a1a2a3 = '%s a%d, a%d, a%d';
op_a1a2b3 = '%s a%d, a%d, b%d';
op_a1a2c3 = '%s a%d, a%d, %d';
op_a1a2x3 = '%s a%d, a%d, %x';
op_a1c2c3 = '%s a%d, %d, %d';
op_a1c2x3 = '%s a%d, %d, %x';
op_a1f2c3 = '%s a%d, f%d, %d';
op_b1b2b3 = '%s b%d, b%d, b%d';
op_b1f2f3 = '%s b%d, f%d, f%d';
op_f1f2b3 = '%s f%d, f%d, b%d';
op_f1f2c3 = '%s f%d, f%d, %d';
op_f1f2f3 = '%s f%d, f%d, f%d';
op_f1f2a3 = '%s f%d, f%d, a%d';
op_f1a2b3 = '%s f%d, a%d, b%d';
op_f1a2c3 = '%s f%d, a%d, %d';
op_f1a2a3 = '%s f%d, a%d, a%d';
op_m1a2m3m4 = '%s m%d, a%d, m%d, m%d';
op_m1a2m3r4 = '%s m%d, a%d, m%d, m%d';
op_a1a2c3c4 = '%s a%d, a%d, %d, %d';
hreg: array of string = ('ll', 'hl', 'lh', 'hh');
callID: array of string = ('call0', 'call4', 'call8', 'call12');
b4const_signed: array of integer = (-1, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 16, 32, 64, 128, 256);
b4const_unsigned: array of integer = (32768, 65536, 2, 3, 4, 5, 6, 7, 8, 10, 12, 16, 32, 64, 128, 256);
OpCodeNOP = $0000;
OpCodeLoadSPL = $B7CD; // in r28, 0x3d
OpCodeLoadSPH = $B7DE; // in r29, 0x3e
OpCodeLoadSRegR0 = $B60F; // in r0, 0x3f
OpCodeLoadSRegR16 = $B70F; // in r16, 0x3f, avrtiny subarch
OpCodeCli = $94F8; // cli
OpCodeSetSPH = $BFDE; // out 0x3e, r29
OpCodeSetSPL = $BFCD; // out 0x3d, r28
OpCodeSetSregR0 = $BE0F; // out 0x3f, r0
OpCodeSetSregR16 = $BF0F; // out 0x3f, r16
OpCodeRet = $9508; // ret
OpCodeReti = $9518; // reti
// Zero register gets zeroed at start of interrupt
OpCodeZeroR1 = $2411; // eor r1, r1
OpCodeZeroR16 = $2700; // eor r16, r16
OpCodePushMask = $920F; // PUSH 1001 001d dddd 1111
OpCodePopMask = $900F; // POP 1001 000d dddd 1111
// Frame pointer is r28:r29, so fix register index in opcode
OpCodeAdjustFrameLMask = $50C0; // subi r28, k, 0101 kkkk dddd kkkk, rd = 16 + d
OpCodeAdjustFrameHMask = $40D0; // sbci r28, k, 0100 kkkk dddd kkkk, rd = 16 + d
// Not yet implemented in FPC, but more compact option
OpCodeAdjustFrameMask = $9720; // sbiw r28, k, 1001 0111 kkdd kkkk, rd = 24 + d*2
OpCodeStoreOnStackMask = $8208; // std Y+2, r24 10q0 qq1r rrrr 1qqq
{ TXtensaAsmInstruction }
procedure TXtensaAsmInstruction.ReadCode;
begin
if not (diCodeRead in FFlags) then begin
if not FAsmDecoder.FProcess.ReadData(FAddress, INSTR_CODEBIN_LEN, FCodeBin) then
Include(FFlags, diCodeReadError);
Include(FFlags, diCodeRead);
end;
end;
constructor TXtensaAsmInstruction.Create(AAsmDecoder: TXtensaAsmDecoder);
begin
FAsmDecoder := AAsmDecoder;
inherited Create;
AddReference;
end;
procedure TXtensaAsmInstruction.SetAddress(AnAddress: TDBGPtr);
begin
FAddress := AnAddress;
FFlags := [];
end;
function TXtensaAsmInstruction.IsCallInstruction: boolean;
var
op0, op1, op2, r, m: byte;
begin
Result := False;
ReadCode;
op0 := lo(FCodeBin[0]);
op1 := lo(FCodeBin[2]);
op2 := hi(FCodeBin[2]);
r := hi(FCodeBin[1]);
m := FCodeBin[0] shr 6;
if ((op0 = 0) and (op1 = 0) and (op2 = 0) and
(r = 0) and (m = 3)) or // callx
(op0 = 5) then // call
Result := true;
end;
function TXtensaAsmInstruction.IsReturnInstruction: boolean;
var
op0, op1, op2, r, t, m, n: byte;
begin
Result := False;
ReadCode;
op0 := lo(FCodeBin[0]);
op1 := lo(FCodeBin[2]);
op2 := hi(FCodeBin[2]);
r := hi(FCodeBin[1]);
t := hi(FCodeBin[0]);
m := FCodeBin[0] shr 6;
n := hi(FCodeBin[0]) and 3;
if ((op0 = 0) and (op1 = 0) and (op2 = 0) and
(r = 0) and (m = 2) and (n in [0, 1])) or // ret, retw
((op0 = 13) and (r = 15) and (t in [0, 1])) then // ret.n, retw.n
Result := true;
end;
function TXtensaAsmInstruction.IsLeaveStackFrame: boolean;
begin
Result := false;
end;
function TXtensaAsmInstruction.InstructionLength: Integer;
begin
Result := 3;
ReadCode;
// op0 in 8..13
if lo(FCodeBin[0]) in [8..13] then // narrow instruction series
Result := 2;
end;
type
TPrologueState = (psStart, psEntry, psStoreParams, psBody, psReturn);
function TXtensaAsmDecoder.FParsePrologue(AnAddress, AStartPC, AEndPC: TDBGPtr;
ACallType: TCallType; out returnAddressOffset: word; out
AnIsOutsideFrame: Boolean): Boolean;
var
ADataLen: Cardinal;
//AData: PByte;
//stackState: TPrologueState;
begin
ADataLen := Min(MaxPrologueSize, AnAddress - AStartPC + 3);
Result := ReadCodeAt(AStartPC, ADataLen);
if not Result then
exit;
//AData := @FCodeBin[0];
// Example prologue for procedure call2(p2: integer);
// 004136 entry a1, 32
// 0129 s32i.n a2, a1, 0 // store p2 to stack
AnIsOutsideFrame := true;
//stackState := psStart;
end;
function TXtensaAsmDecoder.FParseEpilogue(AnAddress, AStartPC, AEndPC: TDBGPtr;
out returnAddressOffset: word; out AnIsOutsideFrame: Boolean): Boolean;
begin
end;
function TXtensaAsmDecoder.GetLastErrorWasMemReadErr: Boolean;
begin
Result := FLastErrWasMem;
end;
function TXtensaAsmDecoder.GetMaxInstrSize: integer;
begin
Result := 3;
end;
function TXtensaAsmDecoder.GetMinInstrSize: integer;
begin
Result := 2;
end;
function TXtensaAsmDecoder.GetCanReverseDisassemble: boolean;
begin
Result := False;
end;
function TXtensaAsmDecoder.ReadCodeAt(AnAddress: TDBGPtr; var ALen: Cardinal
): Boolean;
begin
Result := FProcess.ReadData(AnAddress, ALen, FCodeBin[0], ALen);
FLastErrWasMem := not Result;
end;
procedure TXtensaAsmDecoder.Disassemble(var AAddress: Pointer; out
ACodeBytes: String; out ACode: String);
var
CodeIdx: byte;
pcode: PByte;
c0, c1, c2, op0, op1, op2, r, s, t: byte;
imm: int32;
m, n: byte;
w, x, y, half: byte;
begin
pcode := AAddress;
CodeIdx := 0;
c0 := pcode[CodeIdx];
inc(CodeIdx);
c1 := pcode[CodeIdx];
inc(CodeIdx);
// Values used for narrow and 3 byte instructions
op0 := lo(c0);
r := hi(c1);
s := lo(c1);
t := hi(c0);
// Values used for 3 byte instructions, only read if not a narrow instruction
if not(op0 in [8..13]) then
begin
c2 := pcode[CodeIdx];
inc(CodeIdx);
op1 := lo(c2);
op2 := hi(c2);
end;
case op0 of // Table 7-192 / Whole Opcode Space
0 : case op1 of // table 7-193 / QRST
0 : case op2 of // table 7-194 / RST0
0 : case r of // table 7-195 / ST0
0 : begin // table 7-196 / SNM0
m := c0 shr 6;
n := hi(c0) and 3;
case m of
0: ACode := 'ill';
1: ACode := 'reserved';
2: case n of // table 7-197 / JR
0: ACode := 'ret';
1: ACode := 'retw';
2: ACode := format(op_a1, ['jx', s]);
3: ACode := 'reserved';
end;
3: case n of // table 7-198 / CALLX
0: ACode := format(op_a1, ['callx0', s]);
1: ACode := format(op_a1, ['callx4', s]);
2: ACode := format(op_a1, ['callx8', s]);
3: ACode := format(op_a1, ['callx12', s]);
end;
end;
end;
1 : ACode := format(op_a1a2, ['movsp', t, s]);
2 : case t of // table 7-199 / SYNC
0 : ACode := 'isync';
1 : ACode := 'rsync';
2 : ACode := 'esync';
3 : ACode := 'dsync';
8 : ACode := 'excw';
12: ACode := 'memw';
13: ACode := 'extw';
15: ACode := 'nop';
else
ACode := 'reserved';
end;
3 : case t of // table 7-200 / RFEI
0 : case s of // table 7-201 / RFET
0: ACode := 'rfe';
1: ACode := 'rfue';
2: ACode := 'rfde';
4: ACode := 'rfwo';
5: ACode := 'rfwu';
otherwise
ACode := 'reserved';
end;
1: ACode := format(op_c1, ['rfi', s]);
2: case s of // Table RFM
0: ACode := 'rfme';
1: ACode := 'clrex';
otherwise
ACode := 'reserved';
end;
3: case t of // BLKSR - Listed but not described in document from 2022
0: ACode := 'pfend.a';
1: ACode := 'pfend.o';
2: ACode := 'pfnxt.f';
3: ACode := 'pfwait.a';
4: ACode := 'pfwait.r';
otherwise
ACode := 'reserved';
end;
otherwise
ACode := 'reserved';
end;
4 : ACode := format(op_c1c2, ['break', s, t]); // xtensa-esp32-elf-objdump decodes the operands in this sequence
5 : case s of // SYSIM
0: ACode := 'syscall';
1: ACode := 'simcall';
2: ACode := 'halt';
otherwise
ACode := 'reserved';
end;
6 : ACode := format(op_a1c2,['rsil', t, s]);
7 : case s of // WTLS
0: format(op_c1, ['wait', s]);
// 4..7: CSR parity error test, cannot find description
14: ACode := 'lddr32.p';
15: ACode := 'sddr32.p';
otherwise
ACode := 'reserved';
end;
8 : ACode := format(op_b1b2, ['any4', t, s]);
9 : ACode := format(op_b1b2, ['all4', t, s]);
10: ACode := format(op_b1b2, ['any8', t, s]);
11: ACode := format(op_b1b2, ['all8', t, s]);
otherwise
ACode := 'reserved';
end;
1 : ACode := format(op_a1a2a3, ['and', r, s, t]);
2 : ACode := format(op_a1a2a3, ['or', r, s, t]);
3 : ACode := format(op_a1a2a3, ['xor', r, s, t]);
4 : case r of // table 7-202 / ST1
0 : ACode := format(op_a1, ['ssr', s]);
1 : ACode := format(op_a1, ['ssl', s]);
2 : ACode := format(op_a1, ['ssa8l', s]);
3 : ACode := format(op_a1, ['ssa8b', s]);
4 : ACode := format(op_c1, ['ssai', s or ((t and 1) shl 4)]);
6 : ACode := format(op_a1a2, ['rer', t, s]);
7 : ACode := format(op_a1a2, ['wer', t, s]);
8 : ACode := format(op_c1, ['rotw', SarShortint(shortint(t shl 4), 4)]);
10: ACode := format(op_a1, ['getex', t]);
14: ACode := format(op_a1a2, ['nsa', t, s]);
15: ACode := format(op_a1a2, ['nsau', t, s]);
otherwise
ACode := 'reserved';
end;
5 : case r of // table 7-203 / TLB
3 : ACode := format(op_a1a2, ['ritlb0', t, s]);
4 : ACode := format(op_a1, ['iitlb', s]);
5 : ACode := format(op_a1a2, ['pitlb', t, s]);
6 : ACode := format(op_a1a2, ['witlb', t, s]);
7 : ACode := format(op_a1a2, ['ritlb1', t, s]);
11: ACode := format(op_a1a2, ['rdtlb0', t, s]); // or rptlb0
12: ACode := format(op_a1, ['idtlb', s]);
13: ACode := format(op_a1a2, ['pdtlb', t, s]);
14: ACode := format(op_a1a2, ['wdtlb', t, s]); // or wptlb
15: ACode := format(op_a1a2, ['rdtlb1', t, s]); // or rptlb1
otherwise
ACode := 'reserved';
end;
6 : case s of // table 7-204 / RT0
0 : ACode := format(op_a1a2, ['neg', r, t]);
1 : ACode := format(op_a1a2, ['abs', r, t]);
otherwise
ACode := 'reserved';
end;
8 : ACode := format(op_a1a2a3, ['add', r, s, t]);
9 : ACode := format(op_a1a2a3, ['addx2', r, s, t]);
10: ACode := format(op_a1a2a3, ['addx4', r, s, t]);
11: ACode := format(op_a1a2a3, ['addx8', r, s, t]);
12: ACode := format(op_a1a2a3, ['sub', r, s, t]);
13: ACode := format(op_a1a2a3, ['subx2', r, s, t]);
14: ACode := format(op_a1a2a3, ['subx4', r, s, t]);
15: ACode := format(op_a1a2a3, ['subx8', r, s, t]);
otherwise
ACode := 'reserved';
end;
1 : case op2 of // table 7-205 / RST1
0, 1 : ACode := format(op_a1a2c3, ['slli', r, s, 32 - (t or ((op2 and 1) shl 4))]);
2, 3 : ACode := format(op_a1a2c3, ['srai', r, t, s or ((op2 and 1) shl 4)]);
4 : ACode := format(op_a1a2c3, ['srli', r, t, s]);
6 : ACode := format(op_a1c2, ['xsr', r, c1]);
7 : ACode := 'unclear'; // Table 7-206 / ACCER => encoding doesn't match instructions
8 : ACode := format(op_a1a2a3, ['src', r, s, t]);
9 : ACode := format(op_a1a2, ['srl', r, t]);
10: ACode := format(op_a1a2, ['sll', r, s]);
11: ACode := format(op_a1a2, ['sra', r, t]);
12: ACode := format(op_a1a2a3, ['mul16u', r, s, t]);
13: ACode := format(op_a1a2a3, ['mul16s', r, s, t]);
15: case r of // Table 7-207 / IMP
0 : ACode := format(op_a1a2, ['lict', t, s]);
1 : ACode := format(op_a1a2, ['sict', t, s]);
2 : ACode := format(op_a1a2, ['licw', t, s]);
3 : ACode := format(op_a1a2, ['sicw', t, s]);
4 : ACode := format(op_a1a2, ['l32ex', t, s]);
5 : ACode := format(op_a1a2, ['s32ex', t, s]);
8 : ACode := format(op_a1a2, ['ldct', t, s]);
9 : ACode := format(op_a1a2, ['sdct', t, s]);
14: case t of // Table 7-208 / RFDX
0 : ACode := 'rfdo';
1 : ACode := 'rfdd';
otherwise
ACode := 'reserved';
end;
otherwise
ACode := 'reserved';
end;
otherwise
ACode := 'reserved';
end;
2 : case op2 of // table 7-209 / RST2
0 : ACode := format(op_b1b2b3, ['andb', r, s, t]);
1 : ACode := format(op_b1b2b3, ['andbc', r, s, t]);
2 : ACode := format(op_b1b2b3, ['orb', r, s, t]);
3 : ACode := format(op_b1b2b3, ['orbc', r, s, t]);
4 : ACode := format(op_b1b2b3, ['xorb', r, s, t]);
6 : ACode := format(op_a1a2a3, ['saltu', r, s, t]);
7 : ACode := format(op_a1a2a3, ['salt', r, s, t]);
8 : ACode := format(op_a1a2a3, ['mull', r, s, t]);
10: ACode := format(op_a1a2a3, ['muluh', r, s, t]);
11: ACode := format(op_a1a2a3, ['mulsh', r, s, t]);
12: ACode := format(op_a1a2a3, ['quou', r, s, t]);
13: ACode := format(op_a1a2a3, ['quos', r, s, t]);
14: ACode := format(op_a1a2a3, ['remu', r, s, t]);
15: ACode := format(op_a1a2a3, ['rems', r, s, t]);
otherwise
ACode := 'reserved';
end;
3 : case op2 of // table 7-210 / RST3
0 : ACode := format(op_a1c2, ['rsr', t, c1]);
1 : ACode := format(op_a1c2, ['wsr', t, c1]);
2 : ACode := format(op_a1a2c3, ['sext', r, s, t+7]);
3 : ACode := format(op_a1a2c3, ['clamps', r, s, t+7]);
4 : ACode := format(op_a1a2a3, ['min', r, s, t]);
5 : ACode := format(op_a1a2a3, ['max', r, s, t]);
6 : ACode := format(op_a1a2a3, ['minu', r, s, t]);
7 : ACode := format(op_a1a2a3, ['maxu', r, s, t]);
8 : ACode := format(op_a1a2a3, ['moveqz', r, s, t]);
9 : ACode := format(op_a1a2a3, ['movnez', r, s, t]);
10: ACode := format(op_a1a2a3, ['movltz', r, s, t]);
11: ACode := format(op_a1a2a3, ['movgez', r, s, t]);
12: ACode := format(op_a1a2b3, ['movf', r, s, t]);
13: ACode := format(op_a1a2b3, ['movt', r, s, t]);
14: ACode := format(op_a1c2, ['rur', r, 16*s+t]);
15: ACode := format(op_a1c2, ['wur', r, 16*s+t]);
otherwise
ACode := 'reserved';
end;
4, 5: ACode := format(op_a1a2c3c4, ['extui', r, t, word(s) or (word(op1 and 1) shl 4), op2+1]);
6 : ACode := 'cust0';
7 : ACode := 'cust1';
8 : case op2 of // table 7-211 / LSCX
0 : ACode := format(op_f1a2a3, ['lsx', r, t, s]);
1 : ACode := format(op_f1a2a3, ['lsxu', r, t, s]);
2 : ACode := format(op_f1a2a3, ['ldx', r, t, s]);
3 : ACode := format(op_f1a2a3, ['ldxp', r, t, s]);
4 : ACode := format(op_f1a2a3, ['ssx', r, t, s]);
5 : ACode := format(op_f1a2a3, ['ssxu', r, t, s]);
6 : ACode := format(op_f1a2a3, ['sdx', r, t, s]);
7 : ACode := format(op_f1a2a3, ['sdxp', r, t, s]);
otherwise
ACode := 'reserved';
end;
9 : case op2 of // table 7-212 / LSC4
0 : ACode := format(op_a1a2c3, ['l32e', t, s, -4*(16-r)]);
1 : case r of // Table BLKPRF
1 : ACode := format(op_a1a2, ['dpfr.b', s, t]);
2 : ACode := format(op_a1a2, ['dpfw.b', s, t]);
3 : ACode := format(op_a1a2, ['dpfm.b', s, t]);
5 : ACode := format(op_a1a2, ['dpfr.bf', s, t]);
6 : ACode := format(op_a1a2, ['dpfw.bf', s, t]);
7 : ACode := format(op_a1a2, ['dpfm.bf', s, t]);
9 : ACode := format(op_a1a2, ['dhi.b', s, t]);
10: ACode := format(op_a1a2, ['dhwb.b', s, t]);
11: ACode := format(op_a1a2, ['dhwbi.b', s, t]);
otherwise
ACode := 'reserved';
end;
// 2 : Table DISPL, instructions not described
4 : ACode := format(op_a1a2c3, ['s32e', t, s, -4*(16-r)]);
5 : ACode := format(op_a1a2c3, ['s32nb', t, s, 4*r]);
// 10: Table DISPS, instructions not described
otherwise
ACode := 'reserved';
end;
10: case op2 of // table 7-213 / FP0
0 : ACode := format(op_f1f2f3, ['add.s', r, s, t]);
1 : ACode := format(op_f1f2f3, ['sub.s', r, s, t]);
2 : ACode := format(op_f1f2f3, ['mul.s', r, s, t]);
4 : ACode := format(op_f1f2f3, ['madd.s', r, s, t]);
5 : ACode := format(op_f1f2f3, ['msub.s', r, s, t]);
6 : ACode := format(op_f1f2f3, ['maddn.s', r, s, t]);
7 : ACode := format(op_f1f2f3, ['divn.s', r, s, t]);
8 : ACode := format(op_a1f2c3, ['round.s', r, s, t]);
9 : ACode := format(op_a1f2c3, ['trunc.s', r, s, t]);
10: ACode := format(op_a1f2c3, ['floor.s', r, s, t]);
11: ACode := format(op_a1f2c3, ['ceil.s', r, s, t]);
12: ACode := format(op_f1a2c3, ['float.s', r, s, t]);
13: ACode := format(op_f1a2c3, ['ufloat.s', r, s, t]);
14: ACode := format(op_a1f2c3, ['utrunc.s', r, s, t]);
15: case t of // table 7-214 / FP1OP
0 : ACode := format(op_f1f2, ['mov.s', r, s]);
1 : ACode := format(op_f1f2, ['abs.s', r, s]);
2 : ACode := format(op_f1f2, ['cvtd.s', r, s]);
3 : ACode := format(op_f1c2, ['const.s', r, s]);
4 : ACode := format(op_a1f2, ['rfr', r, s]);
5 : ACode := format(op_f1a2, ['wfr', r, s]);
6 : ACode := format(op_f1f2, ['neg.s', r, s]);
7 : ACode := format(op_f1f2, ['div0.s', r, s]);
8 : ACode := format(op_f1f2, ['recip0.s', r, s]);
9 : ACode := format(op_f1f2, ['sqrt0.s', r, s]);
10: ACode := format(op_f1f2, ['rsqrt0.s', r, s]);
11: ACode := format(op_f1f2, ['nexp01.s', r, s]);
12: ACode := format(op_f1f2, ['mksadj.s', r, s]);
13: ACode := format(op_f1f2, ['mkdadj.s', r, s]);
14: ACode := format(op_f1f2, ['addexp.s', r, s]);
15: ACode := format(op_f1f2, ['addexpm.s', r, s]);
otherwise
ACode := 'reserved';
end;
otherwise
ACode := 'reserved';
end;
11: case op2 of // table 7-215 / FP1
1 : ACode := format(op_b1f2f3, ['un.s', r, s, t]);
2 : ACode := format(op_b1f2f3, ['oeq.s', r, s, t]);
3 : ACode := format(op_b1f2f3, ['ueq.s', r, s, t]);
4 : ACode := format(op_b1f2f3, ['olt.s', r, s, t]);
5 : ACode := format(op_b1f2f3, ['ult.s', r, s, t]);
6 : ACode := format(op_b1f2f3, ['ole.s', r, s, t]);
7 : ACode := format(op_b1f2f3, ['ule.s', r, s, t]);
8 : ACode := format(op_f1f2a3, ['moveqz.s', r, s, t]);
9 : ACode := format(op_f1f2a3, ['movnez.s', r, s, t]);
10: ACode := format(op_f1f2a3, ['movltz.s', r, s, t]);
11: ACode := format(op_f1f2a3, ['movgez.s', r, s, t]);
12: ACode := format(op_f1f2b3, ['movf.s', r, s, t]);
13: ACode := format(op_f1f2b3, ['movt.s', r, s, t]);
otherwise
ACode := 'reserved';
end;
14: case op2 of // Table DFP1
1 : ACode := format(op_b1f2f3, ['un.d', r, s, t]);
2 : ACode := format(op_b1f2f3, ['oeq.d', r, s, t]);
3 : ACode := format(op_b1f2f3, ['ueq.d', r, s, t]);
4 : ACode := format(op_b1f2f3, ['olt.d', r, s, t]);
5 : ACode := format(op_b1f2f3, ['ult.d', r, s, t]);
6 : ACode := format(op_b1f2f3, ['ole.d', r, s, t]);
7 : ACode := format(op_b1f2f3, ['ule.d', r, s, t]);
8 : ACode := format(op_f1a2a3, ['wfrd', r, s, t]);
otherwise
ACode := 'reserved';
end;
15: case op2 of // Table DFP0
0 : ACode := format(op_f1f2f3, ['add.d', r, s, t]);
1 : ACode := format(op_f1f2f3, ['sub.d', r, s, t]);
2 : ACode := format(op_f1f2f3, ['mul.d', r, s, t]);
4 : ACode := format(op_f1f2f3, ['madd.d', r, s, t]);
5 : ACode := format(op_f1f2f3, ['msub.d', r, s, t]);
6 : ACode := format(op_f1f2f3, ['maddn.d', r, s, t]);
7 : ACode := format(op_f1f2f3, ['divn.d', r, s, t]);
8 : ACode := format(op_a1f2c3, ['round.d', r, s, t]);
9 : ACode := format(op_a1f2c3, ['trunc.d', r, s, t]);
10: ACode := format(op_a1f2c3, ['floor.d', r, s, t]);
11: ACode := format(op_a1f2c3, ['ceil.d', r, s, t]);
otherwise
ACode := 'reserved';
end;
otherwise
ACode := 'reserved';
end;
1 : begin
imm := word(c1) or (word(c2) shl 8);
imm := {(int32(AAddress+3) and $FFFFFFFC) +} int32((uint32(imm) shl 2) or $FFFC0000);
ACode := format(op_a1c2, ['l32r', t, imm]);
end;
2 : case r of // table 7-216 / LSAI
0 : ACode := format(op_a1a2c3, ['l8ui', t, s, c2]);
1 : ACode := format(op_a1a2c3, ['l16ui', t, s, 2*word(c2)]);
2 : ACode := format(op_a1a2c3, ['l32i', t, s, 4*word(c2)]);
4 : ACode := format(op_a1a2c3, ['s8i', t, s, c2]);
5 : ACode := format(op_a1a2c3, ['s16i', t, s, 2*word(c2)]);
6 : ACode := format(op_a1a2c3, ['s32i', t, s, 4*word(c2)]);
7 : case t of // table 7-217 / CACHE
0 : ACode := format(op_a1c2, ['dpfr', s, c2]);
1 : ACode := format(op_a1c2, ['dpfw', s, c2]);
2 : ACode := format(op_a1c2, ['dpfro', s, c2]);
3 : ACode := format(op_a1c2, ['dpfwo', s, c2]);
4 : ACode := format(op_a1c2, ['dhwb', s, c2]);
5 : ACode := format(op_a1c2, ['dhwbi', s, c2]);
6 : ACode := format(op_a1c2, ['dhi', s, c2]);
7 : ACode := format(op_a1c2, ['dii', s, c2]);
8 : case op1 of // table 7-218 / DCE
0 : ACode := format(op_a1c2, ['dpfl', s, 16*word(op2)]);
1 : ACode := format(op_a1c2, ['dci', s, 16*word(op2)]);
2 : ACode := format(op_a1c2, ['dhu', s, 16*word(op2)]);
3 : ACode := format(op_a1c2, ['diu', s, 16*word(op2)]);
4 : ACode := format(op_a1c2, ['diwb', s, 16*word(op2)]);
5 : ACode := format(op_a1c2, ['diwbi', s, 16*word(op2)]);
6 : ACode := format(op_a1c2, ['dcwb', s, 16*word(op2)]);
7 : ACode := format(op_a1c2, ['dcwbi', s, 16*word(op2)]);
otherwise
ACode := 'reserved';
end;
12: ACode := format(op_a1c2, ['ipf', s, 4*word(c2)]);
13: case op1 of // table 7-219 / ICE
0 : ACode := format(op_a1c2, ['ipfl', s, 16*word(op2)]);
2 : ACode := format(op_a1c2, ['ihu', s, 16*word(op2)]);
3 : ACode := format(op_a1c2, ['iiu', s, 16*word(op2)]);
otherwise
ACode := 'reserved';
end;
14: ACode := format(op_a1c2, ['ihi', s, 4*word(c2)]);
15: ACode := format(op_a1c2, ['iii', s, 4*word(c2)]);
otherwise
ACode := 'reserved';
end;
9 : ACode := format(op_a1a2c3, ['l16si', t, s, 2*word(c2)]);
10: begin
imm := c2 + (word(s) shl 8);
if imm and $800 > 0 then
imm := int32(uint32(imm) or $FFFFF000);
ACode := format(op_a1c2, ['movi', t, imm]);
end;
11: ACode := format(op_a1a2c3, ['l32ai', t, s, 4*word(c2)]);
12: ACode := format(op_a1a2c3, ['addi', t, s, ShortInt(c2)]);
13: ACode := format(op_a1a2c3, ['addmi', t, s, integer(ShortInt(c2)) shl 8]); // xtensa-esp32-elf-objdump show the constant as hex value
14: ACode := format(op_a1a2c3, ['s32c1i', t, s, 4*word(c2)]);
15: ACode := format(op_a1a2c3, ['s32ri', t, s, 4*word(c2)]);
otherwise
ACode := 'reserved';
end;
3 : case r of // table 7-220 / LSCI
0 : ACode := format(op_f1a2c3, ['lsi', t, s, 4*word(c2)]);
1 : ACode := format(op_f1a2c3, ['ldi', t, s, 4*word(c2)]);
4 : ACode := format(op_f1a2c3, ['ssi', t, s, 4*word(c2)]);
5 : ACode := format(op_f1a2c3, ['sdi', t, s, 4*word(c2)]);
8 : ACode := format(op_f1a2c3, ['lsiu', t, s, 4*word(c2)]);
9 : ACode := format(op_f1a2c3, ['ldiu', t, s, 4*word(c2)]);
12: ACode := format(op_f1a2c3, ['ssiu', t, s, 4*word(c2)]);
13: ACode := format(op_f1a2c3, ['sdiu', t, s, 4*word(c2)]);
otherwise
ACode := 'reserved';
end;
4 : begin
w := hi(c1) and 3;
x := (hi(c1) shr 2) and 1;
y := ((c0 shr 6) and 1) + 2;
half := c2 and 3;
case op2 of // table 7-221 / MAC16D
0 : case op1 of // table 7-222 / MACID
8..11 : ACode := format(op_m1a2m3m4, ['mula.dd.'+hreg[half]+'.ldinc', w, s, x, y]);
otherwise
ACode := 'reserved';
end;
1 : case op1 of // table 7-226 / MACCD
8..11 : ACode := format(op_m1a2m3m4, ['mula.dd.'+hreg[half]+'.lddec', w, s, x, y]);
otherwise
ACode := 'reserved';
end;
2 : case op1 of // table 7-224 / MACDD
4..7 : ACode := format(op_m1m2, ['mul.dd.'+hreg[half], x, y]);
8..11 : ACode := format(op_m1m2, ['mula.dd.'+hreg[half], x, y]);
12..15: ACode := format(op_m1m2, ['muls.dd.'+hreg[half], x, y]);
otherwise
ACode := 'reserved';
end;
3 : case op1 of // table 7-225 / MACAD
4..7 : ACode := format(op_a1m2, ['mul.ad.'+hreg[half], s, y]);
8..11 : ACode := format(op_a1m2, ['mula.ad.'+hreg[half], s, y]);
12..15: ACode := format(op_a1m2, ['muls.ad.'+hreg[half], s, y]);
otherwise
ACode := 'reserved';
end;
4 : case op1 of // table 7-223 / MACIA
8..11 : ACode := format(op_m1a2m3r4, ['mula.da.'+hreg[half]+'.ldinc', w, s, x, t]);
otherwise
ACode := 'reserved';
end;
5 : case op1 of // table 7-227 / MACCA
8..11 : ACode := format(op_m1a2m3r4, ['mula.da.'+hreg[half]+'.lddec', w, s, x, t]);
otherwise
ACode := 'reserved';
end;
6 : case op1 of // table 7-228 / MACDA
4..7 : ACode := format(op_m1a2, ['mul.da.'+hreg[half], x, t]);
8..11 : ACode := format(op_m1a2, ['mula.da.'+hreg[half], x, t]);
12..15: ACode := format(op_m1a2, ['muls.da.'+hreg[half], x, t]);
otherwise
ACode := 'reserved';
end;
7 : case op1 of // table 7-229 / MACAA
0..3 : ACode := format(op_a1a2, ['umul.aa.'+hreg[half], s, t]);
4..7 : ACode := format(op_a1a2, ['mul.aa.'+hreg[half], s, t]);
8..11 : ACode := format(op_a1a2, ['mula.aa.'+hreg[half], s, t]);
12..15: ACode := format(op_a1a2, ['muls.aa.'+hreg[half], s, t]);
otherwise
ACode := 'reserved';
end;
8 : case op1 of // table 7-230 / MACI
0 : ACode := format(op_m1a2, ['ldinc', w, s]);
otherwise
ACode := 'reserved';
end;
9 : case op1 of // table 7-231 / MACC
0 : ACode := format(op_m1a2, ['lddec', w, s]);
otherwise
ACode := 'reserved';
end;
otherwise
ACode := 'reserved';
end;
end;
5 : begin // table 7-232 / CALLN
n := (c0 shr 4) and 3;
// Left shift into 32 bit
imm := (int32(c2) shl 24) or (int32(c1) shl 16) or (int32(c0 and $C0) shl 8);
// Then right shift to get 20 bit signed value
imm := {(int32(AAddress) and $FFFFFFFC) +} int32((SarLongint(imm, 12) + 4) and $FFFFFFFC);
ACode := format(op_c1, [callID[n], imm]);
end;
6 : begin
m := (c0 shr 6);
n := (c0 shr 4) and 3;
case n of // table 7-233 / SI
0 : begin
// Left shift into 32 bit
imm := (int32(c2) shl 24) or (int32(c1) shl 16) or (int32(c0 and $C0) shl 8);
// Then right shift to get 18 bit signed value
imm := {int32(AAddress) +} SarLongint(imm, 14) + 4;
ACode := format(op_c1, ['j', imm]);
end;
1 : begin
// Left shift into 32 bit
imm := (int32(c2) shl 24) or (int32(c1) shl 16);
// Then right shift to get 12 bit signed value
imm := {int32(AAddress) +} SarLongint(imm, 20) + 4;
case m of // table 7-234 / BZ
0 : ACode := format(op_a1c2, ['beqz', s, imm]);
1 : ACode := format(op_a1c2, ['bnez', s, imm]);
2 : ACode := format(op_a1c2, ['bltz', s, imm]);
3 : ACode := format(op_a1c2, ['bgez', s, imm]);
otherwise
ACode := 'reserved';
end;
end;
2 : begin
imm := {int32(AAddress) +} SmallInt(ShortInt(c2))+4;
case m of // table 7-235 / BI0
0 : ACode := format(op_a1c2c3, ['beqi', s, b4const_signed[r], imm]);
1 : ACode := format(op_a1c2c3, ['bnei', s, b4const_signed[r], imm]);
2 : ACode := format(op_a1c2c3, ['blti', s, b4const_signed[r], imm]);
3 : ACode := format(op_a1c2c3, ['bgei', s, b4const_signed[r], imm]);
otherwise
ACode := 'reserved';
end;
end;
3 : begin
case m of // table 7-236 / BI1
0 : ACode := format(op_a1c2, ['entry', s, 8*((c2 shl 4) or r)]);
1 : case r of // table 7-237 / B1
0 : ACode := format(op_b1c2, ['bf', s, SmallInt(ShortInt(c2))+4]);
1 : ACode := format(op_b1c2, ['bt', s, SmallInt(ShortInt(c2))+4]);
8 : ACode := format(op_a1c2, ['loop', s, word(c2)+4]);
9 : ACode := format(op_a1c2, ['loopnez', s, word(c2)+4]);
10: ACode := format(op_a1c2, ['loopgtz', s, word(c2)+4]);
otherwise
ACode := 'reserved';
end;
2 : ACode := format(op_a1c2c3, ['bltui', s, b4const_unsigned[r], word(c2)+4]); // Check
3 : ACode := format(op_a1c2c3, ['bgeui', s, b4const_unsigned[r], SmallInt(ShortInt(c2))+4]); // Check
otherwise
ACode := 'reserved';
end;
end;
otherwise
ACode := 'reserved';
end;
end;
7 : begin
imm := {int32(AAddress) +} ShortInt(SmallInt(c2))+4;
case r of // table7-238 / B
0 : ACode := format(op_a1a2c3, ['bnone', s, t, imm]);
1 : ACode := format(op_a1a2c3, ['beq', s, t, imm]);
2 : ACode := format(op_a1a2c3, ['blt', s, t, imm]);
3 : ACode := format(op_a1a2c3, ['bltu', s, t, imm]);
4 : ACode := format(op_a1a2c3, ['ball', s, t, imm]);
5 : ACode := format(op_a1a2c3, ['bbc', s, t, imm]);
6, 7: ACode := format(op_a1c2c3, ['bbci', s, t + (r and 1) shl 4, imm]);
8 : ACode := format(op_a1a2c3, ['bany', s, t, imm]);
9 : ACode := format(op_a1a2c3, ['bne', s, t, imm]);
10: ACode := format(op_a1a2c3, ['bge', s, t, imm]);
11: ACode := format(op_a1a2c3, ['bgeu', s, t, imm]);
12: ACode := format(op_a1a2c3, ['bnall', s, t, imm]);
13: ACode := format(op_a1a2c3, ['bbs', s, t, imm]);
14,15: ACode := format(op_a1c2c3, ['bbsi', s, t + (r and 1) shl 4, imm]);
otherwise
ACode := 'reserved';
end;
end;
8 : ACode := format(op_a1a2c3, ['l32i.n', s, t, 4*word(r)]);
9 : ACode := format(op_a1a2c3, ['s32i.n', s, t, 4*word(r)]);
10: ACode := format(op_a1a2a3, ['add.n', r, s, t]);
11: if t = 0 then
ACode := format(op_a1a2c3, ['addi.n', r, s, -1])
else
ACode := format(op_a1a2c3, ['addi.n', r, s, t]);
12: case t of // table 7-239 / ST2
0..7: begin
imm := int32(r) or int32(t and 7) shl 4;
// Check if imm represents an encoded negative value, sign extend to 32 bit
if (imm shr 5) = 3 then
imm := int32(int32(imm) or $FFFFFF80);
ACode := format(op_a1c2, ['movi.n', s, imm]);
end;
8..11: begin
imm := {int32(AAddress) +} word(r) or (word(t and 3) shl 4) + 4;
ACode := format(op_a1c2, ['beqz.n', s, imm]);
end;
12..15: begin
imm := {int32(AAddress) +} word(r) or (word(t and 3) shl 4) + 4;
ACode := format(op_a1c2, ['bnez.n', s, imm]);
end;
otherwise
ACode := 'reserved';
end;
13: case r of // table 7-240 / ST3
0 : ACode := format(op_a1a2, ['mov.n', t, s]);
15: case t of // table 7-241
0 : ACode := format(op, ['ret.n']);
1 : ACode := format(op, ['retw.n']);
2 : ACode := format(op_c1, ['break.n', s]);
3 : ACode := format(op, ['nop.n']);
6 : case s of // table ILH
0 : ACode := format(op, ['ill.n']);
1 : ACode := format(op, ['halt.n']);
otherwise
ACode := 'reserved';
end;
otherwise
ACode := 'reserved';
end;
otherwise
ACode := 'reserved';
end;
otherwise
ACode := 'reserved';
end;
// memory, display as normal (BE) hex value
ACodeBytes := '';
for m := 0 to CodeIdx - 1 do
ACodeBytes := HexStr(pcode[m], 2) + ACodeBytes;
Inc(AAddress, CodeIdx);
end;
function TXtensaAsmDecoder.GetInstructionInfo(AnAddress: TDBGPtr
): TDbgAsmInstruction;
begin
if (FLastInstr = nil) or (FLastInstr.RefCount > 1) then begin
ReleaseRefAndNil(FLastInstr);
FLastInstr := TXtensaAsmInstruction.Create(Self);
end;
FLastInstr.SetAddress(AnAddress);
Result := FLastInstr;
end;
function TXtensaAsmDecoder.GetFunctionFrameInfo(AnAddress: TDBGPtr; out
AnIsOutsideFrame: Boolean): Boolean;
begin
Result := False;
end;
function TXtensaAsmDecoder.GetBreakInstruction(const ALocation: TDBGPtr; out
BreakInstructionLength: Integer): QWord;
begin
BreakInstructionLength := GetInstructionInfo(ALocation).InstructionLength;
// Set the user fields s and t to 0
if BreakInstructionLength = 2 then
Result := $000000 { ILL} // $F0D2 { BREAK }
else
Result := $F06D { ILL.N }; // 4000 { BREAK.N }
end;
function TXtensaAsmDecoder.BreakInstructionOffset: Int8;
begin
Result := 0; // ?
end;
function TXtensaAsmDecoder.GetFunctionFrameReturnAddress(AnAddress, AStartPC,
AEndPC: TDBGPtr; ACallType: TCallType; out returnAddressOffset: word; out
AnIsOutsideFrame: Boolean): Boolean;
begin
result := false;
exit;
{ Cases to consider:
A - if (AStartPC + MaxPrologueSize < AnAddress) and (AnAddress + MaxEpilogueSize < AEndPC)
then currently inside stack frame. Parse prologue to figure out
offset from frame pointer to return address.
B - if (AStartPC + MaxPrologueSize < AnAddress)
then possibly before final stack frame. Need to parse prologue up to AnAddress
to figure out how far the stack has moved since entry to calculate offset
from SP to return address. If frame pointer has been configured before
AnAddress, assume inside frame and return offset relative to frame pointer.
C - if (AnAddress + MaxEpilogueSize < AEndPC)
then possibly inside frame teardown. Need to reverse parse epilogue up to AnAddress
to figure out how much frame will unwind to calculate offset to return address.
If frame pointer has been restored before AnAddress then ouside frame.
}
// Return address always in a0
returnAddressOffset := 0;
if (AnAddress = AStartPC) or (AnAddress = AEndPC) then
begin
AnIsOutsideFrame := true;
exit;
end
else
result := FParsePrologue(AnAddress, AStartPC, AEndPC, ACallType, returnAddressOffset, AnIsOutsideFrame);
end;
constructor TXtensaAsmDecoder.Create(AProcess: TDbgProcess);
begin
FProcess := AProcess;
end;
destructor TXtensaAsmDecoder.Destroy;
begin
ReleaseRefAndNil(FLastInstr);
inherited Destroy;
end;
initialization
DebugLogger.FindOrRegisterLogGroup('DBG_WARNINGS' {$IFDEF DBG_WARNINGS} , True {$ENDIF} );
end.