blob: afe31db95063ec4c214049dbdb52bda4717ecbb7 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// Copyright 2012 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
Steve Blocka7e24c12009-10-30 11:49:00 +00004
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005#include <stdarg.h>
Steve Blocka7e24c12009-10-30 11:49:00 +00006#include <stdlib.h>
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007#include <cmath>
Steve Blocka7e24c12009-10-30 11:49:00 +00008
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009#if V8_TARGET_ARCH_ARM
10
11#include "src/arm/constants-arm.h"
12#include "src/arm/simulator-arm.h"
13#include "src/assembler.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014#include "src/base/bits.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015#include "src/codegen.h"
16#include "src/disasm.h"
Ben Murdoch097c5b22016-05-18 11:27:45 +010017#include "src/runtime/runtime-utils.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000018
John Reck59135872010-11-02 12:39:01 -070019#if defined(USE_SIMULATOR)
Steve Blocka7e24c12009-10-30 11:49:00 +000020
21// Only build the simulator if not compiling for real ARM hardware.
Steve Block1e0659c2011-05-24 12:43:12 +010022namespace v8 {
23namespace internal {
Steve Blocka7e24c12009-10-30 11:49:00 +000024
25// This macro provides a platform independent use of sscanf. The reason for
Leon Clarked91b9f72010-01-27 17:25:45 +000026// SScanF not being implemented in a platform independent way through
27// ::v8::internal::OS in the same way as SNPrintF is that the
28// Windows C Run-Time Library does not provide vsscanf.
Steve Blocka7e24c12009-10-30 11:49:00 +000029#define SScanF sscanf // NOLINT
30
Steve Block44f0eee2011-05-26 01:26:41 +010031// The ArmDebugger class is used by the simulator while debugging simulated ARM
Steve Blocka7e24c12009-10-30 11:49:00 +000032// code.
Steve Block44f0eee2011-05-26 01:26:41 +010033class ArmDebugger {
Steve Blocka7e24c12009-10-30 11:49:00 +000034 public:
Ben Murdoch3ef787d2012-04-12 10:51:47 +010035 explicit ArmDebugger(Simulator* sim) : sim_(sim) { }
Steve Block44f0eee2011-05-26 01:26:41 +010036 ~ArmDebugger();
Steve Blocka7e24c12009-10-30 11:49:00 +000037
Steve Block1e0659c2011-05-24 12:43:12 +010038 void Stop(Instruction* instr);
Steve Blocka7e24c12009-10-30 11:49:00 +000039 void Debug();
40
41 private:
Steve Block1e0659c2011-05-24 12:43:12 +010042 static const Instr kBreakpointInstr =
43 (al | (7*B25) | (1*B24) | kBreakpoint);
44 static const Instr kNopInstr = (al | (13*B21));
Steve Blocka7e24c12009-10-30 11:49:00 +000045
46 Simulator* sim_;
47
48 int32_t GetRegisterValue(int regnum);
Ben Murdoch8b112d22011-06-08 16:22:53 +010049 double GetRegisterPairDoubleValue(int regnum);
Ben Murdochb0fe1622011-05-05 13:52:32 +010050 double GetVFPDoubleRegisterValue(int regnum);
Steve Blocka7e24c12009-10-30 11:49:00 +000051 bool GetValue(const char* desc, int32_t* value);
Steve Block6ded16b2010-05-10 14:33:55 +010052 bool GetVFPSingleValue(const char* desc, float* value);
53 bool GetVFPDoubleValue(const char* desc, double* value);
Steve Blocka7e24c12009-10-30 11:49:00 +000054
55 // Set or delete a breakpoint. Returns true if successful.
Steve Block1e0659c2011-05-24 12:43:12 +010056 bool SetBreakpoint(Instruction* breakpc);
57 bool DeleteBreakpoint(Instruction* breakpc);
Steve Blocka7e24c12009-10-30 11:49:00 +000058
59 // Undo and redo all breakpoints. This is needed to bracket disassembly and
60 // execution to skip past breakpoints when run from the debugger.
61 void UndoBreakpoints();
62 void RedoBreakpoints();
63};
64
65
Steve Block44f0eee2011-05-26 01:26:41 +010066ArmDebugger::~ArmDebugger() {
Steve Blocka7e24c12009-10-30 11:49:00 +000067}
68
69
70
71#ifdef GENERATED_CODE_COVERAGE
72static FILE* coverage_log = NULL;
73
74
75static void InitializeCoverage() {
76 char* file_name = getenv("V8_GENERATED_CODE_COVERAGE_LOG");
77 if (file_name != NULL) {
78 coverage_log = fopen(file_name, "aw+");
79 }
80}
81
82
Steve Block44f0eee2011-05-26 01:26:41 +010083void ArmDebugger::Stop(Instruction* instr) {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -080084 // Get the stop code.
Steve Block1e0659c2011-05-24 12:43:12 +010085 uint32_t code = instr->SvcValue() & kStopCodeMask;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -080086 // Retrieve the encoded address, which comes just after this stop.
87 char** msg_address =
Steve Block1e0659c2011-05-24 12:43:12 +010088 reinterpret_cast<char**>(sim_->get_pc() + Instruction::kInstrSize);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -080089 char* msg = *msg_address;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000090 DCHECK(msg != NULL);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -080091
92 // Update this stop description.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000093 if (isWatchedStop(code) && !watched_stops_[code].desc) {
94 watched_stops_[code].desc = msg;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -080095 }
96
97 if (strlen(msg) > 0) {
Steve Blocka7e24c12009-10-30 11:49:00 +000098 if (coverage_log != NULL) {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -080099 fprintf(coverage_log, "%s\n", msg);
Steve Blocka7e24c12009-10-30 11:49:00 +0000100 fflush(coverage_log);
101 }
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800102 // Overwrite the instruction and address with nops.
103 instr->SetInstructionBits(kNopInstr);
Steve Block1e0659c2011-05-24 12:43:12 +0100104 reinterpret_cast<Instruction*>(msg_address)->SetInstructionBits(kNopInstr);
Steve Blocka7e24c12009-10-30 11:49:00 +0000105 }
Steve Block1e0659c2011-05-24 12:43:12 +0100106 sim_->set_pc(sim_->get_pc() + 2 * Instruction::kInstrSize);
Steve Blocka7e24c12009-10-30 11:49:00 +0000107}
108
109#else // ndef GENERATED_CODE_COVERAGE
110
111static void InitializeCoverage() {
112}
113
114
Steve Block44f0eee2011-05-26 01:26:41 +0100115void ArmDebugger::Stop(Instruction* instr) {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800116 // Get the stop code.
Steve Block1e0659c2011-05-24 12:43:12 +0100117 uint32_t code = instr->SvcValue() & kStopCodeMask;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800118 // Retrieve the encoded address, which comes just after this stop.
Steve Block1e0659c2011-05-24 12:43:12 +0100119 char* msg = *reinterpret_cast<char**>(sim_->get_pc()
120 + Instruction::kInstrSize);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800121 // Update this stop description.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000122 if (sim_->isWatchedStop(code) && !sim_->watched_stops_[code].desc) {
123 sim_->watched_stops_[code].desc = msg;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800124 }
Steve Block1e0659c2011-05-24 12:43:12 +0100125 // Print the stop message and code if it is not the default code.
126 if (code != kMaxStopCode) {
127 PrintF("Simulator hit stop %u: %s\n", code, msg);
128 } else {
129 PrintF("Simulator hit %s\n", msg);
130 }
131 sim_->set_pc(sim_->get_pc() + 2 * Instruction::kInstrSize);
Steve Blocka7e24c12009-10-30 11:49:00 +0000132 Debug();
133}
134#endif
135
136
Steve Block44f0eee2011-05-26 01:26:41 +0100137int32_t ArmDebugger::GetRegisterValue(int regnum) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000138 if (regnum == kPCRegister) {
139 return sim_->get_pc();
140 } else {
141 return sim_->get_register(regnum);
142 }
143}
144
145
Ben Murdoch8b112d22011-06-08 16:22:53 +0100146double ArmDebugger::GetRegisterPairDoubleValue(int regnum) {
147 return sim_->get_double_from_register_pair(regnum);
148}
149
150
Steve Block44f0eee2011-05-26 01:26:41 +0100151double ArmDebugger::GetVFPDoubleRegisterValue(int regnum) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100152 return sim_->get_double_from_d_register(regnum);
153}
154
155
Steve Block44f0eee2011-05-26 01:26:41 +0100156bool ArmDebugger::GetValue(const char* desc, int32_t* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000157 int regnum = Registers::Number(desc);
158 if (regnum != kNoRegister) {
159 *value = GetRegisterValue(regnum);
160 return true;
161 } else {
Steve Block6ded16b2010-05-10 14:33:55 +0100162 if (strncmp(desc, "0x", 2) == 0) {
163 return SScanF(desc + 2, "%x", reinterpret_cast<uint32_t*>(value)) == 1;
164 } else {
165 return SScanF(desc, "%u", reinterpret_cast<uint32_t*>(value)) == 1;
166 }
167 }
168 return false;
169}
170
171
Steve Block44f0eee2011-05-26 01:26:41 +0100172bool ArmDebugger::GetVFPSingleValue(const char* desc, float* value) {
Steve Block6ded16b2010-05-10 14:33:55 +0100173 bool is_double;
174 int regnum = VFPRegisters::Number(desc, &is_double);
175 if (regnum != kNoRegister && !is_double) {
176 *value = sim_->get_float_from_s_register(regnum);
177 return true;
178 }
179 return false;
180}
181
182
Steve Block44f0eee2011-05-26 01:26:41 +0100183bool ArmDebugger::GetVFPDoubleValue(const char* desc, double* value) {
Steve Block6ded16b2010-05-10 14:33:55 +0100184 bool is_double;
185 int regnum = VFPRegisters::Number(desc, &is_double);
186 if (regnum != kNoRegister && is_double) {
187 *value = sim_->get_double_from_d_register(regnum);
188 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +0000189 }
190 return false;
191}
192
193
Steve Block44f0eee2011-05-26 01:26:41 +0100194bool ArmDebugger::SetBreakpoint(Instruction* breakpc) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000195 // Check if a breakpoint can be set. If not return without any side-effects.
196 if (sim_->break_pc_ != NULL) {
197 return false;
198 }
199
200 // Set the breakpoint.
201 sim_->break_pc_ = breakpc;
202 sim_->break_instr_ = breakpc->InstructionBits();
203 // Not setting the breakpoint instruction in the code itself. It will be set
204 // when the debugger shell continues.
205 return true;
206}
207
208
Steve Block44f0eee2011-05-26 01:26:41 +0100209bool ArmDebugger::DeleteBreakpoint(Instruction* breakpc) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000210 if (sim_->break_pc_ != NULL) {
211 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
212 }
213
214 sim_->break_pc_ = NULL;
215 sim_->break_instr_ = 0;
216 return true;
217}
218
219
Steve Block44f0eee2011-05-26 01:26:41 +0100220void ArmDebugger::UndoBreakpoints() {
Steve Blocka7e24c12009-10-30 11:49:00 +0000221 if (sim_->break_pc_ != NULL) {
222 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
223 }
224}
225
226
Steve Block44f0eee2011-05-26 01:26:41 +0100227void ArmDebugger::RedoBreakpoints() {
Steve Blocka7e24c12009-10-30 11:49:00 +0000228 if (sim_->break_pc_ != NULL) {
229 sim_->break_pc_->SetInstructionBits(kBreakpointInstr);
230 }
231}
232
233
Steve Block44f0eee2011-05-26 01:26:41 +0100234void ArmDebugger::Debug() {
Steve Blocka7e24c12009-10-30 11:49:00 +0000235 intptr_t last_pc = -1;
236 bool done = false;
237
238#define COMMAND_SIZE 63
239#define ARG_SIZE 255
240
241#define STR(a) #a
242#define XSTR(a) STR(a)
243
244 char cmd[COMMAND_SIZE + 1];
245 char arg1[ARG_SIZE + 1];
246 char arg2[ARG_SIZE + 1];
Steve Block6ded16b2010-05-10 14:33:55 +0100247 char* argv[3] = { cmd, arg1, arg2 };
Steve Blocka7e24c12009-10-30 11:49:00 +0000248
249 // make sure to have a proper terminating character if reaching the limit
250 cmd[COMMAND_SIZE] = 0;
251 arg1[ARG_SIZE] = 0;
252 arg2[ARG_SIZE] = 0;
253
254 // Undo all set breakpoints while running in the debugger shell. This will
255 // make them invisible to all commands.
256 UndoBreakpoints();
257
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000258 while (!done && !sim_->has_bad_pc()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000259 if (last_pc != sim_->get_pc()) {
260 disasm::NameConverter converter;
261 disasm::Disassembler dasm(converter);
262 // use a reasonably large buffer
263 v8::internal::EmbeddedVector<char, 256> buffer;
264 dasm.InstructionDecode(buffer,
265 reinterpret_cast<byte*>(sim_->get_pc()));
266 PrintF(" 0x%08x %s\n", sim_->get_pc(), buffer.start());
267 last_pc = sim_->get_pc();
268 }
269 char* line = ReadLine("sim> ");
270 if (line == NULL) {
271 break;
272 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100273 char* last_input = sim_->last_debugger_input();
274 if (strcmp(line, "\n") == 0 && last_input != NULL) {
275 line = last_input;
276 } else {
277 // Ownership is transferred to sim_;
278 sim_->set_last_debugger_input(line);
279 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000280 // Use sscanf to parse the individual parts of the command line. At the
281 // moment no command expects more than two parameters.
Steve Block6ded16b2010-05-10 14:33:55 +0100282 int argc = SScanF(line,
Steve Blocka7e24c12009-10-30 11:49:00 +0000283 "%" XSTR(COMMAND_SIZE) "s "
284 "%" XSTR(ARG_SIZE) "s "
285 "%" XSTR(ARG_SIZE) "s",
286 cmd, arg1, arg2);
287 if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
Steve Block1e0659c2011-05-24 12:43:12 +0100288 sim_->InstructionDecode(reinterpret_cast<Instruction*>(sim_->get_pc()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000289 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) {
290 // Execute the one instruction we broke at with breakpoints disabled.
Steve Block1e0659c2011-05-24 12:43:12 +0100291 sim_->InstructionDecode(reinterpret_cast<Instruction*>(sim_->get_pc()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000292 // Leave the debugger shell.
293 done = true;
294 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100295 if (argc == 2 || (argc == 3 && strcmp(arg2, "fp") == 0)) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000296 int32_t value;
Steve Block6ded16b2010-05-10 14:33:55 +0100297 float svalue;
298 double dvalue;
Steve Blocka7e24c12009-10-30 11:49:00 +0000299 if (strcmp(arg1, "all") == 0) {
300 for (int i = 0; i < kNumRegisters; i++) {
301 value = GetRegisterValue(i);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100302 PrintF(
303 "%3s: 0x%08x %10d",
304 RegisterConfiguration::Crankshaft()->GetGeneralRegisterName(
305 i),
306 value, value);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100307 if ((argc == 3 && strcmp(arg2, "fp") == 0) &&
308 i < 8 &&
309 (i % 2) == 0) {
310 dvalue = GetRegisterPairDoubleValue(i);
311 PrintF(" (%f)\n", dvalue);
312 } else {
313 PrintF("\n");
314 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000315 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000316 for (int i = 0; i < DwVfpRegister::NumRegisters(); i++) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100317 dvalue = GetVFPDoubleRegisterValue(i);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000318 uint64_t as_words = bit_cast<uint64_t>(dvalue);
Steve Block44f0eee2011-05-26 01:26:41 +0100319 PrintF("%3s: %f 0x%08x %08x\n",
320 VFPRegisters::Name(i, true),
321 dvalue,
322 static_cast<uint32_t>(as_words >> 32),
323 static_cast<uint32_t>(as_words & 0xffffffff));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100324 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000325 } else {
326 if (GetValue(arg1, &value)) {
327 PrintF("%s: 0x%08x %d \n", arg1, value, value);
Steve Block6ded16b2010-05-10 14:33:55 +0100328 } else if (GetVFPSingleValue(arg1, &svalue)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000329 uint32_t as_word = bit_cast<uint32_t>(svalue);
Steve Block44f0eee2011-05-26 01:26:41 +0100330 PrintF("%s: %f 0x%08x\n", arg1, svalue, as_word);
Steve Block6ded16b2010-05-10 14:33:55 +0100331 } else if (GetVFPDoubleValue(arg1, &dvalue)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000332 uint64_t as_words = bit_cast<uint64_t>(dvalue);
Steve Block44f0eee2011-05-26 01:26:41 +0100333 PrintF("%s: %f 0x%08x %08x\n",
334 arg1,
335 dvalue,
336 static_cast<uint32_t>(as_words >> 32),
337 static_cast<uint32_t>(as_words & 0xffffffff));
Steve Blocka7e24c12009-10-30 11:49:00 +0000338 } else {
339 PrintF("%s unrecognized\n", arg1);
340 }
341 }
342 } else {
343 PrintF("print <register>\n");
344 }
345 } else if ((strcmp(cmd, "po") == 0)
346 || (strcmp(cmd, "printobject") == 0)) {
Steve Block6ded16b2010-05-10 14:33:55 +0100347 if (argc == 2) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000348 int32_t value;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000349 OFStream os(stdout);
Steve Blocka7e24c12009-10-30 11:49:00 +0000350 if (GetValue(arg1, &value)) {
351 Object* obj = reinterpret_cast<Object*>(value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000352 os << arg1 << ": \n";
Steve Blocka7e24c12009-10-30 11:49:00 +0000353#ifdef DEBUG
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000354 obj->Print(os);
355 os << "\n";
Steve Blocka7e24c12009-10-30 11:49:00 +0000356#else
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000357 os << Brief(obj) << "\n";
Steve Blocka7e24c12009-10-30 11:49:00 +0000358#endif
359 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000360 os << arg1 << " unrecognized\n";
Steve Blocka7e24c12009-10-30 11:49:00 +0000361 }
362 } else {
363 PrintF("printobject <value>\n");
364 }
Steve Block6ded16b2010-05-10 14:33:55 +0100365 } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0) {
366 int32_t* cur = NULL;
367 int32_t* end = NULL;
368 int next_arg = 1;
369
370 if (strcmp(cmd, "stack") == 0) {
371 cur = reinterpret_cast<int32_t*>(sim_->get_register(Simulator::sp));
372 } else { // "mem"
373 int32_t value;
374 if (!GetValue(arg1, &value)) {
375 PrintF("%s unrecognized\n", arg1);
376 continue;
377 }
378 cur = reinterpret_cast<int32_t*>(value);
379 next_arg++;
380 }
381
382 int32_t words;
383 if (argc == next_arg) {
384 words = 10;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000385 } else {
Steve Block6ded16b2010-05-10 14:33:55 +0100386 if (!GetValue(argv[next_arg], &words)) {
387 words = 10;
388 }
389 }
390 end = cur + words;
391
392 while (cur < end) {
Ben Murdochc5610432016-08-08 18:44:38 +0100393 PrintF(" 0x%08" V8PRIxPTR ": 0x%08x %10d",
Ben Murdochf87a2032010-10-22 12:50:53 +0100394 reinterpret_cast<intptr_t>(cur), *cur, *cur);
Steve Block44f0eee2011-05-26 01:26:41 +0100395 HeapObject* obj = reinterpret_cast<HeapObject*>(*cur);
396 int value = *cur;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000397 Heap* current_heap = sim_->isolate_->heap();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100398 if (((value & 1) == 0) ||
399 current_heap->ContainsSlow(obj->address())) {
Steve Block44f0eee2011-05-26 01:26:41 +0100400 PrintF(" (");
401 if ((value & 1) == 0) {
402 PrintF("smi %d", value / 2);
403 } else {
404 obj->ShortPrint();
405 }
406 PrintF(")");
407 }
408 PrintF("\n");
Steve Block6ded16b2010-05-10 14:33:55 +0100409 cur++;
410 }
Steve Block44f0eee2011-05-26 01:26:41 +0100411 } else if (strcmp(cmd, "disasm") == 0 || strcmp(cmd, "di") == 0) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000412 disasm::NameConverter converter;
413 disasm::Disassembler dasm(converter);
414 // use a reasonably large buffer
415 v8::internal::EmbeddedVector<char, 256> buffer;
416
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800417 byte* prev = NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +0000418 byte* cur = NULL;
419 byte* end = NULL;
420
Steve Block6ded16b2010-05-10 14:33:55 +0100421 if (argc == 1) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000422 cur = reinterpret_cast<byte*>(sim_->get_pc());
Steve Block1e0659c2011-05-24 12:43:12 +0100423 end = cur + (10 * Instruction::kInstrSize);
Steve Block6ded16b2010-05-10 14:33:55 +0100424 } else if (argc == 2) {
Steve Block44f0eee2011-05-26 01:26:41 +0100425 int regnum = Registers::Number(arg1);
426 if (regnum != kNoRegister || strncmp(arg1, "0x", 2) == 0) {
427 // The argument is an address or a register name.
428 int32_t value;
429 if (GetValue(arg1, &value)) {
430 cur = reinterpret_cast<byte*>(value);
431 // Disassemble 10 instructions at <arg1>.
432 end = cur + (10 * Instruction::kInstrSize);
433 }
434 } else {
435 // The argument is the number of instructions.
436 int32_t value;
437 if (GetValue(arg1, &value)) {
438 cur = reinterpret_cast<byte*>(sim_->get_pc());
439 // Disassemble <arg1> instructions.
440 end = cur + (value * Instruction::kInstrSize);
441 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000442 }
443 } else {
444 int32_t value1;
445 int32_t value2;
446 if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
447 cur = reinterpret_cast<byte*>(value1);
Steve Block1e0659c2011-05-24 12:43:12 +0100448 end = cur + (value2 * Instruction::kInstrSize);
Steve Blocka7e24c12009-10-30 11:49:00 +0000449 }
450 }
451
452 while (cur < end) {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800453 prev = cur;
454 cur += dasm.InstructionDecode(buffer, cur);
Ben Murdochc5610432016-08-08 18:44:38 +0100455 PrintF(" 0x%08" V8PRIxPTR " %s\n", reinterpret_cast<intptr_t>(prev),
456 buffer.start());
Steve Blocka7e24c12009-10-30 11:49:00 +0000457 }
458 } else if (strcmp(cmd, "gdb") == 0) {
459 PrintF("relinquishing control to gdb\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000460 v8::base::OS::DebugBreak();
Steve Blocka7e24c12009-10-30 11:49:00 +0000461 PrintF("regaining control from gdb\n");
462 } else if (strcmp(cmd, "break") == 0) {
Steve Block6ded16b2010-05-10 14:33:55 +0100463 if (argc == 2) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000464 int32_t value;
465 if (GetValue(arg1, &value)) {
Steve Block1e0659c2011-05-24 12:43:12 +0100466 if (!SetBreakpoint(reinterpret_cast<Instruction*>(value))) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000467 PrintF("setting breakpoint failed\n");
468 }
469 } else {
470 PrintF("%s unrecognized\n", arg1);
471 }
472 } else {
473 PrintF("break <address>\n");
474 }
475 } else if (strcmp(cmd, "del") == 0) {
476 if (!DeleteBreakpoint(NULL)) {
477 PrintF("deleting breakpoint failed\n");
478 }
479 } else if (strcmp(cmd, "flags") == 0) {
480 PrintF("N flag: %d; ", sim_->n_flag_);
481 PrintF("Z flag: %d; ", sim_->z_flag_);
482 PrintF("C flag: %d; ", sim_->c_flag_);
483 PrintF("V flag: %d\n", sim_->v_flag_);
Steve Blockd0582a62009-12-15 09:54:21 +0000484 PrintF("INVALID OP flag: %d; ", sim_->inv_op_vfp_flag_);
485 PrintF("DIV BY ZERO flag: %d; ", sim_->div_zero_vfp_flag_);
486 PrintF("OVERFLOW flag: %d; ", sim_->overflow_vfp_flag_);
487 PrintF("UNDERFLOW flag: %d; ", sim_->underflow_vfp_flag_);
Steve Block1e0659c2011-05-24 12:43:12 +0100488 PrintF("INEXACT flag: %d;\n", sim_->inexact_vfp_flag_);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800489 } else if (strcmp(cmd, "stop") == 0) {
490 int32_t value;
Steve Block1e0659c2011-05-24 12:43:12 +0100491 intptr_t stop_pc = sim_->get_pc() - 2 * Instruction::kInstrSize;
492 Instruction* stop_instr = reinterpret_cast<Instruction*>(stop_pc);
493 Instruction* msg_address =
494 reinterpret_cast<Instruction*>(stop_pc + Instruction::kInstrSize);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800495 if ((argc == 2) && (strcmp(arg1, "unstop") == 0)) {
496 // Remove the current stop.
497 if (sim_->isStopInstruction(stop_instr)) {
498 stop_instr->SetInstructionBits(kNopInstr);
499 msg_address->SetInstructionBits(kNopInstr);
500 } else {
501 PrintF("Not at debugger stop.\n");
502 }
503 } else if (argc == 3) {
504 // Print information about all/the specified breakpoint(s).
505 if (strcmp(arg1, "info") == 0) {
506 if (strcmp(arg2, "all") == 0) {
507 PrintF("Stop information:\n");
508 for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) {
509 sim_->PrintStopInfo(i);
510 }
511 } else if (GetValue(arg2, &value)) {
512 sim_->PrintStopInfo(value);
513 } else {
514 PrintF("Unrecognized argument.\n");
515 }
516 } else if (strcmp(arg1, "enable") == 0) {
517 // Enable all/the specified breakpoint(s).
518 if (strcmp(arg2, "all") == 0) {
519 for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) {
520 sim_->EnableStop(i);
521 }
522 } else if (GetValue(arg2, &value)) {
523 sim_->EnableStop(value);
524 } else {
525 PrintF("Unrecognized argument.\n");
526 }
527 } else if (strcmp(arg1, "disable") == 0) {
528 // Disable all/the specified breakpoint(s).
529 if (strcmp(arg2, "all") == 0) {
530 for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) {
531 sim_->DisableStop(i);
532 }
533 } else if (GetValue(arg2, &value)) {
534 sim_->DisableStop(value);
535 } else {
536 PrintF("Unrecognized argument.\n");
537 }
538 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000539 } else {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800540 PrintF("Wrong usage. Use help command for more information.\n");
Steve Blocka7e24c12009-10-30 11:49:00 +0000541 }
Leon Clarkee46be812010-01-19 14:06:41 +0000542 } else if ((strcmp(cmd, "t") == 0) || strcmp(cmd, "trace") == 0) {
543 ::v8::internal::FLAG_trace_sim = !::v8::internal::FLAG_trace_sim;
544 PrintF("Trace of executed instructions is %s\n",
545 ::v8::internal::FLAG_trace_sim ? "on" : "off");
Steve Blocka7e24c12009-10-30 11:49:00 +0000546 } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
547 PrintF("cont\n");
548 PrintF(" continue execution (alias 'c')\n");
549 PrintF("stepi\n");
550 PrintF(" step one instruction (alias 'si')\n");
551 PrintF("print <register>\n");
552 PrintF(" print register content (alias 'p')\n");
553 PrintF(" use register name 'all' to print all registers\n");
Ben Murdoch8b112d22011-06-08 16:22:53 +0100554 PrintF(" add argument 'fp' to print register pair double values\n");
Steve Blocka7e24c12009-10-30 11:49:00 +0000555 PrintF("printobject <register>\n");
556 PrintF(" print an object from a register (alias 'po')\n");
557 PrintF("flags\n");
558 PrintF(" print flags\n");
Steve Block6ded16b2010-05-10 14:33:55 +0100559 PrintF("stack [<words>]\n");
560 PrintF(" dump stack content, default dump 10 words)\n");
561 PrintF("mem <address> [<words>]\n");
562 PrintF(" dump memory content, default dump 10 words)\n");
Steve Blocka7e24c12009-10-30 11:49:00 +0000563 PrintF("disasm [<instructions>]\n");
Steve Block44f0eee2011-05-26 01:26:41 +0100564 PrintF("disasm [<address/register>]\n");
565 PrintF("disasm [[<address/register>] <instructions>]\n");
566 PrintF(" disassemble code, default is 10 instructions\n");
567 PrintF(" from pc (alias 'di')\n");
Steve Blocka7e24c12009-10-30 11:49:00 +0000568 PrintF("gdb\n");
569 PrintF(" enter gdb\n");
570 PrintF("break <address>\n");
571 PrintF(" set a break point on the address\n");
572 PrintF("del\n");
573 PrintF(" delete the breakpoint\n");
Leon Clarkee46be812010-01-19 14:06:41 +0000574 PrintF("trace (alias 't')\n");
Steve Block6ded16b2010-05-10 14:33:55 +0100575 PrintF(" toogle the tracing of all executed statements\n");
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800576 PrintF("stop feature:\n");
577 PrintF(" Description:\n");
578 PrintF(" Stops are debug instructions inserted by\n");
579 PrintF(" the Assembler::stop() function.\n");
580 PrintF(" When hitting a stop, the Simulator will\n");
Steve Block44f0eee2011-05-26 01:26:41 +0100581 PrintF(" stop and and give control to the ArmDebugger.\n");
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800582 PrintF(" The first %d stop codes are watched:\n",
583 Simulator::kNumOfWatchedStops);
584 PrintF(" - They can be enabled / disabled: the Simulator\n");
Steve Block44f0eee2011-05-26 01:26:41 +0100585 PrintF(" will / won't stop when hitting them.\n");
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800586 PrintF(" - The Simulator keeps track of how many times they \n");
587 PrintF(" are met. (See the info command.) Going over a\n");
588 PrintF(" disabled stop still increases its counter. \n");
589 PrintF(" Commands:\n");
590 PrintF(" stop info all/<code> : print infos about number <code>\n");
591 PrintF(" or all stop(s).\n");
592 PrintF(" stop enable/disable all/<code> : enables / disables\n");
593 PrintF(" all or number <code> stop(s)\n");
594 PrintF(" stop unstop\n");
595 PrintF(" ignore the stop instruction at the current location\n");
596 PrintF(" from now on\n");
Steve Blocka7e24c12009-10-30 11:49:00 +0000597 } else {
598 PrintF("Unknown command: %s\n", cmd);
599 }
600 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000601 }
602
603 // Add all the breakpoints back to stop execution and enter the debugger
604 // shell when hit.
605 RedoBreakpoints();
606
607#undef COMMAND_SIZE
608#undef ARG_SIZE
609
610#undef STR
611#undef XSTR
612}
613
614
Steve Block6ded16b2010-05-10 14:33:55 +0100615static bool ICacheMatch(void* one, void* two) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000616 DCHECK((reinterpret_cast<intptr_t>(one) & CachePage::kPageMask) == 0);
617 DCHECK((reinterpret_cast<intptr_t>(two) & CachePage::kPageMask) == 0);
Steve Block6ded16b2010-05-10 14:33:55 +0100618 return one == two;
619}
620
621
622static uint32_t ICacheHash(void* key) {
623 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)) >> 2;
624}
625
626
627static bool AllOnOnePage(uintptr_t start, int size) {
628 intptr_t start_page = (start & ~CachePage::kPageMask);
629 intptr_t end_page = ((start + size) & ~CachePage::kPageMask);
630 return start_page == end_page;
631}
632
633
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100634void Simulator::set_last_debugger_input(char* input) {
635 DeleteArray(last_debugger_input_);
636 last_debugger_input_ = input;
637}
638
Ben Murdoch61f157c2016-09-16 13:49:30 +0100639void Simulator::FlushICache(base::HashMap* i_cache, void* start_addr,
Steve Block44f0eee2011-05-26 01:26:41 +0100640 size_t size) {
Steve Block6ded16b2010-05-10 14:33:55 +0100641 intptr_t start = reinterpret_cast<intptr_t>(start_addr);
642 int intra_line = (start & CachePage::kLineMask);
643 start -= intra_line;
644 size += intra_line;
645 size = ((size - 1) | CachePage::kLineMask) + 1;
646 int offset = (start & CachePage::kPageMask);
647 while (!AllOnOnePage(start, size - 1)) {
648 int bytes_to_flush = CachePage::kPageSize - offset;
Steve Block44f0eee2011-05-26 01:26:41 +0100649 FlushOnePage(i_cache, start, bytes_to_flush);
Steve Block6ded16b2010-05-10 14:33:55 +0100650 start += bytes_to_flush;
651 size -= bytes_to_flush;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000652 DCHECK_EQ(0, start & CachePage::kPageMask);
Steve Block6ded16b2010-05-10 14:33:55 +0100653 offset = 0;
654 }
655 if (size != 0) {
Steve Block44f0eee2011-05-26 01:26:41 +0100656 FlushOnePage(i_cache, start, size);
Steve Block6ded16b2010-05-10 14:33:55 +0100657 }
658}
659
Ben Murdoch61f157c2016-09-16 13:49:30 +0100660CachePage* Simulator::GetCachePage(base::HashMap* i_cache, void* page) {
661 base::HashMap::Entry* entry = i_cache->LookupOrInsert(page, ICacheHash(page));
Steve Block6ded16b2010-05-10 14:33:55 +0100662 if (entry->value == NULL) {
663 CachePage* new_page = new CachePage();
664 entry->value = new_page;
665 }
666 return reinterpret_cast<CachePage*>(entry->value);
667}
668
669
670// Flush from start up to and not including start + size.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100671void Simulator::FlushOnePage(base::HashMap* i_cache, intptr_t start, int size) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000672 DCHECK(size <= CachePage::kPageSize);
673 DCHECK(AllOnOnePage(start, size - 1));
674 DCHECK((start & CachePage::kLineMask) == 0);
675 DCHECK((size & CachePage::kLineMask) == 0);
Steve Block6ded16b2010-05-10 14:33:55 +0100676 void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask));
677 int offset = (start & CachePage::kPageMask);
Steve Block44f0eee2011-05-26 01:26:41 +0100678 CachePage* cache_page = GetCachePage(i_cache, page);
Steve Block6ded16b2010-05-10 14:33:55 +0100679 char* valid_bytemap = cache_page->ValidityByte(offset);
680 memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift);
681}
682
Ben Murdoch61f157c2016-09-16 13:49:30 +0100683void Simulator::CheckICache(base::HashMap* i_cache, Instruction* instr) {
Steve Block6ded16b2010-05-10 14:33:55 +0100684 intptr_t address = reinterpret_cast<intptr_t>(instr);
685 void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
686 void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask));
687 int offset = (address & CachePage::kPageMask);
Steve Block44f0eee2011-05-26 01:26:41 +0100688 CachePage* cache_page = GetCachePage(i_cache, page);
Steve Block6ded16b2010-05-10 14:33:55 +0100689 char* cache_valid_byte = cache_page->ValidityByte(offset);
690 bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID);
691 char* cached_line = cache_page->CachedData(offset & ~CachePage::kLineMask);
692 if (cache_hit) {
693 // Check that the data in memory matches the contents of the I-cache.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000694 CHECK_EQ(0,
695 memcmp(reinterpret_cast<void*>(instr),
696 cache_page->CachedData(offset), Instruction::kInstrSize));
Steve Block6ded16b2010-05-10 14:33:55 +0100697 } else {
698 // Cache miss. Load memory into the cache.
699 memcpy(cached_line, line, CachePage::kLineLength);
700 *cache_valid_byte = CachePage::LINE_VALID;
701 }
702}
703
704
Ben Murdoch257744e2011-11-30 15:57:28 +0000705void Simulator::Initialize(Isolate* isolate) {
706 if (isolate->simulator_initialized()) return;
707 isolate->set_simulator_initialized(true);
708 ::v8::internal::ExternalReference::set_redirector(isolate,
709 &RedirectExternalReference);
Steve Blocka7e24c12009-10-30 11:49:00 +0000710}
711
712
Ben Murdoch257744e2011-11-30 15:57:28 +0000713Simulator::Simulator(Isolate* isolate) : isolate_(isolate) {
Steve Block44f0eee2011-05-26 01:26:41 +0100714 i_cache_ = isolate_->simulator_i_cache();
Steve Block6ded16b2010-05-10 14:33:55 +0100715 if (i_cache_ == NULL) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100716 i_cache_ = new base::HashMap(&ICacheMatch);
Steve Block44f0eee2011-05-26 01:26:41 +0100717 isolate_->set_simulator_i_cache(i_cache_);
Steve Block6ded16b2010-05-10 14:33:55 +0100718 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000719 Initialize(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100720 // Set up simulator support first. Some of this information is needed to
Steve Blocka7e24c12009-10-30 11:49:00 +0000721 // setup the architecture state.
722 size_t stack_size = 1 * 1024*1024; // allocate 1MB for stack
723 stack_ = reinterpret_cast<char*>(malloc(stack_size));
724 pc_modified_ = false;
725 icount_ = 0;
726 break_pc_ = NULL;
727 break_instr_ = 0;
728
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100729 // Set up architecture state.
Steve Blocka7e24c12009-10-30 11:49:00 +0000730 // All registers are initialized to zero to start with.
731 for (int i = 0; i < num_registers; i++) {
732 registers_[i] = 0;
733 }
734 n_flag_ = false;
735 z_flag_ = false;
736 c_flag_ = false;
737 v_flag_ = false;
738
Steve Blockd0582a62009-12-15 09:54:21 +0000739 // Initializing VFP registers.
740 // All registers are initialized to zero to start with
741 // even though s_registers_ & d_registers_ share the same
742 // physical registers in the target.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000743 for (int i = 0; i < num_d_registers * 2; i++) {
744 vfp_registers_[i] = 0;
Steve Blockd0582a62009-12-15 09:54:21 +0000745 }
746 n_flag_FPSCR_ = false;
747 z_flag_FPSCR_ = false;
748 c_flag_FPSCR_ = false;
749 v_flag_FPSCR_ = false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000750 FPSCR_rounding_mode_ = RN;
751 FPSCR_default_NaN_mode_ = false;
Steve Blockd0582a62009-12-15 09:54:21 +0000752
753 inv_op_vfp_flag_ = false;
754 div_zero_vfp_flag_ = false;
755 overflow_vfp_flag_ = false;
756 underflow_vfp_flag_ = false;
757 inexact_vfp_flag_ = false;
758
Steve Blocka7e24c12009-10-30 11:49:00 +0000759 // The sp is initialized to point to the bottom (high address) of the
760 // allocated stack area. To be safe in potential stack underflows we leave
761 // some buffer below.
762 registers_[sp] = reinterpret_cast<int32_t>(stack_) + stack_size - 64;
763 // The lr and pc are initialized to a known bad value that will cause an
764 // access violation if the simulator ever tries to execute it.
765 registers_[pc] = bad_lr;
766 registers_[lr] = bad_lr;
767 InitializeCoverage();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100768
769 last_debugger_input_ = NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +0000770}
771
772
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000773Simulator::~Simulator() { free(stack_); }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000774
775
Steve Blocka7e24c12009-10-30 11:49:00 +0000776// When the generated code calls an external reference we need to catch that in
777// the simulator. The external reference will be a function compiled for the
778// host architecture. We need to call that function instead of trying to
779// execute it with the simulator. We do that by redirecting the external
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800780// reference to a svc (Supervisor Call) instruction that is handled by
Steve Blocka7e24c12009-10-30 11:49:00 +0000781// the simulator. We write the original destination of the jump just at a known
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800782// offset from the svc instruction so the simulator knows what to call.
Steve Blocka7e24c12009-10-30 11:49:00 +0000783class Redirection {
784 public:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000785 Redirection(Isolate* isolate, void* external_function,
786 ExternalReference::Type type)
Steve Blocka7e24c12009-10-30 11:49:00 +0000787 : external_function_(external_function),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000788 swi_instruction_(al | (0xf * B24) | kCallRtRedirected),
Steve Block1e0659c2011-05-24 12:43:12 +0100789 type_(type),
Steve Block44f0eee2011-05-26 01:26:41 +0100790 next_(NULL) {
Steve Block44f0eee2011-05-26 01:26:41 +0100791 next_ = isolate->simulator_redirection();
792 Simulator::current(isolate)->
793 FlushICache(isolate->simulator_i_cache(),
794 reinterpret_cast<void*>(&swi_instruction_),
795 Instruction::kInstrSize);
796 isolate->set_simulator_redirection(this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000797 }
798
799 void* address_of_swi_instruction() {
800 return reinterpret_cast<void*>(&swi_instruction_);
801 }
802
803 void* external_function() { return external_function_; }
Steve Block1e0659c2011-05-24 12:43:12 +0100804 ExternalReference::Type type() { return type_; }
Steve Blocka7e24c12009-10-30 11:49:00 +0000805
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000806 static Redirection* Get(Isolate* isolate, void* external_function,
Steve Block1e0659c2011-05-24 12:43:12 +0100807 ExternalReference::Type type) {
Steve Block44f0eee2011-05-26 01:26:41 +0100808 Redirection* current = isolate->simulator_redirection();
809 for (; current != NULL; current = current->next_) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000810 if (current->external_function_ == external_function) {
811 DCHECK_EQ(current->type(), type);
812 return current;
813 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000814 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000815 return new Redirection(isolate, external_function, type);
Steve Blocka7e24c12009-10-30 11:49:00 +0000816 }
817
Steve Block1e0659c2011-05-24 12:43:12 +0100818 static Redirection* FromSwiInstruction(Instruction* swi_instruction) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000819 char* addr_of_swi = reinterpret_cast<char*>(swi_instruction);
820 char* addr_of_redirection =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000821 addr_of_swi - offsetof(Redirection, swi_instruction_);
Steve Blocka7e24c12009-10-30 11:49:00 +0000822 return reinterpret_cast<Redirection*>(addr_of_redirection);
823 }
824
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000825 static void* ReverseRedirection(int32_t reg) {
826 Redirection* redirection = FromSwiInstruction(
827 reinterpret_cast<Instruction*>(reinterpret_cast<void*>(reg)));
828 return redirection->external_function();
829 }
830
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000831 static void DeleteChain(Redirection* redirection) {
832 while (redirection != nullptr) {
833 Redirection* next = redirection->next_;
834 delete redirection;
835 redirection = next;
836 }
837 }
838
Steve Blocka7e24c12009-10-30 11:49:00 +0000839 private:
840 void* external_function_;
841 uint32_t swi_instruction_;
Steve Block1e0659c2011-05-24 12:43:12 +0100842 ExternalReference::Type type_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000843 Redirection* next_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000844};
845
846
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000847// static
Ben Murdoch61f157c2016-09-16 13:49:30 +0100848void Simulator::TearDown(base::HashMap* i_cache, Redirection* first) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000849 Redirection::DeleteChain(first);
850 if (i_cache != nullptr) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100851 for (base::HashMap::Entry* entry = i_cache->Start(); entry != nullptr;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000852 entry = i_cache->Next(entry)) {
853 delete static_cast<CachePage*>(entry->value);
854 }
855 delete i_cache;
856 }
857}
858
859
860void* Simulator::RedirectExternalReference(Isolate* isolate,
861 void* external_function,
Steve Block1e0659c2011-05-24 12:43:12 +0100862 ExternalReference::Type type) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000863 Redirection* redirection = Redirection::Get(isolate, external_function, type);
Steve Blocka7e24c12009-10-30 11:49:00 +0000864 return redirection->address_of_swi_instruction();
865}
866
867
868// Get the active Simulator for the current thread.
Steve Block44f0eee2011-05-26 01:26:41 +0100869Simulator* Simulator::current(Isolate* isolate) {
870 v8::internal::Isolate::PerIsolateThreadData* isolate_data =
Ben Murdoch257744e2011-11-30 15:57:28 +0000871 isolate->FindOrAllocatePerThreadDataForThisThread();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000872 DCHECK(isolate_data != NULL);
Steve Block44f0eee2011-05-26 01:26:41 +0100873
874 Simulator* sim = isolate_data->simulator();
Steve Blocka7e24c12009-10-30 11:49:00 +0000875 if (sim == NULL) {
Steve Block44f0eee2011-05-26 01:26:41 +0100876 // TODO(146): delete the simulator object when a thread/isolate goes away.
Ben Murdoch257744e2011-11-30 15:57:28 +0000877 sim = new Simulator(isolate);
Steve Block44f0eee2011-05-26 01:26:41 +0100878 isolate_data->set_simulator(sim);
Steve Blocka7e24c12009-10-30 11:49:00 +0000879 }
880 return sim;
881}
882
883
884// Sets the register in the architecture state. It will also deal with updating
885// Simulator internal state for special registers such as PC.
886void Simulator::set_register(int reg, int32_t value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000887 DCHECK((reg >= 0) && (reg < num_registers));
Steve Blocka7e24c12009-10-30 11:49:00 +0000888 if (reg == pc) {
889 pc_modified_ = true;
890 }
891 registers_[reg] = value;
892}
893
894
895// Get the register from the architecture state. This function does handle
896// the special case of accessing the PC register.
897int32_t Simulator::get_register(int reg) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000898 DCHECK((reg >= 0) && (reg < num_registers));
Steve Block791712a2010-08-27 10:21:07 +0100899 // Stupid code added to avoid bug in GCC.
900 // See: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43949
901 if (reg >= num_registers) return 0;
902 // End stupid code.
Steve Block1e0659c2011-05-24 12:43:12 +0100903 return registers_[reg] + ((reg == pc) ? Instruction::kPCReadOffset : 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000904}
905
906
Ben Murdoch8b112d22011-06-08 16:22:53 +0100907double Simulator::get_double_from_register_pair(int reg) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000908 DCHECK((reg >= 0) && (reg < num_registers) && ((reg % 2) == 0));
Ben Murdoch8b112d22011-06-08 16:22:53 +0100909
910 double dm_val = 0.0;
911 // Read the bits from the unsigned integer register_[] array
912 // into the double precision floating point value and return it.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000913 char buffer[2 * sizeof(vfp_registers_[0])];
Ben Murdoch8b112d22011-06-08 16:22:53 +0100914 memcpy(buffer, &registers_[reg], 2 * sizeof(registers_[0]));
915 memcpy(&dm_val, buffer, 2 * sizeof(registers_[0]));
916 return(dm_val);
917}
918
919
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000920void Simulator::set_register_pair_from_double(int reg, double* value) {
921 DCHECK((reg >= 0) && (reg < num_registers) && ((reg % 2) == 0));
922 memcpy(registers_ + reg, value, sizeof(*value));
923}
924
925
Kristian Monsen25f61362010-05-21 11:50:48 +0100926void Simulator::set_dw_register(int dreg, const int* dbl) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000927 DCHECK((dreg >= 0) && (dreg < num_d_registers));
Kristian Monsen25f61362010-05-21 11:50:48 +0100928 registers_[dreg] = dbl[0];
929 registers_[dreg + 1] = dbl[1];
930}
931
932
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000933void Simulator::get_d_register(int dreg, uint64_t* value) {
934 DCHECK((dreg >= 0) && (dreg < DwVfpRegister::NumRegisters()));
935 memcpy(value, vfp_registers_ + dreg * 2, sizeof(*value));
936}
937
938
939void Simulator::set_d_register(int dreg, const uint64_t* value) {
940 DCHECK((dreg >= 0) && (dreg < DwVfpRegister::NumRegisters()));
941 memcpy(vfp_registers_ + dreg * 2, value, sizeof(*value));
942}
943
944
945void Simulator::get_d_register(int dreg, uint32_t* value) {
946 DCHECK((dreg >= 0) && (dreg < DwVfpRegister::NumRegisters()));
947 memcpy(value, vfp_registers_ + dreg * 2, sizeof(*value) * 2);
948}
949
950
951void Simulator::set_d_register(int dreg, const uint32_t* value) {
952 DCHECK((dreg >= 0) && (dreg < DwVfpRegister::NumRegisters()));
953 memcpy(vfp_registers_ + dreg * 2, value, sizeof(*value) * 2);
954}
955
956
957void Simulator::get_q_register(int qreg, uint64_t* value) {
958 DCHECK((qreg >= 0) && (qreg < num_q_registers));
959 memcpy(value, vfp_registers_ + qreg * 4, sizeof(*value) * 2);
960}
961
962
963void Simulator::set_q_register(int qreg, const uint64_t* value) {
964 DCHECK((qreg >= 0) && (qreg < num_q_registers));
965 memcpy(vfp_registers_ + qreg * 4, value, sizeof(*value) * 2);
966}
967
968
969void Simulator::get_q_register(int qreg, uint32_t* value) {
970 DCHECK((qreg >= 0) && (qreg < num_q_registers));
971 memcpy(value, vfp_registers_ + qreg * 4, sizeof(*value) * 4);
972}
973
974
975void Simulator::set_q_register(int qreg, const uint32_t* value) {
976 DCHECK((qreg >= 0) && (qreg < num_q_registers));
977 memcpy(vfp_registers_ + qreg * 4, value, sizeof(*value) * 4);
978}
979
980
Steve Blocka7e24c12009-10-30 11:49:00 +0000981// Raw access to the PC register.
982void Simulator::set_pc(int32_t value) {
983 pc_modified_ = true;
984 registers_[pc] = value;
985}
986
987
Ben Murdochb0fe1622011-05-05 13:52:32 +0100988bool Simulator::has_bad_pc() const {
989 return ((registers_[pc] == bad_lr) || (registers_[pc] == end_sim_pc));
990}
991
992
Steve Blocka7e24c12009-10-30 11:49:00 +0000993// Raw access to the PC register without the special adjustment when reading.
994int32_t Simulator::get_pc() const {
995 return registers_[pc];
996}
997
998
Steve Blockd0582a62009-12-15 09:54:21 +0000999// Getting from and setting into VFP registers.
1000void Simulator::set_s_register(int sreg, unsigned int value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001001 DCHECK((sreg >= 0) && (sreg < num_s_registers));
1002 vfp_registers_[sreg] = value;
Steve Blockd0582a62009-12-15 09:54:21 +00001003}
1004
1005
1006unsigned int Simulator::get_s_register(int sreg) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001007 DCHECK((sreg >= 0) && (sreg < num_s_registers));
1008 return vfp_registers_[sreg];
Steve Blockd0582a62009-12-15 09:54:21 +00001009}
1010
1011
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001012template<class InputType, int register_size>
1013void Simulator::SetVFPRegister(int reg_index, const InputType& value) {
1014 DCHECK(reg_index >= 0);
1015 if (register_size == 1) DCHECK(reg_index < num_s_registers);
1016 if (register_size == 2) DCHECK(reg_index < DwVfpRegister::NumRegisters());
1017
1018 char buffer[register_size * sizeof(vfp_registers_[0])];
1019 memcpy(buffer, &value, register_size * sizeof(vfp_registers_[0]));
1020 memcpy(&vfp_registers_[reg_index * register_size], buffer,
1021 register_size * sizeof(vfp_registers_[0]));
Steve Blockd0582a62009-12-15 09:54:21 +00001022}
1023
1024
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001025template<class ReturnType, int register_size>
1026ReturnType Simulator::GetFromVFPRegister(int reg_index) {
1027 DCHECK(reg_index >= 0);
1028 if (register_size == 1) DCHECK(reg_index < num_s_registers);
1029 if (register_size == 2) DCHECK(reg_index < DwVfpRegister::NumRegisters());
1030
1031 ReturnType value = 0;
1032 char buffer[register_size * sizeof(vfp_registers_[0])];
1033 memcpy(buffer, &vfp_registers_[register_size * reg_index],
1034 register_size * sizeof(vfp_registers_[0]));
1035 memcpy(&value, buffer, register_size * sizeof(vfp_registers_[0]));
1036 return value;
Steve Blockd0582a62009-12-15 09:54:21 +00001037}
1038
Ben Murdochda12d292016-06-02 14:46:10 +01001039void Simulator::SetSpecialRegister(SRegisterFieldMask reg_and_mask,
1040 uint32_t value) {
1041 // Only CPSR_f is implemented. Of that, only N, Z, C and V are implemented.
1042 if ((reg_and_mask == CPSR_f) && ((value & ~kSpecialCondition) == 0)) {
1043 n_flag_ = ((value & (1 << 31)) != 0);
1044 z_flag_ = ((value & (1 << 30)) != 0);
1045 c_flag_ = ((value & (1 << 29)) != 0);
1046 v_flag_ = ((value & (1 << 28)) != 0);
1047 } else {
1048 UNIMPLEMENTED();
1049 }
1050}
1051
1052uint32_t Simulator::GetFromSpecialRegister(SRegister reg) {
1053 uint32_t result = 0;
1054 // Only CPSR_f is implemented.
1055 if (reg == CPSR) {
1056 if (n_flag_) result |= (1 << 31);
1057 if (z_flag_) result |= (1 << 30);
1058 if (c_flag_) result |= (1 << 29);
1059 if (v_flag_) result |= (1 << 28);
1060 } else {
1061 UNIMPLEMENTED();
1062 }
1063 return result;
1064}
Steve Blockd0582a62009-12-15 09:54:21 +00001065
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001066// Runtime FP routines take:
1067// - two double arguments
1068// - one double argument and zero or one integer arguments.
1069// All are consructed here from r0-r3 or d0, d1 and r0.
1070void Simulator::GetFpArgs(double* x, double* y, int32_t* z) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001071 if (use_eabi_hardfloat()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001072 *x = get_double_from_d_register(0);
1073 *y = get_double_from_d_register(1);
1074 *z = get_register(0);
Ben Murdoch257744e2011-11-30 15:57:28 +00001075 } else {
Ben Murdoch257744e2011-11-30 15:57:28 +00001076 // Registers 0 and 1 -> x.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001077 *x = get_double_from_register_pair(0);
1078 // Register 2 and 3 -> y.
1079 *y = get_double_from_register_pair(2);
1080 // Register 2 -> z
1081 *z = get_register(2);
Ben Murdoch257744e2011-11-30 15:57:28 +00001082 }
1083}
1084
1085
1086// The return value is either in r0/r1 or d0.
Steve Blocka7e24c12009-10-30 11:49:00 +00001087void Simulator::SetFpResult(const double& result) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001088 if (use_eabi_hardfloat()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001089 char buffer[2 * sizeof(vfp_registers_[0])];
Ben Murdoch257744e2011-11-30 15:57:28 +00001090 memcpy(buffer, &result, sizeof(buffer));
1091 // Copy result to d0.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001092 memcpy(vfp_registers_, buffer, sizeof(buffer));
Ben Murdoch257744e2011-11-30 15:57:28 +00001093 } else {
1094 char buffer[2 * sizeof(registers_[0])];
1095 memcpy(buffer, &result, sizeof(buffer));
1096 // Copy result to r0 and r1.
1097 memcpy(registers_, buffer, sizeof(buffer));
1098 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001099}
1100
1101
1102void Simulator::TrashCallerSaveRegisters() {
1103 // We don't trash the registers with the return value.
1104 registers_[2] = 0x50Bad4U;
1105 registers_[3] = 0x50Bad4U;
1106 registers_[12] = 0x50Bad4U;
1107}
1108
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001109
Kristian Monsen25f61362010-05-21 11:50:48 +01001110// Some Operating Systems allow unaligned access on ARMv7 targets. We
1111// assume that unaligned accesses are not allowed unless the v8 build system
1112// defines the CAN_USE_UNALIGNED_ACCESSES macro to be non-zero.
1113// The following statements below describes the behavior of the ARM CPUs
1114// that don't support unaligned access.
1115// Some ARM platforms raise an interrupt on detecting unaligned access.
1116// On others it does a funky rotation thing. For now we
1117// simply disallow unaligned reads. Note that simulator runs have the runtime
Steve Blocka7e24c12009-10-30 11:49:00 +00001118// system running directly on the host system and only generated code is
1119// executed in the simulator. Since the host is typically IA32 we will not
Kristian Monsen25f61362010-05-21 11:50:48 +01001120// get the correct ARM-like behaviour on unaligned accesses for those ARM
1121// targets that don't support unaligned loads and stores.
1122
Steve Blocka7e24c12009-10-30 11:49:00 +00001123
Steve Block1e0659c2011-05-24 12:43:12 +01001124int Simulator::ReadW(int32_t addr, Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001125 if (FLAG_enable_unaligned_accesses || (addr & 3) == 0) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001126 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
1127 return *ptr;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001128 } else {
1129 PrintF("Unaligned read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1130 addr,
1131 reinterpret_cast<intptr_t>(instr));
1132 UNIMPLEMENTED();
1133 return 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00001134 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001135}
1136
1137
Steve Block1e0659c2011-05-24 12:43:12 +01001138void Simulator::WriteW(int32_t addr, int value, Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001139 if (FLAG_enable_unaligned_accesses || (addr & 3) == 0) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001140 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
1141 *ptr = value;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001142 } else {
1143 PrintF("Unaligned write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1144 addr,
1145 reinterpret_cast<intptr_t>(instr));
1146 UNIMPLEMENTED();
Steve Blocka7e24c12009-10-30 11:49:00 +00001147 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001148}
1149
1150
Steve Block1e0659c2011-05-24 12:43:12 +01001151uint16_t Simulator::ReadHU(int32_t addr, Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001152 if (FLAG_enable_unaligned_accesses || (addr & 1) == 0) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001153 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1154 return *ptr;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001155 } else {
1156 PrintF("Unaligned unsigned halfword read at 0x%08x, pc=0x%08"
1157 V8PRIxPTR "\n",
1158 addr,
1159 reinterpret_cast<intptr_t>(instr));
1160 UNIMPLEMENTED();
1161 return 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00001162 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001163}
1164
1165
Steve Block1e0659c2011-05-24 12:43:12 +01001166int16_t Simulator::ReadH(int32_t addr, Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001167 if (FLAG_enable_unaligned_accesses || (addr & 1) == 0) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001168 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
1169 return *ptr;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001170 } else {
1171 PrintF("Unaligned signed halfword read at 0x%08x\n", addr);
1172 UNIMPLEMENTED();
1173 return 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00001174 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001175}
1176
1177
Steve Block1e0659c2011-05-24 12:43:12 +01001178void Simulator::WriteH(int32_t addr, uint16_t value, Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001179 if (FLAG_enable_unaligned_accesses || (addr & 1) == 0) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001180 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1181 *ptr = value;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001182 } else {
1183 PrintF("Unaligned unsigned halfword write at 0x%08x, pc=0x%08"
1184 V8PRIxPTR "\n",
1185 addr,
1186 reinterpret_cast<intptr_t>(instr));
1187 UNIMPLEMENTED();
Steve Blocka7e24c12009-10-30 11:49:00 +00001188 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001189}
1190
1191
Steve Block1e0659c2011-05-24 12:43:12 +01001192void Simulator::WriteH(int32_t addr, int16_t value, Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001193 if (FLAG_enable_unaligned_accesses || (addr & 1) == 0) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001194 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
1195 *ptr = value;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001196 } else {
1197 PrintF("Unaligned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1198 addr,
1199 reinterpret_cast<intptr_t>(instr));
1200 UNIMPLEMENTED();
Steve Blocka7e24c12009-10-30 11:49:00 +00001201 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001202}
1203
1204
1205uint8_t Simulator::ReadBU(int32_t addr) {
1206 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1207 return *ptr;
1208}
1209
1210
1211int8_t Simulator::ReadB(int32_t addr) {
1212 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
1213 return *ptr;
1214}
1215
1216
1217void Simulator::WriteB(int32_t addr, uint8_t value) {
1218 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1219 *ptr = value;
1220}
1221
1222
1223void Simulator::WriteB(int32_t addr, int8_t value) {
1224 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
1225 *ptr = value;
1226}
1227
1228
Kristian Monsen25f61362010-05-21 11:50:48 +01001229int32_t* Simulator::ReadDW(int32_t addr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001230 if (FLAG_enable_unaligned_accesses || (addr & 3) == 0) {
Kristian Monsen25f61362010-05-21 11:50:48 +01001231 int32_t* ptr = reinterpret_cast<int32_t*>(addr);
1232 return ptr;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001233 } else {
1234 PrintF("Unaligned read at 0x%08x\n", addr);
1235 UNIMPLEMENTED();
1236 return 0;
Kristian Monsen25f61362010-05-21 11:50:48 +01001237 }
Kristian Monsen25f61362010-05-21 11:50:48 +01001238}
1239
1240
1241void Simulator::WriteDW(int32_t addr, int32_t value1, int32_t value2) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001242 if (FLAG_enable_unaligned_accesses || (addr & 3) == 0) {
Kristian Monsen25f61362010-05-21 11:50:48 +01001243 int32_t* ptr = reinterpret_cast<int32_t*>(addr);
1244 *ptr++ = value1;
1245 *ptr = value2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001246 } else {
1247 PrintF("Unaligned write at 0x%08x\n", addr);
1248 UNIMPLEMENTED();
Kristian Monsen25f61362010-05-21 11:50:48 +01001249 }
Kristian Monsen25f61362010-05-21 11:50:48 +01001250}
1251
1252
Steve Blocka7e24c12009-10-30 11:49:00 +00001253// Returns the limit of the stack area to enable checking for stack overflows.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001254uintptr_t Simulator::StackLimit(uintptr_t c_limit) const {
1255 // The simulator uses a separate JS stack. If we have exhausted the C stack,
1256 // we also drop down the JS limit to reflect the exhaustion on the JS stack.
1257 if (GetCurrentStackPosition() < c_limit) {
1258 return reinterpret_cast<uintptr_t>(get_sp());
1259 }
1260
1261 // Otherwise the limit is the JS stack. Leave a safety margin of 1024 bytes
1262 // to prevent overrunning the stack when pushing values.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001263 return reinterpret_cast<uintptr_t>(stack_) + 1024;
Steve Blocka7e24c12009-10-30 11:49:00 +00001264}
1265
1266
1267// Unsupported instructions use Format to print an error and stop execution.
Steve Block1e0659c2011-05-24 12:43:12 +01001268void Simulator::Format(Instruction* instr, const char* format) {
Ben Murdochc5610432016-08-08 18:44:38 +01001269 PrintF("Simulator found unsupported instruction:\n 0x%08" V8PRIxPTR ": %s\n",
Ben Murdochf87a2032010-10-22 12:50:53 +01001270 reinterpret_cast<intptr_t>(instr), format);
Steve Blocka7e24c12009-10-30 11:49:00 +00001271 UNIMPLEMENTED();
1272}
1273
1274
1275// Checks if the current instruction should be executed based on its
1276// condition bits.
Steve Block1e0659c2011-05-24 12:43:12 +01001277bool Simulator::ConditionallyExecute(Instruction* instr) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001278 switch (instr->ConditionField()) {
Steve Block1e0659c2011-05-24 12:43:12 +01001279 case eq: return z_flag_;
1280 case ne: return !z_flag_;
1281 case cs: return c_flag_;
1282 case cc: return !c_flag_;
1283 case mi: return n_flag_;
1284 case pl: return !n_flag_;
1285 case vs: return v_flag_;
1286 case vc: return !v_flag_;
1287 case hi: return c_flag_ && !z_flag_;
1288 case ls: return !c_flag_ || z_flag_;
1289 case ge: return n_flag_ == v_flag_;
1290 case lt: return n_flag_ != v_flag_;
1291 case gt: return !z_flag_ && (n_flag_ == v_flag_);
1292 case le: return z_flag_ || (n_flag_ != v_flag_);
1293 case al: return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00001294 default: UNREACHABLE();
1295 }
1296 return false;
1297}
1298
1299
1300// Calculate and set the Negative and Zero flags.
1301void Simulator::SetNZFlags(int32_t val) {
1302 n_flag_ = (val < 0);
1303 z_flag_ = (val == 0);
1304}
1305
1306
1307// Set the Carry flag.
1308void Simulator::SetCFlag(bool val) {
1309 c_flag_ = val;
1310}
1311
1312
1313// Set the oVerflow flag.
1314void Simulator::SetVFlag(bool val) {
1315 v_flag_ = val;
1316}
1317
1318
1319// Calculate C flag value for additions.
Ben Murdoch257744e2011-11-30 15:57:28 +00001320bool Simulator::CarryFrom(int32_t left, int32_t right, int32_t carry) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001321 uint32_t uleft = static_cast<uint32_t>(left);
1322 uint32_t uright = static_cast<uint32_t>(right);
1323 uint32_t urest = 0xffffffffU - uleft;
1324
Ben Murdoch257744e2011-11-30 15:57:28 +00001325 return (uright > urest) ||
1326 (carry && (((uright + 1) > urest) || (uright > (urest - 1))));
Steve Blocka7e24c12009-10-30 11:49:00 +00001327}
1328
1329
1330// Calculate C flag value for subtractions.
Ben Murdochda12d292016-06-02 14:46:10 +01001331bool Simulator::BorrowFrom(int32_t left, int32_t right, int32_t carry) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001332 uint32_t uleft = static_cast<uint32_t>(left);
1333 uint32_t uright = static_cast<uint32_t>(right);
1334
Ben Murdochda12d292016-06-02 14:46:10 +01001335 return (uright > uleft) ||
1336 (!carry && (((uright + 1) > uleft) || (uright > (uleft - 1))));
Steve Blocka7e24c12009-10-30 11:49:00 +00001337}
1338
1339
1340// Calculate V flag value for additions and subtractions.
1341bool Simulator::OverflowFrom(int32_t alu_out,
1342 int32_t left, int32_t right, bool addition) {
1343 bool overflow;
1344 if (addition) {
1345 // operands have the same sign
1346 overflow = ((left >= 0 && right >= 0) || (left < 0 && right < 0))
1347 // and operands and result have different sign
1348 && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
1349 } else {
1350 // operands have different signs
1351 overflow = ((left < 0 && right >= 0) || (left >= 0 && right < 0))
1352 // and first operand and result have different signs
1353 && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
1354 }
1355 return overflow;
1356}
1357
1358
Steve Blockd0582a62009-12-15 09:54:21 +00001359// Support for VFP comparisons.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001360void Simulator::Compute_FPSCR_Flags(float val1, float val2) {
1361 if (std::isnan(val1) || std::isnan(val2)) {
1362 n_flag_FPSCR_ = false;
1363 z_flag_FPSCR_ = false;
1364 c_flag_FPSCR_ = true;
1365 v_flag_FPSCR_ = true;
1366 // All non-NaN cases.
1367 } else if (val1 == val2) {
1368 n_flag_FPSCR_ = false;
1369 z_flag_FPSCR_ = true;
1370 c_flag_FPSCR_ = true;
1371 v_flag_FPSCR_ = false;
1372 } else if (val1 < val2) {
1373 n_flag_FPSCR_ = true;
1374 z_flag_FPSCR_ = false;
1375 c_flag_FPSCR_ = false;
1376 v_flag_FPSCR_ = false;
1377 } else {
1378 // Case when (val1 > val2).
1379 n_flag_FPSCR_ = false;
1380 z_flag_FPSCR_ = false;
1381 c_flag_FPSCR_ = true;
1382 v_flag_FPSCR_ = false;
1383 }
1384}
1385
1386
Steve Blockd0582a62009-12-15 09:54:21 +00001387void Simulator::Compute_FPSCR_Flags(double val1, double val2) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001388 if (std::isnan(val1) || std::isnan(val2)) {
Leon Clarkee46be812010-01-19 14:06:41 +00001389 n_flag_FPSCR_ = false;
1390 z_flag_FPSCR_ = false;
1391 c_flag_FPSCR_ = true;
1392 v_flag_FPSCR_ = true;
Steve Blockd0582a62009-12-15 09:54:21 +00001393 // All non-NaN cases.
Leon Clarkee46be812010-01-19 14:06:41 +00001394 } else if (val1 == val2) {
Steve Blockd0582a62009-12-15 09:54:21 +00001395 n_flag_FPSCR_ = false;
1396 z_flag_FPSCR_ = true;
1397 c_flag_FPSCR_ = true;
1398 v_flag_FPSCR_ = false;
1399 } else if (val1 < val2) {
1400 n_flag_FPSCR_ = true;
1401 z_flag_FPSCR_ = false;
1402 c_flag_FPSCR_ = false;
1403 v_flag_FPSCR_ = false;
1404 } else {
1405 // Case when (val1 > val2).
1406 n_flag_FPSCR_ = false;
1407 z_flag_FPSCR_ = false;
1408 c_flag_FPSCR_ = true;
1409 v_flag_FPSCR_ = false;
1410 }
1411}
1412
1413
1414void Simulator::Copy_FPSCR_to_APSR() {
1415 n_flag_ = n_flag_FPSCR_;
1416 z_flag_ = z_flag_FPSCR_;
1417 c_flag_ = c_flag_FPSCR_;
1418 v_flag_ = v_flag_FPSCR_;
1419}
1420
1421
Steve Blocka7e24c12009-10-30 11:49:00 +00001422// Addressing Mode 1 - Data-processing operands:
1423// Get the value based on the shifter_operand with register.
Steve Block1e0659c2011-05-24 12:43:12 +01001424int32_t Simulator::GetShiftRm(Instruction* instr, bool* carry_out) {
1425 ShiftOp shift = instr->ShiftField();
1426 int shift_amount = instr->ShiftAmountValue();
1427 int32_t result = get_register(instr->RmValue());
Steve Blocka7e24c12009-10-30 11:49:00 +00001428 if (instr->Bit(4) == 0) {
1429 // by immediate
1430 if ((shift == ROR) && (shift_amount == 0)) {
1431 UNIMPLEMENTED();
1432 return result;
1433 } else if (((shift == LSR) || (shift == ASR)) && (shift_amount == 0)) {
1434 shift_amount = 32;
1435 }
1436 switch (shift) {
1437 case ASR: {
1438 if (shift_amount == 0) {
1439 if (result < 0) {
1440 result = 0xffffffff;
1441 *carry_out = true;
1442 } else {
1443 result = 0;
1444 *carry_out = false;
1445 }
1446 } else {
1447 result >>= (shift_amount - 1);
1448 *carry_out = (result & 1) == 1;
1449 result >>= 1;
1450 }
1451 break;
1452 }
1453
1454 case LSL: {
1455 if (shift_amount == 0) {
1456 *carry_out = c_flag_;
1457 } else {
1458 result <<= (shift_amount - 1);
1459 *carry_out = (result < 0);
1460 result <<= 1;
1461 }
1462 break;
1463 }
1464
1465 case LSR: {
1466 if (shift_amount == 0) {
1467 result = 0;
1468 *carry_out = c_flag_;
1469 } else {
1470 uint32_t uresult = static_cast<uint32_t>(result);
1471 uresult >>= (shift_amount - 1);
1472 *carry_out = (uresult & 1) == 1;
1473 uresult >>= 1;
1474 result = static_cast<int32_t>(uresult);
1475 }
1476 break;
1477 }
1478
1479 case ROR: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001480 if (shift_amount == 0) {
1481 *carry_out = c_flag_;
1482 } else {
1483 uint32_t left = static_cast<uint32_t>(result) >> shift_amount;
1484 uint32_t right = static_cast<uint32_t>(result) << (32 - shift_amount);
1485 result = right | left;
1486 *carry_out = (static_cast<uint32_t>(result) >> 31) != 0;
1487 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001488 break;
1489 }
1490
1491 default: {
1492 UNREACHABLE();
1493 break;
1494 }
1495 }
1496 } else {
1497 // by register
Steve Block1e0659c2011-05-24 12:43:12 +01001498 int rs = instr->RsValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00001499 shift_amount = get_register(rs) &0xff;
1500 switch (shift) {
1501 case ASR: {
1502 if (shift_amount == 0) {
1503 *carry_out = c_flag_;
1504 } else if (shift_amount < 32) {
1505 result >>= (shift_amount - 1);
1506 *carry_out = (result & 1) == 1;
1507 result >>= 1;
1508 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001509 DCHECK(shift_amount >= 32);
Steve Blocka7e24c12009-10-30 11:49:00 +00001510 if (result < 0) {
1511 *carry_out = true;
1512 result = 0xffffffff;
1513 } else {
1514 *carry_out = false;
1515 result = 0;
1516 }
1517 }
1518 break;
1519 }
1520
1521 case LSL: {
1522 if (shift_amount == 0) {
1523 *carry_out = c_flag_;
1524 } else if (shift_amount < 32) {
1525 result <<= (shift_amount - 1);
1526 *carry_out = (result < 0);
1527 result <<= 1;
1528 } else if (shift_amount == 32) {
1529 *carry_out = (result & 1) == 1;
1530 result = 0;
1531 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001532 DCHECK(shift_amount > 32);
Steve Blocka7e24c12009-10-30 11:49:00 +00001533 *carry_out = false;
1534 result = 0;
1535 }
1536 break;
1537 }
1538
1539 case LSR: {
1540 if (shift_amount == 0) {
1541 *carry_out = c_flag_;
1542 } else if (shift_amount < 32) {
1543 uint32_t uresult = static_cast<uint32_t>(result);
1544 uresult >>= (shift_amount - 1);
1545 *carry_out = (uresult & 1) == 1;
1546 uresult >>= 1;
1547 result = static_cast<int32_t>(uresult);
1548 } else if (shift_amount == 32) {
1549 *carry_out = (result < 0);
1550 result = 0;
1551 } else {
1552 *carry_out = false;
1553 result = 0;
1554 }
1555 break;
1556 }
1557
1558 case ROR: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001559 if (shift_amount == 0) {
1560 *carry_out = c_flag_;
1561 } else {
1562 uint32_t left = static_cast<uint32_t>(result) >> shift_amount;
1563 uint32_t right = static_cast<uint32_t>(result) << (32 - shift_amount);
1564 result = right | left;
1565 *carry_out = (static_cast<uint32_t>(result) >> 31) != 0;
1566 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001567 break;
1568 }
1569
1570 default: {
1571 UNREACHABLE();
1572 break;
1573 }
1574 }
1575 }
1576 return result;
1577}
1578
1579
1580// Addressing Mode 1 - Data-processing operands:
1581// Get the value based on the shifter_operand with immediate.
Steve Block1e0659c2011-05-24 12:43:12 +01001582int32_t Simulator::GetImm(Instruction* instr, bool* carry_out) {
1583 int rotate = instr->RotateValue() * 2;
1584 int immed8 = instr->Immed8Value();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001585 int imm = base::bits::RotateRight32(immed8, rotate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001586 *carry_out = (rotate == 0) ? c_flag_ : (imm < 0);
1587 return imm;
1588}
1589
1590
1591static int count_bits(int bit_vector) {
1592 int count = 0;
1593 while (bit_vector != 0) {
1594 if ((bit_vector & 1) != 0) {
1595 count++;
1596 }
1597 bit_vector >>= 1;
1598 }
1599 return count;
1600}
1601
1602
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001603int32_t Simulator::ProcessPU(Instruction* instr,
1604 int num_regs,
1605 int reg_size,
1606 intptr_t* start_address,
1607 intptr_t* end_address) {
Steve Block1e0659c2011-05-24 12:43:12 +01001608 int rn = instr->RnValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00001609 int32_t rn_val = get_register(rn);
Steve Blocka7e24c12009-10-30 11:49:00 +00001610 switch (instr->PUField()) {
Steve Block1e0659c2011-05-24 12:43:12 +01001611 case da_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00001612 UNIMPLEMENTED();
1613 break;
1614 }
Steve Block1e0659c2011-05-24 12:43:12 +01001615 case ia_x: {
Ben Murdoch8b112d22011-06-08 16:22:53 +01001616 *start_address = rn_val;
1617 *end_address = rn_val + (num_regs * reg_size) - reg_size;
1618 rn_val = rn_val + (num_regs * reg_size);
Steve Blocka7e24c12009-10-30 11:49:00 +00001619 break;
1620 }
Steve Block1e0659c2011-05-24 12:43:12 +01001621 case db_x: {
Ben Murdoch8b112d22011-06-08 16:22:53 +01001622 *start_address = rn_val - (num_regs * reg_size);
1623 *end_address = rn_val - reg_size;
1624 rn_val = *start_address;
Steve Blocka7e24c12009-10-30 11:49:00 +00001625 break;
1626 }
Steve Block1e0659c2011-05-24 12:43:12 +01001627 case ib_x: {
Ben Murdoch8b112d22011-06-08 16:22:53 +01001628 *start_address = rn_val + reg_size;
1629 *end_address = rn_val + (num_regs * reg_size);
1630 rn_val = *end_address;
Steve Blocka7e24c12009-10-30 11:49:00 +00001631 break;
1632 }
1633 default: {
1634 UNREACHABLE();
1635 break;
1636 }
1637 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001638 return rn_val;
Ben Murdoch8b112d22011-06-08 16:22:53 +01001639}
1640
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001641
Ben Murdoch8b112d22011-06-08 16:22:53 +01001642// Addressing Mode 4 - Load and Store Multiple
1643void Simulator::HandleRList(Instruction* instr, bool load) {
1644 int rlist = instr->RlistValue();
1645 int num_regs = count_bits(rlist);
1646
1647 intptr_t start_address = 0;
1648 intptr_t end_address = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001649 int32_t rn_val =
1650 ProcessPU(instr, num_regs, kPointerSize, &start_address, &end_address);
Ben Murdoch8b112d22011-06-08 16:22:53 +01001651
Steve Blocka7e24c12009-10-30 11:49:00 +00001652 intptr_t* address = reinterpret_cast<intptr_t*>(start_address);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001653 // Catch null pointers a little earlier.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001654 DCHECK(start_address > 8191 || start_address < 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001655 int reg = 0;
1656 while (rlist != 0) {
1657 if ((rlist & 1) != 0) {
1658 if (load) {
1659 set_register(reg, *address);
1660 } else {
1661 *address = get_register(reg);
1662 }
1663 address += 1;
1664 }
1665 reg++;
1666 rlist >>= 1;
1667 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001668 DCHECK(end_address == ((intptr_t)address) - 4);
1669 if (instr->HasW()) {
1670 set_register(instr->RnValue(), rn_val);
1671 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001672}
1673
1674
Ben Murdoch8b112d22011-06-08 16:22:53 +01001675// Addressing Mode 6 - Load and Store Multiple Coprocessor registers.
1676void Simulator::HandleVList(Instruction* instr) {
1677 VFPRegPrecision precision =
1678 (instr->SzValue() == 0) ? kSinglePrecision : kDoublePrecision;
1679 int operand_size = (precision == kSinglePrecision) ? 4 : 8;
1680
1681 bool load = (instr->VLValue() == 0x1);
1682
1683 int vd;
1684 int num_regs;
1685 vd = instr->VFPDRegValue(precision);
1686 if (precision == kSinglePrecision) {
1687 num_regs = instr->Immed8Value();
1688 } else {
1689 num_regs = instr->Immed8Value() / 2;
1690 }
1691
1692 intptr_t start_address = 0;
1693 intptr_t end_address = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001694 int32_t rn_val =
1695 ProcessPU(instr, num_regs, operand_size, &start_address, &end_address);
Ben Murdoch8b112d22011-06-08 16:22:53 +01001696
1697 intptr_t* address = reinterpret_cast<intptr_t*>(start_address);
1698 for (int reg = vd; reg < vd + num_regs; reg++) {
1699 if (precision == kSinglePrecision) {
1700 if (load) {
1701 set_s_register_from_sinteger(
1702 reg, ReadW(reinterpret_cast<int32_t>(address), instr));
1703 } else {
1704 WriteW(reinterpret_cast<int32_t>(address),
1705 get_sinteger_from_s_register(reg), instr);
1706 }
1707 address += 1;
1708 } else {
1709 if (load) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001710 int32_t data[] = {
1711 ReadW(reinterpret_cast<int32_t>(address), instr),
1712 ReadW(reinterpret_cast<int32_t>(address + 1), instr)
1713 };
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001714 set_d_register(reg, reinterpret_cast<uint32_t*>(data));
Ben Murdoch8b112d22011-06-08 16:22:53 +01001715 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001716 uint32_t data[2];
1717 get_d_register(reg, data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001718 WriteW(reinterpret_cast<int32_t>(address), data[0], instr);
1719 WriteW(reinterpret_cast<int32_t>(address + 1), data[1], instr);
Ben Murdoch8b112d22011-06-08 16:22:53 +01001720 }
1721 address += 2;
1722 }
1723 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001724 DCHECK(reinterpret_cast<intptr_t>(address) - operand_size == end_address);
1725 if (instr->HasW()) {
1726 set_register(instr->RnValue(), rn_val);
1727 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01001728}
1729
1730
Steve Blocka7e24c12009-10-30 11:49:00 +00001731// Calls into the V8 runtime are based on this very simple interface.
1732// Note: To be able to return two values from some calls the code in runtime.cc
1733// uses the ObjectPair which is essentially two 32-bit values stuffed into a
1734// 64-bit value. With the code below we assume that all runtime calls return
1735// 64 bits of result. If they don't, the r1 result register contains a bogus
1736// value, which is fine because it is caller-saved.
1737typedef int64_t (*SimulatorRuntimeCall)(int32_t arg0,
1738 int32_t arg1,
1739 int32_t arg2,
Ben Murdochb0fe1622011-05-05 13:52:32 +01001740 int32_t arg3,
Steve Block44f0eee2011-05-26 01:26:41 +01001741 int32_t arg4,
1742 int32_t arg5);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001743
Ben Murdoch097c5b22016-05-18 11:27:45 +01001744typedef ObjectTriple (*SimulatorRuntimeTripleCall)(int32_t arg0, int32_t arg1,
1745 int32_t arg2, int32_t arg3,
1746 int32_t arg4);
1747
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001748// These prototypes handle the four types of FP calls.
1749typedef int64_t (*SimulatorRuntimeCompareCall)(double darg0, double darg1);
1750typedef double (*SimulatorRuntimeFPFPCall)(double darg0, double darg1);
1751typedef double (*SimulatorRuntimeFPCall)(double darg0);
1752typedef double (*SimulatorRuntimeFPIntCall)(double darg0, int32_t arg0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001753
Steve Block1e0659c2011-05-24 12:43:12 +01001754// This signature supports direct call in to API function native callback
1755// (refer to InvocationCallback in v8.h).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001756typedef void (*SimulatorRuntimeDirectApiCall)(int32_t arg0);
1757typedef void (*SimulatorRuntimeProfilingApiCall)(int32_t arg0, void* arg1);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001758
1759// This signature supports direct call to accessor getter callback.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001760typedef void (*SimulatorRuntimeDirectGetterCall)(int32_t arg0, int32_t arg1);
1761typedef void (*SimulatorRuntimeProfilingGetterCall)(
1762 int32_t arg0, int32_t arg1, void* arg2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001763
1764// Software interrupt instructions are used by the simulator to call into the
1765// C-based V8 runtime.
Steve Block1e0659c2011-05-24 12:43:12 +01001766void Simulator::SoftwareInterrupt(Instruction* instr) {
1767 int svc = instr->SvcValue();
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001768 switch (svc) {
Steve Block1e0659c2011-05-24 12:43:12 +01001769 case kCallRtRedirected: {
Steve Block6ded16b2010-05-10 14:33:55 +01001770 // Check if stack is aligned. Error if not aligned is reported below to
1771 // include information on the function called.
1772 bool stack_aligned =
1773 (get_register(sp)
1774 & (::v8::internal::FLAG_sim_stack_alignment - 1)) == 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00001775 Redirection* redirection = Redirection::FromSwiInstruction(instr);
1776 int32_t arg0 = get_register(r0);
1777 int32_t arg1 = get_register(r1);
1778 int32_t arg2 = get_register(r2);
1779 int32_t arg3 = get_register(r3);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001780 int32_t* stack_pointer = reinterpret_cast<int32_t*>(get_register(sp));
Steve Block44f0eee2011-05-26 01:26:41 +01001781 int32_t arg4 = stack_pointer[0];
1782 int32_t arg5 = stack_pointer[1];
Ben Murdoch257744e2011-11-30 15:57:28 +00001783 bool fp_call =
1784 (redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) ||
1785 (redirection->type() == ExternalReference::BUILTIN_COMPARE_CALL) ||
1786 (redirection->type() == ExternalReference::BUILTIN_FP_CALL) ||
1787 (redirection->type() == ExternalReference::BUILTIN_FP_INT_CALL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001788 // This is dodgy but it works because the C entry stubs are never moved.
1789 // See comment in codegen-arm.cc and bug 1242173.
1790 int32_t saved_lr = get_register(lr);
Steve Block1e0659c2011-05-24 12:43:12 +01001791 intptr_t external =
1792 reinterpret_cast<intptr_t>(redirection->external_function());
Ben Murdoch257744e2011-11-30 15:57:28 +00001793 if (fp_call) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001794 double dval0, dval1; // one or two double parameters
1795 int32_t ival; // zero or one integer parameters
1796 int64_t iresult = 0; // integer return value
1797 double dresult = 0; // double return value
1798 GetFpArgs(&dval0, &dval1, &ival);
Steve Block6ded16b2010-05-10 14:33:55 +01001799 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001800 SimulatorRuntimeCall generic_target =
1801 reinterpret_cast<SimulatorRuntimeCall>(external);
Ben Murdoch257744e2011-11-30 15:57:28 +00001802 switch (redirection->type()) {
1803 case ExternalReference::BUILTIN_FP_FP_CALL:
1804 case ExternalReference::BUILTIN_COMPARE_CALL:
Ben Murdoch257744e2011-11-30 15:57:28 +00001805 PrintF("Call to host function at %p with args %f, %f",
Ben Murdoch61f157c2016-09-16 13:49:30 +01001806 static_cast<void*>(FUNCTION_ADDR(generic_target)), dval0,
1807 dval1);
Ben Murdoch257744e2011-11-30 15:57:28 +00001808 break;
1809 case ExternalReference::BUILTIN_FP_CALL:
Ben Murdoch257744e2011-11-30 15:57:28 +00001810 PrintF("Call to host function at %p with arg %f",
Ben Murdoch61f157c2016-09-16 13:49:30 +01001811 static_cast<void*>(FUNCTION_ADDR(generic_target)), dval0);
Ben Murdoch257744e2011-11-30 15:57:28 +00001812 break;
1813 case ExternalReference::BUILTIN_FP_INT_CALL:
Ben Murdoch257744e2011-11-30 15:57:28 +00001814 PrintF("Call to host function at %p with args %f, %d",
Ben Murdoch61f157c2016-09-16 13:49:30 +01001815 static_cast<void*>(FUNCTION_ADDR(generic_target)), dval0,
1816 ival);
Ben Murdoch257744e2011-11-30 15:57:28 +00001817 break;
1818 default:
1819 UNREACHABLE();
1820 break;
1821 }
Steve Block6ded16b2010-05-10 14:33:55 +01001822 if (!stack_aligned) {
1823 PrintF(" with unaligned stack %08x\n", get_register(sp));
1824 }
1825 PrintF("\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00001826 }
Steve Block6ded16b2010-05-10 14:33:55 +01001827 CHECK(stack_aligned);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001828 switch (redirection->type()) {
1829 case ExternalReference::BUILTIN_COMPARE_CALL: {
1830 SimulatorRuntimeCompareCall target =
1831 reinterpret_cast<SimulatorRuntimeCompareCall>(external);
1832 iresult = target(dval0, dval1);
1833 set_register(r0, static_cast<int32_t>(iresult));
1834 set_register(r1, static_cast<int32_t>(iresult >> 32));
1835 break;
1836 }
1837 case ExternalReference::BUILTIN_FP_FP_CALL: {
1838 SimulatorRuntimeFPFPCall target =
1839 reinterpret_cast<SimulatorRuntimeFPFPCall>(external);
1840 dresult = target(dval0, dval1);
1841 SetFpResult(dresult);
1842 break;
1843 }
1844 case ExternalReference::BUILTIN_FP_CALL: {
Ben Murdoch257744e2011-11-30 15:57:28 +00001845 SimulatorRuntimeFPCall target =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001846 reinterpret_cast<SimulatorRuntimeFPCall>(external);
1847 dresult = target(dval0);
1848 SetFpResult(dresult);
1849 break;
1850 }
1851 case ExternalReference::BUILTIN_FP_INT_CALL: {
1852 SimulatorRuntimeFPIntCall target =
1853 reinterpret_cast<SimulatorRuntimeFPIntCall>(external);
1854 dresult = target(dval0, ival);
1855 SetFpResult(dresult);
1856 break;
1857 }
1858 default:
1859 UNREACHABLE();
1860 break;
1861 }
1862 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
1863 switch (redirection->type()) {
1864 case ExternalReference::BUILTIN_COMPARE_CALL:
1865 PrintF("Returned %08x\n", static_cast<int32_t>(iresult));
1866 break;
1867 case ExternalReference::BUILTIN_FP_FP_CALL:
1868 case ExternalReference::BUILTIN_FP_CALL:
1869 case ExternalReference::BUILTIN_FP_INT_CALL:
1870 PrintF("Returned %f\n", dresult);
1871 break;
1872 default:
1873 UNREACHABLE();
1874 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00001875 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001876 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001877 } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) {
Steve Block1e0659c2011-05-24 12:43:12 +01001878 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001879 PrintF("Call to host function at %p args %08x",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001880 reinterpret_cast<void*>(external), arg0);
Steve Block1e0659c2011-05-24 12:43:12 +01001881 if (!stack_aligned) {
1882 PrintF(" with unaligned stack %08x\n", get_register(sp));
1883 }
1884 PrintF("\n");
1885 }
1886 CHECK(stack_aligned);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001887 SimulatorRuntimeDirectApiCall target =
1888 reinterpret_cast<SimulatorRuntimeDirectApiCall>(external);
1889 target(arg0);
1890 } else if (
1891 redirection->type() == ExternalReference::PROFILING_API_CALL) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001892 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
1893 PrintF("Call to host function at %p args %08x %08x",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001894 reinterpret_cast<void*>(external), arg0, arg1);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001895 if (!stack_aligned) {
1896 PrintF(" with unaligned stack %08x\n", get_register(sp));
1897 }
1898 PrintF("\n");
1899 }
1900 CHECK(stack_aligned);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001901 SimulatorRuntimeProfilingApiCall target =
1902 reinterpret_cast<SimulatorRuntimeProfilingApiCall>(external);
1903 target(arg0, Redirection::ReverseRedirection(arg1));
1904 } else if (
1905 redirection->type() == ExternalReference::DIRECT_GETTER_CALL) {
1906 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
1907 PrintF("Call to host function at %p args %08x %08x",
1908 reinterpret_cast<void*>(external), arg0, arg1);
1909 if (!stack_aligned) {
1910 PrintF(" with unaligned stack %08x\n", get_register(sp));
1911 }
1912 PrintF("\n");
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001913 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001914 CHECK(stack_aligned);
1915 SimulatorRuntimeDirectGetterCall target =
1916 reinterpret_cast<SimulatorRuntimeDirectGetterCall>(external);
1917 target(arg0, arg1);
1918 } else if (
1919 redirection->type() == ExternalReference::PROFILING_GETTER_CALL) {
1920 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
1921 PrintF("Call to host function at %p args %08x %08x %08x",
1922 reinterpret_cast<void*>(external), arg0, arg1, arg2);
1923 if (!stack_aligned) {
1924 PrintF(" with unaligned stack %08x\n", get_register(sp));
1925 }
1926 PrintF("\n");
1927 }
1928 CHECK(stack_aligned);
1929 SimulatorRuntimeProfilingGetterCall target =
1930 reinterpret_cast<SimulatorRuntimeProfilingGetterCall>(
1931 external);
1932 target(arg0, arg1, Redirection::ReverseRedirection(arg2));
Ben Murdoch097c5b22016-05-18 11:27:45 +01001933 } else if (redirection->type() ==
1934 ExternalReference::BUILTIN_CALL_TRIPLE) {
1935 // builtin call returning ObjectTriple.
1936 SimulatorRuntimeTripleCall target =
1937 reinterpret_cast<SimulatorRuntimeTripleCall>(external);
1938 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
1939 PrintF(
1940 "Call to host triple returning runtime function %p "
1941 "args %08x, %08x, %08x, %08x, %08x",
Ben Murdoch61f157c2016-09-16 13:49:30 +01001942 static_cast<void*>(FUNCTION_ADDR(target)), arg1, arg2, arg3, arg4,
1943 arg5);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001944 if (!stack_aligned) {
1945 PrintF(" with unaligned stack %08x\n", get_register(sp));
1946 }
1947 PrintF("\n");
1948 }
1949 CHECK(stack_aligned);
1950 // arg0 is a hidden argument pointing to the return location, so don't
1951 // pass it to the target function.
1952 ObjectTriple result = target(arg1, arg2, arg3, arg4, arg5);
1953 if (::v8::internal::FLAG_trace_sim) {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001954 PrintF("Returned { %p, %p, %p }\n", static_cast<void*>(result.x),
1955 static_cast<void*>(result.y), static_cast<void*>(result.z));
Ben Murdoch097c5b22016-05-18 11:27:45 +01001956 }
1957 // Return is passed back in address pointed to by hidden first argument.
1958 ObjectTriple* sim_result = reinterpret_cast<ObjectTriple*>(arg0);
1959 *sim_result = result;
1960 set_register(r0, arg0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001961 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01001962 // builtin call.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001963 DCHECK(redirection->type() == ExternalReference::BUILTIN_CALL ||
1964 redirection->type() == ExternalReference::BUILTIN_CALL_PAIR);
Steve Blocka7e24c12009-10-30 11:49:00 +00001965 SimulatorRuntimeCall target =
1966 reinterpret_cast<SimulatorRuntimeCall>(external);
Steve Block6ded16b2010-05-10 14:33:55 +01001967 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001968 PrintF(
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001969 "Call to host function at %p "
Steve Block44f0eee2011-05-26 01:26:41 +01001970 "args %08x, %08x, %08x, %08x, %08x, %08x",
Ben Murdoch61f157c2016-09-16 13:49:30 +01001971 static_cast<void*>(FUNCTION_ADDR(target)), arg0, arg1, arg2, arg3,
1972 arg4, arg5);
Steve Block6ded16b2010-05-10 14:33:55 +01001973 if (!stack_aligned) {
1974 PrintF(" with unaligned stack %08x\n", get_register(sp));
1975 }
1976 PrintF("\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00001977 }
Steve Block6ded16b2010-05-10 14:33:55 +01001978 CHECK(stack_aligned);
Steve Block44f0eee2011-05-26 01:26:41 +01001979 int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5);
Steve Blocka7e24c12009-10-30 11:49:00 +00001980 int32_t lo_res = static_cast<int32_t>(result);
1981 int32_t hi_res = static_cast<int32_t>(result >> 32);
1982 if (::v8::internal::FLAG_trace_sim) {
1983 PrintF("Returned %08x\n", lo_res);
1984 }
1985 set_register(r0, lo_res);
1986 set_register(r1, hi_res);
1987 }
1988 set_register(lr, saved_lr);
1989 set_pc(get_register(lr));
1990 break;
1991 }
Steve Block1e0659c2011-05-24 12:43:12 +01001992 case kBreakpoint: {
Steve Block44f0eee2011-05-26 01:26:41 +01001993 ArmDebugger dbg(this);
Steve Blocka7e24c12009-10-30 11:49:00 +00001994 dbg.Debug();
1995 break;
1996 }
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001997 // stop uses all codes greater than 1 << 23.
Steve Blocka7e24c12009-10-30 11:49:00 +00001998 default: {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001999 if (svc >= (1 << 23)) {
2000 uint32_t code = svc & kStopCodeMask;
2001 if (isWatchedStop(code)) {
2002 IncreaseStopCounter(code);
2003 }
2004 // Stop if it is enabled, otherwise go on jumping over the stop
2005 // and the message address.
2006 if (isEnabledStop(code)) {
Steve Block44f0eee2011-05-26 01:26:41 +01002007 ArmDebugger dbg(this);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002008 dbg.Stop(instr);
2009 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01002010 set_pc(get_pc() + 2 * Instruction::kInstrSize);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002011 }
2012 } else {
2013 // This is not a valid svc code.
2014 UNREACHABLE();
2015 break;
2016 }
2017 }
2018 }
2019}
2020
2021
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002022float Simulator::canonicalizeNaN(float value) {
2023 // Default NaN value, see "NaN handling" in "IEEE 754 standard implementation
2024 // choices" of the ARM Reference Manual.
2025 const uint32_t kDefaultNaN = 0x7FC00000u;
2026 if (FPSCR_default_NaN_mode_ && std::isnan(value)) {
2027 value = bit_cast<float>(kDefaultNaN);
2028 }
2029 return value;
2030}
2031
2032
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002033double Simulator::canonicalizeNaN(double value) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002034 // Default NaN value, see "NaN handling" in "IEEE 754 standard implementation
2035 // choices" of the ARM Reference Manual.
2036 const uint64_t kDefaultNaN = V8_UINT64_C(0x7FF8000000000000);
2037 if (FPSCR_default_NaN_mode_ && std::isnan(value)) {
2038 value = bit_cast<double>(kDefaultNaN);
2039 }
2040 return value;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002041}
2042
2043
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002044// Stop helper functions.
Steve Block1e0659c2011-05-24 12:43:12 +01002045bool Simulator::isStopInstruction(Instruction* instr) {
2046 return (instr->Bits(27, 24) == 0xF) && (instr->SvcValue() >= kStopCode);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002047}
2048
2049
2050bool Simulator::isWatchedStop(uint32_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002051 DCHECK(code <= kMaxStopCode);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002052 return code < kNumOfWatchedStops;
2053}
2054
2055
2056bool Simulator::isEnabledStop(uint32_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002057 DCHECK(code <= kMaxStopCode);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002058 // Unwatched stops are always enabled.
2059 return !isWatchedStop(code) ||
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002060 !(watched_stops_[code].count & kStopDisabledBit);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002061}
2062
2063
2064void Simulator::EnableStop(uint32_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002065 DCHECK(isWatchedStop(code));
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002066 if (!isEnabledStop(code)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002067 watched_stops_[code].count &= ~kStopDisabledBit;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002068 }
2069}
2070
2071
2072void Simulator::DisableStop(uint32_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002073 DCHECK(isWatchedStop(code));
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002074 if (isEnabledStop(code)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002075 watched_stops_[code].count |= kStopDisabledBit;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002076 }
2077}
2078
2079
2080void Simulator::IncreaseStopCounter(uint32_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002081 DCHECK(code <= kMaxStopCode);
2082 DCHECK(isWatchedStop(code));
2083 if ((watched_stops_[code].count & ~(1 << 31)) == 0x7fffffff) {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002084 PrintF("Stop counter for code %i has overflowed.\n"
2085 "Enabling this code and reseting the counter to 0.\n", code);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002086 watched_stops_[code].count = 0;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002087 EnableStop(code);
2088 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002089 watched_stops_[code].count++;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002090 }
2091}
2092
2093
2094// Print a stop status.
2095void Simulator::PrintStopInfo(uint32_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002096 DCHECK(code <= kMaxStopCode);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002097 if (!isWatchedStop(code)) {
2098 PrintF("Stop not watched.");
2099 } else {
2100 const char* state = isEnabledStop(code) ? "Enabled" : "Disabled";
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002101 int32_t count = watched_stops_[code].count & ~kStopDisabledBit;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002102 // Don't print the state of unused breakpoints.
2103 if (count != 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002104 if (watched_stops_[code].desc) {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002105 PrintF("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002106 code, code, state, count, watched_stops_[code].desc);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002107 } else {
2108 PrintF("stop %i - 0x%x: \t%s, \tcounter = %i\n",
2109 code, code, state, count);
2110 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002111 }
2112 }
2113}
2114
2115
2116// Handle execution based on instruction types.
2117
2118// Instruction types 0 and 1 are both rolled into one function because they
2119// only differ in the handling of the shifter_operand.
Steve Block1e0659c2011-05-24 12:43:12 +01002120void Simulator::DecodeType01(Instruction* instr) {
2121 int type = instr->TypeValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00002122 if ((type == 0) && instr->IsSpecialType0()) {
2123 // multiply instruction or extra loads and stores
2124 if (instr->Bits(7, 4) == 9) {
2125 if (instr->Bit(24) == 0) {
2126 // Raw field decoding here. Multiply instructions have their Rd in
2127 // funny places.
Steve Block1e0659c2011-05-24 12:43:12 +01002128 int rn = instr->RnValue();
2129 int rm = instr->RmValue();
2130 int rs = instr->RsValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00002131 int32_t rs_val = get_register(rs);
2132 int32_t rm_val = get_register(rm);
2133 if (instr->Bit(23) == 0) {
2134 if (instr->Bit(21) == 0) {
2135 // The MUL instruction description (A 4.1.33) refers to Rd as being
2136 // the destination for the operation, but it confusingly uses the
2137 // Rn field to encode it.
2138 // Format(instr, "mul'cond's 'rn, 'rm, 'rs");
2139 int rd = rn; // Remap the rn field to the Rd register.
2140 int32_t alu_out = rm_val * rs_val;
2141 set_register(rd, alu_out);
2142 if (instr->HasS()) {
2143 SetNZFlags(alu_out);
2144 }
2145 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002146 int rd = instr->RdValue();
2147 int32_t acc_value = get_register(rd);
2148 if (instr->Bit(22) == 0) {
2149 // The MLA instruction description (A 4.1.28) refers to the order
2150 // of registers as "Rd, Rm, Rs, Rn". But confusingly it uses the
2151 // Rn field to encode the Rd register and the Rd field to encode
2152 // the Rn register.
2153 // Format(instr, "mla'cond's 'rn, 'rm, 'rs, 'rd");
2154 int32_t mul_out = rm_val * rs_val;
2155 int32_t result = acc_value + mul_out;
2156 set_register(rn, result);
2157 } else {
2158 // Format(instr, "mls'cond's 'rn, 'rm, 'rs, 'rd");
2159 int32_t mul_out = rm_val * rs_val;
2160 int32_t result = acc_value - mul_out;
2161 set_register(rn, result);
2162 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002163 }
2164 } else {
2165 // The signed/long multiply instructions use the terms RdHi and RdLo
2166 // when referring to the target registers. They are mapped to the Rn
2167 // and Rd fields as follows:
2168 // RdLo == Rd
2169 // RdHi == Rn (This is confusingly stored in variable rd here
2170 // because the mul instruction from above uses the
2171 // Rn field to encode the Rd register. Good luck figuring
2172 // this out without reading the ARM instruction manual
2173 // at a very detailed level.)
2174 // Format(instr, "'um'al'cond's 'rd, 'rn, 'rs, 'rm");
2175 int rd_hi = rn; // Remap the rn field to the RdHi register.
Steve Block1e0659c2011-05-24 12:43:12 +01002176 int rd_lo = instr->RdValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00002177 int32_t hi_res = 0;
2178 int32_t lo_res = 0;
2179 if (instr->Bit(22) == 1) {
2180 int64_t left_op = static_cast<int32_t>(rm_val);
2181 int64_t right_op = static_cast<int32_t>(rs_val);
2182 uint64_t result = left_op * right_op;
2183 hi_res = static_cast<int32_t>(result >> 32);
2184 lo_res = static_cast<int32_t>(result & 0xffffffff);
2185 } else {
2186 // unsigned multiply
2187 uint64_t left_op = static_cast<uint32_t>(rm_val);
2188 uint64_t right_op = static_cast<uint32_t>(rs_val);
2189 uint64_t result = left_op * right_op;
2190 hi_res = static_cast<int32_t>(result >> 32);
2191 lo_res = static_cast<int32_t>(result & 0xffffffff);
2192 }
2193 set_register(rd_lo, lo_res);
2194 set_register(rd_hi, hi_res);
2195 if (instr->HasS()) {
2196 UNIMPLEMENTED();
2197 }
2198 }
2199 } else {
Steve Blockd0582a62009-12-15 09:54:21 +00002200 UNIMPLEMENTED(); // Not used by V8.
Steve Blocka7e24c12009-10-30 11:49:00 +00002201 }
2202 } else {
2203 // extra load/store instructions
Steve Block1e0659c2011-05-24 12:43:12 +01002204 int rd = instr->RdValue();
2205 int rn = instr->RnValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00002206 int32_t rn_val = get_register(rn);
2207 int32_t addr = 0;
2208 if (instr->Bit(22) == 0) {
Steve Block1e0659c2011-05-24 12:43:12 +01002209 int rm = instr->RmValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00002210 int32_t rm_val = get_register(rm);
2211 switch (instr->PUField()) {
Steve Block1e0659c2011-05-24 12:43:12 +01002212 case da_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002213 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], -'rm");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002214 DCHECK(!instr->HasW());
Steve Blocka7e24c12009-10-30 11:49:00 +00002215 addr = rn_val;
2216 rn_val -= rm_val;
2217 set_register(rn, rn_val);
2218 break;
2219 }
Steve Block1e0659c2011-05-24 12:43:12 +01002220 case ia_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002221 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], +'rm");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002222 DCHECK(!instr->HasW());
Steve Blocka7e24c12009-10-30 11:49:00 +00002223 addr = rn_val;
2224 rn_val += rm_val;
2225 set_register(rn, rn_val);
2226 break;
2227 }
Steve Block1e0659c2011-05-24 12:43:12 +01002228 case db_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002229 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, -'rm]'w");
2230 rn_val -= rm_val;
2231 addr = rn_val;
2232 if (instr->HasW()) {
2233 set_register(rn, rn_val);
2234 }
2235 break;
2236 }
Steve Block1e0659c2011-05-24 12:43:12 +01002237 case ib_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002238 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, +'rm]'w");
2239 rn_val += rm_val;
2240 addr = rn_val;
2241 if (instr->HasW()) {
2242 set_register(rn, rn_val);
2243 }
2244 break;
2245 }
2246 default: {
2247 // The PU field is a 2-bit field.
2248 UNREACHABLE();
2249 break;
2250 }
2251 }
2252 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01002253 int32_t imm_val = (instr->ImmedHValue() << 4) | instr->ImmedLValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00002254 switch (instr->PUField()) {
Steve Block1e0659c2011-05-24 12:43:12 +01002255 case da_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002256 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], #-'off8");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002257 DCHECK(!instr->HasW());
Steve Blocka7e24c12009-10-30 11:49:00 +00002258 addr = rn_val;
2259 rn_val -= imm_val;
2260 set_register(rn, rn_val);
2261 break;
2262 }
Steve Block1e0659c2011-05-24 12:43:12 +01002263 case ia_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002264 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], #+'off8");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002265 DCHECK(!instr->HasW());
Steve Blocka7e24c12009-10-30 11:49:00 +00002266 addr = rn_val;
2267 rn_val += imm_val;
2268 set_register(rn, rn_val);
2269 break;
2270 }
Steve Block1e0659c2011-05-24 12:43:12 +01002271 case db_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002272 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, #-'off8]'w");
2273 rn_val -= imm_val;
2274 addr = rn_val;
2275 if (instr->HasW()) {
2276 set_register(rn, rn_val);
2277 }
2278 break;
2279 }
Steve Block1e0659c2011-05-24 12:43:12 +01002280 case ib_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002281 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, #+'off8]'w");
2282 rn_val += imm_val;
2283 addr = rn_val;
2284 if (instr->HasW()) {
2285 set_register(rn, rn_val);
2286 }
2287 break;
2288 }
2289 default: {
2290 // The PU field is a 2-bit field.
2291 UNREACHABLE();
2292 break;
2293 }
2294 }
2295 }
Kristian Monsen25f61362010-05-21 11:50:48 +01002296 if (((instr->Bits(7, 4) & 0xd) == 0xd) && (instr->Bit(20) == 0)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002297 DCHECK((rd % 2) == 0);
Kristian Monsen25f61362010-05-21 11:50:48 +01002298 if (instr->HasH()) {
2299 // The strd instruction.
2300 int32_t value1 = get_register(rd);
2301 int32_t value2 = get_register(rd+1);
2302 WriteDW(addr, value1, value2);
2303 } else {
2304 // The ldrd instruction.
2305 int* rn_data = ReadDW(addr);
2306 set_dw_register(rd, rn_data);
2307 }
2308 } else if (instr->HasH()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002309 if (instr->HasSign()) {
2310 if (instr->HasL()) {
2311 int16_t val = ReadH(addr, instr);
2312 set_register(rd, val);
2313 } else {
2314 int16_t val = get_register(rd);
2315 WriteH(addr, val, instr);
2316 }
2317 } else {
2318 if (instr->HasL()) {
2319 uint16_t val = ReadHU(addr, instr);
2320 set_register(rd, val);
2321 } else {
2322 uint16_t val = get_register(rd);
2323 WriteH(addr, val, instr);
2324 }
2325 }
2326 } else {
2327 // signed byte loads
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002328 DCHECK(instr->HasSign());
2329 DCHECK(instr->HasL());
Steve Blocka7e24c12009-10-30 11:49:00 +00002330 int8_t val = ReadB(addr);
2331 set_register(rd, val);
2332 }
2333 return;
2334 }
Steve Block6ded16b2010-05-10 14:33:55 +01002335 } else if ((type == 0) && instr->IsMiscType0()) {
Ben Murdochda12d292016-06-02 14:46:10 +01002336 if ((instr->Bits(27, 23) == 2) && (instr->Bits(21, 20) == 2) &&
2337 (instr->Bits(15, 4) == 0xf00)) {
2338 // MSR
2339 int rm = instr->RmValue();
2340 DCHECK_NE(pc, rm); // UNPREDICTABLE
2341 SRegisterFieldMask sreg_and_mask =
2342 instr->BitField(22, 22) | instr->BitField(19, 16);
2343 SetSpecialRegister(sreg_and_mask, get_register(rm));
2344 } else if ((instr->Bits(27, 23) == 2) && (instr->Bits(21, 20) == 0) &&
2345 (instr->Bits(11, 0) == 0)) {
2346 // MRS
2347 int rd = instr->RdValue();
2348 DCHECK_NE(pc, rd); // UNPREDICTABLE
2349 SRegister sreg = static_cast<SRegister>(instr->BitField(22, 22));
2350 set_register(rd, GetFromSpecialRegister(sreg));
2351 } else if (instr->Bits(22, 21) == 1) {
Steve Block1e0659c2011-05-24 12:43:12 +01002352 int rm = instr->RmValue();
2353 switch (instr->BitField(7, 4)) {
Steve Block6ded16b2010-05-10 14:33:55 +01002354 case BX:
2355 set_pc(get_register(rm));
2356 break;
2357 case BLX: {
2358 uint32_t old_pc = get_pc();
2359 set_pc(get_register(rm));
Steve Block1e0659c2011-05-24 12:43:12 +01002360 set_register(lr, old_pc + Instruction::kInstrSize);
Steve Block6ded16b2010-05-10 14:33:55 +01002361 break;
2362 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01002363 case BKPT: {
Steve Block44f0eee2011-05-26 01:26:41 +01002364 ArmDebugger dbg(this);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002365 PrintF("Simulator hit BKPT.\n");
2366 dbg.Debug();
Steve Block6ded16b2010-05-10 14:33:55 +01002367 break;
Ben Murdochb0fe1622011-05-05 13:52:32 +01002368 }
Steve Block6ded16b2010-05-10 14:33:55 +01002369 default:
2370 UNIMPLEMENTED();
2371 }
2372 } else if (instr->Bits(22, 21) == 3) {
Steve Block1e0659c2011-05-24 12:43:12 +01002373 int rm = instr->RmValue();
2374 int rd = instr->RdValue();
2375 switch (instr->BitField(7, 4)) {
Steve Block6ded16b2010-05-10 14:33:55 +01002376 case CLZ: {
2377 uint32_t bits = get_register(rm);
2378 int leading_zeros = 0;
2379 if (bits == 0) {
2380 leading_zeros = 32;
2381 } else {
2382 while ((bits & 0x80000000u) == 0) {
2383 bits <<= 1;
2384 leading_zeros++;
2385 }
2386 }
2387 set_register(rd, leading_zeros);
2388 break;
2389 }
2390 default:
2391 UNIMPLEMENTED();
2392 }
2393 } else {
2394 PrintF("%08x\n", instr->InstructionBits());
2395 UNIMPLEMENTED();
2396 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002397 } else if ((type == 1) && instr->IsNopType1()) {
2398 // NOP.
Steve Blocka7e24c12009-10-30 11:49:00 +00002399 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01002400 int rd = instr->RdValue();
2401 int rn = instr->RnValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00002402 int32_t rn_val = get_register(rn);
2403 int32_t shifter_operand = 0;
2404 bool shifter_carry_out = 0;
2405 if (type == 0) {
2406 shifter_operand = GetShiftRm(instr, &shifter_carry_out);
2407 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002408 DCHECK(instr->TypeValue() == 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00002409 shifter_operand = GetImm(instr, &shifter_carry_out);
2410 }
2411 int32_t alu_out;
2412
2413 switch (instr->OpcodeField()) {
2414 case AND: {
2415 // Format(instr, "and'cond's 'rd, 'rn, 'shift_rm");
2416 // Format(instr, "and'cond's 'rd, 'rn, 'imm");
2417 alu_out = rn_val & shifter_operand;
2418 set_register(rd, alu_out);
2419 if (instr->HasS()) {
2420 SetNZFlags(alu_out);
2421 SetCFlag(shifter_carry_out);
2422 }
2423 break;
2424 }
2425
2426 case EOR: {
2427 // Format(instr, "eor'cond's 'rd, 'rn, 'shift_rm");
2428 // Format(instr, "eor'cond's 'rd, 'rn, 'imm");
2429 alu_out = rn_val ^ shifter_operand;
2430 set_register(rd, alu_out);
2431 if (instr->HasS()) {
2432 SetNZFlags(alu_out);
2433 SetCFlag(shifter_carry_out);
2434 }
2435 break;
2436 }
2437
2438 case SUB: {
2439 // Format(instr, "sub'cond's 'rd, 'rn, 'shift_rm");
2440 // Format(instr, "sub'cond's 'rd, 'rn, 'imm");
2441 alu_out = rn_val - shifter_operand;
2442 set_register(rd, alu_out);
2443 if (instr->HasS()) {
2444 SetNZFlags(alu_out);
2445 SetCFlag(!BorrowFrom(rn_val, shifter_operand));
2446 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, false));
2447 }
2448 break;
2449 }
2450
2451 case RSB: {
2452 // Format(instr, "rsb'cond's 'rd, 'rn, 'shift_rm");
2453 // Format(instr, "rsb'cond's 'rd, 'rn, 'imm");
2454 alu_out = shifter_operand - rn_val;
2455 set_register(rd, alu_out);
2456 if (instr->HasS()) {
2457 SetNZFlags(alu_out);
2458 SetCFlag(!BorrowFrom(shifter_operand, rn_val));
2459 SetVFlag(OverflowFrom(alu_out, shifter_operand, rn_val, false));
2460 }
2461 break;
2462 }
2463
2464 case ADD: {
2465 // Format(instr, "add'cond's 'rd, 'rn, 'shift_rm");
2466 // Format(instr, "add'cond's 'rd, 'rn, 'imm");
2467 alu_out = rn_val + shifter_operand;
2468 set_register(rd, alu_out);
2469 if (instr->HasS()) {
2470 SetNZFlags(alu_out);
2471 SetCFlag(CarryFrom(rn_val, shifter_operand));
2472 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, true));
2473 }
2474 break;
2475 }
2476
2477 case ADC: {
Ben Murdoch257744e2011-11-30 15:57:28 +00002478 // Format(instr, "adc'cond's 'rd, 'rn, 'shift_rm");
2479 // Format(instr, "adc'cond's 'rd, 'rn, 'imm");
2480 alu_out = rn_val + shifter_operand + GetCarry();
2481 set_register(rd, alu_out);
2482 if (instr->HasS()) {
2483 SetNZFlags(alu_out);
2484 SetCFlag(CarryFrom(rn_val, shifter_operand, GetCarry()));
2485 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, true));
2486 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002487 break;
2488 }
2489
2490 case SBC: {
Ben Murdochda12d292016-06-02 14:46:10 +01002491 // Format(instr, "sbc'cond's 'rd, 'rn, 'shift_rm");
2492 // Format(instr, "sbc'cond's 'rd, 'rn, 'imm");
2493 alu_out = (rn_val - shifter_operand) - (GetCarry() ? 0 : 1);
2494 set_register(rd, alu_out);
2495 if (instr->HasS()) {
2496 SetNZFlags(alu_out);
2497 SetCFlag(!BorrowFrom(rn_val, shifter_operand, GetCarry()));
2498 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, false));
2499 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002500 break;
2501 }
2502
2503 case RSC: {
2504 Format(instr, "rsc'cond's 'rd, 'rn, 'shift_rm");
2505 Format(instr, "rsc'cond's 'rd, 'rn, 'imm");
2506 break;
2507 }
2508
2509 case TST: {
2510 if (instr->HasS()) {
2511 // Format(instr, "tst'cond 'rn, 'shift_rm");
2512 // Format(instr, "tst'cond 'rn, 'imm");
2513 alu_out = rn_val & shifter_operand;
2514 SetNZFlags(alu_out);
2515 SetCFlag(shifter_carry_out);
2516 } else {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002517 // Format(instr, "movw'cond 'rd, 'imm").
Steve Block1e0659c2011-05-24 12:43:12 +01002518 alu_out = instr->ImmedMovwMovtValue();
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002519 set_register(rd, alu_out);
Steve Blocka7e24c12009-10-30 11:49:00 +00002520 }
2521 break;
2522 }
2523
2524 case TEQ: {
2525 if (instr->HasS()) {
2526 // Format(instr, "teq'cond 'rn, 'shift_rm");
2527 // Format(instr, "teq'cond 'rn, 'imm");
2528 alu_out = rn_val ^ shifter_operand;
2529 SetNZFlags(alu_out);
2530 SetCFlag(shifter_carry_out);
2531 } else {
Steve Block6ded16b2010-05-10 14:33:55 +01002532 // Other instructions matching this pattern are handled in the
2533 // miscellaneous instructions part above.
2534 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +00002535 }
2536 break;
2537 }
2538
2539 case CMP: {
2540 if (instr->HasS()) {
2541 // Format(instr, "cmp'cond 'rn, 'shift_rm");
2542 // Format(instr, "cmp'cond 'rn, 'imm");
2543 alu_out = rn_val - shifter_operand;
2544 SetNZFlags(alu_out);
2545 SetCFlag(!BorrowFrom(rn_val, shifter_operand));
2546 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, false));
2547 } else {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002548 // Format(instr, "movt'cond 'rd, 'imm").
2549 alu_out = (get_register(rd) & 0xffff) |
Steve Block1e0659c2011-05-24 12:43:12 +01002550 (instr->ImmedMovwMovtValue() << 16);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002551 set_register(rd, alu_out);
Steve Blocka7e24c12009-10-30 11:49:00 +00002552 }
2553 break;
2554 }
2555
2556 case CMN: {
2557 if (instr->HasS()) {
2558 // Format(instr, "cmn'cond 'rn, 'shift_rm");
2559 // Format(instr, "cmn'cond 'rn, 'imm");
2560 alu_out = rn_val + shifter_operand;
2561 SetNZFlags(alu_out);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002562 SetCFlag(CarryFrom(rn_val, shifter_operand));
Steve Blocka7e24c12009-10-30 11:49:00 +00002563 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, true));
2564 } else {
Steve Block6ded16b2010-05-10 14:33:55 +01002565 // Other instructions matching this pattern are handled in the
2566 // miscellaneous instructions part above.
2567 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +00002568 }
2569 break;
2570 }
2571
2572 case ORR: {
2573 // Format(instr, "orr'cond's 'rd, 'rn, 'shift_rm");
2574 // Format(instr, "orr'cond's 'rd, 'rn, 'imm");
2575 alu_out = rn_val | shifter_operand;
2576 set_register(rd, alu_out);
2577 if (instr->HasS()) {
2578 SetNZFlags(alu_out);
2579 SetCFlag(shifter_carry_out);
2580 }
2581 break;
2582 }
2583
2584 case MOV: {
2585 // Format(instr, "mov'cond's 'rd, 'shift_rm");
2586 // Format(instr, "mov'cond's 'rd, 'imm");
2587 alu_out = shifter_operand;
2588 set_register(rd, alu_out);
2589 if (instr->HasS()) {
2590 SetNZFlags(alu_out);
2591 SetCFlag(shifter_carry_out);
2592 }
2593 break;
2594 }
2595
2596 case BIC: {
2597 // Format(instr, "bic'cond's 'rd, 'rn, 'shift_rm");
2598 // Format(instr, "bic'cond's 'rd, 'rn, 'imm");
2599 alu_out = rn_val & ~shifter_operand;
2600 set_register(rd, alu_out);
2601 if (instr->HasS()) {
2602 SetNZFlags(alu_out);
2603 SetCFlag(shifter_carry_out);
2604 }
2605 break;
2606 }
2607
2608 case MVN: {
2609 // Format(instr, "mvn'cond's 'rd, 'shift_rm");
2610 // Format(instr, "mvn'cond's 'rd, 'imm");
2611 alu_out = ~shifter_operand;
2612 set_register(rd, alu_out);
2613 if (instr->HasS()) {
2614 SetNZFlags(alu_out);
2615 SetCFlag(shifter_carry_out);
2616 }
2617 break;
2618 }
2619
2620 default: {
2621 UNREACHABLE();
2622 break;
2623 }
2624 }
2625 }
2626}
2627
2628
Steve Block1e0659c2011-05-24 12:43:12 +01002629void Simulator::DecodeType2(Instruction* instr) {
2630 int rd = instr->RdValue();
2631 int rn = instr->RnValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00002632 int32_t rn_val = get_register(rn);
Steve Block1e0659c2011-05-24 12:43:12 +01002633 int32_t im_val = instr->Offset12Value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002634 int32_t addr = 0;
2635 switch (instr->PUField()) {
Steve Block1e0659c2011-05-24 12:43:12 +01002636 case da_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002637 // Format(instr, "'memop'cond'b 'rd, ['rn], #-'off12");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002638 DCHECK(!instr->HasW());
Steve Blocka7e24c12009-10-30 11:49:00 +00002639 addr = rn_val;
2640 rn_val -= im_val;
2641 set_register(rn, rn_val);
2642 break;
2643 }
Steve Block1e0659c2011-05-24 12:43:12 +01002644 case ia_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002645 // Format(instr, "'memop'cond'b 'rd, ['rn], #+'off12");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002646 DCHECK(!instr->HasW());
Steve Blocka7e24c12009-10-30 11:49:00 +00002647 addr = rn_val;
2648 rn_val += im_val;
2649 set_register(rn, rn_val);
2650 break;
2651 }
Steve Block1e0659c2011-05-24 12:43:12 +01002652 case db_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002653 // Format(instr, "'memop'cond'b 'rd, ['rn, #-'off12]'w");
2654 rn_val -= im_val;
2655 addr = rn_val;
2656 if (instr->HasW()) {
2657 set_register(rn, rn_val);
2658 }
2659 break;
2660 }
Steve Block1e0659c2011-05-24 12:43:12 +01002661 case ib_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002662 // Format(instr, "'memop'cond'b 'rd, ['rn, #+'off12]'w");
2663 rn_val += im_val;
2664 addr = rn_val;
2665 if (instr->HasW()) {
2666 set_register(rn, rn_val);
2667 }
2668 break;
2669 }
2670 default: {
2671 UNREACHABLE();
2672 break;
2673 }
2674 }
2675 if (instr->HasB()) {
2676 if (instr->HasL()) {
2677 byte val = ReadBU(addr);
2678 set_register(rd, val);
2679 } else {
2680 byte val = get_register(rd);
2681 WriteB(addr, val);
2682 }
2683 } else {
2684 if (instr->HasL()) {
2685 set_register(rd, ReadW(addr, instr));
2686 } else {
2687 WriteW(addr, get_register(rd), instr);
2688 }
2689 }
2690}
2691
2692
Steve Block1e0659c2011-05-24 12:43:12 +01002693void Simulator::DecodeType3(Instruction* instr) {
2694 int rd = instr->RdValue();
2695 int rn = instr->RnValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00002696 int32_t rn_val = get_register(rn);
2697 bool shifter_carry_out = 0;
2698 int32_t shifter_operand = GetShiftRm(instr, &shifter_carry_out);
2699 int32_t addr = 0;
2700 switch (instr->PUField()) {
Steve Block1e0659c2011-05-24 12:43:12 +01002701 case da_x: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002702 DCHECK(!instr->HasW());
Steve Blocka7e24c12009-10-30 11:49:00 +00002703 Format(instr, "'memop'cond'b 'rd, ['rn], -'shift_rm");
Kristian Monsen50ef84f2010-07-29 15:18:00 +01002704 UNIMPLEMENTED();
Steve Blocka7e24c12009-10-30 11:49:00 +00002705 break;
2706 }
Steve Block1e0659c2011-05-24 12:43:12 +01002707 case ia_x: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002708 if (instr->Bit(4) == 0) {
2709 // Memop.
2710 } else {
2711 if (instr->Bit(5) == 0) {
2712 switch (instr->Bits(22, 21)) {
2713 case 0:
2714 if (instr->Bit(20) == 0) {
2715 if (instr->Bit(6) == 0) {
2716 // Pkhbt.
2717 uint32_t rn_val = get_register(rn);
2718 uint32_t rm_val = get_register(instr->RmValue());
2719 int32_t shift = instr->Bits(11, 7);
2720 rm_val <<= shift;
2721 set_register(rd, (rn_val & 0xFFFF) | (rm_val & 0xFFFF0000U));
2722 } else {
2723 // Pkhtb.
2724 uint32_t rn_val = get_register(rn);
2725 int32_t rm_val = get_register(instr->RmValue());
2726 int32_t shift = instr->Bits(11, 7);
2727 if (shift == 0) {
2728 shift = 32;
2729 }
2730 rm_val >>= shift;
2731 set_register(rd, (rn_val & 0xFFFF0000U) | (rm_val & 0xFFFF));
2732 }
2733 } else {
2734 UNIMPLEMENTED();
2735 }
2736 break;
2737 case 1:
2738 UNIMPLEMENTED();
2739 break;
2740 case 2:
2741 UNIMPLEMENTED();
2742 break;
2743 case 3: {
2744 // Usat.
2745 int32_t sat_pos = instr->Bits(20, 16);
2746 int32_t sat_val = (1 << sat_pos) - 1;
2747 int32_t shift = instr->Bits(11, 7);
2748 int32_t shift_type = instr->Bit(6);
2749 int32_t rm_val = get_register(instr->RmValue());
2750 if (shift_type == 0) { // LSL
2751 rm_val <<= shift;
2752 } else { // ASR
2753 rm_val >>= shift;
2754 }
2755 // If saturation occurs, the Q flag should be set in the CPSR.
2756 // There is no Q flag yet, and no instruction (MRS) to read the
2757 // CPSR directly.
2758 if (rm_val > sat_val) {
2759 rm_val = sat_val;
2760 } else if (rm_val < 0) {
2761 rm_val = 0;
2762 }
2763 set_register(rd, rm_val);
2764 break;
2765 }
Kristian Monsen50ef84f2010-07-29 15:18:00 +01002766 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002767 } else {
2768 switch (instr->Bits(22, 21)) {
2769 case 0:
2770 UNIMPLEMENTED();
2771 break;
2772 case 1:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002773 if (instr->Bits(9, 6) == 1) {
2774 if (instr->Bit(20) == 0) {
2775 if (instr->Bits(19, 16) == 0xF) {
2776 // Sxtb.
2777 int32_t rm_val = get_register(instr->RmValue());
2778 int32_t rotate = instr->Bits(11, 10);
2779 switch (rotate) {
2780 case 0:
2781 break;
2782 case 1:
2783 rm_val = (rm_val >> 8) | (rm_val << 24);
2784 break;
2785 case 2:
2786 rm_val = (rm_val >> 16) | (rm_val << 16);
2787 break;
2788 case 3:
2789 rm_val = (rm_val >> 24) | (rm_val << 8);
2790 break;
2791 }
2792 set_register(rd, static_cast<int8_t>(rm_val));
2793 } else {
2794 // Sxtab.
2795 int32_t rn_val = get_register(rn);
2796 int32_t rm_val = get_register(instr->RmValue());
2797 int32_t rotate = instr->Bits(11, 10);
2798 switch (rotate) {
2799 case 0:
2800 break;
2801 case 1:
2802 rm_val = (rm_val >> 8) | (rm_val << 24);
2803 break;
2804 case 2:
2805 rm_val = (rm_val >> 16) | (rm_val << 16);
2806 break;
2807 case 3:
2808 rm_val = (rm_val >> 24) | (rm_val << 8);
2809 break;
2810 }
2811 set_register(rd, rn_val + static_cast<int8_t>(rm_val));
2812 }
2813 } else {
2814 if (instr->Bits(19, 16) == 0xF) {
2815 // Sxth.
2816 int32_t rm_val = get_register(instr->RmValue());
2817 int32_t rotate = instr->Bits(11, 10);
2818 switch (rotate) {
2819 case 0:
2820 break;
2821 case 1:
2822 rm_val = (rm_val >> 8) | (rm_val << 24);
2823 break;
2824 case 2:
2825 rm_val = (rm_val >> 16) | (rm_val << 16);
2826 break;
2827 case 3:
2828 rm_val = (rm_val >> 24) | (rm_val << 8);
2829 break;
2830 }
2831 set_register(rd, static_cast<int16_t>(rm_val));
2832 } else {
2833 // Sxtah.
2834 int32_t rn_val = get_register(rn);
2835 int32_t rm_val = get_register(instr->RmValue());
2836 int32_t rotate = instr->Bits(11, 10);
2837 switch (rotate) {
2838 case 0:
2839 break;
2840 case 1:
2841 rm_val = (rm_val >> 8) | (rm_val << 24);
2842 break;
2843 case 2:
2844 rm_val = (rm_val >> 16) | (rm_val << 16);
2845 break;
2846 case 3:
2847 rm_val = (rm_val >> 24) | (rm_val << 8);
2848 break;
2849 }
2850 set_register(rd, rn_val + static_cast<int16_t>(rm_val));
2851 }
2852 }
2853 } else {
2854 UNREACHABLE();
2855 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002856 break;
2857 case 2:
2858 if ((instr->Bit(20) == 0) && (instr->Bits(9, 6) == 1)) {
2859 if (instr->Bits(19, 16) == 0xF) {
2860 // Uxtb16.
2861 uint32_t rm_val = get_register(instr->RmValue());
2862 int32_t rotate = instr->Bits(11, 10);
2863 switch (rotate) {
2864 case 0:
2865 break;
2866 case 1:
2867 rm_val = (rm_val >> 8) | (rm_val << 24);
2868 break;
2869 case 2:
2870 rm_val = (rm_val >> 16) | (rm_val << 16);
2871 break;
2872 case 3:
2873 rm_val = (rm_val >> 24) | (rm_val << 8);
2874 break;
2875 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002876 set_register(rd, (rm_val & 0xFF) | (rm_val & 0xFF0000));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002877 } else {
2878 UNIMPLEMENTED();
2879 }
2880 } else {
2881 UNIMPLEMENTED();
2882 }
2883 break;
2884 case 3:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002885 if ((instr->Bits(9, 6) == 1)) {
2886 if (instr->Bit(20) == 0) {
2887 if (instr->Bits(19, 16) == 0xF) {
2888 // Uxtb.
2889 uint32_t rm_val = get_register(instr->RmValue());
2890 int32_t rotate = instr->Bits(11, 10);
2891 switch (rotate) {
2892 case 0:
2893 break;
2894 case 1:
2895 rm_val = (rm_val >> 8) | (rm_val << 24);
2896 break;
2897 case 2:
2898 rm_val = (rm_val >> 16) | (rm_val << 16);
2899 break;
2900 case 3:
2901 rm_val = (rm_val >> 24) | (rm_val << 8);
2902 break;
2903 }
2904 set_register(rd, (rm_val & 0xFF));
2905 } else {
2906 // Uxtab.
2907 uint32_t rn_val = get_register(rn);
2908 uint32_t rm_val = get_register(instr->RmValue());
2909 int32_t rotate = instr->Bits(11, 10);
2910 switch (rotate) {
2911 case 0:
2912 break;
2913 case 1:
2914 rm_val = (rm_val >> 8) | (rm_val << 24);
2915 break;
2916 case 2:
2917 rm_val = (rm_val >> 16) | (rm_val << 16);
2918 break;
2919 case 3:
2920 rm_val = (rm_val >> 24) | (rm_val << 8);
2921 break;
2922 }
2923 set_register(rd, rn_val + (rm_val & 0xFF));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002924 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002925 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002926 if (instr->Bits(19, 16) == 0xF) {
2927 // Uxth.
2928 uint32_t rm_val = get_register(instr->RmValue());
2929 int32_t rotate = instr->Bits(11, 10);
2930 switch (rotate) {
2931 case 0:
2932 break;
2933 case 1:
2934 rm_val = (rm_val >> 8) | (rm_val << 24);
2935 break;
2936 case 2:
2937 rm_val = (rm_val >> 16) | (rm_val << 16);
2938 break;
2939 case 3:
2940 rm_val = (rm_val >> 24) | (rm_val << 8);
2941 break;
2942 }
2943 set_register(rd, (rm_val & 0xFFFF));
2944 } else {
2945 // Uxtah.
2946 uint32_t rn_val = get_register(rn);
2947 uint32_t rm_val = get_register(instr->RmValue());
2948 int32_t rotate = instr->Bits(11, 10);
2949 switch (rotate) {
2950 case 0:
2951 break;
2952 case 1:
2953 rm_val = (rm_val >> 8) | (rm_val << 24);
2954 break;
2955 case 2:
2956 rm_val = (rm_val >> 16) | (rm_val << 16);
2957 break;
2958 case 3:
2959 rm_val = (rm_val >> 24) | (rm_val << 8);
2960 break;
2961 }
2962 set_register(rd, rn_val + (rm_val & 0xFFFF));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002963 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002964 }
2965 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002966 // PU == 0b01, BW == 0b11, Bits(9, 6) != 0b0001
2967 if ((instr->Bits(20, 16) == 0x1f) &&
2968 (instr->Bits(11, 4) == 0xf3)) {
2969 // Rbit.
2970 uint32_t rm_val = get_register(instr->RmValue());
2971 set_register(rd, base::bits::ReverseBits(rm_val));
2972 } else {
2973 UNIMPLEMENTED();
2974 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002975 }
2976 break;
Kristian Monsen50ef84f2010-07-29 15:18:00 +01002977 }
Kristian Monsen50ef84f2010-07-29 15:18:00 +01002978 }
2979 return;
Kristian Monsen50ef84f2010-07-29 15:18:00 +01002980 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002981 break;
2982 }
Steve Block1e0659c2011-05-24 12:43:12 +01002983 case db_x: {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002984 if (instr->Bits(22, 20) == 0x5) {
2985 if (instr->Bits(7, 4) == 0x1) {
2986 int rm = instr->RmValue();
2987 int32_t rm_val = get_register(rm);
2988 int rs = instr->RsValue();
2989 int32_t rs_val = get_register(rs);
2990 if (instr->Bits(15, 12) == 0xF) {
2991 // SMMUL (in V8 notation matching ARM ISA format)
2992 // Format(instr, "smmul'cond 'rn, 'rm, 'rs");
2993 rn_val = base::bits::SignedMulHigh32(rm_val, rs_val);
2994 } else {
2995 // SMMLA (in V8 notation matching ARM ISA format)
2996 // Format(instr, "smmla'cond 'rn, 'rm, 'rs, 'rd");
2997 int rd = instr->RdValue();
2998 int32_t rd_val = get_register(rd);
2999 rn_val = base::bits::SignedMulHighAndAdd32(rm_val, rs_val, rd_val);
3000 }
3001 set_register(rn, rn_val);
3002 return;
3003 }
3004 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003005 if (FLAG_enable_sudiv) {
3006 if (instr->Bits(5, 4) == 0x1) {
3007 if ((instr->Bit(22) == 0x0) && (instr->Bit(20) == 0x1)) {
3008 // (s/u)div (in V8 notation matching ARM ISA format) rn = rm/rs
3009 // Format(instr, "'(s/u)div'cond'b 'rn, 'rm, 'rs);
3010 int rm = instr->RmValue();
3011 int32_t rm_val = get_register(rm);
3012 int rs = instr->RsValue();
3013 int32_t rs_val = get_register(rs);
3014 int32_t ret_val = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003015 // udiv
3016 if (instr->Bit(21) == 0x1) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003017 ret_val = bit_cast<int32_t>(base::bits::UnsignedDiv32(
3018 bit_cast<uint32_t>(rm_val), bit_cast<uint32_t>(rs_val)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003019 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003020 ret_val = base::bits::SignedDiv32(rm_val, rs_val);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003021 }
3022 set_register(rn, ret_val);
3023 return;
3024 }
3025 }
3026 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003027 // Format(instr, "'memop'cond'b 'rd, ['rn, -'shift_rm]'w");
3028 addr = rn_val - shifter_operand;
3029 if (instr->HasW()) {
3030 set_register(rn, addr);
3031 }
3032 break;
3033 }
Steve Block1e0659c2011-05-24 12:43:12 +01003034 case ib_x: {
Andrei Popescu31002712010-02-23 13:46:05 +00003035 if (instr->HasW() && (instr->Bits(6, 4) == 0x5)) {
3036 uint32_t widthminus1 = static_cast<uint32_t>(instr->Bits(20, 16));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003037 uint32_t lsbit = static_cast<uint32_t>(instr->Bits(11, 7));
Andrei Popescu31002712010-02-23 13:46:05 +00003038 uint32_t msbit = widthminus1 + lsbit;
3039 if (msbit <= 31) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003040 if (instr->Bit(22)) {
3041 // ubfx - unsigned bitfield extract.
3042 uint32_t rm_val =
Steve Block1e0659c2011-05-24 12:43:12 +01003043 static_cast<uint32_t>(get_register(instr->RmValue()));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003044 uint32_t extr_val = rm_val << (31 - msbit);
3045 extr_val = extr_val >> (31 - widthminus1);
Steve Block1e0659c2011-05-24 12:43:12 +01003046 set_register(instr->RdValue(), extr_val);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003047 } else {
3048 // sbfx - signed bitfield extract.
Steve Block1e0659c2011-05-24 12:43:12 +01003049 int32_t rm_val = get_register(instr->RmValue());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003050 int32_t extr_val = rm_val << (31 - msbit);
3051 extr_val = extr_val >> (31 - widthminus1);
Steve Block1e0659c2011-05-24 12:43:12 +01003052 set_register(instr->RdValue(), extr_val);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003053 }
3054 } else {
3055 UNREACHABLE();
3056 }
3057 return;
3058 } else if (!instr->HasW() && (instr->Bits(6, 4) == 0x1)) {
3059 uint32_t lsbit = static_cast<uint32_t>(instr->Bits(11, 7));
3060 uint32_t msbit = static_cast<uint32_t>(instr->Bits(20, 16));
3061 if (msbit >= lsbit) {
3062 // bfc or bfi - bitfield clear/insert.
3063 uint32_t rd_val =
Steve Block1e0659c2011-05-24 12:43:12 +01003064 static_cast<uint32_t>(get_register(instr->RdValue()));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003065 uint32_t bitcount = msbit - lsbit + 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003066 uint32_t mask = 0xffffffffu >> (32 - bitcount);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003067 rd_val &= ~(mask << lsbit);
Steve Block1e0659c2011-05-24 12:43:12 +01003068 if (instr->RmValue() != 15) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003069 // bfi - bitfield insert.
3070 uint32_t rm_val =
Steve Block1e0659c2011-05-24 12:43:12 +01003071 static_cast<uint32_t>(get_register(instr->RmValue()));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003072 rm_val &= mask;
3073 rd_val |= rm_val << lsbit;
3074 }
Steve Block1e0659c2011-05-24 12:43:12 +01003075 set_register(instr->RdValue(), rd_val);
Andrei Popescu31002712010-02-23 13:46:05 +00003076 } else {
3077 UNREACHABLE();
3078 }
3079 return;
3080 } else {
3081 // Format(instr, "'memop'cond'b 'rd, ['rn, +'shift_rm]'w");
3082 addr = rn_val + shifter_operand;
3083 if (instr->HasW()) {
3084 set_register(rn, addr);
3085 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003086 }
3087 break;
3088 }
3089 default: {
3090 UNREACHABLE();
3091 break;
3092 }
3093 }
3094 if (instr->HasB()) {
3095 if (instr->HasL()) {
3096 uint8_t byte = ReadB(addr);
3097 set_register(rd, byte);
3098 } else {
Andrei Popescu31002712010-02-23 13:46:05 +00003099 uint8_t byte = get_register(rd);
3100 WriteB(addr, byte);
Steve Blocka7e24c12009-10-30 11:49:00 +00003101 }
3102 } else {
3103 if (instr->HasL()) {
3104 set_register(rd, ReadW(addr, instr));
3105 } else {
3106 WriteW(addr, get_register(rd), instr);
3107 }
3108 }
3109}
3110
3111
Steve Block1e0659c2011-05-24 12:43:12 +01003112void Simulator::DecodeType4(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003113 DCHECK(instr->Bit(22) == 0); // only allowed to be set in privileged mode
Steve Blocka7e24c12009-10-30 11:49:00 +00003114 if (instr->HasL()) {
3115 // Format(instr, "ldm'cond'pu 'rn'w, 'rlist");
3116 HandleRList(instr, true);
3117 } else {
3118 // Format(instr, "stm'cond'pu 'rn'w, 'rlist");
3119 HandleRList(instr, false);
3120 }
3121}
3122
3123
Steve Block1e0659c2011-05-24 12:43:12 +01003124void Simulator::DecodeType5(Instruction* instr) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003125 // Format(instr, "b'l'cond 'target");
Steve Block1e0659c2011-05-24 12:43:12 +01003126 int off = (instr->SImmed24Value() << 2);
Steve Blocka7e24c12009-10-30 11:49:00 +00003127 intptr_t pc_address = get_pc();
3128 if (instr->HasLink()) {
Steve Block1e0659c2011-05-24 12:43:12 +01003129 set_register(lr, pc_address + Instruction::kInstrSize);
Steve Blocka7e24c12009-10-30 11:49:00 +00003130 }
3131 int pc_reg = get_register(pc);
3132 set_pc(pc_reg + off);
3133}
3134
3135
Steve Block1e0659c2011-05-24 12:43:12 +01003136void Simulator::DecodeType6(Instruction* instr) {
Steve Blockd0582a62009-12-15 09:54:21 +00003137 DecodeType6CoprocessorIns(instr);
Steve Blocka7e24c12009-10-30 11:49:00 +00003138}
3139
3140
Steve Block1e0659c2011-05-24 12:43:12 +01003141void Simulator::DecodeType7(Instruction* instr) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003142 if (instr->Bit(24) == 1) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003143 SoftwareInterrupt(instr);
3144 } else {
Steve Blockd0582a62009-12-15 09:54:21 +00003145 DecodeTypeVFP(instr);
Steve Blocka7e24c12009-10-30 11:49:00 +00003146 }
3147}
3148
3149
Steve Block1e0659c2011-05-24 12:43:12 +01003150// void Simulator::DecodeTypeVFP(Instruction* instr)
Steve Blockd0582a62009-12-15 09:54:21 +00003151// The Following ARMv7 VFPv instructions are currently supported.
Leon Clarkee46be812010-01-19 14:06:41 +00003152// vmov :Sn = Rt
3153// vmov :Rt = Sn
3154// vcvt: Dd = Sm
3155// vcvt: Sd = Dm
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003156// vcvt.f64.s32 Dd, Dd, #<fbits>
Steve Block44f0eee2011-05-26 01:26:41 +01003157// Dd = vabs(Dm)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003158// Sd = vabs(Sm)
Steve Block44f0eee2011-05-26 01:26:41 +01003159// Dd = vneg(Dm)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003160// Sd = vneg(Sm)
Leon Clarkee46be812010-01-19 14:06:41 +00003161// Dd = vadd(Dn, Dm)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003162// Sd = vadd(Sn, Sm)
Leon Clarkee46be812010-01-19 14:06:41 +00003163// Dd = vsub(Dn, Dm)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003164// Sd = vsub(Sn, Sm)
Leon Clarkee46be812010-01-19 14:06:41 +00003165// Dd = vmul(Dn, Dm)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003166// Sd = vmul(Sn, Sm)
Leon Clarkee46be812010-01-19 14:06:41 +00003167// Dd = vdiv(Dn, Dm)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003168// Sd = vdiv(Sn, Sm)
Steve Blockd0582a62009-12-15 09:54:21 +00003169// vcmp(Dd, Dm)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003170// vcmp(Sd, Sm)
Steve Block8defd9f2010-07-08 12:39:36 +01003171// Dd = vsqrt(Dm)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003172// Sd = vsqrt(Sm)
3173// vmrs
Steve Block1e0659c2011-05-24 12:43:12 +01003174void Simulator::DecodeTypeVFP(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003175 DCHECK((instr->TypeValue() == 7) && (instr->Bit(24) == 0x0) );
3176 DCHECK(instr->Bits(11, 9) == 0x5);
Steve Blockd0582a62009-12-15 09:54:21 +00003177
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003178 // Obtain single precision register codes.
3179 int m = instr->VFPMRegValue(kSinglePrecision);
3180 int d = instr->VFPDRegValue(kSinglePrecision);
3181 int n = instr->VFPNRegValue(kSinglePrecision);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003182 // Obtain double precision register codes.
Steve Block1e0659c2011-05-24 12:43:12 +01003183 int vm = instr->VFPMRegValue(kDoublePrecision);
3184 int vd = instr->VFPDRegValue(kDoublePrecision);
3185 int vn = instr->VFPNRegValue(kDoublePrecision);
Steve Blockd0582a62009-12-15 09:54:21 +00003186
Steve Block6ded16b2010-05-10 14:33:55 +01003187 if (instr->Bit(4) == 0) {
Steve Block1e0659c2011-05-24 12:43:12 +01003188 if (instr->Opc1Value() == 0x7) {
Steve Block6ded16b2010-05-10 14:33:55 +01003189 // Other data processing instructions
Steve Block1e0659c2011-05-24 12:43:12 +01003190 if ((instr->Opc2Value() == 0x0) && (instr->Opc3Value() == 0x1)) {
Steve Block8defd9f2010-07-08 12:39:36 +01003191 // vmov register to register.
Steve Block1e0659c2011-05-24 12:43:12 +01003192 if (instr->SzValue() == 0x1) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003193 uint32_t data[2];
3194 get_d_register(vm, data);
3195 set_d_register(vd, data);
Steve Block8defd9f2010-07-08 12:39:36 +01003196 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003197 set_s_register(d, get_s_register(m));
Steve Block8defd9f2010-07-08 12:39:36 +01003198 }
Steve Block1e0659c2011-05-24 12:43:12 +01003199 } else if ((instr->Opc2Value() == 0x0) && (instr->Opc3Value() == 0x3)) {
3200 // vabs
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003201 if (instr->SzValue() == 0x1) {
3202 double dm_value = get_double_from_d_register(vm);
3203 double dd_value = std::fabs(dm_value);
3204 dd_value = canonicalizeNaN(dd_value);
3205 set_d_register_from_double(vd, dd_value);
3206 } else {
3207 float sm_value = get_float_from_s_register(m);
3208 float sd_value = std::fabs(sm_value);
3209 sd_value = canonicalizeNaN(sd_value);
3210 set_s_register_from_float(d, sd_value);
3211 }
Steve Block44f0eee2011-05-26 01:26:41 +01003212 } else if ((instr->Opc2Value() == 0x1) && (instr->Opc3Value() == 0x1)) {
3213 // vneg
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003214 if (instr->SzValue() == 0x1) {
3215 double dm_value = get_double_from_d_register(vm);
3216 double dd_value = -dm_value;
3217 dd_value = canonicalizeNaN(dd_value);
3218 set_d_register_from_double(vd, dd_value);
3219 } else {
3220 float sm_value = get_float_from_s_register(m);
3221 float sd_value = -sm_value;
3222 sd_value = canonicalizeNaN(sd_value);
3223 set_s_register_from_float(d, sd_value);
3224 }
Steve Block1e0659c2011-05-24 12:43:12 +01003225 } else if ((instr->Opc2Value() == 0x7) && (instr->Opc3Value() == 0x3)) {
Steve Block6ded16b2010-05-10 14:33:55 +01003226 DecodeVCVTBetweenDoubleAndSingle(instr);
Steve Block1e0659c2011-05-24 12:43:12 +01003227 } else if ((instr->Opc2Value() == 0x8) && (instr->Opc3Value() & 0x1)) {
Steve Block6ded16b2010-05-10 14:33:55 +01003228 DecodeVCVTBetweenFloatingPointAndInteger(instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003229 } else if ((instr->Opc2Value() == 0xA) && (instr->Opc3Value() == 0x3) &&
3230 (instr->Bit(8) == 1)) {
3231 // vcvt.f64.s32 Dd, Dd, #<fbits>
3232 int fraction_bits = 32 - ((instr->Bits(3, 0) << 1) | instr->Bit(5));
3233 int fixed_value = get_sinteger_from_s_register(vd * 2);
3234 double divide = 1 << fraction_bits;
3235 set_d_register_from_double(vd, fixed_value / divide);
Steve Block1e0659c2011-05-24 12:43:12 +01003236 } else if (((instr->Opc2Value() >> 1) == 0x6) &&
3237 (instr->Opc3Value() & 0x1)) {
Steve Block6ded16b2010-05-10 14:33:55 +01003238 DecodeVCVTBetweenFloatingPointAndInteger(instr);
Steve Block1e0659c2011-05-24 12:43:12 +01003239 } else if (((instr->Opc2Value() == 0x4) || (instr->Opc2Value() == 0x5)) &&
3240 (instr->Opc3Value() & 0x1)) {
Steve Block6ded16b2010-05-10 14:33:55 +01003241 DecodeVCMP(instr);
Steve Block1e0659c2011-05-24 12:43:12 +01003242 } else if (((instr->Opc2Value() == 0x1)) && (instr->Opc3Value() == 0x3)) {
Steve Block8defd9f2010-07-08 12:39:36 +01003243 // vsqrt
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003244 lazily_initialize_fast_sqrt(isolate_);
3245 if (instr->SzValue() == 0x1) {
3246 double dm_value = get_double_from_d_register(vm);
3247 double dd_value = fast_sqrt(dm_value, isolate_);
3248 dd_value = canonicalizeNaN(dd_value);
3249 set_d_register_from_double(vd, dd_value);
3250 } else {
3251 float sm_value = get_float_from_s_register(m);
3252 float sd_value = fast_sqrt(sm_value, isolate_);
3253 sd_value = canonicalizeNaN(sd_value);
3254 set_s_register_from_float(d, sd_value);
3255 }
Steve Block1e0659c2011-05-24 12:43:12 +01003256 } else if (instr->Opc3Value() == 0x0) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +01003257 // vmov immediate.
Steve Block1e0659c2011-05-24 12:43:12 +01003258 if (instr->SzValue() == 0x1) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +01003259 set_d_register_from_double(vd, instr->DoubleImmedVmov());
3260 } else {
Ben Murdochda12d292016-06-02 14:46:10 +01003261 set_s_register_from_float(d, instr->DoubleImmedVmov());
Ben Murdoch3bec4d22010-07-22 14:51:16 +01003262 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003263 } else if (((instr->Opc2Value() == 0x6)) && (instr->Opc3Value() == 0x3)) {
3264 // vrintz - truncate
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003265 if (instr->SzValue() == 0x1) {
3266 double dm_value = get_double_from_d_register(vm);
3267 double dd_value = trunc(dm_value);
3268 dd_value = canonicalizeNaN(dd_value);
3269 set_d_register_from_double(vd, dd_value);
3270 } else {
3271 float sm_value = get_float_from_s_register(m);
3272 float sd_value = truncf(sm_value);
3273 sd_value = canonicalizeNaN(sd_value);
3274 set_s_register_from_float(d, sd_value);
3275 }
Steve Block6ded16b2010-05-10 14:33:55 +01003276 } else {
3277 UNREACHABLE(); // Not used by V8.
3278 }
Steve Block1e0659c2011-05-24 12:43:12 +01003279 } else if (instr->Opc1Value() == 0x3) {
Steve Block1e0659c2011-05-24 12:43:12 +01003280 if (instr->Opc3Value() & 0x1) {
Steve Block6ded16b2010-05-10 14:33:55 +01003281 // vsub
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003282 if (instr->SzValue() == 0x1) {
3283 double dn_value = get_double_from_d_register(vn);
3284 double dm_value = get_double_from_d_register(vm);
3285 double dd_value = dn_value - dm_value;
3286 dd_value = canonicalizeNaN(dd_value);
3287 set_d_register_from_double(vd, dd_value);
3288 } else {
3289 float sn_value = get_float_from_s_register(n);
3290 float sm_value = get_float_from_s_register(m);
3291 float sd_value = sn_value - sm_value;
3292 sd_value = canonicalizeNaN(sd_value);
3293 set_s_register_from_float(d, sd_value);
3294 }
Steve Block6ded16b2010-05-10 14:33:55 +01003295 } else {
3296 // vadd
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003297 if (instr->SzValue() == 0x1) {
3298 double dn_value = get_double_from_d_register(vn);
3299 double dm_value = get_double_from_d_register(vm);
3300 double dd_value = dn_value + dm_value;
3301 dd_value = canonicalizeNaN(dd_value);
3302 set_d_register_from_double(vd, dd_value);
3303 } else {
3304 float sn_value = get_float_from_s_register(n);
3305 float sm_value = get_float_from_s_register(m);
3306 float sd_value = sn_value + sm_value;
3307 sd_value = canonicalizeNaN(sd_value);
3308 set_s_register_from_float(d, sd_value);
3309 }
Steve Block6ded16b2010-05-10 14:33:55 +01003310 }
Steve Block1e0659c2011-05-24 12:43:12 +01003311 } else if ((instr->Opc1Value() == 0x2) && !(instr->Opc3Value() & 0x1)) {
Steve Block6ded16b2010-05-10 14:33:55 +01003312 // vmul
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003313 if (instr->SzValue() == 0x1) {
3314 double dn_value = get_double_from_d_register(vn);
3315 double dm_value = get_double_from_d_register(vm);
3316 double dd_value = dn_value * dm_value;
3317 dd_value = canonicalizeNaN(dd_value);
3318 set_d_register_from_double(vd, dd_value);
3319 } else {
3320 float sn_value = get_float_from_s_register(n);
3321 float sm_value = get_float_from_s_register(m);
3322 float sd_value = sn_value * sm_value;
3323 sd_value = canonicalizeNaN(sd_value);
3324 set_s_register_from_float(d, sd_value);
Steve Block6ded16b2010-05-10 14:33:55 +01003325 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003326 } else if ((instr->Opc1Value() == 0x0)) {
3327 // vmla, vmls
3328 const bool is_vmls = (instr->Opc3Value() & 0x1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003329 if (instr->SzValue() == 0x1) {
3330 const double dd_val = get_double_from_d_register(vd);
3331 const double dn_val = get_double_from_d_register(vn);
3332 const double dm_val = get_double_from_d_register(vm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003333
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003334 // Note: we do the mul and add/sub in separate steps to avoid getting a
3335 // result with too high precision.
3336 set_d_register_from_double(vd, dn_val * dm_val);
3337 if (is_vmls) {
3338 set_d_register_from_double(
3339 vd, canonicalizeNaN(dd_val - get_double_from_d_register(vd)));
3340 } else {
3341 set_d_register_from_double(
3342 vd, canonicalizeNaN(dd_val + get_double_from_d_register(vd)));
3343 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003344 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003345 const float sd_val = get_float_from_s_register(d);
3346 const float sn_val = get_float_from_s_register(n);
3347 const float sm_val = get_float_from_s_register(m);
3348
3349 // Note: we do the mul and add/sub in separate steps to avoid getting a
3350 // result with too high precision.
3351 set_s_register_from_float(d, sn_val * sm_val);
3352 if (is_vmls) {
3353 set_s_register_from_float(
3354 d, canonicalizeNaN(sd_val - get_float_from_s_register(d)));
3355 } else {
3356 set_s_register_from_float(
3357 d, canonicalizeNaN(sd_val + get_float_from_s_register(d)));
3358 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003359 }
Steve Block1e0659c2011-05-24 12:43:12 +01003360 } else if ((instr->Opc1Value() == 0x4) && !(instr->Opc3Value() & 0x1)) {
Steve Block6ded16b2010-05-10 14:33:55 +01003361 // vdiv
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003362 if (instr->SzValue() == 0x1) {
3363 double dn_value = get_double_from_d_register(vn);
3364 double dm_value = get_double_from_d_register(vm);
3365 double dd_value = dn_value / dm_value;
3366 div_zero_vfp_flag_ = (dm_value == 0);
3367 dd_value = canonicalizeNaN(dd_value);
3368 set_d_register_from_double(vd, dd_value);
3369 } else {
3370 float sn_value = get_float_from_s_register(n);
3371 float sm_value = get_float_from_s_register(m);
3372 float sd_value = sn_value / sm_value;
3373 div_zero_vfp_flag_ = (sm_value == 0);
3374 sd_value = canonicalizeNaN(sd_value);
3375 set_s_register_from_float(d, sd_value);
Steve Block6ded16b2010-05-10 14:33:55 +01003376 }
Steve Block6ded16b2010-05-10 14:33:55 +01003377 } else {
3378 UNIMPLEMENTED(); // Not used by V8.
3379 }
3380 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01003381 if ((instr->VCValue() == 0x0) &&
3382 (instr->VAValue() == 0x0)) {
Steve Block6ded16b2010-05-10 14:33:55 +01003383 DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003384 } else if ((instr->VLValue() == 0x0) &&
3385 (instr->VCValue() == 0x1) &&
3386 (instr->Bit(23) == 0x0)) {
3387 // vmov (ARM core register to scalar)
3388 int vd = instr->Bits(19, 16) | (instr->Bit(7) << 4);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003389 uint32_t data[2];
3390 get_d_register(vd, data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003391 data[instr->Bit(21)] = get_register(instr->RtValue());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003392 set_d_register(vd, data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003393 } else if ((instr->VLValue() == 0x1) &&
3394 (instr->VCValue() == 0x1) &&
3395 (instr->Bit(23) == 0x0)) {
3396 // vmov (scalar to ARM core register)
3397 int vn = instr->Bits(19, 16) | (instr->Bit(7) << 4);
3398 double dn_value = get_double_from_d_register(vn);
3399 int32_t data[2];
3400 memcpy(data, &dn_value, 8);
3401 set_register(instr->RtValue(), data[instr->Bit(21)]);
Steve Block1e0659c2011-05-24 12:43:12 +01003402 } else if ((instr->VLValue() == 0x1) &&
3403 (instr->VCValue() == 0x0) &&
3404 (instr->VAValue() == 0x7) &&
Steve Block6ded16b2010-05-10 14:33:55 +01003405 (instr->Bits(19, 16) == 0x1)) {
3406 // vmrs
Steve Block1e0659c2011-05-24 12:43:12 +01003407 uint32_t rt = instr->RtValue();
Russell Brenner90bac252010-11-18 13:33:46 -08003408 if (rt == 0xF) {
Steve Blockd0582a62009-12-15 09:54:21 +00003409 Copy_FPSCR_to_APSR();
Russell Brenner90bac252010-11-18 13:33:46 -08003410 } else {
3411 // Emulate FPSCR from the Simulator flags.
3412 uint32_t fpscr = (n_flag_FPSCR_ << 31) |
3413 (z_flag_FPSCR_ << 30) |
3414 (c_flag_FPSCR_ << 29) |
3415 (v_flag_FPSCR_ << 28) |
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003416 (FPSCR_default_NaN_mode_ << 25) |
Russell Brenner90bac252010-11-18 13:33:46 -08003417 (inexact_vfp_flag_ << 4) |
3418 (underflow_vfp_flag_ << 3) |
3419 (overflow_vfp_flag_ << 2) |
3420 (div_zero_vfp_flag_ << 1) |
3421 (inv_op_vfp_flag_ << 0) |
Steve Block1e0659c2011-05-24 12:43:12 +01003422 (FPSCR_rounding_mode_);
Russell Brenner90bac252010-11-18 13:33:46 -08003423 set_register(rt, fpscr);
3424 }
Steve Block1e0659c2011-05-24 12:43:12 +01003425 } else if ((instr->VLValue() == 0x0) &&
3426 (instr->VCValue() == 0x0) &&
3427 (instr->VAValue() == 0x7) &&
Russell Brenner90bac252010-11-18 13:33:46 -08003428 (instr->Bits(19, 16) == 0x1)) {
3429 // vmsr
Steve Block1e0659c2011-05-24 12:43:12 +01003430 uint32_t rt = instr->RtValue();
Russell Brenner90bac252010-11-18 13:33:46 -08003431 if (rt == pc) {
3432 UNREACHABLE();
3433 } else {
3434 uint32_t rt_value = get_register(rt);
3435 n_flag_FPSCR_ = (rt_value >> 31) & 1;
3436 z_flag_FPSCR_ = (rt_value >> 30) & 1;
3437 c_flag_FPSCR_ = (rt_value >> 29) & 1;
3438 v_flag_FPSCR_ = (rt_value >> 28) & 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003439 FPSCR_default_NaN_mode_ = (rt_value >> 25) & 1;
Russell Brenner90bac252010-11-18 13:33:46 -08003440 inexact_vfp_flag_ = (rt_value >> 4) & 1;
3441 underflow_vfp_flag_ = (rt_value >> 3) & 1;
3442 overflow_vfp_flag_ = (rt_value >> 2) & 1;
3443 div_zero_vfp_flag_ = (rt_value >> 1) & 1;
3444 inv_op_vfp_flag_ = (rt_value >> 0) & 1;
3445 FPSCR_rounding_mode_ =
Steve Block1e0659c2011-05-24 12:43:12 +01003446 static_cast<VFPRoundingMode>((rt_value) & kVFPRoundingModeMask);
Russell Brenner90bac252010-11-18 13:33:46 -08003447 }
Steve Blockd0582a62009-12-15 09:54:21 +00003448 } else {
3449 UNIMPLEMENTED(); // Not used by V8.
3450 }
Steve Block6ded16b2010-05-10 14:33:55 +01003451 }
3452}
3453
3454
Steve Block1e0659c2011-05-24 12:43:12 +01003455void Simulator::DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(
3456 Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003457 DCHECK((instr->Bit(4) == 1) && (instr->VCValue() == 0x0) &&
Steve Block1e0659c2011-05-24 12:43:12 +01003458 (instr->VAValue() == 0x0));
Steve Block6ded16b2010-05-10 14:33:55 +01003459
Steve Block1e0659c2011-05-24 12:43:12 +01003460 int t = instr->RtValue();
3461 int n = instr->VFPNRegValue(kSinglePrecision);
3462 bool to_arm_register = (instr->VLValue() == 0x1);
Steve Block6ded16b2010-05-10 14:33:55 +01003463
3464 if (to_arm_register) {
3465 int32_t int_value = get_sinteger_from_s_register(n);
3466 set_register(t, int_value);
3467 } else {
3468 int32_t rs_val = get_register(t);
3469 set_s_register_from_sinteger(n, rs_val);
3470 }
3471}
3472
3473
Steve Block1e0659c2011-05-24 12:43:12 +01003474void Simulator::DecodeVCMP(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003475 DCHECK((instr->Bit(4) == 0) && (instr->Opc1Value() == 0x7));
3476 DCHECK(((instr->Opc2Value() == 0x4) || (instr->Opc2Value() == 0x5)) &&
Steve Block1e0659c2011-05-24 12:43:12 +01003477 (instr->Opc3Value() & 0x1));
Steve Block6ded16b2010-05-10 14:33:55 +01003478 // Comparison.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003479
3480 VFPRegPrecision precision = kSinglePrecision;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003481 if (instr->SzValue() == 0x1) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003482 precision = kDoublePrecision;
3483 }
Steve Block6ded16b2010-05-10 14:33:55 +01003484
Steve Block1e0659c2011-05-24 12:43:12 +01003485 int d = instr->VFPDRegValue(precision);
Iain Merrick75681382010-08-19 15:07:18 +01003486 int m = 0;
Steve Block1e0659c2011-05-24 12:43:12 +01003487 if (instr->Opc2Value() == 0x4) {
3488 m = instr->VFPMRegValue(precision);
Iain Merrick75681382010-08-19 15:07:18 +01003489 }
Steve Block6ded16b2010-05-10 14:33:55 +01003490
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003491 if (precision == kDoublePrecision) {
Steve Block6ded16b2010-05-10 14:33:55 +01003492 double dd_value = get_double_from_d_register(d);
Iain Merrick75681382010-08-19 15:07:18 +01003493 double dm_value = 0.0;
Steve Block1e0659c2011-05-24 12:43:12 +01003494 if (instr->Opc2Value() == 0x4) {
Iain Merrick75681382010-08-19 15:07:18 +01003495 dm_value = get_double_from_d_register(m);
3496 }
Steve Block6ded16b2010-05-10 14:33:55 +01003497
Ben Murdoch086aeea2011-05-13 15:57:08 +01003498 // Raise exceptions for quiet NaNs if necessary.
3499 if (instr->Bit(7) == 1) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003500 if (std::isnan(dd_value)) {
Ben Murdoch086aeea2011-05-13 15:57:08 +01003501 inv_op_vfp_flag_ = true;
3502 }
3503 }
3504
Steve Block6ded16b2010-05-10 14:33:55 +01003505 Compute_FPSCR_Flags(dd_value, dm_value);
3506 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003507 float sd_value = get_float_from_s_register(d);
3508 float sm_value = 0.0;
3509 if (instr->Opc2Value() == 0x4) {
3510 sm_value = get_float_from_s_register(m);
3511 }
3512
3513 // Raise exceptions for quiet NaNs if necessary.
3514 if (instr->Bit(7) == 1) {
3515 if (std::isnan(sd_value)) {
3516 inv_op_vfp_flag_ = true;
3517 }
3518 }
3519
3520 Compute_FPSCR_Flags(sd_value, sm_value);
Steve Block6ded16b2010-05-10 14:33:55 +01003521 }
3522}
3523
3524
Steve Block1e0659c2011-05-24 12:43:12 +01003525void Simulator::DecodeVCVTBetweenDoubleAndSingle(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003526 DCHECK((instr->Bit(4) == 0) && (instr->Opc1Value() == 0x7));
3527 DCHECK((instr->Opc2Value() == 0x7) && (instr->Opc3Value() == 0x3));
Steve Block6ded16b2010-05-10 14:33:55 +01003528
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003529 VFPRegPrecision dst_precision = kDoublePrecision;
3530 VFPRegPrecision src_precision = kSinglePrecision;
Steve Block1e0659c2011-05-24 12:43:12 +01003531 if (instr->SzValue() == 1) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003532 dst_precision = kSinglePrecision;
3533 src_precision = kDoublePrecision;
3534 }
Steve Block6ded16b2010-05-10 14:33:55 +01003535
Steve Block1e0659c2011-05-24 12:43:12 +01003536 int dst = instr->VFPDRegValue(dst_precision);
3537 int src = instr->VFPMRegValue(src_precision);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003538
3539 if (dst_precision == kSinglePrecision) {
Steve Block6ded16b2010-05-10 14:33:55 +01003540 double val = get_double_from_d_register(src);
3541 set_s_register_from_float(dst, static_cast<float>(val));
3542 } else {
3543 float val = get_float_from_s_register(src);
3544 set_d_register_from_double(dst, static_cast<double>(val));
3545 }
3546}
3547
Steve Block1e0659c2011-05-24 12:43:12 +01003548bool get_inv_op_vfp_flag(VFPRoundingMode mode,
3549 double val,
3550 bool unsigned_) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003551 DCHECK((mode == RN) || (mode == RM) || (mode == RZ));
Steve Block1e0659c2011-05-24 12:43:12 +01003552 double max_uint = static_cast<double>(0xffffffffu);
3553 double max_int = static_cast<double>(kMaxInt);
3554 double min_int = static_cast<double>(kMinInt);
Steve Block6ded16b2010-05-10 14:33:55 +01003555
Steve Block1e0659c2011-05-24 12:43:12 +01003556 // Check for NaN.
3557 if (val != val) {
3558 return true;
3559 }
3560
3561 // Check for overflow. This code works because 32bit integers can be
3562 // exactly represented by ieee-754 64bit floating-point values.
3563 switch (mode) {
3564 case RN:
3565 return unsigned_ ? (val >= (max_uint + 0.5)) ||
3566 (val < -0.5)
3567 : (val >= (max_int + 0.5)) ||
3568 (val < (min_int - 0.5));
3569
3570 case RM:
3571 return unsigned_ ? (val >= (max_uint + 1.0)) ||
3572 (val < 0)
3573 : (val >= (max_int + 1.0)) ||
3574 (val < min_int);
3575
3576 case RZ:
3577 return unsigned_ ? (val >= (max_uint + 1.0)) ||
3578 (val <= -1)
3579 : (val >= (max_int + 1.0)) ||
3580 (val <= (min_int - 1.0));
3581 default:
3582 UNREACHABLE();
3583 return true;
3584 }
3585}
3586
3587
3588// We call this function only if we had a vfp invalid exception.
3589// It returns the correct saturated value.
3590int VFPConversionSaturate(double val, bool unsigned_res) {
3591 if (val != val) {
3592 return 0;
3593 } else {
3594 if (unsigned_res) {
3595 return (val < 0) ? 0 : 0xffffffffu;
3596 } else {
3597 return (val < 0) ? kMinInt : kMaxInt;
3598 }
3599 }
3600}
3601
3602
3603void Simulator::DecodeVCVTBetweenFloatingPointAndInteger(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003604 DCHECK((instr->Bit(4) == 0) && (instr->Opc1Value() == 0x7) &&
Steve Block1e0659c2011-05-24 12:43:12 +01003605 (instr->Bits(27, 23) == 0x1D));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003606 DCHECK(((instr->Opc2Value() == 0x8) && (instr->Opc3Value() & 0x1)) ||
Steve Block1e0659c2011-05-24 12:43:12 +01003607 (((instr->Opc2Value() >> 1) == 0x6) && (instr->Opc3Value() & 0x1)));
Steve Block6ded16b2010-05-10 14:33:55 +01003608
3609 // Conversion between floating-point and integer.
Steve Block6ded16b2010-05-10 14:33:55 +01003610 bool to_integer = (instr->Bit(18) == 1);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003611
Steve Block1e0659c2011-05-24 12:43:12 +01003612 VFPRegPrecision src_precision = (instr->SzValue() == 1) ? kDoublePrecision
3613 : kSinglePrecision;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003614
Steve Block6ded16b2010-05-10 14:33:55 +01003615 if (to_integer) {
Steve Block1e0659c2011-05-24 12:43:12 +01003616 // We are playing with code close to the C++ standard's limits below,
3617 // hence the very simple code and heavy checks.
3618 //
3619 // Note:
3620 // C++ defines default type casting from floating point to integer as
3621 // (close to) rounding toward zero ("fractional part discarded").
3622
3623 int dst = instr->VFPDRegValue(kSinglePrecision);
3624 int src = instr->VFPMRegValue(src_precision);
3625
3626 // Bit 7 in vcvt instructions indicates if we should use the FPSCR rounding
3627 // mode or the default Round to Zero mode.
3628 VFPRoundingMode mode = (instr->Bit(7) != 1) ? FPSCR_rounding_mode_
3629 : RZ;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003630 DCHECK((mode == RM) || (mode == RZ) || (mode == RN));
Steve Block1e0659c2011-05-24 12:43:12 +01003631
Steve Block6ded16b2010-05-10 14:33:55 +01003632 bool unsigned_integer = (instr->Bit(16) == 0);
Steve Block1e0659c2011-05-24 12:43:12 +01003633 bool double_precision = (src_precision == kDoublePrecision);
3634
3635 double val = double_precision ? get_double_from_d_register(src)
3636 : get_float_from_s_register(src);
3637
3638 int temp = unsigned_integer ? static_cast<uint32_t>(val)
3639 : static_cast<int32_t>(val);
3640
3641 inv_op_vfp_flag_ = get_inv_op_vfp_flag(mode, val, unsigned_integer);
3642
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003643 double abs_diff =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003644 unsigned_integer ? std::fabs(val - static_cast<uint32_t>(temp))
3645 : std::fabs(val - temp);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003646
3647 inexact_vfp_flag_ = (abs_diff != 0);
3648
Steve Block1e0659c2011-05-24 12:43:12 +01003649 if (inv_op_vfp_flag_) {
3650 temp = VFPConversionSaturate(val, unsigned_integer);
Russell Brenner90bac252010-11-18 13:33:46 -08003651 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01003652 switch (mode) {
3653 case RN: {
Steve Block1e0659c2011-05-24 12:43:12 +01003654 int val_sign = (val > 0) ? 1 : -1;
3655 if (abs_diff > 0.5) {
3656 temp += val_sign;
3657 } else if (abs_diff == 0.5) {
3658 // Round to even if exactly halfway.
3659 temp = ((temp % 2) == 0) ? temp : temp + val_sign;
3660 }
3661 break;
3662 }
3663
3664 case RM:
3665 temp = temp > val ? temp - 1 : temp;
3666 break;
3667
3668 case RZ:
3669 // Nothing to do.
3670 break;
3671
3672 default:
3673 UNREACHABLE();
3674 }
Steve Blockd0582a62009-12-15 09:54:21 +00003675 }
Steve Block6ded16b2010-05-10 14:33:55 +01003676
Steve Block1e0659c2011-05-24 12:43:12 +01003677 // Update the destination register.
3678 set_s_register_from_sinteger(dst, temp);
Russell Brenner90bac252010-11-18 13:33:46 -08003679
Steve Block6ded16b2010-05-10 14:33:55 +01003680 } else {
3681 bool unsigned_integer = (instr->Bit(7) == 0);
3682
Steve Block1e0659c2011-05-24 12:43:12 +01003683 int dst = instr->VFPDRegValue(src_precision);
3684 int src = instr->VFPMRegValue(kSinglePrecision);
Steve Block6ded16b2010-05-10 14:33:55 +01003685
3686 int val = get_sinteger_from_s_register(src);
3687
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003688 if (src_precision == kDoublePrecision) {
Steve Block6ded16b2010-05-10 14:33:55 +01003689 if (unsigned_integer) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003690 set_d_register_from_double(
3691 dst, static_cast<double>(static_cast<uint32_t>(val)));
Steve Block6ded16b2010-05-10 14:33:55 +01003692 } else {
3693 set_d_register_from_double(dst, static_cast<double>(val));
3694 }
3695 } else {
3696 if (unsigned_integer) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003697 set_s_register_from_float(
3698 dst, static_cast<float>(static_cast<uint32_t>(val)));
Steve Block6ded16b2010-05-10 14:33:55 +01003699 } else {
3700 set_s_register_from_float(dst, static_cast<float>(val));
3701 }
Steve Blockd0582a62009-12-15 09:54:21 +00003702 }
3703 }
3704}
3705
3706
Steve Block1e0659c2011-05-24 12:43:12 +01003707// void Simulator::DecodeType6CoprocessorIns(Instruction* instr)
Steve Blockd0582a62009-12-15 09:54:21 +00003708// Decode Type 6 coprocessor instructions.
Leon Clarkee46be812010-01-19 14:06:41 +00003709// Dm = vmov(Rt, Rt2)
3710// <Rt, Rt2> = vmov(Dm)
Leon Clarked91b9f72010-01-27 17:25:45 +00003711// Ddst = MEM(Rbase + 4*offset).
3712// MEM(Rbase + 4*offset) = Dsrc.
Steve Block1e0659c2011-05-24 12:43:12 +01003713void Simulator::DecodeType6CoprocessorIns(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003714 DCHECK((instr->TypeValue() == 6));
Steve Blockd0582a62009-12-15 09:54:21 +00003715
Steve Block1e0659c2011-05-24 12:43:12 +01003716 if (instr->CoprocessorValue() == 0xA) {
3717 switch (instr->OpcodeValue()) {
Steve Block6ded16b2010-05-10 14:33:55 +01003718 case 0x8:
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003719 case 0xA:
3720 case 0xC:
3721 case 0xE: { // Load and store single precision float to memory.
Steve Block1e0659c2011-05-24 12:43:12 +01003722 int rn = instr->RnValue();
3723 int vd = instr->VFPDRegValue(kSinglePrecision);
3724 int offset = instr->Immed8Value();
Steve Block6ded16b2010-05-10 14:33:55 +01003725 if (!instr->HasU()) {
3726 offset = -offset;
3727 }
3728
3729 int32_t address = get_register(rn) + 4 * offset;
3730 if (instr->HasL()) {
3731 // Load double from memory: vldr.
3732 set_s_register_from_sinteger(vd, ReadW(address, instr));
3733 } else {
3734 // Store double to memory: vstr.
3735 WriteW(address, get_sinteger_from_s_register(vd), instr);
3736 }
3737 break;
3738 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01003739 case 0x4:
3740 case 0x5:
3741 case 0x6:
3742 case 0x7:
3743 case 0x9:
3744 case 0xB:
3745 // Load/store multiple single from memory: vldm/vstm.
3746 HandleVList(instr);
3747 break;
Steve Block6ded16b2010-05-10 14:33:55 +01003748 default:
3749 UNIMPLEMENTED(); // Not used by V8.
Steve Block6ded16b2010-05-10 14:33:55 +01003750 }
Steve Block1e0659c2011-05-24 12:43:12 +01003751 } else if (instr->CoprocessorValue() == 0xB) {
3752 switch (instr->OpcodeValue()) {
Leon Clarked91b9f72010-01-27 17:25:45 +00003753 case 0x2:
3754 // Load and store double to two GP registers
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003755 if (instr->Bits(7, 6) != 0 || instr->Bit(4) != 1) {
Leon Clarked91b9f72010-01-27 17:25:45 +00003756 UNIMPLEMENTED(); // Not used by V8.
3757 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01003758 int rt = instr->RtValue();
3759 int rn = instr->RnValue();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003760 int vm = instr->VFPMRegValue(kDoublePrecision);
Leon Clarked91b9f72010-01-27 17:25:45 +00003761 if (instr->HasL()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003762 uint32_t data[2];
3763 get_d_register(vm, data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003764 set_register(rt, data[0]);
3765 set_register(rn, data[1]);
Leon Clarked91b9f72010-01-27 17:25:45 +00003766 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003767 int32_t data[] = { get_register(rt), get_register(rn) };
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003768 set_d_register(vm, reinterpret_cast<uint32_t*>(data));
Leon Clarked91b9f72010-01-27 17:25:45 +00003769 }
3770 }
3771 break;
3772 case 0x8:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003773 case 0xA:
3774 case 0xC:
3775 case 0xE: { // Load and store double to memory.
Steve Block1e0659c2011-05-24 12:43:12 +01003776 int rn = instr->RnValue();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003777 int vd = instr->VFPDRegValue(kDoublePrecision);
Steve Block1e0659c2011-05-24 12:43:12 +01003778 int offset = instr->Immed8Value();
Leon Clarked91b9f72010-01-27 17:25:45 +00003779 if (!instr->HasU()) {
3780 offset = -offset;
3781 }
3782 int32_t address = get_register(rn) + 4 * offset;
3783 if (instr->HasL()) {
3784 // Load double from memory: vldr.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003785 int32_t data[] = {
3786 ReadW(address, instr),
3787 ReadW(address + 4, instr)
3788 };
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003789 set_d_register(vd, reinterpret_cast<uint32_t*>(data));
Leon Clarked91b9f72010-01-27 17:25:45 +00003790 } else {
3791 // Store double to memory: vstr.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003792 uint32_t data[2];
3793 get_d_register(vd, data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003794 WriteW(address, data[0], instr);
3795 WriteW(address + 4, data[1], instr);
Leon Clarked91b9f72010-01-27 17:25:45 +00003796 }
3797 break;
3798 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01003799 case 0x4:
3800 case 0x5:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003801 case 0x6:
3802 case 0x7:
Ben Murdoch8b112d22011-06-08 16:22:53 +01003803 case 0x9:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003804 case 0xB:
Ben Murdoch8b112d22011-06-08 16:22:53 +01003805 // Load/store multiple double from memory: vldm/vstm.
3806 HandleVList(instr);
3807 break;
Leon Clarked91b9f72010-01-27 17:25:45 +00003808 default:
3809 UNIMPLEMENTED(); // Not used by V8.
Leon Clarked91b9f72010-01-27 17:25:45 +00003810 }
Steve Block6ded16b2010-05-10 14:33:55 +01003811 } else {
3812 UNIMPLEMENTED(); // Not used by V8.
Steve Blockd0582a62009-12-15 09:54:21 +00003813 }
3814}
3815
3816
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003817void Simulator::DecodeSpecialCondition(Instruction* instr) {
3818 switch (instr->SpecialValue()) {
3819 case 5:
3820 if ((instr->Bits(18, 16) == 0) && (instr->Bits(11, 6) == 0x28) &&
3821 (instr->Bit(4) == 1)) {
3822 // vmovl signed
3823 if ((instr->VdValue() & 1) != 0) UNIMPLEMENTED();
3824 int Vd = (instr->Bit(22) << 3) | (instr->VdValue() >> 1);
3825 int Vm = (instr->Bit(5) << 4) | instr->VmValue();
3826 int imm3 = instr->Bits(21, 19);
3827 if ((imm3 != 1) && (imm3 != 2) && (imm3 != 4)) UNIMPLEMENTED();
3828 int esize = 8 * imm3;
3829 int elements = 64 / esize;
3830 int8_t from[8];
3831 get_d_register(Vm, reinterpret_cast<uint64_t*>(from));
3832 int16_t to[8];
3833 int e = 0;
3834 while (e < elements) {
3835 to[e] = from[e];
3836 e++;
3837 }
3838 set_q_register(Vd, reinterpret_cast<uint64_t*>(to));
3839 } else {
3840 UNIMPLEMENTED();
3841 }
3842 break;
3843 case 7:
3844 if ((instr->Bits(18, 16) == 0) && (instr->Bits(11, 6) == 0x28) &&
3845 (instr->Bit(4) == 1)) {
3846 // vmovl unsigned
3847 if ((instr->VdValue() & 1) != 0) UNIMPLEMENTED();
3848 int Vd = (instr->Bit(22) << 3) | (instr->VdValue() >> 1);
3849 int Vm = (instr->Bit(5) << 4) | instr->VmValue();
3850 int imm3 = instr->Bits(21, 19);
3851 if ((imm3 != 1) && (imm3 != 2) && (imm3 != 4)) UNIMPLEMENTED();
3852 int esize = 8 * imm3;
3853 int elements = 64 / esize;
3854 uint8_t from[8];
3855 get_d_register(Vm, reinterpret_cast<uint64_t*>(from));
3856 uint16_t to[8];
3857 int e = 0;
3858 while (e < elements) {
3859 to[e] = from[e];
3860 e++;
3861 }
3862 set_q_register(Vd, reinterpret_cast<uint64_t*>(to));
3863 } else {
3864 UNIMPLEMENTED();
3865 }
3866 break;
3867 case 8:
3868 if (instr->Bits(21, 20) == 0) {
3869 // vst1
3870 int Vd = (instr->Bit(22) << 4) | instr->VdValue();
3871 int Rn = instr->VnValue();
3872 int type = instr->Bits(11, 8);
3873 int Rm = instr->VmValue();
3874 int32_t address = get_register(Rn);
3875 int regs = 0;
3876 switch (type) {
3877 case nlt_1:
3878 regs = 1;
3879 break;
3880 case nlt_2:
3881 regs = 2;
3882 break;
3883 case nlt_3:
3884 regs = 3;
3885 break;
3886 case nlt_4:
3887 regs = 4;
3888 break;
3889 default:
3890 UNIMPLEMENTED();
3891 break;
3892 }
3893 int r = 0;
3894 while (r < regs) {
3895 uint32_t data[2];
3896 get_d_register(Vd + r, data);
3897 WriteW(address, data[0], instr);
3898 WriteW(address + 4, data[1], instr);
3899 address += 8;
3900 r++;
3901 }
3902 if (Rm != 15) {
3903 if (Rm == 13) {
3904 set_register(Rn, address);
3905 } else {
3906 set_register(Rn, get_register(Rn) + get_register(Rm));
3907 }
3908 }
3909 } else if (instr->Bits(21, 20) == 2) {
3910 // vld1
3911 int Vd = (instr->Bit(22) << 4) | instr->VdValue();
3912 int Rn = instr->VnValue();
3913 int type = instr->Bits(11, 8);
3914 int Rm = instr->VmValue();
3915 int32_t address = get_register(Rn);
3916 int regs = 0;
3917 switch (type) {
3918 case nlt_1:
3919 regs = 1;
3920 break;
3921 case nlt_2:
3922 regs = 2;
3923 break;
3924 case nlt_3:
3925 regs = 3;
3926 break;
3927 case nlt_4:
3928 regs = 4;
3929 break;
3930 default:
3931 UNIMPLEMENTED();
3932 break;
3933 }
3934 int r = 0;
3935 while (r < regs) {
3936 uint32_t data[2];
3937 data[0] = ReadW(address, instr);
3938 data[1] = ReadW(address + 4, instr);
3939 set_d_register(Vd + r, data);
3940 address += 8;
3941 r++;
3942 }
3943 if (Rm != 15) {
3944 if (Rm == 13) {
3945 set_register(Rn, address);
3946 } else {
3947 set_register(Rn, get_register(Rn) + get_register(Rm));
3948 }
3949 }
3950 } else {
3951 UNIMPLEMENTED();
3952 }
3953 break;
3954 case 0xA:
3955 case 0xB:
3956 if ((instr->Bits(22, 20) == 5) && (instr->Bits(15, 12) == 0xf)) {
3957 // pld: ignore instruction.
Ben Murdoch097c5b22016-05-18 11:27:45 +01003958 } else if (instr->SpecialValue() == 0xA && instr->Bits(22, 20) == 7) {
3959 // dsb, dmb, isb: ignore instruction for now.
3960 // TODO(binji): implement
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003961 } else {
3962 UNIMPLEMENTED();
3963 }
3964 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003965 case 0x1D:
3966 if (instr->Opc1Value() == 0x7 && instr->Opc3Value() == 0x1 &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003967 instr->Bits(11, 9) == 0x5 && instr->Bits(19, 18) == 0x2) {
3968 if (instr->SzValue() == 0x1) {
3969 int vm = instr->VFPMRegValue(kDoublePrecision);
3970 int vd = instr->VFPDRegValue(kDoublePrecision);
3971 double dm_value = get_double_from_d_register(vm);
3972 double dd_value = 0.0;
3973 int rounding_mode = instr->Bits(17, 16);
3974 switch (rounding_mode) {
3975 case 0x0: // vrinta - round with ties to away from zero
3976 dd_value = round(dm_value);
3977 break;
3978 case 0x1: { // vrintn - round with ties to even
3979 dd_value = nearbyint(dm_value);
3980 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003981 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003982 case 0x2: // vrintp - ceil
3983 dd_value = ceil(dm_value);
3984 break;
3985 case 0x3: // vrintm - floor
3986 dd_value = floor(dm_value);
3987 break;
3988 default:
3989 UNREACHABLE(); // Case analysis is exhaustive.
3990 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003991 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003992 dd_value = canonicalizeNaN(dd_value);
3993 set_d_register_from_double(vd, dd_value);
3994 } else {
3995 int m = instr->VFPMRegValue(kSinglePrecision);
3996 int d = instr->VFPDRegValue(kSinglePrecision);
3997 float sm_value = get_float_from_s_register(m);
3998 float sd_value = 0.0;
3999 int rounding_mode = instr->Bits(17, 16);
4000 switch (rounding_mode) {
4001 case 0x0: // vrinta - round with ties to away from zero
4002 sd_value = roundf(sm_value);
4003 break;
4004 case 0x1: { // vrintn - round with ties to even
4005 sd_value = nearbyintf(sm_value);
4006 break;
4007 }
4008 case 0x2: // vrintp - ceil
4009 sd_value = ceilf(sm_value);
4010 break;
4011 case 0x3: // vrintm - floor
4012 sd_value = floorf(sm_value);
4013 break;
4014 default:
4015 UNREACHABLE(); // Case analysis is exhaustive.
4016 break;
4017 }
4018 sd_value = canonicalizeNaN(sd_value);
4019 set_s_register_from_float(d, sd_value);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004020 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004021 } else {
4022 UNIMPLEMENTED();
4023 }
4024 break;
Ben Murdochc5610432016-08-08 18:44:38 +01004025 case 0x1C:
4026 if ((instr->Bits(11, 9) == 0x5) && (instr->Bit(6) == 0) &&
4027 (instr->Bit(4) == 0)) {
4028 // VSEL* (floating-point)
4029 bool condition_holds;
4030 switch (instr->Bits(21, 20)) {
4031 case 0x0: // VSELEQ
4032 condition_holds = (z_flag_ == 1);
4033 break;
4034 case 0x1: // VSELVS
4035 condition_holds = (v_flag_ == 1);
4036 break;
4037 case 0x2: // VSELGE
4038 condition_holds = (n_flag_ == v_flag_);
4039 break;
4040 case 0x3: // VSELGT
4041 condition_holds = ((z_flag_ == 0) && (n_flag_ == v_flag_));
4042 break;
4043 default:
4044 UNREACHABLE(); // Case analysis is exhaustive.
4045 break;
4046 }
4047 if (instr->SzValue() == 0x1) {
4048 int n = instr->VFPNRegValue(kDoublePrecision);
4049 int m = instr->VFPMRegValue(kDoublePrecision);
4050 int d = instr->VFPDRegValue(kDoublePrecision);
4051 double result = get_double_from_d_register(condition_holds ? n : m);
4052 set_d_register_from_double(d, result);
4053 } else {
4054 int n = instr->VFPNRegValue(kSinglePrecision);
4055 int m = instr->VFPMRegValue(kSinglePrecision);
4056 int d = instr->VFPDRegValue(kSinglePrecision);
4057 float result = get_float_from_s_register(condition_holds ? n : m);
4058 set_s_register_from_float(d, result);
4059 }
4060 } else {
4061 UNIMPLEMENTED();
4062 }
4063 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004064 default:
4065 UNIMPLEMENTED();
4066 break;
4067 }
4068}
4069
4070
Steve Blocka7e24c12009-10-30 11:49:00 +00004071// Executes the current instruction.
Steve Block1e0659c2011-05-24 12:43:12 +01004072void Simulator::InstructionDecode(Instruction* instr) {
Steve Block6ded16b2010-05-10 14:33:55 +01004073 if (v8::internal::FLAG_check_icache) {
Steve Block44f0eee2011-05-26 01:26:41 +01004074 CheckICache(isolate_->simulator_i_cache(), instr);
Steve Block6ded16b2010-05-10 14:33:55 +01004075 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004076 pc_modified_ = false;
4077 if (::v8::internal::FLAG_trace_sim) {
4078 disasm::NameConverter converter;
4079 disasm::Disassembler dasm(converter);
4080 // use a reasonably large buffer
4081 v8::internal::EmbeddedVector<char, 256> buffer;
4082 dasm.InstructionDecode(buffer,
4083 reinterpret_cast<byte*>(instr));
Ben Murdochc5610432016-08-08 18:44:38 +01004084 PrintF(" 0x%08" V8PRIxPTR " %s\n", reinterpret_cast<intptr_t>(instr),
4085 buffer.start());
Steve Blocka7e24c12009-10-30 11:49:00 +00004086 }
Steve Block1e0659c2011-05-24 12:43:12 +01004087 if (instr->ConditionField() == kSpecialCondition) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004088 DecodeSpecialCondition(instr);
Steve Blocka7e24c12009-10-30 11:49:00 +00004089 } else if (ConditionallyExecute(instr)) {
Steve Block1e0659c2011-05-24 12:43:12 +01004090 switch (instr->TypeValue()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004091 case 0:
4092 case 1: {
4093 DecodeType01(instr);
4094 break;
4095 }
4096 case 2: {
4097 DecodeType2(instr);
4098 break;
4099 }
4100 case 3: {
4101 DecodeType3(instr);
4102 break;
4103 }
4104 case 4: {
4105 DecodeType4(instr);
4106 break;
4107 }
4108 case 5: {
4109 DecodeType5(instr);
4110 break;
4111 }
4112 case 6: {
4113 DecodeType6(instr);
4114 break;
4115 }
4116 case 7: {
4117 DecodeType7(instr);
4118 break;
4119 }
4120 default: {
4121 UNIMPLEMENTED();
4122 break;
4123 }
4124 }
Steve Block1e0659c2011-05-24 12:43:12 +01004125 // If the instruction is a non taken conditional stop, we need to skip the
4126 // inlined message address.
4127 } else if (instr->IsStop()) {
4128 set_pc(get_pc() + 2 * Instruction::kInstrSize);
Steve Blocka7e24c12009-10-30 11:49:00 +00004129 }
4130 if (!pc_modified_) {
Steve Block1e0659c2011-05-24 12:43:12 +01004131 set_register(pc, reinterpret_cast<int32_t>(instr)
4132 + Instruction::kInstrSize);
Steve Blocka7e24c12009-10-30 11:49:00 +00004133 }
4134}
4135
4136
Steve Blocka7e24c12009-10-30 11:49:00 +00004137void Simulator::Execute() {
4138 // Get the PC to simulate. Cannot use the accessor here as we need the
4139 // raw PC value and not the one used as input to arithmetic instructions.
4140 int program_counter = get_pc();
4141
4142 if (::v8::internal::FLAG_stop_sim_at == 0) {
4143 // Fast version of the dispatch loop without checking whether the simulator
4144 // should be stopping at a particular executed instruction.
4145 while (program_counter != end_sim_pc) {
Steve Block1e0659c2011-05-24 12:43:12 +01004146 Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
Steve Blocka7e24c12009-10-30 11:49:00 +00004147 icount_++;
4148 InstructionDecode(instr);
4149 program_counter = get_pc();
4150 }
4151 } else {
4152 // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when
4153 // we reach the particular instuction count.
4154 while (program_counter != end_sim_pc) {
Steve Block1e0659c2011-05-24 12:43:12 +01004155 Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
Steve Blocka7e24c12009-10-30 11:49:00 +00004156 icount_++;
4157 if (icount_ == ::v8::internal::FLAG_stop_sim_at) {
Steve Block44f0eee2011-05-26 01:26:41 +01004158 ArmDebugger dbg(this);
Steve Blocka7e24c12009-10-30 11:49:00 +00004159 dbg.Debug();
4160 } else {
4161 InstructionDecode(instr);
4162 }
4163 program_counter = get_pc();
4164 }
4165 }
4166}
4167
4168
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004169void Simulator::CallInternal(byte* entry) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004170 // Adjust JS-based stack limit to C-based stack limit.
4171 isolate_->stack_guard()->AdjustStackLimitForSimulator();
4172
Steve Blocka7e24c12009-10-30 11:49:00 +00004173 // Prepare to execute the code at entry
4174 set_register(pc, reinterpret_cast<int32_t>(entry));
4175 // Put down marker for end of simulation. The simulator will stop simulation
4176 // when the PC reaches this value. By saving the "end simulation" value into
4177 // the LR the simulation stops when returning to this call point.
4178 set_register(lr, end_sim_pc);
4179
4180 // Remember the values of callee-saved registers.
4181 // The code below assumes that r9 is not used as sb (static base) in
4182 // simulator code and therefore is regarded as a callee-saved register.
4183 int32_t r4_val = get_register(r4);
4184 int32_t r5_val = get_register(r5);
4185 int32_t r6_val = get_register(r6);
4186 int32_t r7_val = get_register(r7);
4187 int32_t r8_val = get_register(r8);
4188 int32_t r9_val = get_register(r9);
4189 int32_t r10_val = get_register(r10);
4190 int32_t r11_val = get_register(r11);
4191
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004192 // Set up the callee-saved registers with a known value. To be able to check
Steve Blocka7e24c12009-10-30 11:49:00 +00004193 // that they are preserved properly across JS execution.
4194 int32_t callee_saved_value = icount_;
4195 set_register(r4, callee_saved_value);
4196 set_register(r5, callee_saved_value);
4197 set_register(r6, callee_saved_value);
4198 set_register(r7, callee_saved_value);
4199 set_register(r8, callee_saved_value);
4200 set_register(r9, callee_saved_value);
4201 set_register(r10, callee_saved_value);
4202 set_register(r11, callee_saved_value);
4203
4204 // Start the simulation
4205 Execute();
4206
4207 // Check that the callee-saved registers have been preserved.
4208 CHECK_EQ(callee_saved_value, get_register(r4));
4209 CHECK_EQ(callee_saved_value, get_register(r5));
4210 CHECK_EQ(callee_saved_value, get_register(r6));
4211 CHECK_EQ(callee_saved_value, get_register(r7));
4212 CHECK_EQ(callee_saved_value, get_register(r8));
4213 CHECK_EQ(callee_saved_value, get_register(r9));
4214 CHECK_EQ(callee_saved_value, get_register(r10));
4215 CHECK_EQ(callee_saved_value, get_register(r11));
4216
4217 // Restore callee-saved registers with the original value.
4218 set_register(r4, r4_val);
4219 set_register(r5, r5_val);
4220 set_register(r6, r6_val);
4221 set_register(r7, r7_val);
4222 set_register(r8, r8_val);
4223 set_register(r9, r9_val);
4224 set_register(r10, r10_val);
4225 set_register(r11, r11_val);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004226}
4227
4228
4229int32_t Simulator::Call(byte* entry, int argument_count, ...) {
4230 va_list parameters;
4231 va_start(parameters, argument_count);
4232 // Set up arguments
4233
4234 // First four arguments passed in registers.
4235 DCHECK(argument_count >= 4);
4236 set_register(r0, va_arg(parameters, int32_t));
4237 set_register(r1, va_arg(parameters, int32_t));
4238 set_register(r2, va_arg(parameters, int32_t));
4239 set_register(r3, va_arg(parameters, int32_t));
4240
4241 // Remaining arguments passed on stack.
4242 int original_stack = get_register(sp);
4243 // Compute position of stack on entry to generated code.
4244 int entry_stack = (original_stack - (argument_count - 4) * sizeof(int32_t));
4245 if (base::OS::ActivationFrameAlignment() != 0) {
4246 entry_stack &= -base::OS::ActivationFrameAlignment();
4247 }
4248 // Store remaining arguments on stack, from low to high memory.
4249 intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
4250 for (int i = 4; i < argument_count; i++) {
4251 stack_argument[i - 4] = va_arg(parameters, int32_t);
4252 }
4253 va_end(parameters);
4254 set_register(sp, entry_stack);
4255
4256 CallInternal(entry);
Steve Blocka7e24c12009-10-30 11:49:00 +00004257
4258 // Pop stack passed arguments.
4259 CHECK_EQ(entry_stack, get_register(sp));
4260 set_register(sp, original_stack);
4261
4262 int32_t result = get_register(r0);
4263 return result;
4264}
4265
Steve Blockd0582a62009-12-15 09:54:21 +00004266
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004267void Simulator::CallFP(byte* entry, double d0, double d1) {
4268 if (use_eabi_hardfloat()) {
4269 set_d_register_from_double(0, d0);
4270 set_d_register_from_double(1, d1);
4271 } else {
4272 set_register_pair_from_double(0, &d0);
4273 set_register_pair_from_double(2, &d1);
4274 }
4275 CallInternal(entry);
4276}
4277
4278
4279int32_t Simulator::CallFPReturnsInt(byte* entry, double d0, double d1) {
4280 CallFP(entry, d0, d1);
4281 int32_t result = get_register(r0);
4282 return result;
4283}
4284
4285
4286double Simulator::CallFPReturnsDouble(byte* entry, double d0, double d1) {
4287 CallFP(entry, d0, d1);
4288 if (use_eabi_hardfloat()) {
4289 return get_double_from_d_register(0);
4290 } else {
4291 return get_double_from_register_pair(0);
4292 }
4293}
4294
4295
Steve Blockd0582a62009-12-15 09:54:21 +00004296uintptr_t Simulator::PushAddress(uintptr_t address) {
4297 int new_sp = get_register(sp) - sizeof(uintptr_t);
4298 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp);
4299 *stack_slot = address;
4300 set_register(sp, new_sp);
4301 return new_sp;
4302}
4303
4304
4305uintptr_t Simulator::PopAddress() {
4306 int current_sp = get_register(sp);
4307 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp);
4308 uintptr_t address = *stack_slot;
4309 set_register(sp, current_sp + sizeof(uintptr_t));
4310 return address;
4311}
4312
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004313} // namespace internal
4314} // namespace v8
Steve Blocka7e24c12009-10-30 11:49:00 +00004315
John Reck59135872010-11-02 12:39:01 -07004316#endif // USE_SIMULATOR
Leon Clarkef7060e22010-06-03 12:02:55 +01004317
4318#endif // V8_TARGET_ARCH_ARM