Commit 0d94d7c7 authored by erik.corry@gmail.com's avatar erik.corry@gmail.com

Add vfp support on ARM. Patch from John Jozwiak.

Review URL: http://codereview.chromium.org/348019

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3292 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 3773f96e
......@@ -19,3 +19,4 @@ Rafal Krypa <rafal@krypa.net>
Rene Rebe <rene@exactcode.de>
Ryan Dahl <coldredlemur@gmail.com>
Patrick Gansterer <paroga@paroga.com>
John Jozwiak <jjozwiak@codeaurora.org>
This diff is collapsed.
......@@ -102,6 +102,57 @@ extern Register sp;
extern Register lr;
extern Register pc;
// Support for VFP registers s0 to s32 (d0 to d16).
// Note that "sN:sM" is the same as "dN/2".
extern Register s0;
extern Register s1;
extern Register s2;
extern Register s3;
extern Register s4;
extern Register s5;
extern Register s6;
extern Register s7;
extern Register s8;
extern Register s9;
extern Register s10;
extern Register s11;
extern Register s12;
extern Register s13;
extern Register s14;
extern Register s15;
extern Register s16;
extern Register s17;
extern Register s18;
extern Register s19;
extern Register s20;
extern Register s21;
extern Register s22;
extern Register s23;
extern Register s24;
extern Register s25;
extern Register s26;
extern Register s27;
extern Register s28;
extern Register s29;
extern Register s30;
extern Register s31;
extern Register d0;
extern Register d1;
extern Register d2;
extern Register d3;
extern Register d4;
extern Register d5;
extern Register d6;
extern Register d7;
extern Register d8;
extern Register d9;
extern Register d10;
extern Register d11;
extern Register d12;
extern Register d13;
extern Register d14;
extern Register d15;
// Coprocessor register
struct CRegister {
......@@ -372,6 +423,30 @@ class MemOperand BASE_EMBEDDED {
friend class Assembler;
};
// CpuFeatures keeps track of which features are supported by the target CPU.
// Supported features must be enabled by a Scope before use.
class CpuFeatures : public AllStatic {
public:
enum Feature { VFP3 = 1 };
// Detect features of the target CPU. Set safe defaults if the serializer
// is enabled (snapshots must be portable).
static void Probe();
// Check whether a feature is supported by the target CPU.
static bool IsSupported(Feature f) {
if (f == VFP3 && !FLAG_enable_vfp3) return false;
return (supported_ & (static_cast<uint64_t>(1) << f)) != 0;
}
// Check whether a feature is currently enabled.
static bool IsEnabled(Feature f) {
return (enabled_ & (static_cast<uint64_t>(1) << f)) != 0;
}
private:
static uint64_t supported_;
static uint64_t enabled_;
};
typedef int32_t Instr;
......@@ -655,6 +730,66 @@ class Assembler : public Malloced {
void stc2(Coprocessor coproc, CRegister crd, Register base, int option,
LFlag l = Short); // v5 and above
// Support for VFP.
// All these APIs support S0 to S31 and D0 to D15.
// Currently these APIs do not support extended D registers, i.e, D16 to D31.
// However, some simple modifications can allow
// these APIs to support D16 to D31.
void fmdrr(const Register dst,
const Register src1,
const Register src2,
const SBit s = LeaveCC,
const Condition cond = al);
void fmrrd(const Register dst1,
const Register dst2,
const Register src,
const SBit s = LeaveCC,
const Condition cond = al);
void fmsr(const Register dst,
const Register src,
const SBit s = LeaveCC,
const Condition cond = al);
void fmrs(const Register dst,
const Register src,
const SBit s = LeaveCC,
const Condition cond = al);
void fsitod(const Register dst,
const Register src,
const SBit s = LeaveCC,
const Condition cond = al);
void ftosid(const Register dst,
const Register src,
const SBit s = LeaveCC,
const Condition cond = al);
void faddd(const Register dst,
const Register src1,
const Register src2,
const SBit s = LeaveCC,
const Condition cond = al);
void fsubd(const Register dst,
const Register src1,
const Register src2,
const SBit s = LeaveCC,
const Condition cond = al);
void fmuld(const Register dst,
const Register src1,
const Register src2,
const SBit s = LeaveCC,
const Condition cond = al);
void fdivd(const Register dst,
const Register src1,
const Register src2,
const SBit s = LeaveCC,
const Condition cond = al);
void fcmp(const Register src1,
const Register src2,
const SBit s = LeaveCC,
const Condition cond = al);
void vmrs(const Register dst,
const Condition cond = al);
// Pseudo instructions
void nop() { mov(r0, Operand(r0)); }
......
This diff is collapsed.
......@@ -66,6 +66,28 @@ const char* Registers::Name(int reg) {
return result;
}
// Support for VFP registers s0 to s31 (d0 to d15).
// Note that "sN:sM" is the same as "dN/2"
// These register names are defined in a way to match the native disassembler
// formatting. See for example the command "objdump -d <binary file>".
const char* VFPRegisters::names_[kNumVFPRegisters] = {
"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
"s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15",
"s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23",
"s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31",
"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
"d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15",
};
const char* VFPRegisters::Name(int reg) {
const char* result;
if ((0 <= reg) && (reg < kNumVFPRegisters)) {
result = names_[reg];
} else {
result = "no_vfp_reg";
}
return result;
}
int Registers::Number(const char* name) {
// Look through the canonical names.
......
......@@ -75,6 +75,9 @@ namespace arm {
// Number of registers in normal ARM mode.
static const int kNumRegisters = 16;
// VFP support.
static const int kNumVFPRegisters = 48;
// PC is register 15.
static const int kPCRegister = 15;
static const int kNoRegister = -1;
......@@ -231,6 +234,16 @@ class Instr {
inline int RnField() const { return Bits(19, 16); }
inline int RdField() const { return Bits(15, 12); }
// Support for VFP.
// Vn(19-16) | Vd(15-12) | Vm(3-0)
inline int VnField() const { return Bits(19, 16); }
inline int VmField() const { return Bits(3, 0); }
inline int VdField() const { return Bits(15, 12); }
inline int NField() const { return Bit(7); }
inline int MField() const { return Bit(5); }
inline int DField() const { return Bit(22); }
inline int RtField() const { return Bits(15, 12); }
// Fields used in Data processing instructions
inline Opcode OpcodeField() const {
return static_cast<Opcode>(Bits(24, 21));
......@@ -315,6 +328,15 @@ class Registers {
static const RegisterAlias aliases_[];
};
// Helper functions for converting between VFP register numbers and names.
class VFPRegisters {
public:
// Return the name of the register.
static const char* Name(int reg);
private:
static const char* names_[kNumVFPRegisters];
};
} } // namespace assembler::arm
......
......@@ -33,12 +33,13 @@
#include "v8.h"
#include "cpu.h"
#include "macro-assembler.h"
namespace v8 {
namespace internal {
void CPU::Setup() {
// Nothing to do.
CpuFeatures::Probe();
}
......
......@@ -97,6 +97,10 @@ class Decoder {
// Printing of common values.
void PrintRegister(int reg);
void PrintSRegister(int reg);
void PrintDRegister(int reg);
int FormatVFPRegister(Instr* instr, const char* format);
int FormatVFPinstruction(Instr* instr, const char* format);
void PrintCondition(Instr* instr);
void PrintShiftRm(Instr* instr);
void PrintShiftImm(Instr* instr);
......@@ -121,6 +125,10 @@ class Decoder {
void DecodeType6(Instr* instr);
void DecodeType7(Instr* instr);
void DecodeUnconditional(Instr* instr);
// For VFP support.
void DecodeTypeVFP(Instr* instr);
void DecodeType6CoprocessorIns(Instr* instr);
const disasm::NameConverter& converter_;
v8::internal::Vector<char> out_buffer_;
......@@ -171,6 +179,16 @@ void Decoder::PrintRegister(int reg) {
Print(converter_.NameOfCPURegister(reg));
}
// Print the VFP S register name according to the active name converter.
void Decoder::PrintSRegister(int reg) {
Print(assembler::arm::VFPRegisters::Name(reg));
}
// Print the VFP D register name according to the active name converter.
void Decoder::PrintDRegister(int reg) {
Print(assembler::arm::VFPRegisters::Name(reg + 32));
}
// These shift names are defined in a way to match the native disassembler
// formatting. See for example the command "objdump -d <binary file>".
......@@ -290,6 +308,10 @@ int Decoder::FormatRegister(Instr* instr, const char* format) {
int reg = instr->RmField();
PrintRegister(reg);
return 2;
} else if (format[1] == 't') { // 'rt: Rt register
int reg = instr->RtField();
PrintRegister(reg);
return 2;
} else if (format[1] == 'l') {
// 'rlist: register list for load and store multiple instructions
ASSERT(STRING_STARTS_WITH(format, "rlist"));
......@@ -314,6 +336,39 @@ int Decoder::FormatRegister(Instr* instr, const char* format) {
return -1;
}
// Handle all VFP register based formatting in this function to reduce the
// complexity of FormatOption.
int Decoder::FormatVFPRegister(Instr* instr, const char* format) {
ASSERT((format[0] == 'S') || (format[0] == 'D'));
if (format[1] == 'n') {
int reg = instr->VnField();
if (format[0] == 'S') PrintSRegister(((reg << 1) | instr->NField()));
if (format[0] == 'D') PrintDRegister(reg);
return 2;
} else if (format[1] == 'm') {
int reg = instr->VmField();
if (format[0] == 'S') PrintSRegister(((reg << 1) | instr->MField()));
if (format[0] == 'D') PrintDRegister(reg);
return 2;
} else if (format[1] == 'd') {
int reg = instr->VdField();
if (format[0] == 'S') PrintSRegister(((reg << 1) | instr->DField()));
if (format[0] == 'D') PrintDRegister(reg);
return 2;
}
UNREACHABLE();
return -1;
}
int Decoder::FormatVFPinstruction(Instr* instr, const char* format) {
Print(format);
return 0;
}
// FormatOption takes a formatting string and interprets it based on
// the current instructions. The format string points to the first
......@@ -459,6 +514,13 @@ int Decoder::FormatOption(Instr* instr, const char* format) {
}
return 1;
}
case 'v': {
return FormatVFPinstruction(instr, format);
}
case 'S':
case 'D': {
return FormatVFPRegister(instr, format);
}
case 'w': { // 'w: W field of load and store instructions
if (instr->HasW()) {
Print("!");
......@@ -761,8 +823,7 @@ void Decoder::DecodeType5(Instr* instr) {
void Decoder::DecodeType6(Instr* instr) {
// Coprocessor instructions currently not supported.
Unknown(instr);
DecodeType6CoprocessorIns(instr);
}
......@@ -770,12 +831,10 @@ void Decoder::DecodeType7(Instr* instr) {
if (instr->Bit(24) == 1) {
Format(instr, "swi'cond 'swi");
} else {
// Coprocessor instructions currently not supported.
Unknown(instr);
DecodeTypeVFP(instr);
}
}
void Decoder::DecodeUnconditional(Instr* instr) {
if (instr->Bits(7, 4) == 0xB && instr->Bits(27, 25) == 0 && instr->HasL()) {
Format(instr, "'memop'h'pu 'rd, ");
......@@ -837,6 +896,138 @@ void Decoder::DecodeUnconditional(Instr* instr) {
}
// void Decoder::DecodeTypeVFP(Instr* instr)
// Implements the following
// VFP instructions
// fmsr :Sn = Rt
// fmrs :Rt = Sn
// fsitod: Dd = Sm
// ftosid: Sd = Dm
// Dd = faddd(Dn, Dm)
// Dd = fsubd(Dn, Dm)
// Dd = fmuld(Dn, Dm)
// Dd = fdivd(Dn, Dm)
// vcmp(Dd, Dm)
// VMRS
void Decoder::DecodeTypeVFP(Instr* instr) {
ASSERT((instr->TypeField() == 7) && (instr->Bit(24) == 0x0) );
if (instr->Bit(23) == 1) {
if ((instr->Bits(21, 19) == 0x7) &&
(instr->Bits(18, 16) == 0x5) &&
(instr->Bits(11, 9) == 0x5) &&
(instr->Bit(8) == 1) &&
(instr->Bit(6) == 1) &&
(instr->Bit(4) == 0)) {
Format(instr, "vcvt.s32.f64'cond 'Sd, 'Dm");
} else if ((instr->Bits(21, 19) == 0x7) &&
(instr->Bits(18, 16) == 0x0) &&
(instr->Bits(11, 9) == 0x5) &&
(instr->Bit(8) == 1) &&
(instr->Bit(7) == 1) &&
(instr->Bit(6) == 1) &&
(instr->Bit(4) == 0)) {
Format(instr, "vcvt.f64.s32'cond 'Dd, 'Sm");
} else if ((instr->Bit(21) == 0x0) &&
(instr->Bit(20) == 0x0) &&
(instr->Bits(11, 9) == 0x5) &&
(instr->Bit(8) == 1) &&
(instr->Bit(6) == 0) &&
(instr->Bit(4) == 0)) {
Format(instr, "vdiv.f64'cond 'Dd, 'Dn, 'Dm");
} else if ((instr->Bits(21, 20) == 0x3) &&
(instr->Bits(19, 16) == 0x4) &&
(instr->Bits(11, 9) == 0x5) &&
(instr->Bit(8) == 0x1) &&
(instr->Bit(6) == 0x1) &&
(instr->Bit(4) == 0x0)) {
Format(instr, "vcmp.f64'cond 'Dd, 'Dm");
} else if ((instr->Bits(23, 20) == 0xF) &&
(instr->Bits(19, 16) == 0x1) &&
(instr->Bits(11, 8) == 0xA) &&
(instr->Bits(7, 5) == 0x0) &&
(instr->Bit(4) == 0x1) &&
(instr->Bits(3, 0) == 0x0)) {
if (instr->Bits(15, 12) == 0xF)
Format(instr, "vmrs'cond APSR, FPSCR");
else
Unknown(instr); // not used by V8
} else {
Unknown(instr); // not used by V8
}
} else if (instr->Bit(21) == 1) {
if ((instr->Bit(20) == 0x1) &&
(instr->Bits(11, 9) == 0x5) &&
(instr->Bit(8) == 0x1) &&
(instr->Bit(6) == 0) &&
(instr->Bit(4) == 0)) {
Format(instr, "vadd.f64'cond 'Dd, 'Dn, 'Dm");
} else if ((instr->Bit(20) == 0x1) &&
(instr->Bits(11, 9) == 0x5) &&
(instr->Bit(8) == 0x1) &&
(instr->Bit(6) == 1) &&
(instr->Bit(4) == 0)) {
Format(instr, "vsub.f64'cond 'Dd, 'Dn, 'Dm");
} else if ((instr->Bit(20) == 0x0) &&
(instr->Bits(11, 9) == 0x5) &&
(instr->Bit(8) == 0x1) &&
(instr->Bit(6) == 0) &&
(instr->Bit(4) == 0)) {
Format(instr, "vmul.f64'cond 'Dd, 'Dn, 'Dm");
} else {
Unknown(instr); // not used by V8
}
} else {
if ((instr->Bit(20) == 0x0) &&
(instr->Bits(11, 8) == 0xA) &&
(instr->Bits(6, 5) == 0x0) &&
(instr->Bit(4) == 1) &&
(instr->Bits(3, 0) == 0x0)) {
Format(instr, "vmov'cond 'Sn, 'rt");
} else if ((instr->Bit(20) == 0x1) &&
(instr->Bits(11, 8) == 0xA) &&
(instr->Bits(6, 5) == 0x0) &&
(instr->Bit(4) == 1) &&
(instr->Bits(3, 0) == 0x0)) {
Format(instr, "vmov'cond 'rt, 'Sn");
} else {
Unknown(instr); // not used by V8
}
}
}
// Decode Type 6 coprocessor instructions
// Dm = fmdrr(Rt, Rt2)
// <Rt, Rt2> = fmrrd(Dm)
void Decoder::DecodeType6CoprocessorIns(Instr* instr) {
ASSERT((instr->TypeField() == 6));
if (instr->Bit(23) == 1) {
Unknown(instr); // not used by V8
} else if (instr->Bit(22) == 1) {
if ((instr->Bits(27, 24) == 0xC) &&
(instr->Bit(22) == 1) &&
(instr->Bits(11, 8) == 0xB) &&
(instr->Bits(7, 6) == 0x0) &&
(instr->Bit(4) == 1)) {
if (instr->Bit(20) == 0) {
Format(instr, "vmov'cond 'Dm, 'rt, 'rn");
} else if (instr->Bit(20) == 1) {
Format(instr, "vmov'cond 'rt, 'rn, 'Dm");
}
} else {
Unknown(instr); // not used by V8
}
} else if (instr->Bit(21) == 1) {
Unknown(instr); // not used by V8
} else {
Unknown(instr); // not used by V8
}
}
// Disassemble the instruction at *instr_ptr into the output buffer.
int Decoder::InstructionDecode(byte* instr_ptr) {
Instr* instr = Instr::At(instr_ptr);
......
This diff is collapsed.
......@@ -97,7 +97,6 @@ namespace arm {
class Simulator {
public:
friend class Debugger;
enum Register {
no_reg = -1,
r0 = 0, r1, r2, r3, r4, r5, r6, r7,
......@@ -105,7 +104,15 @@ class Simulator {
num_registers,
sp = 13,
lr = 14,
pc = 15
pc = 15,
s0 = 0, s1, s2, s3, s4, s5, s6, s7,
s8, s9, s10, s11, s12, s13, s14, s15,
s16, s17, s18, s19, s20, s21, s22, s23,
s24, s25, s26, s27, s28, s29, s30, s31,
num_s_registers = 32,
d0 = 0, d1, d2, d3, d4, d5, d6, d7,
d8, d9, d10, d11, d12, d13, d14, d15,
num_d_registers = 16
};
Simulator();
......@@ -121,6 +128,16 @@ class Simulator {
void set_register(int reg, int32_t value);
int32_t get_register(int reg) const;
// Support for VFP.
void set_s_register(int reg, unsigned int value);
unsigned int get_s_register(int reg) const;
void set_d_register_from_double(int dreg, const double& dbl);
double get_double_from_d_register(int dreg);
void set_s_register_from_float(int sreg, const float dbl);
float get_float_from_s_register(int sreg);
void set_s_register_from_sinteger(int reg, const int value);
int get_sinteger_from_s_register(int reg);
// Special case of set_register and get_register to access the raw PC value.
void set_pc(int32_t value);
int32_t get_pc() const;
......@@ -175,6 +192,10 @@ class Simulator {
int32_t right,
bool addition);
// Support for VFP.
void Compute_FPSCR_Flags(double val1, double val2);
void Copy_FPSCR_to_APSR();
// Helper functions to decode common "addressing" modes
int32_t GetShiftRm(Instr* instr, bool* carry_out);
int32_t GetImm(Instr* instr, bool* carry_out);
......@@ -206,6 +227,10 @@ class Simulator {
void DecodeType7(Instr* instr);
void DecodeUnconditional(Instr* instr);
// Support for VFP.
void DecodeTypeVFP(Instr* instr);
void DecodeType6CoprocessorIns(Instr* instr);
// Executes one instruction.
void InstructionDecode(Instr* instr);
......@@ -226,6 +251,20 @@ class Simulator {
bool c_flag_;
bool v_flag_;
// VFP architecture state.
unsigned int vfp_register[32/*num_s_registers*/];
bool n_flag_FPSCR_;
bool z_flag_FPSCR_;
bool c_flag_FPSCR_;
bool v_flag_FPSCR_;
// VFP FP exception flags architecture state.
bool inv_op_vfp_flag_;
bool div_zero_vfp_flag_;
bool overflow_vfp_flag_;
bool underflow_vfp_flag_;
bool inexact_vfp_flag_;
// Simulator support.
char* stack_;
bool pc_modified_;
......
......@@ -114,6 +114,8 @@ DEFINE_bool(enable_rdtsc, true,
"enable use of RDTSC instruction if available")
DEFINE_bool(enable_sahf, true,
"enable use of SAHF instruction if available (X64 only)")
DEFINE_bool(enable_vfp3, true,
"enable use of VFP3 instructions if available")
// bootstrapper.cc
DEFINE_string(expose_natives_as, NULL, "expose natives in global object")
......
......@@ -89,6 +89,46 @@ double OS::nan_value() {
}
bool OS::fgrep_vfp(const char* file_name, const char* string) {
// Simple detection of VFP at runtime for Linux.
// It is based on /proc/cpuinfo, which reveals hardware configuration
// to user-space applications. According to ARM (mid 2009), no similar
// facility is universally available on the ARM architectures,
// so it's up to individual OSes to provide such.
//
// This is written as a straight shot one pass parser
// and not using STL string and ifstream because,
// on Linux, it's reading from a (non-mmap-able)
// character special device.
FILE* f = NULL;
if (NULL == (f = fopen(file_name, "r")))
return false;
const char* what = string;
int k;
while (EOF != (k = fgetc(f))) {
if (k == *what) {
++what;
while ((*what != '\0') && (*what == fgetc(f))) {
++what;
}
if (*what == '\0') {
fclose(f);
return true;
} else {
what = string;
}
}
}
fclose(f);
// Did not find string in the file file_name.
return false;
}
int OS::ActivationFrameAlignment() {
#ifdef V8_TARGET_ARCH_ARM
// On EABI ARM targets this is required for fp correctness in the
......
......@@ -250,6 +250,9 @@ class OS {
// Returns the double constant NAN
static double nan_value();
// Support runtime detection of VFP3 on linux platforms.
static bool fgrep_vfp(const char * file_name, const char * string);
// Returns the activation frame alignment constraint or zero if
// the platform doesn't care. Guaranteed to be a power of two.
static int ActivationFrameAlignment();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment