mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-05 10:37:58 +02:00
1089 lines
48 KiB
ObjectPascal
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.
|