blob: 6af535553fb8bb7d3177d63106a50bd020cf7130 [file] [log] [blame]
Ben Murdoch8b112d22011-06-08 16:22:53 +01001// Copyright 2011 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
Steve Block44f0eee2011-05-26 01:26:41 +010052// The ArmDebugger class is used by the simulator while debugging simulated ARM
Steve Blocka7e24c12009-10-30 11:49:00 +000053// code.
Steve Block44f0eee2011-05-26 01:26:41 +010054class ArmDebugger {
Steve Blocka7e24c12009-10-30 11:49:00 +000055 public:
Steve Block44f0eee2011-05-26 01:26:41 +010056 explicit ArmDebugger(Simulator* sim);
57 ~ArmDebugger();
Steve Blocka7e24c12009-10-30 11:49:00 +000058
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 Murdoch8b112d22011-06-08 16:22:53 +010070 double GetRegisterPairDoubleValue(int regnum);
Ben Murdochb0fe1622011-05-05 13:52:32 +010071 double GetVFPDoubleRegisterValue(int regnum);
Steve Blocka7e24c12009-10-30 11:49:00 +000072 bool GetValue(const char* desc, int32_t* value);
Steve Block6ded16b2010-05-10 14:33:55 +010073 bool GetVFPSingleValue(const char* desc, float* value);
74 bool GetVFPDoubleValue(const char* desc, double* value);
Steve Blocka7e24c12009-10-30 11:49:00 +000075
76 // Set or delete a breakpoint. Returns true if successful.
Steve Block1e0659c2011-05-24 12:43:12 +010077 bool SetBreakpoint(Instruction* breakpc);
78 bool DeleteBreakpoint(Instruction* breakpc);
Steve Blocka7e24c12009-10-30 11:49:00 +000079
80 // Undo and redo all breakpoints. This is needed to bracket disassembly and
81 // execution to skip past breakpoints when run from the debugger.
82 void UndoBreakpoints();
83 void RedoBreakpoints();
84};
85
86
Steve Block44f0eee2011-05-26 01:26:41 +010087ArmDebugger::ArmDebugger(Simulator* sim) {
Steve Blocka7e24c12009-10-30 11:49:00 +000088 sim_ = sim;
89}
90
91
Steve Block44f0eee2011-05-26 01:26:41 +010092ArmDebugger::~ArmDebugger() {
Steve Blocka7e24c12009-10-30 11:49:00 +000093}
94
95
96
97#ifdef GENERATED_CODE_COVERAGE
98static FILE* coverage_log = NULL;
99
100
101static void InitializeCoverage() {
102 char* file_name = getenv("V8_GENERATED_CODE_COVERAGE_LOG");
103 if (file_name != NULL) {
104 coverage_log = fopen(file_name, "aw+");
105 }
106}
107
108
Steve Block44f0eee2011-05-26 01:26:41 +0100109void ArmDebugger::Stop(Instruction* instr) {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800110 // Get the stop code.
Steve Block1e0659c2011-05-24 12:43:12 +0100111 uint32_t code = instr->SvcValue() & kStopCodeMask;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800112 // Retrieve the encoded address, which comes just after this stop.
113 char** msg_address =
Steve Block1e0659c2011-05-24 12:43:12 +0100114 reinterpret_cast<char**>(sim_->get_pc() + Instruction::kInstrSize);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800115 char* msg = *msg_address;
116 ASSERT(msg != NULL);
117
118 // Update this stop description.
119 if (isWatchedStop(code) && !watched_stops[code].desc) {
120 watched_stops[code].desc = msg;
121 }
122
123 if (strlen(msg) > 0) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000124 if (coverage_log != NULL) {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800125 fprintf(coverage_log, "%s\n", msg);
Steve Blocka7e24c12009-10-30 11:49:00 +0000126 fflush(coverage_log);
127 }
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800128 // Overwrite the instruction and address with nops.
129 instr->SetInstructionBits(kNopInstr);
Steve Block1e0659c2011-05-24 12:43:12 +0100130 reinterpret_cast<Instruction*>(msg_address)->SetInstructionBits(kNopInstr);
Steve Blocka7e24c12009-10-30 11:49:00 +0000131 }
Steve Block1e0659c2011-05-24 12:43:12 +0100132 sim_->set_pc(sim_->get_pc() + 2 * Instruction::kInstrSize);
Steve Blocka7e24c12009-10-30 11:49:00 +0000133}
134
135#else // ndef GENERATED_CODE_COVERAGE
136
137static void InitializeCoverage() {
138}
139
140
Steve Block44f0eee2011-05-26 01:26:41 +0100141void ArmDebugger::Stop(Instruction* instr) {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800142 // Get the stop code.
Steve Block1e0659c2011-05-24 12:43:12 +0100143 uint32_t code = instr->SvcValue() & kStopCodeMask;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800144 // Retrieve the encoded address, which comes just after this stop.
Steve Block1e0659c2011-05-24 12:43:12 +0100145 char* msg = *reinterpret_cast<char**>(sim_->get_pc()
146 + Instruction::kInstrSize);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800147 // Update this stop description.
148 if (sim_->isWatchedStop(code) && !sim_->watched_stops[code].desc) {
149 sim_->watched_stops[code].desc = msg;
150 }
Steve Block1e0659c2011-05-24 12:43:12 +0100151 // Print the stop message and code if it is not the default code.
152 if (code != kMaxStopCode) {
153 PrintF("Simulator hit stop %u: %s\n", code, msg);
154 } else {
155 PrintF("Simulator hit %s\n", msg);
156 }
157 sim_->set_pc(sim_->get_pc() + 2 * Instruction::kInstrSize);
Steve Blocka7e24c12009-10-30 11:49:00 +0000158 Debug();
159}
160#endif
161
162
Steve Block44f0eee2011-05-26 01:26:41 +0100163int32_t ArmDebugger::GetRegisterValue(int regnum) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000164 if (regnum == kPCRegister) {
165 return sim_->get_pc();
166 } else {
167 return sim_->get_register(regnum);
168 }
169}
170
171
Ben Murdoch8b112d22011-06-08 16:22:53 +0100172double ArmDebugger::GetRegisterPairDoubleValue(int regnum) {
173 return sim_->get_double_from_register_pair(regnum);
174}
175
176
Steve Block44f0eee2011-05-26 01:26:41 +0100177double ArmDebugger::GetVFPDoubleRegisterValue(int regnum) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100178 return sim_->get_double_from_d_register(regnum);
179}
180
181
Steve Block44f0eee2011-05-26 01:26:41 +0100182bool ArmDebugger::GetValue(const char* desc, int32_t* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000183 int regnum = Registers::Number(desc);
184 if (regnum != kNoRegister) {
185 *value = GetRegisterValue(regnum);
186 return true;
187 } else {
Steve Block6ded16b2010-05-10 14:33:55 +0100188 if (strncmp(desc, "0x", 2) == 0) {
189 return SScanF(desc + 2, "%x", reinterpret_cast<uint32_t*>(value)) == 1;
190 } else {
191 return SScanF(desc, "%u", reinterpret_cast<uint32_t*>(value)) == 1;
192 }
193 }
194 return false;
195}
196
197
Steve Block44f0eee2011-05-26 01:26:41 +0100198bool ArmDebugger::GetVFPSingleValue(const char* desc, float* value) {
Steve Block6ded16b2010-05-10 14:33:55 +0100199 bool is_double;
200 int regnum = VFPRegisters::Number(desc, &is_double);
201 if (regnum != kNoRegister && !is_double) {
202 *value = sim_->get_float_from_s_register(regnum);
203 return true;
204 }
205 return false;
206}
207
208
Steve Block44f0eee2011-05-26 01:26:41 +0100209bool ArmDebugger::GetVFPDoubleValue(const char* desc, double* value) {
Steve Block6ded16b2010-05-10 14:33:55 +0100210 bool is_double;
211 int regnum = VFPRegisters::Number(desc, &is_double);
212 if (regnum != kNoRegister && is_double) {
213 *value = sim_->get_double_from_d_register(regnum);
214 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +0000215 }
216 return false;
217}
218
219
Steve Block44f0eee2011-05-26 01:26:41 +0100220bool ArmDebugger::SetBreakpoint(Instruction* breakpc) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000221 // Check if a breakpoint can be set. If not return without any side-effects.
222 if (sim_->break_pc_ != NULL) {
223 return false;
224 }
225
226 // Set the breakpoint.
227 sim_->break_pc_ = breakpc;
228 sim_->break_instr_ = breakpc->InstructionBits();
229 // Not setting the breakpoint instruction in the code itself. It will be set
230 // when the debugger shell continues.
231 return true;
232}
233
234
Steve Block44f0eee2011-05-26 01:26:41 +0100235bool ArmDebugger::DeleteBreakpoint(Instruction* breakpc) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000236 if (sim_->break_pc_ != NULL) {
237 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
238 }
239
240 sim_->break_pc_ = NULL;
241 sim_->break_instr_ = 0;
242 return true;
243}
244
245
Steve Block44f0eee2011-05-26 01:26:41 +0100246void ArmDebugger::UndoBreakpoints() {
Steve Blocka7e24c12009-10-30 11:49:00 +0000247 if (sim_->break_pc_ != NULL) {
248 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
249 }
250}
251
252
Steve Block44f0eee2011-05-26 01:26:41 +0100253void ArmDebugger::RedoBreakpoints() {
Steve Blocka7e24c12009-10-30 11:49:00 +0000254 if (sim_->break_pc_ != NULL) {
255 sim_->break_pc_->SetInstructionBits(kBreakpointInstr);
256 }
257}
258
259
Steve Block44f0eee2011-05-26 01:26:41 +0100260void ArmDebugger::Debug() {
Steve Blocka7e24c12009-10-30 11:49:00 +0000261 intptr_t last_pc = -1;
262 bool done = false;
263
264#define COMMAND_SIZE 63
265#define ARG_SIZE 255
266
267#define STR(a) #a
268#define XSTR(a) STR(a)
269
270 char cmd[COMMAND_SIZE + 1];
271 char arg1[ARG_SIZE + 1];
272 char arg2[ARG_SIZE + 1];
Steve Block6ded16b2010-05-10 14:33:55 +0100273 char* argv[3] = { cmd, arg1, arg2 };
Steve Blocka7e24c12009-10-30 11:49:00 +0000274
275 // make sure to have a proper terminating character if reaching the limit
276 cmd[COMMAND_SIZE] = 0;
277 arg1[ARG_SIZE] = 0;
278 arg2[ARG_SIZE] = 0;
279
280 // Undo all set breakpoints while running in the debugger shell. This will
281 // make them invisible to all commands.
282 UndoBreakpoints();
283
284 while (!done) {
285 if (last_pc != sim_->get_pc()) {
286 disasm::NameConverter converter;
287 disasm::Disassembler dasm(converter);
288 // use a reasonably large buffer
289 v8::internal::EmbeddedVector<char, 256> buffer;
290 dasm.InstructionDecode(buffer,
291 reinterpret_cast<byte*>(sim_->get_pc()));
292 PrintF(" 0x%08x %s\n", sim_->get_pc(), buffer.start());
293 last_pc = sim_->get_pc();
294 }
295 char* line = ReadLine("sim> ");
296 if (line == NULL) {
297 break;
298 } else {
299 // Use sscanf to parse the individual parts of the command line. At the
300 // moment no command expects more than two parameters.
Steve Block6ded16b2010-05-10 14:33:55 +0100301 int argc = SScanF(line,
Steve Blocka7e24c12009-10-30 11:49:00 +0000302 "%" XSTR(COMMAND_SIZE) "s "
303 "%" XSTR(ARG_SIZE) "s "
304 "%" XSTR(ARG_SIZE) "s",
305 cmd, arg1, arg2);
306 if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
Steve Block1e0659c2011-05-24 12:43:12 +0100307 sim_->InstructionDecode(reinterpret_cast<Instruction*>(sim_->get_pc()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000308 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) {
309 // Execute the one instruction we broke at with breakpoints disabled.
Steve Block1e0659c2011-05-24 12:43:12 +0100310 sim_->InstructionDecode(reinterpret_cast<Instruction*>(sim_->get_pc()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000311 // Leave the debugger shell.
312 done = true;
313 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100314 if (argc == 2 || (argc == 3 && strcmp(arg2, "fp") == 0)) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000315 int32_t value;
Steve Block6ded16b2010-05-10 14:33:55 +0100316 float svalue;
317 double dvalue;
Steve Blocka7e24c12009-10-30 11:49:00 +0000318 if (strcmp(arg1, "all") == 0) {
319 for (int i = 0; i < kNumRegisters; i++) {
320 value = GetRegisterValue(i);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100321 PrintF("%3s: 0x%08x %10d", Registers::Name(i), value, value);
322 if ((argc == 3 && strcmp(arg2, "fp") == 0) &&
323 i < 8 &&
324 (i % 2) == 0) {
325 dvalue = GetRegisterPairDoubleValue(i);
326 PrintF(" (%f)\n", dvalue);
327 } else {
328 PrintF("\n");
329 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000330 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100331 for (int i = 0; i < kNumVFPDoubleRegisters; i++) {
332 dvalue = GetVFPDoubleRegisterValue(i);
Steve Block44f0eee2011-05-26 01:26:41 +0100333 uint64_t as_words = BitCast<uint64_t>(dvalue);
334 PrintF("%3s: %f 0x%08x %08x\n",
335 VFPRegisters::Name(i, true),
336 dvalue,
337 static_cast<uint32_t>(as_words >> 32),
338 static_cast<uint32_t>(as_words & 0xffffffff));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100339 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000340 } else {
341 if (GetValue(arg1, &value)) {
342 PrintF("%s: 0x%08x %d \n", arg1, value, value);
Steve Block6ded16b2010-05-10 14:33:55 +0100343 } else if (GetVFPSingleValue(arg1, &svalue)) {
Steve Block44f0eee2011-05-26 01:26:41 +0100344 uint32_t as_word = BitCast<uint32_t>(svalue);
345 PrintF("%s: %f 0x%08x\n", arg1, svalue, as_word);
Steve Block6ded16b2010-05-10 14:33:55 +0100346 } else if (GetVFPDoubleValue(arg1, &dvalue)) {
Steve Block44f0eee2011-05-26 01:26:41 +0100347 uint64_t as_words = BitCast<uint64_t>(dvalue);
348 PrintF("%s: %f 0x%08x %08x\n",
349 arg1,
350 dvalue,
351 static_cast<uint32_t>(as_words >> 32),
352 static_cast<uint32_t>(as_words & 0xffffffff));
Steve Blocka7e24c12009-10-30 11:49:00 +0000353 } else {
354 PrintF("%s unrecognized\n", arg1);
355 }
356 }
357 } else {
358 PrintF("print <register>\n");
359 }
360 } else if ((strcmp(cmd, "po") == 0)
361 || (strcmp(cmd, "printobject") == 0)) {
Steve Block6ded16b2010-05-10 14:33:55 +0100362 if (argc == 2) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000363 int32_t value;
364 if (GetValue(arg1, &value)) {
365 Object* obj = reinterpret_cast<Object*>(value);
366 PrintF("%s: \n", arg1);
367#ifdef DEBUG
368 obj->PrintLn();
369#else
370 obj->ShortPrint();
371 PrintF("\n");
372#endif
373 } else {
374 PrintF("%s unrecognized\n", arg1);
375 }
376 } else {
377 PrintF("printobject <value>\n");
378 }
Steve Block6ded16b2010-05-10 14:33:55 +0100379 } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0) {
380 int32_t* cur = NULL;
381 int32_t* end = NULL;
382 int next_arg = 1;
383
384 if (strcmp(cmd, "stack") == 0) {
385 cur = reinterpret_cast<int32_t*>(sim_->get_register(Simulator::sp));
386 } else { // "mem"
387 int32_t value;
388 if (!GetValue(arg1, &value)) {
389 PrintF("%s unrecognized\n", arg1);
390 continue;
391 }
392 cur = reinterpret_cast<int32_t*>(value);
393 next_arg++;
394 }
395
396 int32_t words;
397 if (argc == next_arg) {
398 words = 10;
399 } else if (argc == next_arg + 1) {
400 if (!GetValue(argv[next_arg], &words)) {
401 words = 10;
402 }
403 }
404 end = cur + words;
405
406 while (cur < end) {
Steve Block44f0eee2011-05-26 01:26:41 +0100407 PrintF(" 0x%08x: 0x%08x %10d",
Ben Murdochf87a2032010-10-22 12:50:53 +0100408 reinterpret_cast<intptr_t>(cur), *cur, *cur);
Steve Block44f0eee2011-05-26 01:26:41 +0100409 HeapObject* obj = reinterpret_cast<HeapObject*>(*cur);
410 int value = *cur;
411 Heap* current_heap = v8::internal::Isolate::Current()->heap();
412 if (current_heap->Contains(obj) || ((value & 1) == 0)) {
413 PrintF(" (");
414 if ((value & 1) == 0) {
415 PrintF("smi %d", value / 2);
416 } else {
417 obj->ShortPrint();
418 }
419 PrintF(")");
420 }
421 PrintF("\n");
Steve Block6ded16b2010-05-10 14:33:55 +0100422 cur++;
423 }
Steve Block44f0eee2011-05-26 01:26:41 +0100424 } else if (strcmp(cmd, "disasm") == 0 || strcmp(cmd, "di") == 0) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000425 disasm::NameConverter converter;
426 disasm::Disassembler dasm(converter);
427 // use a reasonably large buffer
428 v8::internal::EmbeddedVector<char, 256> buffer;
429
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800430 byte* prev = NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +0000431 byte* cur = NULL;
432 byte* end = NULL;
433
Steve Block6ded16b2010-05-10 14:33:55 +0100434 if (argc == 1) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000435 cur = reinterpret_cast<byte*>(sim_->get_pc());
Steve Block1e0659c2011-05-24 12:43:12 +0100436 end = cur + (10 * Instruction::kInstrSize);
Steve Block6ded16b2010-05-10 14:33:55 +0100437 } else if (argc == 2) {
Steve Block44f0eee2011-05-26 01:26:41 +0100438 int regnum = Registers::Number(arg1);
439 if (regnum != kNoRegister || strncmp(arg1, "0x", 2) == 0) {
440 // The argument is an address or a register name.
441 int32_t value;
442 if (GetValue(arg1, &value)) {
443 cur = reinterpret_cast<byte*>(value);
444 // Disassemble 10 instructions at <arg1>.
445 end = cur + (10 * Instruction::kInstrSize);
446 }
447 } else {
448 // The argument is the number of instructions.
449 int32_t value;
450 if (GetValue(arg1, &value)) {
451 cur = reinterpret_cast<byte*>(sim_->get_pc());
452 // Disassemble <arg1> instructions.
453 end = cur + (value * Instruction::kInstrSize);
454 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000455 }
456 } else {
457 int32_t value1;
458 int32_t value2;
459 if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
460 cur = reinterpret_cast<byte*>(value1);
Steve Block1e0659c2011-05-24 12:43:12 +0100461 end = cur + (value2 * Instruction::kInstrSize);
Steve Blocka7e24c12009-10-30 11:49:00 +0000462 }
463 }
464
465 while (cur < end) {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800466 prev = cur;
467 cur += dasm.InstructionDecode(buffer, cur);
Ben Murdochf87a2032010-10-22 12:50:53 +0100468 PrintF(" 0x%08x %s\n",
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800469 reinterpret_cast<intptr_t>(prev), buffer.start());
Steve Blocka7e24c12009-10-30 11:49:00 +0000470 }
471 } else if (strcmp(cmd, "gdb") == 0) {
472 PrintF("relinquishing control to gdb\n");
473 v8::internal::OS::DebugBreak();
474 PrintF("regaining control from gdb\n");
475 } else if (strcmp(cmd, "break") == 0) {
Steve Block6ded16b2010-05-10 14:33:55 +0100476 if (argc == 2) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000477 int32_t value;
478 if (GetValue(arg1, &value)) {
Steve Block1e0659c2011-05-24 12:43:12 +0100479 if (!SetBreakpoint(reinterpret_cast<Instruction*>(value))) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000480 PrintF("setting breakpoint failed\n");
481 }
482 } else {
483 PrintF("%s unrecognized\n", arg1);
484 }
485 } else {
486 PrintF("break <address>\n");
487 }
488 } else if (strcmp(cmd, "del") == 0) {
489 if (!DeleteBreakpoint(NULL)) {
490 PrintF("deleting breakpoint failed\n");
491 }
492 } else if (strcmp(cmd, "flags") == 0) {
493 PrintF("N flag: %d; ", sim_->n_flag_);
494 PrintF("Z flag: %d; ", sim_->z_flag_);
495 PrintF("C flag: %d; ", sim_->c_flag_);
496 PrintF("V flag: %d\n", sim_->v_flag_);
Steve Blockd0582a62009-12-15 09:54:21 +0000497 PrintF("INVALID OP flag: %d; ", sim_->inv_op_vfp_flag_);
498 PrintF("DIV BY ZERO flag: %d; ", sim_->div_zero_vfp_flag_);
499 PrintF("OVERFLOW flag: %d; ", sim_->overflow_vfp_flag_);
500 PrintF("UNDERFLOW flag: %d; ", sim_->underflow_vfp_flag_);
Steve Block1e0659c2011-05-24 12:43:12 +0100501 PrintF("INEXACT flag: %d;\n", sim_->inexact_vfp_flag_);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800502 } else if (strcmp(cmd, "stop") == 0) {
503 int32_t value;
Steve Block1e0659c2011-05-24 12:43:12 +0100504 intptr_t stop_pc = sim_->get_pc() - 2 * Instruction::kInstrSize;
505 Instruction* stop_instr = reinterpret_cast<Instruction*>(stop_pc);
506 Instruction* msg_address =
507 reinterpret_cast<Instruction*>(stop_pc + Instruction::kInstrSize);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800508 if ((argc == 2) && (strcmp(arg1, "unstop") == 0)) {
509 // Remove the current stop.
510 if (sim_->isStopInstruction(stop_instr)) {
511 stop_instr->SetInstructionBits(kNopInstr);
512 msg_address->SetInstructionBits(kNopInstr);
513 } else {
514 PrintF("Not at debugger stop.\n");
515 }
516 } else if (argc == 3) {
517 // Print information about all/the specified breakpoint(s).
518 if (strcmp(arg1, "info") == 0) {
519 if (strcmp(arg2, "all") == 0) {
520 PrintF("Stop information:\n");
521 for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) {
522 sim_->PrintStopInfo(i);
523 }
524 } else if (GetValue(arg2, &value)) {
525 sim_->PrintStopInfo(value);
526 } else {
527 PrintF("Unrecognized argument.\n");
528 }
529 } else if (strcmp(arg1, "enable") == 0) {
530 // Enable all/the specified breakpoint(s).
531 if (strcmp(arg2, "all") == 0) {
532 for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) {
533 sim_->EnableStop(i);
534 }
535 } else if (GetValue(arg2, &value)) {
536 sim_->EnableStop(value);
537 } else {
538 PrintF("Unrecognized argument.\n");
539 }
540 } else if (strcmp(arg1, "disable") == 0) {
541 // Disable all/the specified breakpoint(s).
542 if (strcmp(arg2, "all") == 0) {
543 for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) {
544 sim_->DisableStop(i);
545 }
546 } else if (GetValue(arg2, &value)) {
547 sim_->DisableStop(value);
548 } else {
549 PrintF("Unrecognized argument.\n");
550 }
551 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000552 } else {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800553 PrintF("Wrong usage. Use help command for more information.\n");
Steve Blocka7e24c12009-10-30 11:49:00 +0000554 }
Leon Clarkee46be812010-01-19 14:06:41 +0000555 } else if ((strcmp(cmd, "t") == 0) || strcmp(cmd, "trace") == 0) {
556 ::v8::internal::FLAG_trace_sim = !::v8::internal::FLAG_trace_sim;
557 PrintF("Trace of executed instructions is %s\n",
558 ::v8::internal::FLAG_trace_sim ? "on" : "off");
Steve Blocka7e24c12009-10-30 11:49:00 +0000559 } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
560 PrintF("cont\n");
561 PrintF(" continue execution (alias 'c')\n");
562 PrintF("stepi\n");
563 PrintF(" step one instruction (alias 'si')\n");
564 PrintF("print <register>\n");
565 PrintF(" print register content (alias 'p')\n");
566 PrintF(" use register name 'all' to print all registers\n");
Ben Murdoch8b112d22011-06-08 16:22:53 +0100567 PrintF(" add argument 'fp' to print register pair double values\n");
Steve Blocka7e24c12009-10-30 11:49:00 +0000568 PrintF("printobject <register>\n");
569 PrintF(" print an object from a register (alias 'po')\n");
570 PrintF("flags\n");
571 PrintF(" print flags\n");
Steve Block6ded16b2010-05-10 14:33:55 +0100572 PrintF("stack [<words>]\n");
573 PrintF(" dump stack content, default dump 10 words)\n");
574 PrintF("mem <address> [<words>]\n");
575 PrintF(" dump memory content, default dump 10 words)\n");
Steve Blocka7e24c12009-10-30 11:49:00 +0000576 PrintF("disasm [<instructions>]\n");
Steve Block44f0eee2011-05-26 01:26:41 +0100577 PrintF("disasm [<address/register>]\n");
578 PrintF("disasm [[<address/register>] <instructions>]\n");
579 PrintF(" disassemble code, default is 10 instructions\n");
580 PrintF(" from pc (alias 'di')\n");
Steve Blocka7e24c12009-10-30 11:49:00 +0000581 PrintF("gdb\n");
582 PrintF(" enter gdb\n");
583 PrintF("break <address>\n");
584 PrintF(" set a break point on the address\n");
585 PrintF("del\n");
586 PrintF(" delete the breakpoint\n");
Leon Clarkee46be812010-01-19 14:06:41 +0000587 PrintF("trace (alias 't')\n");
Steve Block6ded16b2010-05-10 14:33:55 +0100588 PrintF(" toogle the tracing of all executed statements\n");
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800589 PrintF("stop feature:\n");
590 PrintF(" Description:\n");
591 PrintF(" Stops are debug instructions inserted by\n");
592 PrintF(" the Assembler::stop() function.\n");
593 PrintF(" When hitting a stop, the Simulator will\n");
Steve Block44f0eee2011-05-26 01:26:41 +0100594 PrintF(" stop and and give control to the ArmDebugger.\n");
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800595 PrintF(" The first %d stop codes are watched:\n",
596 Simulator::kNumOfWatchedStops);
597 PrintF(" - They can be enabled / disabled: the Simulator\n");
Steve Block44f0eee2011-05-26 01:26:41 +0100598 PrintF(" will / won't stop when hitting them.\n");
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800599 PrintF(" - The Simulator keeps track of how many times they \n");
600 PrintF(" are met. (See the info command.) Going over a\n");
601 PrintF(" disabled stop still increases its counter. \n");
602 PrintF(" Commands:\n");
603 PrintF(" stop info all/<code> : print infos about number <code>\n");
604 PrintF(" or all stop(s).\n");
605 PrintF(" stop enable/disable all/<code> : enables / disables\n");
606 PrintF(" all or number <code> stop(s)\n");
607 PrintF(" stop unstop\n");
608 PrintF(" ignore the stop instruction at the current location\n");
609 PrintF(" from now on\n");
Steve Blocka7e24c12009-10-30 11:49:00 +0000610 } else {
611 PrintF("Unknown command: %s\n", cmd);
612 }
613 }
614 DeleteArray(line);
615 }
616
617 // Add all the breakpoints back to stop execution and enter the debugger
618 // shell when hit.
619 RedoBreakpoints();
620
621#undef COMMAND_SIZE
622#undef ARG_SIZE
623
624#undef STR
625#undef XSTR
626}
627
628
Steve Block6ded16b2010-05-10 14:33:55 +0100629static bool ICacheMatch(void* one, void* two) {
630 ASSERT((reinterpret_cast<intptr_t>(one) & CachePage::kPageMask) == 0);
631 ASSERT((reinterpret_cast<intptr_t>(two) & CachePage::kPageMask) == 0);
632 return one == two;
633}
634
635
636static uint32_t ICacheHash(void* key) {
637 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)) >> 2;
638}
639
640
641static bool AllOnOnePage(uintptr_t start, int size) {
642 intptr_t start_page = (start & ~CachePage::kPageMask);
643 intptr_t end_page = ((start + size) & ~CachePage::kPageMask);
644 return start_page == end_page;
645}
646
647
Steve Block44f0eee2011-05-26 01:26:41 +0100648void Simulator::FlushICache(v8::internal::HashMap* i_cache,
649 void* start_addr,
650 size_t size) {
Steve Block6ded16b2010-05-10 14:33:55 +0100651 intptr_t start = reinterpret_cast<intptr_t>(start_addr);
652 int intra_line = (start & CachePage::kLineMask);
653 start -= intra_line;
654 size += intra_line;
655 size = ((size - 1) | CachePage::kLineMask) + 1;
656 int offset = (start & CachePage::kPageMask);
657 while (!AllOnOnePage(start, size - 1)) {
658 int bytes_to_flush = CachePage::kPageSize - offset;
Steve Block44f0eee2011-05-26 01:26:41 +0100659 FlushOnePage(i_cache, start, bytes_to_flush);
Steve Block6ded16b2010-05-10 14:33:55 +0100660 start += bytes_to_flush;
661 size -= bytes_to_flush;
662 ASSERT_EQ(0, start & CachePage::kPageMask);
663 offset = 0;
664 }
665 if (size != 0) {
Steve Block44f0eee2011-05-26 01:26:41 +0100666 FlushOnePage(i_cache, start, size);
Steve Block6ded16b2010-05-10 14:33:55 +0100667 }
668}
669
670
Steve Block44f0eee2011-05-26 01:26:41 +0100671CachePage* Simulator::GetCachePage(v8::internal::HashMap* i_cache, void* page) {
672 v8::internal::HashMap::Entry* entry = i_cache->Lookup(page,
673 ICacheHash(page),
674 true);
Steve Block6ded16b2010-05-10 14:33:55 +0100675 if (entry->value == NULL) {
676 CachePage* new_page = new CachePage();
677 entry->value = new_page;
678 }
679 return reinterpret_cast<CachePage*>(entry->value);
680}
681
682
683// Flush from start up to and not including start + size.
Steve Block44f0eee2011-05-26 01:26:41 +0100684void Simulator::FlushOnePage(v8::internal::HashMap* i_cache,
685 intptr_t start,
686 int size) {
Steve Block6ded16b2010-05-10 14:33:55 +0100687 ASSERT(size <= CachePage::kPageSize);
688 ASSERT(AllOnOnePage(start, size - 1));
689 ASSERT((start & CachePage::kLineMask) == 0);
690 ASSERT((size & CachePage::kLineMask) == 0);
691 void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask));
692 int offset = (start & CachePage::kPageMask);
Steve Block44f0eee2011-05-26 01:26:41 +0100693 CachePage* cache_page = GetCachePage(i_cache, page);
Steve Block6ded16b2010-05-10 14:33:55 +0100694 char* valid_bytemap = cache_page->ValidityByte(offset);
695 memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift);
696}
697
698
Steve Block44f0eee2011-05-26 01:26:41 +0100699void Simulator::CheckICache(v8::internal::HashMap* i_cache,
700 Instruction* instr) {
Steve Block6ded16b2010-05-10 14:33:55 +0100701 intptr_t address = reinterpret_cast<intptr_t>(instr);
702 void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
703 void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask));
704 int offset = (address & CachePage::kPageMask);
Steve Block44f0eee2011-05-26 01:26:41 +0100705 CachePage* cache_page = GetCachePage(i_cache, page);
Steve Block6ded16b2010-05-10 14:33:55 +0100706 char* cache_valid_byte = cache_page->ValidityByte(offset);
707 bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID);
708 char* cached_line = cache_page->CachedData(offset & ~CachePage::kLineMask);
709 if (cache_hit) {
710 // Check that the data in memory matches the contents of the I-cache.
711 CHECK(memcmp(reinterpret_cast<void*>(instr),
712 cache_page->CachedData(offset),
Steve Block1e0659c2011-05-24 12:43:12 +0100713 Instruction::kInstrSize) == 0);
Steve Block6ded16b2010-05-10 14:33:55 +0100714 } else {
715 // Cache miss. Load memory into the cache.
716 memcpy(cached_line, line, CachePage::kLineLength);
717 *cache_valid_byte = CachePage::LINE_VALID;
718 }
719}
720
721
Ben Murdoch257744e2011-11-30 15:57:28 +0000722void Simulator::Initialize(Isolate* isolate) {
723 if (isolate->simulator_initialized()) return;
724 isolate->set_simulator_initialized(true);
725 ::v8::internal::ExternalReference::set_redirector(isolate,
726 &RedirectExternalReference);
Steve Blocka7e24c12009-10-30 11:49:00 +0000727}
728
729
Ben Murdoch257744e2011-11-30 15:57:28 +0000730Simulator::Simulator(Isolate* isolate) : isolate_(isolate) {
Steve Block44f0eee2011-05-26 01:26:41 +0100731 i_cache_ = isolate_->simulator_i_cache();
Steve Block6ded16b2010-05-10 14:33:55 +0100732 if (i_cache_ == NULL) {
733 i_cache_ = new v8::internal::HashMap(&ICacheMatch);
Steve Block44f0eee2011-05-26 01:26:41 +0100734 isolate_->set_simulator_i_cache(i_cache_);
Steve Block6ded16b2010-05-10 14:33:55 +0100735 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000736 Initialize(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000737 // Setup simulator support first. Some of this information is needed to
738 // setup the architecture state.
739 size_t stack_size = 1 * 1024*1024; // allocate 1MB for stack
740 stack_ = reinterpret_cast<char*>(malloc(stack_size));
741 pc_modified_ = false;
742 icount_ = 0;
743 break_pc_ = NULL;
744 break_instr_ = 0;
745
746 // Setup architecture state.
747 // All registers are initialized to zero to start with.
748 for (int i = 0; i < num_registers; i++) {
749 registers_[i] = 0;
750 }
751 n_flag_ = false;
752 z_flag_ = false;
753 c_flag_ = false;
754 v_flag_ = false;
755
Steve Blockd0582a62009-12-15 09:54:21 +0000756 // Initializing VFP registers.
757 // All registers are initialized to zero to start with
758 // even though s_registers_ & d_registers_ share the same
759 // physical registers in the target.
760 for (int i = 0; i < num_s_registers; i++) {
761 vfp_register[i] = 0;
762 }
763 n_flag_FPSCR_ = false;
764 z_flag_FPSCR_ = false;
765 c_flag_FPSCR_ = false;
766 v_flag_FPSCR_ = false;
Russell Brenner90bac252010-11-18 13:33:46 -0800767 FPSCR_rounding_mode_ = RZ;
Steve Blockd0582a62009-12-15 09:54:21 +0000768
769 inv_op_vfp_flag_ = false;
770 div_zero_vfp_flag_ = false;
771 overflow_vfp_flag_ = false;
772 underflow_vfp_flag_ = false;
773 inexact_vfp_flag_ = false;
774
Steve Blocka7e24c12009-10-30 11:49:00 +0000775 // The sp is initialized to point to the bottom (high address) of the
776 // allocated stack area. To be safe in potential stack underflows we leave
777 // some buffer below.
778 registers_[sp] = reinterpret_cast<int32_t>(stack_) + stack_size - 64;
779 // The lr and pc are initialized to a known bad value that will cause an
780 // access violation if the simulator ever tries to execute it.
781 registers_[pc] = bad_lr;
782 registers_[lr] = bad_lr;
783 InitializeCoverage();
784}
785
786
787// When the generated code calls an external reference we need to catch that in
788// the simulator. The external reference will be a function compiled for the
789// host architecture. We need to call that function instead of trying to
790// execute it with the simulator. We do that by redirecting the external
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800791// reference to a svc (Supervisor Call) instruction that is handled by
Steve Blocka7e24c12009-10-30 11:49:00 +0000792// the simulator. We write the original destination of the jump just at a known
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800793// offset from the svc instruction so the simulator knows what to call.
Steve Blocka7e24c12009-10-30 11:49:00 +0000794class Redirection {
795 public:
Steve Block1e0659c2011-05-24 12:43:12 +0100796 Redirection(void* external_function, ExternalReference::Type type)
Steve Blocka7e24c12009-10-30 11:49:00 +0000797 : external_function_(external_function),
Steve Block1e0659c2011-05-24 12:43:12 +0100798 swi_instruction_(al | (0xf*B24) | kCallRtRedirected),
799 type_(type),
Steve Block44f0eee2011-05-26 01:26:41 +0100800 next_(NULL) {
801 Isolate* isolate = Isolate::Current();
802 next_ = isolate->simulator_redirection();
803 Simulator::current(isolate)->
804 FlushICache(isolate->simulator_i_cache(),
805 reinterpret_cast<void*>(&swi_instruction_),
806 Instruction::kInstrSize);
807 isolate->set_simulator_redirection(this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000808 }
809
810 void* address_of_swi_instruction() {
811 return reinterpret_cast<void*>(&swi_instruction_);
812 }
813
814 void* external_function() { return external_function_; }
Steve Block1e0659c2011-05-24 12:43:12 +0100815 ExternalReference::Type type() { return type_; }
Steve Blocka7e24c12009-10-30 11:49:00 +0000816
Steve Block1e0659c2011-05-24 12:43:12 +0100817 static Redirection* Get(void* external_function,
818 ExternalReference::Type type) {
Steve Block44f0eee2011-05-26 01:26:41 +0100819 Isolate* isolate = Isolate::Current();
820 Redirection* current = isolate->simulator_redirection();
821 for (; current != NULL; current = current->next_) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000822 if (current->external_function_ == external_function) return current;
823 }
Steve Block1e0659c2011-05-24 12:43:12 +0100824 return new Redirection(external_function, type);
Steve Blocka7e24c12009-10-30 11:49:00 +0000825 }
826
Steve Block1e0659c2011-05-24 12:43:12 +0100827 static Redirection* FromSwiInstruction(Instruction* swi_instruction) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000828 char* addr_of_swi = reinterpret_cast<char*>(swi_instruction);
829 char* addr_of_redirection =
830 addr_of_swi - OFFSET_OF(Redirection, swi_instruction_);
831 return reinterpret_cast<Redirection*>(addr_of_redirection);
832 }
833
834 private:
835 void* external_function_;
836 uint32_t swi_instruction_;
Steve Block1e0659c2011-05-24 12:43:12 +0100837 ExternalReference::Type type_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000838 Redirection* next_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000839};
840
841
Steve Blocka7e24c12009-10-30 11:49:00 +0000842void* Simulator::RedirectExternalReference(void* external_function,
Steve Block1e0659c2011-05-24 12:43:12 +0100843 ExternalReference::Type type) {
844 Redirection* redirection = Redirection::Get(external_function, type);
Steve Blocka7e24c12009-10-30 11:49:00 +0000845 return redirection->address_of_swi_instruction();
846}
847
848
849// Get the active Simulator for the current thread.
Steve Block44f0eee2011-05-26 01:26:41 +0100850Simulator* Simulator::current(Isolate* isolate) {
851 v8::internal::Isolate::PerIsolateThreadData* isolate_data =
Ben Murdoch257744e2011-11-30 15:57:28 +0000852 isolate->FindOrAllocatePerThreadDataForThisThread();
Steve Block44f0eee2011-05-26 01:26:41 +0100853 ASSERT(isolate_data != NULL);
854
855 Simulator* sim = isolate_data->simulator();
Steve Blocka7e24c12009-10-30 11:49:00 +0000856 if (sim == NULL) {
Steve Block44f0eee2011-05-26 01:26:41 +0100857 // TODO(146): delete the simulator object when a thread/isolate goes away.
Ben Murdoch257744e2011-11-30 15:57:28 +0000858 sim = new Simulator(isolate);
Steve Block44f0eee2011-05-26 01:26:41 +0100859 isolate_data->set_simulator(sim);
Steve Blocka7e24c12009-10-30 11:49:00 +0000860 }
861 return sim;
862}
863
864
865// Sets the register in the architecture state. It will also deal with updating
866// Simulator internal state for special registers such as PC.
867void Simulator::set_register(int reg, int32_t value) {
868 ASSERT((reg >= 0) && (reg < num_registers));
869 if (reg == pc) {
870 pc_modified_ = true;
871 }
872 registers_[reg] = value;
873}
874
875
876// Get the register from the architecture state. This function does handle
877// the special case of accessing the PC register.
878int32_t Simulator::get_register(int reg) const {
879 ASSERT((reg >= 0) && (reg < num_registers));
Steve Block791712a2010-08-27 10:21:07 +0100880 // Stupid code added to avoid bug in GCC.
881 // See: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43949
882 if (reg >= num_registers) return 0;
883 // End stupid code.
Steve Block1e0659c2011-05-24 12:43:12 +0100884 return registers_[reg] + ((reg == pc) ? Instruction::kPCReadOffset : 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000885}
886
887
Ben Murdoch8b112d22011-06-08 16:22:53 +0100888double Simulator::get_double_from_register_pair(int reg) {
889 ASSERT((reg >= 0) && (reg < num_registers) && ((reg % 2) == 0));
890
891 double dm_val = 0.0;
892 // Read the bits from the unsigned integer register_[] array
893 // into the double precision floating point value and return it.
894 char buffer[2 * sizeof(vfp_register[0])];
895 memcpy(buffer, &registers_[reg], 2 * sizeof(registers_[0]));
896 memcpy(&dm_val, buffer, 2 * sizeof(registers_[0]));
897 return(dm_val);
898}
899
900
Kristian Monsen25f61362010-05-21 11:50:48 +0100901void Simulator::set_dw_register(int dreg, const int* dbl) {
902 ASSERT((dreg >= 0) && (dreg < num_d_registers));
903 registers_[dreg] = dbl[0];
904 registers_[dreg + 1] = dbl[1];
905}
906
907
Steve Blocka7e24c12009-10-30 11:49:00 +0000908// Raw access to the PC register.
909void Simulator::set_pc(int32_t value) {
910 pc_modified_ = true;
911 registers_[pc] = value;
912}
913
914
Ben Murdochb0fe1622011-05-05 13:52:32 +0100915bool Simulator::has_bad_pc() const {
916 return ((registers_[pc] == bad_lr) || (registers_[pc] == end_sim_pc));
917}
918
919
Steve Blocka7e24c12009-10-30 11:49:00 +0000920// Raw access to the PC register without the special adjustment when reading.
921int32_t Simulator::get_pc() const {
922 return registers_[pc];
923}
924
925
Steve Blockd0582a62009-12-15 09:54:21 +0000926// Getting from and setting into VFP registers.
927void Simulator::set_s_register(int sreg, unsigned int value) {
928 ASSERT((sreg >= 0) && (sreg < num_s_registers));
929 vfp_register[sreg] = value;
930}
931
932
933unsigned int Simulator::get_s_register(int sreg) const {
934 ASSERT((sreg >= 0) && (sreg < num_s_registers));
935 return vfp_register[sreg];
936}
937
938
939void Simulator::set_s_register_from_float(int sreg, const float flt) {
940 ASSERT((sreg >= 0) && (sreg < num_s_registers));
941 // Read the bits from the single precision floating point value
942 // into the unsigned integer element of vfp_register[] given by index=sreg.
943 char buffer[sizeof(vfp_register[0])];
944 memcpy(buffer, &flt, sizeof(vfp_register[0]));
945 memcpy(&vfp_register[sreg], buffer, sizeof(vfp_register[0]));
946}
947
948
949void Simulator::set_s_register_from_sinteger(int sreg, const int sint) {
950 ASSERT((sreg >= 0) && (sreg < num_s_registers));
951 // Read the bits from the integer value into the unsigned integer element of
952 // vfp_register[] given by index=sreg.
953 char buffer[sizeof(vfp_register[0])];
954 memcpy(buffer, &sint, sizeof(vfp_register[0]));
955 memcpy(&vfp_register[sreg], buffer, sizeof(vfp_register[0]));
956}
957
958
959void Simulator::set_d_register_from_double(int dreg, const double& dbl) {
960 ASSERT((dreg >= 0) && (dreg < num_d_registers));
961 // Read the bits from the double precision floating point value into the two
962 // consecutive unsigned integer elements of vfp_register[] given by index
963 // 2*sreg and 2*sreg+1.
964 char buffer[2 * sizeof(vfp_register[0])];
965 memcpy(buffer, &dbl, 2 * sizeof(vfp_register[0]));
Steve Blockd0582a62009-12-15 09:54:21 +0000966 memcpy(&vfp_register[dreg * 2], buffer, 2 * sizeof(vfp_register[0]));
Steve Blockd0582a62009-12-15 09:54:21 +0000967}
968
969
970float Simulator::get_float_from_s_register(int sreg) {
971 ASSERT((sreg >= 0) && (sreg < num_s_registers));
972
973 float sm_val = 0.0;
974 // Read the bits from the unsigned integer vfp_register[] array
975 // into the single precision floating point value and return it.
976 char buffer[sizeof(vfp_register[0])];
977 memcpy(buffer, &vfp_register[sreg], sizeof(vfp_register[0]));
978 memcpy(&sm_val, buffer, sizeof(vfp_register[0]));
979 return(sm_val);
980}
981
982
983int Simulator::get_sinteger_from_s_register(int sreg) {
984 ASSERT((sreg >= 0) && (sreg < num_s_registers));
985
986 int sm_val = 0;
987 // Read the bits from the unsigned integer vfp_register[] array
988 // into the single precision floating point value and return it.
989 char buffer[sizeof(vfp_register[0])];
990 memcpy(buffer, &vfp_register[sreg], sizeof(vfp_register[0]));
991 memcpy(&sm_val, buffer, sizeof(vfp_register[0]));
992 return(sm_val);
993}
994
995
996double Simulator::get_double_from_d_register(int dreg) {
997 ASSERT((dreg >= 0) && (dreg < num_d_registers));
998
999 double dm_val = 0.0;
1000 // Read the bits from the unsigned integer vfp_register[] array
1001 // into the double precision floating point value and return it.
1002 char buffer[2 * sizeof(vfp_register[0])];
Steve Blockd0582a62009-12-15 09:54:21 +00001003 memcpy(buffer, &vfp_register[2 * dreg], 2 * sizeof(vfp_register[0]));
Steve Blockd0582a62009-12-15 09:54:21 +00001004 memcpy(&dm_val, buffer, 2 * sizeof(vfp_register[0]));
1005 return(dm_val);
1006}
1007
1008
Ben Murdoch257744e2011-11-30 15:57:28 +00001009// For use in calls that take two double values, constructed either
1010// from r0-r3 or d0 and d1.
Steve Blocka7e24c12009-10-30 11:49:00 +00001011void Simulator::GetFpArgs(double* x, double* y) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001012 if (use_eabi_hardfloat()) {
1013 *x = vfp_register[0];
1014 *y = vfp_register[1];
1015 } else {
1016 // We use a char buffer to get around the strict-aliasing rules which
1017 // otherwise allow the compiler to optimize away the copy.
1018 char buffer[sizeof(*x)];
1019 // Registers 0 and 1 -> x.
1020 memcpy(buffer, registers_, sizeof(*x));
1021 memcpy(x, buffer, sizeof(*x));
1022 // Registers 2 and 3 -> y.
1023 memcpy(buffer, registers_ + 2, sizeof(*y));
1024 memcpy(y, buffer, sizeof(*y));
1025 }
1026}
1027
1028// For use in calls that take one double value, constructed either
1029// from r0 and r1 or d0.
1030void Simulator::GetFpArgs(double* x) {
1031 if (use_eabi_hardfloat()) {
1032 *x = vfp_register[0];
1033 } else {
1034 // We use a char buffer to get around the strict-aliasing rules which
1035 // otherwise allow the compiler to optimize away the copy.
1036 char buffer[sizeof(*x)];
1037 // Registers 0 and 1 -> x.
1038 memcpy(buffer, registers_, sizeof(*x));
1039 memcpy(x, buffer, sizeof(*x));
1040 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001041}
1042
1043
Ben Murdoch257744e2011-11-30 15:57:28 +00001044// For use in calls that take one double value constructed either
1045// from r0 and r1 or d0 and one integer value.
1046void Simulator::GetFpArgs(double* x, int32_t* y) {
1047 if (use_eabi_hardfloat()) {
1048 *x = vfp_register[0];
1049 *y = registers_[1];
1050 } else {
1051 // We use a char buffer to get around the strict-aliasing rules which
1052 // otherwise allow the compiler to optimize away the copy.
1053 char buffer[sizeof(*x)];
1054 // Registers 0 and 1 -> x.
1055 memcpy(buffer, registers_, sizeof(*x));
1056 memcpy(x, buffer, sizeof(*x));
1057 // Register 2 -> y.
1058 memcpy(buffer, registers_ + 2, sizeof(*y));
1059 memcpy(y, buffer, sizeof(*y));
1060 }
1061}
1062
1063
1064// The return value is either in r0/r1 or d0.
Steve Blocka7e24c12009-10-30 11:49:00 +00001065void Simulator::SetFpResult(const double& result) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001066 if (use_eabi_hardfloat()) {
1067 char buffer[2 * sizeof(vfp_register[0])];
1068 memcpy(buffer, &result, sizeof(buffer));
1069 // Copy result to d0.
1070 memcpy(vfp_register, buffer, sizeof(buffer));
1071 } else {
1072 char buffer[2 * sizeof(registers_[0])];
1073 memcpy(buffer, &result, sizeof(buffer));
1074 // Copy result to r0 and r1.
1075 memcpy(registers_, buffer, sizeof(buffer));
1076 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001077}
1078
1079
1080void Simulator::TrashCallerSaveRegisters() {
1081 // We don't trash the registers with the return value.
1082 registers_[2] = 0x50Bad4U;
1083 registers_[3] = 0x50Bad4U;
1084 registers_[12] = 0x50Bad4U;
1085}
1086
Kristian Monsen25f61362010-05-21 11:50:48 +01001087// Some Operating Systems allow unaligned access on ARMv7 targets. We
1088// assume that unaligned accesses are not allowed unless the v8 build system
1089// defines the CAN_USE_UNALIGNED_ACCESSES macro to be non-zero.
1090// The following statements below describes the behavior of the ARM CPUs
1091// that don't support unaligned access.
1092// Some ARM platforms raise an interrupt on detecting unaligned access.
1093// On others it does a funky rotation thing. For now we
1094// simply disallow unaligned reads. Note that simulator runs have the runtime
Steve Blocka7e24c12009-10-30 11:49:00 +00001095// system running directly on the host system and only generated code is
1096// executed in the simulator. Since the host is typically IA32 we will not
Kristian Monsen25f61362010-05-21 11:50:48 +01001097// get the correct ARM-like behaviour on unaligned accesses for those ARM
1098// targets that don't support unaligned loads and stores.
1099
Steve Blocka7e24c12009-10-30 11:49:00 +00001100
Steve Block1e0659c2011-05-24 12:43:12 +01001101int Simulator::ReadW(int32_t addr, Instruction* instr) {
Kristian Monsen25f61362010-05-21 11:50:48 +01001102#if V8_TARGET_CAN_READ_UNALIGNED
1103 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
1104 return *ptr;
1105#else
Steve Blocka7e24c12009-10-30 11:49:00 +00001106 if ((addr & 3) == 0) {
1107 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
1108 return *ptr;
1109 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001110 PrintF("Unaligned read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1111 addr,
1112 reinterpret_cast<intptr_t>(instr));
Steve Blocka7e24c12009-10-30 11:49:00 +00001113 UNIMPLEMENTED();
1114 return 0;
Kristian Monsen25f61362010-05-21 11:50:48 +01001115#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00001116}
1117
1118
Steve Block1e0659c2011-05-24 12:43:12 +01001119void Simulator::WriteW(int32_t addr, int value, Instruction* instr) {
Kristian Monsen25f61362010-05-21 11:50:48 +01001120#if V8_TARGET_CAN_READ_UNALIGNED
1121 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
1122 *ptr = value;
1123 return;
1124#else
Steve Blocka7e24c12009-10-30 11:49:00 +00001125 if ((addr & 3) == 0) {
1126 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
1127 *ptr = value;
1128 return;
1129 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001130 PrintF("Unaligned write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1131 addr,
1132 reinterpret_cast<intptr_t>(instr));
Steve Blocka7e24c12009-10-30 11:49:00 +00001133 UNIMPLEMENTED();
Kristian Monsen25f61362010-05-21 11:50:48 +01001134#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00001135}
1136
1137
Steve Block1e0659c2011-05-24 12:43:12 +01001138uint16_t Simulator::ReadHU(int32_t addr, Instruction* instr) {
Kristian Monsen25f61362010-05-21 11:50:48 +01001139#if V8_TARGET_CAN_READ_UNALIGNED
1140 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1141 return *ptr;
1142#else
Steve Blocka7e24c12009-10-30 11:49:00 +00001143 if ((addr & 1) == 0) {
1144 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1145 return *ptr;
1146 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001147 PrintF("Unaligned unsigned halfword read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1148 addr,
1149 reinterpret_cast<intptr_t>(instr));
Steve Blocka7e24c12009-10-30 11:49:00 +00001150 UNIMPLEMENTED();
1151 return 0;
Kristian Monsen25f61362010-05-21 11:50:48 +01001152#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00001153}
1154
1155
Steve Block1e0659c2011-05-24 12:43:12 +01001156int16_t Simulator::ReadH(int32_t addr, Instruction* instr) {
Kristian Monsen25f61362010-05-21 11:50:48 +01001157#if V8_TARGET_CAN_READ_UNALIGNED
1158 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
1159 return *ptr;
1160#else
Steve Blocka7e24c12009-10-30 11:49:00 +00001161 if ((addr & 1) == 0) {
1162 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
1163 return *ptr;
1164 }
1165 PrintF("Unaligned signed halfword read at 0x%08x\n", addr);
1166 UNIMPLEMENTED();
1167 return 0;
Kristian Monsen25f61362010-05-21 11:50:48 +01001168#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00001169}
1170
1171
Steve Block1e0659c2011-05-24 12:43:12 +01001172void Simulator::WriteH(int32_t addr, uint16_t value, Instruction* instr) {
Kristian Monsen25f61362010-05-21 11:50:48 +01001173#if V8_TARGET_CAN_READ_UNALIGNED
1174 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1175 *ptr = value;
1176 return;
1177#else
Steve Blocka7e24c12009-10-30 11:49:00 +00001178 if ((addr & 1) == 0) {
1179 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1180 *ptr = value;
1181 return;
1182 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001183 PrintF("Unaligned unsigned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1184 addr,
1185 reinterpret_cast<intptr_t>(instr));
Steve Blocka7e24c12009-10-30 11:49:00 +00001186 UNIMPLEMENTED();
Kristian Monsen25f61362010-05-21 11:50:48 +01001187#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00001188}
1189
1190
Steve Block1e0659c2011-05-24 12:43:12 +01001191void Simulator::WriteH(int32_t addr, int16_t value, Instruction* instr) {
Kristian Monsen25f61362010-05-21 11:50:48 +01001192#if V8_TARGET_CAN_READ_UNALIGNED
1193 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
1194 *ptr = value;
1195 return;
1196#else
Steve Blocka7e24c12009-10-30 11:49:00 +00001197 if ((addr & 1) == 0) {
1198 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
1199 *ptr = value;
1200 return;
1201 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001202 PrintF("Unaligned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1203 addr,
1204 reinterpret_cast<intptr_t>(instr));
Steve Blocka7e24c12009-10-30 11:49:00 +00001205 UNIMPLEMENTED();
Kristian Monsen25f61362010-05-21 11:50:48 +01001206#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00001207}
1208
1209
1210uint8_t Simulator::ReadBU(int32_t addr) {
1211 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1212 return *ptr;
1213}
1214
1215
1216int8_t Simulator::ReadB(int32_t addr) {
1217 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
1218 return *ptr;
1219}
1220
1221
1222void Simulator::WriteB(int32_t addr, uint8_t value) {
1223 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1224 *ptr = value;
1225}
1226
1227
1228void Simulator::WriteB(int32_t addr, int8_t value) {
1229 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
1230 *ptr = value;
1231}
1232
1233
Kristian Monsen25f61362010-05-21 11:50:48 +01001234int32_t* Simulator::ReadDW(int32_t addr) {
1235#if V8_TARGET_CAN_READ_UNALIGNED
1236 int32_t* ptr = reinterpret_cast<int32_t*>(addr);
1237 return ptr;
1238#else
1239 if ((addr & 3) == 0) {
1240 int32_t* ptr = reinterpret_cast<int32_t*>(addr);
1241 return ptr;
1242 }
1243 PrintF("Unaligned read at 0x%08x\n", addr);
1244 UNIMPLEMENTED();
1245 return 0;
1246#endif
1247}
1248
1249
1250void Simulator::WriteDW(int32_t addr, int32_t value1, int32_t value2) {
1251#if V8_TARGET_CAN_READ_UNALIGNED
1252 int32_t* ptr = reinterpret_cast<int32_t*>(addr);
1253 *ptr++ = value1;
1254 *ptr = value2;
1255 return;
1256#else
1257 if ((addr & 3) == 0) {
1258 int32_t* ptr = reinterpret_cast<int32_t*>(addr);
1259 *ptr++ = value1;
1260 *ptr = value2;
1261 return;
1262 }
1263 PrintF("Unaligned write at 0x%08x\n", addr);
1264 UNIMPLEMENTED();
1265#endif
1266}
1267
1268
Steve Blocka7e24c12009-10-30 11:49:00 +00001269// Returns the limit of the stack area to enable checking for stack overflows.
1270uintptr_t Simulator::StackLimit() const {
1271 // Leave a safety margin of 256 bytes to prevent overrunning the stack when
1272 // pushing values.
1273 return reinterpret_cast<uintptr_t>(stack_) + 256;
1274}
1275
1276
1277// Unsupported instructions use Format to print an error and stop execution.
Steve Block1e0659c2011-05-24 12:43:12 +01001278void Simulator::Format(Instruction* instr, const char* format) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001279 PrintF("Simulator found unsupported instruction:\n 0x%08x: %s\n",
Ben Murdochf87a2032010-10-22 12:50:53 +01001280 reinterpret_cast<intptr_t>(instr), format);
Steve Blocka7e24c12009-10-30 11:49:00 +00001281 UNIMPLEMENTED();
1282}
1283
1284
1285// Checks if the current instruction should be executed based on its
1286// condition bits.
Steve Block1e0659c2011-05-24 12:43:12 +01001287bool Simulator::ConditionallyExecute(Instruction* instr) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001288 switch (instr->ConditionField()) {
Steve Block1e0659c2011-05-24 12:43:12 +01001289 case eq: return z_flag_;
1290 case ne: return !z_flag_;
1291 case cs: return c_flag_;
1292 case cc: return !c_flag_;
1293 case mi: return n_flag_;
1294 case pl: return !n_flag_;
1295 case vs: return v_flag_;
1296 case vc: return !v_flag_;
1297 case hi: return c_flag_ && !z_flag_;
1298 case ls: return !c_flag_ || z_flag_;
1299 case ge: return n_flag_ == v_flag_;
1300 case lt: return n_flag_ != v_flag_;
1301 case gt: return !z_flag_ && (n_flag_ == v_flag_);
1302 case le: return z_flag_ || (n_flag_ != v_flag_);
1303 case al: return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00001304 default: UNREACHABLE();
1305 }
1306 return false;
1307}
1308
1309
1310// Calculate and set the Negative and Zero flags.
1311void Simulator::SetNZFlags(int32_t val) {
1312 n_flag_ = (val < 0);
1313 z_flag_ = (val == 0);
1314}
1315
1316
1317// Set the Carry flag.
1318void Simulator::SetCFlag(bool val) {
1319 c_flag_ = val;
1320}
1321
1322
1323// Set the oVerflow flag.
1324void Simulator::SetVFlag(bool val) {
1325 v_flag_ = val;
1326}
1327
1328
1329// Calculate C flag value for additions.
Ben Murdoch257744e2011-11-30 15:57:28 +00001330bool Simulator::CarryFrom(int32_t left, int32_t right, int32_t carry) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001331 uint32_t uleft = static_cast<uint32_t>(left);
1332 uint32_t uright = static_cast<uint32_t>(right);
1333 uint32_t urest = 0xffffffffU - uleft;
1334
Ben Murdoch257744e2011-11-30 15:57:28 +00001335 return (uright > urest) ||
1336 (carry && (((uright + 1) > urest) || (uright > (urest - 1))));
Steve Blocka7e24c12009-10-30 11:49:00 +00001337}
1338
1339
1340// Calculate C flag value for subtractions.
1341bool Simulator::BorrowFrom(int32_t left, int32_t right) {
1342 uint32_t uleft = static_cast<uint32_t>(left);
1343 uint32_t uright = static_cast<uint32_t>(right);
1344
1345 return (uright > uleft);
1346}
1347
1348
1349// Calculate V flag value for additions and subtractions.
1350bool Simulator::OverflowFrom(int32_t alu_out,
1351 int32_t left, int32_t right, bool addition) {
1352 bool overflow;
1353 if (addition) {
1354 // operands have the same sign
1355 overflow = ((left >= 0 && right >= 0) || (left < 0 && right < 0))
1356 // and operands and result have different sign
1357 && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
1358 } else {
1359 // operands have different signs
1360 overflow = ((left < 0 && right >= 0) || (left >= 0 && right < 0))
1361 // and first operand and result have different signs
1362 && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
1363 }
1364 return overflow;
1365}
1366
1367
Steve Blockd0582a62009-12-15 09:54:21 +00001368// Support for VFP comparisons.
1369void Simulator::Compute_FPSCR_Flags(double val1, double val2) {
Leon Clarkee46be812010-01-19 14:06:41 +00001370 if (isnan(val1) || isnan(val2)) {
1371 n_flag_FPSCR_ = false;
1372 z_flag_FPSCR_ = false;
1373 c_flag_FPSCR_ = true;
1374 v_flag_FPSCR_ = true;
Steve Blockd0582a62009-12-15 09:54:21 +00001375 // All non-NaN cases.
Leon Clarkee46be812010-01-19 14:06:41 +00001376 } else if (val1 == val2) {
Steve Blockd0582a62009-12-15 09:54:21 +00001377 n_flag_FPSCR_ = false;
1378 z_flag_FPSCR_ = true;
1379 c_flag_FPSCR_ = true;
1380 v_flag_FPSCR_ = false;
1381 } else if (val1 < val2) {
1382 n_flag_FPSCR_ = true;
1383 z_flag_FPSCR_ = false;
1384 c_flag_FPSCR_ = false;
1385 v_flag_FPSCR_ = false;
1386 } else {
1387 // Case when (val1 > val2).
1388 n_flag_FPSCR_ = false;
1389 z_flag_FPSCR_ = false;
1390 c_flag_FPSCR_ = true;
1391 v_flag_FPSCR_ = false;
1392 }
1393}
1394
1395
1396void Simulator::Copy_FPSCR_to_APSR() {
1397 n_flag_ = n_flag_FPSCR_;
1398 z_flag_ = z_flag_FPSCR_;
1399 c_flag_ = c_flag_FPSCR_;
1400 v_flag_ = v_flag_FPSCR_;
1401}
1402
1403
Steve Blocka7e24c12009-10-30 11:49:00 +00001404// Addressing Mode 1 - Data-processing operands:
1405// Get the value based on the shifter_operand with register.
Steve Block1e0659c2011-05-24 12:43:12 +01001406int32_t Simulator::GetShiftRm(Instruction* instr, bool* carry_out) {
1407 ShiftOp shift = instr->ShiftField();
1408 int shift_amount = instr->ShiftAmountValue();
1409 int32_t result = get_register(instr->RmValue());
Steve Blocka7e24c12009-10-30 11:49:00 +00001410 if (instr->Bit(4) == 0) {
1411 // by immediate
1412 if ((shift == ROR) && (shift_amount == 0)) {
1413 UNIMPLEMENTED();
1414 return result;
1415 } else if (((shift == LSR) || (shift == ASR)) && (shift_amount == 0)) {
1416 shift_amount = 32;
1417 }
1418 switch (shift) {
1419 case ASR: {
1420 if (shift_amount == 0) {
1421 if (result < 0) {
1422 result = 0xffffffff;
1423 *carry_out = true;
1424 } else {
1425 result = 0;
1426 *carry_out = false;
1427 }
1428 } else {
1429 result >>= (shift_amount - 1);
1430 *carry_out = (result & 1) == 1;
1431 result >>= 1;
1432 }
1433 break;
1434 }
1435
1436 case LSL: {
1437 if (shift_amount == 0) {
1438 *carry_out = c_flag_;
1439 } else {
1440 result <<= (shift_amount - 1);
1441 *carry_out = (result < 0);
1442 result <<= 1;
1443 }
1444 break;
1445 }
1446
1447 case LSR: {
1448 if (shift_amount == 0) {
1449 result = 0;
1450 *carry_out = c_flag_;
1451 } else {
1452 uint32_t uresult = static_cast<uint32_t>(result);
1453 uresult >>= (shift_amount - 1);
1454 *carry_out = (uresult & 1) == 1;
1455 uresult >>= 1;
1456 result = static_cast<int32_t>(uresult);
1457 }
1458 break;
1459 }
1460
1461 case ROR: {
1462 UNIMPLEMENTED();
1463 break;
1464 }
1465
1466 default: {
1467 UNREACHABLE();
1468 break;
1469 }
1470 }
1471 } else {
1472 // by register
Steve Block1e0659c2011-05-24 12:43:12 +01001473 int rs = instr->RsValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00001474 shift_amount = get_register(rs) &0xff;
1475 switch (shift) {
1476 case ASR: {
1477 if (shift_amount == 0) {
1478 *carry_out = c_flag_;
1479 } else if (shift_amount < 32) {
1480 result >>= (shift_amount - 1);
1481 *carry_out = (result & 1) == 1;
1482 result >>= 1;
1483 } else {
1484 ASSERT(shift_amount >= 32);
1485 if (result < 0) {
1486 *carry_out = true;
1487 result = 0xffffffff;
1488 } else {
1489 *carry_out = false;
1490 result = 0;
1491 }
1492 }
1493 break;
1494 }
1495
1496 case LSL: {
1497 if (shift_amount == 0) {
1498 *carry_out = c_flag_;
1499 } else if (shift_amount < 32) {
1500 result <<= (shift_amount - 1);
1501 *carry_out = (result < 0);
1502 result <<= 1;
1503 } else if (shift_amount == 32) {
1504 *carry_out = (result & 1) == 1;
1505 result = 0;
1506 } else {
1507 ASSERT(shift_amount > 32);
1508 *carry_out = false;
1509 result = 0;
1510 }
1511 break;
1512 }
1513
1514 case LSR: {
1515 if (shift_amount == 0) {
1516 *carry_out = c_flag_;
1517 } else if (shift_amount < 32) {
1518 uint32_t uresult = static_cast<uint32_t>(result);
1519 uresult >>= (shift_amount - 1);
1520 *carry_out = (uresult & 1) == 1;
1521 uresult >>= 1;
1522 result = static_cast<int32_t>(uresult);
1523 } else if (shift_amount == 32) {
1524 *carry_out = (result < 0);
1525 result = 0;
1526 } else {
1527 *carry_out = false;
1528 result = 0;
1529 }
1530 break;
1531 }
1532
1533 case ROR: {
1534 UNIMPLEMENTED();
1535 break;
1536 }
1537
1538 default: {
1539 UNREACHABLE();
1540 break;
1541 }
1542 }
1543 }
1544 return result;
1545}
1546
1547
1548// Addressing Mode 1 - Data-processing operands:
1549// Get the value based on the shifter_operand with immediate.
Steve Block1e0659c2011-05-24 12:43:12 +01001550int32_t Simulator::GetImm(Instruction* instr, bool* carry_out) {
1551 int rotate = instr->RotateValue() * 2;
1552 int immed8 = instr->Immed8Value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001553 int imm = (immed8 >> rotate) | (immed8 << (32 - rotate));
1554 *carry_out = (rotate == 0) ? c_flag_ : (imm < 0);
1555 return imm;
1556}
1557
1558
1559static int count_bits(int bit_vector) {
1560 int count = 0;
1561 while (bit_vector != 0) {
1562 if ((bit_vector & 1) != 0) {
1563 count++;
1564 }
1565 bit_vector >>= 1;
1566 }
1567 return count;
1568}
1569
1570
Ben Murdoch8b112d22011-06-08 16:22:53 +01001571void Simulator::ProcessPUW(Instruction* instr,
1572 int num_regs,
1573 int reg_size,
1574 intptr_t* start_address,
1575 intptr_t* end_address) {
Steve Block1e0659c2011-05-24 12:43:12 +01001576 int rn = instr->RnValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00001577 int32_t rn_val = get_register(rn);
Steve Blocka7e24c12009-10-30 11:49:00 +00001578 switch (instr->PUField()) {
Steve Block1e0659c2011-05-24 12:43:12 +01001579 case da_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00001580 UNIMPLEMENTED();
1581 break;
1582 }
Steve Block1e0659c2011-05-24 12:43:12 +01001583 case ia_x: {
Ben Murdoch8b112d22011-06-08 16:22:53 +01001584 *start_address = rn_val;
1585 *end_address = rn_val + (num_regs * reg_size) - reg_size;
1586 rn_val = rn_val + (num_regs * reg_size);
Steve Blocka7e24c12009-10-30 11:49:00 +00001587 break;
1588 }
Steve Block1e0659c2011-05-24 12:43:12 +01001589 case db_x: {
Ben Murdoch8b112d22011-06-08 16:22:53 +01001590 *start_address = rn_val - (num_regs * reg_size);
1591 *end_address = rn_val - reg_size;
1592 rn_val = *start_address;
Steve Blocka7e24c12009-10-30 11:49:00 +00001593 break;
1594 }
Steve Block1e0659c2011-05-24 12:43:12 +01001595 case ib_x: {
Ben Murdoch8b112d22011-06-08 16:22:53 +01001596 *start_address = rn_val + reg_size;
1597 *end_address = rn_val + (num_regs * reg_size);
1598 rn_val = *end_address;
Steve Blocka7e24c12009-10-30 11:49:00 +00001599 break;
1600 }
1601 default: {
1602 UNREACHABLE();
1603 break;
1604 }
1605 }
1606 if (instr->HasW()) {
1607 set_register(rn, rn_val);
1608 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01001609}
1610
1611// Addressing Mode 4 - Load and Store Multiple
1612void Simulator::HandleRList(Instruction* instr, bool load) {
1613 int rlist = instr->RlistValue();
1614 int num_regs = count_bits(rlist);
1615
1616 intptr_t start_address = 0;
1617 intptr_t end_address = 0;
1618 ProcessPUW(instr, num_regs, kPointerSize, &start_address, &end_address);
1619
Steve Blocka7e24c12009-10-30 11:49:00 +00001620 intptr_t* address = reinterpret_cast<intptr_t*>(start_address);
1621 int reg = 0;
1622 while (rlist != 0) {
1623 if ((rlist & 1) != 0) {
1624 if (load) {
1625 set_register(reg, *address);
1626 } else {
1627 *address = get_register(reg);
1628 }
1629 address += 1;
1630 }
1631 reg++;
1632 rlist >>= 1;
1633 }
1634 ASSERT(end_address == ((intptr_t)address) - 4);
1635}
1636
1637
Ben Murdoch8b112d22011-06-08 16:22:53 +01001638// Addressing Mode 6 - Load and Store Multiple Coprocessor registers.
1639void Simulator::HandleVList(Instruction* instr) {
1640 VFPRegPrecision precision =
1641 (instr->SzValue() == 0) ? kSinglePrecision : kDoublePrecision;
1642 int operand_size = (precision == kSinglePrecision) ? 4 : 8;
1643
1644 bool load = (instr->VLValue() == 0x1);
1645
1646 int vd;
1647 int num_regs;
1648 vd = instr->VFPDRegValue(precision);
1649 if (precision == kSinglePrecision) {
1650 num_regs = instr->Immed8Value();
1651 } else {
1652 num_regs = instr->Immed8Value() / 2;
1653 }
1654
1655 intptr_t start_address = 0;
1656 intptr_t end_address = 0;
1657 ProcessPUW(instr, num_regs, operand_size, &start_address, &end_address);
1658
1659 intptr_t* address = reinterpret_cast<intptr_t*>(start_address);
1660 for (int reg = vd; reg < vd + num_regs; reg++) {
1661 if (precision == kSinglePrecision) {
1662 if (load) {
1663 set_s_register_from_sinteger(
1664 reg, ReadW(reinterpret_cast<int32_t>(address), instr));
1665 } else {
1666 WriteW(reinterpret_cast<int32_t>(address),
1667 get_sinteger_from_s_register(reg), instr);
1668 }
1669 address += 1;
1670 } else {
1671 if (load) {
1672 set_s_register_from_sinteger(
1673 2 * reg, ReadW(reinterpret_cast<int32_t>(address), instr));
1674 set_s_register_from_sinteger(
1675 2 * reg + 1, ReadW(reinterpret_cast<int32_t>(address + 1), instr));
1676 } else {
1677 WriteW(reinterpret_cast<int32_t>(address),
1678 get_sinteger_from_s_register(2 * reg), instr);
1679 WriteW(reinterpret_cast<int32_t>(address + 1),
1680 get_sinteger_from_s_register(2 * reg + 1), instr);
1681 }
1682 address += 2;
1683 }
1684 }
1685 ASSERT(reinterpret_cast<intptr_t>(address) - operand_size == end_address);
1686}
1687
1688
Steve Blocka7e24c12009-10-30 11:49:00 +00001689// Calls into the V8 runtime are based on this very simple interface.
1690// Note: To be able to return two values from some calls the code in runtime.cc
1691// uses the ObjectPair which is essentially two 32-bit values stuffed into a
1692// 64-bit value. With the code below we assume that all runtime calls return
1693// 64 bits of result. If they don't, the r1 result register contains a bogus
1694// value, which is fine because it is caller-saved.
1695typedef int64_t (*SimulatorRuntimeCall)(int32_t arg0,
1696 int32_t arg1,
1697 int32_t arg2,
Ben Murdochb0fe1622011-05-05 13:52:32 +01001698 int32_t arg3,
Steve Block44f0eee2011-05-26 01:26:41 +01001699 int32_t arg4,
1700 int32_t arg5);
Steve Blocka7e24c12009-10-30 11:49:00 +00001701typedef double (*SimulatorRuntimeFPCall)(int32_t arg0,
1702 int32_t arg1,
1703 int32_t arg2,
1704 int32_t arg3);
1705
Steve Block1e0659c2011-05-24 12:43:12 +01001706// This signature supports direct call in to API function native callback
1707// (refer to InvocationCallback in v8.h).
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001708typedef v8::Handle<v8::Value> (*SimulatorRuntimeDirectApiCall)(int32_t arg0);
1709
1710// This signature supports direct call to accessor getter callback.
1711typedef v8::Handle<v8::Value> (*SimulatorRuntimeDirectGetterCall)(int32_t arg0,
1712 int32_t arg1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001713
1714// Software interrupt instructions are used by the simulator to call into the
1715// C-based V8 runtime.
Steve Block1e0659c2011-05-24 12:43:12 +01001716void Simulator::SoftwareInterrupt(Instruction* instr) {
1717 int svc = instr->SvcValue();
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001718 switch (svc) {
Steve Block1e0659c2011-05-24 12:43:12 +01001719 case kCallRtRedirected: {
Steve Block6ded16b2010-05-10 14:33:55 +01001720 // Check if stack is aligned. Error if not aligned is reported below to
1721 // include information on the function called.
1722 bool stack_aligned =
1723 (get_register(sp)
1724 & (::v8::internal::FLAG_sim_stack_alignment - 1)) == 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00001725 Redirection* redirection = Redirection::FromSwiInstruction(instr);
1726 int32_t arg0 = get_register(r0);
1727 int32_t arg1 = get_register(r1);
1728 int32_t arg2 = get_register(r2);
1729 int32_t arg3 = get_register(r3);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001730 int32_t* stack_pointer = reinterpret_cast<int32_t*>(get_register(sp));
Steve Block44f0eee2011-05-26 01:26:41 +01001731 int32_t arg4 = stack_pointer[0];
1732 int32_t arg5 = stack_pointer[1];
Ben Murdoch257744e2011-11-30 15:57:28 +00001733 bool fp_call =
1734 (redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) ||
1735 (redirection->type() == ExternalReference::BUILTIN_COMPARE_CALL) ||
1736 (redirection->type() == ExternalReference::BUILTIN_FP_CALL) ||
1737 (redirection->type() == ExternalReference::BUILTIN_FP_INT_CALL);
1738 if (use_eabi_hardfloat()) {
1739 // With the hard floating point calling convention, double
1740 // arguments are passed in VFP registers. Fetch the arguments
1741 // from there and call the builtin using soft floating point
1742 // convention.
1743 switch (redirection->type()) {
1744 case ExternalReference::BUILTIN_FP_FP_CALL:
1745 case ExternalReference::BUILTIN_COMPARE_CALL:
1746 arg0 = vfp_register[0];
1747 arg1 = vfp_register[1];
1748 arg2 = vfp_register[2];
1749 arg3 = vfp_register[3];
1750 break;
1751 case ExternalReference::BUILTIN_FP_CALL:
1752 arg0 = vfp_register[0];
1753 arg1 = vfp_register[1];
1754 break;
1755 case ExternalReference::BUILTIN_FP_INT_CALL:
1756 arg0 = vfp_register[0];
1757 arg1 = vfp_register[1];
1758 arg2 = get_register(0);
1759 break;
1760 default:
1761 break;
1762 }
1763 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001764 // This is dodgy but it works because the C entry stubs are never moved.
1765 // See comment in codegen-arm.cc and bug 1242173.
1766 int32_t saved_lr = get_register(lr);
Steve Block1e0659c2011-05-24 12:43:12 +01001767 intptr_t external =
1768 reinterpret_cast<intptr_t>(redirection->external_function());
Ben Murdoch257744e2011-11-30 15:57:28 +00001769 if (fp_call) {
Steve Block6ded16b2010-05-10 14:33:55 +01001770 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001771 SimulatorRuntimeFPCall target =
1772 reinterpret_cast<SimulatorRuntimeFPCall>(external);
1773 double dval0, dval1;
1774 int32_t ival;
1775 switch (redirection->type()) {
1776 case ExternalReference::BUILTIN_FP_FP_CALL:
1777 case ExternalReference::BUILTIN_COMPARE_CALL:
1778 GetFpArgs(&dval0, &dval1);
1779 PrintF("Call to host function at %p with args %f, %f",
1780 FUNCTION_ADDR(target), dval0, dval1);
1781 break;
1782 case ExternalReference::BUILTIN_FP_CALL:
1783 GetFpArgs(&dval0);
1784 PrintF("Call to host function at %p with arg %f",
1785 FUNCTION_ADDR(target), dval0);
1786 break;
1787 case ExternalReference::BUILTIN_FP_INT_CALL:
1788 GetFpArgs(&dval0, &ival);
1789 PrintF("Call to host function at %p with args %f, %d",
1790 FUNCTION_ADDR(target), dval0, ival);
1791 break;
1792 default:
1793 UNREACHABLE();
1794 break;
1795 }
Steve Block6ded16b2010-05-10 14:33:55 +01001796 if (!stack_aligned) {
1797 PrintF(" with unaligned stack %08x\n", get_register(sp));
1798 }
1799 PrintF("\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00001800 }
Steve Block6ded16b2010-05-10 14:33:55 +01001801 CHECK(stack_aligned);
Ben Murdoch257744e2011-11-30 15:57:28 +00001802 if (redirection->type() != ExternalReference::BUILTIN_COMPARE_CALL) {
1803 SimulatorRuntimeFPCall target =
1804 reinterpret_cast<SimulatorRuntimeFPCall>(external);
1805 double result = target(arg0, arg1, arg2, arg3);
1806 SetFpResult(result);
1807 } else {
1808 SimulatorRuntimeCall target =
1809 reinterpret_cast<SimulatorRuntimeCall>(external);
1810 int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5);
1811 int32_t lo_res = static_cast<int32_t>(result);
1812 int32_t hi_res = static_cast<int32_t>(result >> 32);
1813 if (::v8::internal::FLAG_trace_sim) {
1814 PrintF("Returned %08x\n", lo_res);
1815 }
1816 set_register(r0, lo_res);
1817 set_register(r1, hi_res);
1818 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001819 } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) {
1820 SimulatorRuntimeDirectApiCall target =
1821 reinterpret_cast<SimulatorRuntimeDirectApiCall>(external);
Steve Block1e0659c2011-05-24 12:43:12 +01001822 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001823 PrintF("Call to host function at %p args %08x",
1824 FUNCTION_ADDR(target), arg0);
Steve Block1e0659c2011-05-24 12:43:12 +01001825 if (!stack_aligned) {
1826 PrintF(" with unaligned stack %08x\n", get_register(sp));
1827 }
1828 PrintF("\n");
1829 }
1830 CHECK(stack_aligned);
1831 v8::Handle<v8::Value> result = target(arg0);
1832 if (::v8::internal::FLAG_trace_sim) {
1833 PrintF("Returned %p\n", reinterpret_cast<void *>(*result));
1834 }
1835 set_register(r0, (int32_t) *result);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001836 } else if (redirection->type() == ExternalReference::DIRECT_GETTER_CALL) {
1837 SimulatorRuntimeDirectGetterCall target =
1838 reinterpret_cast<SimulatorRuntimeDirectGetterCall>(external);
1839 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
1840 PrintF("Call to host function at %p args %08x %08x",
1841 FUNCTION_ADDR(target), arg0, arg1);
1842 if (!stack_aligned) {
1843 PrintF(" with unaligned stack %08x\n", get_register(sp));
1844 }
1845 PrintF("\n");
1846 }
1847 CHECK(stack_aligned);
1848 v8::Handle<v8::Value> result = target(arg0, arg1);
1849 if (::v8::internal::FLAG_trace_sim) {
1850 PrintF("Returned %p\n", reinterpret_cast<void *>(*result));
1851 }
1852 set_register(r0, (int32_t) *result);
Steve Blocka7e24c12009-10-30 11:49:00 +00001853 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01001854 // builtin call.
1855 ASSERT(redirection->type() == ExternalReference::BUILTIN_CALL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001856 SimulatorRuntimeCall target =
1857 reinterpret_cast<SimulatorRuntimeCall>(external);
Steve Block6ded16b2010-05-10 14:33:55 +01001858 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001859 PrintF(
Steve Block44f0eee2011-05-26 01:26:41 +01001860 "Call to host function at %p"
1861 "args %08x, %08x, %08x, %08x, %08x, %08x",
Steve Blocka7e24c12009-10-30 11:49:00 +00001862 FUNCTION_ADDR(target),
1863 arg0,
1864 arg1,
1865 arg2,
Ben Murdochb0fe1622011-05-05 13:52:32 +01001866 arg3,
Steve Block44f0eee2011-05-26 01:26:41 +01001867 arg4,
1868 arg5);
Steve Block6ded16b2010-05-10 14:33:55 +01001869 if (!stack_aligned) {
1870 PrintF(" with unaligned stack %08x\n", get_register(sp));
1871 }
1872 PrintF("\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00001873 }
Steve Block6ded16b2010-05-10 14:33:55 +01001874 CHECK(stack_aligned);
Steve Block44f0eee2011-05-26 01:26:41 +01001875 int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5);
Steve Blocka7e24c12009-10-30 11:49:00 +00001876 int32_t lo_res = static_cast<int32_t>(result);
1877 int32_t hi_res = static_cast<int32_t>(result >> 32);
1878 if (::v8::internal::FLAG_trace_sim) {
1879 PrintF("Returned %08x\n", lo_res);
1880 }
1881 set_register(r0, lo_res);
1882 set_register(r1, hi_res);
1883 }
1884 set_register(lr, saved_lr);
1885 set_pc(get_register(lr));
1886 break;
1887 }
Steve Block1e0659c2011-05-24 12:43:12 +01001888 case kBreakpoint: {
Steve Block44f0eee2011-05-26 01:26:41 +01001889 ArmDebugger dbg(this);
Steve Blocka7e24c12009-10-30 11:49:00 +00001890 dbg.Debug();
1891 break;
1892 }
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001893 // stop uses all codes greater than 1 << 23.
Steve Blocka7e24c12009-10-30 11:49:00 +00001894 default: {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001895 if (svc >= (1 << 23)) {
1896 uint32_t code = svc & kStopCodeMask;
1897 if (isWatchedStop(code)) {
1898 IncreaseStopCounter(code);
1899 }
1900 // Stop if it is enabled, otherwise go on jumping over the stop
1901 // and the message address.
1902 if (isEnabledStop(code)) {
Steve Block44f0eee2011-05-26 01:26:41 +01001903 ArmDebugger dbg(this);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001904 dbg.Stop(instr);
1905 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01001906 set_pc(get_pc() + 2 * Instruction::kInstrSize);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001907 }
1908 } else {
1909 // This is not a valid svc code.
1910 UNREACHABLE();
1911 break;
1912 }
1913 }
1914 }
1915}
1916
1917
1918// Stop helper functions.
Steve Block1e0659c2011-05-24 12:43:12 +01001919bool Simulator::isStopInstruction(Instruction* instr) {
1920 return (instr->Bits(27, 24) == 0xF) && (instr->SvcValue() >= kStopCode);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001921}
1922
1923
1924bool Simulator::isWatchedStop(uint32_t code) {
1925 ASSERT(code <= kMaxStopCode);
1926 return code < kNumOfWatchedStops;
1927}
1928
1929
1930bool Simulator::isEnabledStop(uint32_t code) {
1931 ASSERT(code <= kMaxStopCode);
1932 // Unwatched stops are always enabled.
1933 return !isWatchedStop(code) ||
1934 !(watched_stops[code].count & kStopDisabledBit);
1935}
1936
1937
1938void Simulator::EnableStop(uint32_t code) {
1939 ASSERT(isWatchedStop(code));
1940 if (!isEnabledStop(code)) {
1941 watched_stops[code].count &= ~kStopDisabledBit;
1942 }
1943}
1944
1945
1946void Simulator::DisableStop(uint32_t code) {
1947 ASSERT(isWatchedStop(code));
1948 if (isEnabledStop(code)) {
1949 watched_stops[code].count |= kStopDisabledBit;
1950 }
1951}
1952
1953
1954void Simulator::IncreaseStopCounter(uint32_t code) {
1955 ASSERT(code <= kMaxStopCode);
1956 ASSERT(isWatchedStop(code));
1957 if ((watched_stops[code].count & ~(1 << 31)) == 0x7fffffff) {
1958 PrintF("Stop counter for code %i has overflowed.\n"
1959 "Enabling this code and reseting the counter to 0.\n", code);
1960 watched_stops[code].count = 0;
1961 EnableStop(code);
1962 } else {
1963 watched_stops[code].count++;
1964 }
1965}
1966
1967
1968// Print a stop status.
1969void Simulator::PrintStopInfo(uint32_t code) {
1970 ASSERT(code <= kMaxStopCode);
1971 if (!isWatchedStop(code)) {
1972 PrintF("Stop not watched.");
1973 } else {
1974 const char* state = isEnabledStop(code) ? "Enabled" : "Disabled";
1975 int32_t count = watched_stops[code].count & ~kStopDisabledBit;
1976 // Don't print the state of unused breakpoints.
1977 if (count != 0) {
1978 if (watched_stops[code].desc) {
1979 PrintF("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n",
1980 code, code, state, count, watched_stops[code].desc);
1981 } else {
1982 PrintF("stop %i - 0x%x: \t%s, \tcounter = %i\n",
1983 code, code, state, count);
1984 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001985 }
1986 }
1987}
1988
1989
1990// Handle execution based on instruction types.
1991
1992// Instruction types 0 and 1 are both rolled into one function because they
1993// only differ in the handling of the shifter_operand.
Steve Block1e0659c2011-05-24 12:43:12 +01001994void Simulator::DecodeType01(Instruction* instr) {
1995 int type = instr->TypeValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00001996 if ((type == 0) && instr->IsSpecialType0()) {
1997 // multiply instruction or extra loads and stores
1998 if (instr->Bits(7, 4) == 9) {
1999 if (instr->Bit(24) == 0) {
2000 // Raw field decoding here. Multiply instructions have their Rd in
2001 // funny places.
Steve Block1e0659c2011-05-24 12:43:12 +01002002 int rn = instr->RnValue();
2003 int rm = instr->RmValue();
2004 int rs = instr->RsValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00002005 int32_t rs_val = get_register(rs);
2006 int32_t rm_val = get_register(rm);
2007 if (instr->Bit(23) == 0) {
2008 if (instr->Bit(21) == 0) {
2009 // The MUL instruction description (A 4.1.33) refers to Rd as being
2010 // the destination for the operation, but it confusingly uses the
2011 // Rn field to encode it.
2012 // Format(instr, "mul'cond's 'rn, 'rm, 'rs");
2013 int rd = rn; // Remap the rn field to the Rd register.
2014 int32_t alu_out = rm_val * rs_val;
2015 set_register(rd, alu_out);
2016 if (instr->HasS()) {
2017 SetNZFlags(alu_out);
2018 }
2019 } else {
2020 // The MLA instruction description (A 4.1.28) refers to the order
2021 // of registers as "Rd, Rm, Rs, Rn". But confusingly it uses the
2022 // Rn field to encode the Rd register and the Rd field to encode
2023 // the Rn register.
2024 Format(instr, "mla'cond's 'rn, 'rm, 'rs, 'rd");
2025 }
2026 } else {
2027 // The signed/long multiply instructions use the terms RdHi and RdLo
2028 // when referring to the target registers. They are mapped to the Rn
2029 // and Rd fields as follows:
2030 // RdLo == Rd
2031 // RdHi == Rn (This is confusingly stored in variable rd here
2032 // because the mul instruction from above uses the
2033 // Rn field to encode the Rd register. Good luck figuring
2034 // this out without reading the ARM instruction manual
2035 // at a very detailed level.)
2036 // Format(instr, "'um'al'cond's 'rd, 'rn, 'rs, 'rm");
2037 int rd_hi = rn; // Remap the rn field to the RdHi register.
Steve Block1e0659c2011-05-24 12:43:12 +01002038 int rd_lo = instr->RdValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00002039 int32_t hi_res = 0;
2040 int32_t lo_res = 0;
2041 if (instr->Bit(22) == 1) {
2042 int64_t left_op = static_cast<int32_t>(rm_val);
2043 int64_t right_op = static_cast<int32_t>(rs_val);
2044 uint64_t result = left_op * right_op;
2045 hi_res = static_cast<int32_t>(result >> 32);
2046 lo_res = static_cast<int32_t>(result & 0xffffffff);
2047 } else {
2048 // unsigned multiply
2049 uint64_t left_op = static_cast<uint32_t>(rm_val);
2050 uint64_t right_op = static_cast<uint32_t>(rs_val);
2051 uint64_t result = left_op * right_op;
2052 hi_res = static_cast<int32_t>(result >> 32);
2053 lo_res = static_cast<int32_t>(result & 0xffffffff);
2054 }
2055 set_register(rd_lo, lo_res);
2056 set_register(rd_hi, hi_res);
2057 if (instr->HasS()) {
2058 UNIMPLEMENTED();
2059 }
2060 }
2061 } else {
Steve Blockd0582a62009-12-15 09:54:21 +00002062 UNIMPLEMENTED(); // Not used by V8.
Steve Blocka7e24c12009-10-30 11:49:00 +00002063 }
2064 } else {
2065 // extra load/store instructions
Steve Block1e0659c2011-05-24 12:43:12 +01002066 int rd = instr->RdValue();
2067 int rn = instr->RnValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00002068 int32_t rn_val = get_register(rn);
2069 int32_t addr = 0;
2070 if (instr->Bit(22) == 0) {
Steve Block1e0659c2011-05-24 12:43:12 +01002071 int rm = instr->RmValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00002072 int32_t rm_val = get_register(rm);
2073 switch (instr->PUField()) {
Steve Block1e0659c2011-05-24 12:43:12 +01002074 case da_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002075 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], -'rm");
2076 ASSERT(!instr->HasW());
2077 addr = rn_val;
2078 rn_val -= rm_val;
2079 set_register(rn, rn_val);
2080 break;
2081 }
Steve Block1e0659c2011-05-24 12:43:12 +01002082 case ia_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002083 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], +'rm");
2084 ASSERT(!instr->HasW());
2085 addr = rn_val;
2086 rn_val += rm_val;
2087 set_register(rn, rn_val);
2088 break;
2089 }
Steve Block1e0659c2011-05-24 12:43:12 +01002090 case db_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002091 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, -'rm]'w");
2092 rn_val -= rm_val;
2093 addr = rn_val;
2094 if (instr->HasW()) {
2095 set_register(rn, rn_val);
2096 }
2097 break;
2098 }
Steve Block1e0659c2011-05-24 12:43:12 +01002099 case ib_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002100 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, +'rm]'w");
2101 rn_val += rm_val;
2102 addr = rn_val;
2103 if (instr->HasW()) {
2104 set_register(rn, rn_val);
2105 }
2106 break;
2107 }
2108 default: {
2109 // The PU field is a 2-bit field.
2110 UNREACHABLE();
2111 break;
2112 }
2113 }
2114 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01002115 int32_t imm_val = (instr->ImmedHValue() << 4) | instr->ImmedLValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00002116 switch (instr->PUField()) {
Steve Block1e0659c2011-05-24 12:43:12 +01002117 case da_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002118 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], #-'off8");
2119 ASSERT(!instr->HasW());
2120 addr = rn_val;
2121 rn_val -= imm_val;
2122 set_register(rn, rn_val);
2123 break;
2124 }
Steve Block1e0659c2011-05-24 12:43:12 +01002125 case ia_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002126 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], #+'off8");
2127 ASSERT(!instr->HasW());
2128 addr = rn_val;
2129 rn_val += imm_val;
2130 set_register(rn, rn_val);
2131 break;
2132 }
Steve Block1e0659c2011-05-24 12:43:12 +01002133 case db_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002134 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, #-'off8]'w");
2135 rn_val -= imm_val;
2136 addr = rn_val;
2137 if (instr->HasW()) {
2138 set_register(rn, rn_val);
2139 }
2140 break;
2141 }
Steve Block1e0659c2011-05-24 12:43:12 +01002142 case ib_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002143 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, #+'off8]'w");
2144 rn_val += imm_val;
2145 addr = rn_val;
2146 if (instr->HasW()) {
2147 set_register(rn, rn_val);
2148 }
2149 break;
2150 }
2151 default: {
2152 // The PU field is a 2-bit field.
2153 UNREACHABLE();
2154 break;
2155 }
2156 }
2157 }
Kristian Monsen25f61362010-05-21 11:50:48 +01002158 if (((instr->Bits(7, 4) & 0xd) == 0xd) && (instr->Bit(20) == 0)) {
2159 ASSERT((rd % 2) == 0);
2160 if (instr->HasH()) {
2161 // The strd instruction.
2162 int32_t value1 = get_register(rd);
2163 int32_t value2 = get_register(rd+1);
2164 WriteDW(addr, value1, value2);
2165 } else {
2166 // The ldrd instruction.
2167 int* rn_data = ReadDW(addr);
2168 set_dw_register(rd, rn_data);
2169 }
2170 } else if (instr->HasH()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002171 if (instr->HasSign()) {
2172 if (instr->HasL()) {
2173 int16_t val = ReadH(addr, instr);
2174 set_register(rd, val);
2175 } else {
2176 int16_t val = get_register(rd);
2177 WriteH(addr, val, instr);
2178 }
2179 } else {
2180 if (instr->HasL()) {
2181 uint16_t val = ReadHU(addr, instr);
2182 set_register(rd, val);
2183 } else {
2184 uint16_t val = get_register(rd);
2185 WriteH(addr, val, instr);
2186 }
2187 }
2188 } else {
2189 // signed byte loads
2190 ASSERT(instr->HasSign());
2191 ASSERT(instr->HasL());
2192 int8_t val = ReadB(addr);
2193 set_register(rd, val);
2194 }
2195 return;
2196 }
Steve Block6ded16b2010-05-10 14:33:55 +01002197 } else if ((type == 0) && instr->IsMiscType0()) {
2198 if (instr->Bits(22, 21) == 1) {
Steve Block1e0659c2011-05-24 12:43:12 +01002199 int rm = instr->RmValue();
2200 switch (instr->BitField(7, 4)) {
Steve Block6ded16b2010-05-10 14:33:55 +01002201 case BX:
2202 set_pc(get_register(rm));
2203 break;
2204 case BLX: {
2205 uint32_t old_pc = get_pc();
2206 set_pc(get_register(rm));
Steve Block1e0659c2011-05-24 12:43:12 +01002207 set_register(lr, old_pc + Instruction::kInstrSize);
Steve Block6ded16b2010-05-10 14:33:55 +01002208 break;
2209 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01002210 case BKPT: {
Steve Block44f0eee2011-05-26 01:26:41 +01002211 ArmDebugger dbg(this);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002212 PrintF("Simulator hit BKPT.\n");
2213 dbg.Debug();
Steve Block6ded16b2010-05-10 14:33:55 +01002214 break;
Ben Murdochb0fe1622011-05-05 13:52:32 +01002215 }
Steve Block6ded16b2010-05-10 14:33:55 +01002216 default:
2217 UNIMPLEMENTED();
2218 }
2219 } else if (instr->Bits(22, 21) == 3) {
Steve Block1e0659c2011-05-24 12:43:12 +01002220 int rm = instr->RmValue();
2221 int rd = instr->RdValue();
2222 switch (instr->BitField(7, 4)) {
Steve Block6ded16b2010-05-10 14:33:55 +01002223 case CLZ: {
2224 uint32_t bits = get_register(rm);
2225 int leading_zeros = 0;
2226 if (bits == 0) {
2227 leading_zeros = 32;
2228 } else {
2229 while ((bits & 0x80000000u) == 0) {
2230 bits <<= 1;
2231 leading_zeros++;
2232 }
2233 }
2234 set_register(rd, leading_zeros);
2235 break;
2236 }
2237 default:
2238 UNIMPLEMENTED();
2239 }
2240 } else {
2241 PrintF("%08x\n", instr->InstructionBits());
2242 UNIMPLEMENTED();
2243 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002244 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01002245 int rd = instr->RdValue();
2246 int rn = instr->RnValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00002247 int32_t rn_val = get_register(rn);
2248 int32_t shifter_operand = 0;
2249 bool shifter_carry_out = 0;
2250 if (type == 0) {
2251 shifter_operand = GetShiftRm(instr, &shifter_carry_out);
2252 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01002253 ASSERT(instr->TypeValue() == 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00002254 shifter_operand = GetImm(instr, &shifter_carry_out);
2255 }
2256 int32_t alu_out;
2257
2258 switch (instr->OpcodeField()) {
2259 case AND: {
2260 // Format(instr, "and'cond's 'rd, 'rn, 'shift_rm");
2261 // Format(instr, "and'cond's 'rd, 'rn, 'imm");
2262 alu_out = rn_val & shifter_operand;
2263 set_register(rd, alu_out);
2264 if (instr->HasS()) {
2265 SetNZFlags(alu_out);
2266 SetCFlag(shifter_carry_out);
2267 }
2268 break;
2269 }
2270
2271 case EOR: {
2272 // Format(instr, "eor'cond's 'rd, 'rn, 'shift_rm");
2273 // Format(instr, "eor'cond's 'rd, 'rn, 'imm");
2274 alu_out = rn_val ^ shifter_operand;
2275 set_register(rd, alu_out);
2276 if (instr->HasS()) {
2277 SetNZFlags(alu_out);
2278 SetCFlag(shifter_carry_out);
2279 }
2280 break;
2281 }
2282
2283 case SUB: {
2284 // Format(instr, "sub'cond's 'rd, 'rn, 'shift_rm");
2285 // Format(instr, "sub'cond's 'rd, 'rn, 'imm");
2286 alu_out = rn_val - shifter_operand;
2287 set_register(rd, alu_out);
2288 if (instr->HasS()) {
2289 SetNZFlags(alu_out);
2290 SetCFlag(!BorrowFrom(rn_val, shifter_operand));
2291 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, false));
2292 }
2293 break;
2294 }
2295
2296 case RSB: {
2297 // Format(instr, "rsb'cond's 'rd, 'rn, 'shift_rm");
2298 // Format(instr, "rsb'cond's 'rd, 'rn, 'imm");
2299 alu_out = shifter_operand - rn_val;
2300 set_register(rd, alu_out);
2301 if (instr->HasS()) {
2302 SetNZFlags(alu_out);
2303 SetCFlag(!BorrowFrom(shifter_operand, rn_val));
2304 SetVFlag(OverflowFrom(alu_out, shifter_operand, rn_val, false));
2305 }
2306 break;
2307 }
2308
2309 case ADD: {
2310 // Format(instr, "add'cond's 'rd, 'rn, 'shift_rm");
2311 // Format(instr, "add'cond's 'rd, 'rn, 'imm");
2312 alu_out = rn_val + shifter_operand;
2313 set_register(rd, alu_out);
2314 if (instr->HasS()) {
2315 SetNZFlags(alu_out);
2316 SetCFlag(CarryFrom(rn_val, shifter_operand));
2317 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, true));
2318 }
2319 break;
2320 }
2321
2322 case ADC: {
Ben Murdoch257744e2011-11-30 15:57:28 +00002323 // Format(instr, "adc'cond's 'rd, 'rn, 'shift_rm");
2324 // Format(instr, "adc'cond's 'rd, 'rn, 'imm");
2325 alu_out = rn_val + shifter_operand + GetCarry();
2326 set_register(rd, alu_out);
2327 if (instr->HasS()) {
2328 SetNZFlags(alu_out);
2329 SetCFlag(CarryFrom(rn_val, shifter_operand, GetCarry()));
2330 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, true));
2331 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002332 break;
2333 }
2334
2335 case SBC: {
2336 Format(instr, "sbc'cond's 'rd, 'rn, 'shift_rm");
2337 Format(instr, "sbc'cond's 'rd, 'rn, 'imm");
2338 break;
2339 }
2340
2341 case RSC: {
2342 Format(instr, "rsc'cond's 'rd, 'rn, 'shift_rm");
2343 Format(instr, "rsc'cond's 'rd, 'rn, 'imm");
2344 break;
2345 }
2346
2347 case TST: {
2348 if (instr->HasS()) {
2349 // Format(instr, "tst'cond 'rn, 'shift_rm");
2350 // Format(instr, "tst'cond 'rn, 'imm");
2351 alu_out = rn_val & shifter_operand;
2352 SetNZFlags(alu_out);
2353 SetCFlag(shifter_carry_out);
2354 } else {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002355 // Format(instr, "movw'cond 'rd, 'imm").
Steve Block1e0659c2011-05-24 12:43:12 +01002356 alu_out = instr->ImmedMovwMovtValue();
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002357 set_register(rd, alu_out);
Steve Blocka7e24c12009-10-30 11:49:00 +00002358 }
2359 break;
2360 }
2361
2362 case TEQ: {
2363 if (instr->HasS()) {
2364 // Format(instr, "teq'cond 'rn, 'shift_rm");
2365 // Format(instr, "teq'cond 'rn, 'imm");
2366 alu_out = rn_val ^ shifter_operand;
2367 SetNZFlags(alu_out);
2368 SetCFlag(shifter_carry_out);
2369 } else {
Steve Block6ded16b2010-05-10 14:33:55 +01002370 // Other instructions matching this pattern are handled in the
2371 // miscellaneous instructions part above.
2372 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +00002373 }
2374 break;
2375 }
2376
2377 case CMP: {
2378 if (instr->HasS()) {
2379 // Format(instr, "cmp'cond 'rn, 'shift_rm");
2380 // Format(instr, "cmp'cond 'rn, 'imm");
2381 alu_out = rn_val - shifter_operand;
2382 SetNZFlags(alu_out);
2383 SetCFlag(!BorrowFrom(rn_val, shifter_operand));
2384 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, false));
2385 } else {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002386 // Format(instr, "movt'cond 'rd, 'imm").
2387 alu_out = (get_register(rd) & 0xffff) |
Steve Block1e0659c2011-05-24 12:43:12 +01002388 (instr->ImmedMovwMovtValue() << 16);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002389 set_register(rd, alu_out);
Steve Blocka7e24c12009-10-30 11:49:00 +00002390 }
2391 break;
2392 }
2393
2394 case CMN: {
2395 if (instr->HasS()) {
2396 // Format(instr, "cmn'cond 'rn, 'shift_rm");
2397 // Format(instr, "cmn'cond 'rn, 'imm");
2398 alu_out = rn_val + shifter_operand;
2399 SetNZFlags(alu_out);
2400 SetCFlag(!CarryFrom(rn_val, shifter_operand));
2401 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, true));
2402 } else {
Steve Block6ded16b2010-05-10 14:33:55 +01002403 // Other instructions matching this pattern are handled in the
2404 // miscellaneous instructions part above.
2405 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +00002406 }
2407 break;
2408 }
2409
2410 case ORR: {
2411 // Format(instr, "orr'cond's 'rd, 'rn, 'shift_rm");
2412 // Format(instr, "orr'cond's 'rd, 'rn, 'imm");
2413 alu_out = rn_val | shifter_operand;
2414 set_register(rd, alu_out);
2415 if (instr->HasS()) {
2416 SetNZFlags(alu_out);
2417 SetCFlag(shifter_carry_out);
2418 }
2419 break;
2420 }
2421
2422 case MOV: {
2423 // Format(instr, "mov'cond's 'rd, 'shift_rm");
2424 // Format(instr, "mov'cond's 'rd, 'imm");
2425 alu_out = shifter_operand;
2426 set_register(rd, alu_out);
2427 if (instr->HasS()) {
2428 SetNZFlags(alu_out);
2429 SetCFlag(shifter_carry_out);
2430 }
2431 break;
2432 }
2433
2434 case BIC: {
2435 // Format(instr, "bic'cond's 'rd, 'rn, 'shift_rm");
2436 // Format(instr, "bic'cond's 'rd, 'rn, 'imm");
2437 alu_out = rn_val & ~shifter_operand;
2438 set_register(rd, alu_out);
2439 if (instr->HasS()) {
2440 SetNZFlags(alu_out);
2441 SetCFlag(shifter_carry_out);
2442 }
2443 break;
2444 }
2445
2446 case MVN: {
2447 // Format(instr, "mvn'cond's 'rd, 'shift_rm");
2448 // Format(instr, "mvn'cond's 'rd, 'imm");
2449 alu_out = ~shifter_operand;
2450 set_register(rd, alu_out);
2451 if (instr->HasS()) {
2452 SetNZFlags(alu_out);
2453 SetCFlag(shifter_carry_out);
2454 }
2455 break;
2456 }
2457
2458 default: {
2459 UNREACHABLE();
2460 break;
2461 }
2462 }
2463 }
2464}
2465
2466
Steve Block1e0659c2011-05-24 12:43:12 +01002467void Simulator::DecodeType2(Instruction* instr) {
2468 int rd = instr->RdValue();
2469 int rn = instr->RnValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00002470 int32_t rn_val = get_register(rn);
Steve Block1e0659c2011-05-24 12:43:12 +01002471 int32_t im_val = instr->Offset12Value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002472 int32_t addr = 0;
2473 switch (instr->PUField()) {
Steve Block1e0659c2011-05-24 12:43:12 +01002474 case da_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002475 // Format(instr, "'memop'cond'b 'rd, ['rn], #-'off12");
2476 ASSERT(!instr->HasW());
2477 addr = rn_val;
2478 rn_val -= im_val;
2479 set_register(rn, rn_val);
2480 break;
2481 }
Steve Block1e0659c2011-05-24 12:43:12 +01002482 case ia_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002483 // Format(instr, "'memop'cond'b 'rd, ['rn], #+'off12");
2484 ASSERT(!instr->HasW());
2485 addr = rn_val;
2486 rn_val += im_val;
2487 set_register(rn, rn_val);
2488 break;
2489 }
Steve Block1e0659c2011-05-24 12:43:12 +01002490 case db_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002491 // Format(instr, "'memop'cond'b 'rd, ['rn, #-'off12]'w");
2492 rn_val -= im_val;
2493 addr = rn_val;
2494 if (instr->HasW()) {
2495 set_register(rn, rn_val);
2496 }
2497 break;
2498 }
Steve Block1e0659c2011-05-24 12:43:12 +01002499 case ib_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002500 // Format(instr, "'memop'cond'b 'rd, ['rn, #+'off12]'w");
2501 rn_val += im_val;
2502 addr = rn_val;
2503 if (instr->HasW()) {
2504 set_register(rn, rn_val);
2505 }
2506 break;
2507 }
2508 default: {
2509 UNREACHABLE();
2510 break;
2511 }
2512 }
2513 if (instr->HasB()) {
2514 if (instr->HasL()) {
2515 byte val = ReadBU(addr);
2516 set_register(rd, val);
2517 } else {
2518 byte val = get_register(rd);
2519 WriteB(addr, val);
2520 }
2521 } else {
2522 if (instr->HasL()) {
2523 set_register(rd, ReadW(addr, instr));
2524 } else {
2525 WriteW(addr, get_register(rd), instr);
2526 }
2527 }
2528}
2529
2530
Steve Block1e0659c2011-05-24 12:43:12 +01002531void Simulator::DecodeType3(Instruction* instr) {
2532 int rd = instr->RdValue();
2533 int rn = instr->RnValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00002534 int32_t rn_val = get_register(rn);
2535 bool shifter_carry_out = 0;
2536 int32_t shifter_operand = GetShiftRm(instr, &shifter_carry_out);
2537 int32_t addr = 0;
2538 switch (instr->PUField()) {
Steve Block1e0659c2011-05-24 12:43:12 +01002539 case da_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002540 ASSERT(!instr->HasW());
2541 Format(instr, "'memop'cond'b 'rd, ['rn], -'shift_rm");
Kristian Monsen50ef84f2010-07-29 15:18:00 +01002542 UNIMPLEMENTED();
Steve Blocka7e24c12009-10-30 11:49:00 +00002543 break;
2544 }
Steve Block1e0659c2011-05-24 12:43:12 +01002545 case ia_x: {
Kristian Monsen50ef84f2010-07-29 15:18:00 +01002546 if (instr->HasW()) {
2547 ASSERT(instr->Bits(5, 4) == 0x1);
2548
2549 if (instr->Bit(22) == 0x1) { // USAT.
2550 int32_t sat_pos = instr->Bits(20, 16);
2551 int32_t sat_val = (1 << sat_pos) - 1;
2552 int32_t shift = instr->Bits(11, 7);
2553 int32_t shift_type = instr->Bit(6);
Steve Block1e0659c2011-05-24 12:43:12 +01002554 int32_t rm_val = get_register(instr->RmValue());
Kristian Monsen50ef84f2010-07-29 15:18:00 +01002555 if (shift_type == 0) { // LSL
2556 rm_val <<= shift;
2557 } else { // ASR
2558 rm_val >>= shift;
2559 }
2560 // If saturation occurs, the Q flag should be set in the CPSR.
2561 // There is no Q flag yet, and no instruction (MRS) to read the
2562 // CPSR directly.
2563 if (rm_val > sat_val) {
2564 rm_val = sat_val;
2565 } else if (rm_val < 0) {
2566 rm_val = 0;
2567 }
2568 set_register(rd, rm_val);
2569 } else { // SSAT.
2570 UNIMPLEMENTED();
2571 }
2572 return;
2573 } else {
2574 Format(instr, "'memop'cond'b 'rd, ['rn], +'shift_rm");
2575 UNIMPLEMENTED();
2576 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002577 break;
2578 }
Steve Block1e0659c2011-05-24 12:43:12 +01002579 case db_x: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002580 // Format(instr, "'memop'cond'b 'rd, ['rn, -'shift_rm]'w");
2581 addr = rn_val - shifter_operand;
2582 if (instr->HasW()) {
2583 set_register(rn, addr);
2584 }
2585 break;
2586 }
Steve Block1e0659c2011-05-24 12:43:12 +01002587 case ib_x: {
Andrei Popescu31002712010-02-23 13:46:05 +00002588 if (instr->HasW() && (instr->Bits(6, 4) == 0x5)) {
2589 uint32_t widthminus1 = static_cast<uint32_t>(instr->Bits(20, 16));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002590 uint32_t lsbit = static_cast<uint32_t>(instr->Bits(11, 7));
Andrei Popescu31002712010-02-23 13:46:05 +00002591 uint32_t msbit = widthminus1 + lsbit;
2592 if (msbit <= 31) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002593 if (instr->Bit(22)) {
2594 // ubfx - unsigned bitfield extract.
2595 uint32_t rm_val =
Steve Block1e0659c2011-05-24 12:43:12 +01002596 static_cast<uint32_t>(get_register(instr->RmValue()));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002597 uint32_t extr_val = rm_val << (31 - msbit);
2598 extr_val = extr_val >> (31 - widthminus1);
Steve Block1e0659c2011-05-24 12:43:12 +01002599 set_register(instr->RdValue(), extr_val);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002600 } else {
2601 // sbfx - signed bitfield extract.
Steve Block1e0659c2011-05-24 12:43:12 +01002602 int32_t rm_val = get_register(instr->RmValue());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002603 int32_t extr_val = rm_val << (31 - msbit);
2604 extr_val = extr_val >> (31 - widthminus1);
Steve Block1e0659c2011-05-24 12:43:12 +01002605 set_register(instr->RdValue(), extr_val);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002606 }
2607 } else {
2608 UNREACHABLE();
2609 }
2610 return;
2611 } else if (!instr->HasW() && (instr->Bits(6, 4) == 0x1)) {
2612 uint32_t lsbit = static_cast<uint32_t>(instr->Bits(11, 7));
2613 uint32_t msbit = static_cast<uint32_t>(instr->Bits(20, 16));
2614 if (msbit >= lsbit) {
2615 // bfc or bfi - bitfield clear/insert.
2616 uint32_t rd_val =
Steve Block1e0659c2011-05-24 12:43:12 +01002617 static_cast<uint32_t>(get_register(instr->RdValue()));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002618 uint32_t bitcount = msbit - lsbit + 1;
2619 uint32_t mask = (1 << bitcount) - 1;
2620 rd_val &= ~(mask << lsbit);
Steve Block1e0659c2011-05-24 12:43:12 +01002621 if (instr->RmValue() != 15) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002622 // bfi - bitfield insert.
2623 uint32_t rm_val =
Steve Block1e0659c2011-05-24 12:43:12 +01002624 static_cast<uint32_t>(get_register(instr->RmValue()));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002625 rm_val &= mask;
2626 rd_val |= rm_val << lsbit;
2627 }
Steve Block1e0659c2011-05-24 12:43:12 +01002628 set_register(instr->RdValue(), rd_val);
Andrei Popescu31002712010-02-23 13:46:05 +00002629 } else {
2630 UNREACHABLE();
2631 }
2632 return;
2633 } else {
2634 // Format(instr, "'memop'cond'b 'rd, ['rn, +'shift_rm]'w");
2635 addr = rn_val + shifter_operand;
2636 if (instr->HasW()) {
2637 set_register(rn, addr);
2638 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002639 }
2640 break;
2641 }
2642 default: {
2643 UNREACHABLE();
2644 break;
2645 }
2646 }
2647 if (instr->HasB()) {
2648 if (instr->HasL()) {
2649 uint8_t byte = ReadB(addr);
2650 set_register(rd, byte);
2651 } else {
Andrei Popescu31002712010-02-23 13:46:05 +00002652 uint8_t byte = get_register(rd);
2653 WriteB(addr, byte);
Steve Blocka7e24c12009-10-30 11:49:00 +00002654 }
2655 } else {
2656 if (instr->HasL()) {
2657 set_register(rd, ReadW(addr, instr));
2658 } else {
2659 WriteW(addr, get_register(rd), instr);
2660 }
2661 }
2662}
2663
2664
Steve Block1e0659c2011-05-24 12:43:12 +01002665void Simulator::DecodeType4(Instruction* instr) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002666 ASSERT(instr->Bit(22) == 0); // only allowed to be set in privileged mode
2667 if (instr->HasL()) {
2668 // Format(instr, "ldm'cond'pu 'rn'w, 'rlist");
2669 HandleRList(instr, true);
2670 } else {
2671 // Format(instr, "stm'cond'pu 'rn'w, 'rlist");
2672 HandleRList(instr, false);
2673 }
2674}
2675
2676
Steve Block1e0659c2011-05-24 12:43:12 +01002677void Simulator::DecodeType5(Instruction* instr) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002678 // Format(instr, "b'l'cond 'target");
Steve Block1e0659c2011-05-24 12:43:12 +01002679 int off = (instr->SImmed24Value() << 2);
Steve Blocka7e24c12009-10-30 11:49:00 +00002680 intptr_t pc_address = get_pc();
2681 if (instr->HasLink()) {
Steve Block1e0659c2011-05-24 12:43:12 +01002682 set_register(lr, pc_address + Instruction::kInstrSize);
Steve Blocka7e24c12009-10-30 11:49:00 +00002683 }
2684 int pc_reg = get_register(pc);
2685 set_pc(pc_reg + off);
2686}
2687
2688
Steve Block1e0659c2011-05-24 12:43:12 +01002689void Simulator::DecodeType6(Instruction* instr) {
Steve Blockd0582a62009-12-15 09:54:21 +00002690 DecodeType6CoprocessorIns(instr);
Steve Blocka7e24c12009-10-30 11:49:00 +00002691}
2692
2693
Steve Block1e0659c2011-05-24 12:43:12 +01002694void Simulator::DecodeType7(Instruction* instr) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002695 if (instr->Bit(24) == 1) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002696 SoftwareInterrupt(instr);
2697 } else {
Steve Blockd0582a62009-12-15 09:54:21 +00002698 DecodeTypeVFP(instr);
Steve Blocka7e24c12009-10-30 11:49:00 +00002699 }
2700}
2701
2702
Steve Block1e0659c2011-05-24 12:43:12 +01002703// void Simulator::DecodeTypeVFP(Instruction* instr)
Steve Blockd0582a62009-12-15 09:54:21 +00002704// The Following ARMv7 VFPv instructions are currently supported.
Leon Clarkee46be812010-01-19 14:06:41 +00002705// vmov :Sn = Rt
2706// vmov :Rt = Sn
2707// vcvt: Dd = Sm
2708// vcvt: Sd = Dm
Steve Block44f0eee2011-05-26 01:26:41 +01002709// Dd = vabs(Dm)
2710// Dd = vneg(Dm)
Leon Clarkee46be812010-01-19 14:06:41 +00002711// Dd = vadd(Dn, Dm)
2712// Dd = vsub(Dn, Dm)
2713// Dd = vmul(Dn, Dm)
2714// Dd = vdiv(Dn, Dm)
Steve Blockd0582a62009-12-15 09:54:21 +00002715// vcmp(Dd, Dm)
Steve Block8defd9f2010-07-08 12:39:36 +01002716// vmrs
2717// Dd = vsqrt(Dm)
Steve Block1e0659c2011-05-24 12:43:12 +01002718void Simulator::DecodeTypeVFP(Instruction* instr) {
2719 ASSERT((instr->TypeValue() == 7) && (instr->Bit(24) == 0x0) );
Steve Block6ded16b2010-05-10 14:33:55 +01002720 ASSERT(instr->Bits(11, 9) == 0x5);
Steve Blockd0582a62009-12-15 09:54:21 +00002721
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002722 // Obtain double precision register codes.
Steve Block1e0659c2011-05-24 12:43:12 +01002723 int vm = instr->VFPMRegValue(kDoublePrecision);
2724 int vd = instr->VFPDRegValue(kDoublePrecision);
2725 int vn = instr->VFPNRegValue(kDoublePrecision);
Steve Blockd0582a62009-12-15 09:54:21 +00002726
Steve Block6ded16b2010-05-10 14:33:55 +01002727 if (instr->Bit(4) == 0) {
Steve Block1e0659c2011-05-24 12:43:12 +01002728 if (instr->Opc1Value() == 0x7) {
Steve Block6ded16b2010-05-10 14:33:55 +01002729 // Other data processing instructions
Steve Block1e0659c2011-05-24 12:43:12 +01002730 if ((instr->Opc2Value() == 0x0) && (instr->Opc3Value() == 0x1)) {
Steve Block8defd9f2010-07-08 12:39:36 +01002731 // vmov register to register.
Steve Block1e0659c2011-05-24 12:43:12 +01002732 if (instr->SzValue() == 0x1) {
2733 int m = instr->VFPMRegValue(kDoublePrecision);
2734 int d = instr->VFPDRegValue(kDoublePrecision);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002735 set_d_register_from_double(d, get_double_from_d_register(m));
Steve Block8defd9f2010-07-08 12:39:36 +01002736 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01002737 int m = instr->VFPMRegValue(kSinglePrecision);
2738 int d = instr->VFPDRegValue(kSinglePrecision);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002739 set_s_register_from_float(d, get_float_from_s_register(m));
Steve Block8defd9f2010-07-08 12:39:36 +01002740 }
Steve Block1e0659c2011-05-24 12:43:12 +01002741 } else if ((instr->Opc2Value() == 0x0) && (instr->Opc3Value() == 0x3)) {
2742 // vabs
2743 double dm_value = get_double_from_d_register(vm);
2744 double dd_value = fabs(dm_value);
2745 set_d_register_from_double(vd, dd_value);
Steve Block44f0eee2011-05-26 01:26:41 +01002746 } else if ((instr->Opc2Value() == 0x1) && (instr->Opc3Value() == 0x1)) {
2747 // vneg
2748 double dm_value = get_double_from_d_register(vm);
2749 double dd_value = -dm_value;
2750 set_d_register_from_double(vd, dd_value);
Steve Block1e0659c2011-05-24 12:43:12 +01002751 } else if ((instr->Opc2Value() == 0x7) && (instr->Opc3Value() == 0x3)) {
Steve Block6ded16b2010-05-10 14:33:55 +01002752 DecodeVCVTBetweenDoubleAndSingle(instr);
Steve Block1e0659c2011-05-24 12:43:12 +01002753 } else if ((instr->Opc2Value() == 0x8) && (instr->Opc3Value() & 0x1)) {
Steve Block6ded16b2010-05-10 14:33:55 +01002754 DecodeVCVTBetweenFloatingPointAndInteger(instr);
Steve Block1e0659c2011-05-24 12:43:12 +01002755 } else if (((instr->Opc2Value() >> 1) == 0x6) &&
2756 (instr->Opc3Value() & 0x1)) {
Steve Block6ded16b2010-05-10 14:33:55 +01002757 DecodeVCVTBetweenFloatingPointAndInteger(instr);
Steve Block1e0659c2011-05-24 12:43:12 +01002758 } else if (((instr->Opc2Value() == 0x4) || (instr->Opc2Value() == 0x5)) &&
2759 (instr->Opc3Value() & 0x1)) {
Steve Block6ded16b2010-05-10 14:33:55 +01002760 DecodeVCMP(instr);
Steve Block1e0659c2011-05-24 12:43:12 +01002761 } else if (((instr->Opc2Value() == 0x1)) && (instr->Opc3Value() == 0x3)) {
Steve Block8defd9f2010-07-08 12:39:36 +01002762 // vsqrt
2763 double dm_value = get_double_from_d_register(vm);
2764 double dd_value = sqrt(dm_value);
2765 set_d_register_from_double(vd, dd_value);
Steve Block1e0659c2011-05-24 12:43:12 +01002766 } else if (instr->Opc3Value() == 0x0) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002767 // vmov immediate.
Steve Block1e0659c2011-05-24 12:43:12 +01002768 if (instr->SzValue() == 0x1) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002769 set_d_register_from_double(vd, instr->DoubleImmedVmov());
2770 } else {
2771 UNREACHABLE(); // Not used by v8.
2772 }
Steve Block6ded16b2010-05-10 14:33:55 +01002773 } else {
2774 UNREACHABLE(); // Not used by V8.
2775 }
Steve Block1e0659c2011-05-24 12:43:12 +01002776 } else if (instr->Opc1Value() == 0x3) {
2777 if (instr->SzValue() != 0x1) {
Steve Block6ded16b2010-05-10 14:33:55 +01002778 UNREACHABLE(); // Not used by V8.
2779 }
2780
Steve Block1e0659c2011-05-24 12:43:12 +01002781 if (instr->Opc3Value() & 0x1) {
Steve Block6ded16b2010-05-10 14:33:55 +01002782 // vsub
2783 double dn_value = get_double_from_d_register(vn);
2784 double dm_value = get_double_from_d_register(vm);
2785 double dd_value = dn_value - dm_value;
2786 set_d_register_from_double(vd, dd_value);
2787 } else {
2788 // vadd
2789 double dn_value = get_double_from_d_register(vn);
2790 double dm_value = get_double_from_d_register(vm);
2791 double dd_value = dn_value + dm_value;
2792 set_d_register_from_double(vd, dd_value);
2793 }
Steve Block1e0659c2011-05-24 12:43:12 +01002794 } else if ((instr->Opc1Value() == 0x2) && !(instr->Opc3Value() & 0x1)) {
Steve Block6ded16b2010-05-10 14:33:55 +01002795 // vmul
Steve Block1e0659c2011-05-24 12:43:12 +01002796 if (instr->SzValue() != 0x1) {
Steve Block6ded16b2010-05-10 14:33:55 +01002797 UNREACHABLE(); // Not used by V8.
2798 }
2799
2800 double dn_value = get_double_from_d_register(vn);
2801 double dm_value = get_double_from_d_register(vm);
2802 double dd_value = dn_value * dm_value;
2803 set_d_register_from_double(vd, dd_value);
Steve Block1e0659c2011-05-24 12:43:12 +01002804 } else if ((instr->Opc1Value() == 0x4) && !(instr->Opc3Value() & 0x1)) {
Steve Block6ded16b2010-05-10 14:33:55 +01002805 // vdiv
Steve Block1e0659c2011-05-24 12:43:12 +01002806 if (instr->SzValue() != 0x1) {
Steve Block6ded16b2010-05-10 14:33:55 +01002807 UNREACHABLE(); // Not used by V8.
2808 }
2809
Steve Blockd0582a62009-12-15 09:54:21 +00002810 double dn_value = get_double_from_d_register(vn);
2811 double dm_value = get_double_from_d_register(vm);
2812 double dd_value = dn_value / dm_value;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002813 div_zero_vfp_flag_ = (dm_value == 0);
Steve Blockd0582a62009-12-15 09:54:21 +00002814 set_d_register_from_double(vd, dd_value);
Steve Block6ded16b2010-05-10 14:33:55 +01002815 } else {
2816 UNIMPLEMENTED(); // Not used by V8.
2817 }
2818 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01002819 if ((instr->VCValue() == 0x0) &&
2820 (instr->VAValue() == 0x0)) {
Steve Block6ded16b2010-05-10 14:33:55 +01002821 DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(instr);
Steve Block1e0659c2011-05-24 12:43:12 +01002822 } else if ((instr->VLValue() == 0x1) &&
2823 (instr->VCValue() == 0x0) &&
2824 (instr->VAValue() == 0x7) &&
Steve Block6ded16b2010-05-10 14:33:55 +01002825 (instr->Bits(19, 16) == 0x1)) {
2826 // vmrs
Steve Block1e0659c2011-05-24 12:43:12 +01002827 uint32_t rt = instr->RtValue();
Russell Brenner90bac252010-11-18 13:33:46 -08002828 if (rt == 0xF) {
Steve Blockd0582a62009-12-15 09:54:21 +00002829 Copy_FPSCR_to_APSR();
Russell Brenner90bac252010-11-18 13:33:46 -08002830 } else {
2831 // Emulate FPSCR from the Simulator flags.
2832 uint32_t fpscr = (n_flag_FPSCR_ << 31) |
2833 (z_flag_FPSCR_ << 30) |
2834 (c_flag_FPSCR_ << 29) |
2835 (v_flag_FPSCR_ << 28) |
2836 (inexact_vfp_flag_ << 4) |
2837 (underflow_vfp_flag_ << 3) |
2838 (overflow_vfp_flag_ << 2) |
2839 (div_zero_vfp_flag_ << 1) |
2840 (inv_op_vfp_flag_ << 0) |
Steve Block1e0659c2011-05-24 12:43:12 +01002841 (FPSCR_rounding_mode_);
Russell Brenner90bac252010-11-18 13:33:46 -08002842 set_register(rt, fpscr);
2843 }
Steve Block1e0659c2011-05-24 12:43:12 +01002844 } else if ((instr->VLValue() == 0x0) &&
2845 (instr->VCValue() == 0x0) &&
2846 (instr->VAValue() == 0x7) &&
Russell Brenner90bac252010-11-18 13:33:46 -08002847 (instr->Bits(19, 16) == 0x1)) {
2848 // vmsr
Steve Block1e0659c2011-05-24 12:43:12 +01002849 uint32_t rt = instr->RtValue();
Russell Brenner90bac252010-11-18 13:33:46 -08002850 if (rt == pc) {
2851 UNREACHABLE();
2852 } else {
2853 uint32_t rt_value = get_register(rt);
2854 n_flag_FPSCR_ = (rt_value >> 31) & 1;
2855 z_flag_FPSCR_ = (rt_value >> 30) & 1;
2856 c_flag_FPSCR_ = (rt_value >> 29) & 1;
2857 v_flag_FPSCR_ = (rt_value >> 28) & 1;
2858 inexact_vfp_flag_ = (rt_value >> 4) & 1;
2859 underflow_vfp_flag_ = (rt_value >> 3) & 1;
2860 overflow_vfp_flag_ = (rt_value >> 2) & 1;
2861 div_zero_vfp_flag_ = (rt_value >> 1) & 1;
2862 inv_op_vfp_flag_ = (rt_value >> 0) & 1;
2863 FPSCR_rounding_mode_ =
Steve Block1e0659c2011-05-24 12:43:12 +01002864 static_cast<VFPRoundingMode>((rt_value) & kVFPRoundingModeMask);
Russell Brenner90bac252010-11-18 13:33:46 -08002865 }
Steve Blockd0582a62009-12-15 09:54:21 +00002866 } else {
2867 UNIMPLEMENTED(); // Not used by V8.
2868 }
Steve Block6ded16b2010-05-10 14:33:55 +01002869 }
2870}
2871
2872
Steve Block1e0659c2011-05-24 12:43:12 +01002873void Simulator::DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(
2874 Instruction* instr) {
2875 ASSERT((instr->Bit(4) == 1) && (instr->VCValue() == 0x0) &&
2876 (instr->VAValue() == 0x0));
Steve Block6ded16b2010-05-10 14:33:55 +01002877
Steve Block1e0659c2011-05-24 12:43:12 +01002878 int t = instr->RtValue();
2879 int n = instr->VFPNRegValue(kSinglePrecision);
2880 bool to_arm_register = (instr->VLValue() == 0x1);
Steve Block6ded16b2010-05-10 14:33:55 +01002881
2882 if (to_arm_register) {
2883 int32_t int_value = get_sinteger_from_s_register(n);
2884 set_register(t, int_value);
2885 } else {
2886 int32_t rs_val = get_register(t);
2887 set_s_register_from_sinteger(n, rs_val);
2888 }
2889}
2890
2891
Steve Block1e0659c2011-05-24 12:43:12 +01002892void Simulator::DecodeVCMP(Instruction* instr) {
2893 ASSERT((instr->Bit(4) == 0) && (instr->Opc1Value() == 0x7));
2894 ASSERT(((instr->Opc2Value() == 0x4) || (instr->Opc2Value() == 0x5)) &&
2895 (instr->Opc3Value() & 0x1));
Steve Block6ded16b2010-05-10 14:33:55 +01002896 // Comparison.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002897
2898 VFPRegPrecision precision = kSinglePrecision;
Steve Block1e0659c2011-05-24 12:43:12 +01002899 if (instr->SzValue() == 1) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002900 precision = kDoublePrecision;
2901 }
Steve Block6ded16b2010-05-10 14:33:55 +01002902
Steve Block1e0659c2011-05-24 12:43:12 +01002903 int d = instr->VFPDRegValue(precision);
Iain Merrick75681382010-08-19 15:07:18 +01002904 int m = 0;
Steve Block1e0659c2011-05-24 12:43:12 +01002905 if (instr->Opc2Value() == 0x4) {
2906 m = instr->VFPMRegValue(precision);
Iain Merrick75681382010-08-19 15:07:18 +01002907 }
Steve Block6ded16b2010-05-10 14:33:55 +01002908
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002909 if (precision == kDoublePrecision) {
Steve Block6ded16b2010-05-10 14:33:55 +01002910 double dd_value = get_double_from_d_register(d);
Iain Merrick75681382010-08-19 15:07:18 +01002911 double dm_value = 0.0;
Steve Block1e0659c2011-05-24 12:43:12 +01002912 if (instr->Opc2Value() == 0x4) {
Iain Merrick75681382010-08-19 15:07:18 +01002913 dm_value = get_double_from_d_register(m);
2914 }
Steve Block6ded16b2010-05-10 14:33:55 +01002915
Ben Murdoch086aeea2011-05-13 15:57:08 +01002916 // Raise exceptions for quiet NaNs if necessary.
2917 if (instr->Bit(7) == 1) {
2918 if (isnan(dd_value)) {
2919 inv_op_vfp_flag_ = true;
2920 }
2921 }
2922
Steve Block6ded16b2010-05-10 14:33:55 +01002923 Compute_FPSCR_Flags(dd_value, dm_value);
2924 } else {
2925 UNIMPLEMENTED(); // Not used by V8.
2926 }
2927}
2928
2929
Steve Block1e0659c2011-05-24 12:43:12 +01002930void Simulator::DecodeVCVTBetweenDoubleAndSingle(Instruction* instr) {
2931 ASSERT((instr->Bit(4) == 0) && (instr->Opc1Value() == 0x7));
2932 ASSERT((instr->Opc2Value() == 0x7) && (instr->Opc3Value() == 0x3));
Steve Block6ded16b2010-05-10 14:33:55 +01002933
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002934 VFPRegPrecision dst_precision = kDoublePrecision;
2935 VFPRegPrecision src_precision = kSinglePrecision;
Steve Block1e0659c2011-05-24 12:43:12 +01002936 if (instr->SzValue() == 1) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002937 dst_precision = kSinglePrecision;
2938 src_precision = kDoublePrecision;
2939 }
Steve Block6ded16b2010-05-10 14:33:55 +01002940
Steve Block1e0659c2011-05-24 12:43:12 +01002941 int dst = instr->VFPDRegValue(dst_precision);
2942 int src = instr->VFPMRegValue(src_precision);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002943
2944 if (dst_precision == kSinglePrecision) {
Steve Block6ded16b2010-05-10 14:33:55 +01002945 double val = get_double_from_d_register(src);
2946 set_s_register_from_float(dst, static_cast<float>(val));
2947 } else {
2948 float val = get_float_from_s_register(src);
2949 set_d_register_from_double(dst, static_cast<double>(val));
2950 }
2951}
2952
Steve Block1e0659c2011-05-24 12:43:12 +01002953bool get_inv_op_vfp_flag(VFPRoundingMode mode,
2954 double val,
2955 bool unsigned_) {
2956 ASSERT((mode == RN) || (mode == RM) || (mode == RZ));
2957 double max_uint = static_cast<double>(0xffffffffu);
2958 double max_int = static_cast<double>(kMaxInt);
2959 double min_int = static_cast<double>(kMinInt);
Steve Block6ded16b2010-05-10 14:33:55 +01002960
Steve Block1e0659c2011-05-24 12:43:12 +01002961 // Check for NaN.
2962 if (val != val) {
2963 return true;
2964 }
2965
2966 // Check for overflow. This code works because 32bit integers can be
2967 // exactly represented by ieee-754 64bit floating-point values.
2968 switch (mode) {
2969 case RN:
2970 return unsigned_ ? (val >= (max_uint + 0.5)) ||
2971 (val < -0.5)
2972 : (val >= (max_int + 0.5)) ||
2973 (val < (min_int - 0.5));
2974
2975 case RM:
2976 return unsigned_ ? (val >= (max_uint + 1.0)) ||
2977 (val < 0)
2978 : (val >= (max_int + 1.0)) ||
2979 (val < min_int);
2980
2981 case RZ:
2982 return unsigned_ ? (val >= (max_uint + 1.0)) ||
2983 (val <= -1)
2984 : (val >= (max_int + 1.0)) ||
2985 (val <= (min_int - 1.0));
2986 default:
2987 UNREACHABLE();
2988 return true;
2989 }
2990}
2991
2992
2993// We call this function only if we had a vfp invalid exception.
2994// It returns the correct saturated value.
2995int VFPConversionSaturate(double val, bool unsigned_res) {
2996 if (val != val) {
2997 return 0;
2998 } else {
2999 if (unsigned_res) {
3000 return (val < 0) ? 0 : 0xffffffffu;
3001 } else {
3002 return (val < 0) ? kMinInt : kMaxInt;
3003 }
3004 }
3005}
3006
3007
3008void Simulator::DecodeVCVTBetweenFloatingPointAndInteger(Instruction* instr) {
3009 ASSERT((instr->Bit(4) == 0) && (instr->Opc1Value() == 0x7) &&
3010 (instr->Bits(27, 23) == 0x1D));
3011 ASSERT(((instr->Opc2Value() == 0x8) && (instr->Opc3Value() & 0x1)) ||
3012 (((instr->Opc2Value() >> 1) == 0x6) && (instr->Opc3Value() & 0x1)));
Steve Block6ded16b2010-05-10 14:33:55 +01003013
3014 // Conversion between floating-point and integer.
Steve Block6ded16b2010-05-10 14:33:55 +01003015 bool to_integer = (instr->Bit(18) == 1);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003016
Steve Block1e0659c2011-05-24 12:43:12 +01003017 VFPRegPrecision src_precision = (instr->SzValue() == 1) ? kDoublePrecision
3018 : kSinglePrecision;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003019
Steve Block6ded16b2010-05-10 14:33:55 +01003020 if (to_integer) {
Steve Block1e0659c2011-05-24 12:43:12 +01003021 // We are playing with code close to the C++ standard's limits below,
3022 // hence the very simple code and heavy checks.
3023 //
3024 // Note:
3025 // C++ defines default type casting from floating point to integer as
3026 // (close to) rounding toward zero ("fractional part discarded").
3027
3028 int dst = instr->VFPDRegValue(kSinglePrecision);
3029 int src = instr->VFPMRegValue(src_precision);
3030
3031 // Bit 7 in vcvt instructions indicates if we should use the FPSCR rounding
3032 // mode or the default Round to Zero mode.
3033 VFPRoundingMode mode = (instr->Bit(7) != 1) ? FPSCR_rounding_mode_
3034 : RZ;
3035 ASSERT((mode == RM) || (mode == RZ) || (mode == RN));
3036
Steve Block6ded16b2010-05-10 14:33:55 +01003037 bool unsigned_integer = (instr->Bit(16) == 0);
Steve Block1e0659c2011-05-24 12:43:12 +01003038 bool double_precision = (src_precision == kDoublePrecision);
3039
3040 double val = double_precision ? get_double_from_d_register(src)
3041 : get_float_from_s_register(src);
3042
3043 int temp = unsigned_integer ? static_cast<uint32_t>(val)
3044 : static_cast<int32_t>(val);
3045
3046 inv_op_vfp_flag_ = get_inv_op_vfp_flag(mode, val, unsigned_integer);
3047
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003048 double abs_diff =
3049 unsigned_integer ? fabs(val - static_cast<uint32_t>(temp))
3050 : fabs(val - temp);
3051
3052 inexact_vfp_flag_ = (abs_diff != 0);
3053
Steve Block1e0659c2011-05-24 12:43:12 +01003054 if (inv_op_vfp_flag_) {
3055 temp = VFPConversionSaturate(val, unsigned_integer);
Russell Brenner90bac252010-11-18 13:33:46 -08003056 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01003057 switch (mode) {
3058 case RN: {
Steve Block1e0659c2011-05-24 12:43:12 +01003059 int val_sign = (val > 0) ? 1 : -1;
3060 if (abs_diff > 0.5) {
3061 temp += val_sign;
3062 } else if (abs_diff == 0.5) {
3063 // Round to even if exactly halfway.
3064 temp = ((temp % 2) == 0) ? temp : temp + val_sign;
3065 }
3066 break;
3067 }
3068
3069 case RM:
3070 temp = temp > val ? temp - 1 : temp;
3071 break;
3072
3073 case RZ:
3074 // Nothing to do.
3075 break;
3076
3077 default:
3078 UNREACHABLE();
3079 }
Steve Blockd0582a62009-12-15 09:54:21 +00003080 }
Steve Block6ded16b2010-05-10 14:33:55 +01003081
Steve Block1e0659c2011-05-24 12:43:12 +01003082 // Update the destination register.
3083 set_s_register_from_sinteger(dst, temp);
Russell Brenner90bac252010-11-18 13:33:46 -08003084
Steve Block6ded16b2010-05-10 14:33:55 +01003085 } else {
3086 bool unsigned_integer = (instr->Bit(7) == 0);
3087
Steve Block1e0659c2011-05-24 12:43:12 +01003088 int dst = instr->VFPDRegValue(src_precision);
3089 int src = instr->VFPMRegValue(kSinglePrecision);
Steve Block6ded16b2010-05-10 14:33:55 +01003090
3091 int val = get_sinteger_from_s_register(src);
3092
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003093 if (src_precision == kDoublePrecision) {
Steve Block6ded16b2010-05-10 14:33:55 +01003094 if (unsigned_integer) {
3095 set_d_register_from_double(dst,
3096 static_cast<double>((uint32_t)val));
3097 } else {
3098 set_d_register_from_double(dst, static_cast<double>(val));
3099 }
3100 } else {
3101 if (unsigned_integer) {
3102 set_s_register_from_float(dst,
3103 static_cast<float>((uint32_t)val));
3104 } else {
3105 set_s_register_from_float(dst, static_cast<float>(val));
3106 }
Steve Blockd0582a62009-12-15 09:54:21 +00003107 }
3108 }
3109}
3110
3111
Steve Block1e0659c2011-05-24 12:43:12 +01003112// void Simulator::DecodeType6CoprocessorIns(Instruction* instr)
Steve Blockd0582a62009-12-15 09:54:21 +00003113// Decode Type 6 coprocessor instructions.
Leon Clarkee46be812010-01-19 14:06:41 +00003114// Dm = vmov(Rt, Rt2)
3115// <Rt, Rt2> = vmov(Dm)
Leon Clarked91b9f72010-01-27 17:25:45 +00003116// Ddst = MEM(Rbase + 4*offset).
3117// MEM(Rbase + 4*offset) = Dsrc.
Steve Block1e0659c2011-05-24 12:43:12 +01003118void Simulator::DecodeType6CoprocessorIns(Instruction* instr) {
3119 ASSERT((instr->TypeValue() == 6));
Steve Blockd0582a62009-12-15 09:54:21 +00003120
Steve Block1e0659c2011-05-24 12:43:12 +01003121 if (instr->CoprocessorValue() == 0xA) {
3122 switch (instr->OpcodeValue()) {
Steve Block6ded16b2010-05-10 14:33:55 +01003123 case 0x8:
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003124 case 0xA:
3125 case 0xC:
3126 case 0xE: { // Load and store single precision float to memory.
Steve Block1e0659c2011-05-24 12:43:12 +01003127 int rn = instr->RnValue();
3128 int vd = instr->VFPDRegValue(kSinglePrecision);
3129 int offset = instr->Immed8Value();
Steve Block6ded16b2010-05-10 14:33:55 +01003130 if (!instr->HasU()) {
3131 offset = -offset;
3132 }
3133
3134 int32_t address = get_register(rn) + 4 * offset;
3135 if (instr->HasL()) {
3136 // Load double from memory: vldr.
3137 set_s_register_from_sinteger(vd, ReadW(address, instr));
3138 } else {
3139 // Store double to memory: vstr.
3140 WriteW(address, get_sinteger_from_s_register(vd), instr);
3141 }
3142 break;
3143 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01003144 case 0x4:
3145 case 0x5:
3146 case 0x6:
3147 case 0x7:
3148 case 0x9:
3149 case 0xB:
3150 // Load/store multiple single from memory: vldm/vstm.
3151 HandleVList(instr);
3152 break;
Steve Block6ded16b2010-05-10 14:33:55 +01003153 default:
3154 UNIMPLEMENTED(); // Not used by V8.
Steve Block6ded16b2010-05-10 14:33:55 +01003155 }
Steve Block1e0659c2011-05-24 12:43:12 +01003156 } else if (instr->CoprocessorValue() == 0xB) {
3157 switch (instr->OpcodeValue()) {
Leon Clarked91b9f72010-01-27 17:25:45 +00003158 case 0x2:
3159 // Load and store double to two GP registers
3160 if (instr->Bits(7, 4) != 0x1) {
3161 UNIMPLEMENTED(); // Not used by V8.
3162 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01003163 int rt = instr->RtValue();
3164 int rn = instr->RnValue();
3165 int vm = instr->VmValue();
Leon Clarked91b9f72010-01-27 17:25:45 +00003166 if (instr->HasL()) {
3167 int32_t rt_int_value = get_sinteger_from_s_register(2*vm);
3168 int32_t rn_int_value = get_sinteger_from_s_register(2*vm+1);
3169
3170 set_register(rt, rt_int_value);
3171 set_register(rn, rn_int_value);
3172 } else {
3173 int32_t rs_val = get_register(rt);
3174 int32_t rn_val = get_register(rn);
3175
3176 set_s_register_from_sinteger(2*vm, rs_val);
3177 set_s_register_from_sinteger((2*vm+1), rn_val);
3178 }
3179 }
3180 break;
3181 case 0x8:
3182 case 0xC: { // Load and store double to memory.
Steve Block1e0659c2011-05-24 12:43:12 +01003183 int rn = instr->RnValue();
3184 int vd = instr->VdValue();
3185 int offset = instr->Immed8Value();
Leon Clarked91b9f72010-01-27 17:25:45 +00003186 if (!instr->HasU()) {
3187 offset = -offset;
3188 }
3189 int32_t address = get_register(rn) + 4 * offset;
3190 if (instr->HasL()) {
3191 // Load double from memory: vldr.
3192 set_s_register_from_sinteger(2*vd, ReadW(address, instr));
3193 set_s_register_from_sinteger(2*vd + 1, ReadW(address + 4, instr));
3194 } else {
3195 // Store double to memory: vstr.
3196 WriteW(address, get_sinteger_from_s_register(2*vd), instr);
3197 WriteW(address + 4, get_sinteger_from_s_register(2*vd + 1), instr);
3198 }
3199 break;
3200 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01003201 case 0x4:
3202 case 0x5:
3203 case 0x9:
3204 // Load/store multiple double from memory: vldm/vstm.
3205 HandleVList(instr);
3206 break;
Leon Clarked91b9f72010-01-27 17:25:45 +00003207 default:
3208 UNIMPLEMENTED(); // Not used by V8.
Leon Clarked91b9f72010-01-27 17:25:45 +00003209 }
Steve Block6ded16b2010-05-10 14:33:55 +01003210 } else {
3211 UNIMPLEMENTED(); // Not used by V8.
Steve Blockd0582a62009-12-15 09:54:21 +00003212 }
3213}
3214
3215
Steve Blocka7e24c12009-10-30 11:49:00 +00003216// Executes the current instruction.
Steve Block1e0659c2011-05-24 12:43:12 +01003217void Simulator::InstructionDecode(Instruction* instr) {
Steve Block6ded16b2010-05-10 14:33:55 +01003218 if (v8::internal::FLAG_check_icache) {
Steve Block44f0eee2011-05-26 01:26:41 +01003219 CheckICache(isolate_->simulator_i_cache(), instr);
Steve Block6ded16b2010-05-10 14:33:55 +01003220 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003221 pc_modified_ = false;
3222 if (::v8::internal::FLAG_trace_sim) {
3223 disasm::NameConverter converter;
3224 disasm::Disassembler dasm(converter);
3225 // use a reasonably large buffer
3226 v8::internal::EmbeddedVector<char, 256> buffer;
3227 dasm.InstructionDecode(buffer,
3228 reinterpret_cast<byte*>(instr));
Ben Murdochf87a2032010-10-22 12:50:53 +01003229 PrintF(" 0x%08x %s\n", reinterpret_cast<intptr_t>(instr), buffer.start());
Steve Blocka7e24c12009-10-30 11:49:00 +00003230 }
Steve Block1e0659c2011-05-24 12:43:12 +01003231 if (instr->ConditionField() == kSpecialCondition) {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08003232 UNIMPLEMENTED();
Steve Blocka7e24c12009-10-30 11:49:00 +00003233 } else if (ConditionallyExecute(instr)) {
Steve Block1e0659c2011-05-24 12:43:12 +01003234 switch (instr->TypeValue()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003235 case 0:
3236 case 1: {
3237 DecodeType01(instr);
3238 break;
3239 }
3240 case 2: {
3241 DecodeType2(instr);
3242 break;
3243 }
3244 case 3: {
3245 DecodeType3(instr);
3246 break;
3247 }
3248 case 4: {
3249 DecodeType4(instr);
3250 break;
3251 }
3252 case 5: {
3253 DecodeType5(instr);
3254 break;
3255 }
3256 case 6: {
3257 DecodeType6(instr);
3258 break;
3259 }
3260 case 7: {
3261 DecodeType7(instr);
3262 break;
3263 }
3264 default: {
3265 UNIMPLEMENTED();
3266 break;
3267 }
3268 }
Steve Block1e0659c2011-05-24 12:43:12 +01003269 // If the instruction is a non taken conditional stop, we need to skip the
3270 // inlined message address.
3271 } else if (instr->IsStop()) {
3272 set_pc(get_pc() + 2 * Instruction::kInstrSize);
Steve Blocka7e24c12009-10-30 11:49:00 +00003273 }
3274 if (!pc_modified_) {
Steve Block1e0659c2011-05-24 12:43:12 +01003275 set_register(pc, reinterpret_cast<int32_t>(instr)
3276 + Instruction::kInstrSize);
Steve Blocka7e24c12009-10-30 11:49:00 +00003277 }
3278}
3279
3280
Steve Blocka7e24c12009-10-30 11:49:00 +00003281void Simulator::Execute() {
3282 // Get the PC to simulate. Cannot use the accessor here as we need the
3283 // raw PC value and not the one used as input to arithmetic instructions.
3284 int program_counter = get_pc();
3285
3286 if (::v8::internal::FLAG_stop_sim_at == 0) {
3287 // Fast version of the dispatch loop without checking whether the simulator
3288 // should be stopping at a particular executed instruction.
3289 while (program_counter != end_sim_pc) {
Steve Block1e0659c2011-05-24 12:43:12 +01003290 Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
Steve Blocka7e24c12009-10-30 11:49:00 +00003291 icount_++;
3292 InstructionDecode(instr);
3293 program_counter = get_pc();
3294 }
3295 } else {
3296 // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when
3297 // we reach the particular instuction count.
3298 while (program_counter != end_sim_pc) {
Steve Block1e0659c2011-05-24 12:43:12 +01003299 Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
Steve Blocka7e24c12009-10-30 11:49:00 +00003300 icount_++;
3301 if (icount_ == ::v8::internal::FLAG_stop_sim_at) {
Steve Block44f0eee2011-05-26 01:26:41 +01003302 ArmDebugger dbg(this);
Steve Blocka7e24c12009-10-30 11:49:00 +00003303 dbg.Debug();
3304 } else {
3305 InstructionDecode(instr);
3306 }
3307 program_counter = get_pc();
3308 }
3309 }
3310}
3311
3312
3313int32_t Simulator::Call(byte* entry, int argument_count, ...) {
3314 va_list parameters;
3315 va_start(parameters, argument_count);
3316 // Setup arguments
3317
3318 // First four arguments passed in registers.
3319 ASSERT(argument_count >= 4);
3320 set_register(r0, va_arg(parameters, int32_t));
3321 set_register(r1, va_arg(parameters, int32_t));
3322 set_register(r2, va_arg(parameters, int32_t));
3323 set_register(r3, va_arg(parameters, int32_t));
3324
3325 // Remaining arguments passed on stack.
3326 int original_stack = get_register(sp);
3327 // Compute position of stack on entry to generated code.
3328 int entry_stack = (original_stack - (argument_count - 4) * sizeof(int32_t));
3329 if (OS::ActivationFrameAlignment() != 0) {
3330 entry_stack &= -OS::ActivationFrameAlignment();
3331 }
3332 // Store remaining arguments on stack, from low to high memory.
3333 intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
3334 for (int i = 4; i < argument_count; i++) {
3335 stack_argument[i - 4] = va_arg(parameters, int32_t);
3336 }
3337 va_end(parameters);
3338 set_register(sp, entry_stack);
3339
3340 // Prepare to execute the code at entry
3341 set_register(pc, reinterpret_cast<int32_t>(entry));
3342 // Put down marker for end of simulation. The simulator will stop simulation
3343 // when the PC reaches this value. By saving the "end simulation" value into
3344 // the LR the simulation stops when returning to this call point.
3345 set_register(lr, end_sim_pc);
3346
3347 // Remember the values of callee-saved registers.
3348 // The code below assumes that r9 is not used as sb (static base) in
3349 // simulator code and therefore is regarded as a callee-saved register.
3350 int32_t r4_val = get_register(r4);
3351 int32_t r5_val = get_register(r5);
3352 int32_t r6_val = get_register(r6);
3353 int32_t r7_val = get_register(r7);
3354 int32_t r8_val = get_register(r8);
3355 int32_t r9_val = get_register(r9);
3356 int32_t r10_val = get_register(r10);
3357 int32_t r11_val = get_register(r11);
3358
3359 // Setup the callee-saved registers with a known value. To be able to check
3360 // that they are preserved properly across JS execution.
3361 int32_t callee_saved_value = icount_;
3362 set_register(r4, callee_saved_value);
3363 set_register(r5, callee_saved_value);
3364 set_register(r6, callee_saved_value);
3365 set_register(r7, callee_saved_value);
3366 set_register(r8, callee_saved_value);
3367 set_register(r9, callee_saved_value);
3368 set_register(r10, callee_saved_value);
3369 set_register(r11, callee_saved_value);
3370
3371 // Start the simulation
3372 Execute();
3373
3374 // Check that the callee-saved registers have been preserved.
3375 CHECK_EQ(callee_saved_value, get_register(r4));
3376 CHECK_EQ(callee_saved_value, get_register(r5));
3377 CHECK_EQ(callee_saved_value, get_register(r6));
3378 CHECK_EQ(callee_saved_value, get_register(r7));
3379 CHECK_EQ(callee_saved_value, get_register(r8));
3380 CHECK_EQ(callee_saved_value, get_register(r9));
3381 CHECK_EQ(callee_saved_value, get_register(r10));
3382 CHECK_EQ(callee_saved_value, get_register(r11));
3383
3384 // Restore callee-saved registers with the original value.
3385 set_register(r4, r4_val);
3386 set_register(r5, r5_val);
3387 set_register(r6, r6_val);
3388 set_register(r7, r7_val);
3389 set_register(r8, r8_val);
3390 set_register(r9, r9_val);
3391 set_register(r10, r10_val);
3392 set_register(r11, r11_val);
3393
3394 // Pop stack passed arguments.
3395 CHECK_EQ(entry_stack, get_register(sp));
3396 set_register(sp, original_stack);
3397
3398 int32_t result = get_register(r0);
3399 return result;
3400}
3401
Steve Blockd0582a62009-12-15 09:54:21 +00003402
3403uintptr_t Simulator::PushAddress(uintptr_t address) {
3404 int new_sp = get_register(sp) - sizeof(uintptr_t);
3405 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp);
3406 *stack_slot = address;
3407 set_register(sp, new_sp);
3408 return new_sp;
3409}
3410
3411
3412uintptr_t Simulator::PopAddress() {
3413 int current_sp = get_register(sp);
3414 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp);
3415 uintptr_t address = *stack_slot;
3416 set_register(sp, current_sp + sizeof(uintptr_t));
3417 return address;
3418}
3419
Steve Block1e0659c2011-05-24 12:43:12 +01003420} } // namespace v8::internal
Steve Blocka7e24c12009-10-30 11:49:00 +00003421
John Reck59135872010-11-02 12:39:01 -07003422#endif // USE_SIMULATOR
Leon Clarkef7060e22010-06-03 12:02:55 +01003423
3424#endif // V8_TARGET_ARCH_ARM