blob: e4601f3e3f30b933b92ccaf5582dec1987253797 [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>
29#include <cstdarg>
30#include "v8.h"
31
32#include "disasm.h"
33#include "assembler.h"
34#include "arm/constants-arm.h"
35#include "arm/simulator-arm.h"
36
37#if !defined(__arm__)
38
39// Only build the simulator if not compiling for real ARM hardware.
40namespace assembler {
41namespace arm {
42
43using ::v8::internal::Object;
44using ::v8::internal::PrintF;
45using ::v8::internal::OS;
46using ::v8::internal::ReadLine;
47using ::v8::internal::DeleteArray;
48
49// This macro provides a platform independent use of sscanf. The reason for
Leon Clarked91b9f72010-01-27 17:25:45 +000050// SScanF not being implemented in a platform independent way through
51// ::v8::internal::OS in the same way as SNPrintF is that the
52// Windows C Run-Time Library does not provide vsscanf.
Steve Blocka7e24c12009-10-30 11:49:00 +000053#define SScanF sscanf // NOLINT
54
55// The Debugger class is used by the simulator while debugging simulated ARM
56// code.
57class Debugger {
58 public:
59 explicit Debugger(Simulator* sim);
60 ~Debugger();
61
62 void Stop(Instr* instr);
63 void Debug();
64
65 private:
66 static const instr_t kBreakpointInstr =
67 ((AL << 28) | (7 << 25) | (1 << 24) | break_point);
68 static const instr_t kNopInstr =
69 ((AL << 28) | (13 << 21));
70
71 Simulator* sim_;
72
73 int32_t GetRegisterValue(int regnum);
74 bool GetValue(const char* desc, int32_t* value);
Steve Block6ded16b2010-05-10 14:33:55 +010075 bool GetVFPSingleValue(const char* desc, float* value);
76 bool GetVFPDoubleValue(const char* desc, double* value);
Steve Blocka7e24c12009-10-30 11:49:00 +000077
78 // Set or delete a breakpoint. Returns true if successful.
79 bool SetBreakpoint(Instr* breakpc);
80 bool DeleteBreakpoint(Instr* breakpc);
81
82 // Undo and redo all breakpoints. This is needed to bracket disassembly and
83 // execution to skip past breakpoints when run from the debugger.
84 void UndoBreakpoints();
85 void RedoBreakpoints();
86};
87
88
89Debugger::Debugger(Simulator* sim) {
90 sim_ = sim;
91}
92
93
94Debugger::~Debugger() {
95}
96
97
98
99#ifdef GENERATED_CODE_COVERAGE
100static FILE* coverage_log = NULL;
101
102
103static void InitializeCoverage() {
104 char* file_name = getenv("V8_GENERATED_CODE_COVERAGE_LOG");
105 if (file_name != NULL) {
106 coverage_log = fopen(file_name, "aw+");
107 }
108}
109
110
111void Debugger::Stop(Instr* instr) {
112 char* str = reinterpret_cast<char*>(instr->InstructionBits() & 0x0fffffff);
113 if (strlen(str) > 0) {
114 if (coverage_log != NULL) {
115 fprintf(coverage_log, "%s\n", str);
116 fflush(coverage_log);
117 }
118 instr->SetInstructionBits(0xe1a00000); // Overwrite with nop.
119 }
120 sim_->set_pc(sim_->get_pc() + Instr::kInstrSize);
121}
122
123#else // ndef GENERATED_CODE_COVERAGE
124
125static void InitializeCoverage() {
126}
127
128
129void Debugger::Stop(Instr* instr) {
130 const char* str = (const char*)(instr->InstructionBits() & 0x0fffffff);
131 PrintF("Simulator hit %s\n", str);
132 sim_->set_pc(sim_->get_pc() + Instr::kInstrSize);
133 Debug();
134}
135#endif
136
137
138int32_t Debugger::GetRegisterValue(int regnum) {
139 if (regnum == kPCRegister) {
140 return sim_->get_pc();
141 } else {
142 return sim_->get_register(regnum);
143 }
144}
145
146
147bool Debugger::GetValue(const char* desc, int32_t* value) {
148 int regnum = Registers::Number(desc);
149 if (regnum != kNoRegister) {
150 *value = GetRegisterValue(regnum);
151 return true;
152 } else {
Steve Block6ded16b2010-05-10 14:33:55 +0100153 if (strncmp(desc, "0x", 2) == 0) {
154 return SScanF(desc + 2, "%x", reinterpret_cast<uint32_t*>(value)) == 1;
155 } else {
156 return SScanF(desc, "%u", reinterpret_cast<uint32_t*>(value)) == 1;
157 }
158 }
159 return false;
160}
161
162
163bool Debugger::GetVFPSingleValue(const char* desc, float* value) {
164 bool is_double;
165 int regnum = VFPRegisters::Number(desc, &is_double);
166 if (regnum != kNoRegister && !is_double) {
167 *value = sim_->get_float_from_s_register(regnum);
168 return true;
169 }
170 return false;
171}
172
173
174bool Debugger::GetVFPDoubleValue(const char* desc, double* value) {
175 bool is_double;
176 int regnum = VFPRegisters::Number(desc, &is_double);
177 if (regnum != kNoRegister && is_double) {
178 *value = sim_->get_double_from_d_register(regnum);
179 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +0000180 }
181 return false;
182}
183
184
185bool Debugger::SetBreakpoint(Instr* breakpc) {
186 // Check if a breakpoint can be set. If not return without any side-effects.
187 if (sim_->break_pc_ != NULL) {
188 return false;
189 }
190
191 // Set the breakpoint.
192 sim_->break_pc_ = breakpc;
193 sim_->break_instr_ = breakpc->InstructionBits();
194 // Not setting the breakpoint instruction in the code itself. It will be set
195 // when the debugger shell continues.
196 return true;
197}
198
199
200bool Debugger::DeleteBreakpoint(Instr* breakpc) {
201 if (sim_->break_pc_ != NULL) {
202 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
203 }
204
205 sim_->break_pc_ = NULL;
206 sim_->break_instr_ = 0;
207 return true;
208}
209
210
211void Debugger::UndoBreakpoints() {
212 if (sim_->break_pc_ != NULL) {
213 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
214 }
215}
216
217
218void Debugger::RedoBreakpoints() {
219 if (sim_->break_pc_ != NULL) {
220 sim_->break_pc_->SetInstructionBits(kBreakpointInstr);
221 }
222}
223
224
225void Debugger::Debug() {
226 intptr_t last_pc = -1;
227 bool done = false;
228
229#define COMMAND_SIZE 63
230#define ARG_SIZE 255
231
232#define STR(a) #a
233#define XSTR(a) STR(a)
234
235 char cmd[COMMAND_SIZE + 1];
236 char arg1[ARG_SIZE + 1];
237 char arg2[ARG_SIZE + 1];
Steve Block6ded16b2010-05-10 14:33:55 +0100238 char* argv[3] = { cmd, arg1, arg2 };
Steve Blocka7e24c12009-10-30 11:49:00 +0000239
240 // make sure to have a proper terminating character if reaching the limit
241 cmd[COMMAND_SIZE] = 0;
242 arg1[ARG_SIZE] = 0;
243 arg2[ARG_SIZE] = 0;
244
245 // Undo all set breakpoints while running in the debugger shell. This will
246 // make them invisible to all commands.
247 UndoBreakpoints();
248
249 while (!done) {
250 if (last_pc != sim_->get_pc()) {
251 disasm::NameConverter converter;
252 disasm::Disassembler dasm(converter);
253 // use a reasonably large buffer
254 v8::internal::EmbeddedVector<char, 256> buffer;
255 dasm.InstructionDecode(buffer,
256 reinterpret_cast<byte*>(sim_->get_pc()));
257 PrintF(" 0x%08x %s\n", sim_->get_pc(), buffer.start());
258 last_pc = sim_->get_pc();
259 }
260 char* line = ReadLine("sim> ");
261 if (line == NULL) {
262 break;
263 } else {
264 // Use sscanf to parse the individual parts of the command line. At the
265 // moment no command expects more than two parameters.
Steve Block6ded16b2010-05-10 14:33:55 +0100266 int argc = SScanF(line,
Steve Blocka7e24c12009-10-30 11:49:00 +0000267 "%" XSTR(COMMAND_SIZE) "s "
268 "%" XSTR(ARG_SIZE) "s "
269 "%" XSTR(ARG_SIZE) "s",
270 cmd, arg1, arg2);
271 if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
272 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc()));
273 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) {
274 // Execute the one instruction we broke at with breakpoints disabled.
275 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc()));
276 // Leave the debugger shell.
277 done = true;
278 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
Steve Block6ded16b2010-05-10 14:33:55 +0100279 if (argc == 2) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000280 int32_t value;
Steve Block6ded16b2010-05-10 14:33:55 +0100281 float svalue;
282 double dvalue;
Steve Blocka7e24c12009-10-30 11:49:00 +0000283 if (strcmp(arg1, "all") == 0) {
284 for (int i = 0; i < kNumRegisters; i++) {
285 value = GetRegisterValue(i);
286 PrintF("%3s: 0x%08x %10d\n", Registers::Name(i), value, value);
287 }
288 } else {
289 if (GetValue(arg1, &value)) {
290 PrintF("%s: 0x%08x %d \n", arg1, value, value);
Steve Block6ded16b2010-05-10 14:33:55 +0100291 } else if (GetVFPSingleValue(arg1, &svalue)) {
292 PrintF("%s: %f \n", arg1, svalue);
293 } else if (GetVFPDoubleValue(arg1, &dvalue)) {
294 PrintF("%s: %lf \n", arg1, dvalue);
Steve Blocka7e24c12009-10-30 11:49:00 +0000295 } else {
296 PrintF("%s unrecognized\n", arg1);
297 }
298 }
299 } else {
300 PrintF("print <register>\n");
301 }
302 } else if ((strcmp(cmd, "po") == 0)
303 || (strcmp(cmd, "printobject") == 0)) {
Steve Block6ded16b2010-05-10 14:33:55 +0100304 if (argc == 2) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000305 int32_t value;
306 if (GetValue(arg1, &value)) {
307 Object* obj = reinterpret_cast<Object*>(value);
308 PrintF("%s: \n", arg1);
309#ifdef DEBUG
310 obj->PrintLn();
311#else
312 obj->ShortPrint();
313 PrintF("\n");
314#endif
315 } else {
316 PrintF("%s unrecognized\n", arg1);
317 }
318 } else {
319 PrintF("printobject <value>\n");
320 }
Steve Block6ded16b2010-05-10 14:33:55 +0100321 } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0) {
322 int32_t* cur = NULL;
323 int32_t* end = NULL;
324 int next_arg = 1;
325
326 if (strcmp(cmd, "stack") == 0) {
327 cur = reinterpret_cast<int32_t*>(sim_->get_register(Simulator::sp));
328 } else { // "mem"
329 int32_t value;
330 if (!GetValue(arg1, &value)) {
331 PrintF("%s unrecognized\n", arg1);
332 continue;
333 }
334 cur = reinterpret_cast<int32_t*>(value);
335 next_arg++;
336 }
337
338 int32_t words;
339 if (argc == next_arg) {
340 words = 10;
341 } else if (argc == next_arg + 1) {
342 if (!GetValue(argv[next_arg], &words)) {
343 words = 10;
344 }
345 }
346 end = cur + words;
347
348 while (cur < end) {
349 PrintF(" 0x%08x: 0x%08x %10d\n", cur, *cur, *cur);
350 cur++;
351 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000352 } else if (strcmp(cmd, "disasm") == 0) {
353 disasm::NameConverter converter;
354 disasm::Disassembler dasm(converter);
355 // use a reasonably large buffer
356 v8::internal::EmbeddedVector<char, 256> buffer;
357
358 byte* cur = NULL;
359 byte* end = NULL;
360
Steve Block6ded16b2010-05-10 14:33:55 +0100361 if (argc == 1) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000362 cur = reinterpret_cast<byte*>(sim_->get_pc());
363 end = cur + (10 * Instr::kInstrSize);
Steve Block6ded16b2010-05-10 14:33:55 +0100364 } else if (argc == 2) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000365 int32_t value;
366 if (GetValue(arg1, &value)) {
367 cur = reinterpret_cast<byte*>(value);
368 // no length parameter passed, assume 10 instructions
369 end = cur + (10 * Instr::kInstrSize);
370 }
371 } else {
372 int32_t value1;
373 int32_t value2;
374 if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
375 cur = reinterpret_cast<byte*>(value1);
376 end = cur + (value2 * Instr::kInstrSize);
377 }
378 }
379
380 while (cur < end) {
381 dasm.InstructionDecode(buffer, cur);
382 PrintF(" 0x%08x %s\n", cur, buffer.start());
383 cur += Instr::kInstrSize;
384 }
385 } else if (strcmp(cmd, "gdb") == 0) {
386 PrintF("relinquishing control to gdb\n");
387 v8::internal::OS::DebugBreak();
388 PrintF("regaining control from gdb\n");
389 } else if (strcmp(cmd, "break") == 0) {
Steve Block6ded16b2010-05-10 14:33:55 +0100390 if (argc == 2) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000391 int32_t value;
392 if (GetValue(arg1, &value)) {
393 if (!SetBreakpoint(reinterpret_cast<Instr*>(value))) {
394 PrintF("setting breakpoint failed\n");
395 }
396 } else {
397 PrintF("%s unrecognized\n", arg1);
398 }
399 } else {
400 PrintF("break <address>\n");
401 }
402 } else if (strcmp(cmd, "del") == 0) {
403 if (!DeleteBreakpoint(NULL)) {
404 PrintF("deleting breakpoint failed\n");
405 }
406 } else if (strcmp(cmd, "flags") == 0) {
407 PrintF("N flag: %d; ", sim_->n_flag_);
408 PrintF("Z flag: %d; ", sim_->z_flag_);
409 PrintF("C flag: %d; ", sim_->c_flag_);
410 PrintF("V flag: %d\n", sim_->v_flag_);
Steve Blockd0582a62009-12-15 09:54:21 +0000411 PrintF("INVALID OP flag: %d; ", sim_->inv_op_vfp_flag_);
412 PrintF("DIV BY ZERO flag: %d; ", sim_->div_zero_vfp_flag_);
413 PrintF("OVERFLOW flag: %d; ", sim_->overflow_vfp_flag_);
414 PrintF("UNDERFLOW flag: %d; ", sim_->underflow_vfp_flag_);
415 PrintF("INEXACT flag: %d; ", sim_->inexact_vfp_flag_);
Steve Blocka7e24c12009-10-30 11:49:00 +0000416 } else if (strcmp(cmd, "unstop") == 0) {
417 intptr_t stop_pc = sim_->get_pc() - Instr::kInstrSize;
418 Instr* stop_instr = reinterpret_cast<Instr*>(stop_pc);
419 if (stop_instr->ConditionField() == special_condition) {
420 stop_instr->SetInstructionBits(kNopInstr);
421 } else {
422 PrintF("Not at debugger stop.");
423 }
Leon Clarkee46be812010-01-19 14:06:41 +0000424 } else if ((strcmp(cmd, "t") == 0) || strcmp(cmd, "trace") == 0) {
425 ::v8::internal::FLAG_trace_sim = !::v8::internal::FLAG_trace_sim;
426 PrintF("Trace of executed instructions is %s\n",
427 ::v8::internal::FLAG_trace_sim ? "on" : "off");
Steve Blocka7e24c12009-10-30 11:49:00 +0000428 } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
429 PrintF("cont\n");
430 PrintF(" continue execution (alias 'c')\n");
431 PrintF("stepi\n");
432 PrintF(" step one instruction (alias 'si')\n");
433 PrintF("print <register>\n");
434 PrintF(" print register content (alias 'p')\n");
435 PrintF(" use register name 'all' to print all registers\n");
436 PrintF("printobject <register>\n");
437 PrintF(" print an object from a register (alias 'po')\n");
438 PrintF("flags\n");
439 PrintF(" print flags\n");
Steve Block6ded16b2010-05-10 14:33:55 +0100440 PrintF("stack [<words>]\n");
441 PrintF(" dump stack content, default dump 10 words)\n");
442 PrintF("mem <address> [<words>]\n");
443 PrintF(" dump memory content, default dump 10 words)\n");
Steve Blocka7e24c12009-10-30 11:49:00 +0000444 PrintF("disasm [<instructions>]\n");
445 PrintF("disasm [[<address>] <instructions>]\n");
446 PrintF(" disassemble code, default is 10 instructions from pc\n");
447 PrintF("gdb\n");
448 PrintF(" enter gdb\n");
449 PrintF("break <address>\n");
450 PrintF(" set a break point on the address\n");
451 PrintF("del\n");
452 PrintF(" delete the breakpoint\n");
453 PrintF("unstop\n");
454 PrintF(" ignore the stop instruction at the current location");
Leon Clarkee46be812010-01-19 14:06:41 +0000455 PrintF(" from now on\n");
456 PrintF("trace (alias 't')\n");
Steve Block6ded16b2010-05-10 14:33:55 +0100457 PrintF(" toogle the tracing of all executed statements\n");
Steve Blocka7e24c12009-10-30 11:49:00 +0000458 } else {
459 PrintF("Unknown command: %s\n", cmd);
460 }
461 }
462 DeleteArray(line);
463 }
464
465 // Add all the breakpoints back to stop execution and enter the debugger
466 // shell when hit.
467 RedoBreakpoints();
468
469#undef COMMAND_SIZE
470#undef ARG_SIZE
471
472#undef STR
473#undef XSTR
474}
475
476
Steve Block6ded16b2010-05-10 14:33:55 +0100477static bool ICacheMatch(void* one, void* two) {
478 ASSERT((reinterpret_cast<intptr_t>(one) & CachePage::kPageMask) == 0);
479 ASSERT((reinterpret_cast<intptr_t>(two) & CachePage::kPageMask) == 0);
480 return one == two;
481}
482
483
484static uint32_t ICacheHash(void* key) {
485 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)) >> 2;
486}
487
488
489static bool AllOnOnePage(uintptr_t start, int size) {
490 intptr_t start_page = (start & ~CachePage::kPageMask);
491 intptr_t end_page = ((start + size) & ~CachePage::kPageMask);
492 return start_page == end_page;
493}
494
495
496void Simulator::FlushICache(void* start_addr, size_t size) {
497 intptr_t start = reinterpret_cast<intptr_t>(start_addr);
498 int intra_line = (start & CachePage::kLineMask);
499 start -= intra_line;
500 size += intra_line;
501 size = ((size - 1) | CachePage::kLineMask) + 1;
502 int offset = (start & CachePage::kPageMask);
503 while (!AllOnOnePage(start, size - 1)) {
504 int bytes_to_flush = CachePage::kPageSize - offset;
505 FlushOnePage(start, bytes_to_flush);
506 start += bytes_to_flush;
507 size -= bytes_to_flush;
508 ASSERT_EQ(0, start & CachePage::kPageMask);
509 offset = 0;
510 }
511 if (size != 0) {
512 FlushOnePage(start, size);
513 }
514}
515
516
517CachePage* Simulator::GetCachePage(void* page) {
518 v8::internal::HashMap::Entry* entry = i_cache_->Lookup(page,
519 ICacheHash(page),
520 true);
521 if (entry->value == NULL) {
522 CachePage* new_page = new CachePage();
523 entry->value = new_page;
524 }
525 return reinterpret_cast<CachePage*>(entry->value);
526}
527
528
529// Flush from start up to and not including start + size.
530void Simulator::FlushOnePage(intptr_t start, int size) {
531 ASSERT(size <= CachePage::kPageSize);
532 ASSERT(AllOnOnePage(start, size - 1));
533 ASSERT((start & CachePage::kLineMask) == 0);
534 ASSERT((size & CachePage::kLineMask) == 0);
535 void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask));
536 int offset = (start & CachePage::kPageMask);
537 CachePage* cache_page = GetCachePage(page);
538 char* valid_bytemap = cache_page->ValidityByte(offset);
539 memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift);
540}
541
542
543void Simulator::CheckICache(Instr* instr) {
544 intptr_t address = reinterpret_cast<intptr_t>(instr);
545 void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
546 void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask));
547 int offset = (address & CachePage::kPageMask);
548 CachePage* cache_page = GetCachePage(page);
549 char* cache_valid_byte = cache_page->ValidityByte(offset);
550 bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID);
551 char* cached_line = cache_page->CachedData(offset & ~CachePage::kLineMask);
552 if (cache_hit) {
553 // Check that the data in memory matches the contents of the I-cache.
554 CHECK(memcmp(reinterpret_cast<void*>(instr),
555 cache_page->CachedData(offset),
556 Instr::kInstrSize) == 0);
557 } else {
558 // Cache miss. Load memory into the cache.
559 memcpy(cached_line, line, CachePage::kLineLength);
560 *cache_valid_byte = CachePage::LINE_VALID;
561 }
562}
563
564
Steve Blocka7e24c12009-10-30 11:49:00 +0000565// Create one simulator per thread and keep it in thread local storage.
566static v8::internal::Thread::LocalStorageKey simulator_key;
567
568
569bool Simulator::initialized_ = false;
570
571
572void Simulator::Initialize() {
573 if (initialized_) return;
574 simulator_key = v8::internal::Thread::CreateThreadLocalKey();
575 initialized_ = true;
576 ::v8::internal::ExternalReference::set_redirector(&RedirectExternalReference);
577}
578
579
Steve Block6ded16b2010-05-10 14:33:55 +0100580v8::internal::HashMap* Simulator::i_cache_ = NULL;
581
582
Steve Blocka7e24c12009-10-30 11:49:00 +0000583Simulator::Simulator() {
Steve Block6ded16b2010-05-10 14:33:55 +0100584 if (i_cache_ == NULL) {
585 i_cache_ = new v8::internal::HashMap(&ICacheMatch);
586 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000587 Initialize();
588 // Setup simulator support first. Some of this information is needed to
589 // setup the architecture state.
590 size_t stack_size = 1 * 1024*1024; // allocate 1MB for stack
591 stack_ = reinterpret_cast<char*>(malloc(stack_size));
592 pc_modified_ = false;
593 icount_ = 0;
594 break_pc_ = NULL;
595 break_instr_ = 0;
596
597 // Setup architecture state.
598 // All registers are initialized to zero to start with.
599 for (int i = 0; i < num_registers; i++) {
600 registers_[i] = 0;
601 }
602 n_flag_ = false;
603 z_flag_ = false;
604 c_flag_ = false;
605 v_flag_ = false;
606
Steve Blockd0582a62009-12-15 09:54:21 +0000607 // Initializing VFP registers.
608 // All registers are initialized to zero to start with
609 // even though s_registers_ & d_registers_ share the same
610 // physical registers in the target.
611 for (int i = 0; i < num_s_registers; i++) {
612 vfp_register[i] = 0;
613 }
614 n_flag_FPSCR_ = false;
615 z_flag_FPSCR_ = false;
616 c_flag_FPSCR_ = false;
617 v_flag_FPSCR_ = false;
618
619 inv_op_vfp_flag_ = false;
620 div_zero_vfp_flag_ = false;
621 overflow_vfp_flag_ = false;
622 underflow_vfp_flag_ = false;
623 inexact_vfp_flag_ = false;
624
Steve Blocka7e24c12009-10-30 11:49:00 +0000625 // The sp is initialized to point to the bottom (high address) of the
626 // allocated stack area. To be safe in potential stack underflows we leave
627 // some buffer below.
628 registers_[sp] = reinterpret_cast<int32_t>(stack_) + stack_size - 64;
629 // The lr and pc are initialized to a known bad value that will cause an
630 // access violation if the simulator ever tries to execute it.
631 registers_[pc] = bad_lr;
632 registers_[lr] = bad_lr;
633 InitializeCoverage();
634}
635
636
637// When the generated code calls an external reference we need to catch that in
638// the simulator. The external reference will be a function compiled for the
639// host architecture. We need to call that function instead of trying to
640// execute it with the simulator. We do that by redirecting the external
641// reference to a swi (software-interrupt) instruction that is handled by
642// the simulator. We write the original destination of the jump just at a known
643// offset from the swi instruction so the simulator knows what to call.
644class Redirection {
645 public:
646 Redirection(void* external_function, bool fp_return)
647 : external_function_(external_function),
648 swi_instruction_((AL << 28) | (0xf << 24) | call_rt_redirected),
649 fp_return_(fp_return),
650 next_(list_) {
Steve Block6ded16b2010-05-10 14:33:55 +0100651 Simulator::current()->
652 FlushICache(reinterpret_cast<void*>(&swi_instruction_),
653 Instr::kInstrSize);
Steve Blocka7e24c12009-10-30 11:49:00 +0000654 list_ = this;
655 }
656
657 void* address_of_swi_instruction() {
658 return reinterpret_cast<void*>(&swi_instruction_);
659 }
660
661 void* external_function() { return external_function_; }
662 bool fp_return() { return fp_return_; }
663
664 static Redirection* Get(void* external_function, bool fp_return) {
665 Redirection* current;
666 for (current = list_; current != NULL; current = current->next_) {
667 if (current->external_function_ == external_function) return current;
668 }
669 return new Redirection(external_function, fp_return);
670 }
671
672 static Redirection* FromSwiInstruction(Instr* swi_instruction) {
673 char* addr_of_swi = reinterpret_cast<char*>(swi_instruction);
674 char* addr_of_redirection =
675 addr_of_swi - OFFSET_OF(Redirection, swi_instruction_);
676 return reinterpret_cast<Redirection*>(addr_of_redirection);
677 }
678
679 private:
680 void* external_function_;
681 uint32_t swi_instruction_;
682 bool fp_return_;
683 Redirection* next_;
684 static Redirection* list_;
685};
686
687
688Redirection* Redirection::list_ = NULL;
689
690
691void* Simulator::RedirectExternalReference(void* external_function,
692 bool fp_return) {
693 Redirection* redirection = Redirection::Get(external_function, fp_return);
694 return redirection->address_of_swi_instruction();
695}
696
697
698// Get the active Simulator for the current thread.
699Simulator* Simulator::current() {
700 Initialize();
701 Simulator* sim = reinterpret_cast<Simulator*>(
702 v8::internal::Thread::GetThreadLocal(simulator_key));
703 if (sim == NULL) {
704 // TODO(146): delete the simulator object when a thread goes away.
705 sim = new Simulator();
706 v8::internal::Thread::SetThreadLocal(simulator_key, sim);
707 }
708 return sim;
709}
710
711
712// Sets the register in the architecture state. It will also deal with updating
713// Simulator internal state for special registers such as PC.
714void Simulator::set_register(int reg, int32_t value) {
715 ASSERT((reg >= 0) && (reg < num_registers));
716 if (reg == pc) {
717 pc_modified_ = true;
718 }
719 registers_[reg] = value;
720}
721
722
723// Get the register from the architecture state. This function does handle
724// the special case of accessing the PC register.
725int32_t Simulator::get_register(int reg) const {
726 ASSERT((reg >= 0) && (reg < num_registers));
727 return registers_[reg] + ((reg == pc) ? Instr::kPCReadOffset : 0);
728}
729
730
Kristian Monsen25f61362010-05-21 11:50:48 +0100731void Simulator::set_dw_register(int dreg, const int* dbl) {
732 ASSERT((dreg >= 0) && (dreg < num_d_registers));
733 registers_[dreg] = dbl[0];
734 registers_[dreg + 1] = dbl[1];
735}
736
737
Steve Blocka7e24c12009-10-30 11:49:00 +0000738// Raw access to the PC register.
739void Simulator::set_pc(int32_t value) {
740 pc_modified_ = true;
741 registers_[pc] = value;
742}
743
744
745// Raw access to the PC register without the special adjustment when reading.
746int32_t Simulator::get_pc() const {
747 return registers_[pc];
748}
749
750
Steve Blockd0582a62009-12-15 09:54:21 +0000751// Getting from and setting into VFP registers.
752void Simulator::set_s_register(int sreg, unsigned int value) {
753 ASSERT((sreg >= 0) && (sreg < num_s_registers));
754 vfp_register[sreg] = value;
755}
756
757
758unsigned int Simulator::get_s_register(int sreg) const {
759 ASSERT((sreg >= 0) && (sreg < num_s_registers));
760 return vfp_register[sreg];
761}
762
763
764void Simulator::set_s_register_from_float(int sreg, const float flt) {
765 ASSERT((sreg >= 0) && (sreg < num_s_registers));
766 // Read the bits from the single precision floating point value
767 // into the unsigned integer element of vfp_register[] given by index=sreg.
768 char buffer[sizeof(vfp_register[0])];
769 memcpy(buffer, &flt, sizeof(vfp_register[0]));
770 memcpy(&vfp_register[sreg], buffer, sizeof(vfp_register[0]));
771}
772
773
774void Simulator::set_s_register_from_sinteger(int sreg, const int sint) {
775 ASSERT((sreg >= 0) && (sreg < num_s_registers));
776 // Read the bits from the integer value into the unsigned integer element of
777 // vfp_register[] given by index=sreg.
778 char buffer[sizeof(vfp_register[0])];
779 memcpy(buffer, &sint, sizeof(vfp_register[0]));
780 memcpy(&vfp_register[sreg], buffer, sizeof(vfp_register[0]));
781}
782
783
784void Simulator::set_d_register_from_double(int dreg, const double& dbl) {
785 ASSERT((dreg >= 0) && (dreg < num_d_registers));
786 // Read the bits from the double precision floating point value into the two
787 // consecutive unsigned integer elements of vfp_register[] given by index
788 // 2*sreg and 2*sreg+1.
789 char buffer[2 * sizeof(vfp_register[0])];
790 memcpy(buffer, &dbl, 2 * sizeof(vfp_register[0]));
791#ifndef BIG_ENDIAN_FLOATING_POINT
792 memcpy(&vfp_register[dreg * 2], buffer, 2 * sizeof(vfp_register[0]));
793#else
794 memcpy(&vfp_register[dreg * 2], &buffer[4], sizeof(vfp_register[0]));
795 memcpy(&vfp_register[dreg * 2 + 1], &buffer[0], sizeof(vfp_register[0]));
796#endif
797}
798
799
800float Simulator::get_float_from_s_register(int sreg) {
801 ASSERT((sreg >= 0) && (sreg < num_s_registers));
802
803 float sm_val = 0.0;
804 // Read the bits from the unsigned integer vfp_register[] array
805 // into the single precision floating point value and return it.
806 char buffer[sizeof(vfp_register[0])];
807 memcpy(buffer, &vfp_register[sreg], sizeof(vfp_register[0]));
808 memcpy(&sm_val, buffer, sizeof(vfp_register[0]));
809 return(sm_val);
810}
811
812
813int Simulator::get_sinteger_from_s_register(int sreg) {
814 ASSERT((sreg >= 0) && (sreg < num_s_registers));
815
816 int sm_val = 0;
817 // Read the bits from the unsigned integer vfp_register[] array
818 // into the single precision floating point value and return it.
819 char buffer[sizeof(vfp_register[0])];
820 memcpy(buffer, &vfp_register[sreg], sizeof(vfp_register[0]));
821 memcpy(&sm_val, buffer, sizeof(vfp_register[0]));
822 return(sm_val);
823}
824
825
826double Simulator::get_double_from_d_register(int dreg) {
827 ASSERT((dreg >= 0) && (dreg < num_d_registers));
828
829 double dm_val = 0.0;
830 // Read the bits from the unsigned integer vfp_register[] array
831 // into the double precision floating point value and return it.
832 char buffer[2 * sizeof(vfp_register[0])];
833#ifdef BIG_ENDIAN_FLOATING_POINT
834 memcpy(&buffer[0], &vfp_register[2 * dreg + 1], sizeof(vfp_register[0]));
835 memcpy(&buffer[4], &vfp_register[2 * dreg], sizeof(vfp_register[0]));
836#else
837 memcpy(buffer, &vfp_register[2 * dreg], 2 * sizeof(vfp_register[0]));
838#endif
839 memcpy(&dm_val, buffer, 2 * sizeof(vfp_register[0]));
840 return(dm_val);
841}
842
843
Steve Blocka7e24c12009-10-30 11:49:00 +0000844// For use in calls that take two double values, constructed from r0, r1, r2
845// and r3.
846void Simulator::GetFpArgs(double* x, double* y) {
847 // We use a char buffer to get around the strict-aliasing rules which
848 // otherwise allow the compiler to optimize away the copy.
849 char buffer[2 * sizeof(registers_[0])];
850 // Registers 0 and 1 -> x.
851 memcpy(buffer, registers_, sizeof(buffer));
852 memcpy(x, buffer, sizeof(buffer));
853 // Registers 2 and 3 -> y.
854 memcpy(buffer, registers_ + 2, sizeof(buffer));
855 memcpy(y, buffer, sizeof(buffer));
856}
857
858
859void Simulator::SetFpResult(const double& result) {
860 char buffer[2 * sizeof(registers_[0])];
861 memcpy(buffer, &result, sizeof(buffer));
862 // result -> registers 0 and 1.
863 memcpy(registers_, buffer, sizeof(buffer));
864}
865
866
867void Simulator::TrashCallerSaveRegisters() {
868 // We don't trash the registers with the return value.
869 registers_[2] = 0x50Bad4U;
870 registers_[3] = 0x50Bad4U;
871 registers_[12] = 0x50Bad4U;
872}
873
Kristian Monsen25f61362010-05-21 11:50:48 +0100874// Some Operating Systems allow unaligned access on ARMv7 targets. We
875// assume that unaligned accesses are not allowed unless the v8 build system
876// defines the CAN_USE_UNALIGNED_ACCESSES macro to be non-zero.
877// The following statements below describes the behavior of the ARM CPUs
878// that don't support unaligned access.
879// Some ARM platforms raise an interrupt on detecting unaligned access.
880// On others it does a funky rotation thing. For now we
881// simply disallow unaligned reads. Note that simulator runs have the runtime
Steve Blocka7e24c12009-10-30 11:49:00 +0000882// system running directly on the host system and only generated code is
883// executed in the simulator. Since the host is typically IA32 we will not
Kristian Monsen25f61362010-05-21 11:50:48 +0100884// get the correct ARM-like behaviour on unaligned accesses for those ARM
885// targets that don't support unaligned loads and stores.
886
Steve Blocka7e24c12009-10-30 11:49:00 +0000887
888int Simulator::ReadW(int32_t addr, Instr* instr) {
Kristian Monsen25f61362010-05-21 11:50:48 +0100889#if V8_TARGET_CAN_READ_UNALIGNED
890 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
891 return *ptr;
892#else
Steve Blocka7e24c12009-10-30 11:49:00 +0000893 if ((addr & 3) == 0) {
894 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
895 return *ptr;
896 }
Kristian Monsen25f61362010-05-21 11:50:48 +0100897 PrintF("Unaligned read at 0x%08x, pc=%p\n", addr, instr);
Steve Blocka7e24c12009-10-30 11:49:00 +0000898 UNIMPLEMENTED();
899 return 0;
Kristian Monsen25f61362010-05-21 11:50:48 +0100900#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000901}
902
903
904void Simulator::WriteW(int32_t addr, int value, Instr* instr) {
Kristian Monsen25f61362010-05-21 11:50:48 +0100905#if V8_TARGET_CAN_READ_UNALIGNED
906 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
907 *ptr = value;
908 return;
909#else
Steve Blocka7e24c12009-10-30 11:49:00 +0000910 if ((addr & 3) == 0) {
911 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
912 *ptr = value;
913 return;
914 }
915 PrintF("Unaligned write at 0x%08x, pc=%p\n", addr, instr);
916 UNIMPLEMENTED();
Kristian Monsen25f61362010-05-21 11:50:48 +0100917#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000918}
919
920
921uint16_t Simulator::ReadHU(int32_t addr, Instr* instr) {
Kristian Monsen25f61362010-05-21 11:50:48 +0100922#if V8_TARGET_CAN_READ_UNALIGNED
923 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
924 return *ptr;
925#else
Steve Blocka7e24c12009-10-30 11:49:00 +0000926 if ((addr & 1) == 0) {
927 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
928 return *ptr;
929 }
930 PrintF("Unaligned unsigned halfword read at 0x%08x, pc=%p\n", addr, instr);
931 UNIMPLEMENTED();
932 return 0;
Kristian Monsen25f61362010-05-21 11:50:48 +0100933#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000934}
935
936
937int16_t Simulator::ReadH(int32_t addr, Instr* instr) {
Kristian Monsen25f61362010-05-21 11:50:48 +0100938#if V8_TARGET_CAN_READ_UNALIGNED
939 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
940 return *ptr;
941#else
Steve Blocka7e24c12009-10-30 11:49:00 +0000942 if ((addr & 1) == 0) {
943 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
944 return *ptr;
945 }
946 PrintF("Unaligned signed halfword read at 0x%08x\n", addr);
947 UNIMPLEMENTED();
948 return 0;
Kristian Monsen25f61362010-05-21 11:50:48 +0100949#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000950}
951
952
953void Simulator::WriteH(int32_t addr, uint16_t value, Instr* instr) {
Kristian Monsen25f61362010-05-21 11:50:48 +0100954#if V8_TARGET_CAN_READ_UNALIGNED
955 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
956 *ptr = value;
957 return;
958#else
Steve Blocka7e24c12009-10-30 11:49:00 +0000959 if ((addr & 1) == 0) {
960 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
961 *ptr = value;
962 return;
963 }
964 PrintF("Unaligned unsigned halfword write at 0x%08x, pc=%p\n", addr, instr);
965 UNIMPLEMENTED();
Kristian Monsen25f61362010-05-21 11:50:48 +0100966#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000967}
968
969
970void Simulator::WriteH(int32_t addr, int16_t value, Instr* instr) {
Kristian Monsen25f61362010-05-21 11:50:48 +0100971#if V8_TARGET_CAN_READ_UNALIGNED
972 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
973 *ptr = value;
974 return;
975#else
Steve Blocka7e24c12009-10-30 11:49:00 +0000976 if ((addr & 1) == 0) {
977 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
978 *ptr = value;
979 return;
980 }
981 PrintF("Unaligned halfword write at 0x%08x, pc=%p\n", addr, instr);
982 UNIMPLEMENTED();
Kristian Monsen25f61362010-05-21 11:50:48 +0100983#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000984}
985
986
987uint8_t Simulator::ReadBU(int32_t addr) {
988 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
989 return *ptr;
990}
991
992
993int8_t Simulator::ReadB(int32_t addr) {
994 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
995 return *ptr;
996}
997
998
999void Simulator::WriteB(int32_t addr, uint8_t value) {
1000 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1001 *ptr = value;
1002}
1003
1004
1005void Simulator::WriteB(int32_t addr, int8_t value) {
1006 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
1007 *ptr = value;
1008}
1009
1010
Kristian Monsen25f61362010-05-21 11:50:48 +01001011int32_t* Simulator::ReadDW(int32_t addr) {
1012#if V8_TARGET_CAN_READ_UNALIGNED
1013 int32_t* ptr = reinterpret_cast<int32_t*>(addr);
1014 return ptr;
1015#else
1016 if ((addr & 3) == 0) {
1017 int32_t* ptr = reinterpret_cast<int32_t*>(addr);
1018 return ptr;
1019 }
1020 PrintF("Unaligned read at 0x%08x\n", addr);
1021 UNIMPLEMENTED();
1022 return 0;
1023#endif
1024}
1025
1026
1027void Simulator::WriteDW(int32_t addr, int32_t value1, int32_t value2) {
1028#if V8_TARGET_CAN_READ_UNALIGNED
1029 int32_t* ptr = reinterpret_cast<int32_t*>(addr);
1030 *ptr++ = value1;
1031 *ptr = value2;
1032 return;
1033#else
1034 if ((addr & 3) == 0) {
1035 int32_t* ptr = reinterpret_cast<int32_t*>(addr);
1036 *ptr++ = value1;
1037 *ptr = value2;
1038 return;
1039 }
1040 PrintF("Unaligned write at 0x%08x\n", addr);
1041 UNIMPLEMENTED();
1042#endif
1043}
1044
1045
Steve Blocka7e24c12009-10-30 11:49:00 +00001046// Returns the limit of the stack area to enable checking for stack overflows.
1047uintptr_t Simulator::StackLimit() const {
1048 // Leave a safety margin of 256 bytes to prevent overrunning the stack when
1049 // pushing values.
1050 return reinterpret_cast<uintptr_t>(stack_) + 256;
1051}
1052
1053
1054// Unsupported instructions use Format to print an error and stop execution.
1055void Simulator::Format(Instr* instr, const char* format) {
1056 PrintF("Simulator found unsupported instruction:\n 0x%08x: %s\n",
1057 instr, format);
1058 UNIMPLEMENTED();
1059}
1060
1061
1062// Checks if the current instruction should be executed based on its
1063// condition bits.
1064bool Simulator::ConditionallyExecute(Instr* instr) {
1065 switch (instr->ConditionField()) {
1066 case EQ: return z_flag_;
1067 case NE: return !z_flag_;
1068 case CS: return c_flag_;
1069 case CC: return !c_flag_;
1070 case MI: return n_flag_;
1071 case PL: return !n_flag_;
1072 case VS: return v_flag_;
1073 case VC: return !v_flag_;
1074 case HI: return c_flag_ && !z_flag_;
1075 case LS: return !c_flag_ || z_flag_;
1076 case GE: return n_flag_ == v_flag_;
1077 case LT: return n_flag_ != v_flag_;
1078 case GT: return !z_flag_ && (n_flag_ == v_flag_);
1079 case LE: return z_flag_ || (n_flag_ != v_flag_);
1080 case AL: return true;
1081 default: UNREACHABLE();
1082 }
1083 return false;
1084}
1085
1086
1087// Calculate and set the Negative and Zero flags.
1088void Simulator::SetNZFlags(int32_t val) {
1089 n_flag_ = (val < 0);
1090 z_flag_ = (val == 0);
1091}
1092
1093
1094// Set the Carry flag.
1095void Simulator::SetCFlag(bool val) {
1096 c_flag_ = val;
1097}
1098
1099
1100// Set the oVerflow flag.
1101void Simulator::SetVFlag(bool val) {
1102 v_flag_ = val;
1103}
1104
1105
1106// Calculate C flag value for additions.
1107bool Simulator::CarryFrom(int32_t left, int32_t right) {
1108 uint32_t uleft = static_cast<uint32_t>(left);
1109 uint32_t uright = static_cast<uint32_t>(right);
1110 uint32_t urest = 0xffffffffU - uleft;
1111
1112 return (uright > urest);
1113}
1114
1115
1116// Calculate C flag value for subtractions.
1117bool Simulator::BorrowFrom(int32_t left, int32_t right) {
1118 uint32_t uleft = static_cast<uint32_t>(left);
1119 uint32_t uright = static_cast<uint32_t>(right);
1120
1121 return (uright > uleft);
1122}
1123
1124
1125// Calculate V flag value for additions and subtractions.
1126bool Simulator::OverflowFrom(int32_t alu_out,
1127 int32_t left, int32_t right, bool addition) {
1128 bool overflow;
1129 if (addition) {
1130 // operands have the same sign
1131 overflow = ((left >= 0 && right >= 0) || (left < 0 && right < 0))
1132 // and operands and result have different sign
1133 && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
1134 } else {
1135 // operands have different signs
1136 overflow = ((left < 0 && right >= 0) || (left >= 0 && right < 0))
1137 // and first operand and result have different signs
1138 && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
1139 }
1140 return overflow;
1141}
1142
1143
Steve Blockd0582a62009-12-15 09:54:21 +00001144// Support for VFP comparisons.
1145void Simulator::Compute_FPSCR_Flags(double val1, double val2) {
Leon Clarkee46be812010-01-19 14:06:41 +00001146 if (isnan(val1) || isnan(val2)) {
1147 n_flag_FPSCR_ = false;
1148 z_flag_FPSCR_ = false;
1149 c_flag_FPSCR_ = true;
1150 v_flag_FPSCR_ = true;
Steve Blockd0582a62009-12-15 09:54:21 +00001151 // All non-NaN cases.
Leon Clarkee46be812010-01-19 14:06:41 +00001152 } else if (val1 == val2) {
Steve Blockd0582a62009-12-15 09:54:21 +00001153 n_flag_FPSCR_ = false;
1154 z_flag_FPSCR_ = true;
1155 c_flag_FPSCR_ = true;
1156 v_flag_FPSCR_ = false;
1157 } else if (val1 < val2) {
1158 n_flag_FPSCR_ = true;
1159 z_flag_FPSCR_ = false;
1160 c_flag_FPSCR_ = false;
1161 v_flag_FPSCR_ = false;
1162 } else {
1163 // Case when (val1 > val2).
1164 n_flag_FPSCR_ = false;
1165 z_flag_FPSCR_ = false;
1166 c_flag_FPSCR_ = true;
1167 v_flag_FPSCR_ = false;
1168 }
1169}
1170
1171
1172void Simulator::Copy_FPSCR_to_APSR() {
1173 n_flag_ = n_flag_FPSCR_;
1174 z_flag_ = z_flag_FPSCR_;
1175 c_flag_ = c_flag_FPSCR_;
1176 v_flag_ = v_flag_FPSCR_;
1177}
1178
1179
Steve Blocka7e24c12009-10-30 11:49:00 +00001180// Addressing Mode 1 - Data-processing operands:
1181// Get the value based on the shifter_operand with register.
1182int32_t Simulator::GetShiftRm(Instr* instr, bool* carry_out) {
1183 Shift shift = instr->ShiftField();
1184 int shift_amount = instr->ShiftAmountField();
1185 int32_t result = get_register(instr->RmField());
1186 if (instr->Bit(4) == 0) {
1187 // by immediate
1188 if ((shift == ROR) && (shift_amount == 0)) {
1189 UNIMPLEMENTED();
1190 return result;
1191 } else if (((shift == LSR) || (shift == ASR)) && (shift_amount == 0)) {
1192 shift_amount = 32;
1193 }
1194 switch (shift) {
1195 case ASR: {
1196 if (shift_amount == 0) {
1197 if (result < 0) {
1198 result = 0xffffffff;
1199 *carry_out = true;
1200 } else {
1201 result = 0;
1202 *carry_out = false;
1203 }
1204 } else {
1205 result >>= (shift_amount - 1);
1206 *carry_out = (result & 1) == 1;
1207 result >>= 1;
1208 }
1209 break;
1210 }
1211
1212 case LSL: {
1213 if (shift_amount == 0) {
1214 *carry_out = c_flag_;
1215 } else {
1216 result <<= (shift_amount - 1);
1217 *carry_out = (result < 0);
1218 result <<= 1;
1219 }
1220 break;
1221 }
1222
1223 case LSR: {
1224 if (shift_amount == 0) {
1225 result = 0;
1226 *carry_out = c_flag_;
1227 } else {
1228 uint32_t uresult = static_cast<uint32_t>(result);
1229 uresult >>= (shift_amount - 1);
1230 *carry_out = (uresult & 1) == 1;
1231 uresult >>= 1;
1232 result = static_cast<int32_t>(uresult);
1233 }
1234 break;
1235 }
1236
1237 case ROR: {
1238 UNIMPLEMENTED();
1239 break;
1240 }
1241
1242 default: {
1243 UNREACHABLE();
1244 break;
1245 }
1246 }
1247 } else {
1248 // by register
1249 int rs = instr->RsField();
1250 shift_amount = get_register(rs) &0xff;
1251 switch (shift) {
1252 case ASR: {
1253 if (shift_amount == 0) {
1254 *carry_out = c_flag_;
1255 } else if (shift_amount < 32) {
1256 result >>= (shift_amount - 1);
1257 *carry_out = (result & 1) == 1;
1258 result >>= 1;
1259 } else {
1260 ASSERT(shift_amount >= 32);
1261 if (result < 0) {
1262 *carry_out = true;
1263 result = 0xffffffff;
1264 } else {
1265 *carry_out = false;
1266 result = 0;
1267 }
1268 }
1269 break;
1270 }
1271
1272 case LSL: {
1273 if (shift_amount == 0) {
1274 *carry_out = c_flag_;
1275 } else if (shift_amount < 32) {
1276 result <<= (shift_amount - 1);
1277 *carry_out = (result < 0);
1278 result <<= 1;
1279 } else if (shift_amount == 32) {
1280 *carry_out = (result & 1) == 1;
1281 result = 0;
1282 } else {
1283 ASSERT(shift_amount > 32);
1284 *carry_out = false;
1285 result = 0;
1286 }
1287 break;
1288 }
1289
1290 case LSR: {
1291 if (shift_amount == 0) {
1292 *carry_out = c_flag_;
1293 } else if (shift_amount < 32) {
1294 uint32_t uresult = static_cast<uint32_t>(result);
1295 uresult >>= (shift_amount - 1);
1296 *carry_out = (uresult & 1) == 1;
1297 uresult >>= 1;
1298 result = static_cast<int32_t>(uresult);
1299 } else if (shift_amount == 32) {
1300 *carry_out = (result < 0);
1301 result = 0;
1302 } else {
1303 *carry_out = false;
1304 result = 0;
1305 }
1306 break;
1307 }
1308
1309 case ROR: {
1310 UNIMPLEMENTED();
1311 break;
1312 }
1313
1314 default: {
1315 UNREACHABLE();
1316 break;
1317 }
1318 }
1319 }
1320 return result;
1321}
1322
1323
1324// Addressing Mode 1 - Data-processing operands:
1325// Get the value based on the shifter_operand with immediate.
1326int32_t Simulator::GetImm(Instr* instr, bool* carry_out) {
1327 int rotate = instr->RotateField() * 2;
1328 int immed8 = instr->Immed8Field();
1329 int imm = (immed8 >> rotate) | (immed8 << (32 - rotate));
1330 *carry_out = (rotate == 0) ? c_flag_ : (imm < 0);
1331 return imm;
1332}
1333
1334
1335static int count_bits(int bit_vector) {
1336 int count = 0;
1337 while (bit_vector != 0) {
1338 if ((bit_vector & 1) != 0) {
1339 count++;
1340 }
1341 bit_vector >>= 1;
1342 }
1343 return count;
1344}
1345
1346
1347// Addressing Mode 4 - Load and Store Multiple
1348void Simulator::HandleRList(Instr* instr, bool load) {
1349 int rn = instr->RnField();
1350 int32_t rn_val = get_register(rn);
1351 int rlist = instr->RlistField();
1352 int num_regs = count_bits(rlist);
1353
1354 intptr_t start_address = 0;
1355 intptr_t end_address = 0;
1356 switch (instr->PUField()) {
1357 case 0: {
1358 // Print("da");
1359 UNIMPLEMENTED();
1360 break;
1361 }
1362 case 1: {
1363 // Print("ia");
1364 start_address = rn_val;
1365 end_address = rn_val + (num_regs * 4) - 4;
1366 rn_val = rn_val + (num_regs * 4);
1367 break;
1368 }
1369 case 2: {
1370 // Print("db");
1371 start_address = rn_val - (num_regs * 4);
1372 end_address = rn_val - 4;
1373 rn_val = start_address;
1374 break;
1375 }
1376 case 3: {
1377 // Print("ib");
1378 UNIMPLEMENTED();
1379 break;
1380 }
1381 default: {
1382 UNREACHABLE();
1383 break;
1384 }
1385 }
1386 if (instr->HasW()) {
1387 set_register(rn, rn_val);
1388 }
1389 intptr_t* address = reinterpret_cast<intptr_t*>(start_address);
1390 int reg = 0;
1391 while (rlist != 0) {
1392 if ((rlist & 1) != 0) {
1393 if (load) {
1394 set_register(reg, *address);
1395 } else {
1396 *address = get_register(reg);
1397 }
1398 address += 1;
1399 }
1400 reg++;
1401 rlist >>= 1;
1402 }
1403 ASSERT(end_address == ((intptr_t)address) - 4);
1404}
1405
1406
1407// Calls into the V8 runtime are based on this very simple interface.
1408// Note: To be able to return two values from some calls the code in runtime.cc
1409// uses the ObjectPair which is essentially two 32-bit values stuffed into a
1410// 64-bit value. With the code below we assume that all runtime calls return
1411// 64 bits of result. If they don't, the r1 result register contains a bogus
1412// value, which is fine because it is caller-saved.
1413typedef int64_t (*SimulatorRuntimeCall)(int32_t arg0,
1414 int32_t arg1,
1415 int32_t arg2,
1416 int32_t arg3);
1417typedef double (*SimulatorRuntimeFPCall)(int32_t arg0,
1418 int32_t arg1,
1419 int32_t arg2,
1420 int32_t arg3);
1421
1422
1423// Software interrupt instructions are used by the simulator to call into the
1424// C-based V8 runtime.
1425void Simulator::SoftwareInterrupt(Instr* instr) {
1426 int swi = instr->SwiField();
1427 switch (swi) {
1428 case call_rt_redirected: {
Steve Block6ded16b2010-05-10 14:33:55 +01001429 // Check if stack is aligned. Error if not aligned is reported below to
1430 // include information on the function called.
1431 bool stack_aligned =
1432 (get_register(sp)
1433 & (::v8::internal::FLAG_sim_stack_alignment - 1)) == 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00001434 Redirection* redirection = Redirection::FromSwiInstruction(instr);
1435 int32_t arg0 = get_register(r0);
1436 int32_t arg1 = get_register(r1);
1437 int32_t arg2 = get_register(r2);
1438 int32_t arg3 = get_register(r3);
1439 // This is dodgy but it works because the C entry stubs are never moved.
1440 // See comment in codegen-arm.cc and bug 1242173.
1441 int32_t saved_lr = get_register(lr);
1442 if (redirection->fp_return()) {
1443 intptr_t external =
1444 reinterpret_cast<intptr_t>(redirection->external_function());
1445 SimulatorRuntimeFPCall target =
1446 reinterpret_cast<SimulatorRuntimeFPCall>(external);
Steve Block6ded16b2010-05-10 14:33:55 +01001447 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001448 double x, y;
1449 GetFpArgs(&x, &y);
Steve Block6ded16b2010-05-10 14:33:55 +01001450 PrintF("Call to host function at %p with args %f, %f",
Steve Blocka7e24c12009-10-30 11:49:00 +00001451 FUNCTION_ADDR(target), x, y);
Steve Block6ded16b2010-05-10 14:33:55 +01001452 if (!stack_aligned) {
1453 PrintF(" with unaligned stack %08x\n", get_register(sp));
1454 }
1455 PrintF("\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00001456 }
Steve Block6ded16b2010-05-10 14:33:55 +01001457 CHECK(stack_aligned);
Steve Blocka7e24c12009-10-30 11:49:00 +00001458 double result = target(arg0, arg1, arg2, arg3);
1459 SetFpResult(result);
1460 } else {
1461 intptr_t external =
1462 reinterpret_cast<int32_t>(redirection->external_function());
1463 SimulatorRuntimeCall target =
1464 reinterpret_cast<SimulatorRuntimeCall>(external);
Steve Block6ded16b2010-05-10 14:33:55 +01001465 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001466 PrintF(
Steve Block6ded16b2010-05-10 14:33:55 +01001467 "Call to host function at %p with args %08x, %08x, %08x, %08x",
Steve Blocka7e24c12009-10-30 11:49:00 +00001468 FUNCTION_ADDR(target),
1469 arg0,
1470 arg1,
1471 arg2,
1472 arg3);
Steve Block6ded16b2010-05-10 14:33:55 +01001473 if (!stack_aligned) {
1474 PrintF(" with unaligned stack %08x\n", get_register(sp));
1475 }
1476 PrintF("\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00001477 }
Steve Block6ded16b2010-05-10 14:33:55 +01001478 CHECK(stack_aligned);
Steve Blocka7e24c12009-10-30 11:49:00 +00001479 int64_t result = target(arg0, arg1, arg2, arg3);
1480 int32_t lo_res = static_cast<int32_t>(result);
1481 int32_t hi_res = static_cast<int32_t>(result >> 32);
1482 if (::v8::internal::FLAG_trace_sim) {
1483 PrintF("Returned %08x\n", lo_res);
1484 }
1485 set_register(r0, lo_res);
1486 set_register(r1, hi_res);
1487 }
1488 set_register(lr, saved_lr);
1489 set_pc(get_register(lr));
1490 break;
1491 }
1492 case break_point: {
1493 Debugger dbg(this);
1494 dbg.Debug();
1495 break;
1496 }
1497 default: {
1498 UNREACHABLE();
1499 break;
1500 }
1501 }
1502}
1503
1504
1505// Handle execution based on instruction types.
1506
1507// Instruction types 0 and 1 are both rolled into one function because they
1508// only differ in the handling of the shifter_operand.
1509void Simulator::DecodeType01(Instr* instr) {
1510 int type = instr->TypeField();
1511 if ((type == 0) && instr->IsSpecialType0()) {
1512 // multiply instruction or extra loads and stores
1513 if (instr->Bits(7, 4) == 9) {
1514 if (instr->Bit(24) == 0) {
1515 // Raw field decoding here. Multiply instructions have their Rd in
1516 // funny places.
1517 int rn = instr->RnField();
1518 int rm = instr->RmField();
1519 int rs = instr->RsField();
1520 int32_t rs_val = get_register(rs);
1521 int32_t rm_val = get_register(rm);
1522 if (instr->Bit(23) == 0) {
1523 if (instr->Bit(21) == 0) {
1524 // The MUL instruction description (A 4.1.33) refers to Rd as being
1525 // the destination for the operation, but it confusingly uses the
1526 // Rn field to encode it.
1527 // Format(instr, "mul'cond's 'rn, 'rm, 'rs");
1528 int rd = rn; // Remap the rn field to the Rd register.
1529 int32_t alu_out = rm_val * rs_val;
1530 set_register(rd, alu_out);
1531 if (instr->HasS()) {
1532 SetNZFlags(alu_out);
1533 }
1534 } else {
1535 // The MLA instruction description (A 4.1.28) refers to the order
1536 // of registers as "Rd, Rm, Rs, Rn". But confusingly it uses the
1537 // Rn field to encode the Rd register and the Rd field to encode
1538 // the Rn register.
1539 Format(instr, "mla'cond's 'rn, 'rm, 'rs, 'rd");
1540 }
1541 } else {
1542 // The signed/long multiply instructions use the terms RdHi and RdLo
1543 // when referring to the target registers. They are mapped to the Rn
1544 // and Rd fields as follows:
1545 // RdLo == Rd
1546 // RdHi == Rn (This is confusingly stored in variable rd here
1547 // because the mul instruction from above uses the
1548 // Rn field to encode the Rd register. Good luck figuring
1549 // this out without reading the ARM instruction manual
1550 // at a very detailed level.)
1551 // Format(instr, "'um'al'cond's 'rd, 'rn, 'rs, 'rm");
1552 int rd_hi = rn; // Remap the rn field to the RdHi register.
1553 int rd_lo = instr->RdField();
1554 int32_t hi_res = 0;
1555 int32_t lo_res = 0;
1556 if (instr->Bit(22) == 1) {
1557 int64_t left_op = static_cast<int32_t>(rm_val);
1558 int64_t right_op = static_cast<int32_t>(rs_val);
1559 uint64_t result = left_op * right_op;
1560 hi_res = static_cast<int32_t>(result >> 32);
1561 lo_res = static_cast<int32_t>(result & 0xffffffff);
1562 } else {
1563 // unsigned multiply
1564 uint64_t left_op = static_cast<uint32_t>(rm_val);
1565 uint64_t right_op = static_cast<uint32_t>(rs_val);
1566 uint64_t result = left_op * right_op;
1567 hi_res = static_cast<int32_t>(result >> 32);
1568 lo_res = static_cast<int32_t>(result & 0xffffffff);
1569 }
1570 set_register(rd_lo, lo_res);
1571 set_register(rd_hi, hi_res);
1572 if (instr->HasS()) {
1573 UNIMPLEMENTED();
1574 }
1575 }
1576 } else {
Steve Blockd0582a62009-12-15 09:54:21 +00001577 UNIMPLEMENTED(); // Not used by V8.
Steve Blocka7e24c12009-10-30 11:49:00 +00001578 }
1579 } else {
1580 // extra load/store instructions
1581 int rd = instr->RdField();
1582 int rn = instr->RnField();
1583 int32_t rn_val = get_register(rn);
1584 int32_t addr = 0;
1585 if (instr->Bit(22) == 0) {
1586 int rm = instr->RmField();
1587 int32_t rm_val = get_register(rm);
1588 switch (instr->PUField()) {
1589 case 0: {
1590 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], -'rm");
1591 ASSERT(!instr->HasW());
1592 addr = rn_val;
1593 rn_val -= rm_val;
1594 set_register(rn, rn_val);
1595 break;
1596 }
1597 case 1: {
1598 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], +'rm");
1599 ASSERT(!instr->HasW());
1600 addr = rn_val;
1601 rn_val += rm_val;
1602 set_register(rn, rn_val);
1603 break;
1604 }
1605 case 2: {
1606 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, -'rm]'w");
1607 rn_val -= rm_val;
1608 addr = rn_val;
1609 if (instr->HasW()) {
1610 set_register(rn, rn_val);
1611 }
1612 break;
1613 }
1614 case 3: {
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 default: {
1624 // The PU field is a 2-bit field.
1625 UNREACHABLE();
1626 break;
1627 }
1628 }
1629 } else {
1630 int32_t imm_val = (instr->ImmedHField() << 4) | instr->ImmedLField();
1631 switch (instr->PUField()) {
1632 case 0: {
1633 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], #-'off8");
1634 ASSERT(!instr->HasW());
1635 addr = rn_val;
1636 rn_val -= imm_val;
1637 set_register(rn, rn_val);
1638 break;
1639 }
1640 case 1: {
1641 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], #+'off8");
1642 ASSERT(!instr->HasW());
1643 addr = rn_val;
1644 rn_val += imm_val;
1645 set_register(rn, rn_val);
1646 break;
1647 }
1648 case 2: {
1649 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, #-'off8]'w");
1650 rn_val -= imm_val;
1651 addr = rn_val;
1652 if (instr->HasW()) {
1653 set_register(rn, rn_val);
1654 }
1655 break;
1656 }
1657 case 3: {
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 default: {
1667 // The PU field is a 2-bit field.
1668 UNREACHABLE();
1669 break;
1670 }
1671 }
1672 }
Kristian Monsen25f61362010-05-21 11:50:48 +01001673 if (((instr->Bits(7, 4) & 0xd) == 0xd) && (instr->Bit(20) == 0)) {
1674 ASSERT((rd % 2) == 0);
1675 if (instr->HasH()) {
1676 // The strd instruction.
1677 int32_t value1 = get_register(rd);
1678 int32_t value2 = get_register(rd+1);
1679 WriteDW(addr, value1, value2);
1680 } else {
1681 // The ldrd instruction.
1682 int* rn_data = ReadDW(addr);
1683 set_dw_register(rd, rn_data);
1684 }
1685 } else if (instr->HasH()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001686 if (instr->HasSign()) {
1687 if (instr->HasL()) {
1688 int16_t val = ReadH(addr, instr);
1689 set_register(rd, val);
1690 } else {
1691 int16_t val = get_register(rd);
1692 WriteH(addr, val, instr);
1693 }
1694 } else {
1695 if (instr->HasL()) {
1696 uint16_t val = ReadHU(addr, instr);
1697 set_register(rd, val);
1698 } else {
1699 uint16_t val = get_register(rd);
1700 WriteH(addr, val, instr);
1701 }
1702 }
1703 } else {
1704 // signed byte loads
1705 ASSERT(instr->HasSign());
1706 ASSERT(instr->HasL());
1707 int8_t val = ReadB(addr);
1708 set_register(rd, val);
1709 }
1710 return;
1711 }
Steve Block6ded16b2010-05-10 14:33:55 +01001712 } else if ((type == 0) && instr->IsMiscType0()) {
1713 if (instr->Bits(22, 21) == 1) {
1714 int rm = instr->RmField();
1715 switch (instr->Bits(7, 4)) {
1716 case BX:
1717 set_pc(get_register(rm));
1718 break;
1719 case BLX: {
1720 uint32_t old_pc = get_pc();
1721 set_pc(get_register(rm));
1722 set_register(lr, old_pc + Instr::kInstrSize);
1723 break;
1724 }
1725 case BKPT:
1726 v8::internal::OS::DebugBreak();
1727 break;
1728 default:
1729 UNIMPLEMENTED();
1730 }
1731 } else if (instr->Bits(22, 21) == 3) {
1732 int rm = instr->RmField();
1733 int rd = instr->RdField();
1734 switch (instr->Bits(7, 4)) {
1735 case CLZ: {
1736 uint32_t bits = get_register(rm);
1737 int leading_zeros = 0;
1738 if (bits == 0) {
1739 leading_zeros = 32;
1740 } else {
1741 while ((bits & 0x80000000u) == 0) {
1742 bits <<= 1;
1743 leading_zeros++;
1744 }
1745 }
1746 set_register(rd, leading_zeros);
1747 break;
1748 }
1749 default:
1750 UNIMPLEMENTED();
1751 }
1752 } else {
1753 PrintF("%08x\n", instr->InstructionBits());
1754 UNIMPLEMENTED();
1755 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001756 } else {
1757 int rd = instr->RdField();
1758 int rn = instr->RnField();
1759 int32_t rn_val = get_register(rn);
1760 int32_t shifter_operand = 0;
1761 bool shifter_carry_out = 0;
1762 if (type == 0) {
1763 shifter_operand = GetShiftRm(instr, &shifter_carry_out);
1764 } else {
1765 ASSERT(instr->TypeField() == 1);
1766 shifter_operand = GetImm(instr, &shifter_carry_out);
1767 }
1768 int32_t alu_out;
1769
1770 switch (instr->OpcodeField()) {
1771 case AND: {
1772 // Format(instr, "and'cond's 'rd, 'rn, 'shift_rm");
1773 // Format(instr, "and'cond's 'rd, 'rn, 'imm");
1774 alu_out = rn_val & shifter_operand;
1775 set_register(rd, alu_out);
1776 if (instr->HasS()) {
1777 SetNZFlags(alu_out);
1778 SetCFlag(shifter_carry_out);
1779 }
1780 break;
1781 }
1782
1783 case EOR: {
1784 // Format(instr, "eor'cond's 'rd, 'rn, 'shift_rm");
1785 // Format(instr, "eor'cond's 'rd, 'rn, 'imm");
1786 alu_out = rn_val ^ shifter_operand;
1787 set_register(rd, alu_out);
1788 if (instr->HasS()) {
1789 SetNZFlags(alu_out);
1790 SetCFlag(shifter_carry_out);
1791 }
1792 break;
1793 }
1794
1795 case SUB: {
1796 // Format(instr, "sub'cond's 'rd, 'rn, 'shift_rm");
1797 // Format(instr, "sub'cond's 'rd, 'rn, 'imm");
1798 alu_out = rn_val - shifter_operand;
1799 set_register(rd, alu_out);
1800 if (instr->HasS()) {
1801 SetNZFlags(alu_out);
1802 SetCFlag(!BorrowFrom(rn_val, shifter_operand));
1803 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, false));
1804 }
1805 break;
1806 }
1807
1808 case RSB: {
1809 // Format(instr, "rsb'cond's 'rd, 'rn, 'shift_rm");
1810 // Format(instr, "rsb'cond's 'rd, 'rn, 'imm");
1811 alu_out = shifter_operand - rn_val;
1812 set_register(rd, alu_out);
1813 if (instr->HasS()) {
1814 SetNZFlags(alu_out);
1815 SetCFlag(!BorrowFrom(shifter_operand, rn_val));
1816 SetVFlag(OverflowFrom(alu_out, shifter_operand, rn_val, false));
1817 }
1818 break;
1819 }
1820
1821 case ADD: {
1822 // Format(instr, "add'cond's 'rd, 'rn, 'shift_rm");
1823 // Format(instr, "add'cond's 'rd, 'rn, 'imm");
1824 alu_out = rn_val + shifter_operand;
1825 set_register(rd, alu_out);
1826 if (instr->HasS()) {
1827 SetNZFlags(alu_out);
1828 SetCFlag(CarryFrom(rn_val, shifter_operand));
1829 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, true));
1830 }
1831 break;
1832 }
1833
1834 case ADC: {
1835 Format(instr, "adc'cond's 'rd, 'rn, 'shift_rm");
1836 Format(instr, "adc'cond's 'rd, 'rn, 'imm");
1837 break;
1838 }
1839
1840 case SBC: {
1841 Format(instr, "sbc'cond's 'rd, 'rn, 'shift_rm");
1842 Format(instr, "sbc'cond's 'rd, 'rn, 'imm");
1843 break;
1844 }
1845
1846 case RSC: {
1847 Format(instr, "rsc'cond's 'rd, 'rn, 'shift_rm");
1848 Format(instr, "rsc'cond's 'rd, 'rn, 'imm");
1849 break;
1850 }
1851
1852 case TST: {
1853 if (instr->HasS()) {
1854 // Format(instr, "tst'cond 'rn, 'shift_rm");
1855 // Format(instr, "tst'cond 'rn, 'imm");
1856 alu_out = rn_val & shifter_operand;
1857 SetNZFlags(alu_out);
1858 SetCFlag(shifter_carry_out);
1859 } else {
1860 UNIMPLEMENTED();
1861 }
1862 break;
1863 }
1864
1865 case TEQ: {
1866 if (instr->HasS()) {
1867 // Format(instr, "teq'cond 'rn, 'shift_rm");
1868 // Format(instr, "teq'cond 'rn, 'imm");
1869 alu_out = rn_val ^ shifter_operand;
1870 SetNZFlags(alu_out);
1871 SetCFlag(shifter_carry_out);
1872 } else {
Steve Block6ded16b2010-05-10 14:33:55 +01001873 // Other instructions matching this pattern are handled in the
1874 // miscellaneous instructions part above.
1875 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +00001876 }
1877 break;
1878 }
1879
1880 case CMP: {
1881 if (instr->HasS()) {
1882 // Format(instr, "cmp'cond 'rn, 'shift_rm");
1883 // Format(instr, "cmp'cond 'rn, 'imm");
1884 alu_out = rn_val - shifter_operand;
1885 SetNZFlags(alu_out);
1886 SetCFlag(!BorrowFrom(rn_val, shifter_operand));
1887 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, false));
1888 } else {
1889 UNIMPLEMENTED();
1890 }
1891 break;
1892 }
1893
1894 case CMN: {
1895 if (instr->HasS()) {
1896 // Format(instr, "cmn'cond 'rn, 'shift_rm");
1897 // Format(instr, "cmn'cond 'rn, 'imm");
1898 alu_out = rn_val + shifter_operand;
1899 SetNZFlags(alu_out);
1900 SetCFlag(!CarryFrom(rn_val, shifter_operand));
1901 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, true));
1902 } else {
Steve Block6ded16b2010-05-10 14:33:55 +01001903 // Other instructions matching this pattern are handled in the
1904 // miscellaneous instructions part above.
1905 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +00001906 }
1907 break;
1908 }
1909
1910 case ORR: {
1911 // Format(instr, "orr'cond's 'rd, 'rn, 'shift_rm");
1912 // Format(instr, "orr'cond's 'rd, 'rn, 'imm");
1913 alu_out = rn_val | shifter_operand;
1914 set_register(rd, alu_out);
1915 if (instr->HasS()) {
1916 SetNZFlags(alu_out);
1917 SetCFlag(shifter_carry_out);
1918 }
1919 break;
1920 }
1921
1922 case MOV: {
1923 // Format(instr, "mov'cond's 'rd, 'shift_rm");
1924 // Format(instr, "mov'cond's 'rd, 'imm");
1925 alu_out = shifter_operand;
1926 set_register(rd, alu_out);
1927 if (instr->HasS()) {
1928 SetNZFlags(alu_out);
1929 SetCFlag(shifter_carry_out);
1930 }
1931 break;
1932 }
1933
1934 case BIC: {
1935 // Format(instr, "bic'cond's 'rd, 'rn, 'shift_rm");
1936 // Format(instr, "bic'cond's 'rd, 'rn, 'imm");
1937 alu_out = rn_val & ~shifter_operand;
1938 set_register(rd, alu_out);
1939 if (instr->HasS()) {
1940 SetNZFlags(alu_out);
1941 SetCFlag(shifter_carry_out);
1942 }
1943 break;
1944 }
1945
1946 case MVN: {
1947 // Format(instr, "mvn'cond's 'rd, 'shift_rm");
1948 // Format(instr, "mvn'cond's 'rd, 'imm");
1949 alu_out = ~shifter_operand;
1950 set_register(rd, alu_out);
1951 if (instr->HasS()) {
1952 SetNZFlags(alu_out);
1953 SetCFlag(shifter_carry_out);
1954 }
1955 break;
1956 }
1957
1958 default: {
1959 UNREACHABLE();
1960 break;
1961 }
1962 }
1963 }
1964}
1965
1966
1967void Simulator::DecodeType2(Instr* instr) {
1968 int rd = instr->RdField();
1969 int rn = instr->RnField();
1970 int32_t rn_val = get_register(rn);
1971 int32_t im_val = instr->Offset12Field();
1972 int32_t addr = 0;
1973 switch (instr->PUField()) {
1974 case 0: {
1975 // Format(instr, "'memop'cond'b 'rd, ['rn], #-'off12");
1976 ASSERT(!instr->HasW());
1977 addr = rn_val;
1978 rn_val -= im_val;
1979 set_register(rn, rn_val);
1980 break;
1981 }
1982 case 1: {
1983 // Format(instr, "'memop'cond'b 'rd, ['rn], #+'off12");
1984 ASSERT(!instr->HasW());
1985 addr = rn_val;
1986 rn_val += im_val;
1987 set_register(rn, rn_val);
1988 break;
1989 }
1990 case 2: {
1991 // Format(instr, "'memop'cond'b 'rd, ['rn, #-'off12]'w");
1992 rn_val -= im_val;
1993 addr = rn_val;
1994 if (instr->HasW()) {
1995 set_register(rn, rn_val);
1996 }
1997 break;
1998 }
1999 case 3: {
2000 // Format(instr, "'memop'cond'b 'rd, ['rn, #+'off12]'w");
2001 rn_val += im_val;
2002 addr = rn_val;
2003 if (instr->HasW()) {
2004 set_register(rn, rn_val);
2005 }
2006 break;
2007 }
2008 default: {
2009 UNREACHABLE();
2010 break;
2011 }
2012 }
2013 if (instr->HasB()) {
2014 if (instr->HasL()) {
2015 byte val = ReadBU(addr);
2016 set_register(rd, val);
2017 } else {
2018 byte val = get_register(rd);
2019 WriteB(addr, val);
2020 }
2021 } else {
2022 if (instr->HasL()) {
2023 set_register(rd, ReadW(addr, instr));
2024 } else {
2025 WriteW(addr, get_register(rd), instr);
2026 }
2027 }
2028}
2029
2030
2031void Simulator::DecodeType3(Instr* instr) {
Andrei Popescu31002712010-02-23 13:46:05 +00002032 ASSERT(instr->Bits(6, 4) == 0x5 || instr->Bit(4) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00002033 int rd = instr->RdField();
2034 int rn = instr->RnField();
2035 int32_t rn_val = get_register(rn);
2036 bool shifter_carry_out = 0;
2037 int32_t shifter_operand = GetShiftRm(instr, &shifter_carry_out);
2038 int32_t addr = 0;
2039 switch (instr->PUField()) {
2040 case 0: {
2041 ASSERT(!instr->HasW());
2042 Format(instr, "'memop'cond'b 'rd, ['rn], -'shift_rm");
2043 break;
2044 }
2045 case 1: {
2046 ASSERT(!instr->HasW());
2047 Format(instr, "'memop'cond'b 'rd, ['rn], +'shift_rm");
2048 break;
2049 }
2050 case 2: {
2051 // Format(instr, "'memop'cond'b 'rd, ['rn, -'shift_rm]'w");
2052 addr = rn_val - shifter_operand;
2053 if (instr->HasW()) {
2054 set_register(rn, addr);
2055 }
2056 break;
2057 }
2058 case 3: {
Steve Block6ded16b2010-05-10 14:33:55 +01002059 // UBFX.
Andrei Popescu31002712010-02-23 13:46:05 +00002060 if (instr->HasW() && (instr->Bits(6, 4) == 0x5)) {
2061 uint32_t widthminus1 = static_cast<uint32_t>(instr->Bits(20, 16));
2062 uint32_t lsbit = static_cast<uint32_t>(instr->ShiftAmountField());
2063 uint32_t msbit = widthminus1 + lsbit;
2064 if (msbit <= 31) {
2065 uint32_t rm_val =
2066 static_cast<uint32_t>(get_register(instr->RmField()));
2067 uint32_t extr_val = rm_val << (31 - msbit);
2068 extr_val = extr_val >> (31 - widthminus1);
2069 set_register(instr->RdField(), extr_val);
2070 } else {
2071 UNREACHABLE();
2072 }
2073 return;
2074 } else {
2075 // Format(instr, "'memop'cond'b 'rd, ['rn, +'shift_rm]'w");
2076 addr = rn_val + shifter_operand;
2077 if (instr->HasW()) {
2078 set_register(rn, addr);
2079 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002080 }
2081 break;
2082 }
2083 default: {
2084 UNREACHABLE();
2085 break;
2086 }
2087 }
2088 if (instr->HasB()) {
2089 if (instr->HasL()) {
2090 uint8_t byte = ReadB(addr);
2091 set_register(rd, byte);
2092 } else {
Andrei Popescu31002712010-02-23 13:46:05 +00002093 uint8_t byte = get_register(rd);
2094 WriteB(addr, byte);
Steve Blocka7e24c12009-10-30 11:49:00 +00002095 }
2096 } else {
2097 if (instr->HasL()) {
2098 set_register(rd, ReadW(addr, instr));
2099 } else {
2100 WriteW(addr, get_register(rd), instr);
2101 }
2102 }
2103}
2104
2105
2106void Simulator::DecodeType4(Instr* instr) {
2107 ASSERT(instr->Bit(22) == 0); // only allowed to be set in privileged mode
2108 if (instr->HasL()) {
2109 // Format(instr, "ldm'cond'pu 'rn'w, 'rlist");
2110 HandleRList(instr, true);
2111 } else {
2112 // Format(instr, "stm'cond'pu 'rn'w, 'rlist");
2113 HandleRList(instr, false);
2114 }
2115}
2116
2117
2118void Simulator::DecodeType5(Instr* instr) {
2119 // Format(instr, "b'l'cond 'target");
2120 int off = (instr->SImmed24Field() << 2);
2121 intptr_t pc_address = get_pc();
2122 if (instr->HasLink()) {
2123 set_register(lr, pc_address + Instr::kInstrSize);
2124 }
2125 int pc_reg = get_register(pc);
2126 set_pc(pc_reg + off);
2127}
2128
2129
2130void Simulator::DecodeType6(Instr* instr) {
Steve Blockd0582a62009-12-15 09:54:21 +00002131 DecodeType6CoprocessorIns(instr);
Steve Blocka7e24c12009-10-30 11:49:00 +00002132}
2133
2134
2135void Simulator::DecodeType7(Instr* instr) {
2136 if (instr->Bit(24) == 1) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002137 SoftwareInterrupt(instr);
2138 } else {
Steve Blockd0582a62009-12-15 09:54:21 +00002139 DecodeTypeVFP(instr);
Steve Blocka7e24c12009-10-30 11:49:00 +00002140 }
2141}
2142
2143
2144void Simulator::DecodeUnconditional(Instr* instr) {
2145 if (instr->Bits(7, 4) == 0x0B && instr->Bits(27, 25) == 0 && instr->HasL()) {
2146 // Load halfword instruction, either register or immediate offset.
2147 int rd = instr->RdField();
2148 int rn = instr->RnField();
2149 int32_t rn_val = get_register(rn);
2150 int32_t addr = 0;
2151 int32_t offset;
2152 if (instr->Bit(22) == 0) {
2153 // Register offset.
2154 int rm = instr->RmField();
2155 offset = get_register(rm);
2156 } else {
2157 // Immediate offset
2158 offset = instr->Bits(3, 0) + (instr->Bits(11, 8) << 4);
2159 }
2160 switch (instr->PUField()) {
2161 case 0: {
2162 // Post index, negative.
2163 ASSERT(!instr->HasW());
2164 addr = rn_val;
2165 rn_val -= offset;
2166 set_register(rn, rn_val);
2167 break;
2168 }
2169 case 1: {
2170 // Post index, positive.
2171 ASSERT(!instr->HasW());
2172 addr = rn_val;
2173 rn_val += offset;
2174 set_register(rn, rn_val);
2175 break;
2176 }
2177 case 2: {
2178 // Pre index or offset, negative.
2179 rn_val -= offset;
2180 addr = rn_val;
2181 if (instr->HasW()) {
2182 set_register(rn, rn_val);
2183 }
2184 break;
2185 }
2186 case 3: {
2187 // Pre index or offset, positive.
2188 rn_val += offset;
2189 addr = rn_val;
2190 if (instr->HasW()) {
2191 set_register(rn, rn_val);
2192 }
2193 break;
2194 }
2195 default: {
2196 // The PU field is a 2-bit field.
2197 UNREACHABLE();
2198 break;
2199 }
2200 }
2201 // Not sign extending, so load as unsigned.
2202 uint16_t halfword = ReadH(addr, instr);
2203 set_register(rd, halfword);
2204 } else {
2205 Debugger dbg(this);
2206 dbg.Stop(instr);
2207 }
2208}
2209
2210
Steve Block6ded16b2010-05-10 14:33:55 +01002211// Depending on value of last_bit flag glue register code from vm and m values
2212// (where m is expected to be a single bit).
2213static int GlueRegCode(bool last_bit, int vm, int m) {
2214 return last_bit ? ((vm << 1) | m) : ((m << 4) | vm);
2215}
2216
2217
Steve Blockd0582a62009-12-15 09:54:21 +00002218// void Simulator::DecodeTypeVFP(Instr* instr)
2219// The Following ARMv7 VFPv instructions are currently supported.
Leon Clarkee46be812010-01-19 14:06:41 +00002220// vmov :Sn = Rt
2221// vmov :Rt = Sn
2222// vcvt: Dd = Sm
2223// vcvt: Sd = Dm
2224// Dd = vadd(Dn, Dm)
2225// Dd = vsub(Dn, Dm)
2226// Dd = vmul(Dn, Dm)
2227// Dd = vdiv(Dn, Dm)
Steve Blockd0582a62009-12-15 09:54:21 +00002228// vcmp(Dd, Dm)
2229// VMRS
2230void Simulator::DecodeTypeVFP(Instr* instr) {
2231 ASSERT((instr->TypeField() == 7) && (instr->Bit(24) == 0x0) );
Steve Block6ded16b2010-05-10 14:33:55 +01002232 ASSERT(instr->Bits(11, 9) == 0x5);
Steve Blockd0582a62009-12-15 09:54:21 +00002233
Steve Blockd0582a62009-12-15 09:54:21 +00002234 int vm = instr->VmField();
Steve Blockd0582a62009-12-15 09:54:21 +00002235 int vd = instr->VdField();
Steve Block6ded16b2010-05-10 14:33:55 +01002236 int vn = instr->VnField();
Steve Blockd0582a62009-12-15 09:54:21 +00002237
Steve Block6ded16b2010-05-10 14:33:55 +01002238 if (instr->Bit(4) == 0) {
2239 if (instr->Opc1Field() == 0x7) {
2240 // Other data processing instructions
2241 if ((instr->Opc2Field() == 0x7) && (instr->Opc3Field() == 0x3)) {
2242 DecodeVCVTBetweenDoubleAndSingle(instr);
2243 } else if ((instr->Opc2Field() == 0x8) && (instr->Opc3Field() & 0x1)) {
2244 DecodeVCVTBetweenFloatingPointAndInteger(instr);
2245 } else if (((instr->Opc2Field() >> 1) == 0x6) &&
2246 (instr->Opc3Field() & 0x1)) {
2247 DecodeVCVTBetweenFloatingPointAndInteger(instr);
2248 } else if (((instr->Opc2Field() == 0x4) || (instr->Opc2Field() == 0x5)) &&
2249 (instr->Opc3Field() & 0x1)) {
2250 DecodeVCMP(instr);
2251 } else {
2252 UNREACHABLE(); // Not used by V8.
2253 }
2254 } else if (instr->Opc1Field() == 0x3) {
2255 if (instr->SzField() != 0x1) {
2256 UNREACHABLE(); // Not used by V8.
2257 }
2258
2259 if (instr->Opc3Field() & 0x1) {
2260 // vsub
2261 double dn_value = get_double_from_d_register(vn);
2262 double dm_value = get_double_from_d_register(vm);
2263 double dd_value = dn_value - dm_value;
2264 set_d_register_from_double(vd, dd_value);
2265 } else {
2266 // vadd
2267 double dn_value = get_double_from_d_register(vn);
2268 double dm_value = get_double_from_d_register(vm);
2269 double dd_value = dn_value + dm_value;
2270 set_d_register_from_double(vd, dd_value);
2271 }
2272 } else if ((instr->Opc1Field() == 0x2) && !(instr->Opc3Field() & 0x1)) {
2273 // vmul
2274 if (instr->SzField() != 0x1) {
2275 UNREACHABLE(); // Not used by V8.
2276 }
2277
2278 double dn_value = get_double_from_d_register(vn);
2279 double dm_value = get_double_from_d_register(vm);
2280 double dd_value = dn_value * dm_value;
2281 set_d_register_from_double(vd, dd_value);
2282 } else if ((instr->Opc1Field() == 0x4) && !(instr->Opc3Field() & 0x1)) {
2283 // vdiv
2284 if (instr->SzField() != 0x1) {
2285 UNREACHABLE(); // Not used by V8.
2286 }
2287
Steve Blockd0582a62009-12-15 09:54:21 +00002288 double dn_value = get_double_from_d_register(vn);
2289 double dm_value = get_double_from_d_register(vm);
2290 double dd_value = dn_value / dm_value;
2291 set_d_register_from_double(vd, dd_value);
Steve Block6ded16b2010-05-10 14:33:55 +01002292 } else {
2293 UNIMPLEMENTED(); // Not used by V8.
2294 }
2295 } else {
2296 if ((instr->VCField() == 0x0) &&
2297 (instr->VAField() == 0x0)) {
2298 DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(instr);
2299 } else if ((instr->VLField() == 0x1) &&
2300 (instr->VCField() == 0x0) &&
2301 (instr->VAField() == 0x7) &&
2302 (instr->Bits(19, 16) == 0x1)) {
2303 // vmrs
2304 if (instr->RtField() == 0xF)
Steve Blockd0582a62009-12-15 09:54:21 +00002305 Copy_FPSCR_to_APSR();
2306 else
2307 UNIMPLEMENTED(); // Not used by V8.
2308 } else {
2309 UNIMPLEMENTED(); // Not used by V8.
2310 }
Steve Block6ded16b2010-05-10 14:33:55 +01002311 }
2312}
2313
2314
2315void Simulator::DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(Instr* instr) {
2316 ASSERT((instr->Bit(4) == 1) && (instr->VCField() == 0x0) &&
2317 (instr->VAField() == 0x0));
2318
2319 int t = instr->RtField();
2320 int n = GlueRegCode(true, instr->VnField(), instr->NField());
2321 bool to_arm_register = (instr->VLField() == 0x1);
2322
2323 if (to_arm_register) {
2324 int32_t int_value = get_sinteger_from_s_register(n);
2325 set_register(t, int_value);
2326 } else {
2327 int32_t rs_val = get_register(t);
2328 set_s_register_from_sinteger(n, rs_val);
2329 }
2330}
2331
2332
2333void Simulator::DecodeVCMP(Instr* instr) {
2334 ASSERT((instr->Bit(4) == 0) && (instr->Opc1Field() == 0x7));
2335 ASSERT(((instr->Opc2Field() == 0x4) || (instr->Opc2Field() == 0x5)) &&
2336 (instr->Opc3Field() & 0x1));
2337
2338 // Comparison.
2339 bool dp_operation = (instr->SzField() == 1);
2340
2341 if (instr->Bit(7) != 0) {
2342 // Raising exceptions for quiet NaNs are not supported.
2343 UNIMPLEMENTED(); // Not used by V8.
2344 }
2345
2346 int d = GlueRegCode(!dp_operation, instr->VdField(), instr->DField());
2347 int m = GlueRegCode(!dp_operation, instr->VmField(), instr->MField());
2348
2349 if (dp_operation) {
2350 double dd_value = get_double_from_d_register(d);
2351 double dm_value = get_double_from_d_register(m);
2352
2353 Compute_FPSCR_Flags(dd_value, dm_value);
2354 } else {
2355 UNIMPLEMENTED(); // Not used by V8.
2356 }
2357}
2358
2359
2360void Simulator::DecodeVCVTBetweenDoubleAndSingle(Instr* instr) {
2361 ASSERT((instr->Bit(4) == 0) && (instr->Opc1Field() == 0x7));
2362 ASSERT((instr->Opc2Field() == 0x7) && (instr->Opc3Field() == 0x3));
2363
2364 bool double_to_single = (instr->SzField() == 1);
2365 int dst = GlueRegCode(double_to_single, instr->VdField(), instr->DField());
2366 int src = GlueRegCode(!double_to_single, instr->VmField(), instr->MField());
2367
2368 if (double_to_single) {
2369 double val = get_double_from_d_register(src);
2370 set_s_register_from_float(dst, static_cast<float>(val));
2371 } else {
2372 float val = get_float_from_s_register(src);
2373 set_d_register_from_double(dst, static_cast<double>(val));
2374 }
2375}
2376
2377
2378void Simulator::DecodeVCVTBetweenFloatingPointAndInteger(Instr* instr) {
2379 ASSERT((instr->Bit(4) == 0) && (instr->Opc1Field() == 0x7));
2380 ASSERT(((instr->Opc2Field() == 0x8) && (instr->Opc3Field() & 0x1)) ||
2381 (((instr->Opc2Field() >> 1) == 0x6) && (instr->Opc3Field() & 0x1)));
2382
2383 // Conversion between floating-point and integer.
2384 int vd = instr->VdField();
2385 int d = instr->DField();
2386 int vm = instr->VmField();
2387 int m = instr->MField();
2388
2389 bool to_integer = (instr->Bit(18) == 1);
2390 bool dp_operation = (instr->SzField() == 1);
2391 if (to_integer) {
2392 bool unsigned_integer = (instr->Bit(16) == 0);
2393 if (instr->Bit(7) != 1) {
2394 // Only rounding towards zero supported.
Steve Blockd0582a62009-12-15 09:54:21 +00002395 UNIMPLEMENTED(); // Not used by V8.
2396 }
Steve Block6ded16b2010-05-10 14:33:55 +01002397
2398 int dst = GlueRegCode(true, vd, d);
2399 int src = GlueRegCode(!dp_operation, vm, m);
2400
2401 if (dp_operation) {
2402 double val = get_double_from_d_register(src);
2403
2404 int sint = unsigned_integer ? static_cast<uint32_t>(val) :
2405 static_cast<int32_t>(val);
2406
2407 set_s_register_from_sinteger(dst, sint);
Steve Blockd0582a62009-12-15 09:54:21 +00002408 } else {
Steve Block6ded16b2010-05-10 14:33:55 +01002409 float val = get_float_from_s_register(src);
2410
2411 int sint = unsigned_integer ? static_cast<uint32_t>(val) :
2412 static_cast<int32_t>(val);
2413
2414 set_s_register_from_sinteger(dst, sint);
2415 }
2416 } else {
2417 bool unsigned_integer = (instr->Bit(7) == 0);
2418
2419 int dst = GlueRegCode(!dp_operation, vd, d);
2420 int src = GlueRegCode(true, vm, m);
2421
2422 int val = get_sinteger_from_s_register(src);
2423
2424 if (dp_operation) {
2425 if (unsigned_integer) {
2426 set_d_register_from_double(dst,
2427 static_cast<double>((uint32_t)val));
2428 } else {
2429 set_d_register_from_double(dst, static_cast<double>(val));
2430 }
2431 } else {
2432 if (unsigned_integer) {
2433 set_s_register_from_float(dst,
2434 static_cast<float>((uint32_t)val));
2435 } else {
2436 set_s_register_from_float(dst, static_cast<float>(val));
2437 }
Steve Blockd0582a62009-12-15 09:54:21 +00002438 }
2439 }
2440}
2441
2442
2443// void Simulator::DecodeType6CoprocessorIns(Instr* instr)
2444// Decode Type 6 coprocessor instructions.
Leon Clarkee46be812010-01-19 14:06:41 +00002445// Dm = vmov(Rt, Rt2)
2446// <Rt, Rt2> = vmov(Dm)
Leon Clarked91b9f72010-01-27 17:25:45 +00002447// Ddst = MEM(Rbase + 4*offset).
2448// MEM(Rbase + 4*offset) = Dsrc.
Steve Blockd0582a62009-12-15 09:54:21 +00002449void Simulator::DecodeType6CoprocessorIns(Instr* instr) {
2450 ASSERT((instr->TypeField() == 6));
2451
Steve Block6ded16b2010-05-10 14:33:55 +01002452 if (instr->CoprocessorField() == 0xA) {
2453 switch (instr->OpcodeField()) {
2454 case 0x8:
2455 case 0xC: { // Load and store float to memory.
2456 int rn = instr->RnField();
2457 int vd = instr->VdField();
2458 int offset = instr->Immed8Field();
2459 if (!instr->HasU()) {
2460 offset = -offset;
2461 }
2462
2463 int32_t address = get_register(rn) + 4 * offset;
2464 if (instr->HasL()) {
2465 // Load double from memory: vldr.
2466 set_s_register_from_sinteger(vd, ReadW(address, instr));
2467 } else {
2468 // Store double to memory: vstr.
2469 WriteW(address, get_sinteger_from_s_register(vd), instr);
2470 }
2471 break;
2472 }
2473 default:
2474 UNIMPLEMENTED(); // Not used by V8.
2475 break;
2476 }
2477 } else if (instr->CoprocessorField() == 0xB) {
Leon Clarked91b9f72010-01-27 17:25:45 +00002478 switch (instr->OpcodeField()) {
2479 case 0x2:
2480 // Load and store double to two GP registers
2481 if (instr->Bits(7, 4) != 0x1) {
2482 UNIMPLEMENTED(); // Not used by V8.
2483 } else {
2484 int rt = instr->RtField();
2485 int rn = instr->RnField();
2486 int vm = instr->VmField();
2487 if (instr->HasL()) {
2488 int32_t rt_int_value = get_sinteger_from_s_register(2*vm);
2489 int32_t rn_int_value = get_sinteger_from_s_register(2*vm+1);
2490
2491 set_register(rt, rt_int_value);
2492 set_register(rn, rn_int_value);
2493 } else {
2494 int32_t rs_val = get_register(rt);
2495 int32_t rn_val = get_register(rn);
2496
2497 set_s_register_from_sinteger(2*vm, rs_val);
2498 set_s_register_from_sinteger((2*vm+1), rn_val);
2499 }
2500 }
2501 break;
2502 case 0x8:
2503 case 0xC: { // Load and store double to memory.
2504 int rn = instr->RnField();
2505 int vd = instr->VdField();
2506 int offset = instr->Immed8Field();
2507 if (!instr->HasU()) {
2508 offset = -offset;
2509 }
2510 int32_t address = get_register(rn) + 4 * offset;
2511 if (instr->HasL()) {
2512 // Load double from memory: vldr.
2513 set_s_register_from_sinteger(2*vd, ReadW(address, instr));
2514 set_s_register_from_sinteger(2*vd + 1, ReadW(address + 4, instr));
2515 } else {
2516 // Store double to memory: vstr.
2517 WriteW(address, get_sinteger_from_s_register(2*vd), instr);
2518 WriteW(address + 4, get_sinteger_from_s_register(2*vd + 1), instr);
2519 }
2520 break;
2521 }
2522 default:
2523 UNIMPLEMENTED(); // Not used by V8.
2524 break;
2525 }
Steve Block6ded16b2010-05-10 14:33:55 +01002526 } else {
2527 UNIMPLEMENTED(); // Not used by V8.
Steve Blockd0582a62009-12-15 09:54:21 +00002528 }
2529}
2530
2531
Steve Blocka7e24c12009-10-30 11:49:00 +00002532// Executes the current instruction.
2533void Simulator::InstructionDecode(Instr* instr) {
Steve Block6ded16b2010-05-10 14:33:55 +01002534 if (v8::internal::FLAG_check_icache) {
2535 CheckICache(instr);
2536 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002537 pc_modified_ = false;
2538 if (::v8::internal::FLAG_trace_sim) {
2539 disasm::NameConverter converter;
2540 disasm::Disassembler dasm(converter);
2541 // use a reasonably large buffer
2542 v8::internal::EmbeddedVector<char, 256> buffer;
2543 dasm.InstructionDecode(buffer,
2544 reinterpret_cast<byte*>(instr));
2545 PrintF(" 0x%08x %s\n", instr, buffer.start());
2546 }
2547 if (instr->ConditionField() == special_condition) {
2548 DecodeUnconditional(instr);
2549 } else if (ConditionallyExecute(instr)) {
2550 switch (instr->TypeField()) {
2551 case 0:
2552 case 1: {
2553 DecodeType01(instr);
2554 break;
2555 }
2556 case 2: {
2557 DecodeType2(instr);
2558 break;
2559 }
2560 case 3: {
2561 DecodeType3(instr);
2562 break;
2563 }
2564 case 4: {
2565 DecodeType4(instr);
2566 break;
2567 }
2568 case 5: {
2569 DecodeType5(instr);
2570 break;
2571 }
2572 case 6: {
2573 DecodeType6(instr);
2574 break;
2575 }
2576 case 7: {
2577 DecodeType7(instr);
2578 break;
2579 }
2580 default: {
2581 UNIMPLEMENTED();
2582 break;
2583 }
2584 }
2585 }
2586 if (!pc_modified_) {
2587 set_register(pc, reinterpret_cast<int32_t>(instr) + Instr::kInstrSize);
2588 }
2589}
2590
2591
Steve Blocka7e24c12009-10-30 11:49:00 +00002592void Simulator::Execute() {
2593 // Get the PC to simulate. Cannot use the accessor here as we need the
2594 // raw PC value and not the one used as input to arithmetic instructions.
2595 int program_counter = get_pc();
2596
2597 if (::v8::internal::FLAG_stop_sim_at == 0) {
2598 // Fast version of the dispatch loop without checking whether the simulator
2599 // should be stopping at a particular executed instruction.
2600 while (program_counter != end_sim_pc) {
2601 Instr* instr = reinterpret_cast<Instr*>(program_counter);
2602 icount_++;
2603 InstructionDecode(instr);
2604 program_counter = get_pc();
2605 }
2606 } else {
2607 // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when
2608 // we reach the particular instuction count.
2609 while (program_counter != end_sim_pc) {
2610 Instr* instr = reinterpret_cast<Instr*>(program_counter);
2611 icount_++;
2612 if (icount_ == ::v8::internal::FLAG_stop_sim_at) {
2613 Debugger dbg(this);
2614 dbg.Debug();
2615 } else {
2616 InstructionDecode(instr);
2617 }
2618 program_counter = get_pc();
2619 }
2620 }
2621}
2622
2623
2624int32_t Simulator::Call(byte* entry, int argument_count, ...) {
2625 va_list parameters;
2626 va_start(parameters, argument_count);
2627 // Setup arguments
2628
2629 // First four arguments passed in registers.
2630 ASSERT(argument_count >= 4);
2631 set_register(r0, va_arg(parameters, int32_t));
2632 set_register(r1, va_arg(parameters, int32_t));
2633 set_register(r2, va_arg(parameters, int32_t));
2634 set_register(r3, va_arg(parameters, int32_t));
2635
2636 // Remaining arguments passed on stack.
2637 int original_stack = get_register(sp);
2638 // Compute position of stack on entry to generated code.
2639 int entry_stack = (original_stack - (argument_count - 4) * sizeof(int32_t));
2640 if (OS::ActivationFrameAlignment() != 0) {
2641 entry_stack &= -OS::ActivationFrameAlignment();
2642 }
2643 // Store remaining arguments on stack, from low to high memory.
2644 intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
2645 for (int i = 4; i < argument_count; i++) {
2646 stack_argument[i - 4] = va_arg(parameters, int32_t);
2647 }
2648 va_end(parameters);
2649 set_register(sp, entry_stack);
2650
2651 // Prepare to execute the code at entry
2652 set_register(pc, reinterpret_cast<int32_t>(entry));
2653 // Put down marker for end of simulation. The simulator will stop simulation
2654 // when the PC reaches this value. By saving the "end simulation" value into
2655 // the LR the simulation stops when returning to this call point.
2656 set_register(lr, end_sim_pc);
2657
2658 // Remember the values of callee-saved registers.
2659 // The code below assumes that r9 is not used as sb (static base) in
2660 // simulator code and therefore is regarded as a callee-saved register.
2661 int32_t r4_val = get_register(r4);
2662 int32_t r5_val = get_register(r5);
2663 int32_t r6_val = get_register(r6);
2664 int32_t r7_val = get_register(r7);
2665 int32_t r8_val = get_register(r8);
2666 int32_t r9_val = get_register(r9);
2667 int32_t r10_val = get_register(r10);
2668 int32_t r11_val = get_register(r11);
2669
2670 // Setup the callee-saved registers with a known value. To be able to check
2671 // that they are preserved properly across JS execution.
2672 int32_t callee_saved_value = icount_;
2673 set_register(r4, callee_saved_value);
2674 set_register(r5, callee_saved_value);
2675 set_register(r6, callee_saved_value);
2676 set_register(r7, callee_saved_value);
2677 set_register(r8, callee_saved_value);
2678 set_register(r9, callee_saved_value);
2679 set_register(r10, callee_saved_value);
2680 set_register(r11, callee_saved_value);
2681
2682 // Start the simulation
2683 Execute();
2684
2685 // Check that the callee-saved registers have been preserved.
2686 CHECK_EQ(callee_saved_value, get_register(r4));
2687 CHECK_EQ(callee_saved_value, get_register(r5));
2688 CHECK_EQ(callee_saved_value, get_register(r6));
2689 CHECK_EQ(callee_saved_value, get_register(r7));
2690 CHECK_EQ(callee_saved_value, get_register(r8));
2691 CHECK_EQ(callee_saved_value, get_register(r9));
2692 CHECK_EQ(callee_saved_value, get_register(r10));
2693 CHECK_EQ(callee_saved_value, get_register(r11));
2694
2695 // Restore callee-saved registers with the original value.
2696 set_register(r4, r4_val);
2697 set_register(r5, r5_val);
2698 set_register(r6, r6_val);
2699 set_register(r7, r7_val);
2700 set_register(r8, r8_val);
2701 set_register(r9, r9_val);
2702 set_register(r10, r10_val);
2703 set_register(r11, r11_val);
2704
2705 // Pop stack passed arguments.
2706 CHECK_EQ(entry_stack, get_register(sp));
2707 set_register(sp, original_stack);
2708
2709 int32_t result = get_register(r0);
2710 return result;
2711}
2712
Steve Blockd0582a62009-12-15 09:54:21 +00002713
2714uintptr_t Simulator::PushAddress(uintptr_t address) {
2715 int new_sp = get_register(sp) - sizeof(uintptr_t);
2716 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp);
2717 *stack_slot = address;
2718 set_register(sp, new_sp);
2719 return new_sp;
2720}
2721
2722
2723uintptr_t Simulator::PopAddress() {
2724 int current_sp = get_register(sp);
2725 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp);
2726 uintptr_t address = *stack_slot;
2727 set_register(sp, current_sp + sizeof(uintptr_t));
2728 return address;
2729}
2730
Steve Blocka7e24c12009-10-30 11:49:00 +00002731} } // namespace assembler::arm
2732
Steve Block6ded16b2010-05-10 14:33:55 +01002733#endif // __arm__