Commit f88e7e82 authored by whesse@chromium.org's avatar whesse@chromium.org

Add vstr and vldr floating point load and store to ARM assembler, disassembler, and simulator.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3687 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 76774115
......@@ -30,9 +30,9 @@
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
// The original source code covered by the above license above has been modified
// significantly by Google Inc.
// Copyright 2006-2008 the V8 project authors. All rights reserved.
// The original source code covered by the above license above has been
// modified significantly by Google Inc.
// Copyright 2010 the V8 project authors. All rights reserved.
#include "v8.h"
......@@ -1371,6 +1371,36 @@ void Assembler::stc2(Coprocessor coproc,
// Support for VFP.
void Assembler::vldr(const DwVfpRegister dst,
const Register base,
int offset,
const Condition cond) {
// Ddst = MEM(Rbase + offset).
// Instruction details available in ARM DDI 0406A, A8-628.
// cond(31-28) | 1101(27-24)| 1001(23-20) | Rbase(19-16) |
// Vdst(15-12) | 1011(11-8) | offset
ASSERT(CpuFeatures::IsEnabled(VFP3));
ASSERT(offset % 4 == 0);
emit(cond | 0xD9*B20 | base.code()*B16 | dst.code()*B12 |
0xB*B8 | ((offset / 4) & 255));
}
void Assembler::vstr(const DwVfpRegister src,
const Register base,
int offset,
const Condition cond) {
// MEM(Rbase + offset) = Dsrc.
// Instruction details available in ARM DDI 0406A, A8-786.
// cond(31-28) | 1101(27-24)| 1000(23-20) | | Rbase(19-16) |
// Vsrc(15-12) | 1011(11-8) | (offset/4)
ASSERT(CpuFeatures::IsEnabled(VFP3));
ASSERT(offset % 4 == 0);
emit(cond | 0xD8*B20 | base.code()*B16 | src.code()*B12 |
0xB*B8 | ((offset / 4) & 255));
}
void Assembler::vmov(const DwVfpRegister dst,
const Register src1,
const Register src2,
......
......@@ -30,9 +30,9 @@
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
// The original source code covered by the above license above has been modified
// significantly by Google Inc.
// Copyright 2006-2008 the V8 project authors. All rights reserved.
// The original source code covered by the above license above has been
// modified significantly by Google Inc.
// Copyright 2010 the V8 project authors. All rights reserved.
// A light-weight ARM Assembler
// Generates user mode instructions for the ARM architecture up to version 5
......@@ -796,6 +796,14 @@ class Assembler : public Malloced {
// However, some simple modifications can allow
// these APIs to support D16 to D31.
void vldr(const DwVfpRegister dst,
const Register base,
int offset, // Offset must be a multiple of 4.
const Condition cond = al);
void vstr(const DwVfpRegister src,
const Register base,
int offset, // Offset must be a multiple of 4.
const Condition cond = al);
void vmov(const DwVfpRegister dst,
const Register src1,
const Register src2,
......
// Copyright 2009 the V8 project authors. All rights reserved.
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
......@@ -237,6 +237,7 @@ class Instr {
inline int RnField() const { return Bits(19, 16); }
inline int RdField() const { return Bits(15, 12); }
inline int CoprocessorField() const { return Bits(11, 8); }
// Support for VFP.
// Vn(19-16) | Vd(15-12) | Vm(3-0)
inline int VnField() const { return Bits(19, 16); }
......@@ -246,6 +247,8 @@ class Instr {
inline int MField() const { return Bit(5); }
inline int DField() const { return Bit(22); }
inline int RtField() const { return Bits(15, 12); }
inline int PField() const { return Bit(24); }
inline int UField() const { return Bit(23); }
// Fields used in Data processing instructions
inline Opcode OpcodeField() const {
......@@ -296,6 +299,7 @@ class Instr {
inline bool HasB() const { return BField() == 1; }
inline bool HasW() const { return WField() == 1; }
inline bool HasL() const { return LField() == 1; }
inline bool HasU() const { return UField() == 1; }
inline bool HasSign() const { return SignField() == 1; }
inline bool HasH() const { return HField() == 1; }
inline bool HasLink() const { return LinkField() == 1; }
......
// Copyright 2007-2009 the V8 project authors. All rights reserved.
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
......@@ -998,29 +998,43 @@ void Decoder::DecodeTypeVFP(Instr* instr) {
// Decode Type 6 coprocessor instructions.
// Dm = vmov(Rt, Rt2)
// <Rt, Rt2> = vmov(Dm)
// Ddst = MEM(Rbase + 4*offset).
// MEM(Rbase + 4*offset) = Dsrc.
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) {
if (instr->CoprocessorField() != 0xB) {
Unknown(instr); // Not used by V8.
} else {
Unknown(instr); // Not used by V8.
switch (instr->OpcodeField()) {
case 0x2:
// Load and store double to two GP registers
if (instr->Bits(7, 4) != 0x1) {
Unknown(instr); // Not used by V8.
} else if (instr->HasL()) {
Format(instr, "vmov'cond 'rt, 'rn, 'Dm");
} else {
Format(instr, "vmov'cond 'Dm, 'rt, 'rn");
}
break;
case 0x8:
if (instr->HasL()) {
Format(instr, "vldr'cond 'Dd, ['rn - 4*'off8]");
} else {
Format(instr, "vstr'cond 'Dd, ['rn - 4*'off8]");
}
break;
case 0xC:
if (instr->HasL()) {
Format(instr, "vldr'cond 'Dd, ['rn + 4*'off8]");
} else {
Format(instr, "vstr'cond 'Dd, ['rn + 4*'off8]");
}
break;
default:
Unknown(instr); // Not used by V8.
break;
}
}
}
......
// Copyright 2009 the V8 project authors. All rights reserved.
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
......@@ -47,9 +47,9 @@ using ::v8::internal::ReadLine;
using ::v8::internal::DeleteArray;
// This macro provides a platform independent use of sscanf. The reason for
// SScanF not being implemented in a platform independent was through
// ::v8::internal::OS in the same way as SNPrintF is that the Windows C Run-Time
// Library does not provide vsscanf.
// SScanF not being implemented in a platform independent way through
// ::v8::internal::OS in the same way as SNPrintF is that the
// Windows C Run-Time Library does not provide vsscanf.
#define SScanF sscanf // NOLINT
// The Debugger class is used by the simulator while debugging simulated ARM
......@@ -2033,42 +2033,62 @@ void Simulator::DecodeTypeVFP(Instr* instr) {
// Decode Type 6 coprocessor instructions.
// Dm = vmov(Rt, Rt2)
// <Rt, Rt2> = vmov(Dm)
// Ddst = MEM(Rbase + 4*offset).
// MEM(Rbase + 4*offset) = Dsrc.
void Simulator::DecodeType6CoprocessorIns(Instr* instr) {
ASSERT((instr->TypeField() == 6));
int rt = instr->RtField();
int rn = instr->RnField();
int vm = instr->VmField();
if (instr->CoprocessorField() != 0xB) {
UNIMPLEMENTED(); // Not used by V8.
} else {
switch (instr->OpcodeField()) {
case 0x2:
// Load and store double to two GP registers
if (instr->Bits(7, 4) != 0x1) {
UNIMPLEMENTED(); // Not used by V8.
} else {
int rt = instr->RtField();
int rn = instr->RnField();
int vm = instr->VmField();
if (instr->HasL()) {
int32_t rt_int_value = get_sinteger_from_s_register(2*vm);
int32_t rn_int_value = get_sinteger_from_s_register(2*vm+1);
if (instr->Bit(23) == 1) {
UNIMPLEMENTED();
} 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) {
int32_t rs_val = get_register(rt);
int32_t rn_val = get_register(rn);
set_s_register_from_sinteger(2*vm, rs_val);
set_s_register_from_sinteger((2*vm+1), rn_val);
} else if (instr->Bit(20) == 1) {
int32_t rt_int_value = get_sinteger_from_s_register(2*vm);
int32_t rn_int_value = get_sinteger_from_s_register(2*vm+1);
set_register(rt, rt_int_value);
set_register(rn, rn_int_value);
set_register(rt, rt_int_value);
set_register(rn, rn_int_value);
} else {
int32_t rs_val = get_register(rt);
int32_t rn_val = get_register(rn);
set_s_register_from_sinteger(2*vm, rs_val);
set_s_register_from_sinteger((2*vm+1), rn_val);
}
}
break;
case 0x8:
case 0xC: { // Load and store double to memory.
int rn = instr->RnField();
int vd = instr->VdField();
int offset = instr->Immed8Field();
if (!instr->HasU()) {
offset = -offset;
}
int32_t address = get_register(rn) + 4 * offset;
if (instr->HasL()) {
// Load double from memory: vldr.
set_s_register_from_sinteger(2*vd, ReadW(address, instr));
set_s_register_from_sinteger(2*vd + 1, ReadW(address + 4, instr));
} else {
// Store double to memory: vstr.
WriteW(address, get_sinteger_from_s_register(2*vd), instr);
WriteW(address + 4, get_sinteger_from_s_register(2*vd + 1), instr);
}
break;
}
} else {
UNIMPLEMENTED();
default:
UNIMPLEMENTED(); // Not used by V8.
break;
}
} else if (instr->Bit(21) == 1) {
UNIMPLEMENTED();
} else {
UNIMPLEMENTED();
}
}
......
// Copyright 2006-2008 the V8 project authors. All rights reserved.
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
......@@ -224,4 +224,63 @@ TEST(3) {
}
TEST(4) {
// Test the VFP floating point instructions.
InitializeVM();
v8::HandleScope scope;
typedef struct {
double a;
double b;
double c;
} T;
T t;
// Create a function that accepts &t, and loads, manipulates, and stores
// the doubles t.a, t.b, and t.c.
Assembler assm(NULL, 0);
Label L, C;
ASSERT(CpuFeatures::IsSupported(VFP3));
if (CpuFeatures::IsSupported(VFP3)) {
CpuFeatures::Scope scope(VFP3);
__ mov(ip, Operand(sp));
__ stm(db_w, sp, r4.bit() | fp.bit() | lr.bit());
__ sub(fp, ip, Operand(4));
__ mov(r4, Operand(r0));
__ vldr(d6, r4, OFFSET_OF(T, a));
__ vldr(d7, r4, OFFSET_OF(T, b));
__ vadd(d5, d6, d7);
__ vstr(d5, r4, OFFSET_OF(T, c));
__ vmov(r2, r3, d5);
__ vmov(d4, r2, r3);
__ vstr(d4, r4, OFFSET_OF(T, b));
__ ldm(ia_w, sp, r4.bit() | fp.bit() | pc.bit());
}
CodeDesc desc;
assm.GetCode(&desc);
Object* code = Heap::CreateCode(desc,
NULL,
Code::ComputeFlags(Code::STUB),
Handle<Object>(Heap::undefined_value()));
CHECK(code->IsCode());
#ifdef DEBUG
Code::cast(code)->Print();
#endif
F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
t.a = 1.5;
t.b = 2.75;
t.c = 17.17;
Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
USE(dummy);
CHECK_EQ(4.25, t.c);
CHECK_EQ(4.25, t.b);
CHECK_EQ(1.5, t.a);
}
#undef __
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