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-inl.h"
14 #include "src/base/bits.h"
15 #include "src/codegen.h"
16 #include "src/disasm.h"
17 #include "src/macro-assembler.h"
18 #include "src/objects-inl.h"
19 #include "src/runtime/runtime-utils.h"
20
21 #if defined(USE_SIMULATOR)
22
23 // Only build the simulator if not compiling for real ARM hardware.
24 namespace v8 {
25 namespace internal {
26
27 // static
28 base::LazyInstance<Simulator::GlobalMonitor>::type Simulator::global_monitor_ =
29 LAZY_INSTANCE_INITIALIZER;
30
31 // This macro provides a platform independent use of sscanf. The reason for
32 // SScanF not being implemented in a platform independent way through
33 // ::v8::internal::OS in the same way as SNPrintF is that the
34 // Windows C Run-Time Library does not provide vsscanf.
35 #define SScanF sscanf // NOLINT
36
37 // The ArmDebugger class is used by the simulator while debugging simulated ARM
38 // code.
39 class ArmDebugger {
40 public:
ArmDebugger(Simulator * sim)41 explicit ArmDebugger(Simulator* sim) : sim_(sim) { }
42
43 void Stop(Instruction* instr);
44 void Debug();
45
46 private:
47 static const Instr kBreakpointInstr =
48 (al | (7*B25) | (1*B24) | kBreakpoint);
49 static const Instr kNopInstr = (al | (13*B21));
50
51 Simulator* sim_;
52
53 int32_t GetRegisterValue(int regnum);
54 double GetRegisterPairDoubleValue(int regnum);
55 double GetVFPDoubleRegisterValue(int regnum);
56 bool GetValue(const char* desc, int32_t* value);
57 bool GetVFPSingleValue(const char* desc, float* value);
58 bool GetVFPDoubleValue(const char* desc, double* value);
59
60 // Set or delete a breakpoint. Returns true if successful.
61 bool SetBreakpoint(Instruction* breakpc);
62 bool DeleteBreakpoint(Instruction* breakpc);
63
64 // Undo and redo all breakpoints. This is needed to bracket disassembly and
65 // execution to skip past breakpoints when run from the debugger.
66 void UndoBreakpoints();
67 void RedoBreakpoints();
68 };
69
Stop(Instruction * instr)70 void ArmDebugger::Stop(Instruction* instr) {
71 // Get the stop code.
72 uint32_t code = instr->SvcValue() & kStopCodeMask;
73 // Print the stop message and code if it is not the default code.
74 if (code != kMaxStopCode) {
75 PrintF("Simulator hit stop %u\n", code);
76 } else {
77 PrintF("Simulator hit\n");
78 }
79 Debug();
80 }
81
GetRegisterValue(int regnum)82 int32_t ArmDebugger::GetRegisterValue(int regnum) {
83 if (regnum == kPCRegister) {
84 return sim_->get_pc();
85 } else {
86 return sim_->get_register(regnum);
87 }
88 }
89
GetRegisterPairDoubleValue(int regnum)90 double ArmDebugger::GetRegisterPairDoubleValue(int regnum) {
91 return sim_->get_double_from_register_pair(regnum);
92 }
93
94
GetVFPDoubleRegisterValue(int regnum)95 double ArmDebugger::GetVFPDoubleRegisterValue(int regnum) {
96 return sim_->get_double_from_d_register(regnum).get_scalar();
97 }
98
99
GetValue(const char * desc,int32_t * value)100 bool ArmDebugger::GetValue(const char* desc, int32_t* value) {
101 int regnum = Registers::Number(desc);
102 if (regnum != kNoRegister) {
103 *value = GetRegisterValue(regnum);
104 return true;
105 } else {
106 if (strncmp(desc, "0x", 2) == 0) {
107 return SScanF(desc + 2, "%x", reinterpret_cast<uint32_t*>(value)) == 1;
108 } else {
109 return SScanF(desc, "%u", reinterpret_cast<uint32_t*>(value)) == 1;
110 }
111 }
112 return false;
113 }
114
115
GetVFPSingleValue(const char * desc,float * value)116 bool ArmDebugger::GetVFPSingleValue(const char* desc, float* value) {
117 bool is_double;
118 int regnum = VFPRegisters::Number(desc, &is_double);
119 if (regnum != kNoRegister && !is_double) {
120 *value = sim_->get_float_from_s_register(regnum).get_scalar();
121 return true;
122 }
123 return false;
124 }
125
126
GetVFPDoubleValue(const char * desc,double * value)127 bool ArmDebugger::GetVFPDoubleValue(const char* desc, double* value) {
128 bool is_double;
129 int regnum = VFPRegisters::Number(desc, &is_double);
130 if (regnum != kNoRegister && is_double) {
131 *value = sim_->get_double_from_d_register(regnum).get_scalar();
132 return true;
133 }
134 return false;
135 }
136
137
SetBreakpoint(Instruction * breakpc)138 bool ArmDebugger::SetBreakpoint(Instruction* breakpc) {
139 // Check if a breakpoint can be set. If not return without any side-effects.
140 if (sim_->break_pc_ != nullptr) {
141 return false;
142 }
143
144 // Set the breakpoint.
145 sim_->break_pc_ = breakpc;
146 sim_->break_instr_ = breakpc->InstructionBits();
147 // Not setting the breakpoint instruction in the code itself. It will be set
148 // when the debugger shell continues.
149 return true;
150 }
151
152
DeleteBreakpoint(Instruction * breakpc)153 bool ArmDebugger::DeleteBreakpoint(Instruction* breakpc) {
154 if (sim_->break_pc_ != nullptr) {
155 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
156 }
157
158 sim_->break_pc_ = nullptr;
159 sim_->break_instr_ = 0;
160 return true;
161 }
162
163
UndoBreakpoints()164 void ArmDebugger::UndoBreakpoints() {
165 if (sim_->break_pc_ != nullptr) {
166 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
167 }
168 }
169
170
RedoBreakpoints()171 void ArmDebugger::RedoBreakpoints() {
172 if (sim_->break_pc_ != nullptr) {
173 sim_->break_pc_->SetInstructionBits(kBreakpointInstr);
174 }
175 }
176
177
Debug()178 void ArmDebugger::Debug() {
179 intptr_t last_pc = -1;
180 bool done = false;
181
182 #define COMMAND_SIZE 63
183 #define ARG_SIZE 255
184
185 #define STR(a) #a
186 #define XSTR(a) STR(a)
187
188 char cmd[COMMAND_SIZE + 1];
189 char arg1[ARG_SIZE + 1];
190 char arg2[ARG_SIZE + 1];
191 char* argv[3] = { cmd, arg1, arg2 };
192
193 // make sure to have a proper terminating character if reaching the limit
194 cmd[COMMAND_SIZE] = 0;
195 arg1[ARG_SIZE] = 0;
196 arg2[ARG_SIZE] = 0;
197
198 // Undo all set breakpoints while running in the debugger shell. This will
199 // make them invisible to all commands.
200 UndoBreakpoints();
201
202 while (!done && !sim_->has_bad_pc()) {
203 if (last_pc != sim_->get_pc()) {
204 disasm::NameConverter converter;
205 disasm::Disassembler dasm(converter);
206 // use a reasonably large buffer
207 v8::internal::EmbeddedVector<char, 256> buffer;
208 dasm.InstructionDecode(buffer,
209 reinterpret_cast<byte*>(sim_->get_pc()));
210 PrintF(" 0x%08x %s\n", sim_->get_pc(), buffer.start());
211 last_pc = sim_->get_pc();
212 }
213 char* line = ReadLine("sim> ");
214 if (line == nullptr) {
215 break;
216 } else {
217 char* last_input = sim_->last_debugger_input();
218 if (strcmp(line, "\n") == 0 && last_input != nullptr) {
219 line = last_input;
220 } else {
221 // Ownership is transferred to sim_;
222 sim_->set_last_debugger_input(line);
223 }
224 // Use sscanf to parse the individual parts of the command line. At the
225 // moment no command expects more than two parameters.
226 int argc = SScanF(line,
227 "%" XSTR(COMMAND_SIZE) "s "
228 "%" XSTR(ARG_SIZE) "s "
229 "%" XSTR(ARG_SIZE) "s",
230 cmd, arg1, arg2);
231 if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
232 sim_->InstructionDecode(reinterpret_cast<Instruction*>(sim_->get_pc()));
233 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) {
234 // Execute the one instruction we broke at with breakpoints disabled.
235 sim_->InstructionDecode(reinterpret_cast<Instruction*>(sim_->get_pc()));
236 // Leave the debugger shell.
237 done = true;
238 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
239 if (argc == 2 || (argc == 3 && strcmp(arg2, "fp") == 0)) {
240 int32_t value;
241 float svalue;
242 double dvalue;
243 if (strcmp(arg1, "all") == 0) {
244 for (int i = 0; i < kNumRegisters; i++) {
245 value = GetRegisterValue(i);
246 PrintF(
247 "%3s: 0x%08x %10d",
248 RegisterConfiguration::Default()->GetGeneralRegisterName(i),
249 value, value);
250 if ((argc == 3 && strcmp(arg2, "fp") == 0) &&
251 i < 8 &&
252 (i % 2) == 0) {
253 dvalue = GetRegisterPairDoubleValue(i);
254 PrintF(" (%f)\n", dvalue);
255 } else {
256 PrintF("\n");
257 }
258 }
259 for (int i = 0; i < DwVfpRegister::NumRegisters(); i++) {
260 dvalue = GetVFPDoubleRegisterValue(i);
261 uint64_t as_words = bit_cast<uint64_t>(dvalue);
262 PrintF("%3s: %f 0x%08x %08x\n", VFPRegisters::Name(i, true),
263 dvalue, static_cast<uint32_t>(as_words >> 32),
264 static_cast<uint32_t>(as_words & 0xFFFFFFFF));
265 }
266 } else {
267 if (GetValue(arg1, &value)) {
268 PrintF("%s: 0x%08x %d \n", arg1, value, value);
269 } else if (GetVFPSingleValue(arg1, &svalue)) {
270 uint32_t as_word = bit_cast<uint32_t>(svalue);
271 PrintF("%s: %f 0x%08x\n", arg1, svalue, as_word);
272 } else if (GetVFPDoubleValue(arg1, &dvalue)) {
273 uint64_t as_words = bit_cast<uint64_t>(dvalue);
274 PrintF("%s: %f 0x%08x %08x\n", arg1, 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 StdoutStream os;
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 = nullptr;
306 int32_t* end = nullptr;
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 = nullptr;
357 byte* cur = nullptr;
358 byte* end = nullptr;
359
360 if (argc == 1) {
361 cur = reinterpret_cast<byte*>(sim_->get_pc());
362 end = cur + (10 * 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 * 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 * 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 * 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(nullptr)) {
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() - kInstrSize;
431 Instruction* stop_instr = reinterpret_cast<Instruction*>(stop_pc);
432 if ((argc == 2) && (strcmp(arg1, "unstop") == 0)) {
433 // Remove the current stop.
434 if (sim_->isStopInstruction(stop_instr)) {
435 stop_instr->SetInstructionBits(kNopInstr);
436 } else {
437 PrintF("Not at debugger stop.\n");
438 }
439 } else if (argc == 3) {
440 // Print information about all/the specified breakpoint(s).
441 if (strcmp(arg1, "info") == 0) {
442 if (strcmp(arg2, "all") == 0) {
443 PrintF("Stop information:\n");
444 for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) {
445 sim_->PrintStopInfo(i);
446 }
447 } else if (GetValue(arg2, &value)) {
448 sim_->PrintStopInfo(value);
449 } else {
450 PrintF("Unrecognized argument.\n");
451 }
452 } else if (strcmp(arg1, "enable") == 0) {
453 // Enable all/the specified breakpoint(s).
454 if (strcmp(arg2, "all") == 0) {
455 for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) {
456 sim_->EnableStop(i);
457 }
458 } else if (GetValue(arg2, &value)) {
459 sim_->EnableStop(value);
460 } else {
461 PrintF("Unrecognized argument.\n");
462 }
463 } else if (strcmp(arg1, "disable") == 0) {
464 // Disable all/the specified breakpoint(s).
465 if (strcmp(arg2, "all") == 0) {
466 for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) {
467 sim_->DisableStop(i);
468 }
469 } else if (GetValue(arg2, &value)) {
470 sim_->DisableStop(value);
471 } else {
472 PrintF("Unrecognized argument.\n");
473 }
474 }
475 } else {
476 PrintF("Wrong usage. Use help command for more information.\n");
477 }
478 } else if ((strcmp(cmd, "t") == 0) || strcmp(cmd, "trace") == 0) {
479 ::v8::internal::FLAG_trace_sim = !::v8::internal::FLAG_trace_sim;
480 PrintF("Trace of executed instructions is %s\n",
481 ::v8::internal::FLAG_trace_sim ? "on" : "off");
482 } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
483 PrintF("cont\n");
484 PrintF(" continue execution (alias 'c')\n");
485 PrintF("stepi\n");
486 PrintF(" step one instruction (alias 'si')\n");
487 PrintF("print <register>\n");
488 PrintF(" print register content (alias 'p')\n");
489 PrintF(" use register name 'all' to print all registers\n");
490 PrintF(" add argument 'fp' to print register pair double values\n");
491 PrintF("printobject <register>\n");
492 PrintF(" print an object from a register (alias 'po')\n");
493 PrintF("flags\n");
494 PrintF(" print flags\n");
495 PrintF("stack [<words>]\n");
496 PrintF(" dump stack content, default dump 10 words)\n");
497 PrintF("mem <address> [<words>]\n");
498 PrintF(" dump memory content, default dump 10 words)\n");
499 PrintF("disasm [<instructions>]\n");
500 PrintF("disasm [<address/register>]\n");
501 PrintF("disasm [[<address/register>] <instructions>]\n");
502 PrintF(" disassemble code, default is 10 instructions\n");
503 PrintF(" from pc (alias 'di')\n");
504 PrintF("gdb\n");
505 PrintF(" enter gdb\n");
506 PrintF("break <address>\n");
507 PrintF(" set a break point on the address\n");
508 PrintF("del\n");
509 PrintF(" delete the breakpoint\n");
510 PrintF("trace (alias 't')\n");
511 PrintF(" toogle the tracing of all executed statements\n");
512 PrintF("stop feature:\n");
513 PrintF(" Description:\n");
514 PrintF(" Stops are debug instructions inserted by\n");
515 PrintF(" the Assembler::stop() function.\n");
516 PrintF(" When hitting a stop, the Simulator will\n");
517 PrintF(" stop and give control to the ArmDebugger.\n");
518 PrintF(" The first %d stop codes are watched:\n",
519 Simulator::kNumOfWatchedStops);
520 PrintF(" - They can be enabled / disabled: the Simulator\n");
521 PrintF(" will / won't stop when hitting them.\n");
522 PrintF(" - The Simulator keeps track of how many times they \n");
523 PrintF(" are met. (See the info command.) Going over a\n");
524 PrintF(" disabled stop still increases its counter. \n");
525 PrintF(" Commands:\n");
526 PrintF(" stop info all/<code> : print infos about number <code>\n");
527 PrintF(" or all stop(s).\n");
528 PrintF(" stop enable/disable all/<code> : enables / disables\n");
529 PrintF(" all or number <code> stop(s)\n");
530 PrintF(" stop unstop\n");
531 PrintF(" ignore the stop instruction at the current location\n");
532 PrintF(" from now on\n");
533 } else {
534 PrintF("Unknown command: %s\n", cmd);
535 }
536 }
537 }
538
539 // Add all the breakpoints back to stop execution and enter the debugger
540 // shell when hit.
541 RedoBreakpoints();
542
543 #undef COMMAND_SIZE
544 #undef ARG_SIZE
545
546 #undef STR
547 #undef XSTR
548 }
549
ICacheMatch(void * one,void * two)550 bool Simulator::ICacheMatch(void* one, void* two) {
551 DCHECK_EQ(reinterpret_cast<intptr_t>(one) & CachePage::kPageMask, 0);
552 DCHECK_EQ(reinterpret_cast<intptr_t>(two) & CachePage::kPageMask, 0);
553 return one == two;
554 }
555
556
ICacheHash(void * key)557 static uint32_t ICacheHash(void* key) {
558 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)) >> 2;
559 }
560
561
AllOnOnePage(uintptr_t start,int size)562 static bool AllOnOnePage(uintptr_t start, int size) {
563 intptr_t start_page = (start & ~CachePage::kPageMask);
564 intptr_t end_page = ((start + size) & ~CachePage::kPageMask);
565 return start_page == end_page;
566 }
567
set_last_debugger_input(char * input)568 void Simulator::set_last_debugger_input(char* input) {
569 DeleteArray(last_debugger_input_);
570 last_debugger_input_ = input;
571 }
572
SetRedirectInstruction(Instruction * instruction)573 void Simulator::SetRedirectInstruction(Instruction* instruction) {
574 instruction->SetInstructionBits(al | (0xF * B24) | kCallRtRedirected);
575 }
576
FlushICache(base::CustomMatcherHashMap * i_cache,void * start_addr,size_t size)577 void Simulator::FlushICache(base::CustomMatcherHashMap* i_cache,
578 void* start_addr, size_t size) {
579 intptr_t start = reinterpret_cast<intptr_t>(start_addr);
580 int intra_line = (start & CachePage::kLineMask);
581 start -= intra_line;
582 size += intra_line;
583 size = ((size - 1) | CachePage::kLineMask) + 1;
584 int offset = (start & CachePage::kPageMask);
585 while (!AllOnOnePage(start, size - 1)) {
586 int bytes_to_flush = CachePage::kPageSize - offset;
587 FlushOnePage(i_cache, start, bytes_to_flush);
588 start += bytes_to_flush;
589 size -= bytes_to_flush;
590 DCHECK_EQ(0, start & CachePage::kPageMask);
591 offset = 0;
592 }
593 if (size != 0) {
594 FlushOnePage(i_cache, start, size);
595 }
596 }
597
GetCachePage(base::CustomMatcherHashMap * i_cache,void * page)598 CachePage* Simulator::GetCachePage(base::CustomMatcherHashMap* i_cache,
599 void* page) {
600 base::HashMap::Entry* entry = i_cache->LookupOrInsert(page, ICacheHash(page));
601 if (entry->value == nullptr) {
602 CachePage* new_page = new CachePage();
603 entry->value = new_page;
604 }
605 return reinterpret_cast<CachePage*>(entry->value);
606 }
607
608
609 // Flush from start up to and not including start + size.
FlushOnePage(base::CustomMatcherHashMap * i_cache,intptr_t start,int size)610 void Simulator::FlushOnePage(base::CustomMatcherHashMap* i_cache,
611 intptr_t start, int size) {
612 DCHECK_LE(size, CachePage::kPageSize);
613 DCHECK(AllOnOnePage(start, size - 1));
614 DCHECK_EQ(start & CachePage::kLineMask, 0);
615 DCHECK_EQ(size & CachePage::kLineMask, 0);
616 void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask));
617 int offset = (start & CachePage::kPageMask);
618 CachePage* cache_page = GetCachePage(i_cache, page);
619 char* valid_bytemap = cache_page->ValidityByte(offset);
620 memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift);
621 }
622
CheckICache(base::CustomMatcherHashMap * i_cache,Instruction * instr)623 void Simulator::CheckICache(base::CustomMatcherHashMap* i_cache,
624 Instruction* instr) {
625 intptr_t address = reinterpret_cast<intptr_t>(instr);
626 void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
627 void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask));
628 int offset = (address & CachePage::kPageMask);
629 CachePage* cache_page = GetCachePage(i_cache, page);
630 char* cache_valid_byte = cache_page->ValidityByte(offset);
631 bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID);
632 char* cached_line = cache_page->CachedData(offset & ~CachePage::kLineMask);
633 if (cache_hit) {
634 // Check that the data in memory matches the contents of the I-cache.
635 CHECK_EQ(0, memcmp(reinterpret_cast<void*>(instr),
636 cache_page->CachedData(offset), kInstrSize));
637 } else {
638 // Cache miss. Load memory into the cache.
639 memcpy(cached_line, line, CachePage::kLineLength);
640 *cache_valid_byte = CachePage::LINE_VALID;
641 }
642 }
643
644
Simulator(Isolate * isolate)645 Simulator::Simulator(Isolate* isolate) : isolate_(isolate) {
646 // Set up simulator support first. Some of this information is needed to
647 // setup the architecture state.
648 size_t stack_size = 1 * 1024*1024; // allocate 1MB for stack
649 stack_ = reinterpret_cast<char*>(malloc(stack_size));
650 pc_modified_ = false;
651 icount_ = 0;
652 break_pc_ = nullptr;
653 break_instr_ = 0;
654
655 // Set up architecture state.
656 // All registers are initialized to zero to start with.
657 for (int i = 0; i < num_registers; i++) {
658 registers_[i] = 0;
659 }
660 n_flag_ = false;
661 z_flag_ = false;
662 c_flag_ = false;
663 v_flag_ = false;
664
665 // Initializing VFP registers.
666 // All registers are initialized to zero to start with
667 // even though s_registers_ & d_registers_ share the same
668 // physical registers in the target.
669 for (int i = 0; i < num_d_registers * 2; i++) {
670 vfp_registers_[i] = 0;
671 }
672 n_flag_FPSCR_ = false;
673 z_flag_FPSCR_ = false;
674 c_flag_FPSCR_ = false;
675 v_flag_FPSCR_ = false;
676 FPSCR_rounding_mode_ = RN;
677 FPSCR_default_NaN_mode_ = false;
678
679 inv_op_vfp_flag_ = false;
680 div_zero_vfp_flag_ = false;
681 overflow_vfp_flag_ = false;
682 underflow_vfp_flag_ = false;
683 inexact_vfp_flag_ = false;
684
685 // The sp is initialized to point to the bottom (high address) of the
686 // allocated stack area. To be safe in potential stack underflows we leave
687 // some buffer below.
688 registers_[sp] = reinterpret_cast<int32_t>(stack_) + stack_size - 64;
689 // The lr and pc are initialized to a known bad value that will cause an
690 // access violation if the simulator ever tries to execute it.
691 registers_[pc] = bad_lr;
692 registers_[lr] = bad_lr;
693
694 last_debugger_input_ = nullptr;
695 }
696
~Simulator()697 Simulator::~Simulator() {
698 global_monitor_.Pointer()->RemoveProcessor(&global_monitor_processor_);
699 free(stack_);
700 }
701
702
703 // Get the active Simulator for the current thread.
current(Isolate * isolate)704 Simulator* Simulator::current(Isolate* isolate) {
705 v8::internal::Isolate::PerIsolateThreadData* isolate_data =
706 isolate->FindOrAllocatePerThreadDataForThisThread();
707 DCHECK_NOT_NULL(isolate_data);
708
709 Simulator* sim = isolate_data->simulator();
710 if (sim == nullptr) {
711 // TODO(146): delete the simulator object when a thread/isolate goes away.
712 sim = new Simulator(isolate);
713 isolate_data->set_simulator(sim);
714 }
715 return sim;
716 }
717
718
719 // Sets the register in the architecture state. It will also deal with updating
720 // Simulator internal state for special registers such as PC.
set_register(int reg,int32_t value)721 void Simulator::set_register(int reg, int32_t value) {
722 DCHECK((reg >= 0) && (reg < num_registers));
723 if (reg == pc) {
724 pc_modified_ = true;
725 }
726 registers_[reg] = value;
727 }
728
729
730 // Get the register from the architecture state. This function does handle
731 // the special case of accessing the PC register.
get_register(int reg) const732 int32_t Simulator::get_register(int reg) const {
733 DCHECK((reg >= 0) && (reg < num_registers));
734 // Stupid code added to avoid bug in GCC.
735 // See: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43949
736 if (reg >= num_registers) return 0;
737 // End stupid code.
738 return registers_[reg] + ((reg == pc) ? Instruction::kPcLoadDelta : 0);
739 }
740
741
get_double_from_register_pair(int reg)742 double Simulator::get_double_from_register_pair(int reg) {
743 DCHECK((reg >= 0) && (reg < num_registers) && ((reg % 2) == 0));
744
745 double dm_val = 0.0;
746 // Read the bits from the unsigned integer register_[] array
747 // into the double precision floating point value and return it.
748 char buffer[2 * sizeof(vfp_registers_[0])];
749 memcpy(buffer, ®isters_[reg], 2 * sizeof(registers_[0]));
750 memcpy(&dm_val, buffer, 2 * sizeof(registers_[0]));
751 return(dm_val);
752 }
753
754
set_register_pair_from_double(int reg,double * value)755 void Simulator::set_register_pair_from_double(int reg, double* value) {
756 DCHECK((reg >= 0) && (reg < num_registers) && ((reg % 2) == 0));
757 memcpy(registers_ + reg, value, sizeof(*value));
758 }
759
760
set_dw_register(int dreg,const int * dbl)761 void Simulator::set_dw_register(int dreg, const int* dbl) {
762 DCHECK((dreg >= 0) && (dreg < num_d_registers));
763 registers_[dreg] = dbl[0];
764 registers_[dreg + 1] = dbl[1];
765 }
766
767
get_d_register(int dreg,uint64_t * value)768 void Simulator::get_d_register(int dreg, uint64_t* value) {
769 DCHECK((dreg >= 0) && (dreg < DwVfpRegister::NumRegisters()));
770 memcpy(value, vfp_registers_ + dreg * 2, sizeof(*value));
771 }
772
773
set_d_register(int dreg,const uint64_t * value)774 void Simulator::set_d_register(int dreg, const uint64_t* value) {
775 DCHECK((dreg >= 0) && (dreg < DwVfpRegister::NumRegisters()));
776 memcpy(vfp_registers_ + dreg * 2, value, sizeof(*value));
777 }
778
779
get_d_register(int dreg,uint32_t * value)780 void Simulator::get_d_register(int dreg, uint32_t* value) {
781 DCHECK((dreg >= 0) && (dreg < DwVfpRegister::NumRegisters()));
782 memcpy(value, vfp_registers_ + dreg * 2, sizeof(*value) * 2);
783 }
784
785
set_d_register(int dreg,const uint32_t * value)786 void Simulator::set_d_register(int dreg, const uint32_t* value) {
787 DCHECK((dreg >= 0) && (dreg < DwVfpRegister::NumRegisters()));
788 memcpy(vfp_registers_ + dreg * 2, value, sizeof(*value) * 2);
789 }
790
791 template <typename T, int SIZE>
get_neon_register(int reg,T (& value)[SIZE/sizeof (T)])792 void Simulator::get_neon_register(int reg, T (&value)[SIZE / sizeof(T)]) {
793 DCHECK(SIZE == kSimd128Size || SIZE == kDoubleSize);
794 DCHECK_LE(0, reg);
795 DCHECK_GT(SIZE == kSimd128Size ? num_q_registers : num_d_registers, reg);
796 memcpy(value, vfp_registers_ + reg * (SIZE / 4), SIZE);
797 }
798
799 template <typename T, int SIZE>
set_neon_register(int reg,const T (& value)[SIZE/sizeof (T)])800 void Simulator::set_neon_register(int reg, const T (&value)[SIZE / sizeof(T)]) {
801 DCHECK(SIZE == kSimd128Size || SIZE == kDoubleSize);
802 DCHECK_LE(0, reg);
803 DCHECK_GT(SIZE == kSimd128Size ? num_q_registers : num_d_registers, reg);
804 memcpy(vfp_registers_ + reg * (SIZE / 4), value, SIZE);
805 }
806
807 // Raw access to the PC register.
set_pc(int32_t value)808 void Simulator::set_pc(int32_t value) {
809 pc_modified_ = true;
810 registers_[pc] = value;
811 }
812
813
has_bad_pc() const814 bool Simulator::has_bad_pc() const {
815 return ((registers_[pc] == bad_lr) || (registers_[pc] == end_sim_pc));
816 }
817
818
819 // Raw access to the PC register without the special adjustment when reading.
get_pc() const820 int32_t Simulator::get_pc() const {
821 return registers_[pc];
822 }
823
824
825 // Getting from and setting into VFP registers.
set_s_register(int sreg,unsigned int value)826 void Simulator::set_s_register(int sreg, unsigned int value) {
827 DCHECK((sreg >= 0) && (sreg < num_s_registers));
828 vfp_registers_[sreg] = value;
829 }
830
831
get_s_register(int sreg) const832 unsigned int Simulator::get_s_register(int sreg) const {
833 DCHECK((sreg >= 0) && (sreg < num_s_registers));
834 return vfp_registers_[sreg];
835 }
836
837
838 template<class InputType, int register_size>
SetVFPRegister(int reg_index,const InputType & value)839 void Simulator::SetVFPRegister(int reg_index, const InputType& value) {
840 unsigned bytes = register_size * sizeof(vfp_registers_[0]);
841 DCHECK_EQ(sizeof(InputType), bytes);
842 DCHECK_GE(reg_index, 0);
843 if (register_size == 1) DCHECK(reg_index < num_s_registers);
844 if (register_size == 2) DCHECK(reg_index < DwVfpRegister::NumRegisters());
845
846 memcpy(&vfp_registers_[reg_index * register_size], &value, bytes);
847 }
848
849
850 template<class ReturnType, int register_size>
GetFromVFPRegister(int reg_index)851 ReturnType Simulator::GetFromVFPRegister(int reg_index) {
852 unsigned bytes = register_size * sizeof(vfp_registers_[0]);
853 DCHECK_EQ(sizeof(ReturnType), bytes);
854 DCHECK_GE(reg_index, 0);
855 if (register_size == 1) DCHECK(reg_index < num_s_registers);
856 if (register_size == 2) DCHECK(reg_index < DwVfpRegister::NumRegisters());
857
858 ReturnType value;
859 memcpy(&value, &vfp_registers_[register_size * reg_index], bytes);
860 return value;
861 }
862
SetSpecialRegister(SRegisterFieldMask reg_and_mask,uint32_t value)863 void Simulator::SetSpecialRegister(SRegisterFieldMask reg_and_mask,
864 uint32_t value) {
865 // Only CPSR_f is implemented. Of that, only N, Z, C and V are implemented.
866 if ((reg_and_mask == CPSR_f) && ((value & ~kSpecialCondition) == 0)) {
867 n_flag_ = ((value & (1 << 31)) != 0);
868 z_flag_ = ((value & (1 << 30)) != 0);
869 c_flag_ = ((value & (1 << 29)) != 0);
870 v_flag_ = ((value & (1 << 28)) != 0);
871 } else {
872 UNIMPLEMENTED();
873 }
874 }
875
GetFromSpecialRegister(SRegister reg)876 uint32_t Simulator::GetFromSpecialRegister(SRegister reg) {
877 uint32_t result = 0;
878 // Only CPSR_f is implemented.
879 if (reg == CPSR) {
880 if (n_flag_) result |= (1 << 31);
881 if (z_flag_) result |= (1 << 30);
882 if (c_flag_) result |= (1 << 29);
883 if (v_flag_) result |= (1 << 28);
884 } else {
885 UNIMPLEMENTED();
886 }
887 return result;
888 }
889
890 // Runtime FP routines take:
891 // - two double arguments
892 // - one double argument and zero or one integer arguments.
893 // All are consructed here from r0-r3 or d0, d1 and r0.
GetFpArgs(double * x,double * y,int32_t * z)894 void Simulator::GetFpArgs(double* x, double* y, int32_t* z) {
895 if (use_eabi_hardfloat()) {
896 *x = get_double_from_d_register(0).get_scalar();
897 *y = get_double_from_d_register(1).get_scalar();
898 *z = get_register(0);
899 } else {
900 // Registers 0 and 1 -> x.
901 *x = get_double_from_register_pair(0);
902 // Register 2 and 3 -> y.
903 *y = get_double_from_register_pair(2);
904 // Register 2 -> z
905 *z = get_register(2);
906 }
907 }
908
909
910 // The return value is either in r0/r1 or d0.
SetFpResult(const double & result)911 void Simulator::SetFpResult(const double& result) {
912 if (use_eabi_hardfloat()) {
913 char buffer[2 * sizeof(vfp_registers_[0])];
914 memcpy(buffer, &result, sizeof(buffer));
915 // Copy result to d0.
916 memcpy(vfp_registers_, buffer, sizeof(buffer));
917 } else {
918 char buffer[2 * sizeof(registers_[0])];
919 memcpy(buffer, &result, sizeof(buffer));
920 // Copy result to r0 and r1.
921 memcpy(registers_, buffer, sizeof(buffer));
922 }
923 }
924
925
TrashCallerSaveRegisters()926 void Simulator::TrashCallerSaveRegisters() {
927 // We don't trash the registers with the return value.
928 registers_[2] = 0x50BAD4U;
929 registers_[3] = 0x50BAD4U;
930 registers_[12] = 0x50BAD4U;
931 }
932
ReadW(int32_t addr)933 int Simulator::ReadW(int32_t addr) {
934 // All supported ARM targets allow unaligned accesses, so we don't need to
935 // check the alignment here.
936 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
937 local_monitor_.NotifyLoad(addr);
938 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
939 return *ptr;
940 }
941
ReadExW(int32_t addr)942 int Simulator::ReadExW(int32_t addr) {
943 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
944 local_monitor_.NotifyLoadExcl(addr, TransactionSize::Word);
945 global_monitor_.Pointer()->NotifyLoadExcl_Locked(addr,
946 &global_monitor_processor_);
947 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
948 return *ptr;
949 }
950
WriteW(int32_t addr,int value)951 void Simulator::WriteW(int32_t addr, int value) {
952 // All supported ARM targets allow unaligned accesses, so we don't need to
953 // check the alignment here.
954 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
955 local_monitor_.NotifyStore(addr);
956 global_monitor_.Pointer()->NotifyStore_Locked(addr,
957 &global_monitor_processor_);
958 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
959 *ptr = value;
960 }
961
WriteExW(int32_t addr,int value)962 int Simulator::WriteExW(int32_t addr, int value) {
963 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
964 if (local_monitor_.NotifyStoreExcl(addr, TransactionSize::Word) &&
965 global_monitor_.Pointer()->NotifyStoreExcl_Locked(
966 addr, &global_monitor_processor_)) {
967 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
968 *ptr = value;
969 return 0;
970 } else {
971 return 1;
972 }
973 }
974
ReadHU(int32_t addr)975 uint16_t Simulator::ReadHU(int32_t addr) {
976 // All supported ARM targets allow unaligned accesses, so we don't need to
977 // check the alignment here.
978 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
979 local_monitor_.NotifyLoad(addr);
980 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
981 return *ptr;
982 }
983
ReadH(int32_t addr)984 int16_t Simulator::ReadH(int32_t addr) {
985 // All supported ARM targets allow unaligned accesses, so we don't need to
986 // check the alignment here.
987 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
988 local_monitor_.NotifyLoad(addr);
989 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
990 return *ptr;
991 }
992
ReadExHU(int32_t addr)993 uint16_t Simulator::ReadExHU(int32_t addr) {
994 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
995 local_monitor_.NotifyLoadExcl(addr, TransactionSize::HalfWord);
996 global_monitor_.Pointer()->NotifyLoadExcl_Locked(addr,
997 &global_monitor_processor_);
998 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
999 return *ptr;
1000 }
1001
WriteH(int32_t addr,uint16_t value)1002 void Simulator::WriteH(int32_t addr, uint16_t value) {
1003 // All supported ARM targets allow unaligned accesses, so we don't need to
1004 // check the alignment here.
1005 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
1006 local_monitor_.NotifyStore(addr);
1007 global_monitor_.Pointer()->NotifyStore_Locked(addr,
1008 &global_monitor_processor_);
1009 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1010 *ptr = value;
1011 }
1012
WriteH(int32_t addr,int16_t value)1013 void Simulator::WriteH(int32_t addr, int16_t value) {
1014 // All supported ARM targets allow unaligned accesses, so we don't need to
1015 // check the alignment here.
1016 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
1017 local_monitor_.NotifyStore(addr);
1018 global_monitor_.Pointer()->NotifyStore_Locked(addr,
1019 &global_monitor_processor_);
1020 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
1021 *ptr = value;
1022 }
1023
WriteExH(int32_t addr,uint16_t value)1024 int Simulator::WriteExH(int32_t addr, uint16_t value) {
1025 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
1026 if (local_monitor_.NotifyStoreExcl(addr, TransactionSize::HalfWord) &&
1027 global_monitor_.Pointer()->NotifyStoreExcl_Locked(
1028 addr, &global_monitor_processor_)) {
1029 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1030 *ptr = value;
1031 return 0;
1032 } else {
1033 return 1;
1034 }
1035 }
1036
ReadBU(int32_t addr)1037 uint8_t Simulator::ReadBU(int32_t addr) {
1038 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
1039 local_monitor_.NotifyLoad(addr);
1040 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1041 return *ptr;
1042 }
1043
ReadB(int32_t addr)1044 int8_t Simulator::ReadB(int32_t addr) {
1045 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
1046 local_monitor_.NotifyLoad(addr);
1047 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
1048 return *ptr;
1049 }
1050
ReadExBU(int32_t addr)1051 uint8_t Simulator::ReadExBU(int32_t addr) {
1052 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
1053 local_monitor_.NotifyLoadExcl(addr, TransactionSize::Byte);
1054 global_monitor_.Pointer()->NotifyLoadExcl_Locked(addr,
1055 &global_monitor_processor_);
1056 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1057 return *ptr;
1058 }
1059
WriteB(int32_t addr,uint8_t value)1060 void Simulator::WriteB(int32_t addr, uint8_t value) {
1061 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
1062 local_monitor_.NotifyStore(addr);
1063 global_monitor_.Pointer()->NotifyStore_Locked(addr,
1064 &global_monitor_processor_);
1065 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1066 *ptr = value;
1067 }
1068
WriteB(int32_t addr,int8_t value)1069 void Simulator::WriteB(int32_t addr, int8_t value) {
1070 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
1071 local_monitor_.NotifyStore(addr);
1072 global_monitor_.Pointer()->NotifyStore_Locked(addr,
1073 &global_monitor_processor_);
1074 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
1075 *ptr = value;
1076 }
1077
WriteExB(int32_t addr,uint8_t value)1078 int Simulator::WriteExB(int32_t addr, uint8_t value) {
1079 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
1080 if (local_monitor_.NotifyStoreExcl(addr, TransactionSize::Byte) &&
1081 global_monitor_.Pointer()->NotifyStoreExcl_Locked(
1082 addr, &global_monitor_processor_)) {
1083 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1084 *ptr = value;
1085 return 0;
1086 } else {
1087 return 1;
1088 }
1089 }
1090
ReadDW(int32_t addr)1091 int32_t* Simulator::ReadDW(int32_t addr) {
1092 // All supported ARM targets allow unaligned accesses, so we don't need to
1093 // check the alignment here.
1094 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
1095 local_monitor_.NotifyLoad(addr);
1096 int32_t* ptr = reinterpret_cast<int32_t*>(addr);
1097 return ptr;
1098 }
1099
ReadExDW(int32_t addr)1100 int32_t* Simulator::ReadExDW(int32_t addr) {
1101 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
1102 local_monitor_.NotifyLoadExcl(addr, TransactionSize::DoubleWord);
1103 global_monitor_.Pointer()->NotifyLoadExcl_Locked(addr,
1104 &global_monitor_processor_);
1105 int32_t* ptr = reinterpret_cast<int32_t*>(addr);
1106 return ptr;
1107 }
1108
WriteDW(int32_t addr,int32_t value1,int32_t value2)1109 void Simulator::WriteDW(int32_t addr, int32_t value1, int32_t value2) {
1110 // All supported ARM targets allow unaligned accesses, so we don't need to
1111 // check the alignment here.
1112 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
1113 local_monitor_.NotifyStore(addr);
1114 global_monitor_.Pointer()->NotifyStore_Locked(addr,
1115 &global_monitor_processor_);
1116 int32_t* ptr = reinterpret_cast<int32_t*>(addr);
1117 *ptr++ = value1;
1118 *ptr = value2;
1119 }
1120
WriteExDW(int32_t addr,int32_t value1,int32_t value2)1121 int Simulator::WriteExDW(int32_t addr, int32_t value1, int32_t value2) {
1122 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
1123 if (local_monitor_.NotifyStoreExcl(addr, TransactionSize::DoubleWord) &&
1124 global_monitor_.Pointer()->NotifyStoreExcl_Locked(
1125 addr, &global_monitor_processor_)) {
1126 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
1127 *ptr++ = value1;
1128 *ptr = value2;
1129 return 0;
1130 } else {
1131 return 1;
1132 }
1133 }
1134
1135 // Returns the limit of the stack area to enable checking for stack overflows.
StackLimit(uintptr_t c_limit) const1136 uintptr_t Simulator::StackLimit(uintptr_t c_limit) const {
1137 // The simulator uses a separate JS stack. If we have exhausted the C stack,
1138 // we also drop down the JS limit to reflect the exhaustion on the JS stack.
1139 if (GetCurrentStackPosition() < c_limit) {
1140 return reinterpret_cast<uintptr_t>(get_sp());
1141 }
1142
1143 // Otherwise the limit is the JS stack. Leave a safety margin of 1024 bytes
1144 // to prevent overrunning the stack when pushing values.
1145 return reinterpret_cast<uintptr_t>(stack_) + 1024;
1146 }
1147
1148
1149 // Unsupported instructions use Format to print an error and stop execution.
Format(Instruction * instr,const char * format)1150 void Simulator::Format(Instruction* instr, const char* format) {
1151 PrintF("Simulator found unsupported instruction:\n 0x%08" V8PRIxPTR ": %s\n",
1152 reinterpret_cast<intptr_t>(instr), format);
1153 UNIMPLEMENTED();
1154 }
1155
1156
1157 // Checks if the current instruction should be executed based on its
1158 // condition bits.
ConditionallyExecute(Instruction * instr)1159 bool Simulator::ConditionallyExecute(Instruction* instr) {
1160 switch (instr->ConditionField()) {
1161 case eq: return z_flag_;
1162 case ne: return !z_flag_;
1163 case cs: return c_flag_;
1164 case cc: return !c_flag_;
1165 case mi: return n_flag_;
1166 case pl: return !n_flag_;
1167 case vs: return v_flag_;
1168 case vc: return !v_flag_;
1169 case hi: return c_flag_ && !z_flag_;
1170 case ls: return !c_flag_ || z_flag_;
1171 case ge: return n_flag_ == v_flag_;
1172 case lt: return n_flag_ != v_flag_;
1173 case gt: return !z_flag_ && (n_flag_ == v_flag_);
1174 case le: return z_flag_ || (n_flag_ != v_flag_);
1175 case al: return true;
1176 default: UNREACHABLE();
1177 }
1178 return false;
1179 }
1180
1181
1182 // Calculate and set the Negative and Zero flags.
SetNZFlags(int32_t val)1183 void Simulator::SetNZFlags(int32_t val) {
1184 n_flag_ = (val < 0);
1185 z_flag_ = (val == 0);
1186 }
1187
1188
1189 // Set the Carry flag.
SetCFlag(bool val)1190 void Simulator::SetCFlag(bool val) {
1191 c_flag_ = val;
1192 }
1193
1194
1195 // Set the oVerflow flag.
SetVFlag(bool val)1196 void Simulator::SetVFlag(bool val) {
1197 v_flag_ = val;
1198 }
1199
1200
1201 // Calculate C flag value for additions.
CarryFrom(int32_t left,int32_t right,int32_t carry)1202 bool Simulator::CarryFrom(int32_t left, int32_t right, int32_t carry) {
1203 uint32_t uleft = static_cast<uint32_t>(left);
1204 uint32_t uright = static_cast<uint32_t>(right);
1205 uint32_t urest = 0xFFFFFFFFU - uleft;
1206
1207 return (uright > urest) ||
1208 (carry && (((uright + 1) > urest) || (uright > (urest - 1))));
1209 }
1210
1211
1212 // Calculate C flag value for subtractions.
BorrowFrom(int32_t left,int32_t right,int32_t carry)1213 bool Simulator::BorrowFrom(int32_t left, int32_t right, int32_t carry) {
1214 uint32_t uleft = static_cast<uint32_t>(left);
1215 uint32_t uright = static_cast<uint32_t>(right);
1216
1217 return (uright > uleft) ||
1218 (!carry && (((uright + 1) > uleft) || (uright > (uleft - 1))));
1219 }
1220
1221
1222 // Calculate V flag value for additions and subtractions.
OverflowFrom(int32_t alu_out,int32_t left,int32_t right,bool addition)1223 bool Simulator::OverflowFrom(int32_t alu_out,
1224 int32_t left, int32_t right, bool addition) {
1225 bool overflow;
1226 if (addition) {
1227 // operands have the same sign
1228 overflow = ((left >= 0 && right >= 0) || (left < 0 && right < 0))
1229 // and operands and result have different sign
1230 && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
1231 } else {
1232 // operands have different signs
1233 overflow = ((left < 0 && right >= 0) || (left >= 0 && right < 0))
1234 // and first operand and result have different signs
1235 && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
1236 }
1237 return overflow;
1238 }
1239
1240
1241 // Support for VFP comparisons.
Compute_FPSCR_Flags(float val1,float val2)1242 void Simulator::Compute_FPSCR_Flags(float val1, float val2) {
1243 if (std::isnan(val1) || std::isnan(val2)) {
1244 n_flag_FPSCR_ = false;
1245 z_flag_FPSCR_ = false;
1246 c_flag_FPSCR_ = true;
1247 v_flag_FPSCR_ = true;
1248 // All non-NaN cases.
1249 } else if (val1 == val2) {
1250 n_flag_FPSCR_ = false;
1251 z_flag_FPSCR_ = true;
1252 c_flag_FPSCR_ = true;
1253 v_flag_FPSCR_ = false;
1254 } else if (val1 < val2) {
1255 n_flag_FPSCR_ = true;
1256 z_flag_FPSCR_ = false;
1257 c_flag_FPSCR_ = false;
1258 v_flag_FPSCR_ = false;
1259 } else {
1260 // Case when (val1 > val2).
1261 n_flag_FPSCR_ = false;
1262 z_flag_FPSCR_ = false;
1263 c_flag_FPSCR_ = true;
1264 v_flag_FPSCR_ = false;
1265 }
1266 }
1267
1268
Compute_FPSCR_Flags(double val1,double val2)1269 void Simulator::Compute_FPSCR_Flags(double val1, double val2) {
1270 if (std::isnan(val1) || std::isnan(val2)) {
1271 n_flag_FPSCR_ = false;
1272 z_flag_FPSCR_ = false;
1273 c_flag_FPSCR_ = true;
1274 v_flag_FPSCR_ = true;
1275 // All non-NaN cases.
1276 } else if (val1 == val2) {
1277 n_flag_FPSCR_ = false;
1278 z_flag_FPSCR_ = true;
1279 c_flag_FPSCR_ = true;
1280 v_flag_FPSCR_ = false;
1281 } else if (val1 < val2) {
1282 n_flag_FPSCR_ = true;
1283 z_flag_FPSCR_ = false;
1284 c_flag_FPSCR_ = false;
1285 v_flag_FPSCR_ = false;
1286 } else {
1287 // Case when (val1 > val2).
1288 n_flag_FPSCR_ = false;
1289 z_flag_FPSCR_ = false;
1290 c_flag_FPSCR_ = true;
1291 v_flag_FPSCR_ = false;
1292 }
1293 }
1294
1295
Copy_FPSCR_to_APSR()1296 void Simulator::Copy_FPSCR_to_APSR() {
1297 n_flag_ = n_flag_FPSCR_;
1298 z_flag_ = z_flag_FPSCR_;
1299 c_flag_ = c_flag_FPSCR_;
1300 v_flag_ = v_flag_FPSCR_;
1301 }
1302
1303
1304 // Addressing Mode 1 - Data-processing operands:
1305 // Get the value based on the shifter_operand with register.
GetShiftRm(Instruction * instr,bool * carry_out)1306 int32_t Simulator::GetShiftRm(Instruction* instr, bool* carry_out) {
1307 ShiftOp shift = instr->ShiftField();
1308 int shift_amount = instr->ShiftAmountValue();
1309 int32_t result = get_register(instr->RmValue());
1310 if (instr->Bit(4) == 0) {
1311 // by immediate
1312 if ((shift == ROR) && (shift_amount == 0)) {
1313 UNIMPLEMENTED();
1314 return result;
1315 } else if (((shift == LSR) || (shift == ASR)) && (shift_amount == 0)) {
1316 shift_amount = 32;
1317 }
1318 switch (shift) {
1319 case ASR: {
1320 if (shift_amount == 0) {
1321 if (result < 0) {
1322 result = 0xFFFFFFFF;
1323 *carry_out = true;
1324 } else {
1325 result = 0;
1326 *carry_out = false;
1327 }
1328 } else {
1329 result >>= (shift_amount - 1);
1330 *carry_out = (result & 1) == 1;
1331 result >>= 1;
1332 }
1333 break;
1334 }
1335
1336 case LSL: {
1337 if (shift_amount == 0) {
1338 *carry_out = c_flag_;
1339 } else {
1340 result <<= (shift_amount - 1);
1341 *carry_out = (result < 0);
1342 result <<= 1;
1343 }
1344 break;
1345 }
1346
1347 case LSR: {
1348 if (shift_amount == 0) {
1349 result = 0;
1350 *carry_out = c_flag_;
1351 } else {
1352 uint32_t uresult = static_cast<uint32_t>(result);
1353 uresult >>= (shift_amount - 1);
1354 *carry_out = (uresult & 1) == 1;
1355 uresult >>= 1;
1356 result = static_cast<int32_t>(uresult);
1357 }
1358 break;
1359 }
1360
1361 case ROR: {
1362 if (shift_amount == 0) {
1363 *carry_out = c_flag_;
1364 } else {
1365 uint32_t left = static_cast<uint32_t>(result) >> shift_amount;
1366 uint32_t right = static_cast<uint32_t>(result) << (32 - shift_amount);
1367 result = right | left;
1368 *carry_out = (static_cast<uint32_t>(result) >> 31) != 0;
1369 }
1370 break;
1371 }
1372
1373 default: {
1374 UNREACHABLE();
1375 break;
1376 }
1377 }
1378 } else {
1379 // by register
1380 int rs = instr->RsValue();
1381 shift_amount = get_register(rs) & 0xFF;
1382 switch (shift) {
1383 case ASR: {
1384 if (shift_amount == 0) {
1385 *carry_out = c_flag_;
1386 } else if (shift_amount < 32) {
1387 result >>= (shift_amount - 1);
1388 *carry_out = (result & 1) == 1;
1389 result >>= 1;
1390 } else {
1391 DCHECK_GE(shift_amount, 32);
1392 if (result < 0) {
1393 *carry_out = true;
1394 result = 0xFFFFFFFF;
1395 } else {
1396 *carry_out = false;
1397 result = 0;
1398 }
1399 }
1400 break;
1401 }
1402
1403 case LSL: {
1404 if (shift_amount == 0) {
1405 *carry_out = c_flag_;
1406 } else if (shift_amount < 32) {
1407 result <<= (shift_amount - 1);
1408 *carry_out = (result < 0);
1409 result <<= 1;
1410 } else if (shift_amount == 32) {
1411 *carry_out = (result & 1) == 1;
1412 result = 0;
1413 } else {
1414 DCHECK_GT(shift_amount, 32);
1415 *carry_out = false;
1416 result = 0;
1417 }
1418 break;
1419 }
1420
1421 case LSR: {
1422 if (shift_amount == 0) {
1423 *carry_out = c_flag_;
1424 } else if (shift_amount < 32) {
1425 uint32_t uresult = static_cast<uint32_t>(result);
1426 uresult >>= (shift_amount - 1);
1427 *carry_out = (uresult & 1) == 1;
1428 uresult >>= 1;
1429 result = static_cast<int32_t>(uresult);
1430 } else if (shift_amount == 32) {
1431 *carry_out = (result < 0);
1432 result = 0;
1433 } else {
1434 *carry_out = false;
1435 result = 0;
1436 }
1437 break;
1438 }
1439
1440 case ROR: {
1441 if (shift_amount == 0) {
1442 *carry_out = c_flag_;
1443 } else {
1444 uint32_t left = static_cast<uint32_t>(result) >> shift_amount;
1445 uint32_t right = static_cast<uint32_t>(result) << (32 - shift_amount);
1446 result = right | left;
1447 *carry_out = (static_cast<uint32_t>(result) >> 31) != 0;
1448 }
1449 break;
1450 }
1451
1452 default: {
1453 UNREACHABLE();
1454 break;
1455 }
1456 }
1457 }
1458 return result;
1459 }
1460
1461
1462 // Addressing Mode 1 - Data-processing operands:
1463 // Get the value based on the shifter_operand with immediate.
GetImm(Instruction * instr,bool * carry_out)1464 int32_t Simulator::GetImm(Instruction* instr, bool* carry_out) {
1465 int rotate = instr->RotateValue() * 2;
1466 int immed8 = instr->Immed8Value();
1467 int imm = base::bits::RotateRight32(immed8, rotate);
1468 *carry_out = (rotate == 0) ? c_flag_ : (imm < 0);
1469 return imm;
1470 }
1471
1472
count_bits(int bit_vector)1473 static int count_bits(int bit_vector) {
1474 int count = 0;
1475 while (bit_vector != 0) {
1476 if ((bit_vector & 1) != 0) {
1477 count++;
1478 }
1479 bit_vector >>= 1;
1480 }
1481 return count;
1482 }
1483
1484
ProcessPU(Instruction * instr,int num_regs,int reg_size,intptr_t * start_address,intptr_t * end_address)1485 int32_t Simulator::ProcessPU(Instruction* instr,
1486 int num_regs,
1487 int reg_size,
1488 intptr_t* start_address,
1489 intptr_t* end_address) {
1490 int rn = instr->RnValue();
1491 int32_t rn_val = get_register(rn);
1492 switch (instr->PUField()) {
1493 case da_x: {
1494 UNIMPLEMENTED();
1495 break;
1496 }
1497 case ia_x: {
1498 *start_address = rn_val;
1499 *end_address = rn_val + (num_regs * reg_size) - reg_size;
1500 rn_val = rn_val + (num_regs * reg_size);
1501 break;
1502 }
1503 case db_x: {
1504 *start_address = rn_val - (num_regs * reg_size);
1505 *end_address = rn_val - reg_size;
1506 rn_val = *start_address;
1507 break;
1508 }
1509 case ib_x: {
1510 *start_address = rn_val + reg_size;
1511 *end_address = rn_val + (num_regs * reg_size);
1512 rn_val = *end_address;
1513 break;
1514 }
1515 default: {
1516 UNREACHABLE();
1517 break;
1518 }
1519 }
1520 return rn_val;
1521 }
1522
1523
1524 // Addressing Mode 4 - Load and Store Multiple
HandleRList(Instruction * instr,bool load)1525 void Simulator::HandleRList(Instruction* instr, bool load) {
1526 int rlist = instr->RlistValue();
1527 int num_regs = count_bits(rlist);
1528
1529 intptr_t start_address = 0;
1530 intptr_t end_address = 0;
1531 int32_t rn_val =
1532 ProcessPU(instr, num_regs, kPointerSize, &start_address, &end_address);
1533
1534 intptr_t* address = reinterpret_cast<intptr_t*>(start_address);
1535 // Catch null pointers a little earlier.
1536 DCHECK(start_address > 8191 || start_address < 0);
1537 int reg = 0;
1538 while (rlist != 0) {
1539 if ((rlist & 1) != 0) {
1540 if (load) {
1541 set_register(reg, *address);
1542 } else {
1543 *address = get_register(reg);
1544 }
1545 address += 1;
1546 }
1547 reg++;
1548 rlist >>= 1;
1549 }
1550 DCHECK(end_address == ((intptr_t)address) - 4);
1551 if (instr->HasW()) {
1552 set_register(instr->RnValue(), rn_val);
1553 }
1554 }
1555
1556
1557 // Addressing Mode 6 - Load and Store Multiple Coprocessor registers.
HandleVList(Instruction * instr)1558 void Simulator::HandleVList(Instruction* instr) {
1559 VFPRegPrecision precision =
1560 (instr->SzValue() == 0) ? kSinglePrecision : kDoublePrecision;
1561 int operand_size = (precision == kSinglePrecision) ? 4 : 8;
1562
1563 bool load = (instr->VLValue() == 0x1);
1564
1565 int vd;
1566 int num_regs;
1567 vd = instr->VFPDRegValue(precision);
1568 if (precision == kSinglePrecision) {
1569 num_regs = instr->Immed8Value();
1570 } else {
1571 num_regs = instr->Immed8Value() / 2;
1572 }
1573
1574 intptr_t start_address = 0;
1575 intptr_t end_address = 0;
1576 int32_t rn_val =
1577 ProcessPU(instr, num_regs, operand_size, &start_address, &end_address);
1578
1579 intptr_t* address = reinterpret_cast<intptr_t*>(start_address);
1580 for (int reg = vd; reg < vd + num_regs; reg++) {
1581 if (precision == kSinglePrecision) {
1582 if (load) {
1583 set_s_register_from_sinteger(reg,
1584 ReadW(reinterpret_cast<int32_t>(address)));
1585 } else {
1586 WriteW(reinterpret_cast<int32_t>(address),
1587 get_sinteger_from_s_register(reg));
1588 }
1589 address += 1;
1590 } else {
1591 if (load) {
1592 int32_t data[] = {ReadW(reinterpret_cast<int32_t>(address)),
1593 ReadW(reinterpret_cast<int32_t>(address + 1))};
1594 set_d_register(reg, reinterpret_cast<uint32_t*>(data));
1595 } else {
1596 uint32_t data[2];
1597 get_d_register(reg, data);
1598 WriteW(reinterpret_cast<int32_t>(address), data[0]);
1599 WriteW(reinterpret_cast<int32_t>(address + 1), data[1]);
1600 }
1601 address += 2;
1602 }
1603 }
1604 DCHECK(reinterpret_cast<intptr_t>(address) - operand_size == end_address);
1605 if (instr->HasW()) {
1606 set_register(instr->RnValue(), rn_val);
1607 }
1608 }
1609
1610
1611 // Calls into the V8 runtime are based on this very simple interface.
1612 // Note: To be able to return two values from some calls the code in runtime.cc
1613 // uses the ObjectPair which is essentially two 32-bit values stuffed into a
1614 // 64-bit value. With the code below we assume that all runtime calls return
1615 // 64 bits of result. If they don't, the r1 result register contains a bogus
1616 // value, which is fine because it is caller-saved.
1617 typedef int64_t (*SimulatorRuntimeCall)(int32_t arg0, int32_t arg1,
1618 int32_t arg2, int32_t arg3,
1619 int32_t arg4, int32_t arg5,
1620 int32_t arg6, int32_t arg7,
1621 int32_t arg8);
1622
1623 // These prototypes handle the four types of FP calls.
1624 typedef int64_t (*SimulatorRuntimeCompareCall)(double darg0, double darg1);
1625 typedef double (*SimulatorRuntimeFPFPCall)(double darg0, double darg1);
1626 typedef double (*SimulatorRuntimeFPCall)(double darg0);
1627 typedef double (*SimulatorRuntimeFPIntCall)(double darg0, int32_t arg0);
1628
1629 // This signature supports direct call in to API function native callback
1630 // (refer to InvocationCallback in v8.h).
1631 typedef void (*SimulatorRuntimeDirectApiCall)(int32_t arg0);
1632 typedef void (*SimulatorRuntimeProfilingApiCall)(int32_t arg0, void* arg1);
1633
1634 // This signature supports direct call to accessor getter callback.
1635 typedef void (*SimulatorRuntimeDirectGetterCall)(int32_t arg0, int32_t arg1);
1636 typedef void (*SimulatorRuntimeProfilingGetterCall)(
1637 int32_t arg0, int32_t arg1, void* arg2);
1638
1639 // Software interrupt instructions are used by the simulator to call into the
1640 // C-based V8 runtime.
SoftwareInterrupt(Instruction * instr)1641 void Simulator::SoftwareInterrupt(Instruction* instr) {
1642 int svc = instr->SvcValue();
1643 switch (svc) {
1644 case kCallRtRedirected: {
1645 // Check if stack is aligned. Error if not aligned is reported below to
1646 // include information on the function called.
1647 bool stack_aligned =
1648 (get_register(sp)
1649 & (::v8::internal::FLAG_sim_stack_alignment - 1)) == 0;
1650 Redirection* redirection = Redirection::FromInstruction(instr);
1651 int32_t arg0 = get_register(r0);
1652 int32_t arg1 = get_register(r1);
1653 int32_t arg2 = get_register(r2);
1654 int32_t arg3 = get_register(r3);
1655 int32_t* stack_pointer = reinterpret_cast<int32_t*>(get_register(sp));
1656 int32_t arg4 = stack_pointer[0];
1657 int32_t arg5 = stack_pointer[1];
1658 int32_t arg6 = stack_pointer[2];
1659 int32_t arg7 = stack_pointer[3];
1660 int32_t arg8 = stack_pointer[4];
1661 STATIC_ASSERT(kMaxCParameters == 9);
1662
1663 bool fp_call =
1664 (redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) ||
1665 (redirection->type() == ExternalReference::BUILTIN_COMPARE_CALL) ||
1666 (redirection->type() == ExternalReference::BUILTIN_FP_CALL) ||
1667 (redirection->type() == ExternalReference::BUILTIN_FP_INT_CALL);
1668 // This is dodgy but it works because the C entry stubs are never moved.
1669 // See comment in codegen-arm.cc and bug 1242173.
1670 int32_t saved_lr = get_register(lr);
1671 intptr_t external =
1672 reinterpret_cast<intptr_t>(redirection->external_function());
1673 if (fp_call) {
1674 double dval0, dval1; // one or two double parameters
1675 int32_t ival; // zero or one integer parameters
1676 int64_t iresult = 0; // integer return value
1677 double dresult = 0; // double return value
1678 GetFpArgs(&dval0, &dval1, &ival);
1679 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
1680 SimulatorRuntimeCall generic_target =
1681 reinterpret_cast<SimulatorRuntimeCall>(external);
1682 switch (redirection->type()) {
1683 case ExternalReference::BUILTIN_FP_FP_CALL:
1684 case ExternalReference::BUILTIN_COMPARE_CALL:
1685 PrintF("Call to host function at %p with args %f, %f",
1686 reinterpret_cast<void*>(FUNCTION_ADDR(generic_target)),
1687 dval0, dval1);
1688 break;
1689 case ExternalReference::BUILTIN_FP_CALL:
1690 PrintF("Call to host function at %p with arg %f",
1691 reinterpret_cast<void*>(FUNCTION_ADDR(generic_target)),
1692 dval0);
1693 break;
1694 case ExternalReference::BUILTIN_FP_INT_CALL:
1695 PrintF("Call to host function at %p with args %f, %d",
1696 reinterpret_cast<void*>(FUNCTION_ADDR(generic_target)),
1697 dval0, ival);
1698 break;
1699 default:
1700 UNREACHABLE();
1701 break;
1702 }
1703 if (!stack_aligned) {
1704 PrintF(" with unaligned stack %08x\n", get_register(sp));
1705 }
1706 PrintF("\n");
1707 }
1708 CHECK(stack_aligned);
1709 switch (redirection->type()) {
1710 case ExternalReference::BUILTIN_COMPARE_CALL: {
1711 SimulatorRuntimeCompareCall target =
1712 reinterpret_cast<SimulatorRuntimeCompareCall>(external);
1713 iresult = target(dval0, dval1);
1714 set_register(r0, static_cast<int32_t>(iresult));
1715 set_register(r1, static_cast<int32_t>(iresult >> 32));
1716 break;
1717 }
1718 case ExternalReference::BUILTIN_FP_FP_CALL: {
1719 SimulatorRuntimeFPFPCall target =
1720 reinterpret_cast<SimulatorRuntimeFPFPCall>(external);
1721 dresult = target(dval0, dval1);
1722 SetFpResult(dresult);
1723 break;
1724 }
1725 case ExternalReference::BUILTIN_FP_CALL: {
1726 SimulatorRuntimeFPCall target =
1727 reinterpret_cast<SimulatorRuntimeFPCall>(external);
1728 dresult = target(dval0);
1729 SetFpResult(dresult);
1730 break;
1731 }
1732 case ExternalReference::BUILTIN_FP_INT_CALL: {
1733 SimulatorRuntimeFPIntCall target =
1734 reinterpret_cast<SimulatorRuntimeFPIntCall>(external);
1735 dresult = target(dval0, ival);
1736 SetFpResult(dresult);
1737 break;
1738 }
1739 default:
1740 UNREACHABLE();
1741 break;
1742 }
1743 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
1744 switch (redirection->type()) {
1745 case ExternalReference::BUILTIN_COMPARE_CALL:
1746 PrintF("Returned %08x\n", static_cast<int32_t>(iresult));
1747 break;
1748 case ExternalReference::BUILTIN_FP_FP_CALL:
1749 case ExternalReference::BUILTIN_FP_CALL:
1750 case ExternalReference::BUILTIN_FP_INT_CALL:
1751 PrintF("Returned %f\n", dresult);
1752 break;
1753 default:
1754 UNREACHABLE();
1755 break;
1756 }
1757 }
1758 } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) {
1759 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
1760 PrintF("Call to host function at %p args %08x",
1761 reinterpret_cast<void*>(external), arg0);
1762 if (!stack_aligned) {
1763 PrintF(" with unaligned stack %08x\n", get_register(sp));
1764 }
1765 PrintF("\n");
1766 }
1767 CHECK(stack_aligned);
1768 SimulatorRuntimeDirectApiCall target =
1769 reinterpret_cast<SimulatorRuntimeDirectApiCall>(external);
1770 target(arg0);
1771 } else if (
1772 redirection->type() == ExternalReference::PROFILING_API_CALL) {
1773 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
1774 PrintF("Call to host function at %p args %08x %08x",
1775 reinterpret_cast<void*>(external), arg0, arg1);
1776 if (!stack_aligned) {
1777 PrintF(" with unaligned stack %08x\n", get_register(sp));
1778 }
1779 PrintF("\n");
1780 }
1781 CHECK(stack_aligned);
1782 SimulatorRuntimeProfilingApiCall target =
1783 reinterpret_cast<SimulatorRuntimeProfilingApiCall>(external);
1784 target(arg0, Redirection::ReverseRedirection(arg1));
1785 } else if (
1786 redirection->type() == ExternalReference::DIRECT_GETTER_CALL) {
1787 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
1788 PrintF("Call to host function at %p args %08x %08x",
1789 reinterpret_cast<void*>(external), arg0, arg1);
1790 if (!stack_aligned) {
1791 PrintF(" with unaligned stack %08x\n", get_register(sp));
1792 }
1793 PrintF("\n");
1794 }
1795 CHECK(stack_aligned);
1796 SimulatorRuntimeDirectGetterCall target =
1797 reinterpret_cast<SimulatorRuntimeDirectGetterCall>(external);
1798 target(arg0, arg1);
1799 } else if (
1800 redirection->type() == ExternalReference::PROFILING_GETTER_CALL) {
1801 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
1802 PrintF("Call to host function at %p args %08x %08x %08x",
1803 reinterpret_cast<void*>(external), arg0, arg1, arg2);
1804 if (!stack_aligned) {
1805 PrintF(" with unaligned stack %08x\n", get_register(sp));
1806 }
1807 PrintF("\n");
1808 }
1809 CHECK(stack_aligned);
1810 SimulatorRuntimeProfilingGetterCall target =
1811 reinterpret_cast<SimulatorRuntimeProfilingGetterCall>(
1812 external);
1813 target(arg0, arg1, Redirection::ReverseRedirection(arg2));
1814 } else {
1815 // builtin call.
1816 DCHECK(redirection->type() == ExternalReference::BUILTIN_CALL ||
1817 redirection->type() == ExternalReference::BUILTIN_CALL_PAIR);
1818 SimulatorRuntimeCall target =
1819 reinterpret_cast<SimulatorRuntimeCall>(external);
1820 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
1821 PrintF(
1822 "Call to host function at %p "
1823 "args %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x",
1824 reinterpret_cast<void*>(FUNCTION_ADDR(target)), arg0, arg1, arg2,
1825 arg3, arg4, arg5, arg6, arg7, arg8);
1826 if (!stack_aligned) {
1827 PrintF(" with unaligned stack %08x\n", get_register(sp));
1828 }
1829 PrintF("\n");
1830 }
1831 CHECK(stack_aligned);
1832 int64_t result =
1833 target(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
1834 int32_t lo_res = static_cast<int32_t>(result);
1835 int32_t hi_res = static_cast<int32_t>(result >> 32);
1836 if (::v8::internal::FLAG_trace_sim) {
1837 PrintF("Returned %08x\n", lo_res);
1838 }
1839 set_register(r0, lo_res);
1840 set_register(r1, hi_res);
1841 }
1842 set_register(lr, saved_lr);
1843 set_pc(get_register(lr));
1844 break;
1845 }
1846 case kBreakpoint: {
1847 ArmDebugger dbg(this);
1848 dbg.Debug();
1849 break;
1850 }
1851 // stop uses all codes greater than 1 << 23.
1852 default: {
1853 if (svc >= (1 << 23)) {
1854 uint32_t code = svc & kStopCodeMask;
1855 if (isWatchedStop(code)) {
1856 IncreaseStopCounter(code);
1857 }
1858 // Stop if it is enabled, otherwise go on jumping over the stop
1859 // and the message address.
1860 if (isEnabledStop(code)) {
1861 ArmDebugger dbg(this);
1862 dbg.Stop(instr);
1863 }
1864 } else {
1865 // This is not a valid svc code.
1866 UNREACHABLE();
1867 break;
1868 }
1869 }
1870 }
1871 }
1872
1873
canonicalizeNaN(float value)1874 float Simulator::canonicalizeNaN(float value) {
1875 // Default NaN value, see "NaN handling" in "IEEE 754 standard implementation
1876 // choices" of the ARM Reference Manual.
1877 constexpr uint32_t kDefaultNaN = 0x7FC00000u;
1878 if (FPSCR_default_NaN_mode_ && std::isnan(value)) {
1879 value = bit_cast<float>(kDefaultNaN);
1880 }
1881 return value;
1882 }
1883
canonicalizeNaN(Float32 value)1884 Float32 Simulator::canonicalizeNaN(Float32 value) {
1885 // Default NaN value, see "NaN handling" in "IEEE 754 standard implementation
1886 // choices" of the ARM Reference Manual.
1887 constexpr Float32 kDefaultNaN = Float32::FromBits(0x7FC00000u);
1888 return FPSCR_default_NaN_mode_ && value.is_nan() ? kDefaultNaN : value;
1889 }
1890
canonicalizeNaN(double value)1891 double Simulator::canonicalizeNaN(double value) {
1892 // Default NaN value, see "NaN handling" in "IEEE 754 standard implementation
1893 // choices" of the ARM Reference Manual.
1894 constexpr uint64_t kDefaultNaN = uint64_t{0x7FF8000000000000};
1895 if (FPSCR_default_NaN_mode_ && std::isnan(value)) {
1896 value = bit_cast<double>(kDefaultNaN);
1897 }
1898 return value;
1899 }
1900
canonicalizeNaN(Float64 value)1901 Float64 Simulator::canonicalizeNaN(Float64 value) {
1902 // Default NaN value, see "NaN handling" in "IEEE 754 standard implementation
1903 // choices" of the ARM Reference Manual.
1904 constexpr Float64 kDefaultNaN =
1905 Float64::FromBits(uint64_t{0x7FF8000000000000});
1906 return FPSCR_default_NaN_mode_ && value.is_nan() ? kDefaultNaN : value;
1907 }
1908
1909 // Stop helper functions.
isStopInstruction(Instruction * instr)1910 bool Simulator::isStopInstruction(Instruction* instr) {
1911 return (instr->Bits(27, 24) == 0xF) && (instr->SvcValue() >= kStopCode);
1912 }
1913
1914
isWatchedStop(uint32_t code)1915 bool Simulator::isWatchedStop(uint32_t code) {
1916 DCHECK_LE(code, kMaxStopCode);
1917 return code < kNumOfWatchedStops;
1918 }
1919
1920
isEnabledStop(uint32_t code)1921 bool Simulator::isEnabledStop(uint32_t code) {
1922 DCHECK_LE(code, kMaxStopCode);
1923 // Unwatched stops are always enabled.
1924 return !isWatchedStop(code) ||
1925 !(watched_stops_[code].count & kStopDisabledBit);
1926 }
1927
1928
EnableStop(uint32_t code)1929 void Simulator::EnableStop(uint32_t code) {
1930 DCHECK(isWatchedStop(code));
1931 if (!isEnabledStop(code)) {
1932 watched_stops_[code].count &= ~kStopDisabledBit;
1933 }
1934 }
1935
1936
DisableStop(uint32_t code)1937 void Simulator::DisableStop(uint32_t code) {
1938 DCHECK(isWatchedStop(code));
1939 if (isEnabledStop(code)) {
1940 watched_stops_[code].count |= kStopDisabledBit;
1941 }
1942 }
1943
1944
IncreaseStopCounter(uint32_t code)1945 void Simulator::IncreaseStopCounter(uint32_t code) {
1946 DCHECK_LE(code, kMaxStopCode);
1947 DCHECK(isWatchedStop(code));
1948 if ((watched_stops_[code].count & ~(1 << 31)) == 0x7FFFFFFF) {
1949 PrintF("Stop counter for code %i has overflowed.\n"
1950 "Enabling this code and reseting the counter to 0.\n", code);
1951 watched_stops_[code].count = 0;
1952 EnableStop(code);
1953 } else {
1954 watched_stops_[code].count++;
1955 }
1956 }
1957
1958
1959 // Print a stop status.
PrintStopInfo(uint32_t code)1960 void Simulator::PrintStopInfo(uint32_t code) {
1961 DCHECK_LE(code, kMaxStopCode);
1962 if (!isWatchedStop(code)) {
1963 PrintF("Stop not watched.");
1964 } else {
1965 const char* state = isEnabledStop(code) ? "Enabled" : "Disabled";
1966 int32_t count = watched_stops_[code].count & ~kStopDisabledBit;
1967 // Don't print the state of unused breakpoints.
1968 if (count != 0) {
1969 if (watched_stops_[code].desc) {
1970 PrintF("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n",
1971 code, code, state, count, watched_stops_[code].desc);
1972 } else {
1973 PrintF("stop %i - 0x%x: \t%s, \tcounter = %i\n",
1974 code, code, state, count);
1975 }
1976 }
1977 }
1978 }
1979
1980
1981 // Handle execution based on instruction types.
1982
1983 // Instruction types 0 and 1 are both rolled into one function because they
1984 // only differ in the handling of the shifter_operand.
DecodeType01(Instruction * instr)1985 void Simulator::DecodeType01(Instruction* instr) {
1986 int type = instr->TypeValue();
1987 if ((type == 0) && instr->IsSpecialType0()) {
1988 // multiply instruction or extra loads and stores
1989 if (instr->Bits(7, 4) == 9) {
1990 if (instr->Bit(24) == 0) {
1991 // Raw field decoding here. Multiply instructions have their Rd in
1992 // funny places.
1993 int rn = instr->RnValue();
1994 int rm = instr->RmValue();
1995 int rs = instr->RsValue();
1996 int32_t rs_val = get_register(rs);
1997 int32_t rm_val = get_register(rm);
1998 if (instr->Bit(23) == 0) {
1999 if (instr->Bit(21) == 0) {
2000 // The MUL instruction description (A 4.1.33) refers to Rd as being
2001 // the destination for the operation, but it confusingly uses the
2002 // Rn field to encode it.
2003 // Format(instr, "mul'cond's 'rn, 'rm, 'rs");
2004 int rd = rn; // Remap the rn field to the Rd register.
2005 int32_t alu_out = rm_val * rs_val;
2006 set_register(rd, alu_out);
2007 if (instr->HasS()) {
2008 SetNZFlags(alu_out);
2009 }
2010 } else {
2011 int rd = instr->RdValue();
2012 int32_t acc_value = get_register(rd);
2013 if (instr->Bit(22) == 0) {
2014 // The MLA instruction description (A 4.1.28) refers to the order
2015 // of registers as "Rd, Rm, Rs, Rn". But confusingly it uses the
2016 // Rn field to encode the Rd register and the Rd field to encode
2017 // the Rn register.
2018 // Format(instr, "mla'cond's 'rn, 'rm, 'rs, 'rd");
2019 int32_t mul_out = rm_val * rs_val;
2020 int32_t result = acc_value + mul_out;
2021 set_register(rn, result);
2022 } else {
2023 // Format(instr, "mls'cond's 'rn, 'rm, 'rs, 'rd");
2024 int32_t mul_out = rm_val * rs_val;
2025 int32_t result = acc_value - mul_out;
2026 set_register(rn, result);
2027 }
2028 }
2029 } else {
2030 // The signed/long multiply instructions use the terms RdHi and RdLo
2031 // when referring to the target registers. They are mapped to the Rn
2032 // and Rd fields as follows:
2033 // RdLo == Rd
2034 // RdHi == Rn (This is confusingly stored in variable rd here
2035 // because the mul instruction from above uses the
2036 // Rn field to encode the Rd register. Good luck figuring
2037 // this out without reading the ARM instruction manual
2038 // at a very detailed level.)
2039 // Format(instr, "'um'al'cond's 'rd, 'rn, 'rs, 'rm");
2040 int rd_hi = rn; // Remap the rn field to the RdHi register.
2041 int rd_lo = instr->RdValue();
2042 int32_t hi_res = 0;
2043 int32_t lo_res = 0;
2044 if (instr->Bit(22) == 1) {
2045 int64_t left_op = static_cast<int32_t>(rm_val);
2046 int64_t right_op = static_cast<int32_t>(rs_val);
2047 uint64_t result = left_op * right_op;
2048 hi_res = static_cast<int32_t>(result >> 32);
2049 lo_res = static_cast<int32_t>(result & 0xFFFFFFFF);
2050 } else {
2051 // unsigned multiply
2052 uint64_t left_op = static_cast<uint32_t>(rm_val);
2053 uint64_t right_op = static_cast<uint32_t>(rs_val);
2054 uint64_t result = left_op * right_op;
2055 hi_res = static_cast<int32_t>(result >> 32);
2056 lo_res = static_cast<int32_t>(result & 0xFFFFFFFF);
2057 }
2058 set_register(rd_lo, lo_res);
2059 set_register(rd_hi, hi_res);
2060 if (instr->HasS()) {
2061 UNIMPLEMENTED();
2062 }
2063 }
2064 } else {
2065 if (instr->Bits(24, 23) == 3) {
2066 if (instr->Bit(20) == 1) {
2067 // ldrex
2068 int rt = instr->RtValue();
2069 int rn = instr->RnValue();
2070 int32_t addr = get_register(rn);
2071 switch (instr->Bits(22, 21)) {
2072 case 0: {
2073 // Format(instr, "ldrex'cond 'rt, ['rn]");
2074 int value = ReadExW(addr);
2075 set_register(rt, value);
2076 break;
2077 }
2078 case 1: {
2079 // Format(instr, "ldrexd'cond 'rt, ['rn]");
2080 int* rn_data = ReadExDW(addr);
2081 set_dw_register(rt, rn_data);
2082 break;
2083 }
2084 case 2: {
2085 // Format(instr, "ldrexb'cond 'rt, ['rn]");
2086 uint8_t value = ReadExBU(addr);
2087 set_register(rt, value);
2088 break;
2089 }
2090 case 3: {
2091 // Format(instr, "ldrexh'cond 'rt, ['rn]");
2092 uint16_t value = ReadExHU(addr);
2093 set_register(rt, value);
2094 break;
2095 }
2096 default:
2097 UNREACHABLE();
2098 break;
2099 }
2100 } else {
2101 // The instruction is documented as strex rd, rt, [rn], but the
2102 // "rt" register is using the rm bits.
2103 int rd = instr->RdValue();
2104 int rt = instr->RmValue();
2105 int rn = instr->RnValue();
2106 DCHECK_NE(rd, rn);
2107 DCHECK_NE(rd, rt);
2108 int32_t addr = get_register(rn);
2109 switch (instr->Bits(22, 21)) {
2110 case 0: {
2111 // Format(instr, "strex'cond 'rd, 'rm, ['rn]");
2112 int value = get_register(rt);
2113 int status = WriteExW(addr, value);
2114 set_register(rd, status);
2115 break;
2116 }
2117 case 1: {
2118 // Format(instr, "strexd'cond 'rd, 'rm, ['rn]");
2119 DCHECK_EQ(rt % 2, 0);
2120 int32_t value1 = get_register(rt);
2121 int32_t value2 = get_register(rt + 1);
2122 int status = WriteExDW(addr, value1, value2);
2123 set_register(rd, status);
2124 break;
2125 }
2126 case 2: {
2127 // Format(instr, "strexb'cond 'rd, 'rm, ['rn]");
2128 uint8_t value = get_register(rt);
2129 int status = WriteExB(addr, value);
2130 set_register(rd, status);
2131 break;
2132 }
2133 case 3: {
2134 // Format(instr, "strexh'cond 'rd, 'rm, ['rn]");
2135 uint16_t value = get_register(rt);
2136 int status = WriteExH(addr, value);
2137 set_register(rd, status);
2138 break;
2139 }
2140 default:
2141 UNREACHABLE();
2142 break;
2143 }
2144 }
2145 } else {
2146 UNIMPLEMENTED(); // Not used by V8.
2147 }
2148 }
2149 } else {
2150 // extra load/store instructions
2151 int rd = instr->RdValue();
2152 int rn = instr->RnValue();
2153 int32_t rn_val = get_register(rn);
2154 int32_t addr = 0;
2155 if (instr->Bit(22) == 0) {
2156 int rm = instr->RmValue();
2157 int32_t rm_val = get_register(rm);
2158 switch (instr->PUField()) {
2159 case da_x: {
2160 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], -'rm");
2161 DCHECK(!instr->HasW());
2162 addr = rn_val;
2163 rn_val -= rm_val;
2164 set_register(rn, rn_val);
2165 break;
2166 }
2167 case ia_x: {
2168 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], +'rm");
2169 DCHECK(!instr->HasW());
2170 addr = rn_val;
2171 rn_val += rm_val;
2172 set_register(rn, rn_val);
2173 break;
2174 }
2175 case db_x: {
2176 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, -'rm]'w");
2177 rn_val -= rm_val;
2178 addr = rn_val;
2179 if (instr->HasW()) {
2180 set_register(rn, rn_val);
2181 }
2182 break;
2183 }
2184 case ib_x: {
2185 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, +'rm]'w");
2186 rn_val += rm_val;
2187 addr = rn_val;
2188 if (instr->HasW()) {
2189 set_register(rn, rn_val);
2190 }
2191 break;
2192 }
2193 default: {
2194 // The PU field is a 2-bit field.
2195 UNREACHABLE();
2196 break;
2197 }
2198 }
2199 } else {
2200 int32_t imm_val = (instr->ImmedHValue() << 4) | instr->ImmedLValue();
2201 switch (instr->PUField()) {
2202 case da_x: {
2203 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], #-'off8");
2204 DCHECK(!instr->HasW());
2205 addr = rn_val;
2206 rn_val -= imm_val;
2207 set_register(rn, rn_val);
2208 break;
2209 }
2210 case ia_x: {
2211 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], #+'off8");
2212 DCHECK(!instr->HasW());
2213 addr = rn_val;
2214 rn_val += imm_val;
2215 set_register(rn, rn_val);
2216 break;
2217 }
2218 case db_x: {
2219 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, #-'off8]'w");
2220 rn_val -= imm_val;
2221 addr = rn_val;
2222 if (instr->HasW()) {
2223 set_register(rn, rn_val);
2224 }
2225 break;
2226 }
2227 case ib_x: {
2228 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, #+'off8]'w");
2229 rn_val += imm_val;
2230 addr = rn_val;
2231 if (instr->HasW()) {
2232 set_register(rn, rn_val);
2233 }
2234 break;
2235 }
2236 default: {
2237 // The PU field is a 2-bit field.
2238 UNREACHABLE();
2239 break;
2240 }
2241 }
2242 }
2243 if (((instr->Bits(7, 4) & 0xD) == 0xD) && (instr->Bit(20) == 0)) {
2244 DCHECK_EQ(rd % 2, 0);
2245 if (instr->HasH()) {
2246 // The strd instruction.
2247 int32_t value1 = get_register(rd);
2248 int32_t value2 = get_register(rd+1);
2249 WriteDW(addr, value1, value2);
2250 } else {
2251 // The ldrd instruction.
2252 int* rn_data = ReadDW(addr);
2253 set_dw_register(rd, rn_data);
2254 }
2255 } else if (instr->HasH()) {
2256 if (instr->HasSign()) {
2257 if (instr->HasL()) {
2258 int16_t val = ReadH(addr);
2259 set_register(rd, val);
2260 } else {
2261 int16_t val = get_register(rd);
2262 WriteH(addr, val);
2263 }
2264 } else {
2265 if (instr->HasL()) {
2266 uint16_t val = ReadHU(addr);
2267 set_register(rd, val);
2268 } else {
2269 uint16_t val = get_register(rd);
2270 WriteH(addr, val);
2271 }
2272 }
2273 } else {
2274 // signed byte loads
2275 DCHECK(instr->HasSign());
2276 DCHECK(instr->HasL());
2277 int8_t val = ReadB(addr);
2278 set_register(rd, val);
2279 }
2280 return;
2281 }
2282 } else if ((type == 0) && instr->IsMiscType0()) {
2283 if ((instr->Bits(27, 23) == 2) && (instr->Bits(21, 20) == 2) &&
2284 (instr->Bits(15, 4) == 0xF00)) {
2285 // MSR
2286 int rm = instr->RmValue();
2287 DCHECK_NE(pc, rm); // UNPREDICTABLE
2288 SRegisterFieldMask sreg_and_mask =
2289 instr->BitField(22, 22) | instr->BitField(19, 16);
2290 SetSpecialRegister(sreg_and_mask, get_register(rm));
2291 } else if ((instr->Bits(27, 23) == 2) && (instr->Bits(21, 20) == 0) &&
2292 (instr->Bits(11, 0) == 0)) {
2293 // MRS
2294 int rd = instr->RdValue();
2295 DCHECK_NE(pc, rd); // UNPREDICTABLE
2296 SRegister sreg = static_cast<SRegister>(instr->BitField(22, 22));
2297 set_register(rd, GetFromSpecialRegister(sreg));
2298 } else if (instr->Bits(22, 21) == 1) {
2299 int rm = instr->RmValue();
2300 switch (instr->BitField(7, 4)) {
2301 case BX:
2302 set_pc(get_register(rm));
2303 break;
2304 case BLX: {
2305 uint32_t old_pc = get_pc();
2306 set_pc(get_register(rm));
2307 set_register(lr, old_pc + kInstrSize);
2308 break;
2309 }
2310 case BKPT: {
2311 ArmDebugger dbg(this);
2312 PrintF("Simulator hit BKPT.\n");
2313 dbg.Debug();
2314 break;
2315 }
2316 default:
2317 UNIMPLEMENTED();
2318 }
2319 } else if (instr->Bits(22, 21) == 3) {
2320 int rm = instr->RmValue();
2321 int rd = instr->RdValue();
2322 switch (instr->BitField(7, 4)) {
2323 case CLZ: {
2324 uint32_t bits = get_register(rm);
2325 int leading_zeros = 0;
2326 if (bits == 0) {
2327 leading_zeros = 32;
2328 } else {
2329 while ((bits & 0x80000000u) == 0) {
2330 bits <<= 1;
2331 leading_zeros++;
2332 }
2333 }
2334 set_register(rd, leading_zeros);
2335 break;
2336 }
2337 default:
2338 UNIMPLEMENTED();
2339 }
2340 } else {
2341 PrintF("%08x\n", instr->InstructionBits());
2342 UNIMPLEMENTED();
2343 }
2344 } else if ((type == 1) && instr->IsNopLikeType1()) {
2345 if (instr->BitField(7, 0) == 0) {
2346 // NOP.
2347 } else if (instr->BitField(7, 0) == 20) {
2348 // CSDB.
2349 } else {
2350 PrintF("%08x\n", instr->InstructionBits());
2351 UNIMPLEMENTED();
2352 }
2353 } else {
2354 int rd = instr->RdValue();
2355 int rn = instr->RnValue();
2356 int32_t rn_val = get_register(rn);
2357 int32_t shifter_operand = 0;
2358 bool shifter_carry_out = 0;
2359 if (type == 0) {
2360 shifter_operand = GetShiftRm(instr, &shifter_carry_out);
2361 } else {
2362 DCHECK_EQ(instr->TypeValue(), 1);
2363 shifter_operand = GetImm(instr, &shifter_carry_out);
2364 }
2365 int32_t alu_out;
2366
2367 switch (instr->OpcodeField()) {
2368 case AND: {
2369 // Format(instr, "and'cond's 'rd, 'rn, 'shift_rm");
2370 // Format(instr, "and'cond's 'rd, 'rn, 'imm");
2371 alu_out = rn_val & shifter_operand;
2372 set_register(rd, alu_out);
2373 if (instr->HasS()) {
2374 SetNZFlags(alu_out);
2375 SetCFlag(shifter_carry_out);
2376 }
2377 break;
2378 }
2379
2380 case EOR: {
2381 // Format(instr, "eor'cond's 'rd, 'rn, 'shift_rm");
2382 // Format(instr, "eor'cond's 'rd, 'rn, 'imm");
2383 alu_out = rn_val ^ shifter_operand;
2384 set_register(rd, alu_out);
2385 if (instr->HasS()) {
2386 SetNZFlags(alu_out);
2387 SetCFlag(shifter_carry_out);
2388 }
2389 break;
2390 }
2391
2392 case SUB: {
2393 // Format(instr, "sub'cond's 'rd, 'rn, 'shift_rm");
2394 // Format(instr, "sub'cond's 'rd, 'rn, 'imm");
2395 alu_out = rn_val - shifter_operand;
2396 set_register(rd, alu_out);
2397 if (instr->HasS()) {
2398 SetNZFlags(alu_out);
2399 SetCFlag(!BorrowFrom(rn_val, shifter_operand));
2400 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, false));
2401 }
2402 break;
2403 }
2404
2405 case RSB: {
2406 // Format(instr, "rsb'cond's 'rd, 'rn, 'shift_rm");
2407 // Format(instr, "rsb'cond's 'rd, 'rn, 'imm");
2408 alu_out = shifter_operand - rn_val;
2409 set_register(rd, alu_out);
2410 if (instr->HasS()) {
2411 SetNZFlags(alu_out);
2412 SetCFlag(!BorrowFrom(shifter_operand, rn_val));
2413 SetVFlag(OverflowFrom(alu_out, shifter_operand, rn_val, false));
2414 }
2415 break;
2416 }
2417
2418 case ADD: {
2419 // Format(instr, "add'cond's 'rd, 'rn, 'shift_rm");
2420 // Format(instr, "add'cond's 'rd, 'rn, 'imm");
2421 alu_out = rn_val + shifter_operand;
2422 set_register(rd, alu_out);
2423 if (instr->HasS()) {
2424 SetNZFlags(alu_out);
2425 SetCFlag(CarryFrom(rn_val, shifter_operand));
2426 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, true));
2427 }
2428 break;
2429 }
2430
2431 case ADC: {
2432 // Format(instr, "adc'cond's 'rd, 'rn, 'shift_rm");
2433 // Format(instr, "adc'cond's 'rd, 'rn, 'imm");
2434 alu_out = rn_val + shifter_operand + GetCarry();
2435 set_register(rd, alu_out);
2436 if (instr->HasS()) {
2437 SetNZFlags(alu_out);
2438 SetCFlag(CarryFrom(rn_val, shifter_operand, GetCarry()));
2439 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, true));
2440 }
2441 break;
2442 }
2443
2444 case SBC: {
2445 // Format(instr, "sbc'cond's 'rd, 'rn, 'shift_rm");
2446 // Format(instr, "sbc'cond's 'rd, 'rn, 'imm");
2447 alu_out = (rn_val - shifter_operand) - (GetCarry() ? 0 : 1);
2448 set_register(rd, alu_out);
2449 if (instr->HasS()) {
2450 SetNZFlags(alu_out);
2451 SetCFlag(!BorrowFrom(rn_val, shifter_operand, GetCarry()));
2452 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, false));
2453 }
2454 break;
2455 }
2456
2457 case RSC: {
2458 Format(instr, "rsc'cond's 'rd, 'rn, 'shift_rm");
2459 Format(instr, "rsc'cond's 'rd, 'rn, 'imm");
2460 break;
2461 }
2462
2463 case TST: {
2464 if (instr->HasS()) {
2465 // Format(instr, "tst'cond 'rn, 'shift_rm");
2466 // Format(instr, "tst'cond 'rn, 'imm");
2467 alu_out = rn_val & shifter_operand;
2468 SetNZFlags(alu_out);
2469 SetCFlag(shifter_carry_out);
2470 } else {
2471 // Format(instr, "movw'cond 'rd, 'imm").
2472 alu_out = instr->ImmedMovwMovtValue();
2473 set_register(rd, alu_out);
2474 }
2475 break;
2476 }
2477
2478 case TEQ: {
2479 if (instr->HasS()) {
2480 // Format(instr, "teq'cond 'rn, 'shift_rm");
2481 // Format(instr, "teq'cond 'rn, 'imm");
2482 alu_out = rn_val ^ shifter_operand;
2483 SetNZFlags(alu_out);
2484 SetCFlag(shifter_carry_out);
2485 } else {
2486 // Other instructions matching this pattern are handled in the
2487 // miscellaneous instructions part above.
2488 UNREACHABLE();
2489 }
2490 break;
2491 }
2492
2493 case CMP: {
2494 if (instr->HasS()) {
2495 // Format(instr, "cmp'cond 'rn, 'shift_rm");
2496 // Format(instr, "cmp'cond 'rn, 'imm");
2497 alu_out = rn_val - shifter_operand;
2498 SetNZFlags(alu_out);
2499 SetCFlag(!BorrowFrom(rn_val, shifter_operand));
2500 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, false));
2501 } else {
2502 // Format(instr, "movt'cond 'rd, 'imm").
2503 alu_out =
2504 (get_register(rd) & 0xFFFF) | (instr->ImmedMovwMovtValue() << 16);
2505 set_register(rd, alu_out);
2506 }
2507 break;
2508 }
2509
2510 case CMN: {
2511 if (instr->HasS()) {
2512 // Format(instr, "cmn'cond 'rn, 'shift_rm");
2513 // Format(instr, "cmn'cond 'rn, 'imm");
2514 alu_out = rn_val + shifter_operand;
2515 SetNZFlags(alu_out);
2516 SetCFlag(CarryFrom(rn_val, shifter_operand));
2517 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, true));
2518 } else {
2519 // Other instructions matching this pattern are handled in the
2520 // miscellaneous instructions part above.
2521 UNREACHABLE();
2522 }
2523 break;
2524 }
2525
2526 case ORR: {
2527 // Format(instr, "orr'cond's 'rd, 'rn, 'shift_rm");
2528 // Format(instr, "orr'cond's 'rd, 'rn, 'imm");
2529 alu_out = rn_val | shifter_operand;
2530 set_register(rd, alu_out);
2531 if (instr->HasS()) {
2532 SetNZFlags(alu_out);
2533 SetCFlag(shifter_carry_out);
2534 }
2535 break;
2536 }
2537
2538 case MOV: {
2539 // Format(instr, "mov'cond's 'rd, 'shift_rm");
2540 // Format(instr, "mov'cond's 'rd, 'imm");
2541 alu_out = shifter_operand;
2542 set_register(rd, alu_out);
2543 if (instr->HasS()) {
2544 SetNZFlags(alu_out);
2545 SetCFlag(shifter_carry_out);
2546 }
2547 break;
2548 }
2549
2550 case BIC: {
2551 // Format(instr, "bic'cond's 'rd, 'rn, 'shift_rm");
2552 // Format(instr, "bic'cond's 'rd, 'rn, 'imm");
2553 alu_out = rn_val & ~shifter_operand;
2554 set_register(rd, alu_out);
2555 if (instr->HasS()) {
2556 SetNZFlags(alu_out);
2557 SetCFlag(shifter_carry_out);
2558 }
2559 break;
2560 }
2561
2562 case MVN: {
2563 // Format(instr, "mvn'cond's 'rd, 'shift_rm");
2564 // Format(instr, "mvn'cond's 'rd, 'imm");
2565 alu_out = ~shifter_operand;
2566 set_register(rd, alu_out);
2567 if (instr->HasS()) {
2568 SetNZFlags(alu_out);
2569 SetCFlag(shifter_carry_out);
2570 }
2571 break;
2572 }
2573
2574 default: {
2575 UNREACHABLE();
2576 break;
2577 }
2578 }
2579 }
2580 }
2581
2582
DecodeType2(Instruction * instr)2583 void Simulator::DecodeType2(Instruction* instr) {
2584 int rd = instr->RdValue();
2585 int rn = instr->RnValue();
2586 int32_t rn_val = get_register(rn);
2587 int32_t im_val = instr->Offset12Value();
2588 int32_t addr = 0;
2589 switch (instr->PUField()) {
2590 case da_x: {
2591 // Format(instr, "'memop'cond'b 'rd, ['rn], #-'off12");
2592 DCHECK(!instr->HasW());
2593 addr = rn_val;
2594 rn_val -= im_val;
2595 set_register(rn, rn_val);
2596 break;
2597 }
2598 case ia_x: {
2599 // Format(instr, "'memop'cond'b 'rd, ['rn], #+'off12");
2600 DCHECK(!instr->HasW());
2601 addr = rn_val;
2602 rn_val += im_val;
2603 set_register(rn, rn_val);
2604 break;
2605 }
2606 case db_x: {
2607 // Format(instr, "'memop'cond'b 'rd, ['rn, #-'off12]'w");
2608 rn_val -= im_val;
2609 addr = rn_val;
2610 if (instr->HasW()) {
2611 set_register(rn, rn_val);
2612 }
2613 break;
2614 }
2615 case ib_x: {
2616 // Format(instr, "'memop'cond'b 'rd, ['rn, #+'off12]'w");
2617 rn_val += im_val;
2618 addr = rn_val;
2619 if (instr->HasW()) {
2620 set_register(rn, rn_val);
2621 }
2622 break;
2623 }
2624 default: {
2625 UNREACHABLE();
2626 break;
2627 }
2628 }
2629 if (instr->HasB()) {
2630 if (instr->HasL()) {
2631 byte val = ReadBU(addr);
2632 set_register(rd, val);
2633 } else {
2634 byte val = get_register(rd);
2635 WriteB(addr, val);
2636 }
2637 } else {
2638 if (instr->HasL()) {
2639 set_register(rd, ReadW(addr));
2640 } else {
2641 WriteW(addr, get_register(rd));
2642 }
2643 }
2644 }
2645
2646
DecodeType3(Instruction * instr)2647 void Simulator::DecodeType3(Instruction* instr) {
2648 int rd = instr->RdValue();
2649 int rn = instr->RnValue();
2650 int32_t rn_val = get_register(rn);
2651 bool shifter_carry_out = 0;
2652 int32_t shifter_operand = GetShiftRm(instr, &shifter_carry_out);
2653 int32_t addr = 0;
2654 switch (instr->PUField()) {
2655 case da_x: {
2656 DCHECK(!instr->HasW());
2657 Format(instr, "'memop'cond'b 'rd, ['rn], -'shift_rm");
2658 UNIMPLEMENTED();
2659 break;
2660 }
2661 case ia_x: {
2662 if (instr->Bit(4) == 0) {
2663 // Memop.
2664 } else {
2665 if (instr->Bit(5) == 0) {
2666 switch (instr->Bits(22, 21)) {
2667 case 0:
2668 if (instr->Bit(20) == 0) {
2669 if (instr->Bit(6) == 0) {
2670 // Pkhbt.
2671 uint32_t rn_val = get_register(rn);
2672 uint32_t rm_val = get_register(instr->RmValue());
2673 int32_t shift = instr->Bits(11, 7);
2674 rm_val <<= shift;
2675 set_register(rd, (rn_val & 0xFFFF) | (rm_val & 0xFFFF0000U));
2676 } else {
2677 // Pkhtb.
2678 uint32_t rn_val = get_register(rn);
2679 int32_t rm_val = get_register(instr->RmValue());
2680 int32_t shift = instr->Bits(11, 7);
2681 if (shift == 0) {
2682 shift = 32;
2683 }
2684 rm_val >>= shift;
2685 set_register(rd, (rn_val & 0xFFFF0000U) | (rm_val & 0xFFFF));
2686 }
2687 } else {
2688 UNIMPLEMENTED();
2689 }
2690 break;
2691 case 1:
2692 UNIMPLEMENTED();
2693 break;
2694 case 2:
2695 UNIMPLEMENTED();
2696 break;
2697 case 3: {
2698 // Usat.
2699 int32_t sat_pos = instr->Bits(20, 16);
2700 int32_t sat_val = (1 << sat_pos) - 1;
2701 int32_t shift = instr->Bits(11, 7);
2702 int32_t shift_type = instr->Bit(6);
2703 int32_t rm_val = get_register(instr->RmValue());
2704 if (shift_type == 0) { // LSL
2705 rm_val <<= shift;
2706 } else { // ASR
2707 rm_val >>= shift;
2708 }
2709 // If saturation occurs, the Q flag should be set in the CPSR.
2710 // There is no Q flag yet, and no instruction (MRS) to read the
2711 // CPSR directly.
2712 if (rm_val > sat_val) {
2713 rm_val = sat_val;
2714 } else if (rm_val < 0) {
2715 rm_val = 0;
2716 }
2717 set_register(rd, rm_val);
2718 break;
2719 }
2720 }
2721 } else {
2722 switch (instr->Bits(22, 21)) {
2723 case 0:
2724 UNIMPLEMENTED();
2725 break;
2726 case 1:
2727 if (instr->Bits(9, 6) == 1) {
2728 if (instr->Bit(20) == 0) {
2729 if (instr->Bits(19, 16) == 0xF) {
2730 // Sxtb.
2731 int32_t rm_val = get_register(instr->RmValue());
2732 int32_t rotate = instr->Bits(11, 10);
2733 switch (rotate) {
2734 case 0:
2735 break;
2736 case 1:
2737 rm_val = (rm_val >> 8) | (rm_val << 24);
2738 break;
2739 case 2:
2740 rm_val = (rm_val >> 16) | (rm_val << 16);
2741 break;
2742 case 3:
2743 rm_val = (rm_val >> 24) | (rm_val << 8);
2744 break;
2745 }
2746 set_register(rd, static_cast<int8_t>(rm_val));
2747 } else {
2748 // Sxtab.
2749 int32_t rn_val = get_register(rn);
2750 int32_t rm_val = get_register(instr->RmValue());
2751 int32_t rotate = instr->Bits(11, 10);
2752 switch (rotate) {
2753 case 0:
2754 break;
2755 case 1:
2756 rm_val = (rm_val >> 8) | (rm_val << 24);
2757 break;
2758 case 2:
2759 rm_val = (rm_val >> 16) | (rm_val << 16);
2760 break;
2761 case 3:
2762 rm_val = (rm_val >> 24) | (rm_val << 8);
2763 break;
2764 }
2765 set_register(rd, rn_val + static_cast<int8_t>(rm_val));
2766 }
2767 } else {
2768 if (instr->Bits(19, 16) == 0xF) {
2769 // Sxth.
2770 int32_t rm_val = get_register(instr->RmValue());
2771 int32_t rotate = instr->Bits(11, 10);
2772 switch (rotate) {
2773 case 0:
2774 break;
2775 case 1:
2776 rm_val = (rm_val >> 8) | (rm_val << 24);
2777 break;
2778 case 2:
2779 rm_val = (rm_val >> 16) | (rm_val << 16);
2780 break;
2781 case 3:
2782 rm_val = (rm_val >> 24) | (rm_val << 8);
2783 break;
2784 }
2785 set_register(rd, static_cast<int16_t>(rm_val));
2786 } else {
2787 // Sxtah.
2788 int32_t rn_val = get_register(rn);
2789 int32_t rm_val = get_register(instr->RmValue());
2790 int32_t rotate = instr->Bits(11, 10);
2791 switch (rotate) {
2792 case 0:
2793 break;
2794 case 1:
2795 rm_val = (rm_val >> 8) | (rm_val << 24);
2796 break;
2797 case 2:
2798 rm_val = (rm_val >> 16) | (rm_val << 16);
2799 break;
2800 case 3:
2801 rm_val = (rm_val >> 24) | (rm_val << 8);
2802 break;
2803 }
2804 set_register(rd, rn_val + static_cast<int16_t>(rm_val));
2805 }
2806 }
2807 } else if (instr->Bits(27, 16) == 0x6BF &&
2808 instr->Bits(11, 4) == 0xF3) {
2809 // Rev.
2810 uint32_t rm_val = get_register(instr->RmValue());
2811 set_register(rd, ByteReverse(rm_val));
2812 } else {
2813 UNREACHABLE();
2814 }
2815 break;
2816 case 2:
2817 if ((instr->Bit(20) == 0) && (instr->Bits(9, 6) == 1)) {
2818 if (instr->Bits(19, 16) == 0xF) {
2819 // Uxtb16.
2820 uint32_t rm_val = get_register(instr->RmValue());
2821 int32_t rotate = instr->Bits(11, 10);
2822 switch (rotate) {
2823 case 0:
2824 break;
2825 case 1:
2826 rm_val = (rm_val >> 8) | (rm_val << 24);
2827 break;
2828 case 2:
2829 rm_val = (rm_val >> 16) | (rm_val << 16);
2830 break;
2831 case 3:
2832 rm_val = (rm_val >> 24) | (rm_val << 8);
2833 break;
2834 }
2835 set_register(rd, (rm_val & 0xFF) | (rm_val & 0xFF0000));
2836 } else {
2837 UNIMPLEMENTED();
2838 }
2839 } else {
2840 UNIMPLEMENTED();
2841 }
2842 break;
2843 case 3:
2844 if ((instr->Bits(9, 6) == 1)) {
2845 if (instr->Bit(20) == 0) {
2846 if (instr->Bits(19, 16) == 0xF) {
2847 // Uxtb.
2848 uint32_t rm_val = get_register(instr->RmValue());
2849 int32_t rotate = instr->Bits(11, 10);
2850 switch (rotate) {
2851 case 0:
2852 break;
2853 case 1:
2854 rm_val = (rm_val >> 8) | (rm_val << 24);
2855 break;
2856 case 2:
2857 rm_val = (rm_val >> 16) | (rm_val << 16);
2858 break;
2859 case 3:
2860 rm_val = (rm_val >> 24) | (rm_val << 8);
2861 break;
2862 }
2863 set_register(rd, (rm_val & 0xFF));
2864 } else {
2865 // Uxtab.
2866 uint32_t rn_val = get_register(rn);
2867 uint32_t rm_val = get_register(instr->RmValue());
2868 int32_t rotate = instr->Bits(11, 10);
2869 switch (rotate) {
2870 case 0:
2871 break;
2872 case 1:
2873 rm_val = (rm_val >> 8) | (rm_val << 24);
2874 break;
2875 case 2:
2876 rm_val = (rm_val >> 16) | (rm_val << 16);
2877 break;
2878 case 3:
2879 rm_val = (rm_val >> 24) | (rm_val << 8);
2880 break;
2881 }
2882 set_register(rd, rn_val + (rm_val & 0xFF));
2883 }
2884 } else {
2885 if (instr->Bits(19, 16) == 0xF) {
2886 // Uxth.
2887 uint32_t rm_val = get_register(instr->RmValue());
2888 int32_t rotate = instr->Bits(11, 10);
2889 switch (rotate) {
2890 case 0:
2891 break;
2892 case 1:
2893 rm_val = (rm_val >> 8) | (rm_val << 24);
2894 break;
2895 case 2:
2896 rm_val = (rm_val >> 16) | (rm_val << 16);
2897 break;
2898 case 3:
2899 rm_val = (rm_val >> 24) | (rm_val << 8);
2900 break;
2901 }
2902 set_register(rd, (rm_val & 0xFFFF));
2903 } else {
2904 // Uxtah.
2905 uint32_t rn_val = get_register(rn);
2906 uint32_t rm_val = get_register(instr->RmValue());
2907 int32_t rotate = instr->Bits(11, 10);
2908 switch (rotate) {
2909 case 0:
2910 break;
2911 case 1:
2912 rm_val = (rm_val >> 8) | (rm_val << 24);
2913 break;
2914 case 2:
2915 rm_val = (rm_val >> 16) | (rm_val << 16);
2916 break;
2917 case 3:
2918 rm_val = (rm_val >> 24) | (rm_val << 8);
2919 break;
2920 }
2921 set_register(rd, rn_val + (rm_val & 0xFFFF));
2922 }
2923 }
2924 } else {
2925 // PU == 0b01, BW == 0b11, Bits(9, 6) != 0b0001
2926 if ((instr->Bits(20, 16) == 0x1F) &&
2927 (instr->Bits(11, 4) == 0xF3)) {
2928 // Rbit.
2929 uint32_t rm_val = get_register(instr->RmValue());
2930 set_register(rd, base::bits::ReverseBits(rm_val));
2931 } else {
2932 UNIMPLEMENTED();
2933 }
2934 }
2935 break;
2936 }
2937 }
2938 return;
2939 }
2940 break;
2941 }
2942 case db_x: {
2943 if (instr->Bits(22, 20) == 0x5) {
2944 if (instr->Bits(7, 4) == 0x1) {
2945 int rm = instr->RmValue();
2946 int32_t rm_val = get_register(rm);
2947 int rs = instr->RsValue();
2948 int32_t rs_val = get_register(rs);
2949 if (instr->Bits(15, 12) == 0xF) {
2950 // SMMUL (in V8 notation matching ARM ISA format)
2951 // Format(instr, "smmul'cond 'rn, 'rm, 'rs");
2952 rn_val = base::bits::SignedMulHigh32(rm_val, rs_val);
2953 } else {
2954 // SMMLA (in V8 notation matching ARM ISA format)
2955 // Format(instr, "smmla'cond 'rn, 'rm, 'rs, 'rd");
2956 int rd = instr->RdValue();
2957 int32_t rd_val = get_register(rd);
2958 rn_val = base::bits::SignedMulHighAndAdd32(rm_val, rs_val, rd_val);
2959 }
2960 set_register(rn, rn_val);
2961 return;
2962 }
2963 }
2964 if (instr->Bits(5, 4) == 0x1) {
2965 if ((instr->Bit(22) == 0x0) && (instr->Bit(20) == 0x1)) {
2966 // (s/u)div (in V8 notation matching ARM ISA format) rn = rm/rs
2967 // Format(instr, "'(s/u)div'cond'b 'rn, 'rm, 'rs);
2968 int rm = instr->RmValue();
2969 int32_t rm_val = get_register(rm);
2970 int rs = instr->RsValue();
2971 int32_t rs_val = get_register(rs);
2972 int32_t ret_val = 0;
2973 // udiv
2974 if (instr->Bit(21) == 0x1) {
2975 ret_val = bit_cast<int32_t>(base::bits::UnsignedDiv32(
2976 bit_cast<uint32_t>(rm_val), bit_cast<uint32_t>(rs_val)));
2977 } else {
2978 ret_val = base::bits::SignedDiv32(rm_val, rs_val);
2979 }
2980 set_register(rn, ret_val);
2981 return;
2982 }
2983 }
2984 // Format(instr, "'memop'cond'b 'rd, ['rn, -'shift_rm]'w");
2985 addr = rn_val - shifter_operand;
2986 if (instr->HasW()) {
2987 set_register(rn, addr);
2988 }
2989 break;
2990 }
2991 case ib_x: {
2992 if (instr->HasW() && (instr->Bits(6, 4) == 0x5)) {
2993 uint32_t widthminus1 = static_cast<uint32_t>(instr->Bits(20, 16));
2994 uint32_t lsbit = static_cast<uint32_t>(instr->Bits(11, 7));
2995 uint32_t msbit = widthminus1 + lsbit;
2996 if (msbit <= 31) {
2997 if (instr->Bit(22)) {
2998 // ubfx - unsigned bitfield extract.
2999 uint32_t rm_val =
3000 static_cast<uint32_t>(get_register(instr->RmValue()));
3001 uint32_t extr_val = rm_val << (31 - msbit);
3002 extr_val = extr_val >> (31 - widthminus1);
3003 set_register(instr->RdValue(), extr_val);
3004 } else {
3005 // sbfx - signed bitfield extract.
3006 int32_t rm_val = get_register(instr->RmValue());
3007 int32_t extr_val = rm_val << (31 - msbit);
3008 extr_val = extr_val >> (31 - widthminus1);
3009 set_register(instr->RdValue(), extr_val);
3010 }
3011 } else {
3012 UNREACHABLE();
3013 }
3014 return;
3015 } else if (!instr->HasW() && (instr->Bits(6, 4) == 0x1)) {
3016 uint32_t lsbit = static_cast<uint32_t>(instr->Bits(11, 7));
3017 uint32_t msbit = static_cast<uint32_t>(instr->Bits(20, 16));
3018 if (msbit >= lsbit) {
3019 // bfc or bfi - bitfield clear/insert.
3020 uint32_t rd_val =
3021 static_cast<uint32_t>(get_register(instr->RdValue()));
3022 uint32_t bitcount = msbit - lsbit + 1;
3023 uint32_t mask = 0xFFFFFFFFu >> (32 - bitcount);
3024 rd_val &= ~(mask << lsbit);
3025 if (instr->RmValue() != 15) {
3026 // bfi - bitfield insert.
3027 uint32_t rm_val =
3028 static_cast<uint32_t>(get_register(instr->RmValue()));
3029 rm_val &= mask;
3030 rd_val |= rm_val << lsbit;
3031 }
3032 set_register(instr->RdValue(), rd_val);
3033 } else {
3034 UNREACHABLE();
3035 }
3036 return;
3037 } else {
3038 // Format(instr, "'memop'cond'b 'rd, ['rn, +'shift_rm]'w");
3039 addr = rn_val + shifter_operand;
3040 if (instr->HasW()) {
3041 set_register(rn, addr);
3042 }
3043 }
3044 break;
3045 }
3046 default: {
3047 UNREACHABLE();
3048 break;
3049 }
3050 }
3051 if (instr->HasB()) {
3052 if (instr->HasL()) {
3053 uint8_t byte = ReadB(addr);
3054 set_register(rd, byte);
3055 } else {
3056 uint8_t byte = get_register(rd);
3057 WriteB(addr, byte);
3058 }
3059 } else {
3060 if (instr->HasL()) {
3061 set_register(rd, ReadW(addr));
3062 } else {
3063 WriteW(addr, get_register(rd));
3064 }
3065 }
3066 }
3067
3068
DecodeType4(Instruction * instr)3069 void Simulator::DecodeType4(Instruction* instr) {
3070 DCHECK_EQ(instr->Bit(22), 0); // only allowed to be set in privileged mode
3071 if (instr->HasL()) {
3072 // Format(instr, "ldm'cond'pu 'rn'w, 'rlist");
3073 HandleRList(instr, true);
3074 } else {
3075 // Format(instr, "stm'cond'pu 'rn'w, 'rlist");
3076 HandleRList(instr, false);
3077 }
3078 }
3079
3080
DecodeType5(Instruction * instr)3081 void Simulator::DecodeType5(Instruction* instr) {
3082 // Format(instr, "b'l'cond 'target");
3083 int off = (instr->SImmed24Value() << 2);
3084 intptr_t pc_address = get_pc();
3085 if (instr->HasLink()) {
3086 set_register(lr, pc_address + kInstrSize);
3087 }
3088 int pc_reg = get_register(pc);
3089 set_pc(pc_reg + off);
3090 }
3091
3092
DecodeType6(Instruction * instr)3093 void Simulator::DecodeType6(Instruction* instr) {
3094 DecodeType6CoprocessorIns(instr);
3095 }
3096
3097
DecodeType7(Instruction * instr)3098 void Simulator::DecodeType7(Instruction* instr) {
3099 if (instr->Bit(24) == 1) {
3100 SoftwareInterrupt(instr);
3101 } else {
3102 switch (instr->CoprocessorValue()) {
3103 case 10: // Fall through.
3104 case 11:
3105 DecodeTypeVFP(instr);
3106 break;
3107 case 15:
3108 DecodeTypeCP15(instr);
3109 break;
3110 default:
3111 UNIMPLEMENTED();
3112 }
3113 }
3114 }
3115
3116
3117 // void Simulator::DecodeTypeVFP(Instruction* instr)
3118 // The Following ARMv7 VFPv instructions are currently supported.
3119 // vmov :Sn = Rt
3120 // vmov :Rt = Sn
3121 // vcvt: Dd = Sm
3122 // vcvt: Sd = Dm
3123 // vcvt.f64.s32 Dd, Dd, #<fbits>
3124 // Dd = vabs(Dm)
3125 // Sd = vabs(Sm)
3126 // Dd = vneg(Dm)
3127 // Sd = vneg(Sm)
3128 // Dd = vadd(Dn, Dm)
3129 // Sd = vadd(Sn, Sm)
3130 // Dd = vsub(Dn, Dm)
3131 // Sd = vsub(Sn, Sm)
3132 // Dd = vmul(Dn, Dm)
3133 // Sd = vmul(Sn, Sm)
3134 // Dd = vdiv(Dn, Dm)
3135 // Sd = vdiv(Sn, Sm)
3136 // vcmp(Dd, Dm)
3137 // vcmp(Sd, Sm)
3138 // Dd = vsqrt(Dm)
3139 // Sd = vsqrt(Sm)
3140 // vmrs
3141 // vdup.size Qd, Rt.
DecodeTypeVFP(Instruction * instr)3142 void Simulator::DecodeTypeVFP(Instruction* instr) {
3143 DCHECK((instr->TypeValue() == 7) && (instr->Bit(24) == 0x0) );
3144 DCHECK_EQ(instr->Bits(11, 9), 0x5);
3145 // Obtain single precision register codes.
3146 int m = instr->VFPMRegValue(kSinglePrecision);
3147 int d = instr->VFPDRegValue(kSinglePrecision);
3148 int n = instr->VFPNRegValue(kSinglePrecision);
3149 // Obtain double precision register codes.
3150 int vm = instr->VFPMRegValue(kDoublePrecision);
3151 int vd = instr->VFPDRegValue(kDoublePrecision);
3152 int vn = instr->VFPNRegValue(kDoublePrecision);
3153
3154 if (instr->Bit(4) == 0) {
3155 if (instr->Opc1Value() == 0x7) {
3156 // Other data processing instructions
3157 if ((instr->Opc2Value() == 0x0) && (instr->Opc3Value() == 0x1)) {
3158 // vmov register to register.
3159 if (instr->SzValue() == 0x1) {
3160 uint32_t data[2];
3161 get_d_register(vm, data);
3162 set_d_register(vd, data);
3163 } else {
3164 set_s_register(d, get_s_register(m));
3165 }
3166 } else if ((instr->Opc2Value() == 0x0) && (instr->Opc3Value() == 0x3)) {
3167 // vabs
3168 if (instr->SzValue() == 0x1) {
3169 Float64 dm = get_double_from_d_register(vm);
3170 constexpr uint64_t kSignBit64 = uint64_t{1} << 63;
3171 Float64 dd = Float64::FromBits(dm.get_bits() & ~kSignBit64);
3172 dd = canonicalizeNaN(dd);
3173 set_d_register_from_double(vd, dd);
3174 } else {
3175 Float32 sm = get_float_from_s_register(m);
3176 constexpr uint32_t kSignBit32 = uint32_t{1} << 31;
3177 Float32 sd = Float32::FromBits(sm.get_bits() & ~kSignBit32);
3178 sd = canonicalizeNaN(sd);
3179 set_s_register_from_float(d, sd);
3180 }
3181 } else if ((instr->Opc2Value() == 0x1) && (instr->Opc3Value() == 0x1)) {
3182 // vneg
3183 if (instr->SzValue() == 0x1) {
3184 Float64 dm = get_double_from_d_register(vm);
3185 constexpr uint64_t kSignBit64 = uint64_t{1} << 63;
3186 Float64 dd = Float64::FromBits(dm.get_bits() ^ kSignBit64);
3187 dd = canonicalizeNaN(dd);
3188 set_d_register_from_double(vd, dd);
3189 } else {
3190 Float32 sm = get_float_from_s_register(m);
3191 constexpr uint32_t kSignBit32 = uint32_t{1} << 31;
3192 Float32 sd = Float32::FromBits(sm.get_bits() ^ kSignBit32);
3193 sd = canonicalizeNaN(sd);
3194 set_s_register_from_float(d, sd);
3195 }
3196 } else if ((instr->Opc2Value() == 0x7) && (instr->Opc3Value() == 0x3)) {
3197 DecodeVCVTBetweenDoubleAndSingle(instr);
3198 } else if ((instr->Opc2Value() == 0x8) && (instr->Opc3Value() & 0x1)) {
3199 DecodeVCVTBetweenFloatingPointAndInteger(instr);
3200 } else if ((instr->Opc2Value() == 0xA) && (instr->Opc3Value() == 0x3) &&
3201 (instr->Bit(8) == 1)) {
3202 // vcvt.f64.s32 Dd, Dd, #<fbits>
3203 int fraction_bits = 32 - ((instr->Bits(3, 0) << 1) | instr->Bit(5));
3204 int fixed_value = get_sinteger_from_s_register(vd * 2);
3205 double divide = 1 << fraction_bits;
3206 set_d_register_from_double(vd, fixed_value / divide);
3207 } else if (((instr->Opc2Value() >> 1) == 0x6) &&
3208 (instr->Opc3Value() & 0x1)) {
3209 DecodeVCVTBetweenFloatingPointAndInteger(instr);
3210 } else if (((instr->Opc2Value() == 0x4) || (instr->Opc2Value() == 0x5)) &&
3211 (instr->Opc3Value() & 0x1)) {
3212 DecodeVCMP(instr);
3213 } else if (((instr->Opc2Value() == 0x1)) && (instr->Opc3Value() == 0x3)) {
3214 // vsqrt
3215 lazily_initialize_fast_sqrt(isolate_);
3216 if (instr->SzValue() == 0x1) {
3217 double dm_value = get_double_from_d_register(vm).get_scalar();
3218 double dd_value = fast_sqrt(dm_value, isolate_);
3219 dd_value = canonicalizeNaN(dd_value);
3220 set_d_register_from_double(vd, dd_value);
3221 } else {
3222 float sm_value = get_float_from_s_register(m).get_scalar();
3223 float sd_value = fast_sqrt(sm_value, isolate_);
3224 sd_value = canonicalizeNaN(sd_value);
3225 set_s_register_from_float(d, sd_value);
3226 }
3227 } else if (instr->Opc3Value() == 0x0) {
3228 // vmov immediate.
3229 if (instr->SzValue() == 0x1) {
3230 set_d_register_from_double(vd, instr->DoubleImmedVmov());
3231 } else {
3232 // Cast double to float.
3233 float value = instr->DoubleImmedVmov().get_scalar();
3234 set_s_register_from_float(d, value);
3235 }
3236 } else if (((instr->Opc2Value() == 0x6)) && (instr->Opc3Value() == 0x3)) {
3237 // vrintz - truncate
3238 if (instr->SzValue() == 0x1) {
3239 double dm_value = get_double_from_d_register(vm).get_scalar();
3240 double dd_value = trunc(dm_value);
3241 dd_value = canonicalizeNaN(dd_value);
3242 set_d_register_from_double(vd, dd_value);
3243 } else {
3244 float sm_value = get_float_from_s_register(m).get_scalar();
3245 float sd_value = truncf(sm_value);
3246 sd_value = canonicalizeNaN(sd_value);
3247 set_s_register_from_float(d, sd_value);
3248 }
3249 } else {
3250 UNREACHABLE(); // Not used by V8.
3251 }
3252 } else if (instr->Opc1Value() == 0x3) {
3253 if (instr->Opc3Value() & 0x1) {
3254 // vsub
3255 if (instr->SzValue() == 0x1) {
3256 double dn_value = get_double_from_d_register(vn).get_scalar();
3257 double dm_value = get_double_from_d_register(vm).get_scalar();
3258 double dd_value = dn_value - dm_value;
3259 dd_value = canonicalizeNaN(dd_value);
3260 set_d_register_from_double(vd, dd_value);
3261 } else {
3262 float sn_value = get_float_from_s_register(n).get_scalar();
3263 float sm_value = get_float_from_s_register(m).get_scalar();
3264 float sd_value = sn_value - sm_value;
3265 sd_value = canonicalizeNaN(sd_value);
3266 set_s_register_from_float(d, sd_value);
3267 }
3268 } else {
3269 // vadd
3270 if (instr->SzValue() == 0x1) {
3271 double dn_value = get_double_from_d_register(vn).get_scalar();
3272 double dm_value = get_double_from_d_register(vm).get_scalar();
3273 double dd_value = dn_value + dm_value;
3274 dd_value = canonicalizeNaN(dd_value);
3275 set_d_register_from_double(vd, dd_value);
3276 } else {
3277 float sn_value = get_float_from_s_register(n).get_scalar();
3278 float sm_value = get_float_from_s_register(m).get_scalar();
3279 float sd_value = sn_value + sm_value;
3280 sd_value = canonicalizeNaN(sd_value);
3281 set_s_register_from_float(d, sd_value);
3282 }
3283 }
3284 } else if ((instr->Opc1Value() == 0x2) && !(instr->Opc3Value() & 0x1)) {
3285 // vmul
3286 if (instr->SzValue() == 0x1) {
3287 double dn_value = get_double_from_d_register(vn).get_scalar();
3288 double dm_value = get_double_from_d_register(vm).get_scalar();
3289 double dd_value = dn_value * dm_value;
3290 dd_value = canonicalizeNaN(dd_value);
3291 set_d_register_from_double(vd, dd_value);
3292 } else {
3293 float sn_value = get_float_from_s_register(n).get_scalar();
3294 float sm_value = get_float_from_s_register(m).get_scalar();
3295 float sd_value = sn_value * sm_value;
3296 sd_value = canonicalizeNaN(sd_value);
3297 set_s_register_from_float(d, sd_value);
3298 }
3299 } else if ((instr->Opc1Value() == 0x0)) {
3300 // vmla, vmls
3301 const bool is_vmls = (instr->Opc3Value() & 0x1);
3302 if (instr->SzValue() == 0x1) {
3303 const double dd_val = get_double_from_d_register(vd).get_scalar();
3304 const double dn_val = get_double_from_d_register(vn).get_scalar();
3305 const double dm_val = get_double_from_d_register(vm).get_scalar();
3306
3307 // Note: we do the mul and add/sub in separate steps to avoid getting a
3308 // result with too high precision.
3309 const double res = dn_val * dm_val;
3310 set_d_register_from_double(vd, res);
3311 if (is_vmls) {
3312 set_d_register_from_double(vd, canonicalizeNaN(dd_val - res));
3313 } else {
3314 set_d_register_from_double(vd, canonicalizeNaN(dd_val + res));
3315 }
3316 } else {
3317 const float sd_val = get_float_from_s_register(d).get_scalar();
3318 const float sn_val = get_float_from_s_register(n).get_scalar();
3319 const float sm_val = get_float_from_s_register(m).get_scalar();
3320
3321 // Note: we do the mul and add/sub in separate steps to avoid getting a
3322 // result with too high precision.
3323 const float res = sn_val * sm_val;
3324 set_s_register_from_float(d, res);
3325 if (is_vmls) {
3326 set_s_register_from_float(d, canonicalizeNaN(sd_val - res));
3327 } else {
3328 set_s_register_from_float(d, canonicalizeNaN(sd_val + res));
3329 }
3330 }
3331 } else if ((instr->Opc1Value() == 0x4) && !(instr->Opc3Value() & 0x1)) {
3332 // vdiv
3333 if (instr->SzValue() == 0x1) {
3334 double dn_value = get_double_from_d_register(vn).get_scalar();
3335 double dm_value = get_double_from_d_register(vm).get_scalar();
3336 double dd_value = dn_value / dm_value;
3337 div_zero_vfp_flag_ = (dm_value == 0);
3338 dd_value = canonicalizeNaN(dd_value);
3339 set_d_register_from_double(vd, dd_value);
3340 } else {
3341 float sn_value = get_float_from_s_register(n).get_scalar();
3342 float sm_value = get_float_from_s_register(m).get_scalar();
3343 float sd_value = sn_value / sm_value;
3344 div_zero_vfp_flag_ = (sm_value == 0);
3345 sd_value = canonicalizeNaN(sd_value);
3346 set_s_register_from_float(d, sd_value);
3347 }
3348 } else {
3349 UNIMPLEMENTED(); // Not used by V8.
3350 }
3351 } else {
3352 if ((instr->VCValue() == 0x0) &&
3353 (instr->VAValue() == 0x0)) {
3354 DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(instr);
3355 } else if ((instr->VLValue() == 0x0) && (instr->VCValue() == 0x1)) {
3356 if (instr->Bit(23) == 0) {
3357 // vmov (ARM core register to scalar)
3358 int vd = instr->VFPNRegValue(kDoublePrecision);
3359 int rt = instr->RtValue();
3360 int opc1_opc2 = (instr->Bits(22, 21) << 2) | instr->Bits(6, 5);
3361 if ((opc1_opc2 & 0xB) == 0) {
3362 // NeonS32/NeonU32
3363 uint32_t data[2];
3364 get_d_register(vd, data);
3365 data[instr->Bit(21)] = get_register(rt);
3366 set_d_register(vd, data);
3367 } else {
3368 uint64_t data;
3369 get_d_register(vd, &data);
3370 uint64_t rt_value = get_register(rt);
3371 if ((opc1_opc2 & 0x8) != 0) {
3372 // NeonS8 / NeonU8
3373 int i = opc1_opc2 & 0x7;
3374 int shift = i * kBitsPerByte;
3375 const uint64_t mask = 0xFF;
3376 data &= ~(mask << shift);
3377 data |= (rt_value & mask) << shift;
3378 set_d_register(vd, &data);
3379 } else if ((opc1_opc2 & 0x1) != 0) {
3380 // NeonS16 / NeonU16
3381 int i = (opc1_opc2 >> 1) & 0x3;
3382 int shift = i * kBitsPerByte * kShortSize;
3383 const uint64_t mask = 0xFFFF;
3384 data &= ~(mask << shift);
3385 data |= (rt_value & mask) << shift;
3386 set_d_register(vd, &data);
3387 } else {
3388 UNREACHABLE(); // Not used by V8.
3389 }
3390 }
3391 } else {
3392 // vdup.size Qd, Rt.
3393 NeonSize size = Neon32;
3394 if (instr->Bit(5) != 0)
3395 size = Neon16;
3396 else if (instr->Bit(22) != 0)
3397 size = Neon8;
3398 int vd = instr->VFPNRegValue(kSimd128Precision);
3399 int rt = instr->RtValue();
3400 uint32_t rt_value = get_register(rt);
3401 uint32_t q_data[4];
3402 switch (size) {
3403 case Neon8: {
3404 rt_value &= 0xFF;
3405 uint8_t* dst = reinterpret_cast<uint8_t*>(q_data);
3406 for (int i = 0; i < 16; i++) {
3407 dst[i] = rt_value;
3408 }
3409 break;
3410 }
3411 case Neon16: {
3412 // Perform pairwise op.
3413 rt_value &= 0xFFFFu;
3414 uint32_t rt_rt = (rt_value << 16) | (rt_value & 0xFFFFu);
3415 for (int i = 0; i < 4; i++) {
3416 q_data[i] = rt_rt;
3417 }
3418 break;
3419 }
3420 case Neon32: {
3421 for (int i = 0; i < 4; i++) {
3422 q_data[i] = rt_value;
3423 }
3424 break;
3425 }
3426 default:
3427 UNREACHABLE();
3428 break;
3429 }
3430 set_neon_register(vd, q_data);
3431 }
3432 } else if ((instr->VLValue() == 0x1) && (instr->VCValue() == 0x1)) {
3433 // vmov (scalar to ARM core register)
3434 int vn = instr->VFPNRegValue(kDoublePrecision);
3435 int rt = instr->RtValue();
3436 int opc1_opc2 = (instr->Bits(22, 21) << 2) | instr->Bits(6, 5);
3437 uint64_t data;
3438 get_d_register(vn, &data);
3439 if ((opc1_opc2 & 0xB) == 0) {
3440 // NeonS32 / NeonU32
3441 int32_t int_data[2];
3442 memcpy(int_data, &data, sizeof(int_data));
3443 set_register(rt, int_data[instr->Bit(21)]);
3444 } else {
3445 uint64_t data;
3446 get_d_register(vn, &data);
3447 bool u = instr->Bit(23) != 0;
3448 if ((opc1_opc2 & 0x8) != 0) {
3449 // NeonS8 / NeonU8
3450 int i = opc1_opc2 & 0x7;
3451 int shift = i * kBitsPerByte;
3452 uint32_t scalar = (data >> shift) & 0xFFu;
3453 if (!u && (scalar & 0x80) != 0) scalar |= 0xFFFFFF00;
3454 set_register(rt, scalar);
3455 } else if ((opc1_opc2 & 0x1) != 0) {
3456 // NeonS16 / NeonU16
3457 int i = (opc1_opc2 >> 1) & 0x3;
3458 int shift = i * kBitsPerByte * kShortSize;
3459 uint32_t scalar = (data >> shift) & 0xFFFFu;
3460 if (!u && (scalar & 0x8000) != 0) scalar |= 0xFFFF0000;
3461 set_register(rt, scalar);
3462 } else {
3463 UNREACHABLE(); // Not used by V8.
3464 }
3465 }
3466 } else if ((instr->VLValue() == 0x1) &&
3467 (instr->VCValue() == 0x0) &&
3468 (instr->VAValue() == 0x7) &&
3469 (instr->Bits(19, 16) == 0x1)) {
3470 // vmrs
3471 uint32_t rt = instr->RtValue();
3472 if (rt == 0xF) {
3473 Copy_FPSCR_to_APSR();
3474 } else {
3475 // Emulate FPSCR from the Simulator flags.
3476 uint32_t fpscr = (n_flag_FPSCR_ << 31) |
3477 (z_flag_FPSCR_ << 30) |
3478 (c_flag_FPSCR_ << 29) |
3479 (v_flag_FPSCR_ << 28) |
3480 (FPSCR_default_NaN_mode_ << 25) |
3481 (inexact_vfp_flag_ << 4) |
3482 (underflow_vfp_flag_ << 3) |
3483 (overflow_vfp_flag_ << 2) |
3484 (div_zero_vfp_flag_ << 1) |
3485 (inv_op_vfp_flag_ << 0) |
3486 (FPSCR_rounding_mode_);
3487 set_register(rt, fpscr);
3488 }
3489 } else if ((instr->VLValue() == 0x0) &&
3490 (instr->VCValue() == 0x0) &&
3491 (instr->VAValue() == 0x7) &&
3492 (instr->Bits(19, 16) == 0x1)) {
3493 // vmsr
3494 uint32_t rt = instr->RtValue();
3495 if (rt == pc) {
3496 UNREACHABLE();
3497 } else {
3498 uint32_t rt_value = get_register(rt);
3499 n_flag_FPSCR_ = (rt_value >> 31) & 1;
3500 z_flag_FPSCR_ = (rt_value >> 30) & 1;
3501 c_flag_FPSCR_ = (rt_value >> 29) & 1;
3502 v_flag_FPSCR_ = (rt_value >> 28) & 1;
3503 FPSCR_default_NaN_mode_ = (rt_value >> 25) & 1;
3504 inexact_vfp_flag_ = (rt_value >> 4) & 1;
3505 underflow_vfp_flag_ = (rt_value >> 3) & 1;
3506 overflow_vfp_flag_ = (rt_value >> 2) & 1;
3507 div_zero_vfp_flag_ = (rt_value >> 1) & 1;
3508 inv_op_vfp_flag_ = (rt_value >> 0) & 1;
3509 FPSCR_rounding_mode_ =
3510 static_cast<VFPRoundingMode>((rt_value) & kVFPRoundingModeMask);
3511 }
3512 } else {
3513 UNIMPLEMENTED(); // Not used by V8.
3514 }
3515 }
3516 }
3517
DecodeTypeCP15(Instruction * instr)3518 void Simulator::DecodeTypeCP15(Instruction* instr) {
3519 DCHECK((instr->TypeValue() == 7) && (instr->Bit(24) == 0x0));
3520 DCHECK_EQ(instr->CoprocessorValue(), 15);
3521
3522 if (instr->Bit(4) == 1) {
3523 // mcr
3524 int crn = instr->Bits(19, 16);
3525 int crm = instr->Bits(3, 0);
3526 int opc1 = instr->Bits(23, 21);
3527 int opc2 = instr->Bits(7, 5);
3528 if ((opc1 == 0) && (crn == 7)) {
3529 // ARMv6 memory barrier operations.
3530 // Details available in ARM DDI 0406C.b, B3-1750.
3531 if (((crm == 10) && (opc2 == 5)) || // CP15DMB
3532 ((crm == 10) && (opc2 == 4)) || // CP15DSB
3533 ((crm == 5) && (opc2 == 4))) { // CP15ISB
3534 // These are ignored by the simulator for now.
3535 } else {
3536 UNIMPLEMENTED();
3537 }
3538 }
3539 } else {
3540 UNIMPLEMENTED();
3541 }
3542 }
3543
DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(Instruction * instr)3544 void Simulator::DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(
3545 Instruction* instr) {
3546 DCHECK((instr->Bit(4) == 1) && (instr->VCValue() == 0x0) &&
3547 (instr->VAValue() == 0x0));
3548
3549 int t = instr->RtValue();
3550 int n = instr->VFPNRegValue(kSinglePrecision);
3551 bool to_arm_register = (instr->VLValue() == 0x1);
3552
3553 if (to_arm_register) {
3554 int32_t int_value = get_sinteger_from_s_register(n);
3555 set_register(t, int_value);
3556 } else {
3557 int32_t rs_val = get_register(t);
3558 set_s_register_from_sinteger(n, rs_val);
3559 }
3560 }
3561
3562
DecodeVCMP(Instruction * instr)3563 void Simulator::DecodeVCMP(Instruction* instr) {
3564 DCHECK((instr->Bit(4) == 0) && (instr->Opc1Value() == 0x7));
3565 DCHECK(((instr->Opc2Value() == 0x4) || (instr->Opc2Value() == 0x5)) &&
3566 (instr->Opc3Value() & 0x1));
3567 // Comparison.
3568
3569 VFPRegPrecision precision = kSinglePrecision;
3570 if (instr->SzValue() == 0x1) {
3571 precision = kDoublePrecision;
3572 }
3573
3574 int d = instr->VFPDRegValue(precision);
3575 int m = 0;
3576 if (instr->Opc2Value() == 0x4) {
3577 m = instr->VFPMRegValue(precision);
3578 }
3579
3580 if (precision == kDoublePrecision) {
3581 double dd_value = get_double_from_d_register(d).get_scalar();
3582 double dm_value = 0.0;
3583 if (instr->Opc2Value() == 0x4) {
3584 dm_value = get_double_from_d_register(m).get_scalar();
3585 }
3586
3587 // Raise exceptions for quiet NaNs if necessary.
3588 if (instr->Bit(7) == 1) {
3589 if (std::isnan(dd_value)) {
3590 inv_op_vfp_flag_ = true;
3591 }
3592 }
3593
3594 Compute_FPSCR_Flags(dd_value, dm_value);
3595 } else {
3596 float sd_value = get_float_from_s_register(d).get_scalar();
3597 float sm_value = 0.0;
3598 if (instr->Opc2Value() == 0x4) {
3599 sm_value = get_float_from_s_register(m).get_scalar();
3600 }
3601
3602 // Raise exceptions for quiet NaNs if necessary.
3603 if (instr->Bit(7) == 1) {
3604 if (std::isnan(sd_value)) {
3605 inv_op_vfp_flag_ = true;
3606 }
3607 }
3608
3609 Compute_FPSCR_Flags(sd_value, sm_value);
3610 }
3611 }
3612
3613
DecodeVCVTBetweenDoubleAndSingle(Instruction * instr)3614 void Simulator::DecodeVCVTBetweenDoubleAndSingle(Instruction* instr) {
3615 DCHECK((instr->Bit(4) == 0) && (instr->Opc1Value() == 0x7));
3616 DCHECK((instr->Opc2Value() == 0x7) && (instr->Opc3Value() == 0x3));
3617
3618 VFPRegPrecision dst_precision = kDoublePrecision;
3619 VFPRegPrecision src_precision = kSinglePrecision;
3620 if (instr->SzValue() == 1) {
3621 dst_precision = kSinglePrecision;
3622 src_precision = kDoublePrecision;
3623 }
3624
3625 int dst = instr->VFPDRegValue(dst_precision);
3626 int src = instr->VFPMRegValue(src_precision);
3627
3628 if (dst_precision == kSinglePrecision) {
3629 double val = get_double_from_d_register(src).get_scalar();
3630 set_s_register_from_float(dst, static_cast<float>(val));
3631 } else {
3632 float val = get_float_from_s_register(src).get_scalar();
3633 set_d_register_from_double(dst, static_cast<double>(val));
3634 }
3635 }
3636
get_inv_op_vfp_flag(VFPRoundingMode mode,double val,bool unsigned_)3637 bool get_inv_op_vfp_flag(VFPRoundingMode mode,
3638 double val,
3639 bool unsigned_) {
3640 DCHECK((mode == RN) || (mode == RM) || (mode == RZ));
3641 double max_uint = static_cast<double>(0xFFFFFFFFu);
3642 double max_int = static_cast<double>(kMaxInt);
3643 double min_int = static_cast<double>(kMinInt);
3644
3645 // Check for NaN.
3646 if (val != val) {
3647 return true;
3648 }
3649
3650 // Check for overflow. This code works because 32bit integers can be
3651 // exactly represented by ieee-754 64bit floating-point values.
3652 switch (mode) {
3653 case RN:
3654 return unsigned_ ? (val >= (max_uint + 0.5)) ||
3655 (val < -0.5)
3656 : (val >= (max_int + 0.5)) ||
3657 (val < (min_int - 0.5));
3658
3659 case RM:
3660 return unsigned_ ? (val >= (max_uint + 1.0)) ||
3661 (val < 0)
3662 : (val >= (max_int + 1.0)) ||
3663 (val < min_int);
3664
3665 case RZ:
3666 return unsigned_ ? (val >= (max_uint + 1.0)) ||
3667 (val <= -1)
3668 : (val >= (max_int + 1.0)) ||
3669 (val <= (min_int - 1.0));
3670 default:
3671 UNREACHABLE();
3672 }
3673 }
3674
3675
3676 // We call this function only if we had a vfp invalid exception.
3677 // It returns the correct saturated value.
VFPConversionSaturate(double val,bool unsigned_res)3678 int VFPConversionSaturate(double val, bool unsigned_res) {
3679 if (val != val) {
3680 return 0;
3681 } else {
3682 if (unsigned_res) {
3683 return (val < 0) ? 0 : 0xFFFFFFFFu;
3684 } else {
3685 return (val < 0) ? kMinInt : kMaxInt;
3686 }
3687 }
3688 }
3689
ConvertDoubleToInt(double val,bool unsigned_integer,VFPRoundingMode mode)3690 int32_t Simulator::ConvertDoubleToInt(double val, bool unsigned_integer,
3691 VFPRoundingMode mode) {
3692 // TODO(jkummerow): These casts are undefined behavior if the integral
3693 // part of {val} does not fit into the destination type.
3694 int32_t result =
3695 unsigned_integer ? static_cast<uint32_t>(val) : static_cast<int32_t>(val);
3696
3697 inv_op_vfp_flag_ = get_inv_op_vfp_flag(mode, val, unsigned_integer);
3698
3699 double abs_diff = unsigned_integer
3700 ? std::fabs(val - static_cast<uint32_t>(result))
3701 : std::fabs(val - result);
3702
3703 inexact_vfp_flag_ = (abs_diff != 0);
3704
3705 if (inv_op_vfp_flag_) {
3706 result = VFPConversionSaturate(val, unsigned_integer);
3707 } else {
3708 switch (mode) {
3709 case RN: {
3710 int val_sign = (val > 0) ? 1 : -1;
3711 if (abs_diff > 0.5) {
3712 result += val_sign;
3713 } else if (abs_diff == 0.5) {
3714 // Round to even if exactly halfway.
3715 result = ((result % 2) == 0) ? result : result + val_sign;
3716 }
3717 break;
3718 }
3719
3720 case RM:
3721 result = result > val ? result - 1 : result;
3722 break;
3723
3724 case RZ:
3725 // Nothing to do.
3726 break;
3727
3728 default:
3729 UNREACHABLE();
3730 }
3731 }
3732 return result;
3733 }
3734
DecodeVCVTBetweenFloatingPointAndInteger(Instruction * instr)3735 void Simulator::DecodeVCVTBetweenFloatingPointAndInteger(Instruction* instr) {
3736 DCHECK((instr->Bit(4) == 0) && (instr->Opc1Value() == 0x7) &&
3737 (instr->Bits(27, 23) == 0x1D));
3738 DCHECK(((instr->Opc2Value() == 0x8) && (instr->Opc3Value() & 0x1)) ||
3739 (((instr->Opc2Value() >> 1) == 0x6) && (instr->Opc3Value() & 0x1)));
3740
3741 // Conversion between floating-point and integer.
3742 bool to_integer = (instr->Bit(18) == 1);
3743
3744 VFPRegPrecision src_precision = (instr->SzValue() == 1) ? kDoublePrecision
3745 : kSinglePrecision;
3746
3747 if (to_integer) {
3748 // We are playing with code close to the C++ standard's limits below,
3749 // hence the very simple code and heavy checks.
3750 //
3751 // Note:
3752 // C++ defines default type casting from floating point to integer as
3753 // (close to) rounding toward zero ("fractional part discarded").
3754
3755 int dst = instr->VFPDRegValue(kSinglePrecision);
3756 int src = instr->VFPMRegValue(src_precision);
3757
3758 // Bit 7 in vcvt instructions indicates if we should use the FPSCR rounding
3759 // mode or the default Round to Zero mode.
3760 VFPRoundingMode mode = (instr->Bit(7) != 1) ? FPSCR_rounding_mode_
3761 : RZ;
3762 DCHECK((mode == RM) || (mode == RZ) || (mode == RN));
3763
3764 bool unsigned_integer = (instr->Bit(16) == 0);
3765 bool double_precision = (src_precision == kDoublePrecision);
3766
3767 double val = double_precision ? get_double_from_d_register(src).get_scalar()
3768 : get_float_from_s_register(src).get_scalar();
3769
3770 int32_t temp = ConvertDoubleToInt(val, unsigned_integer, mode);
3771
3772 // Update the destination register.
3773 set_s_register_from_sinteger(dst, temp);
3774
3775 } else {
3776 bool unsigned_integer = (instr->Bit(7) == 0);
3777
3778 int dst = instr->VFPDRegValue(src_precision);
3779 int src = instr->VFPMRegValue(kSinglePrecision);
3780
3781 int val = get_sinteger_from_s_register(src);
3782
3783 if (src_precision == kDoublePrecision) {
3784 if (unsigned_integer) {
3785 set_d_register_from_double(
3786 dst, static_cast<double>(static_cast<uint32_t>(val)));
3787 } else {
3788 set_d_register_from_double(dst, static_cast<double>(val));
3789 }
3790 } else {
3791 if (unsigned_integer) {
3792 set_s_register_from_float(
3793 dst, static_cast<float>(static_cast<uint32_t>(val)));
3794 } else {
3795 set_s_register_from_float(dst, static_cast<float>(val));
3796 }
3797 }
3798 }
3799 }
3800
3801
3802 // void Simulator::DecodeType6CoprocessorIns(Instruction* instr)
3803 // Decode Type 6 coprocessor instructions.
3804 // Dm = vmov(Rt, Rt2)
3805 // <Rt, Rt2> = vmov(Dm)
3806 // Ddst = MEM(Rbase + 4*offset).
3807 // MEM(Rbase + 4*offset) = Dsrc.
DecodeType6CoprocessorIns(Instruction * instr)3808 void Simulator::DecodeType6CoprocessorIns(Instruction* instr) {
3809 DCHECK_EQ(instr->TypeValue(), 6);
3810
3811 if (instr->CoprocessorValue() == 0xA) {
3812 switch (instr->OpcodeValue()) {
3813 case 0x8:
3814 case 0xA:
3815 case 0xC:
3816 case 0xE: { // Load and store single precision float to memory.
3817 int rn = instr->RnValue();
3818 int vd = instr->VFPDRegValue(kSinglePrecision);
3819 int offset = instr->Immed8Value();
3820 if (!instr->HasU()) {
3821 offset = -offset;
3822 }
3823
3824 int32_t address = get_register(rn) + 4 * offset;
3825 // Load and store address for singles must be at least four-byte
3826 // aligned.
3827 DCHECK_EQ(address % 4, 0);
3828 if (instr->HasL()) {
3829 // Load single from memory: vldr.
3830 set_s_register_from_sinteger(vd, ReadW(address));
3831 } else {
3832 // Store single to memory: vstr.
3833 WriteW(address, get_sinteger_from_s_register(vd));
3834 }
3835 break;
3836 }
3837 case 0x4:
3838 case 0x5:
3839 case 0x6:
3840 case 0x7:
3841 case 0x9:
3842 case 0xB:
3843 // Load/store multiple single from memory: vldm/vstm.
3844 HandleVList(instr);
3845 break;
3846 default:
3847 UNIMPLEMENTED(); // Not used by V8.
3848 }
3849 } else if (instr->CoprocessorValue() == 0xB) {
3850 switch (instr->OpcodeValue()) {
3851 case 0x2:
3852 // Load and store double to two GP registers
3853 if (instr->Bits(7, 6) != 0 || instr->Bit(4) != 1) {
3854 UNIMPLEMENTED(); // Not used by V8.
3855 } else {
3856 int rt = instr->RtValue();
3857 int rn = instr->RnValue();
3858 int vm = instr->VFPMRegValue(kDoublePrecision);
3859 if (instr->HasL()) {
3860 uint32_t data[2];
3861 get_d_register(vm, data);
3862 set_register(rt, data[0]);
3863 set_register(rn, data[1]);
3864 } else {
3865 int32_t data[] = { get_register(rt), get_register(rn) };
3866 set_d_register(vm, reinterpret_cast<uint32_t*>(data));
3867 }
3868 }
3869 break;
3870 case 0x8:
3871 case 0xA:
3872 case 0xC:
3873 case 0xE: { // Load and store double to memory.
3874 int rn = instr->RnValue();
3875 int vd = instr->VFPDRegValue(kDoublePrecision);
3876 int offset = instr->Immed8Value();
3877 if (!instr->HasU()) {
3878 offset = -offset;
3879 }
3880 int32_t address = get_register(rn) + 4 * offset;
3881 // Load and store address for doubles must be at least four-byte
3882 // aligned.
3883 DCHECK_EQ(address % 4, 0);
3884 if (instr->HasL()) {
3885 // Load double from memory: vldr.
3886 int32_t data[] = {ReadW(address), ReadW(address + 4)};
3887 set_d_register(vd, reinterpret_cast<uint32_t*>(data));
3888 } else {
3889 // Store double to memory: vstr.
3890 uint32_t data[2];
3891 get_d_register(vd, data);
3892 WriteW(address, data[0]);
3893 WriteW(address + 4, data[1]);
3894 }
3895 break;
3896 }
3897 case 0x4:
3898 case 0x5:
3899 case 0x6:
3900 case 0x7:
3901 case 0x9:
3902 case 0xB:
3903 // Load/store multiple double from memory: vldm/vstm.
3904 HandleVList(instr);
3905 break;
3906 default:
3907 UNIMPLEMENTED(); // Not used by V8.
3908 }
3909 } else {
3910 UNIMPLEMENTED(); // Not used by V8.
3911 }
3912 }
3913
3914 // Templated operations for NEON instructions.
3915 template <typename T, typename U>
Widen(T value)3916 U Widen(T value) {
3917 static_assert(sizeof(int64_t) > sizeof(T), "T must be int32_t or smaller");
3918 static_assert(sizeof(U) > sizeof(T), "T must smaller than U");
3919 return static_cast<U>(value);
3920 }
3921
3922 template <typename T, typename U>
Narrow(T value)3923 U Narrow(T value) {
3924 static_assert(sizeof(int8_t) < sizeof(T), "T must be int16_t or larger");
3925 static_assert(sizeof(U) < sizeof(T), "T must larger than U");
3926 static_assert(std::is_unsigned<T>() == std::is_unsigned<U>(),
3927 "Signed-ness of T and U must match");
3928 // Make sure value can be expressed in the smaller type; otherwise, the
3929 // casted result is implementation defined.
3930 DCHECK_LE(std::numeric_limits<T>::min(), value);
3931 DCHECK_GE(std::numeric_limits<T>::max(), value);
3932 return static_cast<U>(value);
3933 }
3934
3935 template <typename T>
Clamp(int64_t value)3936 T Clamp(int64_t value) {
3937 static_assert(sizeof(int64_t) > sizeof(T), "T must be int32_t or smaller");
3938 int64_t min = static_cast<int64_t>(std::numeric_limits<T>::min());
3939 int64_t max = static_cast<int64_t>(std::numeric_limits<T>::max());
3940 int64_t clamped = std::max(min, std::min(max, value));
3941 return static_cast<T>(clamped);
3942 }
3943
3944 template <typename T, typename U>
Widen(Simulator * simulator,int Vd,int Vm)3945 void Widen(Simulator* simulator, int Vd, int Vm) {
3946 static const int kLanes = 8 / sizeof(T);
3947 T src[kLanes];
3948 U dst[kLanes];
3949 simulator->get_neon_register<T, kDoubleSize>(Vm, src);
3950 for (int i = 0; i < kLanes; i++) {
3951 dst[i] = Widen<T, U>(src[i]);
3952 }
3953 simulator->set_neon_register(Vd, dst);
3954 }
3955
3956 template <typename T, int SIZE>
Abs(Simulator * simulator,int Vd,int Vm)3957 void Abs(Simulator* simulator, int Vd, int Vm) {
3958 static const int kElems = SIZE / sizeof(T);
3959 T src[kElems];
3960 simulator->get_neon_register<T, SIZE>(Vm, src);
3961 for (int i = 0; i < kElems; i++) {
3962 src[i] = std::abs(src[i]);
3963 }
3964 simulator->set_neon_register<T, SIZE>(Vd, src);
3965 }
3966
3967 template <typename T, int SIZE>
Neg(Simulator * simulator,int Vd,int Vm)3968 void Neg(Simulator* simulator, int Vd, int Vm) {
3969 static const int kElems = SIZE / sizeof(T);
3970 T src[kElems];
3971 simulator->get_neon_register<T, SIZE>(Vm, src);
3972 for (int i = 0; i < kElems; i++) {
3973 src[i] = -src[i];
3974 }
3975 simulator->set_neon_register<T, SIZE>(Vd, src);
3976 }
3977
3978 template <typename T, typename U>
SaturatingNarrow(Simulator * simulator,int Vd,int Vm)3979 void SaturatingNarrow(Simulator* simulator, int Vd, int Vm) {
3980 static const int kLanes = 16 / sizeof(T);
3981 T src[kLanes];
3982 U dst[kLanes];
3983 simulator->get_neon_register(Vm, src);
3984 for (int i = 0; i < kLanes; i++) {
3985 dst[i] = Narrow<T, U>(Clamp<U>(src[i]));
3986 }
3987 simulator->set_neon_register<U, kDoubleSize>(Vd, dst);
3988 }
3989
3990 template <typename T>
AddSaturate(Simulator * simulator,int Vd,int Vm,int Vn)3991 void AddSaturate(Simulator* simulator, int Vd, int Vm, int Vn) {
3992 static const int kLanes = 16 / sizeof(T);
3993 T src1[kLanes], src2[kLanes];
3994 simulator->get_neon_register(Vn, src1);
3995 simulator->get_neon_register(Vm, src2);
3996 for (int i = 0; i < kLanes; i++) {
3997 src1[i] = Clamp<T>(Widen<T, int64_t>(src1[i]) + Widen<T, int64_t>(src2[i]));
3998 }
3999 simulator->set_neon_register(Vd, src1);
4000 }
4001
4002 template <typename T>
SubSaturate(Simulator * simulator,int Vd,int Vm,int Vn)4003 void SubSaturate(Simulator* simulator, int Vd, int Vm, int Vn) {
4004 static const int kLanes = 16 / sizeof(T);
4005 T src1[kLanes], src2[kLanes];
4006 simulator->get_neon_register(Vn, src1);
4007 simulator->get_neon_register(Vm, src2);
4008 for (int i = 0; i < kLanes; i++) {
4009 src1[i] = Clamp<T>(Widen<T, int64_t>(src1[i]) - Widen<T, int64_t>(src2[i]));
4010 }
4011 simulator->set_neon_register(Vd, src1);
4012 }
4013
4014 template <typename T, int SIZE>
Zip(Simulator * simulator,int Vd,int Vm)4015 void Zip(Simulator* simulator, int Vd, int Vm) {
4016 static const int kElems = SIZE / sizeof(T);
4017 static const int kPairs = kElems / 2;
4018 T src1[kElems], src2[kElems], dst1[kElems], dst2[kElems];
4019 simulator->get_neon_register<T, SIZE>(Vd, src1);
4020 simulator->get_neon_register<T, SIZE>(Vm, src2);
4021 for (int i = 0; i < kPairs; i++) {
4022 dst1[i * 2] = src1[i];
4023 dst1[i * 2 + 1] = src2[i];
4024 dst2[i * 2] = src1[i + kPairs];
4025 dst2[i * 2 + 1] = src2[i + kPairs];
4026 }
4027 simulator->set_neon_register<T, SIZE>(Vd, dst1);
4028 simulator->set_neon_register<T, SIZE>(Vm, dst2);
4029 }
4030
4031 template <typename T, int SIZE>
Unzip(Simulator * simulator,int Vd,int Vm)4032 void Unzip(Simulator* simulator, int Vd, int Vm) {
4033 static const int kElems = SIZE / sizeof(T);
4034 static const int kPairs = kElems / 2;
4035 T src1[kElems], src2[kElems], dst1[kElems], dst2[kElems];
4036 simulator->get_neon_register<T, SIZE>(Vd, src1);
4037 simulator->get_neon_register<T, SIZE>(Vm, src2);
4038 for (int i = 0; i < kPairs; i++) {
4039 dst1[i] = src1[i * 2];
4040 dst1[i + kPairs] = src2[i * 2];
4041 dst2[i] = src1[i * 2 + 1];
4042 dst2[i + kPairs] = src2[i * 2 + 1];
4043 }
4044 simulator->set_neon_register<T, SIZE>(Vd, dst1);
4045 simulator->set_neon_register<T, SIZE>(Vm, dst2);
4046 }
4047
4048 template <typename T, int SIZE>
Transpose(Simulator * simulator,int Vd,int Vm)4049 void Transpose(Simulator* simulator, int Vd, int Vm) {
4050 static const int kElems = SIZE / sizeof(T);
4051 static const int kPairs = kElems / 2;
4052 T src1[kElems], src2[kElems];
4053 simulator->get_neon_register<T, SIZE>(Vd, src1);
4054 simulator->get_neon_register<T, SIZE>(Vm, src2);
4055 for (int i = 0; i < kPairs; i++) {
4056 std::swap(src1[2 * i + 1], src2[2 * i]);
4057 }
4058 simulator->set_neon_register<T, SIZE>(Vd, src1);
4059 simulator->set_neon_register<T, SIZE>(Vm, src2);
4060 }
4061
4062 template <typename T, int SIZE>
Test(Simulator * simulator,int Vd,int Vm,int Vn)4063 void Test(Simulator* simulator, int Vd, int Vm, int Vn) {
4064 static const int kElems = SIZE / sizeof(T);
4065 T src1[kElems], src2[kElems];
4066 simulator->get_neon_register<T, SIZE>(Vn, src1);
4067 simulator->get_neon_register<T, SIZE>(Vm, src2);
4068 for (int i = 0; i < kElems; i++) {
4069 src1[i] = (src1[i] & src2[i]) != 0 ? -1 : 0;
4070 }
4071 simulator->set_neon_register<T, SIZE>(Vd, src1);
4072 }
4073
4074 template <typename T, int SIZE>
Add(Simulator * simulator,int Vd,int Vm,int Vn)4075 void Add(Simulator* simulator, int Vd, int Vm, int Vn) {
4076 static const int kElems = SIZE / sizeof(T);
4077 T src1[kElems], src2[kElems];
4078 simulator->get_neon_register<T, SIZE>(Vn, src1);
4079 simulator->get_neon_register<T, SIZE>(Vm, src2);
4080 for (int i = 0; i < kElems; i++) {
4081 src1[i] += src2[i];
4082 }
4083 simulator->set_neon_register<T, SIZE>(Vd, src1);
4084 }
4085
4086 template <typename T, int SIZE>
Sub(Simulator * simulator,int Vd,int Vm,int Vn)4087 void Sub(Simulator* simulator, int Vd, int Vm, int Vn) {
4088 static const int kElems = SIZE / sizeof(T);
4089 T src1[kElems], src2[kElems];
4090 simulator->get_neon_register<T, SIZE>(Vn, src1);
4091 simulator->get_neon_register<T, SIZE>(Vm, src2);
4092 for (int i = 0; i < kElems; i++) {
4093 src1[i] -= src2[i];
4094 }
4095 simulator->set_neon_register<T, SIZE>(Vd, src1);
4096 }
4097
4098 template <typename T, int SIZE>
Mul(Simulator * simulator,int Vd,int Vm,int Vn)4099 void Mul(Simulator* simulator, int Vd, int Vm, int Vn) {
4100 static const int kElems = SIZE / sizeof(T);
4101 T src1[kElems], src2[kElems];
4102 simulator->get_neon_register<T, SIZE>(Vn, src1);
4103 simulator->get_neon_register<T, SIZE>(Vm, src2);
4104 for (int i = 0; i < kElems; i++) {
4105 src1[i] *= src2[i];
4106 }
4107 simulator->set_neon_register<T, SIZE>(Vd, src1);
4108 }
4109
4110 template <typename T, int SIZE>
ShiftLeft(Simulator * simulator,int Vd,int Vm,int shift)4111 void ShiftLeft(Simulator* simulator, int Vd, int Vm, int shift) {
4112 static const int kElems = SIZE / sizeof(T);
4113 T src[kElems];
4114 simulator->get_neon_register<T, SIZE>(Vm, src);
4115 for (int i = 0; i < kElems; i++) {
4116 src[i] <<= shift;
4117 }
4118 simulator->set_neon_register<T, SIZE>(Vd, src);
4119 }
4120
4121 template <typename T, int SIZE>
ShiftRight(Simulator * simulator,int Vd,int Vm,int shift)4122 void ShiftRight(Simulator* simulator, int Vd, int Vm, int shift) {
4123 static const int kElems = SIZE / sizeof(T);
4124 T src[kElems];
4125 simulator->get_neon_register<T, SIZE>(Vm, src);
4126 for (int i = 0; i < kElems; i++) {
4127 src[i] >>= shift;
4128 }
4129 simulator->set_neon_register<T, SIZE>(Vd, src);
4130 }
4131
4132 template <typename T, int SIZE>
ArithmeticShiftRight(Simulator * simulator,int Vd,int Vm,int shift)4133 void ArithmeticShiftRight(Simulator* simulator, int Vd, int Vm, int shift) {
4134 static const int kElems = SIZE / sizeof(T);
4135 T src[kElems];
4136 simulator->get_neon_register<T, SIZE>(Vm, src);
4137 for (int i = 0; i < kElems; i++) {
4138 src[i] = ArithmeticShiftRight(src[i], shift);
4139 }
4140 simulator->set_neon_register<T, SIZE>(Vd, src);
4141 }
4142
4143 template <typename T, int SIZE>
ShiftLeftAndInsert(Simulator * simulator,int Vd,int Vm,int shift)4144 void ShiftLeftAndInsert(Simulator* simulator, int Vd, int Vm, int shift) {
4145 static const int kElems = SIZE / sizeof(T);
4146 T src[kElems];
4147 T dst[kElems];
4148 simulator->get_neon_register<T, SIZE>(Vm, src);
4149 simulator->get_neon_register<T, SIZE>(Vd, dst);
4150 uint64_t mask = (1llu << shift) - 1llu;
4151 for (int i = 0; i < kElems; i++) {
4152 dst[i] = (src[i] << shift) | (dst[i] & mask);
4153 }
4154 simulator->set_neon_register<T, SIZE>(Vd, dst);
4155 }
4156
4157 template <typename T, int SIZE>
ShiftRightAndInsert(Simulator * simulator,int Vd,int Vm,int shift)4158 void ShiftRightAndInsert(Simulator* simulator, int Vd, int Vm, int shift) {
4159 static const int kElems = SIZE / sizeof(T);
4160 T src[kElems];
4161 T dst[kElems];
4162 simulator->get_neon_register<T, SIZE>(Vm, src);
4163 simulator->get_neon_register<T, SIZE>(Vd, dst);
4164 uint64_t mask = ~((1llu << (kBitsPerByte * SIZE - shift)) - 1llu);
4165 for (int i = 0; i < kElems; i++) {
4166 dst[i] = (src[i] >> shift) | (dst[i] & mask);
4167 }
4168 simulator->set_neon_register<T, SIZE>(Vd, dst);
4169 }
4170
4171 template <typename T, int SIZE>
CompareEqual(Simulator * simulator,int Vd,int Vm,int Vn)4172 void CompareEqual(Simulator* simulator, int Vd, int Vm, int Vn) {
4173 static const int kElems = SIZE / sizeof(T);
4174 T src1[kElems], src2[kElems];
4175 simulator->get_neon_register<T, SIZE>(Vn, src1);
4176 simulator->get_neon_register<T, SIZE>(Vm, src2);
4177 for (int i = 0; i < kElems; i++) {
4178 src1[i] = src1[i] == src2[i] ? -1 : 0;
4179 }
4180 simulator->set_neon_register<T, SIZE>(Vd, src1);
4181 }
4182
4183 template <typename T, int SIZE>
CompareGreater(Simulator * simulator,int Vd,int Vm,int Vn,bool ge)4184 void CompareGreater(Simulator* simulator, int Vd, int Vm, int Vn, bool ge) {
4185 static const int kElems = SIZE / sizeof(T);
4186 T src1[kElems], src2[kElems];
4187 simulator->get_neon_register<T, SIZE>(Vn, src1);
4188 simulator->get_neon_register<T, SIZE>(Vm, src2);
4189 for (int i = 0; i < kElems; i++) {
4190 if (ge)
4191 src1[i] = src1[i] >= src2[i] ? -1 : 0;
4192 else
4193 src1[i] = src1[i] > src2[i] ? -1 : 0;
4194 }
4195 simulator->set_neon_register<T, SIZE>(Vd, src1);
4196 }
4197
4198 template <typename T>
MinMax(T a,T b,bool is_min)4199 T MinMax(T a, T b, bool is_min) {
4200 return is_min ? std::min(a, b) : std::max(a, b);
4201 }
4202
4203 template <typename T, int SIZE>
MinMax(Simulator * simulator,int Vd,int Vm,int Vn,bool min)4204 void MinMax(Simulator* simulator, int Vd, int Vm, int Vn, bool min) {
4205 static const int kElems = SIZE / sizeof(T);
4206 T src1[kElems], src2[kElems];
4207 simulator->get_neon_register<T, SIZE>(Vn, src1);
4208 simulator->get_neon_register<T, SIZE>(Vm, src2);
4209 for (int i = 0; i < kElems; i++) {
4210 src1[i] = MinMax(src1[i], src2[i], min);
4211 }
4212 simulator->set_neon_register<T, SIZE>(Vd, src1);
4213 }
4214
4215 template <typename T>
PairwiseMinMax(Simulator * simulator,int Vd,int Vm,int Vn,bool min)4216 void PairwiseMinMax(Simulator* simulator, int Vd, int Vm, int Vn, bool min) {
4217 static const int kElems = kDoubleSize / sizeof(T);
4218 static const int kPairs = kElems / 2;
4219 T dst[kElems], src1[kElems], src2[kElems];
4220 simulator->get_neon_register<T, kDoubleSize>(Vn, src1);
4221 simulator->get_neon_register<T, kDoubleSize>(Vm, src2);
4222 for (int i = 0; i < kPairs; i++) {
4223 dst[i] = MinMax(src1[i * 2], src1[i * 2 + 1], min);
4224 dst[i + kPairs] = MinMax(src2[i * 2], src2[i * 2 + 1], min);
4225 }
4226 simulator->set_neon_register<T, kDoubleSize>(Vd, dst);
4227 }
4228
4229 template <typename T>
PairwiseAdd(Simulator * simulator,int Vd,int Vm,int Vn)4230 void PairwiseAdd(Simulator* simulator, int Vd, int Vm, int Vn) {
4231 static const int kElems = kDoubleSize / sizeof(T);
4232 static const int kPairs = kElems / 2;
4233 T dst[kElems], src1[kElems], src2[kElems];
4234 simulator->get_neon_register<T, kDoubleSize>(Vn, src1);
4235 simulator->get_neon_register<T, kDoubleSize>(Vm, src2);
4236 for (int i = 0; i < kPairs; i++) {
4237 dst[i] = src1[i * 2] + src1[i * 2 + 1];
4238 dst[i + kPairs] = src2[i * 2] + src2[i * 2 + 1];
4239 }
4240 simulator->set_neon_register<T, kDoubleSize>(Vd, dst);
4241 }
4242
DecodeSpecialCondition(Instruction * instr)4243 void Simulator::DecodeSpecialCondition(Instruction* instr) {
4244 switch (instr->SpecialValue()) {
4245 case 4: {
4246 int Vd, Vm, Vn;
4247 if (instr->Bit(6) == 0) {
4248 Vd = instr->VFPDRegValue(kDoublePrecision);
4249 Vm = instr->VFPMRegValue(kDoublePrecision);
4250 Vn = instr->VFPNRegValue(kDoublePrecision);
4251 } else {
4252 Vd = instr->VFPDRegValue(kSimd128Precision);
4253 Vm = instr->VFPMRegValue(kSimd128Precision);
4254 Vn = instr->VFPNRegValue(kSimd128Precision);
4255 }
4256 switch (instr->Bits(11, 8)) {
4257 case 0x0: {
4258 if (instr->Bit(4) == 1) {
4259 // vqadd.s<size> Qd, Qm, Qn.
4260 NeonSize size = static_cast<NeonSize>(instr->Bits(21, 20));
4261 switch (size) {
4262 case Neon8:
4263 AddSaturate<int8_t>(this, Vd, Vm, Vn);
4264 break;
4265 case Neon16:
4266 AddSaturate<int16_t>(this, Vd, Vm, Vn);
4267 break;
4268 case Neon32:
4269 AddSaturate<int32_t>(this, Vd, Vm, Vn);
4270 break;
4271 default:
4272 UNREACHABLE();
4273 break;
4274 }
4275 } else {
4276 UNIMPLEMENTED();
4277 }
4278 break;
4279 }
4280 case 0x1: {
4281 if (instr->Bits(21, 20) == 2 && instr->Bit(6) == 1 &&
4282 instr->Bit(4) == 1) {
4283 // vmov Qd, Qm.
4284 // vorr, Qd, Qm, Qn.
4285 uint32_t src1[4];
4286 get_neon_register(Vm, src1);
4287 if (Vm != Vn) {
4288 uint32_t src2[4];
4289 get_neon_register(Vn, src2);
4290 for (int i = 0; i < 4; i++) {
4291 src1[i] = src1[i] | src2[i];
4292 }
4293 }
4294 set_neon_register(Vd, src1);
4295 } else if (instr->Bits(21, 20) == 0 && instr->Bit(6) == 1 &&
4296 instr->Bit(4) == 1) {
4297 // vand Qd, Qm, Qn.
4298 uint32_t src1[4], src2[4];
4299 get_neon_register(Vn, src1);
4300 get_neon_register(Vm, src2);
4301 for (int i = 0; i < 4; i++) {
4302 src1[i] = src1[i] & src2[i];
4303 }
4304 set_neon_register(Vd, src1);
4305 } else {
4306 UNIMPLEMENTED();
4307 }
4308 break;
4309 }
4310 case 0x2: {
4311 if (instr->Bit(4) == 1) {
4312 // vqsub.s<size> Qd, Qm, Qn.
4313 NeonSize size = static_cast<NeonSize>(instr->Bits(21, 20));
4314 switch (size) {
4315 case Neon8:
4316 SubSaturate<int8_t>(this, Vd, Vm, Vn);
4317 break;
4318 case Neon16:
4319 SubSaturate<int16_t>(this, Vd, Vm, Vn);
4320 break;
4321 case Neon32:
4322 SubSaturate<int32_t>(this, Vd, Vm, Vn);
4323 break;
4324 default:
4325 UNREACHABLE();
4326 break;
4327 }
4328 } else {
4329 UNIMPLEMENTED();
4330 }
4331 break;
4332 }
4333 case 0x3: {
4334 // vcge/vcgt.s<size> Qd, Qm, Qn.
4335 bool ge = instr->Bit(4) == 1;
4336 NeonSize size = static_cast<NeonSize>(instr->Bits(21, 20));
4337 switch (size) {
4338 case Neon8:
4339 CompareGreater<int8_t, kSimd128Size>(this, Vd, Vm, Vn, ge);
4340 break;
4341 case Neon16:
4342 CompareGreater<int16_t, kSimd128Size>(this, Vd, Vm, Vn, ge);
4343 break;
4344 case Neon32:
4345 CompareGreater<int32_t, kSimd128Size>(this, Vd, Vm, Vn, ge);
4346 break;
4347 default:
4348 UNREACHABLE();
4349 break;
4350 }
4351 break;
4352 }
4353 case 0x6: {
4354 // vmin/vmax.s<size> Qd, Qm, Qn.
4355 NeonSize size = static_cast<NeonSize>(instr->Bits(21, 20));
4356 bool min = instr->Bit(4) != 0;
4357 switch (size) {
4358 case Neon8:
4359 MinMax<int8_t, kSimd128Size>(this, Vd, Vm, Vn, min);
4360 break;
4361 case Neon16:
4362 MinMax<int16_t, kSimd128Size>(this, Vd, Vm, Vn, min);
4363 break;
4364 case Neon32:
4365 MinMax<int32_t, kSimd128Size>(this, Vd, Vm, Vn, min);
4366 break;
4367 default:
4368 UNREACHABLE();
4369 break;
4370 }
4371 break;
4372 }
4373 case 0x8: {
4374 // vadd/vtst
4375 NeonSize size = static_cast<NeonSize>(instr->Bits(21, 20));
4376 if (instr->Bit(4) == 0) {
4377 // vadd.i<size> Qd, Qm, Qn.
4378 switch (size) {
4379 case Neon8:
4380 Add<uint8_t, kSimd128Size>(this, Vd, Vm, Vn);
4381 break;
4382 case Neon16:
4383 Add<uint16_t, kSimd128Size>(this, Vd, Vm, Vn);
4384 break;
4385 case Neon32:
4386 Add<uint32_t, kSimd128Size>(this, Vd, Vm, Vn);
4387 break;
4388 default:
4389 UNREACHABLE();
4390 break;
4391 }
4392 } else {
4393 // vtst.i<size> Qd, Qm, Qn.
4394 switch (size) {
4395 case Neon8:
4396 Test<uint8_t, kSimd128Size>(this, Vd, Vm, Vn);
4397 break;
4398 case Neon16:
4399 Test<uint16_t, kSimd128Size>(this, Vd, Vm, Vn);
4400 break;
4401 case Neon32:
4402 Test<uint32_t, kSimd128Size>(this, Vd, Vm, Vn);
4403 break;
4404 default:
4405 UNREACHABLE();
4406 break;
4407 }
4408 }
4409 break;
4410 }
4411 case 0x9: {
4412 if (instr->Bit(6) == 1 && instr->Bit(4) == 1) {
4413 // vmul.i<size> Qd, Qm, Qn.
4414 NeonSize size = static_cast<NeonSize>(instr->Bits(21, 20));
4415 switch (size) {
4416 case Neon8:
4417 Mul<uint8_t, kSimd128Size>(this, Vd, Vm, Vn);
4418 break;
4419 case Neon16:
4420 Mul<uint16_t, kSimd128Size>(this, Vd, Vm, Vn);
4421 break;
4422 case Neon32:
4423 Mul<uint32_t, kSimd128Size>(this, Vd, Vm, Vn);
4424 break;
4425 default:
4426 UNREACHABLE();
4427 break;
4428 }
4429 } else {
4430 UNIMPLEMENTED();
4431 }
4432 break;
4433 }
4434 case 0xA: {
4435 // vpmin/vpmax.s<size> Dd, Dm, Dn.
4436 NeonSize size = static_cast<NeonSize>(instr->Bits(21, 20));
4437 bool min = instr->Bit(4) != 0;
4438 switch (size) {
4439 case Neon8:
4440 PairwiseMinMax<int8_t>(this, Vd, Vm, Vn, min);
4441 break;
4442 case Neon16:
4443 PairwiseMinMax<int16_t>(this, Vd, Vm, Vn, min);
4444 break;
4445 case Neon32:
4446 PairwiseMinMax<int32_t>(this, Vd, Vm, Vn, min);
4447 break;
4448 default:
4449 UNREACHABLE();
4450 break;
4451 }
4452 break;
4453 }
4454 case 0xB: {
4455 // vpadd.i<size> Dd, Dm, Dn.
4456 NeonSize size = static_cast<NeonSize>(instr->Bits(21, 20));
4457 switch (size) {
4458 case Neon8:
4459 PairwiseAdd<int8_t>(this, Vd, Vm, Vn);
4460 break;
4461 case Neon16:
4462 PairwiseAdd<int16_t>(this, Vd, Vm, Vn);
4463 break;
4464 case Neon32:
4465 PairwiseAdd<int32_t>(this, Vd, Vm, Vn);
4466 break;
4467 default:
4468 UNREACHABLE();
4469 break;
4470 }
4471 break;
4472 }
4473 case 0xD: {
4474 if (instr->Bit(4) == 0) {
4475 float src1[4], src2[4];
4476 get_neon_register(Vn, src1);
4477 get_neon_register(Vm, src2);
4478 for (int i = 0; i < 4; i++) {
4479 if (instr->Bit(21) == 0) {
4480 // vadd.f32 Qd, Qm, Qn.
4481 src1[i] = src1[i] + src2[i];
4482 } else {
4483 // vsub.f32 Qd, Qm, Qn.
4484 src1[i] = src1[i] - src2[i];
4485 }
4486 }
4487 set_neon_register(Vd, src1);
4488 } else {
4489 UNIMPLEMENTED();
4490 }
4491 break;
4492 }
4493 case 0xE: {
4494 if (instr->Bits(21, 20) == 0 && instr->Bit(4) == 0) {
4495 // vceq.f32.
4496 float src1[4], src2[4];
4497 get_neon_register(Vn, src1);
4498 get_neon_register(Vm, src2);
4499 uint32_t dst[4];
4500 for (int i = 0; i < 4; i++) {
4501 dst[i] = (src1[i] == src2[i]) ? 0xFFFFFFFF : 0;
4502 }
4503 set_neon_register(Vd, dst);
4504 } else {
4505 UNIMPLEMENTED();
4506 }
4507 break;
4508 }
4509 case 0xF: {
4510 if (instr->Bit(20) == 0 && instr->Bit(6) == 1) {
4511 float src1[4], src2[4];
4512 get_neon_register(Vn, src1);
4513 get_neon_register(Vm, src2);
4514 if (instr->Bit(4) == 1) {
4515 if (instr->Bit(21) == 0) {
4516 // vrecps.f32 Qd, Qm, Qn.
4517 for (int i = 0; i < 4; i++) {
4518 src1[i] = 2.0f - src1[i] * src2[i];
4519 }
4520 } else {
4521 // vrsqrts.f32 Qd, Qm, Qn.
4522 for (int i = 0; i < 4; i++) {
4523 src1[i] = (3.0f - src1[i] * src2[i]) * 0.5f;
4524 }
4525 }
4526 } else {
4527 // vmin/vmax.f32 Qd, Qm, Qn.
4528 bool min = instr->Bit(21) == 1;
4529 for (int i = 0; i < 4; i++) {
4530 src1[i] = MinMax(src1[i], src2[i], min);
4531 }
4532 }
4533 set_neon_register(Vd, src1);
4534 } else {
4535 UNIMPLEMENTED();
4536 }
4537 break;
4538 }
4539 default:
4540 UNIMPLEMENTED();
4541 break;
4542 }
4543 break;
4544 }
4545 case 5:
4546 if ((instr->Bits(18, 16) == 0) && (instr->Bits(11, 6) == 0x28) &&
4547 (instr->Bit(4) == 1)) {
4548 // vmovl signed
4549 if ((instr->VdValue() & 1) != 0) UNIMPLEMENTED();
4550 int Vd = instr->VFPDRegValue(kSimd128Precision);
4551 int Vm = instr->VFPMRegValue(kDoublePrecision);
4552 int imm3 = instr->Bits(21, 19);
4553 switch (imm3) {
4554 case 1:
4555 Widen<int8_t, int16_t>(this, Vd, Vm);
4556 break;
4557 case 2:
4558 Widen<int16_t, int32_t>(this, Vd, Vm);
4559 break;
4560 case 4:
4561 Widen<int32_t, int64_t>(this, Vd, Vm);
4562 break;
4563 default:
4564 UNIMPLEMENTED();
4565 break;
4566 }
4567 } else if (instr->Bits(21, 20) == 3 && instr->Bit(4) == 0) {
4568 // vext.
4569 int imm4 = instr->Bits(11, 8);
4570 int Vd = instr->VFPDRegValue(kSimd128Precision);
4571 int Vm = instr->VFPMRegValue(kSimd128Precision);
4572 int Vn = instr->VFPNRegValue(kSimd128Precision);
4573 uint8_t src1[16], src2[16], dst[16];
4574 get_neon_register(Vn, src1);
4575 get_neon_register(Vm, src2);
4576 int boundary = kSimd128Size - imm4;
4577 int i = 0;
4578 for (; i < boundary; i++) {
4579 dst[i] = src1[i + imm4];
4580 }
4581 for (; i < 16; i++) {
4582 dst[i] = src2[i - boundary];
4583 }
4584 set_neon_register(Vd, dst);
4585 } else if (instr->Bits(11, 7) == 0xA && instr->Bit(4) == 1) {
4586 // vshl.i<size> Qd, Qm, shift
4587 int size = base::bits::RoundDownToPowerOfTwo32(instr->Bits(21, 16));
4588 int shift = instr->Bits(21, 16) - size;
4589 int Vd = instr->VFPDRegValue(kSimd128Precision);
4590 int Vm = instr->VFPMRegValue(kSimd128Precision);
4591 NeonSize ns = static_cast<NeonSize>(size / 16);
4592 switch (ns) {
4593 case Neon8:
4594 ShiftLeft<uint8_t, kSimd128Size>(this, Vd, Vm, shift);
4595 break;
4596 case Neon16:
4597 ShiftLeft<uint16_t, kSimd128Size>(this, Vd, Vm, shift);
4598 break;
4599 case Neon32:
4600 ShiftLeft<uint32_t, kSimd128Size>(this, Vd, Vm, shift);
4601 break;
4602 default:
4603 UNREACHABLE();
4604 break;
4605 }
4606 } else if (instr->Bits(11, 7) == 0 && instr->Bit(4) == 1) {
4607 // vshr.s<size> Qd, Qm, shift
4608 int size = base::bits::RoundDownToPowerOfTwo32(instr->Bits(21, 16));
4609 int shift = 2 * size - instr->Bits(21, 16);
4610 int Vd = instr->VFPDRegValue(kSimd128Precision);
4611 int Vm = instr->VFPMRegValue(kSimd128Precision);
4612 NeonSize ns = static_cast<NeonSize>(size / 16);
4613 switch (ns) {
4614 case Neon8:
4615 ArithmeticShiftRight<int8_t, kSimd128Size>(this, Vd, Vm, shift);
4616 break;
4617 case Neon16:
4618 ArithmeticShiftRight<int16_t, kSimd128Size>(this, Vd, Vm, shift);
4619 break;
4620 case Neon32:
4621 ArithmeticShiftRight<int32_t, kSimd128Size>(this, Vd, Vm, shift);
4622 break;
4623 default:
4624 UNREACHABLE();
4625 break;
4626 }
4627 } else {
4628 UNIMPLEMENTED();
4629 }
4630 break;
4631 case 6: {
4632 int Vd, Vm, Vn;
4633 if (instr->Bit(6) == 0) {
4634 Vd = instr->VFPDRegValue(kDoublePrecision);
4635 Vm = instr->VFPMRegValue(kDoublePrecision);
4636 Vn = instr->VFPNRegValue(kDoublePrecision);
4637 } else {
4638 Vd = instr->VFPDRegValue(kSimd128Precision);
4639 Vm = instr->VFPMRegValue(kSimd128Precision);
4640 Vn = instr->VFPNRegValue(kSimd128Precision);
4641 }
4642 switch (instr->Bits(11, 8)) {
4643 case 0x0: {
4644 if (instr->Bit(4) == 1) {
4645 // vqadd.u<size> Qd, Qm, Qn.
4646 NeonSize size = static_cast<NeonSize>(instr->Bits(21, 20));
4647 switch (size) {
4648 case Neon8:
4649 AddSaturate<uint8_t>(this, Vd, Vm, Vn);
4650 break;
4651 case Neon16:
4652 AddSaturate<uint16_t>(this, Vd, Vm, Vn);
4653 break;
4654 case Neon32:
4655 AddSaturate<uint32_t>(this, Vd, Vm, Vn);
4656 break;
4657 default:
4658 UNREACHABLE();
4659 break;
4660 }
4661 } else {
4662 UNIMPLEMENTED();
4663 }
4664 break;
4665 }
4666 case 0x1: {
4667 if (instr->Bits(21, 20) == 1 && instr->Bit(4) == 1) {
4668 // vbsl.size Qd, Qm, Qn.
4669 uint32_t dst[4], src1[4], src2[4];
4670 get_neon_register(Vd, dst);
4671 get_neon_register(Vn, src1);
4672 get_neon_register(Vm, src2);
4673 for (int i = 0; i < 4; i++) {
4674 dst[i] = (dst[i] & src1[i]) | (~dst[i] & src2[i]);
4675 }
4676 set_neon_register(Vd, dst);
4677 } else if (instr->Bits(21, 20) == 0 && instr->Bit(4) == 1) {
4678 if (instr->Bit(6) == 0) {
4679 // veor Dd, Dn, Dm
4680 uint64_t src1, src2;
4681 get_d_register(Vn, &src1);
4682 get_d_register(Vm, &src2);
4683 src1 ^= src2;
4684 set_d_register(Vd, &src1);
4685
4686 } else {
4687 // veor Qd, Qn, Qm
4688 uint32_t src1[4], src2[4];
4689 get_neon_register(Vn, src1);
4690 get_neon_register(Vm, src2);
4691 for (int i = 0; i < 4; i++) src1[i] ^= src2[i];
4692 set_neon_register(Vd, src1);
4693 }
4694 } else {
4695 UNIMPLEMENTED();
4696 }
4697 break;
4698 }
4699 case 0x2: {
4700 if (instr->Bit(4) == 1) {
4701 // vqsub.u<size> Qd, Qm, Qn.
4702 NeonSize size = static_cast<NeonSize>(instr->Bits(21, 20));
4703 switch (size) {
4704 case Neon8:
4705 SubSaturate<uint8_t>(this, Vd, Vm, Vn);
4706 break;
4707 case Neon16:
4708 SubSaturate<uint16_t>(this, Vd, Vm, Vn);
4709 break;
4710 case Neon32:
4711 SubSaturate<uint32_t>(this, Vd, Vm, Vn);
4712 break;
4713 default:
4714 UNREACHABLE();
4715 break;
4716 }
4717 } else {
4718 UNIMPLEMENTED();
4719 }
4720 break;
4721 }
4722 case 0x3: {
4723 // vcge/vcgt.u<size> Qd, Qm, Qn.
4724 bool ge = instr->Bit(4) == 1;
4725 NeonSize size = static_cast<NeonSize>(instr->Bits(21, 20));
4726 switch (size) {
4727 case Neon8:
4728 CompareGreater<uint8_t, kSimd128Size>(this, Vd, Vm, Vn, ge);
4729 break;
4730 case Neon16:
4731 CompareGreater<uint16_t, kSimd128Size>(this, Vd, Vm, Vn, ge);
4732 break;
4733 case Neon32:
4734 CompareGreater<uint32_t, kSimd128Size>(this, Vd, Vm, Vn, ge);
4735 break;
4736 default:
4737 UNREACHABLE();
4738 break;
4739 }
4740 break;
4741 }
4742 case 0x6: {
4743 // vmin/vmax.u<size> Qd, Qm, Qn.
4744 NeonSize size = static_cast<NeonSize>(instr->Bits(21, 20));
4745 bool min = instr->Bit(4) != 0;
4746 switch (size) {
4747 case Neon8:
4748 MinMax<uint8_t, kSimd128Size>(this, Vd, Vm, Vn, min);
4749 break;
4750 case Neon16:
4751 MinMax<uint16_t, kSimd128Size>(this, Vd, Vm, Vn, min);
4752 break;
4753 case Neon32:
4754 MinMax<uint32_t, kSimd128Size>(this, Vd, Vm, Vn, min);
4755 break;
4756 default:
4757 UNREACHABLE();
4758 break;
4759 }
4760 break;
4761 }
4762 case 0x8: {
4763 if (instr->Bit(4) == 0) {
4764 // vsub.size Qd, Qm, Qn.
4765 NeonSize size = static_cast<NeonSize>(instr->Bits(21, 20));
4766 switch (size) {
4767 case Neon8:
4768 Sub<uint8_t, kSimd128Size>(this, Vd, Vm, Vn);
4769 break;
4770 case Neon16:
4771 Sub<uint16_t, kSimd128Size>(this, Vd, Vm, Vn);
4772 break;
4773 case Neon32:
4774 Sub<uint32_t, kSimd128Size>(this, Vd, Vm, Vn);
4775 break;
4776 default:
4777 UNREACHABLE();
4778 break;
4779 }
4780 } else {
4781 // vceq.size Qd, Qm, Qn.
4782 NeonSize size = static_cast<NeonSize>(instr->Bits(21, 20));
4783 switch (size) {
4784 case Neon8:
4785 CompareEqual<uint8_t, kSimd128Size>(this, Vd, Vm, Vn);
4786 break;
4787 case Neon16:
4788 CompareEqual<uint16_t, kSimd128Size>(this, Vd, Vm, Vn);
4789 break;
4790 case Neon32:
4791 CompareEqual<uint32_t, kSimd128Size>(this, Vd, Vm, Vn);
4792 break;
4793 default:
4794 UNREACHABLE();
4795 break;
4796 }
4797 }
4798 break;
4799 }
4800 case 0xA: {
4801 // vpmin/vpmax.u<size> Dd, Dm, Dn.
4802 NeonSize size = static_cast<NeonSize>(instr->Bits(21, 20));
4803 bool min = instr->Bit(4) != 0;
4804 switch (size) {
4805 case Neon8:
4806 PairwiseMinMax<uint8_t>(this, Vd, Vm, Vn, min);
4807 break;
4808 case Neon16:
4809 PairwiseMinMax<uint16_t>(this, Vd, Vm, Vn, min);
4810 break;
4811 case Neon32:
4812 PairwiseMinMax<uint32_t>(this, Vd, Vm, Vn, min);
4813 break;
4814 default:
4815 UNREACHABLE();
4816 break;
4817 }
4818 break;
4819 }
4820 case 0xD: {
4821 if (instr->Bits(21, 20) == 0 && instr->Bit(6) == 1 &&
4822 instr->Bit(4) == 1) {
4823 // vmul.f32 Qd, Qn, Qm
4824 float src1[4], src2[4];
4825 get_neon_register(Vn, src1);
4826 get_neon_register(Vm, src2);
4827 for (int i = 0; i < 4; i++) {
4828 src1[i] = src1[i] * src2[i];
4829 }
4830 set_neon_register(Vd, src1);
4831 } else if (instr->Bits(21, 20) == 0 && instr->Bit(6) == 0 &&
4832 instr->Bit(4) == 0) {
4833 // vpadd.f32 Dd, Dn, Dm
4834 PairwiseAdd<float>(this, Vd, Vm, Vn);
4835 } else {
4836 UNIMPLEMENTED();
4837 }
4838 break;
4839 }
4840 case 0xE: {
4841 if (instr->Bit(20) == 0 && instr->Bit(4) == 0) {
4842 // vcge/vcgt.f32 Qd, Qm, Qn
4843 bool ge = instr->Bit(21) == 0;
4844 float src1[4], src2[4];
4845 get_neon_register(Vn, src1);
4846 get_neon_register(Vm, src2);
4847 uint32_t dst[4];
4848 for (int i = 0; i < 4; i++) {
4849 if (ge) {
4850 dst[i] = src1[i] >= src2[i] ? 0xFFFFFFFFu : 0;
4851 } else {
4852 dst[i] = src1[i] > src2[i] ? 0xFFFFFFFFu : 0;
4853 }
4854 }
4855 set_neon_register(Vd, dst);
4856 } else {
4857 UNIMPLEMENTED();
4858 }
4859 break;
4860 }
4861 default:
4862 UNREACHABLE();
4863 break;
4864 }
4865 break;
4866 }
4867 case 7:
4868 if ((instr->Bits(18, 16) == 0) && (instr->Bits(11, 6) == 0x28) &&
4869 (instr->Bit(4) == 1)) {
4870 // vmovl unsigned
4871 if ((instr->VdValue() & 1) != 0) UNIMPLEMENTED();
4872 int Vd = instr->VFPDRegValue(kSimd128Precision);
4873 int Vm = instr->VFPMRegValue(kDoublePrecision);
4874 int imm3 = instr->Bits(21, 19);
4875 switch (imm3) {
4876 case 1:
4877 Widen<uint8_t, uint16_t>(this, Vd, Vm);
4878 break;
4879 case 2:
4880 Widen<uint16_t, uint32_t>(this, Vd, Vm);
4881 break;
4882 case 4:
4883 Widen<uint32_t, uint64_t>(this, Vd, Vm);
4884 break;
4885 default:
4886 UNIMPLEMENTED();
4887 break;
4888 }
4889 } else if (instr->Opc1Value() == 7 && instr->Bit(4) == 0) {
4890 if (instr->Bits(19, 16) == 0xB && instr->Bits(11, 9) == 0x3 &&
4891 instr->Bit(6) == 1) {
4892 // vcvt.<Td>.<Tm> Qd, Qm.
4893 int Vd = instr->VFPDRegValue(kSimd128Precision);
4894 int Vm = instr->VFPMRegValue(kSimd128Precision);
4895 uint32_t q_data[4];
4896 get_neon_register(Vm, q_data);
4897 int op = instr->Bits(8, 7);
4898 for (int i = 0; i < 4; i++) {
4899 switch (op) {
4900 case 0:
4901 // f32 <- s32, round towards nearest.
4902 q_data[i] = bit_cast<uint32_t>(std::round(
4903 static_cast<float>(bit_cast<int32_t>(q_data[i]))));
4904 break;
4905 case 1:
4906 // f32 <- u32, round towards nearest.
4907 q_data[i] = bit_cast<uint32_t>(
4908 std::round(static_cast<float>(q_data[i])));
4909 break;
4910 case 2:
4911 // s32 <- f32, round to zero.
4912 q_data[i] = static_cast<uint32_t>(
4913 ConvertDoubleToInt(bit_cast<float>(q_data[i]), false, RZ));
4914 break;
4915 case 3:
4916 // u32 <- f32, round to zero.
4917 q_data[i] = static_cast<uint32_t>(
4918 ConvertDoubleToInt(bit_cast<float>(q_data[i]), true, RZ));
4919 break;
4920 }
4921 }
4922 set_neon_register(Vd, q_data);
4923 } else if (instr->Bits(17, 16) == 0x2 && instr->Bits(11, 7) == 0) {
4924 if (instr->Bit(6) == 0) {
4925 // vswp Dd, Dm.
4926 uint64_t dval, mval;
4927 int vd = instr->VFPDRegValue(kDoublePrecision);
4928 int vm = instr->VFPMRegValue(kDoublePrecision);
4929 get_d_register(vd, &dval);
4930 get_d_register(vm, &mval);
4931 set_d_register(vm, &dval);
4932 set_d_register(vd, &mval);
4933 } else {
4934 // vswp Qd, Qm.
4935 uint32_t dval[4], mval[4];
4936 int vd = instr->VFPDRegValue(kSimd128Precision);
4937 int vm = instr->VFPMRegValue(kSimd128Precision);
4938 get_neon_register(vd, dval);
4939 get_neon_register(vm, mval);
4940 set_neon_register(vm, dval);
4941 set_neon_register(vd, mval);
4942 }
4943 } else if (instr->Bits(11, 7) == 0x18) {
4944 // vdup.<size> Dd, Dm[index].
4945 // vdup.<size> Qd, Dm[index].
4946 int vm = instr->VFPMRegValue(kDoublePrecision);
4947 int imm4 = instr->Bits(19, 16);
4948 int size = 0, index = 0, mask = 0;
4949 if ((imm4 & 0x1) != 0) {
4950 size = 8;
4951 index = imm4 >> 1;
4952 mask = 0xFFu;
4953 } else if ((imm4 & 0x2) != 0) {
4954 size = 16;
4955 index = imm4 >> 2;
4956 mask = 0xFFFFu;
4957 } else {
4958 size = 32;
4959 index = imm4 >> 3;
4960 mask = 0xFFFFFFFFu;
4961 }
4962 uint64_t d_data;
4963 get_d_register(vm, &d_data);
4964 uint32_t scalar = (d_data >> (size * index)) & mask;
4965 uint32_t duped = scalar;
4966 for (int i = 1; i < 32 / size; i++) {
4967 scalar <<= size;
4968 duped |= scalar;
4969 }
4970 uint32_t result[4] = {duped, duped, duped, duped};
4971 if (instr->Bit(6) == 0) {
4972 int vd = instr->VFPDRegValue(kDoublePrecision);
4973 set_d_register(vd, result);
4974 } else {
4975 int vd = instr->VFPDRegValue(kSimd128Precision);
4976 set_neon_register(vd, result);
4977 }
4978 } else if (instr->Bits(19, 16) == 0 && instr->Bits(11, 6) == 0x17) {
4979 // vmvn Qd, Qm.
4980 int vd = instr->VFPDRegValue(kSimd128Precision);
4981 int vm = instr->VFPMRegValue(kSimd128Precision);
4982 uint32_t q_data[4];
4983 get_neon_register(vm, q_data);
4984 for (int i = 0; i < 4; i++) q_data[i] = ~q_data[i];
4985 set_neon_register(vd, q_data);
4986 } else if (instr->Bits(11, 10) == 0x2) {
4987 // vtb[l,x] Dd, <list>, Dm.
4988 int vd = instr->VFPDRegValue(kDoublePrecision);
4989 int vn = instr->VFPNRegValue(kDoublePrecision);
4990 int vm = instr->VFPMRegValue(kDoublePrecision);
4991 int table_len = (instr->Bits(9, 8) + 1) * kDoubleSize;
4992 bool vtbx = instr->Bit(6) != 0; // vtbl / vtbx
4993 uint64_t destination = 0, indices = 0, result = 0;
4994 get_d_register(vd, &destination);
4995 get_d_register(vm, &indices);
4996 for (int i = 0; i < kDoubleSize; i++) {
4997 int shift = i * kBitsPerByte;
4998 int index = (indices >> shift) & 0xFF;
4999 if (index < table_len) {
5000 uint64_t table;
5001 get_d_register(vn + index / kDoubleSize, &table);
5002 result |=
5003 ((table >> ((index % kDoubleSize) * kBitsPerByte)) & 0xFF)
5004 << shift;
5005 } else if (vtbx) {
5006 result |= destination & (0xFFull << shift);
5007 }
5008 }
5009 set_d_register(vd, &result);
5010 } else if (instr->Bits(17, 16) == 0x2 && instr->Bits(11, 8) == 0x1) {
5011 NeonSize size = static_cast<NeonSize>(instr->Bits(19, 18));
5012 if (instr->Bit(6) == 0) {
5013 int Vd = instr->VFPDRegValue(kDoublePrecision);
5014 int Vm = instr->VFPMRegValue(kDoublePrecision);
5015 if (instr->Bit(7) == 1) {
5016 // vzip.<size> Dd, Dm.
5017 switch (size) {
5018 case Neon8:
5019 Zip<uint8_t, kDoubleSize>(this, Vd, Vm);
5020 break;
5021 case Neon16:
5022 Zip<uint16_t, kDoubleSize>(this, Vd, Vm);
5023 break;
5024 case Neon32:
5025 UNIMPLEMENTED();
5026 break;
5027 default:
5028 UNREACHABLE();
5029 break;
5030 }
5031 } else {
5032 // vuzp.<size> Dd, Dm.
5033 switch (size) {
5034 case Neon8:
5035 Unzip<uint8_t, kDoubleSize>(this, Vd, Vm);
5036 break;
5037 case Neon16:
5038 Unzip<uint16_t, kDoubleSize>(this, Vd, Vm);
5039 break;
5040 case Neon32:
5041 UNIMPLEMENTED();
5042 break;
5043 default:
5044 UNREACHABLE();
5045 break;
5046 }
5047 }
5048 } else {
5049 int Vd = instr->VFPDRegValue(kSimd128Precision);
5050 int Vm = instr->VFPMRegValue(kSimd128Precision);
5051 if (instr->Bit(7) == 1) {
5052 // vzip.<size> Qd, Qm.
5053 switch (size) {
5054 case Neon8:
5055 Zip<uint8_t, kSimd128Size>(this, Vd, Vm);
5056 break;
5057 case Neon16:
5058 Zip<uint16_t, kSimd128Size>(this, Vd, Vm);
5059 break;
5060 case Neon32:
5061 Zip<uint32_t, kSimd128Size>(this, Vd, Vm);
5062 break;
5063 default:
5064 UNREACHABLE();
5065 break;
5066 }
5067 } else {
5068 // vuzp.<size> Qd, Qm.
5069 switch (size) {
5070 case Neon8:
5071 Unzip<uint8_t, kSimd128Size>(this, Vd, Vm);
5072 break;
5073 case Neon16:
5074 Unzip<uint16_t, kSimd128Size>(this, Vd, Vm);
5075 break;
5076 case Neon32:
5077 Unzip<uint32_t, kSimd128Size>(this, Vd, Vm);
5078 break;
5079 default:
5080 UNREACHABLE();
5081 break;
5082 }
5083 }
5084 }
5085 } else if (instr->Bits(17, 16) == 0 && instr->Bits(11, 9) == 0) {
5086 // vrev<op>.size Qd, Qm
5087 int Vd = instr->VFPDRegValue(kSimd128Precision);
5088 int Vm = instr->VFPMRegValue(kSimd128Precision);
5089 NeonSize size = static_cast<NeonSize>(instr->Bits(19, 18));
5090 NeonSize op = static_cast<NeonSize>(static_cast<int>(Neon64) -
5091 instr->Bits(8, 7));
5092 switch (op) {
5093 case Neon16: {
5094 DCHECK_EQ(Neon8, size);
5095 uint8_t src[16];
5096 get_neon_register(Vm, src);
5097 for (int i = 0; i < 16; i += 2) {
5098 std::swap(src[i], src[i + 1]);
5099 }
5100 set_neon_register(Vd, src);
5101 break;
5102 }
5103 case Neon32: {
5104 switch (size) {
5105 case Neon16: {
5106 uint16_t src[8];
5107 get_neon_register(Vm, src);
5108 for (int i = 0; i < 8; i += 2) {
5109 std::swap(src[i], src[i + 1]);
5110 }
5111 set_neon_register(Vd, src);
5112 break;
5113 }
5114 case Neon8: {
5115 uint8_t src[16];
5116 get_neon_register(Vm, src);
5117 for (int i = 0; i < 4; i++) {
5118 std::swap(src[i * 4], src[i * 4 + 3]);
5119 std::swap(src[i * 4 + 1], src[i * 4 + 2]);
5120 }
5121 set_neon_register(Vd, src);
5122 break;
5123 }
5124 default:
5125 UNREACHABLE();
5126 break;
5127 }
5128 break;
5129 }
5130 case Neon64: {
5131 switch (size) {
5132 case Neon32: {
5133 uint32_t src[4];
5134 get_neon_register(Vm, src);
5135 std::swap(src[0], src[1]);
5136 std::swap(src[2], src[3]);
5137 set_neon_register(Vd, src);
5138 break;
5139 }
5140 case Neon16: {
5141 uint16_t src[8];
5142 get_neon_register(Vm, src);
5143 for (int i = 0; i < 2; i++) {
5144 std::swap(src[i * 4], src[i * 4 + 3]);
5145 std::swap(src[i * 4 + 1], src[i * 4 + 2]);
5146 }
5147 set_neon_register(Vd, src);
5148 break;
5149 }
5150 case Neon8: {
5151 uint8_t src[16];
5152 get_neon_register(Vm, src);
5153 for (int i = 0; i < 4; i++) {
5154 std::swap(src[i], src[7 - i]);
5155 std::swap(src[i + 8], src[15 - i]);
5156 }
5157 set_neon_register(Vd, src);
5158 break;
5159 }
5160 default:
5161 UNREACHABLE();
5162 break;
5163 }
5164 break;
5165 }
5166 default:
5167 UNREACHABLE();
5168 break;
5169 }
5170 } else if (instr->Bits(17, 16) == 0x2 && instr->Bits(11, 7) == 0x1) {
5171 NeonSize size = static_cast<NeonSize>(instr->Bits(19, 18));
5172 if (instr->Bit(6) == 0) {
5173 int Vd = instr->VFPDRegValue(kDoublePrecision);
5174 int Vm = instr->VFPMRegValue(kDoublePrecision);
5175 // vtrn.<size> Dd, Dm.
5176 switch (size) {
5177 case Neon8:
5178 Transpose<uint8_t, kDoubleSize>(this, Vd, Vm);
5179 break;
5180 case Neon16:
5181 Transpose<uint16_t, kDoubleSize>(this, Vd, Vm);
5182 break;
5183 case Neon32:
5184 Transpose<uint32_t, kDoubleSize>(this, Vd, Vm);
5185 break;
5186 default:
5187 UNREACHABLE();
5188 break;
5189 }
5190 } else {
5191 int Vd = instr->VFPDRegValue(kSimd128Precision);
5192 int Vm = instr->VFPMRegValue(kSimd128Precision);
5193 // vtrn.<size> Qd, Qm.
5194 switch (size) {
5195 case Neon8:
5196 Transpose<uint8_t, kSimd128Size>(this, Vd, Vm);
5197 break;
5198 case Neon16:
5199 Transpose<uint16_t, kSimd128Size>(this, Vd, Vm);
5200 break;
5201 case Neon32:
5202 Transpose<uint32_t, kSimd128Size>(this, Vd, Vm);
5203 break;
5204 default:
5205 UNREACHABLE();
5206 break;
5207 }
5208 }
5209 } else if (instr->Bits(17, 16) == 0x1 && instr->Bit(11) == 0) {
5210 int Vd = instr->VFPDRegValue(kSimd128Precision);
5211 int Vm = instr->VFPMRegValue(kSimd128Precision);
5212 NeonSize size = static_cast<NeonSize>(instr->Bits(19, 18));
5213 if (instr->Bits(9, 6) == 0xD) {
5214 // vabs<type>.<size> Qd, Qm
5215 if (instr->Bit(10) != 0) {
5216 // floating point (clear sign bits)
5217 uint32_t src[4];
5218 get_neon_register(Vm, src);
5219 for (int i = 0; i < 4; i++) {
5220 src[i] &= ~0x80000000;
5221 }
5222 set_neon_register(Vd, src);
5223 } else {
5224 // signed integer
5225 switch (size) {
5226 case Neon8:
5227 Abs<int8_t, kSimd128Size>(this, Vd, Vm);
5228 break;
5229 case Neon16:
5230 Abs<int16_t, kSimd128Size>(this, Vd, Vm);
5231 break;
5232 case Neon32:
5233 Abs<int32_t, kSimd128Size>(this, Vd, Vm);
5234 break;
5235 default:
5236 UNIMPLEMENTED();
5237 break;
5238 }
5239 }
5240 } else if (instr->Bits(9, 6) == 0xF) {
5241 // vneg<type>.<size> Qd, Qm (signed integer)
5242 if (instr->Bit(10) != 0) {
5243 // floating point (toggle sign bits)
5244 uint32_t src[4];
5245 get_neon_register(Vm, src);
5246 for (int i = 0; i < 4; i++) {
5247 src[i] ^= 0x80000000;
5248 }
5249 set_neon_register(Vd, src);
5250 } else {
5251 // signed integer
5252 switch (size) {
5253 case Neon8:
5254 Neg<int8_t, kSimd128Size>(this, Vd, Vm);
5255 break;
5256 case Neon16:
5257 Neg<int16_t, kSimd128Size>(this, Vd, Vm);
5258 break;
5259 case Neon32:
5260 Neg<int32_t, kSimd128Size>(this, Vd, Vm);
5261 break;
5262 default:
5263 UNIMPLEMENTED();
5264 break;
5265 }
5266 }
5267 } else {
5268 UNIMPLEMENTED();
5269 }
5270 } else if (instr->Bits(19, 18) == 0x2 && instr->Bits(11, 8) == 0x5) {
5271 // vrecpe/vrsqrte.f32 Qd, Qm.
5272 int Vd = instr->VFPDRegValue(kSimd128Precision);
5273 int Vm = instr->VFPMRegValue(kSimd128Precision);
5274 uint32_t src[4];
5275 get_neon_register(Vm, src);
5276 if (instr->Bit(7) == 0) {
5277 for (int i = 0; i < 4; i++) {
5278 float denom = bit_cast<float>(src[i]);
5279 div_zero_vfp_flag_ = (denom == 0);
5280 float result = 1.0f / denom;
5281 result = canonicalizeNaN(result);
5282 src[i] = bit_cast<uint32_t>(result);
5283 }
5284 } else {
5285 lazily_initialize_fast_sqrt(isolate_);
5286 for (int i = 0; i < 4; i++) {
5287 float radicand = bit_cast<float>(src[i]);
5288 float result = 1.0f / fast_sqrt(radicand, isolate_);
5289 result = canonicalizeNaN(result);
5290 src[i] = bit_cast<uint32_t>(result);
5291 }
5292 }
5293 set_neon_register(Vd, src);
5294 } else if (instr->Bits(17, 16) == 0x2 && instr->Bits(11, 8) == 0x2 &&
5295 instr->Bits(7, 6) != 0) {
5296 // vqmovn.<type><size> Dd, Qm.
5297 int Vd = instr->VFPDRegValue(kDoublePrecision);
5298 int Vm = instr->VFPMRegValue(kSimd128Precision);
5299 NeonSize size = static_cast<NeonSize>(instr->Bits(19, 18));
5300 bool is_unsigned = instr->Bit(6) != 0;
5301 switch (size) {
5302 case Neon8: {
5303 if (is_unsigned) {
5304 SaturatingNarrow<uint16_t, uint8_t>(this, Vd, Vm);
5305 } else {
5306 SaturatingNarrow<int16_t, int8_t>(this, Vd, Vm);
5307 }
5308 break;
5309 }
5310 case Neon16: {
5311 if (is_unsigned) {
5312 SaturatingNarrow<uint32_t, uint16_t>(this, Vd, Vm);
5313 } else {
5314 SaturatingNarrow<int32_t, int16_t>(this, Vd, Vm);
5315 }
5316 break;
5317 }
5318 case Neon32: {
5319 if (is_unsigned) {
5320 SaturatingNarrow<uint64_t, uint32_t>(this, Vd, Vm);
5321 } else {
5322 SaturatingNarrow<int64_t, int32_t>(this, Vd, Vm);
5323 }
5324 break;
5325 }
5326 default:
5327 UNIMPLEMENTED();
5328 break;
5329 }
5330 } else {
5331 UNIMPLEMENTED();
5332 }
5333 } else if (instr->Bits(11, 7) == 0 && instr->Bit(4) == 1) {
5334 // vshr.u<size> Qd, Qm, shift
5335 int size = base::bits::RoundDownToPowerOfTwo32(instr->Bits(21, 16));
5336 int shift = 2 * size - instr->Bits(21, 16);
5337 int Vd = instr->VFPDRegValue(kSimd128Precision);
5338 int Vm = instr->VFPMRegValue(kSimd128Precision);
5339 NeonSize ns = static_cast<NeonSize>(size / 16);
5340 switch (ns) {
5341 case Neon8:
5342 ShiftRight<uint8_t, kSimd128Size>(this, Vd, Vm, shift);
5343 break;
5344 case Neon16:
5345 ShiftRight<uint16_t, kSimd128Size>(this, Vd, Vm, shift);
5346 break;
5347 case Neon32:
5348 ShiftRight<uint32_t, kSimd128Size>(this, Vd, Vm, shift);
5349 break;
5350 default:
5351 UNREACHABLE();
5352 break;
5353 }
5354 } else if (instr->Bits(11, 8) == 0x5 && instr->Bit(6) == 0 &&
5355 instr->Bit(4) == 1) {
5356 // vsli.<size> Dd, Dm, shift
5357 int imm7 = instr->Bits(21, 16);
5358 if (instr->Bit(7) != 0) imm7 += 64;
5359 int size = base::bits::RoundDownToPowerOfTwo32(imm7);
5360 int shift = imm7 - size;
5361 int Vd = instr->VFPDRegValue(kDoublePrecision);
5362 int Vm = instr->VFPMRegValue(kDoublePrecision);
5363 switch (size) {
5364 case 8:
5365 ShiftLeftAndInsert<uint8_t, kDoubleSize>(this, Vd, Vm, shift);
5366 break;
5367 case 16:
5368 ShiftLeftAndInsert<uint16_t, kDoubleSize>(this, Vd, Vm, shift);
5369 break;
5370 case 32:
5371 ShiftLeftAndInsert<uint32_t, kDoubleSize>(this, Vd, Vm, shift);
5372 break;
5373 case 64:
5374 ShiftLeftAndInsert<uint64_t, kDoubleSize>(this, Vd, Vm, shift);
5375 break;
5376 default:
5377 UNREACHABLE();
5378 break;
5379 }
5380 } else if (instr->Bits(11, 8) == 0x4 && instr->Bit(6) == 0 &&
5381 instr->Bit(4) == 1) {
5382 // vsri.<size> Dd, Dm, shift
5383 int imm7 = instr->Bits(21, 16);
5384 if (instr->Bit(7) != 0) imm7 += 64;
5385 int size = base::bits::RoundDownToPowerOfTwo32(imm7);
5386 int shift = 2 * size - imm7;
5387 int Vd = instr->VFPDRegValue(kDoublePrecision);
5388 int Vm = instr->VFPMRegValue(kDoublePrecision);
5389 switch (size) {
5390 case 8:
5391 ShiftRightAndInsert<uint8_t, kDoubleSize>(this, Vd, Vm, shift);
5392 break;
5393 case 16:
5394 ShiftRightAndInsert<uint16_t, kDoubleSize>(this, Vd, Vm, shift);
5395 break;
5396 case 32:
5397 ShiftRightAndInsert<uint32_t, kDoubleSize>(this, Vd, Vm, shift);
5398 break;
5399 case 64:
5400 ShiftRightAndInsert<uint64_t, kDoubleSize>(this, Vd, Vm, shift);
5401 break;
5402 default:
5403 UNREACHABLE();
5404 break;
5405 }
5406 } else {
5407 UNIMPLEMENTED();
5408 }
5409 break;
5410 case 8:
5411 if (instr->Bits(21, 20) == 0) {
5412 // vst1
5413 int Vd = (instr->Bit(22) << 4) | instr->VdValue();
5414 int Rn = instr->VnValue();
5415 int type = instr->Bits(11, 8);
5416 int Rm = instr->VmValue();
5417 int32_t address = get_register(Rn);
5418 int regs = 0;
5419 switch (type) {
5420 case nlt_1:
5421 regs = 1;
5422 break;
5423 case nlt_2:
5424 regs = 2;
5425 break;
5426 case nlt_3:
5427 regs = 3;
5428 break;
5429 case nlt_4:
5430 regs = 4;
5431 break;
5432 default:
5433 UNIMPLEMENTED();
5434 break;
5435 }
5436 int r = 0;
5437 while (r < regs) {
5438 uint32_t data[2];
5439 get_d_register(Vd + r, data);
5440 WriteW(address, data[0]);
5441 WriteW(address + 4, data[1]);
5442 address += 8;
5443 r++;
5444 }
5445 if (Rm != 15) {
5446 if (Rm == 13) {
5447 set_register(Rn, address);
5448 } else {
5449 set_register(Rn, get_register(Rn) + get_register(Rm));
5450 }
5451 }
5452 } else if (instr->Bits(21, 20) == 2) {
5453 // vld1
5454 int Vd = (instr->Bit(22) << 4) | instr->VdValue();
5455 int Rn = instr->VnValue();
5456 int type = instr->Bits(11, 8);
5457 int Rm = instr->VmValue();
5458 int32_t address = get_register(Rn);
5459 int regs = 0;
5460 switch (type) {
5461 case nlt_1:
5462 regs = 1;
5463 break;
5464 case nlt_2:
5465 regs = 2;
5466 break;
5467 case nlt_3:
5468 regs = 3;
5469 break;
5470 case nlt_4:
5471 regs = 4;
5472 break;
5473 default:
5474 UNIMPLEMENTED();
5475 break;
5476 }
5477 int r = 0;
5478 while (r < regs) {
5479 uint32_t data[2];
5480 data[0] = ReadW(address);
5481 data[1] = ReadW(address + 4);
5482 set_d_register(Vd + r, data);
5483 address += 8;
5484 r++;
5485 }
5486 if (Rm != 15) {
5487 if (Rm == 13) {
5488 set_register(Rn, address);
5489 } else {
5490 set_register(Rn, get_register(Rn) + get_register(Rm));
5491 }
5492 }
5493 } else {
5494 UNIMPLEMENTED();
5495 }
5496 break;
5497 case 0xA:
5498 case 0xB:
5499 if ((instr->Bits(22, 20) == 5) && (instr->Bits(15, 12) == 0xF)) {
5500 // pld: ignore instruction.
5501 } else if (instr->SpecialValue() == 0xA && instr->Bits(22, 20) == 7) {
5502 // dsb, dmb, isb: ignore instruction for now.
5503 // TODO(binji): implement
5504 // Also refer to the ARMv6 CP15 equivalents in DecodeTypeCP15.
5505 } else {
5506 UNIMPLEMENTED();
5507 }
5508 break;
5509 case 0x1D:
5510 if (instr->Opc1Value() == 0x7 && instr->Opc3Value() == 0x1 &&
5511 instr->Bits(11, 9) == 0x5 && instr->Bits(19, 18) == 0x2) {
5512 if (instr->SzValue() == 0x1) {
5513 int vm = instr->VFPMRegValue(kDoublePrecision);
5514 int vd = instr->VFPDRegValue(kDoublePrecision);
5515 double dm_value = get_double_from_d_register(vm).get_scalar();
5516 double dd_value = 0.0;
5517 int rounding_mode = instr->Bits(17, 16);
5518 switch (rounding_mode) {
5519 case 0x0: // vrinta - round with ties to away from zero
5520 dd_value = round(dm_value);
5521 break;
5522 case 0x1: { // vrintn - round with ties to even
5523 dd_value = nearbyint(dm_value);
5524 break;
5525 }
5526 case 0x2: // vrintp - ceil
5527 dd_value = ceil(dm_value);
5528 break;
5529 case 0x3: // vrintm - floor
5530 dd_value = floor(dm_value);
5531 break;
5532 default:
5533 UNREACHABLE(); // Case analysis is exhaustive.
5534 break;
5535 }
5536 dd_value = canonicalizeNaN(dd_value);
5537 set_d_register_from_double(vd, dd_value);
5538 } else {
5539 int m = instr->VFPMRegValue(kSinglePrecision);
5540 int d = instr->VFPDRegValue(kSinglePrecision);
5541 float sm_value = get_float_from_s_register(m).get_scalar();
5542 float sd_value = 0.0;
5543 int rounding_mode = instr->Bits(17, 16);
5544 switch (rounding_mode) {
5545 case 0x0: // vrinta - round with ties to away from zero
5546 sd_value = roundf(sm_value);
5547 break;
5548 case 0x1: { // vrintn - round with ties to even
5549 sd_value = nearbyintf(sm_value);
5550 break;
5551 }
5552 case 0x2: // vrintp - ceil
5553 sd_value = ceilf(sm_value);
5554 break;
5555 case 0x3: // vrintm - floor
5556 sd_value = floorf(sm_value);
5557 break;
5558 default:
5559 UNREACHABLE(); // Case analysis is exhaustive.
5560 break;
5561 }
5562 sd_value = canonicalizeNaN(sd_value);
5563 set_s_register_from_float(d, sd_value);
5564 }
5565 } else if ((instr->Opc1Value() == 0x4) && (instr->Bits(11, 9) == 0x5) &&
5566 (instr->Bit(4) == 0x0)) {
5567 if (instr->SzValue() == 0x1) {
5568 int m = instr->VFPMRegValue(kDoublePrecision);
5569 int n = instr->VFPNRegValue(kDoublePrecision);
5570 int d = instr->VFPDRegValue(kDoublePrecision);
5571 double dn_value = get_double_from_d_register(n).get_scalar();
5572 double dm_value = get_double_from_d_register(m).get_scalar();
5573 double dd_value;
5574 if (instr->Bit(6) == 0x1) { // vminnm
5575 if ((dn_value < dm_value) || std::isnan(dm_value)) {
5576 dd_value = dn_value;
5577 } else if ((dm_value < dn_value) || std::isnan(dn_value)) {
5578 dd_value = dm_value;
5579 } else {
5580 DCHECK_EQ(dn_value, dm_value);
5581 // Make sure that we pick the most negative sign for +/-0.
5582 dd_value = std::signbit(dn_value) ? dn_value : dm_value;
5583 }
5584 } else { // vmaxnm
5585 if ((dn_value > dm_value) || std::isnan(dm_value)) {
5586 dd_value = dn_value;
5587 } else if ((dm_value > dn_value) || std::isnan(dn_value)) {
5588 dd_value = dm_value;
5589 } else {
5590 DCHECK_EQ(dn_value, dm_value);
5591 // Make sure that we pick the most positive sign for +/-0.
5592 dd_value = std::signbit(dn_value) ? dm_value : dn_value;
5593 }
5594 }
5595 dd_value = canonicalizeNaN(dd_value);
5596 set_d_register_from_double(d, dd_value);
5597 } else {
5598 int m = instr->VFPMRegValue(kSinglePrecision);
5599 int n = instr->VFPNRegValue(kSinglePrecision);
5600 int d = instr->VFPDRegValue(kSinglePrecision);
5601 float sn_value = get_float_from_s_register(n).get_scalar();
5602 float sm_value = get_float_from_s_register(m).get_scalar();
5603 float sd_value;
5604 if (instr->Bit(6) == 0x1) { // vminnm
5605 if ((sn_value < sm_value) || std::isnan(sm_value)) {
5606 sd_value = sn_value;
5607 } else if ((sm_value < sn_value) || std::isnan(sn_value)) {
5608 sd_value = sm_value;
5609 } else {
5610 DCHECK_EQ(sn_value, sm_value);
5611 // Make sure that we pick the most negative sign for +/-0.
5612 sd_value = std::signbit(sn_value) ? sn_value : sm_value;
5613 }
5614 } else { // vmaxnm
5615 if ((sn_value > sm_value) || std::isnan(sm_value)) {
5616 sd_value = sn_value;
5617 } else if ((sm_value > sn_value) || std::isnan(sn_value)) {
5618 sd_value = sm_value;
5619 } else {
5620 DCHECK_EQ(sn_value, sm_value);
5621 // Make sure that we pick the most positive sign for +/-0.
5622 sd_value = std::signbit(sn_value) ? sm_value : sn_value;
5623 }
5624 }
5625 sd_value = canonicalizeNaN(sd_value);
5626 set_s_register_from_float(d, sd_value);
5627 }
5628 } else {
5629 UNIMPLEMENTED();
5630 }
5631 break;
5632 case 0x1C:
5633 if ((instr->Bits(11, 9) == 0x5) && (instr->Bit(6) == 0) &&
5634 (instr->Bit(4) == 0)) {
5635 // VSEL* (floating-point)
5636 bool condition_holds;
5637 switch (instr->Bits(21, 20)) {
5638 case 0x0: // VSELEQ
5639 condition_holds = (z_flag_ == 1);
5640 break;
5641 case 0x1: // VSELVS
5642 condition_holds = (v_flag_ == 1);
5643 break;
5644 case 0x2: // VSELGE
5645 condition_holds = (n_flag_ == v_flag_);
5646 break;
5647 case 0x3: // VSELGT
5648 condition_holds = ((z_flag_ == 0) && (n_flag_ == v_flag_));
5649 break;
5650 default:
5651 UNREACHABLE(); // Case analysis is exhaustive.
5652 break;
5653 }
5654 if (instr->SzValue() == 0x1) {
5655 int n = instr->VFPNRegValue(kDoublePrecision);
5656 int m = instr->VFPMRegValue(kDoublePrecision);
5657 int d = instr->VFPDRegValue(kDoublePrecision);
5658 Float64 result = get_double_from_d_register(condition_holds ? n : m);
5659 set_d_register_from_double(d, result);
5660 } else {
5661 int n = instr->VFPNRegValue(kSinglePrecision);
5662 int m = instr->VFPMRegValue(kSinglePrecision);
5663 int d = instr->VFPDRegValue(kSinglePrecision);
5664 Float32 result = get_float_from_s_register(condition_holds ? n : m);
5665 set_s_register_from_float(d, result);
5666 }
5667 } else {
5668 UNIMPLEMENTED();
5669 }
5670 break;
5671 default:
5672 UNIMPLEMENTED();
5673 break;
5674 }
5675 }
5676
5677
5678 // Executes the current instruction.
InstructionDecode(Instruction * instr)5679 void Simulator::InstructionDecode(Instruction* instr) {
5680 if (v8::internal::FLAG_check_icache) {
5681 CheckICache(i_cache(), instr);
5682 }
5683 pc_modified_ = false;
5684 if (::v8::internal::FLAG_trace_sim) {
5685 disasm::NameConverter converter;
5686 disasm::Disassembler dasm(converter);
5687 // use a reasonably large buffer
5688 v8::internal::EmbeddedVector<char, 256> buffer;
5689 dasm.InstructionDecode(buffer,
5690 reinterpret_cast<byte*>(instr));
5691 PrintF(" 0x%08" V8PRIxPTR " %s\n", reinterpret_cast<intptr_t>(instr),
5692 buffer.start());
5693 }
5694 if (instr->ConditionField() == kSpecialCondition) {
5695 DecodeSpecialCondition(instr);
5696 } else if (ConditionallyExecute(instr)) {
5697 switch (instr->TypeValue()) {
5698 case 0:
5699 case 1: {
5700 DecodeType01(instr);
5701 break;
5702 }
5703 case 2: {
5704 DecodeType2(instr);
5705 break;
5706 }
5707 case 3: {
5708 DecodeType3(instr);
5709 break;
5710 }
5711 case 4: {
5712 DecodeType4(instr);
5713 break;
5714 }
5715 case 5: {
5716 DecodeType5(instr);
5717 break;
5718 }
5719 case 6: {
5720 DecodeType6(instr);
5721 break;
5722 }
5723 case 7: {
5724 DecodeType7(instr);
5725 break;
5726 }
5727 default: {
5728 UNIMPLEMENTED();
5729 break;
5730 }
5731 }
5732 }
5733 if (!pc_modified_) {
5734 set_register(pc, reinterpret_cast<int32_t>(instr) + kInstrSize);
5735 }
5736 }
5737
Execute()5738 void Simulator::Execute() {
5739 // Get the PC to simulate. Cannot use the accessor here as we need the
5740 // raw PC value and not the one used as input to arithmetic instructions.
5741 int program_counter = get_pc();
5742
5743 if (::v8::internal::FLAG_stop_sim_at == 0) {
5744 // Fast version of the dispatch loop without checking whether the simulator
5745 // should be stopping at a particular executed instruction.
5746 while (program_counter != end_sim_pc) {
5747 Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
5748 icount_++;
5749 InstructionDecode(instr);
5750 program_counter = get_pc();
5751 }
5752 } else {
5753 // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when
5754 // we reach the particular instruction count.
5755 while (program_counter != end_sim_pc) {
5756 Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
5757 icount_++;
5758 if (icount_ == ::v8::internal::FLAG_stop_sim_at) {
5759 ArmDebugger dbg(this);
5760 dbg.Debug();
5761 } else {
5762 InstructionDecode(instr);
5763 }
5764 program_counter = get_pc();
5765 }
5766 }
5767 }
5768
CallInternal(Address entry)5769 void Simulator::CallInternal(Address entry) {
5770 // Adjust JS-based stack limit to C-based stack limit.
5771 isolate_->stack_guard()->AdjustStackLimitForSimulator();
5772
5773 // Prepare to execute the code at entry
5774 set_register(pc, static_cast<int32_t>(entry));
5775 // Put down marker for end of simulation. The simulator will stop simulation
5776 // when the PC reaches this value. By saving the "end simulation" value into
5777 // the LR the simulation stops when returning to this call point.
5778 set_register(lr, end_sim_pc);
5779
5780 // Remember the values of callee-saved registers.
5781 // The code below assumes that r9 is not used as sb (static base) in
5782 // simulator code and therefore is regarded as a callee-saved register.
5783 int32_t r4_val = get_register(r4);
5784 int32_t r5_val = get_register(r5);
5785 int32_t r6_val = get_register(r6);
5786 int32_t r7_val = get_register(r7);
5787 int32_t r8_val = get_register(r8);
5788 int32_t r9_val = get_register(r9);
5789 int32_t r10_val = get_register(r10);
5790 int32_t r11_val = get_register(r11);
5791
5792 // Set up the callee-saved registers with a known value. To be able to check
5793 // that they are preserved properly across JS execution.
5794 int32_t callee_saved_value = icount_;
5795 set_register(r4, callee_saved_value);
5796 set_register(r5, callee_saved_value);
5797 set_register(r6, callee_saved_value);
5798 set_register(r7, callee_saved_value);
5799 set_register(r8, callee_saved_value);
5800 set_register(r9, callee_saved_value);
5801 set_register(r10, callee_saved_value);
5802 set_register(r11, callee_saved_value);
5803
5804 // Start the simulation
5805 Execute();
5806
5807 // Check that the callee-saved registers have been preserved.
5808 CHECK_EQ(callee_saved_value, get_register(r4));
5809 CHECK_EQ(callee_saved_value, get_register(r5));
5810 CHECK_EQ(callee_saved_value, get_register(r6));
5811 CHECK_EQ(callee_saved_value, get_register(r7));
5812 CHECK_EQ(callee_saved_value, get_register(r8));
5813 CHECK_EQ(callee_saved_value, get_register(r9));
5814 CHECK_EQ(callee_saved_value, get_register(r10));
5815 CHECK_EQ(callee_saved_value, get_register(r11));
5816
5817 // Restore callee-saved registers with the original value.
5818 set_register(r4, r4_val);
5819 set_register(r5, r5_val);
5820 set_register(r6, r6_val);
5821 set_register(r7, r7_val);
5822 set_register(r8, r8_val);
5823 set_register(r9, r9_val);
5824 set_register(r10, r10_val);
5825 set_register(r11, r11_val);
5826 }
5827
CallImpl(Address entry,int argument_count,const intptr_t * arguments)5828 intptr_t Simulator::CallImpl(Address entry, int argument_count,
5829 const intptr_t* arguments) {
5830 // Set up arguments
5831
5832 // First four arguments passed in registers.
5833 int reg_arg_count = std::min(4, argument_count);
5834 if (reg_arg_count > 0) set_register(r0, arguments[0]);
5835 if (reg_arg_count > 1) set_register(r1, arguments[1]);
5836 if (reg_arg_count > 2) set_register(r2, arguments[2]);
5837 if (reg_arg_count > 3) set_register(r3, arguments[3]);
5838
5839 // Remaining arguments passed on stack.
5840 int original_stack = get_register(sp);
5841 // Compute position of stack on entry to generated code.
5842 int entry_stack = (original_stack - (argument_count - 4) * sizeof(int32_t));
5843 if (base::OS::ActivationFrameAlignment() != 0) {
5844 entry_stack &= -base::OS::ActivationFrameAlignment();
5845 }
5846 // Store remaining arguments on stack, from low to high memory.
5847 memcpy(reinterpret_cast<intptr_t*>(entry_stack), arguments + reg_arg_count,
5848 (argument_count - reg_arg_count) * sizeof(*arguments));
5849 set_register(sp, entry_stack);
5850
5851 CallInternal(entry);
5852
5853 // Pop stack passed arguments.
5854 CHECK_EQ(entry_stack, get_register(sp));
5855 set_register(sp, original_stack);
5856
5857 return get_register(r0);
5858 }
5859
CallFPImpl(Address entry,double d0,double d1)5860 intptr_t Simulator::CallFPImpl(Address entry, double d0, double d1) {
5861 if (use_eabi_hardfloat()) {
5862 set_d_register_from_double(0, d0);
5863 set_d_register_from_double(1, d1);
5864 } else {
5865 set_register_pair_from_double(0, &d0);
5866 set_register_pair_from_double(2, &d1);
5867 }
5868 CallInternal(entry);
5869 return get_register(r0);
5870 }
5871
5872
PushAddress(uintptr_t address)5873 uintptr_t Simulator::PushAddress(uintptr_t address) {
5874 int new_sp = get_register(sp) - sizeof(uintptr_t);
5875 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp);
5876 *stack_slot = address;
5877 set_register(sp, new_sp);
5878 return new_sp;
5879 }
5880
5881
PopAddress()5882 uintptr_t Simulator::PopAddress() {
5883 int current_sp = get_register(sp);
5884 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp);
5885 uintptr_t address = *stack_slot;
5886 set_register(sp, current_sp + sizeof(uintptr_t));
5887 return address;
5888 }
5889
LocalMonitor()5890 Simulator::LocalMonitor::LocalMonitor()
5891 : access_state_(MonitorAccess::Open),
5892 tagged_addr_(0),
5893 size_(TransactionSize::None) {}
5894
Clear()5895 void Simulator::LocalMonitor::Clear() {
5896 access_state_ = MonitorAccess::Open;
5897 tagged_addr_ = 0;
5898 size_ = TransactionSize::None;
5899 }
5900
NotifyLoad(int32_t addr)5901 void Simulator::LocalMonitor::NotifyLoad(int32_t addr) {
5902 if (access_state_ == MonitorAccess::Exclusive) {
5903 // A load could cause a cache eviction which will affect the monitor. As a
5904 // result, it's most strict to unconditionally clear the local monitor on
5905 // load.
5906 Clear();
5907 }
5908 }
5909
NotifyLoadExcl(int32_t addr,TransactionSize size)5910 void Simulator::LocalMonitor::NotifyLoadExcl(int32_t addr,
5911 TransactionSize size) {
5912 access_state_ = MonitorAccess::Exclusive;
5913 tagged_addr_ = addr;
5914 size_ = size;
5915 }
5916
NotifyStore(int32_t addr)5917 void Simulator::LocalMonitor::NotifyStore(int32_t addr) {
5918 if (access_state_ == MonitorAccess::Exclusive) {
5919 // It is implementation-defined whether a non-exclusive store to an address
5920 // covered by the local monitor during exclusive access transitions to open
5921 // or exclusive access. See ARM DDI 0406C.b, A3.4.1.
5922 //
5923 // However, a store could cause a cache eviction which will affect the
5924 // monitor. As a result, it's most strict to unconditionally clear the
5925 // local monitor on store.
5926 Clear();
5927 }
5928 }
5929
NotifyStoreExcl(int32_t addr,TransactionSize size)5930 bool Simulator::LocalMonitor::NotifyStoreExcl(int32_t addr,
5931 TransactionSize size) {
5932 if (access_state_ == MonitorAccess::Exclusive) {
5933 // It is allowed for a processor to require that the address matches
5934 // exactly (A3.4.5), so this comparison does not mask addr.
5935 if (addr == tagged_addr_ && size_ == size) {
5936 Clear();
5937 return true;
5938 } else {
5939 // It is implementation-defined whether an exclusive store to a
5940 // non-tagged address will update memory. Behavior is unpredictable if
5941 // the transaction size of the exclusive store differs from that of the
5942 // exclusive load. See ARM DDI 0406C.b, A3.4.5.
5943 Clear();
5944 return false;
5945 }
5946 } else {
5947 DCHECK(access_state_ == MonitorAccess::Open);
5948 return false;
5949 }
5950 }
5951
Processor()5952 Simulator::GlobalMonitor::Processor::Processor()
5953 : access_state_(MonitorAccess::Open),
5954 tagged_addr_(0),
5955 next_(nullptr),
5956 prev_(nullptr),
5957 failure_counter_(0) {}
5958
Clear_Locked()5959 void Simulator::GlobalMonitor::Processor::Clear_Locked() {
5960 access_state_ = MonitorAccess::Open;
5961 tagged_addr_ = 0;
5962 }
5963
NotifyLoadExcl_Locked(int32_t addr)5964 void Simulator::GlobalMonitor::Processor::NotifyLoadExcl_Locked(int32_t addr) {
5965 access_state_ = MonitorAccess::Exclusive;
5966 tagged_addr_ = addr;
5967 }
5968
NotifyStore_Locked(int32_t addr,bool is_requesting_processor)5969 void Simulator::GlobalMonitor::Processor::NotifyStore_Locked(
5970 int32_t addr, bool is_requesting_processor) {
5971 if (access_state_ == MonitorAccess::Exclusive) {
5972 // It is implementation-defined whether a non-exclusive store by the
5973 // requesting processor to an address covered by the global monitor
5974 // during exclusive access transitions to open or exclusive access.
5975 //
5976 // For any other processor, the access state always transitions to open
5977 // access.
5978 //
5979 // See ARM DDI 0406C.b, A3.4.2.
5980 //
5981 // However, similar to the local monitor, it is possible that a store
5982 // caused a cache eviction, which can affect the montior, so
5983 // conservatively, we always clear the monitor.
5984 Clear_Locked();
5985 }
5986 }
5987
NotifyStoreExcl_Locked(int32_t addr,bool is_requesting_processor)5988 bool Simulator::GlobalMonitor::Processor::NotifyStoreExcl_Locked(
5989 int32_t addr, bool is_requesting_processor) {
5990 if (access_state_ == MonitorAccess::Exclusive) {
5991 if (is_requesting_processor) {
5992 // It is allowed for a processor to require that the address matches
5993 // exactly (A3.4.5), so this comparison does not mask addr.
5994 if (addr == tagged_addr_) {
5995 // The access state for the requesting processor after a successful
5996 // exclusive store is implementation-defined, but according to the ARM
5997 // DDI, this has no effect on the subsequent operation of the global
5998 // monitor.
5999 Clear_Locked();
6000 // Introduce occasional strex failures. This is to simulate the
6001 // behavior of hardware, which can randomly fail due to background
6002 // cache evictions.
6003 if (failure_counter_++ >= kMaxFailureCounter) {
6004 failure_counter_ = 0;
6005 return false;
6006 } else {
6007 return true;
6008 }
6009 }
6010 } else if ((addr & kExclusiveTaggedAddrMask) ==
6011 (tagged_addr_ & kExclusiveTaggedAddrMask)) {
6012 // Check the masked addresses when responding to a successful lock by
6013 // another processor so the implementation is more conservative (i.e. the
6014 // granularity of locking is as large as possible.)
6015 Clear_Locked();
6016 return false;
6017 }
6018 }
6019 return false;
6020 }
6021
GlobalMonitor()6022 Simulator::GlobalMonitor::GlobalMonitor() : head_(nullptr) {}
6023
NotifyLoadExcl_Locked(int32_t addr,Processor * processor)6024 void Simulator::GlobalMonitor::NotifyLoadExcl_Locked(int32_t addr,
6025 Processor* processor) {
6026 processor->NotifyLoadExcl_Locked(addr);
6027 PrependProcessor_Locked(processor);
6028 }
6029
NotifyStore_Locked(int32_t addr,Processor * processor)6030 void Simulator::GlobalMonitor::NotifyStore_Locked(int32_t addr,
6031 Processor* processor) {
6032 // Notify each processor of the store operation.
6033 for (Processor* iter = head_; iter; iter = iter->next_) {
6034 bool is_requesting_processor = iter == processor;
6035 iter->NotifyStore_Locked(addr, is_requesting_processor);
6036 }
6037 }
6038
NotifyStoreExcl_Locked(int32_t addr,Processor * processor)6039 bool Simulator::GlobalMonitor::NotifyStoreExcl_Locked(int32_t addr,
6040 Processor* processor) {
6041 DCHECK(IsProcessorInLinkedList_Locked(processor));
6042 if (processor->NotifyStoreExcl_Locked(addr, true)) {
6043 // Notify the other processors that this StoreExcl succeeded.
6044 for (Processor* iter = head_; iter; iter = iter->next_) {
6045 if (iter != processor) {
6046 iter->NotifyStoreExcl_Locked(addr, false);
6047 }
6048 }
6049 return true;
6050 } else {
6051 return false;
6052 }
6053 }
6054
IsProcessorInLinkedList_Locked(Processor * processor) const6055 bool Simulator::GlobalMonitor::IsProcessorInLinkedList_Locked(
6056 Processor* processor) const {
6057 return head_ == processor || processor->next_ || processor->prev_;
6058 }
6059
PrependProcessor_Locked(Processor * processor)6060 void Simulator::GlobalMonitor::PrependProcessor_Locked(Processor* processor) {
6061 if (IsProcessorInLinkedList_Locked(processor)) {
6062 return;
6063 }
6064
6065 if (head_) {
6066 head_->prev_ = processor;
6067 }
6068 processor->prev_ = nullptr;
6069 processor->next_ = head_;
6070 head_ = processor;
6071 }
6072
RemoveProcessor(Processor * processor)6073 void Simulator::GlobalMonitor::RemoveProcessor(Processor* processor) {
6074 base::LockGuard<base::Mutex> lock_guard(&mutex);
6075 if (!IsProcessorInLinkedList_Locked(processor)) {
6076 return;
6077 }
6078
6079 if (processor->prev_) {
6080 processor->prev_->next_ = processor->next_;
6081 } else {
6082 head_ = processor->next_;
6083 }
6084 if (processor->next_) {
6085 processor->next_->prev_ = processor->prev_;
6086 }
6087 processor->prev_ = nullptr;
6088 processor->next_ = nullptr;
6089 }
6090
6091 } // namespace internal
6092 } // namespace v8
6093
6094 #endif // USE_SIMULATOR
6095
6096 #endif // V8_TARGET_ARCH_ARM
6097