| /******************************************************************************* |
| * Copyright (c) 2009, 2010 Nokia and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Nokia - Initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.cdt.debug.edc.internal.arm.disassembler; |
| |
| import java.nio.BufferUnderflowException; |
| import java.nio.ByteBuffer; |
| import java.nio.ByteOrder; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.eclipse.cdt.core.IAddress; |
| import org.eclipse.cdt.debug.edc.JumpToAddress; |
| import org.eclipse.cdt.debug.edc.disassembler.AssemblyFormatter; |
| import org.eclipse.cdt.debug.edc.disassembler.CodeBufferUnderflowException; |
| import org.eclipse.cdt.debug.edc.disassembler.DisassembledInstruction; |
| import org.eclipse.cdt.debug.edc.disassembler.IDisassembler; |
| import org.eclipse.cdt.debug.edc.disassembler.IDisassembler.IDisassemblerOptions; |
| import org.eclipse.cdt.debug.edc.internal.arm.ARMPlugin; |
| import org.eclipse.cdt.debug.edc.internal.arm.disassembler.DisassemblerARM.IDisassemblerOptionsARM; |
| import org.eclipse.core.runtime.CoreException; |
| |
| /** |
| * Single instruction disassembler for ARM. |
| */ |
| public class InstructionParserARM { |
| |
| public static final int DISASSEMBLER_MODE_ARM = 1; |
| public static final int DISASSEMBLER_MODE_THUMB = 2; |
| public static final int BIG_ENDIAN_MODE = 1; |
| public static final int LITTLE_ENDIAN_MODE = 2; |
| |
| public static final int ARMv4 = 400; |
| public static final int ARMv4T = 401; |
| public static final int ARMv5 = 500; |
| public static final int ARMv6T = 601; |
| public static final int ARMv6 = 600; |
| public static final int ARMv6T2 = 602; |
| public static final int ARMv6K = 640; |
| public static final int ARMv7 = 700; |
| |
| private static final char TAB = '\t'; |
| |
| private List<Integer> prefixes = new ArrayList<Integer>(); |
| private List<Integer> prefixesUsed = new ArrayList<Integer>(); |
| |
| private int endianMode = LITTLE_ENDIAN_MODE; |
| private int disassemblerMode = DISASSEMBLER_MODE_THUMB; |
| private int versionMode = ARMv7; |
| private Map<String, Object> disassemblerOptions = null; |
| |
| /** |
| * address of the first byte of the instruction |
| */ |
| private IAddress address; |
| |
| /** |
| * raw data of the instruction. |
| */ |
| private ByteBuffer codeBuffer; |
| |
| /** |
| * start value of position (read pointer) of the code ByteBuffer. |
| */ |
| final private int startPosition; |
| |
| /** |
| * result of disassembling the instruction, an |
| * {@link DisassembledInstruction} object. |
| */ |
| private DisassembledInstruction result = null; |
| |
| private boolean isSoleDestination; |
| private boolean isSubroutineAddress; |
| private IAddress jumpToAddr; |
| private String addrExpression; |
| |
| /** |
| * prepare to disassemble the instruction at the current position of the |
| * given byte buffer. |
| */ |
| public InstructionParserARM(IAddress addr, ByteBuffer codeBuffer) { |
| this.address = addr; |
| this.codeBuffer = codeBuffer; |
| this.startPosition = codeBuffer.position(); |
| } |
| |
| private void initialize(Map<String, Object> options) { |
| prefixes.clear(); |
| prefixesUsed.clear(); |
| isSoleDestination = false; |
| isSubroutineAddress = false; |
| jumpToAddr = null; |
| addrExpression = null; |
| result = new DisassembledInstruction(); // start new |
| |
| // Make sure the code buffer is in big-endian |
| if (codeBuffer.order() == ByteOrder.LITTLE_ENDIAN) |
| codeBuffer.order(ByteOrder.BIG_ENDIAN); |
| |
| disassemblerOptions = options; |
| |
| Object mode = options.get(IDisassemblerOptionsARM.ENDIAN_MODE); |
| endianMode = (mode != null) ? ((Integer) mode).intValue() : LITTLE_ENDIAN_MODE; |
| |
| mode = options.get(IDisassemblerOptionsARM.DISASSEMBLER_MODE); |
| disassemblerMode |
| = (mode != null) ? ((Integer) mode).intValue() : DISASSEMBLER_MODE_THUMB; |
| |
| mode = options.get(IDisassemblerOptionsARM.VERSION_MODE); |
| versionMode |
| = (mode != null) ? ((Integer) mode).intValue() : ARMv7; |
| } |
| |
| /** |
| * Disassemble the given byte buffer to get one instruction. This method can |
| * be called more than once to disassemble the same instruction with |
| * different options. |
| * |
| * @param options |
| * - disassembler options |
| * @return output of disassembling the instruction, an |
| * {@link DisassembledInstruction} object. |
| * @throws CoreException |
| */ |
| public DisassembledInstruction disassemble(Map<String, Object> options) |
| throws CoreException { |
| initialize(options); |
| |
| String mnemonics = null; |
| CoreException err = null; |
| |
| try { |
| if (disassemblerMode == DISASSEMBLER_MODE_ARM) { |
| mnemonics = parseARMOpcode(); |
| } else { |
| mnemonics = parseThumbOpcode(); |
| } |
| } catch (BufferUnderflowException e) { |
| throw new CodeBufferUnderflowException(e); |
| } |
| |
| // Now we are done with parsing. |
| // Fill in result. |
| // |
| int instSize = codeBuffer.position() - startPosition; |
| result.setSize(instSize); |
| StringBuffer asmOutput = new StringBuffer(); |
| |
| // Note we want to show "address" and "bytes" in |
| // error message when error/exception occurs. |
| |
| if (checkBooleanOption(IDisassemblerOptions.MNEMONICS_SHOW_ADDRESS) || err != null) { |
| asmOutput.append(AssemblyFormatter.formatForAddressColumn(address)); |
| } |
| |
| if (checkBooleanOption(IDisassemblerOptions.MNEMONICS_SHOW_BYTES) || err != null) { |
| int currPos = codeBuffer.position(); |
| asmOutput.append(AssemblyFormatter.formatForByteColumn(codeBuffer, startPosition, instSize)); |
| codeBuffer.position(currPos); |
| } |
| |
| if (err != null) { |
| // create informative error message |
| String msg = "Fail to disassemble this instruction (address + code-bytes): " + asmOutput.toString(); |
| msg += "\nCause: " + err.getMessage(); |
| throw ARMPlugin.newCoreException(msg); |
| } else { |
| // Now fill in output. |
| result.setAddress(address); |
| |
| fillInJumpToAddress(); |
| |
| // Append the instruction proper |
| asmOutput.append(mnemonics); |
| |
| result.setMnemonics(asmOutput.toString()); |
| } |
| |
| return result; |
| } |
| |
| private boolean checkBooleanOption(String option) { |
| if (!disassemblerOptions.containsKey(option)) |
| return false; |
| |
| Boolean value = (Boolean) disassemblerOptions.get(option); |
| return value.booleanValue(); |
| } |
| |
| private void fillInJumpToAddress() { |
| JumpToAddress jta = null; |
| if (jumpToAddr != null) { |
| jta = new JumpToAddress(jumpToAddr, isSoleDestination, isSubroutineAddress); |
| } else if (addrExpression != null) { |
| jta = new JumpToAddress(addrExpression, isSoleDestination, isSubroutineAddress); |
| } |
| result.setJumpToAddress(jta); |
| } |
| |
| /** |
| * Disassemble a 32-bit ARM instruction |
| * Reference manual citations (e.g., "A8.6.16") refer to sections in the ARM Architecture |
| * Reference Manual ARMv7-A and ARMv7-R Edition, Errata markup |
| * @return disassembled instruction |
| */ |
| private String parseARMOpcode() { |
| byte b0, b1, b2, b3; |
| if (endianMode == BIG_ENDIAN_MODE) { |
| b0 = codeBuffer.get(); |
| b1 = codeBuffer.get(); |
| b2 = codeBuffer.get(); |
| b3 = codeBuffer.get(); |
| } else { |
| b3 = codeBuffer.get(); |
| b2 = codeBuffer.get(); |
| b1 = codeBuffer.get(); |
| b0 = codeBuffer.get(); |
| } |
| int opcode |
| = ((b0 & 0xff) << 24) + ((b1 & 0xff) << 16) + ((b2 & 0xff) << 8) + ((b3 & 0xff)); |
| |
| OpcodeARM.Index opcodeIndex = OpcodeARM.Index.invalid; |
| String mnemonic = ""; |
| |
| for (OpcodeARM armOpcode : OpcodeARM.arm_opcode_table) { |
| int result = opcode & armOpcode.getOpcodeMask(); |
| if (result == armOpcode.getOpcodeResult()) { |
| opcodeIndex = armOpcode.getIndex(); |
| mnemonic = armOpcode.getMnemonic(); |
| break; |
| } |
| } |
| |
| String instruction = ""; |
| String condString = ""; |
| |
| String tempStr = ""; |
| long offset; |
| int startReg; // first reg in range |
| int imm; // immediate |
| int reg; // register |
| int q; // VFP bit to decide whether to use q or d registers |
| int fld1; // arbitrary instruction field |
| |
| switch (opcodeIndex) { |
| case arm_b: // A8.6.16 B |
| // b<c> <label> |
| case arm_bl: // A8.6.23 BL, BLX (immediate) |
| // bl<c> <label> |
| offset = getBranchOffset(opcode); |
| condString = getArmCondition(opcode); |
| isSoleDestination = (condString.length() == 0); // true if unconditional b or bl |
| isSubroutineAddress = (opcodeIndex == OpcodeARM.Index.arm_bl); // only bl is a subroutine call |
| jumpToAddr = address.add(offset); // immediate address known |
| instruction = mnemonic + condString + "\t" + jumpToAddr.toHexAddressString(); |
| break; |
| |
| case arm_blx__imm: // A8.6.23 BL, BLX (immediate) |
| // blx <label> |
| offset = getBranchOffset(opcode) | ((opcode >> 23) & 2); |
| isSoleDestination = true; // no condition |
| isSubroutineAddress = true; |
| jumpToAddr = address.add(offset); // immediate address known |
| instruction = mnemonic + "\t" + jumpToAddr.toHexAddressString(); |
| break; |
| |
| case arm_blx__reg: // A8.6.24 BLX (register) |
| // blx<c> <Rm> |
| condString = getArmCondition(opcode); |
| tempStr = getR_0(opcode); |
| instruction = mnemonic + condString + "\t" + tempStr; |
| isSoleDestination = (condString.length() == 0); // true if unconditional blx |
| isSubroutineAddress = true; |
| addrExpression = tempStr; // branches to the address in Rm register |
| break; |
| |
| case arm_bx: // A8.6.25 BX |
| // bx<c> Rm |
| case arm_bxj: // A8.6.26 BXJ |
| // bxj<c> <Rm> |
| condString = getArmCondition(opcode); |
| tempStr = getR_0(opcode); |
| instruction = mnemonic + condString + "\t" + tempStr; |
| isSoleDestination = (condString.length() == 0); // true if unconditional bx |
| isSubroutineAddress = false; |
| addrExpression = tempStr; // branches to the address in Rm register |
| break; |
| |
| case arm_adc__imm: // A8.6.1 ADC (immediate) |
| // adc{s}<c> <Rd>,<Rn>,#<const> |
| case arm_adc__reg: // A8.6.2 ADC (register) |
| // adc{s}<c> <Rd>,<Rn>,<Rm>{,<shift>} |
| case arm_add__imm: // A8.6.5 ADD (immediate, ARM) |
| // add{s}<c> <Rd>,<Rn>,#<const> |
| // A8.6.8 ADD (SP plus immediate) |
| // add{s}<c> <Rd>,sp,#<const> |
| case arm_add__reg: // A8.6.6 ADD (register) |
| // add{s}<c> <Rd>,<Rn>,<Rm>{,<shift>} |
| // A8.6.9 ADD (SP plus register) |
| // add{s}<c> <Rd>,sp,<Rm>{,<shift>} |
| case arm_and__imm: // A8.6.11 AND (immediate) |
| // and{s}<c> <Rd>,<Rn>,#<const> |
| case arm_and__reg: // A8.6.12 AND (register) |
| // and{s}<c> <Rd>,<Rn>,<Rm>{,<shift>} |
| case arm_bic__imm: // A8.6.19 BIC (immediate) |
| // bic{s}<c> <Rd>,<Rn>,#<const> |
| case arm_bic__reg: // A8.6.20 BIC (register) |
| // bic{s}<c> <Rd>,<Rn>,<Rm>{,<shift>} |
| case arm_eor__imm: // A8.6.44 EOR (immediate) |
| // eor{s}<c> <Rd>,<Rn>,#<const> |
| case arm_eor__reg: // A8.6.45 EOR (register) |
| // eor{s}<c> <Rd>,<Rn>,<Rm>{,<shift>} |
| case arm_orr__imm: // A8.6.113 ORR (immediate) |
| // orr{s}<c> <Rd>,<Rn>,#<const> |
| case arm_orr__reg: // A8.6.114 ORR (register) |
| // orr{s}<c> <Rd>,<Rn>,<Rm>{,<shift>} |
| case arm_rsb__imm: // A8.6.142 RSB (immediate) |
| // rsb{s}<c> <Rd>,<Rn>,#<const> |
| case arm_rsb__reg: // A8.6.143 RSB (register) |
| // rsb{s}<c> <Rd>,<Rn>,<Rm>{,<shift>} |
| case arm_rsc__imm: // A8.6.145 RSC (immediate) |
| // rsc{s}<c> <Rd>,<Rn>,#<const> |
| case arm_rsc__reg: // A8.6.146 RSC (register) |
| // rsc{s}<c> <Rd>,<Rn>,<Rm>{,<shift>} |
| case arm_sbc__imm: // A8.6.151 SBC (immediate) |
| // sbc{s}<c> <Rd>,<Rn>,#<const> |
| case arm_sbc__reg: // A8.6.152 SBC (register) |
| // sbc{s}<c> <Rd>,<Rn>,<Rm>{,<shift>} |
| case arm_sub__imm: // A8.6.212 SUB (immediate, ARM) |
| // sub{s}<c> <Rd>,<Rn>,#<const> |
| // A8.6.215 SUB (SP minus immediate) |
| // sub{s}<c> <Rd>,sp,#<const> |
| case arm_sub__reg: // A8.6.213 SUB (register) |
| // sub{s}<c> <Rd>,<Rn>,<Rm>{,<shift>} |
| // A8.6.216 SUB (SP minus register) |
| // sub{s} <Rd>,sp,<Rm>{,<shift>} |
| condString = getArmCondition(opcode); |
| tempStr = getR_12(opcode); |
| instruction = mnemonic + getS(opcode) + condString + "\t" |
| + tempStr + "," + getR_16(opcode) + "," + getShifterOperand(opcode); |
| |
| if (tempStr.equals("pc")) |
| setDefaultPCJumpProperties(condString.length() == 0); // true if unconditional |
| break; |
| |
| case arm_adc__rsr: // A8.6.3 ADC (register-shifted register) |
| // adc{s}<c> <Rd>,<Rn>,<Rm>,<type> <Rs> |
| case arm_add__rsr: // A8.6.7 ADD (register-shifted register) |
| // add{s}<c> <Rd>,<Rn>,<Rm>,<type> <Rs> |
| case arm_and__rsr: // A8.6.13 AND (register-shifted register) |
| // and{s}<c> <Rd>,<Rn>,<Rm>,<type> <Rs> |
| case arm_bic__rsr: // A8.6.21 BIC (register-shifted register) |
| // bic{s}<c> <Rd>,<Rn>,<Rm>,<type> <Rs> |
| case arm_eor__rsr: // A8.6.46 EOR (register-shifted register) |
| // eor{s}<c> <Rd>,<Rn>,<Rm>,<type> <Rs> |
| case arm_orr__rsr: // A8.6.115 ORR (register-shifted register) |
| // orr{s}<c> <Rd>,<Rn>,<Rm>,<type> <Rs> |
| case arm_rsb__rsr: // A8.6.144 RSB (register-shifted register) |
| // rsb{s}<c> <Rd>,<Rn>,<Rm>,<type> <Rs> |
| case arm_rsc__rsr: // A8.6.147 RSC (register-shifted register) |
| // rsc{s}<c> <Rd>,<Rn>,<Rm>,<type> <Rs> |
| case arm_sbc__rsr: // A8.6.153 SBC (register-shifted register) |
| // sbc{s}<c> <Rd>,<Rn>,<Rm>,<type> <Rs> |
| case arm_sub__rsr: // A8.6.214 SUB (register-shifted register) |
| // sub{s}<c> <Rd>,<Rn>,<Rm>,<type> <Rs> |
| instruction = mnemonic + getS(opcode) + getArmCondition(opcode) + "\t" |
| + getR_12(opcode) + "," + getR_16(opcode) + "," + getShifterOperand(opcode); |
| // No PC check: if Rd is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_adr__higher: // A8.6.10 ADR |
| // adr<c> <Rd>,<label> |
| // add<c> <Rd>,pc,#imm12 Alternate form |
| case arm_adr__lower: // A8.6.10 ADR |
| // adr<c> <Rd>,<label> |
| // sub<c> <Rd>,pc,#imm12 Alternate form |
| condString = getArmCondition(opcode); |
| tempStr = getR_12(opcode); |
| imm = opcode & 0xfff; |
| instruction = mnemonic + condString + "\t" + tempStr + ",pc,#" + getHexValue(imm); |
| |
| if (tempStr.equals("pc")) |
| setDefaultPCJumpProperties(condString.length() == 0); // true if unconditional |
| break; |
| |
| case arm_asr__imm: // A8.6.14 ASR (immediate) |
| // asr{s}<c> <Rd>,<Rm>,#<imm> |
| case arm_lsl__imm: // A8.6.88 LSL (immediate) |
| // lsl{s}<c> <Rd>,<Rm>,#<imm5> |
| case arm_lsr__imm: // A8.6.90 LSR (immediate) |
| // lsr{s}<c> <Rd>,<Rm>,#<imm> |
| case arm_ror__imm: // A8.6.139 ROR (immediate) |
| // ror{s}<c> <Rd>,<Rm>,#<imm> |
| condString = getArmCondition(opcode); |
| tempStr = getR_12(opcode); |
| imm = (opcode >> 7) & 0x1f; |
| if (imm == 0) |
| imm = 32; |
| instruction = mnemonic + getS(opcode) + condString + "\t" |
| + tempStr + "," + getR_0(opcode) + ",#" + imm; |
| |
| if (tempStr.equals("pc")) |
| setDefaultPCJumpProperties(condString.length() == 0); // true if unconditional |
| break; |
| |
| case arm_asr__reg: // A8.6.15 ASR (register) |
| // asr{s}<c> <Rd>,<Rn>,<Rm> |
| case arm_lsl__reg: // A8.6.89 LSL (register) |
| // lsl{s}<c> <Rd>,<Rn>,<Rm> |
| case arm_lsr__reg: // A8.6.91 LSR (register) |
| // lsr{s}<c> <Rd>,<Rn>,<Rm> |
| case arm_ror__reg: // A8.6.140 ROR (register) |
| // ror{s}<c> <Rd>,<Rn>,<Rm> |
| instruction = mnemonic + getS(opcode) + getArmCondition(opcode) + "\t" |
| + getR_12(opcode) + "," + getR_0(opcode) + "," + getR_8(opcode); |
| // No PC check: if Rd, Rn, or Rm is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_bfc: // A8.6.17 BFC |
| // bfc<c> <Rd>,#<lsb>,#<width> |
| { |
| int lsb = (opcode >> 7) & 0x1f; |
| int msb = (opcode >> 16) & 0x1f; |
| int width = msb - lsb + 1; |
| if (msb < lsb) |
| width = 0; |
| instruction = mnemonic + getArmCondition(opcode) + "\t" |
| + getR_12(opcode) + ",#" + lsb + ",#" + width; |
| } |
| // No PC check: if Rd is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_bfi: // A8.6.18 BFI |
| // bfi<c> <Rd>,<Rn>,#<lsb>,#<width> |
| { |
| int lsb = (opcode >> 7) & 0x1f; |
| int msb = (opcode >> 16) & 0x1f; |
| int width = msb - lsb + 1; |
| if (msb < lsb) |
| width = 0; |
| instruction = mnemonic + getArmCondition(opcode) + "\t" |
| + getR_12(opcode) + "," + getR_0(opcode) + ",#" + lsb + ",#" + width; |
| } |
| // No PC check: if Rd is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_bkpt: // A8.6.22 BKPT |
| // bkpt #<imm16> |
| instruction = mnemonic + "\t" + "#" + getHexValue((((opcode >> 4) & 0xfff0) | (opcode & 0xf))); |
| // No PC check: not applicable |
| break; |
| |
| case arm_cdp: // A8.6.28 CDP, CDP2 |
| // cdp<c> <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2> |
| mnemonic += getArmCondition(opcode); |
| case arm_cdp2: // A8.6.28 CDP, CDP2 |
| // cdp2<c> <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2> |
| instruction = mnemonic + "\t" + getCo_cdp_operands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_clrex: // A8.6.30 CLREX |
| // clrex |
| if (ARMv6K > versionMode) { |
| instruction = IDisassembler.INVALID_OPCODE; |
| break; |
| } |
| instruction = mnemonic; |
| // No PC check: not applicable |
| break; |
| |
| case arm_clz: // A8.6.31 CLZ |
| // clz<c> <Rd>,<Rm> |
| case arm_rbit: // A8.6.134 RBIT |
| // rbit<c> <Rd>,<Rm> |
| case arm_rev: // A8.6.135 REV |
| // rev<c> <Rd>,<Rm> |
| case arm_rev16: // A8.6.136 REV16 |
| // rev16<c> <Rd>,<Rm> |
| case arm_revsh: // A8.6.137 REVSH |
| // revsh<c> <Rd>,<Rm> |
| instruction = mnemonic + getArmCondition(opcode) + "\t" + getR_12(opcode) + "," + getR_0(opcode); |
| // No PC check: if Rd or Rm is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_cmn__imm: // A8.6.32 CMN (immediate) |
| // cmn<c> <Rn>,#<const> |
| case arm_cmp__imm: // A8.6.35 CMP (immediate) |
| // cmp<c> <Rn>,#<const> |
| case arm_teq__imm: // A8.6.227 TEQ (immediate) |
| // teq<c> <Rn>,#<const> |
| case arm_tst__imm: // A8.6.230 TST (immediate) |
| // tst<c> <Rn>,#<const> |
| imm = opcode & 0xfff; |
| instruction = mnemonic + getArmCondition(opcode) + "\t" + getR_16(opcode) + "," + getShifterOperand(opcode); |
| // No PC check: no registers changed |
| break; |
| |
| case arm_cmn__reg: // A8.6.33 CMN (register) |
| // cmn<c> <Rn>,<Rm>{,<shift>} |
| case arm_cmn__rsr: // A8.6.34 CMN (register-shifted register) |
| // cmn<c> <Rn>,<Rm>,<type> <Rs> |
| case arm_cmp__reg: // A8.6.36 CMP (register) |
| // cmp<c> <Rn>,<Rm>{,<shift>} |
| case arm_cmp__rsr: // A8.6.37 CMP (register-shifted register) |
| // cmp<c> <Rn>,<Rm>,<type> <Rs> |
| case arm_teq__reg: // A8.6.228 TEQ (register) |
| // teq<c> <Rn>,<Rm>{,<shift>} |
| case arm_teq__rsr: // A8.6.229 TEQ (register-shifted register) |
| // teq<c> <Rn>,<Rm>,<type> <Rs> |
| case arm_tst__reg: // A8.6.231 TST (register) |
| // tst<c> <Rn>,<Rm>{,<shift>} |
| case arm_tst__rsr: // A8.6.232 TST (register-shifted register) |
| // tst<c> <Rn>,<Rm>,<type> <Rs> |
| instruction = mnemonic + getArmCondition(opcode) + "\t" |
| + getR_16(opcode) + "," + getShifterOperand(opcode); |
| // No PC check: no registers changed |
| break; |
| |
| case arm_cps: // B6.1.1 CPS |
| // cps<effect> <iflags>{,#<mode>} |
| // cps #<mode> |
| instruction = mnemonic + getCo_cps_instruction(opcode, false); |
| // No PC check: not applicable |
| break; |
| |
| case arm_dbg: // A8.6.40 DBG |
| // dbg<c> #<option> |
| if (ARMv6T2 > versionMode) |
| instruction = IDisassembler.INVALID_OPCODE; |
| else if (ARMv7 > versionMode) |
| instruction = "nop" + getArmCondition(opcode); |
| else |
| instruction = mnemonic + getArmCondition(opcode) + "\t" + "#" + (opcode & 0xf); |
| // No PC check: no registers changed |
| break; |
| |
| case arm_dmb: // A8.6.41 DMB |
| // dmb #<option> |
| case arm_dsb: // A8.6.42 DSB |
| // dsb #<option> |
| if (ARMv7 > versionMode) |
| instruction = IDisassembler.INVALID_OPCODE; |
| else |
| instruction = mnemonic + "\t" + getDataBarrierOption(opcode); |
| // No PC check: no registers changed |
| break; |
| |
| case arm_isb: // A8.6.49 ISB |
| // isb #<option> |
| if (ARMv7 > versionMode) |
| instruction = IDisassembler.INVALID_OPCODE; |
| else |
| instruction = mnemonic + "\t" + getInstructionBarrierOption(opcode); |
| // No PC check: no registers changed |
| break; |
| |
| case arm_ldc__imm: // A8.6.51 LDC, LDC2 (immediate) |
| // ldc{l}<c> <coproc>,<CRd>,[<Rn>,#+/-<imm>]{!} |
| // ldc{l}<c> <coproc>,<CRd>,[<Rn>],#+/-<imm> |
| // ldc{l}<c> <coproc>,<CRd>,[<Rn>],<option> |
| case arm_ldc__lit: // A8.6.52 LDC, LDC2 (literal) |
| // ldc{l}<c> <coproc>,<CRd>,<label> |
| // ldc{l}<c> <coproc>,<CRd>,[pc,#-0] Special case |
| // ldc{l}<c> <coproc>,<CRd>,[pc],<option> |
| case arm_ldc2__imm: // A8.6.51 LDC, LDC2 (immediate) |
| // ldc2{l}<c> <coproc>,<CRd>,[<Rn>,#+/-<imm>]{!} |
| // ldc2{l}<c> <coproc>,<CRd>,[<Rn>],#+/-<imm> |
| // ldc2{l}<c> <coproc>,<CRd>,[<Rn>],<option> |
| case arm_ldc2__lit: // A8.6.52 LDC, LDC2 (literal) |
| // ldc2{l}<c> <coproc>,<CRd>,<label> |
| // ldc2{l}<c> <coproc>,<CRd>,[pc,#-0] Special case |
| // ldc2{l}<c> <coproc>,<CRd>,[pc],<option> |
| case arm_stc: // A8.6.188 STC, STC2 |
| // stc{l}<c> <coproc>,<CRd>,[<Rn>,#+/-<imm>]{!} |
| // stc{l}<c> <coproc>,<CRd>,[<Rn>],#+/-<imm> |
| // stc{l}<c> <coproc>,<CRd>,[<Rn>],<option> |
| case arm_stc2: // A8.6.188 STC, STC2 |
| // stc2{l}<c> <coproc>,<CRd>,[<Rn>,#+/-<imm>]{!} |
| // stc2{l}<c> <coproc>,<CRd>,[<Rn>],#+/-<imm> |
| // stc2{l}<c> <coproc>,<CRd>,[<Rn>],<option> |
| instruction = mnemonic + getL(opcode) + getArmCondition(opcode) + "\t" |
| + getCoprocessor(opcode) + "," + getCR_12(opcode) + "," + getAddrModeImm8(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_ldr__imm: // A8.6.58 LDR (immediate, ARM) |
| // ldr<c> <Rt>,[<Rn>{,#+/-<imm12>}] |
| // ldr<c> <Rt>,[<Rn>],#+/-<imm12> |
| // ldr<c> <Rt>,[<Rn>,#+/-<imm12>]! |
| case arm_strt__imm: // A8.6.210 STRT |
| // strt<c> <Rt>, [<Rn>] {, +/-<imm12>} |
| condString = getArmCondition(opcode); |
| tempStr = getR_12(opcode); |
| instruction = mnemonic + condString + "\t" + tempStr + "," + getAddrMode2(opcode, 24); |
| |
| // only the load can change the PC |
| if (isBitEnabled(opcode, 20) && tempStr.equals("pc")) |
| setDefaultPCJumpProperties(condString.length() == 0); // true if unconditional |
| break; |
| |
| case arm_ldr__lit: // A8.6.59 LDR (literal) |
| // ldr<c> <Rt>,<label> |
| // ldr<c> <Rt>,[pc,#+/-<imm>] Alternative form |
| condString = getArmCondition(opcode); |
| tempStr = getR_12(opcode); |
| imm = opcode & 0xfff; |
| instruction = mnemonic + condString + "\t" |
| + tempStr + "," + getAddrModePCImm(opcode, imm); |
| |
| if (tempStr.equals("pc")) |
| setDefaultPCJumpProperties(condString.length() == 0); // true if unconditional |
| break; |
| |
| case arm_ldrb__imm: // A8.6.62 LDRB (immediate, ARM) |
| // ldrb<c> <Rt>,[<Rn>{,#+/-<imm12>}] |
| // ldrb<c> <Rt>,[<Rn>],#+/-<imm12> |
| // ldrb<c> <Rt>,[<Rn>,#+/-<imm12>]! |
| case arm_ldrbt__imm: // A8.6.65 LDRBT |
| // ldrbt<c> <Rt>,[<Rn>],#+/-<imm12> |
| case arm_ldrt__imm: // A8.6.65 LDRBT |
| // ldrt<c> <Rt>, [<Rn>] {, #+/-<imm12>} |
| case arm_str__imm: // A8.6.194 STR (immediate, ARM) |
| // str<c> <Rt>,[<Rn>{,#+/-<imm12>}] |
| // str<c> <Rt>,[<Rn>],#+/-<imm12> |
| // str<c> <Rt>,[<Rn>,#+/-<imm12>]! |
| case arm_strb__imm: // A8.6.197 STRB (immediate, ARM) |
| // strb<c> <Rt>,[<Rn>{,#+/-<imm12>}] |
| // strb<c> <Rt>,[<Rn>],#+/-<imm12> |
| // strb<c> <Rt>,[<Rn>,#+/-<imm12>]! |
| instruction = mnemonic + getArmCondition(opcode) + "\t" + getR_12(opcode) + "," + getAddrMode2(opcode, 24); |
| // No PC check: for non-str, if Rt is PC, the instruction is UNPREDICTABLE; |
| // for str, the destination is memory - not a register |
| break; |
| |
| case arm_ldrb__lit: // A8.6.63 LDRB (literal) |
| // ldrb<c> <Rt>,<label> |
| // ldrb<c> <Rt>,[pc,#+/-<imm>] Alternative form |
| imm = opcode & 0xfff; |
| instruction = mnemonic + getArmCondition(opcode) + "\t" |
| + getR_12(opcode) + "," + getAddrModePCImm(opcode, imm); |
| // No PC check: if Rt is PC, the instruction is UNPREDICTABLE; |
| break; |
| |
| case arm_ldrd__imm: // A8.6.66 LDRD (immediate) |
| // ldrd<c> <Rt>,<Rt2>,[<Rn>{,#+/-<imm8>}] |
| // ldrd<c> <Rt>,<Rt2>,[<Rn>],#+/-<imm8> |
| // ldrd<c> <Rt>,<Rt2>,[<Rn>,#+/-<imm8>]! |
| startReg = (opcode >> 12) & 0xf; |
| instruction = mnemonic + getArmCondition(opcode) + "\t" |
| + getRegName(startReg) + "," + getRegName(startReg + 1) + "," |
| + getAddrModeSplitImm8(opcode); |
| // No PC check: if Rt is odd or is LR (register 14), the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_ldrd__lit: // A8.6.67 LDRD (literal) |
| // ldrd<c> <Rt>,<Rt2>,<label> |
| // ldrd<c> <Rt>,<Rt2>,[pc,#+/-<imm>] Alternative form |
| imm = ((opcode >> 4) & 0xf0) | (opcode & 0xf); |
| startReg = (opcode >> 12) & 0xf; |
| instruction = mnemonic + getArmCondition(opcode) + "\t" |
| + getRegName(startReg) + "," + getRegName(startReg + 1) + "," |
| + getAddrModePCImm(opcode, imm); |
| // No PC check: if Rt is odd or is LR (register 14), the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_ldrh__imm: // A8.6.75 LDRH (literal) |
| // ldrh<c> <Rt>,[<Rn>{,#+/-<imm8>}] |
| // ldrh<c> <Rt>,[<Rn>],#+/-<imm8> |
| // ldrh<c> <Rt>,[<Rn>,#+/-<imm8>]! |
| case arm_ldrsb__imm: // A8.6.81 LDRSBT |
| // ldrsb<c> <Rt>,[<Rn>{,#+/-<imm8>}] |
| // ldrsb<c> <Rt>,[<Rn>],#+/-<imm8> |
| // ldrsb<c> <Rt>,[<Rn>,#+/-<imm8>]! |
| case arm_ldrsh__imm: // A8.6.82 LDRSH (immediate) |
| // ldrsh<c> <Rt>,[<Rn>{,#+/-<imm8>}] |
| // ldrsh<c> <Rt>,[<Rn>],#+/-<imm8> |
| // ldrsh<c> <Rt>,[<Rn>,#+/-<imm8>]! |
| case arm_strh__imm: // A8.6.207 STRH (immediate, ARM) |
| // strh<c> <Rt>,[<Rn>{,#+/-<imm8>}] |
| // strh<c> <Rt>,[<Rn>],#+/-<imm8> |
| // strh<c> <Rt>,[<Rn>,#+/-<imm8>]! |
| instruction = mnemonic + getArmCondition(opcode) + "\t" + getR_12(opcode) |
| + "," + getAddrModeSplitImm8(opcode); |
| // No PC check: if Rt is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_ldrh__lit: // A8.6.75 LDRH (literal) |
| // ldrh<c> <Rt>,<label> |
| // ldrh<c> <Rt>,[pc,#+/-<imm>] Alternative form |
| case arm_ldrsb__lit: // A8.6.79 LDRSB (literal) |
| // ldrsb<c> <Rt>,<label> |
| // ldrsb<c> <Rt>,[pc,#+/-<imm>] Alternative form |
| case arm_ldrsh__lit: // A8.6.83 LDRSH (literal) |
| // ldrsh<c> <Rt>,<label> |
| // ldrsh<c> <Rt>,[pc,#+/-<imm>] Alternative form |
| imm = ((opcode >> 4) & 0xf0) | (opcode & 0xf); |
| instruction = mnemonic + getArmCondition(opcode) + "\t" |
| + getR_12(opcode) + "," + getAddrModePCImm(opcode, imm); |
| // No PC check: if Rt is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_ldm: // A8.6.53 LDM / LDMIA / LDMFD |
| // ldm<c> <Rn>{!},<registers> |
| case arm_ldmda: // A8.6.54 LDMDA / LDMFA |
| // ldmda<c> <Rn>{!},<registers> |
| case arm_ldmdb: // A8.6.55 LDMDB / LDMEA |
| // ldmdb<c> <Rn>{!},<registers> |
| case arm_ldmib: // A8.6.56 LDMIB / LDMED |
| // ldmib<c> <Rn>{!},<registers> |
| case arm_stm__regs: // A8.6.189 STM / STMIA / STMEA |
| // stm<c> <Rn>{!},<registers> |
| case arm_stmda: // A8.6.190 STMDA / STMED |
| // stmda<c> <Rn>{!},<registers> |
| case arm_stmdb: // A8.6.191 STMDB / STMFD |
| // stmdb<c> <Rn>{!},<registers> |
| case arm_stmib: // A8.6.192 STMIB / STMFA |
| // stmib<c> <Rn>{!},<registers> |
| condString = getArmCondition(opcode); |
| tempStr = getRegList(opcode); |
| instruction = mnemonic + condString + "\t" |
| + getR_16(opcode) + getW(opcode) + "," + tempStr; |
| |
| // only the loads can change the PC |
| if (isBitEnabled(opcode, 20) && tempStr.contains("pc")) |
| setDefaultPCJumpProperties(condString.length() == 0); // true if unconditional |
| // Note: having PC (register 15) in the register list is deprecated |
| break; |
| |
| case arm_ldm__exc_ret: // B6.1.2 LDM (exception return) |
| // ldm{<amode>}<c> <Rn>{!},<registers_with_pc>^ |
| condString = getArmCondition(opcode); |
| tempStr = getRegList(opcode); |
| instruction = mnemonic + getAddrMode(opcode) + condString + "\t" |
| + getR_16(opcode) + getW(opcode) + "," + tempStr + "^"; |
| |
| if (tempStr.contains("pc")) |
| setDefaultPCJumpProperties(condString.length() == 0); // true if unconditional |
| break; |
| |
| case arm_ldm__user_reg: // B6.1.3 LDM (user registers) |
| // ldm{<amode>}<c> <Rn>,<registers_without_pc>^ |
| case arm_stm__usr_regs: // stm{amode}<c> <Rn>,<registers>^ |
| // stm{amode}<c> <Rn>,<registers>^ |
| instruction = mnemonic + getAddrMode(opcode) + getArmCondition(opcode) + "\t" |
| + getR_16(opcode) + "," + getRegList(opcode) + "^"; |
| // No PC check: not applicable |
| break; |
| |
| case arm_ldr__reg: // A8.6.60 LDR (register) |
| // ldr<c> <Rt>,[<Rn>,+/-<Rm>{, <shift>}]{!} |
| // ldr<c> <Rt>,[<Rn>],+/-<Rm>{, <shift>} |
| condString = getArmCondition(opcode); |
| tempStr = getR_12(opcode); |
| instruction = mnemonic + condString + "\t" |
| + tempStr + "," + getAddrMode2(opcode, 24); |
| |
| if (tempStr.equals("pc")) |
| setDefaultPCJumpProperties(condString.length() == 0); // true if unconditional |
| break; |
| |
| case arm_ldrb__reg: // A8.6.64 LDRB (register) |
| // ldrb<c> <Rt>,[<Rn>,+/-<Rm>{, <shift>}]{!} |
| // ldrb<c> <Rt>,[<Rn>],+/-<Rm>{, <shift>} |
| case arm_ldrbt__reg: // A8.6.65 LDRBT |
| // ldrbt<c> <Rt>,[<Rn>],+/-<Rm>{, <shift>} |
| case arm_ldrt__reg: // A8.6.86 LDRT |
| // ldrt<c> <Rt>,[<Rn>],+/-<Rm>{, <shift>} |
| case arm_strbt__reg: // A8.6.199 STRBT |
| // strbt<c> <Rt>,[<Rn>],+/-<Rm>{, <shift>} |
| case arm_strt__reg: // A8.6.210 STRT |
| // strt<c> <Rt>,[<Rn>],+/-<Rm>{, <shift>} |
| instruction = mnemonic + getArmCondition(opcode) + "\t" |
| + getR_12(opcode) + "," + getAddrMode2(opcode, 24); |
| // No PC check: for non-str, if Rt is PC, the instruction is UNPREDICTABLE |
| // for str, the destination is memory - not a register |
| break; |
| |
| case arm_ldrd__reg: // A8.6.68 LDRD (register) |
| // ldrd<c> <Rt>,<Rt2>,[<Rn>,+/-<Rm>]{!} |
| // ldrd<c> <Rt>,<Rt2>,[<Rn>],+/-<Rm> |
| case arm_strd__reg: // A8.6.201 STRD (register) |
| // strd<c> <Rt>,<Rt2>,[<Rn>,+/-<Rm>]{!} |
| // strd<c> <Rt>,<Rt2>,[<Rn>],+/-<Rm> |
| startReg = (opcode >> 12) & 0xf; |
| instruction = mnemonic + getArmCondition(opcode) + "\t" + getRegName(startReg) |
| + "," + getRegName(startReg + 1) + "," + getAddrModeSplitImm8(opcode); |
| // No PC check: if Rt is odd or is LR (register 14), the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_ldrex: // A8.6.69 LDREX |
| // ldrex<c> <Rt>,[<Rn>] |
| case arm_ldrexb: // A8.6.70 LDREXB |
| // ldrexb<c> <Rt>, [<Rn>] |
| case arm_ldrexh: // A8.6.72 LDREXH |
| // ldrexh<c> <Rt>, [<Rn>] |
| instruction = mnemonic + getArmCondition(opcode) + "\t" |
| + getR_12(opcode) + ",[" + getR_16(opcode) + "]"; |
| // No PC check: if Rt is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_ldrexd: // A8.6.71 LDREXD |
| // ldrexd<c> <Rt>,<Rt2>,[<Rn>] |
| startReg = (opcode >> 12) & 0xf; |
| instruction = mnemonic + getArmCondition(opcode) + "\t" |
| + getRegName(startReg) + "," + getRegName(startReg + 1) + ",[" + getR_16(opcode) + "]"; |
| // No PC check: if Rt is odd or is LR (register 14), the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_ldrh__reg: // A8.6.76 LDRH (register) |
| // ldrh<c> <Rt>,[<Rn>,+/-<Rm>]{!} |
| // ldrh<c> <Rt>,[<Rn>],+/-<Rm> |
| case arm_ldrsb__reg: // A8.6.80 LDRSB (register) |
| // ldrsb<c> <Rt>,[<Rn>,+/-<Rm>]{!} |
| // ldrsb<c> <Rt>,[<Rn>],+/-<Rm> |
| case arm_ldrsh__reg: // A8.6.85 LDRSHT |
| // ldrsh<c> <Rt>,[<Rn>,+/-<Rm>]{!} |
| // ldrsh<c> <Rt>,[<Rn>],+/-<Rm> |
| case arm_strh__reg: // A8.6.208 STRH (register) |
| // strh<c> <Rt>,[<Rn>,+/-<Rm>]{!} |
| // strh<c> <Rt>,[<Rn>],+/-<Rm> |
| instruction = mnemonic + getArmCondition(opcode) + "\t" + getR_12(opcode) |
| + "," + getAddrModeSplitImm8(opcode); |
| // No PC check: for non-str, if Rt is PC, the instruction is UNPREDICTABLE; |
| // for str, the destination is memory - not a register |
| break; |
| |
| case arm_ldrht__imm: // A8.6.77 LDRHT |
| // ldrht<c> <Rt>, [<Rn>] {, #+/-<imm8>} |
| case arm_ldrsbt__imm: // A8.6.81 LDRSBT |
| // ldrsbt<c> <Rt>, [<Rn>] {, #+/-<imm8>} |
| case arm_ldrsht__imm: // A8.6.85 LDRSHT |
| // ldrsht<c> <Rt>, [<Rn>] {, #+/-<imm8>} |
| case arm_strht__imm: // A8.6.209 STRHT |
| // strht<c> <Rt>, [<Rn>] {, #+/-<imm8>} |
| { |
| int offsetHi = (opcode >> 4) & 0xf0; |
| int offsetLo = opcode & 0xf; |
| offset = offsetHi | offsetLo; |
| instruction = mnemonic + getArmCondition(opcode) + "\t" |
| + getR_12(opcode) + ",[" + getR_16(opcode) + "]"; |
| if (offset != 0) |
| instruction += ",#" + ((isBitEnabled(opcode, 23)) ? "" : "-") + getHexValue(offset); |
| } |
| // No PC check: for non-str, if Rt is PC, the instruction is UNPREDICTABLE; |
| // for str, the destination is memory - not a register |
| break; |
| |
| case arm_ldrht__reg: // A8.6.77 LDRHT |
| // ldrht<c> <Rt>, [<Rn>], +/-<Rm> |
| case arm_ldrsbt__reg: // A8.6.81 LDRSBT |
| // ldrsbt<c> <Rt>, [<Rn>], +/-<Rm> |
| case arm_ldrsht__reg: // A8.6.85 LDRSHT |
| // ldrsht<c> <Rt>, [<Rn>], +/-<Rm> |
| case arm_strht__reg: // A8.6.209 STRHT |
| // strht<c> <Rt>, [<Rn>], +/-<Rm> |
| instruction = mnemonic + getArmCondition(opcode) + "\t" |
| + getR_12(opcode) + ",[" + getR_16(opcode) |
| + (isBitEnabled(opcode, 23) ? "]," : "],-") + getR_0(opcode); |
| // No PC check: for non-str, if Rt is PC, the instruction is UNPREDICTABLE; |
| // for str, the destination is memory - not a register |
| break; |
| |
| case arm_mcr: // A8.6.92 MCR, MCR2 |
| // mcr<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} |
| mnemonic += getArmCondition(opcode); |
| // no break! |
| case arm_mcr2: // A8.6.92 MCR, MCR2 |
| // mcr2<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} |
| instruction = mnemonic + getCo_mcr_operands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_mcrr: // A8.6.93 MCRR, MCRR2 |
| // mcrr<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> |
| case arm_mrrc: // A8.6.101 MRRC, MRRC2 |
| // mrrc<c> <coproc>,<opc>,<Rt>,<Rt2>,<CRm> |
| mnemonic += getArmCondition(opcode); |
| // no break! |
| case arm_mcrr2: // A8.6.93 MCRR, MCRR2 |
| // mcrr2<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> |
| case arm_mrrc2: // A8.6.101 MRRC, MRRC2 |
| // mrrc2<c> <coproc>,<opc>,<Rt>,<Rt2>,<CRm> |
| instruction = mnemonic + getCo_mrr_operands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_mla: // A8.6.94 MLA |
| // mla{s}<c> <Rd>,<Rn>,<Rm>,<Ra> |
| instruction = mnemonic + getS(opcode) + getArmCondition(opcode) + "\t" |
| + getR_16(opcode) + "," + getR_0(opcode) + "," + getR_8(opcode) + "," + getR_12(opcode); |
| // No PC check: if Rd is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_mls: // A8.6.95 MLS |
| // mls<c> <Rd>,<Rn>,<Rm>,<Ra> |
| case arm_usada8: // A8.6.254 USADA8 |
| // usada8<c> <Rd>,<Rn>,<Rm>,<Ra> |
| instruction = mnemonic + getArmCondition(opcode) + "\t" |
| + getR_16(opcode) + "," + getR_0(opcode) + "," + getR_8(opcode) + "," + getR_12(opcode); |
| // No PC check: if Rd is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_mov__imm: // A8.6.96 MOV (immediate) |
| // mov{s}<c> <Rd>,#<const> |
| case arm_mvn__imm: // A8.6.106 MVN (immediate) |
| // mvn{s}<c> <Rd>,#<const> |
| condString = getArmCondition(opcode); |
| tempStr = getR_12(opcode); |
| imm = opcode & 0xfff; |
| instruction = mnemonic + getS(opcode) + condString + "\t" + tempStr + "," + getShifterOperand(opcode); |
| |
| if (tempStr.equals("pc")) |
| setDefaultPCJumpProperties(condString.length() == 0); // true if unconditional |
| break; |
| |
| case arm_mov__reg: // A8.6.97 MOV (register) |
| // mov{s}<c> <Rd>,<Rm> |
| case arm_rrx: // A8.6.141 RRX |
| // rrx{s}<c> <Rd>,<Rm> |
| condString = getArmCondition(opcode); |
| tempStr = getR_12(opcode); |
| instruction = mnemonic + getS(opcode) + condString + "\t" + tempStr + "," + getR_0(opcode); |
| |
| if (tempStr.equals("pc")) |
| setDefaultPCJumpProperties(condString.length() == 0); // true if unconditional |
| break; |
| |
| case arm_movw: // A8.6.96 MOV (immediate) |
| // movw<c> <Rd>,#<imm16> |
| case arm_movt: // A8.6.99 MOVT |
| // movt<c> <Rd>,#<imm16> |
| imm = ((opcode >> 4) & 0xf000) | (opcode & 0xfff); |
| instruction = mnemonic + getArmCondition(opcode) + "\t" |
| + getR_12(opcode) + ",#" + getHexValue(imm); |
| // No PC check: if Rd is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_mrc: // A8.6.100 MRC, MRC2 |
| // mrc<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} |
| mnemonic += getArmCondition(opcode); |
| // no break! |
| case arm_mrc2: // A8.6.100 MRC, MRC2 |
| // mrc2<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} |
| instruction = mnemonic + getCo_mrc_operands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_mrs: // A8.6.102 MRS |
| // mrs<c> <Rd>,<spec_reg> |
| instruction = mnemonic + getArmCondition(opcode) + "\t" + getR_12(opcode) |
| + "," + getStatusReg(opcode, 22); |
| // No PC check: if Rd is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_msr__imm: // A8.6.103 MSR (immediate) |
| // msr<c> <spec_reg>,#<const> |
| case arm_msr__reg: // A8.6.104 MSR (register) |
| // msr<c> <spec_reg>,<Rn> |
| // mask<1> field (CPSR f field; APSR nzcvq bits) |
| // mask<0> field (CPSR s field; APSR g bit) |
| instruction = mnemonic + getArmCondition(opcode) + "\tcpsr_" |
| + (isBitEnabled(opcode, 19) ? "f" : "") |
| + (isBitEnabled(opcode, 18) ? "s" : "") + ","; |
| if (isBitEnabled(opcode, 25)) |
| instruction += getShifterOperand(opcode); |
| else |
| instruction += getR_0(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_msr__sys_imm: // B6.1.6 MSR (immediate) |
| // msr<c> <spec_reg>,#<const> |
| case arm_msr__sys_reg: // B6.1.7 MSR (register) |
| // msr<c> <spec_reg>,<Rn> |
| instruction = mnemonic + getArmCondition(opcode) + "\t" |
| + getStatusReg(opcode, 22) + getStatusRegFields(opcode, 16); |
| if (isBitEnabled(opcode, 25)) |
| instruction += "," + getShifterOperand(opcode); |
| else |
| instruction += "," + getR_0(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_mul: // A8.6.105 MUL |
| // mul{s}<c> <Rd>,<Rn>,<Rm> |
| instruction = mnemonic + getS(opcode) + getArmCondition(opcode) + "\t" |
| + getR_16(opcode) + "," + getR_0(opcode) + "," + getR_8(opcode); |
| // No PC check: if Rd, Rn, or Rm is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_mvn__reg: // A8.6.107 MVN (register) |
| // mvn{s}<c> <Rd>,<Rm>{,<shift>} |
| condString = getArmCondition(opcode); |
| tempStr = getR_12(opcode); |
| instruction = mnemonic + getS(opcode) + condString + "\t" |
| + tempStr + "," + getShifterOperand(opcode); |
| |
| if (tempStr.equals("pc")) |
| setDefaultPCJumpProperties(condString.length() == 0); // true if unconditional |
| break; |
| |
| case arm_mvn__rsr: // A8.6.108 MVN (register-shifted register) |
| // mvn{s}<c> <Rd>,<Rm>,<type> <Rs> |
| instruction = mnemonic + getS(opcode) + getArmCondition(opcode) + "\t" |
| + getR_12(opcode) + "," + getShifterOperand(opcode); |
| // No PC check: if Rn, Rm, or Rs is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_nop: // A8.6.110 NOP |
| // nop<c> |
| if (ARMv6T2 > versionMode) |
| instruction = IDisassembler.INVALID_OPCODE; |
| else |
| instruction = mnemonic + getArmCondition(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_pkh: // A8.6.116 PKH |
| // pkhbt<c> <Rd>,<Rn>,<Rm>{,lsl #<imm>} |
| // pkhtb<c> <Rd>,<Rn>,<Rm>{,asr #<imm>} |
| imm = (opcode >> 7) & 0x1f; |
| // based on tb field (bit 6) |
| if (isBitEnabled(opcode, 6)) { |
| if (imm == 0) |
| imm = 32; |
| instruction = mnemonic + "tb" + getArmCondition(opcode) + "\t" |
| + getR_12(opcode) + "," + getR_16(opcode) + "," + getR_0(opcode) |
| + ",asr #" + imm; |
| } else { |
| instruction = mnemonic + "bt" + getArmCondition(opcode) + "\t" |
| + getR_12(opcode) + "," + getR_16(opcode) + "," + getR_0(opcode); |
| if (imm != 0) |
| instruction += ",lsl #" + imm; |
| } |
| // No PC check: if Rd is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_pld__lit: // A8.6.118 PLD (literal) |
| // pld <label> |
| // pld [pc,#+/-<imm>] Alternative form |
| imm = opcode & 0xfff; |
| instruction = mnemonic + "\t" + getAddrModePCImm(opcode, imm); |
| // No PC check: not applicable |
| break; |
| |
| case arm_pld__imm: // A8.6.117 PLD, PLDW (immediate) |
| // pld{w} [<Rn>,#+/-<imm12>] |
| instruction = mnemonic + (isBitEnabled(opcode, 22) ? "\t" : "w\t") + getAddrMode2(opcode, 24); |
| // No PC check: not applicable |
| break; |
| |
| case arm_pld__reg: // A8.6.119 PLD, PLDW (register) |
| // pld{w}<c> [<Rn>,+/-<Rm>{, <shift>}] |
| mnemonic += (isBitEnabled(opcode, 22) ? "\t" : "w\t") + getArmCondition(opcode); |
| instruction = mnemonic + "\t" + getAddrMode2(opcode, 24); |
| // No PC check: not applicable |
| break; |
| |
| case arm_pli__imm_lit: // A8.6.120 PLI (immediate, literal) |
| // pli [<Rn>,#+/-<imm12>] |
| // pli <label> |
| // pli [pc,#+/-<imm>] Alternative form |
| imm = opcode & 0xfff; |
| instruction = mnemonic + "\t" |
| + (getR_16(opcode).equals("pc") |
| ? getAddrModePCImm(opcode, imm) |
| : getAddrMode2(opcode, 20)); // picked bit 20 because it is 1 |
| // No PC check: not applicable |
| break; |
| |
| case arm_pli__reg: // A8.6.121 PLI (register) |
| // pli [<Rn>,+/-<Rm>{, <shift>}] |
| instruction = mnemonic + "\t" + getAddrMode2(opcode, 20); // picked bit 20 because it is 1 |
| // No PC check: not applicable |
| break; |
| |
| case arm_pop__regs: // A8.6.122 POP |
| // pop<c> <registers> <registers> contains more than one register |
| condString = getArmCondition(opcode); |
| tempStr = getRegList(opcode); |
| instruction = mnemonic + condString + "\t" + tempStr; |
| |
| if (tempStr.contains("pc")) |
| setDefaultPCJumpProperties(condString.length() == 0); // true if unconditional |
| break; |
| |
| case arm_pop__reg: // A8.6.122 POP |
| // pop<c> <registers> <registers> contains one register, <Rt> |
| condString = getArmCondition(opcode); |
| tempStr = getR_12(opcode); |
| instruction = mnemonic + condString + "\t{" + tempStr + "}"; |
| |
| if (tempStr.equals("pc")) |
| setDefaultPCJumpProperties(condString.length() == 0); // true if unconditional |
| break; |
| |
| case arm_push__reg: // A8.6.123 PUSH |
| // push<c> <registers> <registers> contains one register, <Rt> |
| instruction = mnemonic + getArmCondition(opcode) + "\t{" + getR_12(opcode) + "}"; |
| // No PC check: not applicable |
| break; |
| |
| case arm_push__regs: // A8.6.123 PUSH |
| // push<c> <registers> <registers> contains more than one register |
| instruction = mnemonic + getArmCondition(opcode) + "\t" + getRegList(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_qadd: // A8.6.124 QADD |
| // qadd<c> <Rd>,<Rm>,<Rn> |
| case arm_qdadd: // A8.6.128 QDADD |
| // qdadd<c> <Rd>,<Rm>,<Rn> |
| case arm_qdsub: // A8.6.129 QDSUB |
| // qdsub<c> <Rd>,<Rm>,<Rn> |
| case arm_qsub: // A8.6.131 QSUB |
| // qsub<c> <Rd>,<Rm>,<Rn> |
| instruction = mnemonic + getArmCondition(opcode) + "\t" |
| + getR_12(opcode) + "," + getR_0(opcode) + "," + getR_16(opcode); |
| // No PC check: if Rd is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case arm__r_dnm_math: // A8.6.125 QADD16 |
| // qadd16<c> <Rd>,<Rn>,<Rm> |
| // A8.6.126 QADD8 |
| // qadd8<c> <Rd>,<Rn>,<Rm> |
| // A8.6.127 QASX |
| // qasx<c> <Rd>,<Rn>,<Rm> |
| // A8.6.130 QSAX |
| // qsax<c> <Rd>,<Rn>,<Rm> |
| // A8.6.132 QSUB16 |
| // qsub16<c> <Rd>,<Rn>,<Rm> |
| // A8.6.133 QSUB8 |
| // qsub8<c> <Rd>,<Rn>,<Rm> |
| // A8.6.148 SADD16 |
| // sadd16<c> <Rd>,<Rn>,<Rm> |
| // A8.6.149 SADD8 |
| // sadd8<c> <Rd>,<Rn>,<Rm> |
| // A8.6.150 SASX |
| // sasx<c> <Rd>,<Rn>,<Rm> |
| // A8.6.159 SHADD16 |
| // shadd16<c> <Rd>,<Rn>,<Rm> |
| // A8.6.160 SHADD8 |
| // shadd8<c> <Rd>,<Rn>,<Rm> |
| // A8.6.161 SHASX |
| // shasx<c> <Rd>,<Rn>,<Rm> |
| // A8.6.162 SHSAX |
| // shsax<c> <Rd>,<Rn>,<Rm> |
| // A8.6.163 SHSUB16 |
| // shsub16<c> <Rd>,<Rn>,<Rm> |
| // A8.6.164 SHSUB8 |
| // shsub8<c> <Rd>,<Rn>,<Rm> |
| // A8.6.185 SSAX |
| // ssax<c> <Rd>,<Rn>,<Rm> |
| // A8.6.186 SSUB16 |
| // ssub16<c> <Rd>,<Rn>,<Rm> |
| // A8.6.187 SSUB8 |
| // ssub8<c> <Rd>,<Rn>,<Rm> |
| // A8.6.233 UADD16 |
| // uadd16<c> <Rd>,<Rn>,<Rm> |
| // A8.6.234 UADD8 |
| // uadd8<c> <Rd>,<Rn>,<Rm> |
| // A8.6.235 UASX |
| // uasx<c> <Rd>,<Rn>,<Rm> |
| // A8.6.238 UHADD16 |
| // uhadd16<c> <Rd>,<Rn>,<Rm> |
| // A8.6.239 UHADD8 |
| // uhadd8<c> <Rd>,<Rn>,<Rm> |
| // A8.6.240 UHASX |
| // uhasx<c> <Rd>,<Rn>,<Rm> |
| // A8.6.241 UHSAX |
| // uhsax<c> <Rd>,<Rn>,<Rm> |
| // A8.6.242 UHSUB16 |
| // uhsub16<c> <Rd>,<Rn>,<Rm> |
| // A8.6.243 UHSUB8 |
| // uhsub8<c> <Rd>,<Rn>,<Rm> |
| // A8.6.247 UQADD16 |
| // uqadd16<c> <Rd>,<Rn>,<Rm> |
| // A8.6.248 UQADD8 |
| // uqadd8<c> <Rd>,<Rn>,<Rm> |
| // A8.6.249 UQASX |
| // uqasx<c> <Rd>,<Rn>,<Rm> |
| // A8.6.250 UQSAX |
| // uqsax<c> <Rd>,<Rn>,<Rm> |
| // A8.6.251 UQSUB16 |
| // uqsub16<c> <Rd>,<Rn>,<Rm> |
| // A8.6.252 UQSUB8 |
| // uqsub8<c> <Rd>,<Rn>,<Rm> |
| // A8.6.257 USAX |
| // usax<c> <Rd>,<Rn>,<Rm> |
| // A8.6.258 USUB16 |
| // usub16<c> <Rd>,<Rn>,<Rm> |
| // A8.6.259 USUB8 |
| // usub8<c> <Rd>,<Rn>,<Rm> |
| switch (opcode >> 20 & 7) { |
| case 1: mnemonic = "s"; break; |
| case 2: mnemonic = "q"; break; |
| case 3: mnemonic = "sh"; break; |
| case 5: mnemonic = "u"; break; |
| case 6: mnemonic = "uq"; break; |
| case 7: mnemonic = "uh"; break; |
| default: mnemonic = ""; |
| } |
| switch (opcode >> 5 & 7) { |
| case 0: mnemonic += "add16"; break; |
| case 1: mnemonic += "asx"; break; |
| case 2: mnemonic += "sax"; break; |
| case 3: mnemonic += "sub16"; break; |
| case 4: mnemonic += "add8"; break; |
| case 7: mnemonic += "sub8"; break; |
| } |
| // no break! |
| case arm_sel: |
| // sel<c> <Rd>,<Rn>,<Rm> |
| instruction = mnemonic + getArmCondition(opcode) + "\t" |
| + getR_12(opcode) + "," + getR_16(opcode) + "," + getR_0(opcode); |
| // No PC check: if Rd, Rn, or Rm is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_rfe: // B6.1.8 RFE |
| // rfe{<amode>} <Rn>{!} |
| mnemonic += getAddrMode(opcode); |
| instruction = mnemonic + "\t" + getR_16(opcode) + getW(opcode); |
| // loads the PC from memory |
| // Is this right? |
| setDefaultPCJumpProperties(true); // true if unconditional |
| break; |
| |
| case arm_sbfx: // A8.6.154 SBFX |
| // sbfx<c> <Rd>,<Rn>,#<lsb>,#<width> |
| case arm_ubfx: // A8.6.236 UBFX |
| // ubfx<c> <Rd>,<Rn>,#<lsb>,#<width> |
| { |
| int lsb = (opcode >> 7) & 0x1f; |
| int width = ((opcode >> 16) & 0x1f) + 1; |
| instruction = mnemonic + getArmCondition(opcode) + "\t" |
| + getR_12(opcode) + "," + getR_0(opcode) + ",#" + lsb + ",#" +width; |
| } |
| // No PC check: for non-str, if Rd is PC, the instruction is UNPREDICTABLE; |
| // for str, the destination is memory - not a register |
| break; |
| |
| case arm_setend: // A8.6.157 SETEND |
| // setend <endian_specifier> Cannot be conditional |
| instruction = mnemonic + "\t"; |
| if ((opcode & (1 << 9)) == 0) |
| instruction = instruction + "le"; |
| else |
| instruction = instruction + "be"; |
| // No PC check: not applicable |
| break; |
| |
| case arm_sev: // A8.6.158 SEV |
| // sev<c> |
| case arm_wfe: // A8.6.411 WFE |
| // wfe<c> |
| case arm_wfi: // A8.6.412 WFI |
| // wfi<c> |
| case arm_yield: // A8.6.413 YIELD |
| // yield<c> |
| if (ARMv6T2 > versionMode) |
| instruction = IDisassembler.INVALID_OPCODE; |
| else if (ARMv6K > versionMode) |
| instruction = "nop" + getArmCondition(opcode); |
| else |
| instruction = mnemonic + getArmCondition(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_smc: // B6.1.9 SMC (previously SMI) |
| // smc<c> #<imm4> |
| instruction = mnemonic + getArmCondition(opcode) + "\t#" + getHexValue((opcode & 0xf)); |
| // No PC check: not applicable |
| break; |
| |
| case arm_smla: // A8.6.166 SMLABB, SMLABT, SMLATB, SMLATT |
| // smla<x><y><c> <Rd>,<Rn>,<Rm>,<Ra> |
| instruction = mnemonic + getBorT(opcode, 5) + getBorT(opcode, 6) + getArmCondition(opcode) + "\t" |
| + getR_16(opcode) + "," + getR_0(opcode) + "," + getR_8(opcode) + "," + getR_12(opcode); |
| // No PC check: if Rd is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_smlad: // A8.6.167 SMLAD |
| // smlad{x}<c> <Rd>,<Rn>,<Rm>,<Ra> |
| case arm_smlsd: // A8.6.172 SMLSD |
| // smlsd{x}<c> <Rd>,<Rn>,<Rm>,<Ra> |
| instruction = mnemonic + getX(opcode, 5) + getArmCondition(opcode) + "\t" |
| + getR_16(opcode) + "," + getR_0(opcode) + "," + getR_8(opcode) + "," + getR_12(opcode); |
| // No PC check: if Rd is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_smlal: // A8.6.168 SMLAL |
| // smlal{s}<c> <RdLo>,<RdHi>,<Rn>,<Rm> |
| instruction = mnemonic + getS(opcode) + getArmCondition(opcode) + "\t" |
| + getR_12(opcode) + "," + getR_16(opcode) + "," + getR_0(opcode) + "," + getR_8(opcode); |
| // No PC check: if RdLo or RdHi is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_smlalxy: // A8.6.169 SMLALBB, SMLALBT, SMLALTB, SMLALTT |
| // smlal<x><y><c> <RdLo>,<RdHi>,<Rn>,<Rm> |
| instruction = mnemonic + getBorT(opcode, 5) + getBorT(opcode, 6) + getArmCondition(opcode) + "\t" |
| + getR_12(opcode) + "," + getR_16(opcode) + "," + getR_0(opcode) + "," + getR_8(opcode); |
| // No PC check: if RdLo or RdHi is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_smlald: // A8.6.170 SMLALD |
| // smlald{x}<c> <RdLo>,<RdHi>,<Rn>,<Rm> |
| case arm_smlsld: // A8.6.173 SMLSLD |
| // smlsld{x}<c> <RdLo>,<RdHi>,<Rn>,<Rm> |
| instruction = mnemonic + getX(opcode, 5) + getArmCondition(opcode) + "\t" |
| + getR_12(opcode) + "," + getR_16(opcode) + "," + getR_0(opcode) + "," + getR_8(opcode); |
| // No PC check: if Rd is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_smlaw: // A8.6.171 SMLAWB, SMLAWT |
| // smlaw<y><c> <Rd>,<Rn>,<Rm>,<Ra> |
| instruction = mnemonic + getBorT(opcode, 6) + getArmCondition(opcode) + "\t" |
| + getR_16(opcode) + "," + getR_0(opcode) + "," + getR_8(opcode) + "," + getR_12(opcode); |
| // No PC check: if Rd is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_smmla: // A8.6.174 SMMLA |
| // smmla{r}<c> <Rd>,<Rn>,<Rm>,<Ra> |
| case arm_smmls: // A8.6.175 SMMLS |
| // smmls{r}<c> <Rd>,<Rn>,<Rm>,<Ra> |
| instruction = mnemonic + getR(opcode, 5) + getArmCondition(opcode) + "\t" |
| + getR_16(opcode) + "," + getR_0(opcode) + "," + getR_8(opcode) + "," + getR_12(opcode); |
| // No PC check: if Rd is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_smmul: // A8.6.176 SMMUL |
| // smmul{r}<c> <Rd>,<Rn>,<Rm> |
| instruction = mnemonic + getR(opcode, 5) + getArmCondition(opcode) + "\t" |
| + getR_16(opcode) + "," + getR_0(opcode) + "," + getR_8(opcode); |
| // No PC check: if Rd is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_smuad: // A8.6.177 SMUAD |
| // smuad{x}<c> <Rd>,<Rn>,<Rm> |
| case arm_smusd: // A8.6.181 SMUSD |
| // smusd{x}<c> <Rd>,<Rn>,<Rm> |
| instruction = mnemonic + getX(opcode, 5) + getArmCondition(opcode) + "\t" |
| + getR_16(opcode) + "," + getR_0(opcode) + "," + getR_8(opcode); |
| // No PC check: if Rd is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_smul: // A8.6.178 SMULBB, SMULBT, SMULTB, SMULTT |
| // smul<x><y><c> <Rd>,<Rn>,<Rm> |
| instruction = mnemonic + getBorT(opcode, 5) + getBorT(opcode, 6) + getArmCondition(opcode) + "\t" |
| + getR_16(opcode) + "," + getR_0(opcode) + "," + getR_8(opcode); |
| // No PC check: if Rd is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_smull: // A8.6.179 SMULL |
| // smull{s}<c> <RdLo>,<RdHi>,<Rn>,<Rm> |
| instruction = mnemonic + getS(opcode) + getArmCondition(opcode) + "\t" |
| + getR_12(opcode) + "," + getR_16(opcode) + "," + getR_0(opcode) + "," + getR_8(opcode); |
| // No PC check: if RdLo or RdHi is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_smulw: // A8.6.180 SMULWB, SMULWT |
| // smulw<y><c> <Rd>,<Rn>,<Rm> |
| instruction = mnemonic + getBorT(opcode, 6) + getArmCondition(opcode) + "\t" |
| + getR_16(opcode) + "," + getR_0(opcode) + "," + getR_8(opcode); |
| // No PC check: if Rd is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_srs: // B6.1.10 SRS |
| // srs{<amode>} sp{!},#<mode> |
| instruction = mnemonic + getAddrMode(opcode) + "\t" |
| + "sp" + getW(opcode) + ",#" + getHexValue((opcode & 0x1f)); |
| // No PC check: not applicable |
| break; |
| |
| case arm_ssat: // A8.6.183 SSAT |
| // ssat<c> <Rd>,#<imm>,<Rn>{,<shift>} |
| case arm_usat: // A8.6.255 USAT |
| // usat<c> <Rd>,#<imm5>,<Rn>{,<shift>} |
| imm = ((opcode >> 16) & 0x1f); |
| if ((opcode & (1 << 22)) == 0) |
| imm++; |
| |
| if (((opcode >> 6) & 0x3f) != 0) { |
| int shiftCnt = (opcode >> 7) & 0x1f; |
| if ((opcode & (1 << 6)) == 0) |
| tempStr = ",lsl #" + shiftCnt; |
| else { |
| if (shiftCnt == 0) |
| shiftCnt = 32; |
| tempStr = ",asr #" + shiftCnt; |
| } |
| } |
| instruction = mnemonic + getArmCondition(opcode) + "\t" |
| + getR_12(opcode) + ",#" + imm + "," + getR_0(opcode) + tempStr; |
| // No PC check: if Rd is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_ssat16: // A8.6.184 SSAT16 |
| // ssat16<c> <Rd>,#<imm>,<Rn> |
| imm = ((opcode >> 16) & 0xf) + 1; |
| instruction = mnemonic + getArmCondition(opcode) + "\t" |
| + getR_12(opcode) + ",#" + imm + "," + getR_0(opcode); |
| // No PC check: if Rd is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_str__reg: // A8.6.195 STR (register) |
| // str<c> <Rt>,[<Rn>,+/-<Rm>{, <shift>}]{!} |
| // str<c> <Rt>,[<Rn>],+/-<Rm>{, <shift>} |
| case arm_strb__reg: // A8.6.198 STRB (register) |
| // strb<c> <Rt>,[<Rn>,+/-<Rm>{, <shift>}]{!} |
| // strb<c> <Rt>,[<Rn>],+/-<Rm>{, <shift>} |
| case arm_strbt__imm: // A8.6.199 STRBT |
| // strbt<c> <Rt>,[<Rn>],#+/-<imm12> |
| mnemonic += getArmCondition(opcode); |
| instruction = mnemonic + "\t" + getR_12(opcode) + "," + getAddrMode2(opcode, 24); |
| // No PC check: if Rt is PC, the instruction is UNPREDICTABLE; |
| break; |
| |
| case arm_strd__imm: // A8.6.200 STRD (immediate) |
| // strd<c> <Rt>,<Rt2>,[<Rn>{,#+/-<imm8>}] |
| // strd<c> <Rt>,<Rt2>,[<Rn>],#+/-<imm8> |
| // strd<c> <Rt>,<Rt2>,[<Rn>,#+/-<imm8>]! |
| reg = (opcode >> 12) & 0xf; |
| instruction = mnemonic + getArmCondition(opcode) + "\t" + getRegName(reg) |
| + "," + getRegName(reg + 1) + "," + getAddrModeSplitImm8(opcode); |
| // No PC check: if Rt is odd or is LR (register 14), the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_strex: // A8.6.202 STREX |
| // strex<c> <Rd>,<Rt>,[<Rn>] |
| case arm_strexb: // A8.6.203 STREXB |
| // strexb<c> <Rd>,<Rt>,[<Rn>] |
| case arm_strexh: // A8.6.205 STREXH |
| // strexh<c> <Rd>,<Rt>,[<Rn>] |
| instruction = mnemonic + getArmCondition(opcode) + "\t" |
| + getR_12(opcode) + "," + getR_0(opcode) + ",[" + getR_16(opcode) + "]"; |
| // No PC check: if Rd is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_strexd: // A8.6.204 STREXD |
| // strexd<c> <Rd>,<Rt>,<Rt2>,[<Rn>] |
| startReg = opcode & 0xf; |
| instruction = mnemonic + getArmCondition(opcode) + "\t" |
| + getR_12(opcode) + "," + getRegName(startReg) + "," |
| + getRegName(startReg + 1) + ",[" + getR_16(opcode) + "]"; |
| // No PC check: if Rd is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_svc: // A8.6.218 SVC (previously SWI) |
| // svc<c> #<imm24> |
| instruction = mnemonic + getArmCondition(opcode) + "\t" + getImmediate24(opcode); |
| // No PC check: the destination is memory - not a register |
| break; |
| |
| case arm_swp: // A8.6.219 SWP, SWPB |
| // swp{b}<c> <Rt>,<Rt2>,[<Rn>] |
| instruction = mnemonic + getB(opcode) + getArmCondition(opcode) + "\t" |
| + getR_12(opcode) + "," + getR_0(opcode) + ",[" + getR_16(opcode) + "]"; |
| // No PC check: if Rt or Rt2 is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_sxtab: // A8.6.220 SXTAB |
| // sxtab<c> <Rd>,<Rn>,<Rm>{,<rotation>} |
| case arm_sxtab16: // A8.6.221 SXTAB16 |
| // sxtab16<c> <Rd>,<Rn>,<Rm>{,<rotation>} |
| case arm_sxtah: // A8.6.222 SXTAH |
| // sxtah<c> <Rd>,<Rn>,<Rm>{,<rotation>} |
| case arm_uxtab: // A8.6.260 UXTAB |
| // uxtab<c> <Rd>,<Rn>,<Rm>{,<rotation>} |
| case arm_uxtab16: // A8.6.261 UXTAB16 |
| // uxtab16<c> <Rd>,<Rn>,<Rm>{,<rotation>} |
| case arm_uxtah: // A8.6.262 UXTAH |
| // uxtah<c> <Rd>,<Rn>,<Rm>{,<rotation>} |
| instruction = mnemonic + getArmCondition(opcode) + "\t" |
| + getR_12(opcode) + "," + getR_16(opcode) + "," + getR_0(opcode) |
| + getRotationOperand(opcode, 10); |
| // No PC check: if Rd is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_sxtb: // A8.6.223 SXTB |
| // sxtb<c> <Rd>,<Rm>{,<rotation>} |
| case arm_sxtb16: // A8.6.224 SXTB16 |
| // sxtb16<c> <Rd>,<Rm>{,<rotation>} |
| case arm_sxth: // A8.6.225 SXTH |
| // sxth<c> <Rd>,<Rm>{,<rotation>} |
| case arm_uxtb: // A8.6.263 UXTB |
| // uxtb<c> <Rd>,<Rm>{,<rotation>} |
| case arm_uxtb16: // A8.6.264 UXTB16 |
| // uxtb16<c> <Rd>,<Rm>{,<rotation>} |
| case arm_uxth: // A8.6.265 UXTH |
| // uxth<c> <Rd>,<Rm>{,<rotation>} |
| instruction = mnemonic + getArmCondition(opcode) + "\t" |
| + getR_12(opcode) + "," + getR_0(opcode) |
| + getRotationOperand(opcode, 10); |
| // No PC check: if Rd is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_umaal: // A8.6.244 UMAAL |
| // umaal<c> <RdLo>,<RdHi>,<Rn>,<Rm> |
| instruction = mnemonic + getArmCondition(opcode) + "\t" |
| + getR_12(opcode) + "," + getR_16(opcode) + "," + getR_0(opcode) + "," + getR_8(opcode); |
| // No PC check: if RdLo or RdHi is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_umlal: // A8.6.245 UMLAL |
| // umlal{s}<c> <RdLo>,<RdHi>,<Rn>,<Rm> |
| case arm_umull: // A8.6.246 UMULL |
| // umull{s}<c> <RdLo>,<RdHi>,<Rn>,<Rm> |
| instruction = mnemonic + getS(opcode) + getArmCondition(opcode) + "\t" |
| + getR_12(opcode) + "," + getR_16(opcode) + "," + getR_0(opcode) + "," + getR_8(opcode); |
| // No PC check: if RdLo or RdHi is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_usad8: // A8.6.253 USAD8 |
| // usad8<c> <Rd>,<Rn>,<Rm> |
| instruction = mnemonic + getArmCondition(opcode) + "\t" |
| + getR_16(opcode) + "," + getR_0(opcode) + "," + getR_8(opcode); |
| // No PC check: if Rd is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_usat16: // A8.6.256 USAT16 |
| // usat16<c> <Rd>,#<imm4>,<Rn> |
| instruction = mnemonic + getArmCondition(opcode) + "\t" |
| + getR_12(opcode) + ",#" + ((opcode >> 16) & 0xf) + "," + getR_0(opcode); |
| // No PC check: if Rd is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case arm_undefined: |
| instruction = mnemonic; |
| // No PC check: not applicable |
| break; |
| |
| // VFP instructions |
| |
| case arm_vhadd_vhsub: // A8.6.306 VHADD, VHSUB |
| // vhadd<c> <Qd>, <Qn>, <Qm> |
| // vhadd<c> <Dd>, <Dn>, <Dm> |
| // vhsub<c> <Qd>, <Qn>, <Qm> |
| // vhsub<c> <Dd>, <Dn>, <Dm> |
| mnemonic += isBitEnabled(opcode, 9) ? "sub" : "add"; |
| case arm_vaba: // A8.6.266 VABA, VABAL |
| // vaba<c>.<dt> <Qd>, <Qn>, <Qm> |
| // vaba<c>.<dt> <Dd>, <Dn>, <Dm> |
| case arm_vabd__int: // A8.6.267 VABD, VABDL (integer) |
| // vabd<c>.<dt> <Qd>, <Qn>, <Qm> |
| // vabd<c>.<dt> <Dd>, <Dn>, <Dm> |
| case arm_vcge__reg_int: // A8.6.282 VCGE (register) |
| // vceq<c>.<dt> <Qd>, <Qn>, <Qm> |
| // vceq<c>.<dt> <Dd>, <Dn>, <Dm> |
| case arm_vcgt__reg_int: // A8.6.284 VCGT (register) |
| // vcgt<c>.<dt> <Qd>, <Qn>, <Qm> |
| // vcgt<c>.<dt> <Dd>, <Dn>, <Dm> |
| case arm_vqadd: // A8.6.357 VQADD |
| // vqadd<c>.<dt> <Qd>,<Qn>,<Qm> |
| // vqadd<c>.<dt> <Dd>,<Dn>,<Dm> |
| case arm_vrhadd: // A8.6.374 VRHADD |
| // vrhadd<c> <Qd>, <Qn>, <Qm> |
| // vrhadd<c> <Dd>, <Dn>, <Dm> |
| case arm_vqsub: // A8.6.369 VQSUB |
| // vqsub<c>.<type><size> <Qd>, <Qn>, <Qm> |
| // vqsub<c>.<type><size> <Dd>, <Dn>, <Dm> |
| instruction = mnemonic + getVFPSorUDataType(opcode, 24) + getVFPQorDdnmRegs(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vqdml__vec: // A8.6.358 VQDMLAL, VQDMLSL |
| // vqd<op><c>.<dt> <Qd>,<Dn>,<Dm> |
| // bit24 == 0, so can use getVFPSorUDataType |
| mnemonic += isBitEnabled(opcode, 9) ? "sl" : "al"; |
| // can use getVFPSorUDataType() because bit 24 is always '0' |
| // no break! |
| case arm_vabal: // A8.6.266 VABA, VABAL |
| // vabal<c>.<dt> <Qd>,<Dn>,<Dm> |
| case arm_vabdl: // A8.6.267 VABD, VABDL (integer) |
| // vabdl<c>.<dt> <Qd>,<Dn>,<Dm> |
| case arm_vqdmull__vec: // A8.6.360 VQDMULL |
| // vqdmull<c>.<dt> <Qd>,<Dn>,<Dm> |
| // bit24 == 0, so can use getVFPSorUDataType |
| instruction = mnemonic + getVFPSorUDataType(opcode, 24) |
| + TAB + getVFPQdDnDmRegs(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vabd__f32: // A8.6.268 VABD (floating-point) |
| // vabd<c>.f32 <Qd>, <Qn>, <Qm> |
| // vabd<c>.f32 <Dd>, <Dn>, <Dm> |
| case arm_vadd__f32: // A8.6.272 VADD (floating-point) |
| // vadd<c>.f32 <Qd>, <Qn>, <Qm> |
| // vadd<c>.f32 <Dd>, <Dn>, <Dm> |
| case arm_vceq__reg_f32: // A8.6.280 VCEQ (register) |
| // vceq<c>.f32 <Qd>, <Qn>, <Qm> |
| // vceq<c>.f32 <Dd>, <Dn>, <Dm> |
| case arm_vcge__reg_f32: // A8.6.282 VCGE (register) |
| // vcge<c>.f32 <Qd>, <Qn>, <Qm> |
| // vcge<c>.f32 <Dd>, <Dn>, <Dm> |
| case arm_vcgt__reg_f32: // A8.6.284 VCGT (register) |
| // vcgt<c>.f32 <Qd>, <Qn>, <Qm> |
| // vcgt<c>.f32 <Dd>, <Dn>, <Dm> |
| case arm_vmul_f32: // A8.6.338 VMUL (floating-point) |
| // vmul<c>.f32 <Qd>, <Qn>, <Qm> |
| // vmul<c>.f32 <Dd>, <Dn>, <Dm> |
| case arm_vpadd__f32: // A8.6.350 VPADD (floating-point) |
| // vpadd<c>.f32 <Dd>, <Dn>, <Dm> |
| case arm_vrecps: // A8.6.372 VRECPS |
| // vrecps<c>.f32 <Qd>, <Qn>, <Qm> |
| // vrecps<c>.f32 <Dd>, <Dn>, <Dm> |
| case arm_vrsqrts: // A8.6.379 VRSQRTS |
| // vrsqrts<c>.f32 <Qd>, <Qn>, <Qm> |
| // vrsqrts<c>.f32 <Dd>, <Dn>, <Dm> |
| case arm_vsub__f32: // A8.6.402 VSUB (floating-point) |
| // vsub<c>.f32 <Qd>, <Qn>, <Qm> |
| // vsub<c>.f32 <Dd>, <Dn>, <Dm> |
| instruction = mnemonic + ".f32\t" + getVFPQorDdnmRegs(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vabs: // A8.6.269 VABS |
| // vabs<c>.<dt> <Qd>, <Qm> |
| // vabs<c>.<dt> <Dd>, <Dm> |
| case arm_vneg: // A8.6.342 VNEG |
| // vneg<c>.<dt> <Qd>, <Qm> |
| // vneg<c>.<dt> <Dd>, <Dm> |
| instruction = mnemonic + getVFPSorUorFQorDdmOperands(opcode, 10, 4); // chose bit 4 because it is 0 |
| // No PC check: not applicable |
| break; |
| |
| case arm_vabs__f: // A8.6.269 VABS |
| // vabs<c>.f64 <Dd>, <Dm> |
| // vabs<c>.f32 <Sd>, <Sm> |
| case arm_vmov__reg_f: // A8.6.327 VMOV (register) |
| // vmov<c>.f64 <Dd>, <Dm> |
| // vmov<c>.f32 <Sd>, <Sm> |
| case arm_vneg__f: // A8.6.342 VNEG |
| // vneg<c>.f64 <Dd>, <Dm> |
| // vneg<c>.f32 <Sd>, <Sm> |
| case arm_vsqrt: // A8.6.388 VSQRT |
| // vsqrt<c>.f64 <Dd>, <Dm> |
| // vsqrt<c>.f32 <Sd>, <Sm> |
| instruction = mnemonic + getArmCondition(opcode) + getVFPSzF64F32dmOperands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vacge_vacgt: // A8.6.270 VACGE, VACGT, VACLE, VACLT |
| // vacge<c>.f32 <Qd>, <Qn>, <Qm> |
| // vacge<c>.f32 <Dd>, <Dn>, <Dm> |
| // vacgt<c>.f32 <Qd>, <Qn>, <Qm> |
| // vacgt<c>.f32 <Dd>, <Dn>, <Dm> |
| instruction = mnemonic + getVFP_vacge_vacgt(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vadd__int: // A8.6.271 VADD (integer) |
| // vadd<c>.<dt> <Qd>, <Qn>, <Qm> |
| // vadd<c>.<dt> <Dd>, <Dn>, <Dm> |
| case arm_vceq__reg_int: // A8.6.280 VCEQ (register) |
| // vceq<c>.<dt> <Qd>, <Qn>, <Qm> |
| // vceq<c>.<dt> <Dd>, <Dn>, <Dm> |
| case arm_vpadd__int: // A8.6.349 VPADD (integer) |
| // vpadd<c>.<dt> <Dd>, <Dn>, <Dm> |
| case arm_vsub__int: // A8.6.401 VSUB (integer) |
| // vsub<c>.<dt> <Qd>, <Qn>, <Qm> |
| // vsub<c>.<dt> <Dd>, <Dn>, <Dm> |
| instruction = mnemonic + getVFPIDataTypeQorDdnmOperands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vnml: // A8.6.343 VNMLA, VNMLS, VNMUL |
| // vnmla<c>.f64 <Dd>, <Dn>, <Dm> |
| // vnmla<c>.f32 <Sd>, <Sn>, <Sm> |
| // vnmls<c>.f64 <Dd>, <Dn>, <Dm> |
| // vnmls<c>.f32 <Sd>, <Sn>, <Sm> |
| mnemonic += isBitEnabled(opcode, 6) ? 'a' : 's'; |
| // no break! |
| case arm_vadd__fp_f: // A8.6.272 VADD (floating-point) |
| // vadd<c>.f64 <Dd>, <Dn>, <Dm> |
| // vadd<c>.f32 <Sd>, <Sn>, <Sm> |
| case arm_vdiv: // A8.6.301 VDIV |
| // vdiv<c>.f64 <Dd>, <Dn>, <Dm> |
| // vdiv<c>.f32 <Sd>, <Sn>, <Sm> |
| case arm_vmul__fp_2: // A8.6.338 VMUL (floating-point) |
| // vmul<c>.f64 <Dd>, <Dn>, <Dm> |
| // vmul<c>.f32 <Sd>, <Sn>, <Sm> |
| case arm_vnmul: // A8.6.343 VNMLA, VNMLS, VNMUL |
| // vnmul<c>.f64 <Dd>, <Dn>, <Dm> |
| // vnmul<c>.f32 <Sd>, <Sn>, <Sm> |
| case arm_vsub__fp_f: // A8.6.402 VSUB (floating-point) |
| // vsub<c>.f64 <Dd>, <Dn>, <Dm> |
| // vsub<c>.f32 <Sd>, <Sn>, <Sm> |
| instruction = mnemonic + getArmCondition(opcode) + getVFPSzF64F32dnmOperands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vaddhn: // A8.6.273 VADDHN |
| // vaddhn<c>.<dt> <Dd>, <Qn>, <Qm> |
| case arm_vraddhn: // A8.6.370 VRADDHN |
| // vraddhn<c>.<dt> <Dd>, <Qn>, <Qm> |
| case arm_vrsubhn: // A8.6.381 VRSUBHN |
| // vrsubhn<c>.<dt> <Dd>, <Qn>, <Qm> |
| case arm_vsubhn: // A8.6.403 VSUBHN |
| // vsubhn<c>.<dt> <Dd>, <Qn>, <Qm> |
| instruction = mnemonic + getVFPIDataType2DdQnDmOperands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vaddl_vaddw: // A8.6.274 VADDL, VADDW |
| // vaddl<c>.<dt> <Qd>, <Dn>, <Dm> |
| // vaddw<c>.<dt> <Qd>, <Qn>, <Dm> |
| case arm_vsubl_vsubw: // A8.6.404 VSUBL, VSUBW |
| // vsubl<c>.<dt> <Qd>, <Dn>, <Dm> |
| // vsubw<c>.<dt> {<Qd>,} <Qn>, <Dm> |
| instruction = mnemonic + getVFP_vXXXl_vXXXw(opcode, 24); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vbif_vbit_vbsl_veor: // A8.6.279 VBIF, VBIT, VBSL |
| // vbif<c> <Qd>, <Qn>, <Qm> |
| // vbif<c> <Dd>, <Dn>, <Dm> |
| // vbit<c> <Qd>, <Qn>, <Qm> |
| // vbit<c> <Dd>, <Dn>, <Dm> |
| // vbsl<c> <Qd>, <Qn>, <Qm> |
| // vbsl<c> <Dd>, <Dn>, <Dm> |
| // A8.6.304 VEOR |
| // veor<c> <Qd>, <Qn>, <Qm> |
| // veor<c> <Dd>, <Dn>, <Dm> |
| mnemonic = getVFP_vbif_vbit_vbsl_veor_mnemonic(opcode); |
| // no break! |
| case arm_vand: // A8.6.276 VAND (register) |
| // vand<c> <Qd>, <Qn>, <Qm> |
| // vand<c> <Dd>, <Dn>, <Dm> |
| case arm_vbic: // A8.6.278 VBIC (register) |
| // vbic<c> <Qd>, <Qn>, <Qm> |
| // vbic<c> <Dd>, <Dn>, <Dm> |
| case arm_vorn: // A8.6.345 VORN (register) |
| // vorn<c> <Qd>, <Qn>, <Qm> |
| // vorn<c> <Dd>, <Dn>, <Dm> |
| instruction = mnemonic + getVFPQorDdnmRegs(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vmov_vorr: // A8.6.327 VMOV (register) |
| // vmov<c> <Qd>, <Qm> |
| // vmov<c> <Dd>, <Dm> |
| // A8.6.347 VORR (register) |
| // vorr<c> <Qd>, <Qn>, <Qm> |
| // vorr<c> <Dd>, <Dn>, <Dm> |
| // mnemonic is "vmov" by default |
| if (getBit(opcode, 7) == getBit(opcode, 5) && |
| (opcode & 0xf) == (opcode >> 16 & 0xf)) { |
| instruction = mnemonic + TAB + getVFPQorDdmRegs(opcode); |
| } else { |
| instruction = "vorr" + getVFPQorDdnmRegs(opcode); |
| } |
| // No PC check: not applicable |
| break; |
| |
| case arm_vmov_vbitwise: // A8.6.277 VBIC (immediate) |
| // vbic<c>.<dt> <Qd>, #<imm> |
| // vbic<c>.<dt> <Dd>, #<imm> |
| // A8.6.326 VMOV (immediate) |
| // vmov<c>.<dt> <Qd>, #<imm> |
| // vmov<c>.<dt> <Dd>, #<imm> |
| // A8.6.340 VMVN (immediate) |
| // vmvn<c>.<dt> <Qd>, #<imm> |
| // vmvn<c>.<dt> <Dd>, #<imm> |
| // A8.6.346 VORR (immediate) |
| // vorr<c>.<dt> <Qd>, #<imm> |
| // vorr<c>.<dt> <Dd>, #<imm> |
| instruction = getVFP_vmov_vbitwise_instruction(opcode, 24); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vceq__imm0: // A8.6.281 VCEQ (immediate #0) |
| // vceq<c>.<dt> <Qd>, <Qm>, #0 |
| // vceq<c>.<dt> <Dd>, <Dm>, #0 |
| instruction = mnemonic + getVFPIorFQorDdmOperands(opcode, 10) + ",#0"; |
| // No PC check: not applicable |
| break; |
| |
| case arm_vcge__imm0: // A8.6.283 VCGE (immediate #0) |
| // vcge<c>.<dt> <Qd>, <Qm>, #0 |
| // vcge<c>.<dt> <Dd>, <Dm>, #0 |
| case arm_vcgt__imm0: // A8.6.285 VCGT (immediate #0) |
| // vcgt<c>.<dt> <Qd>, <Qm>, #0 |
| // vcgt<c>.<dt> <Dd>, <Dm>, #0 |
| case arm_vcle: // A8.6.287 VCLE (immediate #0) |
| // vcle<c>.<dt> <Qd>, <Qm>, #0 |
| // vcle<c>.<dt> <Dd>, <Dm>, #0 |
| case arm_vclt: // A8.6.290 VCLT (immediate #0) |
| // vclt<c>.<dt> <Qd>, <Qm>, #0 |
| // vclt<c>.<dt> <Dd>, <Dm>, #0 |
| instruction = mnemonic + getVFPSorUorFQorDdmOperands(opcode, 10, 11) + ",#0"; // chose bit 11 because it is 0 |
| // No PC check: not applicable |
| break; |
| |
| case arm_vcls: // A8.6.288 VCLS |
| // vcls<c>.<dt> <Qd>, <Qm> |
| // vcls<c>.<dt> <Dd>, <Dm> |
| case arm_vqabs: // A8.6.356 VQABS |
| // vqabs<c>.<dt> <Qd>,<Qm> |
| // vqabs<c>.<dt> <Dd>,<Dm> |
| case arm_vqneg: // A8.6.362 VQNEG |
| // vqneg<c>.<dt> <Qd>,<Qm> |
| // vqneg<c>.<dt> <Dd>,<Dm> |
| instruction = mnemonic + getVFPSorUorFQorDdmOperands(opcode, 4, 11); // chose bit 11 because it is 0 |
| // No PC check: not applicable |
| break; |
| |
| case arm_vclz: // A8.6.291 VCLZ |
| // vclz<c>.<dt> <Qd>, <Qm> |
| // vclz<c>.<dt> <Dd>, <Dm> |
| instruction = mnemonic + getVFPIorFQorDdmOperands(opcode, 11); // chose bit 11 because it is 0 |
| // No PC check: not applicable |
| break; |
| |
| case arm_vcmp__reg: // A8.6.292 VCMP, VCMPE |
| // vcmp{e}<c>.f64 <Dd>, <Dm> |
| // vcmp{e}<c>.f32 <Sd>, <Sm> |
| instruction = mnemonic + getE(opcode) + getArmCondition(opcode) |
| + getVFPSzF64F32dmOperands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vcmp__to_0: // A8.6.292 VCMP, VCMPE |
| // vcmp{e}<c>.f64 <Dd>, #0.0 |
| // vcmp{e}<c>.f32 <Sd>, #0.0 |
| instruction = mnemonic + getE(opcode) + getArmCondition(opcode) |
| + getVFP_vcmpTo0Operands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vcnt: // A8.6.293 VCNT |
| // vcnt<c>.8 <Qd>, <Qm> |
| // vcnt<c>.8 <Dd>, <Dm> |
| mnemonic += ".8"; |
| case arm_vmvn: // A8.6.341 VMVN (register) |
| // vmvn<c> <Qd>, <Qm> |
| // vmvn<c> <Dd>, <Dm> |
| case arm_vswp: // A8.6.405 VSWP |
| // vswp<c> <Qd>, <Qm> |
| // vswp<c> <Dd>, <Dm> |
| instruction = mnemonic + getVFPQorDdmRegs(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vcvt__fp_i_vec: // A8.6.294 VCVT (between floating-point and integer, Advanced SIMD) |
| // vcvt<c>.<Td>.<Tm> <Qd>, <Qm> |
| // vcvt<c>.<Td>.<Tm> <Dd>, <Dm> |
| instruction = mnemonic + getVFP_vcvtFpIVecOperands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vcvt__fp_i_reg: // A8.6.295 VCVT, VCVTR (between floating-point and integer, VFP) |
| // vcvt{r}<c>.s32.f64 <Sd>, <Dm> |
| // vcvt{r}<c>.s32.f32 <Sd>, <Sm> |
| // vcvt{r}<c>.u32.f64 <Sd>, <Dm> |
| // vcvt{r}<c>.u32.f32 <Sd>, <Sm> |
| // vcvt<c>.f64.<Tm> <Dd>, <Sm> |
| // vcvt<c>.f32.<Tm> <Sd>, <Sm> |
| if (isBitEnabled(opcode, 18) && !isBitEnabled(opcode, 7)) |
| mnemonic += "r"; |
| instruction = mnemonic + getArmCondition(opcode) + getVFP_vcvtFpIRegOperands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vcvt__fp_fix_vec: // A8.6.296 VCVT (between floating-point and fixed-point, Advanced SIMD) |
| // vcvt<c>.<Td>.<Tm> <Qd>, <Qm>, #<fbits> |
| // vcvt<c>.<Td>.<Tm> <Dd>, <Dm>, #<fbits> |
| instruction = mnemonic + getVFP_vcvtFpFixVecOperands(opcode, 24); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vcvt__fp_fix_reg: // A8.6.297 VCVT (between floating-point and fixed-point, VFP) |
| // vcvt<c>.<Td>.f64 <Dd>, <Dd>, #<fbits> |
| // vcvt<c>.<Td>.f32 <Sd>, <Sd>, #<fbits> |
| // vcvt<c>.f64.<Td> <Dd>, <Dd>, #<fbits> |
| // vcvt<c>.f32.<Td> <Sd>, <Sd>, #<fbits> |
| instruction = mnemonic + getArmCondition(opcode) + getVFP_vcvtFpFixRegOperands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vcvt__dp_sp: // A8.6.298 VCVT (between double-precision and single-precision) |
| // vcvt<c>.f64.f32 <Dd>, <Sm> |
| // vcvt<c>.f32.f64 <Sd>, <Dm> |
| instruction = mnemonic + getArmCondition(opcode) + getVFP_vcvtDpSpOperands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vcvt__hp_sp_vec: // A8.6.299 VCVT (between half-precision and single-precision, Advanced SIMD) |
| // vcvt<c>.f32.f16 <Qd>, <Dm> |
| // vcvt<c>.f16.f32 <Dd>, <Qm> |
| instruction = mnemonic + getVFP_vcvtHpSpVecOperands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vcvt__hp_sp_reg: // A8.6.300 VCVTB, VCVTT (between half-precision and single-precision, VFP) |
| // vcvt<y><c>.f32.f16 <Sd>, <Sm> |
| // vcvt<y><c>.f16.f32 <Sd>, <Sm> |
| mnemonic += isBitEnabled(opcode, 7) ? "t" : "b"; |
| instruction = mnemonic + getArmCondition(opcode) + getVFP_vcvtHpSpRegOperands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vdup__scalar: // A8.6.302 VDUP (scalar) |
| // vdup<c>.<size> <Qd>, <Dm[x]> |
| // vdup<c>.<size> <Dd>, <Dm[x]> |
| instruction = mnemonic + getVFP_vdupScalarOperands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vdup__reg: // A8.6.303 VDUP (ARM core register) |
| // vdup<c>.<size> <Qd>, <Rt> |
| // vdup<c>.<size> <Dd>, <Rt> |
| mnemonic += getArmCondition(opcode); |
| instruction = mnemonic + getVFP_vdupRegOperands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vext: // A8.6.305 VEXT |
| // vext<c>.8 <Qd>, <Qn>, <Qm>, #<imm> |
| // vext<c>.8 <Dd>, <Dn>, <Dm>, #<imm> |
| instruction = mnemonic + ".8" + getVFPQorDdnmRegs(opcode) |
| + ",#" + (opcode >> 8 & 0xf); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vld__multi: // A8.6.307 VLD1 (multiple single elements) |
| // vld1<c>.<size> <list>, [<Rn>{@<align>}]{!} |
| // vld1<c>.<size> <list>, [<Rn>{@<align>}], <Rm> |
| // A8.6.310 VLD2 (multiple 2-element structures) |
| // vld2<c>.<size> <list>, [<Rn>{@<align>}]{!} |
| // vld2<c>.<size> <list>, [<Rn>{@<align>}], <Rm> |
| // A8.6.313 VLD3 (multiple 3-element structures) |
| // vld3<c>.<size> <list>, [<Rn>{@<align>}]{!} |
| // vld3<c>.<size> <list>, [<Rn>{@<align>}], <Rm> |
| // A8.6.316 VLD4 (multiple 4-element structures) |
| // vld4<c>.<size> <list>, [<Rn>{@<align>}]{!} |
| // vld4<c>.<size> <list>, [<Rn>{@<align>}], <Rm> |
| case arm_vst__multi: // A8.6.391 VST1 (multiple single elements) |
| // vst1<c>.<size> <list>, [<Rn>{@<align>}]{!} |
| // vst1<c>.<size> <list>, [<Rn>{@<align>}], <Rm> |
| // A8.6.393 VST2 (multiple 2-element structures) |
| // vst2<c>.<size> <list>, [<Rn>{@<align>}]{!} |
| // vst2<c>.<size> <list>, [<Rn>{@<align>}], <Rm> |
| // A8.6.395 VST3 (multiple 3-element structures) |
| // vst3<c>.<size> <list>, [<Rn>{@<align>}]{!} |
| // vst3<c>.<size> <list>, [<Rn>{@<align>}], <Rm> |
| // A8.6.397 VST4 (multiple 4-element structures) |
| // vst4<c>.<size> <list>, [<Rn>{@<align>}]{!} |
| // vst4<c>.<size> <list>, [<Rn>{@<align>}], <Rm> |
| instruction = mnemonic + getVFP_vXX_multi(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vld__xlane: // A8.6.308 VLD1 (single element to one lane) |
| // vld1<c>.<size> <list>, [<Rn>{@<align>}}]{!} |
| // vld1<c>.<size> <list>, [<Rn>{@<align>}}], <Rm> |
| // A8.6.309 VLD1 (single element to all lanes) |
| // vld1<c>.<size> <list>, [<Rn>{@<align>}}]{!} |
| // vld1<c>.<size> <list>, [<Rn>{@<align>}}], <Rm> |
| // A8.6.311 VLD2 (single 2-element structure to one lane) |
| // vld2<c>.<size> <list>, [<Rn>{@<align>}}]{!} |
| // vld2<c>.<size> <list>, [<Rn>{@<align>}}], <Rm> |
| // A8.6.312 VLD2 (single 2-element structure to all lanes) |
| // vld2<c>.<size> <list>, [<Rn>{@<align>}}]{!} |
| // vld2<c>.<size> <list>, [<Rn>{@<align>}}], <Rm> |
| // A8.6.314 VLD3 (single 3-element structure to one lane) |
| // vld3<c>.<size> <list>, [<Rn>{@<align>}}]{!} |
| // vld3<c>.<size> <list>, [<Rn>{@<align>}}], <Rm> |
| // A8.6.315 VLD3 (single 3-element structure to all lanes) |
| // vld3<c>.<size> <list>, [<Rn>{@<align>}}]{!} |
| // vld3<c>.<size> <list>, [<Rn>{@<align>}}], <Rm> |
| // A8.6.317 VLD4 (single 4-element structure to one lane) |
| // vld4<c>.<size> <list>, [<Rn>{@<align>}}]{!} |
| // vld4<c>.<size> <list>, [<Rn>{@<align>}}], <Rm> |
| // A8.6.318 VLD4 (single 4-element structure to all lanes) |
| // vld4<c>.<size> <list>, [<Rn>{@<align>}}]{!} |
| // vld4<c>.<size> <list>, [<Rn>{@<align>}}], <Rm> |
| case arm_vst__xlane: // A8.6.392 VST1 (single element from one lane) |
| // vst1<c>.<size> <list>, [<Rn>{@<align>}}]{!} |
| // vst1<c>.<size> <list>, [<Rn>{@<align>}}], <Rm> |
| // A8.6.394 VST2 (single 2-element structure from one lane) |
| // vst2<c>.<size> <list>, [<Rn>{@<align>}}]{!} |
| // vst2<c>.<size> <list>, [<Rn>{@<align>}}], <Rm> |
| // A8.6.396 VST3 (single 3-element structure from one lane) |
| // vst3<c>.<size> <list>, [<Rn>{@<align>}}]{!} |
| // vst3<c>.<size> <list>, [<Rn>{@<align>}}], <Rm> |
| // A8.6.398 VST4 (single 4-element structure from one lane) |
| // vst4<c>.<size> <list>, [<Rn>{@<align>}}]{!} |
| // vst4<c>.<size> <list>, [<Rn>{@<align>}}], <Rm> |
| instruction = mnemonic + getVFP_vXX_Xlane(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vldm__64: // A8.6.319 VLDM |
| // vldm{mode}<c> <Rn>{!}, <list> <list> is consecutive 64-bit registers |
| case arm_vldm__32: // A8.6.319 VLDM |
| // vldm{mode}<c> <Rn>{!}, <list> <list> is consecutive 32-bit registers |
| case arm_vstm__64: // A8.6.399 VSTM |
| // vstm{mode}<c> <Rn>{!}, <list> <list> is consecutive 64-bit registers |
| case arm_vstm__32: // A8.6.399 VSTM |
| // vstm{mode}<c> <Rn>{!}, <list> <list> is consecutive 32-bit registers |
| instruction = mnemonic + getVFPIncDec(opcode) + getArmCondition(opcode) |
| + getVFP_vXXm(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vldr__64: // A8.6.320 VLDR |
| // vldr<c> <Dd>, [<Rn>{, #+/-<imm>}] |
| // vldr<c> <Dd>, <label> |
| // vldr<c> <Dd>, [pc,#+/-<imm>] Alternative form |
| case arm_vldr__32: // A8.6.320 VLDR |
| // vldr<c> <Sd>, [<Rn>{, #+/-<imm>}] |
| // vldr<c> <Sd>, <label> |
| // vldr<c> <Sd>, [pc,#+/-<imm>] Alternative form |
| case arm_vstr__64: // A8.6.400 VSTR |
| // vstr<c> <Dd>, [<Rn>{, #+/-<imm>}] |
| case arm_vstr__32: // A8.6.400 VSTR |
| // vstr<c> <Sd>, [<Rn>{, #+/-<imm>}] |
| instruction = mnemonic + getArmCondition(opcode) + getVFP_vXXr(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vmax_vmin__int: // A8.6.321 VMAX, VMIN (integer) |
| // vmax<c>.<dt> <Qd>, <Qn>, <Qm> |
| // vmax<c>.<dt> <Dd>, <Dn>, <Dm> |
| // vmin<c>.<dt> <Qd>, <Qn>, <Qm> |
| // vmin<c>.<dt> <Dd>, <Dn>, <Dm> |
| case arm_vpmax_vpmin__int: // A8.6.352 VPMAX, VPMIN (integer) |
| // vp<op><c>.<dt> <Dd>, <Dn>, <Dm> |
| // (this works despite no Q version because Q==1 is UNDEFINED) |
| instruction = mnemonic + (isBitEnabled(opcode, 4) ? "min" : "max") |
| + getVFPSorUDataType(opcode, 24) + getVFPQorDdnmRegs(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vmax_vmin__fp: // A8.6.322 VMAX, VMIN (floating-point) |
| // vmax<c>.f32 <Qd>, <Qn>, <Qm> |
| // vmax<c>.f32 <Dd>, <Dn>, <Dm> |
| // vmin<c>.f32 <Qd>, <Qn>, <Qm> |
| // vmin<c>.f32 <Dd>, <Dn>, <Dm> |
| case arm_vpmax_vpmin__fp: // A8.6.353 VPMAX, VPMIN (floating-point) |
| // vp<op><c>.f32 <Dd>, <Dn>, <Dm> |
| instruction = mnemonic + (isBitEnabled(opcode, 21) ? "min.f32" : "max.f32") |
| + getVFPQorDdnmRegs(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vml__int: // A8.6.323 VMLA, VMLAL, VMLS, VMLSL (integer) |
| // v<op><c>.<dt> <Qd>, <Qn>, <Qm> |
| // v<op><c>.<dt> <Dd>, <Dn>, <Dm> |
| mnemonic += isBitEnabled(opcode, 24) ? 's' : 'a'; |
| instruction = mnemonic + getVFPIDataType(opcode, 20) + TAB + getVFPQorDdnmRegs(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vml__int_long: // A8.6.323 VMLA, VMLAL, VMLS, VMLSL (integer) |
| // v<op>l<c>.<dt> <Qd>, <Dn>, <Dm> |
| mnemonic += isBitEnabled(opcode, 9) ? "sl" : "al"; |
| instruction = mnemonic + getVFPSorUDataType(opcode, 24) |
| + TAB + getVFPQdDnDmRegs(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vml__f32: // A8.6.324 VMLA, VMLS (floating-point) |
| // v<op><c>.f32 <Qd>, <Qn>, <Qm> |
| // v<op><c>.f32 <Dd>, <Dn>, <Dm> |
| mnemonic += isBitEnabled(opcode, 21) ? "s.f32" : "a.f32"; |
| instruction = mnemonic + TAB + getVFPQorDdnmRegs(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vml__fp: // A8.6.324 VMLA, VMLS (floating-point) |
| // v<op><c>.f64 <Dd>, <Dn>, <Dm> |
| // v<op><c>.f32 <Sd>, <Sn>, <Sm> |
| mnemonic += isBitEnabled(opcode, 6) ? 's' : 'a' + getArmCondition(opcode); |
| instruction = mnemonic + getVFPSzF64F32dnmOperands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vml__scalar: // A8.6.325 VMLA, VMLAL, VMLS, VMLSL (by scalar) |
| // v<op><c>.<dt> <Qd>, <Qn>, <Dm[x]> |
| // v<op><c>.<dt> <Dd>, <Dn>, <Dm[x]> |
| // v<op>l<c>.<dt> <Qd>, <Dn>, <Dm[x]> |
| mnemonic += isBitEnabled(opcode, 10) ? 's' : 'a'; |
| case arm_vmul__scalar: // A8.6.339 VMUL, VMULL (by scalar) |
| // vmul<c>.<dt> <Qd>, <Qn>, <Dm[x]> |
| // vmul<c>.<dt> <Dd>, <Dn>, <Dm[x]> |
| // vmull<c>.<dt> <Qd>,<Dn>,<Dm[x]> |
| case arm_vqdmull__scalar: // A8.6.360 VQDMULL |
| // vqdmull<c>.<dt> <Qd>,<Dn>,<Dm[x]> |
| // bit 9 == 1, so getVFP_vmXXScalar() works |
| instruction = mnemonic + getVFP_vmXXScalar(opcode, 24); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vmov__imm: // A8.6.326 VMOV (immediate) |
| // vmov<c>.f64 <Dd>, #<imm> |
| // vmov<c>.f32 <Sd>, #<imm> |
| mnemonic += getArmCondition(opcode) + getVFPSzF64F32Type(getBit(opcode, 8)); |
| imm = (opcode >> 16 & 0xf) << 4 | opcode & 0xf; |
| instruction = mnemonic + TAB + getVFPDorSReg(opcode, getBit(opcode, 8), 12, 22) |
| + ",#" + getHexValue(imm); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vmov_5: // A8.6.328 VMOV (ARM core register to scalar) |
| // vmov<c>.<size> <Dd[x]>, <Rt> |
| mnemonic += getArmCondition(opcode); |
| instruction = mnemonic + getVFP_vmovArmCoreRegToScalar(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vmov_6: // A8.6.329 VMOV (scalar to ARM core register) |
| // vmov<c>.<dt> <Rt>, <Dn[x]> |
| mnemonic += getArmCondition(opcode); |
| instruction = mnemonic + getVFP_vmovScalarToArmCoreReg(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vmov_7: // A8.6.330 VMOV (between ARM core register and |
| // single-precision register) |
| // vmov<c> <Sn>, <Rt> |
| // vmov<c> <Rt>, <Sn> |
| mnemonic += getArmCondition(opcode); |
| instruction = mnemonic + getVFP_vmovBetweenArmCoreAndSinglePrecReg(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vmov_8: // A8.6.331 VMOV (between two ARM core registers and |
| // two single-precision registers) |
| // vmov<c> <Sm>, <Sm1>, <Rt>, <Rt2> |
| // vmov<c> <Rt>, <Rt2>, <Sm>, <Sm1> |
| mnemonic += getArmCondition(opcode); |
| instruction = mnemonic + getVFP_vmovBetween2ArmCoreAndSinglePrecRegs(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vmov_9: // A8.6.332 VMOV (between two ARM core registers and |
| // a doubleword extension register) |
| // vmov<c> <Dm>, <Rt>, <Rt2> |
| // vmov<c> <Rt>, <Rt2>, <Dm> |
| mnemonic += getArmCondition(opcode); |
| instruction = mnemonic + getVFP_vmovBetween2ArmCoreAnd1DoublewordExtensionRegs(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vmovl: // A8.6.333 VMOVL |
| // vmovl<c>.<dt> <Qd>, <Dm> |
| case arm_vshll__various: // A8.6.384 VSHLL |
| // vshll<c>.<type><size> <Qd>, <Dm>, #<imm> (0 < <imm> < <size>) |
| instruction = mnemonic + getVFP_vmovl_vshll_operands(opcode, 24); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vmovn: // A8.6.334 VMOVN |
| // vmovn<c>.<dt> <Dd>, <Qm> |
| fld1 = (opcode >> 18) & 3; // size field |
| |
| tempStr = ".i16"; |
| if (fld1 == 1) |
| tempStr = ".i32"; |
| else if (fld1 == 2) |
| tempStr = ".i64"; |
| |
| instruction = mnemonic + tempStr + "\t" |
| + getVFPQorDReg(opcode, 0, 12, 22) + "," +getVFPQorDReg(opcode, 1, 0, 5); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vmrs: // A8.6.335 VMRS |
| // vmrs<c> <Rt>, fpscr |
| // B6.1.14 VMRS |
| // vmrs<c> <Rt>,<spec_reg> |
| instruction = mnemonic + getArmCondition(opcode) + "\t" |
| + getR_12(opcode) + "," + getVFPSpecialReg(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vmsr: // A8.6.336 VMSR |
| // vmsr<c> fpscr, <Rt> |
| // B6.1.15 VMSR |
| // vmsr<c> <spec_reg>,<Rt> |
| instruction = mnemonic + getArmCondition(opcode) + "\t" |
| + getVFPSpecialReg(opcode) + "," + getR_12(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vmul_1: // A8.6.337 VMUL, VMULL (integer and polynomial) |
| // vmul<c>.<dt> <Qd>, <Qn>, <Qm> |
| // vmul<c>.<dt> <Dd>, <Dn>, <Dm> |
| // 1 1 1 1 0 0 1 op_24_24 0 D_22_22 size_21_20 Vn_19_16 Vd_15_12 1 0 0 1 N_7_7 Q_6_6 M_5_5 1 Vm_3_0 |
| mnemonic += (isBitEnabled(opcode, 24) ? ".p" : ".i") + getVFPDataTypeSize(opcode, 20); |
| instruction = mnemonic + TAB + getVFPQorDdnmRegs(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vmull: // A8.6.337 VMUL, VMULL (integer and polynomial) |
| // vmull<c>.<dt> <Qd>, <Dn>, <Dm> |
| mnemonic += isBitEnabled(opcode, 9) ? getVFPPDataType(opcode, 20) : getVFPSorUDataType(opcode, 24); |
| instruction = mnemonic + TAB + getVFPQdDnDmRegs(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vpadal: // A8.6.348 VPADAL |
| // vpadal<c>.<dt> <Qd>, <Qm> |
| // vpadal<c>.<dt> <Dd>, <Dm> |
| case arm_vpaddl: // A8.6.351 VPADDL |
| // vpaddl<c>.<dt> <Qd>, <Qm> |
| // vpaddl<c>.<dt> <Dd>, <Dm> |
| instruction = mnemonic + getVFPSorUorFQorDdmOperands(opcode, 4, 7); // chose bit 4 because it is 0 |
| // No PC check: not applicable |
| break; |
| |
| case arm_vpop: // A8.6.354 VPOP |
| // vpop<c> <list> (<list> is consecutive 64-bit registers) |
| // vpop<c> <list> (<list> is consecutive 32-bit registers) |
| case arm_vpush: // A8.6.355 VPUSH |
| // vpush<c> <list> (<list> is consecutive 64-bit registers) |
| // vpush<c> <list> (<list> is consecutive 32-bit registers) |
| instruction = mnemonic + getArmCondition(opcode) + getVFP_vpop_vpush_operands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vqdml__scalar: // A8.6.358 VQDMLAL, VQDMLSL |
| // vqd<op><c>.<dt> <Qd>,<Dn>,<Dm[x]> |
| mnemonic += isBitEnabled(opcode, 10) ? "sl.s" : "al.s"; |
| instruction = mnemonic + getVFPScalarOperands(opcode, 1, 0); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vqdmulh__vec: // A8.6.359 VQDMULH |
| // vqdmulh<c>.<dt> <Qd>,<Qn>,<Qm> |
| // vqdmulh<c>.<dt> <Dd>,<Dn>,<Dm> |
| case arm_vqrdmulh__vec: // A8.6.363 VQRDMULH |
| // vqrdmulh<c>.<dt> <Qd>,<Qn>,<Qm> |
| // vqrdmulh<c>.<dt> <Dd>,<Dn>,<Dm> |
| mnemonic += isBitEnabled(opcode, 20) ? ".s16" : ".s32"; |
| instruction = mnemonic + TAB + getVFPQorDdnmRegs(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vqdmulh__scalar: // A8.6.359 VQDMULH |
| // vqdmulh<c>.<dt> <Qd>,<Qn>,<Dm[x]> |
| // vqdmulh<c>.<dt> <Dd>,<Dn>,<Dm[x]> |
| case arm_vqrdmulh__scalar: // A8.6.363 VQRDMULH |
| // vqrdmulh<c>.<dt> <Qd>,<Qn>,<Dm[x]> |
| // vqrdmulh<c>.<dt> <Dd>,<Dn>,<Dm[x]> |
| q = getBit(opcode, 24); |
| instruction = mnemonic + ".s" + getVFPScalarOperands(opcode, q, q); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vqmov: // A8.6.361 VQMOVN, VQMOVUN |
| // vqmov{u}n<c>.<type><size> <Dd>,<Qm> |
| instruction = mnemonic + getVFP_vqmov_instruction(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vqrshl: // A8.6.364 VQRSHL |
| // vqrshl<c>.<type><size> <Qd>,<Qm>,<Qn> |
| // vqrshl<c>.<type><size> <Dd>,<Dm>,<Dn> |
| case arm_vqshl__reg: // A8.6.366 VQSHL (register) |
| // vqshl<c>.<type><size> <Qd>,<Qm>,<Qn> |
| // vqshl<c>.<type><size> <Dd>,<Dm>,<Dn> |
| case arm_vrshl: // A8.6.375 VRSHL |
| // vrshl<c>.<type><size> <Qd>,<Qm>,<Qn> |
| // vrshl<c>.<type><size> <Dd>,<Dm>,<Dn> |
| case arm_vshl__reg: // A8.6.383 VSHL (register) |
| // vshl<c>.<type><size> <Qd>,<Qm>,<Qn> |
| // vshl<c>.<type><size> <Dd>,<Dm>,<Dn> |
| instruction = mnemonic + getVFPSorUDataType(opcode, 24) + getVFPQorDdmnRegs(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vqrshr: // A8.6.365 VQRSHRN, VQRSHRUN |
| // vqrshr{u}n<c>.<type><size> <Dd>,<Qm>,#<imm> |
| case arm_vqshr: // A8.6.368 VQSHRN, VQSHRUN |
| // vqshr{u}n<c>.<type><size> <Dd>,<Qm>,#<imm> |
| instruction = mnemonic + getVFP_vqXshr_instruction(opcode, 24); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vqshl__imm: // A8.6.367 VQSHL, VQSHLU (immediate) |
| // vqshl{u}<c>.<type><size> <Qd>,<Qm>,#<imm> |
| // vqshl{u}<c>.<type><size> <Dd>,<Dm>,#<imm> |
| instruction = mnemonic + getVFP_vqshl_instruction(opcode, 24); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vrecpe: // A8.6.371 VRECPE |
| // vrecpe<c>.<dt> <Qd>, <Qm> |
| // vrecpe<c>.<dt> <Dd>, <Dm> |
| case arm_vrsqrte: // A8.6.378 VRSQRTE |
| // vrsqrte<c>.<dt> <Qd>, <Qm> |
| // vrsqrte<c>.<dt> <Dd>, <Dm> |
| instruction = mnemonic + getVFPSorUorFQorDdmOperands(opcode, 8, 10); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vrev: // A8.6.373 VREV16, VREV32, VREV64 |
| // vrev<n><c>.<size> <Qd>,<Qm> |
| // vrev<n><c>.<size> <Dd>,<Dm> |
| instruction = mnemonic + getVFP_vrev_instruction(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vrshr: // A8.6.376 VRSHR |
| // vrshr<c>.<type><size> <Qd>, <Qm>, #<imm> |
| // vrshr<c>.<type><size> <Dd>, <Dm>, #<imm> |
| case arm_vrsra: // A8.6.380 VRSRA |
| // vrsra<c>.<type><size> <Qd>, <Qm>, #<imm> |
| // vrsra<c>.<type><size> <Dd>, <Dm>, #<imm> |
| case arm_vshr: // A8.6.385 VSHR |
| // vshr<c>.<type><size> <Qd>, <Qm>, #<imm> |
| // vshr<c>.<type><size> <Dd>, <Dm>, #<imm> |
| case arm_vsra: // A8.6.389 VSRA |
| // vsra<c>.<type><size> <Qd>, <Qm>, #<imm> |
| // vsra<c>.<type><size> <Dd>, <Dm>, #<imm> |
| mnemonic += isBitEnabled(opcode, 24) ? ".u" : ".s"; |
| // no break |
| case arm_vsri: // A8.6.390 VSRI |
| // vsri<c>.<size> <Qd>, <Qm>, #<imm> |
| // vsri<c>.<size> <Dd>, <Dm>, #<imm> |
| instruction = mnemonic + getVFP_vXrX_instruction(opcode, true); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vrshrn: // A8.6.377 VRSHRN |
| // vrshrn<c>.i<size> <Dd>, <Qm>, #<imm> |
| case arm_vshrn: // A8.6.386 VSHRN |
| // vshrn<c>.i<size> <Dd>, <Qm>, #<imm> |
| instruction = mnemonic + getVFP_vXshrn_instruction(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vshl__imm: // A8.6.382 VSHL (immediate) |
| // vshl<c>.i<size> <Qd>, <Qm>, #<imm> |
| // vshl<c>.i<size> <Dd>, <Dm>, #<imm> |
| case arm_vsli: // A8.6.387 VSLI |
| // vsli<c>.<size> <Qd>, <Qm>, #<imm> |
| // vsli<c>.<size> <Dd>, <Dm>, #<imm> |
| instruction = mnemonic + getVFP_vXrX_instruction(opcode, false); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vshll__max: // A8.6.384 VSHLL |
| // vshll<c>.<type><size> <Qd>, <Dm>, #<imm> (<imm> == <size>) |
| mnemonic += getVFPIDataType3(opcode, 18); |
| instruction = mnemonic + TAB + getVFPQorDReg(opcode, 1, 12, 22) |
| + ',' + getVFPQorDReg(opcode, 0, 0, 5) + ",#" + (8 << (opcode >> 18 & 3)); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vtb: // A8.6.406 VTBL, VTBX |
| // v<op><c>.8 <Dd>, <list>, <Dm> |
| instruction = mnemonic + getVFP_vtb_instruction(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vtrn: // A8.6.407 VTRN |
| // vtrn<c>.<size> <Qd>, <Qm> |
| // vtrn<c>.<size> <Dd>, <Dm> |
| case arm_vuzp: // A8.6.409 VUZP |
| // vuzp<c>.<size> <Qd>, <Qm> |
| // vuzp<c>.<size> <Dd>, <Dm> |
| case arm_vzip: // A8.6.410 VZIP |
| // vzip<c>.<size> <Qd>, <Qm> |
| // vzip<c>.<size> <Dd>, <Dm> |
| instruction = mnemonic + getVFPSzQorDdmOperands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case arm_vtst: // A8.6.408 VTST |
| // vtst<c>.<size> <Qd>, <Qn>, <Qm> |
| // vtst<c>.<size> <Dd>, <Dn>, <Dm> |
| instruction = mnemonic + getVFPSzQorDdnmOperands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| default: |
| instruction = IDisassembler.INVALID_OPCODE; |
| break; |
| } |
| return instruction; |
| } |
| |
| |
| /** |
| * Disassemble a 16-bit Thumb instruction |
| * Reference manual citations (e.g., "A8.6.2") refer to sections in the ARM Architecture |
| * Reference Manual ARMv7-A and ARMv7-R Edition, Errata markup |
| * @return disassembled instruction |
| */ |
| private String parseThumbOpcode() throws BufferUnderflowException { |
| byte b0, b1; |
| if (endianMode == BIG_ENDIAN_MODE && (codeBuffer.remaining() > 1)) { |
| b0 = codeBuffer.get(); |
| b1 = codeBuffer.get(); |
| } else { |
| b1 = codeBuffer.get(); |
| b0 = codeBuffer.get(); |
| } |
| int opcode = (b0 & 0xff) << 8 | b1 & 0xff; |
| if (0xf0 == (b0 & 0xf0) || 0xe8 == (b0 & 0xe8)) { |
| if (endianMode == BIG_ENDIAN_MODE && (codeBuffer.remaining() > 1)) { |
| b0 = codeBuffer.get(); |
| b1 = codeBuffer.get(); |
| } else { |
| b1 = codeBuffer.get(); |
| b0 = codeBuffer.get(); |
| } |
| opcode = opcode << 16 | (b0 & 0xff) << 8 | (b1 & 0xff); |
| return parseThumb2Opcode(opcode); |
| } |
| |
| OpcodeARM.Index opcodeIndex = OpcodeARM.Index.invalid; |
| String mnemonic = ""; |
| |
| for (OpcodeARM thumbOpcode : OpcodeARM.thumb_opcode_table) { |
| int result = opcode & thumbOpcode.getOpcodeMask(); |
| if (result == thumbOpcode.getOpcodeResult()) { |
| opcodeIndex = thumbOpcode.getIndex(); |
| mnemonic = thumbOpcode.getMnemonic(); |
| break; |
| } |
| } |
| |
| String instruction = ""; |
| String regList = ""; |
| String regOp = ""; |
| int offset; |
| int bit; |
| switch (opcodeIndex) { |
| case thumb_adc: // A8.6.2 ADC (register) |
| // adcs <Rdn>,<Rm> Outside IT block. |
| // adc<c> <Rdn>,<Rm> Inside IT block. |
| instruction = mnemonic + "s\t" + getThumbReg(opcode, 0) + "," + getThumbReg(opcode, 3); |
| // No PC check: Rdn cannot be PC |
| break; |
| |
| case thumb_add__imm: // A8.6.4 ADD (immediate, Thumb) |
| // adds <Rdn>,#<imm8> Outside IT block. |
| // add<c> <Rdn>,#<imm8> Inside IT block. |
| instruction = mnemonic + "s\t" + getThumbReg(opcode, 8) + "," + getThumbImmediate8(opcode, 1); |
| // No PC check: Rdn cannot be PC |
| break; |
| |
| case thumb_add__imm_to_sp: // A8.6.8 ADD (SP plus immediate) |
| // add<c> sp,sp,#<imm> |
| instruction = mnemonic + "\tsp,sp," + getThumbImmediate7(opcode, 4); |
| // No PC check: not applicable |
| break; |
| |
| case thumb_add__reg: // A8.6.6 ADD (register) |
| // add<c> <Rdn>,<Rm> If <Rdn> is PC, must be outside or last in IT block. |
| // A8.6.9 ADD (SP plus register) |
| // add<c> <Rdm>, sp, <Rdm> |
| // A8.6.9 ADD (SP plus register) |
| // add<c> sp,<Rm> |
| regOp = getThumbRegHigh(opcode, 0, 7); |
| instruction = mnemonic + "\t" + regOp + "," + getThumbRegHigh(opcode, 3, 6); |
| |
| if (regOp.equals("pc")) |
| setDefaultPCJumpProperties(true); |
| // Note: having PC (register 15) as the destination register is deprecated |
| break; |
| |
| case thumb_add__reg_imm: // A8.6.4 ADD (immediate, Thumb) |
| // adds <Rd>,<Rn>,#<imm3> Outside IT block. |
| // add<c> <Rd>,<Rn>,#<imm3> Inside IT block. |
| instruction = mnemonic + "s\t" |
| + getThumbReg(opcode, 0) + "," + getThumbReg(opcode, 3) + "," + getThumbImmediate3(opcode); |
| // No PC check: Rd cannot be PC |
| break; |
| |
| case thumb_add__reg_reg: // A8.6.6 ADD (register) |
| // adds <Rd>,<Rn>,<Rm> Outside IT block. |
| // add<c> <Rd>,<Rn>,<Rm> Inside IT block. |
| instruction = mnemonic + "s\t" |
| + getThumbReg(opcode, 0) + "," + getThumbReg(opcode, 3) + "," + getThumbReg(opcode, 6); |
| // No PC check: Rd cannot be PC |
| break; |
| |
| case thumb_add__sp_imm: // A8.6.8 ADD (SP plus immediate) |
| // add<c> <Rd>,sp,#<imm> |
| instruction = mnemonic + "\t" |
| + getThumbReg(opcode, 8) + ",sp," + getThumbImmediate8(opcode, 4); |
| // No PC check: Rd cannot be PC |
| break; |
| |
| case thumb_adr: // A8.6.10 ADR |
| // adr<c> <Rd>,<label> |
| // add <Rd>,pc,imm8 Alternative form |
| instruction = mnemonic + "\t" |
| + getThumbReg(opcode, 8) + ",pc," + getThumbImmediate8(opcode, 4); |
| // No PC check: Rd cannot be PC |
| break; |
| |
| case thumb_and: // A8.6.12 AND (register) |
| // ands <Rdn>,<Rm> Outside IT block. |
| // and<c> <Rdn>,<Rm> Inside IT block. |
| instruction = mnemonic + "s\t" + getThumbReg(opcode, 0) + "," + getThumbReg(opcode, 3); |
| // No PC check: Rdn cannot be PC |
| break; |
| |
| case thumb_asr__imm: // A8.6.14 ASR (immediate) |
| // asrs <Rd>,<Rm>,#<imm> Outside IT block. |
| // asr<c> <Rd>,<Rm>,#<imm> Inside IT block. |
| instruction = mnemonic + "s\t" |
| + getThumbReg(opcode, 0) + "," + getThumbReg(opcode, 3) + "," + getThumbImmediate5(opcode, 1); |
| // No PC check: Rd cannot be PC |
| break; |
| |
| case thumb_asr__reg: // A8.6.15 ASR (register) |
| // asrs <Rdn>,<Rm> Outside IT block. |
| // asr<c> <Rdn>,<Rm> Inside IT block. |
| instruction = mnemonic + "s\t" + getThumbReg(opcode, 0) + "," + getThumbReg(opcode, 3); |
| // No PC check: Rdn cannot be PC |
| break; |
| |
| case thumb_b_1: // A8.6.16 B |
| // b<c> <label> Not permitted in IT block. |
| offset = getThumbBranchOffset8(opcode); |
| String condString = getThumbCondition(opcode); |
| isSoleDestination = condString.length() == 0; // true if unconditional |
| isSubroutineAddress = false; |
| jumpToAddr = address.add(offset); |
| instruction = mnemonic + condString + "\t" + jumpToAddr.toHexAddressString(); |
| break; |
| |
| case thumb_b_2: // A8.6.16 B |
| // b<c> <label> Outside or last in IT block |
| offset = getThumbBranchOffset11(opcode); |
| isSoleDestination = true; |
| isSubroutineAddress = false; |
| jumpToAddr = address.add(offset); |
| instruction = mnemonic + "\t" + jumpToAddr.toHexAddressString(); |
| break; |
| |
| case thumb_bic: // A8.6.20 BIC (register) |
| // bics <Rdn>,<Rm> Outside IT block. |
| // bic<c> <Rdn>,<Rm> Inside IT block. |
| instruction = mnemonic + "s\t" + getThumbReg(opcode, 0) + "," + getThumbReg(opcode, 3); |
| // No PC check: Rdn cannot be PC |
| break; |
| |
| case thumb_bkpt: // A8.6.22 BKPT |
| // bkpt #<imm8> |
| case thumb_svc: // A8.6.218 SVC (previously SWI) |
| // svc<c> #<imm8> |
| instruction = mnemonic + "\t" + getThumbImmediate8(opcode, 1); |
| // No PC check: not applicable |
| break; |
| |
| case thumb_blx: // A8.6.24 BLX (register) |
| // blx<c> <Rm> Outside or last in IT block |
| instruction = mnemonic + "\t" + getThumbReg(opcode, 3); |
| isSoleDestination = true; |
| isSubroutineAddress = true; |
| addrExpression = getThumbReg(opcode, 3); |
| break; |
| |
| case thumb_bx: // A8.6.25 BX |
| // bx<c> <Rm> Outside or last in IT block |
| instruction = mnemonic + "\t" + getThumbRegHigh(opcode, 3,6); |
| isSoleDestination = true; |
| isSubroutineAddress = false; |
| addrExpression = getThumbRegHigh(opcode, 3, 6); |
| break; |
| |
| case thumb_cbnz_cbz: // A8.6.27 CBNZ, CBZ |
| // cb{n}z <Rn>,<label> Not permitted in IT block. |
| offset = ((opcode >> 3) & 0x1f) * 2; |
| String addN = ((opcode & (1 << 11)) != 0) ? "n" : ""; |
| isSoleDestination = true; |
| isSubroutineAddress = false; |
| jumpToAddr = address.add(offset); |
| instruction = mnemonic + addN + "z\t" |
| + getThumbReg(opcode, 0) + "," + jumpToAddr.toHexAddressString(); |
| // No PC check: not applicable |
| break; |
| |
| case thumb_cmn: // A8.6.33 CMN (register) |
| // cmn<c> <Rn>,<Rm> |
| instruction = mnemonic + "\t" + getThumbReg(opcode, 0) + "," + getThumbReg(opcode, 3); |
| // No PC check: Rd cannot be PC |
| break; |
| |
| case thumb_cmp__imm: // A8.6.35 CMP (immediate) |
| // cmp<c> <Rn>,#<imm8> |
| instruction = mnemonic + "\t" + getThumbReg(opcode, 8) + "," + getThumbImmediate8(opcode, 1); |
| // No PC check: not applicable |
| break; |
| |
| case thumb_cmp__reg: // A8.6.36 CMP (register) |
| // cmp<c> <Rn>,<Rm> <Rn> and <Rm> both from R0-R7 |
| instruction = mnemonic + "\t" + getThumbReg(opcode, 0) + "," + getThumbReg(opcode, 3); |
| // No PC check: not applicable |
| break; |
| |
| case thumb_cmp__reg_hi: // A8.6.36 CMP (register) |
| // cmp<c> <Rn>,<Rm> <Rn> and <Rm> not both from R0-R7 |
| instruction = mnemonic + "\t" + getThumbRegHigh(opcode, 0, 7) + "," + getThumbRegHigh(opcode, 3, 6); |
| // No PC check: not applicable |
| break; |
| |
| case thumb_cps: // B6.1.1 CPS |
| // cps<effect> <iflags> Not permitted in IT block. |
| instruction = mnemonic + getThumbEffect(opcode) + "\t" + getThumbIFlags(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb_eor: // A8.6.45 EOR (register) |
| // eors <Rdn>,<Rm> Outside IT block. |
| // eor<c> <Rdn>,<Rm> Inside IT block. |
| instruction = mnemonic + "s\t" + getThumbReg(opcode, 0) + "," + getThumbReg(opcode, 3); |
| // No PC check: Rd cannot be PC |
| break; |
| |
| case thumb_it: // A8.6.50 IT |
| // it{x{y{z}}} <firstcond> Not permitted in IT block |
| int mask = opcode & 0xf; |
| int cond = (opcode >> 4) & 0xf; |
| int mask3 = (mask >> 3) & 1; |
| int mask2 = (mask >> 2) & 1; |
| int mask1 = (mask >> 1) & 1; |
| int mask0 = mask & 1; |
| int cond0 = cond & 1; |
| String xyz = ""; |
| if ((mask3 == cond0) && ((mask & 7) == 4)) |
| xyz = "t"; |
| else if ((mask3 != cond0) && ((mask & 7) == 4)) |
| xyz = "e"; |
| else if ((mask3 == cond0) && (mask2 == cond0) && ((mask & 3) == 2)) |
| xyz = "tt"; |
| else if ((mask3 != cond0) && (mask2 == cond0) && ((mask & 3) == 2)) |
| xyz = "et"; |
| else if ((mask3 == cond0) && (mask2 != cond0) && ((mask & 3) == 2)) |
| xyz = "te"; |
| else if ((mask3 != cond0) && (mask2 != cond0) && ((mask & 3) == 2)) |
| xyz = "ee"; |
| else if ((mask3 == cond0) && (mask2 == cond0) && (mask1 == cond0) && (mask0 == 1)) |
| xyz = "ttt"; |
| else if ((mask3 != cond0) && (mask2 == cond0) && (mask1 == cond0) && (mask0 == 1)) |
| xyz = "ett"; |
| else if ((mask3 == cond0) && (mask2 != cond0) && (mask1 == cond0) && (mask0 == 1)) |
| xyz = "tet"; |
| else if ((mask3 != cond0) && (mask2 != cond0) && (mask1 == cond0) && (mask0 == 1)) |
| xyz = "eet"; |
| else if ((mask3 == cond0) && (mask2 == cond0) && (mask1 != cond0) && (mask0 == 1)) |
| xyz = "tte"; |
| else if ((mask3 != cond0) && (mask2 == cond0) && (mask1 != cond0) && (mask0 == 1)) |
| xyz = "ete"; |
| else if ((mask3 == cond0) && (mask2 != cond0) && (mask1 != cond0) && (mask0 == 1)) |
| xyz = "tee"; |
| else if ((mask3 != cond0) && (mask2 != cond0) && (mask1 != cond0) && (mask0 == 1)) |
| xyz = "eee"; |
| instruction = mnemonic + xyz + "\t" + getCondition(cond); |
| // No PC check: not applicable |
| break; |
| |
| case thumb_ldm: // A8.6.53 LDM / LDMIA / LDMFD |
| // ldm<c> <Rn>!,<registers> <Rn> not included in <registers> |
| // ldm<c> <Rn>,<registers> <Rn> included in <registers> |
| regOp = getThumbReg(opcode, 8); |
| regList = getThumbRegList(opcode, null); |
| String addExclaim = regList.contains(regOp)? "" : "!"; |
| instruction = mnemonic + "\t" + regOp + addExclaim + "," + regList; |
| // No PC check: Rn cannot be PC and regList cannot contain PC |
| break; |
| |
| case thumb_ldr__imm: // A8.6.57 LDR (immediate, Thumb) |
| // ldr<c> <Rt>, [<Rn>{,#<imm>}] |
| instruction = mnemonic + "\t" + getThumbReg(opcode, 0) + ",[" + getThumbReg(opcode, 3); |
| if (((opcode >> 6) & 0x1f) != 0) |
| instruction += "," + getThumbImmediate5(opcode, 4); |
| instruction += "]"; |
| // No PC check: Rt cannot be PC |
| break; |
| |
| case thumb_ldr__imm_sp: // A8.6.57 LDR (immediate, Thumb) |
| // ldr<c> <Rt>,[sp{,#<imm>}] |
| instruction = mnemonic + "\t" + getThumbReg(opcode, 8) + ",[sp"; |
| if ((opcode & 0xff) != 0) |
| instruction += "," + getThumbImmediate8(opcode, 4); |
| instruction += "]"; |
| // No PC check: Rt cannot be PC |
| break; |
| |
| case thumb_ldr__lit: // A8.6.59 LDR (literal) |
| // ldr<c> <Rt>,<label> |
| // ldr<c> <Rt>,[pc, #<imm>] Alternative form |
| { |
| long imm = (opcode & 0xff) * 4; |
| String addr = Long.toHexString((address.getValue().longValue() & 0xfffffffc) + ((opcode & 0xff) * 4)); |
| int addrLen = addr.length(); |
| if (addrLen > 8) |
| addr = addr.substring(addrLen - 8); |
| |
| instruction = mnemonic + "\t" + getThumbReg(opcode, 8) + ",[pc,#" + getHexValue(imm) + "] ; 0x" + addr; |
| } |
| // No PC check: Rt cannot be PC |
| break; |
| |
| case thumb_ldr__reg: // A8.6.60 LDR (register) |
| // ldr<c> <Rt>,[<Rn>,<Rm>] |
| instruction = mnemonic + "\t" + getThumbReg(opcode, 0) + ",[" + getThumbReg(opcode, 3) + "," |
| + getThumbReg(opcode, 6) + "]"; |
| // No PC check: Rt cannot be PC |
| break; |
| |
| case thumb_ldrb__imm: // A8.6.61 LDRB (immediate, Thumb) |
| // ldrb<c> <Rt>,[<Rn>{,#<imm5>}] |
| instruction = mnemonic + "\t" + getThumbReg(opcode, 0) + ",[" + getThumbReg(opcode, 3); |
| if (((opcode >> 6) & 0x1f) != 0) |
| instruction += "," + getThumbImmediate5(opcode, 1); |
| instruction += "]"; |
| // No PC check: Rt cannot be PC |
| break; |
| |
| case thumb_ldrb__reg: // A8.6.64 LDRB (register) |
| // ldrb<c> <Rt>,[<Rn>,<Rm>] |
| case thumb_ldrh__reg: // A8.6.73 LDRH (immediate, Thumb) |
| // ldrh<c> <Rt>,[<Rn>,<Rm>] |
| case thumb_ldrsb: // A8.6.80 LDRSB (register) |
| // ldrsb<c> <Rt>,[<Rn>,<Rm>] |
| case thumb_ldrsh: // A8.6.84 LDRSH (register) |
| // ldrsh<c> <Rt>,[<Rn>,<Rm>] |
| instruction = mnemonic + "\t" + getThumbReg(opcode, 0) + ",[" + getThumbReg(opcode, 3) + "," |
| + getThumbReg(opcode, 6) + "]"; |
| // No PC check: Rt cannot be PC |
| break; |
| |
| case thumb_ldrh__imm: // A8.6.73 LDRH (immediate, Thumb) |
| // ldrh<c> <Rt>,[<Rn>{,#<imm>}] |
| instruction = mnemonic + "\t" + getThumbReg(opcode, 0) + ",[" + getThumbReg(opcode, 3); |
| if (((opcode >> 6) & 0x1f) != 0) |
| instruction += "," + getThumbImmediate5(opcode, 2); |
| instruction += "]"; |
| // No PC check: Rt cannot be PC |
| break; |
| |
| case thumb_lsl__imm: // A8.6.88 LSL (immediate) |
| // lsls <Rd>,<Rm>,#<imm5> Outside IT block. |
| // lsl<c> <Rd>,<Rm>,#<imm5> Inside IT block. |
| case thumb_lsr__imm: // A8.6.90 LSR (immediate) |
| // lsrs <Rd>,<Rm>,#<imm> Outside IT block. |
| // lsr<c> <Rd>,<Rm>,#<imm> Inside IT block. |
| instruction = mnemonic + "s\t" + getThumbReg(opcode, 0) + "," + getThumbReg(opcode, 3) |
| + ",#" + ((opcode >> 6) & 0x1f); |
| // No PC check: Rt cannot be PC |
| break; |
| |
| case thumb_lsl__reg: // A8.6.89 LSL (register) |
| // lsls <Rdn>,<Rm> Outside IT block. |
| // lsl<c> <Rdn>,<Rm> Inside IT block. |
| case thumb_lsr__reg: // A8.6.91 LSR (register) |
| // lsrs <Rdn>,<Rm> Outside IT block. |
| // lsr<c> <Rdn>,<Rm> Inside IT block. |
| instruction = mnemonic + "s\t" + getThumbReg(opcode, 0) + "," + getThumbReg(opcode, 3); |
| // No PC check: Rt cannot be PC |
| break; |
| |
| case thumb_mov__imm: // A8.6.96 MOV (immediate) |
| // movs <Rd>,#<imm8> Outside IT block. |
| // mov<c> <Rd>,#<imm8> Inside IT block. |
| instruction = mnemonic + "s\t" + getThumbReg(opcode, 8) + "," + getThumbImmediate8(opcode, 1); |
| // No PC check: Rt cannot be PC |
| break; |
| |
| case thumb_mov__reg: // A8.6.97 MOV (register) |
| // mov<c> <Rd>,<Rm> If <Rd> is PC, must be outside or |
| // last in IT block. |
| regOp = getThumbRegHigh(opcode, 0, 7); |
| instruction = mnemonic + "\t" + regOp + "," + getThumbRegHigh(opcode, 3, 6); |
| if (regOp.equals("pc")) { |
| isSoleDestination = true; |
| isSubroutineAddress = false; |
| addrExpression = getThumbRegHigh(opcode, 3, 6); |
| } |
| break; |
| |
| case thumb_movs: // A8.6.97 MOV (register) |
| // movs <Rd>,<Rm> Not permitted in IT block |
| instruction = mnemonic + "\t" + getThumbReg(opcode, 0) + "," + getThumbReg(opcode, 3); |
| // No PC check: Rd cannot be PC |
| break; |
| |
| case thumb_mul: // A8.6.105 MUL |
| // muls <Rdm>,<Rn>,<Rdm> Outside IT block. |
| // mul<c> <Rdm>,<Rn>,<Rdm> Inside IT block. |
| instruction = mnemonic + "s\t" |
| + getThumbReg(opcode, 0) + "," + getThumbReg(opcode, 3) + "," + getThumbReg(opcode, 0); |
| // No PC check: Rdm cannot be PC |
| break; |
| |
| case thumb_mvn: // A8.6.107 MVN (register) |
| // mvns <Rd>,<Rm> Outside IT block. |
| // mvn<c> <Rd>,<Rm> Inside IT block. |
| case thumb_orr: // A8.6.114 ORR (register) |
| // orrs <Rdn>,<Rm> Outside IT block. |
| // orr<c> <Rdn>,<Rm> Inside IT block. |
| instruction = mnemonic + "s\t" + getThumbReg(opcode, 0) + "," + getThumbReg(opcode, 3); |
| // No PC check: Rd or Rdn cannot be PC |
| break; |
| |
| case thumb_nop: // A8.6.110 NOP |
| // nop<c> |
| case thumb_sev: // A8.6.158 SEV |
| // sev<c> |
| case thumb_wfe: // A8.6.411 WFE |
| // wfe<c> |
| case thumb_wfi: // A8.6.412 WFI |
| // wfi<c> |
| case thumb_yield: // A8.6.413 YIELD |
| // yield<c> |
| instruction = mnemonic; |
| // No PC check: not applicable |
| break; |
| |
| case thumb_pop: // A8.6.122 POP |
| // pop<c> <registers> |
| bit = (opcode >> 8) & 1; |
| if (bit == 1) { |
| // This is an unconditional jump. |
| regList = getThumbRegList(opcode, "pc"); |
| |
| setDefaultPCJumpProperties(true); |
| } else { |
| regList = getThumbRegList(opcode, null); |
| } |
| instruction = mnemonic + "\t" + regList; |
| break; |
| |
| case thumb_push: // A8.6.123 PUSH |
| // push<c> <registers> |
| bit = (opcode >> 8) & 1; |
| if (bit == 1) { |
| regList = getThumbRegList(opcode, "lr"); |
| } else { |
| regList = getThumbRegList(opcode, null); |
| } |
| instruction = mnemonic + "\t" + regList; |
| // No PC check: not applicable |
| break; |
| |
| case thumb_rev: // A8.6.135 REV |
| // rev<c> <Rd>,<Rm> |
| case thumb_rev16: // A8.6.136 REV16 |
| // rev16<c> <Rd>,<Rm> |
| case thumb_revsh: // A8.6.137 REVSH |
| // revsh<c> <Rd>,<Rm> |
| instruction = mnemonic + "\t" + getThumbReg(opcode, 0) + "," + getThumbReg(opcode, 3); |
| // No PC check: Rd cannot be PC |
| break; |
| |
| case thumb_ror: // A8.6.140 ROR (register) |
| // rors <Rdn>,<Rm> Outside IT block. |
| // ror<c> <Rdn>,<Rm> Inside IT block. |
| case thumb_sbc: // A8.6.152 SBC (register) |
| // sbcs <Rdn>,<Rm> Outside IT block. |
| // sbc<c> <Rdn>,<Rm> Inside IT block. |
| instruction = mnemonic + "s\t" + getThumbReg(opcode, 0) + "," + getThumbReg(opcode, 3); |
| // No PC check: Rd or Rdn cannot be PC |
| break; |
| |
| case thumb_rsb: // A8.6.142 RSB (immediate) |
| // rsbs <Rd>,<Rn>,#0 Outside IT block. |
| // rsb<c> <Rd>,<Rn>,#0 Inside IT block. |
| instruction = mnemonic + "s\t" + getThumbReg(opcode, 0) + "," + getThumbReg(opcode, 3) + ",#0"; |
| // No PC check: Rd or Rdn cannot be PC |
| break; |
| |
| case thumb_setend: // A8.6.157 SETEND |
| // setend <endian_specifier> Not permitted in IT block |
| String endian = (((opcode >> 3) & 1) == 1) ? "be" : "le"; |
| instruction = mnemonic + "\t" + endian; |
| // No PC check: not applicable |
| break; |
| |
| case thumb_stm: // A8.6.189 STM / STMIA / STMEA |
| // stm<c> <Rn>!,<registers> |
| instruction = mnemonic + "\t" + getThumbReg(opcode, 8) + "!," + getThumbRegList(opcode, null); |
| // No PC check: not applicable |
| break; |
| |
| case thumb_str__imm: // A8.6.193 STR (immediate, Thumb) |
| // str<c> <Rt>, [<Rn>{,#<imm>}] |
| instruction = mnemonic + "\t" + getThumbReg(opcode, 0) + ",[" + getThumbReg(opcode, 3); |
| if (((opcode >> 6) & 0x1f) != 0) |
| instruction += "," + getThumbImmediate5(opcode, 4); |
| instruction += "]"; |
| // No PC check: Rt cannot be PC |
| break; |
| |
| case thumb_str__imm_sp: // A8.6.193 STR (immediate, Thumb) |
| // str<c> <Rt>,[sp,#<imm>] |
| instruction = mnemonic + "\t" + getThumbReg(opcode, 8) + ",[sp," + getThumbImmediate8(opcode, 4) + "]"; |
| // No PC check: Rt cannot be PC |
| break; |
| |
| case thumb_str__reg: // A8.6.195 STR (register) |
| // str<c> <Rt>,[<Rn>,<Rm>] |
| instruction = mnemonic + "\t" + getThumbReg(opcode, 0) + ",[" + getThumbReg(opcode, 3) + "," |
| + getThumbReg(opcode, 6) + "]"; |
| // No PC check: Rt cannot be PC |
| break; |
| |
| case thumb_strb__imm: // A8.6.196 STRB (immediate, Thumb) |
| // strb<c> <Rt>,[<Rn>,#<imm5>] |
| instruction = mnemonic + "\t" + getThumbReg(opcode, 0) + ",[" + getThumbReg(opcode, 3); |
| if (((opcode >> 6) & 0x1f) != 0) |
| instruction += "," + getThumbImmediate5(opcode, 1); |
| instruction += "]"; |
| // No PC check: Rt cannot be PC |
| break; |
| |
| case thumb_strb__reg: // A8.6.198 STRB (register) |
| // strb<c> <Rt>,[<Rn>,<Rm>] |
| instruction = mnemonic + "\t" + getThumbReg(opcode, 0) + ",[" + getThumbReg(opcode, 3) + "," |
| + getThumbReg(opcode, 6) + "]"; |
| // No PC check: Rt cannot be PC |
| break; |
| |
| case thumb_strh__imm: // A8.6.206 STRH (immediate, Thumb) |
| // strh<c> <Rt>,[<Rn>{,#<imm>}] |
| instruction = mnemonic + "\t" + getThumbReg(opcode, 0) + ",[" + getThumbReg(opcode, 3); |
| if (((opcode >> 6) & 0x1f) != 0) |
| instruction += "," + getThumbImmediate5(opcode, 2); |
| instruction += "]"; |
| // No PC check: Rt cannot be PC |
| break; |
| |
| case thumb_strh__reg: // A8.6.208 STRH (register) |
| // strh<c> <Rt>,[<Rn>,<Rm>] |
| instruction = mnemonic + "\t" + getThumbReg(opcode, 0) + ",[" + getThumbReg(opcode, 3) + "," |
| + getThumbReg(opcode, 6) + "]"; |
| // No PC check: Rt cannot be PC |
| break; |
| |
| case thumb_sub__imm: // A8.6.211 SUB (immediate, Thumb) |
| // subs <Rdn>,#<imm8> Outside IT block. |
| // sub<c> <Rdn>,#<imm8> Inside IT block. |
| instruction = mnemonic + "s\t" + getThumbReg(opcode, 8) + "," + getThumbImmediate8(opcode, 1); |
| // No PC check: Rdn cannot be PC |
| break; |
| |
| case thumb_sub__imm_from_sp: // A8.6.215 SUB (SP minus immediate) |
| // sub<c> sp,sp,#<imm> |
| instruction = mnemonic + "\tsp,sp," + getThumbImmediate7(opcode, 4); |
| // No PC check: not applicable |
| break; |
| |
| case thumb_sub__reg_imm: // A8.6.211 SUB (immediate, Thumb) |
| // subs <Rd>,<Rn>,#<imm3> Outside IT block. |
| // sub<c> <Rd>,<Rn>,#<imm3> Inside IT block. |
| instruction = mnemonic + "s\t" + getThumbReg(opcode, 0) + "," + getThumbReg(opcode, 3) + "," |
| + getThumbImmediate3(opcode); |
| // No PC check: Rd cannot be PC |
| break; |
| |
| case thumb_sub__reg_reg: // A8.6.213 SUB (register) |
| // subs <Rd>,<Rn>,<Rm> Outside IT block. |
| // sub<c> <Rd>,<Rn>,<Rm> Inside IT block. |
| instruction = mnemonic + "s\t" + getThumbReg(opcode, 0) + "," + getThumbReg(opcode, 3) + "," |
| + getThumbReg(opcode, 6); |
| // No PC check: Rd cannot be PC |
| break; |
| |
| case thumb_sxtb: // A8.6.223 SXTB |
| // sxtb<c> <Rd>,<Rm> |
| case thumb_sxth: // A8.6.225 SXTH |
| // sxth<c> <Rd>,<Rm> |
| case thumb_tst: // A8.6.231 TST (register) |
| // tst<c> <Rn>,<Rm> |
| case thumb_uxtb: // A8.6.263 UXTB |
| // uxtb<c> <Rd>,<Rm> |
| case thumb_uxth: // A8.6.265 UXTH |
| // uxth<c> <Rd>,<Rm> |
| instruction = mnemonic + "\t" + getThumbReg(opcode, 0) + "," + getThumbReg(opcode, 3); |
| // No PC check: Rd cannot be PC |
| break; |
| |
| case thumb_undefined: |
| instruction = mnemonic; |
| // No PC check: not applicable |
| break; |
| |
| default: |
| instruction = IDisassembler.INVALID_OPCODE; |
| break; |
| } |
| return instruction; |
| } |
| |
| |
| /** |
| * Disassemble a 32-bit Thumb instruction |
| * Reference manual citations (e.g., "A8.6.4") refer to sections in the ARM Architecture |
| * Reference Manual ARMv7-A and ARMv7-R Edition, Errata markup |
| * @param opcode instruction to parse |
| * @return disassembled instruction |
| */ |
| private String parseThumb2Opcode(int opcode) throws BufferUnderflowException { |
| OpcodeARM.Index opcodeIndex = OpcodeARM.Index.invalid; |
| String mnemonic = ""; |
| |
| for (OpcodeARM thumb2Opcode : OpcodeARM.thumb2_opcode_table) { |
| int result = opcode & thumb2Opcode.getOpcodeMask(); |
| if (result == thumb2Opcode.getOpcodeResult()) { |
| opcodeIndex = thumb2Opcode.getIndex(); |
| if (ARMv6 > versionMode |
| && opcodeIndex != OpcodeARM.Index.thumb2_bl |
| && opcodeIndex != OpcodeARM.Index.thumb2_blx) { |
| return IDisassembler.INVALID_OPCODE; |
| } |
| |
| mnemonic = thumb2Opcode.getMnemonic(); |
| break; |
| } |
| } |
| |
| String instruction = ""; |
| String regDest = ""; |
| int offset; |
| boolean checkPC = false; |
| switch (opcodeIndex) { |
| |
| case thumb2_add__imm: // A8.6.4 ADD (immediate) |
| // add{s}<c>.w <Rd>,<Rn>,#<const> |
| // A8.6.8 ADD (SP plus immediate) |
| // addw <Rd>,sp,#<imm12> |
| case thumb2_rsb__imm: // A8.6.142 RSB (immediate) |
| // rsb{s}<c>.w <Rd>,<Rn>,#<const> |
| case thumb2_sub__imm: // A8.6.211 SUB (immediate) |
| // sub{s}<c>.w <Rd>,<Rn>,#<const> |
| instruction = ".w"; |
| // no break! |
| case thumb2_adc__imm: // A8.6.1 ADC (immediate) |
| // adc{s}<c> <Rd>,<Rn>,#<const> |
| case thumb2_and__imm: // A8.6.11 AND (immediate) |
| // and{s}<c> <Rd>,<Rn>,#<const> |
| case thumb2_bic__imm: // A8.6.19 BIC (immediate) |
| // bic{s}<c> <Rd>,<Rn>,#<const> |
| case thumb2_eor__imm: // A8.6.44 EOR (immediate) |
| // eor{s}<c> <Rd>,<Rn>,#<const> |
| case thumb2_orn__imm: // A8.6.111 ORN (immediate) |
| // orn{s}<c> <Rd>,<Rn>,#<const> |
| case thumb2_orr__imm: // A8.6.113 ORR (immediate) |
| // orr{s}<c> <Rd>,<Rn>,#<const> |
| case thumb2_sbc__imm: // A8.6.151 SBC (immediate) |
| // sbc{s}<c> <Rd>,<Rn>,#<const> |
| mnemonic += getS(opcode) + instruction; |
| instruction = mnemonic + TAB + getR_8(opcode) + ',' + getR_16(opcode) |
| + ",#" + getThumb2ExpandImm12(opcode); |
| // No PC check: if Rd is PC, the instruction translates to another enumeral or is UNPREDICTABLE |
| break; |
| |
| case thumb2_addw: // A8.6.4 ADD (immediate, Thumb) |
| // addw<c> <Rd>,<Rn>,#<imm12> |
| case thumb2_subw: // A8.6.211 SUB (immediate, Thumb) |
| // subw<c> <Rd>,<Rn>,#<imm12> |
| instruction = mnemonic + TAB + getR_8(opcode) + ',' + getR_16(opcode) |
| + ",#" + getHexValue(getThumb2RawImm12(opcode)); |
| // No PC check: if Rd is PC, the instruction translates to another enumeral or is UNPREDICTABLE |
| break; |
| |
| case thumb2_adc__reg: // A8.6.2 ADC (register) |
| // adc{s}<c>.w <Rd>,<Rn>,<Rm>{,<shift>} |
| case thumb2_add__reg: // A8.6.6 ADD (register) |
| // add{s}<c>.w <Rd>,<Rn>,<Rm>{,<shift>} |
| // A8.6.9 ADD (SP plus register) |
| // add{s}<c>.w <Rd>,sp,<Rm>{,<shift>} |
| case thumb2_and__reg: // A8.6.12 AND (register) |
| // and{s}<c>.w <Rd>,<Rn>,<Rm>{,<shift>} |
| case thumb2_bic__reg: // A8.6.20 BIC (register) |
| // bic{s}<c>.w <Rd>,<Rn>,<Rm>{,<shift>} |
| case thumb2_eor__reg: // A8.6.45 EOR (register) |
| // eor{s}<c>.w <Rd>,<Rn>,<Rm>{,<shift>} |
| case thumb2_orr__reg: // A8.6.114 ORR (register) |
| // orr{s}<c>.w <Rd>,<Rn>,<Rm>{,<shift>} |
| case thumb2_sbc__reg: // A8.6.152 SBC (register) |
| // sbc{s}<c>.w <Rd>,<Rn>,<Rm>{,<shift>} |
| case thumb2_sub__reg: // A8.6.213 SUB (register) |
| // sub{s}<c>.w <Rd>,<Rn>,<Rm>{,<shift>} |
| instruction = ".w"; |
| // no break! |
| case thumb2_orn__reg: // A8.6.112 ORN (register) |
| // orn{s}<c> <Rd>,<Rn>,<Rm>{,<shift>} |
| case thumb2_rsb__reg: // A8.6.143 RSB (register) |
| // rsb{s}<c> <Rd>,<Rn>,<Rm>{,<shift>} |
| mnemonic += getS(opcode) + instruction; |
| instruction = mnemonic + TAB + getR_8(opcode) + ',' + getR_16(opcode) |
| + ',' + getR_0(opcode) + getThumb2ShiftMode(opcode, 4); |
| // No PC check: if Rd is PC, the instruction translates to another enumeral or is UNPREDICTABLE |
| break; |
| |
| case thumb2_mov__imm: // A8.6.96 MOV (immediate) |
| // mov{s}<c>.w <Rd>,#<const> |
| instruction = ".w"; |
| // no break! |
| case thumb2_mvn__imm: // A8.6.106 MVN (immediate) |
| // mvn{s}<c> <Rd>,#<const> |
| mnemonic += getS(opcode) + instruction; |
| instruction = mnemonic + TAB + getR_8(opcode)+ ",#" + getThumb2ExpandImm12(opcode); |
| // No PC check: if Rd is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case thumb2_mvn__reg: // A8.6.107 MVN (register) |
| // mvn{s}<c>.w <Rd>,<Rm>{,<shift>} |
| instruction = mnemonic + getS(opcode) + ".w\t" + getR_8(opcode) + ',' |
| + getR_0(opcode) + getThumb2ShiftMode(opcode, 4); |
| // No PC check: if Rd is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case thumb2_adr__sub: // A8.6.10 ADR |
| // adr<c>.w <Rd>,<label> |
| // add<c> <Rd>,pc,#imm12 Alternate form |
| case thumb2_adr__add: // A8.6.10 ADR |
| // adr<c>.w <Rd>,<label> |
| // sub<c> <Rd>,pc,#imm12 Alternate form |
| instruction = mnemonic + TAB + getR_8(opcode) + ",pc,#" |
| + getHexValue(getThumb2RawImm12(opcode)); |
| // No PC check: if Rd is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case thumb2_asr__imm: // A8.6.14 ASR (immediate) |
| // asr{s}<c>.w <Rd>,<Rm>,#<imm> |
| case thumb2_lsl__imm: // A8.6.88 LSL (immediate) |
| // lsl{s}<c>.w <Rd>,<Rm>,#<imm> |
| case thumb2_lsr__imm: // A8.6.90 LSR (immediate) |
| // lsr{s}<c>.w <Rd>,<Rm>,#<imm> |
| instruction = ".w"; |
| case thumb2_ror__imm: // A8.6.139 ROR (immediate) |
| // ror{s}<c> <Rd>,<Rm>,#<imm> |
| mnemonic += getS(opcode) + instruction; |
| instruction = mnemonic + TAB + getR_8(opcode) + ',' + getR_0(opcode) |
| + ",#" + getThumb2ShiftValue(opcode, opcode >> 4 & 3); |
| // No PC check: if Rd is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case thumb2_asr__reg: // A8.6.15 ASR (register) |
| // asr{s}<c>.w <Rd>,<Rn>,<Rm> |
| case thumb2_lsl__reg: // A8.6.89 LSL (register) |
| // lsl{s}<c>.w <Rd>,<Rm>,<Rm> |
| case thumb2_lsr__reg: // A8.6.91 LSR (register) |
| // lsr{s}<c>.w <Rd>,<Rn>,<Rm> |
| case thumb2_ror__reg: // A8.6.140 ROR (register) |
| // ror{s}<c>.w <Rd>,<Rn>,<Rm> |
| mnemonic += getS(opcode) + ".w\t"; |
| instruction = mnemonic + getR_8(opcode) + ',' + getR_16(opcode) + ',' + getR_0(opcode); |
| // No PC check: if Rd is PC, the instruction is UNPREDICTABLE |
| break; |
| |
| case thumb2_b__cond: // A8.6.16 B |
| // b<c>.w <label> Not permitted in IT block. |
| instruction = getThumb2Condition(opcode); |
| setDefaultPCJumpProperties(instruction.length() == 0); // true if unconditional b |
| offset = getThumb2_condB_Offset(opcode); |
| jumpToAddr = address.add(offset); |
| instruction = mnemonic + instruction + ".w\t" + jumpToAddr.toHexAddressString(); |
| break; |
| |
| case thumb2_b__uncond: // A8.6.16 B |
| // b<c>.w <label> Outside or last in IT block |
| if (ARMv6 > versionMode) { |
| instruction = IDisassembler.INVALID_OPCODE; |
| break; |
| } |
| // otherwise, no break! |
| case thumb2_bl: // A8.6.23 BL (immediate) |
| // bl<c> <label> Outside or last in IT block |
| // 1 1 1 1 0 S_1_10_10 imm10_1_9_0 1 1 J1_0_13_13 1 J2_0_11_11 imm11_0_10_0 |
| // . . . . . S_1_10_10 imm10_1_9_0 . . J1_0_13_13 . J2_0_11_11 imm11_0_10_0 |
| case thumb2_blx: // A8.6.23 BLX (immediate) // blx<c> <label> Outside or last in IT block |
| // 1 1 1 1 0 S_1_10_10 imm10H_1_9_0 1 1 J1_0_13_13 0 J2_0_11_11 imm10L_0_10_1 h_0_1_0 |
| |
| // If you are confused that the above 3 opcode bit maps are "the same", |
| // my apologies. The manual used to state Encoding T2 bit 0 |
| // was always 0, and now says that bit 0 is field h, |
| // and that blx (immediate) is UNDEFINED for h == 1. |
| // Since h must be 0, and SignExtend() for the 2 cases are: |
| // imm32 = SignExtend(S:I1:I2:imm10:imm11:'0', 32); // Encoding T1 |
| // imm32 = SignExtend(S:I1:I2:imm10H:imm10L:'00', 32) // Encoding T2 |
| // The conclusion is that pretending to get imm11_0_10_0 |
| // for the blx (immediate) T2 case is the same since the |
| // end '0' will match the left 0 in the '00' for T2. |
| // Thus it's okay to use the same code for both cases. |
| |
| { // first, disallow this conditionally based on ref-manual rules if pre-ARMv6 |
| |
| boolean j1 = isBitEnabled(opcode, 13), j2 = isBitEnabled(opcode, 11); |
| if (!(j1 & j2) && ARMv6 > versionMode) { |
| instruction = IDisassembler.INVALID_OPCODE; |
| break; |
| } |
| |
| offset = getThumb2_uncondB_Offset(opcode, j1, j2); |
| } |
| |
| jumpToAddr = address.add(offset); // immediate address known |
| instruction = mnemonic + TAB + jumpToAddr.toHexAddressString(); |
| isSoleDestination = true; |
| isSubroutineAddress = (opcodeIndex != OpcodeARM.Index.thumb2_b__uncond); |
| break; |
| |
| case thumb2_bfi: // A8.6.18 BFI |
| // bfi<c> <Rd>,<Rn>,#<lsb>,#<width> |
| instruction = "," + getR_16(opcode); |
| // no break! |
| case thumb2_bfc: // A8.6.17 BFC |
| // bfc<c> <Rd>,#<lsb>,#<width> |
| { |
| int lsb = opcode >> 10 & 0x1c | opcode >> 6 & 3; |
| int width = (opcode & 0x1f) - lsb + 1; |
| instruction = mnemonic + TAB + getR_8(opcode) + instruction + ",#" + lsb + ",#" + width; |
| // No PC check: if Rd is PC, the instruction is UNPREDICTABLE |
| break; |
| } |
| |
| case thumb2_bfx: // A8.6.154 SBFX |
| // sbfx<c> <Rd>,<Rn>,#<lsb>,#<width> |
| // A8.6.236 UBFX |
| // ubfx<c> <Rd>,<Rn>,#<lsb>,#<width> |
| mnemonic = (isBitEnabled(opcode, 23) ? "u" : "s") + mnemonic; |
| instruction = mnemonic + TAB + getR_8(opcode) + ',' + getR_16(opcode) |
| + ",#" + getThumb2ShiftValue(opcode, 0) + ",#" + ((opcode & 0x1f) + 1); |
| // No PC check: PC at Rd is UNPREDICTABLE |
| break; |
| |
| case thumb2_bxj: // A8.6.26 BXJ |
| // bxj<c> <Rm> Outside or last in IT block |
| instruction = mnemonic + TAB + getR_16(opcode); |
| setDefaultPCJumpProperties(true); |
| break; |
| |
| case thumb2_clrex: // A8.6.30 CLREX |
| // clrex<c> |
| if (ARMv7 > versionMode) { |
| instruction = IDisassembler.INVALID_OPCODE; |
| break; |
| } |
| // else no break! |
| case thumb2_sev: // A8.6.158 SEV |
| // sev<c>.w |
| case thumb2_wfe: // A8.6.411 WFE |
| // wfe<c>.w |
| case thumb2_wfi: // A8.6.412 WFI |
| // wfi<c>.w |
| case thumb2_yield: // A8.6.413 YIELD |
| // yield<c>.w |
| if (ARMv6T2 == versionMode) { |
| mnemonic = "nop.w"; |
| } |
| // else no break! |
| case thumb2_nop: // A8.6.110 NOP |
| // nop<c>.w |
| case thumb2_undefined: |
| if (ARMv6K == versionMode) { |
| instruction = IDisassembler.INVALID_OPCODE; |
| } else if (ARMv6T2 <= versionMode) { |
| instruction = mnemonic; |
| } |
| // No PC check: no registers changed |
| break; |
| |
| case thumb2_reverse: // A8.6.134 RBIT |
| // rbit<c> <Rd>,<Rm> |
| // A8.6.135 REV |
| // rev<c>.w <Rd>,<Rm> |
| // A8.6.136 REV16 |
| // rev16<c>.w <Rd>,<Rm> |
| // A8.6.137 REVSH |
| // revsh<c>.w <Rd>,<Rm> |
| switch (opcode >> 4 & 3) { |
| case 0: mnemonic += "ev.w"; break; |
| case 1: mnemonic += "ev16.w"; break; |
| case 2: mnemonic += "bit"; break; |
| case 3: mnemonic += "evsh.w"; break; |
| } |
| // no break! |
| case thumb2_clz: // A8.6.31 CLZ |
| // clz<c> <Rd>,<Rm> |
| regDest = getR_8(opcode); |
| instruction = mnemonic + TAB + regDest + ',' + getR_0(opcode); |
| // No PC check: PC at Rd is UNPREDICTABLE |
| break; |
| |
| case thumb2_cmn__imm: // A8.6.32 CMN (immediate |
| // cmn<c> <Rn>,#<const> |
| case thumb2_cmp__imm: // A8.6.35 CMP (immediate) |
| // cmp<c>.w <Rn>,#<const> |
| case thumb2_teq__imm: // A8.6.227 TEQ (immediate) |
| // teq<c> <Rn>,#<const> |
| case thumb2_tst__imm: // A8.6.230 TST (immediate) |
| // tst<c> <Rn>,#<const> |
| instruction = mnemonic + TAB + getR_16(opcode) |
| + ",#" + getThumb2ExpandImm12(opcode); |
| // No PC check: no registers changed |
| break; |
| |
| case thumb2_cmn__reg: // A8.6.33 CMN (register) |
| // cmn<c> <Rn>,<Rm>{,<shift>} |
| case thumb2_cmp__reg: // A8.6.36 CMP (register) |
| // cmp<c>.w <Rn>,<Rm> {,<shift>} |
| case thumb2_teq__reg: // A8.6.228 TEQ (register) |
| // teq<c> <Rn>,<Rm>{,<shift>} |
| case thumb2_tst__reg: // A8.6.231 TST (register) |
| // tst<c> <Rn>,<Rm>{,<shift>} |
| instruction = mnemonic + instruction + TAB + getR_16(opcode) + ',' |
| + getR_0(opcode) + getThumb2ShiftMode(opcode, 4); |
| // No PC check: no registers changed |
| break; |
| |
| case thumb2_dbg: // A8.6.40 DBG |
| // dbg<c> #<option> |
| if (ARMv6T2 == versionMode) { |
| instruction = "nop.w"; |
| } else if (ARMv7 > versionMode) { |
| instruction = IDisassembler.INVALID_OPCODE; |
| } else { |
| instruction = mnemonic + "\t#" + (opcode & 0xf); |
| } |
| // No PC check: no registers changed |
| break; |
| |
| case thumb2_dmb: // A8.6.41 DMB |
| // dmb<c> #<option> |
| case thumb2_dsb: // A8.6.42 DSB |
| // dsb<c> #<option> |
| if (ARMv7 > versionMode) |
| instruction = IDisassembler.INVALID_OPCODE; |
| else |
| instruction = mnemonic + TAB + getDataBarrierOption(opcode); |
| // No PC check: no registers changed |
| break; |
| |
| case thumb2_enterx_leavex: // A9.3.1 ENTERX, LEAVEX |
| // enterx Not permitted in IT block. |
| // leavex Not permitted in IT block. |
| instruction = isBitEnabled(opcode, 4) ? mnemonic : "leavex"; |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_isb: // A8.6.49 ISB |
| // isb<c> #<option> |
| if (ARMv7 > versionMode) |
| instruction = IDisassembler.INVALID_OPCODE; |
| else |
| instruction = mnemonic + TAB + getInstructionBarrierOption(opcode); |
| // No PC check: no registers changed |
| break; |
| |
| case thumb2_ldm: // A8.6.53 LDM / LDMIA / LDMFD |
| // ldm<c>.w <Rn>{!},<registers> |
| case thumb2_ldmdb: // A8.6.55 LDMDB / LDMEA |
| // ldmdb<c> <Rn>{!},<registers> |
| regDest = getRegList(opcode); |
| instruction = mnemonic + TAB + getR_16(opcode) + getW(opcode) + ',' + regDest; |
| if (regDest.contains("pc")) |
| setDefaultPCJumpProperties(true); |
| break; |
| |
| case thumb2_ldr: |
| if (isBitEnabled(opcode, 22)) { |
| // exclude ldrt, which has bit 22 set but does not allow RT = PC |
| if (!((opcode >> 8 & 0xf) == 0xe) || !((opcode >> 20 & 0xfff) == 0xf85)) |
| checkPC = true; |
| // most other cases of Rt = 15 end up as thumb2_pld or thumb2_pli |
| } |
| // no break! |
| case thumb2_str: |
| regDest = getR_12(opcode); |
| { |
| String rn = getR_16(opcode); |
| boolean isPC = rn.equals("pc"); |
| boolean isReg = 0 == (opcode >> 6 & 0x3f); |
| if (isBitEnabled(opcode, 22)) { |
| // A8.6.57 LDR (immediate, Thumb) |
| // ldr<c>.w <Rt>,[<Rn>{,#<imm12>}] |
| // ldr<c> <Rt>,[<Rn>,#-<imm8>] |
| // ldr<c> <Rt>,[<Rn>],#+/-<imm8> |
| // ldr<c> <Rt>,[<Rn>,#+/-<imm8>]! |
| // A8.6.59 LDR (literal) |
| // ldr<c>.w <Rt>,<label> |
| // ldr<c>.w <Rt>,[pc,#-0] Special case |
| // A8.6.60 LDR (register) |
| // ldr<c>.w <Rt>,[<Rn>,<Rm>{,lsl #<imm2>}] |
| // A8.6.193 STR (immediate, Thumb) |
| // str<c>.w <Rt>,[<Rn>,#<imm12>] |
| // str<c> <Rt>,[<Rn>,#-<imm8>] |
| // str<c> <Rt>,[<Rn>],#+/-<imm8> |
| // str<c> <Rt>,[<Rn>,#+/-<imm8>]! |
| // A8.6.195 STR (register) |
| // str<c>.w <Rt>,[<Rn>,<Rm>{,lsl #<imm2>}] |
| if (isPC || isBitEnabled(opcode, 23) || isReg) |
| mnemonic += ".w"; |
| else if (0xe == (opcode >> 8 & 0xf)) |
| mnemonic += 't'; |
| |
| } else if (isBitEnabled(opcode, 24)) { |
| // A8.6.78 LDRSB (immediate) |
| // ldrsb<c> <Rt>,[<Rn>,#<imm12>] |
| // A8.6.82 LDRSH (immediate) |
| // ldrsh<c> <Rt>,[<Rn>,#<imm12>] |
| // ldrsb<c> <Rt>,[<Rn>,#-<imm8>] |
| // ldrsb<c> <Rt>,[<Rn>],#+/-<imm8> |
| // ldrsb<c> <Rt>,[<Rn>,#+/-<imm8>]! |
| // A8.6.80 LDRSB (register) |
| // ldrsb<c>.w <Rt>,[<Rn>,<Rm>{,lsl #<imm2>}] |
| // A8.6.84 LDRSH (register) |
| // ldrsh<c>.w <Rt>,[<Rn>,<Rm>{,lsl #<imm2>}] |
| mnemonic += isBitEnabled(opcode, 21) ? "sh" : "sb"; |
| if (!isPC) { |
| if (0xe == (opcode >> 8 & 0xf)) |
| mnemonic += 't'; |
| else if (!isBitEnabled(opcode, 23) && isReg) |
| mnemonic += ".w"; |
| } |
| } else { |
| // A8.6.61 LDRB (immediate, Thumb) |
| // ldrb<c> <Rt>,[<Rn>,#-<imm8>] |
| // ldrb<c> <Rt>,[<Rn>],#+/-<imm8> |
| // ldrb<c> <Rt>,[<Rn>,#+/-<imm8>]! |
| // A8.6.63 LDRB (literal) |
| // ldrb<c> <Rt>,<label> |
| // ldrb<c> <Rt>,[pc,#-0] Special case |
| // A8.6.64 LDRB (register) |
| // ldrb<c>.w <Rt>,[<Rn>,<Rm>{,lsl #<imm2>}] |
| // A8.6.73 LDRH (immediate, Thumb) |
| // ldrh<c>.w <Rt>,[<Rn>{,#<imm12>}] |
| // ldrh<c> <Rt>,[<Rn>,#-<imm8>] |
| // ldrh<c> <Rt>,[<Rn>],#+/-<imm8> |
| // ldrh<c> <Rt>,[<Rn>,#+/-<imm8>]! |
| // A8.6.75 LDRH (literal) |
| // ldrh<c> <Rt>,<label> |
| // ldrh<c> <Rt>,[pc,#-0] Special case |
| // A8.6.76 LDRH (register) |
| // ldrh<c>.w <Rt>,[<Rn>,<Rm>{,lsl #<imm2>}] |
| // A8.6.196 STRB (immediate, Thumb) |
| // strb<c> <Rt>,[<Rn>,#-<imm8>] |
| // strb<c> <Rt>,[<Rn>],#+/-<imm8> |
| // strb<c> <Rt>,[<Rn>,#+/-<imm8>]! |
| // A8.6.198 STRB (register) |
| // strb<c>.w <Rt>,[<Rn>,<Rm>{,lsl #<imm2>}] |
| // A8.6.206 STRH (immediate, Thumb) |
| // strh<c>.w <Rt>,[<Rn>{,#<imm12>}] |
| // strh<c> <Rt>,[<Rn>,#-<imm8>] |
| // strh<c> <Rt>,[<Rn>],#+/-<imm8> |
| // strh<c> <Rt>,[<Rn>,#+/-<imm8>]! |
| // A8.6.208 STRH (register) |
| // strh<c>.w <Rt>,[<Rn>,<Rm>{,lsl #<imm2>}] |
| // A8.6.210 STRT |
| // strt<c> <Rt>,[<Rn>,#<imm8>] |
| mnemonic += isBitEnabled(opcode, 21) ? "h" : "b"; |
| if (!isPC) { |
| if (isBitEnabled(opcode, 23) || isReg) |
| mnemonic += ".w"; |
| else if (0xe == (opcode >> 8 & 0xf)) |
| mnemonic += 't'; |
| } |
| } |
| instruction = mnemonic + TAB + regDest + ','; |
| if (isPC) { |
| // A8.6.59 LDR (literal) |
| // ldr.w <Rt>,[pc,#+/-<imm>] Alternative form |
| // A8.6.63 LDRB (literal) |
| // ldrb <Rt>,[pc,#+/-<imm>] Alternative form |
| // A8.6.75 LDRH (literal) |
| // ldrh <Rt>,[pc,#+/-<imm>] Alternative form |
| // A8.6.79 LDRSB (literal) |
| // ldrsb <Rt>,[pc,#+/-<imm>] Alternative form |
| // A8.6.83 LDRSH (literal) |
| // ldrsh <Rt>,[pc,#+/-<imm>] Alternative form |
| |
| // appends addr as UAL comment |
| instruction += getAddrModePCImm(opcode, opcode & 0xfff); |
| } else if (isBitEnabled(opcode, 23)) { |
| // A8.6.57 LDR (immediate, Thumb) |
| // A8.6.61 LDRB (immediate, Thumb) |
| // A8.6.73 LDRH (immediate, Thumb) |
| // A8.6.78 LDRSB (immediate) |
| // A8.6.193 STR (immediate, Thumb) |
| // A8.6.196 STRB (immediate, Thumb) |
| // A8.6.206 STRH (immediate, Thumb) |
| // <mnemonic><c>.w <Rt>,[<Rn>{,#<imm12>}] |
| // |
| // A8.6.82 LDRSH (immediate) |
| // ldrsh<c> <Rt>,[<Rn>,#<imm12>] |
| instruction += '[' + rn; |
| offset = opcode & 0xfff; |
| if (offset != 0) |
| instruction += ",#" + getHexValue(offset); |
| instruction += ']'; |
| } else if (isReg) { |
| // A8.6.60 LDR (register) |
| // A8.6.64 LDRB (register) |
| // A8.6.76 LDRH (register) |
| // A8.6.80 LDRSB (register) |
| // A8.6.84 LDRSH (register) |
| // A8.6.195 STR (register) |
| // A8.6.198 STRB (register) |
| // A8.6.208 STRH (register) |
| // <mnemonic><c>.w <Rt>,[<Rn>,<Rm>{,lsl #<imm2>}] |
| instruction += getThumb2AddrModeRegImm(opcode); |
| } else { |
| // A8.6.57 LDR (immediate, Thumb) |
| // A8.6.61 LDRB (immediate, Thumb) |
| // A8.6.73 LDRH (immediate, Thumb) |
| // A8.6.78 LDRSB (immediate) |
| // A8.6.82 LDRSH (immediate) |
| // A8.6.193 STR (immediate, Thumb) |
| // A8.6.196 STRB (immediate, Thumb) |
| // A8.6.206 STRH (immediate, Thumb) |
| // <mnemonic><c> <Rt>,[<Rn>,#-<imm8>] |
| // <mnemonic><c> <Rt>,[<Rn>],#+/-<imm8> |
| // <mnemonic><c> <Rt>,[<Rn>,#+/-<imm8>]! |
| |
| instruction += getThumb2AddrModeImm8(opcode, 10, 9, 8, 0); |
| } |
| } |
| if (checkPC && regDest.equals("pc")) |
| setDefaultPCJumpProperties(true); |
| break; |
| |
| case thumb2_ldrex: // A8.6.69 LDREX |
| // ldrex<c> <Rt>,[<Rn>{,#<imm>}] |
| offset = opcode & 0xff; |
| instruction = mnemonic + TAB + getR_12(opcode) + ",[" + getR_16(opcode); |
| if (offset != 0) |
| instruction += ",#" + getHexValue(offset << 2); |
| instruction += ']'; |
| // No PC check: PC at Rt location will generate different instruction or UNPREDICTABLE |
| break; |
| |
| case thumb2_ldrd__imm: // A8.6.66 LDRD (immediate) |
| // ldrd<c> <Rt>,<Rt2>,[<Rn>{,#+/-<imm>}] |
| // ldrd <Rt>,<Rt2>,[<Rn>],#+/-<imm> |
| // ldrd <Rt>,<Rt2>,[<Rn>,#+/-<imm>]! |
| case thumb2_strd: // A8.6.200 STRD (immediate) |
| // strd<c> <Rt>,<Rt2>,[<Rn>{,#+/-<imm>}] |
| // strd <Rt>,<Rt2>,[<Rn>],#+/-<imm> |
| // strd <Rt>,<Rt2>,[<Rn>,#+/-<imm>]! |
| instruction = mnemonic + TAB + getR_12(opcode) + ',' + getR_8(opcode) |
| + ',' + getThumb2AddrModeImm8(opcode, 24, 23, 21, 2); |
| // No PC check: PC in <Rt,Rt2> is UNPREDICTABLE |
| break; |
| |
| case thumb2_ldrd__lit: // A8.6.67 LDRD (literal) |
| // ldrd<c> <Rt>,<Rt2>,<label> |
| // ldrd <Rt>,<Rt2>,[pc,#-0] Special case |
| offset = opcode & 0xff; |
| instruction = mnemonic + TAB + getR_12(opcode) + ',' + getR_8(opcode) |
| + ",[pc,#" + ((isBitEnabled(opcode, 23) && offset != 0) ? "" : "-") |
| + getHexValue(offset<<2) + ']'; |
| // No PC check: PC at Rt is UNPREDICTABLE |
| break; |
| |
| case thumb2_ldrexx: // A8.6.70 LDREXB |
| // ldrexb<c> <Rt>, [<Rn>] |
| // A8.6.71 LDREXD |
| // ldrexd<c> <Rt>,<Rt2>,[<Rn>] |
| // A8.6.72 LDREXH |
| // ldrexh<c> <Rt>, [<Rn>] |
| if (isBitEnabled(opcode, 5)) { |
| mnemonic += 'd'; |
| instruction = "," + getR_8(opcode); |
| } else { |
| mnemonic += isBitEnabled(opcode, 4) ? 'h' : 'b'; |
| } |
| instruction = mnemonic + TAB + getR_12(opcode) + instruction |
| + ",[" + getR_16(opcode) + ']'; |
| // No PC check: PC at Rt is UNPREDICTABLE |
| break; |
| |
| case thumb2_ml: // A8.6.94 MLA |
| // mla<c> <Rd>,<Rn>,<Rm>,<Ra> |
| mnemonic += isBitEnabled(opcode, 4) ? 's' : 'a'; |
| case thumb2_usada8: // A8.6.254 USADA8 |
| // usada8<c> <Rd>,<Rn>,<Rm>,<Ra> |
| instruction = mnemonic + TAB + getR_8(opcode) + ',' + getR_16(opcode) |
| + ',' + getR_0(opcode) + ',' + getR_12(opcode); |
| // No PC check: PC at Rd is UNPREDICTABLE |
| break; |
| |
| case thumb2_mov__reg: // A8.6.97 MOV (register) |
| // mov{s}<c>.w <Rd>,<Rm> |
| instruction = ".w"; |
| // no break! |
| case thumb2_rrx: // A8.6.141 RRX |
| // rrx{s}<c> <Rd>,<Rm> |
| regDest = getR_8(opcode); |
| instruction = mnemonic + getS(opcode) + instruction + TAB + regDest + "," + getR_0(opcode); |
| // No PC check: PC at Rd is UNPREDICTABLE |
| break; |
| |
| case thumb2_movx: // A8.6.96 MOV (immediate) |
| // movw<c> <Rd>,#<imm16> |
| // A8.6.99 MOVT |
| // movt<c> <Rd>,#<imm16> |
| mnemonic += isBitEnabled(opcode, 23) ? 't' : 'w'; |
| instruction = mnemonic + TAB + getR_8(opcode) + ",#" + getThumb2ImmForMovX(opcode); |
| // No PC check: PC at Rd is UNPREDICTABLE |
| break; |
| |
| case thumb2_mrs: // A8.6.102 MRS |
| // mrs<c> <Rd>,<spec_reg> |
| // B6.1.5 MRS |
| // mrs <Rd>,<spec_reg> |
| instruction = mnemonic + TAB + getR_8(opcode) |
| + ',' + (isBitEnabled(opcode, 20) ? 's' : 'c') + "psr"; |
| // No PC check: PC at Rd is UNPREDICTABLE |
| break; |
| |
| case thumb2_msr: // B6.1.7 MSR (register) |
| // msr <spec_reg>,<Rn> |
| instruction = mnemonic + TAB + getStatusReg(opcode, 20) |
| + getStatusRegFields(opcode, 8) + ',' + getR_16(opcode); |
| // No PC check: PC at Rd is UNPREDICTABLE |
| break; |
| |
| case thumb2__r_dnm_math: // A8.6.125 QADD16 |
| // qadd16<c> <Rd>,<Rn>,<Rm> |
| // A8.6.126 QADD8 |
| // qadd8<c> <Rd>,<Rn>,<Rm> |
| // A8.6.127 QASX |
| // qasx<c> <Rd>,<Rn>,<Rm> |
| // A8.6.130 QSAX |
| // qsax<c> <Rd>,<Rn>,<Rm> |
| // A8.6.132 QSUB16 |
| // qsub16<c> <Rd>,<Rn>,<Rm> |
| // A8.6.133 QSUB8 |
| // qsub8<c> <Rd>,<Rn>,<Rm> |
| // A8.6.148 SADD16 |
| // sadd16<c> <Rd>,<Rn>,<Rm> |
| // A8.6.149 SADD8 |
| // sadd8<c> <Rd>,<Rn>,<Rm> |
| // A8.6.150 SASX |
| // sasx<c> <Rd>,<Rn>,<Rm> |
| // A8.6.159 SHADD16 |
| // shadd16<c> <Rd>,<Rn>,<Rm> |
| // A8.6.160 SHADD8 |
| // shadd8<c> <Rd>,<Rn>,<Rm> |
| // A8.6.161 SHASX |
| // shasx<c> <Rd>,<Rn>,<Rm> |
| // A8.6.162 SHSAX |
| // shsax<c> <Rd>,<Rn>,<Rm> |
| // A8.6.163 SHSUB16 |
| // shsub16<c> <Rd>,<Rn>,<Rm> |
| // A8.6.164 SHSUB8 |
| // shsub8<c> <Rd>,<Rn>,<Rm> |
| // A8.6.185 SSAX |
| // ssax<c> <Rd>,<Rn>,<Rm> |
| // A8.6.186 SSUB16 |
| // ssub16<c> <Rd>,<Rn>,<Rm> |
| // A8.6.187 SSUB8 |
| // ssub8<c> <Rd>,<Rn>,<Rm> |
| // A8.6.233 UADD16 |
| // uadd16<c> <Rd>,<Rn>,<Rm> |
| // A8.6.234 UADD8 |
| // uadd8<c> <Rd>,<Rn>,<Rm> |
| // A8.6.235 UASX |
| // uasx<c> <Rd>,<Rn>,<Rm> |
| // A8.6.238 UHADD16 |
| // uhadd16<c> <Rd>,<Rn>,<Rm> |
| // A8.6.239 UHADD8 |
| // uhadd8<c> <Rd>,<Rn>,<Rm> |
| // A8.6.240 UHASX |
| // uhasx<c> <Rd>,<Rn>,<Rm> |
| // A8.6.241 UHSAX |
| // uhsax<c> <Rd>,<Rn>,<Rm> |
| // A8.6.242 UHSUB16 |
| // uhsub16<c> <Rd>,<Rn>,<Rm> |
| // A8.6.243 UHSUB8 |
| // uhsub8<c> <Rd>,<Rn>,<Rm> |
| // A8.6.247 UQADD16 |
| // uqadd16<c> <Rd>,<Rn>,<Rm> |
| // A8.6.248 UQADD8 |
| // uqadd8<c> <Rd>,<Rn>,<Rm> |
| // A8.6.249 UQASX |
| // uqasx<c> <Rd>,<Rn>,<Rm> |
| // A8.6.250 UQSAX |
| // uqsax<c> <Rd>,<Rn>,<Rm> |
| // A8.6.251 UQSUB16 |
| // uqsub16<c> <Rd>,<Rn>,<Rm> |
| // A8.6.252 UQSUB8 |
| // uqsub8<c> <Rd>,<Rn>,<Rm> |
| // A8.6.257 USAX |
| // usax<c> <Rd>,<Rn>,<Rm> |
| // A8.6.258 USUB16 |
| // usub16<c> <Rd>,<Rn>,<Rm> |
| // A8.6.259 USUB8 |
| // usub8<c> <Rd>,<Rn>,<Rm> |
| if (1 == (opcode >> 4 & 7)) |
| mnemonic = ""; |
| else |
| mnemonic = isBitEnabled(opcode, 6) ? "u" : "s"; |
| if (isBitEnabled(opcode, 4)) |
| mnemonic += "q"; |
| else if (isBitEnabled (opcode, 5)) |
| mnemonic += "h"; |
| switch (opcode >> 20 & 7) { |
| case 0: mnemonic += "add8"; break; |
| case 1: mnemonic += "add16"; break; |
| case 2: mnemonic += "asx"; break; |
| case 4: mnemonic += "sub8"; break; |
| case 5: mnemonic += "sub16"; break; |
| case 6: mnemonic += "sax"; break; |
| } |
| // no break! |
| case thumb2_mul: // A8.6.105 MUL |
| // mul<c> <Rd>,<Rn>,<Rm> |
| case thumb2_sel: // A8.6.156 SEL |
| // sel<c> <Rd>,<Rn>,<Rm> |
| case thumb2_usad8: // A8.6.253 USAD8 |
| // usad8<c> <Rd>,<Rn>,<Rm> |
| instruction = mnemonic + TAB + getR_8(opcode) + ',' + getR_16(opcode) + ',' + getR_0(opcode); |
| // No PC check: PC at Rd is UNPREDICTABLE |
| break; |
| |
| case thumb2_sdiv: // A8.6.155 SDIV |
| // sdiv<c> <Rd>,<Rn>,<Rm> |
| case thumb2_udiv: // A8.6.237 UDIV |
| // udiv<c> <Rd>,<Rn>,<Rm> |
| if (ARMv7 > versionMode) { |
| instruction = IDisassembler.INVALID_OPCODE; |
| break; |
| } |
| |
| instruction = mnemonic + TAB + getR_8(opcode) + ',' + getR_16(opcode) + ',' + getR_0(opcode); |
| // No PC check: PC at Rd is UNPREDICTABLE |
| break; |
| |
| case thumb2_qadd: // A8.6.124 QADD |
| // qadd<c> <Rd>,<Rm>,<Rn> |
| // A8.6.128 QDADD |
| // qdadd<c> <Rd>,<Rm>,<Rn> |
| case thumb2_qsub: // A8.6.129 QDSUB |
| // qdsub<c> <Rd>,<Rm>,<Rn> |
| // A8.6.131 QSUB |
| // qsub<c> <Rd>,<Rm>,<Rn> |
| mnemonic = (isBitEnabled(opcode, 4) ? "qd" : "q") + mnemonic; |
| instruction = mnemonic + TAB + getR_8(opcode) + ',' + getR_0(opcode) + ',' + getR_16(opcode); |
| // No PC check: PC at Rd is UNPREDICTABLE |
| break; |
| |
| case thumb2_pkh: // A8.6.116 PKH |
| // pkhbt<c> <Rd>,<Rn>,<Rm>{,lsl #<imm>} |
| // pkhtb <Rd>,<Rn>,<Rm>{,asr #<imm>} |
| // 1 1 1 0 1 0 1 0 1 1 0 0 Rn_1_3_0 (0) imm3_0_14_12 Rd_0_11_8 imm2_0_7_6 tb_0_5_5 0 Rm_0_3_0 |
| mnemonic += isBitEnabled(opcode, 5) ? "tb\t" : "bt\t"; |
| instruction = mnemonic + getR_8(opcode) + ',' + getR_16(opcode) + ',' |
| + getR_0(opcode) + getThumb2ShiftMode(opcode, 4); |
| // No PC check: PC at Rd is UNPREDICTABLE |
| break; |
| |
| case thumb2_pld: |
| case thumb2_pli: |
| if ((opcode >> 16 & 0xf) == 15) { |
| // A8.6.118 PLD (literal) |
| // pld<c> <label> |
| // pld [pc,#-0] Special case |
| // A8.6.120 PLI (immediate, literal) |
| // pli<c> <label> |
| // pli [pc,#-0] Special case |
| instruction = mnemonic + TAB + getAddrModePCImm(opcode, opcode & 0xfff); |
| } else if (isBitEnabled(opcode, 23) || isBitEnabled(opcode, 11)){ |
| String imm; |
| if (isBitEnabled(opcode, 23)) { |
| // A8.6.117 PLD, PLDW (immediate) |
| // pld{w}<c> [<Rn>,#<imm12>] |
| // A8.6.120 PLI (immediate, literal) |
| // pli<c> [<Rn>,#<imm12>] |
| imm = getImmediate12(opcode); |
| } else { |
| // A8.6.117 PLD, PLDW (immediate) |
| // pld{w}<c> [<Rn>,#-<imm8>] |
| // A8.6.120 PLI (immediate, literal) |
| // pli<c> [<Rn>,#-<imm8>] |
| imm = "#-" + getHexValue(opcode & 0xff); |
| } |
| instruction = mnemonic + (isBitEnabled(opcode, 21) ? "w\t[" : "\t[") |
| + getR_16(opcode) + ',' + imm + ']'; |
| } else { |
| // A8.6.119 PLD, PLDW (register) |
| // pld{w}<c> [<Rn>,<Rm>{,lsl #<imm2>}] |
| // A8.6.121 PLI (register) |
| // pli<c> [<Rn>,<Rm>{,lsl #<imm2>}] |
| instruction = mnemonic + (isBitEnabled(opcode, 21) ? "w\t" : "\t") |
| + getThumb2AddrModeRegImm(opcode); |
| } |
| // No PC check: PC at Rn is handled above as literal |
| break; |
| |
| case thumb2_pop__regs: // A8.6.122 POP |
| // pop<c>.w <registers> <registers> contains more than one register |
| checkPC = true; |
| // no break! |
| case thumb2_push__regs: // A8.6.123 PUSH |
| // push<c>.w <registers> <registers> contains more than one register |
| // 1 1 1 0 1 0 0 0 1 0 1 0 1 1 0 1 (0) M_0_14_14 (0) register_list_0_12_0 |
| regDest = getRegList(opcode); |
| instruction = mnemonic + TAB + regDest; |
| if (checkPC && regDest.contains("pc")) |
| setDefaultPCJumpProperties(true); |
| break; |
| |
| case thumb2_pop__reg: // A8.6.122 POP |
| // pop<c>.w <registers> <registers> contains one register, <Rt> |
| checkPC = true; |
| // no break! |
| case thumb2_push__reg: // A8.6.123 PUSH |
| // push<c>.w <registers> <registers> contains one register, <Rt> |
| regDest = getR_12(opcode); |
| instruction = mnemonic + TAB + '{' + regDest + '}'; |
| if (regDest.equals("pc")) |
| setDefaultPCJumpProperties(true); |
| break; |
| |
| case thumb2_rfe: // B6.1.8 RFE |
| // rfe{ia}<c> <Rn>{!} Outside or last in IT block |
| // rfedb <Rn>{!} Outside or last in IT block |
| instruction = mnemonic |
| + (isBitEnabled(opcode, 24) /* && isBitEnabled(opcode, 23) */ ? "ia\t" : "db\t") |
| + getR_16(opcode) + getW(opcode); |
| setDefaultPCJumpProperties(true); |
| break; |
| |
| case thumb2_smc: // B6.1.9 SMC (previously SMI) |
| // smc #<imm4> |
| instruction = mnemonic + "\t#" + getHexValue(opcode >> 16 & 0xf); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_smla: // A8.6.166 SMLABB, SMLABT, SMLATB, SMLATT |
| // smla<x><y><c> <Rd>,<Rn>,<Rm>,<Ra> |
| instruction = mnemonic + getBorT(opcode, 5) + getBorT(opcode, 4) + TAB + getR_8(opcode) |
| + ',' + getR_16(opcode) + ',' + getR_0(opcode) + ',' + getR_12(opcode); |
| // No PC check: PC at Rd is UNPREDICTABLE |
| break; |
| |
| case thumb2_smlad: // A8.6.167 SMLAD |
| // smlad{x}<c> <Rd>,<Rn>,<Rm>,<Ra> |
| case thumb2_smlsd: // A8.6.172 SMLSD |
| // smlsd{x}<c> <Rd>,<Rn>,<Rm>,<Ra> |
| instruction = mnemonic + getX(opcode, 4) + TAB + getR_8(opcode) |
| + ',' + getR_16(opcode) + ',' + getR_0(opcode) + ',' + getR_12(opcode); |
| // No PC check: PC at Rd is UNPREDICTABLE |
| break; |
| |
| case thumb2_smlal: // A8.6.168 SMLAL |
| // smlal<c> <RdLo>,<RdHi>,<Rn>,<Rm> |
| // A8.6.169 SMLALBB, SMLALBT, SMLALTB, SMLALTT |
| // smlal<x><y><c> <RdLo>,<RdHi>,<Rn>,<Rm> |
| if (isBitEnabled(opcode, 7)) |
| mnemonic += getBorT(opcode, 5) + getBorT(opcode, 4); |
| // no break! |
| case thumb2_smull: // A8.6.179 SMULL |
| // smull<c> <RdLo>,<RdHi>,<Rn>,<Rm> |
| case thumb2_umaal: // A8.6.244 UMAAL |
| // umaal<c> <RdLo>,<RdHi>,<Rn>,<Rm> |
| case thumb2_umlal: // A8.6.245 UMLAL |
| // umlal<c> <RdLo>,<RdHi>,<Rn>,<Rm> |
| case thumb2_umull: // A8.6.246 UMULL |
| // umull<c> <RdLo>,<RdHi>,<Rn>,<Rm> |
| instruction = mnemonic + TAB + getR_12(opcode) + ',' + getR_8(opcode) |
| + ',' + getR_16(opcode) + ',' + getR_0(opcode); |
| // No PC check: PC at RdLo or RdHi or Rn or Rm is UNPREDICTABLE |
| break; |
| |
| case thumb2_smlald: // A8.6.170 SMLALD |
| // smlald{x}<c> <RdLo>,<RdHi>,<Rn>,<Rm> |
| case thumb2_smlsld: // A8.6.173 SMLSLD |
| // smlsld{x}<c> <RdLo>,<RdHi>,<Rn>,<Rm> |
| instruction = mnemonic + getX(opcode, 4) + TAB + getR_12(opcode) |
| + ',' + getR_8(opcode) + ',' + getR_16(opcode) + ',' + getR_0(opcode); |
| // No PC check: PC at Rd is UNPREDICTABLE |
| break; |
| |
| case thumb2_smlaw: // A8.6.171 SMLAWB, SMLAWT |
| // smlaw<y><c> <Rd>,<Rn>,<Rm>,<Ra> |
| instruction = mnemonic + getBorT(opcode, 4) + TAB + getR_8(opcode) |
| + ',' + getR_16(opcode) + ',' + getR_0(opcode) + ',' + getR_12(opcode); |
| // No PC check: PC at Rd is UNPREDICTABLE |
| break; |
| |
| case thumb2_smmla: // A8.6.174 SMMLA |
| // smmla{r}<c> <Rd>,<Rn>,<Rm>,<Ra> |
| case thumb2_smmls: // A8.6.175 SMMLS |
| // smmls{r}<c> <Rd>,<Rn>,<Rm>,<Ra> |
| instruction = ',' + getR_12(opcode); |
| // no break! |
| case thumb2_smmul: // A8.6.176 SMMUL |
| // smmul{r}<c> <Rd>,<Rn>,<Rm> |
| instruction = mnemonic + getR(opcode, 4) + TAB + getR_8(opcode) |
| + ',' + getR_16(opcode) + ',' + getR_0(opcode) |
| + instruction; |
| // No PC check: PC at Rd is UNPREDICTABLE |
| break; |
| |
| case thumb2_smuad: // A8.6.177 SMUAD |
| // smuad{x}<c> <Rd>,<Rn>,<Rm> |
| case thumb2_smusd: // A8.6.181 SMUSD |
| // smusd{x}<c> <Rd>,<Rn>,<Rm> |
| instruction = mnemonic + getX(opcode, 4) + TAB + getR_8(opcode) |
| + ',' + getR_16(opcode) + ',' + getR_0(opcode); |
| // No PC check: PC at Rd is UNPREDICTABLE |
| break; |
| |
| case thumb2_smul: // A8.6.178 SMULBB, SMULBT, SMULTB, SMULTT |
| // smul<x><y><c> <Rd>,<Rn>,<Rm> |
| instruction = mnemonic + getBorT(opcode, 5) + getBorT(opcode, 4) + TAB + getR_8(opcode) |
| + ',' + getR_16(opcode) + ',' + getR_0(opcode); |
| // No PC check: PC at Rd is UNPREDICTABLE |
| break; |
| |
| case thumb2_smulw: // A8.6.180 SMULWB, SMULWT |
| // smulw<y><c> <Rd>,<Rn>,<Rm> |
| instruction = mnemonic + getBorT(opcode, 4) + TAB + getR_8(opcode) |
| + ',' + getR_16(opcode) + ',' + getR_0(opcode); |
| // No PC check: PC at Rd is UNPREDICTABLE |
| break; |
| |
| case thumb2_srs: // B6.1.10 SRS |
| // srsdb sp{!},#<mode> |
| // srs{ia} sp{!},#<mode> |
| instruction = mnemonic |
| + (isBitEnabled(opcode, 24) ? "ia" : "db") |
| + "\tsp" + getW(opcode) + ",#" + getHexValue(opcode & 0x1f); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_ssat: // A8.6.183 SSAT |
| // ssat<c> <Rd>,#<imm>,<Rn>{,<shift>} |
| case thumb2_usat: // A8.6.256 USAT16 |
| // usat16<c> <Rd>,#<imm4>,<Rn> |
| offset = (opcode & 0x1f) + 1 - getBit(opcode, 23); |
| instruction = mnemonic + TAB + getR_8(opcode) + ",#" + offset + ',' + getR_16(opcode) |
| + getThumb2ShiftMode(opcode, 20); |
| // No PC check: PC at Rd is UNPREDICTABLE |
| break; |
| |
| case thumb2_ssat16: // A8.6.184 SSAT16 |
| // ssat16<c> <Rd>,#<imm>,<Rn> |
| case thumb2_usat16: // A8.6.256 USAT16 |
| // usat16<c> <Rd>,#<imm4>,<Rn> |
| // . . . . . (0) . . . . . . Rn_1_3_0 . . . . Rd_0_11_8 . . (0)(0) sat_imm_0_3_0 |
| offset = (opcode & 0xf) + 1 - getBit(opcode, 23); |
| instruction = mnemonic + TAB + getR_8(opcode) + ",#" + offset + ',' + getR_16(opcode); |
| // No PC check: PC at Rd is UNPREDICTABLE |
| break; |
| |
| case thumb2_stm: // A8.6.189 STM / STMIA / STMEA |
| // stm<c>.w <Rn>{!},<registers> |
| case thumb2_stmdb: // A8.6.191 STMDB / STMFD |
| // stmdb<c> <Rn>{!},<registers> |
| instruction = mnemonic + TAB + getR_16(opcode) + getW(opcode) |
| + ',' + getRegList(opcode); |
| // No PC check: PC is not eligible for writeback |
| break; |
| |
| case thumb2_strex: // A8.6.202 STREX |
| // strex<c> <Rd>,<Rt>,[<Rn>{,#<imm>}] |
| offset = opcode & 0xff; |
| instruction = mnemonic + TAB + getR_8(opcode) + ',' + getR_12(opcode) + ",[" + getR_16(opcode); |
| if (offset != 0) |
| instruction += ",#" + getHexValue(offset << 2); |
| instruction += ']'; |
| // No PC check: PC at Rd is UNPREDICTABLE |
| break; |
| |
| case thumb2_strexx: // A8.6.203 STREXB |
| // strexb<c> <Rd>,<Rt>,[<Rn>] |
| // A8.6.204 STREXD |
| // strexd<c> <Rd>,<Rt>,<Rt2>,[<Rn>] |
| // A8.6.205 STREXH |
| // strexh<c> <Rd>,<Rt>,[<Rn>] |
| if (isBitEnabled(opcode, 5)) { |
| mnemonic += 'd'; |
| instruction = "," + getR_8(opcode); |
| } else { |
| mnemonic += isBitEnabled(opcode, 4) ? 'h' : 'b'; |
| } |
| instruction = mnemonic + TAB + getR_0(opcode) + ',' + getR_12(opcode) |
| + instruction + ",[" + getR_16(opcode) + ']'; |
| // No PC check: PC at Rt is UNPREDICTABLE |
| break; |
| |
| case thumb2_subs: // B6.1.13 SUBS PC, LR and related instructions |
| // subs pc,lr,#<imm8> Outside or last in IT block |
| instruction = mnemonic + "\tpc,lr,#" + getHexValue(opcode & 0xff); |
| setDefaultPCJumpProperties(true); |
| break; |
| |
| case thumb2_sxtab: // A8.6.220 SXTAB |
| // sxtab<c> <Rd>,<Rn>,<Rm>{,<rotation>} |
| case thumb2_sxtab16: // A8.6.221 SXTAB16 |
| // sxtab16<c> <Rd>,<Rn>,<Rm>{,<rotation>} |
| case thumb2_sxtah: // A8.6.222 SXTAH |
| // sxtah<c> <Rd>,<Rn>,<Rm>{,<rotation>} |
| case thumb2_uxtab: // A8.6.260 UXTAB |
| // uxtab<c> <Rd>,<Rn>,<Rm>{,<rotation>} |
| case thumb2_uxtab16: // A8.6.261 UXTAB16 |
| // uxtab16<c> <Rd>,<Rn>,<Rm>{,<rotation>} |
| case thumb2_uxtah: // A8.6.262 UXTAH |
| // uxtah<c> <Rd>,<Rn>,<Rm>{,<rotation>} |
| instruction = mnemonic + TAB + getR_8(opcode) + ',' + getR_16(opcode) |
| + ',' + getR_0(opcode) + getRotationOperand(opcode, 4); |
| // No PC check: PC at Rd is UNPREDICTABLE |
| break; |
| |
| case thumb2_sxtb: // A8.6.223 SXTB |
| // sxtb<c>.w <Rd>,<Rm>{,<rotation>} |
| case thumb2_sxtb16: // A8.6.224 SXTB16 |
| // sxtb16<c> <Rd>,<Rm>{,<rotation>} |
| case thumb2_sxth: // A8.6.225 SXTH |
| // sxth<c>.w <Rd>,<Rm>{,<rotation>} |
| case thumb2_uxtb: // A8.6.263 UXTB |
| // uxtb<c>.w <Rd>,<Rm>{,<rotation>} |
| case thumb2_uxtb16: // A8.6.264 UXTB16 |
| // uxtb16<c> <Rd>,<Rm>{,<rotation>} |
| case thumb2_uxth: // A8.6.265 UXTH |
| // uxth<c>.w <Rd>,<Rm>{,<rotation>} |
| instruction = mnemonic + TAB + getR_8(opcode) + ',' + getR_0(opcode) |
| + getRotationOperand(opcode, 4); |
| // No PC check: PC at Rd is UNPREDICTABLE |
| break; |
| |
| case thumb2_tb: // A8.6.226 TBB, TBH |
| // tbb<c> [<Rn>,<Rm>] Outside or last in IT block |
| // tbh<c> [<Rn>,<Rm>,LSL #1] Outside or last in IT block |
| mnemonic += isBitEnabled(opcode, 4) ? 'h' : 'b'; |
| instruction = mnemonic + TAB + '[' + getR_16(opcode) + ',' + getR_0(opcode) |
| + (isBitEnabled(opcode, 4) ? ",lsl #1" : "") + ']'; |
| setDefaultPCJumpProperties(false); |
| break; |
| |
| // VFP instructions |
| |
| case thumb2_vhadd_vhsub: // A8.6.306 VHADD, VHSUB |
| // vhadd<c> <Qd>, <Qn>, <Qm> |
| // vhadd<c> <Dd>, <Dn>, <Dm> |
| // vhsub<c> <Qd>, <Qn>, <Qm> |
| // vhsub<c> <Dd>, <Dn>, <Dm> |
| mnemonic += isBitEnabled(opcode, 9) ? "sub" : "add"; |
| case thumb2_vaba: // A8.6.266 VABA, VABAL |
| // vaba<c>.<dt> <Qd>, <Qn>, <Qm> |
| // vaba<c>.<dt> <Dd>, <Dn>, <Dm> |
| case thumb2_vabd__int: // A8.6.267 VABD, VABDL (integer) |
| // vabd<c>.<dt> <Qd>, <Qn>, <Qm> |
| // vabd<c>.<dt> <Dd>, <Dn>, <Dm> |
| case thumb2_vcge__reg_int: // A8.6.282 VCGE (register) |
| // vceq<c>.<dt> <Qd>, <Qn>, <Qm> |
| // vceq<c>.<dt> <Dd>, <Dn>, <Dm> |
| case thumb2_vcgt__reg_int: // A8.6.284 VCGT (register) |
| // vcgt<c>.<dt> <Qd>, <Qn>, <Qm> |
| // vcgt<c>.<dt> <Dd>, <Dn>, <Dm> |
| case thumb2_vqadd: // A8.6.357 VQADD |
| // vqadd<c>.<dt> <Qd>,<Qn>,<Qm> |
| // vqadd<c>.<dt> <Dd>,<Dn>,<Dm> |
| case thumb2_vrhadd: // A8.6.374 VRHADD |
| // vrhadd<c> <Qd>, <Qn>, <Qm> |
| // vrhadd<c> <Dd>, <Dn>, <Dm> |
| case thumb2_vqsub: // A8.6.369 VQSUB |
| // vqsub<c>.<type><size> <Qd>,<Qn>,<Qm> |
| // vqsub<c>.<type><size> <Dd>,<Dn>,<Dm> |
| instruction = mnemonic + getVFPSorUDataType(opcode, 28) + getVFPQorDdnmRegs(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vqdml__vec: // A8.6.358 VQDMLAL, VQDMLSL |
| // vqd<op><c>.<dt> <Qd>,<Dn>,<Dm> |
| mnemonic += isBitEnabled(opcode, 9) ? "sl" : "al"; |
| // can use getVFPSorUDataType() because bit 24 is always '0' |
| // no break! |
| case thumb2_vabal: // A8.6.266 VABA, VABAL |
| // vabal<c>.<dt> <Qd>, <Dn>, <Dm> |
| case thumb2_vabdl: // A8.6.267 VABD, VABDL (integer) |
| // vabdl<c>.<dt> <Qd>, <Dn>, <Dm> |
| case thumb2_vqdmull__vec: // A8.6.360 VQDMULL |
| // vqdmull<c>.<dt> <Qd>,<Dn>,<Dm> |
| instruction = mnemonic + getVFPSorUDataType(opcode, 28) |
| + TAB + getVFPQdDnDmRegs(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vabd__f32: // A8.6.268 VABD (floating-point) |
| // vabd<c>.f32 <Qd>, <Qn>, <Qm> |
| // vabd<c>.f32 <Dd>, <Dn>, <Dm> |
| case thumb2_vadd__f32: // A8.6.272 VADD (floating-point) |
| // vadd<c>.f32 <Qd>, <Qn>, <Qm> |
| // vadd<c>.f32 <Dd>, <Dn>, <Dm> |
| case thumb2_vceq__reg_f32: // A8.6.280 VCEQ (register) |
| // vceq<c>.f32 <Qd>, <Qn>, <Qm> |
| // vceq<c>.f32 <Dd>, <Dn>, <Dm> |
| case thumb2_vcge__reg_f32: // A8.6.282 VCGE (register) |
| // vcge<c>.f32 <Qd>, <Qn>, <Qm> |
| // vcge<c>.f32 <Dd>, <Dn>, <Dm> |
| case thumb2_vcgt__reg_f32: // A8.6.284 VCGT (register) |
| // vcgt<c>.f32 <Qd>, <Qn>, <Qm> |
| // vcgt<c>.f32 <Dd>, <Dn>, <Dm> |
| case thumb2_vmul__f32: // A8.6.338 VMUL (floating-point) |
| // vmul<c>.f32 <Qd>, <Qn>, <Qm> |
| // vmul<c>.f32 <Dd>, <Dn>, <Dm> |
| case thumb2_vpadd__f32: // A8.6.350 VPADD (floating-point) |
| // vpadd<c>.f32 <Dd>, <Dn>, <Dm> |
| case thumb2_vrecps: // A8.6.372 VRECPS |
| // vrecps<c>.f32 <Qd>, <Qn>, <Qm> |
| // vrecps<c>.f32 <Dd>, <Dn>, <Dm> |
| case thumb2_vrsqrts: // A8.6.379 VRSQRTS |
| // vrsqrts<c>.f32 <Qd>, <Qn>, <Qm> |
| // vrsqrts<c>.f32 <Dd>, <Dn>, <Dm> |
| case thumb2_vsub__f32: // A8.6.402 VSUB (floating-point) |
| // vsub<c>.f32 <Qd>, <Qn>, <Qm> |
| // vsub<c>.f32 <Dd>, <Dn>, <Dm> |
| instruction = mnemonic + ".f32\t" + getVFPQorDdnmRegs(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vabs: // A8.6.269 VABS |
| // vabs<c>.<dt> <Qd>, <Qm> |
| // vabs<c>.<dt> <Dd>, <Dm> |
| case thumb2_vneg: // A8.6.342 VNEG |
| // vneg<c>.<dt> <Qd>, <Qm> |
| // vneg<c>.<dt> <Dd>, <Dm> |
| instruction = mnemonic + getVFPSorUorFQorDdmOperands(opcode, 10, 4); // chose bit 11 because it is 0 |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vabs__f: // A8.6.269 VABS |
| // vabs<c>.f64 <Dd>, <Dm> |
| // vabs<c>.f32 <Sd>, <Sm> |
| case thumb2_vmov__reg_f: // A8.6.327 VMOV (register) |
| // vmov<c>.f64 <Dd>, <Dm> |
| // vmov<c>.f32 <Sd>, <Sm> |
| case thumb2_vneg__f: // A8.6.342 VNEG |
| // vneg<c>.f64 <Dd>, <Dm> |
| // vneg<c>.f32 <Sd>, <Sm> |
| case thumb2_vsqrt: // A8.6.388 VSQRT |
| // vsqrt<c>.f64 <Dd>, <Dm> |
| // vsqrt<c>.f32 <Sd>, <Sm> |
| instruction = mnemonic + getVFPSzF64F32dmOperands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vacge_vacgt: // A8.6.270 VACGE, VACGT, VACLE, VACLT |
| // vacge<c>.f32 <Qd>, <Qn>, <Qm> |
| // vacge<c>.f32 <Dd>, <Dn>, <Dm> |
| // vacgt<c>.f32 <Qd>, <Qn>, <Qm> |
| // vacgt<c>.f32 <Dd>, <Dn>, <Dm> |
| instruction = mnemonic + getVFP_vacge_vacgt(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vadd__int: // A8.6.271 VADD (integer) |
| // vadd<c>.<dt> <Qd>, <Qn>, <Qm> |
| // vadd<c>.<dt> <Dd>, <Dn>, <Dm> |
| case thumb2_vceq__reg_int: // A8.6.280 VCEQ (register) |
| // vceq<c>.<dt> <Qd>, <Qn>, <Qm> |
| // vceq<c>.<dt> <Dd>, <Dn>, <Dm> |
| case thumb2_vpadd__int: // A8.6.349 VPADD (integer) |
| // vpadd<c>.<dt> <Dd>, <Dn>, <Dm> |
| case thumb2_vsub__int: // A8.6.401 VSUB (integer) |
| // vsub<c>.<dt> <Qd>, <Qn>, <Qm> |
| // vsub<c>.<dt> <Dd>, <Dn>, <Dm> |
| instruction = mnemonic + getVFPIDataTypeQorDdnmOperands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vnml: // A8.6.343 VNMLA, VNMLS, VNMUL |
| // vnmla<c>.f64 <Dd>, <Dn>, <Dm> |
| // vnmla<c>.f32 <Sd>, <Sn>, <Sm> |
| // vnmls<c>.f64 <Dd>, <Dn>, <Dm> |
| // vnmls<c>.f32 <Sd>, <Sn>, <Sm> |
| mnemonic += isBitEnabled(opcode, 6) ? 'a' : 's'; |
| // no break! |
| case thumb2_vadd__fp_f: // A8.6.272 VADD (floating-point) |
| // vadd<c>.f64 <Dd>, <Dn>, <Dm> |
| // vadd<c>.f32 <Sd>, <Sn>, <Sm> |
| case thumb2_vdiv: // A8.6.301 VDIV |
| // vdiv<c>.f64 <Dd>, <Dn>, <Dm> |
| // vdiv<c>.f32 <Sd>, <Sn>, <Sm> |
| case thumb2_vmul__fp_2: // A8.6.338 VMUL (floating-point) |
| // vmul<c>.f64 <Dd>, <Dn>, <Dm> |
| // vmul<c>.f32 <Sd>, <Sn>, <Sm> |
| case thumb2_vnmul: // A8.6.343 VNMLA, VNMLS, VNMUL |
| // vnmul<c>.f64 <Dd>, <Dn>, <Dm> |
| // vnmul<c>.f32 <Sd>, <Sn>, <Sm> |
| case thumb2_vsub__fp_f: // A8.6.402 VSUB (floating-point) |
| // vsub<c>.f64 <Dd>, <Dn>, <Dm> |
| // vsub<c>.f32 <Sd>, <Sn>, <Sm> |
| instruction = mnemonic + getVFPSzF64F32dnmOperands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vaddhn: // A8.6.273 VADDHN |
| // vaddhn<c>.<dt> <Dd>, <Qn>, <Qm> |
| case thumb2_vraddhn: // A8.6.370 VRADDHN |
| // vraddhn<c>.<dt> <Dd>, <Qn>, <Qm> |
| case thumb2_vrsubhn: // A8.6.381 VRSUBHN |
| // vrsubhn<c>.<dt> <Dd>, <Qn>, <Qm> |
| case thumb2_vsubhn: // A8.6.403 VSUBHN |
| // vsubhn<c>.<dt> <Dd>, <Qn>, <Qm> |
| instruction = mnemonic + getVFPIDataType2DdQnDmOperands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vaddl_vaddw: // A8.6.274 VADDL, VADDW |
| // vaddl<c>.<dt> <Qd>, <Dn>, <Dm> |
| // vaddw<c>.<dt> <Qd>, <Qn>, <Dm> |
| case thumb2_vsubl_vsubw: // A8.6.404 VSUBL, VSUBW |
| // vsubl<c>.<dt> <Qd>, <Dn>, <Dm> |
| // vsubw<c>.<dt> {<Qd>,} <Qn>, <Dm> |
| instruction = mnemonic + getVFP_vXXXl_vXXXw(opcode, 28); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vbif_vbit_vbsl_veor: // A8.6.279 VBIF, VBIT, VBSL |
| // vbif<c> <Qd>, <Qn>, <Qm> |
| // vbif<c> <Dd>, <Dn>, <Dm> |
| // vbit<c> <Qd>, <Qn>, <Qm> |
| // vbit<c> <Dd>, <Dn>, <Dm> |
| // vbsl<c> <Qd>, <Qn>, <Qm> |
| // vbsl<c> <Dd>, <Dn>, <Dm> |
| // veor<c> <Qd>, <Qn>, <Qm> |
| // veor<c> <Dd>, <Dn>, <Dm> |
| mnemonic = getVFP_vbif_vbit_vbsl_veor_mnemonic(opcode); |
| // no break! |
| case thumb2_vand: // A8.6.276 VAND (register) |
| // vand<c> <Qd>, <Qn>, <Qm> |
| // vand<c> <Dd>, <Dn>, <Dm> |
| case thumb2_vbic__reg: // A8.6.278 VBIC (register) |
| // vbic<c> <Qd>, <Qn>, <Qm> |
| // vbic<c> <Dd>, <Dn>, <Dm> |
| case thumb2_vorn: // A8.6.345 VORN (register) |
| // vorn<c> <Qd>, <Qn>, <Qm> |
| // vorn<c> <Dd>, <Dn>, <Dm> |
| instruction = mnemonic + getVFPQorDdnmRegs(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vmov_vorr: // A8.6.327 VMOV (register) |
| // vmov<c> <Qd>, <Qn>, <Qm> |
| // vmov<c> <Dd>, <Dn>, <Dm> |
| // A8.6.347 VORR (register) |
| // vorr<c> <Qd>, <Qn>, <Qm> |
| // vorr<c> <Dd>, <Dn>, <Dm> |
| // mnemonic is "vmov" by default |
| if (getBit(opcode, 7) == getBit(opcode, 5) && |
| (opcode & 0xf) == (opcode >> 16 & 0xf)) { |
| instruction = mnemonic + TAB + getVFPQorDdmRegs(opcode); |
| } else { |
| instruction = "vorr" + getVFPQorDdnmRegs(opcode); |
| } |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vmov_vbitwise: // A8.6.277 VBIC (immediate) |
| // vbic<c>.<dt> <Qd>, #<imm> |
| // vbic<c>.<dt> <Dd>, #<imm> |
| // A8.6.326 VMOV (immediate) |
| // vmov<c>.<dt> <Qd>, #<imm> |
| // vmov<c>.<dt> <Dd>, #<imm> |
| // A8.6.340 VMVN (immediate) |
| // vmvn<c>.<dt> <Qd>, #<imm> |
| // vmvn<c>.<dt> <Dd>, #<imm> |
| // A8.6.346 VORR (immediate) |
| // vorr<c>.<dt> <Qd>, #<imm> |
| // vorr<c>.<dt> <Dd>, #<imm> |
| instruction = getVFP_vmov_vbitwise_instruction(opcode, 28); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vceq__imm0: // A8.6.281 VCEQ (immediate #0) |
| // vceq<c>.<dt> <Qd>, <Qm>, #0 |
| // vceq<c>.<dt> <Dd>, <Dm>, #0 |
| // vceq<c>.<dt> <Qd>, <Qm>, #0 |
| // vceq<c>.<dt> <Dd>, <Dm>, #0 |
| instruction = mnemonic + getVFPIorFQorDdmOperands(opcode, 10) + ",#0"; |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vcge__imm0: // A8.6.283 VCGE (immediate #0) |
| // vcge<c>.<dt> <Qd>, <Qm>, #0 |
| // vcge<c>.<dt> <Dd>, <Dm>, #0 |
| case thumb2_vcgt__imm0: // A8.6.285 VCGT (immediate #0) |
| // vcgt<c>.<dt> <Qd>, <Qm>, #0 |
| // vcgt<c>.<dt> <Dd>, <Dm>, #0 |
| case thumb2_vcle: // A8.6.287 VCLE (immediate #0) |
| // vcle<c>.<dt> <Qd>, <Qm>, #0 |
| // vcle<c>.<dt> <Dd>, <Dm>, #0 |
| case thumb2_vclt: // A8.6.290 VCLT (immediate #0) |
| // vclt<c>.<dt> <Qd>, <Qm>, #0 |
| // vclt<c>.<dt> <Dd>, <Dm>, #0 |
| instruction = mnemonic + getVFPSorUorFQorDdmOperands(opcode, 10, 11) + ",#0"; // chose bit 11 because it is 0 |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vcls: // A8.6.288 VCLS |
| // vcls<c>.<dt> <Qd>, <Qm> |
| // vcls<c>.<dt> <Dd>, <Dm> |
| case thumb2_vqabs: // A8.6.356 VQABS |
| // vqabs<c>.<dt> <Qd>,<Qm> |
| // vqabs<c>.<dt> <Dd>,<Dm> |
| case thumb2_vqneg: // A8.6.362 VQNEG |
| // vqneg<c>.<dt> <Qd>,<Qm> |
| // vqneg<c>.<dt> <Dd>,<Dm> |
| instruction = mnemonic + getVFPSorUorFQorDdmOperands(opcode, 4, 11); // chose bit 11 because it is 0 |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vclz: // A8.6.291 VCLZ |
| // vclz<c>.<dt> <Qd>, <Qm> |
| // vclz<c>.<dt> <Dd>, <Dm> |
| instruction = mnemonic + getVFPIorFQorDdmOperands(opcode, 11); // chose bit 11 because it is 0 |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vcmp__reg: // A8.6.292 VCMP, VCMPE |
| // vcmp{e}<c>.f64 <Dd>, <Dm> |
| // vcmp{e}<c>.f32 <Sd>, <Sm> |
| instruction = mnemonic + getE(opcode) + getVFPSzF64F32dmOperands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vcmp__to_0: // A8.6.292 VCMP, VCMPE |
| // vcmp{e}<c>.f64 <Dd>, #0.0 |
| // vcmp{e}<c>.f32 <Sd>, #0.0 |
| instruction = mnemonic + getE(opcode) + getVFP_vcmpTo0Operands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vcnt: // A8.6.293 VCNT |
| // vcnt<c>.8 <Qd>, <Qm> |
| // vcnt<c>.8 <Dd>, <Dm> |
| mnemonic += ".8"; |
| case thumb2_vmvn: // A8.6.341 VMVN (register) |
| // vmvn<c> <Qd>, <Qm> |
| // vmvn<c> <Dd>, <Dm> |
| case thumb2_vswp: // A8.6.405 VSWP |
| // vswp<c> <Qd>, <Qm> |
| // vswp<c> <Dd>, <Dm> |
| instruction = mnemonic + getVFPQorDdmRegs(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vcvt__fp_i_vec: // A8.6.294 VCVT (between floating-point and integer, Advanced SIMD) |
| // vcvt<c>.<Td>.<Tm> <Qd>, <Qm> |
| // vcvt<c>.<Td>.<Tm> <Dd>, <Dm> |
| instruction = mnemonic + getVFP_vcvtFpIVecOperands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vcvt__fp_i_reg: // A8.6.295 VCVT, VCVTR (between floating-point and integer, VFP) |
| // vcvt{r}<c>.s32.f64 <Sd>, <Dm> |
| // vcvt{r}<c>.s32.f32 <Sd>, <Sm> |
| // vcvt{r}<c>.u32.f64 <Sd>, <Dm> |
| // vcvt{r}<c>.u32.f32 <Sd>, <Sm> |
| // vcvt<c>.f64.<Tm> <Dd>, <Sm> |
| // vcvt<c>.f32.<Tm> <Sd>, <Sm> |
| if (isBitEnabled(opcode, 18) && !isBitEnabled(opcode, 7)) |
| mnemonic += "r"; |
| instruction = mnemonic + getVFP_vcvtFpIRegOperands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vcvt__fp_fix_vec: // A8.6.296 VCVT (between floating-point and fixed-point, Advanced SIMD) |
| // vcvt<c>.<Td>.<Tm> <Qd>, <Qm>, #<fbits> |
| // vcvt<c>.<Td>.<Tm> <Dd>, <Dm>, #<fbits> |
| instruction = mnemonic + getVFP_vcvtFpFixVecOperands(opcode, 28); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vcvt__fp_fix_reg: // A8.6.297 VCVT (between floating-point and fixed-point, VFP) |
| // vcvt<c>.<Td>.f64 <Dd>, <Dd>, #<fbits> |
| // vcvt<c>.<Td>.f32 <Sd>, <Sd>, #<fbits> |
| // vcvt<c>.f64.<Td> <Dd>, <Dd>, #<fbits> |
| // vcvt<c>.f32.<Td> <Sd>, <Sd>, #<fbits> |
| instruction = mnemonic + getVFP_vcvtFpFixRegOperands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vcvt__dp_sp: // A8.6.298 VCVT (between double-precision and single-precision) |
| // vcvt<c>.f64.f32 <Dd>, <Sm> |
| // vcvt<c>.f32.f64 <Sd>, <Dm> |
| instruction = mnemonic + getVFP_vcvtDpSpOperands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vcvt__hp_sp_vec:// A8.6.299 VCVT (between half-precision and single-precision, Advanced SIMD) |
| // vcvt<c>.f32.f16 <Qd>, <Dm> |
| // vcvt<c>.f16.f32 <Dd>, <Qm> |
| instruction = mnemonic + getVFP_vcvtHpSpVecOperands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vcvt__hp_sp_reg:// A8.6.300 VCVTB, VCVTT (between half-precision and single-precision, VFP) |
| // vcvt<y><c>.f32.f16 <Sd>, <Sm> |
| // vcvt<y><c>.f16.f32 <Sd>, <Sm> |
| mnemonic += (isBitEnabled(opcode, 7) ? "t" : "b"); |
| instruction = mnemonic + getVFP_vcvtHpSpRegOperands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vdup__scalar: // A8.6.302 VDUP (scalar) |
| // vdup<c>.<size> <Qd>, <Dm[x]> |
| // vdup<c>.<size> <Dd>, <Dm[x]> |
| instruction = mnemonic + getVFP_vdupScalarOperands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vdup__reg: // A8.6.303 VDUP (ARM core register) |
| // vdup<c>.<size> <Qd>, <Rt> |
| // vdup<c>.<size> <Dd>, <Rt> |
| instruction = mnemonic + getVFP_vdupRegOperands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vext: // A8.6.305 VEXT |
| // vext<c>.8 <Qd>, <Qn>, <Qm>, #<imm> |
| // vext<c>.8 <Dd>, <Dn>, <Dm>, #<imm> |
| instruction = mnemonic + getVFPQorDdnmRegs(opcode) |
| + ",#" + (opcode >> 8 & 0xf); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vld__multi: // A8.6.307 VLD1 (multiple single elements) |
| // vld1<c>.<size> <list>, [<Rn>{@<align>}]{!} |
| // vld1<c>.<size> <list>, [<Rn>{@<align>}], <Rm> |
| // A8.6.310 VLD2 (multiple 2-element structures) |
| // vld2<c>.<size> <list>, [<Rn>{@<align>}]{!} |
| // vld2<c>.<size> <list>, [<Rn>{@<align>}], <Rm> |
| // A8.6.313 VLD3 (multiple 3-element structures) |
| // vld3<c>.<size> <list>, [<Rn>{@<align>}]{!} |
| // vld3<c>.<size> <list>, [<Rn>{@<align>}], <Rm> |
| // A8.6.316 VLD4 (multiple 4-element structures) |
| // vld4<c>.<size> <list>, [<Rn>{@<align>}]{!} |
| // vld4<c>.<size> <list>, [<Rn>{@<align>}], <Rm> |
| case thumb2_vst__multi: // A8.6.391 VST1 (multiple single elements) |
| // vst1<c>.<size> <list>, [<Rn>{@<align>}]{!} |
| // vst1<c>.<size> <list>, [<Rn>{@<align>}], <Rm> |
| // A8.6.393 VST2 (multiple 2-element structures) |
| // vst2<c>.<size> <list>, [<Rn>{@<align>}]{!} |
| // vst2<c>.<size> <list>, [<Rn>{@<align>}], <Rm> |
| // A8.6.395 VST3 (multiple 3-element structures) |
| // vst3<c>.<size> <list>, [<Rn>{@<align>}]{!} |
| // vst3<c>.<size> <list>, [<Rn>{@<align>}], <Rm> |
| // A8.6.397 VST4 (multiple 4-element structures) |
| // vst4<c>.<size> <list>, [<Rn>{@<align>}]{!} |
| // vst4<c>.<size> <list>, [<Rn>{@<align>}], <Rm> |
| instruction = mnemonic + getVFP_vXX_multi(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vld__xlane: // A8.6.308 VLD1 (single element to one lane) |
| // vld1<c>.<size> <list>, [<Rn>{@<align>}}]{!} |
| // vld1<c>.<size> <list>, [<Rn>{@<align>}}], <Rm> |
| // A8.6.309 VLD1 (single element to all lanes) |
| // vld1<c>.<size> <list>, [<Rn>{@<align>}}]{!} |
| // vld1<c>.<size> <list>, [<Rn>{@<align>}}], <Rm> |
| // A8.6.311 VLD2 (single 2-element structure to one lane) |
| // vld2<c>.<size> <list>, [<Rn>{@<align>}}]{!} |
| // vld2<c>.<size> <list>, [<Rn>{@<align>}}], <Rm> |
| // A8.6.312 VLD2 (single 2-element structure to all lanes) |
| // vld2<c>.<size> <list>, [<Rn>{@<align>}}]{!} |
| // vld2<c>.<size> <list>, [<Rn>{@<align>}}], <Rm> |
| // A8.6.314 VLD3 (single 3-element structure to one lane) |
| // vld3<c>.<size> <list>, [<Rn>{@<align>}}]{!} |
| // vld3<c>.<size> <list>, [<Rn>{@<align>}}], <Rm> |
| // A8.6.315 VLD3 (single 3-element structure to all lanes) |
| // vld3<c>.<size> <list>, [<Rn>{@<align>}}]{!} |
| // vld3<c>.<size> <list>, [<Rn>{@<align>}}], <Rm> |
| // A8.6.317 VLD4 (single 4-element structure to one lane) |
| // vld4<c>.<size> <list>, [<Rn>{@<align>}}]{!} |
| // vld4<c>.<size> <list>, [<Rn>{@<align>}}], <Rm> |
| // A8.6.318 VLD4 (single 4-element structure to all lanes) |
| // vld4<c>.<size> <list>, [<Rn>{@<align>}}]{!} |
| // vld4<c>.<size> <list>, [<Rn>{@<align>}}], <Rm> |
| case thumb2_vst__xlane: // A8.6.392 VST1 (single element from one lane) |
| // vst1<c>.<size> <list>, [<Rn>{@<align>}}]{!} |
| // vst1<c>.<size> <list>, [<Rn>{@<align>}}], <Rm> |
| // A8.6.394 VST2 (single 2-element structure from one lane) |
| // vst2<c>.<size> <list>, [<Rn>{@<align>}}]{!} |
| // vst2<c>.<size> <list>, [<Rn>{@<align>}}], <Rm> |
| // A8.6.396 VST3 (single 3-element structure from one lane) |
| // vst3<c>.<size> <list>, [<Rn>{@<align>}}]{!} |
| // vst3<c>.<size> <list>, [<Rn>{@<align>}}], <Rm> |
| // A8.6.398 VST4 (single 4-element structure from one lane) |
| // vst4<c>.<size> <list>, [<Rn>{@<align>}}]{!} |
| // vst4<c>.<size> <list>, [<Rn>{@<align>}}], <Rm> |
| instruction = mnemonic + getVFP_vXX_Xlane(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vldm__64: // A8.6.319 VLDM |
| // vldm{mode}<c> <Rn>{!},<list> (<list> is consecutive 64-bit registers) |
| case thumb2_vldm__32: // A8.6.319 VLDM |
| // vldm{mode}<c> <Rn>{!},<list> (<list> is consecutive 64-bit registers) |
| case thumb2_vstm__64: // A8.6.399 VSTM |
| // vstm{mode}<c> <Rn>{!},<list> (<list> is consecutive 64-bit registers) |
| case thumb2_vstm__32: // A8.6.399 VSTM |
| // vstm{mode}<c> <Rn>{!},<list> (<list> is consecutive 64-bit registers) |
| instruction = mnemonic + getVFPIncDec(opcode) + getVFP_vXXm(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vldr__64: // A8.6.320 VLDR |
| // vldr<c> <Dd>, [<Rn>{,#+/-<imm>}] |
| // vldr<c> <Dd>, <label> |
| // vldr<c> <Dd>, [pc,#-0] Special case |
| case thumb2_vldr__32: // A8.6.320 VLDR |
| // vldr<c> <Sd>, [<Rn>{,#+/-<imm>}] |
| // vldr<c> <Sd>, <label> |
| // vldr<c> <Sd>, [pc,#-0] Special case |
| case thumb2_vstr__64: // A8.6.400 VSTR |
| // vstr<c> <Dd>, [<Rn>{,#+/-<imm>}] |
| case thumb2_vstr__32: // A8.6.400 VSTR |
| // vstr<c> <Sd>, [<Rn>{,#+/-<imm>}] |
| instruction = mnemonic + getVFP_vXXr(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vmax_vmin__int: // A8.6.321 VMAX, VMIN (integer) |
| // vmax<c>.<dt> <Qd>,<Qn>,<Qm> |
| // vmax<c>.<dt> <Dd>,<Dn>,<Dm> |
| // vmin<c>.<dt> <Qd>,<Qn>,<Qm> |
| // vmin<c>.<dt> <Dd>,<Dn>,<Dm> |
| case thumb2_vpmax_vpmin__int: // A8.6.352 VPMAX, VPMIN (integer) |
| // vp<op><c>.<dt> <Dd>, <Dn>, <Dm> |
| // (this works despite no Q version because Q==1 is UNDEFINED) |
| instruction = mnemonic + (isBitEnabled(opcode, 4) ? "min" : "max") |
| + getVFPSorUDataType(opcode, 28) + getVFPQorDdnmRegs(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vmax_vmin__fp: // A8.6.322 VMAX, VMIN (floating-point) |
| // vmax<c>.f32 <Qd>, <Qn>, <Qm> |
| // vmax<c>.f32 <Dd>, <Dn>, <Dm> |
| // vmin<c>.f32 <Qd>, <Qn>, <Qm> |
| // vmin<c>.f32 <Dd>, <Dn>, <Dm> |
| case thumb2_vpmax_vpmin__fp:// A8.6.353 VPMAX, VPMIN (floating-point) |
| // vp<op><c>.f32 <Dd>,<Dn>,<Dm> |
| instruction = mnemonic + (isBitEnabled(opcode, 21) ? "min.f32" : "max.f32") |
| + getVFPQorDdnmRegs(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vml__int: // A8.6.323 VMLA, VMLAL, VMLS, VMLSL (integer) |
| // v<op><c>.<dt> <Qd>, <Qn>, <Qm> |
| // v<op><c>.<dt> <Dd>, <Dn>, <Dm> |
| mnemonic += isBitEnabled(opcode, 28) ? 's' : 'a'; |
| instruction = mnemonic + getVFPIDataType(opcode, 20) + TAB + getVFPQorDdnmRegs(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vml__int_long: // A8.6.323 VMLA, VMLAL, VMLS, VMLSL (integer) |
| // v<op>l<c>.<dt> <Qd>,<Dn>,<Dm> |
| mnemonic += isBitEnabled(opcode, 9) ? "sl" : "al"; |
| instruction = mnemonic + getVFPSorUDataType(opcode, 28) |
| + TAB + getVFPQdDnDmRegs(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vml__f32: // A8.6.324 VMLA, VMLS (floating-point) |
| // v<op><c>.f64 <Dd>, <Dn>, <Dm> |
| // v<op><c>.f32 <Sd>, <Sn>, <Sm> |
| mnemonic += isBitEnabled(opcode, 21) ? "s.f32" : "a.f32"; |
| instruction = mnemonic + TAB + getVFPQorDdnmRegs(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vml__fp: // A8.6.324 VMLA, VMLS (floating-point) |
| // v<op><c>.f64 <Dd>, <Dn>, <Dm> |
| // v<op><c>.f32 <Sd>, <Sn>, <Sm> |
| mnemonic += isBitEnabled(opcode, 6) ? 's' : 'a'; |
| instruction = mnemonic + getVFPSzF64F32dnmOperands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vml__scalar: // A8.6.325 VMLA, VMLAL, VMLS, VMLSL (by scalar) |
| // v<op><c>.<dt> <Qd>, <Qn>, <Dm[x]> |
| // v<op><c>.<dt> <Dd>, <Dn>, <Dm[x]> |
| // v<op>l<c>.<dt> <Qd>, <Dn>, <Dm[x]> |
| mnemonic += isBitEnabled(opcode, 10) ? 's' : 'a'; |
| case thumb2_vmul__scalar: // A8.6.339 VMUL, VMULL (by scalar) |
| // vmul<c>.<dt> <Qd>, <Qn>, <Dm[x]> |
| // vmul<c>.<dt> <Dd>, <Dn>, <Dm[x]> |
| // vmull<c>.<dt> <Qd>,<Dn>,<Dm[x]> |
| case thumb2_vqdmull__scalar:// A8.6.360 VQDMULL |
| // vqdmull<c>.<dt> <Qd>,<Dn>,<Dm[x]> |
| // bit 9 == 1, so getVFP_vmXXScalar() works |
| instruction = mnemonic + getVFP_vmXXScalar(opcode, 28); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vmov__imm: // A8.6.326 VMOV (immediate) |
| // vmov<c>.f64 <Dd>, #<imm> |
| // vmov<c>.f32 <Sd>, #<imm> |
| mnemonic += getVFPSzF64F32Type(getBit(opcode, 8)); |
| instruction = mnemonic + TAB + getVFPDorSReg(opcode, getBit(opcode, 8), 12, 22) |
| + ",#" + getHexValue((opcode >> 16 & 0xf) << 4 | opcode & 0xf); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vmov_5: // A8.6.328 VMOV (ARM core register to scalar) |
| // vmov<c>.<size> <Dd[x]>,<Rt> |
| instruction = mnemonic + getVFP_vmovArmCoreRegToScalar(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vmov_6: // A8.6.329 VMOV (scalar to ARM core register) |
| // vmov<c>.<dt> <Rt>,<Dn[x]> |
| instruction = mnemonic + getVFP_vmovScalarToArmCoreReg(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vmov_7: // A8.6.330 VMOV (between ARM core register and |
| // single-precision register) |
| // vmov<c> <Sn>, <Rt> |
| // vmov<c> <Rt>, <Sn> |
| instruction = mnemonic + getVFP_vmovBetweenArmCoreAndSinglePrecReg(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vmov_8: // A8.6.331 VMOV (between two ARM core registers and |
| // two single-precision registers) |
| // vmov<c> <Sm>, <Sm1>, <Rt>, <Rt2> |
| // vmov<c> <Rt>, <Rt2>, <Sm>, <Sm1> |
| instruction = mnemonic + getVFP_vmovBetween2ArmCoreAndSinglePrecRegs(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vmov_9: // A8.6.332 VMOV (between two ARM core registers and |
| // a doubleword extension register) |
| // vmov<c> <Dm>, <Rt>, <Rt2> |
| // vmov<c> <Rt>, <Rt2>, <Dm> |
| instruction = mnemonic + getVFP_vmovBetween2ArmCoreAnd1DoublewordExtensionRegs(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vmovl: // A8.6.333 VMOVL |
| // vmovl<c>.<dt> <Qd>, <Dm> |
| case thumb2_vshll__various: // A8.6.384 VSHLL |
| // vshll<c>.<type><size> <Qd>,<Dm>,#<imm> (0 < <imm> < <size>) |
| instruction = mnemonic + getVFP_vmovl_vshll_operands(opcode, 28); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vmovn: // A8.6.334 VMOVN |
| // vmovn<c>.<dt> <Dd>,<Qm> |
| mnemonic += getVFPIDataType2(opcode, 18); |
| instruction = mnemonic + TAB + getVFPQorDReg(opcode, 0, 12, 22) |
| + ',' + getVFPQorDReg(opcode, 1, 0, 5); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vmrs: // A8.6.335 VMRS |
| // vmrs<c> <Rt>,fpscr |
| // B6.1.14 VMRS |
| // vmrs<c> <Rt>,<spec_reg> |
| instruction = mnemonic + TAB + getR_12(opcode) + "," + getVFPSpecialReg(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vmsr: // A8.6.336 VMSR |
| // vmsr<c> fpscr,<Rt> |
| // B6.1.15 VMSR |
| // vmsr<c> <spec_reg>,<Rt> |
| instruction = mnemonic + TAB + getVFPSpecialReg(opcode) + "," + getR_12(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vmul_1: // A8.6.337 VMUL, VMULL (integer and polynomial) |
| // vmul<c>.<dt> <Qd>, <Qn>, <Qm> |
| // vmul<c>.<dt> <Dd>, <Dn>, <Dm> |
| mnemonic += (isBitEnabled(opcode, 28) ? ".p" : ".i") + getVFPDataTypeSize(opcode, 20); |
| instruction = mnemonic + TAB + getVFPQorDdnmRegs(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vmull: // A8.6.337 VMUL, VMULL (integer and polynomial) |
| // vmull<c>.<dt> <Qd>, <Dn>, <Dm> |
| mnemonic += isBitEnabled(opcode, 9) ? getVFPPDataType(opcode, 20) : getVFPSorUDataType(opcode, 28); |
| instruction = mnemonic + TAB + getVFPQdDnDmRegs(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vpadal: // A8.6.348 VPADAL |
| // vpadal<c>.<dt> <Qd>, <Qm> |
| // vpadal<c>.<dt> <Dd>, <Dm> |
| case thumb2_vpaddl: // A8.6.351 VPADDL |
| // vpaddl<c>.<dt> <Qd>, <Qm> |
| // vpaddl<c>.<dt> <Dd>, <Dm> |
| instruction = mnemonic + getVFPSorUorFQorDdmOperands(opcode, 4, 7); // chose bit 4 because it is 0 |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vpop: // A8.6.354 VPOP |
| // vpop <list> <list> is consecutive 64-bit registers |
| // vpop <list> <list> is consecutive 32-bit registers |
| case thumb2_vpush: // A8.6.355 VPUSH |
| // vpush <list> <list> is consecutive 64-bit registers |
| // vpush <list> <list> is consecutive 32-bit registers |
| instruction = mnemonic + getVFP_vpop_vpush_operands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vqdml__scalar: // A8.6.358 VQDMLAL, VQDMLSL |
| // vqd<op><c>.<dt> <Qd>,<Dn>,<Dm[x]> |
| mnemonic += isBitEnabled(opcode, 10) ? "sl.s" : "al.s"; |
| instruction = mnemonic + getVFPScalarOperands(opcode, 1, 0); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vqdmulh__vec: // A8.6.359 VQDMULH |
| // vqdmulh<c>.<dt> <Qd>,<Qn>,<Qm> |
| // vqdmulh<c>.<dt> <Dd>,<Dn>,<Dm> |
| case thumb2_vqrdmulh__vec: // A8.6.363 VQRDMULH |
| // vqrdmulh<c>.<dt> <Qd>,<Qn>,<Qm> |
| // vqrdmulh<c>.<dt> <Dd>,<Dn>,<Dm> |
| mnemonic += isBitEnabled(opcode, 20) ? ".s16" : ".s32"; |
| instruction = mnemonic + TAB + getVFPQorDdnmRegs(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vqdmulh__scalar:// A8.6.359 VQDMULH |
| // vqdmulh<c>.<dt> <Qd>,<Qn>,<Dm[x]> |
| // vqdmulh<c>.<dt> <Dd>,<Dn>,<Dm[x]> |
| case thumb2_vqrdmulh__scalar: // A8.6.363 VQRDMULH |
| // vqrdmulh<c>.<dt> <Qd>,<Qn>,<Dm[x]> |
| // vqrdmulh<c>.<dt> <Dd>,<Dn>,<Dm[x]> |
| { |
| int q = getBit(opcode, 28); |
| instruction = mnemonic + ".s" + getVFPScalarOperands(opcode, q, q); |
| } |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vqmov: // A8.6.361 VQMOVN, VQMOVUN |
| // vqmov{u}n<c>.<type><size> <Dd>,<Qm> |
| instruction = mnemonic + getVFP_vqmov_instruction(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vqrshl: // A8.6.364 VQRSHL |
| // vqrshl<c>.<type><size> <Qd>,<Qm>,<Qn> |
| // vqrshl<c>.<type><size> <Dd>,<Dm>,<Dn> |
| case thumb2_vqshl__reg: // A8.6.366 VQSHL (register) |
| // vqshl<c>.<type><size> <Qd>,<Qm>,<Qn> |
| // vqshl<c>.<type><size> <Dd>,<Dm>,<Dn> |
| case thumb2_vrshl: // A8.6.375 VRSHL |
| // vrshl<c>.<type><size> <Qd>,<Qm>,<Qn> |
| // vrshl<c>.<type><size> <Dd>,<Dm>,<Dn> |
| case thumb2_vshl__reg: // A8.6.383 VSHL (register) |
| // vshl<c>.<type><size> <Qd>,<Qm>,<Qn> |
| // vshl<c>.<type><size> <Dd>,<Dm>,<Dn> |
| instruction = mnemonic + getVFPSorUDataType(opcode, 28) + getVFPQorDdmnRegs(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vqrshr: // A8.6.365 VQRSHRN, VQRSHRUN |
| // vqrshr{u}n<c>.<type><size> <Dd>,<Qm>,#<imm> |
| case thumb2_vqshr: // A8.6.368 VQSHRN, VQSHRUN |
| // vqshr{u}n<c>.<type><size> <Dd>,<Qm>,#<imm> |
| instruction = mnemonic + getVFP_vqXshr_instruction(opcode, 28); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vqshl__imm: // A8.6.367 VQSHL, VQSHLU (immediate) |
| // vqshl{u}<c>.<type><size> <Qd>,<Qm>,#<imm> |
| // vqshl{u}<c>.<type><size> <Dd>,<Dm>,#<imm> |
| instruction = mnemonic + getVFP_vqshl_instruction(opcode, 28); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vrecpe: // A8.6.371 VRECPE |
| // vrecpe<c>.<dt> <Qd>, <Qm> |
| // vrecpe<c>.<dt> <Dd>, <Dm> |
| case thumb2_vrsqrte: // A8.6.378 VRSQRTE |
| // vrsqrte<c>.<dt> <Qd>, <Qm> |
| // vrsqrte<c>.<dt> <Dd>, <Dm> |
| instruction = mnemonic + getVFPSorUorFQorDdmOperands(opcode, 8, 10); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vrev: // A8.6.373 VREV16, VREV32, VREV64 |
| // vrev<n><c>.<size> <Qd>,<Qm> |
| // vrev<n><c>.<size> <Dd>,<Dm> |
| instruction = mnemonic + getVFP_vrev_instruction(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vrshr: // A8.6.376 VRSHR |
| // vrshr<c>.<type><size> <Qd>, <Qm>, #<imm> |
| // vrshr<c>.<type><size> <Dd>, <Dm>, #<imm> |
| case thumb2_vrsra: // A8.6.380 VRSRA |
| // vrsra<c>.<type><size> <Qd>, <Qm>, #<imm> |
| // vrsra<c>.<type><size> <Dd>, <Dm>, #<imm> |
| case thumb2_vshr: // A8.6.385 VSHR |
| // vshr<c>.<type><size> <Qd>, <Qm>, #<imm> |
| // vshr<c>.<type><size> <Dd>, <Dm>, #<imm> |
| case thumb2_vsra: // A8.6.389 VSRA |
| // vsra<c>.<type><size> <Qd>, <Qm>, #<imm> |
| // vsra<c>.<type><size> <Dd>, <Dm>, #<imm> |
| mnemonic += (isBitEnabled(opcode, 28) ? ".u" : ".s"); |
| // no break |
| case thumb2_vsri: // A8.6.390 VSRI |
| // vsri<c>.<size> <Qd>, <Qm>, #<imm> |
| // vsri<c>.<size> <Dd>, <Dm>, #<imm> |
| instruction = mnemonic + getVFP_vXrX_instruction(opcode, true); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vrshrn: // A8.6.377 VRSHRN |
| // vrshrn<c>.i<size> <Dd>,<Qm>,#<imm> |
| case thumb2_vshrn: // A8.6.386 VSHRN |
| // vshrn<c>.i<size> <Dd>,<Qm>,#<imm> |
| instruction = mnemonic + getVFP_vXshrn_instruction(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vshl__imm: // A8.6.382 VSHL (immediate) |
| // vshl<c>.i<size> <Qd>, <Qm>, #<imm> |
| // vshl<c>.i<size> <Dd>, <Dm>, #<imm> |
| case thumb2_vsli: // A8.6.387 VSLI |
| // vsli<c>.<size> <Qd>, <Qm>, #<imm> |
| // vsli<c>.<size> <Dd>, <Dm>, #<imm> |
| instruction = mnemonic + getVFP_vXrX_instruction(opcode, false); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vshll__max: // A8.6.384 VSHLL |
| // vshll<c>.<type><size> <Qd>, <Dm>, #<imm> (<imm> == <size>) |
| mnemonic += getVFPIDataType3(opcode, 18); |
| instruction = mnemonic + TAB + getVFPQorDReg(opcode, 1, 12, 22) |
| + ',' + getVFPQorDReg(opcode, 0, 0, 5) + ",#" + (8 << (opcode >> 18 & 3)); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vtb: // A8.6.406 VTBL, VTBX |
| // v<op><c>.8 <Dd>, <list>, <Dm> |
| instruction = mnemonic + getVFP_vtb_instruction(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vtrn: // A8.6.407 VTRN |
| // vtrn<c>.<size> <Qd>, <Qm> |
| // vtrn<c>.<size> <Dd>, <Dm> |
| case thumb2_vuzp: // A8.6.409 VUZP |
| // vuzp<c>.<size> <Qd>, <Qm> |
| // vuzp<c>.<size> <Dd>, <Dm> |
| case thumb2_vzip: // A8.6.410 VZIP |
| // vzip<c>.<size> <Qd>, <Qm> |
| // vzip<c>.<size> <Dd>, <Dm> |
| instruction = mnemonic + getVFPSzQorDdmOperands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_vtst: // A8.6.408 VTST |
| // vtst<c>.<size> <Qd>, <Qn>, <Qm> |
| // vtst<c>.<size> <Dd>, <Dn>, <Dm> |
| instruction = mnemonic + getVFPSzQorDdnmOperands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| // CoProcessor instructions |
| |
| case thumb2_cdp: // A8.6.28 CDP, CDP2 |
| // cdp<c> <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2> |
| case thumb2_cdp2: // A8.6.28 CDP, CDP2 |
| // cdp2<c> <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2> |
| instruction = mnemonic + "\t" + getCo_cdp_operands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_cps: // B6.1.1 CPS |
| // cps<effect>.w <iflags>{,#<mode>} Not permitted in IT block. |
| // cps #<mode> Not permitted in IT block. |
| instruction = mnemonic + getCo_cps_instruction(opcode, true); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_ldc: // A8.6.51 LDC, LDC2 (immediate) |
| // ldc{l}<c> <coproc>,<CRd>,[<Rn>,#+/-<imm>]{!} |
| // ldc{l}<c> <coproc>,<CRd>,[<Rn>],#+/-<imm> |
| // ldc{l}<c> <coproc>,<CRd>,[<Rn>],<option> |
| // A8.6.52 LDC, LDC2 (literal) |
| // ldc{l}<c> <coproc>,<CRd>,<label> |
| // ldc{l}<c> <coproc>,<CRd>,[pc,#-0] |
| // Special case ldc{l}<c> <coproc>,<CRd>,[pc],<option> |
| // A8.6.52 LDC, LDC2 (literal) |
| // ldc2{l}<c> <coproc>,<CRd>,<label> |
| // ldc2{l}<c> <coproc>,<CRd>,[pc,#-0] |
| // Special case ldc2{l}<c> <coproc>,<CRd>,[pc],<option> |
| // A8.6.51 LDC, LDC2 (immediate) |
| // ldc2{l}<c> <coproc>,<CRd>,[<Rn>,#+/-<imm>]{!} ldc2{l}<c> <coproc>,<CRd>,[<Rn>],#+/-<imm> |
| // ldc2{l}<c> <coproc>,<CRd>,[<Rn>],<option> |
| case thumb2_stc: // A8.6.188 STC, STC2 |
| // stc{l}<c> <coproc>,<CRd>,[<Rn>,#+/-<imm>]{!} |
| // stc{l} <coproc>,<CRd>,[<Rn>],#+/-<imm> |
| // stc{l} <coproc>,<CRd>,[<Rn>],<option> |
| // A8.6.188 STC, STC2 |
| // stc2{l}<c> <coproc>,<CRd>,[<Rn>,#+/-<imm>]{!} |
| // stc2{l} <coproc>,<CRd>,[<Rn>],#+/-<imm> |
| // stc2{l} <coproc>,<CRd>,[<Rn>],<option> |
| if (isBitEnabled(opcode, 28)) |
| mnemonic += '2'; |
| instruction = mnemonic + (isBitEnabled(opcode, 22) ? "l\t" : "\t") + getCoprocessor(opcode) |
| + ',' + getCR_12(opcode) + ',' + getAddrModeImm8(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_mcr: // A8.6.92 MCR, MCR2 |
| // mcr<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} |
| // mcr2<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} |
| if (isBitEnabled(opcode, 28)) |
| mnemonic += '2'; |
| instruction = mnemonic + getCo_mcr_operands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_mcrr: // A8.6.93 MCRR, MCRR2 |
| // mcrr<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> |
| // mcrr2<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> |
| case thumb2_mrrc: // A8.6.101 MRRC, MRRC2 |
| // mrrc<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> |
| // mrrc2<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> |
| if (isBitEnabled(opcode, 28)) |
| mnemonic += '2'; |
| instruction = mnemonic + getCo_mrr_operands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| case thumb2_mrc: // A8.6.100 MRC, MRC2 |
| // mrc<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} |
| // A8.6.100 MRC, MRC2 |
| // mrc2<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} |
| if (isBitEnabled(opcode, 28)) |
| mnemonic += '2'; |
| instruction = mnemonic + getCo_mrc_operands(opcode); |
| // No PC check: not applicable |
| break; |
| |
| default: |
| instruction = IDisassembler.INVALID_OPCODE; |
| break; |
| } |
| return instruction; |
| } |
| |
| |
| private String getAddrMode(int opcode) { |
| int amode = (opcode >> 23) & 0x3; |
| if (amode == 0) |
| return "da"; |
| else if (amode == 2) |
| return "db"; |
| else if (amode == 1) |
| return "ia"; |
| else |
| return "ib"; |
| } |
| |
| private String getAddrMode2(int opcode, int pPos) { |
| int regOffset = (opcode >> 25) & 1; |
| int scaled = (opcode >> 5) & 3; |
| int shiftValue = (opcode >> 7) & 0x1f; |
| int shiftMode = (opcode >> 5) & 3; |
| int offset = opcode & 0xfff; |
| String operands = "[" + getR_16(opcode); |
| String sign = isBitEnabled(opcode, 23) ? "" : "-"; |
| if (isBitEnabled(opcode, pPos)) { |
| if (regOffset == 0) { // immediate offset |
| if (offset != 0) |
| operands += ",#" + sign + getHexValue(offset); |
| } else { |
| operands += "," + sign + getR_0(opcode); |
| if (scaled != 0 || shiftValue != 0) // scaled register offset |
| operands += getAddrMode2ScaledRegOffset(opcode, shiftValue, shiftMode); |
| } |
| operands += isBitEnabled(opcode, 21) ? "]!" : "]"; |
| } else { // post-indexed |
| if (regOffset == 0) { // immediate offset |
| operands += "]"; |
| if (offset != 0) |
| operands += ",#" + sign + getHexValue(offset); |
| } else { |
| operands += "]," + sign + getR_0(opcode); |
| if (scaled != 0 || shiftValue != 0) // scaled register offset |
| operands += getAddrMode2ScaledRegOffset(opcode, shiftValue, shiftMode); |
| } |
| } |
| return operands; |
| } |
| |
| private String getAddrMode2ScaledRegOffset(int opcode, int shiftValue, int shiftMode) { |
| String ops = "," + getShiftMode(opcode); |
| if (shiftValue == 0 && (shiftMode == 1 || shiftMode == 2)) // lsr & asr encode shift 32 as shift 0 |
| shiftValue = 32; |
| if (shiftValue != 0) |
| ops += "#" + shiftValue; |
| return ops; |
| } |
| |
| private String getAddrModeImm8(int opcode) { |
| int p = (opcode >> 24) & 1; |
| int u = (opcode >> 23) & 1; |
| int w = (opcode >> 21) & 1; |
| int offset = (opcode & 0xff) * 4; |
| String operands = ""; |
| String sign = (u == 1) ? "" : "-"; |
| if (p == 1) { |
| operands = "[" + getR_16(opcode); |
| if (offset != 0 || u == 0) |
| operands += ",#" + sign + getHexValue(offset); |
| operands += "]"; |
| if (w == 1) { // pre-indexed |
| operands += "!"; |
| } |
| } else { |
| if (w == 1) { // post-indexed |
| operands = "[" + getR_16(opcode) + "],#" + sign + getHexValue(offset); |
| } else { // unindexed |
| operands = "[" + getR_16(opcode) + "]"; |
| if (u == 1) |
| operands += ",{" + (offset/4) + "}"; |
| else |
| operands += ",#" + getHexValue(offset); |
| } |
| } |
| return operands; |
| } |
| |
| private String getAddrModePCImm(int opcode, int imm) { |
| boolean p = isBitEnabled(opcode, 23); |
| String addr = Long.toHexString((address.getValue().longValue() & 0xfffffffc) |
| + (p ? imm : -imm)); |
| int addrLen = addr.length(); |
| if (addrLen > 8) |
| addr = addr.substring(addrLen - 8); |
| return "[pc,#" + (p ? "" : "-") + getHexValue(imm) + "] ; 0x" + addr; |
| } |
| |
| private String getAddrModeSplitImm8(int opcode) { |
| boolean immOffset = isBitEnabled(opcode, 22); |
| int offsetHi = opcode >> 4 & 0xf0; |
| int offsetLo = opcode & 0xf; |
| int offset = offsetHi | offsetLo; |
| String operands = "[" + getR_16(opcode); |
| String sign = (isBitEnabled(opcode, 23)) ? "" : "-"; |
| if (isBitEnabled(opcode, 24)) { |
| if (immOffset) { // immediate offset |
| if (offset != 0) |
| operands += ",#" + sign + getHexValue(offset); |
| } else { // register offset |
| operands += "," + sign + getR_0(opcode); |
| } |
| operands += isBitEnabled(opcode, 21) ? "]!" : "]"; |
| } else { // post-indexed |
| if (immOffset) { // immediate offset |
| operands += "],#" + sign + getHexValue(offset); |
| } else { // register offset |
| operands += "]," + sign + getR_0(opcode); |
| } |
| } |
| return operands; |
| } |
| |
| private String getArmCondition(int opcode) { |
| return getCondition(opcode >> 28 & 0xf); |
| } |
| |
| private int getBit(int opcode, int bit) { |
| return 1 & (opcode >> bit); |
| } |
| |
| private int getBranchOffset(int opcode) { |
| int offset = ((opcode << 8) >> 6) + 8; |
| return offset; |
| } |
| |
| private String getCondition(int condition) { |
| switch (condition) { |
| case 0: return "eq"; |
| case 1: return "ne"; |
| case 2: return "cs"; |
| case 3: return "cc"; |
| case 4: return "mi"; |
| case 5: return "pl"; |
| case 6: return "vs"; |
| case 7: return "vc"; |
| case 8: return "hi"; |
| case 9: return "ls"; |
| case 10: return "ge"; |
| case 11: return "lt"; |
| case 12: return "gt"; |
| case 13: return "le"; |
| |
| case 14: // always (unconditional) |
| |
| case 15: |
| default: |
| return ""; |
| } |
| } |
| |
| private String getCoprocessor(int opcode) { |
| int cproc = (opcode >> 8) & 0xf; |
| return ("p" + cproc); |
| } |
| |
| private String getCR_12(int opcode) { |
| int cReg = (opcode >> 12) & 0xf; |
| return ("c" + cReg); |
| } |
| |
| private String getCR_0(int opcode) { |
| int cReg = opcode & 0xf; |
| return ("c" + cReg); |
| } |
| |
| private String getCR_16(int opcode) { |
| int reg = (opcode >> 16) & 0xf; |
| return ("c" + reg); |
| } |
| |
| private String getDataBarrierOption(int opcode) { |
| int option = opcode & 0xf; |
| switch (option) { |
| case 2: return "oshst"; |
| case 3: return "osh"; |
| case 6: return "nshst"; |
| case 7: return "nsh"; |
| case 10: return "ishst"; |
| case 11: return "ish"; |
| case 14: return "st"; |
| case 15: return "sy"; |
| |
| default: |
| return "#" + option; |
| } |
| } |
| |
| private String getHexValue(int value) { |
| return "0x" + Integer.toHexString(value); |
| } |
| |
| private String getHexValue(long value) { |
| return "0x" + Long.toHexString(value); |
| } |
| |
| private String getImmediate24(int opcode) { |
| int imm24 = opcode & 0xffffff; |
| return "#" + getHexValue(imm24); |
| } |
| |
| private String getImmediate12(int opcode) { |
| int imm12 = opcode & 0xfff; |
| return "#" + getHexValue(imm12); |
| } |
| |
| private String getInstructionBarrierOption(int opcode) { |
| int option = opcode & 0xf; |
| switch (option) { |
| case 15: return "sy"; |
| default: return "#" + option; |
| } |
| } |
| |
| // get 4-bit register number from opcode bits 0-3 |
| private String getR_0(int opcode) { |
| int reg = opcode & 0xf; |
| return getRegName(reg); |
| } |
| |
| // get 4-bit register number from opcode bits 8-11 |
| private String getR_8(int opcode) { |
| int reg = (opcode >> 8) & 0xf; |
| return getRegName(reg); |
| } |
| |
| // get 4-bit register number from opcode bits 12-15 |
| private String getR_12(int opcode) { |
| int reg = (opcode >> 12) & 0xf; |
| return getRegName(reg); |
| } |
| |
| // get 4-bit register number from opcode bits 16-19 |
| private String getR_16(int opcode) { |
| int reg = (opcode >> 16) & 0xf; |
| return getRegName(reg); |
| } |
| |
| private String getRegList(int opcode) { |
| String r0 = ((opcode & 1) == 1) ? "r0," : ""; |
| String r1 = (((opcode >> 1) & 1) == 1) ? "r1," : ""; |
| String r2 = (((opcode >> 2) & 1) == 1) ? "r2," : ""; |
| String r3 = (((opcode >> 3) & 1) == 1) ? "r3," : ""; |
| String r4 = (((opcode >> 4) & 1) == 1) ? "r4," : ""; |
| String r5 = (((opcode >> 5) & 1) == 1) ? "r5," : ""; |
| String r6 = (((opcode >> 6) & 1) == 1) ? "r6," : ""; |
| String r7 = (((opcode >> 7) & 1) == 1) ? "r7," : ""; |
| String r8 = (((opcode >> 8) & 1) == 1) ? "r8," : ""; |
| String r9 = (((opcode >> 9) & 1) == 1) ? "r9," : ""; |
| String r10 = (((opcode >> 10) & 1) == 1) ? "r10," : ""; |
| String r11 = (((opcode >> 11) & 1) == 1) ? "r11," : ""; |
| String r12 = (((opcode >> 12) & 1) == 1) ? "r12," : ""; |
| String sp = (((opcode >> 13) & 1) == 1) ? "sp," : ""; |
| String lr = (((opcode >> 14) & 1) == 1) ? "lr," : ""; |
| String pc = (((opcode >> 15) & 1) == 1) ? "pc," : ""; |
| String regList = "{" + r0 + r1 + r2 + r3 + r4 + r5 + r6 + r7 + r8 + r9 + r10 + r11 + r12 + sp + lr + pc + "}"; |
| regList = regList.replace(",}", "}"); |
| return regList; |
| } |
| |
| private String getRegName(int reg) { |
| switch (reg) { |
| case 13: |
| return "sp"; |
| case 14: |
| return "lr"; |
| case 15: |
| return "pc"; |
| default: |
| return ("r" + reg); |
| } |
| } |
| |
| private String getRotationOperand(int opcode, int bit) { |
| int rotation = ((opcode >> (bit-3)) & 0x18); |
| return (rotation != 0) ? ",ror #" + rotation : ""; |
| } |
| |
| private String getShifterOperand(int opcode) { |
| int shift, immval; |
| int bit25 = (opcode >> 25) & 1; |
| if (bit25 == 1) { // bit set - we have immediate shifter operand |
| shift = (opcode & 0x0f00) >> 7; // rotate_imm*2 |
| immval = (opcode & 0xff); |
| immval = (immval >> shift) | (immval << (32 - shift)); |
| return "#" + getHexValue(immval); |
| } |
| |
| if ((opcode & 0xff0) == 0) // got Rm |
| return getR_0(opcode); |
| |
| // else shifted |
| immval = (opcode >> 7) & 0x1f; |
| if ((opcode & 0x70) == 0x0) {// LSL #imm |
| return getR_0(opcode) + ",lsl #" + immval; |
| } else if ((opcode & 0xf0) == 0x10) {// LSL Rs |
| return getR_0(opcode) + ",lsl " + getR_8(opcode); |
| } else if ((opcode & 0x70) == 0x20) {// LSR #imm |
| if (immval == 0) |
| immval = 32; |
| return getR_0(opcode) + ",lsr #" + immval; |
| } else if ((opcode & 0xf0) == 0x30) {// LSR Rs |
| return getR_0(opcode) + ",lsr " + getR_8(opcode); |
| } else if ((opcode & 0x70) == 0x40) {// ASR #imm |
| if (immval == 0) |
| immval = 32; |
| return getR_0(opcode) + ",asr #" + immval; |
| } else if ((opcode & 0xf0) == 0x50) {// ASR Rs |
| return getR_0(opcode) + ",asr " + getR_8(opcode); |
| } else if ((opcode & 0xff0) == 0x60) {// RRX |
| return getR_0(opcode) + ",rrx"; |
| } else if ((opcode & 0x70) == 0x60) {// ROR #imm |
| return getR_0(opcode) + ",ror #" + immval; |
| } else if ((opcode & 0xf0) == 0x70) {// ROR Rs |
| return getR_0(opcode) + ",ror " + getR_8(opcode); |
| } else { |
| return ",<invalid shift operand>"; |
| } |
| } |
| |
| private String getShiftMode(int opcode) { |
| int shiftMode = (opcode >> 5) & 3; |
| int shiftValue = (opcode >> 7) & 0x1f; |
| switch (shiftMode) { |
| case 0: |
| return "lsl"; |
| case 1: |
| return "lsr"; |
| case 2: |
| return "asr"; |
| case 3: |
| if (shiftValue == 0) { |
| return "rrx"; |
| } else { |
| return "ror"; |
| } |
| default: |
| return ""; |
| } |
| } |
| |
| private String getStatusReg(int opcode, int rPos) { |
| return (isBitEnabled(opcode, rPos) ? 's' : 'c') + "psr"; |
| } |
| |
| private String getStatusRegFields(int opcode, int mask_lsb) { |
| String fields = "_"; |
| boolean c = isBitEnabled(opcode, mask_lsb); |
| boolean x = isBitEnabled(opcode, mask_lsb+1); |
| boolean s = isBitEnabled(opcode, mask_lsb+2); |
| boolean f = isBitEnabled(opcode, mask_lsb+3); |
| if (c) { |
| fields += "c"; |
| } |
| if (x) { |
| fields += "x"; |
| } |
| if (f) { |
| fields += "f"; |
| } |
| if (s) { |
| fields += "s"; |
| } |
| return fields; |
| } |
| |
| /** |
| * Arm--- ... opc1_1_7_4 CRn_1_3_0 CRd___15_12 coproc___11_8 opc2___7_5 . CRm___3_0<br> |
| * Thumb2 ... opc1_1_7_4 CRn_1_3_0 CRd_0_15_12 coproc_0_11_8 opc2_0_7_5 . CRm_0_3_0 |
| * @param opcode |
| * @return String containing all cdp/cdp2 instr operands |
| * <p><listing> |
| * A8.6.28 CDP, CDP2 |
| * {@literal cdp<c> <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2>} |
| * {@literal cdp2<c> <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2>} |
| */ |
| private String getCo_cdp_operands(int opcode) { |
| int cpOpc1 = (opcode >> 20) & 0xf; |
| int cpOpc2 = (opcode >> 5) & 7; |
| return TAB |
| + getCoprocessor(opcode) + ',' + getHexValue(cpOpc1) + ',' + getCR_12(opcode) |
| + ',' + getCR_16(opcode) + ',' + getCR_0(opcode) + ',' + getHexValue(cpOpc2); |
| |
| } |
| |
| /** |
| * Arm--- ... imod_19_18 M_17_17 ...A___7_7 I___6_6 F___5_5 mode_0_4_0<br> |
| * Thumb2 ... ... imod_0_10_9 M_0_8_8 A_0_7_7 I_0_6_6 F_0_5_5 mode_0_4_0 |
| * @param opcode |
| * @param thumb2 boolean: pass true if thumb2 instr (false if ARM) |
| * @return String containing cps mnemonic postfix + TAB + operands |
| * <p><listing> |
| * B6.1.1 CPS Not permitted in IT block |
| * cps {@literal <effect>.w <iflags>}{,#{@literal <mode>}}. |
| * cps {@literal #<mode>} |
| */ |
| private String getCo_cps_instruction(int opcode, boolean thumb2) { |
| int armAdj = thumb2 ? 0 : 9; |
| int imod = opcode >> 9+armAdj & 3; |
| boolean changeMode = isBitEnabled(opcode, 8+armAdj); |
| int mode = opcode & 0x1f; |
| |
| String ops; |
| |
| // treat UNPREDICTABLE ((imod == 0 && !changeMode) || imod == 1) as a change mode to 0 |
| if (imod == 0 || imod == 1) { |
| if (!changeMode || mode == 0) |
| ops = TAB + "#0"; |
| else |
| ops = TAB + "#" + mode; |
| } else { |
| ops = "i" + (imod == 2 ? 'e' : 'd') + TAB; |
| armAdj = thumb2 ? 0 : 1; |
| if (isBitEnabled(opcode, 7 + armAdj)) |
| ops += "a"; |
| if (isBitEnabled(opcode, 6 + armAdj)) |
| ops += "i"; |
| if (isBitEnabled(opcode, 5 + armAdj)) |
| ops += "f"; |
| if (changeMode) |
| ops += ",#" + mode; |
| } |
| return ops; |
| } |
| |
| /** |
| * Arm--- ... opc1_23_21 . CRn_19_16 Rt___15_12 coproc___11_8 opc2___7_5 . CRm___3_0<br> |
| * Thumb2 ... opc1_1_7_5 . CRn_1_3_0 Rt_0_15_12 coproc_0_11_8 opc2_0_7_5 . CRm_0_3_0 |
| * @param opcode |
| * @return String containing + TAB + mcr/mcr2 operands |
| * <p><listing> |
| * A8.6.92 MCR, MCR2 |
| * mcr{@literal <c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>}{,{@literal <opc2>}} |
| * mcr2{@literal <c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>}{,{@literal <opc2>}} |
| */ |
| private String getCo_mcr_operands(int opcode) { |
| int cpOpc1 = opcode >> 21 & 7; |
| int cpOpc2 = opcode >> 5 & 7; |
| return TAB |
| + getCoprocessor(opcode) + ',' + getHexValue(cpOpc1) |
| + ',' + getR_12(opcode) + ',' + getCR_16(opcode) + ',' + getCR_0(opcode) |
| + (cpOpc2 != 0 ? "," + getHexValue(cpOpc2) : ""); |
| } |
| |
| /** |
| * Arm--- ... opc1_23_21 . CRn_19_16 Rt___15_12 coproc___11_8 opc2___7_5 . CRm___3_0<br> |
| * Thumb2 ... opc1_1_7_5 . CRn_1_3_0 Rt_0_15_12 coproc_0_11_8 opc2_0_7_5 . CRm_0_3_0 |
| * @param opcode |
| * @return String containing + TAB + mrc/mrc2 operands |
| * <p><listing> |
| * A8.6.100 MRC, MRC2 |
| * mrc{@literal <c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>}{,{@literal <opc2>}} |
| * mcr2{@literal <c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>}{,{@literal <opc2>}} |
| */ |
| private String getCo_mrc_operands(int opcode) { |
| int cpOpc1 = opcode >> 21 & 7; |
| int cpOpc2 = opcode >> 5 & 7; |
| int rt = opcode >> 12 & 0xf; |
| return TAB |
| + getCoprocessor(opcode) + ',' + getHexValue(cpOpc1) |
| + ',' + (rt == 15 ? "apsr_nzcv" : getRegName(rt)) |
| + ',' + getCR_16(opcode) + ',' + getCR_0(opcode) |
| + (cpOpc2 != 0 ? "," + getHexValue(cpOpc2) : ""); |
| } |
| |
| /** |
| * Arm--- ... Rt2_19_16 Rt___15_12 coproc___11_8 opc1___7_4 CRm___3_0<br> |
| * Thumb2 ... Rt2_1_3_0 Rt_0_15_12 coproc_0_11_8 opc1_0_7_4 CRm_0_3_0 |
| * @param opcode |
| * @return String containing + TAB + mcrr/mcrr2 operands |
| * <p><listing> |
| * A8.6.93 MCRR, MCRR2 |
| * {@literal mcrr<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm>} |
| * {@literal mcrr2<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm>} |
| * A8.6.101 MRRC, MRRC2 |
| * {@literal mrrc<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm>} |
| * {@literal mrrc2<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm>} |
| */ |
| private String getCo_mrr_operands(int opcode) { |
| int cpOpc = opcode >> 4 & 0xf; |
| return TAB |
| + getCoprocessor(opcode) + ',' + getHexValue(cpOpc) |
| + ',' + getR_12(opcode) + ',' + getR_16(opcode) + ',' + getCR_0(opcode); |
| } |
| |
| private int getThumbBranchOffset8(int opcode) { |
| int offset = (byte)(opcode & 0xff); |
| |
| offset = (offset*2) + 4; |
| return offset; |
| } |
| |
| private int getThumbBranchOffset11(int opcode) { |
| short offset = (short) ((opcode << 5) & 0xffff); |
| |
| return (offset / 16) + 4; |
| } |
| |
| private String getThumbCondition(int opcode) { |
| int condition = (opcode >> 8) & 0xf; |
| return getCondition(condition); |
| } |
| |
| private String getThumbEffect(int opcode) { |
| int imod = (opcode >> 4) & 1; |
| if (imod == 0) { |
| return "ie"; |
| } else { |
| return "id"; |
| } |
| } |
| |
| private String getThumbIFlags(int opcode) { |
| int a = (opcode >> 2) & 1; |
| int i = (opcode >> 1) & 1; |
| int f = (opcode & 1); |
| String iflags = ""; |
| iflags += (a == 1) ? "a" : ""; |
| iflags += (i == 1) ? "i" : ""; |
| iflags += (f == 1) ? "f" : ""; |
| return iflags; |
| } |
| |
| private String getThumbImmediate3(int opcode) { |
| int imm = (opcode >> 6) & 7; |
| return "#" + imm; |
| } |
| |
| private String getThumbImmediate5(int opcode, int multiplier) { |
| int imm = ((opcode >> 6) & 0x1f) * multiplier; |
| return "#" + getHexValue(imm); |
| } |
| |
| private String getThumbImmediate7(int opcode, int multiplier) { |
| int imm = (opcode & 0x7f) * multiplier; |
| return "#" + getHexValue(imm); |
| } |
| |
| private String getThumbImmediate8(int opcode, int multiplier) { |
| int imm = (opcode & 0xff) * multiplier; |
| return "#" + getHexValue(imm); |
| } |
| |
| private String getThumbReg(int opcode, int position) { |
| int reg = (opcode >> position) & 7; |
| return getRegName(reg); |
| } |
| |
| private String getThumbRegHigh(int opcode, int position, int hBit) { |
| int reg = (opcode >> position) & 7; |
| int high = (opcode >> hBit) & 1; |
| reg += (high == 1) ? 8 : 0; |
| return getRegName(reg); |
| } |
| |
| private String getThumbRegList(int opcode, String otherRegs) { |
| String r0 = ((opcode & 1) == 1) ? "r0," : ""; |
| String r1 = (((opcode >> 1) & 1) == 1) ? "r1," : ""; |
| String r2 = (((opcode >> 2) & 1) == 1) ? "r2," : ""; |
| String r3 = (((opcode >> 3) & 1) == 1) ? "r3," : ""; |
| String r4 = (((opcode >> 4) & 1) == 1) ? "r4," : ""; |
| String r5 = (((opcode >> 5) & 1) == 1) ? "r5," : ""; |
| String r6 = (((opcode >> 6) & 1) == 1) ? "r6," : ""; |
| String r7 = (((opcode >> 7) & 1) == 1) ? "r7," : ""; |
| String regList = "{" + r0 + r1 + r2 + r3 + r4 + r5 + r6 + r7; |
| if (otherRegs != null) { |
| regList += otherRegs; |
| } |
| regList += "}"; |
| regList = regList.replace(",}", "}"); |
| return regList; |
| } |
| |
| private String getThumb2AddrModeImm8(int opcode, int pBit, int uBit, int wBit, int shift) { |
| int offset = (opcode & 0xff) << shift; |
| String operands = '[' + getR_16(opcode); |
| String sign = isBitEnabled(opcode, uBit) ? "" : "-"; |
| if (isBitEnabled(opcode, pBit)) { |
| if (offset != 0) { |
| operands += ",#" + sign + getHexValue(offset); |
| } |
| operands += isBitEnabled(opcode, wBit) ? "]!" : "]"; |
| } else {// post-indexed |
| operands += ']'; |
| if (offset != 0) { |
| operands += ",#" + sign + getHexValue(offset); |
| } |
| } |
| return operands; |
| } |
| |
| private String getThumb2AddrModeRegImm(int opcode) { |
| String operands = '[' + getR_16(opcode) + ',' + getR_0(opcode); |
| int imm2 = opcode >> 4 & 3; |
| if (imm2 != 0) { |
| operands += ",lsl #" + imm2; |
| } |
| operands += ']'; |
| return operands; |
| } |
| |
| private int getThumb2_condB_Offset(int opcode) { |
| int sSignExtended = signExtend(getBit(opcode, 27) << 20, 20, 32); |
| int j1 = getBit(opcode, 13) << 18; |
| int j2 = getBit(opcode, 11) << 19; |
| return sSignExtended | j2 | j1 | opcode>>4&0x3f000 | (opcode & 0x7ff) << 1; |
| } |
| |
| private int getThumb2_uncondB_Offset(int opcode, boolean j1, boolean j2) { |
| int s = getBit(opcode, 27); |
| int sSignExtended = signExtend(s << 24, 24, 32); |
| boolean sb = s == 1; |
| int i1 = (j1 ^ sb) ? 0 : 1<<22; |
| int i2 = (j2 ^ sb) ? 0 : 1<<23; |
| return sSignExtended | i2 | i1 | opcode >> 4 & 0X3ff000 | (opcode & 0x7ff) << 1; |
| } |
| |
| private String getThumb2Condition(int opcode) { |
| return getCondition((opcode >> 22) & 0xf); |
| } |
| |
| private String getThumb2ExpandImm12(int opcode) { |
| int imm12 = getThumb2RawImm12(opcode), imm32 = 0; |
| if (0 == (imm12 >> 10 & 3)) { |
| int imm8 = imm12 & 0xff; |
| switch (imm12 >> 8 & 3) { |
| case 2: |
| imm32 = imm8 << 24 | imm8 << 8; |
| break; |
| |
| case 3: |
| imm32 = imm8 << 24 | imm8 << 8; |
| case 1: |
| imm32 |= imm8 << 16; |
| case 0: |
| imm32 |= imm8; |
| } |
| } else { |
| int shift = imm12 >> 7 & 31; |
| imm32 = 0x80 | imm12 & 0x7f; |
| imm32 = imm32 >> shift | imm32 << 32-shift; |
| } |
| |
| return getHexValue(imm32); |
| } |
| |
| private String getThumb2ImmForMovX(int x) { |
| return getHexValue((x & 0xf0000) >> 4 | getThumb2RawImm12(x)); |
| } |
| |
| private int getThumb2RawImm12(int x) { |
| return (x & 0x04000000) >> 0xf | (x & 0x7000) >> 4 | x & 0xff; |
| } |
| |
| private static final int |
| LSL = 0, LSR = 1, ASR = 2, RRX_ROR = 3; |
| |
| private String getThumb2ShiftMode(int opcode, int typePos) { |
| int type = opcode >> typePos & 3; |
| int value = getThumb2ShiftValue(opcode, type); |
| if (type == 0 && value == 0) |
| return ""; |
| |
| String shift = ","; |
| switch (type) { |
| case LSL: shift += "lsl"; break; |
| case LSR: shift += "lsr"; break; |
| case ASR: shift += "asr"; break; |
| case RRX_ROR: |
| if (value == 0) |
| return ",rrx"; |
| shift += "ror"; |
| } |
| return shift + " #" + value; |
| } |
| |
| private int getThumb2ShiftValue(int opcode, int type) { |
| int value = (opcode & 0x7000) >> 10 | opcode >> 6 & 3; |
| switch (type) { |
| case LSR: |
| case ASR: |
| if (0 == value) |
| value = 32; |
| } |
| return value; |
| } |
| |
| |
| private String getVFPDorSRegList(int opcode, boolean isD) { |
| int vd15_12 = opcode >> 12 & 0xf; |
| int d22 = getBit(opcode, 22); |
| int reg = isD ? d22 << 4 | vd15_12 : vd15_12 << 1 | d22; |
| int count = opcode & 0xff; |
| if (isD) |
| count /= 2; |
| |
| String list = "{" + (isD ? 'd' : 's') + reg; |
| |
| if (count > 1) |
| list += (isD ? "-d" : "-s") + (reg+count-1); |
| // for (int i = 0; i < count; i++) { |
| // if (count != 0) |
| // list += ","; |
| // list += (isD ? "d" : "s") + (reg + i); |
| // } |
| list += "}"; |
| return list; |
| } |
| |
| private String getVFPDdQmRegs(int opcode) { |
| return getVFPQorDReg(opcode, 0, 12, 22) + ',' + getVFPQorDReg(opcode, 1, 0, 5); |
| } |
| |
| private String getVFPIncDec(int opcode) { |
| int mode = (opcode >> 23) & 3; |
| switch (mode) { |
| case 1: return "ia"; |
| case 2: return "db"; |
| default: |
| return ""; |
| } |
| } |
| |
| private int getVFPDataTypeSize (int opcode, int sizePos) { |
| return 8 << (opcode >> sizePos & 3); |
| } |
| |
| /** |
| * Return 6-bit immediate instruction size |
| * |
| * @param opcode |
| * @param uPos bit indicating unsigned |
| * @param opPos |
| * @return .<type><size> |
| */ |
| private String getVFPImm6Size(int opcode) { |
| int imm6 = opcode >> 16 & 0x3f; |
| if (isBitEnabled(imm6, 5)) |
| return "64"; |
| else if (isBitEnabled(imm6, 4)) |
| return "32"; |
| else |
| return "16"; |
| } |
| |
| /** |
| * Return vqshl{u} sign or unsigned type with bit size |
| * |
| * @param opcode |
| * @param lBit |
| * @param uPos bit indicating unsigned |
| * @param opPos |
| * @return .<type><size> |
| */ |
| private String getVFPVqshlTypeSize(int opcode, int lBit, int uPos, int opPos) { |
| return ((isBitEnabled(opcode, uPos) && isBitEnabled(opcode, opPos)) ? ".u" : ".s") |
| + getVFPLImm6Size(opcode, lBit); |
| } |
| |
| private String getVFPIDataType(int opcode, int sizePos) { |
| return ".i" + getVFPDataTypeSize(opcode, sizePos); |
| } |
| |
| private String getVFPIDataType2(int opcode, int sizePos) { |
| return getVFPIDataType((opcode >> sizePos & 3) + 1, 0); |
| } |
| |
| private String getVFPIDataType3(int opcode, int sizePos) { |
| return ".i" + (8 << (opcode >> sizePos & 3)); |
| } |
| |
| private String getVFPPDataType (int opcode, int sizePos) { |
| return ".p" + getVFPDataTypeSize(opcode, sizePos); |
| } |
| |
| // depending on d, separate register bit is either before or |
| // after the rest of the register bits |
| private String getVFPDorSReg(int opcode, int d, int regPos, int regBitPos) { |
| if (d == 1) |
| return "d" + ((((opcode >> regBitPos) & 1) << 4) | ((opcode >> regPos) & 0xf)); |
| else |
| return "s" + ((((opcode >> regPos) & 0xf) << 1) | ((opcode >> regBitPos) & 1)); |
| } |
| |
| private int getVFPImm6SHRAdj(int opcode, int imm) { |
| if (isBitEnabled(opcode, 21)) |
| imm = 32 - imm; |
| else if (isBitEnabled(opcode, 20)) |
| imm = 16 - imm; |
| else if (isBitEnabled(opcode, 19)) |
| imm = 8 - imm; |
| return imm; |
| } |
| |
| /** |
| * @return 0 when imm6=8|16|32 else value minus top-bit |
| */ |
| private int getVFPQImm6(int opcode) { |
| int imm6 = opcode >> 16 & 0x3f; |
| if (imm6 == 32 || imm6 == 16 || imm6 == 8) { |
| imm6 = 0; |
| } else if (isBitEnabled(imm6, 5)) { |
| imm6 &= 0x1f; |
| } else if (isBitEnabled(imm6, 4)) { |
| imm6 &= 0x0f; |
| } else { // assuming isBitEnabled(imm, 4) |
| imm6 &= 0x07; |
| } |
| return imm6; |
| } |
| |
| private int getVFPImm6Encoded(int opcode) { |
| int imm6 = opcode >> 16 & 0x3f; |
| if (isBitEnabled(imm6, 5)) { |
| return 32 - (imm6 & 0x1f); |
| } else if (isBitEnabled(imm6, 4)) { |
| return 16 - (imm6 & 0xf); |
| } else { // assuming isBitEnabled(imm6, 3) |
| return 8 - (imm6 & 0x7); |
| } |
| } |
| |
| private int getVFPImm6(int opcode) { |
| int imm6 = opcode >> 16 & 0x3f; |
| if (isBitEnabled(imm6, 5)) { |
| return imm6 & 0x1f; |
| } else if (isBitEnabled(imm6, 4)) { |
| return imm6 & 0xf; |
| } else { // assuming isBitEnabled(imm6, 3) |
| return imm6 & 0x7; |
| } |
| } |
| |
| private String getVFPLImm6Size(int opcode, int lBit) { |
| if (lBit == 1) |
| return "64"; |
| else { |
| int imm6 = opcode >> 16 & 0x3f; |
| if (isBitEnabled(imm6, 5)) |
| return "32"; |
| else if (isBitEnabled(imm6, 4)) |
| return "16"; |
| else |
| return "8"; |
| } |
| } |
| |
| private int getVFPQorDRegNum(int opcode, int regPos, int regMsbPos) { |
| return (((opcode >> regMsbPos) & 1 ) << 4) | ((opcode >> regPos) & 0xf); |
| } |
| |
| private String getVFPQorDReg(int opcode, int q, int regPos, int regMsbPos) { |
| return (q == 1) |
| ? "q" + getVFPQorDRegNum(opcode, regPos, regMsbPos) / 2 |
| : "d" + getVFPQorDRegNum(opcode, regPos, regMsbPos); |
| } |
| |
| private String getVFPQUNUorSType(int opcode, int uBit, int opBit) { |
| int op = getBit(opcode, uBit) << 1 | getBit(opcode, opBit); |
| return (1 == op ? "un" : "n") + (3 == op ? ".u" : ".s"); |
| } |
| |
| private String getVFPQUUorSType(int opcode, int l, int uPos, int opPos) { |
| return ((isBitEnabled(opcode, uPos) && !isBitEnabled(opcode, opPos)) ? "u" : "") |
| + getVFPVqshlTypeSize(opcode, l, uPos, opPos); |
| } |
| |
| |
| private String getVFPSize(int opCmode) { |
| switch (opCmode) { |
| case 14: |
| return ".i8"; |
| case 8: case 9: case 10: case 11: |
| case 24: case 25: case 26: case 27: |
| return ".i16"; |
| default: |
| return ".i32"; |
| case 30: |
| return ".i64"; |
| case 15: |
| return ".f32"; |
| case 31: |
| return ""; |
| } |
| } |
| |
| private String getVFPIorFDataType(int opcode, int sizePos, int bitIorF) { |
| int size = 8 << ((opcode >> sizePos) & 0x3); |
| int f = (opcode >> bitIorF) & 1; |
| return (f == 1 ? ".f" : ".i") + size; |
| } |
| |
| private String getVFPSorUDataType(int opcode, int uPos) { |
| return (isBitEnabled(opcode, uPos) ? ".u" : ".s") |
| + getVFPDataTypeSize(opcode, 20); |
| } |
| |
| private String getVFPSorUorFDataType(int opcode, int sizePos, int fPos, int uPos) { |
| return (isBitEnabled(opcode, fPos) ? ".f" : (isBitEnabled(opcode, uPos) ? ".u" : ".s")) |
| + getVFPDataTypeSize(opcode, sizePos); |
| } |
| |
| private String getVFPSpecialReg(int opcode) { |
| switch (opcode >> 16 & 0xf) { |
| case 0: return "fpsid"; |
| case 1: return "fpscr"; |
| case 6: return "mvfr1"; |
| case 7: return "mvfr0"; |
| case 8: return "fpexc"; |
| case 9: return "fpinst"; |
| case 10: return "fpinst2"; |
| default: return "<unknown register>"; |
| } |
| } |
| |
| private String getVFPTdTm(int opcode, int opPos, int sizePos) { |
| switch ((opcode >> opPos & 3) << 2 | opcode >> sizePos & 3) { |
| case 10: return ".s32.f32"; |
| case 14: return ".u32.f32"; |
| case 2: return ".f32.s32"; |
| case 6: return ".f32.u32"; |
| } |
| return ""; |
| } |
| |
| private String getVFPTdTm2(int opcode, int opPos, int unsignedPos) { |
| switch ((opcode >> opPos & 1) << 1 | opcode >> unsignedPos & 1) { |
| case 0: return ".f32.s32"; |
| case 1: return ".f32.u32"; |
| case 2: return ".s32.f32"; |
| case 3: return ".u32.f32"; |
| } |
| return ""; |
| } |
| |
| |
| private String getVFPTdTm3(int opcode, int op2Pos, int opPos, int sz) { |
| int opc2 = opcode >> op2Pos & 7; |
| if (opc2 == 5) |
| return sz == 1 ? ".s32.f64" : ".s32.f32"; |
| else if (opc2 == 4) |
| return sz == 1 ? ".u32.f64" : ".u32.f32"; |
| else |
| switch (sz << 1 | getBit(opcode, opPos)) { |
| case 3: return ".f64.s32"; |
| case 2: return ".f64.u32"; |
| case 1: return ".f32.s32"; |
| case 0: return ".f32.u32"; |
| } |
| return ""; // should never get here |
| } |
| |
| private String getVFPVcvtType(int opcode) { |
| boolean op = isBitEnabled(opcode, 18); |
| boolean u = isBitEnabled(opcode, 16); |
| boolean sf = isBitEnabled(opcode, 8); |
| boolean sx = isBitEnabled(opcode, 7); |
| |
| String td = u ? (sx ? ".u32" : ".u16") : (sx ? ".s32" : ".s16"); |
| String ts = sf ? ".f64" : ".f32"; |
| |
| return op ? td + ts : ts + td; |
| } |
| |
| private String getVFPVldVstSize(int size) { |
| if (size == 0) |
| return ".8"; |
| else if (size == 1) |
| return ".16"; |
| // else if (size == 2) |
| return ".32"; |
| // return ""; |
| } |
| |
| private String getVFPVldVstEnding(int opcode) { |
| int Rm = opcode & 0xf; |
| |
| String suffix = ""; |
| if (Rm == 15) |
| ; |
| else if (Rm == 13) |
| suffix = "!"; |
| else |
| suffix = "," + getRegName(Rm); |
| |
| return suffix; |
| } |
| |
| /** |
| * ARM--- ... D_22_22 size_21_20 Vn_19_16 Vd___15_12 ... N___7_7 Q___6_6 M___5_5 0 Vm___3_0<br> |
| * Thumb2 ... D_1_6_6 size_1_5_4 Vn_1_3_0 Vd_0_15_12 ... N_0_7_7 Q_0_6_6 M_0_5_5 0 Vm_0_3_0 |
| * @param opcode |
| * @return String containing "i8", "i16", "i32" or "i64", + TAB + proper Q-or-D _d,_n,_m register operands |
| * <p><listing> |
| * A8.6.271 VADD (integer) |
| * {@literal vadd<c>.<dt> <Qd>,<Qn>,<Qm> vadd<c>.<dt> <Dd>,<Dn>,<Dm>} |
| * A8.6.280 VCEQ (register) |
| * {@literal vceq<c>.<dt> <Qd>,<Qn>,<Qm> vceq<c>.<dt> <Dd>,<Dn>,<Dm>} |
| * A8.6.349 VPADD (integer) |
| * {@literal vpadd for q==1 UNDEFINED vpadd<c>.<dt> <Dd>,<Dn>,<Dm>} |
| * A8.6.401 VSUB (integer) |
| * {@literal vsub<c>.<dt> <Qd>,<Qn>,<Qm> vsub<c>.<dt> <Dd>,<Dn>,<Dm>} |
| */ |
| private String getVFPIDataTypeQorDdnmOperands(int opcode) { |
| return getVFPIDataType(opcode, 20) + getVFPQorDdnmRegs(opcode); |
| } |
| |
| /** |
| * ARM--- ... D_22_22 size_21_20 Vn_10_16 Vd___15_12 ... N___7_7 . M___5_5 . Vm___3_0<br> |
| * Thumb2 ... D_1_6_6 size_1_5_4 Vn_1_3_0 Vd_0_15_12 ... N_0_7_7 . M_0_5_5 . Vm_0_3_0 |
| * @param opcode |
| * @return String containing "i16", "i32" or "i64", + TAB + the approriate Dd,Qn,Qm register operands |
| * <p><listing> |
| * A8.6.273 VADDHN |
| * {@literal vaddhn<c>.<dt> <Dd>,<Qn>,<Qm>} |
| * A8.6.370 VRADDHN |
| * {@literal vraddhn<c>.<dt> <Dd>,<Qn>,<Qm>} |
| * A8.6.381 VRSUBHN |
| * {@literal vrsubhn<c>.<dt> <Dd>,<Qn>,<Qm>} |
| * A8.6.403 VSUBHN |
| * {@literal vsubhn<c>.<dt> <Dd>,<Qn>,<Qm>} |
| */ |
| private String getVFPIDataType2DdQnDmOperands(int opcode) { |
| String ops = getVFPIDataType2(opcode, 20) |
| + TAB + getVFPQorDReg(opcode, 0, 12, 22) |
| + ',' + getVFPQorDReg(opcode, 1, 16, 7) |
| + ',' + getVFPQorDReg(opcode, 1, 0, 5); |
| return ops; |
| } |
| |
| /** |
| * ARM--- ... D_22_22 size_21_20 Vn_19_16 Vd___15_12 ... N___7_7 . M___5_5 . Vm___3_0<br> |
| * Thumb2 ... D_1_6_6 size_1_5_4 Vn_1_3_0 Vd_0_15_12 ... N_0_7_7 . M_0_5_5 . Vm_0_3_0 |
| * @param opcode |
| * @return String containing a TAB + the approriate Qd,Dn,Dm register operands |
| * <p><listing> |
| * A8.6.266 VABA, VABAL |
| * {@literal vabal<c>.<dt> <Qd>,<Dn>,<Dm>} |
| * A8.6.267 VABD, VABDL (integer) |
| * {@literal vabdl<c>.<dt> <Qd>,<Dn>,<Dm>} |
| * A8.6.323 VMLA, VMLAL, VMLS, VMLSL (integer) |
| * {@literal vmlal<c>.<dt> <Qd>,<Dn>,<Dm>} |
| * {@literal vmlsl<c>.<dt> <Qd>,<Dn>,<Dm>} |
| * A8.6.337 VMUL, VMULL (integer and polynomial) |
| * {@literal vmull<c>.<dt> <Qd>,<Dn>,<Dm>} |
| * A8.6.358 VQDMLAL, VQDMLSL |
| * {@literal vqd<op><c>.<dt> <Qd>,<Dn>,<Dm>} |
| * A8.6.360 VQDMULL |
| * {@literal vqdmull<c>.<dt> <Qd>,<Dn>,<Dm>} |
| * |
| */ |
| private String getVFPQdDnDmRegs(int opcode) { |
| String regs = getVFPQorDReg(opcode, 1, 12, 22) |
| + ',' + getVFPQorDReg(opcode, 0, 16, 7) |
| + ',' + getVFPQorDReg(opcode, 0, 0, 5); |
| return regs; |
| } |
| |
| /** |
| * ARM--- ... D_22_22 ... Vd___15_12 ... Q___6_6 M___5_5 . Vm___3_0<br> |
| * Thumb2 ... D_1_6_6 ... Vd_0_15_12 ... Q_0_6_6 M_0_5_5 . Vm_0_3_0 |
| * @param opcode |
| * @return String containing a TAB + the approriate "q" or "d" _d,_m register operands |
| * <p><listing> |
| * A8.6.293 VCNT |
| * {@literal vcnt<c>.8 <Qd>,<Qm> vcnt<c>.8 <Dd>,<Dm>} |
| * A8.6.327 VMOV (register) |
| * {@literal vmov<c> <Qd>,<Qm> vmov<c> <Dd>,<Dm>} |
| * A8.6.341 VMVN (register) |
| * {@literal vmvn<c> <Qd>,<Qm> vmvn<c> <Dd>,<Dm>} |
| * A8.6.405 VSWP |
| * {@literal vswp<c> <Qd>,<Qm> vswp<c> <Dd>,<Dm>} |
| */ |
| private String getVFPQorDdmRegs(int opcode) { |
| int q = getBit(opcode, 6); |
| return TAB + getVFPQorDReg(opcode, q, 12, 22) + ',' + getVFPQorDReg(opcode, q, 0, 5); |
| } |
| |
| /** |
| * ARM--- ... D_22_22 ... Vn_19_16 Vd___15_12 ... N___7_7 Q___6_6 M___5_5 . Vm___3_0<br> |
| * Thumb2 ... D_1_6_6 ... Vn_1_3_0 Vd_0_15_12 ... N_0_7_7 Q_0_6_6 M_0_5_5 . Vm_0_3_0 |
| * @param opcode |
| * @return String containing a TAB + proper Q-or-D _d,_n,_m register operands |
| * <p><listing> |
| * A8.6.364 VQRSHL |
| * {@literal vqrshl<c>.<type><size> <Qd>,<Qm>,<Qn> vqrshl<c>.<type><size> <Dd>,<Dm>,<Dn>} |
| * A8.6.366 VQSHL (register) |
| * {@literal vqshl<c>.<type><size> <Qd>,<Qm>,<Qn> vqshl<c>.<type><size> <Dd>,<Dm>,<Dn>} |
| * A8.6.375 VRSHL |
| * {@literal vrshl<c>.<type><size> <Qd>,<Qm>,<Qn> vrshl<c>.<type><size> <Dd>,<Dm>,<Dn>} |
| * A8.6.383 VSHL (register) |
| * {@literal vshl<c>.i<size> <Qd>,<Qm>,<Qn> vshl<c>.i<size> <Dd>,<Dm>,<Dn>} |
| */ |
| private String getVFPQorDdmnRegs(int opcode) { |
| int q = getBit(opcode, 6); |
| String regs = TAB + getVFPQorDReg(opcode, q, 12, 22) |
| + ',' + getVFPQorDReg(opcode, q, 0, 5) |
| + ',' + getVFPQorDReg(opcode, q, 16, 7); |
| return regs; |
| } |
| |
| /** |
| * ARM--- ... D_22_22 ... Vn_19_16 Vd___15_12 ... N___7_7 Q___6_6 M___5_5 . Vm___3_0<br> |
| * Thumb2 ... D_1_6_6 ... Vn_1_3_0 Vd_0_15_12 ... N_0_7_7 Q_0_6_6 M_0_5_5 . Vm_0_3_0 |
| * @param opcode |
| * @return String containing a TAB + proper Q-or-D _d,_n,_m register operands |
| * <p><listing> |
| * A8.6.266 VABA, VABAL |
| * {@literal vaba<c>.<dt> <Qd>,<Qn>,<Qm> vaba<c>.<dt> <Dd>,<Dn>,<Dm>} |
| * A8.6.267 VABD, VABDL (integer) |
| * {@literal vabd<c>.<dt> <Qd>,<Qn>,<Qm> vabd<c>.<dt> <Dd>,<Dn>,<Dm>} |
| * A8.6.268 VABD (floating-point) |
| * {@literal vabd<c>.f32 <Qd>,<Qn>,<Qm> vabd<c>.f32 <Dd>,<Dn>,<Dm>} |
| * A8.6.282 VCGE (register) |
| * {@literal vcge<c>.<dt> <Qd>,<Qn>,<Qm> vcge<c>.<dt> <Dd>,<Dn>,<Dm>} |
| * A8.6.272 VADD (floating-point) |
| * {@literal vadd<c>.f32 <Qd>,<Qn>,<Qm> vadd<c>.f32 <Dd>,<Dn>,<Dm>} |
| * A8.6.276 VAND (register) |
| * {@literal vand<c> <Qd>,<Qn>,<Qm> vand<c> <Dd>,<Dn>,<Dm>} |
| * A8.6.278 VBIC (register) |
| * {@literal vbic<c> <Qd>,<Qn>,<Qm> vbic<c> <Dd>,<Dn>,<Dm>} |
| * A8.6.280 VCEQ (register) |
| * {@literal vceq<c>.f32 <Qd>,<Qn>,<Qm> vceq<c>.f32 <Dd>,<Dn>,<Dm>} |
| * A8.6.282 VCGE (register) |
| * {@literal vcge<c>.f32 <Qd>,<Qn>,<Qm> vcge<c>.f32 <Dd>,<Dn>,<Dm>} |
| * A8.6.284 VCGT (register) |
| * {@literal vcgt<c>.f32 <Qd>,<Qn>,<Qm> vcgt<c>.f32 <Dd>,<Dn>,<Dm>} |
| * A8.6.284 VCGT (register) |
| * {@literal vcgt<c>.<dt> <Qd>,<Qn>,<Qm> vcgt<c>.<dt> <Dd>,<Dn>,<Dm>} |
| * A8.6.304 VEOR |
| * {@literal veor <Qd>,<Qn>,<Qm> veor<c> <Dd>,<Dn>,<Dm>} |
| * A8.6.324 VMLA, VMLS (floating point) |
| * {@literal vml<op><c>.f32 <Qd>,<Qn>,<Qm> vml<op><c>.f32 <Dd>,<Dn>,<Dm>} |
| * A8.6.337 VMUL, VMULL (integer and polynomial) |
| * {@literal vmul<c>.<dt> <Qd>,<Qn>,<Qm> vmul<c>.<dt> <Dd>,<Dn>,<Dm>} |
| * A8.6.338 VMUL (floating-point) |
| * {@literal vmul<c>.f32 <Qd>,<Qn>,<Qm> vmul<c>.f32 <Dd>,<Dn>,<Dm>} |
| * A8.6.345 VORN (register) |
| * {@literal vorn <Qd>,<Qn>,<Qm> vorn<c> <Dd>,<Dn>,<Dm>} |
| * A8.6.347 VORR (register) |
| * {@literal vorr<c> <Qd>,<Qn>,<Qm> vorr<c> <Dd>,<Dn>,<Dm>} |
| * A8.6.350 VPADD (floating-point) |
| * {@literal UNDEFINED if q=='1' vpadd<c>.f32 <Dd>,<Dn>,<Dm>} |
| * A8.6.357 VQADD |
| * {@literal vqadd<c>.<dt> <Qd>,<Qn>,<Qm> vqadd<c>.<dt> <Dd>,<Dn>,<Dm>} |
| * A8.6.359 VQDMULH |
| * {@literal vqdmulh<c>.<dt> <Qd>,<Qn>,<Qm> vqadd<c>.<dt> <Dd>,<Dn>,<Dm>} |
| * A8.6.363 VQRDMULH |
| * {@literal vqrdmulh<c>.<dt> <Qd>,<Qn>,<Qm> vqadd<c>.<dt> <Dd>,<Dn>,<Dm>} |
| * A8.6.369 VQSUB |
| * {@literal vqsub<c>.<type><size> <Qd>,<Qn>,<Qm> vqsub<c>.<type><size> <Dd>,<Dn>,<Dm>} |
| * A8.6.374 VRHADD |
| * {@literal vrhadd<c> <Qd>,<Qn>,<Qm> vrhadd<c> <Dd>,<Dn>,<Dm>} |
| * A8.6.372 VRECPS |
| * {@literal vrecps<c>.f32 <Qd>,<Qn>,<Qm> vrecps<c>.f32 <Dd>,<Dn>,<Dm>} |
| * A8.6.379 VRSQRTS |
| * {@literal vrsqrts<c>.f32 <Qd>,<Qn>,<Qm> vrsqrts<c>.f32 <Dd>,<Dn>,<Dm>} |
| * A8.6.402 VSUB (floating-point) |
| * {@literal vsub<c>.f32 <Qd>,<Qn>,<Qm> vsub<c>.f32 <Dd>,<Dn>,<Dm>} |
| */ |
| private String getVFPQorDdnmRegs(int opcode) { |
| int q = getBit(opcode, 6); |
| String regs = TAB + getVFPQorDReg(opcode, q, 12, 22) |
| + ',' + getVFPQorDReg(opcode, q, 16, 7) |
| + ',' + getVFPQorDReg(opcode, q, 0, 5); |
| return regs; |
| } |
| |
| /** |
| * ARM--- ... D_22_22 size_21_20 Vn_19_16 Vd___15_12 ... N___7_7 . M___5_5 . Vm___3_0<br> |
| * Thumb2 ... D_1_6_6 size_1_5_4 Vn_1_3_0 Vd_0_15_12 ... N_0_7_7 . M_0_5_5 . Vm_0_3_0 |
| * @param opcode |
| * @param dType whether to use Qd or Dd register type |
| * @param nType whether to use Qn or Dn register type |
| * @return String containing "16" or "32", + TAB + proper Q-or-D _d,_n,Dm[x] register operands |
| * <p><listing> |
| * A8.6.358 VQDMLAL, VQDMLSL |
| * {@literal vqd<op><c>.<dt> <Qd>,<Dn>,<Dm[x]>} |
| * A8.6.359 VQDMULH |
| * {@literal vqdmulh<c>.<dt> <Qd>,<Qn>,<Dm[x]> vqdmulh<c>.<dt> <Dd>,<Dn>,<Dm[x]>} |
| * A8.6.363 VQRDMULH |
| * {@literal vqrdmulh<c>.<dt> <Qd>,<Qn>,<Dm[x]> vqrdmulh<c>.<dt> <Dd>,<Dn>,<Dm[x]>} |
| */ |
| private String getVFPScalarOperands(int opcode, int dType, int nType) { |
| int index = getBit(opcode, 5); |
| int mR = opcode & 0xf; |
| int size = opcode >> 20 & 3; |
| String postfix; |
| if (size == 1) { |
| postfix = "16"; |
| mR &= 7; // probably not necessary |
| index = index << 1 | getBit(opcode, 3); |
| } else { // size == 2 ; if size == 0 then UNDEFINED |
| postfix = "32"; |
| } |
| return postfix + TAB + getVFPQorDReg(opcode, dType, 12, 22) |
| + ',' + getVFPQorDReg(opcode, nType, 16, 7) |
| + ",d" + mR + '[' + index + ']'; |
| } |
| |
| /** |
| * ARM--- ... D_22_22 . . size_19_18 . . Vd___15_12 ... Q___6_6 M___5_5 . Vm___3_0<br> |
| * Thumb2 ... D_1_6_6 . . size_1_3_2 . . Vd_0_15_12 ... Q_0_6_6 M_0_5_5 . Vm_0_3_0 |
| * @param opcode |
| * @param bitIorF location of the f-flag designating float-or-integer |
| * @param bitSorU location of the u-flag designating unsigned-or-signed integer |
| * @return String containing the data-type + TAB + proper Q-or-D _d,_m reg operands |
| * <p><listing> |
| * A8.6.269 VABS |
| * {@literal vabs<c>.<dt> <Qd>,<Qm> vabs<c>.<dt> <Dd>,<Dm>} |
| * A8.6.288 VCLS |
| * {@literal vcls<c>.<dt> <Qd>,<Qm> vcls<c>.<dt> <Dd>,<Dm>} |
| * A8.6.342 VNEG |
| * {@literal vneg<c>.<dt> <Qd>,<Qm> vneg<c>.<dt> <Dd>,<Dm>} |
| * A8.6.348 VPADAL |
| * {@literal vpadal<c>.<dt> <Qd>,<Qm> vpadal<c>.<dt> <Dd>,<Dm>} |
| * A8.6.351 VPADDL |
| * {@literal vpaddl<c>.<dt> <Qd>,<Qm> vpaddl<c>.<dt> <Dd>,<Dm>} |
| * A8.6.356 VQABS |
| * {@literal vqabs<c>.<dt> <Qd>,<Qm> vqabs<c>.<dt> <Dd>,<Dm>} |
| * A8.6.362 VQNEG |
| * {@literal vqneg<c>.<dt> <Qd>,<Qm> vqneg<c>.<dt> <Dd>,<Dm>} |
| * A8.6.371 VRECPE |
| * {@literal vrecpe<c>.<dt> <Qd>,<Qm> vrecpe<c>.<dt> <Dd>,<Dm>} |
| * A8.6.378 VRSQRTE |
| * {@literal vrsqrte<c>.<dt> <Qd>,<Qm> vrsqrte<c>.<dt> <Dd>,<Dm>} |
| * A8.6.283 VCGE (immediate #0) |
| * {@literal vcge<c>.<dt> <Qd>,<Qm>,#0 vcge<c>.<dt> <Dd>,<Dm>,#0} |
| * A8.6.285 VCGT (immediate #0) |
| * {@literal vcgt<c>.<dt> <Qd>,<Qm>,#0 vcgt<c>.<dt> <Dd>,<Dm>,#0} |
| * A8.6.287 VCLE (immediate #0) |
| * {@literal vcle<c>.<dt> <Qd>,<Qm>,#0 vcle<c>.<dt> <Dd>,<Dm>,#0} |
| * A8.6.290 VCLT (immediate #0) |
| * {@literal vclt<c>.<dt> <Qd>,<Qm>,#0 vclt<c>.<dt> <Dd>,<Dm>,#0} |
| */ |
| private String getVFPSorUorFQorDdmOperands(int opcode, int bitIorF, int bitSorU) { |
| return getVFPSorUorFDataType(opcode, 18, bitIorF, bitSorU) + TAB + getVFPQorDdmRegs(opcode); |
| } |
| |
| /** |
| * ARM--- ... D_22_22 . . size_19_18 . . Vd___15_12 ... Q___6_6 M___5_5 . Vm___3_0<br> |
| * Thumb2 ... D_1_6_6 . . size_1_3_2 . . Vd_0_15_12 ... Q_0_6_6 M_0_5_5 . Vm_0_3_0 |
| * @param opcode |
| * @param bitIorF location of the f-flag designating integer-or-float |
| * @return String containing the data-type + TAB + proper Q-or-D _d,_m reg operands |
| * <p><listing> |
| * A8.6.291 VCLZ |
| * {@literal vclz<c>.<dt> <Qd>,<Qm> vclz<c>.<dt> <Dd>,<Dm>} |
| * A8.6.283 VCGE (immediate #0) |
| * {@literal vcge<c>.<dt> <Qd>,<Qm>,#0 vcge<c>.<dt> <Dd>,<Dm>,#0} |
| * A8.6.285 VCGT (immediate #0) |
| * {@literal vcgt<c>.<dt> <Qd>,<Qm>,#0 vcgt<c>.<dt> <Dd>,<Dm>,#0} |
| * A8.6.287 VCLE (immediate #0) |
| * {@literal vcle<c>.<dt> <Qd>,<Qm>,#0 vcle<c>.<dt> <Dd>,<Dm>,#0} |
| * A8.6.290 VCLT (immediate #0) |
| * {@literal vclt<c>.<dt> <Qd>,<Qm>,#0 vclt<c>.<dt> <Dd>,<Dm>,#0} |
| */ |
| private String getVFPIorFQorDdmOperands(int opcode, int bitIorF) { |
| return getVFPIorFDataType(opcode, 18, bitIorF) + TAB + getVFPQorDdmRegs(opcode); |
| } |
| |
| /** |
| * @param szbit bit containing the sz determining ".f64" or ".f32" |
| * @return String containing ".f64" or ".f32" |
| */ |
| private String getVFPSzF64F32Type(int szbit) { |
| return szbit == 1 ? ".f64" : ".f32"; |
| } |
| |
| /** |
| * ARM--- ... D_22_22 ... Vd___15_12 ... sz___8_8 . . M___5_5 . Vm___3_0<br> |
| * Thumb2 ... D_1_6_6 ... Vd_0_15_12 ... sz_0_8_8 . . M_0_5_5 . Vm_0_3_0 |
| * @param opcode |
| * @return String containing ".f64" or ".f32" + TAB + proper D-or-S _d,_m reg operands |
| * <p><listing> |
| * A8.6.269 VABS |
| * {@literal vabs<c>.f64 <Dd>,<Dm> vabs<c>.f32 <Sd>,<Sm>} |
| * A8.6.327 VMOV (register) |
| * {@literal vmov<c>.f64 <Dd>,<Dm> vmov<c>.f32 <Sd>,<Sm>} |
| * A8.6.342 VNEG |
| * {@literal vneg<c>.f64 <Dd>,<Dm> vneg<c>.f32 <Sd>,<Sm>} |
| * A8.6.388 VSQRT |
| * {@literal vsqrt<c>.f64 <Dd>,<Dm> vsqrt<c>.f32 <Sd>,<Sm>} |
| * A8.6.292 VCMP, VCMPE |
| * vcmp{e}{@literal <c>.f64 <Dd>,<Dm>} vcmp{e}{@literal <c>.f32 <Sd>,<Sm>} |
| */ |
| private String getVFPSzF64F32dmOperands(int opcode) { |
| int sz = getBit(opcode, 8); |
| return getVFPSzF64F32Type(sz) |
| + TAB + getVFPDorSReg(opcode, sz, 12, 22) |
| + ',' + getVFPDorSReg(opcode, sz, 0, 5); |
| } |
| |
| /** |
| * ARM--- ... D_22_22 . . Vn_19_16 Vd___15_12 ... sz___8_8 N___7_7 . M___5_5 . Vm___3_0<br> |
| * Thumb2 ... D_1_6_6 . . Vn_1_3_0 Vd_0_15_12 ... sz_0_8_8 N_0_7_7 . M_0_5_5 . Vm_0_3_0 |
| * @param opcode |
| * @return String containing ".f64" or ".f32" + TAB + proper D-or-S _d,_n,_m reg operands |
| * <p><listing> |
| * A8.6.343 VNMLA, VNMLS, VNMUL |
| * {@literal vnmla<c>.f64 <Dd>,<Dn>,<Dm> vnmla<c>.f32 <Sd>,<Sn>,<Sm>} |
| * {@literal vnmls<c>.f64 <Dd>,<Dn>,<Dm> vnmls<c>.f32 <Sd>,<Sn>,<Sm>} |
| * A8.6.272 VADD (floating-point) |
| * {@literal vadd<c>.f64 <Dd>,<Dn>,<Dm> vadd<c>.f32 <Sd>,<Sn>,<Sm>} |
| * A8.6.301 VDIV |
| * {@literal vdiv<c>.f64 <Dd>,<Dn>,<Dm> vdiv<c>.f32 <Sd>,<Sn>,<Sm>} |
| * A8.6.324 VMLA, VMLS (floating-point) |
| * {@literal vml<op><c>.f64 <Dd>,<Dn>,<Dm> vml<op><c>.f32 <Sd>,<Sn>,<Sm>} |
| * A8.6.338 VMUL (floating-point) |
| * {@literal vmul<c>.f64 <Dd>,<Dn>,<Dm> vmul<c>.f32 <Sd>,<Sn>,<Sm>} |
| * A8.6.343 VNMLA, VNMLS, VNMUL |
| * {@literal vnmul<c>.f64 <Dd>,<Dn>,<Dm> vnmul<c>.f32 <Sd>,<Sn>,<Sm>} |
| * A8.6.402 VSUB (floating-point) |
| * {@literal vsub<c>.f64 <Dd>,<Dn>,<Dm> vsub<c>.f32 <Sd>,<Sn>,<Sm>} |
| */ |
| private String getVFPSzF64F32dnmOperands(int opcode) { |
| int sz = getBit(opcode, 8); |
| return getVFPSzF64F32Type(sz) |
| + TAB + getVFPDorSReg(opcode, sz, 12, 22) |
| + ',' + getVFPDorSReg(opcode, sz, 16, 7) |
| + ',' + getVFPDorSReg(opcode, sz, 0, 5); |
| } |
| |
| /** |
| * ARM--- ... D_22_22 . . sz_19_18 . . Vd___15_12 ... Q___6_6 M___5_5 . Vm___3_0<br> |
| * Thumb2 ... D_1_6_6 . . sz_1_3_2 . . Vd_0_15_12 ... Q_0_6_6 M_0_5_5 . Vm_0_3_0 |
| * @param opcode |
| * @return String containing ".8", ".16" or ".32" + TAB + proper Q-or-D _d,_m reg operands |
| * <p><listing> |
| * A8.6.407 VTRN |
| * {@literal vtrn<c>.<size> <Qd>,<Qm> vtrn<c>.<size> <Dd>,<Dm>} |
| * A8.6.409 VUZP |
| * {@literal vuzp<c>.<size> <Qd>,<Qm> vuzp<c>.<size> <Dd>,<Dm>} |
| * A8.6.410 VZIP |
| * {@literal vzip<c>.<size> <Qd>,<Qm> vzip<c>.<size> <Dd>,<Dm>} |
| */ |
| private String getVFPSzQorDdmOperands(int opcode) { |
| return "." + getVFPDataTypeSize(opcode, 18) + getVFPQorDdmRegs(opcode); |
| } |
| |
| /** |
| * ARM--- ... D_22_22 sz_21_20 Vn_19_16 Vd___15_12 ... N___7_7 Q___6_6 M___5_5 . Vm___3_0<br> |
| * Thumb2 ... D_1_6_6 sz_1_5_4 Vn_1_3_0 Vd_0_15_12 ... N_0_7_7 Q_0_6_6 M_0_5_5 . Vm_0_3_0 |
| * @param opcode |
| * @return String containing ".8" ".16" or ".32" + TAB + proper Q-or-D _d,_n,_m reg operands |
| * <p><listing> |
| * A8.6.408 VTST |
| * {@literal vtst<c>.<size> <Qd>,<Qn>,<Qm> vtst<c>.<size> <Dd>,<Dn>,<Dm>} |
| */ |
| private String getVFPSzQorDdnmOperands(int opcode) { |
| return "." + getVFPDataTypeSize(opcode, 20) + getVFPQorDdnmRegs(opcode); |
| } |
| |
| /** |
| * ARM--- ... D_22_22 op_21_21 sz_20_20 Vn_19_16 Vd___15_12 ... N___7_7 Q___6_6 M___5_5 1 Vm___3_0<br> |
| * Thumb2 ... D_1_6_6 op_1_5_5 sz_1_4_4 Vn_1_3_0 Vd_0_15_12 ... N_0_7_7 Q_0_6_6 M_0_5_5 1 Vm_0_3_0 |
| * @param opcode |
| * @return "ge" or "gt" + "f32" + TAB + proper Q-or-D _d,_n,_m register operands |
| * <p><listing> |
| * A8.6.270 VACGE, VACGT, VACLE, VACLT |
| * {@literal vacge<c>.f32 <Qd>,<Qn>,<Qm> vacge<c>.f32 <Dd>,<Dn>,<Dm>} |
| * {@literal vacgt<c>.f32 <Qd>,<Qn>,<Qm> vacgt<c>.f32 <Dd>,<Dn>,<Dm>} |
| */ |
| private String getVFP_vacge_vacgt(int opcode) { |
| return (isBitEnabled(opcode, 21) ? "gt.f32" : "ge.f32") |
| + getVFPQorDdnmRegs(opcode); |
| } |
| |
| /** |
| * ARM--- ... D_22_22 op_21_20 Vn_19_16 Vd___15_12 ... N___7_7 Q___6_6 M___5_5 1 Vm___3_0<br> |
| * Thumb2 ... D_1_6_6 op_1_5_4 Vn_1_3_0 Vd_0_15_12 ... N_0_7_7 Q_0_6_6 M_0_5_5 1 Vm_0_3_0 |
| * <p><listing> |
| * @param opcode |
| * @return String containing the full mnemonic for this opcode |
| */ |
| private String getVFP_vbif_vbit_vbsl_veor_mnemonic(int opcode) { |
| switch ((opcode >> 20) & 3) { |
| case 0: return "veor"; |
| case 1: return "vbsl"; |
| case 2: return "vbit"; |
| case 3: return "vbif"; |
| } |
| return "v"; // should never get here |
| } |
| |
| /** |
| * ARM--- ... D_22_22 ... Vd___15_12 ... sz___8_8 E___7_7 ...<br> |
| * Thumb2 ... D_1_6_6 ... Vd_0_15_12 ... sz_0_8_8 E_0_7_7 ... |
| * @param opcode |
| * @return String containing ".f32" or ".f64" + TAB + proper D-or-S _d reg operand + ",0.0" |
| * <p><listing> |
| * A8.6.292 VCMP, VCMPE |
| * vcmp{e}{@literal <c>.f64 <Dd>},#0.0 vcmp{e}{@literal <c>.f32 <Sd>},#0.0 |
| */ |
| private String getVFP_vcmpTo0Operands(int opcode) { |
| int sz = getBit(opcode, 8); |
| return getVFPSzF64F32Type(sz) |
| + TAB + getVFPDorSReg(opcode, sz, 12, 22) + ",#0.0"; |
| } |
| |
| /** |
| * ARM--- ... D_22_22 ... Vd___15_12 ... sz___8_8 . . M___5_5 . Vm___3_0<br> |
| * Thumb2 ... D_1_6_6 ... Vd_0_15_12 ... sz_0_8_8 . . M_0_5_5 . Vm_0_3_0 |
| * @param opcode |
| * @return String containing proper mnemonic postfix + TAB + proper D-or-S _d,_m reg operands |
| * <p><listing> |
| * A8.6.298 VCVT (between double-precision and single-precision) |
| * {@literal vcvt<c>.f64.f32 <Dd>,<Sm>} |
| * {@literal vcvt<c>.f32.f64 <Sd>,<Dm>} |
| */ |
| private String getVFP_vcvtDpSpOperands(int opcode) { |
| int sz = getBit(opcode, 8); |
| return (sz == 1 ? ".f32.f64" : ".f64.f32") |
| + TAB + getVFPDorSReg(opcode, 1-sz, 12, 22) |
| + ',' + getVFPDorSReg(opcode, sz, 0, 5); |
| } |
| |
| /** |
| * ARM--- ... D_22_22 ... op_18_18 . U_16_16 Vd___15_12 ... sf___8_8 sx___7_7 . i___5_5 . imm4___3_0<br> |
| * Thumb2 ... D_1_6_6 ... op_1_2_2 . U_1_0_0 Vd_0_15_12 ... sf_0_8_8 sx_0_7_7 . i_0_5_5 . imm4_0_3_0 |
| * @param opcode |
| * @return String containing proper mnemonic postfix + TAB + proper D-or-S _d,_d reg operands |
| * <p><listing> |
| * A8.6.297 VCVT (between floating-point and fixed-point, VFP) |
| * {@literal vcvt<c>.<Td>.f64 <Dd>,<Dd>,#<fbits>} |
| * {@literal vcvt<c>.<Td>.f32 <Sd>,<Sd>,#<fbits>} |
| * {@literal vcvt<c>.f64.<Td> <Dd>,<Dd>,#<fbits>} |
| * {@literal vcvt<c>.f32.<Td> <Sd>,<Sd>,#<fbits>} |
| */ |
| private String getVFP_vcvtFpFixRegOperands(int opcode) { |
| String dreg = getVFPDorSReg(opcode, getBit(opcode, 8), 12, 22); |
| int imm = ((opcode & 0xF) << 1) | getBit(opcode, 5); |
| if (isBitEnabled(opcode, 7)) |
| imm = 32 - imm; |
| else |
| imm = 16 - imm; |
| return getVFPVcvtType(opcode) + TAB + dreg + ',' + dreg |
| + ",#" + imm; |
| } |
| |
| /** |
| * ARM--- ... D_22_22 imm6_21_16 Vd___15_12 ... op___8_8 0 Q___6_6 M___5_5 1 Vm___3_0<br> |
| * Thumb2 ... D_1_6_6 imm6_1_5_0 Vd_0_15_12 ... op_0_8_8 0 Q_0_6_6 M_0_5_5 1 Vm_0_3_0 |
| * @param opcode |
| * @param uBit bit in the opcode containing the u (unsigned) bit |
| * @return String containing proper mnemonic postfix + TAB + proper Q-or-D _d,_m reg operands |
| * <p><listing> |
| * A8.6.296 VCVT (between floating-point and fixed-point, Advanced SIMD) |
| * {@literal vcvt<c>.<Td>.<Tm> <Qd>,<Qm>,#<fbits>} |
| * {@literal vcvt<c>.<Td>.<Tm> <Dd>,<Dm>,#<fbits>} |
| */ |
| private String getVFP_vcvtFpFixVecOperands(int opcode, int uBit) { |
| return getVFPTdTm2(opcode, 8, uBit) + getVFPQorDdmRegs(opcode) |
| + ",#" + (opcode >> 16 & 0x3f); |
| } |
| |
| /** |
| * ARM--- ... D_22_22 . . size_19_18 1 1 Vd___15_12 ... op___8_7 Q___6_6 M___5_5 . Vm___3_0<br> |
| * Thumb2 ... D_1_6_6 . . size_1_3_2 1 1 Vd_0_15_12 ... op_0_8_7 Q_0_6_6 M_0_5_5 . Vm_0_3_0 |
| * @param opcode |
| * @return String containing proper Td.Tm combo + TAB + proper Q-or-D _d,_m reg operands |
| * <p><listing> |
| * A8.6.294 VCVT (between floating-point and integer, Advanced SIMD) |
| * {@literal vcvt<c>.<Td>.<Tm> <Qd>,<Qm>} |
| * {@literal vcvt<c>.<Td>.<Tm> <Dd>,<Dm>} |
| */ |
| private String getVFP_vcvtFpIVecOperands(int opcode) { |
| return getVFPTdTm(opcode, 7, 18) + getVFPQorDdmRegs(opcode); |
| } |
| |
| /** |
| * ARM--- ... D_22_22 ... opc2_18_16 Vd___15_12 ... sz___8_8 op___7_7 . M___5_5 . Vm___3_0<br> |
| * Thumb2 ... D_1_6_6 ... opc2_1_2_0 Vd_0_15_12 ... sz_0_8_8 op_0_7_7 . M_0_5_5 . Vm_0_3_0 |
| * @param opcode |
| * @return String containing proper mnemonic postfix + TAB + proper D-or-S _d,_m reg operands |
| * <p><listing> |
| * A8.6.295 VCVT, VCVTR (between floating-point and integer, VFP) |
| * vcvt{r}{@literal <c>.s32.f64 <Sd>,<Dm>} |
| * vcvt{r}{@literal <c>.s32.f32 <Sd>,<Sm>} |
| * vcvt{r}{@literal <c>.u32.f64 <Sd>,<Dm>} |
| * vcvt{r}{@literal <c>.u32.f32 <Sd>,<Sm>} |
| * {@literal vcvt<c>.f64.<Tm> <Dd>,<Sm>} |
| * {@literal vcvt<c>.f32.<Tm> <Sd>,<Sm>} |
| */ |
| private String getVFP_vcvtFpIRegOperands(int opcode) { |
| int sz = getBit(opcode, 8); |
| String ops = getVFPTdTm3(opcode, 16, 7, sz); |
| int dD = (((opcode & 0x70000) == 0) && (sz == 1)) ? 1 : 0; |
| int mD = (((opcode & 0x70000) == 0) && (sz == 1)) ? 0 : sz; |
| ops += TAB + getVFPDorSReg(opcode, dD, 12, 22) + ',' + getVFPDorSReg(opcode, mD, 0, 5); |
| return ops; |
| } |
| |
| /** |
| * ARM--- ... D_22_22 ... op_16_16 Vd___15_12 ... T___7_7 . M___5_5 . Vm___3_0<br> |
| * Thumb2 ... D_1_6_6 ... op_1_0_0 Vd_0_15_12 ... T_0_7_7 . M_0_5_5 . Vm_0_3_0 |
| * @param opcode |
| * @return String containing proper mnemonic postfix + TAB + proper Sd,Sm reg operands |
| * <p><listing> |
| * A8.6.300 VCVTB, VCVTT (between half-precision and single-precision, VFP) |
| * {@literal vcvt<y><c>.f32.f16 <Sd>, <Sm>} |
| * {@literal vcvt<y><c>.f16.f32 <Sd>, <Sm>} |
| */ |
| private String getVFP_vcvtHpSpRegOperands(int opcode) { |
| return (isBitEnabled(opcode, 16) ? ".f16.f32": ".f32.f16") |
| + TAB + getVFPDorSReg(opcode, 0, 12, 22) |
| + ',' + getVFPDorSReg(opcode, 0, 0, 5); |
| } |
| |
| /** |
| * ARM--- ... D_22_22 . . size_19_18 . . Vd___15_12 ... op___8_8 . . M___5_5 . Vm___3_0<br> |
| * Thumb2 ... D_1_6_6 . . size_1_3_2 ... Vd_0_15_12 . . op_0_8_8 . . M_0_5_5 . Vm_0_3_0 |
| * @param opcode |
| * @return String containing proper mnemonic postfix + TAB + proper Q-or-D _d,_m reg operands |
| * <p><listing> |
| * A8.6.299 VCVT (between half-precision and single-precision, Advanced SIMD) |
| * {@literal vcvt<c>.f32.f16 <Qd>, <Dm>} |
| * {@literal vcvt<c>.f16.f32 <Dd>, <Qm>} |
| */ |
| private String getVFP_vcvtHpSpVecOperands(int opcode) { |
| int sz = getBit(opcode, 8); |
| return (sz == 1 ? ".f32.f16" : ".f16.f32") |
| + TAB + getVFPQorDReg(opcode, sz, 12, 22) |
| + ',' + getVFPQorDReg(opcode, 1-sz, 0, 5); |
| } |
| |
| /** |
| * ARM--- ... b_22_22 Q_21_21 . Vd_19_16 Rt___15_12 ... D___7_7 . e___5_5 ...<br> |
| * Thumb2 ... b_1_6_6 Q_1_5_5 . Vd_1_3_0 Rt_0_15_12 ... D_0_7_7 . e_0_5_5 ... |
| * @param opcode |
| * @return String containing proper mnemonic postfix + TAB + proper Q-or-D _d,Rt reg operands |
| * <p><listing> |
| * A8.6.303 VDUP (ARM core register) |
| * {@literal vdup<c>.<size> <Qd>, <Rt>} |
| * {@literal vdup<c>.<size> <Dd>, <Rt>} |
| */ |
| private String getVFP_vdupRegOperands(int opcode) { |
| int be = getBit(opcode, 22) << 1 | getBit(opcode, 5); |
| String postfix; |
| switch (be) { |
| case 0: postfix = ".32"; break; |
| case 1: postfix = ".16"; break; |
| case 2: postfix = ".8"; break; |
| default: postfix = ".UNDEFINED"; |
| } |
| return postfix + TAB + getVFPQorDReg(opcode, getBit(opcode, 21), 16, 7) + "," + getR_12(opcode); |
| } |
| |
| /** |
| * ARM--- ... D_22_22 . . imm4_19_16 Vd___15_12 ... Q___6_6 M___5_5 . Vm___3_0<br> |
| * Thumb2 ... D_1_6_6 . . imm4_1_3_0 Vd_0_15_12 ... Q_0_6_6 M_0_5_5 . Vm_0_3_0 |
| * @param opcode |
| * @return String containing proper mnemonic postfix + TAB + proper Sd,Sm reg operands |
| * <p><listing> |
| * A8.6.302 VDUP (scalar) |
| * {@literal vdup<c>.<size> <Qd>, <Dm[x]>} |
| * {@literal vdup<c>.<size> <Dd>, <Dm[x]>} |
| */ |
| private String getVFP_vdupScalarOperands(int opcode) { |
| int x, q = getBit(opcode, 6), imm = (opcode >> 16) & 0xf; |
| String postfix; |
| if ((imm & 1) != 0) { |
| postfix = ".8"; |
| x = imm >> 1; |
| } else if ((imm & 2) != 0) { |
| postfix = ".16"; |
| x = imm >> 2; |
| } else { |
| postfix = ".32"; |
| x = imm >> 3; |
| } |
| return postfix |
| + TAB + getVFPQorDReg(opcode, q, 12, 22) |
| + ',' + getVFPQorDReg(opcode, 0, 0, 5) |
| + '[' + x + ']'; |
| } |
| |
| /** |
| * ARM--- ... D_22_22 size_21_20 Vn_19_16 Vd___15_12 0 op___10_10 L___9_9 . N___7_7 1 M___5_5 0 Vm___3_0<br> |
| * Thumb2 ... D_1_6_6 size_1_5_4 Vn_1_3_0 Vd_0_15_12 0 op_0_10_10 L_0_9_9 . N_0_7_7 1 M_0_5_5 0 Vm_0_3_0 |
| * @param opcode |
| * @param quBit shift position of q-bit/u-bit in instruction |
| * @return String containing mnemonic postfix + TAB + proper Q-or-D _d,_n,<Dm[x]> reg operands |
| * <p><listing> |
| * A8.6.325 VMLA, VMLAL, VMLS, VMLSL (by scalar) |
| * {@literal v<op><c>.<dt> <Qd>,<Qn>,<Dm[x]> v<op><c>.<dt> <Dd>,<Dn>,<Dm[x]>} |
| * {@literal v<op>l<c>.<dt> <Qd>,<Dn>,<Dm[x]>} |
| * A8.6.339 VMUL, VMULL (by scalar) |
| * {@literal vmul<c>.<dt> <Qd>,<Qn>,<Dm[x]> vmul<c>.<dt> <Dd>,<Dn>,<Dm[x]>} |
| * {@literal vmull<c>.<dt> <Qd>,<Dn>,<Dm[x]>} |
| * A8.6.360 VQDMULL |
| * {@literal vqdmull<c>.<dt> <Qd>,<Dn>,<Dm[x]>} |
| */ |
| private String getVFP_vmXXScalar(int opcode, int quBit) { |
| int dR, nR, qu = getBit(opcode, quBit); |
| String postfix; |
| |
| if (isBitEnabled(opcode, 9)) { |
| postfix = "l." + ((qu == 0) ? 's' : 'u'); |
| dR = 1; |
| nR = 0; |
| } else { |
| postfix = "." + (isBitEnabled(opcode, 8) ? 'f' : 'i'); |
| dR = nR = qu; |
| } |
| |
| return postfix + getVFPScalarOperands(opcode, dR, nR); |
| } |
| |
| /** |
| * ARM--- ... opc1_22_21 0 Vd_19_16 Rt___15_12 ... D___7_7 opc2___6_5<br> |
| * Thumb2 ... opc1_1_6_5 0 Vd_1_3_0 Rt_0_15_12 ... D_0_7_7 opc2_0_6_5 |
| * @param opcode |
| * @return String containing mnenomic type postfix + TAB + proper Dd[x],Rt reg operands |
| * A8.6.328 VMOV (ARM core register to scalar) |
| * {@literal vmov<c>.<size> <Dd[x]>, <Rt>} |
| */ |
| private String getVFP_vmovArmCoreRegToScalar(int opcode) { |
| int opc1 = opcode >> 21 & 3; |
| int opc2 = opcode >> 5 & 3; |
| int index = 0; |
| String ops = "."; |
| |
| if (isBitEnabled(opc1, 1)) { |
| ops += '8'; |
| index = getBit(opc1, 0) << 2 | opc2; |
| } else if (isBitEnabled(opc2, 0)) { |
| ops += "16"; |
| index = getBit(opc1, 0) << 1 | getBit(opc2, 1); |
| } else if (opc2 == 0) { |
| ops += "32"; |
| index = getBit(opc1, 0); |
| } |
| |
| ops += TAB + getVFPDorSReg(opcode, 1, 16, 7) |
| + '[' + index + "]," + getR_12(opcode); |
| |
| return ops; |
| } |
| |
| /** |
| * ARM--- ... op_20_20 Vn_19_16 Rt___15_12 ... N___7_7<br> |
| * Thumb2 ... op_1_4_4 Vn_1_3_0 Rt_0_15_12 ... N_0_7_7 |
| * @param opcode |
| * @return String TAB + proper Sn,Rt or Rt,Sn operands |
| * A8.6.330 VMOV (between ARM core register and single-precision register) |
| * {@literal vmov<c> <Sn>, <Rt> vmov<c> <Rt>, <Sn>} |
| */ |
| private String getVFP_vmovBetweenArmCoreAndSinglePrecReg(int opcode) { |
| String sn = getVFPDorSReg(opcode, 0, 16, 7); |
| String rt = getR_12(opcode); |
| return TAB + (isBitEnabled(opcode, 20) ? rt + ',' + sn : sn + ',' + rt); |
| } |
| |
| /** |
| * ARM--- ... op_20_20 Rt2_19_16 Rt___15_12 ... M___5_5 . Vm___3_0<br> |
| * Thumb2 ... op_1_4_4 Rt2_1_3_0 Rt_0_15_12 ... M_0_5_5 . Vm_0_3_0 |
| * @param opcode |
| * @return String TAB + proper Dm,Rt,Rt2 or Rt,Rt2,Dm reg operands |
| * <p><listing> |
| * A8.6.332 VMOV (between two ARM core registers and a doubleword extension register) |
| * {@literal vmov<c> <Dm>,<Rt>,<Rt2> vmov<c> <Rt>,<Rt2>,<Dm>} |
| */ |
| private String getVFP_vmovBetween2ArmCoreAnd1DoublewordExtensionRegs(int opcode) { |
| String dm = getVFPDorSReg(opcode, 1, 0, 5); |
| String armCoreRegs = getR_12(opcode) + ',' + getR_16(opcode); |
| if (isBitEnabled(opcode, 20)) |
| return TAB + armCoreRegs + ',' + dm; |
| else |
| return TAB + dm + ',' + armCoreRegs; |
| } |
| |
| /** |
| * ARM--- ... op_20_20 Rt2_19_16 Rt___15_12 ... M___5_5 . Vm___3_0<br> |
| * Thumb2 ... op_1_4_4 Rt2_1_3_0 Rt_0_15_12 ... M_0_5_5 . Vm_0_3_0 |
| * @param opcode |
| * @return String TAB + proper Sn,Sn+1,Rt,Rt2 or Rt,Rt2,Sn,Sn+1 reg operands |
| * <p><listing> |
| * A8.6.331 VMOV (between two ARM core registers and two single-precision registers) |
| * {@literal vmov<c> <Sm>,<Sm1>,<Rt>,<Rt2> vmov<c> <Rt>,<Rt2>,<Sm>,<Sm1>} |
| */ |
| private String getVFP_vmovBetween2ArmCoreAndSinglePrecRegs(int opcode) { |
| int vm = (opcode & 0xf) << 1 | getBit(opcode, 5); |
| String armCoreRegs = getR_12(opcode) + ',' + getR_16(opcode); |
| String singPrecRegs = "s" + vm + ",s" + (vm + 1); |
| if (isBitEnabled(opcode, 20)) |
| return TAB + armCoreRegs + ',' + singPrecRegs; |
| else |
| return TAB + singPrecRegs + ',' + armCoreRegs; |
| } |
| |
| /** |
| * ARM--- ... opc1_22_21 0 Vd_19_16 Rt___15_12 ... D___7_7 opc2___6_5<br> |
| * Thumb2 ... opc1_1_6_5 0 Vd_1_3_0 Rt_0_15_12 ... D_0_7_7 opc2_0_6_5 |
| * @param opcode |
| * @return String containing mnenomic type postfix + TAB + proper Dd[x],Rt reg operands |
| * <p><listing> |
| * A8.6.329 VMOV (scalar to ARM core register) |
| * {@literal vmov<c>.<dt> <Rt>, <Dn[x]>} |
| */ |
| private String getVFP_vmovScalarToArmCoreReg(int opcode) { |
| int opc1 = opcode >> 21 & 3; |
| int opc2 = opcode >> 5 & 3; |
| |
| boolean u = isBitEnabled(opcode, 23); |
| |
| String ops = "."; |
| |
| int index = 0; |
| if (isBitEnabled(opc1, 1)) { |
| ops += u ? "u8" : "s8"; |
| index = getBit(opc1, 0) << 2 | opc2; |
| } else if (isBitEnabled(opc2, 0)) { |
| ops += u ? "u16" : "s16"; |
| index = getBit(opc1, 0) << 1 | getBit(opc2, 1); |
| } else if (opc2 == 0) { |
| ops += "32"; |
| index = getBit(opc1, 0); |
| } |
| ops += TAB + getR_12(opcode) + ',' + getVFPDorSReg(opcode, 1, 16, 7) |
| + '[' + index + ']'; |
| |
| return ops; |
| } |
| |
| private String getVFP_vmov_vbitwise_mnemonic(int opcode) { |
| String mnemonic = ""; |
| // concatenate bit 5 op field with bits 8-11 cmode field |
| int opCmode = ((opcode >> 1) & 0x10) | (opcode >> 8) & 0xf; |
| |
| // find the instruction mnemonic |
| switch (opCmode) { |
| case 0: case 2: case 4: case 6: |
| case 8: case 10: |
| case 12: case 13: case 14: case 15: |
| case 30: |
| mnemonic = "vmov"; |
| break; |
| case 1: case 3: case 5: case 7: |
| case 9: case 11: |
| mnemonic = "vorr"; |
| break; |
| case 16: case 18: case 20: case 22: |
| case 24: case 26: |
| case 28: case 29: |
| mnemonic = "vmvn"; |
| break; |
| case 17: case 19: case 21: case 23: |
| case 25: case 27: |
| mnemonic = "vbic"; |
| break; |
| default: |
| break; |
| } |
| |
| return mnemonic + getVFPSize(opCmode); |
| } |
| |
| /** |
| * ARM--- ... D_22_22 ... imm3_18_16 Vd___15_12 cmode___11_8 . Q___6_6 . . imm4___3_0<br> |
| * Thumb2 ... D_1_6_6 ... imm3_1_2_0 Vd_0_15_12 cmode_0_11_8 . Q_0_6_6 . . imm4_0_3_0 |
| * @param opcode |
| * @param topIBit location of the I bit to place at the top of the imm8 to be constructed |
| * @return String containing the full mnemonic + TAB + proper Q-or-D _d,_m reg operands |
| * <p><listing> |
| * A8.6.277 VBIC (immediate) |
| * {@literal vbic<c>.<dt> <Qd>,#<imm> vbic<c>.<dt> <Dd>,#<imm>} |
| * A8.6.326 VMOV (immediate) |
| * {@literal vmov<c>.<dt> <Qd>,#<imm> vmov<c>.<dt> <Dd>,#<imm>} |
| * A8.6.340 VMVN (immediate) |
| * {@literal vmvn<c>.<dt> <Qd>,#<imm> vmvn<c>.<dt> <Dd>,#<imm>} |
| * A8.6.346 VORR (immediate) |
| * {@literal vorr<c>.<dt> <Qd>,#<imm> vorr<c>.<dt> <Dd>,#<imm>} |
| */ |
| private String getVFP_vmov_vbitwise_instruction(int opcode, int topIBit) { |
| int imm = getBit(opcode, topIBit) << 7 | ((opcode >> 12) & 0x70) | (opcode & 0xf); |
| return getVFP_vmov_vbitwise_mnemonic(opcode) |
| + TAB + getVFPQorDReg(opcode, getBit(opcode, 6), 12, 22) |
| + ",#" + getHexValue(imm); |
| } |
| |
| /** |
| * ARM--- ... D_22_22 imm6_21_16 Vd___15_12 ... M___5_5 . Vm___3_0<br> |
| * Thumb2 ... D_1_6_6 imm6_1_5_0 Vd_0_15_12 ... M_0_5_5 . Vm_0_3_0 |
| * @param opcode |
| * @param uBit shift position of u-bit in instruction |
| * @return String containing mnemonic data type post-fix + TAB + proper Q-or-D _d,_m reg operands |
| * + imm value for vshll instruction |
| * <p><listing> |
| * A8.6.333 VMOVL |
| * {@literal vmovl<c>.<dt> <Qd>,<Dm>} |
| * A8.6.384 VSHLL |
| * {@literal vshll<c>.<type><size> <Qd>,<Dm>,#<imm> (0 < <imm> < <size>)} |
| */ |
| private String getVFP_vmovl_vshll_operands(int opcode, int uBit) { |
| int imm6 = getVFPQImm6(opcode); |
| return getVFPSorUDataType(opcode-(imm6<<16), uBit) |
| + TAB + getVFPQorDReg(opcode, 1, 12, 22) |
| + ',' + getVFPQorDReg(opcode, 0, 0, 5) |
| + (0 == imm6 ? "" : ",#" + imm6); |
| } |
| |
| /** |
| * ARM--- ... D_22_22 ... Vd___15_12 ... imm___3_0<br> |
| * Thumb2 ... D_1_6_6 ... Vd_0_15_12 ... imm_0_3_0 |
| * @param opcode |
| * @param uBit shift position of u-bit in instruction |
| * @return String containing mnemonic data size post-fix + TAB + proper D-or-S <list> reg operands |
| * <p><listing> |
| * A8.6.354 VPOP |
| * {@literal vpop <list> (<list> is consecutive 64-bit registers)} |
| * {@literal vpop <list> (<list> is consecutive 32-bit registers)} |
| * A8.6.355 VPUSH |
| * {@literal vpush <list> (<list> is consecutive 64-bit registers)} |
| * {@literal vpush <list> (<list> is consecutive 32-bit registers)} |
| */ |
| private String getVFP_vpop_vpush_operands(int opcode) { |
| boolean is64 = isBitEnabled(opcode, 8); |
| return TAB + getVFPDorSRegList(opcode, is64); |
| } |
| |
| /** |
| * ARM--- ... D_22_22 . . size_19_18 . . Vd___15_12 ... op___7_6 M___5_5 . Vm___3_0<br> |
| * Thumb2 ... D_1_6_6 . . size_1_3_2 . . Vd_0_15_12 ... op_0_7_6 M_0_5_4 . Vm_0_3_0 |
| * @param opcode |
| * @return String containing mnemonic size postfix + TAB + proper Dd,Qm reg operands |
| * <p><listing> |
| * A8.6.361 VQMOVN |
| * vld1{@literal vqmov{u}n<c>.<type><size> <Dd>, <Qm>} |
| */ |
| private String getVFP_vqmov_instruction(int opcode) { |
| return getVFPQUNUorSType(opcode, 7, 6) + getVFPDataTypeSize((opcode >> 18 & 3)+1, 0) |
| + TAB + getVFPDdQmRegs(opcode); |
| } |
| |
| /** |
| * ARM--- ... D_22_22 imm6_21_16 Vd_15_12 1 ... op___8_8 . . M___5_5 . Vm___3_0<br> |
| * Thumb2 ... D_1_6_6 imm6_1_5_0 Vd_0_15_12 ... op_0_8_8 . . M_0_5_5 . Vm_0_3_0 |
| * @param opcode |
| * @param uBit shift position of u-bit in instruction |
| * @return String containing mnemonic postfix + TAB + proper Dd,Qm,#imm operands |
| * <p><listing> |
| * A8.6.367 VQSHL, VQSHLU (immediate) |
| * vqshl{u}{@literal <c>.<type><size> <Qd>,<Qm>,#<imm>} vqshl{u}{@literal <c>.<type><size> <Dd>,<Dm>,#<imm>} |
| */ |
| private String getVFP_vqshl_instruction(int opcode, int uBit) { |
| int l = getBit(opcode, 7); |
| int imm = l == 1 ? opcode >> 16 & 0x3f : getVFPQImm6(opcode); |
| String typeSize = getVFPQUUorSType(opcode, l, uBit, 8); |
| return typeSize + TAB + getVFPQorDdmRegs(opcode) + ",#" + imm; |
| } |
| |
| /** |
| * ARM--- ... D_22_22 imm6_21_16 Vd_15_12 1 ... op___8_8 . . M___5_5 . Vm___3_0<br> |
| * Thumb2 ... D_1_6_6 imm6_1_5_0 Vd_0_15_12 ... op_0_8_8 . . M_0_5_5 . Vm_0_3_0 |
| * @param opcode |
| * @return String containing mnemonic postfix + TAB + proper Dd,Qm,#imm operands |
| * <p><listing> |
| * A8.6.373 VREV16, VREV32, VREV64 |
| * vrev<n><c>.<size> <Qd>, <Qm> vrev<n><c>.<size> <Dd>, <Dm> |
| */ |
| private String getVFP_vrev_instruction(int opcode) { |
| int op = opcode >> 7 & 3; |
| int size = getVFPDataTypeSize(opcode, 18); |
| return (64 >> op) + "." + size + TAB + getVFPQorDdmRegs(opcode); |
| } |
| |
| /** |
| * ARM--- ... D_22_22 imm6_21_16 Vd_15_12 1 ... op___8_8 . . M___5_5 . Vm___3_0<br> |
| * Thumb2 ... D_1_6_6 imm6_1_5_0 Vd_0_15_12 ... op_0_8_8 . . M_0_5_5 . Vm_0_3_0 |
| * @param opcode |
| * @param uPos shift position of u-bit in instruction |
| * @return String containing mnemonic postfix + TAB + proper Dd,Qm,#imm operands |
| * <p><listing> |
| * A8.6.365 VQRSHRN, VQRSHRUN |
| * vqrshr{u}n{@literal <c>.<type><size> <Dd>,<Qm>,#<imm>} |
| * A8.6.368 VQSHRN, VQSHRUN |
| * vqshr{u}{@literal n<c>.<type><size> <Dd>,<Qm>,#<imm>} |
| */ |
| private String getVFP_vqXshr_instruction(int opcode, int uPos) { |
| int imm = getVFPQImm6(opcode); |
| String typeSize = ((isBitEnabled(opcode, uPos) && isBitEnabled(opcode, 8)) ? ".u" : ".s") |
| + getVFPImm6Size(opcode); |
| return ((isBitEnabled(opcode, uPos) && !isBitEnabled(opcode, 8)) ? "un" : "n") + typeSize + TAB |
| + getVFPDdQmRegs(opcode) + ",#" + getVFPImm6SHRAdj(opcode, imm); |
| } |
| |
| /** |
| * ARM--- ... D_1_6_6 imm6_1_5_0 Vd___15_12 ... L___7_7 Q___6_6 M___5_5 . Vm___3_0<br> |
| * Thumb2 ... D_1_6_6 imm6_1_5_0 Vd_0_15_12 ... L_0_7_7 Q_0_6_6 M_0_5_5 . Vm_0_3_0 |
| * @param opcode |
| * @return String containing TAB + proper Dd,{Dn1-Dnn},Dm reg operands |
| * <p><listing> |
| * A8.6.406 VTBL, VTBX |
| * {@literal v<op><c>.8 <Dd>,<list>,<Dm>} |
| */ |
| private String getVFP_vtb_instruction(int opcode) { |
| int reg = getBit(opcode, 7) << 4 | opcode >> 16 & 0xf; |
| int cnt = opcode >> 8 & 3; |
| String ops = (isBitEnabled(opcode, 6) ? "x" : "l") + ".8\t" |
| + getVFPQorDReg(opcode, 0, 12, 22) + ",{d" + reg; |
| for (int i = 1; i < cnt + 1; ++i) { |
| ops += ",d" + (reg + i); |
| } |
| ops += "}," + getVFPQorDReg(opcode, 0, 0, 5); |
| |
| return ops; |
| } |
| |
| /** |
| * ARM--- ... D_1_6_6 imm6_1_5_0 Vd___15_12 ... L___7_7 Q___6_6 M___5_5 . Vm___3_0<br> |
| * Thumb2 ... D_1_6_6 imm6_1_5_0 Vd_0_15_12 ... L_0_7_7 Q_0_6_6 M_0_5_5 . Vm_0_3_0 |
| * @param opcode |
| * @param encoded whether immediate is in the opcode or must be derived |
| * @return String containing mnemonic postfix + TAB + proper Q-or-D _d,_m,#imm operands |
| * <p><listing> |
| * A8.6.376 VRSHR |
| * {@literal vrshr<c>.<type><size> <Qd>,<Qm>,#<imm> vrshr<c>.<type><size> <Dd>,<Dm>,#<imm>} |
| * A8.6.380 VRSRA |
| * {@literal vrsra<c>.<type><size> <Qd>,<Qm>,#<imm> vrsra<c>.<type><size> <Dd>,<Dm>,#<imm>} |
| * A8.6.382 VSHL (immediate) |
| * {@literal vshl<c>.i<size> <Qd>,<Qm>,#<imm> vshl<c>.i<size> <Dd>,<Dm>,#<imm>} |
| * A8.6.385 VSHR |
| * {@literal vshr<c>.<type><size> <Qd>,<Qm>,#<imm> vshr<c>.<type><size> <Dd>,<Dm>,#<imm>} |
| * A8.6.387 VSLI |
| * {@literal vsli<c>.<size> <Qd>,<Qm>,#<imm> vsli<c>.<size> <Dd>,<Dm>,#<imm>} |
| * A8.6.389 VSRA |
| * {@literal vsra<c>.<type><size> <Qd>,<Qm>,#<imm> vsra<c>.<type><size> <Dd>,<Dm>,#<imm>} |
| * A8.6.390 VSRI |
| * {@literal vsri<c>.<size> <Qd>,<Qm>,#<imm> vsri<c>.<size> <Dd>,<Dm>,#<imm>} |
| */ |
| private String getVFP_vXrX_instruction(int opcode, boolean encoded) { |
| int l = opcode >> 7 & 1; |
| int imm = l == 1 |
| ? (encoded ? 64 - (opcode >> 16 & 0x3f) : opcode >> 16 & 0x3f) |
| : (encoded ? getVFPImm6Encoded(opcode) : getVFPImm6(opcode)); |
| return getVFPLImm6Size(opcode, l) + getVFPQorDdmRegs(opcode) + ",#" + imm; |
| } |
| |
| /** |
| * ARM--- ... D_1_6_6 imm6_1_5_0 Vd___15_12 ... M___5_5 . Vm___3_0<br> |
| * Thumb2 ... D_1_6_6 imm6_1_5_0 Vd_0_15_12 ... M_0_5_5 . Vm_0_3_0 |
| * @param opcode |
| * @return String containing mnemonic size postfix + TAB + proper Dd,Qm,#imm operands |
| * <p><listing> |
| * A8.6.377 VRSHRN |
| * {@literal vrshrn<c>.i<size> <Dd>,<Qm>,#<imm>} |
| * A8.6.386 VSHRN |
| * {@literal vshrn<c>.i<size> <Dd>,<Qm>,#<imm>} |
| */ |
| private String getVFP_vXshrn_instruction(int opcode) { |
| int imm = getVFPQImm6(opcode); |
| String size = ".i" + getVFPImm6Size(opcode); |
| return size + TAB + getVFPDdQmRegs(opcode) + ",#" + getVFPImm6SHRAdj(opcode, imm); |
| } |
| |
| /** |
| * ARM--- ... D_22_22 . . Rn_19_16 Vd___15_12 type___11_8 size___7_6 align___5_4 Rm___3_0<br> |
| * Thumb2 ... D_1_6_6 . . Rn_1_3_0 Vd_0_15_12 type_0_11_8 size_0_7_6 align_0_5_4 Rm_0_3_0 |
| * @param opcode |
| * @return String containing |
| * <p><listing> |
| * A8.6.308 VLD1 (single element to one lane) |
| * vld1{@literal <c>.<size> <list>,[<Rn>}{{@literal @<align>}}]{!} |
| * vld1{@literal <c>.<size> <list>,[<Rn>}{{@literal @<align>}}],{@literal <Rm>} |
| * A8.6.309 VLD1 (single element to all lanes) |
| * vld1{@literal <c>.<size> <list>,[<Rn>}{{@literal @<align>}}]{!} |
| * vld1{@literal <c>.<size> <list>,[<Rn>}{{@literal @<align>}}],{@literal <Rm>} |
| * A8.6.311 VLD2 (single 2-element structure to one lane) |
| * vld2{@literal <c>.<size> <list>,[<Rn>}{{@literal @<align>}}]{!} |
| * vld2{@literal <c>.<size> <list>,[<Rn>}{{@literal @<align>}}],{@literal <Rm>} |
| * A8.6.312 VLD2 (single 2-element structure to all lanes) |
| * vld2{@literal <c>.<size> <list>,[<Rn>}{{@literal @<align>}}]{!} |
| * vld2{@literal <c>.<size> <list>,[<Rn>}{{@literal @<align>}}],{@literal <Rm>} |
| * A8.6.314 VLD3 (single 3-element structure to one lane) |
| * vld3{@literal <c>.<size> <list>,[<Rn>}{{@literal @<align>}}]{!} |
| * vld3{@literal <c>.<size> <list>,[<Rn>}{{@literal @<align>}}],{@literal <Rm>} |
| * A8.6.315 VLD3 (single 3-element structure to all lanes) |
| * vld3{@literal <c>.<size> <list>,[<Rn>}{{@literal @<align>}}]{!} |
| * vld3{@literal <c>.<size> <list>,[<Rn>}{{@literal @<align>}}],{@literal <Rm>} |
| * A8.6.317 VLD4 (single 4-element structure to one lane) |
| * vld4{@literal <c>.<size> <list>,[<Rn>}{{@literal @<align>}}]{!} |
| * vld4{@literal <c>.<size> <list>,[<Rn>}{{@literal @<align>}}],{@literal <Rm>} |
| * A8.6.318 VLD4 (single 4-element structure to all lanes) |
| * vld4{@literal <c>.<size> <list>,[<Rn>}{{@literal @<align>}}]{!} |
| * vld4{@literal <c>.<size> <list>,[<Rn>}{{@literal @<align>}}],{@literal <Rm>} |
| * A8.6.392 VST1 (single element from one lane) |
| * vst1{@literal <c>.<size> <list>,[<Rn>}{{@literal @<align>}}]{!} |
| * vst1{@literal <c>.<size> <list>,[<Rn>}{{@literal @<align>}}],{@literal <Rm>} |
| * A8.6.394 VST2 (single 2-element structure from one lane) |
| * vst2{@literal <c>.<size> <list>,[<Rn>}{{@literal @<align>}}]{!} |
| * vst2{@literal <c>.<size> <list>,[<Rn>}{{@literal @<align>}}],{@literal <Rm>} |
| * A8.6.396 VST3 (single 3-element structure from one lane) |
| * vst3{@literal <c>.<size> <list>,[<Rn>}{{@literal @<align>}}]{!} |
| * vst3{@literal <c>.<size> <list>,[<Rn>}{{@literal @<align>}}],{@literal <Rm>} |
| * A8.6.398 VST4 (single 4-element structure from one lane) |
| * vst4{@literal <c>.<size> <list>,[<Rn>}{{@literal @<align>}}]{!} |
| * vst4{@literal <c>.<size> <list>,[<Rn>}{{@literal @<align>}}],{@literal <Rm>} |
| */ |
| private String getVFP_vXX_Xlane(int opcode) { |
| // careful examination of the bit patterns in the |
| // reference manual shows bits 8 & 9 determine |
| // whether "vld1", "vld2", "vld3", "vld4" |
| // or "vst1", "vst"2, "vst3" or "vst4" |
| int ver = (opcode >> 8 & 3) + 1; |
| |
| // bits 10 & 11 have double use: 0 - 2 means size for 1 lane, but 3 means all lanes |
| int sz = (opcode >> 10 & 3); // size (if not 3) for "one-lane" versions |
| |
| boolean allLanes = 3 == sz; |
| if (allLanes) |
| sz = (opcode >> 6 & 3); // "all-lanes" size |
| |
| int spacing = 1; // spacing: 1 == single, 2 == double |
| int listMembers = ver; // members in register list |
| |
| // vector and index used in all versions |
| int vecReg = getBit(opcode, 22) << 4 | (opcode >> 12 & 0xf); |
| String index = "["; |
| |
| // optional alignment string |
| String alignStr = ""; |
| |
| // initialize postfix version+size and first reg operand (index below) |
| String ops = ver + getVFPVldVstSize(sz) + TAB + "{d" + vecReg; |
| |
| // determine differences for "all-lanes" versions |
| |
| if (allLanes) { |
| boolean align = isBitEnabled(opcode, 4); |
| spacing = getBit(opcode, 5) + 1; |
| |
| index += "]"; |
| |
| // figure out the list member count, spacing and alignment string |
| if (ver == 1) { |
| // vst1 "all-lanes" list can have 1 or 2 elemnts |
| listMembers = spacing; |
| spacing = 1; |
| if (align && sz == 1) alignStr = "@16"; |
| else if (align && sz == 2) alignStr = "@32"; |
| } else if (ver == 2) { |
| if (align && sz == 0) alignStr = "@16"; |
| else if (align && sz == 1) alignStr = "@32"; |
| else if (align && sz == 2) alignStr = "@64"; |
| } else if (ver == 4) { |
| if (align && sz == 0) alignStr = "@32"; |
| else if (align && ((sz == 1) || (sz == 2))) alignStr = "@64"; |
| else if (align && sz == 3) alignStr = "@128"; |
| } |
| } else { |
| // indexAlign bits for "one-lane" versions |
| int ia = opcode >> 4 & 0xf; |
| |
| // index is "[x]", where x are these bits |
| index += (ia >> (sz+1)) + "]"; |
| |
| if (ver > 1) { |
| spacing = sz == 0 ? 1 : getBit(ia, sz) + 1; |
| } |
| |
| listMembers = ver; |
| |
| // figure out the list member count, spacing and alignment string |
| if (ver == 1) { |
| if (sz == 1 && (ia & 3) == 1) alignStr = "@16"; |
| else if (sz == 2 && (ia & 7) == 3) alignStr = "@32"; |
| } else if (ver == 2) { |
| if (sz == 0 && (ia & 1) == 1) alignStr = "@16"; |
| else if (sz == 1 && (ia & 1) == 1) alignStr = "@32"; |
| else if (sz == 2 && (ia & 3) == 1) alignStr = "@64"; |
| } else if (ver == 4) { |
| if (sz == 0 && (ia & 1) == 1) alignStr = "@32"; |
| else if (sz == 1 && (ia & 1) == 1) alignStr = "@64"; |
| else if (sz == 2) { |
| if ((ia & 3) == 1) alignStr = "@64"; |
| else if ((ia & 3) == 2) alignStr = "@128"; |
| } |
| } |
| } |
| |
| // operand generation |
| ops += index; // index determined based on lanes type |
| |
| // get each of the vreg args for each of the versions, spaced properly |
| for (int i = 1; i < listMembers; ++ i) { |
| ops += ",d" + (vecReg + spacing * i) + index; |
| } |
| |
| // complete the generation with the Rn reg |
| // + optional alignment string + the standard ending |
| ops += "},[" + getR_16(opcode) + alignStr + ']' + getVFPVldVstEnding(opcode); |
| return ops; |
| } |
| |
| /** |
| * ARM--- ... D_22_22 . . Rn_19_16 Vd___15_12 type___11_8 size___7_6 align___5_4 Rm___3_0<br> |
| * Thumb2 ... D_1_6_6 . . Rn_1_3_0 Vd_0_15_12 type_0_11_8 size_0_7_6 align_0_5_4 Rm_0_3_0 |
| * @param opcode |
| * @return String containing mnemonic c.size postfix + TAB + all operands |
| * <p><listing> |
| * A8.6.307 VLD1 (multiple single elements) |
| * vld1{@literal <c>.<size> <list>,[<Rn>}{{@literal @<align>}}]{!} |
| * vld1{@literal <c>.<size> <list>,[<Rn>}{{@literal @<align>}}],{@literal <Rm>} |
| * A8.6.310 VLD2 (multiple 2-element structures) |
| * vld2{@literal <c>.<size> <list>,[<Rn>}{{@literal @<align>}}]{!} |
| * vld2{@literal <c>.<size> <list>,[<Rn>}{{@literal @<align>}}],{@literal <Rm>} |
| * A8.6.313 VLD3 (multiple 3-element structures) |
| * vld3{@literal <c>.<size> <list>,[<Rn>}{{@literal @<align>}}]{!} |
| * vld3{@literal <c>.<size> <list>,[<Rn>}{{@literal @<align>}}],{@literal <Rm>} |
| * A8.6.316 VLD4 (multiple 4-element structures) |
| * vld4{@literal <c>.<size> <list>,[<Rn>}{{@literal @<align>}}]{!} |
| * vld4{@literal <c>.<size> <list>,[<Rn>}{{@literal @<align>}}],{@literal <Rm>} |
| * A8.6.391 VSY1 (multiple single elements) |
| * vst1{@literal <c>.<size> <list>,[<Rn>}{{@literal @<align>}}]{!} |
| * vst1{@literal <c>.<size> <list>,[<Rn>}{{@literal @<align>}}],{@literal <Rm>} |
| * A8.6.393 VST2 (multiple 2-element structures) |
| * vst2{@literal <c>.<size> <list>,[<Rn>}{{@literal @<align>}}]{!} |
| * vst2{@literal <c>.<size> <list>,[<Rn>}{{@literal @<align>}}],{@literal <Rm>} |
| * A8.6.395 VST3 (multiple 3-element structures) |
| * vst3{@literal <c>.<size> <list>,[<Rn>}{{@literal @<align>}}]{!} |
| * vst3{@literal <c>.<size> <list>,[<Rn>}{{@literal @<align>}}],{@literal <Rm>} |
| * A8.6.397 VST4 (multiple 4-element structures) |
| * vst4{@literal <c>.<size> <list>,[<Rn>}{{@literal @<align>}}]{!} |
| * vst4{@literal <c>.<size> <list>,[<Rn>}{{@literal @<align>}}],{@literal <Rm>} |
| */ |
| private String getVFP_vXX_multi(int opcode) { |
| int vecReg = (getBit(opcode, 22) << 4) | (opcode >> 12 & 0xf); |
| int type = (opcode >> 8) & 0xf; |
| int align = (opcode >> 4) & 3; |
| int size = 8 << ((opcode >> 6) & 3); |
| |
| String suffix = "1"; |
| String regList; |
| |
| switch (type) { |
| case 7: |
| suffix = "1"; |
| regList = "{d" + vecReg + "}"; |
| break; |
| case 10: |
| suffix = "1"; |
| if (vecReg + 1 > 31) |
| regList = "<register > d31>"; |
| else |
| regList = "{d" + vecReg + ",d" + (vecReg + 1) + "}"; |
| break; |
| case 6: |
| suffix = "1"; |
| if (vecReg + 2 > 31) |
| regList = "<register > d31>"; |
| else |
| regList = "{d" + vecReg + ",d" + (vecReg + 1) |
| + ",d" + (vecReg + 2) + "}"; |
| break; |
| case 2: |
| suffix = "1"; |
| if (vecReg + 3 > 31) |
| regList = "<register > d31>"; |
| else |
| regList = "{d" + vecReg + ",d" + (vecReg + 1) |
| + ",d" + (vecReg + 2) + ",d" + (vecReg + 3) + "}"; |
| break; |
| case 8: |
| suffix = "2"; |
| if (vecReg + 1 > 31) |
| regList = "<register > d31>"; |
| else |
| regList = "{d" + vecReg + ",d" + (vecReg + 1) + "}"; |
| break; |
| case 9: |
| suffix = "2"; |
| if (vecReg + 2 > 31) |
| regList = "<register > d31>"; |
| else |
| regList = "{d" + vecReg + ",d" + (vecReg + 2) + "}"; |
| break; |
| case 3: |
| suffix = "2"; |
| if (vecReg + 3 > 31) |
| regList = "<register > d31>"; |
| else |
| regList = "{d" + vecReg + ",d" + (vecReg + 1) |
| + ",d" + (vecReg + 2) + ",d" + (vecReg + 3) + "}"; |
| break; |
| case 4: |
| suffix = "3"; |
| if (vecReg + 2 > 31) |
| regList = "<register > d31>"; |
| else |
| regList = "{d" + vecReg + ",d" + (vecReg + 1) |
| + ",d" + (vecReg + 2) + "}"; |
| break; |
| case 5: |
| suffix = "3"; |
| if (vecReg + 4 > 31) |
| regList = "<register > d31>"; |
| else |
| regList = "{d" + vecReg + ",d" + (vecReg + 2) |
| + ",d" + (vecReg + 4) + "}"; |
| break; |
| case 0: |
| suffix = "4"; |
| if (vecReg + 3 > 31) |
| regList = "<register > d31>"; |
| else |
| regList = "{d" + vecReg + ",d" + (vecReg + 1) |
| + ",d" + (vecReg + 2) + ",d" + (vecReg + 3) + "}"; |
| break; |
| case 1: |
| suffix = "4"; |
| if (vecReg + 6 > 31) |
| regList = "<register > d31>"; |
| else |
| regList = "{d" + vecReg + ",d" + (vecReg + 2) |
| + ",d" + (vecReg + 4) + ",d" + (vecReg + 6) + "}"; |
| break; |
| default: |
| regList = ""; |
| } |
| |
| String alignStr = ""; |
| if (align == 1) |
| alignStr = "@64"; |
| else if (align == 2) |
| alignStr = "@128"; |
| else if (align == 3) |
| alignStr = "@256"; |
| |
| return suffix + "." + size + TAB + regList |
| + ",[" + getR_16(opcode) + alignStr + "]" |
| + getVFPVldVstEnding(opcode); |
| } |
| |
| /** |
| * ARM--- ... D_22_22 . . Rn_19_16 Vd___15_12 type___11_8 size___7_6 align___5_4 Rm___3_0<br> |
| * Thumb2 ... D_1_6_6 . . Rn_1_3_0 Vd_0_15_12 type_0_11_8 size_0_7_6 align_0_5_4 Rm_0_3_0 |
| * @param opcode |
| * @return String containing mnemonic post-coniditon postfix + TAB + all operands |
| * <p><listing> |
| * A8.6.319 VLDM |
| * vldm{mode}{@literal <c> <Rn>}{!}{@literal <list>} |
| * A8.6.399 VSTM |
| * vstm{mode}{@literal <c> <Rn>}{!}{@literal <list>} |
| */ |
| private String getVFP_vXXm(int opcode) { |
| boolean is64 = isBitEnabled(opcode, 8); |
| return TAB + getR_16(opcode) + getW(opcode) |
| + ',' + getVFPDorSRegList(opcode, is64); |
| } |
| |
| /** |
| * ARM--- ... U_23_23 D_22_22 0 1 Rn_19_16 Vd___15_12 ... imm8___7_0<br> |
| * Thumb2 ... U_1_7_7 D_1_6_6 . . Rn_1_3_0 Vd_0_15_12 ... imm8_0_7_0 |
| * @param opcode |
| * @return String containing post-condition mnemonic prefix |
| * + TAB + proper D-or-S reg & imm8 addressing mode operands |
| * <p><listing> |
| * A8.6.320 VLDR |
| * vldr{@literal <c> <Dd>, [<Rn>}{, #+/-{@literal <imm>}}] |
| * vldr{@literal <c> <Dd>, <label>} |
| * vldr{@literal <c> <Dd>, [pc,#-0] Special case} |
| * A8.6.320 VLDR |
| * vldr{@literal <c> <Sd>, [<Rn>}{, #+/-{@literal <imm>}}] |
| * vldr{@literal <c> <Sd>, <label>} |
| * vldr{@literal <c> <Sd>, [pc,#-0] Special case} |
| * A8.6.400 VSTR |
| * vldr{@literal <c> <Dd>, [<Rn>}{, #+/-{@literal <imm>}}] |
| * A8.6.400 VSTR |
| * vldr{@literal <c> <Sd>, [<Rn>}{, #+/-{@literal <imm>}}] |
| */ |
| private String getVFP_vXXr(int opcode) { |
| int ds = getBit(opcode, 8); |
| return (ds == 1 ? ".64" : ".32") |
| + TAB + getVFPDorSReg(opcode, ds, 12, 22) |
| + ',' + getAddrModeImm8(opcode); |
| } |
| |
| /** |
| * ARM--- ... D_22_22 sz_21_20 Vn_19_16 Vd___15_12 ... op___8_8 N___7_7 . M___5_5 . Vm___3_0<br> |
| * Thumb2 ... D_1_6_6 sz_1_5_4 Vn_1_3_0 Vd_0_15_12 ... op_0_8_8 N_0_7_7 . M_0_5_5 . Vm_0_3_0 |
| * @param opcode |
| * @param uBit shift position of u-bit in instruction |
| * @return "w" or "l" + type mnemonic postfix, a TAB, |
| * and then proper Q-or-D reg operands for the instruction |
| * <p><listing> |
| * A8.6.274 VADDL, VADDW |
| * {@literal vaddl<c>.<dt> <Qd>,<Dn>,<Dm> vaddw<c>.<dt>} {{@literal <Qd>}},{@literal <Qn>,<Dm>} |
| * A8.6.404 VSUBL, VSUBW |
| * {@literal vsubl<c>.<dt> <Qd>,<Dn>,<Dm> vsubw<c>.<dt>} {{@literal <Qd>}},{@literal <Qn>,<Dm>} |
| */ |
| private String getVFP_vXXXl_vXXXw(int opcode, int uBit) { |
| String ops; |
| if (isBitEnabled(opcode, 8)) { |
| ops = 'w' + getVFPSorUDataType(opcode, uBit) + TAB; |
| if (getVFPQorDRegNum(opcode, 12, 22) != getVFPQorDRegNum(opcode, 0, 5)) |
| ops += getVFPQorDReg(opcode, 1, 12, 22) + ','; |
| ops += getVFPQorDReg(opcode, 1, 16, 7); |
| } |
| else |
| ops = 'l' + getVFPSorUDataType(opcode, uBit) |
| + TAB + getVFPQorDReg(opcode, 1, 12, 22) |
| + ',' + getVFPQorDReg(opcode, 0, 16, 7); |
| return ops + ',' + getVFPQorDReg(opcode, 0, 0, 5); |
| } |
| |
| private String getB(int opcode) { |
| return isBitEnabled(opcode, 22) ? "b" : ""; |
| } |
| |
| private String getBorT(int opcode, int bitPos) { |
| return isBitEnabled(opcode, bitPos) ? "t" : "b"; |
| } |
| |
| private String getE(int opcode) { |
| return isBitEnabled(opcode, 7) ? "e" : ""; |
| } |
| |
| private String getL(int opcode) { |
| return isBitEnabled(opcode, 22) ? "l" : ""; |
| } |
| |
| private String getR(int opcode, int bitPos) { |
| return isBitEnabled(opcode, bitPos) ? "r" : ""; |
| } |
| |
| private String getS(int opcode) { |
| return isBitEnabled(opcode, 20) ? "s" : ""; |
| } |
| |
| private String getW(int opcode) { |
| return isBitEnabled(opcode, 21) ? "!" : ""; |
| } |
| |
| private String getX(int opcode, int bitPos) { |
| return isBitEnabled(opcode, bitPos) ? "x" : ""; |
| } |
| |
| private boolean isBitEnabled(int opcode, int bit) { |
| return 0 != (1 & (opcode >> bit)) ; |
| } |
| |
| private void setDefaultPCJumpProperties(boolean soleDestination) { |
| isSoleDestination = soleDestination; |
| isSubroutineAddress = false; |
| |
| // Though it's something like establishing the PC with an address, |
| // we just fake it as using Link Register, which is fine in practice. |
| addrExpression = JumpToAddress.EXPRESSION_LR; |
| } |
| |
| private int signExtend(int value, int leftmostBit, int size) { |
| if (size >= leftmostBit) |
| return value; |
| int leftmostValue = value & (1 << leftmostBit); |
| int extended = 0; |
| for (;++leftmostBit < size ;) { |
| extended = (extended << 1) + leftmostValue; |
| } |
| return extended | leftmostValue; |
| } |
| |
| } |