Index: src/arm/simulator-arm.cc |
diff --git a/src/arm/simulator-arm.cc b/src/arm/simulator-arm.cc |
index 238632aea011818abbd0910608c91062109adf65..807c6047e94a4d2ee99b628e3cca182856bea5aa 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: |