Index: runtime/vm/simulator_arm64.cc |
=================================================================== |
--- runtime/vm/simulator_arm64.cc (revision 34712) |
+++ runtime/vm/simulator_arm64.cc (working copy) |
@@ -291,44 +291,77 @@ |
void Simulator::DecodeMoveWide(Instr* instr) { |
- UnimplementedInstruction(instr); |
+ const Register rd = instr->RdField(); |
+ const int hw = instr->HWField(); |
+ const int64_t shift = hw << 4; |
+ const int64_t shifted_imm = |
+ static_cast<uint64_t>(instr->Imm16Field()) << shift; |
+ |
+ if (instr->SFField()) { |
+ if (instr->Bits(29, 2) == 0) { |
+ // Format(instr, "movn'sf 'rd, 'imm16 'hw"); |
+ set_register(rd, ~shifted_imm, instr->RdMode()); |
+ } else if (instr->Bits(29, 2) == 2) { |
+ // Format(instr, "movz'sf 'rd, 'imm16 'hw"); |
+ set_register(rd, shifted_imm, instr->RdMode()); |
+ } else if (instr->Bits(29, 2) == 3) { |
+ // Format(instr, "movk'sf 'rd, 'imm16 'hw"); |
+ const int64_t rd_val = get_register(rd, instr->RdMode()); |
+ const int64_t result = (rd_val & ~(0xffffL << shift)) | shifted_imm; |
+ set_register(rd, result, instr->RdMode()); |
+ } else { |
+ UnimplementedInstruction(instr); |
+ } |
+ } else if ((hw & 0x2) == 0) { |
+ if (instr->Bits(29, 2) == 0) { |
+ // Format(instr, "movn'sf 'rd, 'imm16 'hw"); |
+ set_wregister(rd, ~shifted_imm & kWRegMask, instr->RdMode()); |
+ } else if (instr->Bits(29, 2) == 2) { |
+ // Format(instr, "movz'sf 'rd, 'imm16 'hw"); |
+ set_wregister(rd, shifted_imm & kWRegMask, instr->RdMode()); |
+ } else if (instr->Bits(29, 2) == 3) { |
+ // Format(instr, "movk'sf 'rd, 'imm16 'hw"); |
+ const int32_t rd_val = get_wregister(rd, instr->RdMode()); |
+ const int32_t result = (rd_val & ~(0xffffL << shift)) | shifted_imm; |
+ set_wregister(rd, result, instr->RdMode()); |
+ } else { |
+ UnimplementedInstruction(instr); |
+ } |
+ } else { |
+ // Dest is 32 bits, but shift is more than 32. |
+ UnimplementedInstruction(instr); |
+ } |
} |
void Simulator::DecodeAddSubImm(Instr* instr) { |
- switch (instr->Bit(30)) { |
- case 0: { |
- // Format(instr, "addi'sf's 'rd, 'rn, 'imm12s"); |
- const Register rd = instr->RdField(); |
- const Register rn = instr->RnField(); |
- const uint32_t imm = (instr->Bit(22) == 1) ? (instr->Imm12Field() << 12) |
- : (instr->Imm12Field()); |
- if (instr->SFField()) { |
- // 64-bit add. |
- const int64_t rn_val = get_register(rn, instr->RnMode()); |
- const int64_t alu_out = rn_val + imm; |
- set_register(rd, alu_out, instr->RdMode()); |
- if (instr->HasS()) { |
- SetNZFlagsX(alu_out); |
- SetCFlag(CarryFromX(rn_val, imm)); |
- SetVFlag(OverflowFromX(alu_out, rn_val, imm, true)); |
- } |
- } else { |
- // 32-bit add. |
- const int32_t rn_val = get_wregister(rn, instr->RnMode()); |
- const int32_t alu_out = rn_val + imm; |
- set_wregister(rd, alu_out, instr->RdMode()); |
- if (instr->HasS()) { |
- SetNZFlagsW(alu_out); |
- SetCFlag(CarryFromW(rn_val, imm)); |
- SetVFlag(OverflowFromW(alu_out, rn_val, imm, true)); |
- } |
- } |
- break; |
+ bool addition = (instr->Bit(30) == 0); |
+ // Format(instr, "addi'sf's 'rd, 'rn, 'imm12s"); |
+ // Format(instr, "subi'sf's 'rd, 'rn, 'imm12s"); |
+ const Register rd = instr->RdField(); |
+ const Register rn = instr->RnField(); |
+ const uint32_t imm = (instr->Bit(22) == 1) ? (instr->Imm12Field() << 12) |
+ : (instr->Imm12Field()); |
+ if (instr->SFField()) { |
+ // 64-bit add. |
+ const int64_t rn_val = get_register(rn, instr->RnMode()); |
+ const int64_t alu_out = addition ? (rn_val + imm) : (rn_val - imm); |
+ set_register(rd, alu_out, instr->RdMode()); |
+ if (instr->HasS()) { |
+ SetNZFlagsX(alu_out); |
+ SetCFlag(CarryFromX(rn_val, imm)); |
+ SetVFlag(OverflowFromX(alu_out, rn_val, imm, addition)); |
} |
- default: |
- UnimplementedInstruction(instr); |
- break; |
+ } else { |
+ // 32-bit add. |
+ const int32_t rn_val = get_wregister(rn, instr->RnMode()); |
+ const int32_t alu_out = addition ? (rn_val + imm) : (rn_val - imm); |
+ set_wregister(rd, alu_out, instr->RdMode()); |
+ if (instr->HasS()) { |
+ SetNZFlagsW(alu_out); |
+ SetCFlag(CarryFromW(rn_val, imm)); |
+ SetVFlag(OverflowFromW(alu_out, rn_val, imm, addition)); |
+ } |
} |
} |