blob: 64262b2b81281da294b5e141753f708b145615b8 [file] [log] [blame]
Leon Clarked91b9f72010-01-27 17:25:45 +00001// Copyright 2010 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdlib.h>
Steve Block8defd9f2010-07-08 12:39:36 +010029#include <math.h>
Steve Blocka7e24c12009-10-30 11:49:00 +000030#include <cstdarg>
31#include "v8.h"
32
Leon Clarkef7060e22010-06-03 12:02:55 +010033#if defined(V8_TARGET_ARCH_ARM)
34
Steve Blocka7e24c12009-10-30 11:49:00 +000035#include "disasm.h"
36#include "assembler.h"
37#include "arm/constants-arm.h"
38#include "arm/simulator-arm.h"
39
40#if !defined(__arm__)
41
42// Only build the simulator if not compiling for real ARM hardware.
43namespace assembler {
44namespace arm {
45
46using ::v8::internal::Object;
47using ::v8::internal::PrintF;
48using ::v8::internal::OS;
49using ::v8::internal::ReadLine;
50using ::v8::internal::DeleteArray;
51
52// This macro provides a platform independent use of sscanf. The reason for
Leon Clarked91b9f72010-01-27 17:25:45 +000053// SScanF not being implemented in a platform independent way through
54// ::v8::internal::OS in the same way as SNPrintF is that the
55// Windows C Run-Time Library does not provide vsscanf.
Steve Blocka7e24c12009-10-30 11:49:00 +000056#define SScanF sscanf // NOLINT
57
58// The Debugger class is used by the simulator while debugging simulated ARM
59// code.
60class Debugger {
61 public:
62 explicit Debugger(Simulator* sim);
63 ~Debugger();
64
65 void Stop(Instr* instr);
66 void Debug();
67
68 private:
69 static const instr_t kBreakpointInstr =
70 ((AL << 28) | (7 << 25) | (1 << 24) | break_point);
71 static const instr_t kNopInstr =
72 ((AL << 28) | (13 << 21));
73
74 Simulator* sim_;
75
76 int32_t GetRegisterValue(int regnum);
77 bool GetValue(const char* desc, int32_t* value);
Steve Block6ded16b2010-05-10 14:33:55 +010078 bool GetVFPSingleValue(const char* desc, float* value);
79 bool GetVFPDoubleValue(const char* desc, double* value);
Steve Blocka7e24c12009-10-30 11:49:00 +000080
81 // Set or delete a breakpoint. Returns true if successful.
82 bool SetBreakpoint(Instr* breakpc);
83 bool DeleteBreakpoint(Instr* breakpc);
84
85 // Undo and redo all breakpoints. This is needed to bracket disassembly and
86 // execution to skip past breakpoints when run from the debugger.
87 void UndoBreakpoints();
88 void RedoBreakpoints();
89};
90
91
92Debugger::Debugger(Simulator* sim) {
93 sim_ = sim;
94}
95
96
97Debugger::~Debugger() {
98}
99
100
101
102#ifdef GENERATED_CODE_COVERAGE
103static FILE* coverage_log = NULL;
104
105
106static void InitializeCoverage() {
107 char* file_name = getenv("V8_GENERATED_CODE_COVERAGE_LOG");
108 if (file_name != NULL) {
109 coverage_log = fopen(file_name, "aw+");
110 }
111}
112
113
114void Debugger::Stop(Instr* instr) {
115 char* str = reinterpret_cast<char*>(instr->InstructionBits() & 0x0fffffff);
116 if (strlen(str) > 0) {
117 if (coverage_log != NULL) {
118 fprintf(coverage_log, "%s\n", str);
119 fflush(coverage_log);
120 }
121 instr->SetInstructionBits(0xe1a00000); // Overwrite with nop.
122 }
123 sim_->set_pc(sim_->get_pc() + Instr::kInstrSize);
124}
125
126#else // ndef GENERATED_CODE_COVERAGE
127
128static void InitializeCoverage() {
129}
130
131
132void Debugger::Stop(Instr* instr) {
133 const char* str = (const char*)(instr->InstructionBits() & 0x0fffffff);
134 PrintF("Simulator hit %s\n", str);
135 sim_->set_pc(sim_->get_pc() + Instr::kInstrSize);
136 Debug();
137}
138#endif
139
140
141int32_t Debugger::GetRegisterValue(int regnum) {
142 if (regnum == kPCRegister) {
143 return sim_->get_pc();
144 } else {
145 return sim_->get_register(regnum);
146 }
147}
148
149
150bool Debugger::GetValue(const char* desc, int32_t* value) {
151 int regnum = Registers::Number(desc);
152 if (regnum != kNoRegister) {
153 *value = GetRegisterValue(regnum);
154 return true;
155 } else {
Steve Block6ded16b2010-05-10 14:33:55 +0100156 if (strncmp(desc, "0x", 2) == 0) {
157 return SScanF(desc + 2, "%x", reinterpret_cast<uint32_t*>(value)) == 1;
158 } else {
159 return SScanF(desc, "%u", reinterpret_cast<uint32_t*>(value)) == 1;
160 }
161 }
162 return false;
163}
164
165
166bool Debugger::GetVFPSingleValue(const char* desc, float* value) {
167 bool is_double;
168 int regnum = VFPRegisters::Number(desc, &is_double);
169 if (regnum != kNoRegister && !is_double) {
170 *value = sim_->get_float_from_s_register(regnum);
171 return true;
172 }
173 return false;
174}
175
176
177bool Debugger::GetVFPDoubleValue(const char* desc, double* value) {
178 bool is_double;
179 int regnum = VFPRegisters::Number(desc, &is_double);
180 if (regnum != kNoRegister && is_double) {
181 *value = sim_->get_double_from_d_register(regnum);
182 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +0000183 }
184 return false;
185}
186
187
188bool Debugger::SetBreakpoint(Instr* breakpc) {
189 // Check if a breakpoint can be set. If not return without any side-effects.
190 if (sim_->break_pc_ != NULL) {
191 return false;
192 }
193
194 // Set the breakpoint.
195 sim_->break_pc_ = breakpc;
196 sim_->break_instr_ = breakpc->InstructionBits();
197 // Not setting the breakpoint instruction in the code itself. It will be set
198 // when the debugger shell continues.
199 return true;
200}
201
202
203bool Debugger::DeleteBreakpoint(Instr* breakpc) {
204 if (sim_->break_pc_ != NULL) {
205 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
206 }
207
208 sim_->break_pc_ = NULL;
209 sim_->break_instr_ = 0;
210 return true;
211}
212
213
214void Debugger::UndoBreakpoints() {
215 if (sim_->break_pc_ != NULL) {
216 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
217 }
218}
219
220
221void Debugger::RedoBreakpoints() {
222 if (sim_->break_pc_ != NULL) {
223 sim_->break_pc_->SetInstructionBits(kBreakpointInstr);
224 }
225}
226
227
228void Debugger::Debug() {
229 intptr_t last_pc = -1;
230 bool done = false;
231
232#define COMMAND_SIZE 63
233#define ARG_SIZE 255
234
235#define STR(a) #a
236#define XSTR(a) STR(a)
237
238 char cmd[COMMAND_SIZE + 1];
239 char arg1[ARG_SIZE + 1];
240 char arg2[ARG_SIZE + 1];
Steve Block6ded16b2010-05-10 14:33:55 +0100241 char* argv[3] = { cmd, arg1, arg2 };
Steve Blocka7e24c12009-10-30 11:49:00 +0000242
243 // make sure to have a proper terminating character if reaching the limit
244 cmd[COMMAND_SIZE] = 0;
245 arg1[ARG_SIZE] = 0;
246 arg2[ARG_SIZE] = 0;
247
248 // Undo all set breakpoints while running in the debugger shell. This will
249 // make them invisible to all commands.
250 UndoBreakpoints();
251
252 while (!done) {
253 if (last_pc != sim_->get_pc()) {
254 disasm::NameConverter converter;
255 disasm::Disassembler dasm(converter);
256 // use a reasonably large buffer
257 v8::internal::EmbeddedVector<char, 256> buffer;
258 dasm.InstructionDecode(buffer,
259 reinterpret_cast<byte*>(sim_->get_pc()));
260 PrintF(" 0x%08x %s\n", sim_->get_pc(), buffer.start());
261 last_pc = sim_->get_pc();
262 }
263 char* line = ReadLine("sim> ");
264 if (line == NULL) {
265 break;
266 } else {
267 // Use sscanf to parse the individual parts of the command line. At the
268 // moment no command expects more than two parameters.
Steve Block6ded16b2010-05-10 14:33:55 +0100269 int argc = SScanF(line,
Steve Blocka7e24c12009-10-30 11:49:00 +0000270 "%" XSTR(COMMAND_SIZE) "s "
271 "%" XSTR(ARG_SIZE) "s "
272 "%" XSTR(ARG_SIZE) "s",
273 cmd, arg1, arg2);
274 if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
275 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc()));
276 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) {
277 // Execute the one instruction we broke at with breakpoints disabled.
278 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc()));
279 // Leave the debugger shell.
280 done = true;
281 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
Steve Block6ded16b2010-05-10 14:33:55 +0100282 if (argc == 2) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000283 int32_t value;
Steve Block6ded16b2010-05-10 14:33:55 +0100284 float svalue;
285 double dvalue;
Steve Blocka7e24c12009-10-30 11:49:00 +0000286 if (strcmp(arg1, "all") == 0) {
287 for (int i = 0; i < kNumRegisters; i++) {
288 value = GetRegisterValue(i);
289 PrintF("%3s: 0x%08x %10d\n", Registers::Name(i), value, value);
290 }
291 } else {
292 if (GetValue(arg1, &value)) {
293 PrintF("%s: 0x%08x %d \n", arg1, value, value);
Steve Block6ded16b2010-05-10 14:33:55 +0100294 } else if (GetVFPSingleValue(arg1, &svalue)) {
295 PrintF("%s: %f \n", arg1, svalue);
296 } else if (GetVFPDoubleValue(arg1, &dvalue)) {
297 PrintF("%s: %lf \n", arg1, dvalue);
Steve Blocka7e24c12009-10-30 11:49:00 +0000298 } else {
299 PrintF("%s unrecognized\n", arg1);
300 }
301 }
302 } else {
303 PrintF("print <register>\n");
304 }
305 } else if ((strcmp(cmd, "po") == 0)
306 || (strcmp(cmd, "printobject") == 0)) {
Steve Block6ded16b2010-05-10 14:33:55 +0100307 if (argc == 2) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000308 int32_t value;
309 if (GetValue(arg1, &value)) {
310 Object* obj = reinterpret_cast<Object*>(value);
311 PrintF("%s: \n", arg1);
312#ifdef DEBUG
313 obj->PrintLn();
314#else
315 obj->ShortPrint();
316 PrintF("\n");
317#endif
318 } else {
319 PrintF("%s unrecognized\n", arg1);
320 }
321 } else {
322 PrintF("printobject <value>\n");
323 }
Steve Block6ded16b2010-05-10 14:33:55 +0100324 } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0) {
325 int32_t* cur = NULL;
326 int32_t* end = NULL;
327 int next_arg = 1;
328
329 if (strcmp(cmd, "stack") == 0) {
330 cur = reinterpret_cast<int32_t*>(sim_->get_register(Simulator::sp));
331 } else { // "mem"
332 int32_t value;
333 if (!GetValue(arg1, &value)) {
334 PrintF("%s unrecognized\n", arg1);
335 continue;
336 }
337 cur = reinterpret_cast<int32_t*>(value);
338 next_arg++;
339 }
340
341 int32_t words;
342 if (argc == next_arg) {
343 words = 10;
344 } else if (argc == next_arg + 1) {
345 if (!GetValue(argv[next_arg], &words)) {
346 words = 10;
347 }
348 }
349 end = cur + words;
350
351 while (cur < end) {
352 PrintF(" 0x%08x: 0x%08x %10d\n", cur, *cur, *cur);
353 cur++;
354 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000355 } else if (strcmp(cmd, "disasm") == 0) {
356 disasm::NameConverter converter;
357 disasm::Disassembler dasm(converter);
358 // use a reasonably large buffer
359 v8::internal::EmbeddedVector<char, 256> buffer;
360
361 byte* cur = NULL;
362 byte* end = NULL;
363
Steve Block6ded16b2010-05-10 14:33:55 +0100364 if (argc == 1) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000365 cur = reinterpret_cast<byte*>(sim_->get_pc());
366 end = cur + (10 * Instr::kInstrSize);
Steve Block6ded16b2010-05-10 14:33:55 +0100367 } else if (argc == 2) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000368 int32_t value;
369 if (GetValue(arg1, &value)) {
370 cur = reinterpret_cast<byte*>(value);
371 // no length parameter passed, assume 10 instructions
372 end = cur + (10 * Instr::kInstrSize);
373 }
374 } else {
375 int32_t value1;
376 int32_t value2;
377 if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
378 cur = reinterpret_cast<byte*>(value1);
379 end = cur + (value2 * Instr::kInstrSize);
380 }
381 }
382
383 while (cur < end) {
384 dasm.InstructionDecode(buffer, cur);
385 PrintF(" 0x%08x %s\n", cur, buffer.start());
386 cur += Instr::kInstrSize;
387 }
388 } else if (strcmp(cmd, "gdb") == 0) {
389 PrintF("relinquishing control to gdb\n");
390 v8::internal::OS::DebugBreak();
391 PrintF("regaining control from gdb\n");
392 } else if (strcmp(cmd, "break") == 0) {
Steve Block6ded16b2010-05-10 14:33:55 +0100393 if (argc == 2) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000394 int32_t value;
395 if (GetValue(arg1, &value)) {
396 if (!SetBreakpoint(reinterpret_cast<Instr*>(value))) {
397 PrintF("setting breakpoint failed\n");
398 }
399 } else {
400 PrintF("%s unrecognized\n", arg1);
401 }
402 } else {
403 PrintF("break <address>\n");
404 }
405 } else if (strcmp(cmd, "del") == 0) {
406 if (!DeleteBreakpoint(NULL)) {
407 PrintF("deleting breakpoint failed\n");
408 }
409 } else if (strcmp(cmd, "flags") == 0) {
410 PrintF("N flag: %d; ", sim_->n_flag_);
411 PrintF("Z flag: %d; ", sim_->z_flag_);
412 PrintF("C flag: %d; ", sim_->c_flag_);
413 PrintF("V flag: %d\n", sim_->v_flag_);
Steve Blockd0582a62009-12-15 09:54:21 +0000414 PrintF("INVALID OP flag: %d; ", sim_->inv_op_vfp_flag_);
415 PrintF("DIV BY ZERO flag: %d; ", sim_->div_zero_vfp_flag_);
416 PrintF("OVERFLOW flag: %d; ", sim_->overflow_vfp_flag_);
417 PrintF("UNDERFLOW flag: %d; ", sim_->underflow_vfp_flag_);
418 PrintF("INEXACT flag: %d; ", sim_->inexact_vfp_flag_);
Steve Blocka7e24c12009-10-30 11:49:00 +0000419 } else if (strcmp(cmd, "unstop") == 0) {
420 intptr_t stop_pc = sim_->get_pc() - Instr::kInstrSize;
421 Instr* stop_instr = reinterpret_cast<Instr*>(stop_pc);
422 if (stop_instr->ConditionField() == special_condition) {
423 stop_instr->SetInstructionBits(kNopInstr);
424 } else {
425 PrintF("Not at debugger stop.");
426 }
Leon Clarkee46be812010-01-19 14:06:41 +0000427 } else if ((strcmp(cmd, "t") == 0) || strcmp(cmd, "trace") == 0) {
428 ::v8::internal::FLAG_trace_sim = !::v8::internal::FLAG_trace_sim;
429 PrintF("Trace of executed instructions is %s\n",
430 ::v8::internal::FLAG_trace_sim ? "on" : "off");
Steve Blocka7e24c12009-10-30 11:49:00 +0000431 } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
432 PrintF("cont\n");
433 PrintF(" continue execution (alias 'c')\n");
434 PrintF("stepi\n");
435 PrintF(" step one instruction (alias 'si')\n");
436 PrintF("print <register>\n");
437 PrintF(" print register content (alias 'p')\n");
438 PrintF(" use register name 'all' to print all registers\n");
439 PrintF("printobject <register>\n");
440 PrintF(" print an object from a register (alias 'po')\n");
441 PrintF("flags\n");
442 PrintF(" print flags\n");
Steve Block6ded16b2010-05-10 14:33:55 +0100443 PrintF("stack [<words>]\n");
444 PrintF(" dump stack content, default dump 10 words)\n");
445 PrintF("mem <address> [<words>]\n");
446 PrintF(" dump memory content, default dump 10 words)\n");
Steve Blocka7e24c12009-10-30 11:49:00 +0000447 PrintF("disasm [<instructions>]\n");
448 PrintF("disasm [[<address>] <instructions>]\n");
449 PrintF(" disassemble code, default is 10 instructions from pc\n");
450 PrintF("gdb\n");
451 PrintF(" enter gdb\n");
452 PrintF("break <address>\n");
453 PrintF(" set a break point on the address\n");
454 PrintF("del\n");
455 PrintF(" delete the breakpoint\n");
456 PrintF("unstop\n");
457 PrintF(" ignore the stop instruction at the current location");
Leon Clarkee46be812010-01-19 14:06:41 +0000458 PrintF(" from now on\n");
459 PrintF("trace (alias 't')\n");
Steve Block6ded16b2010-05-10 14:33:55 +0100460 PrintF(" toogle the tracing of all executed statements\n");
Steve Blocka7e24c12009-10-30 11:49:00 +0000461 } else {
462 PrintF("Unknown command: %s\n", cmd);
463 }
464 }
465 DeleteArray(line);
466 }
467
468 // Add all the breakpoints back to stop execution and enter the debugger
469 // shell when hit.
470 RedoBreakpoints();
471
472#undef COMMAND_SIZE
473#undef ARG_SIZE
474
475#undef STR
476#undef XSTR
477}
478
479
Steve Block6ded16b2010-05-10 14:33:55 +0100480static bool ICacheMatch(void* one, void* two) {
481 ASSERT((reinterpret_cast<intptr_t>(one) & CachePage::kPageMask) == 0);
482 ASSERT((reinterpret_cast<intptr_t>(two) & CachePage::kPageMask) == 0);
483 return one == two;
484}
485
486
487static uint32_t ICacheHash(void* key) {
488 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)) >> 2;
489}
490
491
492static bool AllOnOnePage(uintptr_t start, int size) {
493 intptr_t start_page = (start & ~CachePage::kPageMask);
494 intptr_t end_page = ((start + size) & ~CachePage::kPageMask);
495 return start_page == end_page;
496}
497
498
499void Simulator::FlushICache(void* start_addr, size_t size) {
500 intptr_t start = reinterpret_cast<intptr_t>(start_addr);
501 int intra_line = (start & CachePage::kLineMask);
502 start -= intra_line;
503 size += intra_line;
504 size = ((size - 1) | CachePage::kLineMask) + 1;
505 int offset = (start & CachePage::kPageMask);
506 while (!AllOnOnePage(start, size - 1)) {
507 int bytes_to_flush = CachePage::kPageSize - offset;
508 FlushOnePage(start, bytes_to_flush);
509 start += bytes_to_flush;
510 size -= bytes_to_flush;
511 ASSERT_EQ(0, start & CachePage::kPageMask);
512 offset = 0;
513 }
514 if (size != 0) {
515 FlushOnePage(start, size);
516 }
517}
518
519
520CachePage* Simulator::GetCachePage(void* page) {
521 v8::internal::HashMap::Entry* entry = i_cache_->Lookup(page,
522 ICacheHash(page),
523 true);
524 if (entry->value == NULL) {
525 CachePage* new_page = new CachePage();
526 entry->value = new_page;
527 }
528 return reinterpret_cast<CachePage*>(entry->value);
529}
530
531
532// Flush from start up to and not including start + size.
533void Simulator::FlushOnePage(intptr_t start, int size) {
534 ASSERT(size <= CachePage::kPageSize);
535 ASSERT(AllOnOnePage(start, size - 1));
536 ASSERT((start & CachePage::kLineMask) == 0);
537 ASSERT((size & CachePage::kLineMask) == 0);
538 void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask));
539 int offset = (start & CachePage::kPageMask);
540 CachePage* cache_page = GetCachePage(page);
541 char* valid_bytemap = cache_page->ValidityByte(offset);
542 memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift);
543}
544
545
546void Simulator::CheckICache(Instr* instr) {
547 intptr_t address = reinterpret_cast<intptr_t>(instr);
548 void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
549 void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask));
550 int offset = (address & CachePage::kPageMask);
551 CachePage* cache_page = GetCachePage(page);
552 char* cache_valid_byte = cache_page->ValidityByte(offset);
553 bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID);
554 char* cached_line = cache_page->CachedData(offset & ~CachePage::kLineMask);
555 if (cache_hit) {
556 // Check that the data in memory matches the contents of the I-cache.
557 CHECK(memcmp(reinterpret_cast<void*>(instr),
558 cache_page->CachedData(offset),
559 Instr::kInstrSize) == 0);
560 } else {
561 // Cache miss. Load memory into the cache.
562 memcpy(cached_line, line, CachePage::kLineLength);
563 *cache_valid_byte = CachePage::LINE_VALID;
564 }
565}
566
567
Steve Blocka7e24c12009-10-30 11:49:00 +0000568// Create one simulator per thread and keep it in thread local storage.
569static v8::internal::Thread::LocalStorageKey simulator_key;
570
571
572bool Simulator::initialized_ = false;
573
574
575void Simulator::Initialize() {
576 if (initialized_) return;
577 simulator_key = v8::internal::Thread::CreateThreadLocalKey();
578 initialized_ = true;
579 ::v8::internal::ExternalReference::set_redirector(&RedirectExternalReference);
580}
581
582
Steve Block6ded16b2010-05-10 14:33:55 +0100583v8::internal::HashMap* Simulator::i_cache_ = NULL;
584
585
Steve Blocka7e24c12009-10-30 11:49:00 +0000586Simulator::Simulator() {
Steve Block6ded16b2010-05-10 14:33:55 +0100587 if (i_cache_ == NULL) {
588 i_cache_ = new v8::internal::HashMap(&ICacheMatch);
589 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000590 Initialize();
591 // Setup simulator support first. Some of this information is needed to
592 // setup the architecture state.
593 size_t stack_size = 1 * 1024*1024; // allocate 1MB for stack
594 stack_ = reinterpret_cast<char*>(malloc(stack_size));
595 pc_modified_ = false;
596 icount_ = 0;
597 break_pc_ = NULL;
598 break_instr_ = 0;
599
600 // Setup architecture state.
601 // All registers are initialized to zero to start with.
602 for (int i = 0; i < num_registers; i++) {
603 registers_[i] = 0;
604 }
605 n_flag_ = false;
606 z_flag_ = false;
607 c_flag_ = false;
608 v_flag_ = false;
609
Steve Blockd0582a62009-12-15 09:54:21 +0000610 // Initializing VFP registers.
611 // All registers are initialized to zero to start with
612 // even though s_registers_ & d_registers_ share the same
613 // physical registers in the target.
614 for (int i = 0; i < num_s_registers; i++) {
615 vfp_register[i] = 0;
616 }
617 n_flag_FPSCR_ = false;
618 z_flag_FPSCR_ = false;
619 c_flag_FPSCR_ = false;
620 v_flag_FPSCR_ = false;
621
622 inv_op_vfp_flag_ = false;
623 div_zero_vfp_flag_ = false;
624 overflow_vfp_flag_ = false;
625 underflow_vfp_flag_ = false;
626 inexact_vfp_flag_ = false;
627
Steve Blocka7e24c12009-10-30 11:49:00 +0000628 // The sp is initialized to point to the bottom (high address) of the
629 // allocated stack area. To be safe in potential stack underflows we leave
630 // some buffer below.
631 registers_[sp] = reinterpret_cast<int32_t>(stack_) + stack_size - 64;
632 // The lr and pc are initialized to a known bad value that will cause an
633 // access violation if the simulator ever tries to execute it.
634 registers_[pc] = bad_lr;
635 registers_[lr] = bad_lr;
636 InitializeCoverage();
637}
638
639
640// When the generated code calls an external reference we need to catch that in
641// the simulator. The external reference will be a function compiled for the
642// host architecture. We need to call that function instead of trying to
643// execute it with the simulator. We do that by redirecting the external
644// reference to a swi (software-interrupt) instruction that is handled by
645// the simulator. We write the original destination of the jump just at a known
646// offset from the swi instruction so the simulator knows what to call.
647class Redirection {
648 public:
649 Redirection(void* external_function, bool fp_return)
650 : external_function_(external_function),
651 swi_instruction_((AL << 28) | (0xf << 24) | call_rt_redirected),
652 fp_return_(fp_return),
653 next_(list_) {
Steve Block6ded16b2010-05-10 14:33:55 +0100654 Simulator::current()->
655 FlushICache(reinterpret_cast<void*>(&swi_instruction_),
656 Instr::kInstrSize);
Steve Blocka7e24c12009-10-30 11:49:00 +0000657 list_ = this;
658 }
659
660 void* address_of_swi_instruction() {
661 return reinterpret_cast<void*>(&swi_instruction_);
662 }
663
664 void* external_function() { return external_function_; }
665 bool fp_return() { return fp_return_; }
666
667 static Redirection* Get(void* external_function, bool fp_return) {
668 Redirection* current;
669 for (current = list_; current != NULL; current = current->next_) {
670 if (current->external_function_ == external_function) return current;
671 }
672 return new Redirection(external_function, fp_return);
673 }
674
675 static Redirection* FromSwiInstruction(Instr* swi_instruction) {
676 char* addr_of_swi = reinterpret_cast<char*>(swi_instruction);
677 char* addr_of_redirection =
678 addr_of_swi - OFFSET_OF(Redirection, swi_instruction_);
679 return reinterpret_cast<Redirection*>(addr_of_redirection);
680 }
681
682 private:
683 void* external_function_;
684 uint32_t swi_instruction_;
685 bool fp_return_;
686 Redirection* next_;
687 static Redirection* list_;
688};
689
690
691Redirection* Redirection::list_ = NULL;
692
693
694void* Simulator::RedirectExternalReference(void* external_function,
695 bool fp_return) {
696 Redirection* redirection = Redirection::Get(external_function, fp_return);
697 return redirection->address_of_swi_instruction();
698}
699
700
701// Get the active Simulator for the current thread.
702Simulator* Simulator::current() {
703 Initialize();
704 Simulator* sim = reinterpret_cast<Simulator*>(
705 v8::internal::Thread::GetThreadLocal(simulator_key));
706 if (sim == NULL) {
707 // TODO(146): delete the simulator object when a thread goes away.
708 sim = new Simulator();
709 v8::internal::Thread::SetThreadLocal(simulator_key, sim);
710 }
711 return sim;
712}
713
714
715// Sets the register in the architecture state. It will also deal with updating
716// Simulator internal state for special registers such as PC.
717void Simulator::set_register(int reg, int32_t value) {
718 ASSERT((reg >= 0) && (reg < num_registers));
719 if (reg == pc) {
720 pc_modified_ = true;
721 }
722 registers_[reg] = value;
723}
724
725
726// Get the register from the architecture state. This function does handle
727// the special case of accessing the PC register.
728int32_t Simulator::get_register(int reg) const {
729 ASSERT((reg >= 0) && (reg < num_registers));
Steve Block791712a2010-08-27 10:21:07 +0100730 // Stupid code added to avoid bug in GCC.
731 // See: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43949
732 if (reg >= num_registers) return 0;
733 // End stupid code.
Steve Blocka7e24c12009-10-30 11:49:00 +0000734 return registers_[reg] + ((reg == pc) ? Instr::kPCReadOffset : 0);
735}
736
737
Kristian Monsen25f61362010-05-21 11:50:48 +0100738void Simulator::set_dw_register(int dreg, const int* dbl) {
739 ASSERT((dreg >= 0) && (dreg < num_d_registers));
740 registers_[dreg] = dbl[0];
741 registers_[dreg + 1] = dbl[1];
742}
743
744
Steve Blocka7e24c12009-10-30 11:49:00 +0000745// Raw access to the PC register.
746void Simulator::set_pc(int32_t value) {
747 pc_modified_ = true;
748 registers_[pc] = value;
749}
750
751
752// Raw access to the PC register without the special adjustment when reading.
753int32_t Simulator::get_pc() const {
754 return registers_[pc];
755}
756
757
Steve Blockd0582a62009-12-15 09:54:21 +0000758// Getting from and setting into VFP registers.
759void Simulator::set_s_register(int sreg, unsigned int value) {
760 ASSERT((sreg >= 0) && (sreg < num_s_registers));
761 vfp_register[sreg] = value;
762}
763
764
765unsigned int Simulator::get_s_register(int sreg) const {
766 ASSERT((sreg >= 0) && (sreg < num_s_registers));
767 return vfp_register[sreg];
768}
769
770
771void Simulator::set_s_register_from_float(int sreg, const float flt) {
772 ASSERT((sreg >= 0) && (sreg < num_s_registers));
773 // Read the bits from the single precision floating point value
774 // into the unsigned integer element of vfp_register[] given by index=sreg.
775 char buffer[sizeof(vfp_register[0])];
776 memcpy(buffer, &flt, sizeof(vfp_register[0]));
777 memcpy(&vfp_register[sreg], buffer, sizeof(vfp_register[0]));
778}
779
780
781void Simulator::set_s_register_from_sinteger(int sreg, const int sint) {
782 ASSERT((sreg >= 0) && (sreg < num_s_registers));
783 // Read the bits from the integer value into the unsigned integer element of
784 // vfp_register[] given by index=sreg.
785 char buffer[sizeof(vfp_register[0])];
786 memcpy(buffer, &sint, sizeof(vfp_register[0]));
787 memcpy(&vfp_register[sreg], buffer, sizeof(vfp_register[0]));
788}
789
790
791void Simulator::set_d_register_from_double(int dreg, const double& dbl) {
792 ASSERT((dreg >= 0) && (dreg < num_d_registers));
793 // Read the bits from the double precision floating point value into the two
794 // consecutive unsigned integer elements of vfp_register[] given by index
795 // 2*sreg and 2*sreg+1.
796 char buffer[2 * sizeof(vfp_register[0])];
797 memcpy(buffer, &dbl, 2 * sizeof(vfp_register[0]));
798#ifndef BIG_ENDIAN_FLOATING_POINT
799 memcpy(&vfp_register[dreg * 2], buffer, 2 * sizeof(vfp_register[0]));
800#else
801 memcpy(&vfp_register[dreg * 2], &buffer[4], sizeof(vfp_register[0]));
802 memcpy(&vfp_register[dreg * 2 + 1], &buffer[0], sizeof(vfp_register[0]));
803#endif
804}
805
806
807float Simulator::get_float_from_s_register(int sreg) {
808 ASSERT((sreg >= 0) && (sreg < num_s_registers));
809
810 float sm_val = 0.0;
811 // Read the bits from the unsigned integer vfp_register[] array
812 // into the single precision floating point value and return it.
813 char buffer[sizeof(vfp_register[0])];
814 memcpy(buffer, &vfp_register[sreg], sizeof(vfp_register[0]));
815 memcpy(&sm_val, buffer, sizeof(vfp_register[0]));
816 return(sm_val);
817}
818
819
820int Simulator::get_sinteger_from_s_register(int sreg) {
821 ASSERT((sreg >= 0) && (sreg < num_s_registers));
822
823 int sm_val = 0;
824 // Read the bits from the unsigned integer vfp_register[] array
825 // into the single precision floating point value and return it.
826 char buffer[sizeof(vfp_register[0])];
827 memcpy(buffer, &vfp_register[sreg], sizeof(vfp_register[0]));
828 memcpy(&sm_val, buffer, sizeof(vfp_register[0]));
829 return(sm_val);
830}
831
832
833double Simulator::get_double_from_d_register(int dreg) {
834 ASSERT((dreg >= 0) && (dreg < num_d_registers));
835
836 double dm_val = 0.0;
837 // Read the bits from the unsigned integer vfp_register[] array
838 // into the double precision floating point value and return it.
839 char buffer[2 * sizeof(vfp_register[0])];
840#ifdef BIG_ENDIAN_FLOATING_POINT
841 memcpy(&buffer[0], &vfp_register[2 * dreg + 1], sizeof(vfp_register[0]));
842 memcpy(&buffer[4], &vfp_register[2 * dreg], sizeof(vfp_register[0]));
843#else
844 memcpy(buffer, &vfp_register[2 * dreg], 2 * sizeof(vfp_register[0]));
845#endif
846 memcpy(&dm_val, buffer, 2 * sizeof(vfp_register[0]));
847 return(dm_val);
848}
849
850
Steve Blocka7e24c12009-10-30 11:49:00 +0000851// For use in calls that take two double values, constructed from r0, r1, r2
852// and r3.
853void Simulator::GetFpArgs(double* x, double* y) {
854 // We use a char buffer to get around the strict-aliasing rules which
855 // otherwise allow the compiler to optimize away the copy.
856 char buffer[2 * sizeof(registers_[0])];
857 // Registers 0 and 1 -> x.
858 memcpy(buffer, registers_, sizeof(buffer));
859 memcpy(x, buffer, sizeof(buffer));
860 // Registers 2 and 3 -> y.
861 memcpy(buffer, registers_ + 2, sizeof(buffer));
862 memcpy(y, buffer, sizeof(buffer));
863}
864
865
866void Simulator::SetFpResult(const double& result) {
867 char buffer[2 * sizeof(registers_[0])];
868 memcpy(buffer, &result, sizeof(buffer));
869 // result -> registers 0 and 1.
870 memcpy(registers_, buffer, sizeof(buffer));
871}
872
873
874void Simulator::TrashCallerSaveRegisters() {
875 // We don't trash the registers with the return value.
876 registers_[2] = 0x50Bad4U;
877 registers_[3] = 0x50Bad4U;
878 registers_[12] = 0x50Bad4U;
879}
880
Kristian Monsen25f61362010-05-21 11:50:48 +0100881// Some Operating Systems allow unaligned access on ARMv7 targets. We
882// assume that unaligned accesses are not allowed unless the v8 build system
883// defines the CAN_USE_UNALIGNED_ACCESSES macro to be non-zero.
884// The following statements below describes the behavior of the ARM CPUs
885// that don't support unaligned access.
886// Some ARM platforms raise an interrupt on detecting unaligned access.
887// On others it does a funky rotation thing. For now we
888// simply disallow unaligned reads. Note that simulator runs have the runtime
Steve Blocka7e24c12009-10-30 11:49:00 +0000889// system running directly on the host system and only generated code is
890// executed in the simulator. Since the host is typically IA32 we will not
Kristian Monsen25f61362010-05-21 11:50:48 +0100891// get the correct ARM-like behaviour on unaligned accesses for those ARM
892// targets that don't support unaligned loads and stores.
893
Steve Blocka7e24c12009-10-30 11:49:00 +0000894
895int Simulator::ReadW(int32_t addr, Instr* instr) {
Kristian Monsen25f61362010-05-21 11:50:48 +0100896#if V8_TARGET_CAN_READ_UNALIGNED
897 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
898 return *ptr;
899#else
Steve Blocka7e24c12009-10-30 11:49:00 +0000900 if ((addr & 3) == 0) {
901 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
902 return *ptr;
903 }
Kristian Monsen25f61362010-05-21 11:50:48 +0100904 PrintF("Unaligned read at 0x%08x, pc=%p\n", addr, instr);
Steve Blocka7e24c12009-10-30 11:49:00 +0000905 UNIMPLEMENTED();
906 return 0;
Kristian Monsen25f61362010-05-21 11:50:48 +0100907#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000908}
909
910
911void Simulator::WriteW(int32_t addr, int value, Instr* instr) {
Kristian Monsen25f61362010-05-21 11:50:48 +0100912#if V8_TARGET_CAN_READ_UNALIGNED
913 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
914 *ptr = value;
915 return;
916#else
Steve Blocka7e24c12009-10-30 11:49:00 +0000917 if ((addr & 3) == 0) {
918 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
919 *ptr = value;
920 return;
921 }
922 PrintF("Unaligned write at 0x%08x, pc=%p\n", addr, instr);
923 UNIMPLEMENTED();
Kristian Monsen25f61362010-05-21 11:50:48 +0100924#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000925}
926
927
928uint16_t Simulator::ReadHU(int32_t addr, Instr* instr) {
Kristian Monsen25f61362010-05-21 11:50:48 +0100929#if V8_TARGET_CAN_READ_UNALIGNED
930 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
931 return *ptr;
932#else
Steve Blocka7e24c12009-10-30 11:49:00 +0000933 if ((addr & 1) == 0) {
934 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
935 return *ptr;
936 }
937 PrintF("Unaligned unsigned halfword read at 0x%08x, pc=%p\n", addr, instr);
938 UNIMPLEMENTED();
939 return 0;
Kristian Monsen25f61362010-05-21 11:50:48 +0100940#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000941}
942
943
944int16_t Simulator::ReadH(int32_t addr, Instr* instr) {
Kristian Monsen25f61362010-05-21 11:50:48 +0100945#if V8_TARGET_CAN_READ_UNALIGNED
946 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
947 return *ptr;
948#else
Steve Blocka7e24c12009-10-30 11:49:00 +0000949 if ((addr & 1) == 0) {
950 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
951 return *ptr;
952 }
953 PrintF("Unaligned signed halfword read at 0x%08x\n", addr);
954 UNIMPLEMENTED();
955 return 0;
Kristian Monsen25f61362010-05-21 11:50:48 +0100956#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000957}
958
959
960void Simulator::WriteH(int32_t addr, uint16_t value, Instr* instr) {
Kristian Monsen25f61362010-05-21 11:50:48 +0100961#if V8_TARGET_CAN_READ_UNALIGNED
962 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
963 *ptr = value;
964 return;
965#else
Steve Blocka7e24c12009-10-30 11:49:00 +0000966 if ((addr & 1) == 0) {
967 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
968 *ptr = value;
969 return;
970 }
971 PrintF("Unaligned unsigned halfword write at 0x%08x, pc=%p\n", addr, instr);
972 UNIMPLEMENTED();
Kristian Monsen25f61362010-05-21 11:50:48 +0100973#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000974}
975
976
977void Simulator::WriteH(int32_t addr, int16_t value, Instr* instr) {
Kristian Monsen25f61362010-05-21 11:50:48 +0100978#if V8_TARGET_CAN_READ_UNALIGNED
979 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
980 *ptr = value;
981 return;
982#else
Steve Blocka7e24c12009-10-30 11:49:00 +0000983 if ((addr & 1) == 0) {
984 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
985 *ptr = value;
986 return;
987 }
988 PrintF("Unaligned halfword write at 0x%08x, pc=%p\n", addr, instr);
989 UNIMPLEMENTED();
Kristian Monsen25f61362010-05-21 11:50:48 +0100990#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000991}
992
993
994uint8_t Simulator::ReadBU(int32_t addr) {
995 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
996 return *ptr;
997}
998
999
1000int8_t Simulator::ReadB(int32_t addr) {
1001 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
1002 return *ptr;
1003}
1004
1005
1006void Simulator::WriteB(int32_t addr, uint8_t value) {
1007 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1008 *ptr = value;
1009}
1010
1011
1012void Simulator::WriteB(int32_t addr, int8_t value) {
1013 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
1014 *ptr = value;
1015}
1016
1017
Kristian Monsen25f61362010-05-21 11:50:48 +01001018int32_t* Simulator::ReadDW(int32_t addr) {
1019#if V8_TARGET_CAN_READ_UNALIGNED
1020 int32_t* ptr = reinterpret_cast<int32_t*>(addr);
1021 return ptr;
1022#else
1023 if ((addr & 3) == 0) {
1024 int32_t* ptr = reinterpret_cast<int32_t*>(addr);
1025 return ptr;
1026 }
1027 PrintF("Unaligned read at 0x%08x\n", addr);
1028 UNIMPLEMENTED();
1029 return 0;
1030#endif
1031}
1032
1033
1034void Simulator::WriteDW(int32_t addr, int32_t value1, int32_t value2) {
1035#if V8_TARGET_CAN_READ_UNALIGNED
1036 int32_t* ptr = reinterpret_cast<int32_t*>(addr);
1037 *ptr++ = value1;
1038 *ptr = value2;
1039 return;
1040#else
1041 if ((addr & 3) == 0) {
1042 int32_t* ptr = reinterpret_cast<int32_t*>(addr);
1043 *ptr++ = value1;
1044 *ptr = value2;
1045 return;
1046 }
1047 PrintF("Unaligned write at 0x%08x\n", addr);
1048 UNIMPLEMENTED();
1049#endif
1050}
1051
1052
Steve Blocka7e24c12009-10-30 11:49:00 +00001053// Returns the limit of the stack area to enable checking for stack overflows.
1054uintptr_t Simulator::StackLimit() const {
1055 // Leave a safety margin of 256 bytes to prevent overrunning the stack when
1056 // pushing values.
1057 return reinterpret_cast<uintptr_t>(stack_) + 256;
1058}
1059
1060
1061// Unsupported instructions use Format to print an error and stop execution.
1062void Simulator::Format(Instr* instr, const char* format) {
1063 PrintF("Simulator found unsupported instruction:\n 0x%08x: %s\n",
1064 instr, format);
1065 UNIMPLEMENTED();
1066}
1067
1068
1069// Checks if the current instruction should be executed based on its
1070// condition bits.
1071bool Simulator::ConditionallyExecute(Instr* instr) {
1072 switch (instr->ConditionField()) {
1073 case EQ: return z_flag_;
1074 case NE: return !z_flag_;
1075 case CS: return c_flag_;
1076 case CC: return !c_flag_;
1077 case MI: return n_flag_;
1078 case PL: return !n_flag_;
1079 case VS: return v_flag_;
1080 case VC: return !v_flag_;
1081 case HI: return c_flag_ && !z_flag_;
1082 case LS: return !c_flag_ || z_flag_;
1083 case GE: return n_flag_ == v_flag_;
1084 case LT: return n_flag_ != v_flag_;
1085 case GT: return !z_flag_ && (n_flag_ == v_flag_);
1086 case LE: return z_flag_ || (n_flag_ != v_flag_);
1087 case AL: return true;
1088 default: UNREACHABLE();
1089 }
1090 return false;
1091}
1092
1093
1094// Calculate and set the Negative and Zero flags.
1095void Simulator::SetNZFlags(int32_t val) {
1096 n_flag_ = (val < 0);
1097 z_flag_ = (val == 0);
1098}
1099
1100
1101// Set the Carry flag.
1102void Simulator::SetCFlag(bool val) {
1103 c_flag_ = val;
1104}
1105
1106
1107// Set the oVerflow flag.
1108void Simulator::SetVFlag(bool val) {
1109 v_flag_ = val;
1110}
1111
1112
1113// Calculate C flag value for additions.
1114bool Simulator::CarryFrom(int32_t left, int32_t right) {
1115 uint32_t uleft = static_cast<uint32_t>(left);
1116 uint32_t uright = static_cast<uint32_t>(right);
1117 uint32_t urest = 0xffffffffU - uleft;
1118
1119 return (uright > urest);
1120}
1121
1122
1123// Calculate C flag value for subtractions.
1124bool Simulator::BorrowFrom(int32_t left, int32_t right) {
1125 uint32_t uleft = static_cast<uint32_t>(left);
1126 uint32_t uright = static_cast<uint32_t>(right);
1127
1128 return (uright > uleft);
1129}
1130
1131
1132// Calculate V flag value for additions and subtractions.
1133bool Simulator::OverflowFrom(int32_t alu_out,
1134 int32_t left, int32_t right, bool addition) {
1135 bool overflow;
1136 if (addition) {
1137 // operands have the same sign
1138 overflow = ((left >= 0 && right >= 0) || (left < 0 && right < 0))
1139 // and operands and result have different sign
1140 && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
1141 } else {
1142 // operands have different signs
1143 overflow = ((left < 0 && right >= 0) || (left >= 0 && right < 0))
1144 // and first operand and result have different signs
1145 && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
1146 }
1147 return overflow;
1148}
1149
1150
Steve Blockd0582a62009-12-15 09:54:21 +00001151// Support for VFP comparisons.
1152void Simulator::Compute_FPSCR_Flags(double val1, double val2) {
Leon Clarkee46be812010-01-19 14:06:41 +00001153 if (isnan(val1) || isnan(val2)) {
1154 n_flag_FPSCR_ = false;
1155 z_flag_FPSCR_ = false;
1156 c_flag_FPSCR_ = true;
1157 v_flag_FPSCR_ = true;
Steve Blockd0582a62009-12-15 09:54:21 +00001158 // All non-NaN cases.
Leon Clarkee46be812010-01-19 14:06:41 +00001159 } else if (val1 == val2) {
Steve Blockd0582a62009-12-15 09:54:21 +00001160 n_flag_FPSCR_ = false;
1161 z_flag_FPSCR_ = true;
1162 c_flag_FPSCR_ = true;
1163 v_flag_FPSCR_ = false;
1164 } else if (val1 < val2) {
1165 n_flag_FPSCR_ = true;
1166 z_flag_FPSCR_ = false;
1167 c_flag_FPSCR_ = false;
1168 v_flag_FPSCR_ = false;
1169 } else {
1170 // Case when (val1 > val2).
1171 n_flag_FPSCR_ = false;
1172 z_flag_FPSCR_ = false;
1173 c_flag_FPSCR_ = true;
1174 v_flag_FPSCR_ = false;
1175 }
1176}
1177
1178
1179void Simulator::Copy_FPSCR_to_APSR() {
1180 n_flag_ = n_flag_FPSCR_;
1181 z_flag_ = z_flag_FPSCR_;
1182 c_flag_ = c_flag_FPSCR_;
1183 v_flag_ = v_flag_FPSCR_;
1184}
1185
1186
Steve Blocka7e24c12009-10-30 11:49:00 +00001187// Addressing Mode 1 - Data-processing operands:
1188// Get the value based on the shifter_operand with register.
1189int32_t Simulator::GetShiftRm(Instr* instr, bool* carry_out) {
1190 Shift shift = instr->ShiftField();
1191 int shift_amount = instr->ShiftAmountField();
1192 int32_t result = get_register(instr->RmField());
1193 if (instr->Bit(4) == 0) {
1194 // by immediate
1195 if ((shift == ROR) && (shift_amount == 0)) {
1196 UNIMPLEMENTED();
1197 return result;
1198 } else if (((shift == LSR) || (shift == ASR)) && (shift_amount == 0)) {
1199 shift_amount = 32;
1200 }
1201 switch (shift) {
1202 case ASR: {
1203 if (shift_amount == 0) {
1204 if (result < 0) {
1205 result = 0xffffffff;
1206 *carry_out = true;
1207 } else {
1208 result = 0;
1209 *carry_out = false;
1210 }
1211 } else {
1212 result >>= (shift_amount - 1);
1213 *carry_out = (result & 1) == 1;
1214 result >>= 1;
1215 }
1216 break;
1217 }
1218
1219 case LSL: {
1220 if (shift_amount == 0) {
1221 *carry_out = c_flag_;
1222 } else {
1223 result <<= (shift_amount - 1);
1224 *carry_out = (result < 0);
1225 result <<= 1;
1226 }
1227 break;
1228 }
1229
1230 case LSR: {
1231 if (shift_amount == 0) {
1232 result = 0;
1233 *carry_out = c_flag_;
1234 } else {
1235 uint32_t uresult = static_cast<uint32_t>(result);
1236 uresult >>= (shift_amount - 1);
1237 *carry_out = (uresult & 1) == 1;
1238 uresult >>= 1;
1239 result = static_cast<int32_t>(uresult);
1240 }
1241 break;
1242 }
1243
1244 case ROR: {
1245 UNIMPLEMENTED();
1246 break;
1247 }
1248
1249 default: {
1250 UNREACHABLE();
1251 break;
1252 }
1253 }
1254 } else {
1255 // by register
1256 int rs = instr->RsField();
1257 shift_amount = get_register(rs) &0xff;
1258 switch (shift) {
1259 case ASR: {
1260 if (shift_amount == 0) {
1261 *carry_out = c_flag_;
1262 } else if (shift_amount < 32) {
1263 result >>= (shift_amount - 1);
1264 *carry_out = (result & 1) == 1;
1265 result >>= 1;
1266 } else {
1267 ASSERT(shift_amount >= 32);
1268 if (result < 0) {
1269 *carry_out = true;
1270 result = 0xffffffff;
1271 } else {
1272 *carry_out = false;
1273 result = 0;
1274 }
1275 }
1276 break;
1277 }
1278
1279 case LSL: {
1280 if (shift_amount == 0) {
1281 *carry_out = c_flag_;
1282 } else if (shift_amount < 32) {
1283 result <<= (shift_amount - 1);
1284 *carry_out = (result < 0);
1285 result <<= 1;
1286 } else if (shift_amount == 32) {
1287 *carry_out = (result & 1) == 1;
1288 result = 0;
1289 } else {
1290 ASSERT(shift_amount > 32);
1291 *carry_out = false;
1292 result = 0;
1293 }
1294 break;
1295 }
1296
1297 case LSR: {
1298 if (shift_amount == 0) {
1299 *carry_out = c_flag_;
1300 } else if (shift_amount < 32) {
1301 uint32_t uresult = static_cast<uint32_t>(result);
1302 uresult >>= (shift_amount - 1);
1303 *carry_out = (uresult & 1) == 1;
1304 uresult >>= 1;
1305 result = static_cast<int32_t>(uresult);
1306 } else if (shift_amount == 32) {
1307 *carry_out = (result < 0);
1308 result = 0;
1309 } else {
1310 *carry_out = false;
1311 result = 0;
1312 }
1313 break;
1314 }
1315
1316 case ROR: {
1317 UNIMPLEMENTED();
1318 break;
1319 }
1320
1321 default: {
1322 UNREACHABLE();
1323 break;
1324 }
1325 }
1326 }
1327 return result;
1328}
1329
1330
1331// Addressing Mode 1 - Data-processing operands:
1332// Get the value based on the shifter_operand with immediate.
1333int32_t Simulator::GetImm(Instr* instr, bool* carry_out) {
1334 int rotate = instr->RotateField() * 2;
1335 int immed8 = instr->Immed8Field();
1336 int imm = (immed8 >> rotate) | (immed8 << (32 - rotate));
1337 *carry_out = (rotate == 0) ? c_flag_ : (imm < 0);
1338 return imm;
1339}
1340
1341
1342static int count_bits(int bit_vector) {
1343 int count = 0;
1344 while (bit_vector != 0) {
1345 if ((bit_vector & 1) != 0) {
1346 count++;
1347 }
1348 bit_vector >>= 1;
1349 }
1350 return count;
1351}
1352
1353
1354// Addressing Mode 4 - Load and Store Multiple
1355void Simulator::HandleRList(Instr* instr, bool load) {
1356 int rn = instr->RnField();
1357 int32_t rn_val = get_register(rn);
1358 int rlist = instr->RlistField();
1359 int num_regs = count_bits(rlist);
1360
1361 intptr_t start_address = 0;
1362 intptr_t end_address = 0;
1363 switch (instr->PUField()) {
1364 case 0: {
1365 // Print("da");
1366 UNIMPLEMENTED();
1367 break;
1368 }
1369 case 1: {
1370 // Print("ia");
1371 start_address = rn_val;
1372 end_address = rn_val + (num_regs * 4) - 4;
1373 rn_val = rn_val + (num_regs * 4);
1374 break;
1375 }
1376 case 2: {
1377 // Print("db");
1378 start_address = rn_val - (num_regs * 4);
1379 end_address = rn_val - 4;
1380 rn_val = start_address;
1381 break;
1382 }
1383 case 3: {
1384 // Print("ib");
Steve Block791712a2010-08-27 10:21:07 +01001385 start_address = rn_val + 4;
1386 end_address = rn_val + (num_regs * 4);
1387 rn_val = end_address;
Steve Blocka7e24c12009-10-30 11:49:00 +00001388 break;
1389 }
1390 default: {
1391 UNREACHABLE();
1392 break;
1393 }
1394 }
1395 if (instr->HasW()) {
1396 set_register(rn, rn_val);
1397 }
1398 intptr_t* address = reinterpret_cast<intptr_t*>(start_address);
1399 int reg = 0;
1400 while (rlist != 0) {
1401 if ((rlist & 1) != 0) {
1402 if (load) {
1403 set_register(reg, *address);
1404 } else {
1405 *address = get_register(reg);
1406 }
1407 address += 1;
1408 }
1409 reg++;
1410 rlist >>= 1;
1411 }
1412 ASSERT(end_address == ((intptr_t)address) - 4);
1413}
1414
1415
1416// Calls into the V8 runtime are based on this very simple interface.
1417// Note: To be able to return two values from some calls the code in runtime.cc
1418// uses the ObjectPair which is essentially two 32-bit values stuffed into a
1419// 64-bit value. With the code below we assume that all runtime calls return
1420// 64 bits of result. If they don't, the r1 result register contains a bogus
1421// value, which is fine because it is caller-saved.
1422typedef int64_t (*SimulatorRuntimeCall)(int32_t arg0,
1423 int32_t arg1,
1424 int32_t arg2,
1425 int32_t arg3);
1426typedef double (*SimulatorRuntimeFPCall)(int32_t arg0,
1427 int32_t arg1,
1428 int32_t arg2,
1429 int32_t arg3);
1430
1431
1432// Software interrupt instructions are used by the simulator to call into the
1433// C-based V8 runtime.
1434void Simulator::SoftwareInterrupt(Instr* instr) {
1435 int swi = instr->SwiField();
1436 switch (swi) {
1437 case call_rt_redirected: {
Steve Block6ded16b2010-05-10 14:33:55 +01001438 // Check if stack is aligned. Error if not aligned is reported below to
1439 // include information on the function called.
1440 bool stack_aligned =
1441 (get_register(sp)
1442 & (::v8::internal::FLAG_sim_stack_alignment - 1)) == 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00001443 Redirection* redirection = Redirection::FromSwiInstruction(instr);
1444 int32_t arg0 = get_register(r0);
1445 int32_t arg1 = get_register(r1);
1446 int32_t arg2 = get_register(r2);
1447 int32_t arg3 = get_register(r3);
1448 // This is dodgy but it works because the C entry stubs are never moved.
1449 // See comment in codegen-arm.cc and bug 1242173.
1450 int32_t saved_lr = get_register(lr);
1451 if (redirection->fp_return()) {
1452 intptr_t external =
1453 reinterpret_cast<intptr_t>(redirection->external_function());
1454 SimulatorRuntimeFPCall target =
1455 reinterpret_cast<SimulatorRuntimeFPCall>(external);
Steve Block6ded16b2010-05-10 14:33:55 +01001456 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001457 double x, y;
1458 GetFpArgs(&x, &y);
Steve Block6ded16b2010-05-10 14:33:55 +01001459 PrintF("Call to host function at %p with args %f, %f",
Steve Blocka7e24c12009-10-30 11:49:00 +00001460 FUNCTION_ADDR(target), x, y);
Steve Block6ded16b2010-05-10 14:33:55 +01001461 if (!stack_aligned) {
1462 PrintF(" with unaligned stack %08x\n", get_register(sp));
1463 }
1464 PrintF("\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00001465 }
Steve Block6ded16b2010-05-10 14:33:55 +01001466 CHECK(stack_aligned);
Steve Blocka7e24c12009-10-30 11:49:00 +00001467 double result = target(arg0, arg1, arg2, arg3);
1468 SetFpResult(result);
1469 } else {
1470 intptr_t external =
1471 reinterpret_cast<int32_t>(redirection->external_function());
1472 SimulatorRuntimeCall target =
1473 reinterpret_cast<SimulatorRuntimeCall>(external);
Steve Block6ded16b2010-05-10 14:33:55 +01001474 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001475 PrintF(
Steve Block6ded16b2010-05-10 14:33:55 +01001476 "Call to host function at %p with args %08x, %08x, %08x, %08x",
Steve Blocka7e24c12009-10-30 11:49:00 +00001477 FUNCTION_ADDR(target),
1478 arg0,
1479 arg1,
1480 arg2,
1481 arg3);
Steve Block6ded16b2010-05-10 14:33:55 +01001482 if (!stack_aligned) {
1483 PrintF(" with unaligned stack %08x\n", get_register(sp));
1484 }
1485 PrintF("\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00001486 }
Steve Block6ded16b2010-05-10 14:33:55 +01001487 CHECK(stack_aligned);
Steve Blocka7e24c12009-10-30 11:49:00 +00001488 int64_t result = target(arg0, arg1, arg2, arg3);
1489 int32_t lo_res = static_cast<int32_t>(result);
1490 int32_t hi_res = static_cast<int32_t>(result >> 32);
1491 if (::v8::internal::FLAG_trace_sim) {
1492 PrintF("Returned %08x\n", lo_res);
1493 }
1494 set_register(r0, lo_res);
1495 set_register(r1, hi_res);
1496 }
1497 set_register(lr, saved_lr);
1498 set_pc(get_register(lr));
1499 break;
1500 }
1501 case break_point: {
1502 Debugger dbg(this);
1503 dbg.Debug();
1504 break;
1505 }
1506 default: {
1507 UNREACHABLE();
1508 break;
1509 }
1510 }
1511}
1512
1513
1514// Handle execution based on instruction types.
1515
1516// Instruction types 0 and 1 are both rolled into one function because they
1517// only differ in the handling of the shifter_operand.
1518void Simulator::DecodeType01(Instr* instr) {
1519 int type = instr->TypeField();
1520 if ((type == 0) && instr->IsSpecialType0()) {
1521 // multiply instruction or extra loads and stores
1522 if (instr->Bits(7, 4) == 9) {
1523 if (instr->Bit(24) == 0) {
1524 // Raw field decoding here. Multiply instructions have their Rd in
1525 // funny places.
1526 int rn = instr->RnField();
1527 int rm = instr->RmField();
1528 int rs = instr->RsField();
1529 int32_t rs_val = get_register(rs);
1530 int32_t rm_val = get_register(rm);
1531 if (instr->Bit(23) == 0) {
1532 if (instr->Bit(21) == 0) {
1533 // The MUL instruction description (A 4.1.33) refers to Rd as being
1534 // the destination for the operation, but it confusingly uses the
1535 // Rn field to encode it.
1536 // Format(instr, "mul'cond's 'rn, 'rm, 'rs");
1537 int rd = rn; // Remap the rn field to the Rd register.
1538 int32_t alu_out = rm_val * rs_val;
1539 set_register(rd, alu_out);
1540 if (instr->HasS()) {
1541 SetNZFlags(alu_out);
1542 }
1543 } else {
1544 // The MLA instruction description (A 4.1.28) refers to the order
1545 // of registers as "Rd, Rm, Rs, Rn". But confusingly it uses the
1546 // Rn field to encode the Rd register and the Rd field to encode
1547 // the Rn register.
1548 Format(instr, "mla'cond's 'rn, 'rm, 'rs, 'rd");
1549 }
1550 } else {
1551 // The signed/long multiply instructions use the terms RdHi and RdLo
1552 // when referring to the target registers. They are mapped to the Rn
1553 // and Rd fields as follows:
1554 // RdLo == Rd
1555 // RdHi == Rn (This is confusingly stored in variable rd here
1556 // because the mul instruction from above uses the
1557 // Rn field to encode the Rd register. Good luck figuring
1558 // this out without reading the ARM instruction manual
1559 // at a very detailed level.)
1560 // Format(instr, "'um'al'cond's 'rd, 'rn, 'rs, 'rm");
1561 int rd_hi = rn; // Remap the rn field to the RdHi register.
1562 int rd_lo = instr->RdField();
1563 int32_t hi_res = 0;
1564 int32_t lo_res = 0;
1565 if (instr->Bit(22) == 1) {
1566 int64_t left_op = static_cast<int32_t>(rm_val);
1567 int64_t right_op = static_cast<int32_t>(rs_val);
1568 uint64_t result = left_op * right_op;
1569 hi_res = static_cast<int32_t>(result >> 32);
1570 lo_res = static_cast<int32_t>(result & 0xffffffff);
1571 } else {
1572 // unsigned multiply
1573 uint64_t left_op = static_cast<uint32_t>(rm_val);
1574 uint64_t right_op = static_cast<uint32_t>(rs_val);
1575 uint64_t result = left_op * right_op;
1576 hi_res = static_cast<int32_t>(result >> 32);
1577 lo_res = static_cast<int32_t>(result & 0xffffffff);
1578 }
1579 set_register(rd_lo, lo_res);
1580 set_register(rd_hi, hi_res);
1581 if (instr->HasS()) {
1582 UNIMPLEMENTED();
1583 }
1584 }
1585 } else {
Steve Blockd0582a62009-12-15 09:54:21 +00001586 UNIMPLEMENTED(); // Not used by V8.
Steve Blocka7e24c12009-10-30 11:49:00 +00001587 }
1588 } else {
1589 // extra load/store instructions
1590 int rd = instr->RdField();
1591 int rn = instr->RnField();
1592 int32_t rn_val = get_register(rn);
1593 int32_t addr = 0;
1594 if (instr->Bit(22) == 0) {
1595 int rm = instr->RmField();
1596 int32_t rm_val = get_register(rm);
1597 switch (instr->PUField()) {
1598 case 0: {
1599 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], -'rm");
1600 ASSERT(!instr->HasW());
1601 addr = rn_val;
1602 rn_val -= rm_val;
1603 set_register(rn, rn_val);
1604 break;
1605 }
1606 case 1: {
1607 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], +'rm");
1608 ASSERT(!instr->HasW());
1609 addr = rn_val;
1610 rn_val += rm_val;
1611 set_register(rn, rn_val);
1612 break;
1613 }
1614 case 2: {
1615 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, -'rm]'w");
1616 rn_val -= rm_val;
1617 addr = rn_val;
1618 if (instr->HasW()) {
1619 set_register(rn, rn_val);
1620 }
1621 break;
1622 }
1623 case 3: {
1624 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, +'rm]'w");
1625 rn_val += rm_val;
1626 addr = rn_val;
1627 if (instr->HasW()) {
1628 set_register(rn, rn_val);
1629 }
1630 break;
1631 }
1632 default: {
1633 // The PU field is a 2-bit field.
1634 UNREACHABLE();
1635 break;
1636 }
1637 }
1638 } else {
1639 int32_t imm_val = (instr->ImmedHField() << 4) | instr->ImmedLField();
1640 switch (instr->PUField()) {
1641 case 0: {
1642 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], #-'off8");
1643 ASSERT(!instr->HasW());
1644 addr = rn_val;
1645 rn_val -= imm_val;
1646 set_register(rn, rn_val);
1647 break;
1648 }
1649 case 1: {
1650 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], #+'off8");
1651 ASSERT(!instr->HasW());
1652 addr = rn_val;
1653 rn_val += imm_val;
1654 set_register(rn, rn_val);
1655 break;
1656 }
1657 case 2: {
1658 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, #-'off8]'w");
1659 rn_val -= imm_val;
1660 addr = rn_val;
1661 if (instr->HasW()) {
1662 set_register(rn, rn_val);
1663 }
1664 break;
1665 }
1666 case 3: {
1667 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, #+'off8]'w");
1668 rn_val += imm_val;
1669 addr = rn_val;
1670 if (instr->HasW()) {
1671 set_register(rn, rn_val);
1672 }
1673 break;
1674 }
1675 default: {
1676 // The PU field is a 2-bit field.
1677 UNREACHABLE();
1678 break;
1679 }
1680 }
1681 }
Kristian Monsen25f61362010-05-21 11:50:48 +01001682 if (((instr->Bits(7, 4) & 0xd) == 0xd) && (instr->Bit(20) == 0)) {
1683 ASSERT((rd % 2) == 0);
1684 if (instr->HasH()) {
1685 // The strd instruction.
1686 int32_t value1 = get_register(rd);
1687 int32_t value2 = get_register(rd+1);
1688 WriteDW(addr, value1, value2);
1689 } else {
1690 // The ldrd instruction.
1691 int* rn_data = ReadDW(addr);
1692 set_dw_register(rd, rn_data);
1693 }
1694 } else if (instr->HasH()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001695 if (instr->HasSign()) {
1696 if (instr->HasL()) {
1697 int16_t val = ReadH(addr, instr);
1698 set_register(rd, val);
1699 } else {
1700 int16_t val = get_register(rd);
1701 WriteH(addr, val, instr);
1702 }
1703 } else {
1704 if (instr->HasL()) {
1705 uint16_t val = ReadHU(addr, instr);
1706 set_register(rd, val);
1707 } else {
1708 uint16_t val = get_register(rd);
1709 WriteH(addr, val, instr);
1710 }
1711 }
1712 } else {
1713 // signed byte loads
1714 ASSERT(instr->HasSign());
1715 ASSERT(instr->HasL());
1716 int8_t val = ReadB(addr);
1717 set_register(rd, val);
1718 }
1719 return;
1720 }
Steve Block6ded16b2010-05-10 14:33:55 +01001721 } else if ((type == 0) && instr->IsMiscType0()) {
1722 if (instr->Bits(22, 21) == 1) {
1723 int rm = instr->RmField();
1724 switch (instr->Bits(7, 4)) {
1725 case BX:
1726 set_pc(get_register(rm));
1727 break;
1728 case BLX: {
1729 uint32_t old_pc = get_pc();
1730 set_pc(get_register(rm));
1731 set_register(lr, old_pc + Instr::kInstrSize);
1732 break;
1733 }
1734 case BKPT:
1735 v8::internal::OS::DebugBreak();
1736 break;
1737 default:
1738 UNIMPLEMENTED();
1739 }
1740 } else if (instr->Bits(22, 21) == 3) {
1741 int rm = instr->RmField();
1742 int rd = instr->RdField();
1743 switch (instr->Bits(7, 4)) {
1744 case CLZ: {
1745 uint32_t bits = get_register(rm);
1746 int leading_zeros = 0;
1747 if (bits == 0) {
1748 leading_zeros = 32;
1749 } else {
1750 while ((bits & 0x80000000u) == 0) {
1751 bits <<= 1;
1752 leading_zeros++;
1753 }
1754 }
1755 set_register(rd, leading_zeros);
1756 break;
1757 }
1758 default:
1759 UNIMPLEMENTED();
1760 }
1761 } else {
1762 PrintF("%08x\n", instr->InstructionBits());
1763 UNIMPLEMENTED();
1764 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001765 } else {
1766 int rd = instr->RdField();
1767 int rn = instr->RnField();
1768 int32_t rn_val = get_register(rn);
1769 int32_t shifter_operand = 0;
1770 bool shifter_carry_out = 0;
1771 if (type == 0) {
1772 shifter_operand = GetShiftRm(instr, &shifter_carry_out);
1773 } else {
1774 ASSERT(instr->TypeField() == 1);
1775 shifter_operand = GetImm(instr, &shifter_carry_out);
1776 }
1777 int32_t alu_out;
1778
1779 switch (instr->OpcodeField()) {
1780 case AND: {
1781 // Format(instr, "and'cond's 'rd, 'rn, 'shift_rm");
1782 // Format(instr, "and'cond's 'rd, 'rn, 'imm");
1783 alu_out = rn_val & shifter_operand;
1784 set_register(rd, alu_out);
1785 if (instr->HasS()) {
1786 SetNZFlags(alu_out);
1787 SetCFlag(shifter_carry_out);
1788 }
1789 break;
1790 }
1791
1792 case EOR: {
1793 // Format(instr, "eor'cond's 'rd, 'rn, 'shift_rm");
1794 // Format(instr, "eor'cond's 'rd, 'rn, 'imm");
1795 alu_out = rn_val ^ shifter_operand;
1796 set_register(rd, alu_out);
1797 if (instr->HasS()) {
1798 SetNZFlags(alu_out);
1799 SetCFlag(shifter_carry_out);
1800 }
1801 break;
1802 }
1803
1804 case SUB: {
1805 // Format(instr, "sub'cond's 'rd, 'rn, 'shift_rm");
1806 // Format(instr, "sub'cond's 'rd, 'rn, 'imm");
1807 alu_out = rn_val - shifter_operand;
1808 set_register(rd, alu_out);
1809 if (instr->HasS()) {
1810 SetNZFlags(alu_out);
1811 SetCFlag(!BorrowFrom(rn_val, shifter_operand));
1812 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, false));
1813 }
1814 break;
1815 }
1816
1817 case RSB: {
1818 // Format(instr, "rsb'cond's 'rd, 'rn, 'shift_rm");
1819 // Format(instr, "rsb'cond's 'rd, 'rn, 'imm");
1820 alu_out = shifter_operand - rn_val;
1821 set_register(rd, alu_out);
1822 if (instr->HasS()) {
1823 SetNZFlags(alu_out);
1824 SetCFlag(!BorrowFrom(shifter_operand, rn_val));
1825 SetVFlag(OverflowFrom(alu_out, shifter_operand, rn_val, false));
1826 }
1827 break;
1828 }
1829
1830 case ADD: {
1831 // Format(instr, "add'cond's 'rd, 'rn, 'shift_rm");
1832 // Format(instr, "add'cond's 'rd, 'rn, 'imm");
1833 alu_out = rn_val + shifter_operand;
1834 set_register(rd, alu_out);
1835 if (instr->HasS()) {
1836 SetNZFlags(alu_out);
1837 SetCFlag(CarryFrom(rn_val, shifter_operand));
1838 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, true));
1839 }
1840 break;
1841 }
1842
1843 case ADC: {
1844 Format(instr, "adc'cond's 'rd, 'rn, 'shift_rm");
1845 Format(instr, "adc'cond's 'rd, 'rn, 'imm");
1846 break;
1847 }
1848
1849 case SBC: {
1850 Format(instr, "sbc'cond's 'rd, 'rn, 'shift_rm");
1851 Format(instr, "sbc'cond's 'rd, 'rn, 'imm");
1852 break;
1853 }
1854
1855 case RSC: {
1856 Format(instr, "rsc'cond's 'rd, 'rn, 'shift_rm");
1857 Format(instr, "rsc'cond's 'rd, 'rn, 'imm");
1858 break;
1859 }
1860
1861 case TST: {
1862 if (instr->HasS()) {
1863 // Format(instr, "tst'cond 'rn, 'shift_rm");
1864 // Format(instr, "tst'cond 'rn, 'imm");
1865 alu_out = rn_val & shifter_operand;
1866 SetNZFlags(alu_out);
1867 SetCFlag(shifter_carry_out);
1868 } else {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001869 // Format(instr, "movw'cond 'rd, 'imm").
1870 alu_out = instr->ImmedMovwMovtField();
1871 set_register(rd, alu_out);
Steve Blocka7e24c12009-10-30 11:49:00 +00001872 }
1873 break;
1874 }
1875
1876 case TEQ: {
1877 if (instr->HasS()) {
1878 // Format(instr, "teq'cond 'rn, 'shift_rm");
1879 // Format(instr, "teq'cond 'rn, 'imm");
1880 alu_out = rn_val ^ shifter_operand;
1881 SetNZFlags(alu_out);
1882 SetCFlag(shifter_carry_out);
1883 } else {
Steve Block6ded16b2010-05-10 14:33:55 +01001884 // Other instructions matching this pattern are handled in the
1885 // miscellaneous instructions part above.
1886 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +00001887 }
1888 break;
1889 }
1890
1891 case CMP: {
1892 if (instr->HasS()) {
1893 // Format(instr, "cmp'cond 'rn, 'shift_rm");
1894 // Format(instr, "cmp'cond 'rn, 'imm");
1895 alu_out = rn_val - shifter_operand;
1896 SetNZFlags(alu_out);
1897 SetCFlag(!BorrowFrom(rn_val, shifter_operand));
1898 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, false));
1899 } else {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001900 // Format(instr, "movt'cond 'rd, 'imm").
1901 alu_out = (get_register(rd) & 0xffff) |
1902 (instr->ImmedMovwMovtField() << 16);
1903 set_register(rd, alu_out);
Steve Blocka7e24c12009-10-30 11:49:00 +00001904 }
1905 break;
1906 }
1907
1908 case CMN: {
1909 if (instr->HasS()) {
1910 // Format(instr, "cmn'cond 'rn, 'shift_rm");
1911 // Format(instr, "cmn'cond 'rn, 'imm");
1912 alu_out = rn_val + shifter_operand;
1913 SetNZFlags(alu_out);
1914 SetCFlag(!CarryFrom(rn_val, shifter_operand));
1915 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, true));
1916 } else {
Steve Block6ded16b2010-05-10 14:33:55 +01001917 // Other instructions matching this pattern are handled in the
1918 // miscellaneous instructions part above.
1919 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +00001920 }
1921 break;
1922 }
1923
1924 case ORR: {
1925 // Format(instr, "orr'cond's 'rd, 'rn, 'shift_rm");
1926 // Format(instr, "orr'cond's 'rd, 'rn, 'imm");
1927 alu_out = rn_val | shifter_operand;
1928 set_register(rd, alu_out);
1929 if (instr->HasS()) {
1930 SetNZFlags(alu_out);
1931 SetCFlag(shifter_carry_out);
1932 }
1933 break;
1934 }
1935
1936 case MOV: {
1937 // Format(instr, "mov'cond's 'rd, 'shift_rm");
1938 // Format(instr, "mov'cond's 'rd, 'imm");
1939 alu_out = shifter_operand;
1940 set_register(rd, alu_out);
1941 if (instr->HasS()) {
1942 SetNZFlags(alu_out);
1943 SetCFlag(shifter_carry_out);
1944 }
1945 break;
1946 }
1947
1948 case BIC: {
1949 // Format(instr, "bic'cond's 'rd, 'rn, 'shift_rm");
1950 // Format(instr, "bic'cond's 'rd, 'rn, 'imm");
1951 alu_out = rn_val & ~shifter_operand;
1952 set_register(rd, alu_out);
1953 if (instr->HasS()) {
1954 SetNZFlags(alu_out);
1955 SetCFlag(shifter_carry_out);
1956 }
1957 break;
1958 }
1959
1960 case MVN: {
1961 // Format(instr, "mvn'cond's 'rd, 'shift_rm");
1962 // Format(instr, "mvn'cond's 'rd, 'imm");
1963 alu_out = ~shifter_operand;
1964 set_register(rd, alu_out);
1965 if (instr->HasS()) {
1966 SetNZFlags(alu_out);
1967 SetCFlag(shifter_carry_out);
1968 }
1969 break;
1970 }
1971
1972 default: {
1973 UNREACHABLE();
1974 break;
1975 }
1976 }
1977 }
1978}
1979
1980
1981void Simulator::DecodeType2(Instr* instr) {
1982 int rd = instr->RdField();
1983 int rn = instr->RnField();
1984 int32_t rn_val = get_register(rn);
1985 int32_t im_val = instr->Offset12Field();
1986 int32_t addr = 0;
1987 switch (instr->PUField()) {
1988 case 0: {
1989 // Format(instr, "'memop'cond'b 'rd, ['rn], #-'off12");
1990 ASSERT(!instr->HasW());
1991 addr = rn_val;
1992 rn_val -= im_val;
1993 set_register(rn, rn_val);
1994 break;
1995 }
1996 case 1: {
1997 // Format(instr, "'memop'cond'b 'rd, ['rn], #+'off12");
1998 ASSERT(!instr->HasW());
1999 addr = rn_val;
2000 rn_val += im_val;
2001 set_register(rn, rn_val);
2002 break;
2003 }
2004 case 2: {
2005 // Format(instr, "'memop'cond'b 'rd, ['rn, #-'off12]'w");
2006 rn_val -= im_val;
2007 addr = rn_val;
2008 if (instr->HasW()) {
2009 set_register(rn, rn_val);
2010 }
2011 break;
2012 }
2013 case 3: {
2014 // Format(instr, "'memop'cond'b 'rd, ['rn, #+'off12]'w");
2015 rn_val += im_val;
2016 addr = rn_val;
2017 if (instr->HasW()) {
2018 set_register(rn, rn_val);
2019 }
2020 break;
2021 }
2022 default: {
2023 UNREACHABLE();
2024 break;
2025 }
2026 }
2027 if (instr->HasB()) {
2028 if (instr->HasL()) {
2029 byte val = ReadBU(addr);
2030 set_register(rd, val);
2031 } else {
2032 byte val = get_register(rd);
2033 WriteB(addr, val);
2034 }
2035 } else {
2036 if (instr->HasL()) {
2037 set_register(rd, ReadW(addr, instr));
2038 } else {
2039 WriteW(addr, get_register(rd), instr);
2040 }
2041 }
2042}
2043
2044
2045void Simulator::DecodeType3(Instr* instr) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002046 int rd = instr->RdField();
2047 int rn = instr->RnField();
2048 int32_t rn_val = get_register(rn);
2049 bool shifter_carry_out = 0;
2050 int32_t shifter_operand = GetShiftRm(instr, &shifter_carry_out);
2051 int32_t addr = 0;
2052 switch (instr->PUField()) {
2053 case 0: {
2054 ASSERT(!instr->HasW());
2055 Format(instr, "'memop'cond'b 'rd, ['rn], -'shift_rm");
Kristian Monsen50ef84f2010-07-29 15:18:00 +01002056 UNIMPLEMENTED();
Steve Blocka7e24c12009-10-30 11:49:00 +00002057 break;
2058 }
2059 case 1: {
Kristian Monsen50ef84f2010-07-29 15:18:00 +01002060 if (instr->HasW()) {
2061 ASSERT(instr->Bits(5, 4) == 0x1);
2062
2063 if (instr->Bit(22) == 0x1) { // USAT.
2064 int32_t sat_pos = instr->Bits(20, 16);
2065 int32_t sat_val = (1 << sat_pos) - 1;
2066 int32_t shift = instr->Bits(11, 7);
2067 int32_t shift_type = instr->Bit(6);
2068 int32_t rm_val = get_register(instr->RmField());
2069 if (shift_type == 0) { // LSL
2070 rm_val <<= shift;
2071 } else { // ASR
2072 rm_val >>= shift;
2073 }
2074 // If saturation occurs, the Q flag should be set in the CPSR.
2075 // There is no Q flag yet, and no instruction (MRS) to read the
2076 // CPSR directly.
2077 if (rm_val > sat_val) {
2078 rm_val = sat_val;
2079 } else if (rm_val < 0) {
2080 rm_val = 0;
2081 }
2082 set_register(rd, rm_val);
2083 } else { // SSAT.
2084 UNIMPLEMENTED();
2085 }
2086 return;
2087 } else {
2088 Format(instr, "'memop'cond'b 'rd, ['rn], +'shift_rm");
2089 UNIMPLEMENTED();
2090 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002091 break;
2092 }
2093 case 2: {
2094 // Format(instr, "'memop'cond'b 'rd, ['rn, -'shift_rm]'w");
2095 addr = rn_val - shifter_operand;
2096 if (instr->HasW()) {
2097 set_register(rn, addr);
2098 }
2099 break;
2100 }
2101 case 3: {
Andrei Popescu31002712010-02-23 13:46:05 +00002102 if (instr->HasW() && (instr->Bits(6, 4) == 0x5)) {
2103 uint32_t widthminus1 = static_cast<uint32_t>(instr->Bits(20, 16));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002104 uint32_t lsbit = static_cast<uint32_t>(instr->Bits(11, 7));
Andrei Popescu31002712010-02-23 13:46:05 +00002105 uint32_t msbit = widthminus1 + lsbit;
2106 if (msbit <= 31) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002107 if (instr->Bit(22)) {
2108 // ubfx - unsigned bitfield extract.
2109 uint32_t rm_val =
2110 static_cast<uint32_t>(get_register(instr->RmField()));
2111 uint32_t extr_val = rm_val << (31 - msbit);
2112 extr_val = extr_val >> (31 - widthminus1);
2113 set_register(instr->RdField(), extr_val);
2114 } else {
2115 // sbfx - signed bitfield extract.
2116 int32_t rm_val = get_register(instr->RmField());
2117 int32_t extr_val = rm_val << (31 - msbit);
2118 extr_val = extr_val >> (31 - widthminus1);
2119 set_register(instr->RdField(), extr_val);
2120 }
2121 } else {
2122 UNREACHABLE();
2123 }
2124 return;
2125 } else if (!instr->HasW() && (instr->Bits(6, 4) == 0x1)) {
2126 uint32_t lsbit = static_cast<uint32_t>(instr->Bits(11, 7));
2127 uint32_t msbit = static_cast<uint32_t>(instr->Bits(20, 16));
2128 if (msbit >= lsbit) {
2129 // bfc or bfi - bitfield clear/insert.
2130 uint32_t rd_val =
2131 static_cast<uint32_t>(get_register(instr->RdField()));
2132 uint32_t bitcount = msbit - lsbit + 1;
2133 uint32_t mask = (1 << bitcount) - 1;
2134 rd_val &= ~(mask << lsbit);
2135 if (instr->RmField() != 15) {
2136 // bfi - bitfield insert.
2137 uint32_t rm_val =
2138 static_cast<uint32_t>(get_register(instr->RmField()));
2139 rm_val &= mask;
2140 rd_val |= rm_val << lsbit;
2141 }
2142 set_register(instr->RdField(), rd_val);
Andrei Popescu31002712010-02-23 13:46:05 +00002143 } else {
2144 UNREACHABLE();
2145 }
2146 return;
2147 } else {
2148 // Format(instr, "'memop'cond'b 'rd, ['rn, +'shift_rm]'w");
2149 addr = rn_val + shifter_operand;
2150 if (instr->HasW()) {
2151 set_register(rn, addr);
2152 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002153 }
2154 break;
2155 }
2156 default: {
2157 UNREACHABLE();
2158 break;
2159 }
2160 }
2161 if (instr->HasB()) {
2162 if (instr->HasL()) {
2163 uint8_t byte = ReadB(addr);
2164 set_register(rd, byte);
2165 } else {
Andrei Popescu31002712010-02-23 13:46:05 +00002166 uint8_t byte = get_register(rd);
2167 WriteB(addr, byte);
Steve Blocka7e24c12009-10-30 11:49:00 +00002168 }
2169 } else {
2170 if (instr->HasL()) {
2171 set_register(rd, ReadW(addr, instr));
2172 } else {
2173 WriteW(addr, get_register(rd), instr);
2174 }
2175 }
2176}
2177
2178
2179void Simulator::DecodeType4(Instr* instr) {
2180 ASSERT(instr->Bit(22) == 0); // only allowed to be set in privileged mode
2181 if (instr->HasL()) {
2182 // Format(instr, "ldm'cond'pu 'rn'w, 'rlist");
2183 HandleRList(instr, true);
2184 } else {
2185 // Format(instr, "stm'cond'pu 'rn'w, 'rlist");
2186 HandleRList(instr, false);
2187 }
2188}
2189
2190
2191void Simulator::DecodeType5(Instr* instr) {
2192 // Format(instr, "b'l'cond 'target");
2193 int off = (instr->SImmed24Field() << 2);
2194 intptr_t pc_address = get_pc();
2195 if (instr->HasLink()) {
2196 set_register(lr, pc_address + Instr::kInstrSize);
2197 }
2198 int pc_reg = get_register(pc);
2199 set_pc(pc_reg + off);
2200}
2201
2202
2203void Simulator::DecodeType6(Instr* instr) {
Steve Blockd0582a62009-12-15 09:54:21 +00002204 DecodeType6CoprocessorIns(instr);
Steve Blocka7e24c12009-10-30 11:49:00 +00002205}
2206
2207
2208void Simulator::DecodeType7(Instr* instr) {
2209 if (instr->Bit(24) == 1) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002210 SoftwareInterrupt(instr);
2211 } else {
Steve Blockd0582a62009-12-15 09:54:21 +00002212 DecodeTypeVFP(instr);
Steve Blocka7e24c12009-10-30 11:49:00 +00002213 }
2214}
2215
2216
2217void Simulator::DecodeUnconditional(Instr* instr) {
2218 if (instr->Bits(7, 4) == 0x0B && instr->Bits(27, 25) == 0 && instr->HasL()) {
2219 // Load halfword instruction, either register or immediate offset.
2220 int rd = instr->RdField();
2221 int rn = instr->RnField();
2222 int32_t rn_val = get_register(rn);
2223 int32_t addr = 0;
2224 int32_t offset;
2225 if (instr->Bit(22) == 0) {
2226 // Register offset.
2227 int rm = instr->RmField();
2228 offset = get_register(rm);
2229 } else {
2230 // Immediate offset
2231 offset = instr->Bits(3, 0) + (instr->Bits(11, 8) << 4);
2232 }
2233 switch (instr->PUField()) {
2234 case 0: {
2235 // Post index, negative.
2236 ASSERT(!instr->HasW());
2237 addr = rn_val;
2238 rn_val -= offset;
2239 set_register(rn, rn_val);
2240 break;
2241 }
2242 case 1: {
2243 // Post index, positive.
2244 ASSERT(!instr->HasW());
2245 addr = rn_val;
2246 rn_val += offset;
2247 set_register(rn, rn_val);
2248 break;
2249 }
2250 case 2: {
2251 // Pre index or offset, negative.
2252 rn_val -= offset;
2253 addr = rn_val;
2254 if (instr->HasW()) {
2255 set_register(rn, rn_val);
2256 }
2257 break;
2258 }
2259 case 3: {
2260 // Pre index or offset, positive.
2261 rn_val += offset;
2262 addr = rn_val;
2263 if (instr->HasW()) {
2264 set_register(rn, rn_val);
2265 }
2266 break;
2267 }
2268 default: {
2269 // The PU field is a 2-bit field.
2270 UNREACHABLE();
2271 break;
2272 }
2273 }
2274 // Not sign extending, so load as unsigned.
2275 uint16_t halfword = ReadH(addr, instr);
2276 set_register(rd, halfword);
2277 } else {
2278 Debugger dbg(this);
2279 dbg.Stop(instr);
2280 }
2281}
2282
2283
Steve Blockd0582a62009-12-15 09:54:21 +00002284// void Simulator::DecodeTypeVFP(Instr* instr)
2285// The Following ARMv7 VFPv instructions are currently supported.
Leon Clarkee46be812010-01-19 14:06:41 +00002286// vmov :Sn = Rt
2287// vmov :Rt = Sn
2288// vcvt: Dd = Sm
2289// vcvt: Sd = Dm
2290// Dd = vadd(Dn, Dm)
2291// Dd = vsub(Dn, Dm)
2292// Dd = vmul(Dn, Dm)
2293// Dd = vdiv(Dn, Dm)
Steve Blockd0582a62009-12-15 09:54:21 +00002294// vcmp(Dd, Dm)
Steve Block8defd9f2010-07-08 12:39:36 +01002295// vmrs
2296// Dd = vsqrt(Dm)
Steve Blockd0582a62009-12-15 09:54:21 +00002297void Simulator::DecodeTypeVFP(Instr* instr) {
2298 ASSERT((instr->TypeField() == 7) && (instr->Bit(24) == 0x0) );
Steve Block6ded16b2010-05-10 14:33:55 +01002299 ASSERT(instr->Bits(11, 9) == 0x5);
Steve Blockd0582a62009-12-15 09:54:21 +00002300
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002301 // Obtain double precision register codes.
2302 int vm = instr->VFPMRegCode(kDoublePrecision);
2303 int vd = instr->VFPDRegCode(kDoublePrecision);
2304 int vn = instr->VFPNRegCode(kDoublePrecision);
Steve Blockd0582a62009-12-15 09:54:21 +00002305
Steve Block6ded16b2010-05-10 14:33:55 +01002306 if (instr->Bit(4) == 0) {
2307 if (instr->Opc1Field() == 0x7) {
2308 // Other data processing instructions
Steve Block8defd9f2010-07-08 12:39:36 +01002309 if ((instr->Opc2Field() == 0x0) && (instr->Opc3Field() == 0x1)) {
2310 // vmov register to register.
2311 if (instr->SzField() == 0x1) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002312 int m = instr->VFPMRegCode(kDoublePrecision);
2313 int d = instr->VFPDRegCode(kDoublePrecision);
2314 set_d_register_from_double(d, get_double_from_d_register(m));
Steve Block8defd9f2010-07-08 12:39:36 +01002315 } else {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002316 int m = instr->VFPMRegCode(kSinglePrecision);
2317 int d = instr->VFPDRegCode(kSinglePrecision);
2318 set_s_register_from_float(d, get_float_from_s_register(m));
Steve Block8defd9f2010-07-08 12:39:36 +01002319 }
2320 } else if ((instr->Opc2Field() == 0x7) && (instr->Opc3Field() == 0x3)) {
Steve Block6ded16b2010-05-10 14:33:55 +01002321 DecodeVCVTBetweenDoubleAndSingle(instr);
2322 } else if ((instr->Opc2Field() == 0x8) && (instr->Opc3Field() & 0x1)) {
2323 DecodeVCVTBetweenFloatingPointAndInteger(instr);
2324 } else if (((instr->Opc2Field() >> 1) == 0x6) &&
2325 (instr->Opc3Field() & 0x1)) {
2326 DecodeVCVTBetweenFloatingPointAndInteger(instr);
2327 } else if (((instr->Opc2Field() == 0x4) || (instr->Opc2Field() == 0x5)) &&
2328 (instr->Opc3Field() & 0x1)) {
2329 DecodeVCMP(instr);
Steve Block8defd9f2010-07-08 12:39:36 +01002330 } else if (((instr->Opc2Field() == 0x1)) && (instr->Opc3Field() == 0x3)) {
2331 // vsqrt
2332 double dm_value = get_double_from_d_register(vm);
2333 double dd_value = sqrt(dm_value);
2334 set_d_register_from_double(vd, dd_value);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002335 } else if (instr->Opc3Field() == 0x0) {
2336 // vmov immediate.
2337 if (instr->SzField() == 0x1) {
2338 set_d_register_from_double(vd, instr->DoubleImmedVmov());
2339 } else {
2340 UNREACHABLE(); // Not used by v8.
2341 }
Steve Block6ded16b2010-05-10 14:33:55 +01002342 } else {
2343 UNREACHABLE(); // Not used by V8.
2344 }
2345 } else if (instr->Opc1Field() == 0x3) {
2346 if (instr->SzField() != 0x1) {
2347 UNREACHABLE(); // Not used by V8.
2348 }
2349
2350 if (instr->Opc3Field() & 0x1) {
2351 // vsub
2352 double dn_value = get_double_from_d_register(vn);
2353 double dm_value = get_double_from_d_register(vm);
2354 double dd_value = dn_value - dm_value;
2355 set_d_register_from_double(vd, dd_value);
2356 } else {
2357 // vadd
2358 double dn_value = get_double_from_d_register(vn);
2359 double dm_value = get_double_from_d_register(vm);
2360 double dd_value = dn_value + dm_value;
2361 set_d_register_from_double(vd, dd_value);
2362 }
2363 } else if ((instr->Opc1Field() == 0x2) && !(instr->Opc3Field() & 0x1)) {
2364 // vmul
2365 if (instr->SzField() != 0x1) {
2366 UNREACHABLE(); // Not used by V8.
2367 }
2368
2369 double dn_value = get_double_from_d_register(vn);
2370 double dm_value = get_double_from_d_register(vm);
2371 double dd_value = dn_value * dm_value;
2372 set_d_register_from_double(vd, dd_value);
2373 } else if ((instr->Opc1Field() == 0x4) && !(instr->Opc3Field() & 0x1)) {
2374 // vdiv
2375 if (instr->SzField() != 0x1) {
2376 UNREACHABLE(); // Not used by V8.
2377 }
2378
Steve Blockd0582a62009-12-15 09:54:21 +00002379 double dn_value = get_double_from_d_register(vn);
2380 double dm_value = get_double_from_d_register(vm);
2381 double dd_value = dn_value / dm_value;
2382 set_d_register_from_double(vd, dd_value);
Steve Block6ded16b2010-05-10 14:33:55 +01002383 } else {
2384 UNIMPLEMENTED(); // Not used by V8.
2385 }
2386 } else {
2387 if ((instr->VCField() == 0x0) &&
2388 (instr->VAField() == 0x0)) {
2389 DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(instr);
2390 } else if ((instr->VLField() == 0x1) &&
2391 (instr->VCField() == 0x0) &&
2392 (instr->VAField() == 0x7) &&
2393 (instr->Bits(19, 16) == 0x1)) {
2394 // vmrs
2395 if (instr->RtField() == 0xF)
Steve Blockd0582a62009-12-15 09:54:21 +00002396 Copy_FPSCR_to_APSR();
2397 else
2398 UNIMPLEMENTED(); // Not used by V8.
2399 } else {
2400 UNIMPLEMENTED(); // Not used by V8.
2401 }
Steve Block6ded16b2010-05-10 14:33:55 +01002402 }
2403}
2404
2405
2406void Simulator::DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(Instr* instr) {
2407 ASSERT((instr->Bit(4) == 1) && (instr->VCField() == 0x0) &&
2408 (instr->VAField() == 0x0));
2409
2410 int t = instr->RtField();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002411 int n = instr->VFPNRegCode(kSinglePrecision);
Steve Block6ded16b2010-05-10 14:33:55 +01002412 bool to_arm_register = (instr->VLField() == 0x1);
2413
2414 if (to_arm_register) {
2415 int32_t int_value = get_sinteger_from_s_register(n);
2416 set_register(t, int_value);
2417 } else {
2418 int32_t rs_val = get_register(t);
2419 set_s_register_from_sinteger(n, rs_val);
2420 }
2421}
2422
2423
2424void Simulator::DecodeVCMP(Instr* instr) {
2425 ASSERT((instr->Bit(4) == 0) && (instr->Opc1Field() == 0x7));
2426 ASSERT(((instr->Opc2Field() == 0x4) || (instr->Opc2Field() == 0x5)) &&
2427 (instr->Opc3Field() & 0x1));
Steve Block6ded16b2010-05-10 14:33:55 +01002428 // Comparison.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002429
2430 VFPRegPrecision precision = kSinglePrecision;
2431 if (instr->SzField() == 1) {
2432 precision = kDoublePrecision;
2433 }
Steve Block6ded16b2010-05-10 14:33:55 +01002434
2435 if (instr->Bit(7) != 0) {
2436 // Raising exceptions for quiet NaNs are not supported.
2437 UNIMPLEMENTED(); // Not used by V8.
2438 }
2439
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002440 int d = instr->VFPDRegCode(precision);
Iain Merrick75681382010-08-19 15:07:18 +01002441 int m = 0;
2442 if (instr->Opc2Field() == 0x4) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002443 m = instr->VFPMRegCode(precision);
Iain Merrick75681382010-08-19 15:07:18 +01002444 }
Steve Block6ded16b2010-05-10 14:33:55 +01002445
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002446 if (precision == kDoublePrecision) {
Steve Block6ded16b2010-05-10 14:33:55 +01002447 double dd_value = get_double_from_d_register(d);
Iain Merrick75681382010-08-19 15:07:18 +01002448 double dm_value = 0.0;
2449 if (instr->Opc2Field() == 0x4) {
2450 dm_value = get_double_from_d_register(m);
2451 }
Steve Block6ded16b2010-05-10 14:33:55 +01002452
2453 Compute_FPSCR_Flags(dd_value, dm_value);
2454 } else {
2455 UNIMPLEMENTED(); // Not used by V8.
2456 }
2457}
2458
2459
2460void Simulator::DecodeVCVTBetweenDoubleAndSingle(Instr* instr) {
2461 ASSERT((instr->Bit(4) == 0) && (instr->Opc1Field() == 0x7));
2462 ASSERT((instr->Opc2Field() == 0x7) && (instr->Opc3Field() == 0x3));
2463
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002464 VFPRegPrecision dst_precision = kDoublePrecision;
2465 VFPRegPrecision src_precision = kSinglePrecision;
2466 if (instr->SzField() == 1) {
2467 dst_precision = kSinglePrecision;
2468 src_precision = kDoublePrecision;
2469 }
Steve Block6ded16b2010-05-10 14:33:55 +01002470
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002471 int dst = instr->VFPDRegCode(dst_precision);
2472 int src = instr->VFPMRegCode(src_precision);
2473
2474 if (dst_precision == kSinglePrecision) {
Steve Block6ded16b2010-05-10 14:33:55 +01002475 double val = get_double_from_d_register(src);
2476 set_s_register_from_float(dst, static_cast<float>(val));
2477 } else {
2478 float val = get_float_from_s_register(src);
2479 set_d_register_from_double(dst, static_cast<double>(val));
2480 }
2481}
2482
2483
2484void Simulator::DecodeVCVTBetweenFloatingPointAndInteger(Instr* instr) {
2485 ASSERT((instr->Bit(4) == 0) && (instr->Opc1Field() == 0x7));
2486 ASSERT(((instr->Opc2Field() == 0x8) && (instr->Opc3Field() & 0x1)) ||
2487 (((instr->Opc2Field() >> 1) == 0x6) && (instr->Opc3Field() & 0x1)));
2488
2489 // Conversion between floating-point and integer.
Steve Block6ded16b2010-05-10 14:33:55 +01002490 bool to_integer = (instr->Bit(18) == 1);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002491
2492 VFPRegPrecision src_precision = kSinglePrecision;
2493 if (instr->SzField() == 1) {
2494 src_precision = kDoublePrecision;
2495 }
2496
Steve Block6ded16b2010-05-10 14:33:55 +01002497 if (to_integer) {
2498 bool unsigned_integer = (instr->Bit(16) == 0);
2499 if (instr->Bit(7) != 1) {
2500 // Only rounding towards zero supported.
Steve Blockd0582a62009-12-15 09:54:21 +00002501 UNIMPLEMENTED(); // Not used by V8.
2502 }
Steve Block6ded16b2010-05-10 14:33:55 +01002503
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002504 int dst = instr->VFPDRegCode(kSinglePrecision);
2505 int src = instr->VFPMRegCode(src_precision);
Steve Block6ded16b2010-05-10 14:33:55 +01002506
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002507 if (src_precision == kDoublePrecision) {
Steve Block6ded16b2010-05-10 14:33:55 +01002508 double val = get_double_from_d_register(src);
2509
2510 int sint = unsigned_integer ? static_cast<uint32_t>(val) :
2511 static_cast<int32_t>(val);
2512
2513 set_s_register_from_sinteger(dst, sint);
Steve Blockd0582a62009-12-15 09:54:21 +00002514 } else {
Steve Block6ded16b2010-05-10 14:33:55 +01002515 float val = get_float_from_s_register(src);
2516
2517 int sint = unsigned_integer ? static_cast<uint32_t>(val) :
2518 static_cast<int32_t>(val);
2519
2520 set_s_register_from_sinteger(dst, sint);
2521 }
2522 } else {
2523 bool unsigned_integer = (instr->Bit(7) == 0);
2524
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002525 int dst = instr->VFPDRegCode(src_precision);
2526 int src = instr->VFPMRegCode(kSinglePrecision);
Steve Block6ded16b2010-05-10 14:33:55 +01002527
2528 int val = get_sinteger_from_s_register(src);
2529
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002530 if (src_precision == kDoublePrecision) {
Steve Block6ded16b2010-05-10 14:33:55 +01002531 if (unsigned_integer) {
2532 set_d_register_from_double(dst,
2533 static_cast<double>((uint32_t)val));
2534 } else {
2535 set_d_register_from_double(dst, static_cast<double>(val));
2536 }
2537 } else {
2538 if (unsigned_integer) {
2539 set_s_register_from_float(dst,
2540 static_cast<float>((uint32_t)val));
2541 } else {
2542 set_s_register_from_float(dst, static_cast<float>(val));
2543 }
Steve Blockd0582a62009-12-15 09:54:21 +00002544 }
2545 }
2546}
2547
2548
2549// void Simulator::DecodeType6CoprocessorIns(Instr* instr)
2550// Decode Type 6 coprocessor instructions.
Leon Clarkee46be812010-01-19 14:06:41 +00002551// Dm = vmov(Rt, Rt2)
2552// <Rt, Rt2> = vmov(Dm)
Leon Clarked91b9f72010-01-27 17:25:45 +00002553// Ddst = MEM(Rbase + 4*offset).
2554// MEM(Rbase + 4*offset) = Dsrc.
Steve Blockd0582a62009-12-15 09:54:21 +00002555void Simulator::DecodeType6CoprocessorIns(Instr* instr) {
2556 ASSERT((instr->TypeField() == 6));
2557
Steve Block6ded16b2010-05-10 14:33:55 +01002558 if (instr->CoprocessorField() == 0xA) {
2559 switch (instr->OpcodeField()) {
2560 case 0x8:
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002561 case 0xA:
2562 case 0xC:
2563 case 0xE: { // Load and store single precision float to memory.
Steve Block6ded16b2010-05-10 14:33:55 +01002564 int rn = instr->RnField();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002565 int vd = instr->VFPDRegCode(kSinglePrecision);
Steve Block6ded16b2010-05-10 14:33:55 +01002566 int offset = instr->Immed8Field();
2567 if (!instr->HasU()) {
2568 offset = -offset;
2569 }
2570
2571 int32_t address = get_register(rn) + 4 * offset;
2572 if (instr->HasL()) {
2573 // Load double from memory: vldr.
2574 set_s_register_from_sinteger(vd, ReadW(address, instr));
2575 } else {
2576 // Store double to memory: vstr.
2577 WriteW(address, get_sinteger_from_s_register(vd), instr);
2578 }
2579 break;
2580 }
2581 default:
2582 UNIMPLEMENTED(); // Not used by V8.
2583 break;
2584 }
2585 } else if (instr->CoprocessorField() == 0xB) {
Leon Clarked91b9f72010-01-27 17:25:45 +00002586 switch (instr->OpcodeField()) {
2587 case 0x2:
2588 // Load and store double to two GP registers
2589 if (instr->Bits(7, 4) != 0x1) {
2590 UNIMPLEMENTED(); // Not used by V8.
2591 } else {
2592 int rt = instr->RtField();
2593 int rn = instr->RnField();
2594 int vm = instr->VmField();
2595 if (instr->HasL()) {
2596 int32_t rt_int_value = get_sinteger_from_s_register(2*vm);
2597 int32_t rn_int_value = get_sinteger_from_s_register(2*vm+1);
2598
2599 set_register(rt, rt_int_value);
2600 set_register(rn, rn_int_value);
2601 } else {
2602 int32_t rs_val = get_register(rt);
2603 int32_t rn_val = get_register(rn);
2604
2605 set_s_register_from_sinteger(2*vm, rs_val);
2606 set_s_register_from_sinteger((2*vm+1), rn_val);
2607 }
2608 }
2609 break;
2610 case 0x8:
2611 case 0xC: { // Load and store double to memory.
2612 int rn = instr->RnField();
2613 int vd = instr->VdField();
2614 int offset = instr->Immed8Field();
2615 if (!instr->HasU()) {
2616 offset = -offset;
2617 }
2618 int32_t address = get_register(rn) + 4 * offset;
2619 if (instr->HasL()) {
2620 // Load double from memory: vldr.
2621 set_s_register_from_sinteger(2*vd, ReadW(address, instr));
2622 set_s_register_from_sinteger(2*vd + 1, ReadW(address + 4, instr));
2623 } else {
2624 // Store double to memory: vstr.
2625 WriteW(address, get_sinteger_from_s_register(2*vd), instr);
2626 WriteW(address + 4, get_sinteger_from_s_register(2*vd + 1), instr);
2627 }
2628 break;
2629 }
2630 default:
2631 UNIMPLEMENTED(); // Not used by V8.
2632 break;
2633 }
Steve Block6ded16b2010-05-10 14:33:55 +01002634 } else {
2635 UNIMPLEMENTED(); // Not used by V8.
Steve Blockd0582a62009-12-15 09:54:21 +00002636 }
2637}
2638
2639
Steve Blocka7e24c12009-10-30 11:49:00 +00002640// Executes the current instruction.
2641void Simulator::InstructionDecode(Instr* instr) {
Steve Block6ded16b2010-05-10 14:33:55 +01002642 if (v8::internal::FLAG_check_icache) {
2643 CheckICache(instr);
2644 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002645 pc_modified_ = false;
2646 if (::v8::internal::FLAG_trace_sim) {
2647 disasm::NameConverter converter;
2648 disasm::Disassembler dasm(converter);
2649 // use a reasonably large buffer
2650 v8::internal::EmbeddedVector<char, 256> buffer;
2651 dasm.InstructionDecode(buffer,
2652 reinterpret_cast<byte*>(instr));
2653 PrintF(" 0x%08x %s\n", instr, buffer.start());
2654 }
2655 if (instr->ConditionField() == special_condition) {
2656 DecodeUnconditional(instr);
2657 } else if (ConditionallyExecute(instr)) {
2658 switch (instr->TypeField()) {
2659 case 0:
2660 case 1: {
2661 DecodeType01(instr);
2662 break;
2663 }
2664 case 2: {
2665 DecodeType2(instr);
2666 break;
2667 }
2668 case 3: {
2669 DecodeType3(instr);
2670 break;
2671 }
2672 case 4: {
2673 DecodeType4(instr);
2674 break;
2675 }
2676 case 5: {
2677 DecodeType5(instr);
2678 break;
2679 }
2680 case 6: {
2681 DecodeType6(instr);
2682 break;
2683 }
2684 case 7: {
2685 DecodeType7(instr);
2686 break;
2687 }
2688 default: {
2689 UNIMPLEMENTED();
2690 break;
2691 }
2692 }
2693 }
2694 if (!pc_modified_) {
2695 set_register(pc, reinterpret_cast<int32_t>(instr) + Instr::kInstrSize);
2696 }
2697}
2698
2699
Steve Blocka7e24c12009-10-30 11:49:00 +00002700void Simulator::Execute() {
2701 // Get the PC to simulate. Cannot use the accessor here as we need the
2702 // raw PC value and not the one used as input to arithmetic instructions.
2703 int program_counter = get_pc();
2704
2705 if (::v8::internal::FLAG_stop_sim_at == 0) {
2706 // Fast version of the dispatch loop without checking whether the simulator
2707 // should be stopping at a particular executed instruction.
2708 while (program_counter != end_sim_pc) {
2709 Instr* instr = reinterpret_cast<Instr*>(program_counter);
2710 icount_++;
2711 InstructionDecode(instr);
2712 program_counter = get_pc();
2713 }
2714 } else {
2715 // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when
2716 // we reach the particular instuction count.
2717 while (program_counter != end_sim_pc) {
2718 Instr* instr = reinterpret_cast<Instr*>(program_counter);
2719 icount_++;
2720 if (icount_ == ::v8::internal::FLAG_stop_sim_at) {
2721 Debugger dbg(this);
2722 dbg.Debug();
2723 } else {
2724 InstructionDecode(instr);
2725 }
2726 program_counter = get_pc();
2727 }
2728 }
2729}
2730
2731
2732int32_t Simulator::Call(byte* entry, int argument_count, ...) {
2733 va_list parameters;
2734 va_start(parameters, argument_count);
2735 // Setup arguments
2736
2737 // First four arguments passed in registers.
2738 ASSERT(argument_count >= 4);
2739 set_register(r0, va_arg(parameters, int32_t));
2740 set_register(r1, va_arg(parameters, int32_t));
2741 set_register(r2, va_arg(parameters, int32_t));
2742 set_register(r3, va_arg(parameters, int32_t));
2743
2744 // Remaining arguments passed on stack.
2745 int original_stack = get_register(sp);
2746 // Compute position of stack on entry to generated code.
2747 int entry_stack = (original_stack - (argument_count - 4) * sizeof(int32_t));
2748 if (OS::ActivationFrameAlignment() != 0) {
2749 entry_stack &= -OS::ActivationFrameAlignment();
2750 }
2751 // Store remaining arguments on stack, from low to high memory.
2752 intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
2753 for (int i = 4; i < argument_count; i++) {
2754 stack_argument[i - 4] = va_arg(parameters, int32_t);
2755 }
2756 va_end(parameters);
2757 set_register(sp, entry_stack);
2758
2759 // Prepare to execute the code at entry
2760 set_register(pc, reinterpret_cast<int32_t>(entry));
2761 // Put down marker for end of simulation. The simulator will stop simulation
2762 // when the PC reaches this value. By saving the "end simulation" value into
2763 // the LR the simulation stops when returning to this call point.
2764 set_register(lr, end_sim_pc);
2765
2766 // Remember the values of callee-saved registers.
2767 // The code below assumes that r9 is not used as sb (static base) in
2768 // simulator code and therefore is regarded as a callee-saved register.
2769 int32_t r4_val = get_register(r4);
2770 int32_t r5_val = get_register(r5);
2771 int32_t r6_val = get_register(r6);
2772 int32_t r7_val = get_register(r7);
2773 int32_t r8_val = get_register(r8);
2774 int32_t r9_val = get_register(r9);
2775 int32_t r10_val = get_register(r10);
2776 int32_t r11_val = get_register(r11);
2777
2778 // Setup the callee-saved registers with a known value. To be able to check
2779 // that they are preserved properly across JS execution.
2780 int32_t callee_saved_value = icount_;
2781 set_register(r4, callee_saved_value);
2782 set_register(r5, callee_saved_value);
2783 set_register(r6, callee_saved_value);
2784 set_register(r7, callee_saved_value);
2785 set_register(r8, callee_saved_value);
2786 set_register(r9, callee_saved_value);
2787 set_register(r10, callee_saved_value);
2788 set_register(r11, callee_saved_value);
2789
2790 // Start the simulation
2791 Execute();
2792
2793 // Check that the callee-saved registers have been preserved.
2794 CHECK_EQ(callee_saved_value, get_register(r4));
2795 CHECK_EQ(callee_saved_value, get_register(r5));
2796 CHECK_EQ(callee_saved_value, get_register(r6));
2797 CHECK_EQ(callee_saved_value, get_register(r7));
2798 CHECK_EQ(callee_saved_value, get_register(r8));
2799 CHECK_EQ(callee_saved_value, get_register(r9));
2800 CHECK_EQ(callee_saved_value, get_register(r10));
2801 CHECK_EQ(callee_saved_value, get_register(r11));
2802
2803 // Restore callee-saved registers with the original value.
2804 set_register(r4, r4_val);
2805 set_register(r5, r5_val);
2806 set_register(r6, r6_val);
2807 set_register(r7, r7_val);
2808 set_register(r8, r8_val);
2809 set_register(r9, r9_val);
2810 set_register(r10, r10_val);
2811 set_register(r11, r11_val);
2812
2813 // Pop stack passed arguments.
2814 CHECK_EQ(entry_stack, get_register(sp));
2815 set_register(sp, original_stack);
2816
2817 int32_t result = get_register(r0);
2818 return result;
2819}
2820
Steve Blockd0582a62009-12-15 09:54:21 +00002821
2822uintptr_t Simulator::PushAddress(uintptr_t address) {
2823 int new_sp = get_register(sp) - sizeof(uintptr_t);
2824 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp);
2825 *stack_slot = address;
2826 set_register(sp, new_sp);
2827 return new_sp;
2828}
2829
2830
2831uintptr_t Simulator::PopAddress() {
2832 int current_sp = get_register(sp);
2833 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp);
2834 uintptr_t address = *stack_slot;
2835 set_register(sp, current_sp + sizeof(uintptr_t));
2836 return address;
2837}
2838
Steve Blocka7e24c12009-10-30 11:49:00 +00002839} } // namespace assembler::arm
2840
Steve Block6ded16b2010-05-10 14:33:55 +01002841#endif // __arm__
Leon Clarkef7060e22010-06-03 12:02:55 +01002842
2843#endif // V8_TARGET_ARCH_ARM