/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- *vim:setts=8sts=2etsw=2tw=80:
*/ // Copyright 2011 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file.
// Defines constants and accessor classes to assemble, disassemble and // simulate ARM instructions. // // Section references in the code refer to the "ARM Architecture Reference // Manual" from July 2005 (available at http://www.arm.com/miscPDFs/14128.pdf) // // Constants for specific fields are defined in their respective named enums. // General constants are in an anonymous enum in class Instr.
// Values for the condition field as defined in section A3.2 enum Condition {
kNoCondition = -1,
eq = 0 << 28, // Z set Equal.
ne = 1 << 28, // Z clear Not equal.
cs = 2 << 28, // C set Unsigned higher or same.
cc = 3 << 28, // C clear Unsigned lower.
mi = 4 << 28, // N set Negative.
pl = 5 << 28, // N clear Positive or zero.
vs = 6 << 28, // V set Overflow.
vc = 7 << 28, // V clear No overflow.
hi = 8 << 28, // C set, Z clear Unsigned higher.
ls = 9 << 28, // C clear or Z set Unsigned lower or same.
ge = 10 << 28, // N == V Greater or equal.
lt = 11 << 28, // N != V Less than.
gt = 12 << 28, // Z clear, N == V Greater than.
le = 13 << 28, // Z set or N != V Less then or equal
al = 14 << 28, // Always.
kSpecialCondition = 15 << 28, // Special condition (refer to section A3.2.1).
kNumberOfConditions = 16,
// Aliases.
hs = cs, // C set Unsigned higher or same.
lo = cc // C clear Unsigned lower.
};
// Commute a condition such that {a cond b == b cond' a}. inline Condition CommuteCondition(Condition cond) { switch (cond) { case lo: return hi; case hi: return lo; case hs: return ls; case ls: return hs; case lt: return gt; case gt: return lt; case ge: return le; case le: return ge; default: return cond;
}
}
// Instr is merely used by the Assembler to distinguish 32bit integers // representing instructions from usual 32 bit values. // Instruction objects are pointers to 32bit values, and provide methods to // access the various ISA fields. typedef int32_t Instr;
// Opcodes for Data-processing instructions (instructions with a type 0 and 1) // as defined in section A3.4 enum Opcode { AND = 0 << 21, // Logical AND.
EOR = 1 << 21, // Logical Exclusive OR.
SUB = 2 << 21, // Subtract.
RSB = 3 << 21, // Reverse Subtract.
ADD = 4 << 21, // Add.
ADC = 5 << 21, // Add with Carry.
SBC = 6 << 21, // Subtract with Carry.
RSC = 7 << 21, // Reverse Subtract with Carry.
TST = 8 << 21, // Test.
TEQ = 9 << 21, // Test Equivalence.
CMP = 10 << 21, // Compare.
CMN = 11 << 21, // Compare Negated.
ORR = 12 << 21, // Logical (inclusive) OR.
MOV = 13 << 21, // Move.
BIC = 14 << 21, // Bit Clear.
MVN = 15 << 21// Move Not.
};
// The bits for bit 7-4 for some type 0 miscellaneous instructions. enum MiscInstructionsBits74 { // With bits 22-21 01.
BX = 1 << 4,
BXJ = 2 << 4,
BLX = 3 << 4,
BKPT = 7 << 4,
// With bits 22-21 11.
CLZ = 1 << 4
};
// Load and store exclusive instructions.
// Bit positions. enum {
ExclusiveOpHi = 24, // Hi bit of opcode field
ExclusiveOpLo = 23, // Lo bit of opcode field
ExclusiveSizeHi = 22, // Hi bit of operand size field
ExclusiveSizeLo = 21, // Lo bit of operand size field
ExclusiveLoad = 20// Bit indicating load
};
// Shifter types for Data-processing operands as defined in section A5.1.2. enum ShiftOp {
LSL = 0 << 5, // Logical shift left.
LSR = 1 << 5, // Logical shift right.
ASR = 2 << 5, // Arithmetic shift right.
ROR = 3 << 5, // Rotate right.
// RRX is encoded as ROR with shift_imm == 0. // Use a special code to make the distinction. The RRX ShiftOp is only used // as an argument, and will never actually be encoded. The Assembler will // detect it and emit the correct ROR shift operand with shift_imm == 0.
RRX = -1,
kNumberOfShifts = 4
};
// ----------------------------------------------------------------------------- // Supervisor Call (svc) specific support.
// Special Software Interrupt codes when used in the presence of the ARM // simulator. // svc (formerly swi) provides a 24bit immediate value. Use bits 22:0 for // standard SoftwareInterrupCode. Bit 23 is reserved for the stop feature. enum SoftwareInterruptCodes { // transition to C code
kCallRtRedirected = 0x10, // break point
kBreakpoint = 0x20, // stop
kStopCode = 1 << 23
}; const uint32_t kStopCodeMask = kStopCode - 1; const uint32_t kMaxStopCode = kStopCode - 1; const int32_t kDefaultStopCode = -1;
// Type of VFP register. Determines register encoding. enum VFPRegPrecision { kSinglePrecision = 0, kDoublePrecision = 1 };
// Branch hints are not used on the ARM. They are defined so that they can // appear in shared function signatures, but will be ignored in ARM // implementations. enum Hint { no_hint };
// Hints are not used on the arm. Negating is trivial. inline Hint NegateHint(Hint ignored) { return no_hint; }
// The class Instruction enables access to individual fields defined in the ARM // architecture instruction set encoding as described in figure A3-1. // Note that the Assembler uses typedef int32_t Instr. // // Example: Test whether the instruction at ptr does set the condition code // bits. // // bool InstructionSetsConditionCodes(byte* ptr) { // Instruction* instr = Instruction::At(ptr); // int type = instr->TypeValue(); // return ((type == 0) || (type == 1)) && instr->HasS(); // } // class Instruction { public: enum { kInstrSize = 4, kInstrSizeLog2 = 2, kPCReadOffset = 8 };
// Helper macro to define static accessors. // We use the cast to char* trick to bypass the strict anti-aliasing rules. # define DECLARE_STATIC_TYPED_ACCESSOR(return_type, Name) \ staticinline return_type Name(Instr instr) { \ char* temp = reinterpret_cast<char*>(&instr); \ returnreinterpret_cast<Instruction*>(temp)->Name(); \
}
// Get the raw instruction bits. inline Instr InstructionBits() const { return *reinterpret_cast<const Instr*>(this);
}
// Set the raw instruction bits to value. inlinevoid SetInstructionBits(Instr value) {
*reinterpret_cast<Instr*>(this) = value;
}
// Read one particular bit out of the instruction bits. inlineint Bit(int nr) const { return (InstructionBits() >> nr) & 1; }
// Read a bit field's value out of the instruction bits. inlineint Bits(int hi, int lo) const { return (InstructionBits() >> lo) & ((2 << (hi - lo)) - 1);
}
// Read a bit field out of the instruction bits. inlineint BitField(int hi, int lo) const { return InstructionBits() & (((2 << (hi - lo)) - 1) << lo);
}
// Static support.
// Read one particular bit out of the instruction bits. staticinlineint Bit(Instr instr, int nr) { return (instr >> nr) & 1; }
// Read the value of a bit field out of the instruction bits. staticinlineint Bits(Instr instr, int hi, int lo) { return (instr >> lo) & ((2 << (hi - lo)) - 1);
}
// Read a bit field out of the instruction bits. staticinlineint BitField(Instr instr, int hi, int lo) { return instr & (((2 << (hi - lo)) - 1) << lo);
}
// Accessors for the different named fields used in the ARM encoding. // The naming of these accessor corresponds to figure A3-1. // // Two kind of accessors are declared: // - <Name>Field() will return the raw field, i.e. the field's bits at their // original place in the instruction encoding. // e.g. if instr is the 'addgt r0, r1, r2' instruction, encoded as // 0xC0810002 ConditionField(instr) will return 0xC0000000. // - <Name>Value() will return the field value, shifted back to bit 0. // e.g. if instr is the 'addgt r0, r1, r2' instruction, encoded as // 0xC0810002 ConditionField(instr) will return 0xC.
// Fields used in Software interrupt instructions inline SoftwareInterruptCodes SvcValue() const { returnstatic_cast<SoftwareInterruptCodes>(Bits(23, 0));
}
// Test for special encodings of type 0 instructions (extra loads and stores, // as well as multiplications). inlinebool IsSpecialType0() const { return (Bit(7) == 1) && (Bit(4) == 1); }
// Test for miscellaneous instructions encodings of type 0 instructions. inlinebool IsMiscType0() const { return (Bit(24) == 1) && (Bit(23) == 0) && (Bit(20) == 0) &&
((Bit(7) == 0));
}
// Test for a nop instruction, which falls under type 1. inlinebool IsNopType1() const { return Bits(24, 0) == 0x0120F000; }
// Test for a yield instruction, which falls under type 1. inlinebool IsYieldType1() const { return Bits(24, 0) == 0x0120F001; }
// Test for a nop instruction, which falls under type 1. inlinebool IsCsdbType1() const { return Bits(24, 0) == 0x0120F014; }
// Test for a stop instruction. inlinebool IsStop() const { return (TypeValue() == 7) && (Bit(24) == 1) && (SvcValue() >= kStopCode);
}
// Decoding the double immediate in the vmov instruction. double DoubleImmedVmov() const;
// Instructions are read of out a code stream. The only way to get a // reference to an instruction is to convert a pointer. There is no way // to allocate or create instances of class Instruction. // Use the At(pc) function to create references to Instruction. static Instruction* At(uint8_t* pc) { returnreinterpret_cast<Instruction*>(pc);
}
private: // Join split register codes, depending on single or double precision. // four_bit is the position of the least-significant bit of the four // bit specifier. one_bit is the position of the additional single bit // specifier. inlineint VFPGlueRegValue(VFPRegPrecision pre, int four_bit, int one_bit) { if (pre == kSinglePrecision) { return (Bits(four_bit + 3, four_bit) << 1) | Bit(one_bit);
} return (Bit(one_bit) << 4) | Bits(four_bit + 3, four_bit);
}
// We need to prevent the creation of instances of class Instruction.
Instruction() = delete;
Instruction(const Instruction&) = delete; voidoperator=(const Instruction&) = delete;
};
// Helper functions for converting between register numbers and names. class Registers { public: // Return the name of the register. staticconstchar* Name(int reg);
// Lookup the register number for the name provided. staticint Number(constchar* name);
struct RegisterAlias { int reg; constchar* name;
};
// Helper functions for converting between VFP register numbers and names. class VFPRegisters { public: // Return the name of the register. staticconstchar* Name(int reg, bool is_double);
// Lookup the register number for the name provided. // Set flag pointed by is_double to true if register // is double-precision. staticint Number(constchar* name, bool* is_double);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.