blob: 6c22a0a86acdf51736324dae3e2f943b35e39d35 [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 Murdoch4a90d5f2016-03-22 12:00:34 +0000302 PrintF("%3s: 0x%08x %10d", Register::from_code(i).ToString(),
303 value, value);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100304 if ((argc == 3 && strcmp(arg2, "fp") == 0) &&
305 i < 8 &&
306 (i % 2) == 0) {
307 dvalue = GetRegisterPairDoubleValue(i);
308 PrintF(" (%f)\n", dvalue);
309 } else {
310 PrintF("\n");
311 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000312 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000313 for (int i = 0; i < DwVfpRegister::NumRegisters(); i++) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100314 dvalue = GetVFPDoubleRegisterValue(i);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000315 uint64_t as_words = bit_cast<uint64_t>(dvalue);
Steve Block44f0eee2011-05-26 01:26:41 +0100316 PrintF("%3s: %f 0x%08x %08x\n",
317 VFPRegisters::Name(i, true),
318 dvalue,
319 static_cast<uint32_t>(as_words >> 32),
320 static_cast<uint32_t>(as_words & 0xffffffff));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100321 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000322 } else {
323 if (GetValue(arg1, &value)) {
324 PrintF("%s: 0x%08x %d \n", arg1, value, value);
Steve Block6ded16b2010-05-10 14:33:55 +0100325 } else if (GetVFPSingleValue(arg1, &svalue)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000326 uint32_t as_word = bit_cast<uint32_t>(svalue);
Steve Block44f0eee2011-05-26 01:26:41 +0100327 PrintF("%s: %f 0x%08x\n", arg1, svalue, as_word);
Steve Block6ded16b2010-05-10 14:33:55 +0100328 } else if (GetVFPDoubleValue(arg1, &dvalue)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000329 uint64_t as_words = bit_cast<uint64_t>(dvalue);
Steve Block44f0eee2011-05-26 01:26:41 +0100330 PrintF("%s: %f 0x%08x %08x\n",
331 arg1,
332 dvalue,
333 static_cast<uint32_t>(as_words >> 32),
334 static_cast<uint32_t>(as_words & 0xffffffff));
Steve Blocka7e24c12009-10-30 11:49:00 +0000335 } else {
336 PrintF("%s unrecognized\n", arg1);
337 }
338 }
339 } else {
340 PrintF("print <register>\n");
341 }
342 } else if ((strcmp(cmd, "po") == 0)
343 || (strcmp(cmd, "printobject") == 0)) {
Steve Block6ded16b2010-05-10 14:33:55 +0100344 if (argc == 2) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000345 int32_t value;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000346 OFStream os(stdout);
Steve Blocka7e24c12009-10-30 11:49:00 +0000347 if (GetValue(arg1, &value)) {
348 Object* obj = reinterpret_cast<Object*>(value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000349 os << arg1 << ": \n";
Steve Blocka7e24c12009-10-30 11:49:00 +0000350#ifdef DEBUG
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000351 obj->Print(os);
352 os << "\n";
Steve Blocka7e24c12009-10-30 11:49:00 +0000353#else
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000354 os << Brief(obj) << "\n";
Steve Blocka7e24c12009-10-30 11:49:00 +0000355#endif
356 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000357 os << arg1 << " unrecognized\n";
Steve Blocka7e24c12009-10-30 11:49:00 +0000358 }
359 } else {
360 PrintF("printobject <value>\n");
361 }
Steve Block6ded16b2010-05-10 14:33:55 +0100362 } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0) {
363 int32_t* cur = NULL;
364 int32_t* end = NULL;
365 int next_arg = 1;
366
367 if (strcmp(cmd, "stack") == 0) {
368 cur = reinterpret_cast<int32_t*>(sim_->get_register(Simulator::sp));
369 } else { // "mem"
370 int32_t value;
371 if (!GetValue(arg1, &value)) {
372 PrintF("%s unrecognized\n", arg1);
373 continue;
374 }
375 cur = reinterpret_cast<int32_t*>(value);
376 next_arg++;
377 }
378
379 int32_t words;
380 if (argc == next_arg) {
381 words = 10;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000382 } else {
Steve Block6ded16b2010-05-10 14:33:55 +0100383 if (!GetValue(argv[next_arg], &words)) {
384 words = 10;
385 }
386 }
387 end = cur + words;
388
389 while (cur < end) {
Steve Block44f0eee2011-05-26 01:26:41 +0100390 PrintF(" 0x%08x: 0x%08x %10d",
Ben Murdochf87a2032010-10-22 12:50:53 +0100391 reinterpret_cast<intptr_t>(cur), *cur, *cur);
Steve Block44f0eee2011-05-26 01:26:41 +0100392 HeapObject* obj = reinterpret_cast<HeapObject*>(*cur);
393 int value = *cur;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000394 Heap* current_heap = sim_->isolate_->heap();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100395 if (((value & 1) == 0) ||
396 current_heap->ContainsSlow(obj->address())) {
Steve Block44f0eee2011-05-26 01:26:41 +0100397 PrintF(" (");
398 if ((value & 1) == 0) {
399 PrintF("smi %d", value / 2);
400 } else {
401 obj->ShortPrint();
402 }
403 PrintF(")");
404 }
405 PrintF("\n");
Steve Block6ded16b2010-05-10 14:33:55 +0100406 cur++;
407 }
Steve Block44f0eee2011-05-26 01:26:41 +0100408 } else if (strcmp(cmd, "disasm") == 0 || strcmp(cmd, "di") == 0) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000409 disasm::NameConverter converter;
410 disasm::Disassembler dasm(converter);
411 // use a reasonably large buffer
412 v8::internal::EmbeddedVector<char, 256> buffer;
413
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800414 byte* prev = NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +0000415 byte* cur = NULL;
416 byte* end = NULL;
417
Steve Block6ded16b2010-05-10 14:33:55 +0100418 if (argc == 1) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000419 cur = reinterpret_cast<byte*>(sim_->get_pc());
Steve Block1e0659c2011-05-24 12:43:12 +0100420 end = cur + (10 * Instruction::kInstrSize);
Steve Block6ded16b2010-05-10 14:33:55 +0100421 } else if (argc == 2) {
Steve Block44f0eee2011-05-26 01:26:41 +0100422 int regnum = Registers::Number(arg1);
423 if (regnum != kNoRegister || strncmp(arg1, "0x", 2) == 0) {
424 // The argument is an address or a register name.
425 int32_t value;
426 if (GetValue(arg1, &value)) {
427 cur = reinterpret_cast<byte*>(value);
428 // Disassemble 10 instructions at <arg1>.
429 end = cur + (10 * Instruction::kInstrSize);
430 }
431 } else {
432 // The argument is the number of instructions.
433 int32_t value;
434 if (GetValue(arg1, &value)) {
435 cur = reinterpret_cast<byte*>(sim_->get_pc());
436 // Disassemble <arg1> instructions.
437 end = cur + (value * Instruction::kInstrSize);
438 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000439 }
440 } else {
441 int32_t value1;
442 int32_t value2;
443 if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
444 cur = reinterpret_cast<byte*>(value1);
Steve Block1e0659c2011-05-24 12:43:12 +0100445 end = cur + (value2 * Instruction::kInstrSize);
Steve Blocka7e24c12009-10-30 11:49:00 +0000446 }
447 }
448
449 while (cur < end) {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800450 prev = cur;
451 cur += dasm.InstructionDecode(buffer, cur);
Ben Murdochf87a2032010-10-22 12:50:53 +0100452 PrintF(" 0x%08x %s\n",
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800453 reinterpret_cast<intptr_t>(prev), buffer.start());
Steve Blocka7e24c12009-10-30 11:49:00 +0000454 }
455 } else if (strcmp(cmd, "gdb") == 0) {
456 PrintF("relinquishing control to gdb\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000457 v8::base::OS::DebugBreak();
Steve Blocka7e24c12009-10-30 11:49:00 +0000458 PrintF("regaining control from gdb\n");
459 } else if (strcmp(cmd, "break") == 0) {
Steve Block6ded16b2010-05-10 14:33:55 +0100460 if (argc == 2) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000461 int32_t value;
462 if (GetValue(arg1, &value)) {
Steve Block1e0659c2011-05-24 12:43:12 +0100463 if (!SetBreakpoint(reinterpret_cast<Instruction*>(value))) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000464 PrintF("setting breakpoint failed\n");
465 }
466 } else {
467 PrintF("%s unrecognized\n", arg1);
468 }
469 } else {
470 PrintF("break <address>\n");
471 }
472 } else if (strcmp(cmd, "del") == 0) {
473 if (!DeleteBreakpoint(NULL)) {
474 PrintF("deleting breakpoint failed\n");
475 }
476 } else if (strcmp(cmd, "flags") == 0) {
477 PrintF("N flag: %d; ", sim_->n_flag_);
478 PrintF("Z flag: %d; ", sim_->z_flag_);
479 PrintF("C flag: %d; ", sim_->c_flag_);
480 PrintF("V flag: %d\n", sim_->v_flag_);
Steve Blockd0582a62009-12-15 09:54:21 +0000481 PrintF("INVALID OP flag: %d; ", sim_->inv_op_vfp_flag_);
482 PrintF("DIV BY ZERO flag: %d; ", sim_->div_zero_vfp_flag_);
483 PrintF("OVERFLOW flag: %d; ", sim_->overflow_vfp_flag_);
484 PrintF("UNDERFLOW flag: %d; ", sim_->underflow_vfp_flag_);
Steve Block1e0659c2011-05-24 12:43:12 +0100485 PrintF("INEXACT flag: %d;\n", sim_->inexact_vfp_flag_);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800486 } else if (strcmp(cmd, "stop") == 0) {
487 int32_t value;
Steve Block1e0659c2011-05-24 12:43:12 +0100488 intptr_t stop_pc = sim_->get_pc() - 2 * Instruction::kInstrSize;
489 Instruction* stop_instr = reinterpret_cast<Instruction*>(stop_pc);
490 Instruction* msg_address =
491 reinterpret_cast<Instruction*>(stop_pc + Instruction::kInstrSize);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800492 if ((argc == 2) && (strcmp(arg1, "unstop") == 0)) {
493 // Remove the current stop.
494 if (sim_->isStopInstruction(stop_instr)) {
495 stop_instr->SetInstructionBits(kNopInstr);
496 msg_address->SetInstructionBits(kNopInstr);
497 } else {
498 PrintF("Not at debugger stop.\n");
499 }
500 } else if (argc == 3) {
501 // Print information about all/the specified breakpoint(s).
502 if (strcmp(arg1, "info") == 0) {
503 if (strcmp(arg2, "all") == 0) {
504 PrintF("Stop information:\n");
505 for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) {
506 sim_->PrintStopInfo(i);
507 }
508 } else if (GetValue(arg2, &value)) {
509 sim_->PrintStopInfo(value);
510 } else {
511 PrintF("Unrecognized argument.\n");
512 }
513 } else if (strcmp(arg1, "enable") == 0) {
514 // Enable all/the specified breakpoint(s).
515 if (strcmp(arg2, "all") == 0) {
516 for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) {
517 sim_->EnableStop(i);
518 }
519 } else if (GetValue(arg2, &value)) {
520 sim_->EnableStop(value);
521 } else {
522 PrintF("Unrecognized argument.\n");
523 }
524 } else if (strcmp(arg1, "disable") == 0) {
525 // Disable all/the specified breakpoint(s).
526 if (strcmp(arg2, "all") == 0) {
527 for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) {
528 sim_->DisableStop(i);
529 }
530 } else if (GetValue(arg2, &value)) {
531 sim_->DisableStop(value);
532 } else {
533 PrintF("Unrecognized argument.\n");
534 }
535 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000536 } else {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800537 PrintF("Wrong usage. Use help command for more information.\n");
Steve Blocka7e24c12009-10-30 11:49:00 +0000538 }
Leon Clarkee46be812010-01-19 14:06:41 +0000539 } else if ((strcmp(cmd, "t") == 0) || strcmp(cmd, "trace") == 0) {
540 ::v8::internal::FLAG_trace_sim = !::v8::internal::FLAG_trace_sim;
541 PrintF("Trace of executed instructions is %s\n",
542 ::v8::internal::FLAG_trace_sim ? "on" : "off");
Steve Blocka7e24c12009-10-30 11:49:00 +0000543 } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
544 PrintF("cont\n");
545 PrintF(" continue execution (alias 'c')\n");
546 PrintF("stepi\n");
547 PrintF(" step one instruction (alias 'si')\n");
548 PrintF("print <register>\n");
549 PrintF(" print register content (alias 'p')\n");
550 PrintF(" use register name 'all' to print all registers\n");
Ben Murdoch8b112d22011-06-08 16:22:53 +0100551 PrintF(" add argument 'fp' to print register pair double values\n");
Steve Blocka7e24c12009-10-30 11:49:00 +0000552 PrintF("printobject <register>\n");
553 PrintF(" print an object from a register (alias 'po')\n");
554 PrintF("flags\n");
555 PrintF(" print flags\n");
Steve Block6ded16b2010-05-10 14:33:55 +0100556 PrintF("stack [<words>]\n");
557 PrintF(" dump stack content, default dump 10 words)\n");
558 PrintF("mem <address> [<words>]\n");
559 PrintF(" dump memory content, default dump 10 words)\n");
Steve Blocka7e24c12009-10-30 11:49:00 +0000560 PrintF("disasm [<instructions>]\n");
Steve Block44f0eee2011-05-26 01:26:41 +0100561 PrintF("disasm [<address/register>]\n");
562 PrintF("disasm [[<address/register>] <instructions>]\n");
563 PrintF(" disassemble code, default is 10 instructions\n");
564 PrintF(" from pc (alias 'di')\n");
Steve Blocka7e24c12009-10-30 11:49:00 +0000565 PrintF("gdb\n");
566 PrintF(" enter gdb\n");
567 PrintF("break <address>\n");
568 PrintF(" set a break point on the address\n");
569 PrintF("del\n");
570 PrintF(" delete the breakpoint\n");
Leon Clarkee46be812010-01-19 14:06:41 +0000571 PrintF("trace (alias 't')\n");
Steve Block6ded16b2010-05-10 14:33:55 +0100572 PrintF(" toogle the tracing of all executed statements\n");
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800573 PrintF("stop feature:\n");
574 PrintF(" Description:\n");
575 PrintF(" Stops are debug instructions inserted by\n");
576 PrintF(" the Assembler::stop() function.\n");
577 PrintF(" When hitting a stop, the Simulator will\n");
Steve Block44f0eee2011-05-26 01:26:41 +0100578 PrintF(" stop and and give control to the ArmDebugger.\n");
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800579 PrintF(" The first %d stop codes are watched:\n",
580 Simulator::kNumOfWatchedStops);
581 PrintF(" - They can be enabled / disabled: the Simulator\n");
Steve Block44f0eee2011-05-26 01:26:41 +0100582 PrintF(" will / won't stop when hitting them.\n");
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800583 PrintF(" - The Simulator keeps track of how many times they \n");
584 PrintF(" are met. (See the info command.) Going over a\n");
585 PrintF(" disabled stop still increases its counter. \n");
586 PrintF(" Commands:\n");
587 PrintF(" stop info all/<code> : print infos about number <code>\n");
588 PrintF(" or all stop(s).\n");
589 PrintF(" stop enable/disable all/<code> : enables / disables\n");
590 PrintF(" all or number <code> stop(s)\n");
591 PrintF(" stop unstop\n");
592 PrintF(" ignore the stop instruction at the current location\n");
593 PrintF(" from now on\n");
Steve Blocka7e24c12009-10-30 11:49:00 +0000594 } else {
595 PrintF("Unknown command: %s\n", cmd);
596 }
597 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000598 }
599
600 // Add all the breakpoints back to stop execution and enter the debugger
601 // shell when hit.
602 RedoBreakpoints();
603
604#undef COMMAND_SIZE
605#undef ARG_SIZE
606
607#undef STR
608#undef XSTR
609}
610
611
Steve Block6ded16b2010-05-10 14:33:55 +0100612static bool ICacheMatch(void* one, void* two) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000613 DCHECK((reinterpret_cast<intptr_t>(one) & CachePage::kPageMask) == 0);
614 DCHECK((reinterpret_cast<intptr_t>(two) & CachePage::kPageMask) == 0);
Steve Block6ded16b2010-05-10 14:33:55 +0100615 return one == two;
616}
617
618
619static uint32_t ICacheHash(void* key) {
620 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)) >> 2;
621}
622
623
624static bool AllOnOnePage(uintptr_t start, int size) {
625 intptr_t start_page = (start & ~CachePage::kPageMask);
626 intptr_t end_page = ((start + size) & ~CachePage::kPageMask);
627 return start_page == end_page;
628}
629
630
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100631void Simulator::set_last_debugger_input(char* input) {
632 DeleteArray(last_debugger_input_);
633 last_debugger_input_ = input;
634}
635
636
Steve Block44f0eee2011-05-26 01:26:41 +0100637void Simulator::FlushICache(v8::internal::HashMap* i_cache,
638 void* start_addr,
639 size_t size) {
Steve Block6ded16b2010-05-10 14:33:55 +0100640 intptr_t start = reinterpret_cast<intptr_t>(start_addr);
641 int intra_line = (start & CachePage::kLineMask);
642 start -= intra_line;
643 size += intra_line;
644 size = ((size - 1) | CachePage::kLineMask) + 1;
645 int offset = (start & CachePage::kPageMask);
646 while (!AllOnOnePage(start, size - 1)) {
647 int bytes_to_flush = CachePage::kPageSize - offset;
Steve Block44f0eee2011-05-26 01:26:41 +0100648 FlushOnePage(i_cache, start, bytes_to_flush);
Steve Block6ded16b2010-05-10 14:33:55 +0100649 start += bytes_to_flush;
650 size -= bytes_to_flush;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000651 DCHECK_EQ(0, start & CachePage::kPageMask);
Steve Block6ded16b2010-05-10 14:33:55 +0100652 offset = 0;
653 }
654 if (size != 0) {
Steve Block44f0eee2011-05-26 01:26:41 +0100655 FlushOnePage(i_cache, start, size);
Steve Block6ded16b2010-05-10 14:33:55 +0100656 }
657}
658
659
Steve Block44f0eee2011-05-26 01:26:41 +0100660CachePage* Simulator::GetCachePage(v8::internal::HashMap* i_cache, void* page) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000661 v8::internal::HashMap::Entry* entry =
662 i_cache->LookupOrInsert(page, ICacheHash(page));
Steve Block6ded16b2010-05-10 14:33:55 +0100663 if (entry->value == NULL) {
664 CachePage* new_page = new CachePage();
665 entry->value = new_page;
666 }
667 return reinterpret_cast<CachePage*>(entry->value);
668}
669
670
671// Flush from start up to and not including start + size.
Steve Block44f0eee2011-05-26 01:26:41 +0100672void Simulator::FlushOnePage(v8::internal::HashMap* i_cache,
673 intptr_t start,
674 int size) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000675 DCHECK(size <= CachePage::kPageSize);
676 DCHECK(AllOnOnePage(start, size - 1));
677 DCHECK((start & CachePage::kLineMask) == 0);
678 DCHECK((size & CachePage::kLineMask) == 0);
Steve Block6ded16b2010-05-10 14:33:55 +0100679 void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask));
680 int offset = (start & CachePage::kPageMask);
Steve Block44f0eee2011-05-26 01:26:41 +0100681 CachePage* cache_page = GetCachePage(i_cache, page);
Steve Block6ded16b2010-05-10 14:33:55 +0100682 char* valid_bytemap = cache_page->ValidityByte(offset);
683 memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift);
684}
685
686
Steve Block44f0eee2011-05-26 01:26:41 +0100687void Simulator::CheckICache(v8::internal::HashMap* i_cache,
688 Instruction* instr) {
Steve Block6ded16b2010-05-10 14:33:55 +0100689 intptr_t address = reinterpret_cast<intptr_t>(instr);
690 void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
691 void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask));
692 int offset = (address & CachePage::kPageMask);
Steve Block44f0eee2011-05-26 01:26:41 +0100693 CachePage* cache_page = GetCachePage(i_cache, page);
Steve Block6ded16b2010-05-10 14:33:55 +0100694 char* cache_valid_byte = cache_page->ValidityByte(offset);
695 bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID);
696 char* cached_line = cache_page->CachedData(offset & ~CachePage::kLineMask);
697 if (cache_hit) {
698 // Check that the data in memory matches the contents of the I-cache.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000699 CHECK_EQ(0,
700 memcmp(reinterpret_cast<void*>(instr),
701 cache_page->CachedData(offset), Instruction::kInstrSize));
Steve Block6ded16b2010-05-10 14:33:55 +0100702 } else {
703 // Cache miss. Load memory into the cache.
704 memcpy(cached_line, line, CachePage::kLineLength);
705 *cache_valid_byte = CachePage::LINE_VALID;
706 }
707}
708
709
Ben Murdoch257744e2011-11-30 15:57:28 +0000710void Simulator::Initialize(Isolate* isolate) {
711 if (isolate->simulator_initialized()) return;
712 isolate->set_simulator_initialized(true);
713 ::v8::internal::ExternalReference::set_redirector(isolate,
714 &RedirectExternalReference);
Steve Blocka7e24c12009-10-30 11:49:00 +0000715}
716
717
Ben Murdoch257744e2011-11-30 15:57:28 +0000718Simulator::Simulator(Isolate* isolate) : isolate_(isolate) {
Steve Block44f0eee2011-05-26 01:26:41 +0100719 i_cache_ = isolate_->simulator_i_cache();
Steve Block6ded16b2010-05-10 14:33:55 +0100720 if (i_cache_ == NULL) {
721 i_cache_ = new v8::internal::HashMap(&ICacheMatch);
Steve Block44f0eee2011-05-26 01:26:41 +0100722 isolate_->set_simulator_i_cache(i_cache_);
Steve Block6ded16b2010-05-10 14:33:55 +0100723 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000724 Initialize(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100725 // Set up simulator support first. Some of this information is needed to
Steve Blocka7e24c12009-10-30 11:49:00 +0000726 // setup the architecture state.
727 size_t stack_size = 1 * 1024*1024; // allocate 1MB for stack
728 stack_ = reinterpret_cast<char*>(malloc(stack_size));
729 pc_modified_ = false;
730 icount_ = 0;
731 break_pc_ = NULL;
732 break_instr_ = 0;
733
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100734 // Set up architecture state.
Steve Blocka7e24c12009-10-30 11:49:00 +0000735 // All registers are initialized to zero to start with.
736 for (int i = 0; i < num_registers; i++) {
737 registers_[i] = 0;
738 }
739 n_flag_ = false;
740 z_flag_ = false;
741 c_flag_ = false;
742 v_flag_ = false;
743
Steve Blockd0582a62009-12-15 09:54:21 +0000744 // Initializing VFP registers.
745 // All registers are initialized to zero to start with
746 // even though s_registers_ & d_registers_ share the same
747 // physical registers in the target.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000748 for (int i = 0; i < num_d_registers * 2; i++) {
749 vfp_registers_[i] = 0;
Steve Blockd0582a62009-12-15 09:54:21 +0000750 }
751 n_flag_FPSCR_ = false;
752 z_flag_FPSCR_ = false;
753 c_flag_FPSCR_ = false;
754 v_flag_FPSCR_ = false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000755 FPSCR_rounding_mode_ = RN;
756 FPSCR_default_NaN_mode_ = false;
Steve Blockd0582a62009-12-15 09:54:21 +0000757
758 inv_op_vfp_flag_ = false;
759 div_zero_vfp_flag_ = false;
760 overflow_vfp_flag_ = false;
761 underflow_vfp_flag_ = false;
762 inexact_vfp_flag_ = false;
763
Steve Blocka7e24c12009-10-30 11:49:00 +0000764 // The sp is initialized to point to the bottom (high address) of the
765 // allocated stack area. To be safe in potential stack underflows we leave
766 // some buffer below.
767 registers_[sp] = reinterpret_cast<int32_t>(stack_) + stack_size - 64;
768 // The lr and pc are initialized to a known bad value that will cause an
769 // access violation if the simulator ever tries to execute it.
770 registers_[pc] = bad_lr;
771 registers_[lr] = bad_lr;
772 InitializeCoverage();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100773
774 last_debugger_input_ = NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +0000775}
776
777
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000778Simulator::~Simulator() { free(stack_); }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000779
780
Steve Blocka7e24c12009-10-30 11:49:00 +0000781// When the generated code calls an external reference we need to catch that in
782// the simulator. The external reference will be a function compiled for the
783// host architecture. We need to call that function instead of trying to
784// execute it with the simulator. We do that by redirecting the external
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800785// reference to a svc (Supervisor Call) instruction that is handled by
Steve Blocka7e24c12009-10-30 11:49:00 +0000786// the simulator. We write the original destination of the jump just at a known
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800787// offset from the svc instruction so the simulator knows what to call.
Steve Blocka7e24c12009-10-30 11:49:00 +0000788class Redirection {
789 public:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000790 Redirection(Isolate* isolate, void* external_function,
791 ExternalReference::Type type)
Steve Blocka7e24c12009-10-30 11:49:00 +0000792 : external_function_(external_function),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000793 swi_instruction_(al | (0xf * B24) | kCallRtRedirected),
Steve Block1e0659c2011-05-24 12:43:12 +0100794 type_(type),
Steve Block44f0eee2011-05-26 01:26:41 +0100795 next_(NULL) {
Steve Block44f0eee2011-05-26 01:26:41 +0100796 next_ = isolate->simulator_redirection();
797 Simulator::current(isolate)->
798 FlushICache(isolate->simulator_i_cache(),
799 reinterpret_cast<void*>(&swi_instruction_),
800 Instruction::kInstrSize);
801 isolate->set_simulator_redirection(this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000802 }
803
804 void* address_of_swi_instruction() {
805 return reinterpret_cast<void*>(&swi_instruction_);
806 }
807
808 void* external_function() { return external_function_; }
Steve Block1e0659c2011-05-24 12:43:12 +0100809 ExternalReference::Type type() { return type_; }
Steve Blocka7e24c12009-10-30 11:49:00 +0000810
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000811 static Redirection* Get(Isolate* isolate, void* external_function,
Steve Block1e0659c2011-05-24 12:43:12 +0100812 ExternalReference::Type type) {
Steve Block44f0eee2011-05-26 01:26:41 +0100813 Redirection* current = isolate->simulator_redirection();
814 for (; current != NULL; current = current->next_) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000815 if (current->external_function_ == external_function) {
816 DCHECK_EQ(current->type(), type);
817 return current;
818 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000819 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000820 return new Redirection(isolate, external_function, type);
Steve Blocka7e24c12009-10-30 11:49:00 +0000821 }
822
Steve Block1e0659c2011-05-24 12:43:12 +0100823 static Redirection* FromSwiInstruction(Instruction* swi_instruction) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000824 char* addr_of_swi = reinterpret_cast<char*>(swi_instruction);
825 char* addr_of_redirection =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000826 addr_of_swi - offsetof(Redirection, swi_instruction_);
Steve Blocka7e24c12009-10-30 11:49:00 +0000827 return reinterpret_cast<Redirection*>(addr_of_redirection);
828 }
829
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000830 static void* ReverseRedirection(int32_t reg) {
831 Redirection* redirection = FromSwiInstruction(
832 reinterpret_cast<Instruction*>(reinterpret_cast<void*>(reg)));
833 return redirection->external_function();
834 }
835
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000836 static void DeleteChain(Redirection* redirection) {
837 while (redirection != nullptr) {
838 Redirection* next = redirection->next_;
839 delete redirection;
840 redirection = next;
841 }
842 }
843
Steve Blocka7e24c12009-10-30 11:49:00 +0000844 private:
845 void* external_function_;
846 uint32_t swi_instruction_;
Steve Block1e0659c2011-05-24 12:43:12 +0100847 ExternalReference::Type type_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000848 Redirection* next_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000849};
850
851
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000852// static
853void Simulator::TearDown(HashMap* i_cache, Redirection* first) {
854 Redirection::DeleteChain(first);
855 if (i_cache != nullptr) {
856 for (HashMap::Entry* entry = i_cache->Start(); entry != nullptr;
857 entry = i_cache->Next(entry)) {
858 delete static_cast<CachePage*>(entry->value);
859 }
860 delete i_cache;
861 }
862}
863
864
865void* Simulator::RedirectExternalReference(Isolate* isolate,
866 void* external_function,
Steve Block1e0659c2011-05-24 12:43:12 +0100867 ExternalReference::Type type) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000868 Redirection* redirection = Redirection::Get(isolate, external_function, type);
Steve Blocka7e24c12009-10-30 11:49:00 +0000869 return redirection->address_of_swi_instruction();
870}
871
872
873// Get the active Simulator for the current thread.
Steve Block44f0eee2011-05-26 01:26:41 +0100874Simulator* Simulator::current(Isolate* isolate) {
875 v8::internal::Isolate::PerIsolateThreadData* isolate_data =
Ben Murdoch257744e2011-11-30 15:57:28 +0000876 isolate->FindOrAllocatePerThreadDataForThisThread();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000877 DCHECK(isolate_data != NULL);
Steve Block44f0eee2011-05-26 01:26:41 +0100878
879 Simulator* sim = isolate_data->simulator();
Steve Blocka7e24c12009-10-30 11:49:00 +0000880 if (sim == NULL) {
Steve Block44f0eee2011-05-26 01:26:41 +0100881 // TODO(146): delete the simulator object when a thread/isolate goes away.
Ben Murdoch257744e2011-11-30 15:57:28 +0000882 sim = new Simulator(isolate);
Steve Block44f0eee2011-05-26 01:26:41 +0100883 isolate_data->set_simulator(sim);
Steve Blocka7e24c12009-10-30 11:49:00 +0000884 }
885 return sim;
886}
887
888
889// Sets the register in the architecture state. It will also deal with updating
890// Simulator internal state for special registers such as PC.
891void Simulator::set_register(int reg, int32_t value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000892 DCHECK((reg >= 0) && (reg < num_registers));
Steve Blocka7e24c12009-10-30 11:49:00 +0000893 if (reg == pc) {
894 pc_modified_ = true;
895 }
896 registers_[reg] = value;
897}
898
899
900// Get the register from the architecture state. This function does handle
901// the special case of accessing the PC register.
902int32_t Simulator::get_register(int reg) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000903 DCHECK((reg >= 0) && (reg < num_registers));
Steve Block791712a2010-08-27 10:21:07 +0100904 // Stupid code added to avoid bug in GCC.
905 // See: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43949
906 if (reg >= num_registers) return 0;
907 // End stupid code.
Steve Block1e0659c2011-05-24 12:43:12 +0100908 return registers_[reg] + ((reg == pc) ? Instruction::kPCReadOffset : 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000909}
910
911
Ben Murdoch8b112d22011-06-08 16:22:53 +0100912double Simulator::get_double_from_register_pair(int reg) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000913 DCHECK((reg >= 0) && (reg < num_registers) && ((reg % 2) == 0));
Ben Murdoch8b112d22011-06-08 16:22:53 +0100914
915 double dm_val = 0.0;
916 // Read the bits from the unsigned integer register_[] array
917 // into the double precision floating point value and return it.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000918 char buffer[2 * sizeof(vfp_registers_[0])];
Ben Murdoch8b112d22011-06-08 16:22:53 +0100919 memcpy(buffer, &registers_[reg], 2 * sizeof(registers_[0]));
920 memcpy(&dm_val, buffer, 2 * sizeof(registers_[0]));
921 return(dm_val);
922}
923
924
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000925void Simulator::set_register_pair_from_double(int reg, double* value) {
926 DCHECK((reg >= 0) && (reg < num_registers) && ((reg % 2) == 0));
927 memcpy(registers_ + reg, value, sizeof(*value));
928}
929
930
Kristian Monsen25f61362010-05-21 11:50:48 +0100931void Simulator::set_dw_register(int dreg, const int* dbl) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000932 DCHECK((dreg >= 0) && (dreg < num_d_registers));
Kristian Monsen25f61362010-05-21 11:50:48 +0100933 registers_[dreg] = dbl[0];
934 registers_[dreg + 1] = dbl[1];
935}
936
937
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000938void Simulator::get_d_register(int dreg, uint64_t* value) {
939 DCHECK((dreg >= 0) && (dreg < DwVfpRegister::NumRegisters()));
940 memcpy(value, vfp_registers_ + dreg * 2, sizeof(*value));
941}
942
943
944void Simulator::set_d_register(int dreg, const uint64_t* value) {
945 DCHECK((dreg >= 0) && (dreg < DwVfpRegister::NumRegisters()));
946 memcpy(vfp_registers_ + dreg * 2, value, sizeof(*value));
947}
948
949
950void Simulator::get_d_register(int dreg, uint32_t* value) {
951 DCHECK((dreg >= 0) && (dreg < DwVfpRegister::NumRegisters()));
952 memcpy(value, vfp_registers_ + dreg * 2, sizeof(*value) * 2);
953}
954
955
956void Simulator::set_d_register(int dreg, const uint32_t* value) {
957 DCHECK((dreg >= 0) && (dreg < DwVfpRegister::NumRegisters()));
958 memcpy(vfp_registers_ + dreg * 2, value, sizeof(*value) * 2);
959}
960
961
962void Simulator::get_q_register(int qreg, uint64_t* value) {
963 DCHECK((qreg >= 0) && (qreg < num_q_registers));
964 memcpy(value, vfp_registers_ + qreg * 4, sizeof(*value) * 2);
965}
966
967
968void Simulator::set_q_register(int qreg, const uint64_t* value) {
969 DCHECK((qreg >= 0) && (qreg < num_q_registers));
970 memcpy(vfp_registers_ + qreg * 4, value, sizeof(*value) * 2);
971}
972
973
974void Simulator::get_q_register(int qreg, uint32_t* value) {
975 DCHECK((qreg >= 0) && (qreg < num_q_registers));
976 memcpy(value, vfp_registers_ + qreg * 4, sizeof(*value) * 4);
977}
978
979
980void Simulator::set_q_register(int qreg, const uint32_t* value) {
981 DCHECK((qreg >= 0) && (qreg < num_q_registers));
982 memcpy(vfp_registers_ + qreg * 4, value, sizeof(*value) * 4);
983}
984
985
Steve Blocka7e24c12009-10-30 11:49:00 +0000986// Raw access to the PC register.
987void Simulator::set_pc(int32_t value) {
988 pc_modified_ = true;
989 registers_[pc] = value;
990}
991
992
Ben Murdochb0fe1622011-05-05 13:52:32 +0100993bool Simulator::has_bad_pc() const {
994 return ((registers_[pc] == bad_lr) || (registers_[pc] == end_sim_pc));
995}
996
997
Steve Blocka7e24c12009-10-30 11:49:00 +0000998// Raw access to the PC register without the special adjustment when reading.
999int32_t Simulator::get_pc() const {
1000 return registers_[pc];
1001}
1002
1003
Steve Blockd0582a62009-12-15 09:54:21 +00001004// Getting from and setting into VFP registers.
1005void Simulator::set_s_register(int sreg, unsigned int value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001006 DCHECK((sreg >= 0) && (sreg < num_s_registers));
1007 vfp_registers_[sreg] = value;
Steve Blockd0582a62009-12-15 09:54:21 +00001008}
1009
1010
1011unsigned int Simulator::get_s_register(int sreg) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001012 DCHECK((sreg >= 0) && (sreg < num_s_registers));
1013 return vfp_registers_[sreg];
Steve Blockd0582a62009-12-15 09:54:21 +00001014}
1015
1016
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001017template<class InputType, int register_size>
1018void Simulator::SetVFPRegister(int reg_index, const InputType& value) {
1019 DCHECK(reg_index >= 0);
1020 if (register_size == 1) DCHECK(reg_index < num_s_registers);
1021 if (register_size == 2) DCHECK(reg_index < DwVfpRegister::NumRegisters());
1022
1023 char buffer[register_size * sizeof(vfp_registers_[0])];
1024 memcpy(buffer, &value, register_size * sizeof(vfp_registers_[0]));
1025 memcpy(&vfp_registers_[reg_index * register_size], buffer,
1026 register_size * sizeof(vfp_registers_[0]));
Steve Blockd0582a62009-12-15 09:54:21 +00001027}
1028
1029
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001030template<class ReturnType, int register_size>
1031ReturnType Simulator::GetFromVFPRegister(int reg_index) {
1032 DCHECK(reg_index >= 0);
1033 if (register_size == 1) DCHECK(reg_index < num_s_registers);
1034 if (register_size == 2) DCHECK(reg_index < DwVfpRegister::NumRegisters());
1035
1036 ReturnType value = 0;
1037 char buffer[register_size * sizeof(vfp_registers_[0])];
1038 memcpy(buffer, &vfp_registers_[register_size * reg_index],
1039 register_size * sizeof(vfp_registers_[0]));
1040 memcpy(&value, buffer, register_size * sizeof(vfp_registers_[0]));
1041 return value;
Steve Blockd0582a62009-12-15 09:54:21 +00001042}
1043
Ben Murdochda12d292016-06-02 14:46:10 +01001044void Simulator::SetSpecialRegister(SRegisterFieldMask reg_and_mask,
1045 uint32_t value) {
1046 // Only CPSR_f is implemented. Of that, only N, Z, C and V are implemented.
1047 if ((reg_and_mask == CPSR_f) && ((value & ~kSpecialCondition) == 0)) {
1048 n_flag_ = ((value & (1 << 31)) != 0);
1049 z_flag_ = ((value & (1 << 30)) != 0);
1050 c_flag_ = ((value & (1 << 29)) != 0);
1051 v_flag_ = ((value & (1 << 28)) != 0);
1052 } else {
1053 UNIMPLEMENTED();
1054 }
1055}
1056
1057uint32_t Simulator::GetFromSpecialRegister(SRegister reg) {
1058 uint32_t result = 0;
1059 // Only CPSR_f is implemented.
1060 if (reg == CPSR) {
1061 if (n_flag_) result |= (1 << 31);
1062 if (z_flag_) result |= (1 << 30);
1063 if (c_flag_) result |= (1 << 29);
1064 if (v_flag_) result |= (1 << 28);
1065 } else {
1066 UNIMPLEMENTED();
1067 }
1068 return result;
1069}
Steve Blockd0582a62009-12-15 09:54:21 +00001070
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001071// Runtime FP routines take:
1072// - two double arguments
1073// - one double argument and zero or one integer arguments.
1074// All are consructed here from r0-r3 or d0, d1 and r0.
1075void Simulator::GetFpArgs(double* x, double* y, int32_t* z) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001076 if (use_eabi_hardfloat()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001077 *x = get_double_from_d_register(0);
1078 *y = get_double_from_d_register(1);
1079 *z = get_register(0);
Ben Murdoch257744e2011-11-30 15:57:28 +00001080 } else {
Ben Murdoch257744e2011-11-30 15:57:28 +00001081 // Registers 0 and 1 -> x.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001082 *x = get_double_from_register_pair(0);
1083 // Register 2 and 3 -> y.
1084 *y = get_double_from_register_pair(2);
1085 // Register 2 -> z
1086 *z = get_register(2);
Ben Murdoch257744e2011-11-30 15:57:28 +00001087 }
1088}
1089
1090
1091// The return value is either in r0/r1 or d0.
Steve Blocka7e24c12009-10-30 11:49:00 +00001092void Simulator::SetFpResult(const double& result) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001093 if (use_eabi_hardfloat()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001094 char buffer[2 * sizeof(vfp_registers_[0])];
Ben Murdoch257744e2011-11-30 15:57:28 +00001095 memcpy(buffer, &result, sizeof(buffer));
1096 // Copy result to d0.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001097 memcpy(vfp_registers_, buffer, sizeof(buffer));
Ben Murdoch257744e2011-11-30 15:57:28 +00001098 } else {
1099 char buffer[2 * sizeof(registers_[0])];
1100 memcpy(buffer, &result, sizeof(buffer));
1101 // Copy result to r0 and r1.
1102 memcpy(registers_, buffer, sizeof(buffer));
1103 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001104}
1105
1106
1107void Simulator::TrashCallerSaveRegisters() {
1108 // We don't trash the registers with the return value.
1109 registers_[2] = 0x50Bad4U;
1110 registers_[3] = 0x50Bad4U;
1111 registers_[12] = 0x50Bad4U;
1112}
1113
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001114
Kristian Monsen25f61362010-05-21 11:50:48 +01001115// Some Operating Systems allow unaligned access on ARMv7 targets. We
1116// assume that unaligned accesses are not allowed unless the v8 build system
1117// defines the CAN_USE_UNALIGNED_ACCESSES macro to be non-zero.
1118// The following statements below describes the behavior of the ARM CPUs
1119// that don't support unaligned access.
1120// Some ARM platforms raise an interrupt on detecting unaligned access.
1121// On others it does a funky rotation thing. For now we
1122// simply disallow unaligned reads. Note that simulator runs have the runtime
Steve Blocka7e24c12009-10-30 11:49:00 +00001123// system running directly on the host system and only generated code is
1124// executed in the simulator. Since the host is typically IA32 we will not
Kristian Monsen25f61362010-05-21 11:50:48 +01001125// get the correct ARM-like behaviour on unaligned accesses for those ARM
1126// targets that don't support unaligned loads and stores.
1127
Steve Blocka7e24c12009-10-30 11:49:00 +00001128
Steve Block1e0659c2011-05-24 12:43:12 +01001129int Simulator::ReadW(int32_t addr, Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001130 if (FLAG_enable_unaligned_accesses || (addr & 3) == 0) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001131 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
1132 return *ptr;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001133 } else {
1134 PrintF("Unaligned read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1135 addr,
1136 reinterpret_cast<intptr_t>(instr));
1137 UNIMPLEMENTED();
1138 return 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00001139 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001140}
1141
1142
Steve Block1e0659c2011-05-24 12:43:12 +01001143void Simulator::WriteW(int32_t addr, int value, Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001144 if (FLAG_enable_unaligned_accesses || (addr & 3) == 0) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001145 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
1146 *ptr = value;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001147 } else {
1148 PrintF("Unaligned write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1149 addr,
1150 reinterpret_cast<intptr_t>(instr));
1151 UNIMPLEMENTED();
Steve Blocka7e24c12009-10-30 11:49:00 +00001152 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001153}
1154
1155
Steve Block1e0659c2011-05-24 12:43:12 +01001156uint16_t Simulator::ReadHU(int32_t addr, Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001157 if (FLAG_enable_unaligned_accesses || (addr & 1) == 0) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001158 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1159 return *ptr;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001160 } else {
1161 PrintF("Unaligned unsigned halfword read at 0x%08x, pc=0x%08"
1162 V8PRIxPTR "\n",
1163 addr,
1164 reinterpret_cast<intptr_t>(instr));
1165 UNIMPLEMENTED();
1166 return 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00001167 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001168}
1169
1170
Steve Block1e0659c2011-05-24 12:43:12 +01001171int16_t Simulator::ReadH(int32_t addr, Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001172 if (FLAG_enable_unaligned_accesses || (addr & 1) == 0) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001173 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
1174 return *ptr;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001175 } else {
1176 PrintF("Unaligned signed halfword read at 0x%08x\n", addr);
1177 UNIMPLEMENTED();
1178 return 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00001179 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001180}
1181
1182
Steve Block1e0659c2011-05-24 12:43:12 +01001183void Simulator::WriteH(int32_t addr, uint16_t value, Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001184 if (FLAG_enable_unaligned_accesses || (addr & 1) == 0) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001185 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1186 *ptr = value;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001187 } else {
1188 PrintF("Unaligned unsigned halfword write at 0x%08x, pc=0x%08"
1189 V8PRIxPTR "\n",
1190 addr,
1191 reinterpret_cast<intptr_t>(instr));
1192 UNIMPLEMENTED();
Steve Blocka7e24c12009-10-30 11:49:00 +00001193 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001194}
1195
1196
Steve Block1e0659c2011-05-24 12:43:12 +01001197void Simulator::WriteH(int32_t addr, int16_t value, Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001198 if (FLAG_enable_unaligned_accesses || (addr & 1) == 0) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001199 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
1200 *ptr = value;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001201 } else {
1202 PrintF("Unaligned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1203 addr,
1204 reinterpret_cast<intptr_t>(instr));
1205 UNIMPLEMENTED();
Steve Blocka7e24c12009-10-30 11:49:00 +00001206 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001207}
1208
1209
1210uint8_t Simulator::ReadBU(int32_t addr) {
1211 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1212 return *ptr;
1213}
1214
1215
1216int8_t Simulator::ReadB(int32_t addr) {
1217 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
1218 return *ptr;
1219}
1220
1221
1222void Simulator::WriteB(int32_t addr, uint8_t value) {
1223 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1224 *ptr = value;
1225}
1226
1227
1228void Simulator::WriteB(int32_t addr, int8_t value) {
1229 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
1230 *ptr = value;
1231}
1232
1233
Kristian Monsen25f61362010-05-21 11:50:48 +01001234int32_t* Simulator::ReadDW(int32_t addr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001235 if (FLAG_enable_unaligned_accesses || (addr & 3) == 0) {
Kristian Monsen25f61362010-05-21 11:50:48 +01001236 int32_t* ptr = reinterpret_cast<int32_t*>(addr);
1237 return ptr;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001238 } else {
1239 PrintF("Unaligned read at 0x%08x\n", addr);
1240 UNIMPLEMENTED();
1241 return 0;
Kristian Monsen25f61362010-05-21 11:50:48 +01001242 }
Kristian Monsen25f61362010-05-21 11:50:48 +01001243}
1244
1245
1246void Simulator::WriteDW(int32_t addr, int32_t value1, int32_t value2) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001247 if (FLAG_enable_unaligned_accesses || (addr & 3) == 0) {
Kristian Monsen25f61362010-05-21 11:50:48 +01001248 int32_t* ptr = reinterpret_cast<int32_t*>(addr);
1249 *ptr++ = value1;
1250 *ptr = value2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001251 } else {
1252 PrintF("Unaligned write at 0x%08x\n", addr);
1253 UNIMPLEMENTED();
Kristian Monsen25f61362010-05-21 11:50:48 +01001254 }
Kristian Monsen25f61362010-05-21 11:50:48 +01001255}
1256
1257
Steve Blocka7e24c12009-10-30 11:49:00 +00001258// Returns the limit of the stack area to enable checking for stack overflows.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001259uintptr_t Simulator::StackLimit(uintptr_t c_limit) const {
1260 // The simulator uses a separate JS stack. If we have exhausted the C stack,
1261 // we also drop down the JS limit to reflect the exhaustion on the JS stack.
1262 if (GetCurrentStackPosition() < c_limit) {
1263 return reinterpret_cast<uintptr_t>(get_sp());
1264 }
1265
1266 // Otherwise the limit is the JS stack. Leave a safety margin of 1024 bytes
1267 // to prevent overrunning the stack when pushing values.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001268 return reinterpret_cast<uintptr_t>(stack_) + 1024;
Steve Blocka7e24c12009-10-30 11:49:00 +00001269}
1270
1271
1272// Unsupported instructions use Format to print an error and stop execution.
Steve Block1e0659c2011-05-24 12:43:12 +01001273void Simulator::Format(Instruction* instr, const char* format) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001274 PrintF("Simulator found unsupported instruction:\n 0x%08x: %s\n",
Ben Murdochf87a2032010-10-22 12:50:53 +01001275 reinterpret_cast<intptr_t>(instr), format);
Steve Blocka7e24c12009-10-30 11:49:00 +00001276 UNIMPLEMENTED();
1277}
1278
1279
1280// Checks if the current instruction should be executed based on its
1281// condition bits.
Steve Block1e0659c2011-05-24 12:43:12 +01001282bool Simulator::ConditionallyExecute(Instruction* instr) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001283 switch (instr->ConditionField()) {
Steve Block1e0659c2011-05-24 12:43:12 +01001284 case eq: return z_flag_;
1285 case ne: return !z_flag_;
1286 case cs: return c_flag_;
1287 case cc: return !c_flag_;
1288 case mi: return n_flag_;
1289 case pl: return !n_flag_;
1290 case vs: return v_flag_;
1291 case vc: return !v_flag_;
1292 case hi: return c_flag_ && !z_flag_;
1293 case ls: return !c_flag_ || z_flag_;
1294 case ge: return n_flag_ == v_flag_;
1295 case lt: return n_flag_ != v_flag_;
1296 case gt: return !z_flag_ && (n_flag_ == v_flag_);
1297 case le: return z_flag_ || (n_flag_ != v_flag_);
1298 case al: return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00001299 default: UNREACHABLE();
1300 }
1301 return false;
1302}
1303
1304
1305// Calculate and set the Negative and Zero flags.
1306void Simulator::SetNZFlags(int32_t val) {
1307 n_flag_ = (val < 0);
1308 z_flag_ = (val == 0);
1309}
1310
1311
1312// Set the Carry flag.
1313void Simulator::SetCFlag(bool val) {
1314 c_flag_ = val;
1315}
1316
1317
1318// Set the oVerflow flag.
1319void Simulator::SetVFlag(bool val) {
1320 v_flag_ = val;
1321}
1322
1323
1324// Calculate C flag value for additions.
Ben Murdoch257744e2011-11-30 15:57:28 +00001325bool Simulator::CarryFrom(int32_t left, int32_t right, int32_t carry) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001326 uint32_t uleft = static_cast<uint32_t>(left);
1327 uint32_t uright = static_cast<uint32_t>(right);
1328 uint32_t urest = 0xffffffffU - uleft;
1329
Ben Murdoch257744e2011-11-30 15:57:28 +00001330 return (uright > urest) ||
1331 (carry && (((uright + 1) > urest) || (uright > (urest - 1))));
Steve Blocka7e24c12009-10-30 11:49:00 +00001332}
1333
1334
1335// Calculate C flag value for subtractions.
Ben Murdochda12d292016-06-02 14:46:10 +01001336bool Simulator::BorrowFrom(int32_t left, int32_t right, int32_t carry) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001337 uint32_t uleft = static_cast<uint32_t>(left);
1338 uint32_t uright = static_cast<uint32_t>(right);
1339
Ben Murdochda12d292016-06-02 14:46:10 +01001340 return (uright > uleft) ||
1341 (!carry && (((uright + 1) > uleft) || (uright > (uleft - 1))));
Steve Blocka7e24c12009-10-30 11:49:00 +00001342}
1343
1344
1345// Calculate V flag value for additions and subtractions.
1346bool Simulator::OverflowFrom(int32_t alu_out,
1347 int32_t left, int32_t right, bool addition) {
1348 bool overflow;
1349 if (addition) {
1350 // operands have the same sign
1351 overflow = ((left >= 0 && right >= 0) || (left < 0 && right < 0))
1352 // and operands and result have different sign
1353 && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
1354 } else {
1355 // operands have different signs
1356 overflow = ((left < 0 && right >= 0) || (left >= 0 && right < 0))
1357 // and first operand and result have different signs
1358 && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
1359 }
1360 return overflow;
1361}
1362
1363
Steve Blockd0582a62009-12-15 09:54:21 +00001364// Support for VFP comparisons.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001365void Simulator::Compute_FPSCR_Flags(float val1, float val2) {
1366 if (std::isnan(val1) || std::isnan(val2)) {
1367 n_flag_FPSCR_ = false;
1368 z_flag_FPSCR_ = false;
1369 c_flag_FPSCR_ = true;
1370 v_flag_FPSCR_ = true;
1371 // All non-NaN cases.
1372 } else if (val1 == val2) {
1373 n_flag_FPSCR_ = false;
1374 z_flag_FPSCR_ = true;
1375 c_flag_FPSCR_ = true;
1376 v_flag_FPSCR_ = false;
1377 } else if (val1 < val2) {
1378 n_flag_FPSCR_ = true;
1379 z_flag_FPSCR_ = false;
1380 c_flag_FPSCR_ = false;
1381 v_flag_FPSCR_ = false;
1382 } else {
1383 // Case when (val1 > val2).
1384 n_flag_FPSCR_ = false;
1385 z_flag_FPSCR_ = false;
1386 c_flag_FPSCR_ = true;
1387 v_flag_FPSCR_ = false;
1388 }
1389}
1390
1391
Steve Blockd0582a62009-12-15 09:54:21 +00001392void Simulator::Compute_FPSCR_Flags(double val1, double val2) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001393 if (std::isnan(val1) || std::isnan(val2)) {
Leon Clarkee46be812010-01-19 14:06:41 +00001394 n_flag_FPSCR_ = false;
1395 z_flag_FPSCR_ = false;
1396 c_flag_FPSCR_ = true;
1397 v_flag_FPSCR_ = true;
Steve Blockd0582a62009-12-15 09:54:21 +00001398 // All non-NaN cases.
Leon Clarkee46be812010-01-19 14:06:41 +00001399 } else if (val1 == val2) {
Steve Blockd0582a62009-12-15 09:54:21 +00001400 n_flag_FPSCR_ = false;
1401 z_flag_FPSCR_ = true;
1402 c_flag_FPSCR_ = true;
1403 v_flag_FPSCR_ = false;
1404 } else if (val1 < val2) {
1405 n_flag_FPSCR_ = true;
1406 z_flag_FPSCR_ = false;
1407 c_flag_FPSCR_ = false;
1408 v_flag_FPSCR_ = false;
1409 } else {
1410 // Case when (val1 > val2).
1411 n_flag_FPSCR_ = false;
1412 z_flag_FPSCR_ = false;
1413 c_flag_FPSCR_ = true;
1414 v_flag_FPSCR_ = false;
1415 }
1416}
1417
1418
1419void Simulator::Copy_FPSCR_to_APSR() {
1420 n_flag_ = n_flag_FPSCR_;
1421 z_flag_ = z_flag_FPSCR_;
1422 c_flag_ = c_flag_FPSCR_;
1423 v_flag_ = v_flag_FPSCR_;
1424}
1425
1426
Steve Blocka7e24c12009-10-30 11:49:00 +00001427// Addressing Mode 1 - Data-processing operands:
1428// Get the value based on the shifter_operand with register.
Steve Block1e0659c2011-05-24 12:43:12 +01001429int32_t Simulator::GetShiftRm(Instruction* instr, bool* carry_out) {
1430 ShiftOp shift = instr->ShiftField();
1431 int shift_amount = instr->ShiftAmountValue();
1432 int32_t result = get_register(instr->RmValue());
Steve Blocka7e24c12009-10-30 11:49:00 +00001433 if (instr->Bit(4) == 0) {
1434 // by immediate
1435 if ((shift == ROR) && (shift_amount == 0)) {
1436 UNIMPLEMENTED();
1437 return result;
1438 } else if (((shift == LSR) || (shift == ASR)) && (shift_amount == 0)) {
1439 shift_amount = 32;
1440 }
1441 switch (shift) {
1442 case ASR: {
1443 if (shift_amount == 0) {
1444 if (result < 0) {
1445 result = 0xffffffff;
1446 *carry_out = true;
1447 } else {
1448 result = 0;
1449 *carry_out = false;
1450 }
1451 } else {
1452 result >>= (shift_amount - 1);
1453 *carry_out = (result & 1) == 1;
1454 result >>= 1;
1455 }
1456 break;
1457 }
1458
1459 case LSL: {
1460 if (shift_amount == 0) {
1461 *carry_out = c_flag_;
1462 } else {
1463 result <<= (shift_amount - 1);
1464 *carry_out = (result < 0);
1465 result <<= 1;
1466 }
1467 break;
1468 }
1469
1470 case LSR: {
1471 if (shift_amount == 0) {
1472 result = 0;
1473 *carry_out = c_flag_;
1474 } else {
1475 uint32_t uresult = static_cast<uint32_t>(result);
1476 uresult >>= (shift_amount - 1);
1477 *carry_out = (uresult & 1) == 1;
1478 uresult >>= 1;
1479 result = static_cast<int32_t>(uresult);
1480 }
1481 break;
1482 }
1483
1484 case ROR: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001485 if (shift_amount == 0) {
1486 *carry_out = c_flag_;
1487 } else {
1488 uint32_t left = static_cast<uint32_t>(result) >> shift_amount;
1489 uint32_t right = static_cast<uint32_t>(result) << (32 - shift_amount);
1490 result = right | left;
1491 *carry_out = (static_cast<uint32_t>(result) >> 31) != 0;
1492 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001493 break;
1494 }
1495
1496 default: {
1497 UNREACHABLE();
1498 break;
1499 }
1500 }
1501 } else {
1502 // by register
Steve Block1e0659c2011-05-24 12:43:12 +01001503 int rs = instr->RsValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00001504 shift_amount = get_register(rs) &0xff;
1505 switch (shift) {
1506 case ASR: {
1507 if (shift_amount == 0) {
1508 *carry_out = c_flag_;
1509 } else if (shift_amount < 32) {
1510 result >>= (shift_amount - 1);
1511 *carry_out = (result & 1) == 1;
1512 result >>= 1;
1513 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001514 DCHECK(shift_amount >= 32);
Steve Blocka7e24c12009-10-30 11:49:00 +00001515 if (result < 0) {
1516 *carry_out = true;
1517 result = 0xffffffff;
1518 } else {
1519 *carry_out = false;
1520 result = 0;
1521 }
1522 }
1523 break;
1524 }
1525
1526 case LSL: {
1527 if (shift_amount == 0) {
1528 *carry_out = c_flag_;
1529 } else if (shift_amount < 32) {
1530 result <<= (shift_amount - 1);
1531 *carry_out = (result < 0);
1532 result <<= 1;
1533 } else if (shift_amount == 32) {
1534 *carry_out = (result & 1) == 1;
1535 result = 0;
1536 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001537 DCHECK(shift_amount > 32);
Steve Blocka7e24c12009-10-30 11:49:00 +00001538 *carry_out = false;
1539 result = 0;
1540 }
1541 break;
1542 }
1543
1544 case LSR: {
1545 if (shift_amount == 0) {
1546 *carry_out = c_flag_;
1547 } else if (shift_amount < 32) {
1548 uint32_t uresult = static_cast<uint32_t>(result);
1549 uresult >>= (shift_amount - 1);
1550 *carry_out = (uresult & 1) == 1;
1551 uresult >>= 1;
1552 result = static_cast<int32_t>(uresult);
1553 } else if (shift_amount == 32) {
1554 *carry_out = (result < 0);
1555 result = 0;
1556 } else {
1557 *carry_out = false;
1558 result = 0;
1559 }
1560 break;
1561 }
1562
1563 case ROR: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001564 if (shift_amount == 0) {
1565 *carry_out = c_flag_;
1566 } else {
1567 uint32_t left = static_cast<uint32_t>(result) >> shift_amount;
1568 uint32_t right = static_cast<uint32_t>(result) << (32 - shift_amount);
1569 result = right | left;
1570 *carry_out = (static_cast<uint32_t>(result) >> 31) != 0;
1571 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001572 break;
1573 }
1574
1575 default: {
1576 UNREACHABLE();
1577 break;
1578 }
1579 }
1580 }
1581 return result;
1582}
1583
1584
1585// Addressing Mode 1 - Data-processing operands:
1586// Get the value based on the shifter_operand with immediate.
Steve Block1e0659c2011-05-24 12:43:12 +01001587int32_t Simulator::GetImm(Instruction* instr, bool* carry_out) {
1588 int rotate = instr->RotateValue() * 2;
1589 int immed8 = instr->Immed8Value();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001590 int imm = base::bits::RotateRight32(immed8, rotate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001591 *carry_out = (rotate == 0) ? c_flag_ : (imm < 0);
1592 return imm;
1593}
1594
1595
1596static int count_bits(int bit_vector) {
1597 int count = 0;
1598 while (bit_vector != 0) {
1599 if ((bit_vector & 1) != 0) {
1600 count++;
1601 }
1602 bit_vector >>= 1;
1603 }
1604 return count;
1605}
1606
1607
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001608int32_t Simulator::ProcessPU(Instruction* instr,
1609 int num_regs,
1610 int reg_size,
1611 intptr_t* start_address,
1612 intptr_t* end_address) {
Steve Block1e0659c2011-05-24 12:43:12 +01001613 int rn = instr->RnValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00001614 int32_t rn_val = get_register(rn);
Steve Blocka7e24c12009-10-30 11:49:00 +00001615 switch (instr->PUField()) {
Steve Block1e0659c2011-05-24 12:43:12 +01001616 case da_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00001617 UNIMPLEMENTED();
1618 break;
1619 }
Steve Block1e0659c2011-05-24 12:43:12 +01001620 case ia_x: {
Ben Murdoch8b112d22011-06-08 16:22:53 +01001621 *start_address = rn_val;
1622 *end_address = rn_val + (num_regs * reg_size) - reg_size;
1623 rn_val = rn_val + (num_regs * reg_size);
Steve Blocka7e24c12009-10-30 11:49:00 +00001624 break;
1625 }
Steve Block1e0659c2011-05-24 12:43:12 +01001626 case db_x: {
Ben Murdoch8b112d22011-06-08 16:22:53 +01001627 *start_address = rn_val - (num_regs * reg_size);
1628 *end_address = rn_val - reg_size;
1629 rn_val = *start_address;
Steve Blocka7e24c12009-10-30 11:49:00 +00001630 break;
1631 }
Steve Block1e0659c2011-05-24 12:43:12 +01001632 case ib_x: {
Ben Murdoch8b112d22011-06-08 16:22:53 +01001633 *start_address = rn_val + reg_size;
1634 *end_address = rn_val + (num_regs * reg_size);
1635 rn_val = *end_address;
Steve Blocka7e24c12009-10-30 11:49:00 +00001636 break;
1637 }
1638 default: {
1639 UNREACHABLE();
1640 break;
1641 }
1642 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001643 return rn_val;
Ben Murdoch8b112d22011-06-08 16:22:53 +01001644}
1645
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001646
Ben Murdoch8b112d22011-06-08 16:22:53 +01001647// Addressing Mode 4 - Load and Store Multiple
1648void Simulator::HandleRList(Instruction* instr, bool load) {
1649 int rlist = instr->RlistValue();
1650 int num_regs = count_bits(rlist);
1651
1652 intptr_t start_address = 0;
1653 intptr_t end_address = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001654 int32_t rn_val =
1655 ProcessPU(instr, num_regs, kPointerSize, &start_address, &end_address);
Ben Murdoch8b112d22011-06-08 16:22:53 +01001656
Steve Blocka7e24c12009-10-30 11:49:00 +00001657 intptr_t* address = reinterpret_cast<intptr_t*>(start_address);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001658 // Catch null pointers a little earlier.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001659 DCHECK(start_address > 8191 || start_address < 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001660 int reg = 0;
1661 while (rlist != 0) {
1662 if ((rlist & 1) != 0) {
1663 if (load) {
1664 set_register(reg, *address);
1665 } else {
1666 *address = get_register(reg);
1667 }
1668 address += 1;
1669 }
1670 reg++;
1671 rlist >>= 1;
1672 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001673 DCHECK(end_address == ((intptr_t)address) - 4);
1674 if (instr->HasW()) {
1675 set_register(instr->RnValue(), rn_val);
1676 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001677}
1678
1679
Ben Murdoch8b112d22011-06-08 16:22:53 +01001680// Addressing Mode 6 - Load and Store Multiple Coprocessor registers.
1681void Simulator::HandleVList(Instruction* instr) {
1682 VFPRegPrecision precision =
1683 (instr->SzValue() == 0) ? kSinglePrecision : kDoublePrecision;
1684 int operand_size = (precision == kSinglePrecision) ? 4 : 8;
1685
1686 bool load = (instr->VLValue() == 0x1);
1687
1688 int vd;
1689 int num_regs;
1690 vd = instr->VFPDRegValue(precision);
1691 if (precision == kSinglePrecision) {
1692 num_regs = instr->Immed8Value();
1693 } else {
1694 num_regs = instr->Immed8Value() / 2;
1695 }
1696
1697 intptr_t start_address = 0;
1698 intptr_t end_address = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001699 int32_t rn_val =
1700 ProcessPU(instr, num_regs, operand_size, &start_address, &end_address);
Ben Murdoch8b112d22011-06-08 16:22:53 +01001701
1702 intptr_t* address = reinterpret_cast<intptr_t*>(start_address);
1703 for (int reg = vd; reg < vd + num_regs; reg++) {
1704 if (precision == kSinglePrecision) {
1705 if (load) {
1706 set_s_register_from_sinteger(
1707 reg, ReadW(reinterpret_cast<int32_t>(address), instr));
1708 } else {
1709 WriteW(reinterpret_cast<int32_t>(address),
1710 get_sinteger_from_s_register(reg), instr);
1711 }
1712 address += 1;
1713 } else {
1714 if (load) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001715 int32_t data[] = {
1716 ReadW(reinterpret_cast<int32_t>(address), instr),
1717 ReadW(reinterpret_cast<int32_t>(address + 1), instr)
1718 };
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001719 set_d_register(reg, reinterpret_cast<uint32_t*>(data));
Ben Murdoch8b112d22011-06-08 16:22:53 +01001720 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001721 uint32_t data[2];
1722 get_d_register(reg, data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001723 WriteW(reinterpret_cast<int32_t>(address), data[0], instr);
1724 WriteW(reinterpret_cast<int32_t>(address + 1), data[1], instr);
Ben Murdoch8b112d22011-06-08 16:22:53 +01001725 }
1726 address += 2;
1727 }
1728 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001729 DCHECK(reinterpret_cast<intptr_t>(address) - operand_size == end_address);
1730 if (instr->HasW()) {
1731 set_register(instr->RnValue(), rn_val);
1732 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01001733}
1734
1735
Steve Blocka7e24c12009-10-30 11:49:00 +00001736// Calls into the V8 runtime are based on this very simple interface.
1737// Note: To be able to return two values from some calls the code in runtime.cc
1738// uses the ObjectPair which is essentially two 32-bit values stuffed into a
1739// 64-bit value. With the code below we assume that all runtime calls return
1740// 64 bits of result. If they don't, the r1 result register contains a bogus
1741// value, which is fine because it is caller-saved.
1742typedef int64_t (*SimulatorRuntimeCall)(int32_t arg0,
1743 int32_t arg1,
1744 int32_t arg2,
Ben Murdochb0fe1622011-05-05 13:52:32 +01001745 int32_t arg3,
Steve Block44f0eee2011-05-26 01:26:41 +01001746 int32_t arg4,
1747 int32_t arg5);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001748
Ben Murdoch097c5b22016-05-18 11:27:45 +01001749typedef ObjectTriple (*SimulatorRuntimeTripleCall)(int32_t arg0, int32_t arg1,
1750 int32_t arg2, int32_t arg3,
1751 int32_t arg4);
1752
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001753// These prototypes handle the four types of FP calls.
1754typedef int64_t (*SimulatorRuntimeCompareCall)(double darg0, double darg1);
1755typedef double (*SimulatorRuntimeFPFPCall)(double darg0, double darg1);
1756typedef double (*SimulatorRuntimeFPCall)(double darg0);
1757typedef double (*SimulatorRuntimeFPIntCall)(double darg0, int32_t arg0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001758
Steve Block1e0659c2011-05-24 12:43:12 +01001759// This signature supports direct call in to API function native callback
1760// (refer to InvocationCallback in v8.h).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001761typedef void (*SimulatorRuntimeDirectApiCall)(int32_t arg0);
1762typedef void (*SimulatorRuntimeProfilingApiCall)(int32_t arg0, void* arg1);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001763
1764// This signature supports direct call to accessor getter callback.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001765typedef void (*SimulatorRuntimeDirectGetterCall)(int32_t arg0, int32_t arg1);
1766typedef void (*SimulatorRuntimeProfilingGetterCall)(
1767 int32_t arg0, int32_t arg1, void* arg2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001768
1769// Software interrupt instructions are used by the simulator to call into the
1770// C-based V8 runtime.
Steve Block1e0659c2011-05-24 12:43:12 +01001771void Simulator::SoftwareInterrupt(Instruction* instr) {
1772 int svc = instr->SvcValue();
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001773 switch (svc) {
Steve Block1e0659c2011-05-24 12:43:12 +01001774 case kCallRtRedirected: {
Steve Block6ded16b2010-05-10 14:33:55 +01001775 // Check if stack is aligned. Error if not aligned is reported below to
1776 // include information on the function called.
1777 bool stack_aligned =
1778 (get_register(sp)
1779 & (::v8::internal::FLAG_sim_stack_alignment - 1)) == 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00001780 Redirection* redirection = Redirection::FromSwiInstruction(instr);
1781 int32_t arg0 = get_register(r0);
1782 int32_t arg1 = get_register(r1);
1783 int32_t arg2 = get_register(r2);
1784 int32_t arg3 = get_register(r3);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001785 int32_t* stack_pointer = reinterpret_cast<int32_t*>(get_register(sp));
Steve Block44f0eee2011-05-26 01:26:41 +01001786 int32_t arg4 = stack_pointer[0];
1787 int32_t arg5 = stack_pointer[1];
Ben Murdoch257744e2011-11-30 15:57:28 +00001788 bool fp_call =
1789 (redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) ||
1790 (redirection->type() == ExternalReference::BUILTIN_COMPARE_CALL) ||
1791 (redirection->type() == ExternalReference::BUILTIN_FP_CALL) ||
1792 (redirection->type() == ExternalReference::BUILTIN_FP_INT_CALL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001793 // This is dodgy but it works because the C entry stubs are never moved.
1794 // See comment in codegen-arm.cc and bug 1242173.
1795 int32_t saved_lr = get_register(lr);
Steve Block1e0659c2011-05-24 12:43:12 +01001796 intptr_t external =
1797 reinterpret_cast<intptr_t>(redirection->external_function());
Ben Murdoch257744e2011-11-30 15:57:28 +00001798 if (fp_call) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001799 double dval0, dval1; // one or two double parameters
1800 int32_t ival; // zero or one integer parameters
1801 int64_t iresult = 0; // integer return value
1802 double dresult = 0; // double return value
1803 GetFpArgs(&dval0, &dval1, &ival);
Steve Block6ded16b2010-05-10 14:33:55 +01001804 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001805 SimulatorRuntimeCall generic_target =
1806 reinterpret_cast<SimulatorRuntimeCall>(external);
Ben Murdoch257744e2011-11-30 15:57:28 +00001807 switch (redirection->type()) {
1808 case ExternalReference::BUILTIN_FP_FP_CALL:
1809 case ExternalReference::BUILTIN_COMPARE_CALL:
Ben Murdoch257744e2011-11-30 15:57:28 +00001810 PrintF("Call to host function at %p with args %f, %f",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001811 FUNCTION_ADDR(generic_target), dval0, dval1);
Ben Murdoch257744e2011-11-30 15:57:28 +00001812 break;
1813 case ExternalReference::BUILTIN_FP_CALL:
Ben Murdoch257744e2011-11-30 15:57:28 +00001814 PrintF("Call to host function at %p with arg %f",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001815 FUNCTION_ADDR(generic_target), dval0);
Ben Murdoch257744e2011-11-30 15:57:28 +00001816 break;
1817 case ExternalReference::BUILTIN_FP_INT_CALL:
Ben Murdoch257744e2011-11-30 15:57:28 +00001818 PrintF("Call to host function at %p with args %f, %d",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001819 FUNCTION_ADDR(generic_target), dval0, ival);
Ben Murdoch257744e2011-11-30 15:57:28 +00001820 break;
1821 default:
1822 UNREACHABLE();
1823 break;
1824 }
Steve Block6ded16b2010-05-10 14:33:55 +01001825 if (!stack_aligned) {
1826 PrintF(" with unaligned stack %08x\n", get_register(sp));
1827 }
1828 PrintF("\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00001829 }
Steve Block6ded16b2010-05-10 14:33:55 +01001830 CHECK(stack_aligned);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001831 switch (redirection->type()) {
1832 case ExternalReference::BUILTIN_COMPARE_CALL: {
1833 SimulatorRuntimeCompareCall target =
1834 reinterpret_cast<SimulatorRuntimeCompareCall>(external);
1835 iresult = target(dval0, dval1);
1836 set_register(r0, static_cast<int32_t>(iresult));
1837 set_register(r1, static_cast<int32_t>(iresult >> 32));
1838 break;
1839 }
1840 case ExternalReference::BUILTIN_FP_FP_CALL: {
1841 SimulatorRuntimeFPFPCall target =
1842 reinterpret_cast<SimulatorRuntimeFPFPCall>(external);
1843 dresult = target(dval0, dval1);
1844 SetFpResult(dresult);
1845 break;
1846 }
1847 case ExternalReference::BUILTIN_FP_CALL: {
Ben Murdoch257744e2011-11-30 15:57:28 +00001848 SimulatorRuntimeFPCall target =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001849 reinterpret_cast<SimulatorRuntimeFPCall>(external);
1850 dresult = target(dval0);
1851 SetFpResult(dresult);
1852 break;
1853 }
1854 case ExternalReference::BUILTIN_FP_INT_CALL: {
1855 SimulatorRuntimeFPIntCall target =
1856 reinterpret_cast<SimulatorRuntimeFPIntCall>(external);
1857 dresult = target(dval0, ival);
1858 SetFpResult(dresult);
1859 break;
1860 }
1861 default:
1862 UNREACHABLE();
1863 break;
1864 }
1865 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
1866 switch (redirection->type()) {
1867 case ExternalReference::BUILTIN_COMPARE_CALL:
1868 PrintF("Returned %08x\n", static_cast<int32_t>(iresult));
1869 break;
1870 case ExternalReference::BUILTIN_FP_FP_CALL:
1871 case ExternalReference::BUILTIN_FP_CALL:
1872 case ExternalReference::BUILTIN_FP_INT_CALL:
1873 PrintF("Returned %f\n", dresult);
1874 break;
1875 default:
1876 UNREACHABLE();
1877 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00001878 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001879 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001880 } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) {
Steve Block1e0659c2011-05-24 12:43:12 +01001881 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001882 PrintF("Call to host function at %p args %08x",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001883 reinterpret_cast<void*>(external), arg0);
Steve Block1e0659c2011-05-24 12:43:12 +01001884 if (!stack_aligned) {
1885 PrintF(" with unaligned stack %08x\n", get_register(sp));
1886 }
1887 PrintF("\n");
1888 }
1889 CHECK(stack_aligned);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001890 SimulatorRuntimeDirectApiCall target =
1891 reinterpret_cast<SimulatorRuntimeDirectApiCall>(external);
1892 target(arg0);
1893 } else if (
1894 redirection->type() == ExternalReference::PROFILING_API_CALL) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001895 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
1896 PrintF("Call to host function at %p args %08x %08x",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001897 reinterpret_cast<void*>(external), arg0, arg1);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001898 if (!stack_aligned) {
1899 PrintF(" with unaligned stack %08x\n", get_register(sp));
1900 }
1901 PrintF("\n");
1902 }
1903 CHECK(stack_aligned);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001904 SimulatorRuntimeProfilingApiCall target =
1905 reinterpret_cast<SimulatorRuntimeProfilingApiCall>(external);
1906 target(arg0, Redirection::ReverseRedirection(arg1));
1907 } else if (
1908 redirection->type() == ExternalReference::DIRECT_GETTER_CALL) {
1909 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
1910 PrintF("Call to host function at %p args %08x %08x",
1911 reinterpret_cast<void*>(external), arg0, arg1);
1912 if (!stack_aligned) {
1913 PrintF(" with unaligned stack %08x\n", get_register(sp));
1914 }
1915 PrintF("\n");
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001916 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001917 CHECK(stack_aligned);
1918 SimulatorRuntimeDirectGetterCall target =
1919 reinterpret_cast<SimulatorRuntimeDirectGetterCall>(external);
1920 target(arg0, arg1);
1921 } else if (
1922 redirection->type() == ExternalReference::PROFILING_GETTER_CALL) {
1923 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
1924 PrintF("Call to host function at %p args %08x %08x %08x",
1925 reinterpret_cast<void*>(external), arg0, arg1, arg2);
1926 if (!stack_aligned) {
1927 PrintF(" with unaligned stack %08x\n", get_register(sp));
1928 }
1929 PrintF("\n");
1930 }
1931 CHECK(stack_aligned);
1932 SimulatorRuntimeProfilingGetterCall target =
1933 reinterpret_cast<SimulatorRuntimeProfilingGetterCall>(
1934 external);
1935 target(arg0, arg1, Redirection::ReverseRedirection(arg2));
Ben Murdoch097c5b22016-05-18 11:27:45 +01001936 } else if (redirection->type() ==
1937 ExternalReference::BUILTIN_CALL_TRIPLE) {
1938 // builtin call returning ObjectTriple.
1939 SimulatorRuntimeTripleCall target =
1940 reinterpret_cast<SimulatorRuntimeTripleCall>(external);
1941 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
1942 PrintF(
1943 "Call to host triple returning runtime function %p "
1944 "args %08x, %08x, %08x, %08x, %08x",
1945 FUNCTION_ADDR(target), arg1, arg2, arg3, arg4, arg5);
1946 if (!stack_aligned) {
1947 PrintF(" with unaligned stack %08x\n", get_register(sp));
1948 }
1949 PrintF("\n");
1950 }
1951 CHECK(stack_aligned);
1952 // arg0 is a hidden argument pointing to the return location, so don't
1953 // pass it to the target function.
1954 ObjectTriple result = target(arg1, arg2, arg3, arg4, arg5);
1955 if (::v8::internal::FLAG_trace_sim) {
1956 PrintF("Returned { %p, %p, %p }\n", result.x, result.y, result.z);
1957 }
1958 // Return is passed back in address pointed to by hidden first argument.
1959 ObjectTriple* sim_result = reinterpret_cast<ObjectTriple*>(arg0);
1960 *sim_result = result;
1961 set_register(r0, arg0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001962 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01001963 // builtin call.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001964 DCHECK(redirection->type() == ExternalReference::BUILTIN_CALL ||
1965 redirection->type() == ExternalReference::BUILTIN_CALL_PAIR);
Steve Blocka7e24c12009-10-30 11:49:00 +00001966 SimulatorRuntimeCall target =
1967 reinterpret_cast<SimulatorRuntimeCall>(external);
Steve Block6ded16b2010-05-10 14:33:55 +01001968 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001969 PrintF(
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001970 "Call to host function at %p "
Steve Block44f0eee2011-05-26 01:26:41 +01001971 "args %08x, %08x, %08x, %08x, %08x, %08x",
Steve Blocka7e24c12009-10-30 11:49:00 +00001972 FUNCTION_ADDR(target),
1973 arg0,
1974 arg1,
1975 arg2,
Ben Murdochb0fe1622011-05-05 13:52:32 +01001976 arg3,
Steve Block44f0eee2011-05-26 01:26:41 +01001977 arg4,
1978 arg5);
Steve Block6ded16b2010-05-10 14:33:55 +01001979 if (!stack_aligned) {
1980 PrintF(" with unaligned stack %08x\n", get_register(sp));
1981 }
1982 PrintF("\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00001983 }
Steve Block6ded16b2010-05-10 14:33:55 +01001984 CHECK(stack_aligned);
Steve Block44f0eee2011-05-26 01:26:41 +01001985 int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5);
Steve Blocka7e24c12009-10-30 11:49:00 +00001986 int32_t lo_res = static_cast<int32_t>(result);
1987 int32_t hi_res = static_cast<int32_t>(result >> 32);
1988 if (::v8::internal::FLAG_trace_sim) {
1989 PrintF("Returned %08x\n", lo_res);
1990 }
1991 set_register(r0, lo_res);
1992 set_register(r1, hi_res);
1993 }
1994 set_register(lr, saved_lr);
1995 set_pc(get_register(lr));
1996 break;
1997 }
Steve Block1e0659c2011-05-24 12:43:12 +01001998 case kBreakpoint: {
Steve Block44f0eee2011-05-26 01:26:41 +01001999 ArmDebugger dbg(this);
Steve Blocka7e24c12009-10-30 11:49:00 +00002000 dbg.Debug();
2001 break;
2002 }
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002003 // stop uses all codes greater than 1 << 23.
Steve Blocka7e24c12009-10-30 11:49:00 +00002004 default: {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002005 if (svc >= (1 << 23)) {
2006 uint32_t code = svc & kStopCodeMask;
2007 if (isWatchedStop(code)) {
2008 IncreaseStopCounter(code);
2009 }
2010 // Stop if it is enabled, otherwise go on jumping over the stop
2011 // and the message address.
2012 if (isEnabledStop(code)) {
Steve Block44f0eee2011-05-26 01:26:41 +01002013 ArmDebugger dbg(this);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002014 dbg.Stop(instr);
2015 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01002016 set_pc(get_pc() + 2 * Instruction::kInstrSize);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002017 }
2018 } else {
2019 // This is not a valid svc code.
2020 UNREACHABLE();
2021 break;
2022 }
2023 }
2024 }
2025}
2026
2027
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002028float Simulator::canonicalizeNaN(float value) {
2029 // Default NaN value, see "NaN handling" in "IEEE 754 standard implementation
2030 // choices" of the ARM Reference Manual.
2031 const uint32_t kDefaultNaN = 0x7FC00000u;
2032 if (FPSCR_default_NaN_mode_ && std::isnan(value)) {
2033 value = bit_cast<float>(kDefaultNaN);
2034 }
2035 return value;
2036}
2037
2038
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002039double Simulator::canonicalizeNaN(double value) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002040 // Default NaN value, see "NaN handling" in "IEEE 754 standard implementation
2041 // choices" of the ARM Reference Manual.
2042 const uint64_t kDefaultNaN = V8_UINT64_C(0x7FF8000000000000);
2043 if (FPSCR_default_NaN_mode_ && std::isnan(value)) {
2044 value = bit_cast<double>(kDefaultNaN);
2045 }
2046 return value;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002047}
2048
2049
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002050// Stop helper functions.
Steve Block1e0659c2011-05-24 12:43:12 +01002051bool Simulator::isStopInstruction(Instruction* instr) {
2052 return (instr->Bits(27, 24) == 0xF) && (instr->SvcValue() >= kStopCode);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002053}
2054
2055
2056bool Simulator::isWatchedStop(uint32_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002057 DCHECK(code <= kMaxStopCode);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002058 return code < kNumOfWatchedStops;
2059}
2060
2061
2062bool Simulator::isEnabledStop(uint32_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002063 DCHECK(code <= kMaxStopCode);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002064 // Unwatched stops are always enabled.
2065 return !isWatchedStop(code) ||
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002066 !(watched_stops_[code].count & kStopDisabledBit);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002067}
2068
2069
2070void Simulator::EnableStop(uint32_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002071 DCHECK(isWatchedStop(code));
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002072 if (!isEnabledStop(code)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002073 watched_stops_[code].count &= ~kStopDisabledBit;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002074 }
2075}
2076
2077
2078void Simulator::DisableStop(uint32_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002079 DCHECK(isWatchedStop(code));
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002080 if (isEnabledStop(code)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002081 watched_stops_[code].count |= kStopDisabledBit;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002082 }
2083}
2084
2085
2086void Simulator::IncreaseStopCounter(uint32_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002087 DCHECK(code <= kMaxStopCode);
2088 DCHECK(isWatchedStop(code));
2089 if ((watched_stops_[code].count & ~(1 << 31)) == 0x7fffffff) {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002090 PrintF("Stop counter for code %i has overflowed.\n"
2091 "Enabling this code and reseting the counter to 0.\n", code);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002092 watched_stops_[code].count = 0;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002093 EnableStop(code);
2094 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002095 watched_stops_[code].count++;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002096 }
2097}
2098
2099
2100// Print a stop status.
2101void Simulator::PrintStopInfo(uint32_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002102 DCHECK(code <= kMaxStopCode);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002103 if (!isWatchedStop(code)) {
2104 PrintF("Stop not watched.");
2105 } else {
2106 const char* state = isEnabledStop(code) ? "Enabled" : "Disabled";
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002107 int32_t count = watched_stops_[code].count & ~kStopDisabledBit;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002108 // Don't print the state of unused breakpoints.
2109 if (count != 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002110 if (watched_stops_[code].desc) {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002111 PrintF("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002112 code, code, state, count, watched_stops_[code].desc);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002113 } else {
2114 PrintF("stop %i - 0x%x: \t%s, \tcounter = %i\n",
2115 code, code, state, count);
2116 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002117 }
2118 }
2119}
2120
2121
2122// Handle execution based on instruction types.
2123
2124// Instruction types 0 and 1 are both rolled into one function because they
2125// only differ in the handling of the shifter_operand.
Steve Block1e0659c2011-05-24 12:43:12 +01002126void Simulator::DecodeType01(Instruction* instr) {
2127 int type = instr->TypeValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00002128 if ((type == 0) && instr->IsSpecialType0()) {
2129 // multiply instruction or extra loads and stores
2130 if (instr->Bits(7, 4) == 9) {
2131 if (instr->Bit(24) == 0) {
2132 // Raw field decoding here. Multiply instructions have their Rd in
2133 // funny places.
Steve Block1e0659c2011-05-24 12:43:12 +01002134 int rn = instr->RnValue();
2135 int rm = instr->RmValue();
2136 int rs = instr->RsValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00002137 int32_t rs_val = get_register(rs);
2138 int32_t rm_val = get_register(rm);
2139 if (instr->Bit(23) == 0) {
2140 if (instr->Bit(21) == 0) {
2141 // The MUL instruction description (A 4.1.33) refers to Rd as being
2142 // the destination for the operation, but it confusingly uses the
2143 // Rn field to encode it.
2144 // Format(instr, "mul'cond's 'rn, 'rm, 'rs");
2145 int rd = rn; // Remap the rn field to the Rd register.
2146 int32_t alu_out = rm_val * rs_val;
2147 set_register(rd, alu_out);
2148 if (instr->HasS()) {
2149 SetNZFlags(alu_out);
2150 }
2151 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002152 int rd = instr->RdValue();
2153 int32_t acc_value = get_register(rd);
2154 if (instr->Bit(22) == 0) {
2155 // The MLA instruction description (A 4.1.28) refers to the order
2156 // of registers as "Rd, Rm, Rs, Rn". But confusingly it uses the
2157 // Rn field to encode the Rd register and the Rd field to encode
2158 // the Rn register.
2159 // Format(instr, "mla'cond's 'rn, 'rm, 'rs, 'rd");
2160 int32_t mul_out = rm_val * rs_val;
2161 int32_t result = acc_value + mul_out;
2162 set_register(rn, result);
2163 } else {
2164 // Format(instr, "mls'cond's 'rn, 'rm, 'rs, 'rd");
2165 int32_t mul_out = rm_val * rs_val;
2166 int32_t result = acc_value - mul_out;
2167 set_register(rn, result);
2168 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002169 }
2170 } else {
2171 // The signed/long multiply instructions use the terms RdHi and RdLo
2172 // when referring to the target registers. They are mapped to the Rn
2173 // and Rd fields as follows:
2174 // RdLo == Rd
2175 // RdHi == Rn (This is confusingly stored in variable rd here
2176 // because the mul instruction from above uses the
2177 // Rn field to encode the Rd register. Good luck figuring
2178 // this out without reading the ARM instruction manual
2179 // at a very detailed level.)
2180 // Format(instr, "'um'al'cond's 'rd, 'rn, 'rs, 'rm");
2181 int rd_hi = rn; // Remap the rn field to the RdHi register.
Steve Block1e0659c2011-05-24 12:43:12 +01002182 int rd_lo = instr->RdValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00002183 int32_t hi_res = 0;
2184 int32_t lo_res = 0;
2185 if (instr->Bit(22) == 1) {
2186 int64_t left_op = static_cast<int32_t>(rm_val);
2187 int64_t right_op = static_cast<int32_t>(rs_val);
2188 uint64_t result = left_op * right_op;
2189 hi_res = static_cast<int32_t>(result >> 32);
2190 lo_res = static_cast<int32_t>(result & 0xffffffff);
2191 } else {
2192 // unsigned multiply
2193 uint64_t left_op = static_cast<uint32_t>(rm_val);
2194 uint64_t right_op = static_cast<uint32_t>(rs_val);
2195 uint64_t result = left_op * right_op;
2196 hi_res = static_cast<int32_t>(result >> 32);
2197 lo_res = static_cast<int32_t>(result & 0xffffffff);
2198 }
2199 set_register(rd_lo, lo_res);
2200 set_register(rd_hi, hi_res);
2201 if (instr->HasS()) {
2202 UNIMPLEMENTED();
2203 }
2204 }
2205 } else {
Steve Blockd0582a62009-12-15 09:54:21 +00002206 UNIMPLEMENTED(); // Not used by V8.
Steve Blocka7e24c12009-10-30 11:49:00 +00002207 }
2208 } else {
2209 // extra load/store instructions
Steve Block1e0659c2011-05-24 12:43:12 +01002210 int rd = instr->RdValue();
2211 int rn = instr->RnValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00002212 int32_t rn_val = get_register(rn);
2213 int32_t addr = 0;
2214 if (instr->Bit(22) == 0) {
Steve Block1e0659c2011-05-24 12:43:12 +01002215 int rm = instr->RmValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00002216 int32_t rm_val = get_register(rm);
2217 switch (instr->PUField()) {
Steve Block1e0659c2011-05-24 12:43:12 +01002218 case da_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002219 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], -'rm");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002220 DCHECK(!instr->HasW());
Steve Blocka7e24c12009-10-30 11:49:00 +00002221 addr = rn_val;
2222 rn_val -= rm_val;
2223 set_register(rn, rn_val);
2224 break;
2225 }
Steve Block1e0659c2011-05-24 12:43:12 +01002226 case ia_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002227 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], +'rm");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002228 DCHECK(!instr->HasW());
Steve Blocka7e24c12009-10-30 11:49:00 +00002229 addr = rn_val;
2230 rn_val += rm_val;
2231 set_register(rn, rn_val);
2232 break;
2233 }
Steve Block1e0659c2011-05-24 12:43:12 +01002234 case db_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002235 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, -'rm]'w");
2236 rn_val -= rm_val;
2237 addr = rn_val;
2238 if (instr->HasW()) {
2239 set_register(rn, rn_val);
2240 }
2241 break;
2242 }
Steve Block1e0659c2011-05-24 12:43:12 +01002243 case ib_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002244 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, +'rm]'w");
2245 rn_val += rm_val;
2246 addr = rn_val;
2247 if (instr->HasW()) {
2248 set_register(rn, rn_val);
2249 }
2250 break;
2251 }
2252 default: {
2253 // The PU field is a 2-bit field.
2254 UNREACHABLE();
2255 break;
2256 }
2257 }
2258 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01002259 int32_t imm_val = (instr->ImmedHValue() << 4) | instr->ImmedLValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00002260 switch (instr->PUField()) {
Steve Block1e0659c2011-05-24 12:43:12 +01002261 case da_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002262 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], #-'off8");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002263 DCHECK(!instr->HasW());
Steve Blocka7e24c12009-10-30 11:49:00 +00002264 addr = rn_val;
2265 rn_val -= imm_val;
2266 set_register(rn, rn_val);
2267 break;
2268 }
Steve Block1e0659c2011-05-24 12:43:12 +01002269 case ia_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002270 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], #+'off8");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002271 DCHECK(!instr->HasW());
Steve Blocka7e24c12009-10-30 11:49:00 +00002272 addr = rn_val;
2273 rn_val += imm_val;
2274 set_register(rn, rn_val);
2275 break;
2276 }
Steve Block1e0659c2011-05-24 12:43:12 +01002277 case db_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002278 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, #-'off8]'w");
2279 rn_val -= imm_val;
2280 addr = rn_val;
2281 if (instr->HasW()) {
2282 set_register(rn, rn_val);
2283 }
2284 break;
2285 }
Steve Block1e0659c2011-05-24 12:43:12 +01002286 case ib_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002287 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, #+'off8]'w");
2288 rn_val += imm_val;
2289 addr = rn_val;
2290 if (instr->HasW()) {
2291 set_register(rn, rn_val);
2292 }
2293 break;
2294 }
2295 default: {
2296 // The PU field is a 2-bit field.
2297 UNREACHABLE();
2298 break;
2299 }
2300 }
2301 }
Kristian Monsen25f61362010-05-21 11:50:48 +01002302 if (((instr->Bits(7, 4) & 0xd) == 0xd) && (instr->Bit(20) == 0)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002303 DCHECK((rd % 2) == 0);
Kristian Monsen25f61362010-05-21 11:50:48 +01002304 if (instr->HasH()) {
2305 // The strd instruction.
2306 int32_t value1 = get_register(rd);
2307 int32_t value2 = get_register(rd+1);
2308 WriteDW(addr, value1, value2);
2309 } else {
2310 // The ldrd instruction.
2311 int* rn_data = ReadDW(addr);
2312 set_dw_register(rd, rn_data);
2313 }
2314 } else if (instr->HasH()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002315 if (instr->HasSign()) {
2316 if (instr->HasL()) {
2317 int16_t val = ReadH(addr, instr);
2318 set_register(rd, val);
2319 } else {
2320 int16_t val = get_register(rd);
2321 WriteH(addr, val, instr);
2322 }
2323 } else {
2324 if (instr->HasL()) {
2325 uint16_t val = ReadHU(addr, instr);
2326 set_register(rd, val);
2327 } else {
2328 uint16_t val = get_register(rd);
2329 WriteH(addr, val, instr);
2330 }
2331 }
2332 } else {
2333 // signed byte loads
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002334 DCHECK(instr->HasSign());
2335 DCHECK(instr->HasL());
Steve Blocka7e24c12009-10-30 11:49:00 +00002336 int8_t val = ReadB(addr);
2337 set_register(rd, val);
2338 }
2339 return;
2340 }
Steve Block6ded16b2010-05-10 14:33:55 +01002341 } else if ((type == 0) && instr->IsMiscType0()) {
Ben Murdochda12d292016-06-02 14:46:10 +01002342 if ((instr->Bits(27, 23) == 2) && (instr->Bits(21, 20) == 2) &&
2343 (instr->Bits(15, 4) == 0xf00)) {
2344 // MSR
2345 int rm = instr->RmValue();
2346 DCHECK_NE(pc, rm); // UNPREDICTABLE
2347 SRegisterFieldMask sreg_and_mask =
2348 instr->BitField(22, 22) | instr->BitField(19, 16);
2349 SetSpecialRegister(sreg_and_mask, get_register(rm));
2350 } else if ((instr->Bits(27, 23) == 2) && (instr->Bits(21, 20) == 0) &&
2351 (instr->Bits(11, 0) == 0)) {
2352 // MRS
2353 int rd = instr->RdValue();
2354 DCHECK_NE(pc, rd); // UNPREDICTABLE
2355 SRegister sreg = static_cast<SRegister>(instr->BitField(22, 22));
2356 set_register(rd, GetFromSpecialRegister(sreg));
2357 } else if (instr->Bits(22, 21) == 1) {
Steve Block1e0659c2011-05-24 12:43:12 +01002358 int rm = instr->RmValue();
2359 switch (instr->BitField(7, 4)) {
Steve Block6ded16b2010-05-10 14:33:55 +01002360 case BX:
2361 set_pc(get_register(rm));
2362 break;
2363 case BLX: {
2364 uint32_t old_pc = get_pc();
2365 set_pc(get_register(rm));
Steve Block1e0659c2011-05-24 12:43:12 +01002366 set_register(lr, old_pc + Instruction::kInstrSize);
Steve Block6ded16b2010-05-10 14:33:55 +01002367 break;
2368 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01002369 case BKPT: {
Steve Block44f0eee2011-05-26 01:26:41 +01002370 ArmDebugger dbg(this);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002371 PrintF("Simulator hit BKPT.\n");
2372 dbg.Debug();
Steve Block6ded16b2010-05-10 14:33:55 +01002373 break;
Ben Murdochb0fe1622011-05-05 13:52:32 +01002374 }
Steve Block6ded16b2010-05-10 14:33:55 +01002375 default:
2376 UNIMPLEMENTED();
2377 }
2378 } else if (instr->Bits(22, 21) == 3) {
Steve Block1e0659c2011-05-24 12:43:12 +01002379 int rm = instr->RmValue();
2380 int rd = instr->RdValue();
2381 switch (instr->BitField(7, 4)) {
Steve Block6ded16b2010-05-10 14:33:55 +01002382 case CLZ: {
2383 uint32_t bits = get_register(rm);
2384 int leading_zeros = 0;
2385 if (bits == 0) {
2386 leading_zeros = 32;
2387 } else {
2388 while ((bits & 0x80000000u) == 0) {
2389 bits <<= 1;
2390 leading_zeros++;
2391 }
2392 }
2393 set_register(rd, leading_zeros);
2394 break;
2395 }
2396 default:
2397 UNIMPLEMENTED();
2398 }
2399 } else {
2400 PrintF("%08x\n", instr->InstructionBits());
2401 UNIMPLEMENTED();
2402 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002403 } else if ((type == 1) && instr->IsNopType1()) {
2404 // NOP.
Steve Blocka7e24c12009-10-30 11:49:00 +00002405 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01002406 int rd = instr->RdValue();
2407 int rn = instr->RnValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00002408 int32_t rn_val = get_register(rn);
2409 int32_t shifter_operand = 0;
2410 bool shifter_carry_out = 0;
2411 if (type == 0) {
2412 shifter_operand = GetShiftRm(instr, &shifter_carry_out);
2413 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002414 DCHECK(instr->TypeValue() == 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00002415 shifter_operand = GetImm(instr, &shifter_carry_out);
2416 }
2417 int32_t alu_out;
2418
2419 switch (instr->OpcodeField()) {
2420 case AND: {
2421 // Format(instr, "and'cond's 'rd, 'rn, 'shift_rm");
2422 // Format(instr, "and'cond's 'rd, 'rn, 'imm");
2423 alu_out = rn_val & shifter_operand;
2424 set_register(rd, alu_out);
2425 if (instr->HasS()) {
2426 SetNZFlags(alu_out);
2427 SetCFlag(shifter_carry_out);
2428 }
2429 break;
2430 }
2431
2432 case EOR: {
2433 // Format(instr, "eor'cond's 'rd, 'rn, 'shift_rm");
2434 // Format(instr, "eor'cond's 'rd, 'rn, 'imm");
2435 alu_out = rn_val ^ shifter_operand;
2436 set_register(rd, alu_out);
2437 if (instr->HasS()) {
2438 SetNZFlags(alu_out);
2439 SetCFlag(shifter_carry_out);
2440 }
2441 break;
2442 }
2443
2444 case SUB: {
2445 // Format(instr, "sub'cond's 'rd, 'rn, 'shift_rm");
2446 // Format(instr, "sub'cond's 'rd, 'rn, 'imm");
2447 alu_out = rn_val - shifter_operand;
2448 set_register(rd, alu_out);
2449 if (instr->HasS()) {
2450 SetNZFlags(alu_out);
2451 SetCFlag(!BorrowFrom(rn_val, shifter_operand));
2452 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, false));
2453 }
2454 break;
2455 }
2456
2457 case RSB: {
2458 // Format(instr, "rsb'cond's 'rd, 'rn, 'shift_rm");
2459 // Format(instr, "rsb'cond's 'rd, 'rn, 'imm");
2460 alu_out = shifter_operand - rn_val;
2461 set_register(rd, alu_out);
2462 if (instr->HasS()) {
2463 SetNZFlags(alu_out);
2464 SetCFlag(!BorrowFrom(shifter_operand, rn_val));
2465 SetVFlag(OverflowFrom(alu_out, shifter_operand, rn_val, false));
2466 }
2467 break;
2468 }
2469
2470 case ADD: {
2471 // Format(instr, "add'cond's 'rd, 'rn, 'shift_rm");
2472 // Format(instr, "add'cond's 'rd, 'rn, 'imm");
2473 alu_out = rn_val + shifter_operand;
2474 set_register(rd, alu_out);
2475 if (instr->HasS()) {
2476 SetNZFlags(alu_out);
2477 SetCFlag(CarryFrom(rn_val, shifter_operand));
2478 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, true));
2479 }
2480 break;
2481 }
2482
2483 case ADC: {
Ben Murdoch257744e2011-11-30 15:57:28 +00002484 // Format(instr, "adc'cond's 'rd, 'rn, 'shift_rm");
2485 // Format(instr, "adc'cond's 'rd, 'rn, 'imm");
2486 alu_out = rn_val + shifter_operand + GetCarry();
2487 set_register(rd, alu_out);
2488 if (instr->HasS()) {
2489 SetNZFlags(alu_out);
2490 SetCFlag(CarryFrom(rn_val, shifter_operand, GetCarry()));
2491 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, true));
2492 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002493 break;
2494 }
2495
2496 case SBC: {
Ben Murdochda12d292016-06-02 14:46:10 +01002497 // Format(instr, "sbc'cond's 'rd, 'rn, 'shift_rm");
2498 // Format(instr, "sbc'cond's 'rd, 'rn, 'imm");
2499 alu_out = (rn_val - shifter_operand) - (GetCarry() ? 0 : 1);
2500 set_register(rd, alu_out);
2501 if (instr->HasS()) {
2502 SetNZFlags(alu_out);
2503 SetCFlag(!BorrowFrom(rn_val, shifter_operand, GetCarry()));
2504 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, false));
2505 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002506 break;
2507 }
2508
2509 case RSC: {
2510 Format(instr, "rsc'cond's 'rd, 'rn, 'shift_rm");
2511 Format(instr, "rsc'cond's 'rd, 'rn, 'imm");
2512 break;
2513 }
2514
2515 case TST: {
2516 if (instr->HasS()) {
2517 // Format(instr, "tst'cond 'rn, 'shift_rm");
2518 // Format(instr, "tst'cond 'rn, 'imm");
2519 alu_out = rn_val & shifter_operand;
2520 SetNZFlags(alu_out);
2521 SetCFlag(shifter_carry_out);
2522 } else {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002523 // Format(instr, "movw'cond 'rd, 'imm").
Steve Block1e0659c2011-05-24 12:43:12 +01002524 alu_out = instr->ImmedMovwMovtValue();
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002525 set_register(rd, alu_out);
Steve Blocka7e24c12009-10-30 11:49:00 +00002526 }
2527 break;
2528 }
2529
2530 case TEQ: {
2531 if (instr->HasS()) {
2532 // Format(instr, "teq'cond 'rn, 'shift_rm");
2533 // Format(instr, "teq'cond 'rn, 'imm");
2534 alu_out = rn_val ^ shifter_operand;
2535 SetNZFlags(alu_out);
2536 SetCFlag(shifter_carry_out);
2537 } else {
Steve Block6ded16b2010-05-10 14:33:55 +01002538 // Other instructions matching this pattern are handled in the
2539 // miscellaneous instructions part above.
2540 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +00002541 }
2542 break;
2543 }
2544
2545 case CMP: {
2546 if (instr->HasS()) {
2547 // Format(instr, "cmp'cond 'rn, 'shift_rm");
2548 // Format(instr, "cmp'cond 'rn, 'imm");
2549 alu_out = rn_val - shifter_operand;
2550 SetNZFlags(alu_out);
2551 SetCFlag(!BorrowFrom(rn_val, shifter_operand));
2552 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, false));
2553 } else {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002554 // Format(instr, "movt'cond 'rd, 'imm").
2555 alu_out = (get_register(rd) & 0xffff) |
Steve Block1e0659c2011-05-24 12:43:12 +01002556 (instr->ImmedMovwMovtValue() << 16);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002557 set_register(rd, alu_out);
Steve Blocka7e24c12009-10-30 11:49:00 +00002558 }
2559 break;
2560 }
2561
2562 case CMN: {
2563 if (instr->HasS()) {
2564 // Format(instr, "cmn'cond 'rn, 'shift_rm");
2565 // Format(instr, "cmn'cond 'rn, 'imm");
2566 alu_out = rn_val + shifter_operand;
2567 SetNZFlags(alu_out);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002568 SetCFlag(CarryFrom(rn_val, shifter_operand));
Steve Blocka7e24c12009-10-30 11:49:00 +00002569 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, true));
2570 } else {
Steve Block6ded16b2010-05-10 14:33:55 +01002571 // Other instructions matching this pattern are handled in the
2572 // miscellaneous instructions part above.
2573 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +00002574 }
2575 break;
2576 }
2577
2578 case ORR: {
2579 // Format(instr, "orr'cond's 'rd, 'rn, 'shift_rm");
2580 // Format(instr, "orr'cond's 'rd, 'rn, 'imm");
2581 alu_out = rn_val | shifter_operand;
2582 set_register(rd, alu_out);
2583 if (instr->HasS()) {
2584 SetNZFlags(alu_out);
2585 SetCFlag(shifter_carry_out);
2586 }
2587 break;
2588 }
2589
2590 case MOV: {
2591 // Format(instr, "mov'cond's 'rd, 'shift_rm");
2592 // Format(instr, "mov'cond's 'rd, 'imm");
2593 alu_out = shifter_operand;
2594 set_register(rd, alu_out);
2595 if (instr->HasS()) {
2596 SetNZFlags(alu_out);
2597 SetCFlag(shifter_carry_out);
2598 }
2599 break;
2600 }
2601
2602 case BIC: {
2603 // Format(instr, "bic'cond's 'rd, 'rn, 'shift_rm");
2604 // Format(instr, "bic'cond's 'rd, 'rn, 'imm");
2605 alu_out = rn_val & ~shifter_operand;
2606 set_register(rd, alu_out);
2607 if (instr->HasS()) {
2608 SetNZFlags(alu_out);
2609 SetCFlag(shifter_carry_out);
2610 }
2611 break;
2612 }
2613
2614 case MVN: {
2615 // Format(instr, "mvn'cond's 'rd, 'shift_rm");
2616 // Format(instr, "mvn'cond's 'rd, 'imm");
2617 alu_out = ~shifter_operand;
2618 set_register(rd, alu_out);
2619 if (instr->HasS()) {
2620 SetNZFlags(alu_out);
2621 SetCFlag(shifter_carry_out);
2622 }
2623 break;
2624 }
2625
2626 default: {
2627 UNREACHABLE();
2628 break;
2629 }
2630 }
2631 }
2632}
2633
2634
Steve Block1e0659c2011-05-24 12:43:12 +01002635void Simulator::DecodeType2(Instruction* instr) {
2636 int rd = instr->RdValue();
2637 int rn = instr->RnValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00002638 int32_t rn_val = get_register(rn);
Steve Block1e0659c2011-05-24 12:43:12 +01002639 int32_t im_val = instr->Offset12Value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002640 int32_t addr = 0;
2641 switch (instr->PUField()) {
Steve Block1e0659c2011-05-24 12:43:12 +01002642 case da_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002643 // Format(instr, "'memop'cond'b 'rd, ['rn], #-'off12");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002644 DCHECK(!instr->HasW());
Steve Blocka7e24c12009-10-30 11:49:00 +00002645 addr = rn_val;
2646 rn_val -= im_val;
2647 set_register(rn, rn_val);
2648 break;
2649 }
Steve Block1e0659c2011-05-24 12:43:12 +01002650 case ia_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002651 // Format(instr, "'memop'cond'b 'rd, ['rn], #+'off12");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002652 DCHECK(!instr->HasW());
Steve Blocka7e24c12009-10-30 11:49:00 +00002653 addr = rn_val;
2654 rn_val += im_val;
2655 set_register(rn, rn_val);
2656 break;
2657 }
Steve Block1e0659c2011-05-24 12:43:12 +01002658 case db_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002659 // Format(instr, "'memop'cond'b 'rd, ['rn, #-'off12]'w");
2660 rn_val -= im_val;
2661 addr = rn_val;
2662 if (instr->HasW()) {
2663 set_register(rn, rn_val);
2664 }
2665 break;
2666 }
Steve Block1e0659c2011-05-24 12:43:12 +01002667 case ib_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002668 // Format(instr, "'memop'cond'b 'rd, ['rn, #+'off12]'w");
2669 rn_val += im_val;
2670 addr = rn_val;
2671 if (instr->HasW()) {
2672 set_register(rn, rn_val);
2673 }
2674 break;
2675 }
2676 default: {
2677 UNREACHABLE();
2678 break;
2679 }
2680 }
2681 if (instr->HasB()) {
2682 if (instr->HasL()) {
2683 byte val = ReadBU(addr);
2684 set_register(rd, val);
2685 } else {
2686 byte val = get_register(rd);
2687 WriteB(addr, val);
2688 }
2689 } else {
2690 if (instr->HasL()) {
2691 set_register(rd, ReadW(addr, instr));
2692 } else {
2693 WriteW(addr, get_register(rd), instr);
2694 }
2695 }
2696}
2697
2698
Steve Block1e0659c2011-05-24 12:43:12 +01002699void Simulator::DecodeType3(Instruction* instr) {
2700 int rd = instr->RdValue();
2701 int rn = instr->RnValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00002702 int32_t rn_val = get_register(rn);
2703 bool shifter_carry_out = 0;
2704 int32_t shifter_operand = GetShiftRm(instr, &shifter_carry_out);
2705 int32_t addr = 0;
2706 switch (instr->PUField()) {
Steve Block1e0659c2011-05-24 12:43:12 +01002707 case da_x: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002708 DCHECK(!instr->HasW());
Steve Blocka7e24c12009-10-30 11:49:00 +00002709 Format(instr, "'memop'cond'b 'rd, ['rn], -'shift_rm");
Kristian Monsen50ef84f2010-07-29 15:18:00 +01002710 UNIMPLEMENTED();
Steve Blocka7e24c12009-10-30 11:49:00 +00002711 break;
2712 }
Steve Block1e0659c2011-05-24 12:43:12 +01002713 case ia_x: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002714 if (instr->Bit(4) == 0) {
2715 // Memop.
2716 } else {
2717 if (instr->Bit(5) == 0) {
2718 switch (instr->Bits(22, 21)) {
2719 case 0:
2720 if (instr->Bit(20) == 0) {
2721 if (instr->Bit(6) == 0) {
2722 // Pkhbt.
2723 uint32_t rn_val = get_register(rn);
2724 uint32_t rm_val = get_register(instr->RmValue());
2725 int32_t shift = instr->Bits(11, 7);
2726 rm_val <<= shift;
2727 set_register(rd, (rn_val & 0xFFFF) | (rm_val & 0xFFFF0000U));
2728 } else {
2729 // Pkhtb.
2730 uint32_t rn_val = get_register(rn);
2731 int32_t rm_val = get_register(instr->RmValue());
2732 int32_t shift = instr->Bits(11, 7);
2733 if (shift == 0) {
2734 shift = 32;
2735 }
2736 rm_val >>= shift;
2737 set_register(rd, (rn_val & 0xFFFF0000U) | (rm_val & 0xFFFF));
2738 }
2739 } else {
2740 UNIMPLEMENTED();
2741 }
2742 break;
2743 case 1:
2744 UNIMPLEMENTED();
2745 break;
2746 case 2:
2747 UNIMPLEMENTED();
2748 break;
2749 case 3: {
2750 // Usat.
2751 int32_t sat_pos = instr->Bits(20, 16);
2752 int32_t sat_val = (1 << sat_pos) - 1;
2753 int32_t shift = instr->Bits(11, 7);
2754 int32_t shift_type = instr->Bit(6);
2755 int32_t rm_val = get_register(instr->RmValue());
2756 if (shift_type == 0) { // LSL
2757 rm_val <<= shift;
2758 } else { // ASR
2759 rm_val >>= shift;
2760 }
2761 // If saturation occurs, the Q flag should be set in the CPSR.
2762 // There is no Q flag yet, and no instruction (MRS) to read the
2763 // CPSR directly.
2764 if (rm_val > sat_val) {
2765 rm_val = sat_val;
2766 } else if (rm_val < 0) {
2767 rm_val = 0;
2768 }
2769 set_register(rd, rm_val);
2770 break;
2771 }
Kristian Monsen50ef84f2010-07-29 15:18:00 +01002772 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002773 } else {
2774 switch (instr->Bits(22, 21)) {
2775 case 0:
2776 UNIMPLEMENTED();
2777 break;
2778 case 1:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002779 if (instr->Bits(9, 6) == 1) {
2780 if (instr->Bit(20) == 0) {
2781 if (instr->Bits(19, 16) == 0xF) {
2782 // Sxtb.
2783 int32_t rm_val = get_register(instr->RmValue());
2784 int32_t rotate = instr->Bits(11, 10);
2785 switch (rotate) {
2786 case 0:
2787 break;
2788 case 1:
2789 rm_val = (rm_val >> 8) | (rm_val << 24);
2790 break;
2791 case 2:
2792 rm_val = (rm_val >> 16) | (rm_val << 16);
2793 break;
2794 case 3:
2795 rm_val = (rm_val >> 24) | (rm_val << 8);
2796 break;
2797 }
2798 set_register(rd, static_cast<int8_t>(rm_val));
2799 } else {
2800 // Sxtab.
2801 int32_t rn_val = get_register(rn);
2802 int32_t rm_val = get_register(instr->RmValue());
2803 int32_t rotate = instr->Bits(11, 10);
2804 switch (rotate) {
2805 case 0:
2806 break;
2807 case 1:
2808 rm_val = (rm_val >> 8) | (rm_val << 24);
2809 break;
2810 case 2:
2811 rm_val = (rm_val >> 16) | (rm_val << 16);
2812 break;
2813 case 3:
2814 rm_val = (rm_val >> 24) | (rm_val << 8);
2815 break;
2816 }
2817 set_register(rd, rn_val + static_cast<int8_t>(rm_val));
2818 }
2819 } else {
2820 if (instr->Bits(19, 16) == 0xF) {
2821 // Sxth.
2822 int32_t rm_val = get_register(instr->RmValue());
2823 int32_t rotate = instr->Bits(11, 10);
2824 switch (rotate) {
2825 case 0:
2826 break;
2827 case 1:
2828 rm_val = (rm_val >> 8) | (rm_val << 24);
2829 break;
2830 case 2:
2831 rm_val = (rm_val >> 16) | (rm_val << 16);
2832 break;
2833 case 3:
2834 rm_val = (rm_val >> 24) | (rm_val << 8);
2835 break;
2836 }
2837 set_register(rd, static_cast<int16_t>(rm_val));
2838 } else {
2839 // Sxtah.
2840 int32_t rn_val = get_register(rn);
2841 int32_t rm_val = get_register(instr->RmValue());
2842 int32_t rotate = instr->Bits(11, 10);
2843 switch (rotate) {
2844 case 0:
2845 break;
2846 case 1:
2847 rm_val = (rm_val >> 8) | (rm_val << 24);
2848 break;
2849 case 2:
2850 rm_val = (rm_val >> 16) | (rm_val << 16);
2851 break;
2852 case 3:
2853 rm_val = (rm_val >> 24) | (rm_val << 8);
2854 break;
2855 }
2856 set_register(rd, rn_val + static_cast<int16_t>(rm_val));
2857 }
2858 }
2859 } else {
2860 UNREACHABLE();
2861 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002862 break;
2863 case 2:
2864 if ((instr->Bit(20) == 0) && (instr->Bits(9, 6) == 1)) {
2865 if (instr->Bits(19, 16) == 0xF) {
2866 // Uxtb16.
2867 uint32_t rm_val = get_register(instr->RmValue());
2868 int32_t rotate = instr->Bits(11, 10);
2869 switch (rotate) {
2870 case 0:
2871 break;
2872 case 1:
2873 rm_val = (rm_val >> 8) | (rm_val << 24);
2874 break;
2875 case 2:
2876 rm_val = (rm_val >> 16) | (rm_val << 16);
2877 break;
2878 case 3:
2879 rm_val = (rm_val >> 24) | (rm_val << 8);
2880 break;
2881 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002882 set_register(rd, (rm_val & 0xFF) | (rm_val & 0xFF0000));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002883 } else {
2884 UNIMPLEMENTED();
2885 }
2886 } else {
2887 UNIMPLEMENTED();
2888 }
2889 break;
2890 case 3:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002891 if ((instr->Bits(9, 6) == 1)) {
2892 if (instr->Bit(20) == 0) {
2893 if (instr->Bits(19, 16) == 0xF) {
2894 // Uxtb.
2895 uint32_t rm_val = get_register(instr->RmValue());
2896 int32_t rotate = instr->Bits(11, 10);
2897 switch (rotate) {
2898 case 0:
2899 break;
2900 case 1:
2901 rm_val = (rm_val >> 8) | (rm_val << 24);
2902 break;
2903 case 2:
2904 rm_val = (rm_val >> 16) | (rm_val << 16);
2905 break;
2906 case 3:
2907 rm_val = (rm_val >> 24) | (rm_val << 8);
2908 break;
2909 }
2910 set_register(rd, (rm_val & 0xFF));
2911 } else {
2912 // Uxtab.
2913 uint32_t rn_val = get_register(rn);
2914 uint32_t rm_val = get_register(instr->RmValue());
2915 int32_t rotate = instr->Bits(11, 10);
2916 switch (rotate) {
2917 case 0:
2918 break;
2919 case 1:
2920 rm_val = (rm_val >> 8) | (rm_val << 24);
2921 break;
2922 case 2:
2923 rm_val = (rm_val >> 16) | (rm_val << 16);
2924 break;
2925 case 3:
2926 rm_val = (rm_val >> 24) | (rm_val << 8);
2927 break;
2928 }
2929 set_register(rd, rn_val + (rm_val & 0xFF));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002930 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002931 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002932 if (instr->Bits(19, 16) == 0xF) {
2933 // Uxth.
2934 uint32_t rm_val = get_register(instr->RmValue());
2935 int32_t rotate = instr->Bits(11, 10);
2936 switch (rotate) {
2937 case 0:
2938 break;
2939 case 1:
2940 rm_val = (rm_val >> 8) | (rm_val << 24);
2941 break;
2942 case 2:
2943 rm_val = (rm_val >> 16) | (rm_val << 16);
2944 break;
2945 case 3:
2946 rm_val = (rm_val >> 24) | (rm_val << 8);
2947 break;
2948 }
2949 set_register(rd, (rm_val & 0xFFFF));
2950 } else {
2951 // Uxtah.
2952 uint32_t rn_val = get_register(rn);
2953 uint32_t rm_val = get_register(instr->RmValue());
2954 int32_t rotate = instr->Bits(11, 10);
2955 switch (rotate) {
2956 case 0:
2957 break;
2958 case 1:
2959 rm_val = (rm_val >> 8) | (rm_val << 24);
2960 break;
2961 case 2:
2962 rm_val = (rm_val >> 16) | (rm_val << 16);
2963 break;
2964 case 3:
2965 rm_val = (rm_val >> 24) | (rm_val << 8);
2966 break;
2967 }
2968 set_register(rd, rn_val + (rm_val & 0xFFFF));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002969 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002970 }
2971 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002972 // PU == 0b01, BW == 0b11, Bits(9, 6) != 0b0001
2973 if ((instr->Bits(20, 16) == 0x1f) &&
2974 (instr->Bits(11, 4) == 0xf3)) {
2975 // Rbit.
2976 uint32_t rm_val = get_register(instr->RmValue());
2977 set_register(rd, base::bits::ReverseBits(rm_val));
2978 } else {
2979 UNIMPLEMENTED();
2980 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002981 }
2982 break;
Kristian Monsen50ef84f2010-07-29 15:18:00 +01002983 }
Kristian Monsen50ef84f2010-07-29 15:18:00 +01002984 }
2985 return;
Kristian Monsen50ef84f2010-07-29 15:18:00 +01002986 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002987 break;
2988 }
Steve Block1e0659c2011-05-24 12:43:12 +01002989 case db_x: {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002990 if (instr->Bits(22, 20) == 0x5) {
2991 if (instr->Bits(7, 4) == 0x1) {
2992 int rm = instr->RmValue();
2993 int32_t rm_val = get_register(rm);
2994 int rs = instr->RsValue();
2995 int32_t rs_val = get_register(rs);
2996 if (instr->Bits(15, 12) == 0xF) {
2997 // SMMUL (in V8 notation matching ARM ISA format)
2998 // Format(instr, "smmul'cond 'rn, 'rm, 'rs");
2999 rn_val = base::bits::SignedMulHigh32(rm_val, rs_val);
3000 } else {
3001 // SMMLA (in V8 notation matching ARM ISA format)
3002 // Format(instr, "smmla'cond 'rn, 'rm, 'rs, 'rd");
3003 int rd = instr->RdValue();
3004 int32_t rd_val = get_register(rd);
3005 rn_val = base::bits::SignedMulHighAndAdd32(rm_val, rs_val, rd_val);
3006 }
3007 set_register(rn, rn_val);
3008 return;
3009 }
3010 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003011 if (FLAG_enable_sudiv) {
3012 if (instr->Bits(5, 4) == 0x1) {
3013 if ((instr->Bit(22) == 0x0) && (instr->Bit(20) == 0x1)) {
3014 // (s/u)div (in V8 notation matching ARM ISA format) rn = rm/rs
3015 // Format(instr, "'(s/u)div'cond'b 'rn, 'rm, 'rs);
3016 int rm = instr->RmValue();
3017 int32_t rm_val = get_register(rm);
3018 int rs = instr->RsValue();
3019 int32_t rs_val = get_register(rs);
3020 int32_t ret_val = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003021 // udiv
3022 if (instr->Bit(21) == 0x1) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003023 ret_val = bit_cast<int32_t>(base::bits::UnsignedDiv32(
3024 bit_cast<uint32_t>(rm_val), bit_cast<uint32_t>(rs_val)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003025 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003026 ret_val = base::bits::SignedDiv32(rm_val, rs_val);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003027 }
3028 set_register(rn, ret_val);
3029 return;
3030 }
3031 }
3032 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003033 // Format(instr, "'memop'cond'b 'rd, ['rn, -'shift_rm]'w");
3034 addr = rn_val - shifter_operand;
3035 if (instr->HasW()) {
3036 set_register(rn, addr);
3037 }
3038 break;
3039 }
Steve Block1e0659c2011-05-24 12:43:12 +01003040 case ib_x: {
Andrei Popescu31002712010-02-23 13:46:05 +00003041 if (instr->HasW() && (instr->Bits(6, 4) == 0x5)) {
3042 uint32_t widthminus1 = static_cast<uint32_t>(instr->Bits(20, 16));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003043 uint32_t lsbit = static_cast<uint32_t>(instr->Bits(11, 7));
Andrei Popescu31002712010-02-23 13:46:05 +00003044 uint32_t msbit = widthminus1 + lsbit;
3045 if (msbit <= 31) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003046 if (instr->Bit(22)) {
3047 // ubfx - unsigned bitfield extract.
3048 uint32_t rm_val =
Steve Block1e0659c2011-05-24 12:43:12 +01003049 static_cast<uint32_t>(get_register(instr->RmValue()));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003050 uint32_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 } else {
3054 // sbfx - signed bitfield extract.
Steve Block1e0659c2011-05-24 12:43:12 +01003055 int32_t rm_val = get_register(instr->RmValue());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003056 int32_t extr_val = rm_val << (31 - msbit);
3057 extr_val = extr_val >> (31 - widthminus1);
Steve Block1e0659c2011-05-24 12:43:12 +01003058 set_register(instr->RdValue(), extr_val);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003059 }
3060 } else {
3061 UNREACHABLE();
3062 }
3063 return;
3064 } else if (!instr->HasW() && (instr->Bits(6, 4) == 0x1)) {
3065 uint32_t lsbit = static_cast<uint32_t>(instr->Bits(11, 7));
3066 uint32_t msbit = static_cast<uint32_t>(instr->Bits(20, 16));
3067 if (msbit >= lsbit) {
3068 // bfc or bfi - bitfield clear/insert.
3069 uint32_t rd_val =
Steve Block1e0659c2011-05-24 12:43:12 +01003070 static_cast<uint32_t>(get_register(instr->RdValue()));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003071 uint32_t bitcount = msbit - lsbit + 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003072 uint32_t mask = 0xffffffffu >> (32 - bitcount);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003073 rd_val &= ~(mask << lsbit);
Steve Block1e0659c2011-05-24 12:43:12 +01003074 if (instr->RmValue() != 15) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003075 // bfi - bitfield insert.
3076 uint32_t rm_val =
Steve Block1e0659c2011-05-24 12:43:12 +01003077 static_cast<uint32_t>(get_register(instr->RmValue()));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003078 rm_val &= mask;
3079 rd_val |= rm_val << lsbit;
3080 }
Steve Block1e0659c2011-05-24 12:43:12 +01003081 set_register(instr->RdValue(), rd_val);
Andrei Popescu31002712010-02-23 13:46:05 +00003082 } else {
3083 UNREACHABLE();
3084 }
3085 return;
3086 } else {
3087 // Format(instr, "'memop'cond'b 'rd, ['rn, +'shift_rm]'w");
3088 addr = rn_val + shifter_operand;
3089 if (instr->HasW()) {
3090 set_register(rn, addr);
3091 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003092 }
3093 break;
3094 }
3095 default: {
3096 UNREACHABLE();
3097 break;
3098 }
3099 }
3100 if (instr->HasB()) {
3101 if (instr->HasL()) {
3102 uint8_t byte = ReadB(addr);
3103 set_register(rd, byte);
3104 } else {
Andrei Popescu31002712010-02-23 13:46:05 +00003105 uint8_t byte = get_register(rd);
3106 WriteB(addr, byte);
Steve Blocka7e24c12009-10-30 11:49:00 +00003107 }
3108 } else {
3109 if (instr->HasL()) {
3110 set_register(rd, ReadW(addr, instr));
3111 } else {
3112 WriteW(addr, get_register(rd), instr);
3113 }
3114 }
3115}
3116
3117
Steve Block1e0659c2011-05-24 12:43:12 +01003118void Simulator::DecodeType4(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003119 DCHECK(instr->Bit(22) == 0); // only allowed to be set in privileged mode
Steve Blocka7e24c12009-10-30 11:49:00 +00003120 if (instr->HasL()) {
3121 // Format(instr, "ldm'cond'pu 'rn'w, 'rlist");
3122 HandleRList(instr, true);
3123 } else {
3124 // Format(instr, "stm'cond'pu 'rn'w, 'rlist");
3125 HandleRList(instr, false);
3126 }
3127}
3128
3129
Steve Block1e0659c2011-05-24 12:43:12 +01003130void Simulator::DecodeType5(Instruction* instr) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003131 // Format(instr, "b'l'cond 'target");
Steve Block1e0659c2011-05-24 12:43:12 +01003132 int off = (instr->SImmed24Value() << 2);
Steve Blocka7e24c12009-10-30 11:49:00 +00003133 intptr_t pc_address = get_pc();
3134 if (instr->HasLink()) {
Steve Block1e0659c2011-05-24 12:43:12 +01003135 set_register(lr, pc_address + Instruction::kInstrSize);
Steve Blocka7e24c12009-10-30 11:49:00 +00003136 }
3137 int pc_reg = get_register(pc);
3138 set_pc(pc_reg + off);
3139}
3140
3141
Steve Block1e0659c2011-05-24 12:43:12 +01003142void Simulator::DecodeType6(Instruction* instr) {
Steve Blockd0582a62009-12-15 09:54:21 +00003143 DecodeType6CoprocessorIns(instr);
Steve Blocka7e24c12009-10-30 11:49:00 +00003144}
3145
3146
Steve Block1e0659c2011-05-24 12:43:12 +01003147void Simulator::DecodeType7(Instruction* instr) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003148 if (instr->Bit(24) == 1) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003149 SoftwareInterrupt(instr);
3150 } else {
Steve Blockd0582a62009-12-15 09:54:21 +00003151 DecodeTypeVFP(instr);
Steve Blocka7e24c12009-10-30 11:49:00 +00003152 }
3153}
3154
3155
Steve Block1e0659c2011-05-24 12:43:12 +01003156// void Simulator::DecodeTypeVFP(Instruction* instr)
Steve Blockd0582a62009-12-15 09:54:21 +00003157// The Following ARMv7 VFPv instructions are currently supported.
Leon Clarkee46be812010-01-19 14:06:41 +00003158// vmov :Sn = Rt
3159// vmov :Rt = Sn
3160// vcvt: Dd = Sm
3161// vcvt: Sd = Dm
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003162// vcvt.f64.s32 Dd, Dd, #<fbits>
Steve Block44f0eee2011-05-26 01:26:41 +01003163// Dd = vabs(Dm)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003164// Sd = vabs(Sm)
Steve Block44f0eee2011-05-26 01:26:41 +01003165// Dd = vneg(Dm)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003166// Sd = vneg(Sm)
Leon Clarkee46be812010-01-19 14:06:41 +00003167// Dd = vadd(Dn, Dm)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003168// Sd = vadd(Sn, Sm)
Leon Clarkee46be812010-01-19 14:06:41 +00003169// Dd = vsub(Dn, Dm)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003170// Sd = vsub(Sn, Sm)
Leon Clarkee46be812010-01-19 14:06:41 +00003171// Dd = vmul(Dn, Dm)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003172// Sd = vmul(Sn, Sm)
Leon Clarkee46be812010-01-19 14:06:41 +00003173// Dd = vdiv(Dn, Dm)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003174// Sd = vdiv(Sn, Sm)
Steve Blockd0582a62009-12-15 09:54:21 +00003175// vcmp(Dd, Dm)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003176// vcmp(Sd, Sm)
Steve Block8defd9f2010-07-08 12:39:36 +01003177// Dd = vsqrt(Dm)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003178// Sd = vsqrt(Sm)
3179// vmrs
Steve Block1e0659c2011-05-24 12:43:12 +01003180void Simulator::DecodeTypeVFP(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003181 DCHECK((instr->TypeValue() == 7) && (instr->Bit(24) == 0x0) );
3182 DCHECK(instr->Bits(11, 9) == 0x5);
Steve Blockd0582a62009-12-15 09:54:21 +00003183
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003184 // Obtain single precision register codes.
3185 int m = instr->VFPMRegValue(kSinglePrecision);
3186 int d = instr->VFPDRegValue(kSinglePrecision);
3187 int n = instr->VFPNRegValue(kSinglePrecision);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003188 // Obtain double precision register codes.
Steve Block1e0659c2011-05-24 12:43:12 +01003189 int vm = instr->VFPMRegValue(kDoublePrecision);
3190 int vd = instr->VFPDRegValue(kDoublePrecision);
3191 int vn = instr->VFPNRegValue(kDoublePrecision);
Steve Blockd0582a62009-12-15 09:54:21 +00003192
Steve Block6ded16b2010-05-10 14:33:55 +01003193 if (instr->Bit(4) == 0) {
Steve Block1e0659c2011-05-24 12:43:12 +01003194 if (instr->Opc1Value() == 0x7) {
Steve Block6ded16b2010-05-10 14:33:55 +01003195 // Other data processing instructions
Steve Block1e0659c2011-05-24 12:43:12 +01003196 if ((instr->Opc2Value() == 0x0) && (instr->Opc3Value() == 0x1)) {
Steve Block8defd9f2010-07-08 12:39:36 +01003197 // vmov register to register.
Steve Block1e0659c2011-05-24 12:43:12 +01003198 if (instr->SzValue() == 0x1) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003199 uint32_t data[2];
3200 get_d_register(vm, data);
3201 set_d_register(vd, data);
Steve Block8defd9f2010-07-08 12:39:36 +01003202 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003203 set_s_register(d, get_s_register(m));
Steve Block8defd9f2010-07-08 12:39:36 +01003204 }
Steve Block1e0659c2011-05-24 12:43:12 +01003205 } else if ((instr->Opc2Value() == 0x0) && (instr->Opc3Value() == 0x3)) {
3206 // vabs
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003207 if (instr->SzValue() == 0x1) {
3208 double dm_value = get_double_from_d_register(vm);
3209 double dd_value = std::fabs(dm_value);
3210 dd_value = canonicalizeNaN(dd_value);
3211 set_d_register_from_double(vd, dd_value);
3212 } else {
3213 float sm_value = get_float_from_s_register(m);
3214 float sd_value = std::fabs(sm_value);
3215 sd_value = canonicalizeNaN(sd_value);
3216 set_s_register_from_float(d, sd_value);
3217 }
Steve Block44f0eee2011-05-26 01:26:41 +01003218 } else if ((instr->Opc2Value() == 0x1) && (instr->Opc3Value() == 0x1)) {
3219 // vneg
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003220 if (instr->SzValue() == 0x1) {
3221 double dm_value = get_double_from_d_register(vm);
3222 double dd_value = -dm_value;
3223 dd_value = canonicalizeNaN(dd_value);
3224 set_d_register_from_double(vd, dd_value);
3225 } else {
3226 float sm_value = get_float_from_s_register(m);
3227 float sd_value = -sm_value;
3228 sd_value = canonicalizeNaN(sd_value);
3229 set_s_register_from_float(d, sd_value);
3230 }
Steve Block1e0659c2011-05-24 12:43:12 +01003231 } else if ((instr->Opc2Value() == 0x7) && (instr->Opc3Value() == 0x3)) {
Steve Block6ded16b2010-05-10 14:33:55 +01003232 DecodeVCVTBetweenDoubleAndSingle(instr);
Steve Block1e0659c2011-05-24 12:43:12 +01003233 } else if ((instr->Opc2Value() == 0x8) && (instr->Opc3Value() & 0x1)) {
Steve Block6ded16b2010-05-10 14:33:55 +01003234 DecodeVCVTBetweenFloatingPointAndInteger(instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003235 } else if ((instr->Opc2Value() == 0xA) && (instr->Opc3Value() == 0x3) &&
3236 (instr->Bit(8) == 1)) {
3237 // vcvt.f64.s32 Dd, Dd, #<fbits>
3238 int fraction_bits = 32 - ((instr->Bits(3, 0) << 1) | instr->Bit(5));
3239 int fixed_value = get_sinteger_from_s_register(vd * 2);
3240 double divide = 1 << fraction_bits;
3241 set_d_register_from_double(vd, fixed_value / divide);
Steve Block1e0659c2011-05-24 12:43:12 +01003242 } else if (((instr->Opc2Value() >> 1) == 0x6) &&
3243 (instr->Opc3Value() & 0x1)) {
Steve Block6ded16b2010-05-10 14:33:55 +01003244 DecodeVCVTBetweenFloatingPointAndInteger(instr);
Steve Block1e0659c2011-05-24 12:43:12 +01003245 } else if (((instr->Opc2Value() == 0x4) || (instr->Opc2Value() == 0x5)) &&
3246 (instr->Opc3Value() & 0x1)) {
Steve Block6ded16b2010-05-10 14:33:55 +01003247 DecodeVCMP(instr);
Steve Block1e0659c2011-05-24 12:43:12 +01003248 } else if (((instr->Opc2Value() == 0x1)) && (instr->Opc3Value() == 0x3)) {
Steve Block8defd9f2010-07-08 12:39:36 +01003249 // vsqrt
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003250 lazily_initialize_fast_sqrt(isolate_);
3251 if (instr->SzValue() == 0x1) {
3252 double dm_value = get_double_from_d_register(vm);
3253 double dd_value = fast_sqrt(dm_value, isolate_);
3254 dd_value = canonicalizeNaN(dd_value);
3255 set_d_register_from_double(vd, dd_value);
3256 } else {
3257 float sm_value = get_float_from_s_register(m);
3258 float sd_value = fast_sqrt(sm_value, isolate_);
3259 sd_value = canonicalizeNaN(sd_value);
3260 set_s_register_from_float(d, sd_value);
3261 }
Steve Block1e0659c2011-05-24 12:43:12 +01003262 } else if (instr->Opc3Value() == 0x0) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +01003263 // vmov immediate.
Steve Block1e0659c2011-05-24 12:43:12 +01003264 if (instr->SzValue() == 0x1) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +01003265 set_d_register_from_double(vd, instr->DoubleImmedVmov());
3266 } else {
Ben Murdochda12d292016-06-02 14:46:10 +01003267 set_s_register_from_float(d, instr->DoubleImmedVmov());
Ben Murdoch3bec4d22010-07-22 14:51:16 +01003268 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003269 } else if (((instr->Opc2Value() == 0x6)) && (instr->Opc3Value() == 0x3)) {
3270 // vrintz - truncate
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003271 if (instr->SzValue() == 0x1) {
3272 double dm_value = get_double_from_d_register(vm);
3273 double dd_value = trunc(dm_value);
3274 dd_value = canonicalizeNaN(dd_value);
3275 set_d_register_from_double(vd, dd_value);
3276 } else {
3277 float sm_value = get_float_from_s_register(m);
3278 float sd_value = truncf(sm_value);
3279 sd_value = canonicalizeNaN(sd_value);
3280 set_s_register_from_float(d, sd_value);
3281 }
Steve Block6ded16b2010-05-10 14:33:55 +01003282 } else {
3283 UNREACHABLE(); // Not used by V8.
3284 }
Steve Block1e0659c2011-05-24 12:43:12 +01003285 } else if (instr->Opc1Value() == 0x3) {
Steve Block1e0659c2011-05-24 12:43:12 +01003286 if (instr->Opc3Value() & 0x1) {
Steve Block6ded16b2010-05-10 14:33:55 +01003287 // vsub
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003288 if (instr->SzValue() == 0x1) {
3289 double dn_value = get_double_from_d_register(vn);
3290 double dm_value = get_double_from_d_register(vm);
3291 double dd_value = dn_value - dm_value;
3292 dd_value = canonicalizeNaN(dd_value);
3293 set_d_register_from_double(vd, dd_value);
3294 } else {
3295 float sn_value = get_float_from_s_register(n);
3296 float sm_value = get_float_from_s_register(m);
3297 float sd_value = sn_value - sm_value;
3298 sd_value = canonicalizeNaN(sd_value);
3299 set_s_register_from_float(d, sd_value);
3300 }
Steve Block6ded16b2010-05-10 14:33:55 +01003301 } else {
3302 // vadd
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003303 if (instr->SzValue() == 0x1) {
3304 double dn_value = get_double_from_d_register(vn);
3305 double dm_value = get_double_from_d_register(vm);
3306 double dd_value = dn_value + dm_value;
3307 dd_value = canonicalizeNaN(dd_value);
3308 set_d_register_from_double(vd, dd_value);
3309 } else {
3310 float sn_value = get_float_from_s_register(n);
3311 float sm_value = get_float_from_s_register(m);
3312 float sd_value = sn_value + sm_value;
3313 sd_value = canonicalizeNaN(sd_value);
3314 set_s_register_from_float(d, sd_value);
3315 }
Steve Block6ded16b2010-05-10 14:33:55 +01003316 }
Steve Block1e0659c2011-05-24 12:43:12 +01003317 } else if ((instr->Opc1Value() == 0x2) && !(instr->Opc3Value() & 0x1)) {
Steve Block6ded16b2010-05-10 14:33:55 +01003318 // vmul
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003319 if (instr->SzValue() == 0x1) {
3320 double dn_value = get_double_from_d_register(vn);
3321 double dm_value = get_double_from_d_register(vm);
3322 double dd_value = dn_value * dm_value;
3323 dd_value = canonicalizeNaN(dd_value);
3324 set_d_register_from_double(vd, dd_value);
3325 } else {
3326 float sn_value = get_float_from_s_register(n);
3327 float sm_value = get_float_from_s_register(m);
3328 float sd_value = sn_value * sm_value;
3329 sd_value = canonicalizeNaN(sd_value);
3330 set_s_register_from_float(d, sd_value);
Steve Block6ded16b2010-05-10 14:33:55 +01003331 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003332 } else if ((instr->Opc1Value() == 0x0)) {
3333 // vmla, vmls
3334 const bool is_vmls = (instr->Opc3Value() & 0x1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003335 if (instr->SzValue() == 0x1) {
3336 const double dd_val = get_double_from_d_register(vd);
3337 const double dn_val = get_double_from_d_register(vn);
3338 const double dm_val = get_double_from_d_register(vm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003339
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003340 // Note: we do the mul and add/sub in separate steps to avoid getting a
3341 // result with too high precision.
3342 set_d_register_from_double(vd, dn_val * dm_val);
3343 if (is_vmls) {
3344 set_d_register_from_double(
3345 vd, canonicalizeNaN(dd_val - get_double_from_d_register(vd)));
3346 } else {
3347 set_d_register_from_double(
3348 vd, canonicalizeNaN(dd_val + get_double_from_d_register(vd)));
3349 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003350 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003351 const float sd_val = get_float_from_s_register(d);
3352 const float sn_val = get_float_from_s_register(n);
3353 const float sm_val = get_float_from_s_register(m);
3354
3355 // Note: we do the mul and add/sub in separate steps to avoid getting a
3356 // result with too high precision.
3357 set_s_register_from_float(d, sn_val * sm_val);
3358 if (is_vmls) {
3359 set_s_register_from_float(
3360 d, canonicalizeNaN(sd_val - get_float_from_s_register(d)));
3361 } else {
3362 set_s_register_from_float(
3363 d, canonicalizeNaN(sd_val + get_float_from_s_register(d)));
3364 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003365 }
Steve Block1e0659c2011-05-24 12:43:12 +01003366 } else if ((instr->Opc1Value() == 0x4) && !(instr->Opc3Value() & 0x1)) {
Steve Block6ded16b2010-05-10 14:33:55 +01003367 // vdiv
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003368 if (instr->SzValue() == 0x1) {
3369 double dn_value = get_double_from_d_register(vn);
3370 double dm_value = get_double_from_d_register(vm);
3371 double dd_value = dn_value / dm_value;
3372 div_zero_vfp_flag_ = (dm_value == 0);
3373 dd_value = canonicalizeNaN(dd_value);
3374 set_d_register_from_double(vd, dd_value);
3375 } else {
3376 float sn_value = get_float_from_s_register(n);
3377 float sm_value = get_float_from_s_register(m);
3378 float sd_value = sn_value / sm_value;
3379 div_zero_vfp_flag_ = (sm_value == 0);
3380 sd_value = canonicalizeNaN(sd_value);
3381 set_s_register_from_float(d, sd_value);
Steve Block6ded16b2010-05-10 14:33:55 +01003382 }
Steve Block6ded16b2010-05-10 14:33:55 +01003383 } else {
3384 UNIMPLEMENTED(); // Not used by V8.
3385 }
3386 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01003387 if ((instr->VCValue() == 0x0) &&
3388 (instr->VAValue() == 0x0)) {
Steve Block6ded16b2010-05-10 14:33:55 +01003389 DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003390 } else if ((instr->VLValue() == 0x0) &&
3391 (instr->VCValue() == 0x1) &&
3392 (instr->Bit(23) == 0x0)) {
3393 // vmov (ARM core register to scalar)
3394 int vd = instr->Bits(19, 16) | (instr->Bit(7) << 4);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003395 uint32_t data[2];
3396 get_d_register(vd, data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003397 data[instr->Bit(21)] = get_register(instr->RtValue());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003398 set_d_register(vd, data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003399 } else if ((instr->VLValue() == 0x1) &&
3400 (instr->VCValue() == 0x1) &&
3401 (instr->Bit(23) == 0x0)) {
3402 // vmov (scalar to ARM core register)
3403 int vn = instr->Bits(19, 16) | (instr->Bit(7) << 4);
3404 double dn_value = get_double_from_d_register(vn);
3405 int32_t data[2];
3406 memcpy(data, &dn_value, 8);
3407 set_register(instr->RtValue(), data[instr->Bit(21)]);
Steve Block1e0659c2011-05-24 12:43:12 +01003408 } else if ((instr->VLValue() == 0x1) &&
3409 (instr->VCValue() == 0x0) &&
3410 (instr->VAValue() == 0x7) &&
Steve Block6ded16b2010-05-10 14:33:55 +01003411 (instr->Bits(19, 16) == 0x1)) {
3412 // vmrs
Steve Block1e0659c2011-05-24 12:43:12 +01003413 uint32_t rt = instr->RtValue();
Russell Brenner90bac252010-11-18 13:33:46 -08003414 if (rt == 0xF) {
Steve Blockd0582a62009-12-15 09:54:21 +00003415 Copy_FPSCR_to_APSR();
Russell Brenner90bac252010-11-18 13:33:46 -08003416 } else {
3417 // Emulate FPSCR from the Simulator flags.
3418 uint32_t fpscr = (n_flag_FPSCR_ << 31) |
3419 (z_flag_FPSCR_ << 30) |
3420 (c_flag_FPSCR_ << 29) |
3421 (v_flag_FPSCR_ << 28) |
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003422 (FPSCR_default_NaN_mode_ << 25) |
Russell Brenner90bac252010-11-18 13:33:46 -08003423 (inexact_vfp_flag_ << 4) |
3424 (underflow_vfp_flag_ << 3) |
3425 (overflow_vfp_flag_ << 2) |
3426 (div_zero_vfp_flag_ << 1) |
3427 (inv_op_vfp_flag_ << 0) |
Steve Block1e0659c2011-05-24 12:43:12 +01003428 (FPSCR_rounding_mode_);
Russell Brenner90bac252010-11-18 13:33:46 -08003429 set_register(rt, fpscr);
3430 }
Steve Block1e0659c2011-05-24 12:43:12 +01003431 } else if ((instr->VLValue() == 0x0) &&
3432 (instr->VCValue() == 0x0) &&
3433 (instr->VAValue() == 0x7) &&
Russell Brenner90bac252010-11-18 13:33:46 -08003434 (instr->Bits(19, 16) == 0x1)) {
3435 // vmsr
Steve Block1e0659c2011-05-24 12:43:12 +01003436 uint32_t rt = instr->RtValue();
Russell Brenner90bac252010-11-18 13:33:46 -08003437 if (rt == pc) {
3438 UNREACHABLE();
3439 } else {
3440 uint32_t rt_value = get_register(rt);
3441 n_flag_FPSCR_ = (rt_value >> 31) & 1;
3442 z_flag_FPSCR_ = (rt_value >> 30) & 1;
3443 c_flag_FPSCR_ = (rt_value >> 29) & 1;
3444 v_flag_FPSCR_ = (rt_value >> 28) & 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003445 FPSCR_default_NaN_mode_ = (rt_value >> 25) & 1;
Russell Brenner90bac252010-11-18 13:33:46 -08003446 inexact_vfp_flag_ = (rt_value >> 4) & 1;
3447 underflow_vfp_flag_ = (rt_value >> 3) & 1;
3448 overflow_vfp_flag_ = (rt_value >> 2) & 1;
3449 div_zero_vfp_flag_ = (rt_value >> 1) & 1;
3450 inv_op_vfp_flag_ = (rt_value >> 0) & 1;
3451 FPSCR_rounding_mode_ =
Steve Block1e0659c2011-05-24 12:43:12 +01003452 static_cast<VFPRoundingMode>((rt_value) & kVFPRoundingModeMask);
Russell Brenner90bac252010-11-18 13:33:46 -08003453 }
Steve Blockd0582a62009-12-15 09:54:21 +00003454 } else {
3455 UNIMPLEMENTED(); // Not used by V8.
3456 }
Steve Block6ded16b2010-05-10 14:33:55 +01003457 }
3458}
3459
3460
Steve Block1e0659c2011-05-24 12:43:12 +01003461void Simulator::DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(
3462 Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003463 DCHECK((instr->Bit(4) == 1) && (instr->VCValue() == 0x0) &&
Steve Block1e0659c2011-05-24 12:43:12 +01003464 (instr->VAValue() == 0x0));
Steve Block6ded16b2010-05-10 14:33:55 +01003465
Steve Block1e0659c2011-05-24 12:43:12 +01003466 int t = instr->RtValue();
3467 int n = instr->VFPNRegValue(kSinglePrecision);
3468 bool to_arm_register = (instr->VLValue() == 0x1);
Steve Block6ded16b2010-05-10 14:33:55 +01003469
3470 if (to_arm_register) {
3471 int32_t int_value = get_sinteger_from_s_register(n);
3472 set_register(t, int_value);
3473 } else {
3474 int32_t rs_val = get_register(t);
3475 set_s_register_from_sinteger(n, rs_val);
3476 }
3477}
3478
3479
Steve Block1e0659c2011-05-24 12:43:12 +01003480void Simulator::DecodeVCMP(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003481 DCHECK((instr->Bit(4) == 0) && (instr->Opc1Value() == 0x7));
3482 DCHECK(((instr->Opc2Value() == 0x4) || (instr->Opc2Value() == 0x5)) &&
Steve Block1e0659c2011-05-24 12:43:12 +01003483 (instr->Opc3Value() & 0x1));
Steve Block6ded16b2010-05-10 14:33:55 +01003484 // Comparison.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003485
3486 VFPRegPrecision precision = kSinglePrecision;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003487 if (instr->SzValue() == 0x1) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003488 precision = kDoublePrecision;
3489 }
Steve Block6ded16b2010-05-10 14:33:55 +01003490
Steve Block1e0659c2011-05-24 12:43:12 +01003491 int d = instr->VFPDRegValue(precision);
Iain Merrick75681382010-08-19 15:07:18 +01003492 int m = 0;
Steve Block1e0659c2011-05-24 12:43:12 +01003493 if (instr->Opc2Value() == 0x4) {
3494 m = instr->VFPMRegValue(precision);
Iain Merrick75681382010-08-19 15:07:18 +01003495 }
Steve Block6ded16b2010-05-10 14:33:55 +01003496
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003497 if (precision == kDoublePrecision) {
Steve Block6ded16b2010-05-10 14:33:55 +01003498 double dd_value = get_double_from_d_register(d);
Iain Merrick75681382010-08-19 15:07:18 +01003499 double dm_value = 0.0;
Steve Block1e0659c2011-05-24 12:43:12 +01003500 if (instr->Opc2Value() == 0x4) {
Iain Merrick75681382010-08-19 15:07:18 +01003501 dm_value = get_double_from_d_register(m);
3502 }
Steve Block6ded16b2010-05-10 14:33:55 +01003503
Ben Murdoch086aeea2011-05-13 15:57:08 +01003504 // Raise exceptions for quiet NaNs if necessary.
3505 if (instr->Bit(7) == 1) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003506 if (std::isnan(dd_value)) {
Ben Murdoch086aeea2011-05-13 15:57:08 +01003507 inv_op_vfp_flag_ = true;
3508 }
3509 }
3510
Steve Block6ded16b2010-05-10 14:33:55 +01003511 Compute_FPSCR_Flags(dd_value, dm_value);
3512 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003513 float sd_value = get_float_from_s_register(d);
3514 float sm_value = 0.0;
3515 if (instr->Opc2Value() == 0x4) {
3516 sm_value = get_float_from_s_register(m);
3517 }
3518
3519 // Raise exceptions for quiet NaNs if necessary.
3520 if (instr->Bit(7) == 1) {
3521 if (std::isnan(sd_value)) {
3522 inv_op_vfp_flag_ = true;
3523 }
3524 }
3525
3526 Compute_FPSCR_Flags(sd_value, sm_value);
Steve Block6ded16b2010-05-10 14:33:55 +01003527 }
3528}
3529
3530
Steve Block1e0659c2011-05-24 12:43:12 +01003531void Simulator::DecodeVCVTBetweenDoubleAndSingle(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003532 DCHECK((instr->Bit(4) == 0) && (instr->Opc1Value() == 0x7));
3533 DCHECK((instr->Opc2Value() == 0x7) && (instr->Opc3Value() == 0x3));
Steve Block6ded16b2010-05-10 14:33:55 +01003534
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003535 VFPRegPrecision dst_precision = kDoublePrecision;
3536 VFPRegPrecision src_precision = kSinglePrecision;
Steve Block1e0659c2011-05-24 12:43:12 +01003537 if (instr->SzValue() == 1) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003538 dst_precision = kSinglePrecision;
3539 src_precision = kDoublePrecision;
3540 }
Steve Block6ded16b2010-05-10 14:33:55 +01003541
Steve Block1e0659c2011-05-24 12:43:12 +01003542 int dst = instr->VFPDRegValue(dst_precision);
3543 int src = instr->VFPMRegValue(src_precision);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003544
3545 if (dst_precision == kSinglePrecision) {
Steve Block6ded16b2010-05-10 14:33:55 +01003546 double val = get_double_from_d_register(src);
3547 set_s_register_from_float(dst, static_cast<float>(val));
3548 } else {
3549 float val = get_float_from_s_register(src);
3550 set_d_register_from_double(dst, static_cast<double>(val));
3551 }
3552}
3553
Steve Block1e0659c2011-05-24 12:43:12 +01003554bool get_inv_op_vfp_flag(VFPRoundingMode mode,
3555 double val,
3556 bool unsigned_) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003557 DCHECK((mode == RN) || (mode == RM) || (mode == RZ));
Steve Block1e0659c2011-05-24 12:43:12 +01003558 double max_uint = static_cast<double>(0xffffffffu);
3559 double max_int = static_cast<double>(kMaxInt);
3560 double min_int = static_cast<double>(kMinInt);
Steve Block6ded16b2010-05-10 14:33:55 +01003561
Steve Block1e0659c2011-05-24 12:43:12 +01003562 // Check for NaN.
3563 if (val != val) {
3564 return true;
3565 }
3566
3567 // Check for overflow. This code works because 32bit integers can be
3568 // exactly represented by ieee-754 64bit floating-point values.
3569 switch (mode) {
3570 case RN:
3571 return unsigned_ ? (val >= (max_uint + 0.5)) ||
3572 (val < -0.5)
3573 : (val >= (max_int + 0.5)) ||
3574 (val < (min_int - 0.5));
3575
3576 case RM:
3577 return unsigned_ ? (val >= (max_uint + 1.0)) ||
3578 (val < 0)
3579 : (val >= (max_int + 1.0)) ||
3580 (val < min_int);
3581
3582 case RZ:
3583 return unsigned_ ? (val >= (max_uint + 1.0)) ||
3584 (val <= -1)
3585 : (val >= (max_int + 1.0)) ||
3586 (val <= (min_int - 1.0));
3587 default:
3588 UNREACHABLE();
3589 return true;
3590 }
3591}
3592
3593
3594// We call this function only if we had a vfp invalid exception.
3595// It returns the correct saturated value.
3596int VFPConversionSaturate(double val, bool unsigned_res) {
3597 if (val != val) {
3598 return 0;
3599 } else {
3600 if (unsigned_res) {
3601 return (val < 0) ? 0 : 0xffffffffu;
3602 } else {
3603 return (val < 0) ? kMinInt : kMaxInt;
3604 }
3605 }
3606}
3607
3608
3609void Simulator::DecodeVCVTBetweenFloatingPointAndInteger(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003610 DCHECK((instr->Bit(4) == 0) && (instr->Opc1Value() == 0x7) &&
Steve Block1e0659c2011-05-24 12:43:12 +01003611 (instr->Bits(27, 23) == 0x1D));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003612 DCHECK(((instr->Opc2Value() == 0x8) && (instr->Opc3Value() & 0x1)) ||
Steve Block1e0659c2011-05-24 12:43:12 +01003613 (((instr->Opc2Value() >> 1) == 0x6) && (instr->Opc3Value() & 0x1)));
Steve Block6ded16b2010-05-10 14:33:55 +01003614
3615 // Conversion between floating-point and integer.
Steve Block6ded16b2010-05-10 14:33:55 +01003616 bool to_integer = (instr->Bit(18) == 1);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003617
Steve Block1e0659c2011-05-24 12:43:12 +01003618 VFPRegPrecision src_precision = (instr->SzValue() == 1) ? kDoublePrecision
3619 : kSinglePrecision;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003620
Steve Block6ded16b2010-05-10 14:33:55 +01003621 if (to_integer) {
Steve Block1e0659c2011-05-24 12:43:12 +01003622 // We are playing with code close to the C++ standard's limits below,
3623 // hence the very simple code and heavy checks.
3624 //
3625 // Note:
3626 // C++ defines default type casting from floating point to integer as
3627 // (close to) rounding toward zero ("fractional part discarded").
3628
3629 int dst = instr->VFPDRegValue(kSinglePrecision);
3630 int src = instr->VFPMRegValue(src_precision);
3631
3632 // Bit 7 in vcvt instructions indicates if we should use the FPSCR rounding
3633 // mode or the default Round to Zero mode.
3634 VFPRoundingMode mode = (instr->Bit(7) != 1) ? FPSCR_rounding_mode_
3635 : RZ;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003636 DCHECK((mode == RM) || (mode == RZ) || (mode == RN));
Steve Block1e0659c2011-05-24 12:43:12 +01003637
Steve Block6ded16b2010-05-10 14:33:55 +01003638 bool unsigned_integer = (instr->Bit(16) == 0);
Steve Block1e0659c2011-05-24 12:43:12 +01003639 bool double_precision = (src_precision == kDoublePrecision);
3640
3641 double val = double_precision ? get_double_from_d_register(src)
3642 : get_float_from_s_register(src);
3643
3644 int temp = unsigned_integer ? static_cast<uint32_t>(val)
3645 : static_cast<int32_t>(val);
3646
3647 inv_op_vfp_flag_ = get_inv_op_vfp_flag(mode, val, unsigned_integer);
3648
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003649 double abs_diff =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003650 unsigned_integer ? std::fabs(val - static_cast<uint32_t>(temp))
3651 : std::fabs(val - temp);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003652
3653 inexact_vfp_flag_ = (abs_diff != 0);
3654
Steve Block1e0659c2011-05-24 12:43:12 +01003655 if (inv_op_vfp_flag_) {
3656 temp = VFPConversionSaturate(val, unsigned_integer);
Russell Brenner90bac252010-11-18 13:33:46 -08003657 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01003658 switch (mode) {
3659 case RN: {
Steve Block1e0659c2011-05-24 12:43:12 +01003660 int val_sign = (val > 0) ? 1 : -1;
3661 if (abs_diff > 0.5) {
3662 temp += val_sign;
3663 } else if (abs_diff == 0.5) {
3664 // Round to even if exactly halfway.
3665 temp = ((temp % 2) == 0) ? temp : temp + val_sign;
3666 }
3667 break;
3668 }
3669
3670 case RM:
3671 temp = temp > val ? temp - 1 : temp;
3672 break;
3673
3674 case RZ:
3675 // Nothing to do.
3676 break;
3677
3678 default:
3679 UNREACHABLE();
3680 }
Steve Blockd0582a62009-12-15 09:54:21 +00003681 }
Steve Block6ded16b2010-05-10 14:33:55 +01003682
Steve Block1e0659c2011-05-24 12:43:12 +01003683 // Update the destination register.
3684 set_s_register_from_sinteger(dst, temp);
Russell Brenner90bac252010-11-18 13:33:46 -08003685
Steve Block6ded16b2010-05-10 14:33:55 +01003686 } else {
3687 bool unsigned_integer = (instr->Bit(7) == 0);
3688
Steve Block1e0659c2011-05-24 12:43:12 +01003689 int dst = instr->VFPDRegValue(src_precision);
3690 int src = instr->VFPMRegValue(kSinglePrecision);
Steve Block6ded16b2010-05-10 14:33:55 +01003691
3692 int val = get_sinteger_from_s_register(src);
3693
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003694 if (src_precision == kDoublePrecision) {
Steve Block6ded16b2010-05-10 14:33:55 +01003695 if (unsigned_integer) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003696 set_d_register_from_double(
3697 dst, static_cast<double>(static_cast<uint32_t>(val)));
Steve Block6ded16b2010-05-10 14:33:55 +01003698 } else {
3699 set_d_register_from_double(dst, static_cast<double>(val));
3700 }
3701 } else {
3702 if (unsigned_integer) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003703 set_s_register_from_float(
3704 dst, static_cast<float>(static_cast<uint32_t>(val)));
Steve Block6ded16b2010-05-10 14:33:55 +01003705 } else {
3706 set_s_register_from_float(dst, static_cast<float>(val));
3707 }
Steve Blockd0582a62009-12-15 09:54:21 +00003708 }
3709 }
3710}
3711
3712
Steve Block1e0659c2011-05-24 12:43:12 +01003713// void Simulator::DecodeType6CoprocessorIns(Instruction* instr)
Steve Blockd0582a62009-12-15 09:54:21 +00003714// Decode Type 6 coprocessor instructions.
Leon Clarkee46be812010-01-19 14:06:41 +00003715// Dm = vmov(Rt, Rt2)
3716// <Rt, Rt2> = vmov(Dm)
Leon Clarked91b9f72010-01-27 17:25:45 +00003717// Ddst = MEM(Rbase + 4*offset).
3718// MEM(Rbase + 4*offset) = Dsrc.
Steve Block1e0659c2011-05-24 12:43:12 +01003719void Simulator::DecodeType6CoprocessorIns(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003720 DCHECK((instr->TypeValue() == 6));
Steve Blockd0582a62009-12-15 09:54:21 +00003721
Steve Block1e0659c2011-05-24 12:43:12 +01003722 if (instr->CoprocessorValue() == 0xA) {
3723 switch (instr->OpcodeValue()) {
Steve Block6ded16b2010-05-10 14:33:55 +01003724 case 0x8:
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003725 case 0xA:
3726 case 0xC:
3727 case 0xE: { // Load and store single precision float to memory.
Steve Block1e0659c2011-05-24 12:43:12 +01003728 int rn = instr->RnValue();
3729 int vd = instr->VFPDRegValue(kSinglePrecision);
3730 int offset = instr->Immed8Value();
Steve Block6ded16b2010-05-10 14:33:55 +01003731 if (!instr->HasU()) {
3732 offset = -offset;
3733 }
3734
3735 int32_t address = get_register(rn) + 4 * offset;
3736 if (instr->HasL()) {
3737 // Load double from memory: vldr.
3738 set_s_register_from_sinteger(vd, ReadW(address, instr));
3739 } else {
3740 // Store double to memory: vstr.
3741 WriteW(address, get_sinteger_from_s_register(vd), instr);
3742 }
3743 break;
3744 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01003745 case 0x4:
3746 case 0x5:
3747 case 0x6:
3748 case 0x7:
3749 case 0x9:
3750 case 0xB:
3751 // Load/store multiple single from memory: vldm/vstm.
3752 HandleVList(instr);
3753 break;
Steve Block6ded16b2010-05-10 14:33:55 +01003754 default:
3755 UNIMPLEMENTED(); // Not used by V8.
Steve Block6ded16b2010-05-10 14:33:55 +01003756 }
Steve Block1e0659c2011-05-24 12:43:12 +01003757 } else if (instr->CoprocessorValue() == 0xB) {
3758 switch (instr->OpcodeValue()) {
Leon Clarked91b9f72010-01-27 17:25:45 +00003759 case 0x2:
3760 // Load and store double to two GP registers
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003761 if (instr->Bits(7, 6) != 0 || instr->Bit(4) != 1) {
Leon Clarked91b9f72010-01-27 17:25:45 +00003762 UNIMPLEMENTED(); // Not used by V8.
3763 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01003764 int rt = instr->RtValue();
3765 int rn = instr->RnValue();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003766 int vm = instr->VFPMRegValue(kDoublePrecision);
Leon Clarked91b9f72010-01-27 17:25:45 +00003767 if (instr->HasL()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003768 uint32_t data[2];
3769 get_d_register(vm, data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003770 set_register(rt, data[0]);
3771 set_register(rn, data[1]);
Leon Clarked91b9f72010-01-27 17:25:45 +00003772 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003773 int32_t data[] = { get_register(rt), get_register(rn) };
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003774 set_d_register(vm, reinterpret_cast<uint32_t*>(data));
Leon Clarked91b9f72010-01-27 17:25:45 +00003775 }
3776 }
3777 break;
3778 case 0x8:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003779 case 0xA:
3780 case 0xC:
3781 case 0xE: { // Load and store double to memory.
Steve Block1e0659c2011-05-24 12:43:12 +01003782 int rn = instr->RnValue();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003783 int vd = instr->VFPDRegValue(kDoublePrecision);
Steve Block1e0659c2011-05-24 12:43:12 +01003784 int offset = instr->Immed8Value();
Leon Clarked91b9f72010-01-27 17:25:45 +00003785 if (!instr->HasU()) {
3786 offset = -offset;
3787 }
3788 int32_t address = get_register(rn) + 4 * offset;
3789 if (instr->HasL()) {
3790 // Load double from memory: vldr.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003791 int32_t data[] = {
3792 ReadW(address, instr),
3793 ReadW(address + 4, instr)
3794 };
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003795 set_d_register(vd, reinterpret_cast<uint32_t*>(data));
Leon Clarked91b9f72010-01-27 17:25:45 +00003796 } else {
3797 // Store double to memory: vstr.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003798 uint32_t data[2];
3799 get_d_register(vd, data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003800 WriteW(address, data[0], instr);
3801 WriteW(address + 4, data[1], instr);
Leon Clarked91b9f72010-01-27 17:25:45 +00003802 }
3803 break;
3804 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01003805 case 0x4:
3806 case 0x5:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003807 case 0x6:
3808 case 0x7:
Ben Murdoch8b112d22011-06-08 16:22:53 +01003809 case 0x9:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003810 case 0xB:
Ben Murdoch8b112d22011-06-08 16:22:53 +01003811 // Load/store multiple double from memory: vldm/vstm.
3812 HandleVList(instr);
3813 break;
Leon Clarked91b9f72010-01-27 17:25:45 +00003814 default:
3815 UNIMPLEMENTED(); // Not used by V8.
Leon Clarked91b9f72010-01-27 17:25:45 +00003816 }
Steve Block6ded16b2010-05-10 14:33:55 +01003817 } else {
3818 UNIMPLEMENTED(); // Not used by V8.
Steve Blockd0582a62009-12-15 09:54:21 +00003819 }
3820}
3821
3822
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003823void Simulator::DecodeSpecialCondition(Instruction* instr) {
3824 switch (instr->SpecialValue()) {
3825 case 5:
3826 if ((instr->Bits(18, 16) == 0) && (instr->Bits(11, 6) == 0x28) &&
3827 (instr->Bit(4) == 1)) {
3828 // vmovl signed
3829 if ((instr->VdValue() & 1) != 0) UNIMPLEMENTED();
3830 int Vd = (instr->Bit(22) << 3) | (instr->VdValue() >> 1);
3831 int Vm = (instr->Bit(5) << 4) | instr->VmValue();
3832 int imm3 = instr->Bits(21, 19);
3833 if ((imm3 != 1) && (imm3 != 2) && (imm3 != 4)) UNIMPLEMENTED();
3834 int esize = 8 * imm3;
3835 int elements = 64 / esize;
3836 int8_t from[8];
3837 get_d_register(Vm, reinterpret_cast<uint64_t*>(from));
3838 int16_t to[8];
3839 int e = 0;
3840 while (e < elements) {
3841 to[e] = from[e];
3842 e++;
3843 }
3844 set_q_register(Vd, reinterpret_cast<uint64_t*>(to));
3845 } else {
3846 UNIMPLEMENTED();
3847 }
3848 break;
3849 case 7:
3850 if ((instr->Bits(18, 16) == 0) && (instr->Bits(11, 6) == 0x28) &&
3851 (instr->Bit(4) == 1)) {
3852 // vmovl unsigned
3853 if ((instr->VdValue() & 1) != 0) UNIMPLEMENTED();
3854 int Vd = (instr->Bit(22) << 3) | (instr->VdValue() >> 1);
3855 int Vm = (instr->Bit(5) << 4) | instr->VmValue();
3856 int imm3 = instr->Bits(21, 19);
3857 if ((imm3 != 1) && (imm3 != 2) && (imm3 != 4)) UNIMPLEMENTED();
3858 int esize = 8 * imm3;
3859 int elements = 64 / esize;
3860 uint8_t from[8];
3861 get_d_register(Vm, reinterpret_cast<uint64_t*>(from));
3862 uint16_t to[8];
3863 int e = 0;
3864 while (e < elements) {
3865 to[e] = from[e];
3866 e++;
3867 }
3868 set_q_register(Vd, reinterpret_cast<uint64_t*>(to));
3869 } else {
3870 UNIMPLEMENTED();
3871 }
3872 break;
3873 case 8:
3874 if (instr->Bits(21, 20) == 0) {
3875 // vst1
3876 int Vd = (instr->Bit(22) << 4) | instr->VdValue();
3877 int Rn = instr->VnValue();
3878 int type = instr->Bits(11, 8);
3879 int Rm = instr->VmValue();
3880 int32_t address = get_register(Rn);
3881 int regs = 0;
3882 switch (type) {
3883 case nlt_1:
3884 regs = 1;
3885 break;
3886 case nlt_2:
3887 regs = 2;
3888 break;
3889 case nlt_3:
3890 regs = 3;
3891 break;
3892 case nlt_4:
3893 regs = 4;
3894 break;
3895 default:
3896 UNIMPLEMENTED();
3897 break;
3898 }
3899 int r = 0;
3900 while (r < regs) {
3901 uint32_t data[2];
3902 get_d_register(Vd + r, data);
3903 WriteW(address, data[0], instr);
3904 WriteW(address + 4, data[1], instr);
3905 address += 8;
3906 r++;
3907 }
3908 if (Rm != 15) {
3909 if (Rm == 13) {
3910 set_register(Rn, address);
3911 } else {
3912 set_register(Rn, get_register(Rn) + get_register(Rm));
3913 }
3914 }
3915 } else if (instr->Bits(21, 20) == 2) {
3916 // vld1
3917 int Vd = (instr->Bit(22) << 4) | instr->VdValue();
3918 int Rn = instr->VnValue();
3919 int type = instr->Bits(11, 8);
3920 int Rm = instr->VmValue();
3921 int32_t address = get_register(Rn);
3922 int regs = 0;
3923 switch (type) {
3924 case nlt_1:
3925 regs = 1;
3926 break;
3927 case nlt_2:
3928 regs = 2;
3929 break;
3930 case nlt_3:
3931 regs = 3;
3932 break;
3933 case nlt_4:
3934 regs = 4;
3935 break;
3936 default:
3937 UNIMPLEMENTED();
3938 break;
3939 }
3940 int r = 0;
3941 while (r < regs) {
3942 uint32_t data[2];
3943 data[0] = ReadW(address, instr);
3944 data[1] = ReadW(address + 4, instr);
3945 set_d_register(Vd + r, data);
3946 address += 8;
3947 r++;
3948 }
3949 if (Rm != 15) {
3950 if (Rm == 13) {
3951 set_register(Rn, address);
3952 } else {
3953 set_register(Rn, get_register(Rn) + get_register(Rm));
3954 }
3955 }
3956 } else {
3957 UNIMPLEMENTED();
3958 }
3959 break;
3960 case 0xA:
3961 case 0xB:
3962 if ((instr->Bits(22, 20) == 5) && (instr->Bits(15, 12) == 0xf)) {
3963 // pld: ignore instruction.
Ben Murdoch097c5b22016-05-18 11:27:45 +01003964 } else if (instr->SpecialValue() == 0xA && instr->Bits(22, 20) == 7) {
3965 // dsb, dmb, isb: ignore instruction for now.
3966 // TODO(binji): implement
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003967 } else {
3968 UNIMPLEMENTED();
3969 }
3970 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003971 case 0x1D:
3972 if (instr->Opc1Value() == 0x7 && instr->Opc3Value() == 0x1 &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003973 instr->Bits(11, 9) == 0x5 && instr->Bits(19, 18) == 0x2) {
3974 if (instr->SzValue() == 0x1) {
3975 int vm = instr->VFPMRegValue(kDoublePrecision);
3976 int vd = instr->VFPDRegValue(kDoublePrecision);
3977 double dm_value = get_double_from_d_register(vm);
3978 double dd_value = 0.0;
3979 int rounding_mode = instr->Bits(17, 16);
3980 switch (rounding_mode) {
3981 case 0x0: // vrinta - round with ties to away from zero
3982 dd_value = round(dm_value);
3983 break;
3984 case 0x1: { // vrintn - round with ties to even
3985 dd_value = nearbyint(dm_value);
3986 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003987 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003988 case 0x2: // vrintp - ceil
3989 dd_value = ceil(dm_value);
3990 break;
3991 case 0x3: // vrintm - floor
3992 dd_value = floor(dm_value);
3993 break;
3994 default:
3995 UNREACHABLE(); // Case analysis is exhaustive.
3996 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003997 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003998 dd_value = canonicalizeNaN(dd_value);
3999 set_d_register_from_double(vd, dd_value);
4000 } else {
4001 int m = instr->VFPMRegValue(kSinglePrecision);
4002 int d = instr->VFPDRegValue(kSinglePrecision);
4003 float sm_value = get_float_from_s_register(m);
4004 float sd_value = 0.0;
4005 int rounding_mode = instr->Bits(17, 16);
4006 switch (rounding_mode) {
4007 case 0x0: // vrinta - round with ties to away from zero
4008 sd_value = roundf(sm_value);
4009 break;
4010 case 0x1: { // vrintn - round with ties to even
4011 sd_value = nearbyintf(sm_value);
4012 break;
4013 }
4014 case 0x2: // vrintp - ceil
4015 sd_value = ceilf(sm_value);
4016 break;
4017 case 0x3: // vrintm - floor
4018 sd_value = floorf(sm_value);
4019 break;
4020 default:
4021 UNREACHABLE(); // Case analysis is exhaustive.
4022 break;
4023 }
4024 sd_value = canonicalizeNaN(sd_value);
4025 set_s_register_from_float(d, sd_value);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004026 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004027 } else {
4028 UNIMPLEMENTED();
4029 }
4030 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004031 default:
4032 UNIMPLEMENTED();
4033 break;
4034 }
4035}
4036
4037
Steve Blocka7e24c12009-10-30 11:49:00 +00004038// Executes the current instruction.
Steve Block1e0659c2011-05-24 12:43:12 +01004039void Simulator::InstructionDecode(Instruction* instr) {
Steve Block6ded16b2010-05-10 14:33:55 +01004040 if (v8::internal::FLAG_check_icache) {
Steve Block44f0eee2011-05-26 01:26:41 +01004041 CheckICache(isolate_->simulator_i_cache(), instr);
Steve Block6ded16b2010-05-10 14:33:55 +01004042 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004043 pc_modified_ = false;
4044 if (::v8::internal::FLAG_trace_sim) {
4045 disasm::NameConverter converter;
4046 disasm::Disassembler dasm(converter);
4047 // use a reasonably large buffer
4048 v8::internal::EmbeddedVector<char, 256> buffer;
4049 dasm.InstructionDecode(buffer,
4050 reinterpret_cast<byte*>(instr));
Ben Murdochf87a2032010-10-22 12:50:53 +01004051 PrintF(" 0x%08x %s\n", reinterpret_cast<intptr_t>(instr), buffer.start());
Steve Blocka7e24c12009-10-30 11:49:00 +00004052 }
Steve Block1e0659c2011-05-24 12:43:12 +01004053 if (instr->ConditionField() == kSpecialCondition) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004054 DecodeSpecialCondition(instr);
Steve Blocka7e24c12009-10-30 11:49:00 +00004055 } else if (ConditionallyExecute(instr)) {
Steve Block1e0659c2011-05-24 12:43:12 +01004056 switch (instr->TypeValue()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004057 case 0:
4058 case 1: {
4059 DecodeType01(instr);
4060 break;
4061 }
4062 case 2: {
4063 DecodeType2(instr);
4064 break;
4065 }
4066 case 3: {
4067 DecodeType3(instr);
4068 break;
4069 }
4070 case 4: {
4071 DecodeType4(instr);
4072 break;
4073 }
4074 case 5: {
4075 DecodeType5(instr);
4076 break;
4077 }
4078 case 6: {
4079 DecodeType6(instr);
4080 break;
4081 }
4082 case 7: {
4083 DecodeType7(instr);
4084 break;
4085 }
4086 default: {
4087 UNIMPLEMENTED();
4088 break;
4089 }
4090 }
Steve Block1e0659c2011-05-24 12:43:12 +01004091 // If the instruction is a non taken conditional stop, we need to skip the
4092 // inlined message address.
4093 } else if (instr->IsStop()) {
4094 set_pc(get_pc() + 2 * Instruction::kInstrSize);
Steve Blocka7e24c12009-10-30 11:49:00 +00004095 }
4096 if (!pc_modified_) {
Steve Block1e0659c2011-05-24 12:43:12 +01004097 set_register(pc, reinterpret_cast<int32_t>(instr)
4098 + Instruction::kInstrSize);
Steve Blocka7e24c12009-10-30 11:49:00 +00004099 }
4100}
4101
4102
Steve Blocka7e24c12009-10-30 11:49:00 +00004103void Simulator::Execute() {
4104 // Get the PC to simulate. Cannot use the accessor here as we need the
4105 // raw PC value and not the one used as input to arithmetic instructions.
4106 int program_counter = get_pc();
4107
4108 if (::v8::internal::FLAG_stop_sim_at == 0) {
4109 // Fast version of the dispatch loop without checking whether the simulator
4110 // should be stopping at a particular executed instruction.
4111 while (program_counter != end_sim_pc) {
Steve Block1e0659c2011-05-24 12:43:12 +01004112 Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
Steve Blocka7e24c12009-10-30 11:49:00 +00004113 icount_++;
4114 InstructionDecode(instr);
4115 program_counter = get_pc();
4116 }
4117 } else {
4118 // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when
4119 // we reach the particular instuction count.
4120 while (program_counter != end_sim_pc) {
Steve Block1e0659c2011-05-24 12:43:12 +01004121 Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
Steve Blocka7e24c12009-10-30 11:49:00 +00004122 icount_++;
4123 if (icount_ == ::v8::internal::FLAG_stop_sim_at) {
Steve Block44f0eee2011-05-26 01:26:41 +01004124 ArmDebugger dbg(this);
Steve Blocka7e24c12009-10-30 11:49:00 +00004125 dbg.Debug();
4126 } else {
4127 InstructionDecode(instr);
4128 }
4129 program_counter = get_pc();
4130 }
4131 }
4132}
4133
4134
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004135void Simulator::CallInternal(byte* entry) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004136 // Adjust JS-based stack limit to C-based stack limit.
4137 isolate_->stack_guard()->AdjustStackLimitForSimulator();
4138
Steve Blocka7e24c12009-10-30 11:49:00 +00004139 // Prepare to execute the code at entry
4140 set_register(pc, reinterpret_cast<int32_t>(entry));
4141 // Put down marker for end of simulation. The simulator will stop simulation
4142 // when the PC reaches this value. By saving the "end simulation" value into
4143 // the LR the simulation stops when returning to this call point.
4144 set_register(lr, end_sim_pc);
4145
4146 // Remember the values of callee-saved registers.
4147 // The code below assumes that r9 is not used as sb (static base) in
4148 // simulator code and therefore is regarded as a callee-saved register.
4149 int32_t r4_val = get_register(r4);
4150 int32_t r5_val = get_register(r5);
4151 int32_t r6_val = get_register(r6);
4152 int32_t r7_val = get_register(r7);
4153 int32_t r8_val = get_register(r8);
4154 int32_t r9_val = get_register(r9);
4155 int32_t r10_val = get_register(r10);
4156 int32_t r11_val = get_register(r11);
4157
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004158 // Set up the callee-saved registers with a known value. To be able to check
Steve Blocka7e24c12009-10-30 11:49:00 +00004159 // that they are preserved properly across JS execution.
4160 int32_t callee_saved_value = icount_;
4161 set_register(r4, callee_saved_value);
4162 set_register(r5, callee_saved_value);
4163 set_register(r6, callee_saved_value);
4164 set_register(r7, callee_saved_value);
4165 set_register(r8, callee_saved_value);
4166 set_register(r9, callee_saved_value);
4167 set_register(r10, callee_saved_value);
4168 set_register(r11, callee_saved_value);
4169
4170 // Start the simulation
4171 Execute();
4172
4173 // Check that the callee-saved registers have been preserved.
4174 CHECK_EQ(callee_saved_value, get_register(r4));
4175 CHECK_EQ(callee_saved_value, get_register(r5));
4176 CHECK_EQ(callee_saved_value, get_register(r6));
4177 CHECK_EQ(callee_saved_value, get_register(r7));
4178 CHECK_EQ(callee_saved_value, get_register(r8));
4179 CHECK_EQ(callee_saved_value, get_register(r9));
4180 CHECK_EQ(callee_saved_value, get_register(r10));
4181 CHECK_EQ(callee_saved_value, get_register(r11));
4182
4183 // Restore callee-saved registers with the original value.
4184 set_register(r4, r4_val);
4185 set_register(r5, r5_val);
4186 set_register(r6, r6_val);
4187 set_register(r7, r7_val);
4188 set_register(r8, r8_val);
4189 set_register(r9, r9_val);
4190 set_register(r10, r10_val);
4191 set_register(r11, r11_val);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004192}
4193
4194
4195int32_t Simulator::Call(byte* entry, int argument_count, ...) {
4196 va_list parameters;
4197 va_start(parameters, argument_count);
4198 // Set up arguments
4199
4200 // First four arguments passed in registers.
4201 DCHECK(argument_count >= 4);
4202 set_register(r0, va_arg(parameters, int32_t));
4203 set_register(r1, va_arg(parameters, int32_t));
4204 set_register(r2, va_arg(parameters, int32_t));
4205 set_register(r3, va_arg(parameters, int32_t));
4206
4207 // Remaining arguments passed on stack.
4208 int original_stack = get_register(sp);
4209 // Compute position of stack on entry to generated code.
4210 int entry_stack = (original_stack - (argument_count - 4) * sizeof(int32_t));
4211 if (base::OS::ActivationFrameAlignment() != 0) {
4212 entry_stack &= -base::OS::ActivationFrameAlignment();
4213 }
4214 // Store remaining arguments on stack, from low to high memory.
4215 intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
4216 for (int i = 4; i < argument_count; i++) {
4217 stack_argument[i - 4] = va_arg(parameters, int32_t);
4218 }
4219 va_end(parameters);
4220 set_register(sp, entry_stack);
4221
4222 CallInternal(entry);
Steve Blocka7e24c12009-10-30 11:49:00 +00004223
4224 // Pop stack passed arguments.
4225 CHECK_EQ(entry_stack, get_register(sp));
4226 set_register(sp, original_stack);
4227
4228 int32_t result = get_register(r0);
4229 return result;
4230}
4231
Steve Blockd0582a62009-12-15 09:54:21 +00004232
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004233void Simulator::CallFP(byte* entry, double d0, double d1) {
4234 if (use_eabi_hardfloat()) {
4235 set_d_register_from_double(0, d0);
4236 set_d_register_from_double(1, d1);
4237 } else {
4238 set_register_pair_from_double(0, &d0);
4239 set_register_pair_from_double(2, &d1);
4240 }
4241 CallInternal(entry);
4242}
4243
4244
4245int32_t Simulator::CallFPReturnsInt(byte* entry, double d0, double d1) {
4246 CallFP(entry, d0, d1);
4247 int32_t result = get_register(r0);
4248 return result;
4249}
4250
4251
4252double Simulator::CallFPReturnsDouble(byte* entry, double d0, double d1) {
4253 CallFP(entry, d0, d1);
4254 if (use_eabi_hardfloat()) {
4255 return get_double_from_d_register(0);
4256 } else {
4257 return get_double_from_register_pair(0);
4258 }
4259}
4260
4261
Steve Blockd0582a62009-12-15 09:54:21 +00004262uintptr_t Simulator::PushAddress(uintptr_t address) {
4263 int new_sp = get_register(sp) - sizeof(uintptr_t);
4264 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp);
4265 *stack_slot = address;
4266 set_register(sp, new_sp);
4267 return new_sp;
4268}
4269
4270
4271uintptr_t Simulator::PopAddress() {
4272 int current_sp = get_register(sp);
4273 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp);
4274 uintptr_t address = *stack_slot;
4275 set_register(sp, current_sp + sizeof(uintptr_t));
4276 return address;
4277}
4278
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004279} // namespace internal
4280} // namespace v8
Steve Blocka7e24c12009-10-30 11:49:00 +00004281
John Reck59135872010-11-02 12:39:01 -07004282#endif // USE_SIMULATOR
Leon Clarkef7060e22010-06-03 12:02:55 +01004283
4284#endif // V8_TARGET_ARCH_ARM