⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 arm_disass.pas

📁 一个不出名的GBA模拟器
💻 PAS
📖 第 1 页 / 共 2 页
字号:
//////////////////////////////////////////////////////////////////////

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 + -