1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <stdarg.h>
6 #include <stdlib.h>
7 #include <cmath>
8
9 #if V8_TARGET_ARCH_ARM
10
11 #include "src/arm/constants-arm.h"
12 #include "src/arm/simulator-arm.h"
13 #include "src/assembler.h"
14 #include "src/base/bits.h"
15 #include "src/codegen.h"
16 #include "src/disasm.h"
17 #include "src/runtime/runtime-utils.h"
18
19 #if defined(USE_SIMULATOR)
20
21 // Only build the simulator if not compiling for real ARM hardware.
22 namespace v8 {
23 namespace internal {
24
25 // This macro provides a platform independent use of sscanf. The reason for
26 // SScanF not being implemented in a platform independent way through
27 // ::v8::internal::OS in the same way as SNPrintF is that the
28 // Windows C Run-Time Library does not provide vsscanf.
29 #define SScanF sscanf // NOLINT
30
31 // The ArmDebugger class is used by the simulator while debugging simulated ARM
32 // code.
33 class ArmDebugger {
34 public:
ArmDebugger(Simulator * sim)35 explicit ArmDebugger(Simulator* sim) : sim_(sim) { }
36
37 void Stop(Instruction* instr);
38 void Debug();
39
40 private:
41 static const Instr kBreakpointInstr =
42 (al | (7*B25) | (1*B24) | kBreakpoint);
43 static const Instr kNopInstr = (al | (13*B21));
44
45 Simulator* sim_;
46
47 int32_t GetRegisterValue(int regnum);
48 double GetRegisterPairDoubleValue(int regnum);
49 double GetVFPDoubleRegisterValue(int regnum);
50 bool GetValue(const char* desc, int32_t* value);
51 bool GetVFPSingleValue(const char* desc, float* value);
52 bool GetVFPDoubleValue(const char* desc, double* value);
53
54 // Set or delete a breakpoint. Returns true if successful.
55 bool SetBreakpoint(Instruction* breakpc);
56 bool DeleteBreakpoint(Instruction* breakpc);
57
58 // Undo and redo all breakpoints. This is needed to bracket disassembly and
59 // execution to skip past breakpoints when run from the debugger.
60 void UndoBreakpoints();
61 void RedoBreakpoints();
62 };
63
Stop(Instruction * instr)64 void ArmDebugger::Stop(Instruction* instr) {
65 // Get the stop code.
66 uint32_t code = instr->SvcValue() & kStopCodeMask;
67 // Print the stop message and code if it is not the default code.
68 if (code != kMaxStopCode) {
69 PrintF("Simulator hit stop %u\n", code);
70 } else {
71 PrintF("Simulator hit\n");
72 }
73 sim_->set_pc(sim_->get_pc() + 2 * Instruction::kInstrSize);
74 Debug();
75 }
76
GetRegisterValue(int regnum)77 int32_t ArmDebugger::GetRegisterValue(int regnum) {
78 if (regnum == kPCRegister) {
79 return sim_->get_pc();
80 } else {
81 return sim_->get_register(regnum);
82 }
83 }
84
GetRegisterPairDoubleValue(int regnum)85 double ArmDebugger::GetRegisterPairDoubleValue(int regnum) {
86 return sim_->get_double_from_register_pair(regnum);
87 }
88
89
GetVFPDoubleRegisterValue(int regnum)90 double ArmDebugger::GetVFPDoubleRegisterValue(int regnum) {
91 return sim_->get_double_from_d_register(regnum);
92 }
93
94
GetValue(const char * desc,int32_t * value)95 bool ArmDebugger::GetValue(const char* desc, int32_t* value) {
96 int regnum = Registers::Number(desc);
97 if (regnum != kNoRegister) {
98 *value = GetRegisterValue(regnum);
99 return true;
100 } else {
101 if (strncmp(desc, "0x", 2) == 0) {
102 return SScanF(desc + 2, "%x", reinterpret_cast<uint32_t*>(value)) == 1;
103 } else {
104 return SScanF(desc, "%u", reinterpret_cast<uint32_t*>(value)) == 1;
105 }
106 }
107 return false;
108 }
109
110
GetVFPSingleValue(const char * desc,float * value)111 bool ArmDebugger::GetVFPSingleValue(const char* desc, float* value) {
112 bool is_double;
113 int regnum = VFPRegisters::Number(desc, &is_double);
114 if (regnum != kNoRegister && !is_double) {
115 *value = sim_->get_float_from_s_register(regnum);
116 return true;
117 }
118 return false;
119 }
120
121
GetVFPDoubleValue(const char * desc,double * value)122 bool ArmDebugger::GetVFPDoubleValue(const char* desc, double* value) {
123 bool is_double;
124 int regnum = VFPRegisters::Number(desc, &is_double);
125 if (regnum != kNoRegister && is_double) {
126 *value = sim_->get_double_from_d_register(regnum);
127 return true;
128 }
129 return false;
130 }
131
132
SetBreakpoint(Instruction * breakpc)133 bool ArmDebugger::SetBreakpoint(Instruction* breakpc) {
134 // Check if a breakpoint can be set. If not return without any side-effects.
135 if (sim_->break_pc_ != NULL) {
136 return false;
137 }
138
139 // Set the breakpoint.
140 sim_->break_pc_ = breakpc;
141 sim_->break_instr_ = breakpc->InstructionBits();
142 // Not setting the breakpoint instruction in the code itself. It will be set
143 // when the debugger shell continues.
144 return true;
145 }
146
147
DeleteBreakpoint(Instruction * breakpc)148 bool ArmDebugger::DeleteBreakpoint(Instruction* breakpc) {
149 if (sim_->break_pc_ != NULL) {
150 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
151 }
152
153 sim_->break_pc_ = NULL;
154 sim_->break_instr_ = 0;
155 return true;
156 }
157
158
UndoBreakpoints()159 void ArmDebugger::UndoBreakpoints() {
160 if (sim_->break_pc_ != NULL) {
161 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
162 }
163 }
164
165
RedoBreakpoints()166 void ArmDebugger::RedoBreakpoints() {
167 if (sim_->break_pc_ != NULL) {
168 sim_->break_pc_->SetInstructionBits(kBreakpointInstr);
169 }
170 }
171
172
Debug()173 void ArmDebugger::Debug() {
174 intptr_t last_pc = -1;
175 bool done = false;
176
177 #define COMMAND_SIZE 63
178 #define ARG_SIZE 255
179
180 #define STR(a) #a
181 #define XSTR(a) STR(a)
182
183 char cmd[COMMAND_SIZE + 1];
184 char arg1[ARG_SIZE + 1];
185 char arg2[ARG_SIZE + 1];
186 char* argv[3] = { cmd, arg1, arg2 };
187
188 // make sure to have a proper terminating character if reaching the limit
189 cmd[COMMAND_SIZE] = 0;
190 arg1[ARG_SIZE] = 0;
191 arg2[ARG_SIZE] = 0;
192
193 // Undo all set breakpoints while running in the debugger shell. This will
194 // make them invisible to all commands.
195 UndoBreakpoints();
196
197 while (!done && !sim_->has_bad_pc()) {
198 if (last_pc != sim_->get_pc()) {
199 disasm::NameConverter converter;
200 disasm::Disassembler dasm(converter);
201 // use a reasonably large buffer
202 v8::internal::EmbeddedVector<char, 256> buffer;
203 dasm.InstructionDecode(buffer,
204 reinterpret_cast<byte*>(sim_->get_pc()));
205 PrintF(" 0x%08x %s\n", sim_->get_pc(), buffer.start());
206 last_pc = sim_->get_pc();
207 }
208 char* line = ReadLine("sim> ");
209 if (line == NULL) {
210 break;
211 } else {
212 char* last_input = sim_->last_debugger_input();
213 if (strcmp(line, "\n") == 0 && last_input != NULL) {
214 line = last_input;
215 } else {
216 // Ownership is transferred to sim_;
217 sim_->set_last_debugger_input(line);
218 }
219 // Use sscanf to parse the individual parts of the command line. At the
220 // moment no command expects more than two parameters.
221 int argc = SScanF(line,
222 "%" XSTR(COMMAND_SIZE) "s "
223 "%" XSTR(ARG_SIZE) "s "
224 "%" XSTR(ARG_SIZE) "s",
225 cmd, arg1, arg2);
226 if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
227 sim_->InstructionDecode(reinterpret_cast<Instruction*>(sim_->get_pc()));
228 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) {
229 // Execute the one instruction we broke at with breakpoints disabled.
230 sim_->InstructionDecode(reinterpret_cast<Instruction*>(sim_->get_pc()));
231 // Leave the debugger shell.
232 done = true;
233 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
234 if (argc == 2 || (argc == 3 && strcmp(arg2, "fp") == 0)) {
235 int32_t value;
236 float svalue;
237 double dvalue;
238 if (strcmp(arg1, "all") == 0) {
239 for (int i = 0; i < kNumRegisters; i++) {
240 value = GetRegisterValue(i);
241 PrintF(
242 "%3s: 0x%08x %10d",
243 RegisterConfiguration::Crankshaft()->GetGeneralRegisterName(
244 i),
245 value, value);
246 if ((argc == 3 && strcmp(arg2, "fp") == 0) &&
247 i < 8 &&
248 (i % 2) == 0) {
249 dvalue = GetRegisterPairDoubleValue(i);
250 PrintF(" (%f)\n", dvalue);
251 } else {
252 PrintF("\n");
253 }
254 }
255 for (int i = 0; i < DwVfpRegister::NumRegisters(); i++) {
256 dvalue = GetVFPDoubleRegisterValue(i);
257 uint64_t as_words = bit_cast<uint64_t>(dvalue);
258 PrintF("%3s: %f 0x%08x %08x\n",
259 VFPRegisters::Name(i, true),
260 dvalue,
261 static_cast<uint32_t>(as_words >> 32),
262 static_cast<uint32_t>(as_words & 0xffffffff));
263 }
264 } else {
265 if (GetValue(arg1, &value)) {
266 PrintF("%s: 0x%08x %d \n", arg1, value, value);
267 } else if (GetVFPSingleValue(arg1, &svalue)) {
268 uint32_t as_word = bit_cast<uint32_t>(svalue);
269 PrintF("%s: %f 0x%08x\n", arg1, svalue, as_word);
270 } else if (GetVFPDoubleValue(arg1, &dvalue)) {
271 uint64_t as_words = bit_cast<uint64_t>(dvalue);
272 PrintF("%s: %f 0x%08x %08x\n",
273 arg1,
274 dvalue,
275 static_cast<uint32_t>(as_words >> 32),
276 static_cast<uint32_t>(as_words & 0xffffffff));
277 } else {
278 PrintF("%s unrecognized\n", arg1);
279 }
280 }
281 } else {
282 PrintF("print <register>\n");
283 }
284 } else if ((strcmp(cmd, "po") == 0)
285 || (strcmp(cmd, "printobject") == 0)) {
286 if (argc == 2) {
287 int32_t value;
288 OFStream os(stdout);
289 if (GetValue(arg1, &value)) {
290 Object* obj = reinterpret_cast<Object*>(value);
291 os << arg1 << ": \n";
292 #ifdef DEBUG
293 obj->Print(os);
294 os << "\n";
295 #else
296 os << Brief(obj) << "\n";
297 #endif
298 } else {
299 os << arg1 << " unrecognized\n";
300 }
301 } else {
302 PrintF("printobject <value>\n");
303 }
304 } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0) {
305 int32_t* cur = NULL;
306 int32_t* end = NULL;
307 int next_arg = 1;
308
309 if (strcmp(cmd, "stack") == 0) {
310 cur = reinterpret_cast<int32_t*>(sim_->get_register(Simulator::sp));
311 } else { // "mem"
312 int32_t value;
313 if (!GetValue(arg1, &value)) {
314 PrintF("%s unrecognized\n", arg1);
315 continue;
316 }
317 cur = reinterpret_cast<int32_t*>(value);
318 next_arg++;
319 }
320
321 int32_t words;
322 if (argc == next_arg) {
323 words = 10;
324 } else {
325 if (!GetValue(argv[next_arg], &words)) {
326 words = 10;
327 }
328 }
329 end = cur + words;
330
331 while (cur < end) {
332 PrintF(" 0x%08" V8PRIxPTR ": 0x%08x %10d",
333 reinterpret_cast<intptr_t>(cur), *cur, *cur);
334 HeapObject* obj = reinterpret_cast<HeapObject*>(*cur);
335 int value = *cur;
336 Heap* current_heap = sim_->isolate_->heap();
337 if (((value & 1) == 0) ||
338 current_heap->ContainsSlow(obj->address())) {
339 PrintF(" (");
340 if ((value & 1) == 0) {
341 PrintF("smi %d", value / 2);
342 } else {
343 obj->ShortPrint();
344 }
345 PrintF(")");
346 }
347 PrintF("\n");
348 cur++;
349 }
350 } else if (strcmp(cmd, "disasm") == 0 || strcmp(cmd, "di") == 0) {
351 disasm::NameConverter converter;
352 disasm::Disassembler dasm(converter);
353 // use a reasonably large buffer
354 v8::internal::EmbeddedVector<char, 256> buffer;
355
356 byte* prev = NULL;
357 byte* cur = NULL;
358 byte* end = NULL;
359
360 if (argc == 1) {
361 cur = reinterpret_cast<byte*>(sim_->get_pc());
362 end = cur + (10 * Instruction::kInstrSize);
363 } else if (argc == 2) {
364 int regnum = Registers::Number(arg1);
365 if (regnum != kNoRegister || strncmp(arg1, "0x", 2) == 0) {
366 // The argument is an address or a register name.
367 int32_t value;
368 if (GetValue(arg1, &value)) {
369 cur = reinterpret_cast<byte*>(value);
370 // Disassemble 10 instructions at <arg1>.
371 end = cur + (10 * Instruction::kInstrSize);
372 }
373 } else {
374 // The argument is the number of instructions.
375 int32_t value;
376 if (GetValue(arg1, &value)) {
377 cur = reinterpret_cast<byte*>(sim_->get_pc());
378 // Disassemble <arg1> instructions.
379 end = cur + (value * Instruction::kInstrSize);
380 }
381 }
382 } else {
383 int32_t value1;
384 int32_t value2;
385 if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
386 cur = reinterpret_cast<byte*>(value1);
387 end = cur + (value2 * Instruction::kInstrSize);
388 }
389 }
390
391 while (cur < end) {
392 prev = cur;
393 cur += dasm.InstructionDecode(buffer, cur);
394 PrintF(" 0x%08" V8PRIxPTR " %s\n", reinterpret_cast<intptr_t>(prev),
395 buffer.start());
396 }
397 } else if (strcmp(cmd, "gdb") == 0) {
398 PrintF("relinquishing control to gdb\n");
399 v8::base::OS::DebugBreak();
400 PrintF("regaining control from gdb\n");
401 } else if (strcmp(cmd, "break") == 0) {
402 if (argc == 2) {
403 int32_t value;
404 if (GetValue(arg1, &value)) {
405 if (!SetBreakpoint(reinterpret_cast<Instruction*>(value))) {
406 PrintF("setting breakpoint failed\n");
407 }
408 } else {
409 PrintF("%s unrecognized\n", arg1);
410 }
411 } else {
412 PrintF("break <address>\n");
413 }
414 } else if (strcmp(cmd, "del") == 0) {
415 if (!DeleteBreakpoint(NULL)) {
416 PrintF("deleting breakpoint failed\n");
417 }
418 } else if (strcmp(cmd, "flags") == 0) {
419 PrintF("N flag: %d; ", sim_->n_flag_);
420 PrintF("Z flag: %d; ", sim_->z_flag_);
421 PrintF("C flag: %d; ", sim_->c_flag_);
422 PrintF("V flag: %d\n", sim_->v_flag_);
423 PrintF("INVALID OP flag: %d; ", sim_->inv_op_vfp_flag_);
424 PrintF("DIV BY ZERO flag: %d; ", sim_->div_zero_vfp_flag_);
425 PrintF("OVERFLOW flag: %d; ", sim_->overflow_vfp_flag_);
426 PrintF("UNDERFLOW flag: %d; ", sim_->underflow_vfp_flag_);
427 PrintF("INEXACT flag: %d;\n", sim_->inexact_vfp_flag_);
428 } else if (strcmp(cmd, "stop") == 0) {
429 int32_t value;
430 intptr_t stop_pc = sim_->get_pc() - 2 * Instruction::kInstrSize;
431 Instruction* stop_instr = reinterpret_cast<Instruction*>(stop_pc);
432 Instruction* msg_address =
433 reinterpret_cast<Instruction*>(stop_pc + Instruction::kInstrSize);
434 if ((argc == 2) && (strcmp(arg1, "unstop") == 0)) {
435 // Remove the current stop.
436 if (sim_->isStopInstruction(stop_instr)) {
437 stop_instr->SetInstructionBits(kNopInstr);
438 msg_address->SetInstructionBits(kNopInstr);
439 } else {
440 PrintF("Not at debugger stop.\n");
441 }
442 } else if (argc == 3) {
443 // Print information about all/the specified breakpoint(s).
444 if (strcmp(arg1, "info") == 0) {
445 if (strcmp(arg2, "all") == 0) {
446 PrintF("Stop information:\n");
447 for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) {
448 sim_->PrintStopInfo(i);
449 }
450 } else if (GetValue(arg2, &value)) {
451 sim_->PrintStopInfo(value);
452 } else {
453 PrintF("Unrecognized argument.\n");
454 }
455 } else if (strcmp(arg1, "enable") == 0) {
456 // Enable all/the specified breakpoint(s).
457 if (strcmp(arg2, "all") == 0) {
458 for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) {
459 sim_->EnableStop(i);
460 }
461 } else if (GetValue(arg2, &value)) {
462 sim_->EnableStop(value);
463 } else {
464 PrintF("Unrecognized argument.\n");
465 }
466 } else if (strcmp(arg1, "disable") == 0) {
467 // Disable all/the specified breakpoint(s).
468 if (strcmp(arg2, "all") == 0) {
469 for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) {
470 sim_->DisableStop(i);
471 }
472 } else if (GetValue(arg2, &value)) {
473 sim_->DisableStop(value);
474 } else {
475 PrintF("Unrecognized argument.\n");
476 }
477 }
478 } else {
479 PrintF("Wrong usage. Use help command for more information.\n");
480 }
481 } else if ((strcmp(cmd, "t") == 0) || strcmp(cmd, "trace") == 0) {
482 ::v8::internal::FLAG_trace_sim = !::v8::internal::FLAG_trace_sim;
483 PrintF("Trace of executed instructions is %s\n",
484 ::v8::internal::FLAG_trace_sim ? "on" : "off");
485 } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
486 PrintF("cont\n");
487 PrintF(" continue execution (alias 'c')\n");
488 PrintF("stepi\n");
489 PrintF(" step one instruction (alias 'si')\n");
490 PrintF("print <register>\n");
491 PrintF(" print register content (alias 'p')\n");
492 PrintF(" use register name 'all' to print all registers\n");
493 PrintF(" add argument 'fp' to print register pair double values\n");
494 PrintF("printobject <register>\n");
495 PrintF(" print an object from a register (alias 'po')\n");
496 PrintF("flags\n");
497 PrintF(" print flags\n");
498 PrintF("stack [<words>]\n");
499 PrintF(" dump stack content, default dump 10 words)\n");
500 PrintF("mem <address> [<words>]\n");
501 PrintF(" dump memory content, default dump 10 words)\n");
502 PrintF("disasm [<instructions>]\n");
503 PrintF("disasm [<address/register>]\n");
504 PrintF("disasm [[<address/register>] <instructions>]\n");
505 PrintF(" disassemble code, default is 10 instructions\n");
506 PrintF(" from pc (alias 'di')\n");
507 PrintF("gdb\n");
508 PrintF(" enter gdb\n");
509 PrintF("break <address>\n");
510 PrintF(" set a break point on the address\n");
511 PrintF("del\n");
512 PrintF(" delete the breakpoint\n");
513 PrintF("trace (alias 't')\n");
514 PrintF(" toogle the tracing of all executed statements\n");
515 PrintF("stop feature:\n");
516 PrintF(" Description:\n");
517 PrintF(" Stops are debug instructions inserted by\n");
518 PrintF(" the Assembler::stop() function.\n");
519 PrintF(" When hitting a stop, the Simulator will\n");
520 PrintF(" stop and and give control to the ArmDebugger.\n");
521 PrintF(" The first %d stop codes are watched:\n",
522 Simulator::kNumOfWatchedStops);
523 PrintF(" - They can be enabled / disabled: the Simulator\n");
524 PrintF(" will / won't stop when hitting them.\n");
525 PrintF(" - The Simulator keeps track of how many times they \n");
526 PrintF(" are met. (See the info command.) Going over a\n");
527 PrintF(" disabled stop still increases its counter. \n");
528 PrintF(" Commands:\n");
529 PrintF(" stop info all/<code> : print infos about number <code>\n");
530 PrintF(" or all stop(s).\n");
531 PrintF(" stop enable/disable all/<code> : enables / disables\n");
532 PrintF(" all or number <code> stop(s)\n");
533 PrintF(" stop unstop\n");
534 PrintF(" ignore the stop instruction at the current location\n");
535 PrintF(" from now on\n");
536 } else {
537 PrintF("Unknown command: %s\n", cmd);
538 }
539 }
540 }
541
542 // Add all the breakpoints back to stop execution and enter the debugger
543 // shell when hit.
544 RedoBreakpoints();
545
546 #undef COMMAND_SIZE
547 #undef ARG_SIZE
548
549 #undef STR
550 #undef XSTR
551 }
552
553
ICacheMatch(void * one,void * two)554 static bool ICacheMatch(void* one, void* two) {
555 DCHECK((reinterpret_cast<intptr_t>(one) & CachePage::kPageMask) == 0);
556 DCHECK((reinterpret_cast<intptr_t>(two) & CachePage::kPageMask) == 0);
557 return one == two;
558 }
559
560
ICacheHash(void * key)561 static uint32_t ICacheHash(void* key) {
562 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)) >> 2;
563 }
564
565
AllOnOnePage(uintptr_t start,int size)566 static bool AllOnOnePage(uintptr_t start, int size) {
567 intptr_t start_page = (start & ~CachePage::kPageMask);
568 intptr_t end_page = ((start + size) & ~CachePage::kPageMask);
569 return start_page == end_page;
570 }
571
572
set_last_debugger_input(char * input)573 void Simulator::set_last_debugger_input(char* input) {
574 DeleteArray(last_debugger_input_);
575 last_debugger_input_ = input;
576 }
577
FlushICache(base::CustomMatcherHashMap * i_cache,void * start_addr,size_t size)578 void Simulator::FlushICache(base::CustomMatcherHashMap* i_cache,
579 void* start_addr, size_t size) {
580 intptr_t start = reinterpret_cast<intptr_t>(start_addr);
581 int intra_line = (start & CachePage::kLineMask);
582 start -= intra_line;
583 size += intra_line;
584 size = ((size - 1) | CachePage::kLineMask) + 1;
585 int offset = (start & CachePage::kPageMask);
586 while (!AllOnOnePage(start, size - 1)) {
587 int bytes_to_flush = CachePage::kPageSize - offset;
588 FlushOnePage(i_cache, start, bytes_to_flush);
589 start += bytes_to_flush;
590 size -= bytes_to_flush;
591 DCHECK_EQ(0, start & CachePage::kPageMask);
592 offset = 0;
593 }
594 if (size != 0) {
595 FlushOnePage(i_cache, start, size);
596 }
597 }
598
GetCachePage(base::CustomMatcherHashMap * i_cache,void * page)599 CachePage* Simulator::GetCachePage(base::CustomMatcherHashMap* i_cache,
600 void* page) {
601 base::HashMap::Entry* entry = i_cache->LookupOrInsert(page, ICacheHash(page));
602 if (entry->value == NULL) {
603 CachePage* new_page = new CachePage();
604 entry->value = new_page;
605 }
606 return reinterpret_cast<CachePage*>(entry->value);
607 }
608
609
610 // Flush from start up to and not including start + size.
FlushOnePage(base::CustomMatcherHashMap * i_cache,intptr_t start,int size)611 void Simulator::FlushOnePage(base::CustomMatcherHashMap* i_cache,
612 intptr_t start, int size) {
613 DCHECK(size <= CachePage::kPageSize);
614 DCHECK(AllOnOnePage(start, size - 1));
615 DCHECK((start & CachePage::kLineMask) == 0);
616 DCHECK((size & CachePage::kLineMask) == 0);
617 void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask));
618 int offset = (start & CachePage::kPageMask);
619 CachePage* cache_page = GetCachePage(i_cache, page);
620 char* valid_bytemap = cache_page->ValidityByte(offset);
621 memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift);
622 }
623
CheckICache(base::CustomMatcherHashMap * i_cache,Instruction * instr)624 void Simulator::CheckICache(base::CustomMatcherHashMap* i_cache,
625 Instruction* instr) {
626 intptr_t address = reinterpret_cast<intptr_t>(instr);
627 void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
628 void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask));
629 int offset = (address & CachePage::kPageMask);
630 CachePage* cache_page = GetCachePage(i_cache, page);
631 char* cache_valid_byte = cache_page->ValidityByte(offset);
632 bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID);
633 char* cached_line = cache_page->CachedData(offset & ~CachePage::kLineMask);
634 if (cache_hit) {
635 // Check that the data in memory matches the contents of the I-cache.
636 CHECK_EQ(0,
637 memcmp(reinterpret_cast<void*>(instr),
638 cache_page->CachedData(offset), Instruction::kInstrSize));
639 } else {
640 // Cache miss. Load memory into the cache.
641 memcpy(cached_line, line, CachePage::kLineLength);
642 *cache_valid_byte = CachePage::LINE_VALID;
643 }
644 }
645
646
Initialize(Isolate * isolate)647 void Simulator::Initialize(Isolate* isolate) {
648 if (isolate->simulator_initialized()) return;
649 isolate->set_simulator_initialized(true);
650 ::v8::internal::ExternalReference::set_redirector(isolate,
651 &RedirectExternalReference);
652 }
653
654
Simulator(Isolate * isolate)655 Simulator::Simulator(Isolate* isolate) : isolate_(isolate) {
656 i_cache_ = isolate_->simulator_i_cache();
657 if (i_cache_ == NULL) {
658 i_cache_ = new base::CustomMatcherHashMap(&ICacheMatch);
659 isolate_->set_simulator_i_cache(i_cache_);
660 }
661 Initialize(isolate);
662 // Set up simulator support first. Some of this information is needed to
663 // setup the architecture state.
664 size_t stack_size = 1 * 1024*1024; // allocate 1MB for stack
665 stack_ = reinterpret_cast<char*>(malloc(stack_size));
666 pc_modified_ = false;
667 icount_ = 0;
668 break_pc_ = NULL;
669 break_instr_ = 0;
670
671 // Set up architecture state.
672 // All registers are initialized to zero to start with.
673 for (int i = 0; i < num_registers; i++) {
674 registers_[i] = 0;
675 }
676 n_flag_ = false;
677 z_flag_ = false;
678 c_flag_ = false;
679 v_flag_ = false;
680
681 // Initializing VFP registers.
682 // All registers are initialized to zero to start with
683 // even though s_registers_ & d_registers_ share the same
684 // physical registers in the target.
685 for (int i = 0; i < num_d_registers * 2; i++) {
686 vfp_registers_[i] = 0;
687 }
688 n_flag_FPSCR_ = false;
689 z_flag_FPSCR_ = false;
690 c_flag_FPSCR_ = false;
691 v_flag_FPSCR_ = false;
692 FPSCR_rounding_mode_ = RN;
693 FPSCR_default_NaN_mode_ = false;
694
695 inv_op_vfp_flag_ = false;
696 div_zero_vfp_flag_ = false;
697 overflow_vfp_flag_ = false;
698 underflow_vfp_flag_ = false;
699 inexact_vfp_flag_ = false;
700
701 // The sp is initialized to point to the bottom (high address) of the
702 // allocated stack area. To be safe in potential stack underflows we leave
703 // some buffer below.
704 registers_[sp] = reinterpret_cast<int32_t>(stack_) + stack_size - 64;
705 // The lr and pc are initialized to a known bad value that will cause an
706 // access violation if the simulator ever tries to execute it.
707 registers_[pc] = bad_lr;
708 registers_[lr] = bad_lr;
709
710 last_debugger_input_ = NULL;
711 }
712
713
~Simulator()714 Simulator::~Simulator() { free(stack_); }
715
716
717 // When the generated code calls an external reference we need to catch that in
718 // the simulator. The external reference will be a function compiled for the
719 // host architecture. We need to call that function instead of trying to
720 // execute it with the simulator. We do that by redirecting the external
721 // reference to a svc (Supervisor Call) instruction that is handled by
722 // the simulator. We write the original destination of the jump just at a known
723 // offset from the svc instruction so the simulator knows what to call.
724 class Redirection {
725 public:
Redirection(Isolate * isolate,void * external_function,ExternalReference::Type type)726 Redirection(Isolate* isolate, void* external_function,
727 ExternalReference::Type type)
728 : external_function_(external_function),
729 swi_instruction_(al | (0xf * B24) | kCallRtRedirected),
730 type_(type),
731 next_(NULL) {
732 next_ = isolate->simulator_redirection();
733 Simulator::current(isolate)->
734 FlushICache(isolate->simulator_i_cache(),
735 reinterpret_cast<void*>(&swi_instruction_),
736 Instruction::kInstrSize);
737 isolate->set_simulator_redirection(this);
738 }
739
address_of_swi_instruction()740 void* address_of_swi_instruction() {
741 return reinterpret_cast<void*>(&swi_instruction_);
742 }
743
external_function()744 void* external_function() { return external_function_; }
type()745 ExternalReference::Type type() { return type_; }
746
Get(Isolate * isolate,void * external_function,ExternalReference::Type type)747 static Redirection* Get(Isolate* isolate, void* external_function,
748 ExternalReference::Type type) {
749 Redirection* current = isolate->simulator_redirection();
750 for (; current != NULL; current = current->next_) {
751 if (current->external_function_ == external_function) {
752 DCHECK_EQ(current->type(), type);
753 return current;
754 }
755 }
756 return new Redirection(isolate, external_function, type);
757 }
758
FromSwiInstruction(Instruction * swi_instruction)759 static Redirection* FromSwiInstruction(Instruction* swi_instruction) {
760 char* addr_of_swi = reinterpret_cast<char*>(swi_instruction);
761 char* addr_of_redirection =
762 addr_of_swi - offsetof(Redirection, swi_instruction_);
763 return reinterpret_cast<Redirection*>(addr_of_redirection);
764 }
765
ReverseRedirection(int32_t reg)766 static void* ReverseRedirection(int32_t reg) {
767 Redirection* redirection = FromSwiInstruction(
768 reinterpret_cast<Instruction*>(reinterpret_cast<void*>(reg)));
769 return redirection->external_function();
770 }
771
DeleteChain(Redirection * redirection)772 static void DeleteChain(Redirection* redirection) {
773 while (redirection != nullptr) {
774 Redirection* next = redirection->next_;
775 delete redirection;
776 redirection = next;
777 }
778 }
779
780 private:
781 void* external_function_;
782 uint32_t swi_instruction_;
783 ExternalReference::Type type_;
784 Redirection* next_;
785 };
786
787
788 // static
TearDown(base::CustomMatcherHashMap * i_cache,Redirection * first)789 void Simulator::TearDown(base::CustomMatcherHashMap* i_cache,
790 Redirection* first) {
791 Redirection::DeleteChain(first);
792 if (i_cache != nullptr) {
793 for (base::HashMap::Entry* entry = i_cache->Start(); entry != nullptr;
794 entry = i_cache->Next(entry)) {
795 delete static_cast<CachePage*>(entry->value);
796 }
797 delete i_cache;
798 }
799 }
800
801
RedirectExternalReference(Isolate * isolate,void * external_function,ExternalReference::Type type)802 void* Simulator::RedirectExternalReference(Isolate* isolate,
803 void* external_function,
804 ExternalReference::Type type) {
805 Redirection* redirection = Redirection::Get(isolate, external_function, type);
806 return redirection->address_of_swi_instruction();
807 }
808
809
810 // Get the active Simulator for the current thread.
current(Isolate * isolate)811 Simulator* Simulator::current(Isolate* isolate) {
812 v8::internal::Isolate::PerIsolateThreadData* isolate_data =
813 isolate->FindOrAllocatePerThreadDataForThisThread();
814 DCHECK(isolate_data != NULL);
815
816 Simulator* sim = isolate_data->simulator();
817 if (sim == NULL) {
818 // TODO(146): delete the simulator object when a thread/isolate goes away.
819 sim = new Simulator(isolate);
820 isolate_data->set_simulator(sim);
821 }
822 return sim;
823 }
824
825
826 // Sets the register in the architecture state. It will also deal with updating
827 // Simulator internal state for special registers such as PC.
set_register(int reg,int32_t value)828 void Simulator::set_register(int reg, int32_t value) {
829 DCHECK((reg >= 0) && (reg < num_registers));
830 if (reg == pc) {
831 pc_modified_ = true;
832 }
833 registers_[reg] = value;
834 }
835
836
837 // Get the register from the architecture state. This function does handle
838 // the special case of accessing the PC register.
get_register(int reg) const839 int32_t Simulator::get_register(int reg) const {
840 DCHECK((reg >= 0) && (reg < num_registers));
841 // Stupid code added to avoid bug in GCC.
842 // See: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43949
843 if (reg >= num_registers) return 0;
844 // End stupid code.
845 return registers_[reg] + ((reg == pc) ? Instruction::kPCReadOffset : 0);
846 }
847
848
get_double_from_register_pair(int reg)849 double Simulator::get_double_from_register_pair(int reg) {
850 DCHECK((reg >= 0) && (reg < num_registers) && ((reg % 2) == 0));
851
852 double dm_val = 0.0;
853 // Read the bits from the unsigned integer register_[] array
854 // into the double precision floating point value and return it.
855 char buffer[2 * sizeof(vfp_registers_[0])];
856 memcpy(buffer, ®isters_[reg], 2 * sizeof(registers_[0]));
857 memcpy(&dm_val, buffer, 2 * sizeof(registers_[0]));
858 return(dm_val);
859 }
860
861
set_register_pair_from_double(int reg,double * value)862 void Simulator::set_register_pair_from_double(int reg, double* value) {
863 DCHECK((reg >= 0) && (reg < num_registers) && ((reg % 2) == 0));
864 memcpy(registers_ + reg, value, sizeof(*value));
865 }
866
867
set_dw_register(int dreg,const int * dbl)868 void Simulator::set_dw_register(int dreg, const int* dbl) {
869 DCHECK((dreg >= 0) && (dreg < num_d_registers));
870 registers_[dreg] = dbl[0];
871 registers_[dreg + 1] = dbl[1];
872 }
873
874
get_d_register(int dreg,uint64_t * value)875 void Simulator::get_d_register(int dreg, uint64_t* value) {
876 DCHECK((dreg >= 0) && (dreg < DwVfpRegister::NumRegisters()));
877 memcpy(value, vfp_registers_ + dreg * 2, sizeof(*value));
878 }
879
880
set_d_register(int dreg,const uint64_t * value)881 void Simulator::set_d_register(int dreg, const uint64_t* value) {
882 DCHECK((dreg >= 0) && (dreg < DwVfpRegister::NumRegisters()));
883 memcpy(vfp_registers_ + dreg * 2, value, sizeof(*value));
884 }
885
886
get_d_register(int dreg,uint32_t * value)887 void Simulator::get_d_register(int dreg, uint32_t* value) {
888 DCHECK((dreg >= 0) && (dreg < DwVfpRegister::NumRegisters()));
889 memcpy(value, vfp_registers_ + dreg * 2, sizeof(*value) * 2);
890 }
891
892
set_d_register(int dreg,const uint32_t * value)893 void Simulator::set_d_register(int dreg, const uint32_t* value) {
894 DCHECK((dreg >= 0) && (dreg < DwVfpRegister::NumRegisters()));
895 memcpy(vfp_registers_ + dreg * 2, value, sizeof(*value) * 2);
896 }
897
898
get_q_register(int qreg,uint64_t * value)899 void Simulator::get_q_register(int qreg, uint64_t* value) {
900 DCHECK((qreg >= 0) && (qreg < num_q_registers));
901 memcpy(value, vfp_registers_ + qreg * 4, sizeof(*value) * 2);
902 }
903
904
set_q_register(int qreg,const uint64_t * value)905 void Simulator::set_q_register(int qreg, const uint64_t* value) {
906 DCHECK((qreg >= 0) && (qreg < num_q_registers));
907 memcpy(vfp_registers_ + qreg * 4, value, sizeof(*value) * 2);
908 }
909
910
get_q_register(int qreg,uint32_t * value)911 void Simulator::get_q_register(int qreg, uint32_t* value) {
912 DCHECK((qreg >= 0) && (qreg < num_q_registers));
913 memcpy(value, vfp_registers_ + qreg * 4, sizeof(*value) * 4);
914 }
915
916
set_q_register(int qreg,const uint32_t * value)917 void Simulator::set_q_register(int qreg, const uint32_t* value) {
918 DCHECK((qreg >= 0) && (qreg < num_q_registers));
919 memcpy(vfp_registers_ + qreg * 4, value, sizeof(*value) * 4);
920 }
921
922
923 // Raw access to the PC register.
set_pc(int32_t value)924 void Simulator::set_pc(int32_t value) {
925 pc_modified_ = true;
926 registers_[pc] = value;
927 }
928
929
has_bad_pc() const930 bool Simulator::has_bad_pc() const {
931 return ((registers_[pc] == bad_lr) || (registers_[pc] == end_sim_pc));
932 }
933
934
935 // Raw access to the PC register without the special adjustment when reading.
get_pc() const936 int32_t Simulator::get_pc() const {
937 return registers_[pc];
938 }
939
940
941 // Getting from and setting into VFP registers.
set_s_register(int sreg,unsigned int value)942 void Simulator::set_s_register(int sreg, unsigned int value) {
943 DCHECK((sreg >= 0) && (sreg < num_s_registers));
944 vfp_registers_[sreg] = value;
945 }
946
947
get_s_register(int sreg) const948 unsigned int Simulator::get_s_register(int sreg) const {
949 DCHECK((sreg >= 0) && (sreg < num_s_registers));
950 return vfp_registers_[sreg];
951 }
952
953
954 template<class InputType, int register_size>
SetVFPRegister(int reg_index,const InputType & value)955 void Simulator::SetVFPRegister(int reg_index, const InputType& value) {
956 DCHECK(reg_index >= 0);
957 if (register_size == 1) DCHECK(reg_index < num_s_registers);
958 if (register_size == 2) DCHECK(reg_index < DwVfpRegister::NumRegisters());
959
960 char buffer[register_size * sizeof(vfp_registers_[0])];
961 memcpy(buffer, &value, register_size * sizeof(vfp_registers_[0]));
962 memcpy(&vfp_registers_[reg_index * register_size], buffer,
963 register_size * sizeof(vfp_registers_[0]));
964 }
965
966
967 template<class ReturnType, int register_size>
GetFromVFPRegister(int reg_index)968 ReturnType Simulator::GetFromVFPRegister(int reg_index) {
969 DCHECK(reg_index >= 0);
970 if (register_size == 1) DCHECK(reg_index < num_s_registers);
971 if (register_size == 2) DCHECK(reg_index < DwVfpRegister::NumRegisters());
972
973 ReturnType value = 0;
974 char buffer[register_size * sizeof(vfp_registers_[0])];
975 memcpy(buffer, &vfp_registers_[register_size * reg_index],
976 register_size * sizeof(vfp_registers_[0]));
977 memcpy(&value, buffer, register_size * sizeof(vfp_registers_[0]));
978 return value;
979 }
980
SetSpecialRegister(SRegisterFieldMask reg_and_mask,uint32_t value)981 void Simulator::SetSpecialRegister(SRegisterFieldMask reg_and_mask,
982 uint32_t value) {
983 // Only CPSR_f is implemented. Of that, only N, Z, C and V are implemented.
984 if ((reg_and_mask == CPSR_f) && ((value & ~kSpecialCondition) == 0)) {
985 n_flag_ = ((value & (1 << 31)) != 0);
986 z_flag_ = ((value & (1 << 30)) != 0);
987 c_flag_ = ((value & (1 << 29)) != 0);
988 v_flag_ = ((value & (1 << 28)) != 0);
989 } else {
990 UNIMPLEMENTED();
991 }
992 }
993
GetFromSpecialRegister(SRegister reg)994 uint32_t Simulator::GetFromSpecialRegister(SRegister reg) {
995 uint32_t result = 0;
996 // Only CPSR_f is implemented.
997 if (reg == CPSR) {
998 if (n_flag_) result |= (1 << 31);
999 if (z_flag_) result |= (1 << 30);
1000 if (c_flag_) result |= (1 << 29);
1001 if (v_flag_) result |= (1 << 28);
1002 } else {
1003 UNIMPLEMENTED();
1004 }
1005 return result;
1006 }
1007
1008 // Runtime FP routines take:
1009 // - two double arguments
1010 // - one double argument and zero or one integer arguments.
1011 // All are consructed here from r0-r3 or d0, d1 and r0.
GetFpArgs(double * x,double * y,int32_t * z)1012 void Simulator::GetFpArgs(double* x, double* y, int32_t* z) {
1013 if (use_eabi_hardfloat()) {
1014 *x = get_double_from_d_register(0);
1015 *y = get_double_from_d_register(1);
1016 *z = get_register(0);
1017 } else {
1018 // Registers 0 and 1 -> x.
1019 *x = get_double_from_register_pair(0);
1020 // Register 2 and 3 -> y.
1021 *y = get_double_from_register_pair(2);
1022 // Register 2 -> z
1023 *z = get_register(2);
1024 }
1025 }
1026
1027
1028 // The return value is either in r0/r1 or d0.
SetFpResult(const double & result)1029 void Simulator::SetFpResult(const double& result) {
1030 if (use_eabi_hardfloat()) {
1031 char buffer[2 * sizeof(vfp_registers_[0])];
1032 memcpy(buffer, &result, sizeof(buffer));
1033 // Copy result to d0.
1034 memcpy(vfp_registers_, buffer, sizeof(buffer));
1035 } else {
1036 char buffer[2 * sizeof(registers_[0])];
1037 memcpy(buffer, &result, sizeof(buffer));
1038 // Copy result to r0 and r1.
1039 memcpy(registers_, buffer, sizeof(buffer));
1040 }
1041 }
1042
1043
TrashCallerSaveRegisters()1044 void Simulator::TrashCallerSaveRegisters() {
1045 // We don't trash the registers with the return value.
1046 registers_[2] = 0x50Bad4U;
1047 registers_[3] = 0x50Bad4U;
1048 registers_[12] = 0x50Bad4U;
1049 }
1050
1051
ReadW(int32_t addr,Instruction * instr)1052 int Simulator::ReadW(int32_t addr, Instruction* instr) {
1053 // All supported ARM targets allow unaligned accesses, so we don't need to
1054 // check the alignment here.
1055 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
1056 return *ptr;
1057 }
1058
1059
WriteW(int32_t addr,int value,Instruction * instr)1060 void Simulator::WriteW(int32_t addr, int value, Instruction* instr) {
1061 // All supported ARM targets allow unaligned accesses, so we don't need to
1062 // check the alignment here.
1063 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
1064 *ptr = value;
1065 }
1066
1067
ReadHU(int32_t addr,Instruction * instr)1068 uint16_t Simulator::ReadHU(int32_t addr, Instruction* instr) {
1069 // All supported ARM targets allow unaligned accesses, so we don't need to
1070 // check the alignment here.
1071 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1072 return *ptr;
1073 }
1074
1075
ReadH(int32_t addr,Instruction * instr)1076 int16_t Simulator::ReadH(int32_t addr, Instruction* instr) {
1077 // All supported ARM targets allow unaligned accesses, so we don't need to
1078 // check the alignment here.
1079 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
1080 return *ptr;
1081 }
1082
1083
WriteH(int32_t addr,uint16_t value,Instruction * instr)1084 void Simulator::WriteH(int32_t addr, uint16_t value, Instruction* instr) {
1085 // All supported ARM targets allow unaligned accesses, so we don't need to
1086 // check the alignment here.
1087 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1088 *ptr = value;
1089 }
1090
1091
WriteH(int32_t addr,int16_t value,Instruction * instr)1092 void Simulator::WriteH(int32_t addr, int16_t value, Instruction* instr) {
1093 // All supported ARM targets allow unaligned accesses, so we don't need to
1094 // check the alignment here.
1095 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
1096 *ptr = value;
1097 }
1098
1099
ReadBU(int32_t addr)1100 uint8_t Simulator::ReadBU(int32_t addr) {
1101 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1102 return *ptr;
1103 }
1104
1105
ReadB(int32_t addr)1106 int8_t Simulator::ReadB(int32_t addr) {
1107 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
1108 return *ptr;
1109 }
1110
1111
WriteB(int32_t addr,uint8_t value)1112 void Simulator::WriteB(int32_t addr, uint8_t value) {
1113 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1114 *ptr = value;
1115 }
1116
1117
WriteB(int32_t addr,int8_t value)1118 void Simulator::WriteB(int32_t addr, int8_t value) {
1119 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
1120 *ptr = value;
1121 }
1122
1123
ReadDW(int32_t addr)1124 int32_t* Simulator::ReadDW(int32_t addr) {
1125 // All supported ARM targets allow unaligned accesses, so we don't need to
1126 // check the alignment here.
1127 int32_t* ptr = reinterpret_cast<int32_t*>(addr);
1128 return ptr;
1129 }
1130
1131
WriteDW(int32_t addr,int32_t value1,int32_t value2)1132 void Simulator::WriteDW(int32_t addr, int32_t value1, int32_t value2) {
1133 // All supported ARM targets allow unaligned accesses, so we don't need to
1134 // check the alignment here.
1135 int32_t* ptr = reinterpret_cast<int32_t*>(addr);
1136 *ptr++ = value1;
1137 *ptr = value2;
1138 }
1139
1140
1141 // Returns the limit of the stack area to enable checking for stack overflows.
StackLimit(uintptr_t c_limit) const1142 uintptr_t Simulator::StackLimit(uintptr_t c_limit) const {
1143 // The simulator uses a separate JS stack. If we have exhausted the C stack,
1144 // we also drop down the JS limit to reflect the exhaustion on the JS stack.
1145 if (GetCurrentStackPosition() < c_limit) {
1146 return reinterpret_cast<uintptr_t>(get_sp());
1147 }
1148
1149 // Otherwise the limit is the JS stack. Leave a safety margin of 1024 bytes
1150 // to prevent overrunning the stack when pushing values.
1151 return reinterpret_cast<uintptr_t>(stack_) + 1024;
1152 }
1153
1154
1155 // Unsupported instructions use Format to print an error and stop execution.
Format(Instruction * instr,const char * format)1156 void Simulator::Format(Instruction* instr, const char* format) {
1157 PrintF("Simulator found unsupported instruction:\n 0x%08" V8PRIxPTR ": %s\n",
1158 reinterpret_cast<intptr_t>(instr), format);
1159 UNIMPLEMENTED();
1160 }
1161
1162
1163 // Checks if the current instruction should be executed based on its
1164 // condition bits.
ConditionallyExecute(Instruction * instr)1165 bool Simulator::ConditionallyExecute(Instruction* instr) {
1166 switch (instr->ConditionField()) {
1167 case eq: return z_flag_;
1168 case ne: return !z_flag_;
1169 case cs: return c_flag_;
1170 case cc: return !c_flag_;
1171 case mi: return n_flag_;
1172 case pl: return !n_flag_;
1173 case vs: return v_flag_;
1174 case vc: return !v_flag_;
1175 case hi: return c_flag_ && !z_flag_;
1176 case ls: return !c_flag_ || z_flag_;
1177 case ge: return n_flag_ == v_flag_;
1178 case lt: return n_flag_ != v_flag_;
1179 case gt: return !z_flag_ && (n_flag_ == v_flag_);
1180 case le: return z_flag_ || (n_flag_ != v_flag_);
1181 case al: return true;
1182 default: UNREACHABLE();
1183 }
1184 return false;
1185 }
1186
1187
1188 // Calculate and set the Negative and Zero flags.
SetNZFlags(int32_t val)1189 void Simulator::SetNZFlags(int32_t val) {
1190 n_flag_ = (val < 0);
1191 z_flag_ = (val == 0);
1192 }
1193
1194
1195 // Set the Carry flag.
SetCFlag(bool val)1196 void Simulator::SetCFlag(bool val) {
1197 c_flag_ = val;
1198 }
1199
1200
1201 // Set the oVerflow flag.
SetVFlag(bool val)1202 void Simulator::SetVFlag(bool val) {
1203 v_flag_ = val;
1204 }
1205
1206
1207 // Calculate C flag value for additions.
CarryFrom(int32_t left,int32_t right,int32_t carry)1208 bool Simulator::CarryFrom(int32_t left, int32_t right, int32_t carry) {
1209 uint32_t uleft = static_cast<uint32_t>(left);
1210 uint32_t uright = static_cast<uint32_t>(right);
1211 uint32_t urest = 0xffffffffU - uleft;
1212
1213 return (uright > urest) ||
1214 (carry && (((uright + 1) > urest) || (uright > (urest - 1))));
1215 }
1216
1217
1218 // Calculate C flag value for subtractions.
BorrowFrom(int32_t left,int32_t right,int32_t carry)1219 bool Simulator::BorrowFrom(int32_t left, int32_t right, int32_t carry) {
1220 uint32_t uleft = static_cast<uint32_t>(left);
1221 uint32_t uright = static_cast<uint32_t>(right);
1222
1223 return (uright > uleft) ||
1224 (!carry && (((uright + 1) > uleft) || (uright > (uleft - 1))));
1225 }
1226
1227
1228 // Calculate V flag value for additions and subtractions.
OverflowFrom(int32_t alu_out,int32_t left,int32_t right,bool addition)1229 bool Simulator::OverflowFrom(int32_t alu_out,
1230 int32_t left, int32_t right, bool addition) {
1231 bool overflow;
1232 if (addition) {
1233 // operands have the same sign
1234 overflow = ((left >= 0 && right >= 0) || (left < 0 && right < 0))
1235 // and operands and result have different sign
1236 && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
1237 } else {
1238 // operands have different signs
1239 overflow = ((left < 0 && right >= 0) || (left >= 0 && right < 0))
1240 // and first operand and result have different signs
1241 && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
1242 }
1243 return overflow;
1244 }
1245
1246
1247 // Support for VFP comparisons.
Compute_FPSCR_Flags(float val1,float val2)1248 void Simulator::Compute_FPSCR_Flags(float val1, float val2) {
1249 if (std::isnan(val1) || std::isnan(val2)) {
1250 n_flag_FPSCR_ = false;
1251 z_flag_FPSCR_ = false;
1252 c_flag_FPSCR_ = true;
1253 v_flag_FPSCR_ = true;
1254 // All non-NaN cases.
1255 } else if (val1 == val2) {
1256 n_flag_FPSCR_ = false;
1257 z_flag_FPSCR_ = true;
1258 c_flag_FPSCR_ = true;
1259 v_flag_FPSCR_ = false;
1260 } else if (val1 < val2) {
1261 n_flag_FPSCR_ = true;
1262 z_flag_FPSCR_ = false;
1263 c_flag_FPSCR_ = false;
1264 v_flag_FPSCR_ = false;
1265 } else {
1266 // Case when (val1 > val2).
1267 n_flag_FPSCR_ = false;
1268 z_flag_FPSCR_ = false;
1269 c_flag_FPSCR_ = true;
1270 v_flag_FPSCR_ = false;
1271 }
1272 }
1273
1274
Compute_FPSCR_Flags(double val1,double val2)1275 void Simulator::Compute_FPSCR_Flags(double val1, double val2) {
1276 if (std::isnan(val1) || std::isnan(val2)) {
1277 n_flag_FPSCR_ = false;
1278 z_flag_FPSCR_ = false;
1279 c_flag_FPSCR_ = true;
1280 v_flag_FPSCR_ = true;
1281 // All non-NaN cases.
1282 } else if (val1 == val2) {
1283 n_flag_FPSCR_ = false;
1284 z_flag_FPSCR_ = true;
1285 c_flag_FPSCR_ = true;
1286 v_flag_FPSCR_ = false;
1287 } else if (val1 < val2) {
1288 n_flag_FPSCR_ = true;
1289 z_flag_FPSCR_ = false;
1290 c_flag_FPSCR_ = false;
1291 v_flag_FPSCR_ = false;
1292 } else {
1293 // Case when (val1 > val2).
1294 n_flag_FPSCR_ = false;
1295 z_flag_FPSCR_ = false;
1296 c_flag_FPSCR_ = true;
1297 v_flag_FPSCR_ = false;
1298 }
1299 }
1300
1301
Copy_FPSCR_to_APSR()1302 void Simulator::Copy_FPSCR_to_APSR() {
1303 n_flag_ = n_flag_FPSCR_;
1304 z_flag_ = z_flag_FPSCR_;
1305 c_flag_ = c_flag_FPSCR_;
1306 v_flag_ = v_flag_FPSCR_;
1307 }
1308
1309
1310 // Addressing Mode 1 - Data-processing operands:
1311 // Get the value based on the shifter_operand with register.
GetShiftRm(Instruction * instr,bool * carry_out)1312 int32_t Simulator::GetShiftRm(Instruction* instr, bool* carry_out) {
1313 ShiftOp shift = instr->ShiftField();
1314 int shift_amount = instr->ShiftAmountValue();
1315 int32_t result = get_register(instr->RmValue());
1316 if (instr->Bit(4) == 0) {
1317 // by immediate
1318 if ((shift == ROR) && (shift_amount == 0)) {
1319 UNIMPLEMENTED();
1320 return result;
1321 } else if (((shift == LSR) || (shift == ASR)) && (shift_amount == 0)) {
1322 shift_amount = 32;
1323 }
1324 switch (shift) {
1325 case ASR: {
1326 if (shift_amount == 0) {
1327 if (result < 0) {
1328 result = 0xffffffff;
1329 *carry_out = true;
1330 } else {
1331 result = 0;
1332 *carry_out = false;
1333 }
1334 } else {
1335 result >>= (shift_amount - 1);
1336 *carry_out = (result & 1) == 1;
1337 result >>= 1;
1338 }
1339 break;
1340 }
1341
1342 case LSL: {
1343 if (shift_amount == 0) {
1344 *carry_out = c_flag_;
1345 } else {
1346 result <<= (shift_amount - 1);
1347 *carry_out = (result < 0);
1348 result <<= 1;
1349 }
1350 break;
1351 }
1352
1353 case LSR: {
1354 if (shift_amount == 0) {
1355 result = 0;
1356 *carry_out = c_flag_;
1357 } else {
1358 uint32_t uresult = static_cast<uint32_t>(result);
1359 uresult >>= (shift_amount - 1);
1360 *carry_out = (uresult & 1) == 1;
1361 uresult >>= 1;
1362 result = static_cast<int32_t>(uresult);
1363 }
1364 break;
1365 }
1366
1367 case ROR: {
1368 if (shift_amount == 0) {
1369 *carry_out = c_flag_;
1370 } else {
1371 uint32_t left = static_cast<uint32_t>(result) >> shift_amount;
1372 uint32_t right = static_cast<uint32_t>(result) << (32 - shift_amount);
1373 result = right | left;
1374 *carry_out = (static_cast<uint32_t>(result) >> 31) != 0;
1375 }
1376 break;
1377 }
1378
1379 default: {
1380 UNREACHABLE();
1381 break;
1382 }
1383 }
1384 } else {
1385 // by register
1386 int rs = instr->RsValue();
1387 shift_amount = get_register(rs) &0xff;
1388 switch (shift) {
1389 case ASR: {
1390 if (shift_amount == 0) {
1391 *carry_out = c_flag_;
1392 } else if (shift_amount < 32) {
1393 result >>= (shift_amount - 1);
1394 *carry_out = (result & 1) == 1;
1395 result >>= 1;
1396 } else {
1397 DCHECK(shift_amount >= 32);
1398 if (result < 0) {
1399 *carry_out = true;
1400 result = 0xffffffff;
1401 } else {
1402 *carry_out = false;
1403 result = 0;
1404 }
1405 }
1406 break;
1407 }
1408
1409 case LSL: {
1410 if (shift_amount == 0) {
1411 *carry_out = c_flag_;
1412 } else if (shift_amount < 32) {
1413 result <<= (shift_amount - 1);
1414 *carry_out = (result < 0);
1415 result <<= 1;
1416 } else if (shift_amount == 32) {
1417 *carry_out = (result & 1) == 1;
1418 result = 0;
1419 } else {
1420 DCHECK(shift_amount > 32);
1421 *carry_out = false;
1422 result = 0;
1423 }
1424 break;
1425 }
1426
1427 case LSR: {
1428 if (shift_amount == 0) {
1429 *carry_out = c_flag_;
1430 } else if (shift_amount < 32) {
1431 uint32_t uresult = static_cast<uint32_t>(result);
1432 uresult >>= (shift_amount - 1);
1433 *carry_out = (uresult & 1) == 1;
1434 uresult >>= 1;
1435 result = static_cast<int32_t>(uresult);
1436 } else if (shift_amount == 32) {
1437 *carry_out = (result < 0);
1438 result = 0;
1439 } else {
1440 *carry_out = false;
1441 result = 0;
1442 }
1443 break;
1444 }
1445
1446 case ROR: {
1447 if (shift_amount == 0) {
1448 *carry_out = c_flag_;
1449 } else {
1450 uint32_t left = static_cast<uint32_t>(result) >> shift_amount;
1451 uint32_t right = static_cast<uint32_t>(result) << (32 - shift_amount);
1452 result = right | left;
1453 *carry_out = (static_cast<uint32_t>(result) >> 31) != 0;
1454 }
1455 break;
1456 }
1457
1458 default: {
1459 UNREACHABLE();
1460 break;
1461 }
1462 }
1463 }
1464 return result;
1465 }
1466
1467
1468 // Addressing Mode 1 - Data-processing operands:
1469 // Get the value based on the shifter_operand with immediate.
GetImm(Instruction * instr,bool * carry_out)1470 int32_t Simulator::GetImm(Instruction* instr, bool* carry_out) {
1471 int rotate = instr->RotateValue() * 2;
1472 int immed8 = instr->Immed8Value();
1473 int imm = base::bits::RotateRight32(immed8, rotate);
1474 *carry_out = (rotate == 0) ? c_flag_ : (imm < 0);
1475 return imm;
1476 }
1477
1478
count_bits(int bit_vector)1479 static int count_bits(int bit_vector) {
1480 int count = 0;
1481 while (bit_vector != 0) {
1482 if ((bit_vector & 1) != 0) {
1483 count++;
1484 }
1485 bit_vector >>= 1;
1486 }
1487 return count;
1488 }
1489
1490
ProcessPU(Instruction * instr,int num_regs,int reg_size,intptr_t * start_address,intptr_t * end_address)1491 int32_t Simulator::ProcessPU(Instruction* instr,
1492 int num_regs,
1493 int reg_size,
1494 intptr_t* start_address,
1495 intptr_t* end_address) {
1496 int rn = instr->RnValue();
1497 int32_t rn_val = get_register(rn);
1498 switch (instr->PUField()) {
1499 case da_x: {
1500 UNIMPLEMENTED();
1501 break;
1502 }
1503 case ia_x: {
1504 *start_address = rn_val;
1505 *end_address = rn_val + (num_regs * reg_size) - reg_size;
1506 rn_val = rn_val + (num_regs * reg_size);
1507 break;
1508 }
1509 case db_x: {
1510 *start_address = rn_val - (num_regs * reg_size);
1511 *end_address = rn_val - reg_size;
1512 rn_val = *start_address;
1513 break;
1514 }
1515 case ib_x: {
1516 *start_address = rn_val + reg_size;
1517 *end_address = rn_val + (num_regs * reg_size);
1518 rn_val = *end_address;
1519 break;
1520 }
1521 default: {
1522 UNREACHABLE();
1523 break;
1524 }
1525 }
1526 return rn_val;
1527 }
1528
1529
1530 // Addressing Mode 4 - Load and Store Multiple
HandleRList(Instruction * instr,bool load)1531 void Simulator::HandleRList(Instruction* instr, bool load) {
1532 int rlist = instr->RlistValue();
1533 int num_regs = count_bits(rlist);
1534
1535 intptr_t start_address = 0;
1536 intptr_t end_address = 0;
1537 int32_t rn_val =
1538 ProcessPU(instr, num_regs, kPointerSize, &start_address, &end_address);
1539
1540 intptr_t* address = reinterpret_cast<intptr_t*>(start_address);
1541 // Catch null pointers a little earlier.
1542 DCHECK(start_address > 8191 || start_address < 0);
1543 int reg = 0;
1544 while (rlist != 0) {
1545 if ((rlist & 1) != 0) {
1546 if (load) {
1547 set_register(reg, *address);
1548 } else {
1549 *address = get_register(reg);
1550 }
1551 address += 1;
1552 }
1553 reg++;
1554 rlist >>= 1;
1555 }
1556 DCHECK(end_address == ((intptr_t)address) - 4);
1557 if (instr->HasW()) {
1558 set_register(instr->RnValue(), rn_val);
1559 }
1560 }
1561
1562
1563 // Addressing Mode 6 - Load and Store Multiple Coprocessor registers.
HandleVList(Instruction * instr)1564 void Simulator::HandleVList(Instruction* instr) {
1565 VFPRegPrecision precision =
1566 (instr->SzValue() == 0) ? kSinglePrecision : kDoublePrecision;
1567 int operand_size = (precision == kSinglePrecision) ? 4 : 8;
1568
1569 bool load = (instr->VLValue() == 0x1);
1570
1571 int vd;
1572 int num_regs;
1573 vd = instr->VFPDRegValue(precision);
1574 if (precision == kSinglePrecision) {
1575 num_regs = instr->Immed8Value();
1576 } else {
1577 num_regs = instr->Immed8Value() / 2;
1578 }
1579
1580 intptr_t start_address = 0;
1581 intptr_t end_address = 0;
1582 int32_t rn_val =
1583 ProcessPU(instr, num_regs, operand_size, &start_address, &end_address);
1584
1585 intptr_t* address = reinterpret_cast<intptr_t*>(start_address);
1586 for (int reg = vd; reg < vd + num_regs; reg++) {
1587 if (precision == kSinglePrecision) {
1588 if (load) {
1589 set_s_register_from_sinteger(
1590 reg, ReadW(reinterpret_cast<int32_t>(address), instr));
1591 } else {
1592 WriteW(reinterpret_cast<int32_t>(address),
1593 get_sinteger_from_s_register(reg), instr);
1594 }
1595 address += 1;
1596 } else {
1597 if (load) {
1598 int32_t data[] = {
1599 ReadW(reinterpret_cast<int32_t>(address), instr),
1600 ReadW(reinterpret_cast<int32_t>(address + 1), instr)
1601 };
1602 set_d_register(reg, reinterpret_cast<uint32_t*>(data));
1603 } else {
1604 uint32_t data[2];
1605 get_d_register(reg, data);
1606 WriteW(reinterpret_cast<int32_t>(address), data[0], instr);
1607 WriteW(reinterpret_cast<int32_t>(address + 1), data[1], instr);
1608 }
1609 address += 2;
1610 }
1611 }
1612 DCHECK(reinterpret_cast<intptr_t>(address) - operand_size == end_address);
1613 if (instr->HasW()) {
1614 set_register(instr->RnValue(), rn_val);
1615 }
1616 }
1617
1618
1619 // Calls into the V8 runtime are based on this very simple interface.
1620 // Note: To be able to return two values from some calls the code in runtime.cc
1621 // uses the ObjectPair which is essentially two 32-bit values stuffed into a
1622 // 64-bit value. With the code below we assume that all runtime calls return
1623 // 64 bits of result. If they don't, the r1 result register contains a bogus
1624 // value, which is fine because it is caller-saved.
1625 typedef int64_t (*SimulatorRuntimeCall)(int32_t arg0,
1626 int32_t arg1,
1627 int32_t arg2,
1628 int32_t arg3,
1629 int32_t arg4,
1630 int32_t arg5);
1631
1632 typedef ObjectTriple (*SimulatorRuntimeTripleCall)(int32_t arg0, int32_t arg1,
1633 int32_t arg2, int32_t arg3,
1634 int32_t arg4);
1635
1636 // These prototypes handle the four types of FP calls.
1637 typedef int64_t (*SimulatorRuntimeCompareCall)(double darg0, double darg1);
1638 typedef double (*SimulatorRuntimeFPFPCall)(double darg0, double darg1);
1639 typedef double (*SimulatorRuntimeFPCall)(double darg0);
1640 typedef double (*SimulatorRuntimeFPIntCall)(double darg0, int32_t arg0);
1641
1642 // This signature supports direct call in to API function native callback
1643 // (refer to InvocationCallback in v8.h).
1644 typedef void (*SimulatorRuntimeDirectApiCall)(int32_t arg0);
1645 typedef void (*SimulatorRuntimeProfilingApiCall)(int32_t arg0, void* arg1);
1646
1647 // This signature supports direct call to accessor getter callback.
1648 typedef void (*SimulatorRuntimeDirectGetterCall)(int32_t arg0, int32_t arg1);
1649 typedef void (*SimulatorRuntimeProfilingGetterCall)(
1650 int32_t arg0, int32_t arg1, void* arg2);
1651
1652 // Software interrupt instructions are used by the simulator to call into the
1653 // C-based V8 runtime.
SoftwareInterrupt(Instruction * instr)1654 void Simulator::SoftwareInterrupt(Instruction* instr) {
1655 int svc = instr->SvcValue();
1656 switch (svc) {
1657 case kCallRtRedirected: {
1658 // Check if stack is aligned. Error if not aligned is reported below to
1659 // include information on the function called.
1660 bool stack_aligned =
1661 (get_register(sp)
1662 & (::v8::internal::FLAG_sim_stack_alignment - 1)) == 0;
1663 Redirection* redirection = Redirection::FromSwiInstruction(instr);
1664 int32_t arg0 = get_register(r0);
1665 int32_t arg1 = get_register(r1);
1666 int32_t arg2 = get_register(r2);
1667 int32_t arg3 = get_register(r3);
1668 int32_t* stack_pointer = reinterpret_cast<int32_t*>(get_register(sp));
1669 int32_t arg4 = stack_pointer[0];
1670 int32_t arg5 = stack_pointer[1];
1671 bool fp_call =
1672 (redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) ||
1673 (redirection->type() == ExternalReference::BUILTIN_COMPARE_CALL) ||
1674 (redirection->type() == ExternalReference::BUILTIN_FP_CALL) ||
1675 (redirection->type() == ExternalReference::BUILTIN_FP_INT_CALL);
1676 // This is dodgy but it works because the C entry stubs are never moved.
1677 // See comment in codegen-arm.cc and bug 1242173.
1678 int32_t saved_lr = get_register(lr);
1679 intptr_t external =
1680 reinterpret_cast<intptr_t>(redirection->external_function());
1681 if (fp_call) {
1682 double dval0, dval1; // one or two double parameters
1683 int32_t ival; // zero or one integer parameters
1684 int64_t iresult = 0; // integer return value
1685 double dresult = 0; // double return value
1686 GetFpArgs(&dval0, &dval1, &ival);
1687 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
1688 SimulatorRuntimeCall generic_target =
1689 reinterpret_cast<SimulatorRuntimeCall>(external);
1690 switch (redirection->type()) {
1691 case ExternalReference::BUILTIN_FP_FP_CALL:
1692 case ExternalReference::BUILTIN_COMPARE_CALL:
1693 PrintF("Call to host function at %p with args %f, %f",
1694 static_cast<void*>(FUNCTION_ADDR(generic_target)), dval0,
1695 dval1);
1696 break;
1697 case ExternalReference::BUILTIN_FP_CALL:
1698 PrintF("Call to host function at %p with arg %f",
1699 static_cast<void*>(FUNCTION_ADDR(generic_target)), dval0);
1700 break;
1701 case ExternalReference::BUILTIN_FP_INT_CALL:
1702 PrintF("Call to host function at %p with args %f, %d",
1703 static_cast<void*>(FUNCTION_ADDR(generic_target)), dval0,
1704 ival);
1705 break;
1706 default:
1707 UNREACHABLE();
1708 break;
1709 }
1710 if (!stack_aligned) {
1711 PrintF(" with unaligned stack %08x\n", get_register(sp));
1712 }
1713 PrintF("\n");
1714 }
1715 CHECK(stack_aligned);
1716 switch (redirection->type()) {
1717 case ExternalReference::BUILTIN_COMPARE_CALL: {
1718 SimulatorRuntimeCompareCall target =
1719 reinterpret_cast<SimulatorRuntimeCompareCall>(external);
1720 iresult = target(dval0, dval1);
1721 set_register(r0, static_cast<int32_t>(iresult));
1722 set_register(r1, static_cast<int32_t>(iresult >> 32));
1723 break;
1724 }
1725 case ExternalReference::BUILTIN_FP_FP_CALL: {
1726 SimulatorRuntimeFPFPCall target =
1727 reinterpret_cast<SimulatorRuntimeFPFPCall>(external);
1728 dresult = target(dval0, dval1);
1729 SetFpResult(dresult);
1730 break;
1731 }
1732 case ExternalReference::BUILTIN_FP_CALL: {
1733 SimulatorRuntimeFPCall target =
1734 reinterpret_cast<SimulatorRuntimeFPCall>(external);
1735 dresult = target(dval0);
1736 SetFpResult(dresult);
1737 break;
1738 }
1739 case ExternalReference::BUILTIN_FP_INT_CALL: {
1740 SimulatorRuntimeFPIntCall target =
1741 reinterpret_cast<SimulatorRuntimeFPIntCall>(external);
1742 dresult = target(dval0, ival);
1743 SetFpResult(dresult);
1744 break;
1745 }
1746 default:
1747 UNREACHABLE();
1748 break;
1749 }
1750 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
1751 switch (redirection->type()) {
1752 case ExternalReference::BUILTIN_COMPARE_CALL:
1753 PrintF("Returned %08x\n", static_cast<int32_t>(iresult));
1754 break;
1755 case ExternalReference::BUILTIN_FP_FP_CALL:
1756 case ExternalReference::BUILTIN_FP_CALL:
1757 case ExternalReference::BUILTIN_FP_INT_CALL:
1758 PrintF("Returned %f\n", dresult);
1759 break;
1760 default:
1761 UNREACHABLE();
1762 break;
1763 }
1764 }
1765 } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) {
1766 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
1767 PrintF("Call to host function at %p args %08x",
1768 reinterpret_cast<void*>(external), arg0);
1769 if (!stack_aligned) {
1770 PrintF(" with unaligned stack %08x\n", get_register(sp));
1771 }
1772 PrintF("\n");
1773 }
1774 CHECK(stack_aligned);
1775 SimulatorRuntimeDirectApiCall target =
1776 reinterpret_cast<SimulatorRuntimeDirectApiCall>(external);
1777 target(arg0);
1778 } else if (
1779 redirection->type() == ExternalReference::PROFILING_API_CALL) {
1780 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
1781 PrintF("Call to host function at %p args %08x %08x",
1782 reinterpret_cast<void*>(external), arg0, arg1);
1783 if (!stack_aligned) {
1784 PrintF(" with unaligned stack %08x\n", get_register(sp));
1785 }
1786 PrintF("\n");
1787 }
1788 CHECK(stack_aligned);
1789 SimulatorRuntimeProfilingApiCall target =
1790 reinterpret_cast<SimulatorRuntimeProfilingApiCall>(external);
1791 target(arg0, Redirection::ReverseRedirection(arg1));
1792 } else if (
1793 redirection->type() == ExternalReference::DIRECT_GETTER_CALL) {
1794 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
1795 PrintF("Call to host function at %p args %08x %08x",
1796 reinterpret_cast<void*>(external), arg0, arg1);
1797 if (!stack_aligned) {
1798 PrintF(" with unaligned stack %08x\n", get_register(sp));
1799 }
1800 PrintF("\n");
1801 }
1802 CHECK(stack_aligned);
1803 SimulatorRuntimeDirectGetterCall target =
1804 reinterpret_cast<SimulatorRuntimeDirectGetterCall>(external);
1805 target(arg0, arg1);
1806 } else if (
1807 redirection->type() == ExternalReference::PROFILING_GETTER_CALL) {
1808 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
1809 PrintF("Call to host function at %p args %08x %08x %08x",
1810 reinterpret_cast<void*>(external), arg0, arg1, arg2);
1811 if (!stack_aligned) {
1812 PrintF(" with unaligned stack %08x\n", get_register(sp));
1813 }
1814 PrintF("\n");
1815 }
1816 CHECK(stack_aligned);
1817 SimulatorRuntimeProfilingGetterCall target =
1818 reinterpret_cast<SimulatorRuntimeProfilingGetterCall>(
1819 external);
1820 target(arg0, arg1, Redirection::ReverseRedirection(arg2));
1821 } else if (redirection->type() ==
1822 ExternalReference::BUILTIN_CALL_TRIPLE) {
1823 // builtin call returning ObjectTriple.
1824 SimulatorRuntimeTripleCall target =
1825 reinterpret_cast<SimulatorRuntimeTripleCall>(external);
1826 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
1827 PrintF(
1828 "Call to host triple returning runtime function %p "
1829 "args %08x, %08x, %08x, %08x, %08x",
1830 static_cast<void*>(FUNCTION_ADDR(target)), arg1, arg2, arg3, arg4,
1831 arg5);
1832 if (!stack_aligned) {
1833 PrintF(" with unaligned stack %08x\n", get_register(sp));
1834 }
1835 PrintF("\n");
1836 }
1837 CHECK(stack_aligned);
1838 // arg0 is a hidden argument pointing to the return location, so don't
1839 // pass it to the target function.
1840 ObjectTriple result = target(arg1, arg2, arg3, arg4, arg5);
1841 if (::v8::internal::FLAG_trace_sim) {
1842 PrintF("Returned { %p, %p, %p }\n", static_cast<void*>(result.x),
1843 static_cast<void*>(result.y), static_cast<void*>(result.z));
1844 }
1845 // Return is passed back in address pointed to by hidden first argument.
1846 ObjectTriple* sim_result = reinterpret_cast<ObjectTriple*>(arg0);
1847 *sim_result = result;
1848 set_register(r0, arg0);
1849 } else {
1850 // builtin call.
1851 DCHECK(redirection->type() == ExternalReference::BUILTIN_CALL ||
1852 redirection->type() == ExternalReference::BUILTIN_CALL_PAIR);
1853 SimulatorRuntimeCall target =
1854 reinterpret_cast<SimulatorRuntimeCall>(external);
1855 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
1856 PrintF(
1857 "Call to host function at %p "
1858 "args %08x, %08x, %08x, %08x, %08x, %08x",
1859 static_cast<void*>(FUNCTION_ADDR(target)), arg0, arg1, arg2, arg3,
1860 arg4, arg5);
1861 if (!stack_aligned) {
1862 PrintF(" with unaligned stack %08x\n", get_register(sp));
1863 }
1864 PrintF("\n");
1865 }
1866 CHECK(stack_aligned);
1867 int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5);
1868 int32_t lo_res = static_cast<int32_t>(result);
1869 int32_t hi_res = static_cast<int32_t>(result >> 32);
1870 if (::v8::internal::FLAG_trace_sim) {
1871 PrintF("Returned %08x\n", lo_res);
1872 }
1873 set_register(r0, lo_res);
1874 set_register(r1, hi_res);
1875 }
1876 set_register(lr, saved_lr);
1877 set_pc(get_register(lr));
1878 break;
1879 }
1880 case kBreakpoint: {
1881 ArmDebugger dbg(this);
1882 dbg.Debug();
1883 break;
1884 }
1885 // stop uses all codes greater than 1 << 23.
1886 default: {
1887 if (svc >= (1 << 23)) {
1888 uint32_t code = svc & kStopCodeMask;
1889 if (isWatchedStop(code)) {
1890 IncreaseStopCounter(code);
1891 }
1892 // Stop if it is enabled, otherwise go on jumping over the stop
1893 // and the message address.
1894 if (isEnabledStop(code)) {
1895 ArmDebugger dbg(this);
1896 dbg.Stop(instr);
1897 } else {
1898 set_pc(get_pc() + 2 * Instruction::kInstrSize);
1899 }
1900 } else {
1901 // This is not a valid svc code.
1902 UNREACHABLE();
1903 break;
1904 }
1905 }
1906 }
1907 }
1908
1909
canonicalizeNaN(float value)1910 float Simulator::canonicalizeNaN(float value) {
1911 // Default NaN value, see "NaN handling" in "IEEE 754 standard implementation
1912 // choices" of the ARM Reference Manual.
1913 const uint32_t kDefaultNaN = 0x7FC00000u;
1914 if (FPSCR_default_NaN_mode_ && std::isnan(value)) {
1915 value = bit_cast<float>(kDefaultNaN);
1916 }
1917 return value;
1918 }
1919
1920
canonicalizeNaN(double value)1921 double Simulator::canonicalizeNaN(double value) {
1922 // Default NaN value, see "NaN handling" in "IEEE 754 standard implementation
1923 // choices" of the ARM Reference Manual.
1924 const uint64_t kDefaultNaN = V8_UINT64_C(0x7FF8000000000000);
1925 if (FPSCR_default_NaN_mode_ && std::isnan(value)) {
1926 value = bit_cast<double>(kDefaultNaN);
1927 }
1928 return value;
1929 }
1930
1931
1932 // Stop helper functions.
isStopInstruction(Instruction * instr)1933 bool Simulator::isStopInstruction(Instruction* instr) {
1934 return (instr->Bits(27, 24) == 0xF) && (instr->SvcValue() >= kStopCode);
1935 }
1936
1937
isWatchedStop(uint32_t code)1938 bool Simulator::isWatchedStop(uint32_t code) {
1939 DCHECK(code <= kMaxStopCode);
1940 return code < kNumOfWatchedStops;
1941 }
1942
1943
isEnabledStop(uint32_t code)1944 bool Simulator::isEnabledStop(uint32_t code) {
1945 DCHECK(code <= kMaxStopCode);
1946 // Unwatched stops are always enabled.
1947 return !isWatchedStop(code) ||
1948 !(watched_stops_[code].count & kStopDisabledBit);
1949 }
1950
1951
EnableStop(uint32_t code)1952 void Simulator::EnableStop(uint32_t code) {
1953 DCHECK(isWatchedStop(code));
1954 if (!isEnabledStop(code)) {
1955 watched_stops_[code].count &= ~kStopDisabledBit;
1956 }
1957 }
1958
1959
DisableStop(uint32_t code)1960 void Simulator::DisableStop(uint32_t code) {
1961 DCHECK(isWatchedStop(code));
1962 if (isEnabledStop(code)) {
1963 watched_stops_[code].count |= kStopDisabledBit;
1964 }
1965 }
1966
1967
IncreaseStopCounter(uint32_t code)1968 void Simulator::IncreaseStopCounter(uint32_t code) {
1969 DCHECK(code <= kMaxStopCode);
1970 DCHECK(isWatchedStop(code));
1971 if ((watched_stops_[code].count & ~(1 << 31)) == 0x7fffffff) {
1972 PrintF("Stop counter for code %i has overflowed.\n"
1973 "Enabling this code and reseting the counter to 0.\n", code);
1974 watched_stops_[code].count = 0;
1975 EnableStop(code);
1976 } else {
1977 watched_stops_[code].count++;
1978 }
1979 }
1980
1981
1982 // Print a stop status.
PrintStopInfo(uint32_t code)1983 void Simulator::PrintStopInfo(uint32_t code) {
1984 DCHECK(code <= kMaxStopCode);
1985 if (!isWatchedStop(code)) {
1986 PrintF("Stop not watched.");
1987 } else {
1988 const char* state = isEnabledStop(code) ? "Enabled" : "Disabled";
1989 int32_t count = watched_stops_[code].count & ~kStopDisabledBit;
1990 // Don't print the state of unused breakpoints.
1991 if (count != 0) {
1992 if (watched_stops_[code].desc) {
1993 PrintF("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n",
1994 code, code, state, count, watched_stops_[code].desc);
1995 } else {
1996 PrintF("stop %i - 0x%x: \t%s, \tcounter = %i\n",
1997 code, code, state, count);
1998 }
1999 }
2000 }
2001 }
2002
2003
2004 // Handle execution based on instruction types.
2005
2006 // Instruction types 0 and 1 are both rolled into one function because they
2007 // only differ in the handling of the shifter_operand.
DecodeType01(Instruction * instr)2008 void Simulator::DecodeType01(Instruction* instr) {
2009 int type = instr->TypeValue();
2010 if ((type == 0) && instr->IsSpecialType0()) {
2011 // multiply instruction or extra loads and stores
2012 if (instr->Bits(7, 4) == 9) {
2013 if (instr->Bit(24) == 0) {
2014 // Raw field decoding here. Multiply instructions have their Rd in
2015 // funny places.
2016 int rn = instr->RnValue();
2017 int rm = instr->RmValue();
2018 int rs = instr->RsValue();
2019 int32_t rs_val = get_register(rs);
2020 int32_t rm_val = get_register(rm);
2021 if (instr->Bit(23) == 0) {
2022 if (instr->Bit(21) == 0) {
2023 // The MUL instruction description (A 4.1.33) refers to Rd as being
2024 // the destination for the operation, but it confusingly uses the
2025 // Rn field to encode it.
2026 // Format(instr, "mul'cond's 'rn, 'rm, 'rs");
2027 int rd = rn; // Remap the rn field to the Rd register.
2028 int32_t alu_out = rm_val * rs_val;
2029 set_register(rd, alu_out);
2030 if (instr->HasS()) {
2031 SetNZFlags(alu_out);
2032 }
2033 } else {
2034 int rd = instr->RdValue();
2035 int32_t acc_value = get_register(rd);
2036 if (instr->Bit(22) == 0) {
2037 // The MLA instruction description (A 4.1.28) refers to the order
2038 // of registers as "Rd, Rm, Rs, Rn". But confusingly it uses the
2039 // Rn field to encode the Rd register and the Rd field to encode
2040 // the Rn register.
2041 // Format(instr, "mla'cond's 'rn, 'rm, 'rs, 'rd");
2042 int32_t mul_out = rm_val * rs_val;
2043 int32_t result = acc_value + mul_out;
2044 set_register(rn, result);
2045 } else {
2046 // Format(instr, "mls'cond's 'rn, 'rm, 'rs, 'rd");
2047 int32_t mul_out = rm_val * rs_val;
2048 int32_t result = acc_value - mul_out;
2049 set_register(rn, result);
2050 }
2051 }
2052 } else {
2053 // The signed/long multiply instructions use the terms RdHi and RdLo
2054 // when referring to the target registers. They are mapped to the Rn
2055 // and Rd fields as follows:
2056 // RdLo == Rd
2057 // RdHi == Rn (This is confusingly stored in variable rd here
2058 // because the mul instruction from above uses the
2059 // Rn field to encode the Rd register. Good luck figuring
2060 // this out without reading the ARM instruction manual
2061 // at a very detailed level.)
2062 // Format(instr, "'um'al'cond's 'rd, 'rn, 'rs, 'rm");
2063 int rd_hi = rn; // Remap the rn field to the RdHi register.
2064 int rd_lo = instr->RdValue();
2065 int32_t hi_res = 0;
2066 int32_t lo_res = 0;
2067 if (instr->Bit(22) == 1) {
2068 int64_t left_op = static_cast<int32_t>(rm_val);
2069 int64_t right_op = static_cast<int32_t>(rs_val);
2070 uint64_t result = left_op * right_op;
2071 hi_res = static_cast<int32_t>(result >> 32);
2072 lo_res = static_cast<int32_t>(result & 0xffffffff);
2073 } else {
2074 // unsigned multiply
2075 uint64_t left_op = static_cast<uint32_t>(rm_val);
2076 uint64_t right_op = static_cast<uint32_t>(rs_val);
2077 uint64_t result = left_op * right_op;
2078 hi_res = static_cast<int32_t>(result >> 32);
2079 lo_res = static_cast<int32_t>(result & 0xffffffff);
2080 }
2081 set_register(rd_lo, lo_res);
2082 set_register(rd_hi, hi_res);
2083 if (instr->HasS()) {
2084 UNIMPLEMENTED();
2085 }
2086 }
2087 } else {
2088 UNIMPLEMENTED(); // Not used by V8.
2089 }
2090 } else {
2091 // extra load/store instructions
2092 int rd = instr->RdValue();
2093 int rn = instr->RnValue();
2094 int32_t rn_val = get_register(rn);
2095 int32_t addr = 0;
2096 if (instr->Bit(22) == 0) {
2097 int rm = instr->RmValue();
2098 int32_t rm_val = get_register(rm);
2099 switch (instr->PUField()) {
2100 case da_x: {
2101 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], -'rm");
2102 DCHECK(!instr->HasW());
2103 addr = rn_val;
2104 rn_val -= rm_val;
2105 set_register(rn, rn_val);
2106 break;
2107 }
2108 case ia_x: {
2109 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], +'rm");
2110 DCHECK(!instr->HasW());
2111 addr = rn_val;
2112 rn_val += rm_val;
2113 set_register(rn, rn_val);
2114 break;
2115 }
2116 case db_x: {
2117 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, -'rm]'w");
2118 rn_val -= rm_val;
2119 addr = rn_val;
2120 if (instr->HasW()) {
2121 set_register(rn, rn_val);
2122 }
2123 break;
2124 }
2125 case ib_x: {
2126 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, +'rm]'w");
2127 rn_val += rm_val;
2128 addr = rn_val;
2129 if (instr->HasW()) {
2130 set_register(rn, rn_val);
2131 }
2132 break;
2133 }
2134 default: {
2135 // The PU field is a 2-bit field.
2136 UNREACHABLE();
2137 break;
2138 }
2139 }
2140 } else {
2141 int32_t imm_val = (instr->ImmedHValue() << 4) | instr->ImmedLValue();
2142 switch (instr->PUField()) {
2143 case da_x: {
2144 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], #-'off8");
2145 DCHECK(!instr->HasW());
2146 addr = rn_val;
2147 rn_val -= imm_val;
2148 set_register(rn, rn_val);
2149 break;
2150 }
2151 case ia_x: {
2152 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], #+'off8");
2153 DCHECK(!instr->HasW());
2154 addr = rn_val;
2155 rn_val += imm_val;
2156 set_register(rn, rn_val);
2157 break;
2158 }
2159 case db_x: {
2160 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, #-'off8]'w");
2161 rn_val -= imm_val;
2162 addr = rn_val;
2163 if (instr->HasW()) {
2164 set_register(rn, rn_val);
2165 }
2166 break;
2167 }
2168 case ib_x: {
2169 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, #+'off8]'w");
2170 rn_val += imm_val;
2171 addr = rn_val;
2172 if (instr->HasW()) {
2173 set_register(rn, rn_val);
2174 }
2175 break;
2176 }
2177 default: {
2178 // The PU field is a 2-bit field.
2179 UNREACHABLE();
2180 break;
2181 }
2182 }
2183 }
2184 if (((instr->Bits(7, 4) & 0xd) == 0xd) && (instr->Bit(20) == 0)) {
2185 DCHECK((rd % 2) == 0);
2186 if (instr->HasH()) {
2187 // The strd instruction.
2188 int32_t value1 = get_register(rd);
2189 int32_t value2 = get_register(rd+1);
2190 WriteDW(addr, value1, value2);
2191 } else {
2192 // The ldrd instruction.
2193 int* rn_data = ReadDW(addr);
2194 set_dw_register(rd, rn_data);
2195 }
2196 } else if (instr->HasH()) {
2197 if (instr->HasSign()) {
2198 if (instr->HasL()) {
2199 int16_t val = ReadH(addr, instr);
2200 set_register(rd, val);
2201 } else {
2202 int16_t val = get_register(rd);
2203 WriteH(addr, val, instr);
2204 }
2205 } else {
2206 if (instr->HasL()) {
2207 uint16_t val = ReadHU(addr, instr);
2208 set_register(rd, val);
2209 } else {
2210 uint16_t val = get_register(rd);
2211 WriteH(addr, val, instr);
2212 }
2213 }
2214 } else {
2215 // signed byte loads
2216 DCHECK(instr->HasSign());
2217 DCHECK(instr->HasL());
2218 int8_t val = ReadB(addr);
2219 set_register(rd, val);
2220 }
2221 return;
2222 }
2223 } else if ((type == 0) && instr->IsMiscType0()) {
2224 if ((instr->Bits(27, 23) == 2) && (instr->Bits(21, 20) == 2) &&
2225 (instr->Bits(15, 4) == 0xf00)) {
2226 // MSR
2227 int rm = instr->RmValue();
2228 DCHECK_NE(pc, rm); // UNPREDICTABLE
2229 SRegisterFieldMask sreg_and_mask =
2230 instr->BitField(22, 22) | instr->BitField(19, 16);
2231 SetSpecialRegister(sreg_and_mask, get_register(rm));
2232 } else if ((instr->Bits(27, 23) == 2) && (instr->Bits(21, 20) == 0) &&
2233 (instr->Bits(11, 0) == 0)) {
2234 // MRS
2235 int rd = instr->RdValue();
2236 DCHECK_NE(pc, rd); // UNPREDICTABLE
2237 SRegister sreg = static_cast<SRegister>(instr->BitField(22, 22));
2238 set_register(rd, GetFromSpecialRegister(sreg));
2239 } else if (instr->Bits(22, 21) == 1) {
2240 int rm = instr->RmValue();
2241 switch (instr->BitField(7, 4)) {
2242 case BX:
2243 set_pc(get_register(rm));
2244 break;
2245 case BLX: {
2246 uint32_t old_pc = get_pc();
2247 set_pc(get_register(rm));
2248 set_register(lr, old_pc + Instruction::kInstrSize);
2249 break;
2250 }
2251 case BKPT: {
2252 ArmDebugger dbg(this);
2253 PrintF("Simulator hit BKPT.\n");
2254 dbg.Debug();
2255 break;
2256 }
2257 default:
2258 UNIMPLEMENTED();
2259 }
2260 } else if (instr->Bits(22, 21) == 3) {
2261 int rm = instr->RmValue();
2262 int rd = instr->RdValue();
2263 switch (instr->BitField(7, 4)) {
2264 case CLZ: {
2265 uint32_t bits = get_register(rm);
2266 int leading_zeros = 0;
2267 if (bits == 0) {
2268 leading_zeros = 32;
2269 } else {
2270 while ((bits & 0x80000000u) == 0) {
2271 bits <<= 1;
2272 leading_zeros++;
2273 }
2274 }
2275 set_register(rd, leading_zeros);
2276 break;
2277 }
2278 default:
2279 UNIMPLEMENTED();
2280 }
2281 } else {
2282 PrintF("%08x\n", instr->InstructionBits());
2283 UNIMPLEMENTED();
2284 }
2285 } else if ((type == 1) && instr->IsNopType1()) {
2286 // NOP.
2287 } else {
2288 int rd = instr->RdValue();
2289 int rn = instr->RnValue();
2290 int32_t rn_val = get_register(rn);
2291 int32_t shifter_operand = 0;
2292 bool shifter_carry_out = 0;
2293 if (type == 0) {
2294 shifter_operand = GetShiftRm(instr, &shifter_carry_out);
2295 } else {
2296 DCHECK(instr->TypeValue() == 1);
2297 shifter_operand = GetImm(instr, &shifter_carry_out);
2298 }
2299 int32_t alu_out;
2300
2301 switch (instr->OpcodeField()) {
2302 case AND: {
2303 // Format(instr, "and'cond's 'rd, 'rn, 'shift_rm");
2304 // Format(instr, "and'cond's 'rd, 'rn, 'imm");
2305 alu_out = rn_val & shifter_operand;
2306 set_register(rd, alu_out);
2307 if (instr->HasS()) {
2308 SetNZFlags(alu_out);
2309 SetCFlag(shifter_carry_out);
2310 }
2311 break;
2312 }
2313
2314 case EOR: {
2315 // Format(instr, "eor'cond's 'rd, 'rn, 'shift_rm");
2316 // Format(instr, "eor'cond's 'rd, 'rn, 'imm");
2317 alu_out = rn_val ^ shifter_operand;
2318 set_register(rd, alu_out);
2319 if (instr->HasS()) {
2320 SetNZFlags(alu_out);
2321 SetCFlag(shifter_carry_out);
2322 }
2323 break;
2324 }
2325
2326 case SUB: {
2327 // Format(instr, "sub'cond's 'rd, 'rn, 'shift_rm");
2328 // Format(instr, "sub'cond's 'rd, 'rn, 'imm");
2329 alu_out = rn_val - shifter_operand;
2330 set_register(rd, alu_out);
2331 if (instr->HasS()) {
2332 SetNZFlags(alu_out);
2333 SetCFlag(!BorrowFrom(rn_val, shifter_operand));
2334 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, false));
2335 }
2336 break;
2337 }
2338
2339 case RSB: {
2340 // Format(instr, "rsb'cond's 'rd, 'rn, 'shift_rm");
2341 // Format(instr, "rsb'cond's 'rd, 'rn, 'imm");
2342 alu_out = shifter_operand - rn_val;
2343 set_register(rd, alu_out);
2344 if (instr->HasS()) {
2345 SetNZFlags(alu_out);
2346 SetCFlag(!BorrowFrom(shifter_operand, rn_val));
2347 SetVFlag(OverflowFrom(alu_out, shifter_operand, rn_val, false));
2348 }
2349 break;
2350 }
2351
2352 case ADD: {
2353 // Format(instr, "add'cond's 'rd, 'rn, 'shift_rm");
2354 // Format(instr, "add'cond's 'rd, 'rn, 'imm");
2355 alu_out = rn_val + shifter_operand;
2356 set_register(rd, alu_out);
2357 if (instr->HasS()) {
2358 SetNZFlags(alu_out);
2359 SetCFlag(CarryFrom(rn_val, shifter_operand));
2360 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, true));
2361 }
2362 break;
2363 }
2364
2365 case ADC: {
2366 // Format(instr, "adc'cond's 'rd, 'rn, 'shift_rm");
2367 // Format(instr, "adc'cond's 'rd, 'rn, 'imm");
2368 alu_out = rn_val + shifter_operand + GetCarry();
2369 set_register(rd, alu_out);
2370 if (instr->HasS()) {
2371 SetNZFlags(alu_out);
2372 SetCFlag(CarryFrom(rn_val, shifter_operand, GetCarry()));
2373 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, true));
2374 }
2375 break;
2376 }
2377
2378 case SBC: {
2379 // Format(instr, "sbc'cond's 'rd, 'rn, 'shift_rm");
2380 // Format(instr, "sbc'cond's 'rd, 'rn, 'imm");
2381 alu_out = (rn_val - shifter_operand) - (GetCarry() ? 0 : 1);
2382 set_register(rd, alu_out);
2383 if (instr->HasS()) {
2384 SetNZFlags(alu_out);
2385 SetCFlag(!BorrowFrom(rn_val, shifter_operand, GetCarry()));
2386 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, false));
2387 }
2388 break;
2389 }
2390
2391 case RSC: {
2392 Format(instr, "rsc'cond's 'rd, 'rn, 'shift_rm");
2393 Format(instr, "rsc'cond's 'rd, 'rn, 'imm");
2394 break;
2395 }
2396
2397 case TST: {
2398 if (instr->HasS()) {
2399 // Format(instr, "tst'cond 'rn, 'shift_rm");
2400 // Format(instr, "tst'cond 'rn, 'imm");
2401 alu_out = rn_val & shifter_operand;
2402 SetNZFlags(alu_out);
2403 SetCFlag(shifter_carry_out);
2404 } else {
2405 // Format(instr, "movw'cond 'rd, 'imm").
2406 alu_out = instr->ImmedMovwMovtValue();
2407 set_register(rd, alu_out);
2408 }
2409 break;
2410 }
2411
2412 case TEQ: {
2413 if (instr->HasS()) {
2414 // Format(instr, "teq'cond 'rn, 'shift_rm");
2415 // Format(instr, "teq'cond 'rn, 'imm");
2416 alu_out = rn_val ^ shifter_operand;
2417 SetNZFlags(alu_out);
2418 SetCFlag(shifter_carry_out);
2419 } else {
2420 // Other instructions matching this pattern are handled in the
2421 // miscellaneous instructions part above.
2422 UNREACHABLE();
2423 }
2424 break;
2425 }
2426
2427 case CMP: {
2428 if (instr->HasS()) {
2429 // Format(instr, "cmp'cond 'rn, 'shift_rm");
2430 // Format(instr, "cmp'cond 'rn, 'imm");
2431 alu_out = rn_val - shifter_operand;
2432 SetNZFlags(alu_out);
2433 SetCFlag(!BorrowFrom(rn_val, shifter_operand));
2434 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, false));
2435 } else {
2436 // Format(instr, "movt'cond 'rd, 'imm").
2437 alu_out = (get_register(rd) & 0xffff) |
2438 (instr->ImmedMovwMovtValue() << 16);
2439 set_register(rd, alu_out);
2440 }
2441 break;
2442 }
2443
2444 case CMN: {
2445 if (instr->HasS()) {
2446 // Format(instr, "cmn'cond 'rn, 'shift_rm");
2447 // Format(instr, "cmn'cond 'rn, 'imm");
2448 alu_out = rn_val + shifter_operand;
2449 SetNZFlags(alu_out);
2450 SetCFlag(CarryFrom(rn_val, shifter_operand));
2451 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, true));
2452 } else {
2453 // Other instructions matching this pattern are handled in the
2454 // miscellaneous instructions part above.
2455 UNREACHABLE();
2456 }
2457 break;
2458 }
2459
2460 case ORR: {
2461 // Format(instr, "orr'cond's 'rd, 'rn, 'shift_rm");
2462 // Format(instr, "orr'cond's 'rd, 'rn, 'imm");
2463 alu_out = rn_val | shifter_operand;
2464 set_register(rd, alu_out);
2465 if (instr->HasS()) {
2466 SetNZFlags(alu_out);
2467 SetCFlag(shifter_carry_out);
2468 }
2469 break;
2470 }
2471
2472 case MOV: {
2473 // Format(instr, "mov'cond's 'rd, 'shift_rm");
2474 // Format(instr, "mov'cond's 'rd, 'imm");
2475 alu_out = shifter_operand;
2476 set_register(rd, alu_out);
2477 if (instr->HasS()) {
2478 SetNZFlags(alu_out);
2479 SetCFlag(shifter_carry_out);
2480 }
2481 break;
2482 }
2483
2484 case BIC: {
2485 // Format(instr, "bic'cond's 'rd, 'rn, 'shift_rm");
2486 // Format(instr, "bic'cond's 'rd, 'rn, 'imm");
2487 alu_out = rn_val & ~shifter_operand;
2488 set_register(rd, alu_out);
2489 if (instr->HasS()) {
2490 SetNZFlags(alu_out);
2491 SetCFlag(shifter_carry_out);
2492 }
2493 break;
2494 }
2495
2496 case MVN: {
2497 // Format(instr, "mvn'cond's 'rd, 'shift_rm");
2498 // Format(instr, "mvn'cond's 'rd, 'imm");
2499 alu_out = ~shifter_operand;
2500 set_register(rd, alu_out);
2501 if (instr->HasS()) {
2502 SetNZFlags(alu_out);
2503 SetCFlag(shifter_carry_out);
2504 }
2505 break;
2506 }
2507
2508 default: {
2509 UNREACHABLE();
2510 break;
2511 }
2512 }
2513 }
2514 }
2515
2516
DecodeType2(Instruction * instr)2517 void Simulator::DecodeType2(Instruction* instr) {
2518 int rd = instr->RdValue();
2519 int rn = instr->RnValue();
2520 int32_t rn_val = get_register(rn);
2521 int32_t im_val = instr->Offset12Value();
2522 int32_t addr = 0;
2523 switch (instr->PUField()) {
2524 case da_x: {
2525 // Format(instr, "'memop'cond'b 'rd, ['rn], #-'off12");
2526 DCHECK(!instr->HasW());
2527 addr = rn_val;
2528 rn_val -= im_val;
2529 set_register(rn, rn_val);
2530 break;
2531 }
2532 case ia_x: {
2533 // Format(instr, "'memop'cond'b 'rd, ['rn], #+'off12");
2534 DCHECK(!instr->HasW());
2535 addr = rn_val;
2536 rn_val += im_val;
2537 set_register(rn, rn_val);
2538 break;
2539 }
2540 case db_x: {
2541 // Format(instr, "'memop'cond'b 'rd, ['rn, #-'off12]'w");
2542 rn_val -= im_val;
2543 addr = rn_val;
2544 if (instr->HasW()) {
2545 set_register(rn, rn_val);
2546 }
2547 break;
2548 }
2549 case ib_x: {
2550 // Format(instr, "'memop'cond'b 'rd, ['rn, #+'off12]'w");
2551 rn_val += im_val;
2552 addr = rn_val;
2553 if (instr->HasW()) {
2554 set_register(rn, rn_val);
2555 }
2556 break;
2557 }
2558 default: {
2559 UNREACHABLE();
2560 break;
2561 }
2562 }
2563 if (instr->HasB()) {
2564 if (instr->HasL()) {
2565 byte val = ReadBU(addr);
2566 set_register(rd, val);
2567 } else {
2568 byte val = get_register(rd);
2569 WriteB(addr, val);
2570 }
2571 } else {
2572 if (instr->HasL()) {
2573 set_register(rd, ReadW(addr, instr));
2574 } else {
2575 WriteW(addr, get_register(rd), instr);
2576 }
2577 }
2578 }
2579
2580
DecodeType3(Instruction * instr)2581 void Simulator::DecodeType3(Instruction* instr) {
2582 int rd = instr->RdValue();
2583 int rn = instr->RnValue();
2584 int32_t rn_val = get_register(rn);
2585 bool shifter_carry_out = 0;
2586 int32_t shifter_operand = GetShiftRm(instr, &shifter_carry_out);
2587 int32_t addr = 0;
2588 switch (instr->PUField()) {
2589 case da_x: {
2590 DCHECK(!instr->HasW());
2591 Format(instr, "'memop'cond'b 'rd, ['rn], -'shift_rm");
2592 UNIMPLEMENTED();
2593 break;
2594 }
2595 case ia_x: {
2596 if (instr->Bit(4) == 0) {
2597 // Memop.
2598 } else {
2599 if (instr->Bit(5) == 0) {
2600 switch (instr->Bits(22, 21)) {
2601 case 0:
2602 if (instr->Bit(20) == 0) {
2603 if (instr->Bit(6) == 0) {
2604 // Pkhbt.
2605 uint32_t rn_val = get_register(rn);
2606 uint32_t rm_val = get_register(instr->RmValue());
2607 int32_t shift = instr->Bits(11, 7);
2608 rm_val <<= shift;
2609 set_register(rd, (rn_val & 0xFFFF) | (rm_val & 0xFFFF0000U));
2610 } else {
2611 // Pkhtb.
2612 uint32_t rn_val = get_register(rn);
2613 int32_t rm_val = get_register(instr->RmValue());
2614 int32_t shift = instr->Bits(11, 7);
2615 if (shift == 0) {
2616 shift = 32;
2617 }
2618 rm_val >>= shift;
2619 set_register(rd, (rn_val & 0xFFFF0000U) | (rm_val & 0xFFFF));
2620 }
2621 } else {
2622 UNIMPLEMENTED();
2623 }
2624 break;
2625 case 1:
2626 UNIMPLEMENTED();
2627 break;
2628 case 2:
2629 UNIMPLEMENTED();
2630 break;
2631 case 3: {
2632 // Usat.
2633 int32_t sat_pos = instr->Bits(20, 16);
2634 int32_t sat_val = (1 << sat_pos) - 1;
2635 int32_t shift = instr->Bits(11, 7);
2636 int32_t shift_type = instr->Bit(6);
2637 int32_t rm_val = get_register(instr->RmValue());
2638 if (shift_type == 0) { // LSL
2639 rm_val <<= shift;
2640 } else { // ASR
2641 rm_val >>= shift;
2642 }
2643 // If saturation occurs, the Q flag should be set in the CPSR.
2644 // There is no Q flag yet, and no instruction (MRS) to read the
2645 // CPSR directly.
2646 if (rm_val > sat_val) {
2647 rm_val = sat_val;
2648 } else if (rm_val < 0) {
2649 rm_val = 0;
2650 }
2651 set_register(rd, rm_val);
2652 break;
2653 }
2654 }
2655 } else {
2656 switch (instr->Bits(22, 21)) {
2657 case 0:
2658 UNIMPLEMENTED();
2659 break;
2660 case 1:
2661 if (instr->Bits(9, 6) == 1) {
2662 if (instr->Bit(20) == 0) {
2663 if (instr->Bits(19, 16) == 0xF) {
2664 // Sxtb.
2665 int32_t rm_val = get_register(instr->RmValue());
2666 int32_t rotate = instr->Bits(11, 10);
2667 switch (rotate) {
2668 case 0:
2669 break;
2670 case 1:
2671 rm_val = (rm_val >> 8) | (rm_val << 24);
2672 break;
2673 case 2:
2674 rm_val = (rm_val >> 16) | (rm_val << 16);
2675 break;
2676 case 3:
2677 rm_val = (rm_val >> 24) | (rm_val << 8);
2678 break;
2679 }
2680 set_register(rd, static_cast<int8_t>(rm_val));
2681 } else {
2682 // Sxtab.
2683 int32_t rn_val = get_register(rn);
2684 int32_t rm_val = get_register(instr->RmValue());
2685 int32_t rotate = instr->Bits(11, 10);
2686 switch (rotate) {
2687 case 0:
2688 break;
2689 case 1:
2690 rm_val = (rm_val >> 8) | (rm_val << 24);
2691 break;
2692 case 2:
2693 rm_val = (rm_val >> 16) | (rm_val << 16);
2694 break;
2695 case 3:
2696 rm_val = (rm_val >> 24) | (rm_val << 8);
2697 break;
2698 }
2699 set_register(rd, rn_val + static_cast<int8_t>(rm_val));
2700 }
2701 } else {
2702 if (instr->Bits(19, 16) == 0xF) {
2703 // Sxth.
2704 int32_t rm_val = get_register(instr->RmValue());
2705 int32_t rotate = instr->Bits(11, 10);
2706 switch (rotate) {
2707 case 0:
2708 break;
2709 case 1:
2710 rm_val = (rm_val >> 8) | (rm_val << 24);
2711 break;
2712 case 2:
2713 rm_val = (rm_val >> 16) | (rm_val << 16);
2714 break;
2715 case 3:
2716 rm_val = (rm_val >> 24) | (rm_val << 8);
2717 break;
2718 }
2719 set_register(rd, static_cast<int16_t>(rm_val));
2720 } else {
2721 // Sxtah.
2722 int32_t rn_val = get_register(rn);
2723 int32_t rm_val = get_register(instr->RmValue());
2724 int32_t rotate = instr->Bits(11, 10);
2725 switch (rotate) {
2726 case 0:
2727 break;
2728 case 1:
2729 rm_val = (rm_val >> 8) | (rm_val << 24);
2730 break;
2731 case 2:
2732 rm_val = (rm_val >> 16) | (rm_val << 16);
2733 break;
2734 case 3:
2735 rm_val = (rm_val >> 24) | (rm_val << 8);
2736 break;
2737 }
2738 set_register(rd, rn_val + static_cast<int16_t>(rm_val));
2739 }
2740 }
2741 } else {
2742 UNREACHABLE();
2743 }
2744 break;
2745 case 2:
2746 if ((instr->Bit(20) == 0) && (instr->Bits(9, 6) == 1)) {
2747 if (instr->Bits(19, 16) == 0xF) {
2748 // Uxtb16.
2749 uint32_t rm_val = get_register(instr->RmValue());
2750 int32_t rotate = instr->Bits(11, 10);
2751 switch (rotate) {
2752 case 0:
2753 break;
2754 case 1:
2755 rm_val = (rm_val >> 8) | (rm_val << 24);
2756 break;
2757 case 2:
2758 rm_val = (rm_val >> 16) | (rm_val << 16);
2759 break;
2760 case 3:
2761 rm_val = (rm_val >> 24) | (rm_val << 8);
2762 break;
2763 }
2764 set_register(rd, (rm_val & 0xFF) | (rm_val & 0xFF0000));
2765 } else {
2766 UNIMPLEMENTED();
2767 }
2768 } else {
2769 UNIMPLEMENTED();
2770 }
2771 break;
2772 case 3:
2773 if ((instr->Bits(9, 6) == 1)) {
2774 if (instr->Bit(20) == 0) {
2775 if (instr->Bits(19, 16) == 0xF) {
2776 // Uxtb.
2777 uint32_t rm_val = get_register(instr->RmValue());
2778 int32_t rotate = instr->Bits(11, 10);
2779 switch (rotate) {
2780 case 0:
2781 break;
2782 case 1:
2783 rm_val = (rm_val >> 8) | (rm_val << 24);
2784 break;
2785 case 2:
2786 rm_val = (rm_val >> 16) | (rm_val << 16);
2787 break;
2788 case 3:
2789 rm_val = (rm_val >> 24) | (rm_val << 8);
2790 break;
2791 }
2792 set_register(rd, (rm_val & 0xFF));
2793 } else {
2794 // Uxtab.
2795 uint32_t rn_val = get_register(rn);
2796 uint32_t rm_val = get_register(instr->RmValue());
2797 int32_t rotate = instr->Bits(11, 10);
2798 switch (rotate) {
2799 case 0:
2800 break;
2801 case 1:
2802 rm_val = (rm_val >> 8) | (rm_val << 24);
2803 break;
2804 case 2:
2805 rm_val = (rm_val >> 16) | (rm_val << 16);
2806 break;
2807 case 3:
2808 rm_val = (rm_val >> 24) | (rm_val << 8);
2809 break;
2810 }
2811 set_register(rd, rn_val + (rm_val & 0xFF));
2812 }
2813 } else {
2814 if (instr->Bits(19, 16) == 0xF) {
2815 // Uxth.
2816 uint32_t rm_val = get_register(instr->RmValue());
2817 int32_t rotate = instr->Bits(11, 10);
2818 switch (rotate) {
2819 case 0:
2820 break;
2821 case 1:
2822 rm_val = (rm_val >> 8) | (rm_val << 24);
2823 break;
2824 case 2:
2825 rm_val = (rm_val >> 16) | (rm_val << 16);
2826 break;
2827 case 3:
2828 rm_val = (rm_val >> 24) | (rm_val << 8);
2829 break;
2830 }
2831 set_register(rd, (rm_val & 0xFFFF));
2832 } else {
2833 // Uxtah.
2834 uint32_t rn_val = get_register(rn);
2835 uint32_t rm_val = get_register(instr->RmValue());
2836 int32_t rotate = instr->Bits(11, 10);
2837 switch (rotate) {
2838 case 0:
2839 break;
2840 case 1:
2841 rm_val = (rm_val >> 8) | (rm_val << 24);
2842 break;
2843 case 2:
2844 rm_val = (rm_val >> 16) | (rm_val << 16);
2845 break;
2846 case 3:
2847 rm_val = (rm_val >> 24) | (rm_val << 8);
2848 break;
2849 }
2850 set_register(rd, rn_val + (rm_val & 0xFFFF));
2851 }
2852 }
2853 } else {
2854 // PU == 0b01, BW == 0b11, Bits(9, 6) != 0b0001
2855 if ((instr->Bits(20, 16) == 0x1f) &&
2856 (instr->Bits(11, 4) == 0xf3)) {
2857 // Rbit.
2858 uint32_t rm_val = get_register(instr->RmValue());
2859 set_register(rd, base::bits::ReverseBits(rm_val));
2860 } else {
2861 UNIMPLEMENTED();
2862 }
2863 }
2864 break;
2865 }
2866 }
2867 return;
2868 }
2869 break;
2870 }
2871 case db_x: {
2872 if (instr->Bits(22, 20) == 0x5) {
2873 if (instr->Bits(7, 4) == 0x1) {
2874 int rm = instr->RmValue();
2875 int32_t rm_val = get_register(rm);
2876 int rs = instr->RsValue();
2877 int32_t rs_val = get_register(rs);
2878 if (instr->Bits(15, 12) == 0xF) {
2879 // SMMUL (in V8 notation matching ARM ISA format)
2880 // Format(instr, "smmul'cond 'rn, 'rm, 'rs");
2881 rn_val = base::bits::SignedMulHigh32(rm_val, rs_val);
2882 } else {
2883 // SMMLA (in V8 notation matching ARM ISA format)
2884 // Format(instr, "smmla'cond 'rn, 'rm, 'rs, 'rd");
2885 int rd = instr->RdValue();
2886 int32_t rd_val = get_register(rd);
2887 rn_val = base::bits::SignedMulHighAndAdd32(rm_val, rs_val, rd_val);
2888 }
2889 set_register(rn, rn_val);
2890 return;
2891 }
2892 }
2893 if (instr->Bits(5, 4) == 0x1) {
2894 if ((instr->Bit(22) == 0x0) && (instr->Bit(20) == 0x1)) {
2895 // (s/u)div (in V8 notation matching ARM ISA format) rn = rm/rs
2896 // Format(instr, "'(s/u)div'cond'b 'rn, 'rm, 'rs);
2897 int rm = instr->RmValue();
2898 int32_t rm_val = get_register(rm);
2899 int rs = instr->RsValue();
2900 int32_t rs_val = get_register(rs);
2901 int32_t ret_val = 0;
2902 // udiv
2903 if (instr->Bit(21) == 0x1) {
2904 ret_val = bit_cast<int32_t>(base::bits::UnsignedDiv32(
2905 bit_cast<uint32_t>(rm_val), bit_cast<uint32_t>(rs_val)));
2906 } else {
2907 ret_val = base::bits::SignedDiv32(rm_val, rs_val);
2908 }
2909 set_register(rn, ret_val);
2910 return;
2911 }
2912 }
2913 // Format(instr, "'memop'cond'b 'rd, ['rn, -'shift_rm]'w");
2914 addr = rn_val - shifter_operand;
2915 if (instr->HasW()) {
2916 set_register(rn, addr);
2917 }
2918 break;
2919 }
2920 case ib_x: {
2921 if (instr->HasW() && (instr->Bits(6, 4) == 0x5)) {
2922 uint32_t widthminus1 = static_cast<uint32_t>(instr->Bits(20, 16));
2923 uint32_t lsbit = static_cast<uint32_t>(instr->Bits(11, 7));
2924 uint32_t msbit = widthminus1 + lsbit;
2925 if (msbit <= 31) {
2926 if (instr->Bit(22)) {
2927 // ubfx - unsigned bitfield extract.
2928 uint32_t rm_val =
2929 static_cast<uint32_t>(get_register(instr->RmValue()));
2930 uint32_t extr_val = rm_val << (31 - msbit);
2931 extr_val = extr_val >> (31 - widthminus1);
2932 set_register(instr->RdValue(), extr_val);
2933 } else {
2934 // sbfx - signed bitfield extract.
2935 int32_t rm_val = get_register(instr->RmValue());
2936 int32_t extr_val = rm_val << (31 - msbit);
2937 extr_val = extr_val >> (31 - widthminus1);
2938 set_register(instr->RdValue(), extr_val);
2939 }
2940 } else {
2941 UNREACHABLE();
2942 }
2943 return;
2944 } else if (!instr->HasW() && (instr->Bits(6, 4) == 0x1)) {
2945 uint32_t lsbit = static_cast<uint32_t>(instr->Bits(11, 7));
2946 uint32_t msbit = static_cast<uint32_t>(instr->Bits(20, 16));
2947 if (msbit >= lsbit) {
2948 // bfc or bfi - bitfield clear/insert.
2949 uint32_t rd_val =
2950 static_cast<uint32_t>(get_register(instr->RdValue()));
2951 uint32_t bitcount = msbit - lsbit + 1;
2952 uint32_t mask = 0xffffffffu >> (32 - bitcount);
2953 rd_val &= ~(mask << lsbit);
2954 if (instr->RmValue() != 15) {
2955 // bfi - bitfield insert.
2956 uint32_t rm_val =
2957 static_cast<uint32_t>(get_register(instr->RmValue()));
2958 rm_val &= mask;
2959 rd_val |= rm_val << lsbit;
2960 }
2961 set_register(instr->RdValue(), rd_val);
2962 } else {
2963 UNREACHABLE();
2964 }
2965 return;
2966 } else {
2967 // Format(instr, "'memop'cond'b 'rd, ['rn, +'shift_rm]'w");
2968 addr = rn_val + shifter_operand;
2969 if (instr->HasW()) {
2970 set_register(rn, addr);
2971 }
2972 }
2973 break;
2974 }
2975 default: {
2976 UNREACHABLE();
2977 break;
2978 }
2979 }
2980 if (instr->HasB()) {
2981 if (instr->HasL()) {
2982 uint8_t byte = ReadB(addr);
2983 set_register(rd, byte);
2984 } else {
2985 uint8_t byte = get_register(rd);
2986 WriteB(addr, byte);
2987 }
2988 } else {
2989 if (instr->HasL()) {
2990 set_register(rd, ReadW(addr, instr));
2991 } else {
2992 WriteW(addr, get_register(rd), instr);
2993 }
2994 }
2995 }
2996
2997
DecodeType4(Instruction * instr)2998 void Simulator::DecodeType4(Instruction* instr) {
2999 DCHECK(instr->Bit(22) == 0); // only allowed to be set in privileged mode
3000 if (instr->HasL()) {
3001 // Format(instr, "ldm'cond'pu 'rn'w, 'rlist");
3002 HandleRList(instr, true);
3003 } else {
3004 // Format(instr, "stm'cond'pu 'rn'w, 'rlist");
3005 HandleRList(instr, false);
3006 }
3007 }
3008
3009
DecodeType5(Instruction * instr)3010 void Simulator::DecodeType5(Instruction* instr) {
3011 // Format(instr, "b'l'cond 'target");
3012 int off = (instr->SImmed24Value() << 2);
3013 intptr_t pc_address = get_pc();
3014 if (instr->HasLink()) {
3015 set_register(lr, pc_address + Instruction::kInstrSize);
3016 }
3017 int pc_reg = get_register(pc);
3018 set_pc(pc_reg + off);
3019 }
3020
3021
DecodeType6(Instruction * instr)3022 void Simulator::DecodeType6(Instruction* instr) {
3023 DecodeType6CoprocessorIns(instr);
3024 }
3025
3026
DecodeType7(Instruction * instr)3027 void Simulator::DecodeType7(Instruction* instr) {
3028 if (instr->Bit(24) == 1) {
3029 SoftwareInterrupt(instr);
3030 } else {
3031 switch (instr->CoprocessorValue()) {
3032 case 10: // Fall through.
3033 case 11:
3034 DecodeTypeVFP(instr);
3035 break;
3036 case 15:
3037 DecodeTypeCP15(instr);
3038 break;
3039 default:
3040 UNIMPLEMENTED();
3041 }
3042 }
3043 }
3044
3045
3046 // void Simulator::DecodeTypeVFP(Instruction* instr)
3047 // The Following ARMv7 VFPv instructions are currently supported.
3048 // vmov :Sn = Rt
3049 // vmov :Rt = Sn
3050 // vcvt: Dd = Sm
3051 // vcvt: Sd = Dm
3052 // vcvt.f64.s32 Dd, Dd, #<fbits>
3053 // Dd = vabs(Dm)
3054 // Sd = vabs(Sm)
3055 // Dd = vneg(Dm)
3056 // Sd = vneg(Sm)
3057 // Dd = vadd(Dn, Dm)
3058 // Sd = vadd(Sn, Sm)
3059 // Dd = vsub(Dn, Dm)
3060 // Sd = vsub(Sn, Sm)
3061 // Dd = vmul(Dn, Dm)
3062 // Sd = vmul(Sn, Sm)
3063 // Dd = vdiv(Dn, Dm)
3064 // Sd = vdiv(Sn, Sm)
3065 // vcmp(Dd, Dm)
3066 // vcmp(Sd, Sm)
3067 // Dd = vsqrt(Dm)
3068 // Sd = vsqrt(Sm)
3069 // vmrs
DecodeTypeVFP(Instruction * instr)3070 void Simulator::DecodeTypeVFP(Instruction* instr) {
3071 DCHECK((instr->TypeValue() == 7) && (instr->Bit(24) == 0x0) );
3072 DCHECK(instr->Bits(11, 9) == 0x5);
3073
3074 // Obtain single precision register codes.
3075 int m = instr->VFPMRegValue(kSinglePrecision);
3076 int d = instr->VFPDRegValue(kSinglePrecision);
3077 int n = instr->VFPNRegValue(kSinglePrecision);
3078 // Obtain double precision register codes.
3079 int vm = instr->VFPMRegValue(kDoublePrecision);
3080 int vd = instr->VFPDRegValue(kDoublePrecision);
3081 int vn = instr->VFPNRegValue(kDoublePrecision);
3082
3083 if (instr->Bit(4) == 0) {
3084 if (instr->Opc1Value() == 0x7) {
3085 // Other data processing instructions
3086 if ((instr->Opc2Value() == 0x0) && (instr->Opc3Value() == 0x1)) {
3087 // vmov register to register.
3088 if (instr->SzValue() == 0x1) {
3089 uint32_t data[2];
3090 get_d_register(vm, data);
3091 set_d_register(vd, data);
3092 } else {
3093 set_s_register(d, get_s_register(m));
3094 }
3095 } else if ((instr->Opc2Value() == 0x0) && (instr->Opc3Value() == 0x3)) {
3096 // vabs
3097 if (instr->SzValue() == 0x1) {
3098 double dm_value = get_double_from_d_register(vm);
3099 double dd_value = std::fabs(dm_value);
3100 dd_value = canonicalizeNaN(dd_value);
3101 set_d_register_from_double(vd, dd_value);
3102 } else {
3103 float sm_value = get_float_from_s_register(m);
3104 float sd_value = std::fabs(sm_value);
3105 sd_value = canonicalizeNaN(sd_value);
3106 set_s_register_from_float(d, sd_value);
3107 }
3108 } else if ((instr->Opc2Value() == 0x1) && (instr->Opc3Value() == 0x1)) {
3109 // vneg
3110 if (instr->SzValue() == 0x1) {
3111 double dm_value = get_double_from_d_register(vm);
3112 double dd_value = -dm_value;
3113 dd_value = canonicalizeNaN(dd_value);
3114 set_d_register_from_double(vd, dd_value);
3115 } else {
3116 float sm_value = get_float_from_s_register(m);
3117 float sd_value = -sm_value;
3118 sd_value = canonicalizeNaN(sd_value);
3119 set_s_register_from_float(d, sd_value);
3120 }
3121 } else if ((instr->Opc2Value() == 0x7) && (instr->Opc3Value() == 0x3)) {
3122 DecodeVCVTBetweenDoubleAndSingle(instr);
3123 } else if ((instr->Opc2Value() == 0x8) && (instr->Opc3Value() & 0x1)) {
3124 DecodeVCVTBetweenFloatingPointAndInteger(instr);
3125 } else if ((instr->Opc2Value() == 0xA) && (instr->Opc3Value() == 0x3) &&
3126 (instr->Bit(8) == 1)) {
3127 // vcvt.f64.s32 Dd, Dd, #<fbits>
3128 int fraction_bits = 32 - ((instr->Bits(3, 0) << 1) | instr->Bit(5));
3129 int fixed_value = get_sinteger_from_s_register(vd * 2);
3130 double divide = 1 << fraction_bits;
3131 set_d_register_from_double(vd, fixed_value / divide);
3132 } else if (((instr->Opc2Value() >> 1) == 0x6) &&
3133 (instr->Opc3Value() & 0x1)) {
3134 DecodeVCVTBetweenFloatingPointAndInteger(instr);
3135 } else if (((instr->Opc2Value() == 0x4) || (instr->Opc2Value() == 0x5)) &&
3136 (instr->Opc3Value() & 0x1)) {
3137 DecodeVCMP(instr);
3138 } else if (((instr->Opc2Value() == 0x1)) && (instr->Opc3Value() == 0x3)) {
3139 // vsqrt
3140 lazily_initialize_fast_sqrt(isolate_);
3141 if (instr->SzValue() == 0x1) {
3142 double dm_value = get_double_from_d_register(vm);
3143 double dd_value = fast_sqrt(dm_value, isolate_);
3144 dd_value = canonicalizeNaN(dd_value);
3145 set_d_register_from_double(vd, dd_value);
3146 } else {
3147 float sm_value = get_float_from_s_register(m);
3148 float sd_value = fast_sqrt(sm_value, isolate_);
3149 sd_value = canonicalizeNaN(sd_value);
3150 set_s_register_from_float(d, sd_value);
3151 }
3152 } else if (instr->Opc3Value() == 0x0) {
3153 // vmov immediate.
3154 if (instr->SzValue() == 0x1) {
3155 set_d_register_from_double(vd, instr->DoubleImmedVmov());
3156 } else {
3157 set_s_register_from_float(d, instr->DoubleImmedVmov());
3158 }
3159 } else if (((instr->Opc2Value() == 0x6)) && (instr->Opc3Value() == 0x3)) {
3160 // vrintz - truncate
3161 if (instr->SzValue() == 0x1) {
3162 double dm_value = get_double_from_d_register(vm);
3163 double dd_value = trunc(dm_value);
3164 dd_value = canonicalizeNaN(dd_value);
3165 set_d_register_from_double(vd, dd_value);
3166 } else {
3167 float sm_value = get_float_from_s_register(m);
3168 float sd_value = truncf(sm_value);
3169 sd_value = canonicalizeNaN(sd_value);
3170 set_s_register_from_float(d, sd_value);
3171 }
3172 } else {
3173 UNREACHABLE(); // Not used by V8.
3174 }
3175 } else if (instr->Opc1Value() == 0x3) {
3176 if (instr->Opc3Value() & 0x1) {
3177 // vsub
3178 if (instr->SzValue() == 0x1) {
3179 double dn_value = get_double_from_d_register(vn);
3180 double dm_value = get_double_from_d_register(vm);
3181 double dd_value = dn_value - dm_value;
3182 dd_value = canonicalizeNaN(dd_value);
3183 set_d_register_from_double(vd, dd_value);
3184 } else {
3185 float sn_value = get_float_from_s_register(n);
3186 float sm_value = get_float_from_s_register(m);
3187 float sd_value = sn_value - sm_value;
3188 sd_value = canonicalizeNaN(sd_value);
3189 set_s_register_from_float(d, sd_value);
3190 }
3191 } else {
3192 // vadd
3193 if (instr->SzValue() == 0x1) {
3194 double dn_value = get_double_from_d_register(vn);
3195 double dm_value = get_double_from_d_register(vm);
3196 double dd_value = dn_value + dm_value;
3197 dd_value = canonicalizeNaN(dd_value);
3198 set_d_register_from_double(vd, dd_value);
3199 } else {
3200 float sn_value = get_float_from_s_register(n);
3201 float sm_value = get_float_from_s_register(m);
3202 float sd_value = sn_value + sm_value;
3203 sd_value = canonicalizeNaN(sd_value);
3204 set_s_register_from_float(d, sd_value);
3205 }
3206 }
3207 } else if ((instr->Opc1Value() == 0x2) && !(instr->Opc3Value() & 0x1)) {
3208 // vmul
3209 if (instr->SzValue() == 0x1) {
3210 double dn_value = get_double_from_d_register(vn);
3211 double dm_value = get_double_from_d_register(vm);
3212 double dd_value = dn_value * dm_value;
3213 dd_value = canonicalizeNaN(dd_value);
3214 set_d_register_from_double(vd, dd_value);
3215 } else {
3216 float sn_value = get_float_from_s_register(n);
3217 float sm_value = get_float_from_s_register(m);
3218 float sd_value = sn_value * sm_value;
3219 sd_value = canonicalizeNaN(sd_value);
3220 set_s_register_from_float(d, sd_value);
3221 }
3222 } else if ((instr->Opc1Value() == 0x0)) {
3223 // vmla, vmls
3224 const bool is_vmls = (instr->Opc3Value() & 0x1);
3225 if (instr->SzValue() == 0x1) {
3226 const double dd_val = get_double_from_d_register(vd);
3227 const double dn_val = get_double_from_d_register(vn);
3228 const double dm_val = get_double_from_d_register(vm);
3229
3230 // Note: we do the mul and add/sub in separate steps to avoid getting a
3231 // result with too high precision.
3232 set_d_register_from_double(vd, dn_val * dm_val);
3233 if (is_vmls) {
3234 set_d_register_from_double(
3235 vd, canonicalizeNaN(dd_val - get_double_from_d_register(vd)));
3236 } else {
3237 set_d_register_from_double(
3238 vd, canonicalizeNaN(dd_val + get_double_from_d_register(vd)));
3239 }
3240 } else {
3241 const float sd_val = get_float_from_s_register(d);
3242 const float sn_val = get_float_from_s_register(n);
3243 const float sm_val = get_float_from_s_register(m);
3244
3245 // Note: we do the mul and add/sub in separate steps to avoid getting a
3246 // result with too high precision.
3247 set_s_register_from_float(d, sn_val * sm_val);
3248 if (is_vmls) {
3249 set_s_register_from_float(
3250 d, canonicalizeNaN(sd_val - get_float_from_s_register(d)));
3251 } else {
3252 set_s_register_from_float(
3253 d, canonicalizeNaN(sd_val + get_float_from_s_register(d)));
3254 }
3255 }
3256 } else if ((instr->Opc1Value() == 0x4) && !(instr->Opc3Value() & 0x1)) {
3257 // vdiv
3258 if (instr->SzValue() == 0x1) {
3259 double dn_value = get_double_from_d_register(vn);
3260 double dm_value = get_double_from_d_register(vm);
3261 double dd_value = dn_value / dm_value;
3262 div_zero_vfp_flag_ = (dm_value == 0);
3263 dd_value = canonicalizeNaN(dd_value);
3264 set_d_register_from_double(vd, dd_value);
3265 } else {
3266 float sn_value = get_float_from_s_register(n);
3267 float sm_value = get_float_from_s_register(m);
3268 float sd_value = sn_value / sm_value;
3269 div_zero_vfp_flag_ = (sm_value == 0);
3270 sd_value = canonicalizeNaN(sd_value);
3271 set_s_register_from_float(d, sd_value);
3272 }
3273 } else {
3274 UNIMPLEMENTED(); // Not used by V8.
3275 }
3276 } else {
3277 if ((instr->VCValue() == 0x0) &&
3278 (instr->VAValue() == 0x0)) {
3279 DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(instr);
3280 } else if ((instr->VLValue() == 0x0) &&
3281 (instr->VCValue() == 0x1) &&
3282 (instr->Bit(23) == 0x0)) {
3283 // vmov (ARM core register to scalar)
3284 int vd = instr->Bits(19, 16) | (instr->Bit(7) << 4);
3285 uint32_t data[2];
3286 get_d_register(vd, data);
3287 data[instr->Bit(21)] = get_register(instr->RtValue());
3288 set_d_register(vd, data);
3289 } else if ((instr->VLValue() == 0x1) &&
3290 (instr->VCValue() == 0x1) &&
3291 (instr->Bit(23) == 0x0)) {
3292 // vmov (scalar to ARM core register)
3293 int vn = instr->Bits(19, 16) | (instr->Bit(7) << 4);
3294 double dn_value = get_double_from_d_register(vn);
3295 int32_t data[2];
3296 memcpy(data, &dn_value, 8);
3297 set_register(instr->RtValue(), data[instr->Bit(21)]);
3298 } else if ((instr->VLValue() == 0x1) &&
3299 (instr->VCValue() == 0x0) &&
3300 (instr->VAValue() == 0x7) &&
3301 (instr->Bits(19, 16) == 0x1)) {
3302 // vmrs
3303 uint32_t rt = instr->RtValue();
3304 if (rt == 0xF) {
3305 Copy_FPSCR_to_APSR();
3306 } else {
3307 // Emulate FPSCR from the Simulator flags.
3308 uint32_t fpscr = (n_flag_FPSCR_ << 31) |
3309 (z_flag_FPSCR_ << 30) |
3310 (c_flag_FPSCR_ << 29) |
3311 (v_flag_FPSCR_ << 28) |
3312 (FPSCR_default_NaN_mode_ << 25) |
3313 (inexact_vfp_flag_ << 4) |
3314 (underflow_vfp_flag_ << 3) |
3315 (overflow_vfp_flag_ << 2) |
3316 (div_zero_vfp_flag_ << 1) |
3317 (inv_op_vfp_flag_ << 0) |
3318 (FPSCR_rounding_mode_);
3319 set_register(rt, fpscr);
3320 }
3321 } else if ((instr->VLValue() == 0x0) &&
3322 (instr->VCValue() == 0x0) &&
3323 (instr->VAValue() == 0x7) &&
3324 (instr->Bits(19, 16) == 0x1)) {
3325 // vmsr
3326 uint32_t rt = instr->RtValue();
3327 if (rt == pc) {
3328 UNREACHABLE();
3329 } else {
3330 uint32_t rt_value = get_register(rt);
3331 n_flag_FPSCR_ = (rt_value >> 31) & 1;
3332 z_flag_FPSCR_ = (rt_value >> 30) & 1;
3333 c_flag_FPSCR_ = (rt_value >> 29) & 1;
3334 v_flag_FPSCR_ = (rt_value >> 28) & 1;
3335 FPSCR_default_NaN_mode_ = (rt_value >> 25) & 1;
3336 inexact_vfp_flag_ = (rt_value >> 4) & 1;
3337 underflow_vfp_flag_ = (rt_value >> 3) & 1;
3338 overflow_vfp_flag_ = (rt_value >> 2) & 1;
3339 div_zero_vfp_flag_ = (rt_value >> 1) & 1;
3340 inv_op_vfp_flag_ = (rt_value >> 0) & 1;
3341 FPSCR_rounding_mode_ =
3342 static_cast<VFPRoundingMode>((rt_value) & kVFPRoundingModeMask);
3343 }
3344 } else {
3345 UNIMPLEMENTED(); // Not used by V8.
3346 }
3347 }
3348 }
3349
DecodeTypeCP15(Instruction * instr)3350 void Simulator::DecodeTypeCP15(Instruction* instr) {
3351 DCHECK((instr->TypeValue() == 7) && (instr->Bit(24) == 0x0));
3352 DCHECK(instr->CoprocessorValue() == 15);
3353
3354 if (instr->Bit(4) == 1) {
3355 // mcr
3356 int crn = instr->Bits(19, 16);
3357 int crm = instr->Bits(3, 0);
3358 int opc1 = instr->Bits(23, 21);
3359 int opc2 = instr->Bits(7, 5);
3360 if ((opc1 == 0) && (crn == 7)) {
3361 // ARMv6 memory barrier operations.
3362 // Details available in ARM DDI 0406C.b, B3-1750.
3363 if (((crm == 10) && (opc2 == 5)) || // CP15DMB
3364 ((crm == 10) && (opc2 == 4)) || // CP15DSB
3365 ((crm == 5) && (opc2 == 4))) { // CP15ISB
3366 // These are ignored by the simulator for now.
3367 } else {
3368 UNIMPLEMENTED();
3369 }
3370 }
3371 } else {
3372 UNIMPLEMENTED();
3373 }
3374 }
3375
DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(Instruction * instr)3376 void Simulator::DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(
3377 Instruction* instr) {
3378 DCHECK((instr->Bit(4) == 1) && (instr->VCValue() == 0x0) &&
3379 (instr->VAValue() == 0x0));
3380
3381 int t = instr->RtValue();
3382 int n = instr->VFPNRegValue(kSinglePrecision);
3383 bool to_arm_register = (instr->VLValue() == 0x1);
3384
3385 if (to_arm_register) {
3386 int32_t int_value = get_sinteger_from_s_register(n);
3387 set_register(t, int_value);
3388 } else {
3389 int32_t rs_val = get_register(t);
3390 set_s_register_from_sinteger(n, rs_val);
3391 }
3392 }
3393
3394
DecodeVCMP(Instruction * instr)3395 void Simulator::DecodeVCMP(Instruction* instr) {
3396 DCHECK((instr->Bit(4) == 0) && (instr->Opc1Value() == 0x7));
3397 DCHECK(((instr->Opc2Value() == 0x4) || (instr->Opc2Value() == 0x5)) &&
3398 (instr->Opc3Value() & 0x1));
3399 // Comparison.
3400
3401 VFPRegPrecision precision = kSinglePrecision;
3402 if (instr->SzValue() == 0x1) {
3403 precision = kDoublePrecision;
3404 }
3405
3406 int d = instr->VFPDRegValue(precision);
3407 int m = 0;
3408 if (instr->Opc2Value() == 0x4) {
3409 m = instr->VFPMRegValue(precision);
3410 }
3411
3412 if (precision == kDoublePrecision) {
3413 double dd_value = get_double_from_d_register(d);
3414 double dm_value = 0.0;
3415 if (instr->Opc2Value() == 0x4) {
3416 dm_value = get_double_from_d_register(m);
3417 }
3418
3419 // Raise exceptions for quiet NaNs if necessary.
3420 if (instr->Bit(7) == 1) {
3421 if (std::isnan(dd_value)) {
3422 inv_op_vfp_flag_ = true;
3423 }
3424 }
3425
3426 Compute_FPSCR_Flags(dd_value, dm_value);
3427 } else {
3428 float sd_value = get_float_from_s_register(d);
3429 float sm_value = 0.0;
3430 if (instr->Opc2Value() == 0x4) {
3431 sm_value = get_float_from_s_register(m);
3432 }
3433
3434 // Raise exceptions for quiet NaNs if necessary.
3435 if (instr->Bit(7) == 1) {
3436 if (std::isnan(sd_value)) {
3437 inv_op_vfp_flag_ = true;
3438 }
3439 }
3440
3441 Compute_FPSCR_Flags(sd_value, sm_value);
3442 }
3443 }
3444
3445
DecodeVCVTBetweenDoubleAndSingle(Instruction * instr)3446 void Simulator::DecodeVCVTBetweenDoubleAndSingle(Instruction* instr) {
3447 DCHECK((instr->Bit(4) == 0) && (instr->Opc1Value() == 0x7));
3448 DCHECK((instr->Opc2Value() == 0x7) && (instr->Opc3Value() == 0x3));
3449
3450 VFPRegPrecision dst_precision = kDoublePrecision;
3451 VFPRegPrecision src_precision = kSinglePrecision;
3452 if (instr->SzValue() == 1) {
3453 dst_precision = kSinglePrecision;
3454 src_precision = kDoublePrecision;
3455 }
3456
3457 int dst = instr->VFPDRegValue(dst_precision);
3458 int src = instr->VFPMRegValue(src_precision);
3459
3460 if (dst_precision == kSinglePrecision) {
3461 double val = get_double_from_d_register(src);
3462 set_s_register_from_float(dst, static_cast<float>(val));
3463 } else {
3464 float val = get_float_from_s_register(src);
3465 set_d_register_from_double(dst, static_cast<double>(val));
3466 }
3467 }
3468
get_inv_op_vfp_flag(VFPRoundingMode mode,double val,bool unsigned_)3469 bool get_inv_op_vfp_flag(VFPRoundingMode mode,
3470 double val,
3471 bool unsigned_) {
3472 DCHECK((mode == RN) || (mode == RM) || (mode == RZ));
3473 double max_uint = static_cast<double>(0xffffffffu);
3474 double max_int = static_cast<double>(kMaxInt);
3475 double min_int = static_cast<double>(kMinInt);
3476
3477 // Check for NaN.
3478 if (val != val) {
3479 return true;
3480 }
3481
3482 // Check for overflow. This code works because 32bit integers can be
3483 // exactly represented by ieee-754 64bit floating-point values.
3484 switch (mode) {
3485 case RN:
3486 return unsigned_ ? (val >= (max_uint + 0.5)) ||
3487 (val < -0.5)
3488 : (val >= (max_int + 0.5)) ||
3489 (val < (min_int - 0.5));
3490
3491 case RM:
3492 return unsigned_ ? (val >= (max_uint + 1.0)) ||
3493 (val < 0)
3494 : (val >= (max_int + 1.0)) ||
3495 (val < min_int);
3496
3497 case RZ:
3498 return unsigned_ ? (val >= (max_uint + 1.0)) ||
3499 (val <= -1)
3500 : (val >= (max_int + 1.0)) ||
3501 (val <= (min_int - 1.0));
3502 default:
3503 UNREACHABLE();
3504 return true;
3505 }
3506 }
3507
3508
3509 // We call this function only if we had a vfp invalid exception.
3510 // It returns the correct saturated value.
VFPConversionSaturate(double val,bool unsigned_res)3511 int VFPConversionSaturate(double val, bool unsigned_res) {
3512 if (val != val) {
3513 return 0;
3514 } else {
3515 if (unsigned_res) {
3516 return (val < 0) ? 0 : 0xffffffffu;
3517 } else {
3518 return (val < 0) ? kMinInt : kMaxInt;
3519 }
3520 }
3521 }
3522
3523
DecodeVCVTBetweenFloatingPointAndInteger(Instruction * instr)3524 void Simulator::DecodeVCVTBetweenFloatingPointAndInteger(Instruction* instr) {
3525 DCHECK((instr->Bit(4) == 0) && (instr->Opc1Value() == 0x7) &&
3526 (instr->Bits(27, 23) == 0x1D));
3527 DCHECK(((instr->Opc2Value() == 0x8) && (instr->Opc3Value() & 0x1)) ||
3528 (((instr->Opc2Value() >> 1) == 0x6) && (instr->Opc3Value() & 0x1)));
3529
3530 // Conversion between floating-point and integer.
3531 bool to_integer = (instr->Bit(18) == 1);
3532
3533 VFPRegPrecision src_precision = (instr->SzValue() == 1) ? kDoublePrecision
3534 : kSinglePrecision;
3535
3536 if (to_integer) {
3537 // We are playing with code close to the C++ standard's limits below,
3538 // hence the very simple code and heavy checks.
3539 //
3540 // Note:
3541 // C++ defines default type casting from floating point to integer as
3542 // (close to) rounding toward zero ("fractional part discarded").
3543
3544 int dst = instr->VFPDRegValue(kSinglePrecision);
3545 int src = instr->VFPMRegValue(src_precision);
3546
3547 // Bit 7 in vcvt instructions indicates if we should use the FPSCR rounding
3548 // mode or the default Round to Zero mode.
3549 VFPRoundingMode mode = (instr->Bit(7) != 1) ? FPSCR_rounding_mode_
3550 : RZ;
3551 DCHECK((mode == RM) || (mode == RZ) || (mode == RN));
3552
3553 bool unsigned_integer = (instr->Bit(16) == 0);
3554 bool double_precision = (src_precision == kDoublePrecision);
3555
3556 double val = double_precision ? get_double_from_d_register(src)
3557 : get_float_from_s_register(src);
3558
3559 int temp = unsigned_integer ? static_cast<uint32_t>(val)
3560 : static_cast<int32_t>(val);
3561
3562 inv_op_vfp_flag_ = get_inv_op_vfp_flag(mode, val, unsigned_integer);
3563
3564 double abs_diff =
3565 unsigned_integer ? std::fabs(val - static_cast<uint32_t>(temp))
3566 : std::fabs(val - temp);
3567
3568 inexact_vfp_flag_ = (abs_diff != 0);
3569
3570 if (inv_op_vfp_flag_) {
3571 temp = VFPConversionSaturate(val, unsigned_integer);
3572 } else {
3573 switch (mode) {
3574 case RN: {
3575 int val_sign = (val > 0) ? 1 : -1;
3576 if (abs_diff > 0.5) {
3577 temp += val_sign;
3578 } else if (abs_diff == 0.5) {
3579 // Round to even if exactly halfway.
3580 temp = ((temp % 2) == 0) ? temp : temp + val_sign;
3581 }
3582 break;
3583 }
3584
3585 case RM:
3586 temp = temp > val ? temp - 1 : temp;
3587 break;
3588
3589 case RZ:
3590 // Nothing to do.
3591 break;
3592
3593 default:
3594 UNREACHABLE();
3595 }
3596 }
3597
3598 // Update the destination register.
3599 set_s_register_from_sinteger(dst, temp);
3600
3601 } else {
3602 bool unsigned_integer = (instr->Bit(7) == 0);
3603
3604 int dst = instr->VFPDRegValue(src_precision);
3605 int src = instr->VFPMRegValue(kSinglePrecision);
3606
3607 int val = get_sinteger_from_s_register(src);
3608
3609 if (src_precision == kDoublePrecision) {
3610 if (unsigned_integer) {
3611 set_d_register_from_double(
3612 dst, static_cast<double>(static_cast<uint32_t>(val)));
3613 } else {
3614 set_d_register_from_double(dst, static_cast<double>(val));
3615 }
3616 } else {
3617 if (unsigned_integer) {
3618 set_s_register_from_float(
3619 dst, static_cast<float>(static_cast<uint32_t>(val)));
3620 } else {
3621 set_s_register_from_float(dst, static_cast<float>(val));
3622 }
3623 }
3624 }
3625 }
3626
3627
3628 // void Simulator::DecodeType6CoprocessorIns(Instruction* instr)
3629 // Decode Type 6 coprocessor instructions.
3630 // Dm = vmov(Rt, Rt2)
3631 // <Rt, Rt2> = vmov(Dm)
3632 // Ddst = MEM(Rbase + 4*offset).
3633 // MEM(Rbase + 4*offset) = Dsrc.
DecodeType6CoprocessorIns(Instruction * instr)3634 void Simulator::DecodeType6CoprocessorIns(Instruction* instr) {
3635 DCHECK((instr->TypeValue() == 6));
3636
3637 if (instr->CoprocessorValue() == 0xA) {
3638 switch (instr->OpcodeValue()) {
3639 case 0x8:
3640 case 0xA:
3641 case 0xC:
3642 case 0xE: { // Load and store single precision float to memory.
3643 int rn = instr->RnValue();
3644 int vd = instr->VFPDRegValue(kSinglePrecision);
3645 int offset = instr->Immed8Value();
3646 if (!instr->HasU()) {
3647 offset = -offset;
3648 }
3649
3650 int32_t address = get_register(rn) + 4 * offset;
3651 // Load and store address for singles must be at least four-byte
3652 // aligned.
3653 DCHECK((address % 4) == 0);
3654 if (instr->HasL()) {
3655 // Load single from memory: vldr.
3656 set_s_register_from_sinteger(vd, ReadW(address, instr));
3657 } else {
3658 // Store single to memory: vstr.
3659 WriteW(address, get_sinteger_from_s_register(vd), instr);
3660 }
3661 break;
3662 }
3663 case 0x4:
3664 case 0x5:
3665 case 0x6:
3666 case 0x7:
3667 case 0x9:
3668 case 0xB:
3669 // Load/store multiple single from memory: vldm/vstm.
3670 HandleVList(instr);
3671 break;
3672 default:
3673 UNIMPLEMENTED(); // Not used by V8.
3674 }
3675 } else if (instr->CoprocessorValue() == 0xB) {
3676 switch (instr->OpcodeValue()) {
3677 case 0x2:
3678 // Load and store double to two GP registers
3679 if (instr->Bits(7, 6) != 0 || instr->Bit(4) != 1) {
3680 UNIMPLEMENTED(); // Not used by V8.
3681 } else {
3682 int rt = instr->RtValue();
3683 int rn = instr->RnValue();
3684 int vm = instr->VFPMRegValue(kDoublePrecision);
3685 if (instr->HasL()) {
3686 uint32_t data[2];
3687 get_d_register(vm, data);
3688 set_register(rt, data[0]);
3689 set_register(rn, data[1]);
3690 } else {
3691 int32_t data[] = { get_register(rt), get_register(rn) };
3692 set_d_register(vm, reinterpret_cast<uint32_t*>(data));
3693 }
3694 }
3695 break;
3696 case 0x8:
3697 case 0xA:
3698 case 0xC:
3699 case 0xE: { // Load and store double to memory.
3700 int rn = instr->RnValue();
3701 int vd = instr->VFPDRegValue(kDoublePrecision);
3702 int offset = instr->Immed8Value();
3703 if (!instr->HasU()) {
3704 offset = -offset;
3705 }
3706 int32_t address = get_register(rn) + 4 * offset;
3707 // Load and store address for doubles must be at least four-byte
3708 // aligned.
3709 DCHECK((address % 4) == 0);
3710 if (instr->HasL()) {
3711 // Load double from memory: vldr.
3712 int32_t data[] = {
3713 ReadW(address, instr),
3714 ReadW(address + 4, instr)
3715 };
3716 set_d_register(vd, reinterpret_cast<uint32_t*>(data));
3717 } else {
3718 // Store double to memory: vstr.
3719 uint32_t data[2];
3720 get_d_register(vd, data);
3721 WriteW(address, data[0], instr);
3722 WriteW(address + 4, data[1], instr);
3723 }
3724 break;
3725 }
3726 case 0x4:
3727 case 0x5:
3728 case 0x6:
3729 case 0x7:
3730 case 0x9:
3731 case 0xB:
3732 // Load/store multiple double from memory: vldm/vstm.
3733 HandleVList(instr);
3734 break;
3735 default:
3736 UNIMPLEMENTED(); // Not used by V8.
3737 }
3738 } else {
3739 UNIMPLEMENTED(); // Not used by V8.
3740 }
3741 }
3742
3743
DecodeSpecialCondition(Instruction * instr)3744 void Simulator::DecodeSpecialCondition(Instruction* instr) {
3745 switch (instr->SpecialValue()) {
3746 case 5:
3747 if ((instr->Bits(18, 16) == 0) && (instr->Bits(11, 6) == 0x28) &&
3748 (instr->Bit(4) == 1)) {
3749 // vmovl signed
3750 if ((instr->VdValue() & 1) != 0) UNIMPLEMENTED();
3751 int Vd = (instr->Bit(22) << 3) | (instr->VdValue() >> 1);
3752 int Vm = (instr->Bit(5) << 4) | instr->VmValue();
3753 int imm3 = instr->Bits(21, 19);
3754 if ((imm3 != 1) && (imm3 != 2) && (imm3 != 4)) UNIMPLEMENTED();
3755 int esize = 8 * imm3;
3756 int elements = 64 / esize;
3757 int8_t from[8];
3758 get_d_register(Vm, reinterpret_cast<uint64_t*>(from));
3759 int16_t to[8];
3760 int e = 0;
3761 while (e < elements) {
3762 to[e] = from[e];
3763 e++;
3764 }
3765 set_q_register(Vd, reinterpret_cast<uint64_t*>(to));
3766 } else {
3767 UNIMPLEMENTED();
3768 }
3769 break;
3770 case 7:
3771 if ((instr->Bits(18, 16) == 0) && (instr->Bits(11, 6) == 0x28) &&
3772 (instr->Bit(4) == 1)) {
3773 // vmovl unsigned
3774 if ((instr->VdValue() & 1) != 0) UNIMPLEMENTED();
3775 int Vd = (instr->Bit(22) << 3) | (instr->VdValue() >> 1);
3776 int Vm = (instr->Bit(5) << 4) | instr->VmValue();
3777 int imm3 = instr->Bits(21, 19);
3778 if ((imm3 != 1) && (imm3 != 2) && (imm3 != 4)) UNIMPLEMENTED();
3779 int esize = 8 * imm3;
3780 int elements = 64 / esize;
3781 uint8_t from[8];
3782 get_d_register(Vm, reinterpret_cast<uint64_t*>(from));
3783 uint16_t to[8];
3784 int e = 0;
3785 while (e < elements) {
3786 to[e] = from[e];
3787 e++;
3788 }
3789 set_q_register(Vd, reinterpret_cast<uint64_t*>(to));
3790 } else if ((instr->Bits(21, 16) == 0x32) && (instr->Bits(11, 7) == 0) &&
3791 (instr->Bit(4) == 0)) {
3792 int vd = instr->VFPDRegValue(kDoublePrecision);
3793 int vm = instr->VFPMRegValue(kDoublePrecision);
3794 if (instr->Bit(6) == 0) {
3795 // vswp Dd, Dm.
3796 uint64_t dval, mval;
3797 get_d_register(vd, &dval);
3798 get_d_register(vm, &mval);
3799 set_d_register(vm, &dval);
3800 set_d_register(vd, &mval);
3801 } else {
3802 // Q register vswp unimplemented.
3803 UNIMPLEMENTED();
3804 }
3805 } else {
3806 UNIMPLEMENTED();
3807 }
3808 break;
3809 case 8:
3810 if (instr->Bits(21, 20) == 0) {
3811 // vst1
3812 int Vd = (instr->Bit(22) << 4) | instr->VdValue();
3813 int Rn = instr->VnValue();
3814 int type = instr->Bits(11, 8);
3815 int Rm = instr->VmValue();
3816 int32_t address = get_register(Rn);
3817 int regs = 0;
3818 switch (type) {
3819 case nlt_1:
3820 regs = 1;
3821 break;
3822 case nlt_2:
3823 regs = 2;
3824 break;
3825 case nlt_3:
3826 regs = 3;
3827 break;
3828 case nlt_4:
3829 regs = 4;
3830 break;
3831 default:
3832 UNIMPLEMENTED();
3833 break;
3834 }
3835 int r = 0;
3836 while (r < regs) {
3837 uint32_t data[2];
3838 get_d_register(Vd + r, data);
3839 WriteW(address, data[0], instr);
3840 WriteW(address + 4, data[1], instr);
3841 address += 8;
3842 r++;
3843 }
3844 if (Rm != 15) {
3845 if (Rm == 13) {
3846 set_register(Rn, address);
3847 } else {
3848 set_register(Rn, get_register(Rn) + get_register(Rm));
3849 }
3850 }
3851 } else if (instr->Bits(21, 20) == 2) {
3852 // vld1
3853 int Vd = (instr->Bit(22) << 4) | instr->VdValue();
3854 int Rn = instr->VnValue();
3855 int type = instr->Bits(11, 8);
3856 int Rm = instr->VmValue();
3857 int32_t address = get_register(Rn);
3858 int regs = 0;
3859 switch (type) {
3860 case nlt_1:
3861 regs = 1;
3862 break;
3863 case nlt_2:
3864 regs = 2;
3865 break;
3866 case nlt_3:
3867 regs = 3;
3868 break;
3869 case nlt_4:
3870 regs = 4;
3871 break;
3872 default:
3873 UNIMPLEMENTED();
3874 break;
3875 }
3876 int r = 0;
3877 while (r < regs) {
3878 uint32_t data[2];
3879 data[0] = ReadW(address, instr);
3880 data[1] = ReadW(address + 4, instr);
3881 set_d_register(Vd + r, data);
3882 address += 8;
3883 r++;
3884 }
3885 if (Rm != 15) {
3886 if (Rm == 13) {
3887 set_register(Rn, address);
3888 } else {
3889 set_register(Rn, get_register(Rn) + get_register(Rm));
3890 }
3891 }
3892 } else {
3893 UNIMPLEMENTED();
3894 }
3895 break;
3896 case 0xA:
3897 case 0xB:
3898 if ((instr->Bits(22, 20) == 5) && (instr->Bits(15, 12) == 0xf)) {
3899 // pld: ignore instruction.
3900 } else if (instr->SpecialValue() == 0xA && instr->Bits(22, 20) == 7) {
3901 // dsb, dmb, isb: ignore instruction for now.
3902 // TODO(binji): implement
3903 // Also refer to the ARMv6 CP15 equivalents in DecodeTypeCP15.
3904 } else {
3905 UNIMPLEMENTED();
3906 }
3907 break;
3908 case 0x1D:
3909 if (instr->Opc1Value() == 0x7 && instr->Opc3Value() == 0x1 &&
3910 instr->Bits(11, 9) == 0x5 && instr->Bits(19, 18) == 0x2) {
3911 if (instr->SzValue() == 0x1) {
3912 int vm = instr->VFPMRegValue(kDoublePrecision);
3913 int vd = instr->VFPDRegValue(kDoublePrecision);
3914 double dm_value = get_double_from_d_register(vm);
3915 double dd_value = 0.0;
3916 int rounding_mode = instr->Bits(17, 16);
3917 switch (rounding_mode) {
3918 case 0x0: // vrinta - round with ties to away from zero
3919 dd_value = round(dm_value);
3920 break;
3921 case 0x1: { // vrintn - round with ties to even
3922 dd_value = nearbyint(dm_value);
3923 break;
3924 }
3925 case 0x2: // vrintp - ceil
3926 dd_value = ceil(dm_value);
3927 break;
3928 case 0x3: // vrintm - floor
3929 dd_value = floor(dm_value);
3930 break;
3931 default:
3932 UNREACHABLE(); // Case analysis is exhaustive.
3933 break;
3934 }
3935 dd_value = canonicalizeNaN(dd_value);
3936 set_d_register_from_double(vd, dd_value);
3937 } else {
3938 int m = instr->VFPMRegValue(kSinglePrecision);
3939 int d = instr->VFPDRegValue(kSinglePrecision);
3940 float sm_value = get_float_from_s_register(m);
3941 float sd_value = 0.0;
3942 int rounding_mode = instr->Bits(17, 16);
3943 switch (rounding_mode) {
3944 case 0x0: // vrinta - round with ties to away from zero
3945 sd_value = roundf(sm_value);
3946 break;
3947 case 0x1: { // vrintn - round with ties to even
3948 sd_value = nearbyintf(sm_value);
3949 break;
3950 }
3951 case 0x2: // vrintp - ceil
3952 sd_value = ceilf(sm_value);
3953 break;
3954 case 0x3: // vrintm - floor
3955 sd_value = floorf(sm_value);
3956 break;
3957 default:
3958 UNREACHABLE(); // Case analysis is exhaustive.
3959 break;
3960 }
3961 sd_value = canonicalizeNaN(sd_value);
3962 set_s_register_from_float(d, sd_value);
3963 }
3964 } else if ((instr->Opc1Value() == 0x4) && (instr->Bits(11, 9) == 0x5) &&
3965 (instr->Bit(4) == 0x0)) {
3966 if (instr->SzValue() == 0x1) {
3967 int m = instr->VFPMRegValue(kDoublePrecision);
3968 int n = instr->VFPNRegValue(kDoublePrecision);
3969 int d = instr->VFPDRegValue(kDoublePrecision);
3970 double dn_value = get_double_from_d_register(n);
3971 double dm_value = get_double_from_d_register(m);
3972 double dd_value;
3973 if (instr->Bit(6) == 0x1) { // vminnm
3974 if ((dn_value < dm_value) || std::isnan(dm_value)) {
3975 dd_value = dn_value;
3976 } else if ((dm_value < dn_value) || std::isnan(dn_value)) {
3977 dd_value = dm_value;
3978 } else {
3979 DCHECK_EQ(dn_value, dm_value);
3980 // Make sure that we pick the most negative sign for +/-0.
3981 dd_value = std::signbit(dn_value) ? dn_value : dm_value;
3982 }
3983 } else { // vmaxnm
3984 if ((dn_value > dm_value) || std::isnan(dm_value)) {
3985 dd_value = dn_value;
3986 } else if ((dm_value > dn_value) || std::isnan(dn_value)) {
3987 dd_value = dm_value;
3988 } else {
3989 DCHECK_EQ(dn_value, dm_value);
3990 // Make sure that we pick the most positive sign for +/-0.
3991 dd_value = std::signbit(dn_value) ? dm_value : dn_value;
3992 }
3993 }
3994 dd_value = canonicalizeNaN(dd_value);
3995 set_d_register_from_double(d, dd_value);
3996 } else {
3997 int m = instr->VFPMRegValue(kSinglePrecision);
3998 int n = instr->VFPNRegValue(kSinglePrecision);
3999 int d = instr->VFPDRegValue(kSinglePrecision);
4000 float sn_value = get_float_from_s_register(n);
4001 float sm_value = get_float_from_s_register(m);
4002 float sd_value;
4003 if (instr->Bit(6) == 0x1) { // vminnm
4004 if ((sn_value < sm_value) || std::isnan(sm_value)) {
4005 sd_value = sn_value;
4006 } else if ((sm_value < sn_value) || std::isnan(sn_value)) {
4007 sd_value = sm_value;
4008 } else {
4009 DCHECK_EQ(sn_value, sm_value);
4010 // Make sure that we pick the most negative sign for +/-0.
4011 sd_value = std::signbit(sn_value) ? sn_value : sm_value;
4012 }
4013 } else { // vmaxnm
4014 if ((sn_value > sm_value) || std::isnan(sm_value)) {
4015 sd_value = sn_value;
4016 } else if ((sm_value > sn_value) || std::isnan(sn_value)) {
4017 sd_value = sm_value;
4018 } else {
4019 DCHECK_EQ(sn_value, sm_value);
4020 // Make sure that we pick the most positive sign for +/-0.
4021 sd_value = std::signbit(sn_value) ? sm_value : sn_value;
4022 }
4023 }
4024 sd_value = canonicalizeNaN(sd_value);
4025 set_s_register_from_float(d, sd_value);
4026 }
4027 } else {
4028 UNIMPLEMENTED();
4029 }
4030 break;
4031 case 0x1C:
4032 if ((instr->Bits(11, 9) == 0x5) && (instr->Bit(6) == 0) &&
4033 (instr->Bit(4) == 0)) {
4034 // VSEL* (floating-point)
4035 bool condition_holds;
4036 switch (instr->Bits(21, 20)) {
4037 case 0x0: // VSELEQ
4038 condition_holds = (z_flag_ == 1);
4039 break;
4040 case 0x1: // VSELVS
4041 condition_holds = (v_flag_ == 1);
4042 break;
4043 case 0x2: // VSELGE
4044 condition_holds = (n_flag_ == v_flag_);
4045 break;
4046 case 0x3: // VSELGT
4047 condition_holds = ((z_flag_ == 0) && (n_flag_ == v_flag_));
4048 break;
4049 default:
4050 UNREACHABLE(); // Case analysis is exhaustive.
4051 break;
4052 }
4053 if (instr->SzValue() == 0x1) {
4054 int n = instr->VFPNRegValue(kDoublePrecision);
4055 int m = instr->VFPMRegValue(kDoublePrecision);
4056 int d = instr->VFPDRegValue(kDoublePrecision);
4057 double result = get_double_from_d_register(condition_holds ? n : m);
4058 set_d_register_from_double(d, result);
4059 } else {
4060 int n = instr->VFPNRegValue(kSinglePrecision);
4061 int m = instr->VFPMRegValue(kSinglePrecision);
4062 int d = instr->VFPDRegValue(kSinglePrecision);
4063 float result = get_float_from_s_register(condition_holds ? n : m);
4064 set_s_register_from_float(d, result);
4065 }
4066 } else {
4067 UNIMPLEMENTED();
4068 }
4069 break;
4070 default:
4071 UNIMPLEMENTED();
4072 break;
4073 }
4074 }
4075
4076
4077 // Executes the current instruction.
InstructionDecode(Instruction * instr)4078 void Simulator::InstructionDecode(Instruction* instr) {
4079 if (v8::internal::FLAG_check_icache) {
4080 CheckICache(isolate_->simulator_i_cache(), instr);
4081 }
4082 pc_modified_ = false;
4083 if (::v8::internal::FLAG_trace_sim) {
4084 disasm::NameConverter converter;
4085 disasm::Disassembler dasm(converter);
4086 // use a reasonably large buffer
4087 v8::internal::EmbeddedVector<char, 256> buffer;
4088 dasm.InstructionDecode(buffer,
4089 reinterpret_cast<byte*>(instr));
4090 PrintF(" 0x%08" V8PRIxPTR " %s\n", reinterpret_cast<intptr_t>(instr),
4091 buffer.start());
4092 }
4093 if (instr->ConditionField() == kSpecialCondition) {
4094 DecodeSpecialCondition(instr);
4095 } else if (ConditionallyExecute(instr)) {
4096 switch (instr->TypeValue()) {
4097 case 0:
4098 case 1: {
4099 DecodeType01(instr);
4100 break;
4101 }
4102 case 2: {
4103 DecodeType2(instr);
4104 break;
4105 }
4106 case 3: {
4107 DecodeType3(instr);
4108 break;
4109 }
4110 case 4: {
4111 DecodeType4(instr);
4112 break;
4113 }
4114 case 5: {
4115 DecodeType5(instr);
4116 break;
4117 }
4118 case 6: {
4119 DecodeType6(instr);
4120 break;
4121 }
4122 case 7: {
4123 DecodeType7(instr);
4124 break;
4125 }
4126 default: {
4127 UNIMPLEMENTED();
4128 break;
4129 }
4130 }
4131 // If the instruction is a non taken conditional stop, we need to skip the
4132 // inlined message address.
4133 } else if (instr->IsStop()) {
4134 set_pc(get_pc() + 2 * Instruction::kInstrSize);
4135 }
4136 if (!pc_modified_) {
4137 set_register(pc, reinterpret_cast<int32_t>(instr)
4138 + Instruction::kInstrSize);
4139 }
4140 }
4141
4142
Execute()4143 void Simulator::Execute() {
4144 // Get the PC to simulate. Cannot use the accessor here as we need the
4145 // raw PC value and not the one used as input to arithmetic instructions.
4146 int program_counter = get_pc();
4147
4148 if (::v8::internal::FLAG_stop_sim_at == 0) {
4149 // Fast version of the dispatch loop without checking whether the simulator
4150 // should be stopping at a particular executed instruction.
4151 while (program_counter != end_sim_pc) {
4152 Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
4153 icount_++;
4154 InstructionDecode(instr);
4155 program_counter = get_pc();
4156 }
4157 } else {
4158 // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when
4159 // we reach the particular instuction count.
4160 while (program_counter != end_sim_pc) {
4161 Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
4162 icount_++;
4163 if (icount_ == ::v8::internal::FLAG_stop_sim_at) {
4164 ArmDebugger dbg(this);
4165 dbg.Debug();
4166 } else {
4167 InstructionDecode(instr);
4168 }
4169 program_counter = get_pc();
4170 }
4171 }
4172 }
4173
4174
CallInternal(byte * entry)4175 void Simulator::CallInternal(byte* entry) {
4176 // Adjust JS-based stack limit to C-based stack limit.
4177 isolate_->stack_guard()->AdjustStackLimitForSimulator();
4178
4179 // Prepare to execute the code at entry
4180 set_register(pc, reinterpret_cast<int32_t>(entry));
4181 // Put down marker for end of simulation. The simulator will stop simulation
4182 // when the PC reaches this value. By saving the "end simulation" value into
4183 // the LR the simulation stops when returning to this call point.
4184 set_register(lr, end_sim_pc);
4185
4186 // Remember the values of callee-saved registers.
4187 // The code below assumes that r9 is not used as sb (static base) in
4188 // simulator code and therefore is regarded as a callee-saved register.
4189 int32_t r4_val = get_register(r4);
4190 int32_t r5_val = get_register(r5);
4191 int32_t r6_val = get_register(r6);
4192 int32_t r7_val = get_register(r7);
4193 int32_t r8_val = get_register(r8);
4194 int32_t r9_val = get_register(r9);
4195 int32_t r10_val = get_register(r10);
4196 int32_t r11_val = get_register(r11);
4197
4198 // Set up the callee-saved registers with a known value. To be able to check
4199 // that they are preserved properly across JS execution.
4200 int32_t callee_saved_value = icount_;
4201 set_register(r4, callee_saved_value);
4202 set_register(r5, callee_saved_value);
4203 set_register(r6, callee_saved_value);
4204 set_register(r7, callee_saved_value);
4205 set_register(r8, callee_saved_value);
4206 set_register(r9, callee_saved_value);
4207 set_register(r10, callee_saved_value);
4208 set_register(r11, callee_saved_value);
4209
4210 // Start the simulation
4211 Execute();
4212
4213 // Check that the callee-saved registers have been preserved.
4214 CHECK_EQ(callee_saved_value, get_register(r4));
4215 CHECK_EQ(callee_saved_value, get_register(r5));
4216 CHECK_EQ(callee_saved_value, get_register(r6));
4217 CHECK_EQ(callee_saved_value, get_register(r7));
4218 CHECK_EQ(callee_saved_value, get_register(r8));
4219 CHECK_EQ(callee_saved_value, get_register(r9));
4220 CHECK_EQ(callee_saved_value, get_register(r10));
4221 CHECK_EQ(callee_saved_value, get_register(r11));
4222
4223 // Restore callee-saved registers with the original value.
4224 set_register(r4, r4_val);
4225 set_register(r5, r5_val);
4226 set_register(r6, r6_val);
4227 set_register(r7, r7_val);
4228 set_register(r8, r8_val);
4229 set_register(r9, r9_val);
4230 set_register(r10, r10_val);
4231 set_register(r11, r11_val);
4232 }
4233
4234
Call(byte * entry,int argument_count,...)4235 int32_t Simulator::Call(byte* entry, int argument_count, ...) {
4236 va_list parameters;
4237 va_start(parameters, argument_count);
4238 // Set up arguments
4239
4240 // First four arguments passed in registers.
4241 DCHECK(argument_count >= 4);
4242 set_register(r0, va_arg(parameters, int32_t));
4243 set_register(r1, va_arg(parameters, int32_t));
4244 set_register(r2, va_arg(parameters, int32_t));
4245 set_register(r3, va_arg(parameters, int32_t));
4246
4247 // Remaining arguments passed on stack.
4248 int original_stack = get_register(sp);
4249 // Compute position of stack on entry to generated code.
4250 int entry_stack = (original_stack - (argument_count - 4) * sizeof(int32_t));
4251 if (base::OS::ActivationFrameAlignment() != 0) {
4252 entry_stack &= -base::OS::ActivationFrameAlignment();
4253 }
4254 // Store remaining arguments on stack, from low to high memory.
4255 intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
4256 for (int i = 4; i < argument_count; i++) {
4257 stack_argument[i - 4] = va_arg(parameters, int32_t);
4258 }
4259 va_end(parameters);
4260 set_register(sp, entry_stack);
4261
4262 CallInternal(entry);
4263
4264 // Pop stack passed arguments.
4265 CHECK_EQ(entry_stack, get_register(sp));
4266 set_register(sp, original_stack);
4267
4268 int32_t result = get_register(r0);
4269 return result;
4270 }
4271
4272
CallFP(byte * entry,double d0,double d1)4273 void Simulator::CallFP(byte* entry, double d0, double d1) {
4274 if (use_eabi_hardfloat()) {
4275 set_d_register_from_double(0, d0);
4276 set_d_register_from_double(1, d1);
4277 } else {
4278 set_register_pair_from_double(0, &d0);
4279 set_register_pair_from_double(2, &d1);
4280 }
4281 CallInternal(entry);
4282 }
4283
4284
CallFPReturnsInt(byte * entry,double d0,double d1)4285 int32_t Simulator::CallFPReturnsInt(byte* entry, double d0, double d1) {
4286 CallFP(entry, d0, d1);
4287 int32_t result = get_register(r0);
4288 return result;
4289 }
4290
4291
CallFPReturnsDouble(byte * entry,double d0,double d1)4292 double Simulator::CallFPReturnsDouble(byte* entry, double d0, double d1) {
4293 CallFP(entry, d0, d1);
4294 if (use_eabi_hardfloat()) {
4295 return get_double_from_d_register(0);
4296 } else {
4297 return get_double_from_register_pair(0);
4298 }
4299 }
4300
4301
PushAddress(uintptr_t address)4302 uintptr_t Simulator::PushAddress(uintptr_t address) {
4303 int new_sp = get_register(sp) - sizeof(uintptr_t);
4304 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp);
4305 *stack_slot = address;
4306 set_register(sp, new_sp);
4307 return new_sp;
4308 }
4309
4310
PopAddress()4311 uintptr_t Simulator::PopAddress() {
4312 int current_sp = get_register(sp);
4313 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp);
4314 uintptr_t address = *stack_slot;
4315 set_register(sp, current_sp + sizeof(uintptr_t));
4316 return address;
4317 }
4318
4319 } // namespace internal
4320 } // namespace v8
4321
4322 #endif // USE_SIMULATOR
4323
4324 #endif // V8_TARGET_ARCH_ARM
4325