blob: 8104747f14d49d861d86f97b5550c66e512a9a70 [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 Murdochb0fe1622011-05-05 13:52:32 +01001008 PrintF("Unaligned read at 0x%08x, pc=%p\n", addr, instr);
Steve Blocka7e24c12009-10-30 11:49:00 +00001009 UNIMPLEMENTED();
1010 return 0;
Kristian Monsen25f61362010-05-21 11:50:48 +01001011#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00001012}
1013
1014
Steve Block1e0659c2011-05-24 12:43:12 +01001015void Simulator::WriteW(int32_t addr, int value, Instruction* instr) {
Kristian Monsen25f61362010-05-21 11:50:48 +01001016#if V8_TARGET_CAN_READ_UNALIGNED
1017 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
1018 *ptr = value;
1019 return;
1020#else
Steve Blocka7e24c12009-10-30 11:49:00 +00001021 if ((addr & 3) == 0) {
1022 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
1023 *ptr = value;
1024 return;
1025 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001026 PrintF("Unaligned write at 0x%08x, pc=%p\n", addr, instr);
Steve Blocka7e24c12009-10-30 11:49:00 +00001027 UNIMPLEMENTED();
Kristian Monsen25f61362010-05-21 11:50:48 +01001028#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00001029}
1030
1031
Steve Block1e0659c2011-05-24 12:43:12 +01001032uint16_t Simulator::ReadHU(int32_t addr, Instruction* instr) {
Kristian Monsen25f61362010-05-21 11:50:48 +01001033#if V8_TARGET_CAN_READ_UNALIGNED
1034 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1035 return *ptr;
1036#else
Steve Blocka7e24c12009-10-30 11:49:00 +00001037 if ((addr & 1) == 0) {
1038 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1039 return *ptr;
1040 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001041 PrintF("Unaligned unsigned halfword read at 0x%08x, pc=%p\n", addr, instr);
Steve Blocka7e24c12009-10-30 11:49:00 +00001042 UNIMPLEMENTED();
1043 return 0;
Kristian Monsen25f61362010-05-21 11:50:48 +01001044#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00001045}
1046
1047
Steve Block1e0659c2011-05-24 12:43:12 +01001048int16_t Simulator::ReadH(int32_t addr, Instruction* instr) {
Kristian Monsen25f61362010-05-21 11:50:48 +01001049#if V8_TARGET_CAN_READ_UNALIGNED
1050 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
1051 return *ptr;
1052#else
Steve Blocka7e24c12009-10-30 11:49:00 +00001053 if ((addr & 1) == 0) {
1054 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
1055 return *ptr;
1056 }
1057 PrintF("Unaligned signed halfword read at 0x%08x\n", addr);
1058 UNIMPLEMENTED();
1059 return 0;
Kristian Monsen25f61362010-05-21 11:50:48 +01001060#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00001061}
1062
1063
Steve Block1e0659c2011-05-24 12:43:12 +01001064void Simulator::WriteH(int32_t addr, uint16_t value, Instruction* instr) {
Kristian Monsen25f61362010-05-21 11:50:48 +01001065#if V8_TARGET_CAN_READ_UNALIGNED
1066 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1067 *ptr = value;
1068 return;
1069#else
Steve Blocka7e24c12009-10-30 11:49:00 +00001070 if ((addr & 1) == 0) {
1071 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1072 *ptr = value;
1073 return;
1074 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001075 PrintF("Unaligned unsigned halfword write at 0x%08x, pc=%p\n", addr, instr);
Steve Blocka7e24c12009-10-30 11:49:00 +00001076 UNIMPLEMENTED();
Kristian Monsen25f61362010-05-21 11:50:48 +01001077#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00001078}
1079
1080
Steve Block1e0659c2011-05-24 12:43:12 +01001081void Simulator::WriteH(int32_t addr, int16_t value, Instruction* instr) {
Kristian Monsen25f61362010-05-21 11:50:48 +01001082#if V8_TARGET_CAN_READ_UNALIGNED
1083 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
1084 *ptr = value;
1085 return;
1086#else
Steve Blocka7e24c12009-10-30 11:49:00 +00001087 if ((addr & 1) == 0) {
1088 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
1089 *ptr = value;
1090 return;
1091 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001092 PrintF("Unaligned halfword write at 0x%08x, pc=%p\n", addr, instr);
Steve Blocka7e24c12009-10-30 11:49:00 +00001093 UNIMPLEMENTED();
Kristian Monsen25f61362010-05-21 11:50:48 +01001094#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00001095}
1096
1097
1098uint8_t Simulator::ReadBU(int32_t addr) {
1099 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1100 return *ptr;
1101}
1102
1103
1104int8_t Simulator::ReadB(int32_t addr) {
1105 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
1106 return *ptr;
1107}
1108
1109
1110void Simulator::WriteB(int32_t addr, uint8_t value) {
1111 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1112 *ptr = value;
1113}
1114
1115
1116void Simulator::WriteB(int32_t addr, int8_t value) {
1117 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
1118 *ptr = value;
1119}
1120
1121
Kristian Monsen25f61362010-05-21 11:50:48 +01001122int32_t* Simulator::ReadDW(int32_t addr) {
1123#if V8_TARGET_CAN_READ_UNALIGNED
1124 int32_t* ptr = reinterpret_cast<int32_t*>(addr);
1125 return ptr;
1126#else
1127 if ((addr & 3) == 0) {
1128 int32_t* ptr = reinterpret_cast<int32_t*>(addr);
1129 return ptr;
1130 }
1131 PrintF("Unaligned read at 0x%08x\n", addr);
1132 UNIMPLEMENTED();
1133 return 0;
1134#endif
1135}
1136
1137
1138void Simulator::WriteDW(int32_t addr, int32_t value1, int32_t value2) {
1139#if V8_TARGET_CAN_READ_UNALIGNED
1140 int32_t* ptr = reinterpret_cast<int32_t*>(addr);
1141 *ptr++ = value1;
1142 *ptr = value2;
1143 return;
1144#else
1145 if ((addr & 3) == 0) {
1146 int32_t* ptr = reinterpret_cast<int32_t*>(addr);
1147 *ptr++ = value1;
1148 *ptr = value2;
1149 return;
1150 }
1151 PrintF("Unaligned write at 0x%08x\n", addr);
1152 UNIMPLEMENTED();
1153#endif
1154}
1155
1156
Steve Blocka7e24c12009-10-30 11:49:00 +00001157// Returns the limit of the stack area to enable checking for stack overflows.
1158uintptr_t Simulator::StackLimit() const {
1159 // Leave a safety margin of 256 bytes to prevent overrunning the stack when
1160 // pushing values.
1161 return reinterpret_cast<uintptr_t>(stack_) + 256;
1162}
1163
1164
1165// Unsupported instructions use Format to print an error and stop execution.
Steve Block1e0659c2011-05-24 12:43:12 +01001166void Simulator::Format(Instruction* instr, const char* format) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001167 PrintF("Simulator found unsupported instruction:\n 0x%08x: %s\n",
Ben Murdochf87a2032010-10-22 12:50:53 +01001168 reinterpret_cast<intptr_t>(instr), format);
Steve Blocka7e24c12009-10-30 11:49:00 +00001169 UNIMPLEMENTED();
1170}
1171
1172
1173// Checks if the current instruction should be executed based on its
1174// condition bits.
Steve Block1e0659c2011-05-24 12:43:12 +01001175bool Simulator::ConditionallyExecute(Instruction* instr) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001176 switch (instr->ConditionField()) {
Steve Block1e0659c2011-05-24 12:43:12 +01001177 case eq: return z_flag_;
1178 case ne: return !z_flag_;
1179 case cs: return c_flag_;
1180 case cc: return !c_flag_;
1181 case mi: return n_flag_;
1182 case pl: return !n_flag_;
1183 case vs: return v_flag_;
1184 case vc: return !v_flag_;
1185 case hi: return c_flag_ && !z_flag_;
1186 case ls: return !c_flag_ || z_flag_;
1187 case ge: return n_flag_ == v_flag_;
1188 case lt: return n_flag_ != v_flag_;
1189 case gt: return !z_flag_ && (n_flag_ == v_flag_);
1190 case le: return z_flag_ || (n_flag_ != v_flag_);
1191 case al: return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00001192 default: UNREACHABLE();
1193 }
1194 return false;
1195}
1196
1197
1198// Calculate and set the Negative and Zero flags.
1199void Simulator::SetNZFlags(int32_t val) {
1200 n_flag_ = (val < 0);
1201 z_flag_ = (val == 0);
1202}
1203
1204
1205// Set the Carry flag.
1206void Simulator::SetCFlag(bool val) {
1207 c_flag_ = val;
1208}
1209
1210
1211// Set the oVerflow flag.
1212void Simulator::SetVFlag(bool val) {
1213 v_flag_ = val;
1214}
1215
1216
1217// Calculate C flag value for additions.
1218bool Simulator::CarryFrom(int32_t left, int32_t right) {
1219 uint32_t uleft = static_cast<uint32_t>(left);
1220 uint32_t uright = static_cast<uint32_t>(right);
1221 uint32_t urest = 0xffffffffU - uleft;
1222
1223 return (uright > urest);
1224}
1225
1226
1227// Calculate C flag value for subtractions.
1228bool Simulator::BorrowFrom(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
1232 return (uright > uleft);
1233}
1234
1235
1236// Calculate V flag value for additions and subtractions.
1237bool Simulator::OverflowFrom(int32_t alu_out,
1238 int32_t left, int32_t right, bool addition) {
1239 bool overflow;
1240 if (addition) {
1241 // operands have the same sign
1242 overflow = ((left >= 0 && right >= 0) || (left < 0 && right < 0))
1243 // and operands and result have different sign
1244 && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
1245 } else {
1246 // operands have different signs
1247 overflow = ((left < 0 && right >= 0) || (left >= 0 && right < 0))
1248 // and first operand and result have different signs
1249 && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
1250 }
1251 return overflow;
1252}
1253
1254
Steve Blockd0582a62009-12-15 09:54:21 +00001255// Support for VFP comparisons.
1256void Simulator::Compute_FPSCR_Flags(double val1, double val2) {
Leon Clarkee46be812010-01-19 14:06:41 +00001257 if (isnan(val1) || isnan(val2)) {
1258 n_flag_FPSCR_ = false;
1259 z_flag_FPSCR_ = false;
1260 c_flag_FPSCR_ = true;
1261 v_flag_FPSCR_ = true;
Steve Blockd0582a62009-12-15 09:54:21 +00001262 // All non-NaN cases.
Leon Clarkee46be812010-01-19 14:06:41 +00001263 } else if (val1 == val2) {
Steve Blockd0582a62009-12-15 09:54:21 +00001264 n_flag_FPSCR_ = false;
1265 z_flag_FPSCR_ = true;
1266 c_flag_FPSCR_ = true;
1267 v_flag_FPSCR_ = false;
1268 } else if (val1 < val2) {
1269 n_flag_FPSCR_ = true;
1270 z_flag_FPSCR_ = false;
1271 c_flag_FPSCR_ = false;
1272 v_flag_FPSCR_ = false;
1273 } else {
1274 // Case when (val1 > val2).
1275 n_flag_FPSCR_ = false;
1276 z_flag_FPSCR_ = false;
1277 c_flag_FPSCR_ = true;
1278 v_flag_FPSCR_ = false;
1279 }
1280}
1281
1282
1283void Simulator::Copy_FPSCR_to_APSR() {
1284 n_flag_ = n_flag_FPSCR_;
1285 z_flag_ = z_flag_FPSCR_;
1286 c_flag_ = c_flag_FPSCR_;
1287 v_flag_ = v_flag_FPSCR_;
1288}
1289
1290
Steve Blocka7e24c12009-10-30 11:49:00 +00001291// Addressing Mode 1 - Data-processing operands:
1292// Get the value based on the shifter_operand with register.
Steve Block1e0659c2011-05-24 12:43:12 +01001293int32_t Simulator::GetShiftRm(Instruction* instr, bool* carry_out) {
1294 ShiftOp shift = instr->ShiftField();
1295 int shift_amount = instr->ShiftAmountValue();
1296 int32_t result = get_register(instr->RmValue());
Steve Blocka7e24c12009-10-30 11:49:00 +00001297 if (instr->Bit(4) == 0) {
1298 // by immediate
1299 if ((shift == ROR) && (shift_amount == 0)) {
1300 UNIMPLEMENTED();
1301 return result;
1302 } else if (((shift == LSR) || (shift == ASR)) && (shift_amount == 0)) {
1303 shift_amount = 32;
1304 }
1305 switch (shift) {
1306 case ASR: {
1307 if (shift_amount == 0) {
1308 if (result < 0) {
1309 result = 0xffffffff;
1310 *carry_out = true;
1311 } else {
1312 result = 0;
1313 *carry_out = false;
1314 }
1315 } else {
1316 result >>= (shift_amount - 1);
1317 *carry_out = (result & 1) == 1;
1318 result >>= 1;
1319 }
1320 break;
1321 }
1322
1323 case LSL: {
1324 if (shift_amount == 0) {
1325 *carry_out = c_flag_;
1326 } else {
1327 result <<= (shift_amount - 1);
1328 *carry_out = (result < 0);
1329 result <<= 1;
1330 }
1331 break;
1332 }
1333
1334 case LSR: {
1335 if (shift_amount == 0) {
1336 result = 0;
1337 *carry_out = c_flag_;
1338 } else {
1339 uint32_t uresult = static_cast<uint32_t>(result);
1340 uresult >>= (shift_amount - 1);
1341 *carry_out = (uresult & 1) == 1;
1342 uresult >>= 1;
1343 result = static_cast<int32_t>(uresult);
1344 }
1345 break;
1346 }
1347
1348 case ROR: {
1349 UNIMPLEMENTED();
1350 break;
1351 }
1352
1353 default: {
1354 UNREACHABLE();
1355 break;
1356 }
1357 }
1358 } else {
1359 // by register
Steve Block1e0659c2011-05-24 12:43:12 +01001360 int rs = instr->RsValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00001361 shift_amount = get_register(rs) &0xff;
1362 switch (shift) {
1363 case ASR: {
1364 if (shift_amount == 0) {
1365 *carry_out = c_flag_;
1366 } else if (shift_amount < 32) {
1367 result >>= (shift_amount - 1);
1368 *carry_out = (result & 1) == 1;
1369 result >>= 1;
1370 } else {
1371 ASSERT(shift_amount >= 32);
1372 if (result < 0) {
1373 *carry_out = true;
1374 result = 0xffffffff;
1375 } else {
1376 *carry_out = false;
1377 result = 0;
1378 }
1379 }
1380 break;
1381 }
1382
1383 case LSL: {
1384 if (shift_amount == 0) {
1385 *carry_out = c_flag_;
1386 } else if (shift_amount < 32) {
1387 result <<= (shift_amount - 1);
1388 *carry_out = (result < 0);
1389 result <<= 1;
1390 } else if (shift_amount == 32) {
1391 *carry_out = (result & 1) == 1;
1392 result = 0;
1393 } else {
1394 ASSERT(shift_amount > 32);
1395 *carry_out = false;
1396 result = 0;
1397 }
1398 break;
1399 }
1400
1401 case LSR: {
1402 if (shift_amount == 0) {
1403 *carry_out = c_flag_;
1404 } else if (shift_amount < 32) {
1405 uint32_t uresult = static_cast<uint32_t>(result);
1406 uresult >>= (shift_amount - 1);
1407 *carry_out = (uresult & 1) == 1;
1408 uresult >>= 1;
1409 result = static_cast<int32_t>(uresult);
1410 } else if (shift_amount == 32) {
1411 *carry_out = (result < 0);
1412 result = 0;
1413 } else {
1414 *carry_out = false;
1415 result = 0;
1416 }
1417 break;
1418 }
1419
1420 case ROR: {
1421 UNIMPLEMENTED();
1422 break;
1423 }
1424
1425 default: {
1426 UNREACHABLE();
1427 break;
1428 }
1429 }
1430 }
1431 return result;
1432}
1433
1434
1435// Addressing Mode 1 - Data-processing operands:
1436// Get the value based on the shifter_operand with immediate.
Steve Block1e0659c2011-05-24 12:43:12 +01001437int32_t Simulator::GetImm(Instruction* instr, bool* carry_out) {
1438 int rotate = instr->RotateValue() * 2;
1439 int immed8 = instr->Immed8Value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001440 int imm = (immed8 >> rotate) | (immed8 << (32 - rotate));
1441 *carry_out = (rotate == 0) ? c_flag_ : (imm < 0);
1442 return imm;
1443}
1444
1445
1446static int count_bits(int bit_vector) {
1447 int count = 0;
1448 while (bit_vector != 0) {
1449 if ((bit_vector & 1) != 0) {
1450 count++;
1451 }
1452 bit_vector >>= 1;
1453 }
1454 return count;
1455}
1456
1457
1458// Addressing Mode 4 - Load and Store Multiple
Steve Block1e0659c2011-05-24 12:43:12 +01001459void Simulator::HandleRList(Instruction* instr, bool load) {
1460 int rn = instr->RnValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00001461 int32_t rn_val = get_register(rn);
Steve Block1e0659c2011-05-24 12:43:12 +01001462 int rlist = instr->RlistValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00001463 int num_regs = count_bits(rlist);
1464
1465 intptr_t start_address = 0;
1466 intptr_t end_address = 0;
1467 switch (instr->PUField()) {
Steve Block1e0659c2011-05-24 12:43:12 +01001468 case da_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00001469 UNIMPLEMENTED();
1470 break;
1471 }
Steve Block1e0659c2011-05-24 12:43:12 +01001472 case ia_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00001473 start_address = rn_val;
1474 end_address = rn_val + (num_regs * 4) - 4;
1475 rn_val = rn_val + (num_regs * 4);
1476 break;
1477 }
Steve Block1e0659c2011-05-24 12:43:12 +01001478 case db_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00001479 start_address = rn_val - (num_regs * 4);
1480 end_address = rn_val - 4;
1481 rn_val = start_address;
1482 break;
1483 }
Steve Block1e0659c2011-05-24 12:43:12 +01001484 case ib_x: {
Steve Block791712a2010-08-27 10:21:07 +01001485 start_address = rn_val + 4;
1486 end_address = rn_val + (num_regs * 4);
1487 rn_val = end_address;
Steve Blocka7e24c12009-10-30 11:49:00 +00001488 break;
1489 }
1490 default: {
1491 UNREACHABLE();
1492 break;
1493 }
1494 }
1495 if (instr->HasW()) {
1496 set_register(rn, rn_val);
1497 }
1498 intptr_t* address = reinterpret_cast<intptr_t*>(start_address);
1499 int reg = 0;
1500 while (rlist != 0) {
1501 if ((rlist & 1) != 0) {
1502 if (load) {
1503 set_register(reg, *address);
1504 } else {
1505 *address = get_register(reg);
1506 }
1507 address += 1;
1508 }
1509 reg++;
1510 rlist >>= 1;
1511 }
1512 ASSERT(end_address == ((intptr_t)address) - 4);
1513}
1514
1515
1516// Calls into the V8 runtime are based on this very simple interface.
1517// Note: To be able to return two values from some calls the code in runtime.cc
1518// uses the ObjectPair which is essentially two 32-bit values stuffed into a
1519// 64-bit value. With the code below we assume that all runtime calls return
1520// 64 bits of result. If they don't, the r1 result register contains a bogus
1521// value, which is fine because it is caller-saved.
1522typedef int64_t (*SimulatorRuntimeCall)(int32_t arg0,
1523 int32_t arg1,
1524 int32_t arg2,
Ben Murdochb0fe1622011-05-05 13:52:32 +01001525 int32_t arg3,
1526 int32_t arg4);
Steve Blocka7e24c12009-10-30 11:49:00 +00001527typedef double (*SimulatorRuntimeFPCall)(int32_t arg0,
1528 int32_t arg1,
1529 int32_t arg2,
1530 int32_t arg3);
1531
Steve Block1e0659c2011-05-24 12:43:12 +01001532// This signature supports direct call in to API function native callback
1533// (refer to InvocationCallback in v8.h).
1534typedef v8::Handle<v8::Value> (*SimulatorRuntimeApiCall)(int32_t arg0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001535
1536// Software interrupt instructions are used by the simulator to call into the
1537// C-based V8 runtime.
Steve Block1e0659c2011-05-24 12:43:12 +01001538void Simulator::SoftwareInterrupt(Instruction* instr) {
1539 int svc = instr->SvcValue();
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001540 switch (svc) {
Steve Block1e0659c2011-05-24 12:43:12 +01001541 case kCallRtRedirected: {
Steve Block6ded16b2010-05-10 14:33:55 +01001542 // Check if stack is aligned. Error if not aligned is reported below to
1543 // include information on the function called.
1544 bool stack_aligned =
1545 (get_register(sp)
1546 & (::v8::internal::FLAG_sim_stack_alignment - 1)) == 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00001547 Redirection* redirection = Redirection::FromSwiInstruction(instr);
1548 int32_t arg0 = get_register(r0);
1549 int32_t arg1 = get_register(r1);
1550 int32_t arg2 = get_register(r2);
1551 int32_t arg3 = get_register(r3);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001552 int32_t* stack_pointer = reinterpret_cast<int32_t*>(get_register(sp));
1553 int32_t arg4 = *stack_pointer;
Steve Blocka7e24c12009-10-30 11:49:00 +00001554 // This is dodgy but it works because the C entry stubs are never moved.
1555 // See comment in codegen-arm.cc and bug 1242173.
1556 int32_t saved_lr = get_register(lr);
Steve Block1e0659c2011-05-24 12:43:12 +01001557 intptr_t external =
1558 reinterpret_cast<intptr_t>(redirection->external_function());
1559 if (redirection->type() == ExternalReference::FP_RETURN_CALL) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001560 SimulatorRuntimeFPCall target =
1561 reinterpret_cast<SimulatorRuntimeFPCall>(external);
Steve Block6ded16b2010-05-10 14:33:55 +01001562 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001563 double x, y;
1564 GetFpArgs(&x, &y);
Steve Block6ded16b2010-05-10 14:33:55 +01001565 PrintF("Call to host function at %p with args %f, %f",
Steve Blocka7e24c12009-10-30 11:49:00 +00001566 FUNCTION_ADDR(target), x, y);
Steve Block6ded16b2010-05-10 14:33:55 +01001567 if (!stack_aligned) {
1568 PrintF(" with unaligned stack %08x\n", get_register(sp));
1569 }
1570 PrintF("\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00001571 }
Steve Block6ded16b2010-05-10 14:33:55 +01001572 CHECK(stack_aligned);
Steve Blocka7e24c12009-10-30 11:49:00 +00001573 double result = target(arg0, arg1, arg2, arg3);
1574 SetFpResult(result);
Steve Block1e0659c2011-05-24 12:43:12 +01001575 } else if (redirection->type() == ExternalReference::DIRECT_CALL) {
1576 SimulatorRuntimeApiCall target =
1577 reinterpret_cast<SimulatorRuntimeApiCall>(external);
1578 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
1579 PrintF(
1580 "Call to host function at %p args %08x",
1581 FUNCTION_ADDR(target),
1582 arg0);
1583 if (!stack_aligned) {
1584 PrintF(" with unaligned stack %08x\n", get_register(sp));
1585 }
1586 PrintF("\n");
1587 }
1588 CHECK(stack_aligned);
1589 v8::Handle<v8::Value> result = target(arg0);
1590 if (::v8::internal::FLAG_trace_sim) {
1591 PrintF("Returned %p\n", reinterpret_cast<void *>(*result));
1592 }
1593 set_register(r0, (int32_t) *result);
Steve Blocka7e24c12009-10-30 11:49:00 +00001594 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01001595 // builtin call.
1596 ASSERT(redirection->type() == ExternalReference::BUILTIN_CALL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001597 SimulatorRuntimeCall target =
1598 reinterpret_cast<SimulatorRuntimeCall>(external);
Steve Block6ded16b2010-05-10 14:33:55 +01001599 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001600 PrintF(
Ben Murdochb0fe1622011-05-05 13:52:32 +01001601 "Call to host function at %p args %08x, %08x, %08x, %08x, %0xc",
Steve Blocka7e24c12009-10-30 11:49:00 +00001602 FUNCTION_ADDR(target),
1603 arg0,
1604 arg1,
1605 arg2,
Ben Murdochb0fe1622011-05-05 13:52:32 +01001606 arg3,
1607 arg4);
Steve Block6ded16b2010-05-10 14:33:55 +01001608 if (!stack_aligned) {
1609 PrintF(" with unaligned stack %08x\n", get_register(sp));
1610 }
1611 PrintF("\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00001612 }
Steve Block6ded16b2010-05-10 14:33:55 +01001613 CHECK(stack_aligned);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001614 int64_t result = target(arg0, arg1, arg2, arg3, arg4);
Steve Blocka7e24c12009-10-30 11:49:00 +00001615 int32_t lo_res = static_cast<int32_t>(result);
1616 int32_t hi_res = static_cast<int32_t>(result >> 32);
1617 if (::v8::internal::FLAG_trace_sim) {
1618 PrintF("Returned %08x\n", lo_res);
1619 }
1620 set_register(r0, lo_res);
1621 set_register(r1, hi_res);
1622 }
1623 set_register(lr, saved_lr);
1624 set_pc(get_register(lr));
1625 break;
1626 }
Steve Block1e0659c2011-05-24 12:43:12 +01001627 case kBreakpoint: {
Steve Blocka7e24c12009-10-30 11:49:00 +00001628 Debugger dbg(this);
1629 dbg.Debug();
1630 break;
1631 }
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001632 // stop uses all codes greater than 1 << 23.
Steve Blocka7e24c12009-10-30 11:49:00 +00001633 default: {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001634 if (svc >= (1 << 23)) {
1635 uint32_t code = svc & kStopCodeMask;
1636 if (isWatchedStop(code)) {
1637 IncreaseStopCounter(code);
1638 }
1639 // Stop if it is enabled, otherwise go on jumping over the stop
1640 // and the message address.
1641 if (isEnabledStop(code)) {
1642 Debugger dbg(this);
1643 dbg.Stop(instr);
1644 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01001645 set_pc(get_pc() + 2 * Instruction::kInstrSize);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001646 }
1647 } else {
1648 // This is not a valid svc code.
1649 UNREACHABLE();
1650 break;
1651 }
1652 }
1653 }
1654}
1655
1656
1657// Stop helper functions.
Steve Block1e0659c2011-05-24 12:43:12 +01001658bool Simulator::isStopInstruction(Instruction* instr) {
1659 return (instr->Bits(27, 24) == 0xF) && (instr->SvcValue() >= kStopCode);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001660}
1661
1662
1663bool Simulator::isWatchedStop(uint32_t code) {
1664 ASSERT(code <= kMaxStopCode);
1665 return code < kNumOfWatchedStops;
1666}
1667
1668
1669bool Simulator::isEnabledStop(uint32_t code) {
1670 ASSERT(code <= kMaxStopCode);
1671 // Unwatched stops are always enabled.
1672 return !isWatchedStop(code) ||
1673 !(watched_stops[code].count & kStopDisabledBit);
1674}
1675
1676
1677void Simulator::EnableStop(uint32_t code) {
1678 ASSERT(isWatchedStop(code));
1679 if (!isEnabledStop(code)) {
1680 watched_stops[code].count &= ~kStopDisabledBit;
1681 }
1682}
1683
1684
1685void Simulator::DisableStop(uint32_t code) {
1686 ASSERT(isWatchedStop(code));
1687 if (isEnabledStop(code)) {
1688 watched_stops[code].count |= kStopDisabledBit;
1689 }
1690}
1691
1692
1693void Simulator::IncreaseStopCounter(uint32_t code) {
1694 ASSERT(code <= kMaxStopCode);
1695 ASSERT(isWatchedStop(code));
1696 if ((watched_stops[code].count & ~(1 << 31)) == 0x7fffffff) {
1697 PrintF("Stop counter for code %i has overflowed.\n"
1698 "Enabling this code and reseting the counter to 0.\n", code);
1699 watched_stops[code].count = 0;
1700 EnableStop(code);
1701 } else {
1702 watched_stops[code].count++;
1703 }
1704}
1705
1706
1707// Print a stop status.
1708void Simulator::PrintStopInfo(uint32_t code) {
1709 ASSERT(code <= kMaxStopCode);
1710 if (!isWatchedStop(code)) {
1711 PrintF("Stop not watched.");
1712 } else {
1713 const char* state = isEnabledStop(code) ? "Enabled" : "Disabled";
1714 int32_t count = watched_stops[code].count & ~kStopDisabledBit;
1715 // Don't print the state of unused breakpoints.
1716 if (count != 0) {
1717 if (watched_stops[code].desc) {
1718 PrintF("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n",
1719 code, code, state, count, watched_stops[code].desc);
1720 } else {
1721 PrintF("stop %i - 0x%x: \t%s, \tcounter = %i\n",
1722 code, code, state, count);
1723 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001724 }
1725 }
1726}
1727
1728
1729// Handle execution based on instruction types.
1730
1731// Instruction types 0 and 1 are both rolled into one function because they
1732// only differ in the handling of the shifter_operand.
Steve Block1e0659c2011-05-24 12:43:12 +01001733void Simulator::DecodeType01(Instruction* instr) {
1734 int type = instr->TypeValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00001735 if ((type == 0) && instr->IsSpecialType0()) {
1736 // multiply instruction or extra loads and stores
1737 if (instr->Bits(7, 4) == 9) {
1738 if (instr->Bit(24) == 0) {
1739 // Raw field decoding here. Multiply instructions have their Rd in
1740 // funny places.
Steve Block1e0659c2011-05-24 12:43:12 +01001741 int rn = instr->RnValue();
1742 int rm = instr->RmValue();
1743 int rs = instr->RsValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00001744 int32_t rs_val = get_register(rs);
1745 int32_t rm_val = get_register(rm);
1746 if (instr->Bit(23) == 0) {
1747 if (instr->Bit(21) == 0) {
1748 // The MUL instruction description (A 4.1.33) refers to Rd as being
1749 // the destination for the operation, but it confusingly uses the
1750 // Rn field to encode it.
1751 // Format(instr, "mul'cond's 'rn, 'rm, 'rs");
1752 int rd = rn; // Remap the rn field to the Rd register.
1753 int32_t alu_out = rm_val * rs_val;
1754 set_register(rd, alu_out);
1755 if (instr->HasS()) {
1756 SetNZFlags(alu_out);
1757 }
1758 } else {
1759 // The MLA instruction description (A 4.1.28) refers to the order
1760 // of registers as "Rd, Rm, Rs, Rn". But confusingly it uses the
1761 // Rn field to encode the Rd register and the Rd field to encode
1762 // the Rn register.
1763 Format(instr, "mla'cond's 'rn, 'rm, 'rs, 'rd");
1764 }
1765 } else {
1766 // The signed/long multiply instructions use the terms RdHi and RdLo
1767 // when referring to the target registers. They are mapped to the Rn
1768 // and Rd fields as follows:
1769 // RdLo == Rd
1770 // RdHi == Rn (This is confusingly stored in variable rd here
1771 // because the mul instruction from above uses the
1772 // Rn field to encode the Rd register. Good luck figuring
1773 // this out without reading the ARM instruction manual
1774 // at a very detailed level.)
1775 // Format(instr, "'um'al'cond's 'rd, 'rn, 'rs, 'rm");
1776 int rd_hi = rn; // Remap the rn field to the RdHi register.
Steve Block1e0659c2011-05-24 12:43:12 +01001777 int rd_lo = instr->RdValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00001778 int32_t hi_res = 0;
1779 int32_t lo_res = 0;
1780 if (instr->Bit(22) == 1) {
1781 int64_t left_op = static_cast<int32_t>(rm_val);
1782 int64_t right_op = static_cast<int32_t>(rs_val);
1783 uint64_t result = left_op * right_op;
1784 hi_res = static_cast<int32_t>(result >> 32);
1785 lo_res = static_cast<int32_t>(result & 0xffffffff);
1786 } else {
1787 // unsigned multiply
1788 uint64_t left_op = static_cast<uint32_t>(rm_val);
1789 uint64_t right_op = static_cast<uint32_t>(rs_val);
1790 uint64_t result = left_op * right_op;
1791 hi_res = static_cast<int32_t>(result >> 32);
1792 lo_res = static_cast<int32_t>(result & 0xffffffff);
1793 }
1794 set_register(rd_lo, lo_res);
1795 set_register(rd_hi, hi_res);
1796 if (instr->HasS()) {
1797 UNIMPLEMENTED();
1798 }
1799 }
1800 } else {
Steve Blockd0582a62009-12-15 09:54:21 +00001801 UNIMPLEMENTED(); // Not used by V8.
Steve Blocka7e24c12009-10-30 11:49:00 +00001802 }
1803 } else {
1804 // extra load/store instructions
Steve Block1e0659c2011-05-24 12:43:12 +01001805 int rd = instr->RdValue();
1806 int rn = instr->RnValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00001807 int32_t rn_val = get_register(rn);
1808 int32_t addr = 0;
1809 if (instr->Bit(22) == 0) {
Steve Block1e0659c2011-05-24 12:43:12 +01001810 int rm = instr->RmValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00001811 int32_t rm_val = get_register(rm);
1812 switch (instr->PUField()) {
Steve Block1e0659c2011-05-24 12:43:12 +01001813 case da_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00001814 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], -'rm");
1815 ASSERT(!instr->HasW());
1816 addr = rn_val;
1817 rn_val -= rm_val;
1818 set_register(rn, rn_val);
1819 break;
1820 }
Steve Block1e0659c2011-05-24 12:43:12 +01001821 case ia_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00001822 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], +'rm");
1823 ASSERT(!instr->HasW());
1824 addr = rn_val;
1825 rn_val += rm_val;
1826 set_register(rn, rn_val);
1827 break;
1828 }
Steve Block1e0659c2011-05-24 12:43:12 +01001829 case db_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00001830 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, -'rm]'w");
1831 rn_val -= rm_val;
1832 addr = rn_val;
1833 if (instr->HasW()) {
1834 set_register(rn, rn_val);
1835 }
1836 break;
1837 }
Steve Block1e0659c2011-05-24 12:43:12 +01001838 case ib_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00001839 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, +'rm]'w");
1840 rn_val += rm_val;
1841 addr = rn_val;
1842 if (instr->HasW()) {
1843 set_register(rn, rn_val);
1844 }
1845 break;
1846 }
1847 default: {
1848 // The PU field is a 2-bit field.
1849 UNREACHABLE();
1850 break;
1851 }
1852 }
1853 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01001854 int32_t imm_val = (instr->ImmedHValue() << 4) | instr->ImmedLValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00001855 switch (instr->PUField()) {
Steve Block1e0659c2011-05-24 12:43:12 +01001856 case da_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00001857 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], #-'off8");
1858 ASSERT(!instr->HasW());
1859 addr = rn_val;
1860 rn_val -= imm_val;
1861 set_register(rn, rn_val);
1862 break;
1863 }
Steve Block1e0659c2011-05-24 12:43:12 +01001864 case ia_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00001865 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], #+'off8");
1866 ASSERT(!instr->HasW());
1867 addr = rn_val;
1868 rn_val += imm_val;
1869 set_register(rn, rn_val);
1870 break;
1871 }
Steve Block1e0659c2011-05-24 12:43:12 +01001872 case db_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00001873 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, #-'off8]'w");
1874 rn_val -= imm_val;
1875 addr = rn_val;
1876 if (instr->HasW()) {
1877 set_register(rn, rn_val);
1878 }
1879 break;
1880 }
Steve Block1e0659c2011-05-24 12:43:12 +01001881 case ib_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00001882 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, #+'off8]'w");
1883 rn_val += imm_val;
1884 addr = rn_val;
1885 if (instr->HasW()) {
1886 set_register(rn, rn_val);
1887 }
1888 break;
1889 }
1890 default: {
1891 // The PU field is a 2-bit field.
1892 UNREACHABLE();
1893 break;
1894 }
1895 }
1896 }
Kristian Monsen25f61362010-05-21 11:50:48 +01001897 if (((instr->Bits(7, 4) & 0xd) == 0xd) && (instr->Bit(20) == 0)) {
1898 ASSERT((rd % 2) == 0);
1899 if (instr->HasH()) {
1900 // The strd instruction.
1901 int32_t value1 = get_register(rd);
1902 int32_t value2 = get_register(rd+1);
1903 WriteDW(addr, value1, value2);
1904 } else {
1905 // The ldrd instruction.
1906 int* rn_data = ReadDW(addr);
1907 set_dw_register(rd, rn_data);
1908 }
1909 } else if (instr->HasH()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001910 if (instr->HasSign()) {
1911 if (instr->HasL()) {
1912 int16_t val = ReadH(addr, instr);
1913 set_register(rd, val);
1914 } else {
1915 int16_t val = get_register(rd);
1916 WriteH(addr, val, instr);
1917 }
1918 } else {
1919 if (instr->HasL()) {
1920 uint16_t val = ReadHU(addr, instr);
1921 set_register(rd, val);
1922 } else {
1923 uint16_t val = get_register(rd);
1924 WriteH(addr, val, instr);
1925 }
1926 }
1927 } else {
1928 // signed byte loads
1929 ASSERT(instr->HasSign());
1930 ASSERT(instr->HasL());
1931 int8_t val = ReadB(addr);
1932 set_register(rd, val);
1933 }
1934 return;
1935 }
Steve Block6ded16b2010-05-10 14:33:55 +01001936 } else if ((type == 0) && instr->IsMiscType0()) {
1937 if (instr->Bits(22, 21) == 1) {
Steve Block1e0659c2011-05-24 12:43:12 +01001938 int rm = instr->RmValue();
1939 switch (instr->BitField(7, 4)) {
Steve Block6ded16b2010-05-10 14:33:55 +01001940 case BX:
1941 set_pc(get_register(rm));
1942 break;
1943 case BLX: {
1944 uint32_t old_pc = get_pc();
1945 set_pc(get_register(rm));
Steve Block1e0659c2011-05-24 12:43:12 +01001946 set_register(lr, old_pc + Instruction::kInstrSize);
Steve Block6ded16b2010-05-10 14:33:55 +01001947 break;
1948 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001949 case BKPT: {
1950 Debugger dbg(this);
1951 PrintF("Simulator hit BKPT.\n");
1952 dbg.Debug();
Steve Block6ded16b2010-05-10 14:33:55 +01001953 break;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001954 }
Steve Block6ded16b2010-05-10 14:33:55 +01001955 default:
1956 UNIMPLEMENTED();
1957 }
1958 } else if (instr->Bits(22, 21) == 3) {
Steve Block1e0659c2011-05-24 12:43:12 +01001959 int rm = instr->RmValue();
1960 int rd = instr->RdValue();
1961 switch (instr->BitField(7, 4)) {
Steve Block6ded16b2010-05-10 14:33:55 +01001962 case CLZ: {
1963 uint32_t bits = get_register(rm);
1964 int leading_zeros = 0;
1965 if (bits == 0) {
1966 leading_zeros = 32;
1967 } else {
1968 while ((bits & 0x80000000u) == 0) {
1969 bits <<= 1;
1970 leading_zeros++;
1971 }
1972 }
1973 set_register(rd, leading_zeros);
1974 break;
1975 }
1976 default:
1977 UNIMPLEMENTED();
1978 }
1979 } else {
1980 PrintF("%08x\n", instr->InstructionBits());
1981 UNIMPLEMENTED();
1982 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001983 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01001984 int rd = instr->RdValue();
1985 int rn = instr->RnValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00001986 int32_t rn_val = get_register(rn);
1987 int32_t shifter_operand = 0;
1988 bool shifter_carry_out = 0;
1989 if (type == 0) {
1990 shifter_operand = GetShiftRm(instr, &shifter_carry_out);
1991 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01001992 ASSERT(instr->TypeValue() == 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001993 shifter_operand = GetImm(instr, &shifter_carry_out);
1994 }
1995 int32_t alu_out;
1996
1997 switch (instr->OpcodeField()) {
1998 case AND: {
1999 // Format(instr, "and'cond's 'rd, 'rn, 'shift_rm");
2000 // Format(instr, "and'cond's 'rd, 'rn, 'imm");
2001 alu_out = rn_val & shifter_operand;
2002 set_register(rd, alu_out);
2003 if (instr->HasS()) {
2004 SetNZFlags(alu_out);
2005 SetCFlag(shifter_carry_out);
2006 }
2007 break;
2008 }
2009
2010 case EOR: {
2011 // Format(instr, "eor'cond's 'rd, 'rn, 'shift_rm");
2012 // Format(instr, "eor'cond's 'rd, 'rn, 'imm");
2013 alu_out = rn_val ^ shifter_operand;
2014 set_register(rd, alu_out);
2015 if (instr->HasS()) {
2016 SetNZFlags(alu_out);
2017 SetCFlag(shifter_carry_out);
2018 }
2019 break;
2020 }
2021
2022 case SUB: {
2023 // Format(instr, "sub'cond's 'rd, 'rn, 'shift_rm");
2024 // Format(instr, "sub'cond's 'rd, 'rn, 'imm");
2025 alu_out = rn_val - shifter_operand;
2026 set_register(rd, alu_out);
2027 if (instr->HasS()) {
2028 SetNZFlags(alu_out);
2029 SetCFlag(!BorrowFrom(rn_val, shifter_operand));
2030 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, false));
2031 }
2032 break;
2033 }
2034
2035 case RSB: {
2036 // Format(instr, "rsb'cond's 'rd, 'rn, 'shift_rm");
2037 // Format(instr, "rsb'cond's 'rd, 'rn, 'imm");
2038 alu_out = shifter_operand - rn_val;
2039 set_register(rd, alu_out);
2040 if (instr->HasS()) {
2041 SetNZFlags(alu_out);
2042 SetCFlag(!BorrowFrom(shifter_operand, rn_val));
2043 SetVFlag(OverflowFrom(alu_out, shifter_operand, rn_val, false));
2044 }
2045 break;
2046 }
2047
2048 case ADD: {
2049 // Format(instr, "add'cond's 'rd, 'rn, 'shift_rm");
2050 // Format(instr, "add'cond's 'rd, 'rn, 'imm");
2051 alu_out = rn_val + shifter_operand;
2052 set_register(rd, alu_out);
2053 if (instr->HasS()) {
2054 SetNZFlags(alu_out);
2055 SetCFlag(CarryFrom(rn_val, shifter_operand));
2056 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, true));
2057 }
2058 break;
2059 }
2060
2061 case ADC: {
2062 Format(instr, "adc'cond's 'rd, 'rn, 'shift_rm");
2063 Format(instr, "adc'cond's 'rd, 'rn, 'imm");
2064 break;
2065 }
2066
2067 case SBC: {
2068 Format(instr, "sbc'cond's 'rd, 'rn, 'shift_rm");
2069 Format(instr, "sbc'cond's 'rd, 'rn, 'imm");
2070 break;
2071 }
2072
2073 case RSC: {
2074 Format(instr, "rsc'cond's 'rd, 'rn, 'shift_rm");
2075 Format(instr, "rsc'cond's 'rd, 'rn, 'imm");
2076 break;
2077 }
2078
2079 case TST: {
2080 if (instr->HasS()) {
2081 // Format(instr, "tst'cond 'rn, 'shift_rm");
2082 // Format(instr, "tst'cond 'rn, 'imm");
2083 alu_out = rn_val & shifter_operand;
2084 SetNZFlags(alu_out);
2085 SetCFlag(shifter_carry_out);
2086 } else {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002087 // Format(instr, "movw'cond 'rd, 'imm").
Steve Block1e0659c2011-05-24 12:43:12 +01002088 alu_out = instr->ImmedMovwMovtValue();
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002089 set_register(rd, alu_out);
Steve Blocka7e24c12009-10-30 11:49:00 +00002090 }
2091 break;
2092 }
2093
2094 case TEQ: {
2095 if (instr->HasS()) {
2096 // Format(instr, "teq'cond 'rn, 'shift_rm");
2097 // Format(instr, "teq'cond 'rn, 'imm");
2098 alu_out = rn_val ^ shifter_operand;
2099 SetNZFlags(alu_out);
2100 SetCFlag(shifter_carry_out);
2101 } else {
Steve Block6ded16b2010-05-10 14:33:55 +01002102 // Other instructions matching this pattern are handled in the
2103 // miscellaneous instructions part above.
2104 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +00002105 }
2106 break;
2107 }
2108
2109 case CMP: {
2110 if (instr->HasS()) {
2111 // Format(instr, "cmp'cond 'rn, 'shift_rm");
2112 // Format(instr, "cmp'cond 'rn, 'imm");
2113 alu_out = rn_val - shifter_operand;
2114 SetNZFlags(alu_out);
2115 SetCFlag(!BorrowFrom(rn_val, shifter_operand));
2116 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, false));
2117 } else {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002118 // Format(instr, "movt'cond 'rd, 'imm").
2119 alu_out = (get_register(rd) & 0xffff) |
Steve Block1e0659c2011-05-24 12:43:12 +01002120 (instr->ImmedMovwMovtValue() << 16);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002121 set_register(rd, alu_out);
Steve Blocka7e24c12009-10-30 11:49:00 +00002122 }
2123 break;
2124 }
2125
2126 case CMN: {
2127 if (instr->HasS()) {
2128 // Format(instr, "cmn'cond 'rn, 'shift_rm");
2129 // Format(instr, "cmn'cond 'rn, 'imm");
2130 alu_out = rn_val + shifter_operand;
2131 SetNZFlags(alu_out);
2132 SetCFlag(!CarryFrom(rn_val, shifter_operand));
2133 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, true));
2134 } else {
Steve Block6ded16b2010-05-10 14:33:55 +01002135 // Other instructions matching this pattern are handled in the
2136 // miscellaneous instructions part above.
2137 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +00002138 }
2139 break;
2140 }
2141
2142 case ORR: {
2143 // Format(instr, "orr'cond's 'rd, 'rn, 'shift_rm");
2144 // Format(instr, "orr'cond's 'rd, 'rn, 'imm");
2145 alu_out = rn_val | shifter_operand;
2146 set_register(rd, alu_out);
2147 if (instr->HasS()) {
2148 SetNZFlags(alu_out);
2149 SetCFlag(shifter_carry_out);
2150 }
2151 break;
2152 }
2153
2154 case MOV: {
2155 // Format(instr, "mov'cond's 'rd, 'shift_rm");
2156 // Format(instr, "mov'cond's 'rd, 'imm");
2157 alu_out = shifter_operand;
2158 set_register(rd, alu_out);
2159 if (instr->HasS()) {
2160 SetNZFlags(alu_out);
2161 SetCFlag(shifter_carry_out);
2162 }
2163 break;
2164 }
2165
2166 case BIC: {
2167 // Format(instr, "bic'cond's 'rd, 'rn, 'shift_rm");
2168 // Format(instr, "bic'cond's 'rd, 'rn, 'imm");
2169 alu_out = rn_val & ~shifter_operand;
2170 set_register(rd, alu_out);
2171 if (instr->HasS()) {
2172 SetNZFlags(alu_out);
2173 SetCFlag(shifter_carry_out);
2174 }
2175 break;
2176 }
2177
2178 case MVN: {
2179 // Format(instr, "mvn'cond's 'rd, 'shift_rm");
2180 // Format(instr, "mvn'cond's 'rd, 'imm");
2181 alu_out = ~shifter_operand;
2182 set_register(rd, alu_out);
2183 if (instr->HasS()) {
2184 SetNZFlags(alu_out);
2185 SetCFlag(shifter_carry_out);
2186 }
2187 break;
2188 }
2189
2190 default: {
2191 UNREACHABLE();
2192 break;
2193 }
2194 }
2195 }
2196}
2197
2198
Steve Block1e0659c2011-05-24 12:43:12 +01002199void Simulator::DecodeType2(Instruction* instr) {
2200 int rd = instr->RdValue();
2201 int rn = instr->RnValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00002202 int32_t rn_val = get_register(rn);
Steve Block1e0659c2011-05-24 12:43:12 +01002203 int32_t im_val = instr->Offset12Value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002204 int32_t addr = 0;
2205 switch (instr->PUField()) {
Steve Block1e0659c2011-05-24 12:43:12 +01002206 case da_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002207 // Format(instr, "'memop'cond'b 'rd, ['rn], #-'off12");
2208 ASSERT(!instr->HasW());
2209 addr = rn_val;
2210 rn_val -= im_val;
2211 set_register(rn, rn_val);
2212 break;
2213 }
Steve Block1e0659c2011-05-24 12:43:12 +01002214 case ia_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002215 // Format(instr, "'memop'cond'b 'rd, ['rn], #+'off12");
2216 ASSERT(!instr->HasW());
2217 addr = rn_val;
2218 rn_val += im_val;
2219 set_register(rn, rn_val);
2220 break;
2221 }
Steve Block1e0659c2011-05-24 12:43:12 +01002222 case db_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002223 // Format(instr, "'memop'cond'b 'rd, ['rn, #-'off12]'w");
2224 rn_val -= im_val;
2225 addr = rn_val;
2226 if (instr->HasW()) {
2227 set_register(rn, rn_val);
2228 }
2229 break;
2230 }
Steve Block1e0659c2011-05-24 12:43:12 +01002231 case ib_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002232 // Format(instr, "'memop'cond'b 'rd, ['rn, #+'off12]'w");
2233 rn_val += im_val;
2234 addr = rn_val;
2235 if (instr->HasW()) {
2236 set_register(rn, rn_val);
2237 }
2238 break;
2239 }
2240 default: {
2241 UNREACHABLE();
2242 break;
2243 }
2244 }
2245 if (instr->HasB()) {
2246 if (instr->HasL()) {
2247 byte val = ReadBU(addr);
2248 set_register(rd, val);
2249 } else {
2250 byte val = get_register(rd);
2251 WriteB(addr, val);
2252 }
2253 } else {
2254 if (instr->HasL()) {
2255 set_register(rd, ReadW(addr, instr));
2256 } else {
2257 WriteW(addr, get_register(rd), instr);
2258 }
2259 }
2260}
2261
2262
Steve Block1e0659c2011-05-24 12:43:12 +01002263void Simulator::DecodeType3(Instruction* instr) {
2264 int rd = instr->RdValue();
2265 int rn = instr->RnValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00002266 int32_t rn_val = get_register(rn);
2267 bool shifter_carry_out = 0;
2268 int32_t shifter_operand = GetShiftRm(instr, &shifter_carry_out);
2269 int32_t addr = 0;
2270 switch (instr->PUField()) {
Steve Block1e0659c2011-05-24 12:43:12 +01002271 case da_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002272 ASSERT(!instr->HasW());
2273 Format(instr, "'memop'cond'b 'rd, ['rn], -'shift_rm");
Kristian Monsen50ef84f2010-07-29 15:18:00 +01002274 UNIMPLEMENTED();
Steve Blocka7e24c12009-10-30 11:49:00 +00002275 break;
2276 }
Steve Block1e0659c2011-05-24 12:43:12 +01002277 case ia_x: {
Kristian Monsen50ef84f2010-07-29 15:18:00 +01002278 if (instr->HasW()) {
2279 ASSERT(instr->Bits(5, 4) == 0x1);
2280
2281 if (instr->Bit(22) == 0x1) { // USAT.
2282 int32_t sat_pos = instr->Bits(20, 16);
2283 int32_t sat_val = (1 << sat_pos) - 1;
2284 int32_t shift = instr->Bits(11, 7);
2285 int32_t shift_type = instr->Bit(6);
Steve Block1e0659c2011-05-24 12:43:12 +01002286 int32_t rm_val = get_register(instr->RmValue());
Kristian Monsen50ef84f2010-07-29 15:18:00 +01002287 if (shift_type == 0) { // LSL
2288 rm_val <<= shift;
2289 } else { // ASR
2290 rm_val >>= shift;
2291 }
2292 // If saturation occurs, the Q flag should be set in the CPSR.
2293 // There is no Q flag yet, and no instruction (MRS) to read the
2294 // CPSR directly.
2295 if (rm_val > sat_val) {
2296 rm_val = sat_val;
2297 } else if (rm_val < 0) {
2298 rm_val = 0;
2299 }
2300 set_register(rd, rm_val);
2301 } else { // SSAT.
2302 UNIMPLEMENTED();
2303 }
2304 return;
2305 } else {
2306 Format(instr, "'memop'cond'b 'rd, ['rn], +'shift_rm");
2307 UNIMPLEMENTED();
2308 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002309 break;
2310 }
Steve Block1e0659c2011-05-24 12:43:12 +01002311 case db_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002312 // Format(instr, "'memop'cond'b 'rd, ['rn, -'shift_rm]'w");
2313 addr = rn_val - shifter_operand;
2314 if (instr->HasW()) {
2315 set_register(rn, addr);
2316 }
2317 break;
2318 }
Steve Block1e0659c2011-05-24 12:43:12 +01002319 case ib_x: {
Andrei Popescu31002712010-02-23 13:46:05 +00002320 if (instr->HasW() && (instr->Bits(6, 4) == 0x5)) {
2321 uint32_t widthminus1 = static_cast<uint32_t>(instr->Bits(20, 16));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002322 uint32_t lsbit = static_cast<uint32_t>(instr->Bits(11, 7));
Andrei Popescu31002712010-02-23 13:46:05 +00002323 uint32_t msbit = widthminus1 + lsbit;
2324 if (msbit <= 31) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002325 if (instr->Bit(22)) {
2326 // ubfx - unsigned bitfield extract.
2327 uint32_t rm_val =
Steve Block1e0659c2011-05-24 12:43:12 +01002328 static_cast<uint32_t>(get_register(instr->RmValue()));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002329 uint32_t extr_val = rm_val << (31 - msbit);
2330 extr_val = extr_val >> (31 - widthminus1);
Steve Block1e0659c2011-05-24 12:43:12 +01002331 set_register(instr->RdValue(), extr_val);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002332 } else {
2333 // sbfx - signed bitfield extract.
Steve Block1e0659c2011-05-24 12:43:12 +01002334 int32_t rm_val = get_register(instr->RmValue());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002335 int32_t extr_val = rm_val << (31 - msbit);
2336 extr_val = extr_val >> (31 - widthminus1);
Steve Block1e0659c2011-05-24 12:43:12 +01002337 set_register(instr->RdValue(), extr_val);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002338 }
2339 } else {
2340 UNREACHABLE();
2341 }
2342 return;
2343 } else if (!instr->HasW() && (instr->Bits(6, 4) == 0x1)) {
2344 uint32_t lsbit = static_cast<uint32_t>(instr->Bits(11, 7));
2345 uint32_t msbit = static_cast<uint32_t>(instr->Bits(20, 16));
2346 if (msbit >= lsbit) {
2347 // bfc or bfi - bitfield clear/insert.
2348 uint32_t rd_val =
Steve Block1e0659c2011-05-24 12:43:12 +01002349 static_cast<uint32_t>(get_register(instr->RdValue()));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002350 uint32_t bitcount = msbit - lsbit + 1;
2351 uint32_t mask = (1 << bitcount) - 1;
2352 rd_val &= ~(mask << lsbit);
Steve Block1e0659c2011-05-24 12:43:12 +01002353 if (instr->RmValue() != 15) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002354 // bfi - bitfield insert.
2355 uint32_t rm_val =
Steve Block1e0659c2011-05-24 12:43:12 +01002356 static_cast<uint32_t>(get_register(instr->RmValue()));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002357 rm_val &= mask;
2358 rd_val |= rm_val << lsbit;
2359 }
Steve Block1e0659c2011-05-24 12:43:12 +01002360 set_register(instr->RdValue(), rd_val);
Andrei Popescu31002712010-02-23 13:46:05 +00002361 } else {
2362 UNREACHABLE();
2363 }
2364 return;
2365 } else {
2366 // Format(instr, "'memop'cond'b 'rd, ['rn, +'shift_rm]'w");
2367 addr = rn_val + shifter_operand;
2368 if (instr->HasW()) {
2369 set_register(rn, addr);
2370 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002371 }
2372 break;
2373 }
2374 default: {
2375 UNREACHABLE();
2376 break;
2377 }
2378 }
2379 if (instr->HasB()) {
2380 if (instr->HasL()) {
2381 uint8_t byte = ReadB(addr);
2382 set_register(rd, byte);
2383 } else {
Andrei Popescu31002712010-02-23 13:46:05 +00002384 uint8_t byte = get_register(rd);
2385 WriteB(addr, byte);
Steve Blocka7e24c12009-10-30 11:49:00 +00002386 }
2387 } else {
2388 if (instr->HasL()) {
2389 set_register(rd, ReadW(addr, instr));
2390 } else {
2391 WriteW(addr, get_register(rd), instr);
2392 }
2393 }
2394}
2395
2396
Steve Block1e0659c2011-05-24 12:43:12 +01002397void Simulator::DecodeType4(Instruction* instr) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002398 ASSERT(instr->Bit(22) == 0); // only allowed to be set in privileged mode
2399 if (instr->HasL()) {
2400 // Format(instr, "ldm'cond'pu 'rn'w, 'rlist");
2401 HandleRList(instr, true);
2402 } else {
2403 // Format(instr, "stm'cond'pu 'rn'w, 'rlist");
2404 HandleRList(instr, false);
2405 }
2406}
2407
2408
Steve Block1e0659c2011-05-24 12:43:12 +01002409void Simulator::DecodeType5(Instruction* instr) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002410 // Format(instr, "b'l'cond 'target");
Steve Block1e0659c2011-05-24 12:43:12 +01002411 int off = (instr->SImmed24Value() << 2);
Steve Blocka7e24c12009-10-30 11:49:00 +00002412 intptr_t pc_address = get_pc();
2413 if (instr->HasLink()) {
Steve Block1e0659c2011-05-24 12:43:12 +01002414 set_register(lr, pc_address + Instruction::kInstrSize);
Steve Blocka7e24c12009-10-30 11:49:00 +00002415 }
2416 int pc_reg = get_register(pc);
2417 set_pc(pc_reg + off);
2418}
2419
2420
Steve Block1e0659c2011-05-24 12:43:12 +01002421void Simulator::DecodeType6(Instruction* instr) {
Steve Blockd0582a62009-12-15 09:54:21 +00002422 DecodeType6CoprocessorIns(instr);
Steve Blocka7e24c12009-10-30 11:49:00 +00002423}
2424
2425
Steve Block1e0659c2011-05-24 12:43:12 +01002426void Simulator::DecodeType7(Instruction* instr) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002427 if (instr->Bit(24) == 1) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002428 SoftwareInterrupt(instr);
2429 } else {
Steve Blockd0582a62009-12-15 09:54:21 +00002430 DecodeTypeVFP(instr);
Steve Blocka7e24c12009-10-30 11:49:00 +00002431 }
2432}
2433
2434
Steve Block1e0659c2011-05-24 12:43:12 +01002435// void Simulator::DecodeTypeVFP(Instruction* instr)
Steve Blockd0582a62009-12-15 09:54:21 +00002436// The Following ARMv7 VFPv instructions are currently supported.
Leon Clarkee46be812010-01-19 14:06:41 +00002437// vmov :Sn = Rt
2438// vmov :Rt = Sn
2439// vcvt: Dd = Sm
2440// vcvt: Sd = Dm
2441// Dd = vadd(Dn, Dm)
2442// Dd = vsub(Dn, Dm)
2443// Dd = vmul(Dn, Dm)
2444// Dd = vdiv(Dn, Dm)
Steve Blockd0582a62009-12-15 09:54:21 +00002445// vcmp(Dd, Dm)
Steve Block8defd9f2010-07-08 12:39:36 +01002446// vmrs
2447// Dd = vsqrt(Dm)
Steve Block1e0659c2011-05-24 12:43:12 +01002448void Simulator::DecodeTypeVFP(Instruction* instr) {
2449 ASSERT((instr->TypeValue() == 7) && (instr->Bit(24) == 0x0) );
Steve Block6ded16b2010-05-10 14:33:55 +01002450 ASSERT(instr->Bits(11, 9) == 0x5);
Steve Blockd0582a62009-12-15 09:54:21 +00002451
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002452 // Obtain double precision register codes.
Steve Block1e0659c2011-05-24 12:43:12 +01002453 int vm = instr->VFPMRegValue(kDoublePrecision);
2454 int vd = instr->VFPDRegValue(kDoublePrecision);
2455 int vn = instr->VFPNRegValue(kDoublePrecision);
Steve Blockd0582a62009-12-15 09:54:21 +00002456
Steve Block6ded16b2010-05-10 14:33:55 +01002457 if (instr->Bit(4) == 0) {
Steve Block1e0659c2011-05-24 12:43:12 +01002458 if (instr->Opc1Value() == 0x7) {
Steve Block6ded16b2010-05-10 14:33:55 +01002459 // Other data processing instructions
Steve Block1e0659c2011-05-24 12:43:12 +01002460 if ((instr->Opc2Value() == 0x0) && (instr->Opc3Value() == 0x1)) {
Steve Block8defd9f2010-07-08 12:39:36 +01002461 // vmov register to register.
Steve Block1e0659c2011-05-24 12:43:12 +01002462 if (instr->SzValue() == 0x1) {
2463 int m = instr->VFPMRegValue(kDoublePrecision);
2464 int d = instr->VFPDRegValue(kDoublePrecision);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002465 set_d_register_from_double(d, get_double_from_d_register(m));
Steve Block8defd9f2010-07-08 12:39:36 +01002466 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01002467 int m = instr->VFPMRegValue(kSinglePrecision);
2468 int d = instr->VFPDRegValue(kSinglePrecision);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002469 set_s_register_from_float(d, get_float_from_s_register(m));
Steve Block8defd9f2010-07-08 12:39:36 +01002470 }
Steve Block1e0659c2011-05-24 12:43:12 +01002471 } else if ((instr->Opc2Value() == 0x0) && (instr->Opc3Value() == 0x3)) {
2472 // vabs
2473 double dm_value = get_double_from_d_register(vm);
2474 double dd_value = fabs(dm_value);
2475 set_d_register_from_double(vd, dd_value);
2476 } else if ((instr->Opc2Value() == 0x7) && (instr->Opc3Value() == 0x3)) {
Steve Block6ded16b2010-05-10 14:33:55 +01002477 DecodeVCVTBetweenDoubleAndSingle(instr);
Steve Block1e0659c2011-05-24 12:43:12 +01002478 } else if ((instr->Opc2Value() == 0x8) && (instr->Opc3Value() & 0x1)) {
Steve Block6ded16b2010-05-10 14:33:55 +01002479 DecodeVCVTBetweenFloatingPointAndInteger(instr);
Steve Block1e0659c2011-05-24 12:43:12 +01002480 } else if (((instr->Opc2Value() >> 1) == 0x6) &&
2481 (instr->Opc3Value() & 0x1)) {
Steve Block6ded16b2010-05-10 14:33:55 +01002482 DecodeVCVTBetweenFloatingPointAndInteger(instr);
Steve Block1e0659c2011-05-24 12:43:12 +01002483 } else if (((instr->Opc2Value() == 0x4) || (instr->Opc2Value() == 0x5)) &&
2484 (instr->Opc3Value() & 0x1)) {
Steve Block6ded16b2010-05-10 14:33:55 +01002485 DecodeVCMP(instr);
Steve Block1e0659c2011-05-24 12:43:12 +01002486 } else if (((instr->Opc2Value() == 0x1)) && (instr->Opc3Value() == 0x3)) {
Steve Block8defd9f2010-07-08 12:39:36 +01002487 // vsqrt
2488 double dm_value = get_double_from_d_register(vm);
2489 double dd_value = sqrt(dm_value);
2490 set_d_register_from_double(vd, dd_value);
Steve Block1e0659c2011-05-24 12:43:12 +01002491 } else if (instr->Opc3Value() == 0x0) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002492 // vmov immediate.
Steve Block1e0659c2011-05-24 12:43:12 +01002493 if (instr->SzValue() == 0x1) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002494 set_d_register_from_double(vd, instr->DoubleImmedVmov());
2495 } else {
2496 UNREACHABLE(); // Not used by v8.
2497 }
Steve Block6ded16b2010-05-10 14:33:55 +01002498 } else {
2499 UNREACHABLE(); // Not used by V8.
2500 }
Steve Block1e0659c2011-05-24 12:43:12 +01002501 } else if (instr->Opc1Value() == 0x3) {
2502 if (instr->SzValue() != 0x1) {
Steve Block6ded16b2010-05-10 14:33:55 +01002503 UNREACHABLE(); // Not used by V8.
2504 }
2505
Steve Block1e0659c2011-05-24 12:43:12 +01002506 if (instr->Opc3Value() & 0x1) {
Steve Block6ded16b2010-05-10 14:33:55 +01002507 // vsub
2508 double dn_value = get_double_from_d_register(vn);
2509 double dm_value = get_double_from_d_register(vm);
2510 double dd_value = dn_value - dm_value;
2511 set_d_register_from_double(vd, dd_value);
2512 } else {
2513 // vadd
2514 double dn_value = get_double_from_d_register(vn);
2515 double dm_value = get_double_from_d_register(vm);
2516 double dd_value = dn_value + dm_value;
2517 set_d_register_from_double(vd, dd_value);
2518 }
Steve Block1e0659c2011-05-24 12:43:12 +01002519 } else if ((instr->Opc1Value() == 0x2) && !(instr->Opc3Value() & 0x1)) {
Steve Block6ded16b2010-05-10 14:33:55 +01002520 // vmul
Steve Block1e0659c2011-05-24 12:43:12 +01002521 if (instr->SzValue() != 0x1) {
Steve Block6ded16b2010-05-10 14:33:55 +01002522 UNREACHABLE(); // Not used by V8.
2523 }
2524
2525 double dn_value = get_double_from_d_register(vn);
2526 double dm_value = get_double_from_d_register(vm);
2527 double dd_value = dn_value * dm_value;
2528 set_d_register_from_double(vd, dd_value);
Steve Block1e0659c2011-05-24 12:43:12 +01002529 } else if ((instr->Opc1Value() == 0x4) && !(instr->Opc3Value() & 0x1)) {
Steve Block6ded16b2010-05-10 14:33:55 +01002530 // vdiv
Steve Block1e0659c2011-05-24 12:43:12 +01002531 if (instr->SzValue() != 0x1) {
Steve Block6ded16b2010-05-10 14:33:55 +01002532 UNREACHABLE(); // Not used by V8.
2533 }
2534
Steve Blockd0582a62009-12-15 09:54:21 +00002535 double dn_value = get_double_from_d_register(vn);
2536 double dm_value = get_double_from_d_register(vm);
2537 double dd_value = dn_value / dm_value;
2538 set_d_register_from_double(vd, dd_value);
Steve Block6ded16b2010-05-10 14:33:55 +01002539 } else {
2540 UNIMPLEMENTED(); // Not used by V8.
2541 }
2542 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01002543 if ((instr->VCValue() == 0x0) &&
2544 (instr->VAValue() == 0x0)) {
Steve Block6ded16b2010-05-10 14:33:55 +01002545 DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(instr);
Steve Block1e0659c2011-05-24 12:43:12 +01002546 } else if ((instr->VLValue() == 0x1) &&
2547 (instr->VCValue() == 0x0) &&
2548 (instr->VAValue() == 0x7) &&
Steve Block6ded16b2010-05-10 14:33:55 +01002549 (instr->Bits(19, 16) == 0x1)) {
2550 // vmrs
Steve Block1e0659c2011-05-24 12:43:12 +01002551 uint32_t rt = instr->RtValue();
Russell Brenner90bac252010-11-18 13:33:46 -08002552 if (rt == 0xF) {
Steve Blockd0582a62009-12-15 09:54:21 +00002553 Copy_FPSCR_to_APSR();
Russell Brenner90bac252010-11-18 13:33:46 -08002554 } else {
2555 // Emulate FPSCR from the Simulator flags.
2556 uint32_t fpscr = (n_flag_FPSCR_ << 31) |
2557 (z_flag_FPSCR_ << 30) |
2558 (c_flag_FPSCR_ << 29) |
2559 (v_flag_FPSCR_ << 28) |
2560 (inexact_vfp_flag_ << 4) |
2561 (underflow_vfp_flag_ << 3) |
2562 (overflow_vfp_flag_ << 2) |
2563 (div_zero_vfp_flag_ << 1) |
2564 (inv_op_vfp_flag_ << 0) |
Steve Block1e0659c2011-05-24 12:43:12 +01002565 (FPSCR_rounding_mode_);
Russell Brenner90bac252010-11-18 13:33:46 -08002566 set_register(rt, fpscr);
2567 }
Steve Block1e0659c2011-05-24 12:43:12 +01002568 } else if ((instr->VLValue() == 0x0) &&
2569 (instr->VCValue() == 0x0) &&
2570 (instr->VAValue() == 0x7) &&
Russell Brenner90bac252010-11-18 13:33:46 -08002571 (instr->Bits(19, 16) == 0x1)) {
2572 // vmsr
Steve Block1e0659c2011-05-24 12:43:12 +01002573 uint32_t rt = instr->RtValue();
Russell Brenner90bac252010-11-18 13:33:46 -08002574 if (rt == pc) {
2575 UNREACHABLE();
2576 } else {
2577 uint32_t rt_value = get_register(rt);
2578 n_flag_FPSCR_ = (rt_value >> 31) & 1;
2579 z_flag_FPSCR_ = (rt_value >> 30) & 1;
2580 c_flag_FPSCR_ = (rt_value >> 29) & 1;
2581 v_flag_FPSCR_ = (rt_value >> 28) & 1;
2582 inexact_vfp_flag_ = (rt_value >> 4) & 1;
2583 underflow_vfp_flag_ = (rt_value >> 3) & 1;
2584 overflow_vfp_flag_ = (rt_value >> 2) & 1;
2585 div_zero_vfp_flag_ = (rt_value >> 1) & 1;
2586 inv_op_vfp_flag_ = (rt_value >> 0) & 1;
2587 FPSCR_rounding_mode_ =
Steve Block1e0659c2011-05-24 12:43:12 +01002588 static_cast<VFPRoundingMode>((rt_value) & kVFPRoundingModeMask);
Russell Brenner90bac252010-11-18 13:33:46 -08002589 }
Steve Blockd0582a62009-12-15 09:54:21 +00002590 } else {
2591 UNIMPLEMENTED(); // Not used by V8.
2592 }
Steve Block6ded16b2010-05-10 14:33:55 +01002593 }
2594}
2595
2596
Steve Block1e0659c2011-05-24 12:43:12 +01002597void Simulator::DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(
2598 Instruction* instr) {
2599 ASSERT((instr->Bit(4) == 1) && (instr->VCValue() == 0x0) &&
2600 (instr->VAValue() == 0x0));
Steve Block6ded16b2010-05-10 14:33:55 +01002601
Steve Block1e0659c2011-05-24 12:43:12 +01002602 int t = instr->RtValue();
2603 int n = instr->VFPNRegValue(kSinglePrecision);
2604 bool to_arm_register = (instr->VLValue() == 0x1);
Steve Block6ded16b2010-05-10 14:33:55 +01002605
2606 if (to_arm_register) {
2607 int32_t int_value = get_sinteger_from_s_register(n);
2608 set_register(t, int_value);
2609 } else {
2610 int32_t rs_val = get_register(t);
2611 set_s_register_from_sinteger(n, rs_val);
2612 }
2613}
2614
2615
Steve Block1e0659c2011-05-24 12:43:12 +01002616void Simulator::DecodeVCMP(Instruction* instr) {
2617 ASSERT((instr->Bit(4) == 0) && (instr->Opc1Value() == 0x7));
2618 ASSERT(((instr->Opc2Value() == 0x4) || (instr->Opc2Value() == 0x5)) &&
2619 (instr->Opc3Value() & 0x1));
Steve Block6ded16b2010-05-10 14:33:55 +01002620 // Comparison.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002621
2622 VFPRegPrecision precision = kSinglePrecision;
Steve Block1e0659c2011-05-24 12:43:12 +01002623 if (instr->SzValue() == 1) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002624 precision = kDoublePrecision;
2625 }
Steve Block6ded16b2010-05-10 14:33:55 +01002626
Steve Block1e0659c2011-05-24 12:43:12 +01002627 int d = instr->VFPDRegValue(precision);
Iain Merrick75681382010-08-19 15:07:18 +01002628 int m = 0;
Steve Block1e0659c2011-05-24 12:43:12 +01002629 if (instr->Opc2Value() == 0x4) {
2630 m = instr->VFPMRegValue(precision);
Iain Merrick75681382010-08-19 15:07:18 +01002631 }
Steve Block6ded16b2010-05-10 14:33:55 +01002632
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002633 if (precision == kDoublePrecision) {
Steve Block6ded16b2010-05-10 14:33:55 +01002634 double dd_value = get_double_from_d_register(d);
Iain Merrick75681382010-08-19 15:07:18 +01002635 double dm_value = 0.0;
Steve Block1e0659c2011-05-24 12:43:12 +01002636 if (instr->Opc2Value() == 0x4) {
Iain Merrick75681382010-08-19 15:07:18 +01002637 dm_value = get_double_from_d_register(m);
2638 }
Steve Block6ded16b2010-05-10 14:33:55 +01002639
Ben Murdoch086aeea2011-05-13 15:57:08 +01002640 // Raise exceptions for quiet NaNs if necessary.
2641 if (instr->Bit(7) == 1) {
2642 if (isnan(dd_value)) {
2643 inv_op_vfp_flag_ = true;
2644 }
2645 }
2646
Steve Block6ded16b2010-05-10 14:33:55 +01002647 Compute_FPSCR_Flags(dd_value, dm_value);
2648 } else {
2649 UNIMPLEMENTED(); // Not used by V8.
2650 }
2651}
2652
2653
Steve Block1e0659c2011-05-24 12:43:12 +01002654void Simulator::DecodeVCVTBetweenDoubleAndSingle(Instruction* instr) {
2655 ASSERT((instr->Bit(4) == 0) && (instr->Opc1Value() == 0x7));
2656 ASSERT((instr->Opc2Value() == 0x7) && (instr->Opc3Value() == 0x3));
Steve Block6ded16b2010-05-10 14:33:55 +01002657
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002658 VFPRegPrecision dst_precision = kDoublePrecision;
2659 VFPRegPrecision src_precision = kSinglePrecision;
Steve Block1e0659c2011-05-24 12:43:12 +01002660 if (instr->SzValue() == 1) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002661 dst_precision = kSinglePrecision;
2662 src_precision = kDoublePrecision;
2663 }
Steve Block6ded16b2010-05-10 14:33:55 +01002664
Steve Block1e0659c2011-05-24 12:43:12 +01002665 int dst = instr->VFPDRegValue(dst_precision);
2666 int src = instr->VFPMRegValue(src_precision);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002667
2668 if (dst_precision == kSinglePrecision) {
Steve Block6ded16b2010-05-10 14:33:55 +01002669 double val = get_double_from_d_register(src);
2670 set_s_register_from_float(dst, static_cast<float>(val));
2671 } else {
2672 float val = get_float_from_s_register(src);
2673 set_d_register_from_double(dst, static_cast<double>(val));
2674 }
2675}
2676
Steve Block1e0659c2011-05-24 12:43:12 +01002677bool get_inv_op_vfp_flag(VFPRoundingMode mode,
2678 double val,
2679 bool unsigned_) {
2680 ASSERT((mode == RN) || (mode == RM) || (mode == RZ));
2681 double max_uint = static_cast<double>(0xffffffffu);
2682 double max_int = static_cast<double>(kMaxInt);
2683 double min_int = static_cast<double>(kMinInt);
Steve Block6ded16b2010-05-10 14:33:55 +01002684
Steve Block1e0659c2011-05-24 12:43:12 +01002685 // Check for NaN.
2686 if (val != val) {
2687 return true;
2688 }
2689
2690 // Check for overflow. This code works because 32bit integers can be
2691 // exactly represented by ieee-754 64bit floating-point values.
2692 switch (mode) {
2693 case RN:
2694 return unsigned_ ? (val >= (max_uint + 0.5)) ||
2695 (val < -0.5)
2696 : (val >= (max_int + 0.5)) ||
2697 (val < (min_int - 0.5));
2698
2699 case RM:
2700 return unsigned_ ? (val >= (max_uint + 1.0)) ||
2701 (val < 0)
2702 : (val >= (max_int + 1.0)) ||
2703 (val < min_int);
2704
2705 case RZ:
2706 return unsigned_ ? (val >= (max_uint + 1.0)) ||
2707 (val <= -1)
2708 : (val >= (max_int + 1.0)) ||
2709 (val <= (min_int - 1.0));
2710 default:
2711 UNREACHABLE();
2712 return true;
2713 }
2714}
2715
2716
2717// We call this function only if we had a vfp invalid exception.
2718// It returns the correct saturated value.
2719int VFPConversionSaturate(double val, bool unsigned_res) {
2720 if (val != val) {
2721 return 0;
2722 } else {
2723 if (unsigned_res) {
2724 return (val < 0) ? 0 : 0xffffffffu;
2725 } else {
2726 return (val < 0) ? kMinInt : kMaxInt;
2727 }
2728 }
2729}
2730
2731
2732void Simulator::DecodeVCVTBetweenFloatingPointAndInteger(Instruction* instr) {
2733 ASSERT((instr->Bit(4) == 0) && (instr->Opc1Value() == 0x7) &&
2734 (instr->Bits(27, 23) == 0x1D));
2735 ASSERT(((instr->Opc2Value() == 0x8) && (instr->Opc3Value() & 0x1)) ||
2736 (((instr->Opc2Value() >> 1) == 0x6) && (instr->Opc3Value() & 0x1)));
Steve Block6ded16b2010-05-10 14:33:55 +01002737
2738 // Conversion between floating-point and integer.
Steve Block6ded16b2010-05-10 14:33:55 +01002739 bool to_integer = (instr->Bit(18) == 1);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002740
Steve Block1e0659c2011-05-24 12:43:12 +01002741 VFPRegPrecision src_precision = (instr->SzValue() == 1) ? kDoublePrecision
2742 : kSinglePrecision;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002743
Steve Block6ded16b2010-05-10 14:33:55 +01002744 if (to_integer) {
Steve Block1e0659c2011-05-24 12:43:12 +01002745 // We are playing with code close to the C++ standard's limits below,
2746 // hence the very simple code and heavy checks.
2747 //
2748 // Note:
2749 // C++ defines default type casting from floating point to integer as
2750 // (close to) rounding toward zero ("fractional part discarded").
2751
2752 int dst = instr->VFPDRegValue(kSinglePrecision);
2753 int src = instr->VFPMRegValue(src_precision);
2754
2755 // Bit 7 in vcvt instructions indicates if we should use the FPSCR rounding
2756 // mode or the default Round to Zero mode.
2757 VFPRoundingMode mode = (instr->Bit(7) != 1) ? FPSCR_rounding_mode_
2758 : RZ;
2759 ASSERT((mode == RM) || (mode == RZ) || (mode == RN));
2760
Steve Block6ded16b2010-05-10 14:33:55 +01002761 bool unsigned_integer = (instr->Bit(16) == 0);
Steve Block1e0659c2011-05-24 12:43:12 +01002762 bool double_precision = (src_precision == kDoublePrecision);
2763
2764 double val = double_precision ? get_double_from_d_register(src)
2765 : get_float_from_s_register(src);
2766
2767 int temp = unsigned_integer ? static_cast<uint32_t>(val)
2768 : static_cast<int32_t>(val);
2769
2770 inv_op_vfp_flag_ = get_inv_op_vfp_flag(mode, val, unsigned_integer);
2771
2772 if (inv_op_vfp_flag_) {
2773 temp = VFPConversionSaturate(val, unsigned_integer);
Russell Brenner90bac252010-11-18 13:33:46 -08002774 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01002775 switch (mode) {
2776 case RN: {
2777 double abs_diff =
2778 unsigned_integer ? fabs(val - static_cast<uint32_t>(temp))
2779 : fabs(val - temp);
2780 int val_sign = (val > 0) ? 1 : -1;
2781 if (abs_diff > 0.5) {
2782 temp += val_sign;
2783 } else if (abs_diff == 0.5) {
2784 // Round to even if exactly halfway.
2785 temp = ((temp % 2) == 0) ? temp : temp + val_sign;
2786 }
2787 break;
2788 }
2789
2790 case RM:
2791 temp = temp > val ? temp - 1 : temp;
2792 break;
2793
2794 case RZ:
2795 // Nothing to do.
2796 break;
2797
2798 default:
2799 UNREACHABLE();
2800 }
Steve Blockd0582a62009-12-15 09:54:21 +00002801 }
Steve Block6ded16b2010-05-10 14:33:55 +01002802
Steve Block1e0659c2011-05-24 12:43:12 +01002803 // Update the destination register.
2804 set_s_register_from_sinteger(dst, temp);
Russell Brenner90bac252010-11-18 13:33:46 -08002805
Steve Block6ded16b2010-05-10 14:33:55 +01002806 } else {
2807 bool unsigned_integer = (instr->Bit(7) == 0);
2808
Steve Block1e0659c2011-05-24 12:43:12 +01002809 int dst = instr->VFPDRegValue(src_precision);
2810 int src = instr->VFPMRegValue(kSinglePrecision);
Steve Block6ded16b2010-05-10 14:33:55 +01002811
2812 int val = get_sinteger_from_s_register(src);
2813
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002814 if (src_precision == kDoublePrecision) {
Steve Block6ded16b2010-05-10 14:33:55 +01002815 if (unsigned_integer) {
2816 set_d_register_from_double(dst,
2817 static_cast<double>((uint32_t)val));
2818 } else {
2819 set_d_register_from_double(dst, static_cast<double>(val));
2820 }
2821 } else {
2822 if (unsigned_integer) {
2823 set_s_register_from_float(dst,
2824 static_cast<float>((uint32_t)val));
2825 } else {
2826 set_s_register_from_float(dst, static_cast<float>(val));
2827 }
Steve Blockd0582a62009-12-15 09:54:21 +00002828 }
2829 }
2830}
2831
2832
Steve Block1e0659c2011-05-24 12:43:12 +01002833// void Simulator::DecodeType6CoprocessorIns(Instruction* instr)
Steve Blockd0582a62009-12-15 09:54:21 +00002834// Decode Type 6 coprocessor instructions.
Leon Clarkee46be812010-01-19 14:06:41 +00002835// Dm = vmov(Rt, Rt2)
2836// <Rt, Rt2> = vmov(Dm)
Leon Clarked91b9f72010-01-27 17:25:45 +00002837// Ddst = MEM(Rbase + 4*offset).
2838// MEM(Rbase + 4*offset) = Dsrc.
Steve Block1e0659c2011-05-24 12:43:12 +01002839void Simulator::DecodeType6CoprocessorIns(Instruction* instr) {
2840 ASSERT((instr->TypeValue() == 6));
Steve Blockd0582a62009-12-15 09:54:21 +00002841
Steve Block1e0659c2011-05-24 12:43:12 +01002842 if (instr->CoprocessorValue() == 0xA) {
2843 switch (instr->OpcodeValue()) {
Steve Block6ded16b2010-05-10 14:33:55 +01002844 case 0x8:
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002845 case 0xA:
2846 case 0xC:
2847 case 0xE: { // Load and store single precision float to memory.
Steve Block1e0659c2011-05-24 12:43:12 +01002848 int rn = instr->RnValue();
2849 int vd = instr->VFPDRegValue(kSinglePrecision);
2850 int offset = instr->Immed8Value();
Steve Block6ded16b2010-05-10 14:33:55 +01002851 if (!instr->HasU()) {
2852 offset = -offset;
2853 }
2854
2855 int32_t address = get_register(rn) + 4 * offset;
2856 if (instr->HasL()) {
2857 // Load double from memory: vldr.
2858 set_s_register_from_sinteger(vd, ReadW(address, instr));
2859 } else {
2860 // Store double to memory: vstr.
2861 WriteW(address, get_sinteger_from_s_register(vd), instr);
2862 }
2863 break;
2864 }
2865 default:
2866 UNIMPLEMENTED(); // Not used by V8.
2867 break;
2868 }
Steve Block1e0659c2011-05-24 12:43:12 +01002869 } else if (instr->CoprocessorValue() == 0xB) {
2870 switch (instr->OpcodeValue()) {
Leon Clarked91b9f72010-01-27 17:25:45 +00002871 case 0x2:
2872 // Load and store double to two GP registers
2873 if (instr->Bits(7, 4) != 0x1) {
2874 UNIMPLEMENTED(); // Not used by V8.
2875 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01002876 int rt = instr->RtValue();
2877 int rn = instr->RnValue();
2878 int vm = instr->VmValue();
Leon Clarked91b9f72010-01-27 17:25:45 +00002879 if (instr->HasL()) {
2880 int32_t rt_int_value = get_sinteger_from_s_register(2*vm);
2881 int32_t rn_int_value = get_sinteger_from_s_register(2*vm+1);
2882
2883 set_register(rt, rt_int_value);
2884 set_register(rn, rn_int_value);
2885 } else {
2886 int32_t rs_val = get_register(rt);
2887 int32_t rn_val = get_register(rn);
2888
2889 set_s_register_from_sinteger(2*vm, rs_val);
2890 set_s_register_from_sinteger((2*vm+1), rn_val);
2891 }
2892 }
2893 break;
2894 case 0x8:
2895 case 0xC: { // Load and store double to memory.
Steve Block1e0659c2011-05-24 12:43:12 +01002896 int rn = instr->RnValue();
2897 int vd = instr->VdValue();
2898 int offset = instr->Immed8Value();
Leon Clarked91b9f72010-01-27 17:25:45 +00002899 if (!instr->HasU()) {
2900 offset = -offset;
2901 }
2902 int32_t address = get_register(rn) + 4 * offset;
2903 if (instr->HasL()) {
2904 // Load double from memory: vldr.
2905 set_s_register_from_sinteger(2*vd, ReadW(address, instr));
2906 set_s_register_from_sinteger(2*vd + 1, ReadW(address + 4, instr));
2907 } else {
2908 // Store double to memory: vstr.
2909 WriteW(address, get_sinteger_from_s_register(2*vd), instr);
2910 WriteW(address + 4, get_sinteger_from_s_register(2*vd + 1), instr);
2911 }
2912 break;
2913 }
2914 default:
2915 UNIMPLEMENTED(); // Not used by V8.
2916 break;
2917 }
Steve Block6ded16b2010-05-10 14:33:55 +01002918 } else {
2919 UNIMPLEMENTED(); // Not used by V8.
Steve Blockd0582a62009-12-15 09:54:21 +00002920 }
2921}
2922
2923
Steve Blocka7e24c12009-10-30 11:49:00 +00002924// Executes the current instruction.
Steve Block1e0659c2011-05-24 12:43:12 +01002925void Simulator::InstructionDecode(Instruction* instr) {
Steve Block6ded16b2010-05-10 14:33:55 +01002926 if (v8::internal::FLAG_check_icache) {
2927 CheckICache(instr);
2928 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002929 pc_modified_ = false;
2930 if (::v8::internal::FLAG_trace_sim) {
2931 disasm::NameConverter converter;
2932 disasm::Disassembler dasm(converter);
2933 // use a reasonably large buffer
2934 v8::internal::EmbeddedVector<char, 256> buffer;
2935 dasm.InstructionDecode(buffer,
2936 reinterpret_cast<byte*>(instr));
Ben Murdochf87a2032010-10-22 12:50:53 +01002937 PrintF(" 0x%08x %s\n", reinterpret_cast<intptr_t>(instr), buffer.start());
Steve Blocka7e24c12009-10-30 11:49:00 +00002938 }
Steve Block1e0659c2011-05-24 12:43:12 +01002939 if (instr->ConditionField() == kSpecialCondition) {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002940 UNIMPLEMENTED();
Steve Blocka7e24c12009-10-30 11:49:00 +00002941 } else if (ConditionallyExecute(instr)) {
Steve Block1e0659c2011-05-24 12:43:12 +01002942 switch (instr->TypeValue()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002943 case 0:
2944 case 1: {
2945 DecodeType01(instr);
2946 break;
2947 }
2948 case 2: {
2949 DecodeType2(instr);
2950 break;
2951 }
2952 case 3: {
2953 DecodeType3(instr);
2954 break;
2955 }
2956 case 4: {
2957 DecodeType4(instr);
2958 break;
2959 }
2960 case 5: {
2961 DecodeType5(instr);
2962 break;
2963 }
2964 case 6: {
2965 DecodeType6(instr);
2966 break;
2967 }
2968 case 7: {
2969 DecodeType7(instr);
2970 break;
2971 }
2972 default: {
2973 UNIMPLEMENTED();
2974 break;
2975 }
2976 }
Steve Block1e0659c2011-05-24 12:43:12 +01002977 // If the instruction is a non taken conditional stop, we need to skip the
2978 // inlined message address.
2979 } else if (instr->IsStop()) {
2980 set_pc(get_pc() + 2 * Instruction::kInstrSize);
Steve Blocka7e24c12009-10-30 11:49:00 +00002981 }
2982 if (!pc_modified_) {
Steve Block1e0659c2011-05-24 12:43:12 +01002983 set_register(pc, reinterpret_cast<int32_t>(instr)
2984 + Instruction::kInstrSize);
Steve Blocka7e24c12009-10-30 11:49:00 +00002985 }
2986}
2987
2988
Steve Blocka7e24c12009-10-30 11:49:00 +00002989void Simulator::Execute() {
2990 // Get the PC to simulate. Cannot use the accessor here as we need the
2991 // raw PC value and not the one used as input to arithmetic instructions.
2992 int program_counter = get_pc();
2993
2994 if (::v8::internal::FLAG_stop_sim_at == 0) {
2995 // Fast version of the dispatch loop without checking whether the simulator
2996 // should be stopping at a particular executed instruction.
2997 while (program_counter != end_sim_pc) {
Steve Block1e0659c2011-05-24 12:43:12 +01002998 Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
Steve Blocka7e24c12009-10-30 11:49:00 +00002999 icount_++;
3000 InstructionDecode(instr);
3001 program_counter = get_pc();
3002 }
3003 } else {
3004 // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when
3005 // we reach the particular instuction count.
3006 while (program_counter != end_sim_pc) {
Steve Block1e0659c2011-05-24 12:43:12 +01003007 Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
Steve Blocka7e24c12009-10-30 11:49:00 +00003008 icount_++;
3009 if (icount_ == ::v8::internal::FLAG_stop_sim_at) {
3010 Debugger dbg(this);
3011 dbg.Debug();
3012 } else {
3013 InstructionDecode(instr);
3014 }
3015 program_counter = get_pc();
3016 }
3017 }
3018}
3019
3020
3021int32_t Simulator::Call(byte* entry, int argument_count, ...) {
3022 va_list parameters;
3023 va_start(parameters, argument_count);
3024 // Setup arguments
3025
3026 // First four arguments passed in registers.
3027 ASSERT(argument_count >= 4);
3028 set_register(r0, va_arg(parameters, int32_t));
3029 set_register(r1, va_arg(parameters, int32_t));
3030 set_register(r2, va_arg(parameters, int32_t));
3031 set_register(r3, va_arg(parameters, int32_t));
3032
3033 // Remaining arguments passed on stack.
3034 int original_stack = get_register(sp);
3035 // Compute position of stack on entry to generated code.
3036 int entry_stack = (original_stack - (argument_count - 4) * sizeof(int32_t));
3037 if (OS::ActivationFrameAlignment() != 0) {
3038 entry_stack &= -OS::ActivationFrameAlignment();
3039 }
3040 // Store remaining arguments on stack, from low to high memory.
3041 intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
3042 for (int i = 4; i < argument_count; i++) {
3043 stack_argument[i - 4] = va_arg(parameters, int32_t);
3044 }
3045 va_end(parameters);
3046 set_register(sp, entry_stack);
3047
3048 // Prepare to execute the code at entry
3049 set_register(pc, reinterpret_cast<int32_t>(entry));
3050 // Put down marker for end of simulation. The simulator will stop simulation
3051 // when the PC reaches this value. By saving the "end simulation" value into
3052 // the LR the simulation stops when returning to this call point.
3053 set_register(lr, end_sim_pc);
3054
3055 // Remember the values of callee-saved registers.
3056 // The code below assumes that r9 is not used as sb (static base) in
3057 // simulator code and therefore is regarded as a callee-saved register.
3058 int32_t r4_val = get_register(r4);
3059 int32_t r5_val = get_register(r5);
3060 int32_t r6_val = get_register(r6);
3061 int32_t r7_val = get_register(r7);
3062 int32_t r8_val = get_register(r8);
3063 int32_t r9_val = get_register(r9);
3064 int32_t r10_val = get_register(r10);
3065 int32_t r11_val = get_register(r11);
3066
3067 // Setup the callee-saved registers with a known value. To be able to check
3068 // that they are preserved properly across JS execution.
3069 int32_t callee_saved_value = icount_;
3070 set_register(r4, callee_saved_value);
3071 set_register(r5, callee_saved_value);
3072 set_register(r6, callee_saved_value);
3073 set_register(r7, callee_saved_value);
3074 set_register(r8, callee_saved_value);
3075 set_register(r9, callee_saved_value);
3076 set_register(r10, callee_saved_value);
3077 set_register(r11, callee_saved_value);
3078
3079 // Start the simulation
3080 Execute();
3081
3082 // Check that the callee-saved registers have been preserved.
3083 CHECK_EQ(callee_saved_value, get_register(r4));
3084 CHECK_EQ(callee_saved_value, get_register(r5));
3085 CHECK_EQ(callee_saved_value, get_register(r6));
3086 CHECK_EQ(callee_saved_value, get_register(r7));
3087 CHECK_EQ(callee_saved_value, get_register(r8));
3088 CHECK_EQ(callee_saved_value, get_register(r9));
3089 CHECK_EQ(callee_saved_value, get_register(r10));
3090 CHECK_EQ(callee_saved_value, get_register(r11));
3091
3092 // Restore callee-saved registers with the original value.
3093 set_register(r4, r4_val);
3094 set_register(r5, r5_val);
3095 set_register(r6, r6_val);
3096 set_register(r7, r7_val);
3097 set_register(r8, r8_val);
3098 set_register(r9, r9_val);
3099 set_register(r10, r10_val);
3100 set_register(r11, r11_val);
3101
3102 // Pop stack passed arguments.
3103 CHECK_EQ(entry_stack, get_register(sp));
3104 set_register(sp, original_stack);
3105
3106 int32_t result = get_register(r0);
3107 return result;
3108}
3109
Steve Blockd0582a62009-12-15 09:54:21 +00003110
3111uintptr_t Simulator::PushAddress(uintptr_t address) {
3112 int new_sp = get_register(sp) - sizeof(uintptr_t);
3113 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp);
3114 *stack_slot = address;
3115 set_register(sp, new_sp);
3116 return new_sp;
3117}
3118
3119
3120uintptr_t Simulator::PopAddress() {
3121 int current_sp = get_register(sp);
3122 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp);
3123 uintptr_t address = *stack_slot;
3124 set_register(sp, current_sp + sizeof(uintptr_t));
3125 return address;
3126}
3127
Steve Block1e0659c2011-05-24 12:43:12 +01003128} } // namespace v8::internal
Steve Blocka7e24c12009-10-30 11:49:00 +00003129
John Reck59135872010-11-02 12:39:01 -07003130#endif // USE_SIMULATOR
Leon Clarkef7060e22010-06-03 12:02:55 +01003131
3132#endif // V8_TARGET_ARCH_ARM