blob: f475a18b0937c39b5e10050b12bab9c847e8a227 [file] [log] [blame]
Leon Clarked91b9f72010-01-27 17:25:45 +00001// Copyright 2010 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdlib.h>
Steve Block8defd9f2010-07-08 12:39:36 +010029#include <math.h>
Steve Blocka7e24c12009-10-30 11:49:00 +000030#include <cstdarg>
31#include "v8.h"
32
Leon Clarkef7060e22010-06-03 12:02:55 +010033#if defined(V8_TARGET_ARCH_ARM)
34
Steve Blocka7e24c12009-10-30 11:49:00 +000035#include "disasm.h"
36#include "assembler.h"
37#include "arm/constants-arm.h"
38#include "arm/simulator-arm.h"
39
John Reck59135872010-11-02 12:39:01 -070040#if defined(USE_SIMULATOR)
Steve Blocka7e24c12009-10-30 11:49:00 +000041
42// Only build the simulator if not compiling for real ARM hardware.
Steve Block1e0659c2011-05-24 12:43:12 +010043namespace v8 {
44namespace internal {
Steve Blocka7e24c12009-10-30 11:49:00 +000045
46// This macro provides a platform independent use of sscanf. The reason for
Leon Clarked91b9f72010-01-27 17:25:45 +000047// SScanF not being implemented in a platform independent way through
48// ::v8::internal::OS in the same way as SNPrintF is that the
49// Windows C Run-Time Library does not provide vsscanf.
Steve Blocka7e24c12009-10-30 11:49:00 +000050#define SScanF sscanf // NOLINT
51
52// The Debugger class is used by the simulator while debugging simulated ARM
53// code.
54class Debugger {
55 public:
56 explicit Debugger(Simulator* sim);
57 ~Debugger();
58
Steve Block1e0659c2011-05-24 12:43:12 +010059 void Stop(Instruction* instr);
Steve Blocka7e24c12009-10-30 11:49:00 +000060 void Debug();
61
62 private:
Steve Block1e0659c2011-05-24 12:43:12 +010063 static const Instr kBreakpointInstr =
64 (al | (7*B25) | (1*B24) | kBreakpoint);
65 static const Instr kNopInstr = (al | (13*B21));
Steve Blocka7e24c12009-10-30 11:49:00 +000066
67 Simulator* sim_;
68
69 int32_t GetRegisterValue(int regnum);
Ben Murdochb0fe1622011-05-05 13:52:32 +010070 double GetVFPDoubleRegisterValue(int regnum);
Steve Blocka7e24c12009-10-30 11:49:00 +000071 bool GetValue(const char* desc, int32_t* value);
Steve Block6ded16b2010-05-10 14:33:55 +010072 bool GetVFPSingleValue(const char* desc, float* value);
73 bool GetVFPDoubleValue(const char* desc, double* value);
Steve Blocka7e24c12009-10-30 11:49:00 +000074
75 // Set or delete a breakpoint. Returns true if successful.
Steve Block1e0659c2011-05-24 12:43:12 +010076 bool SetBreakpoint(Instruction* breakpc);
77 bool DeleteBreakpoint(Instruction* breakpc);
Steve Blocka7e24c12009-10-30 11:49:00 +000078
79 // Undo and redo all breakpoints. This is needed to bracket disassembly and
80 // execution to skip past breakpoints when run from the debugger.
81 void UndoBreakpoints();
82 void RedoBreakpoints();
83};
84
85
86Debugger::Debugger(Simulator* sim) {
87 sim_ = sim;
88}
89
90
91Debugger::~Debugger() {
92}
93
94
95
96#ifdef GENERATED_CODE_COVERAGE
97static FILE* coverage_log = NULL;
98
99
100static void InitializeCoverage() {
101 char* file_name = getenv("V8_GENERATED_CODE_COVERAGE_LOG");
102 if (file_name != NULL) {
103 coverage_log = fopen(file_name, "aw+");
104 }
105}
106
107
Steve Block1e0659c2011-05-24 12:43:12 +0100108void Debugger::Stop(Instruction* instr) {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800109 // Get the stop code.
Steve Block1e0659c2011-05-24 12:43:12 +0100110 uint32_t code = instr->SvcValue() & kStopCodeMask;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800111 // Retrieve the encoded address, which comes just after this stop.
112 char** msg_address =
Steve Block1e0659c2011-05-24 12:43:12 +0100113 reinterpret_cast<char**>(sim_->get_pc() + Instruction::kInstrSize);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800114 char* msg = *msg_address;
115 ASSERT(msg != NULL);
116
117 // Update this stop description.
118 if (isWatchedStop(code) && !watched_stops[code].desc) {
119 watched_stops[code].desc = msg;
120 }
121
122 if (strlen(msg) > 0) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000123 if (coverage_log != NULL) {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800124 fprintf(coverage_log, "%s\n", msg);
Steve Blocka7e24c12009-10-30 11:49:00 +0000125 fflush(coverage_log);
126 }
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800127 // Overwrite the instruction and address with nops.
128 instr->SetInstructionBits(kNopInstr);
Steve Block1e0659c2011-05-24 12:43:12 +0100129 reinterpret_cast<Instruction*>(msg_address)->SetInstructionBits(kNopInstr);
Steve Blocka7e24c12009-10-30 11:49:00 +0000130 }
Steve Block1e0659c2011-05-24 12:43:12 +0100131 sim_->set_pc(sim_->get_pc() + 2 * Instruction::kInstrSize);
Steve Blocka7e24c12009-10-30 11:49:00 +0000132}
133
134#else // ndef GENERATED_CODE_COVERAGE
135
136static void InitializeCoverage() {
137}
138
139
Steve Block1e0659c2011-05-24 12:43:12 +0100140void Debugger::Stop(Instruction* instr) {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800141 // Get the stop code.
Steve Block1e0659c2011-05-24 12:43:12 +0100142 uint32_t code = instr->SvcValue() & kStopCodeMask;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800143 // Retrieve the encoded address, which comes just after this stop.
Steve Block1e0659c2011-05-24 12:43:12 +0100144 char* msg = *reinterpret_cast<char**>(sim_->get_pc()
145 + Instruction::kInstrSize);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800146 // Update this stop description.
147 if (sim_->isWatchedStop(code) && !sim_->watched_stops[code].desc) {
148 sim_->watched_stops[code].desc = msg;
149 }
Steve Block1e0659c2011-05-24 12:43:12 +0100150 // Print the stop message and code if it is not the default code.
151 if (code != kMaxStopCode) {
152 PrintF("Simulator hit stop %u: %s\n", code, msg);
153 } else {
154 PrintF("Simulator hit %s\n", msg);
155 }
156 sim_->set_pc(sim_->get_pc() + 2 * Instruction::kInstrSize);
Steve Blocka7e24c12009-10-30 11:49:00 +0000157 Debug();
158}
159#endif
160
161
162int32_t Debugger::GetRegisterValue(int regnum) {
163 if (regnum == kPCRegister) {
164 return sim_->get_pc();
165 } else {
166 return sim_->get_register(regnum);
167 }
168}
169
170
Ben Murdochb0fe1622011-05-05 13:52:32 +0100171double Debugger::GetVFPDoubleRegisterValue(int regnum) {
172 return sim_->get_double_from_d_register(regnum);
173}
174
175
Steve Blocka7e24c12009-10-30 11:49:00 +0000176bool Debugger::GetValue(const char* desc, int32_t* value) {
177 int regnum = Registers::Number(desc);
178 if (regnum != kNoRegister) {
179 *value = GetRegisterValue(regnum);
180 return true;
181 } else {
Steve Block6ded16b2010-05-10 14:33:55 +0100182 if (strncmp(desc, "0x", 2) == 0) {
183 return SScanF(desc + 2, "%x", reinterpret_cast<uint32_t*>(value)) == 1;
184 } else {
185 return SScanF(desc, "%u", reinterpret_cast<uint32_t*>(value)) == 1;
186 }
187 }
188 return false;
189}
190
191
192bool Debugger::GetVFPSingleValue(const char* desc, float* value) {
193 bool is_double;
194 int regnum = VFPRegisters::Number(desc, &is_double);
195 if (regnum != kNoRegister && !is_double) {
196 *value = sim_->get_float_from_s_register(regnum);
197 return true;
198 }
199 return false;
200}
201
202
203bool Debugger::GetVFPDoubleValue(const char* desc, double* value) {
204 bool is_double;
205 int regnum = VFPRegisters::Number(desc, &is_double);
206 if (regnum != kNoRegister && is_double) {
207 *value = sim_->get_double_from_d_register(regnum);
208 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +0000209 }
210 return false;
211}
212
213
Steve Block1e0659c2011-05-24 12:43:12 +0100214bool Debugger::SetBreakpoint(Instruction* breakpc) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000215 // Check if a breakpoint can be set. If not return without any side-effects.
216 if (sim_->break_pc_ != NULL) {
217 return false;
218 }
219
220 // Set the breakpoint.
221 sim_->break_pc_ = breakpc;
222 sim_->break_instr_ = breakpc->InstructionBits();
223 // Not setting the breakpoint instruction in the code itself. It will be set
224 // when the debugger shell continues.
225 return true;
226}
227
228
Steve Block1e0659c2011-05-24 12:43:12 +0100229bool Debugger::DeleteBreakpoint(Instruction* breakpc) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000230 if (sim_->break_pc_ != NULL) {
231 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
232 }
233
234 sim_->break_pc_ = NULL;
235 sim_->break_instr_ = 0;
236 return true;
237}
238
239
240void Debugger::UndoBreakpoints() {
241 if (sim_->break_pc_ != NULL) {
242 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
243 }
244}
245
246
247void Debugger::RedoBreakpoints() {
248 if (sim_->break_pc_ != NULL) {
249 sim_->break_pc_->SetInstructionBits(kBreakpointInstr);
250 }
251}
252
253
254void Debugger::Debug() {
255 intptr_t last_pc = -1;
256 bool done = false;
257
258#define COMMAND_SIZE 63
259#define ARG_SIZE 255
260
261#define STR(a) #a
262#define XSTR(a) STR(a)
263
264 char cmd[COMMAND_SIZE + 1];
265 char arg1[ARG_SIZE + 1];
266 char arg2[ARG_SIZE + 1];
Steve Block6ded16b2010-05-10 14:33:55 +0100267 char* argv[3] = { cmd, arg1, arg2 };
Steve Blocka7e24c12009-10-30 11:49:00 +0000268
269 // make sure to have a proper terminating character if reaching the limit
270 cmd[COMMAND_SIZE] = 0;
271 arg1[ARG_SIZE] = 0;
272 arg2[ARG_SIZE] = 0;
273
274 // Undo all set breakpoints while running in the debugger shell. This will
275 // make them invisible to all commands.
276 UndoBreakpoints();
277
278 while (!done) {
279 if (last_pc != sim_->get_pc()) {
280 disasm::NameConverter converter;
281 disasm::Disassembler dasm(converter);
282 // use a reasonably large buffer
283 v8::internal::EmbeddedVector<char, 256> buffer;
284 dasm.InstructionDecode(buffer,
285 reinterpret_cast<byte*>(sim_->get_pc()));
286 PrintF(" 0x%08x %s\n", sim_->get_pc(), buffer.start());
287 last_pc = sim_->get_pc();
288 }
289 char* line = ReadLine("sim> ");
290 if (line == NULL) {
291 break;
292 } else {
293 // Use sscanf to parse the individual parts of the command line. At the
294 // moment no command expects more than two parameters.
Steve Block6ded16b2010-05-10 14:33:55 +0100295 int argc = SScanF(line,
Steve Blocka7e24c12009-10-30 11:49:00 +0000296 "%" XSTR(COMMAND_SIZE) "s "
297 "%" XSTR(ARG_SIZE) "s "
298 "%" XSTR(ARG_SIZE) "s",
299 cmd, arg1, arg2);
300 if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
Steve Block1e0659c2011-05-24 12:43:12 +0100301 sim_->InstructionDecode(reinterpret_cast<Instruction*>(sim_->get_pc()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000302 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) {
303 // Execute the one instruction we broke at with breakpoints disabled.
Steve Block1e0659c2011-05-24 12:43:12 +0100304 sim_->InstructionDecode(reinterpret_cast<Instruction*>(sim_->get_pc()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000305 // Leave the debugger shell.
306 done = true;
307 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
Steve Block6ded16b2010-05-10 14:33:55 +0100308 if (argc == 2) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000309 int32_t value;
Steve Block6ded16b2010-05-10 14:33:55 +0100310 float svalue;
311 double dvalue;
Steve Blocka7e24c12009-10-30 11:49:00 +0000312 if (strcmp(arg1, "all") == 0) {
313 for (int i = 0; i < kNumRegisters; i++) {
314 value = GetRegisterValue(i);
315 PrintF("%3s: 0x%08x %10d\n", Registers::Name(i), value, value);
316 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100317 for (int i = 0; i < kNumVFPDoubleRegisters; i++) {
318 dvalue = GetVFPDoubleRegisterValue(i);
319 PrintF("%3s: %f\n",
320 VFPRegisters::Name(i, true), dvalue);
321 }
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)) {
326 PrintF("%s: %f \n", arg1, svalue);
327 } else if (GetVFPDoubleValue(arg1, &dvalue)) {
Ben Murdochf87a2032010-10-22 12:50:53 +0100328 PrintF("%s: %f \n", arg1, dvalue);
Steve Blocka7e24c12009-10-30 11:49:00 +0000329 } else {
330 PrintF("%s unrecognized\n", arg1);
331 }
332 }
333 } else {
334 PrintF("print <register>\n");
335 }
336 } else if ((strcmp(cmd, "po") == 0)
337 || (strcmp(cmd, "printobject") == 0)) {
Steve Block6ded16b2010-05-10 14:33:55 +0100338 if (argc == 2) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000339 int32_t value;
340 if (GetValue(arg1, &value)) {
341 Object* obj = reinterpret_cast<Object*>(value);
342 PrintF("%s: \n", arg1);
343#ifdef DEBUG
344 obj->PrintLn();
345#else
346 obj->ShortPrint();
347 PrintF("\n");
348#endif
349 } else {
350 PrintF("%s unrecognized\n", arg1);
351 }
352 } else {
353 PrintF("printobject <value>\n");
354 }
Steve Block6ded16b2010-05-10 14:33:55 +0100355 } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0) {
356 int32_t* cur = NULL;
357 int32_t* end = NULL;
358 int next_arg = 1;
359
360 if (strcmp(cmd, "stack") == 0) {
361 cur = reinterpret_cast<int32_t*>(sim_->get_register(Simulator::sp));
362 } else { // "mem"
363 int32_t value;
364 if (!GetValue(arg1, &value)) {
365 PrintF("%s unrecognized\n", arg1);
366 continue;
367 }
368 cur = reinterpret_cast<int32_t*>(value);
369 next_arg++;
370 }
371
372 int32_t words;
373 if (argc == next_arg) {
374 words = 10;
375 } else if (argc == next_arg + 1) {
376 if (!GetValue(argv[next_arg], &words)) {
377 words = 10;
378 }
379 }
380 end = cur + words;
381
382 while (cur < end) {
Ben Murdochf87a2032010-10-22 12:50:53 +0100383 PrintF(" 0x%08x: 0x%08x %10d\n",
384 reinterpret_cast<intptr_t>(cur), *cur, *cur);
Steve Block6ded16b2010-05-10 14:33:55 +0100385 cur++;
386 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000387 } else if (strcmp(cmd, "disasm") == 0) {
388 disasm::NameConverter converter;
389 disasm::Disassembler dasm(converter);
390 // use a reasonably large buffer
391 v8::internal::EmbeddedVector<char, 256> buffer;
392
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800393 byte* prev = NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +0000394 byte* cur = NULL;
395 byte* end = NULL;
396
Steve Block6ded16b2010-05-10 14:33:55 +0100397 if (argc == 1) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000398 cur = reinterpret_cast<byte*>(sim_->get_pc());
Steve Block1e0659c2011-05-24 12:43:12 +0100399 end = cur + (10 * Instruction::kInstrSize);
Steve Block6ded16b2010-05-10 14:33:55 +0100400 } else if (argc == 2) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000401 int32_t value;
402 if (GetValue(arg1, &value)) {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800403 cur = reinterpret_cast<byte*>(sim_->get_pc());
404 // Disassemble <arg1> instructions.
Steve Block1e0659c2011-05-24 12:43:12 +0100405 end = cur + (value * Instruction::kInstrSize);
Steve Blocka7e24c12009-10-30 11:49:00 +0000406 }
407 } else {
408 int32_t value1;
409 int32_t value2;
410 if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
411 cur = reinterpret_cast<byte*>(value1);
Steve Block1e0659c2011-05-24 12:43:12 +0100412 end = cur + (value2 * Instruction::kInstrSize);
Steve Blocka7e24c12009-10-30 11:49:00 +0000413 }
414 }
415
416 while (cur < end) {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800417 prev = cur;
418 cur += dasm.InstructionDecode(buffer, cur);
Ben Murdochf87a2032010-10-22 12:50:53 +0100419 PrintF(" 0x%08x %s\n",
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800420 reinterpret_cast<intptr_t>(prev), buffer.start());
Steve Blocka7e24c12009-10-30 11:49:00 +0000421 }
422 } else if (strcmp(cmd, "gdb") == 0) {
423 PrintF("relinquishing control to gdb\n");
424 v8::internal::OS::DebugBreak();
425 PrintF("regaining control from gdb\n");
426 } else if (strcmp(cmd, "break") == 0) {
Steve Block6ded16b2010-05-10 14:33:55 +0100427 if (argc == 2) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000428 int32_t value;
429 if (GetValue(arg1, &value)) {
Steve Block1e0659c2011-05-24 12:43:12 +0100430 if (!SetBreakpoint(reinterpret_cast<Instruction*>(value))) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000431 PrintF("setting breakpoint failed\n");
432 }
433 } else {
434 PrintF("%s unrecognized\n", arg1);
435 }
436 } else {
437 PrintF("break <address>\n");
438 }
439 } else if (strcmp(cmd, "del") == 0) {
440 if (!DeleteBreakpoint(NULL)) {
441 PrintF("deleting breakpoint failed\n");
442 }
443 } else if (strcmp(cmd, "flags") == 0) {
444 PrintF("N flag: %d; ", sim_->n_flag_);
445 PrintF("Z flag: %d; ", sim_->z_flag_);
446 PrintF("C flag: %d; ", sim_->c_flag_);
447 PrintF("V flag: %d\n", sim_->v_flag_);
Steve Blockd0582a62009-12-15 09:54:21 +0000448 PrintF("INVALID OP flag: %d; ", sim_->inv_op_vfp_flag_);
449 PrintF("DIV BY ZERO flag: %d; ", sim_->div_zero_vfp_flag_);
450 PrintF("OVERFLOW flag: %d; ", sim_->overflow_vfp_flag_);
451 PrintF("UNDERFLOW flag: %d; ", sim_->underflow_vfp_flag_);
Steve Block1e0659c2011-05-24 12:43:12 +0100452 PrintF("INEXACT flag: %d;\n", sim_->inexact_vfp_flag_);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800453 } else if (strcmp(cmd, "stop") == 0) {
454 int32_t value;
Steve Block1e0659c2011-05-24 12:43:12 +0100455 intptr_t stop_pc = sim_->get_pc() - 2 * Instruction::kInstrSize;
456 Instruction* stop_instr = reinterpret_cast<Instruction*>(stop_pc);
457 Instruction* msg_address =
458 reinterpret_cast<Instruction*>(stop_pc + Instruction::kInstrSize);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800459 if ((argc == 2) && (strcmp(arg1, "unstop") == 0)) {
460 // Remove the current stop.
461 if (sim_->isStopInstruction(stop_instr)) {
462 stop_instr->SetInstructionBits(kNopInstr);
463 msg_address->SetInstructionBits(kNopInstr);
464 } else {
465 PrintF("Not at debugger stop.\n");
466 }
467 } else if (argc == 3) {
468 // Print information about all/the specified breakpoint(s).
469 if (strcmp(arg1, "info") == 0) {
470 if (strcmp(arg2, "all") == 0) {
471 PrintF("Stop information:\n");
472 for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) {
473 sim_->PrintStopInfo(i);
474 }
475 } else if (GetValue(arg2, &value)) {
476 sim_->PrintStopInfo(value);
477 } else {
478 PrintF("Unrecognized argument.\n");
479 }
480 } else if (strcmp(arg1, "enable") == 0) {
481 // Enable all/the specified breakpoint(s).
482 if (strcmp(arg2, "all") == 0) {
483 for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) {
484 sim_->EnableStop(i);
485 }
486 } else if (GetValue(arg2, &value)) {
487 sim_->EnableStop(value);
488 } else {
489 PrintF("Unrecognized argument.\n");
490 }
491 } else if (strcmp(arg1, "disable") == 0) {
492 // Disable all/the specified breakpoint(s).
493 if (strcmp(arg2, "all") == 0) {
494 for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) {
495 sim_->DisableStop(i);
496 }
497 } else if (GetValue(arg2, &value)) {
498 sim_->DisableStop(value);
499 } else {
500 PrintF("Unrecognized argument.\n");
501 }
502 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000503 } else {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800504 PrintF("Wrong usage. Use help command for more information.\n");
Steve Blocka7e24c12009-10-30 11:49:00 +0000505 }
Leon Clarkee46be812010-01-19 14:06:41 +0000506 } else if ((strcmp(cmd, "t") == 0) || strcmp(cmd, "trace") == 0) {
507 ::v8::internal::FLAG_trace_sim = !::v8::internal::FLAG_trace_sim;
508 PrintF("Trace of executed instructions is %s\n",
509 ::v8::internal::FLAG_trace_sim ? "on" : "off");
Steve Blocka7e24c12009-10-30 11:49:00 +0000510 } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
511 PrintF("cont\n");
512 PrintF(" continue execution (alias 'c')\n");
513 PrintF("stepi\n");
514 PrintF(" step one instruction (alias 'si')\n");
515 PrintF("print <register>\n");
516 PrintF(" print register content (alias 'p')\n");
517 PrintF(" use register name 'all' to print all registers\n");
518 PrintF("printobject <register>\n");
519 PrintF(" print an object from a register (alias 'po')\n");
520 PrintF("flags\n");
521 PrintF(" print flags\n");
Steve Block6ded16b2010-05-10 14:33:55 +0100522 PrintF("stack [<words>]\n");
523 PrintF(" dump stack content, default dump 10 words)\n");
524 PrintF("mem <address> [<words>]\n");
525 PrintF(" dump memory content, default dump 10 words)\n");
Steve Blocka7e24c12009-10-30 11:49:00 +0000526 PrintF("disasm [<instructions>]\n");
527 PrintF("disasm [[<address>] <instructions>]\n");
528 PrintF(" disassemble code, default is 10 instructions from pc\n");
529 PrintF("gdb\n");
530 PrintF(" enter gdb\n");
531 PrintF("break <address>\n");
532 PrintF(" set a break point on the address\n");
533 PrintF("del\n");
534 PrintF(" delete the breakpoint\n");
Leon Clarkee46be812010-01-19 14:06:41 +0000535 PrintF("trace (alias 't')\n");
Steve Block6ded16b2010-05-10 14:33:55 +0100536 PrintF(" toogle the tracing of all executed statements\n");
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800537 PrintF("stop feature:\n");
538 PrintF(" Description:\n");
539 PrintF(" Stops are debug instructions inserted by\n");
540 PrintF(" the Assembler::stop() function.\n");
541 PrintF(" When hitting a stop, the Simulator will\n");
542 PrintF(" stop and and give control to the Debugger.\n");
543 PrintF(" The first %d stop codes are watched:\n",
544 Simulator::kNumOfWatchedStops);
545 PrintF(" - They can be enabled / disabled: the Simulator\n");
546 PrintF(" will / won't stop when hitting them.\n");
547 PrintF(" - The Simulator keeps track of how many times they \n");
548 PrintF(" are met. (See the info command.) Going over a\n");
549 PrintF(" disabled stop still increases its counter. \n");
550 PrintF(" Commands:\n");
551 PrintF(" stop info all/<code> : print infos about number <code>\n");
552 PrintF(" or all stop(s).\n");
553 PrintF(" stop enable/disable all/<code> : enables / disables\n");
554 PrintF(" all or number <code> stop(s)\n");
555 PrintF(" stop unstop\n");
556 PrintF(" ignore the stop instruction at the current location\n");
557 PrintF(" from now on\n");
Steve Blocka7e24c12009-10-30 11:49:00 +0000558 } else {
559 PrintF("Unknown command: %s\n", cmd);
560 }
561 }
562 DeleteArray(line);
563 }
564
565 // Add all the breakpoints back to stop execution and enter the debugger
566 // shell when hit.
567 RedoBreakpoints();
568
569#undef COMMAND_SIZE
570#undef ARG_SIZE
571
572#undef STR
573#undef XSTR
574}
575
576
Steve Block6ded16b2010-05-10 14:33:55 +0100577static bool ICacheMatch(void* one, void* two) {
578 ASSERT((reinterpret_cast<intptr_t>(one) & CachePage::kPageMask) == 0);
579 ASSERT((reinterpret_cast<intptr_t>(two) & CachePage::kPageMask) == 0);
580 return one == two;
581}
582
583
584static uint32_t ICacheHash(void* key) {
585 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)) >> 2;
586}
587
588
589static bool AllOnOnePage(uintptr_t start, int size) {
590 intptr_t start_page = (start & ~CachePage::kPageMask);
591 intptr_t end_page = ((start + size) & ~CachePage::kPageMask);
592 return start_page == end_page;
593}
594
595
596void Simulator::FlushICache(void* start_addr, size_t size) {
597 intptr_t start = reinterpret_cast<intptr_t>(start_addr);
598 int intra_line = (start & CachePage::kLineMask);
599 start -= intra_line;
600 size += intra_line;
601 size = ((size - 1) | CachePage::kLineMask) + 1;
602 int offset = (start & CachePage::kPageMask);
603 while (!AllOnOnePage(start, size - 1)) {
604 int bytes_to_flush = CachePage::kPageSize - offset;
605 FlushOnePage(start, bytes_to_flush);
606 start += bytes_to_flush;
607 size -= bytes_to_flush;
608 ASSERT_EQ(0, start & CachePage::kPageMask);
609 offset = 0;
610 }
611 if (size != 0) {
612 FlushOnePage(start, size);
613 }
614}
615
616
617CachePage* Simulator::GetCachePage(void* page) {
618 v8::internal::HashMap::Entry* entry = i_cache_->Lookup(page,
619 ICacheHash(page),
620 true);
621 if (entry->value == NULL) {
622 CachePage* new_page = new CachePage();
623 entry->value = new_page;
624 }
625 return reinterpret_cast<CachePage*>(entry->value);
626}
627
628
629// Flush from start up to and not including start + size.
630void Simulator::FlushOnePage(intptr_t start, int size) {
631 ASSERT(size <= CachePage::kPageSize);
632 ASSERT(AllOnOnePage(start, size - 1));
633 ASSERT((start & CachePage::kLineMask) == 0);
634 ASSERT((size & CachePage::kLineMask) == 0);
635 void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask));
636 int offset = (start & CachePage::kPageMask);
637 CachePage* cache_page = GetCachePage(page);
638 char* valid_bytemap = cache_page->ValidityByte(offset);
639 memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift);
640}
641
642
Steve Block1e0659c2011-05-24 12:43:12 +0100643void Simulator::CheckICache(Instruction* instr) {
Steve Block6ded16b2010-05-10 14:33:55 +0100644 intptr_t address = reinterpret_cast<intptr_t>(instr);
645 void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
646 void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask));
647 int offset = (address & CachePage::kPageMask);
648 CachePage* cache_page = GetCachePage(page);
649 char* cache_valid_byte = cache_page->ValidityByte(offset);
650 bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID);
651 char* cached_line = cache_page->CachedData(offset & ~CachePage::kLineMask);
652 if (cache_hit) {
653 // Check that the data in memory matches the contents of the I-cache.
654 CHECK(memcmp(reinterpret_cast<void*>(instr),
655 cache_page->CachedData(offset),
Steve Block1e0659c2011-05-24 12:43:12 +0100656 Instruction::kInstrSize) == 0);
Steve Block6ded16b2010-05-10 14:33:55 +0100657 } else {
658 // Cache miss. Load memory into the cache.
659 memcpy(cached_line, line, CachePage::kLineLength);
660 *cache_valid_byte = CachePage::LINE_VALID;
661 }
662}
663
664
Steve Blocka7e24c12009-10-30 11:49:00 +0000665// Create one simulator per thread and keep it in thread local storage.
666static v8::internal::Thread::LocalStorageKey simulator_key;
667
668
669bool Simulator::initialized_ = false;
670
671
672void Simulator::Initialize() {
673 if (initialized_) return;
674 simulator_key = v8::internal::Thread::CreateThreadLocalKey();
675 initialized_ = true;
676 ::v8::internal::ExternalReference::set_redirector(&RedirectExternalReference);
677}
678
679
Steve Block6ded16b2010-05-10 14:33:55 +0100680v8::internal::HashMap* Simulator::i_cache_ = NULL;
681
682
Steve Blocka7e24c12009-10-30 11:49:00 +0000683Simulator::Simulator() {
Steve Block6ded16b2010-05-10 14:33:55 +0100684 if (i_cache_ == NULL) {
685 i_cache_ = new v8::internal::HashMap(&ICacheMatch);
686 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000687 Initialize();
688 // Setup simulator support first. Some of this information is needed to
689 // setup the architecture state.
690 size_t stack_size = 1 * 1024*1024; // allocate 1MB for stack
691 stack_ = reinterpret_cast<char*>(malloc(stack_size));
692 pc_modified_ = false;
693 icount_ = 0;
694 break_pc_ = NULL;
695 break_instr_ = 0;
696
697 // Setup architecture state.
698 // All registers are initialized to zero to start with.
699 for (int i = 0; i < num_registers; i++) {
700 registers_[i] = 0;
701 }
702 n_flag_ = false;
703 z_flag_ = false;
704 c_flag_ = false;
705 v_flag_ = false;
706
Steve Blockd0582a62009-12-15 09:54:21 +0000707 // Initializing VFP registers.
708 // All registers are initialized to zero to start with
709 // even though s_registers_ & d_registers_ share the same
710 // physical registers in the target.
711 for (int i = 0; i < num_s_registers; i++) {
712 vfp_register[i] = 0;
713 }
714 n_flag_FPSCR_ = false;
715 z_flag_FPSCR_ = false;
716 c_flag_FPSCR_ = false;
717 v_flag_FPSCR_ = false;
Russell Brenner90bac252010-11-18 13:33:46 -0800718 FPSCR_rounding_mode_ = RZ;
Steve Blockd0582a62009-12-15 09:54:21 +0000719
720 inv_op_vfp_flag_ = false;
721 div_zero_vfp_flag_ = false;
722 overflow_vfp_flag_ = false;
723 underflow_vfp_flag_ = false;
724 inexact_vfp_flag_ = false;
725
Steve Blocka7e24c12009-10-30 11:49:00 +0000726 // The sp is initialized to point to the bottom (high address) of the
727 // allocated stack area. To be safe in potential stack underflows we leave
728 // some buffer below.
729 registers_[sp] = reinterpret_cast<int32_t>(stack_) + stack_size - 64;
730 // The lr and pc are initialized to a known bad value that will cause an
731 // access violation if the simulator ever tries to execute it.
732 registers_[pc] = bad_lr;
733 registers_[lr] = bad_lr;
734 InitializeCoverage();
735}
736
737
738// When the generated code calls an external reference we need to catch that in
739// the simulator. The external reference will be a function compiled for the
740// host architecture. We need to call that function instead of trying to
741// execute it with the simulator. We do that by redirecting the external
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800742// reference to a svc (Supervisor Call) instruction that is handled by
Steve Blocka7e24c12009-10-30 11:49:00 +0000743// the simulator. We write the original destination of the jump just at a known
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800744// offset from the svc instruction so the simulator knows what to call.
Steve Blocka7e24c12009-10-30 11:49:00 +0000745class Redirection {
746 public:
Steve Block1e0659c2011-05-24 12:43:12 +0100747 Redirection(void* external_function, ExternalReference::Type type)
Steve Blocka7e24c12009-10-30 11:49:00 +0000748 : external_function_(external_function),
Steve Block1e0659c2011-05-24 12:43:12 +0100749 swi_instruction_(al | (0xf*B24) | kCallRtRedirected),
750 type_(type),
Steve Blocka7e24c12009-10-30 11:49:00 +0000751 next_(list_) {
Steve Block6ded16b2010-05-10 14:33:55 +0100752 Simulator::current()->
753 FlushICache(reinterpret_cast<void*>(&swi_instruction_),
Steve Block1e0659c2011-05-24 12:43:12 +0100754 Instruction::kInstrSize);
Steve Blocka7e24c12009-10-30 11:49:00 +0000755 list_ = this;
756 }
757
758 void* address_of_swi_instruction() {
759 return reinterpret_cast<void*>(&swi_instruction_);
760 }
761
762 void* external_function() { return external_function_; }
Steve Block1e0659c2011-05-24 12:43:12 +0100763 ExternalReference::Type type() { return type_; }
Steve Blocka7e24c12009-10-30 11:49:00 +0000764
Steve Block1e0659c2011-05-24 12:43:12 +0100765 static Redirection* Get(void* external_function,
766 ExternalReference::Type type) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000767 Redirection* current;
768 for (current = list_; current != NULL; current = current->next_) {
769 if (current->external_function_ == external_function) return current;
770 }
Steve Block1e0659c2011-05-24 12:43:12 +0100771 return new Redirection(external_function, type);
Steve Blocka7e24c12009-10-30 11:49:00 +0000772 }
773
Steve Block1e0659c2011-05-24 12:43:12 +0100774 static Redirection* FromSwiInstruction(Instruction* swi_instruction) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000775 char* addr_of_swi = reinterpret_cast<char*>(swi_instruction);
776 char* addr_of_redirection =
777 addr_of_swi - OFFSET_OF(Redirection, swi_instruction_);
778 return reinterpret_cast<Redirection*>(addr_of_redirection);
779 }
780
781 private:
782 void* external_function_;
783 uint32_t swi_instruction_;
Steve Block1e0659c2011-05-24 12:43:12 +0100784 ExternalReference::Type type_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000785 Redirection* next_;
786 static Redirection* list_;
787};
788
789
790Redirection* Redirection::list_ = NULL;
791
792
793void* Simulator::RedirectExternalReference(void* external_function,
Steve Block1e0659c2011-05-24 12:43:12 +0100794 ExternalReference::Type type) {
795 Redirection* redirection = Redirection::Get(external_function, type);
Steve Blocka7e24c12009-10-30 11:49:00 +0000796 return redirection->address_of_swi_instruction();
797}
798
799
800// Get the active Simulator for the current thread.
801Simulator* Simulator::current() {
802 Initialize();
803 Simulator* sim = reinterpret_cast<Simulator*>(
804 v8::internal::Thread::GetThreadLocal(simulator_key));
805 if (sim == NULL) {
806 // TODO(146): delete the simulator object when a thread goes away.
807 sim = new Simulator();
808 v8::internal::Thread::SetThreadLocal(simulator_key, sim);
809 }
810 return sim;
811}
812
813
814// Sets the register in the architecture state. It will also deal with updating
815// Simulator internal state for special registers such as PC.
816void Simulator::set_register(int reg, int32_t value) {
817 ASSERT((reg >= 0) && (reg < num_registers));
818 if (reg == pc) {
819 pc_modified_ = true;
820 }
821 registers_[reg] = value;
822}
823
824
825// Get the register from the architecture state. This function does handle
826// the special case of accessing the PC register.
827int32_t Simulator::get_register(int reg) const {
828 ASSERT((reg >= 0) && (reg < num_registers));
Steve Block791712a2010-08-27 10:21:07 +0100829 // Stupid code added to avoid bug in GCC.
830 // See: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43949
831 if (reg >= num_registers) return 0;
832 // End stupid code.
Steve Block1e0659c2011-05-24 12:43:12 +0100833 return registers_[reg] + ((reg == pc) ? Instruction::kPCReadOffset : 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000834}
835
836
Kristian Monsen25f61362010-05-21 11:50:48 +0100837void Simulator::set_dw_register(int dreg, const int* dbl) {
838 ASSERT((dreg >= 0) && (dreg < num_d_registers));
839 registers_[dreg] = dbl[0];
840 registers_[dreg + 1] = dbl[1];
841}
842
843
Steve Blocka7e24c12009-10-30 11:49:00 +0000844// Raw access to the PC register.
845void Simulator::set_pc(int32_t value) {
846 pc_modified_ = true;
847 registers_[pc] = value;
848}
849
850
Ben Murdochb0fe1622011-05-05 13:52:32 +0100851bool Simulator::has_bad_pc() const {
852 return ((registers_[pc] == bad_lr) || (registers_[pc] == end_sim_pc));
853}
854
855
Steve Blocka7e24c12009-10-30 11:49:00 +0000856// Raw access to the PC register without the special adjustment when reading.
857int32_t Simulator::get_pc() const {
858 return registers_[pc];
859}
860
861
Steve Blockd0582a62009-12-15 09:54:21 +0000862// Getting from and setting into VFP registers.
863void Simulator::set_s_register(int sreg, unsigned int value) {
864 ASSERT((sreg >= 0) && (sreg < num_s_registers));
865 vfp_register[sreg] = value;
866}
867
868
869unsigned int Simulator::get_s_register(int sreg) const {
870 ASSERT((sreg >= 0) && (sreg < num_s_registers));
871 return vfp_register[sreg];
872}
873
874
875void Simulator::set_s_register_from_float(int sreg, const float flt) {
876 ASSERT((sreg >= 0) && (sreg < num_s_registers));
877 // Read the bits from the single precision floating point value
878 // into the unsigned integer element of vfp_register[] given by index=sreg.
879 char buffer[sizeof(vfp_register[0])];
880 memcpy(buffer, &flt, sizeof(vfp_register[0]));
881 memcpy(&vfp_register[sreg], buffer, sizeof(vfp_register[0]));
882}
883
884
885void Simulator::set_s_register_from_sinteger(int sreg, const int sint) {
886 ASSERT((sreg >= 0) && (sreg < num_s_registers));
887 // Read the bits from the integer value into the unsigned integer element of
888 // vfp_register[] given by index=sreg.
889 char buffer[sizeof(vfp_register[0])];
890 memcpy(buffer, &sint, sizeof(vfp_register[0]));
891 memcpy(&vfp_register[sreg], buffer, sizeof(vfp_register[0]));
892}
893
894
895void Simulator::set_d_register_from_double(int dreg, const double& dbl) {
896 ASSERT((dreg >= 0) && (dreg < num_d_registers));
897 // Read the bits from the double precision floating point value into the two
898 // consecutive unsigned integer elements of vfp_register[] given by index
899 // 2*sreg and 2*sreg+1.
900 char buffer[2 * sizeof(vfp_register[0])];
901 memcpy(buffer, &dbl, 2 * sizeof(vfp_register[0]));
902#ifndef BIG_ENDIAN_FLOATING_POINT
903 memcpy(&vfp_register[dreg * 2], buffer, 2 * sizeof(vfp_register[0]));
904#else
905 memcpy(&vfp_register[dreg * 2], &buffer[4], sizeof(vfp_register[0]));
906 memcpy(&vfp_register[dreg * 2 + 1], &buffer[0], sizeof(vfp_register[0]));
907#endif
908}
909
910
911float Simulator::get_float_from_s_register(int sreg) {
912 ASSERT((sreg >= 0) && (sreg < num_s_registers));
913
914 float sm_val = 0.0;
915 // Read the bits from the unsigned integer vfp_register[] array
916 // into the single precision floating point value and return it.
917 char buffer[sizeof(vfp_register[0])];
918 memcpy(buffer, &vfp_register[sreg], sizeof(vfp_register[0]));
919 memcpy(&sm_val, buffer, sizeof(vfp_register[0]));
920 return(sm_val);
921}
922
923
924int Simulator::get_sinteger_from_s_register(int sreg) {
925 ASSERT((sreg >= 0) && (sreg < num_s_registers));
926
927 int sm_val = 0;
928 // Read the bits from the unsigned integer vfp_register[] array
929 // into the single precision floating point value and return it.
930 char buffer[sizeof(vfp_register[0])];
931 memcpy(buffer, &vfp_register[sreg], sizeof(vfp_register[0]));
932 memcpy(&sm_val, buffer, sizeof(vfp_register[0]));
933 return(sm_val);
934}
935
936
937double Simulator::get_double_from_d_register(int dreg) {
938 ASSERT((dreg >= 0) && (dreg < num_d_registers));
939
940 double dm_val = 0.0;
941 // Read the bits from the unsigned integer vfp_register[] array
942 // into the double precision floating point value and return it.
943 char buffer[2 * sizeof(vfp_register[0])];
944#ifdef BIG_ENDIAN_FLOATING_POINT
945 memcpy(&buffer[0], &vfp_register[2 * dreg + 1], sizeof(vfp_register[0]));
946 memcpy(&buffer[4], &vfp_register[2 * dreg], sizeof(vfp_register[0]));
947#else
948 memcpy(buffer, &vfp_register[2 * dreg], 2 * sizeof(vfp_register[0]));
949#endif
950 memcpy(&dm_val, buffer, 2 * sizeof(vfp_register[0]));
951 return(dm_val);
952}
953
954
Steve Blocka7e24c12009-10-30 11:49:00 +0000955// For use in calls that take two double values, constructed from r0, r1, r2
956// and r3.
957void Simulator::GetFpArgs(double* x, double* y) {
958 // We use a char buffer to get around the strict-aliasing rules which
959 // otherwise allow the compiler to optimize away the copy.
960 char buffer[2 * sizeof(registers_[0])];
961 // Registers 0 and 1 -> x.
962 memcpy(buffer, registers_, sizeof(buffer));
963 memcpy(x, buffer, sizeof(buffer));
964 // Registers 2 and 3 -> y.
965 memcpy(buffer, registers_ + 2, sizeof(buffer));
966 memcpy(y, buffer, sizeof(buffer));
967}
968
969
970void Simulator::SetFpResult(const double& result) {
971 char buffer[2 * sizeof(registers_[0])];
972 memcpy(buffer, &result, sizeof(buffer));
973 // result -> registers 0 and 1.
974 memcpy(registers_, buffer, sizeof(buffer));
975}
976
977
978void Simulator::TrashCallerSaveRegisters() {
979 // We don't trash the registers with the return value.
980 registers_[2] = 0x50Bad4U;
981 registers_[3] = 0x50Bad4U;
982 registers_[12] = 0x50Bad4U;
983}
984
Kristian Monsen25f61362010-05-21 11:50:48 +0100985// Some Operating Systems allow unaligned access on ARMv7 targets. We
986// assume that unaligned accesses are not allowed unless the v8 build system
987// defines the CAN_USE_UNALIGNED_ACCESSES macro to be non-zero.
988// The following statements below describes the behavior of the ARM CPUs
989// that don't support unaligned access.
990// Some ARM platforms raise an interrupt on detecting unaligned access.
991// On others it does a funky rotation thing. For now we
992// simply disallow unaligned reads. Note that simulator runs have the runtime
Steve Blocka7e24c12009-10-30 11:49:00 +0000993// system running directly on the host system and only generated code is
994// executed in the simulator. Since the host is typically IA32 we will not
Kristian Monsen25f61362010-05-21 11:50:48 +0100995// get the correct ARM-like behaviour on unaligned accesses for those ARM
996// targets that don't support unaligned loads and stores.
997
Steve Blocka7e24c12009-10-30 11:49:00 +0000998
Steve Block1e0659c2011-05-24 12:43:12 +0100999int Simulator::ReadW(int32_t addr, Instruction* instr) {
Kristian Monsen25f61362010-05-21 11:50:48 +01001000#if V8_TARGET_CAN_READ_UNALIGNED
1001 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
1002 return *ptr;
1003#else
Steve Blocka7e24c12009-10-30 11:49:00 +00001004 if ((addr & 3) == 0) {
1005 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
1006 return *ptr;
1007 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001008 PrintF("Unaligned read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1009 addr,
1010 reinterpret_cast<intptr_t>(instr));
Steve Blocka7e24c12009-10-30 11:49:00 +00001011 UNIMPLEMENTED();
1012 return 0;
Kristian Monsen25f61362010-05-21 11:50:48 +01001013#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00001014}
1015
1016
Steve Block1e0659c2011-05-24 12:43:12 +01001017void Simulator::WriteW(int32_t addr, int value, Instruction* instr) {
Kristian Monsen25f61362010-05-21 11:50:48 +01001018#if V8_TARGET_CAN_READ_UNALIGNED
1019 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
1020 *ptr = value;
1021 return;
1022#else
Steve Blocka7e24c12009-10-30 11:49:00 +00001023 if ((addr & 3) == 0) {
1024 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
1025 *ptr = value;
1026 return;
1027 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001028 PrintF("Unaligned write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1029 addr,
1030 reinterpret_cast<intptr_t>(instr));
Steve Blocka7e24c12009-10-30 11:49:00 +00001031 UNIMPLEMENTED();
Kristian Monsen25f61362010-05-21 11:50:48 +01001032#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00001033}
1034
1035
Steve Block1e0659c2011-05-24 12:43:12 +01001036uint16_t Simulator::ReadHU(int32_t addr, Instruction* instr) {
Kristian Monsen25f61362010-05-21 11:50:48 +01001037#if V8_TARGET_CAN_READ_UNALIGNED
1038 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1039 return *ptr;
1040#else
Steve Blocka7e24c12009-10-30 11:49:00 +00001041 if ((addr & 1) == 0) {
1042 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1043 return *ptr;
1044 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001045 PrintF("Unaligned unsigned halfword read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1046 addr,
1047 reinterpret_cast<intptr_t>(instr));
Steve Blocka7e24c12009-10-30 11:49:00 +00001048 UNIMPLEMENTED();
1049 return 0;
Kristian Monsen25f61362010-05-21 11:50:48 +01001050#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00001051}
1052
1053
Steve Block1e0659c2011-05-24 12:43:12 +01001054int16_t Simulator::ReadH(int32_t addr, Instruction* instr) {
Kristian Monsen25f61362010-05-21 11:50:48 +01001055#if V8_TARGET_CAN_READ_UNALIGNED
1056 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
1057 return *ptr;
1058#else
Steve Blocka7e24c12009-10-30 11:49:00 +00001059 if ((addr & 1) == 0) {
1060 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
1061 return *ptr;
1062 }
1063 PrintF("Unaligned signed halfword read at 0x%08x\n", addr);
1064 UNIMPLEMENTED();
1065 return 0;
Kristian Monsen25f61362010-05-21 11:50:48 +01001066#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00001067}
1068
1069
Steve Block1e0659c2011-05-24 12:43:12 +01001070void Simulator::WriteH(int32_t addr, uint16_t value, Instruction* instr) {
Kristian Monsen25f61362010-05-21 11:50:48 +01001071#if V8_TARGET_CAN_READ_UNALIGNED
1072 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1073 *ptr = value;
1074 return;
1075#else
Steve Blocka7e24c12009-10-30 11:49:00 +00001076 if ((addr & 1) == 0) {
1077 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1078 *ptr = value;
1079 return;
1080 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001081 PrintF("Unaligned unsigned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1082 addr,
1083 reinterpret_cast<intptr_t>(instr));
Steve Blocka7e24c12009-10-30 11:49:00 +00001084 UNIMPLEMENTED();
Kristian Monsen25f61362010-05-21 11:50:48 +01001085#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00001086}
1087
1088
Steve Block1e0659c2011-05-24 12:43:12 +01001089void Simulator::WriteH(int32_t addr, int16_t value, Instruction* instr) {
Kristian Monsen25f61362010-05-21 11:50:48 +01001090#if V8_TARGET_CAN_READ_UNALIGNED
1091 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
1092 *ptr = value;
1093 return;
1094#else
Steve Blocka7e24c12009-10-30 11:49:00 +00001095 if ((addr & 1) == 0) {
1096 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
1097 *ptr = value;
1098 return;
1099 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001100 PrintF("Unaligned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1101 addr,
1102 reinterpret_cast<intptr_t>(instr));
Steve Blocka7e24c12009-10-30 11:49:00 +00001103 UNIMPLEMENTED();
Kristian Monsen25f61362010-05-21 11:50:48 +01001104#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00001105}
1106
1107
1108uint8_t Simulator::ReadBU(int32_t addr) {
1109 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1110 return *ptr;
1111}
1112
1113
1114int8_t Simulator::ReadB(int32_t addr) {
1115 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
1116 return *ptr;
1117}
1118
1119
1120void Simulator::WriteB(int32_t addr, uint8_t value) {
1121 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1122 *ptr = value;
1123}
1124
1125
1126void Simulator::WriteB(int32_t addr, int8_t value) {
1127 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
1128 *ptr = value;
1129}
1130
1131
Kristian Monsen25f61362010-05-21 11:50:48 +01001132int32_t* Simulator::ReadDW(int32_t addr) {
1133#if V8_TARGET_CAN_READ_UNALIGNED
1134 int32_t* ptr = reinterpret_cast<int32_t*>(addr);
1135 return ptr;
1136#else
1137 if ((addr & 3) == 0) {
1138 int32_t* ptr = reinterpret_cast<int32_t*>(addr);
1139 return ptr;
1140 }
1141 PrintF("Unaligned read at 0x%08x\n", addr);
1142 UNIMPLEMENTED();
1143 return 0;
1144#endif
1145}
1146
1147
1148void Simulator::WriteDW(int32_t addr, int32_t value1, int32_t value2) {
1149#if V8_TARGET_CAN_READ_UNALIGNED
1150 int32_t* ptr = reinterpret_cast<int32_t*>(addr);
1151 *ptr++ = value1;
1152 *ptr = value2;
1153 return;
1154#else
1155 if ((addr & 3) == 0) {
1156 int32_t* ptr = reinterpret_cast<int32_t*>(addr);
1157 *ptr++ = value1;
1158 *ptr = value2;
1159 return;
1160 }
1161 PrintF("Unaligned write at 0x%08x\n", addr);
1162 UNIMPLEMENTED();
1163#endif
1164}
1165
1166
Steve Blocka7e24c12009-10-30 11:49:00 +00001167// Returns the limit of the stack area to enable checking for stack overflows.
1168uintptr_t Simulator::StackLimit() const {
1169 // Leave a safety margin of 256 bytes to prevent overrunning the stack when
1170 // pushing values.
1171 return reinterpret_cast<uintptr_t>(stack_) + 256;
1172}
1173
1174
1175// Unsupported instructions use Format to print an error and stop execution.
Steve Block1e0659c2011-05-24 12:43:12 +01001176void Simulator::Format(Instruction* instr, const char* format) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001177 PrintF("Simulator found unsupported instruction:\n 0x%08x: %s\n",
Ben Murdochf87a2032010-10-22 12:50:53 +01001178 reinterpret_cast<intptr_t>(instr), format);
Steve Blocka7e24c12009-10-30 11:49:00 +00001179 UNIMPLEMENTED();
1180}
1181
1182
1183// Checks if the current instruction should be executed based on its
1184// condition bits.
Steve Block1e0659c2011-05-24 12:43:12 +01001185bool Simulator::ConditionallyExecute(Instruction* instr) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001186 switch (instr->ConditionField()) {
Steve Block1e0659c2011-05-24 12:43:12 +01001187 case eq: return z_flag_;
1188 case ne: return !z_flag_;
1189 case cs: return c_flag_;
1190 case cc: return !c_flag_;
1191 case mi: return n_flag_;
1192 case pl: return !n_flag_;
1193 case vs: return v_flag_;
1194 case vc: return !v_flag_;
1195 case hi: return c_flag_ && !z_flag_;
1196 case ls: return !c_flag_ || z_flag_;
1197 case ge: return n_flag_ == v_flag_;
1198 case lt: return n_flag_ != v_flag_;
1199 case gt: return !z_flag_ && (n_flag_ == v_flag_);
1200 case le: return z_flag_ || (n_flag_ != v_flag_);
1201 case al: return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00001202 default: UNREACHABLE();
1203 }
1204 return false;
1205}
1206
1207
1208// Calculate and set the Negative and Zero flags.
1209void Simulator::SetNZFlags(int32_t val) {
1210 n_flag_ = (val < 0);
1211 z_flag_ = (val == 0);
1212}
1213
1214
1215// Set the Carry flag.
1216void Simulator::SetCFlag(bool val) {
1217 c_flag_ = val;
1218}
1219
1220
1221// Set the oVerflow flag.
1222void Simulator::SetVFlag(bool val) {
1223 v_flag_ = val;
1224}
1225
1226
1227// Calculate C flag value for additions.
1228bool Simulator::CarryFrom(int32_t left, int32_t right) {
1229 uint32_t uleft = static_cast<uint32_t>(left);
1230 uint32_t uright = static_cast<uint32_t>(right);
1231 uint32_t urest = 0xffffffffU - uleft;
1232
1233 return (uright > urest);
1234}
1235
1236
1237// Calculate C flag value for subtractions.
1238bool Simulator::BorrowFrom(int32_t left, int32_t right) {
1239 uint32_t uleft = static_cast<uint32_t>(left);
1240 uint32_t uright = static_cast<uint32_t>(right);
1241
1242 return (uright > uleft);
1243}
1244
1245
1246// Calculate V flag value for additions and subtractions.
1247bool Simulator::OverflowFrom(int32_t alu_out,
1248 int32_t left, int32_t right, bool addition) {
1249 bool overflow;
1250 if (addition) {
1251 // operands have the same sign
1252 overflow = ((left >= 0 && right >= 0) || (left < 0 && right < 0))
1253 // and operands and result have different sign
1254 && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
1255 } else {
1256 // operands have different signs
1257 overflow = ((left < 0 && right >= 0) || (left >= 0 && right < 0))
1258 // and first operand and result have different signs
1259 && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
1260 }
1261 return overflow;
1262}
1263
1264
Steve Blockd0582a62009-12-15 09:54:21 +00001265// Support for VFP comparisons.
1266void Simulator::Compute_FPSCR_Flags(double val1, double val2) {
Leon Clarkee46be812010-01-19 14:06:41 +00001267 if (isnan(val1) || isnan(val2)) {
1268 n_flag_FPSCR_ = false;
1269 z_flag_FPSCR_ = false;
1270 c_flag_FPSCR_ = true;
1271 v_flag_FPSCR_ = true;
Steve Blockd0582a62009-12-15 09:54:21 +00001272 // All non-NaN cases.
Leon Clarkee46be812010-01-19 14:06:41 +00001273 } else if (val1 == val2) {
Steve Blockd0582a62009-12-15 09:54:21 +00001274 n_flag_FPSCR_ = false;
1275 z_flag_FPSCR_ = true;
1276 c_flag_FPSCR_ = true;
1277 v_flag_FPSCR_ = false;
1278 } else if (val1 < val2) {
1279 n_flag_FPSCR_ = true;
1280 z_flag_FPSCR_ = false;
1281 c_flag_FPSCR_ = false;
1282 v_flag_FPSCR_ = false;
1283 } else {
1284 // Case when (val1 > val2).
1285 n_flag_FPSCR_ = false;
1286 z_flag_FPSCR_ = false;
1287 c_flag_FPSCR_ = true;
1288 v_flag_FPSCR_ = false;
1289 }
1290}
1291
1292
1293void Simulator::Copy_FPSCR_to_APSR() {
1294 n_flag_ = n_flag_FPSCR_;
1295 z_flag_ = z_flag_FPSCR_;
1296 c_flag_ = c_flag_FPSCR_;
1297 v_flag_ = v_flag_FPSCR_;
1298}
1299
1300
Steve Blocka7e24c12009-10-30 11:49:00 +00001301// Addressing Mode 1 - Data-processing operands:
1302// Get the value based on the shifter_operand with register.
Steve Block1e0659c2011-05-24 12:43:12 +01001303int32_t Simulator::GetShiftRm(Instruction* instr, bool* carry_out) {
1304 ShiftOp shift = instr->ShiftField();
1305 int shift_amount = instr->ShiftAmountValue();
1306 int32_t result = get_register(instr->RmValue());
Steve Blocka7e24c12009-10-30 11:49:00 +00001307 if (instr->Bit(4) == 0) {
1308 // by immediate
1309 if ((shift == ROR) && (shift_amount == 0)) {
1310 UNIMPLEMENTED();
1311 return result;
1312 } else if (((shift == LSR) || (shift == ASR)) && (shift_amount == 0)) {
1313 shift_amount = 32;
1314 }
1315 switch (shift) {
1316 case ASR: {
1317 if (shift_amount == 0) {
1318 if (result < 0) {
1319 result = 0xffffffff;
1320 *carry_out = true;
1321 } else {
1322 result = 0;
1323 *carry_out = false;
1324 }
1325 } else {
1326 result >>= (shift_amount - 1);
1327 *carry_out = (result & 1) == 1;
1328 result >>= 1;
1329 }
1330 break;
1331 }
1332
1333 case LSL: {
1334 if (shift_amount == 0) {
1335 *carry_out = c_flag_;
1336 } else {
1337 result <<= (shift_amount - 1);
1338 *carry_out = (result < 0);
1339 result <<= 1;
1340 }
1341 break;
1342 }
1343
1344 case LSR: {
1345 if (shift_amount == 0) {
1346 result = 0;
1347 *carry_out = c_flag_;
1348 } else {
1349 uint32_t uresult = static_cast<uint32_t>(result);
1350 uresult >>= (shift_amount - 1);
1351 *carry_out = (uresult & 1) == 1;
1352 uresult >>= 1;
1353 result = static_cast<int32_t>(uresult);
1354 }
1355 break;
1356 }
1357
1358 case ROR: {
1359 UNIMPLEMENTED();
1360 break;
1361 }
1362
1363 default: {
1364 UNREACHABLE();
1365 break;
1366 }
1367 }
1368 } else {
1369 // by register
Steve Block1e0659c2011-05-24 12:43:12 +01001370 int rs = instr->RsValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00001371 shift_amount = get_register(rs) &0xff;
1372 switch (shift) {
1373 case ASR: {
1374 if (shift_amount == 0) {
1375 *carry_out = c_flag_;
1376 } else if (shift_amount < 32) {
1377 result >>= (shift_amount - 1);
1378 *carry_out = (result & 1) == 1;
1379 result >>= 1;
1380 } else {
1381 ASSERT(shift_amount >= 32);
1382 if (result < 0) {
1383 *carry_out = true;
1384 result = 0xffffffff;
1385 } else {
1386 *carry_out = false;
1387 result = 0;
1388 }
1389 }
1390 break;
1391 }
1392
1393 case LSL: {
1394 if (shift_amount == 0) {
1395 *carry_out = c_flag_;
1396 } else if (shift_amount < 32) {
1397 result <<= (shift_amount - 1);
1398 *carry_out = (result < 0);
1399 result <<= 1;
1400 } else if (shift_amount == 32) {
1401 *carry_out = (result & 1) == 1;
1402 result = 0;
1403 } else {
1404 ASSERT(shift_amount > 32);
1405 *carry_out = false;
1406 result = 0;
1407 }
1408 break;
1409 }
1410
1411 case LSR: {
1412 if (shift_amount == 0) {
1413 *carry_out = c_flag_;
1414 } else if (shift_amount < 32) {
1415 uint32_t uresult = static_cast<uint32_t>(result);
1416 uresult >>= (shift_amount - 1);
1417 *carry_out = (uresult & 1) == 1;
1418 uresult >>= 1;
1419 result = static_cast<int32_t>(uresult);
1420 } else if (shift_amount == 32) {
1421 *carry_out = (result < 0);
1422 result = 0;
1423 } else {
1424 *carry_out = false;
1425 result = 0;
1426 }
1427 break;
1428 }
1429
1430 case ROR: {
1431 UNIMPLEMENTED();
1432 break;
1433 }
1434
1435 default: {
1436 UNREACHABLE();
1437 break;
1438 }
1439 }
1440 }
1441 return result;
1442}
1443
1444
1445// Addressing Mode 1 - Data-processing operands:
1446// Get the value based on the shifter_operand with immediate.
Steve Block1e0659c2011-05-24 12:43:12 +01001447int32_t Simulator::GetImm(Instruction* instr, bool* carry_out) {
1448 int rotate = instr->RotateValue() * 2;
1449 int immed8 = instr->Immed8Value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001450 int imm = (immed8 >> rotate) | (immed8 << (32 - rotate));
1451 *carry_out = (rotate == 0) ? c_flag_ : (imm < 0);
1452 return imm;
1453}
1454
1455
1456static int count_bits(int bit_vector) {
1457 int count = 0;
1458 while (bit_vector != 0) {
1459 if ((bit_vector & 1) != 0) {
1460 count++;
1461 }
1462 bit_vector >>= 1;
1463 }
1464 return count;
1465}
1466
1467
1468// Addressing Mode 4 - Load and Store Multiple
Steve Block1e0659c2011-05-24 12:43:12 +01001469void Simulator::HandleRList(Instruction* instr, bool load) {
1470 int rn = instr->RnValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00001471 int32_t rn_val = get_register(rn);
Steve Block1e0659c2011-05-24 12:43:12 +01001472 int rlist = instr->RlistValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00001473 int num_regs = count_bits(rlist);
1474
1475 intptr_t start_address = 0;
1476 intptr_t end_address = 0;
1477 switch (instr->PUField()) {
Steve Block1e0659c2011-05-24 12:43:12 +01001478 case da_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00001479 UNIMPLEMENTED();
1480 break;
1481 }
Steve Block1e0659c2011-05-24 12:43:12 +01001482 case ia_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00001483 start_address = rn_val;
1484 end_address = rn_val + (num_regs * 4) - 4;
1485 rn_val = rn_val + (num_regs * 4);
1486 break;
1487 }
Steve Block1e0659c2011-05-24 12:43:12 +01001488 case db_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00001489 start_address = rn_val - (num_regs * 4);
1490 end_address = rn_val - 4;
1491 rn_val = start_address;
1492 break;
1493 }
Steve Block1e0659c2011-05-24 12:43:12 +01001494 case ib_x: {
Steve Block791712a2010-08-27 10:21:07 +01001495 start_address = rn_val + 4;
1496 end_address = rn_val + (num_regs * 4);
1497 rn_val = end_address;
Steve Blocka7e24c12009-10-30 11:49:00 +00001498 break;
1499 }
1500 default: {
1501 UNREACHABLE();
1502 break;
1503 }
1504 }
1505 if (instr->HasW()) {
1506 set_register(rn, rn_val);
1507 }
1508 intptr_t* address = reinterpret_cast<intptr_t*>(start_address);
1509 int reg = 0;
1510 while (rlist != 0) {
1511 if ((rlist & 1) != 0) {
1512 if (load) {
1513 set_register(reg, *address);
1514 } else {
1515 *address = get_register(reg);
1516 }
1517 address += 1;
1518 }
1519 reg++;
1520 rlist >>= 1;
1521 }
1522 ASSERT(end_address == ((intptr_t)address) - 4);
1523}
1524
1525
1526// Calls into the V8 runtime are based on this very simple interface.
1527// Note: To be able to return two values from some calls the code in runtime.cc
1528// uses the ObjectPair which is essentially two 32-bit values stuffed into a
1529// 64-bit value. With the code below we assume that all runtime calls return
1530// 64 bits of result. If they don't, the r1 result register contains a bogus
1531// value, which is fine because it is caller-saved.
1532typedef int64_t (*SimulatorRuntimeCall)(int32_t arg0,
1533 int32_t arg1,
1534 int32_t arg2,
Ben Murdochb0fe1622011-05-05 13:52:32 +01001535 int32_t arg3,
1536 int32_t arg4);
Steve Blocka7e24c12009-10-30 11:49:00 +00001537typedef double (*SimulatorRuntimeFPCall)(int32_t arg0,
1538 int32_t arg1,
1539 int32_t arg2,
1540 int32_t arg3);
1541
Steve Block1e0659c2011-05-24 12:43:12 +01001542// This signature supports direct call in to API function native callback
1543// (refer to InvocationCallback in v8.h).
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001544typedef v8::Handle<v8::Value> (*SimulatorRuntimeDirectApiCall)(int32_t arg0);
1545
1546// This signature supports direct call to accessor getter callback.
1547typedef v8::Handle<v8::Value> (*SimulatorRuntimeDirectGetterCall)(int32_t arg0,
1548 int32_t arg1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001549
1550// Software interrupt instructions are used by the simulator to call into the
1551// C-based V8 runtime.
Steve Block1e0659c2011-05-24 12:43:12 +01001552void Simulator::SoftwareInterrupt(Instruction* instr) {
1553 int svc = instr->SvcValue();
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001554 switch (svc) {
Steve Block1e0659c2011-05-24 12:43:12 +01001555 case kCallRtRedirected: {
Steve Block6ded16b2010-05-10 14:33:55 +01001556 // Check if stack is aligned. Error if not aligned is reported below to
1557 // include information on the function called.
1558 bool stack_aligned =
1559 (get_register(sp)
1560 & (::v8::internal::FLAG_sim_stack_alignment - 1)) == 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00001561 Redirection* redirection = Redirection::FromSwiInstruction(instr);
1562 int32_t arg0 = get_register(r0);
1563 int32_t arg1 = get_register(r1);
1564 int32_t arg2 = get_register(r2);
1565 int32_t arg3 = get_register(r3);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001566 int32_t* stack_pointer = reinterpret_cast<int32_t*>(get_register(sp));
1567 int32_t arg4 = *stack_pointer;
Steve Blocka7e24c12009-10-30 11:49:00 +00001568 // This is dodgy but it works because the C entry stubs are never moved.
1569 // See comment in codegen-arm.cc and bug 1242173.
1570 int32_t saved_lr = get_register(lr);
Steve Block1e0659c2011-05-24 12:43:12 +01001571 intptr_t external =
1572 reinterpret_cast<intptr_t>(redirection->external_function());
1573 if (redirection->type() == ExternalReference::FP_RETURN_CALL) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001574 SimulatorRuntimeFPCall target =
1575 reinterpret_cast<SimulatorRuntimeFPCall>(external);
Steve Block6ded16b2010-05-10 14:33:55 +01001576 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001577 double x, y;
1578 GetFpArgs(&x, &y);
Steve Block6ded16b2010-05-10 14:33:55 +01001579 PrintF("Call to host function at %p with args %f, %f",
Steve Blocka7e24c12009-10-30 11:49:00 +00001580 FUNCTION_ADDR(target), x, y);
Steve Block6ded16b2010-05-10 14:33:55 +01001581 if (!stack_aligned) {
1582 PrintF(" with unaligned stack %08x\n", get_register(sp));
1583 }
1584 PrintF("\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00001585 }
Steve Block6ded16b2010-05-10 14:33:55 +01001586 CHECK(stack_aligned);
Steve Blocka7e24c12009-10-30 11:49:00 +00001587 double result = target(arg0, arg1, arg2, arg3);
1588 SetFpResult(result);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001589 } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) {
1590 SimulatorRuntimeDirectApiCall target =
1591 reinterpret_cast<SimulatorRuntimeDirectApiCall>(external);
Steve Block1e0659c2011-05-24 12:43:12 +01001592 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001593 PrintF("Call to host function at %p args %08x",
1594 FUNCTION_ADDR(target), arg0);
Steve Block1e0659c2011-05-24 12:43:12 +01001595 if (!stack_aligned) {
1596 PrintF(" with unaligned stack %08x\n", get_register(sp));
1597 }
1598 PrintF("\n");
1599 }
1600 CHECK(stack_aligned);
1601 v8::Handle<v8::Value> result = target(arg0);
1602 if (::v8::internal::FLAG_trace_sim) {
1603 PrintF("Returned %p\n", reinterpret_cast<void *>(*result));
1604 }
1605 set_register(r0, (int32_t) *result);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001606 } else if (redirection->type() == ExternalReference::DIRECT_GETTER_CALL) {
1607 SimulatorRuntimeDirectGetterCall target =
1608 reinterpret_cast<SimulatorRuntimeDirectGetterCall>(external);
1609 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
1610 PrintF("Call to host function at %p args %08x %08x",
1611 FUNCTION_ADDR(target), arg0, arg1);
1612 if (!stack_aligned) {
1613 PrintF(" with unaligned stack %08x\n", get_register(sp));
1614 }
1615 PrintF("\n");
1616 }
1617 CHECK(stack_aligned);
1618 v8::Handle<v8::Value> result = target(arg0, arg1);
1619 if (::v8::internal::FLAG_trace_sim) {
1620 PrintF("Returned %p\n", reinterpret_cast<void *>(*result));
1621 }
1622 set_register(r0, (int32_t) *result);
Steve Blocka7e24c12009-10-30 11:49:00 +00001623 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01001624 // builtin call.
1625 ASSERT(redirection->type() == ExternalReference::BUILTIN_CALL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001626 SimulatorRuntimeCall target =
1627 reinterpret_cast<SimulatorRuntimeCall>(external);
Steve Block6ded16b2010-05-10 14:33:55 +01001628 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001629 PrintF(
Ben Murdochb0fe1622011-05-05 13:52:32 +01001630 "Call to host function at %p args %08x, %08x, %08x, %08x, %0xc",
Steve Blocka7e24c12009-10-30 11:49:00 +00001631 FUNCTION_ADDR(target),
1632 arg0,
1633 arg1,
1634 arg2,
Ben Murdochb0fe1622011-05-05 13:52:32 +01001635 arg3,
1636 arg4);
Steve Block6ded16b2010-05-10 14:33:55 +01001637 if (!stack_aligned) {
1638 PrintF(" with unaligned stack %08x\n", get_register(sp));
1639 }
1640 PrintF("\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00001641 }
Steve Block6ded16b2010-05-10 14:33:55 +01001642 CHECK(stack_aligned);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001643 int64_t result = target(arg0, arg1, arg2, arg3, arg4);
Steve Blocka7e24c12009-10-30 11:49:00 +00001644 int32_t lo_res = static_cast<int32_t>(result);
1645 int32_t hi_res = static_cast<int32_t>(result >> 32);
1646 if (::v8::internal::FLAG_trace_sim) {
1647 PrintF("Returned %08x\n", lo_res);
1648 }
1649 set_register(r0, lo_res);
1650 set_register(r1, hi_res);
1651 }
1652 set_register(lr, saved_lr);
1653 set_pc(get_register(lr));
1654 break;
1655 }
Steve Block1e0659c2011-05-24 12:43:12 +01001656 case kBreakpoint: {
Steve Blocka7e24c12009-10-30 11:49:00 +00001657 Debugger dbg(this);
1658 dbg.Debug();
1659 break;
1660 }
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001661 // stop uses all codes greater than 1 << 23.
Steve Blocka7e24c12009-10-30 11:49:00 +00001662 default: {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001663 if (svc >= (1 << 23)) {
1664 uint32_t code = svc & kStopCodeMask;
1665 if (isWatchedStop(code)) {
1666 IncreaseStopCounter(code);
1667 }
1668 // Stop if it is enabled, otherwise go on jumping over the stop
1669 // and the message address.
1670 if (isEnabledStop(code)) {
1671 Debugger dbg(this);
1672 dbg.Stop(instr);
1673 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01001674 set_pc(get_pc() + 2 * Instruction::kInstrSize);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001675 }
1676 } else {
1677 // This is not a valid svc code.
1678 UNREACHABLE();
1679 break;
1680 }
1681 }
1682 }
1683}
1684
1685
1686// Stop helper functions.
Steve Block1e0659c2011-05-24 12:43:12 +01001687bool Simulator::isStopInstruction(Instruction* instr) {
1688 return (instr->Bits(27, 24) == 0xF) && (instr->SvcValue() >= kStopCode);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001689}
1690
1691
1692bool Simulator::isWatchedStop(uint32_t code) {
1693 ASSERT(code <= kMaxStopCode);
1694 return code < kNumOfWatchedStops;
1695}
1696
1697
1698bool Simulator::isEnabledStop(uint32_t code) {
1699 ASSERT(code <= kMaxStopCode);
1700 // Unwatched stops are always enabled.
1701 return !isWatchedStop(code) ||
1702 !(watched_stops[code].count & kStopDisabledBit);
1703}
1704
1705
1706void Simulator::EnableStop(uint32_t code) {
1707 ASSERT(isWatchedStop(code));
1708 if (!isEnabledStop(code)) {
1709 watched_stops[code].count &= ~kStopDisabledBit;
1710 }
1711}
1712
1713
1714void Simulator::DisableStop(uint32_t code) {
1715 ASSERT(isWatchedStop(code));
1716 if (isEnabledStop(code)) {
1717 watched_stops[code].count |= kStopDisabledBit;
1718 }
1719}
1720
1721
1722void Simulator::IncreaseStopCounter(uint32_t code) {
1723 ASSERT(code <= kMaxStopCode);
1724 ASSERT(isWatchedStop(code));
1725 if ((watched_stops[code].count & ~(1 << 31)) == 0x7fffffff) {
1726 PrintF("Stop counter for code %i has overflowed.\n"
1727 "Enabling this code and reseting the counter to 0.\n", code);
1728 watched_stops[code].count = 0;
1729 EnableStop(code);
1730 } else {
1731 watched_stops[code].count++;
1732 }
1733}
1734
1735
1736// Print a stop status.
1737void Simulator::PrintStopInfo(uint32_t code) {
1738 ASSERT(code <= kMaxStopCode);
1739 if (!isWatchedStop(code)) {
1740 PrintF("Stop not watched.");
1741 } else {
1742 const char* state = isEnabledStop(code) ? "Enabled" : "Disabled";
1743 int32_t count = watched_stops[code].count & ~kStopDisabledBit;
1744 // Don't print the state of unused breakpoints.
1745 if (count != 0) {
1746 if (watched_stops[code].desc) {
1747 PrintF("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n",
1748 code, code, state, count, watched_stops[code].desc);
1749 } else {
1750 PrintF("stop %i - 0x%x: \t%s, \tcounter = %i\n",
1751 code, code, state, count);
1752 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001753 }
1754 }
1755}
1756
1757
1758// Handle execution based on instruction types.
1759
1760// Instruction types 0 and 1 are both rolled into one function because they
1761// only differ in the handling of the shifter_operand.
Steve Block1e0659c2011-05-24 12:43:12 +01001762void Simulator::DecodeType01(Instruction* instr) {
1763 int type = instr->TypeValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00001764 if ((type == 0) && instr->IsSpecialType0()) {
1765 // multiply instruction or extra loads and stores
1766 if (instr->Bits(7, 4) == 9) {
1767 if (instr->Bit(24) == 0) {
1768 // Raw field decoding here. Multiply instructions have their Rd in
1769 // funny places.
Steve Block1e0659c2011-05-24 12:43:12 +01001770 int rn = instr->RnValue();
1771 int rm = instr->RmValue();
1772 int rs = instr->RsValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00001773 int32_t rs_val = get_register(rs);
1774 int32_t rm_val = get_register(rm);
1775 if (instr->Bit(23) == 0) {
1776 if (instr->Bit(21) == 0) {
1777 // The MUL instruction description (A 4.1.33) refers to Rd as being
1778 // the destination for the operation, but it confusingly uses the
1779 // Rn field to encode it.
1780 // Format(instr, "mul'cond's 'rn, 'rm, 'rs");
1781 int rd = rn; // Remap the rn field to the Rd register.
1782 int32_t alu_out = rm_val * rs_val;
1783 set_register(rd, alu_out);
1784 if (instr->HasS()) {
1785 SetNZFlags(alu_out);
1786 }
1787 } else {
1788 // The MLA instruction description (A 4.1.28) refers to the order
1789 // of registers as "Rd, Rm, Rs, Rn". But confusingly it uses the
1790 // Rn field to encode the Rd register and the Rd field to encode
1791 // the Rn register.
1792 Format(instr, "mla'cond's 'rn, 'rm, 'rs, 'rd");
1793 }
1794 } else {
1795 // The signed/long multiply instructions use the terms RdHi and RdLo
1796 // when referring to the target registers. They are mapped to the Rn
1797 // and Rd fields as follows:
1798 // RdLo == Rd
1799 // RdHi == Rn (This is confusingly stored in variable rd here
1800 // because the mul instruction from above uses the
1801 // Rn field to encode the Rd register. Good luck figuring
1802 // this out without reading the ARM instruction manual
1803 // at a very detailed level.)
1804 // Format(instr, "'um'al'cond's 'rd, 'rn, 'rs, 'rm");
1805 int rd_hi = rn; // Remap the rn field to the RdHi register.
Steve Block1e0659c2011-05-24 12:43:12 +01001806 int rd_lo = instr->RdValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00001807 int32_t hi_res = 0;
1808 int32_t lo_res = 0;
1809 if (instr->Bit(22) == 1) {
1810 int64_t left_op = static_cast<int32_t>(rm_val);
1811 int64_t right_op = static_cast<int32_t>(rs_val);
1812 uint64_t result = left_op * right_op;
1813 hi_res = static_cast<int32_t>(result >> 32);
1814 lo_res = static_cast<int32_t>(result & 0xffffffff);
1815 } else {
1816 // unsigned multiply
1817 uint64_t left_op = static_cast<uint32_t>(rm_val);
1818 uint64_t right_op = static_cast<uint32_t>(rs_val);
1819 uint64_t result = left_op * right_op;
1820 hi_res = static_cast<int32_t>(result >> 32);
1821 lo_res = static_cast<int32_t>(result & 0xffffffff);
1822 }
1823 set_register(rd_lo, lo_res);
1824 set_register(rd_hi, hi_res);
1825 if (instr->HasS()) {
1826 UNIMPLEMENTED();
1827 }
1828 }
1829 } else {
Steve Blockd0582a62009-12-15 09:54:21 +00001830 UNIMPLEMENTED(); // Not used by V8.
Steve Blocka7e24c12009-10-30 11:49:00 +00001831 }
1832 } else {
1833 // extra load/store instructions
Steve Block1e0659c2011-05-24 12:43:12 +01001834 int rd = instr->RdValue();
1835 int rn = instr->RnValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00001836 int32_t rn_val = get_register(rn);
1837 int32_t addr = 0;
1838 if (instr->Bit(22) == 0) {
Steve Block1e0659c2011-05-24 12:43:12 +01001839 int rm = instr->RmValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00001840 int32_t rm_val = get_register(rm);
1841 switch (instr->PUField()) {
Steve Block1e0659c2011-05-24 12:43:12 +01001842 case da_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00001843 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], -'rm");
1844 ASSERT(!instr->HasW());
1845 addr = rn_val;
1846 rn_val -= rm_val;
1847 set_register(rn, rn_val);
1848 break;
1849 }
Steve Block1e0659c2011-05-24 12:43:12 +01001850 case ia_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00001851 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], +'rm");
1852 ASSERT(!instr->HasW());
1853 addr = rn_val;
1854 rn_val += rm_val;
1855 set_register(rn, rn_val);
1856 break;
1857 }
Steve Block1e0659c2011-05-24 12:43:12 +01001858 case db_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00001859 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, -'rm]'w");
1860 rn_val -= rm_val;
1861 addr = rn_val;
1862 if (instr->HasW()) {
1863 set_register(rn, rn_val);
1864 }
1865 break;
1866 }
Steve Block1e0659c2011-05-24 12:43:12 +01001867 case ib_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00001868 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, +'rm]'w");
1869 rn_val += rm_val;
1870 addr = rn_val;
1871 if (instr->HasW()) {
1872 set_register(rn, rn_val);
1873 }
1874 break;
1875 }
1876 default: {
1877 // The PU field is a 2-bit field.
1878 UNREACHABLE();
1879 break;
1880 }
1881 }
1882 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01001883 int32_t imm_val = (instr->ImmedHValue() << 4) | instr->ImmedLValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00001884 switch (instr->PUField()) {
Steve Block1e0659c2011-05-24 12:43:12 +01001885 case da_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00001886 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], #-'off8");
1887 ASSERT(!instr->HasW());
1888 addr = rn_val;
1889 rn_val -= imm_val;
1890 set_register(rn, rn_val);
1891 break;
1892 }
Steve Block1e0659c2011-05-24 12:43:12 +01001893 case ia_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00001894 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], #+'off8");
1895 ASSERT(!instr->HasW());
1896 addr = rn_val;
1897 rn_val += imm_val;
1898 set_register(rn, rn_val);
1899 break;
1900 }
Steve Block1e0659c2011-05-24 12:43:12 +01001901 case db_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00001902 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, #-'off8]'w");
1903 rn_val -= imm_val;
1904 addr = rn_val;
1905 if (instr->HasW()) {
1906 set_register(rn, rn_val);
1907 }
1908 break;
1909 }
Steve Block1e0659c2011-05-24 12:43:12 +01001910 case ib_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00001911 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, #+'off8]'w");
1912 rn_val += imm_val;
1913 addr = rn_val;
1914 if (instr->HasW()) {
1915 set_register(rn, rn_val);
1916 }
1917 break;
1918 }
1919 default: {
1920 // The PU field is a 2-bit field.
1921 UNREACHABLE();
1922 break;
1923 }
1924 }
1925 }
Kristian Monsen25f61362010-05-21 11:50:48 +01001926 if (((instr->Bits(7, 4) & 0xd) == 0xd) && (instr->Bit(20) == 0)) {
1927 ASSERT((rd % 2) == 0);
1928 if (instr->HasH()) {
1929 // The strd instruction.
1930 int32_t value1 = get_register(rd);
1931 int32_t value2 = get_register(rd+1);
1932 WriteDW(addr, value1, value2);
1933 } else {
1934 // The ldrd instruction.
1935 int* rn_data = ReadDW(addr);
1936 set_dw_register(rd, rn_data);
1937 }
1938 } else if (instr->HasH()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001939 if (instr->HasSign()) {
1940 if (instr->HasL()) {
1941 int16_t val = ReadH(addr, instr);
1942 set_register(rd, val);
1943 } else {
1944 int16_t val = get_register(rd);
1945 WriteH(addr, val, instr);
1946 }
1947 } else {
1948 if (instr->HasL()) {
1949 uint16_t val = ReadHU(addr, instr);
1950 set_register(rd, val);
1951 } else {
1952 uint16_t val = get_register(rd);
1953 WriteH(addr, val, instr);
1954 }
1955 }
1956 } else {
1957 // signed byte loads
1958 ASSERT(instr->HasSign());
1959 ASSERT(instr->HasL());
1960 int8_t val = ReadB(addr);
1961 set_register(rd, val);
1962 }
1963 return;
1964 }
Steve Block6ded16b2010-05-10 14:33:55 +01001965 } else if ((type == 0) && instr->IsMiscType0()) {
1966 if (instr->Bits(22, 21) == 1) {
Steve Block1e0659c2011-05-24 12:43:12 +01001967 int rm = instr->RmValue();
1968 switch (instr->BitField(7, 4)) {
Steve Block6ded16b2010-05-10 14:33:55 +01001969 case BX:
1970 set_pc(get_register(rm));
1971 break;
1972 case BLX: {
1973 uint32_t old_pc = get_pc();
1974 set_pc(get_register(rm));
Steve Block1e0659c2011-05-24 12:43:12 +01001975 set_register(lr, old_pc + Instruction::kInstrSize);
Steve Block6ded16b2010-05-10 14:33:55 +01001976 break;
1977 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001978 case BKPT: {
1979 Debugger dbg(this);
1980 PrintF("Simulator hit BKPT.\n");
1981 dbg.Debug();
Steve Block6ded16b2010-05-10 14:33:55 +01001982 break;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001983 }
Steve Block6ded16b2010-05-10 14:33:55 +01001984 default:
1985 UNIMPLEMENTED();
1986 }
1987 } else if (instr->Bits(22, 21) == 3) {
Steve Block1e0659c2011-05-24 12:43:12 +01001988 int rm = instr->RmValue();
1989 int rd = instr->RdValue();
1990 switch (instr->BitField(7, 4)) {
Steve Block6ded16b2010-05-10 14:33:55 +01001991 case CLZ: {
1992 uint32_t bits = get_register(rm);
1993 int leading_zeros = 0;
1994 if (bits == 0) {
1995 leading_zeros = 32;
1996 } else {
1997 while ((bits & 0x80000000u) == 0) {
1998 bits <<= 1;
1999 leading_zeros++;
2000 }
2001 }
2002 set_register(rd, leading_zeros);
2003 break;
2004 }
2005 default:
2006 UNIMPLEMENTED();
2007 }
2008 } else {
2009 PrintF("%08x\n", instr->InstructionBits());
2010 UNIMPLEMENTED();
2011 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002012 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01002013 int rd = instr->RdValue();
2014 int rn = instr->RnValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00002015 int32_t rn_val = get_register(rn);
2016 int32_t shifter_operand = 0;
2017 bool shifter_carry_out = 0;
2018 if (type == 0) {
2019 shifter_operand = GetShiftRm(instr, &shifter_carry_out);
2020 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01002021 ASSERT(instr->TypeValue() == 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00002022 shifter_operand = GetImm(instr, &shifter_carry_out);
2023 }
2024 int32_t alu_out;
2025
2026 switch (instr->OpcodeField()) {
2027 case AND: {
2028 // Format(instr, "and'cond's 'rd, 'rn, 'shift_rm");
2029 // Format(instr, "and'cond's 'rd, 'rn, 'imm");
2030 alu_out = rn_val & shifter_operand;
2031 set_register(rd, alu_out);
2032 if (instr->HasS()) {
2033 SetNZFlags(alu_out);
2034 SetCFlag(shifter_carry_out);
2035 }
2036 break;
2037 }
2038
2039 case EOR: {
2040 // Format(instr, "eor'cond's 'rd, 'rn, 'shift_rm");
2041 // Format(instr, "eor'cond's 'rd, 'rn, 'imm");
2042 alu_out = rn_val ^ shifter_operand;
2043 set_register(rd, alu_out);
2044 if (instr->HasS()) {
2045 SetNZFlags(alu_out);
2046 SetCFlag(shifter_carry_out);
2047 }
2048 break;
2049 }
2050
2051 case SUB: {
2052 // Format(instr, "sub'cond's 'rd, 'rn, 'shift_rm");
2053 // Format(instr, "sub'cond's 'rd, 'rn, 'imm");
2054 alu_out = rn_val - shifter_operand;
2055 set_register(rd, alu_out);
2056 if (instr->HasS()) {
2057 SetNZFlags(alu_out);
2058 SetCFlag(!BorrowFrom(rn_val, shifter_operand));
2059 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, false));
2060 }
2061 break;
2062 }
2063
2064 case RSB: {
2065 // Format(instr, "rsb'cond's 'rd, 'rn, 'shift_rm");
2066 // Format(instr, "rsb'cond's 'rd, 'rn, 'imm");
2067 alu_out = shifter_operand - rn_val;
2068 set_register(rd, alu_out);
2069 if (instr->HasS()) {
2070 SetNZFlags(alu_out);
2071 SetCFlag(!BorrowFrom(shifter_operand, rn_val));
2072 SetVFlag(OverflowFrom(alu_out, shifter_operand, rn_val, false));
2073 }
2074 break;
2075 }
2076
2077 case ADD: {
2078 // Format(instr, "add'cond's 'rd, 'rn, 'shift_rm");
2079 // Format(instr, "add'cond's 'rd, 'rn, 'imm");
2080 alu_out = rn_val + shifter_operand;
2081 set_register(rd, alu_out);
2082 if (instr->HasS()) {
2083 SetNZFlags(alu_out);
2084 SetCFlag(CarryFrom(rn_val, shifter_operand));
2085 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, true));
2086 }
2087 break;
2088 }
2089
2090 case ADC: {
2091 Format(instr, "adc'cond's 'rd, 'rn, 'shift_rm");
2092 Format(instr, "adc'cond's 'rd, 'rn, 'imm");
2093 break;
2094 }
2095
2096 case SBC: {
2097 Format(instr, "sbc'cond's 'rd, 'rn, 'shift_rm");
2098 Format(instr, "sbc'cond's 'rd, 'rn, 'imm");
2099 break;
2100 }
2101
2102 case RSC: {
2103 Format(instr, "rsc'cond's 'rd, 'rn, 'shift_rm");
2104 Format(instr, "rsc'cond's 'rd, 'rn, 'imm");
2105 break;
2106 }
2107
2108 case TST: {
2109 if (instr->HasS()) {
2110 // Format(instr, "tst'cond 'rn, 'shift_rm");
2111 // Format(instr, "tst'cond 'rn, 'imm");
2112 alu_out = rn_val & shifter_operand;
2113 SetNZFlags(alu_out);
2114 SetCFlag(shifter_carry_out);
2115 } else {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002116 // Format(instr, "movw'cond 'rd, 'imm").
Steve Block1e0659c2011-05-24 12:43:12 +01002117 alu_out = instr->ImmedMovwMovtValue();
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002118 set_register(rd, alu_out);
Steve Blocka7e24c12009-10-30 11:49:00 +00002119 }
2120 break;
2121 }
2122
2123 case TEQ: {
2124 if (instr->HasS()) {
2125 // Format(instr, "teq'cond 'rn, 'shift_rm");
2126 // Format(instr, "teq'cond 'rn, 'imm");
2127 alu_out = rn_val ^ shifter_operand;
2128 SetNZFlags(alu_out);
2129 SetCFlag(shifter_carry_out);
2130 } else {
Steve Block6ded16b2010-05-10 14:33:55 +01002131 // Other instructions matching this pattern are handled in the
2132 // miscellaneous instructions part above.
2133 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +00002134 }
2135 break;
2136 }
2137
2138 case CMP: {
2139 if (instr->HasS()) {
2140 // Format(instr, "cmp'cond 'rn, 'shift_rm");
2141 // Format(instr, "cmp'cond 'rn, 'imm");
2142 alu_out = rn_val - shifter_operand;
2143 SetNZFlags(alu_out);
2144 SetCFlag(!BorrowFrom(rn_val, shifter_operand));
2145 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, false));
2146 } else {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002147 // Format(instr, "movt'cond 'rd, 'imm").
2148 alu_out = (get_register(rd) & 0xffff) |
Steve Block1e0659c2011-05-24 12:43:12 +01002149 (instr->ImmedMovwMovtValue() << 16);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002150 set_register(rd, alu_out);
Steve Blocka7e24c12009-10-30 11:49:00 +00002151 }
2152 break;
2153 }
2154
2155 case CMN: {
2156 if (instr->HasS()) {
2157 // Format(instr, "cmn'cond 'rn, 'shift_rm");
2158 // Format(instr, "cmn'cond 'rn, 'imm");
2159 alu_out = rn_val + shifter_operand;
2160 SetNZFlags(alu_out);
2161 SetCFlag(!CarryFrom(rn_val, shifter_operand));
2162 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, true));
2163 } else {
Steve Block6ded16b2010-05-10 14:33:55 +01002164 // Other instructions matching this pattern are handled in the
2165 // miscellaneous instructions part above.
2166 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +00002167 }
2168 break;
2169 }
2170
2171 case ORR: {
2172 // Format(instr, "orr'cond's 'rd, 'rn, 'shift_rm");
2173 // Format(instr, "orr'cond's 'rd, 'rn, 'imm");
2174 alu_out = rn_val | shifter_operand;
2175 set_register(rd, alu_out);
2176 if (instr->HasS()) {
2177 SetNZFlags(alu_out);
2178 SetCFlag(shifter_carry_out);
2179 }
2180 break;
2181 }
2182
2183 case MOV: {
2184 // Format(instr, "mov'cond's 'rd, 'shift_rm");
2185 // Format(instr, "mov'cond's 'rd, 'imm");
2186 alu_out = shifter_operand;
2187 set_register(rd, alu_out);
2188 if (instr->HasS()) {
2189 SetNZFlags(alu_out);
2190 SetCFlag(shifter_carry_out);
2191 }
2192 break;
2193 }
2194
2195 case BIC: {
2196 // Format(instr, "bic'cond's 'rd, 'rn, 'shift_rm");
2197 // Format(instr, "bic'cond's 'rd, 'rn, 'imm");
2198 alu_out = rn_val & ~shifter_operand;
2199 set_register(rd, alu_out);
2200 if (instr->HasS()) {
2201 SetNZFlags(alu_out);
2202 SetCFlag(shifter_carry_out);
2203 }
2204 break;
2205 }
2206
2207 case MVN: {
2208 // Format(instr, "mvn'cond's 'rd, 'shift_rm");
2209 // Format(instr, "mvn'cond's 'rd, 'imm");
2210 alu_out = ~shifter_operand;
2211 set_register(rd, alu_out);
2212 if (instr->HasS()) {
2213 SetNZFlags(alu_out);
2214 SetCFlag(shifter_carry_out);
2215 }
2216 break;
2217 }
2218
2219 default: {
2220 UNREACHABLE();
2221 break;
2222 }
2223 }
2224 }
2225}
2226
2227
Steve Block1e0659c2011-05-24 12:43:12 +01002228void Simulator::DecodeType2(Instruction* instr) {
2229 int rd = instr->RdValue();
2230 int rn = instr->RnValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00002231 int32_t rn_val = get_register(rn);
Steve Block1e0659c2011-05-24 12:43:12 +01002232 int32_t im_val = instr->Offset12Value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002233 int32_t addr = 0;
2234 switch (instr->PUField()) {
Steve Block1e0659c2011-05-24 12:43:12 +01002235 case da_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002236 // Format(instr, "'memop'cond'b 'rd, ['rn], #-'off12");
2237 ASSERT(!instr->HasW());
2238 addr = rn_val;
2239 rn_val -= im_val;
2240 set_register(rn, rn_val);
2241 break;
2242 }
Steve Block1e0659c2011-05-24 12:43:12 +01002243 case ia_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002244 // Format(instr, "'memop'cond'b 'rd, ['rn], #+'off12");
2245 ASSERT(!instr->HasW());
2246 addr = rn_val;
2247 rn_val += im_val;
2248 set_register(rn, rn_val);
2249 break;
2250 }
Steve Block1e0659c2011-05-24 12:43:12 +01002251 case db_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002252 // Format(instr, "'memop'cond'b 'rd, ['rn, #-'off12]'w");
2253 rn_val -= im_val;
2254 addr = rn_val;
2255 if (instr->HasW()) {
2256 set_register(rn, rn_val);
2257 }
2258 break;
2259 }
Steve Block1e0659c2011-05-24 12:43:12 +01002260 case ib_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002261 // Format(instr, "'memop'cond'b 'rd, ['rn, #+'off12]'w");
2262 rn_val += im_val;
2263 addr = rn_val;
2264 if (instr->HasW()) {
2265 set_register(rn, rn_val);
2266 }
2267 break;
2268 }
2269 default: {
2270 UNREACHABLE();
2271 break;
2272 }
2273 }
2274 if (instr->HasB()) {
2275 if (instr->HasL()) {
2276 byte val = ReadBU(addr);
2277 set_register(rd, val);
2278 } else {
2279 byte val = get_register(rd);
2280 WriteB(addr, val);
2281 }
2282 } else {
2283 if (instr->HasL()) {
2284 set_register(rd, ReadW(addr, instr));
2285 } else {
2286 WriteW(addr, get_register(rd), instr);
2287 }
2288 }
2289}
2290
2291
Steve Block1e0659c2011-05-24 12:43:12 +01002292void Simulator::DecodeType3(Instruction* instr) {
2293 int rd = instr->RdValue();
2294 int rn = instr->RnValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00002295 int32_t rn_val = get_register(rn);
2296 bool shifter_carry_out = 0;
2297 int32_t shifter_operand = GetShiftRm(instr, &shifter_carry_out);
2298 int32_t addr = 0;
2299 switch (instr->PUField()) {
Steve Block1e0659c2011-05-24 12:43:12 +01002300 case da_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002301 ASSERT(!instr->HasW());
2302 Format(instr, "'memop'cond'b 'rd, ['rn], -'shift_rm");
Kristian Monsen50ef84f2010-07-29 15:18:00 +01002303 UNIMPLEMENTED();
Steve Blocka7e24c12009-10-30 11:49:00 +00002304 break;
2305 }
Steve Block1e0659c2011-05-24 12:43:12 +01002306 case ia_x: {
Kristian Monsen50ef84f2010-07-29 15:18:00 +01002307 if (instr->HasW()) {
2308 ASSERT(instr->Bits(5, 4) == 0x1);
2309
2310 if (instr->Bit(22) == 0x1) { // USAT.
2311 int32_t sat_pos = instr->Bits(20, 16);
2312 int32_t sat_val = (1 << sat_pos) - 1;
2313 int32_t shift = instr->Bits(11, 7);
2314 int32_t shift_type = instr->Bit(6);
Steve Block1e0659c2011-05-24 12:43:12 +01002315 int32_t rm_val = get_register(instr->RmValue());
Kristian Monsen50ef84f2010-07-29 15:18:00 +01002316 if (shift_type == 0) { // LSL
2317 rm_val <<= shift;
2318 } else { // ASR
2319 rm_val >>= shift;
2320 }
2321 // If saturation occurs, the Q flag should be set in the CPSR.
2322 // There is no Q flag yet, and no instruction (MRS) to read the
2323 // CPSR directly.
2324 if (rm_val > sat_val) {
2325 rm_val = sat_val;
2326 } else if (rm_val < 0) {
2327 rm_val = 0;
2328 }
2329 set_register(rd, rm_val);
2330 } else { // SSAT.
2331 UNIMPLEMENTED();
2332 }
2333 return;
2334 } else {
2335 Format(instr, "'memop'cond'b 'rd, ['rn], +'shift_rm");
2336 UNIMPLEMENTED();
2337 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002338 break;
2339 }
Steve Block1e0659c2011-05-24 12:43:12 +01002340 case db_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002341 // Format(instr, "'memop'cond'b 'rd, ['rn, -'shift_rm]'w");
2342 addr = rn_val - shifter_operand;
2343 if (instr->HasW()) {
2344 set_register(rn, addr);
2345 }
2346 break;
2347 }
Steve Block1e0659c2011-05-24 12:43:12 +01002348 case ib_x: {
Andrei Popescu31002712010-02-23 13:46:05 +00002349 if (instr->HasW() && (instr->Bits(6, 4) == 0x5)) {
2350 uint32_t widthminus1 = static_cast<uint32_t>(instr->Bits(20, 16));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002351 uint32_t lsbit = static_cast<uint32_t>(instr->Bits(11, 7));
Andrei Popescu31002712010-02-23 13:46:05 +00002352 uint32_t msbit = widthminus1 + lsbit;
2353 if (msbit <= 31) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002354 if (instr->Bit(22)) {
2355 // ubfx - unsigned bitfield extract.
2356 uint32_t rm_val =
Steve Block1e0659c2011-05-24 12:43:12 +01002357 static_cast<uint32_t>(get_register(instr->RmValue()));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002358 uint32_t extr_val = rm_val << (31 - msbit);
2359 extr_val = extr_val >> (31 - widthminus1);
Steve Block1e0659c2011-05-24 12:43:12 +01002360 set_register(instr->RdValue(), extr_val);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002361 } else {
2362 // sbfx - signed bitfield extract.
Steve Block1e0659c2011-05-24 12:43:12 +01002363 int32_t rm_val = get_register(instr->RmValue());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002364 int32_t extr_val = rm_val << (31 - msbit);
2365 extr_val = extr_val >> (31 - widthminus1);
Steve Block1e0659c2011-05-24 12:43:12 +01002366 set_register(instr->RdValue(), extr_val);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002367 }
2368 } else {
2369 UNREACHABLE();
2370 }
2371 return;
2372 } else if (!instr->HasW() && (instr->Bits(6, 4) == 0x1)) {
2373 uint32_t lsbit = static_cast<uint32_t>(instr->Bits(11, 7));
2374 uint32_t msbit = static_cast<uint32_t>(instr->Bits(20, 16));
2375 if (msbit >= lsbit) {
2376 // bfc or bfi - bitfield clear/insert.
2377 uint32_t rd_val =
Steve Block1e0659c2011-05-24 12:43:12 +01002378 static_cast<uint32_t>(get_register(instr->RdValue()));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002379 uint32_t bitcount = msbit - lsbit + 1;
2380 uint32_t mask = (1 << bitcount) - 1;
2381 rd_val &= ~(mask << lsbit);
Steve Block1e0659c2011-05-24 12:43:12 +01002382 if (instr->RmValue() != 15) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002383 // bfi - bitfield insert.
2384 uint32_t rm_val =
Steve Block1e0659c2011-05-24 12:43:12 +01002385 static_cast<uint32_t>(get_register(instr->RmValue()));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002386 rm_val &= mask;
2387 rd_val |= rm_val << lsbit;
2388 }
Steve Block1e0659c2011-05-24 12:43:12 +01002389 set_register(instr->RdValue(), rd_val);
Andrei Popescu31002712010-02-23 13:46:05 +00002390 } else {
2391 UNREACHABLE();
2392 }
2393 return;
2394 } else {
2395 // Format(instr, "'memop'cond'b 'rd, ['rn, +'shift_rm]'w");
2396 addr = rn_val + shifter_operand;
2397 if (instr->HasW()) {
2398 set_register(rn, addr);
2399 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002400 }
2401 break;
2402 }
2403 default: {
2404 UNREACHABLE();
2405 break;
2406 }
2407 }
2408 if (instr->HasB()) {
2409 if (instr->HasL()) {
2410 uint8_t byte = ReadB(addr);
2411 set_register(rd, byte);
2412 } else {
Andrei Popescu31002712010-02-23 13:46:05 +00002413 uint8_t byte = get_register(rd);
2414 WriteB(addr, byte);
Steve Blocka7e24c12009-10-30 11:49:00 +00002415 }
2416 } else {
2417 if (instr->HasL()) {
2418 set_register(rd, ReadW(addr, instr));
2419 } else {
2420 WriteW(addr, get_register(rd), instr);
2421 }
2422 }
2423}
2424
2425
Steve Block1e0659c2011-05-24 12:43:12 +01002426void Simulator::DecodeType4(Instruction* instr) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002427 ASSERT(instr->Bit(22) == 0); // only allowed to be set in privileged mode
2428 if (instr->HasL()) {
2429 // Format(instr, "ldm'cond'pu 'rn'w, 'rlist");
2430 HandleRList(instr, true);
2431 } else {
2432 // Format(instr, "stm'cond'pu 'rn'w, 'rlist");
2433 HandleRList(instr, false);
2434 }
2435}
2436
2437
Steve Block1e0659c2011-05-24 12:43:12 +01002438void Simulator::DecodeType5(Instruction* instr) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002439 // Format(instr, "b'l'cond 'target");
Steve Block1e0659c2011-05-24 12:43:12 +01002440 int off = (instr->SImmed24Value() << 2);
Steve Blocka7e24c12009-10-30 11:49:00 +00002441 intptr_t pc_address = get_pc();
2442 if (instr->HasLink()) {
Steve Block1e0659c2011-05-24 12:43:12 +01002443 set_register(lr, pc_address + Instruction::kInstrSize);
Steve Blocka7e24c12009-10-30 11:49:00 +00002444 }
2445 int pc_reg = get_register(pc);
2446 set_pc(pc_reg + off);
2447}
2448
2449
Steve Block1e0659c2011-05-24 12:43:12 +01002450void Simulator::DecodeType6(Instruction* instr) {
Steve Blockd0582a62009-12-15 09:54:21 +00002451 DecodeType6CoprocessorIns(instr);
Steve Blocka7e24c12009-10-30 11:49:00 +00002452}
2453
2454
Steve Block1e0659c2011-05-24 12:43:12 +01002455void Simulator::DecodeType7(Instruction* instr) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002456 if (instr->Bit(24) == 1) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002457 SoftwareInterrupt(instr);
2458 } else {
Steve Blockd0582a62009-12-15 09:54:21 +00002459 DecodeTypeVFP(instr);
Steve Blocka7e24c12009-10-30 11:49:00 +00002460 }
2461}
2462
2463
Steve Block1e0659c2011-05-24 12:43:12 +01002464// void Simulator::DecodeTypeVFP(Instruction* instr)
Steve Blockd0582a62009-12-15 09:54:21 +00002465// The Following ARMv7 VFPv instructions are currently supported.
Leon Clarkee46be812010-01-19 14:06:41 +00002466// vmov :Sn = Rt
2467// vmov :Rt = Sn
2468// vcvt: Dd = Sm
2469// vcvt: Sd = Dm
2470// Dd = vadd(Dn, Dm)
2471// Dd = vsub(Dn, Dm)
2472// Dd = vmul(Dn, Dm)
2473// Dd = vdiv(Dn, Dm)
Steve Blockd0582a62009-12-15 09:54:21 +00002474// vcmp(Dd, Dm)
Steve Block8defd9f2010-07-08 12:39:36 +01002475// vmrs
2476// Dd = vsqrt(Dm)
Steve Block1e0659c2011-05-24 12:43:12 +01002477void Simulator::DecodeTypeVFP(Instruction* instr) {
2478 ASSERT((instr->TypeValue() == 7) && (instr->Bit(24) == 0x0) );
Steve Block6ded16b2010-05-10 14:33:55 +01002479 ASSERT(instr->Bits(11, 9) == 0x5);
Steve Blockd0582a62009-12-15 09:54:21 +00002480
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002481 // Obtain double precision register codes.
Steve Block1e0659c2011-05-24 12:43:12 +01002482 int vm = instr->VFPMRegValue(kDoublePrecision);
2483 int vd = instr->VFPDRegValue(kDoublePrecision);
2484 int vn = instr->VFPNRegValue(kDoublePrecision);
Steve Blockd0582a62009-12-15 09:54:21 +00002485
Steve Block6ded16b2010-05-10 14:33:55 +01002486 if (instr->Bit(4) == 0) {
Steve Block1e0659c2011-05-24 12:43:12 +01002487 if (instr->Opc1Value() == 0x7) {
Steve Block6ded16b2010-05-10 14:33:55 +01002488 // Other data processing instructions
Steve Block1e0659c2011-05-24 12:43:12 +01002489 if ((instr->Opc2Value() == 0x0) && (instr->Opc3Value() == 0x1)) {
Steve Block8defd9f2010-07-08 12:39:36 +01002490 // vmov register to register.
Steve Block1e0659c2011-05-24 12:43:12 +01002491 if (instr->SzValue() == 0x1) {
2492 int m = instr->VFPMRegValue(kDoublePrecision);
2493 int d = instr->VFPDRegValue(kDoublePrecision);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002494 set_d_register_from_double(d, get_double_from_d_register(m));
Steve Block8defd9f2010-07-08 12:39:36 +01002495 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01002496 int m = instr->VFPMRegValue(kSinglePrecision);
2497 int d = instr->VFPDRegValue(kSinglePrecision);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002498 set_s_register_from_float(d, get_float_from_s_register(m));
Steve Block8defd9f2010-07-08 12:39:36 +01002499 }
Steve Block1e0659c2011-05-24 12:43:12 +01002500 } else if ((instr->Opc2Value() == 0x0) && (instr->Opc3Value() == 0x3)) {
2501 // vabs
2502 double dm_value = get_double_from_d_register(vm);
2503 double dd_value = fabs(dm_value);
2504 set_d_register_from_double(vd, dd_value);
2505 } else if ((instr->Opc2Value() == 0x7) && (instr->Opc3Value() == 0x3)) {
Steve Block6ded16b2010-05-10 14:33:55 +01002506 DecodeVCVTBetweenDoubleAndSingle(instr);
Steve Block1e0659c2011-05-24 12:43:12 +01002507 } else if ((instr->Opc2Value() == 0x8) && (instr->Opc3Value() & 0x1)) {
Steve Block6ded16b2010-05-10 14:33:55 +01002508 DecodeVCVTBetweenFloatingPointAndInteger(instr);
Steve Block1e0659c2011-05-24 12:43:12 +01002509 } else if (((instr->Opc2Value() >> 1) == 0x6) &&
2510 (instr->Opc3Value() & 0x1)) {
Steve Block6ded16b2010-05-10 14:33:55 +01002511 DecodeVCVTBetweenFloatingPointAndInteger(instr);
Steve Block1e0659c2011-05-24 12:43:12 +01002512 } else if (((instr->Opc2Value() == 0x4) || (instr->Opc2Value() == 0x5)) &&
2513 (instr->Opc3Value() & 0x1)) {
Steve Block6ded16b2010-05-10 14:33:55 +01002514 DecodeVCMP(instr);
Steve Block1e0659c2011-05-24 12:43:12 +01002515 } else if (((instr->Opc2Value() == 0x1)) && (instr->Opc3Value() == 0x3)) {
Steve Block8defd9f2010-07-08 12:39:36 +01002516 // vsqrt
2517 double dm_value = get_double_from_d_register(vm);
2518 double dd_value = sqrt(dm_value);
2519 set_d_register_from_double(vd, dd_value);
Steve Block1e0659c2011-05-24 12:43:12 +01002520 } else if (instr->Opc3Value() == 0x0) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002521 // vmov immediate.
Steve Block1e0659c2011-05-24 12:43:12 +01002522 if (instr->SzValue() == 0x1) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002523 set_d_register_from_double(vd, instr->DoubleImmedVmov());
2524 } else {
2525 UNREACHABLE(); // Not used by v8.
2526 }
Steve Block6ded16b2010-05-10 14:33:55 +01002527 } else {
2528 UNREACHABLE(); // Not used by V8.
2529 }
Steve Block1e0659c2011-05-24 12:43:12 +01002530 } else if (instr->Opc1Value() == 0x3) {
2531 if (instr->SzValue() != 0x1) {
Steve Block6ded16b2010-05-10 14:33:55 +01002532 UNREACHABLE(); // Not used by V8.
2533 }
2534
Steve Block1e0659c2011-05-24 12:43:12 +01002535 if (instr->Opc3Value() & 0x1) {
Steve Block6ded16b2010-05-10 14:33:55 +01002536 // vsub
2537 double dn_value = get_double_from_d_register(vn);
2538 double dm_value = get_double_from_d_register(vm);
2539 double dd_value = dn_value - dm_value;
2540 set_d_register_from_double(vd, dd_value);
2541 } else {
2542 // vadd
2543 double dn_value = get_double_from_d_register(vn);
2544 double dm_value = get_double_from_d_register(vm);
2545 double dd_value = dn_value + dm_value;
2546 set_d_register_from_double(vd, dd_value);
2547 }
Steve Block1e0659c2011-05-24 12:43:12 +01002548 } else if ((instr->Opc1Value() == 0x2) && !(instr->Opc3Value() & 0x1)) {
Steve Block6ded16b2010-05-10 14:33:55 +01002549 // vmul
Steve Block1e0659c2011-05-24 12:43:12 +01002550 if (instr->SzValue() != 0x1) {
Steve Block6ded16b2010-05-10 14:33:55 +01002551 UNREACHABLE(); // Not used by V8.
2552 }
2553
2554 double dn_value = get_double_from_d_register(vn);
2555 double dm_value = get_double_from_d_register(vm);
2556 double dd_value = dn_value * dm_value;
2557 set_d_register_from_double(vd, dd_value);
Steve Block1e0659c2011-05-24 12:43:12 +01002558 } else if ((instr->Opc1Value() == 0x4) && !(instr->Opc3Value() & 0x1)) {
Steve Block6ded16b2010-05-10 14:33:55 +01002559 // vdiv
Steve Block1e0659c2011-05-24 12:43:12 +01002560 if (instr->SzValue() != 0x1) {
Steve Block6ded16b2010-05-10 14:33:55 +01002561 UNREACHABLE(); // Not used by V8.
2562 }
2563
Steve Blockd0582a62009-12-15 09:54:21 +00002564 double dn_value = get_double_from_d_register(vn);
2565 double dm_value = get_double_from_d_register(vm);
2566 double dd_value = dn_value / dm_value;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002567 div_zero_vfp_flag_ = (dm_value == 0);
Steve Blockd0582a62009-12-15 09:54:21 +00002568 set_d_register_from_double(vd, dd_value);
Steve Block6ded16b2010-05-10 14:33:55 +01002569 } else {
2570 UNIMPLEMENTED(); // Not used by V8.
2571 }
2572 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01002573 if ((instr->VCValue() == 0x0) &&
2574 (instr->VAValue() == 0x0)) {
Steve Block6ded16b2010-05-10 14:33:55 +01002575 DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(instr);
Steve Block1e0659c2011-05-24 12:43:12 +01002576 } else if ((instr->VLValue() == 0x1) &&
2577 (instr->VCValue() == 0x0) &&
2578 (instr->VAValue() == 0x7) &&
Steve Block6ded16b2010-05-10 14:33:55 +01002579 (instr->Bits(19, 16) == 0x1)) {
2580 // vmrs
Steve Block1e0659c2011-05-24 12:43:12 +01002581 uint32_t rt = instr->RtValue();
Russell Brenner90bac252010-11-18 13:33:46 -08002582 if (rt == 0xF) {
Steve Blockd0582a62009-12-15 09:54:21 +00002583 Copy_FPSCR_to_APSR();
Russell Brenner90bac252010-11-18 13:33:46 -08002584 } else {
2585 // Emulate FPSCR from the Simulator flags.
2586 uint32_t fpscr = (n_flag_FPSCR_ << 31) |
2587 (z_flag_FPSCR_ << 30) |
2588 (c_flag_FPSCR_ << 29) |
2589 (v_flag_FPSCR_ << 28) |
2590 (inexact_vfp_flag_ << 4) |
2591 (underflow_vfp_flag_ << 3) |
2592 (overflow_vfp_flag_ << 2) |
2593 (div_zero_vfp_flag_ << 1) |
2594 (inv_op_vfp_flag_ << 0) |
Steve Block1e0659c2011-05-24 12:43:12 +01002595 (FPSCR_rounding_mode_);
Russell Brenner90bac252010-11-18 13:33:46 -08002596 set_register(rt, fpscr);
2597 }
Steve Block1e0659c2011-05-24 12:43:12 +01002598 } else if ((instr->VLValue() == 0x0) &&
2599 (instr->VCValue() == 0x0) &&
2600 (instr->VAValue() == 0x7) &&
Russell Brenner90bac252010-11-18 13:33:46 -08002601 (instr->Bits(19, 16) == 0x1)) {
2602 // vmsr
Steve Block1e0659c2011-05-24 12:43:12 +01002603 uint32_t rt = instr->RtValue();
Russell Brenner90bac252010-11-18 13:33:46 -08002604 if (rt == pc) {
2605 UNREACHABLE();
2606 } else {
2607 uint32_t rt_value = get_register(rt);
2608 n_flag_FPSCR_ = (rt_value >> 31) & 1;
2609 z_flag_FPSCR_ = (rt_value >> 30) & 1;
2610 c_flag_FPSCR_ = (rt_value >> 29) & 1;
2611 v_flag_FPSCR_ = (rt_value >> 28) & 1;
2612 inexact_vfp_flag_ = (rt_value >> 4) & 1;
2613 underflow_vfp_flag_ = (rt_value >> 3) & 1;
2614 overflow_vfp_flag_ = (rt_value >> 2) & 1;
2615 div_zero_vfp_flag_ = (rt_value >> 1) & 1;
2616 inv_op_vfp_flag_ = (rt_value >> 0) & 1;
2617 FPSCR_rounding_mode_ =
Steve Block1e0659c2011-05-24 12:43:12 +01002618 static_cast<VFPRoundingMode>((rt_value) & kVFPRoundingModeMask);
Russell Brenner90bac252010-11-18 13:33:46 -08002619 }
Steve Blockd0582a62009-12-15 09:54:21 +00002620 } else {
2621 UNIMPLEMENTED(); // Not used by V8.
2622 }
Steve Block6ded16b2010-05-10 14:33:55 +01002623 }
2624}
2625
2626
Steve Block1e0659c2011-05-24 12:43:12 +01002627void Simulator::DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(
2628 Instruction* instr) {
2629 ASSERT((instr->Bit(4) == 1) && (instr->VCValue() == 0x0) &&
2630 (instr->VAValue() == 0x0));
Steve Block6ded16b2010-05-10 14:33:55 +01002631
Steve Block1e0659c2011-05-24 12:43:12 +01002632 int t = instr->RtValue();
2633 int n = instr->VFPNRegValue(kSinglePrecision);
2634 bool to_arm_register = (instr->VLValue() == 0x1);
Steve Block6ded16b2010-05-10 14:33:55 +01002635
2636 if (to_arm_register) {
2637 int32_t int_value = get_sinteger_from_s_register(n);
2638 set_register(t, int_value);
2639 } else {
2640 int32_t rs_val = get_register(t);
2641 set_s_register_from_sinteger(n, rs_val);
2642 }
2643}
2644
2645
Steve Block1e0659c2011-05-24 12:43:12 +01002646void Simulator::DecodeVCMP(Instruction* instr) {
2647 ASSERT((instr->Bit(4) == 0) && (instr->Opc1Value() == 0x7));
2648 ASSERT(((instr->Opc2Value() == 0x4) || (instr->Opc2Value() == 0x5)) &&
2649 (instr->Opc3Value() & 0x1));
Steve Block6ded16b2010-05-10 14:33:55 +01002650 // Comparison.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002651
2652 VFPRegPrecision precision = kSinglePrecision;
Steve Block1e0659c2011-05-24 12:43:12 +01002653 if (instr->SzValue() == 1) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002654 precision = kDoublePrecision;
2655 }
Steve Block6ded16b2010-05-10 14:33:55 +01002656
Steve Block1e0659c2011-05-24 12:43:12 +01002657 int d = instr->VFPDRegValue(precision);
Iain Merrick75681382010-08-19 15:07:18 +01002658 int m = 0;
Steve Block1e0659c2011-05-24 12:43:12 +01002659 if (instr->Opc2Value() == 0x4) {
2660 m = instr->VFPMRegValue(precision);
Iain Merrick75681382010-08-19 15:07:18 +01002661 }
Steve Block6ded16b2010-05-10 14:33:55 +01002662
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002663 if (precision == kDoublePrecision) {
Steve Block6ded16b2010-05-10 14:33:55 +01002664 double dd_value = get_double_from_d_register(d);
Iain Merrick75681382010-08-19 15:07:18 +01002665 double dm_value = 0.0;
Steve Block1e0659c2011-05-24 12:43:12 +01002666 if (instr->Opc2Value() == 0x4) {
Iain Merrick75681382010-08-19 15:07:18 +01002667 dm_value = get_double_from_d_register(m);
2668 }
Steve Block6ded16b2010-05-10 14:33:55 +01002669
Ben Murdoch086aeea2011-05-13 15:57:08 +01002670 // Raise exceptions for quiet NaNs if necessary.
2671 if (instr->Bit(7) == 1) {
2672 if (isnan(dd_value)) {
2673 inv_op_vfp_flag_ = true;
2674 }
2675 }
2676
Steve Block6ded16b2010-05-10 14:33:55 +01002677 Compute_FPSCR_Flags(dd_value, dm_value);
2678 } else {
2679 UNIMPLEMENTED(); // Not used by V8.
2680 }
2681}
2682
2683
Steve Block1e0659c2011-05-24 12:43:12 +01002684void Simulator::DecodeVCVTBetweenDoubleAndSingle(Instruction* instr) {
2685 ASSERT((instr->Bit(4) == 0) && (instr->Opc1Value() == 0x7));
2686 ASSERT((instr->Opc2Value() == 0x7) && (instr->Opc3Value() == 0x3));
Steve Block6ded16b2010-05-10 14:33:55 +01002687
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002688 VFPRegPrecision dst_precision = kDoublePrecision;
2689 VFPRegPrecision src_precision = kSinglePrecision;
Steve Block1e0659c2011-05-24 12:43:12 +01002690 if (instr->SzValue() == 1) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002691 dst_precision = kSinglePrecision;
2692 src_precision = kDoublePrecision;
2693 }
Steve Block6ded16b2010-05-10 14:33:55 +01002694
Steve Block1e0659c2011-05-24 12:43:12 +01002695 int dst = instr->VFPDRegValue(dst_precision);
2696 int src = instr->VFPMRegValue(src_precision);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002697
2698 if (dst_precision == kSinglePrecision) {
Steve Block6ded16b2010-05-10 14:33:55 +01002699 double val = get_double_from_d_register(src);
2700 set_s_register_from_float(dst, static_cast<float>(val));
2701 } else {
2702 float val = get_float_from_s_register(src);
2703 set_d_register_from_double(dst, static_cast<double>(val));
2704 }
2705}
2706
Steve Block1e0659c2011-05-24 12:43:12 +01002707bool get_inv_op_vfp_flag(VFPRoundingMode mode,
2708 double val,
2709 bool unsigned_) {
2710 ASSERT((mode == RN) || (mode == RM) || (mode == RZ));
2711 double max_uint = static_cast<double>(0xffffffffu);
2712 double max_int = static_cast<double>(kMaxInt);
2713 double min_int = static_cast<double>(kMinInt);
Steve Block6ded16b2010-05-10 14:33:55 +01002714
Steve Block1e0659c2011-05-24 12:43:12 +01002715 // Check for NaN.
2716 if (val != val) {
2717 return true;
2718 }
2719
2720 // Check for overflow. This code works because 32bit integers can be
2721 // exactly represented by ieee-754 64bit floating-point values.
2722 switch (mode) {
2723 case RN:
2724 return unsigned_ ? (val >= (max_uint + 0.5)) ||
2725 (val < -0.5)
2726 : (val >= (max_int + 0.5)) ||
2727 (val < (min_int - 0.5));
2728
2729 case RM:
2730 return unsigned_ ? (val >= (max_uint + 1.0)) ||
2731 (val < 0)
2732 : (val >= (max_int + 1.0)) ||
2733 (val < min_int);
2734
2735 case RZ:
2736 return unsigned_ ? (val >= (max_uint + 1.0)) ||
2737 (val <= -1)
2738 : (val >= (max_int + 1.0)) ||
2739 (val <= (min_int - 1.0));
2740 default:
2741 UNREACHABLE();
2742 return true;
2743 }
2744}
2745
2746
2747// We call this function only if we had a vfp invalid exception.
2748// It returns the correct saturated value.
2749int VFPConversionSaturate(double val, bool unsigned_res) {
2750 if (val != val) {
2751 return 0;
2752 } else {
2753 if (unsigned_res) {
2754 return (val < 0) ? 0 : 0xffffffffu;
2755 } else {
2756 return (val < 0) ? kMinInt : kMaxInt;
2757 }
2758 }
2759}
2760
2761
2762void Simulator::DecodeVCVTBetweenFloatingPointAndInteger(Instruction* instr) {
2763 ASSERT((instr->Bit(4) == 0) && (instr->Opc1Value() == 0x7) &&
2764 (instr->Bits(27, 23) == 0x1D));
2765 ASSERT(((instr->Opc2Value() == 0x8) && (instr->Opc3Value() & 0x1)) ||
2766 (((instr->Opc2Value() >> 1) == 0x6) && (instr->Opc3Value() & 0x1)));
Steve Block6ded16b2010-05-10 14:33:55 +01002767
2768 // Conversion between floating-point and integer.
Steve Block6ded16b2010-05-10 14:33:55 +01002769 bool to_integer = (instr->Bit(18) == 1);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002770
Steve Block1e0659c2011-05-24 12:43:12 +01002771 VFPRegPrecision src_precision = (instr->SzValue() == 1) ? kDoublePrecision
2772 : kSinglePrecision;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002773
Steve Block6ded16b2010-05-10 14:33:55 +01002774 if (to_integer) {
Steve Block1e0659c2011-05-24 12:43:12 +01002775 // We are playing with code close to the C++ standard's limits below,
2776 // hence the very simple code and heavy checks.
2777 //
2778 // Note:
2779 // C++ defines default type casting from floating point to integer as
2780 // (close to) rounding toward zero ("fractional part discarded").
2781
2782 int dst = instr->VFPDRegValue(kSinglePrecision);
2783 int src = instr->VFPMRegValue(src_precision);
2784
2785 // Bit 7 in vcvt instructions indicates if we should use the FPSCR rounding
2786 // mode or the default Round to Zero mode.
2787 VFPRoundingMode mode = (instr->Bit(7) != 1) ? FPSCR_rounding_mode_
2788 : RZ;
2789 ASSERT((mode == RM) || (mode == RZ) || (mode == RN));
2790
Steve Block6ded16b2010-05-10 14:33:55 +01002791 bool unsigned_integer = (instr->Bit(16) == 0);
Steve Block1e0659c2011-05-24 12:43:12 +01002792 bool double_precision = (src_precision == kDoublePrecision);
2793
2794 double val = double_precision ? get_double_from_d_register(src)
2795 : get_float_from_s_register(src);
2796
2797 int temp = unsigned_integer ? static_cast<uint32_t>(val)
2798 : static_cast<int32_t>(val);
2799
2800 inv_op_vfp_flag_ = get_inv_op_vfp_flag(mode, val, unsigned_integer);
2801
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002802 double abs_diff =
2803 unsigned_integer ? fabs(val - static_cast<uint32_t>(temp))
2804 : fabs(val - temp);
2805
2806 inexact_vfp_flag_ = (abs_diff != 0);
2807
Steve Block1e0659c2011-05-24 12:43:12 +01002808 if (inv_op_vfp_flag_) {
2809 temp = VFPConversionSaturate(val, unsigned_integer);
Russell Brenner90bac252010-11-18 13:33:46 -08002810 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01002811 switch (mode) {
2812 case RN: {
Steve Block1e0659c2011-05-24 12:43:12 +01002813 int val_sign = (val > 0) ? 1 : -1;
2814 if (abs_diff > 0.5) {
2815 temp += val_sign;
2816 } else if (abs_diff == 0.5) {
2817 // Round to even if exactly halfway.
2818 temp = ((temp % 2) == 0) ? temp : temp + val_sign;
2819 }
2820 break;
2821 }
2822
2823 case RM:
2824 temp = temp > val ? temp - 1 : temp;
2825 break;
2826
2827 case RZ:
2828 // Nothing to do.
2829 break;
2830
2831 default:
2832 UNREACHABLE();
2833 }
Steve Blockd0582a62009-12-15 09:54:21 +00002834 }
Steve Block6ded16b2010-05-10 14:33:55 +01002835
Steve Block1e0659c2011-05-24 12:43:12 +01002836 // Update the destination register.
2837 set_s_register_from_sinteger(dst, temp);
Russell Brenner90bac252010-11-18 13:33:46 -08002838
Steve Block6ded16b2010-05-10 14:33:55 +01002839 } else {
2840 bool unsigned_integer = (instr->Bit(7) == 0);
2841
Steve Block1e0659c2011-05-24 12:43:12 +01002842 int dst = instr->VFPDRegValue(src_precision);
2843 int src = instr->VFPMRegValue(kSinglePrecision);
Steve Block6ded16b2010-05-10 14:33:55 +01002844
2845 int val = get_sinteger_from_s_register(src);
2846
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002847 if (src_precision == kDoublePrecision) {
Steve Block6ded16b2010-05-10 14:33:55 +01002848 if (unsigned_integer) {
2849 set_d_register_from_double(dst,
2850 static_cast<double>((uint32_t)val));
2851 } else {
2852 set_d_register_from_double(dst, static_cast<double>(val));
2853 }
2854 } else {
2855 if (unsigned_integer) {
2856 set_s_register_from_float(dst,
2857 static_cast<float>((uint32_t)val));
2858 } else {
2859 set_s_register_from_float(dst, static_cast<float>(val));
2860 }
Steve Blockd0582a62009-12-15 09:54:21 +00002861 }
2862 }
2863}
2864
2865
Steve Block1e0659c2011-05-24 12:43:12 +01002866// void Simulator::DecodeType6CoprocessorIns(Instruction* instr)
Steve Blockd0582a62009-12-15 09:54:21 +00002867// Decode Type 6 coprocessor instructions.
Leon Clarkee46be812010-01-19 14:06:41 +00002868// Dm = vmov(Rt, Rt2)
2869// <Rt, Rt2> = vmov(Dm)
Leon Clarked91b9f72010-01-27 17:25:45 +00002870// Ddst = MEM(Rbase + 4*offset).
2871// MEM(Rbase + 4*offset) = Dsrc.
Steve Block1e0659c2011-05-24 12:43:12 +01002872void Simulator::DecodeType6CoprocessorIns(Instruction* instr) {
2873 ASSERT((instr->TypeValue() == 6));
Steve Blockd0582a62009-12-15 09:54:21 +00002874
Steve Block1e0659c2011-05-24 12:43:12 +01002875 if (instr->CoprocessorValue() == 0xA) {
2876 switch (instr->OpcodeValue()) {
Steve Block6ded16b2010-05-10 14:33:55 +01002877 case 0x8:
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002878 case 0xA:
2879 case 0xC:
2880 case 0xE: { // Load and store single precision float to memory.
Steve Block1e0659c2011-05-24 12:43:12 +01002881 int rn = instr->RnValue();
2882 int vd = instr->VFPDRegValue(kSinglePrecision);
2883 int offset = instr->Immed8Value();
Steve Block6ded16b2010-05-10 14:33:55 +01002884 if (!instr->HasU()) {
2885 offset = -offset;
2886 }
2887
2888 int32_t address = get_register(rn) + 4 * offset;
2889 if (instr->HasL()) {
2890 // Load double from memory: vldr.
2891 set_s_register_from_sinteger(vd, ReadW(address, instr));
2892 } else {
2893 // Store double to memory: vstr.
2894 WriteW(address, get_sinteger_from_s_register(vd), instr);
2895 }
2896 break;
2897 }
2898 default:
2899 UNIMPLEMENTED(); // Not used by V8.
2900 break;
2901 }
Steve Block1e0659c2011-05-24 12:43:12 +01002902 } else if (instr->CoprocessorValue() == 0xB) {
2903 switch (instr->OpcodeValue()) {
Leon Clarked91b9f72010-01-27 17:25:45 +00002904 case 0x2:
2905 // Load and store double to two GP registers
2906 if (instr->Bits(7, 4) != 0x1) {
2907 UNIMPLEMENTED(); // Not used by V8.
2908 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01002909 int rt = instr->RtValue();
2910 int rn = instr->RnValue();
2911 int vm = instr->VmValue();
Leon Clarked91b9f72010-01-27 17:25:45 +00002912 if (instr->HasL()) {
2913 int32_t rt_int_value = get_sinteger_from_s_register(2*vm);
2914 int32_t rn_int_value = get_sinteger_from_s_register(2*vm+1);
2915
2916 set_register(rt, rt_int_value);
2917 set_register(rn, rn_int_value);
2918 } else {
2919 int32_t rs_val = get_register(rt);
2920 int32_t rn_val = get_register(rn);
2921
2922 set_s_register_from_sinteger(2*vm, rs_val);
2923 set_s_register_from_sinteger((2*vm+1), rn_val);
2924 }
2925 }
2926 break;
2927 case 0x8:
2928 case 0xC: { // Load and store double to memory.
Steve Block1e0659c2011-05-24 12:43:12 +01002929 int rn = instr->RnValue();
2930 int vd = instr->VdValue();
2931 int offset = instr->Immed8Value();
Leon Clarked91b9f72010-01-27 17:25:45 +00002932 if (!instr->HasU()) {
2933 offset = -offset;
2934 }
2935 int32_t address = get_register(rn) + 4 * offset;
2936 if (instr->HasL()) {
2937 // Load double from memory: vldr.
2938 set_s_register_from_sinteger(2*vd, ReadW(address, instr));
2939 set_s_register_from_sinteger(2*vd + 1, ReadW(address + 4, instr));
2940 } else {
2941 // Store double to memory: vstr.
2942 WriteW(address, get_sinteger_from_s_register(2*vd), instr);
2943 WriteW(address + 4, get_sinteger_from_s_register(2*vd + 1), instr);
2944 }
2945 break;
2946 }
2947 default:
2948 UNIMPLEMENTED(); // Not used by V8.
2949 break;
2950 }
Steve Block6ded16b2010-05-10 14:33:55 +01002951 } else {
2952 UNIMPLEMENTED(); // Not used by V8.
Steve Blockd0582a62009-12-15 09:54:21 +00002953 }
2954}
2955
2956
Steve Blocka7e24c12009-10-30 11:49:00 +00002957// Executes the current instruction.
Steve Block1e0659c2011-05-24 12:43:12 +01002958void Simulator::InstructionDecode(Instruction* instr) {
Steve Block6ded16b2010-05-10 14:33:55 +01002959 if (v8::internal::FLAG_check_icache) {
2960 CheckICache(instr);
2961 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002962 pc_modified_ = false;
2963 if (::v8::internal::FLAG_trace_sim) {
2964 disasm::NameConverter converter;
2965 disasm::Disassembler dasm(converter);
2966 // use a reasonably large buffer
2967 v8::internal::EmbeddedVector<char, 256> buffer;
2968 dasm.InstructionDecode(buffer,
2969 reinterpret_cast<byte*>(instr));
Ben Murdochf87a2032010-10-22 12:50:53 +01002970 PrintF(" 0x%08x %s\n", reinterpret_cast<intptr_t>(instr), buffer.start());
Steve Blocka7e24c12009-10-30 11:49:00 +00002971 }
Steve Block1e0659c2011-05-24 12:43:12 +01002972 if (instr->ConditionField() == kSpecialCondition) {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002973 UNIMPLEMENTED();
Steve Blocka7e24c12009-10-30 11:49:00 +00002974 } else if (ConditionallyExecute(instr)) {
Steve Block1e0659c2011-05-24 12:43:12 +01002975 switch (instr->TypeValue()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002976 case 0:
2977 case 1: {
2978 DecodeType01(instr);
2979 break;
2980 }
2981 case 2: {
2982 DecodeType2(instr);
2983 break;
2984 }
2985 case 3: {
2986 DecodeType3(instr);
2987 break;
2988 }
2989 case 4: {
2990 DecodeType4(instr);
2991 break;
2992 }
2993 case 5: {
2994 DecodeType5(instr);
2995 break;
2996 }
2997 case 6: {
2998 DecodeType6(instr);
2999 break;
3000 }
3001 case 7: {
3002 DecodeType7(instr);
3003 break;
3004 }
3005 default: {
3006 UNIMPLEMENTED();
3007 break;
3008 }
3009 }
Steve Block1e0659c2011-05-24 12:43:12 +01003010 // If the instruction is a non taken conditional stop, we need to skip the
3011 // inlined message address.
3012 } else if (instr->IsStop()) {
3013 set_pc(get_pc() + 2 * Instruction::kInstrSize);
Steve Blocka7e24c12009-10-30 11:49:00 +00003014 }
3015 if (!pc_modified_) {
Steve Block1e0659c2011-05-24 12:43:12 +01003016 set_register(pc, reinterpret_cast<int32_t>(instr)
3017 + Instruction::kInstrSize);
Steve Blocka7e24c12009-10-30 11:49:00 +00003018 }
3019}
3020
3021
Steve Blocka7e24c12009-10-30 11:49:00 +00003022void Simulator::Execute() {
3023 // Get the PC to simulate. Cannot use the accessor here as we need the
3024 // raw PC value and not the one used as input to arithmetic instructions.
3025 int program_counter = get_pc();
3026
3027 if (::v8::internal::FLAG_stop_sim_at == 0) {
3028 // Fast version of the dispatch loop without checking whether the simulator
3029 // should be stopping at a particular executed instruction.
3030 while (program_counter != end_sim_pc) {
Steve Block1e0659c2011-05-24 12:43:12 +01003031 Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
Steve Blocka7e24c12009-10-30 11:49:00 +00003032 icount_++;
3033 InstructionDecode(instr);
3034 program_counter = get_pc();
3035 }
3036 } else {
3037 // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when
3038 // we reach the particular instuction count.
3039 while (program_counter != end_sim_pc) {
Steve Block1e0659c2011-05-24 12:43:12 +01003040 Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
Steve Blocka7e24c12009-10-30 11:49:00 +00003041 icount_++;
3042 if (icount_ == ::v8::internal::FLAG_stop_sim_at) {
3043 Debugger dbg(this);
3044 dbg.Debug();
3045 } else {
3046 InstructionDecode(instr);
3047 }
3048 program_counter = get_pc();
3049 }
3050 }
3051}
3052
3053
3054int32_t Simulator::Call(byte* entry, int argument_count, ...) {
3055 va_list parameters;
3056 va_start(parameters, argument_count);
3057 // Setup arguments
3058
3059 // First four arguments passed in registers.
3060 ASSERT(argument_count >= 4);
3061 set_register(r0, va_arg(parameters, int32_t));
3062 set_register(r1, va_arg(parameters, int32_t));
3063 set_register(r2, va_arg(parameters, int32_t));
3064 set_register(r3, va_arg(parameters, int32_t));
3065
3066 // Remaining arguments passed on stack.
3067 int original_stack = get_register(sp);
3068 // Compute position of stack on entry to generated code.
3069 int entry_stack = (original_stack - (argument_count - 4) * sizeof(int32_t));
3070 if (OS::ActivationFrameAlignment() != 0) {
3071 entry_stack &= -OS::ActivationFrameAlignment();
3072 }
3073 // Store remaining arguments on stack, from low to high memory.
3074 intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
3075 for (int i = 4; i < argument_count; i++) {
3076 stack_argument[i - 4] = va_arg(parameters, int32_t);
3077 }
3078 va_end(parameters);
3079 set_register(sp, entry_stack);
3080
3081 // Prepare to execute the code at entry
3082 set_register(pc, reinterpret_cast<int32_t>(entry));
3083 // Put down marker for end of simulation. The simulator will stop simulation
3084 // when the PC reaches this value. By saving the "end simulation" value into
3085 // the LR the simulation stops when returning to this call point.
3086 set_register(lr, end_sim_pc);
3087
3088 // Remember the values of callee-saved registers.
3089 // The code below assumes that r9 is not used as sb (static base) in
3090 // simulator code and therefore is regarded as a callee-saved register.
3091 int32_t r4_val = get_register(r4);
3092 int32_t r5_val = get_register(r5);
3093 int32_t r6_val = get_register(r6);
3094 int32_t r7_val = get_register(r7);
3095 int32_t r8_val = get_register(r8);
3096 int32_t r9_val = get_register(r9);
3097 int32_t r10_val = get_register(r10);
3098 int32_t r11_val = get_register(r11);
3099
3100 // Setup the callee-saved registers with a known value. To be able to check
3101 // that they are preserved properly across JS execution.
3102 int32_t callee_saved_value = icount_;
3103 set_register(r4, callee_saved_value);
3104 set_register(r5, callee_saved_value);
3105 set_register(r6, callee_saved_value);
3106 set_register(r7, callee_saved_value);
3107 set_register(r8, callee_saved_value);
3108 set_register(r9, callee_saved_value);
3109 set_register(r10, callee_saved_value);
3110 set_register(r11, callee_saved_value);
3111
3112 // Start the simulation
3113 Execute();
3114
3115 // Check that the callee-saved registers have been preserved.
3116 CHECK_EQ(callee_saved_value, get_register(r4));
3117 CHECK_EQ(callee_saved_value, get_register(r5));
3118 CHECK_EQ(callee_saved_value, get_register(r6));
3119 CHECK_EQ(callee_saved_value, get_register(r7));
3120 CHECK_EQ(callee_saved_value, get_register(r8));
3121 CHECK_EQ(callee_saved_value, get_register(r9));
3122 CHECK_EQ(callee_saved_value, get_register(r10));
3123 CHECK_EQ(callee_saved_value, get_register(r11));
3124
3125 // Restore callee-saved registers with the original value.
3126 set_register(r4, r4_val);
3127 set_register(r5, r5_val);
3128 set_register(r6, r6_val);
3129 set_register(r7, r7_val);
3130 set_register(r8, r8_val);
3131 set_register(r9, r9_val);
3132 set_register(r10, r10_val);
3133 set_register(r11, r11_val);
3134
3135 // Pop stack passed arguments.
3136 CHECK_EQ(entry_stack, get_register(sp));
3137 set_register(sp, original_stack);
3138
3139 int32_t result = get_register(r0);
3140 return result;
3141}
3142
Steve Blockd0582a62009-12-15 09:54:21 +00003143
3144uintptr_t Simulator::PushAddress(uintptr_t address) {
3145 int new_sp = get_register(sp) - sizeof(uintptr_t);
3146 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp);
3147 *stack_slot = address;
3148 set_register(sp, new_sp);
3149 return new_sp;
3150}
3151
3152
3153uintptr_t Simulator::PopAddress() {
3154 int current_sp = get_register(sp);
3155 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp);
3156 uintptr_t address = *stack_slot;
3157 set_register(sp, current_sp + sizeof(uintptr_t));
3158 return address;
3159}
3160
Steve Block1e0659c2011-05-24 12:43:12 +01003161} } // namespace v8::internal
Steve Blocka7e24c12009-10-30 11:49:00 +00003162
John Reck59135872010-11-02 12:39:01 -07003163#endif // USE_SIMULATOR
Leon Clarkef7060e22010-06-03 12:02:55 +01003164
3165#endif // V8_TARGET_ARCH_ARM