📄 arm_disass.pas
字号:
//////////////////////////////////////////////////////////////////////
function TArm7Disass.SingleDataSwap: string;
var
Rn, Rd, Rm: byte;
begin
// Assembler syntax
// <SWP>{cond}{B} Rd,Rm,[Rn]
//
// where:
// {cond} two-character condition mnemonic.
// {B} if B is present then byte transfer, otherwise word transfer
// Rd,Rm,Rn are expressions evaluating to valid register numbers
// Parse the operands
Rn := (w shr 16) and $F;
Rd := (w shr 12) and $F;
Rm := w and $F;
if w and (1 shl 22) <> 0 then
Result := Format('swp%5s%s,%s,[%s]', [condCodes[w shr 28]+'b', regCodes[Rd], regCodes[Rm], regCodes[Rn]])
else
Result := Format('swp%5s%s,%s,[%s]', [condCodes[w shr 28], regCodes[Rd], regCodes[Rm], regCodes[Rn]]);
end;
//////////////////////////////////////////////////////////////////////
function TArm7Disass.AluOperation(operand2: string): string;
var
Rn, Rd: byte;
operand1: string;
begin
// Data Processing
// The data processing instruction is only executed if the condition is true.
// The instruction produces a result by performing a specified arithmetic or logical
// operation on one or two operands. The first operand is always a register (Rn).
Result := '';
// Parse the operands
Rn := (w shr 16) and $F;
Rd := (w shr 12) and $F;
// Using R15 as an operand
// If R15 (the PC) is used as an operand in a data processing instruction the register is
// used directly.
//
// The PC value will be the address of the instruction, plus 8 or 12 bytes due to instruction
// prefetching. If the shift amount is specified in the instruction, the PC will be 8 bytes
// ahead. If a register is used to specify the shift amount the PC will be 12 bytes ahead.
// Assembler syntax for data processing
// 1 MOV, MVN (single operand instructions)
// <opcode>{cond}{S} Rd,<Op2>
//
// 2 CMP, CMN, TEQ, TST (instructions which do not produce a result)
// <opcode>{cond} Rn,<Op2>
//
// 3 AND, EOR, SUB, RSB, ADD, ADC, SBC, RSC, ORR, BIC
// <opcode>{cond}{S} Rd,Rn,<Op2>
//
// where:
// <Op2> is Rm{,<shift>} or <#expression>
// {cond} is a two-character condition mnemonic.
// {S} set condition codes if S present (implied for CMP, CMN, TEQ, TST).
// Rd, Rn and Rm are expressions evaluating to a register number.
// <#expression> if this is used, the assembler will attempt to generate a shifted
// immediate 8-bit field to match the expression. If this is
// impossible, it will give an error.
// <shift> is <shiftname> <register> or <shiftname> #expression, or
// RRX (rotate right one bit with extend).
// <shiftname>s are: ASL, LSL, LSR, ASR, ROR. (ASL is a synonym for LSL,
// they assemble to the same code)
if w and (1 shl 20) <> 0 then begin
operand1 := Format('%-4s %s, ', [condCodes[w shr 28]+'s', regCodes[Rd]]);
case ((w shr 21) and $F) of
MOV_OPCODE: Result := Format('mov%s%s', [operand1, operand2]);
MVN_OPCODE: Result := Format('mvn%s%s', [operand1, operand2]);
AND_OPCODE: Result := Format('and%s%s, %s', [operand1, regCodes[Rn], operand2]);
EOR_OPCODE: Result := Format('eor%s%s, %s', [operand1, regCodes[Rn], operand2]);
SUB_OPCODE: Result := Format('sub%s%s, %s', [operand1, regCodes[Rn], operand2]);
RSB_OPCODE: Result := Format('rsb%s%s, %s', [operand1, regCodes[Rn], operand2]);
ADD_OPCODE: Result := Format('add%s%s, %s', [operand1, regCodes[Rn], operand2]);
ADC_OPCODE: Result := Format('adc%s%s, %s', [operand1, regCodes[Rn], operand2]);
SBC_OPCODE: Result := Format('sbc%s%s, %s', [operand1, regCodes[Rn], operand2]);
RSC_OPCODE: Result := Format('rsc%s%s, %s', [operand1, regCodes[Rn], operand2]);
ORR_OPCODE: Result := Format('orr%s%s, %s', [operand1, regCodes[Rn], operand2]);
BIC_OPCODE: Result := Format('bic%s%s, %s', [operand1, regCodes[Rn], operand2]);
TST_OPCODE: Result := Format('tst%-5s%s, %s', [condCodes[w shr 28], regCodes[Rn], operand2]);
TEQ_OPCODE: Result := Format('teq%-5s%s, %s', [condCodes[w shr 28], regCodes[Rn], operand2]);
CMP_OPCODE: Result := Format('cmp%-5s%s, %s', [condCodes[w shr 28], regCodes[Rn], operand2]);
CMN_OPCODE: Result := Format('cmn%-5s%s, %s', [condCodes[w shr 28], regCodes[Rn], operand2]);
end;
//Result := 'Fixme: ALU/PSR Rd=R15, S bit set, mode change not done yet!';
end else begin
operand1 := Format('%-5s%s,', [condCodes[w shr 28], regCodes[Rd]]);
case ((w shr 21) and $F) of
MOV_OPCODE: Result := Format('mov%s %s', [operand1, operand2]);
MVN_OPCODE: Result := Format('mvn%s %s', [operand1, operand2]);
AND_OPCODE: Result := Format('and%s %s, %s', [operand1, regCodes[Rn], operand2]);
EOR_OPCODE: Result := Format('eor%s %s, %s', [operand1, regCodes[Rn], operand2]);
SUB_OPCODE: Result := Format('sub%s %s, %s', [operand1, regCodes[Rn], operand2]);
RSB_OPCODE: Result := Format('rsb%s %s, %s', [operand1, regCodes[Rn], operand2]);
ADD_OPCODE: Result := Format('add%s %s, %s', [operand1, regCodes[Rn], operand2]);
ADC_OPCODE: Result := Format('adc%s %s, %s', [operand1, regCodes[Rn], operand2]);
SBC_OPCODE: Result := Format('sbc%s %s, %s', [operand1, regCodes[Rn], operand2]);
RSC_OPCODE: Result := Format('rsc%s %s, %s', [operand1, regCodes[Rn], operand2]);
ORR_OPCODE: Result := Format('orr%s %s, %s', [operand1, regCodes[Rn], operand2]);
BIC_OPCODE: Result := Format('bic%s %s, %s', [operand1, regCodes[Rn], operand2]);
// Assembler syntax for PSR transfers
// 1 MRS - transfer PSR contents to a register
// MRS{cond} Rd,<psr>
//
// 2 MSR - transfer register contents to PSR
// MSR{cond} <psr>,Rm
//
// 3 MSR - transfer register contents to PSR flag bits only
// MSR{cond} <psrf>,Rm
// The most significant four bits of the register contents are written to the N,Z,C
// & V flags respectively.
//
// 4 MSR - transfer immediate value to PSR flag bits only
// MSR{cond} <psrf>,<#expression>
// The expression should symbolise a 32 bit value of which the most significant
// four bits are written to the N,Z,C and V flags respectively.
//
// Key:
// {cond} two-character condition mnemonic.
// Rd and Rm are expressions evaluating to a register number other than
// R15
// <psr> is CPSR, CPSR_all, SPSR or SPSR_all. (CPSR and
// CPSR_all are synonyms as are SPSR and SPSR_all)
// <psrf> is CPSR_flg or SPSR_flg
// <#expression> where this is used, the assembler will attempt to generate a
// shifted immediate 8-bit field to match the expression. If this is
// impossible, it will give an error.
TST_OPCODE: Result := Format('mrs%-5s%s, CPSR', [condCodes[w shr 28], regCodes[Rd]]);
TEQ_OPCODE: if w and $FFFF0 = $9F000 then begin
// MSR CPSR, Rm cond 00 0 10P1 0 1001 1111 0000 0000 [Rm], P=1
Result := Format('msr%-5sCPSR, %s', [condCodes[w shr 28], regCodes[w and $F]]);
end else if w and $FF000 = $8F000 then begin
// MSR CPSR, Rm cond 00 0 10P1 010001111 0000 0000 [Rm]
// MSR CPSR, operand2 cond 00 1 10P1 010001111 Rotate Immedia
Result := Format('msr%-5sCPSR_flg, %s', [condCodes[w shr 28], operand2]);
end else
Result := '<unknown variant of msr>';
CMP_OPCODE: Result := Format('mrs%-5s%s, SPSR', [condCodes[w shr 28], regCodes[Rd]]);
CMN_OPCODE: if w and $FFFF0 = $9F000 then begin
// MSR SPSR, Rm cond 00 0 10P1 0 1001 1111 0000 0000 [Rm], P=1
Result := Format('msr%-5sSPSR, %s', [condCodes[w shr 28], regCodes[w and $F]]);
end else if w and $FF000 = $8F000 then begin
// MSR SPSR, Rm cond 00 0 10P1 010001111 0000 0000 [Rm]
// MSR SPSR, operand2 cond 00 1 10P1 010001111 Rotate Immedia
Result := Format('msr%-5sSPSR_flg, %s', [condCodes[w shr 28], operand2]);
end else
Result := '<unknown variant of msr>';
end;
end;
end;
//////////////////////////////////////////////////////////////////////
function TArm7Disass.SingleDataTransfer: string;
const
PRE_INCREMENT = 1 shl 24;
FORWARD_BIT = 1 shl 23;
var
Rn, Rd, Rm: byte;
index, operand2: string;
preIncrement: boolean;
addr: uint32;
begin
// Assembler syntax
// <LDR|STR>{cond}{B}{T} Rd,<Address>
//
// where:
// LDR load from memory into a register
//
// STR store from a register into memory
//
// {cond} two-character condition mnemonic.
//
// {B} if B is present then byte transfer, otherwise word transfer
//
// {T} if T is present the W bit will be set in a post-indexed instruction, forcing
// non-privileged mode for the transfer cycle. T is not allowed when a
// pre-indexed addressing mode is specified or implied.
//
// Rd is an expression evaluating to a valid register number.
//
// Rn and Rm are expressions evaluating to a register number. If Rn is R15 then the
// assembler will subtract 8 from the offset value to allow for ARM7TDMI
// pipelining. In this case base write-back should not be specified.
//
// <Address> can be:
// An expression which generates an address:
// <expression>
// The assembler will attempt to generate an instruction using
// the PC as a base and a corrected immediate offset to address
// the location given by evaluating the expression. This will be a
// PC relative, pre-indexed address. If the address is out of
// range, an error will be generated.
//
// A pre-indexed addressing specification:
// [Rn] offset of zero
// [Rn,<#expression>]{!} offset of <expression> bytes
// [Rn,{+/-}Rm{,<shift>}]{!} offset of +/- contents of index register, shifted by <shift>
//
// A post-indexed addressing specification:
// [Rn],<#expression> offset of <expression> bytes
// [Rn],{+/-}Rm{,<shift>} offset of +/- contents of index register, shifted as by <shift>
// Single Data Transfer (LDR, STR)
// The instruction is only executed if the condition is true.
// The single data transfer instructions are used to load or store single bytes or words of
// data. The memory address used in the transfer is calculated by adding an offset to or
// subtracting an offset from a base register.
//
// Data aborts
// A transfer to or from a legal address may cause problems for a memory management
// system. For instance, in a system which uses virtual memory the required data may
// be absent from main memory. The memory manager can signal a problem by taking
// the processor ABORT input HIGH whereupon the Data Abort trap will be taken. It is
// up to the system software to resolve the cause of the problem, then the instruction can
// be restarted and the original program continued.
// Parse the operands
Rn := (w shr 16) and $F;
Rd := (w shr 12) and $F;
Rm := w and $F;
index := regCodes[Rn];
// Offsets
// The offset from the base may be either a 12 bit unsigned binary immediate value in
// the instruction, or a second register (possibly shifted in some way). The offset may be
// added to (U=1) or subtracted from (U=0) the base register Rn. The offset modification
// may be performed either before (pre-indexed, P=1) or after (post-indexed, P=0) the
// base is used as the transfer address.
if w and (1 shl 25) = 0 then
operand2 := Format('#$%x', [w and $FFF])
else
operand2 := BarrelShifter(Rm, (w shr 5) and $3, Format('%d', [(w shr 7) and $1F]));
// Are we indexing forwards or backwards
preIncrement := w and PRE_INCREMENT <> 0;
if operand2 <> '#0' then begin
if preIncrement then begin
if w and FORWARD_BIT <> 0 then index := Format('[%s, %s]', [index, operand2]) else index := Format('[%s, -%s]', [index, operand2]);
if w and (1 shl 21) <> 0 then index := index + '!';
end else begin
if w and FORWARD_BIT <> 0 then index := Format('[%s], %s', [index, operand2]) else index := Format('[%s], -%s', [index, operand2]);
end;
end else
index := '[' + index + ']';
index := Format('%s, %s', [regCodes[Rd], index]);
operand2 := condCodes[w shr 28];
if w and (1 shl 22) <> 0 then operand2 := operand2 + 'b';
// Check the L bit and see if its a load or store
if w and (1 shl 20) <> 0 then begin
if (Rn = R15) and (w and (1 shl 25) = 0) and not UseExactOpcodes then begin
// It's a load 32 bit thingymajig
addr := basePC+8;
if w and FORWARD_BIT <> 0 then addr := addr + w and $FFF else addr := addr - w and $FFF;
Result := Format('ldr%-5s%s, =$%.8x', [operand2, regCodes[Rd], vmReadWord(addr)]);
end else
Result := Format('ldr%-5s%s', [operand2, index]);
end else
Result := Format('str%-5s%s', [operand2, index]);
end;
//////////////////////////////////////////////////////////////////////
function TArm7Disass.BlockDataTransfer: string;
const
LOAD_BIT = 1 shl 20;
WRITEBACK_BIT = 1 shl 21;
INCREMENT_BIT = 1 shl 23;
BEFORE_BIT = 1 shl 24;
var
base: byte;
i: integer;
opcode: string;
begin
// Block Data Transfer (LDM, STM)
//
// Instruction cycle times
// Normal LDM instructions take nS + 1N + 1I and LDM PC takes (n+1)S + 2N + 1I cycles,
// where n is the number of words transferred.
//
// STM instructions take (n-1)S + 2N incremental cycles to execute, where n is the
// number of words transferred.
//
// Assembler syntax
// <LDM|STM>{cond}<FD|ED|FA|EA|IA|IB|DA|DB> Rn{!},<Rlist>{^}
//
// where:
// {cond} two character condition mnemonic.
//
// Rn is an expression evaluating to a valid register number
//
// <Rlist> is a list of registers and register ranges enclosed in {} (e.g. {R0,R2-
// R7,R10}).
//
// {!} if present requests write-back (W=1), otherwise W=0
//
// {^} if present set S bit to load the CPSR along with the PC, or force
// transfer of user bank when in privileged mode
// Addressing mode names
//
// There are different assembler mnemonics for each of the addressing modes,
// depending on whether the instruction is being used to support stacks or for other
// purposes. The equivalence between the names and the values of the bits in the
// instruction are shown in the following table:
//
// FD, ED, FA, EA define pre/post indexing and the up/down bit by reference to the form
// of stack required. The F and E refer to a 揻ull
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -