| Index: src/arm/simulator-arm.cc
|
| diff --git a/src/arm/simulator-arm.cc b/src/arm/simulator-arm.cc
|
| index a29d461ebf55acf87c008b56e2c2fa9b6a5712a1..0fcad2101ff1f35d8b2c397f9e0bb4e63e886c54 100644
|
| --- a/src/arm/simulator-arm.cc
|
| +++ b/src/arm/simulator-arm.cc
|
| @@ -919,6 +919,54 @@ void Simulator::set_dw_register(int dreg, const int* dbl) {
|
| }
|
|
|
|
|
| +void Simulator::get_d_register(int dreg, uint64_t* value) {
|
| + ASSERT((dreg >= 0) && (dreg < DwVfpRegister::NumRegisters()));
|
| + memcpy(value, vfp_registers_ + dreg * 2, sizeof(*value));
|
| +}
|
| +
|
| +
|
| +void Simulator::set_d_register(int dreg, const uint64_t* value) {
|
| + ASSERT((dreg >= 0) && (dreg < DwVfpRegister::NumRegisters()));
|
| + memcpy(vfp_registers_ + dreg * 2, value, sizeof(*value));
|
| +}
|
| +
|
| +
|
| +void Simulator::get_d_register(int dreg, uint32_t* value) {
|
| + ASSERT((dreg >= 0) && (dreg < DwVfpRegister::NumRegisters()));
|
| + memcpy(value, vfp_registers_ + dreg * 2, sizeof(*value) * 2);
|
| +}
|
| +
|
| +
|
| +void Simulator::set_d_register(int dreg, const uint32_t* value) {
|
| + ASSERT((dreg >= 0) && (dreg < DwVfpRegister::NumRegisters()));
|
| + memcpy(vfp_registers_ + dreg * 2, value, sizeof(*value) * 2);
|
| +}
|
| +
|
| +
|
| +void Simulator::get_q_register(int qreg, uint64_t* value) {
|
| + ASSERT((qreg >= 0) && (qreg < num_q_registers));
|
| + memcpy(value, vfp_registers_ + qreg * 4, sizeof(*value) * 2);
|
| +}
|
| +
|
| +
|
| +void Simulator::set_q_register(int qreg, const uint64_t* value) {
|
| + ASSERT((qreg >= 0) && (qreg < num_q_registers));
|
| + memcpy(vfp_registers_ + qreg * 4, value, sizeof(*value) * 2);
|
| +}
|
| +
|
| +
|
| +void Simulator::get_q_register(int qreg, uint32_t* value) {
|
| + ASSERT((qreg >= 0) && (qreg < num_q_registers));
|
| + memcpy(value, vfp_registers_ + qreg * 4, sizeof(*value) * 4);
|
| +}
|
| +
|
| +
|
| +void Simulator::set_q_register(int qreg, const uint32_t* value) {
|
| + ASSERT((qreg >= 0) && (qreg < num_q_registers));
|
| + memcpy(vfp_registers_ + qreg * 4, value, sizeof(*value) * 4);
|
| +}
|
| +
|
| +
|
| // Raw access to the PC register.
|
| void Simulator::set_pc(int32_t value) {
|
| pc_modified_ = true;
|
| @@ -2596,36 +2644,148 @@ void Simulator::DecodeType3(Instruction* instr) {
|
| break;
|
| }
|
| case ia_x: {
|
| - if (instr->HasW()) {
|
| - ASSERT(instr->Bits(5, 4) == 0x1);
|
| -
|
| - if (instr->Bit(22) == 0x1) { // USAT.
|
| - int32_t sat_pos = instr->Bits(20, 16);
|
| - int32_t sat_val = (1 << sat_pos) - 1;
|
| - int32_t shift = instr->Bits(11, 7);
|
| - int32_t shift_type = instr->Bit(6);
|
| - int32_t rm_val = get_register(instr->RmValue());
|
| - if (shift_type == 0) { // LSL
|
| - rm_val <<= shift;
|
| - } else { // ASR
|
| - rm_val >>= shift;
|
| + if (instr->Bit(4) == 0) {
|
| + // Memop.
|
| + } else {
|
| + if (instr->Bit(5) == 0) {
|
| + switch (instr->Bits(22, 21)) {
|
| + case 0:
|
| + if (instr->Bit(20) == 0) {
|
| + if (instr->Bit(6) == 0) {
|
| + // Pkhbt.
|
| + uint32_t rn_val = get_register(rn);
|
| + uint32_t rm_val = get_register(instr->RmValue());
|
| + int32_t shift = instr->Bits(11, 7);
|
| + rm_val <<= shift;
|
| + set_register(rd, (rn_val & 0xFFFF) | (rm_val & 0xFFFF0000U));
|
| + } else {
|
| + // Pkhtb.
|
| + uint32_t rn_val = get_register(rn);
|
| + int32_t rm_val = get_register(instr->RmValue());
|
| + int32_t shift = instr->Bits(11, 7);
|
| + if (shift == 0) {
|
| + shift = 32;
|
| + }
|
| + rm_val >>= shift;
|
| + set_register(rd, (rn_val & 0xFFFF0000U) | (rm_val & 0xFFFF));
|
| + }
|
| + } else {
|
| + UNIMPLEMENTED();
|
| + }
|
| + break;
|
| + case 1:
|
| + UNIMPLEMENTED();
|
| + break;
|
| + case 2:
|
| + UNIMPLEMENTED();
|
| + break;
|
| + case 3: {
|
| + // Usat.
|
| + int32_t sat_pos = instr->Bits(20, 16);
|
| + int32_t sat_val = (1 << sat_pos) - 1;
|
| + int32_t shift = instr->Bits(11, 7);
|
| + int32_t shift_type = instr->Bit(6);
|
| + int32_t rm_val = get_register(instr->RmValue());
|
| + if (shift_type == 0) { // LSL
|
| + rm_val <<= shift;
|
| + } else { // ASR
|
| + rm_val >>= shift;
|
| + }
|
| + // If saturation occurs, the Q flag should be set in the CPSR.
|
| + // There is no Q flag yet, and no instruction (MRS) to read the
|
| + // CPSR directly.
|
| + if (rm_val > sat_val) {
|
| + rm_val = sat_val;
|
| + } else if (rm_val < 0) {
|
| + rm_val = 0;
|
| + }
|
| + set_register(rd, rm_val);
|
| + break;
|
| + }
|
| }
|
| - // If saturation occurs, the Q flag should be set in the CPSR.
|
| - // There is no Q flag yet, and no instruction (MRS) to read the
|
| - // CPSR directly.
|
| - if (rm_val > sat_val) {
|
| - rm_val = sat_val;
|
| - } else if (rm_val < 0) {
|
| - rm_val = 0;
|
| + } else {
|
| + switch (instr->Bits(22, 21)) {
|
| + case 0:
|
| + UNIMPLEMENTED();
|
| + break;
|
| + case 1:
|
| + UNIMPLEMENTED();
|
| + break;
|
| + case 2:
|
| + if ((instr->Bit(20) == 0) && (instr->Bits(9, 6) == 1)) {
|
| + if (instr->Bits(19, 16) == 0xF) {
|
| + // Uxtb16.
|
| + uint32_t rm_val = get_register(instr->RmValue());
|
| + int32_t rotate = instr->Bits(11, 10);
|
| + switch (rotate) {
|
| + case 0:
|
| + break;
|
| + case 1:
|
| + rm_val = (rm_val >> 8) | (rm_val << 24);
|
| + break;
|
| + case 2:
|
| + rm_val = (rm_val >> 16) | (rm_val << 16);
|
| + break;
|
| + case 3:
|
| + rm_val = (rm_val >> 24) | (rm_val << 8);
|
| + break;
|
| + }
|
| + set_register(rd,
|
| + (rm_val & 0xFF) | (rm_val & 0xFF0000));
|
| + } else {
|
| + UNIMPLEMENTED();
|
| + }
|
| + } else {
|
| + UNIMPLEMENTED();
|
| + }
|
| + break;
|
| + case 3:
|
| + if ((instr->Bit(20) == 0) && (instr->Bits(9, 6) == 1)) {
|
| + if (instr->Bits(19, 16) == 0xF) {
|
| + // Uxtb.
|
| + uint32_t rm_val = get_register(instr->RmValue());
|
| + int32_t rotate = instr->Bits(11, 10);
|
| + switch (rotate) {
|
| + case 0:
|
| + break;
|
| + case 1:
|
| + rm_val = (rm_val >> 8) | (rm_val << 24);
|
| + break;
|
| + case 2:
|
| + rm_val = (rm_val >> 16) | (rm_val << 16);
|
| + break;
|
| + case 3:
|
| + rm_val = (rm_val >> 24) | (rm_val << 8);
|
| + break;
|
| + }
|
| + set_register(rd, (rm_val & 0xFF));
|
| + } else {
|
| + // Uxtab.
|
| + uint32_t rn_val = get_register(rn);
|
| + uint32_t rm_val = get_register(instr->RmValue());
|
| + int32_t rotate = instr->Bits(11, 10);
|
| + switch (rotate) {
|
| + case 0:
|
| + break;
|
| + case 1:
|
| + rm_val = (rm_val >> 8) | (rm_val << 24);
|
| + break;
|
| + case 2:
|
| + rm_val = (rm_val >> 16) | (rm_val << 16);
|
| + break;
|
| + case 3:
|
| + rm_val = (rm_val >> 24) | (rm_val << 8);
|
| + break;
|
| + }
|
| + set_register(rd, rn_val + (rm_val & 0xFF));
|
| + }
|
| + } else {
|
| + UNIMPLEMENTED();
|
| + }
|
| + break;
|
| }
|
| - set_register(rd, rm_val);
|
| - } else { // SSAT.
|
| - UNIMPLEMENTED();
|
| }
|
| return;
|
| - } else {
|
| - Format(instr, "'memop'cond'b 'rd, ['rn], +'shift_rm");
|
| - UNIMPLEMENTED();
|
| }
|
| break;
|
| }
|
| @@ -3349,6 +3509,156 @@ void Simulator::DecodeType6CoprocessorIns(Instruction* instr) {
|
| }
|
|
|
|
|
| +void Simulator::DecodeSpecialCondition(Instruction* instr) {
|
| + switch (instr->SpecialValue()) {
|
| + case 5:
|
| + if ((instr->Bits(18, 16) == 0) && (instr->Bits(11, 6) == 0x28) &&
|
| + (instr->Bit(4) == 1)) {
|
| + // vmovl signed
|
| + int Vd = (instr->Bit(22) << 4) | instr->VdValue();
|
| + int Vm = (instr->Bit(5) << 4) | instr->VmValue();
|
| + int imm3 = instr->Bits(21, 19);
|
| + if ((imm3 != 1) && (imm3 != 2) && (imm3 != 4)) UNIMPLEMENTED();
|
| + int esize = 8 * imm3;
|
| + int elements = 64 / esize;
|
| + int8_t from[8];
|
| + get_d_register(Vm, reinterpret_cast<uint64_t*>(from));
|
| + int16_t to[8];
|
| + int e = 0;
|
| + while (e < elements) {
|
| + to[e] = from[e];
|
| + e++;
|
| + }
|
| + set_q_register(Vd, reinterpret_cast<uint64_t*>(to));
|
| + } else {
|
| + UNIMPLEMENTED();
|
| + }
|
| + break;
|
| + case 7:
|
| + if ((instr->Bits(18, 16) == 0) && (instr->Bits(11, 6) == 0x28) &&
|
| + (instr->Bit(4) == 1)) {
|
| + // vmovl unsigned
|
| + int Vd = (instr->Bit(22) << 4) | instr->VdValue();
|
| + int Vm = (instr->Bit(5) << 4) | instr->VmValue();
|
| + int imm3 = instr->Bits(21, 19);
|
| + if ((imm3 != 1) && (imm3 != 2) && (imm3 != 4)) UNIMPLEMENTED();
|
| + int esize = 8 * imm3;
|
| + int elements = 64 / esize;
|
| + uint8_t from[8];
|
| + get_d_register(Vm, reinterpret_cast<uint64_t*>(from));
|
| + uint16_t to[8];
|
| + int e = 0;
|
| + while (e < elements) {
|
| + to[e] = from[e];
|
| + e++;
|
| + }
|
| + set_q_register(Vd, reinterpret_cast<uint64_t*>(to));
|
| + } else {
|
| + UNIMPLEMENTED();
|
| + }
|
| + break;
|
| + case 8:
|
| + if (instr->Bits(21, 20) == 0) {
|
| + // vst1
|
| + int Vd = (instr->Bit(22) << 4) | instr->VdValue();
|
| + int Rn = instr->VnValue();
|
| + int type = instr->Bits(11, 8);
|
| + int Rm = instr->VmValue();
|
| + int32_t address = get_register(Rn);
|
| + int regs = 0;
|
| + switch (type) {
|
| + case nlt_1:
|
| + regs = 1;
|
| + break;
|
| + case nlt_2:
|
| + regs = 2;
|
| + break;
|
| + case nlt_3:
|
| + regs = 3;
|
| + break;
|
| + case nlt_4:
|
| + regs = 4;
|
| + break;
|
| + default:
|
| + UNIMPLEMENTED();
|
| + break;
|
| + }
|
| + int r = 0;
|
| + while (r < regs) {
|
| + uint32_t data[2];
|
| + get_d_register(Vd + r, data);
|
| + WriteW(address, data[0], instr);
|
| + WriteW(address + 4, data[1], instr);
|
| + address += 8;
|
| + r++;
|
| + }
|
| + if (Rm != 15) {
|
| + if (Rm == 13) {
|
| + set_register(Rn, address);
|
| + } else {
|
| + set_register(Rn, get_register(Rn) + get_register(Rm));
|
| + }
|
| + }
|
| + } else if (instr->Bits(21, 20) == 2) {
|
| + // vld1
|
| + int Vd = (instr->Bit(22) << 4) | instr->VdValue();
|
| + int Rn = instr->VnValue();
|
| + int type = instr->Bits(11, 8);
|
| + int Rm = instr->VmValue();
|
| + int32_t address = get_register(Rn);
|
| + int regs = 0;
|
| + switch (type) {
|
| + case nlt_1:
|
| + regs = 1;
|
| + break;
|
| + case nlt_2:
|
| + regs = 2;
|
| + break;
|
| + case nlt_3:
|
| + regs = 3;
|
| + break;
|
| + case nlt_4:
|
| + regs = 4;
|
| + break;
|
| + default:
|
| + UNIMPLEMENTED();
|
| + break;
|
| + }
|
| + int r = 0;
|
| + while (r < regs) {
|
| + uint32_t data[2];
|
| + data[0] = ReadW(address, instr);
|
| + data[1] = ReadW(address + 4, instr);
|
| + set_d_register(Vd + r, data);
|
| + address += 8;
|
| + r++;
|
| + }
|
| + if (Rm != 15) {
|
| + if (Rm == 13) {
|
| + set_register(Rn, address);
|
| + } else {
|
| + set_register(Rn, get_register(Rn) + get_register(Rm));
|
| + }
|
| + }
|
| + } else {
|
| + UNIMPLEMENTED();
|
| + }
|
| + break;
|
| + case 0xA:
|
| + case 0xB:
|
| + if ((instr->Bits(22, 20) == 5) && (instr->Bits(15, 12) == 0xf)) {
|
| + // pld: ignore instruction.
|
| + } else {
|
| + UNIMPLEMENTED();
|
| + }
|
| + break;
|
| + default:
|
| + UNIMPLEMENTED();
|
| + break;
|
| + }
|
| +}
|
| +
|
| +
|
| // Executes the current instruction.
|
| void Simulator::InstructionDecode(Instruction* instr) {
|
| if (v8::internal::FLAG_check_icache) {
|
| @@ -3365,7 +3675,7 @@ void Simulator::InstructionDecode(Instruction* instr) {
|
| PrintF(" 0x%08x %s\n", reinterpret_cast<intptr_t>(instr), buffer.start());
|
| }
|
| if (instr->ConditionField() == kSpecialCondition) {
|
| - UNIMPLEMENTED();
|
| + DecodeSpecialCondition(instr);
|
| } else if (ConditionallyExecute(instr)) {
|
| switch (instr->TypeValue()) {
|
| case 0:
|
|
|