1// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include <setjmp.h> // NOLINT
6#include <stdlib.h>
7
8#include "vm/globals.h"
9#if defined(TARGET_ARCH_ARM)
10
11// Only build the simulator if not compiling for real ARM hardware.
12#if defined(USING_SIMULATOR)
13
14#include "vm/simulator.h"
15
16#include "vm/compiler/assembler/disassembler.h"
17#include "vm/constants.h"
18#include "vm/cpu.h"
19#include "vm/image_snapshot.h"
20#include "vm/native_arguments.h"
21#include "vm/os_thread.h"
22#include "vm/stack_frame.h"
23
24namespace dart {
25
26// constants_arm.h does not define LR constant to prevent accidental direct use
27// of it during code generation. However using LR directly is okay in this
28// file because it is a simulator.
29constexpr Register LR = LR_DO_NOT_USE_DIRECTLY;
30
31DEFINE_FLAG(uint64_t,
32 trace_sim_after,
33 ULLONG_MAX,
34 "Trace simulator execution after instruction count reached.");
35DEFINE_FLAG(uint64_t,
36 stop_sim_at,
37 ULLONG_MAX,
38 "Instruction address or instruction count to stop simulator at.");
39
40// This macro provides a platform independent use of sscanf. The reason for
41// SScanF not being implemented in a platform independent way through
42// OS in the same way as SNPrint is that the Windows C Run-Time
43// Library does not provide vsscanf.
44#define SScanF sscanf // NOLINT
45
46// SimulatorSetjmpBuffer are linked together, and the last created one
47// is referenced by the Simulator. When an exception is thrown, the exception
48// runtime looks at where to jump and finds the corresponding
49// SimulatorSetjmpBuffer based on the stack pointer of the exception handler.
50// The runtime then does a Longjmp on that buffer to return to the simulator.
51class SimulatorSetjmpBuffer {
52 public:
53 void Longjmp() {
54 // "This" is now the last setjmp buffer.
55 simulator_->set_last_setjmp_buffer(this);
56 longjmp(buffer_, 1);
57 }
58
59 explicit SimulatorSetjmpBuffer(Simulator* sim) {
60 simulator_ = sim;
61 link_ = sim->last_setjmp_buffer();
62 sim->set_last_setjmp_buffer(this);
63 sp_ = static_cast<uword>(sim->get_register(SP));
64 }
65
66 ~SimulatorSetjmpBuffer() {
67 ASSERT(simulator_->last_setjmp_buffer() == this);
68 simulator_->set_last_setjmp_buffer(link_);
69 }
70
71 SimulatorSetjmpBuffer* link() { return link_; }
72
73 uword sp() { return sp_; }
74
75 private:
76 uword sp_;
77 Simulator* simulator_;
78 SimulatorSetjmpBuffer* link_;
79 jmp_buf buffer_;
80
81 friend class Simulator;
82};
83
84// The SimulatorDebugger class is used by the simulator while debugging
85// simulated ARM code.
86class SimulatorDebugger {
87 public:
88 explicit SimulatorDebugger(Simulator* sim);
89 ~SimulatorDebugger();
90
91 void Stop(Instr* instr, const char* message);
92 void Debug();
93 char* ReadLine(const char* prompt);
94
95 private:
96 Simulator* sim_;
97
98 bool GetValue(char* desc, uint32_t* value);
99 bool GetFValue(char* desc, float* value);
100 bool GetDValue(char* desc, double* value);
101
102 static TokenPosition GetApproximateTokenIndex(const Code& code, uword pc);
103
104 static void PrintDartFrame(uword vm_instructions,
105 uword isolate_instructions,
106 uword pc,
107 uword fp,
108 uword sp,
109 const Function& function,
110 TokenPosition token_pos,
111 bool is_optimized,
112 bool is_inlined);
113 void PrintBacktrace();
114
115 // Set or delete a breakpoint. Returns true if successful.
116 bool SetBreakpoint(Instr* breakpc);
117 bool DeleteBreakpoint(Instr* breakpc);
118
119 // Undo and redo all breakpoints. This is needed to bracket disassembly and
120 // execution to skip past breakpoints when run from the debugger.
121 void UndoBreakpoints();
122 void RedoBreakpoints();
123};
124
125SimulatorDebugger::SimulatorDebugger(Simulator* sim) {
126 sim_ = sim;
127}
128
129SimulatorDebugger::~SimulatorDebugger() {}
130
131void SimulatorDebugger::Stop(Instr* instr, const char* message) {
132 OS::PrintErr("Simulator hit %s\n", message);
133 Debug();
134}
135
136static Register LookupCpuRegisterByName(const char* name) {
137 static const char* const kNames[] = {
138 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",
139 "r11", "r12", "r13", "r14", "r15", "pc", "lr", "sp", "ip", "fp", "pp"};
140 static const Register kRegisters[] = {R0, R1, R2, R3, R4, R5, R6, R7,
141 R8, R9, R10, R11, R12, R13, R14, R15,
142 PC, LR, SP, IP, FP, PP};
143 ASSERT(ARRAY_SIZE(kNames) == ARRAY_SIZE(kRegisters));
144 for (unsigned i = 0; i < ARRAY_SIZE(kNames); i++) {
145 if (strcmp(kNames[i], name) == 0) {
146 return kRegisters[i];
147 }
148 }
149 return kNoRegister;
150}
151
152static SRegister LookupSRegisterByName(const char* name) {
153 int reg_nr = -1;
154 bool ok = SScanF(name, "s%d", &reg_nr);
155 if (ok && (0 <= reg_nr) && (reg_nr < kNumberOfSRegisters)) {
156 return static_cast<SRegister>(reg_nr);
157 }
158 return kNoSRegister;
159}
160
161static DRegister LookupDRegisterByName(const char* name) {
162 int reg_nr = -1;
163 bool ok = SScanF(name, "d%d", &reg_nr);
164 if (ok && (0 <= reg_nr) && (reg_nr < kNumberOfDRegisters)) {
165 return static_cast<DRegister>(reg_nr);
166 }
167 return kNoDRegister;
168}
169
170bool SimulatorDebugger::GetValue(char* desc, uint32_t* value) {
171 Register reg = LookupCpuRegisterByName(desc);
172 if (reg != kNoRegister) {
173 if (reg == PC) {
174 *value = sim_->get_pc();
175 } else {
176 *value = sim_->get_register(reg);
177 }
178 return true;
179 }
180 if (desc[0] == '*') {
181 uint32_t addr;
182 if (GetValue(desc + 1, &addr)) {
183 if (Simulator::IsIllegalAddress(addr)) {
184 return false;
185 }
186 *value = *(reinterpret_cast<uint32_t*>(addr));
187 return true;
188 }
189 }
190 bool retval = SScanF(desc, "0x%x", value) == 1;
191 if (!retval) {
192 retval = SScanF(desc, "%x", value) == 1;
193 }
194 return retval;
195}
196
197bool SimulatorDebugger::GetFValue(char* desc, float* value) {
198 SRegister sreg = LookupSRegisterByName(desc);
199 if (sreg != kNoSRegister) {
200 *value = sim_->get_sregister(sreg);
201 return true;
202 }
203 if (desc[0] == '*') {
204 uint32_t addr;
205 if (GetValue(desc + 1, &addr)) {
206 if (Simulator::IsIllegalAddress(addr)) {
207 return false;
208 }
209 *value = *(reinterpret_cast<float*>(addr));
210 return true;
211 }
212 }
213 return false;
214}
215
216bool SimulatorDebugger::GetDValue(char* desc, double* value) {
217 DRegister dreg = LookupDRegisterByName(desc);
218 if (dreg != kNoDRegister) {
219 *value = sim_->get_dregister(dreg);
220 return true;
221 }
222 if (desc[0] == '*') {
223 uint32_t addr;
224 if (GetValue(desc + 1, &addr)) {
225 if (Simulator::IsIllegalAddress(addr)) {
226 return false;
227 }
228 *value = *(reinterpret_cast<double*>(addr));
229 return true;
230 }
231 }
232 return false;
233}
234
235TokenPosition SimulatorDebugger::GetApproximateTokenIndex(const Code& code,
236 uword pc) {
237 TokenPosition token_pos = TokenPosition::kNoSource;
238 uword pc_offset = pc - code.PayloadStart();
239 const PcDescriptors& descriptors =
240 PcDescriptors::Handle(code.pc_descriptors());
241 PcDescriptors::Iterator iter(descriptors, UntaggedPcDescriptors::kAnyKind);
242 while (iter.MoveNext()) {
243 if (iter.PcOffset() == pc_offset) {
244 return iter.TokenPos();
245 } else if (!token_pos.IsReal() && (iter.PcOffset() > pc_offset)) {
246 token_pos = iter.TokenPos();
247 }
248 }
249 return token_pos;
250}
251
252#if defined(DART_PRECOMPILED_RUNTIME)
253static const char* ImageName(uword vm_instructions,
254 uword isolate_instructions,
255 uword pc,
256 intptr_t* offset) {
257 const Image vm_image(vm_instructions);
258 const Image isolate_image(isolate_instructions);
259 if (vm_image.contains(pc)) {
260 *offset = pc - vm_instructions;
261 return kVmSnapshotInstructionsAsmSymbol;
262 } else if (isolate_image.contains(pc)) {
263 *offset = pc - isolate_instructions;
264 return kIsolateSnapshotInstructionsAsmSymbol;
265 } else {
266 *offset = 0;
267 return "<unknown>";
268 }
269}
270#endif
271
272void SimulatorDebugger::PrintDartFrame(uword vm_instructions,
273 uword isolate_instructions,
274 uword pc,
275 uword fp,
276 uword sp,
277 const Function& function,
278 TokenPosition token_pos,
279 bool is_optimized,
280 bool is_inlined) {
281 const Script& script = Script::Handle(function.script());
282 const String& func_name = String::Handle(function.QualifiedScrubbedName());
283 const String& url = String::Handle(script.url());
284 intptr_t line, column;
285 if (script.GetTokenLocation(token_pos, &line, &column)) {
286 OS::PrintErr(
287 "pc=0x%" Px " fp=0x%" Px " sp=0x%" Px " %s%s (%s:%" Pd ":%" Pd ")", pc,
288 fp, sp, is_optimized ? (is_inlined ? "inlined " : "optimized ") : "",
289 func_name.ToCString(), url.ToCString(), line, column);
290
291 } else {
292 OS::PrintErr("pc=0x%" Px " fp=0x%" Px " sp=0x%" Px " %s%s (%s)", pc, fp, sp,
293 is_optimized ? (is_inlined ? "inlined " : "optimized ") : "",
294 func_name.ToCString(), url.ToCString());
295 }
296#if defined(DART_PRECOMPILED_RUNTIME)
297 intptr_t offset;
298 auto const symbol_name =
299 ImageName(vm_instructions, isolate_instructions, pc, &offset);
300 OS::PrintErr(" %s+0x%" Px "", symbol_name, offset);
301#endif
302 OS::PrintErr("\n");
303}
304
305void SimulatorDebugger::PrintBacktrace() {
306 auto const T = Thread::Current();
307 auto const Z = T->zone();
308#if defined(DART_PRECOMPILED_RUNTIME)
309 auto const vm_instructions = reinterpret_cast<uword>(
310 Dart::vm_isolate_group()->source()->snapshot_instructions);
311 auto const isolate_instructions = reinterpret_cast<uword>(
312 T->isolate_group()->source()->snapshot_instructions);
313 OS::PrintErr("vm_instructions=0x%" Px ", isolate_instructions=0x%" Px "\n",
314 vm_instructions, isolate_instructions);
315#else
316 const uword vm_instructions = 0;
317 const uword isolate_instructions = 0;
318#endif
319 StackFrameIterator frames(sim_->get_register(FP), sim_->get_register(SP),
320 sim_->get_pc(),
321 ValidationPolicy::kDontValidateFrames, T,
322 StackFrameIterator::kNoCrossThreadIteration);
323 StackFrame* frame = frames.NextFrame();
324 ASSERT(frame != nullptr);
325 Function& function = Function::Handle(Z);
326 Function& inlined_function = Function::Handle(Z);
327 Code& code = Code::Handle(Z);
328 Code& unoptimized_code = Code::Handle(Z);
329 while (frame != nullptr) {
330 if (frame->IsDartFrame()) {
331 code = frame->LookupDartCode();
332 function = code.function();
333 if (code.is_optimized()) {
334 // For optimized frames, extract all the inlined functions if any
335 // into the stack trace.
336 InlinedFunctionsIterator it(code, frame->pc());
337 while (!it.Done()) {
338 // Print each inlined frame with its pc in the corresponding
339 // unoptimized frame.
340 inlined_function = it.function();
341 unoptimized_code = it.code();
342 uword unoptimized_pc = it.pc();
343 it.Advance();
344 if (!it.Done()) {
345 PrintDartFrame(
346 vm_instructions, isolate_instructions, unoptimized_pc,
347 frame->fp(), frame->sp(), inlined_function,
348 GetApproximateTokenIndex(unoptimized_code, unoptimized_pc),
349 true, true);
350 }
351 }
352 // Print the optimized inlining frame below.
353 }
354 PrintDartFrame(vm_instructions, isolate_instructions, frame->pc(),
355 frame->fp(), frame->sp(), function,
356 GetApproximateTokenIndex(code, frame->pc()),
357 code.is_optimized(), false);
358 } else {
359 OS::PrintErr("pc=0x%" Px " fp=0x%" Px " sp=0x%" Px " %s frame",
360 frame->pc(), frame->fp(), frame->sp(),
361 frame->IsEntryFrame()
362 ? "entry"
363 : frame->IsExitFrame()
364 ? "exit"
365 : frame->IsStubFrame() ? "stub" : "invalid");
366#if defined(DART_PRECOMPILED_RUNTIME)
367 intptr_t offset;
368 auto const symbol_name = ImageName(vm_instructions, isolate_instructions,
369 frame->pc(), &offset);
370 OS::PrintErr(" %s+0x%" Px "", symbol_name, offset);
371#endif
372 OS::PrintErr("\n");
373 }
374 frame = frames.NextFrame();
375 }
376}
377
378bool SimulatorDebugger::SetBreakpoint(Instr* breakpc) {
379 // Check if a breakpoint can be set. If not return without any side-effects.
380 if (sim_->break_pc_ != nullptr) {
381 return false;
382 }
383
384 // Set the breakpoint.
385 sim_->break_pc_ = breakpc;
386 sim_->break_instr_ = breakpc->InstructionBits();
387 // Not setting the breakpoint instruction in the code itself. It will be set
388 // when the debugger shell continues.
389 return true;
390}
391
392bool SimulatorDebugger::DeleteBreakpoint(Instr* breakpc) {
393 if (sim_->break_pc_ != nullptr) {
394 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
395 }
396
397 sim_->break_pc_ = nullptr;
398 sim_->break_instr_ = 0;
399 return true;
400}
401
402void SimulatorDebugger::UndoBreakpoints() {
403 if (sim_->break_pc_ != nullptr) {
404 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
405 }
406}
407
408void SimulatorDebugger::RedoBreakpoints() {
409 if (sim_->break_pc_ != nullptr) {
410 sim_->break_pc_->SetInstructionBits(Instr::kSimulatorBreakpointInstruction);
411 }
412}
413
414void SimulatorDebugger::Debug() {
415 intptr_t last_pc = -1;
416 bool done = false;
417
418#define COMMAND_SIZE 63
419#define ARG_SIZE 255
420
421#define STR(a) #a
422#define XSTR(a) STR(a)
423
424 char cmd[COMMAND_SIZE + 1];
425 char arg1[ARG_SIZE + 1];
426 char arg2[ARG_SIZE + 1];
427
428 // make sure to have a proper terminating character if reaching the limit
429 cmd[COMMAND_SIZE] = 0;
430 arg1[ARG_SIZE] = 0;
431 arg2[ARG_SIZE] = 0;
432
433 // Undo all set breakpoints while running in the debugger shell. This will
434 // make them invisible to all commands.
435 UndoBreakpoints();
436
437 while (!done) {
438 if (last_pc != sim_->get_pc()) {
439 last_pc = sim_->get_pc();
440 if (Simulator::IsIllegalAddress(last_pc)) {
441 OS::PrintErr("pc is out of bounds: 0x%" Px "\n", last_pc);
442 } else {
443 if (FLAG_support_disassembler) {
444 Disassembler::Disassemble(last_pc, last_pc + Instr::kInstrSize);
445 } else {
446 OS::PrintErr("Disassembler not supported in this mode.\n");
447 }
448 }
449 }
450 char* line = ReadLine("sim> ");
451 if (line == nullptr) {
452 FATAL("ReadLine failed");
453 } else {
454 // Use sscanf to parse the individual parts of the command line. At the
455 // moment no command expects more than two parameters.
456 int args = SScanF(line,
457 "%" XSTR(COMMAND_SIZE) "s "
458 "%" XSTR(ARG_SIZE) "s "
459 "%" XSTR(ARG_SIZE) "s",
460 cmd, arg1, arg2);
461 if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
462 OS::PrintErr(
463 "c/cont -- continue execution\n"
464 "disasm -- disassemble instrs at current pc location\n"
465 " other variants are:\n"
466 " disasm <address>\n"
467 " disasm <address> <number_of_instructions>\n"
468 " by default 10 instrs are disassembled\n"
469 "del -- delete breakpoints\n"
470 "flags -- print flag values\n"
471 "gdb -- transfer control to gdb\n"
472 "h/help -- print this help string\n"
473 "break <address> -- set break point at specified address\n"
474 "p/print <reg or icount or value or *addr> -- print integer\n"
475 "ps/printsingle <sreg or *addr> -- print float value\n"
476 "pd/printdouble <dreg or *addr> -- print double value\n"
477 "po/printobject <*reg or *addr> -- print object\n"
478 "si/stepi -- single step an instruction\n"
479 "trace -- toggle execution tracing mode\n"
480 "bt -- print backtrace\n"
481 "unstop -- if current pc is a stop instr make it a nop\n"
482 "q/quit -- Quit the debugger and exit the program\n");
483 } else if ((strcmp(cmd, "quit") == 0) || (strcmp(cmd, "q") == 0)) {
484 OS::PrintErr("Quitting\n");
485 OS::Exit(0);
486 } else if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
487 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc()));
488 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) {
489 // Execute the one instruction we broke at with breakpoints disabled.
490 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc()));
491 // Leave the debugger shell.
492 done = true;
493 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
494 if (args == 2) {
495 uint32_t value;
496 if (strcmp(arg1, "icount") == 0) {
497 const uint64_t icount = sim_->get_icount();
498 OS::PrintErr("icount: %" Pu64 " 0x%" Px64 "\n", icount, icount);
499 } else if (GetValue(arg1, &value)) {
500 OS::PrintErr("%s: %u 0x%x\n", arg1, value, value);
501 } else {
502 OS::PrintErr("%s unrecognized\n", arg1);
503 }
504 } else {
505 OS::PrintErr("print <reg or icount or value or *addr>\n");
506 }
507 } else if ((strcmp(cmd, "ps") == 0) ||
508 (strcmp(cmd, "printsingle") == 0)) {
509 if (args == 2) {
510 float fvalue;
511 if (GetFValue(arg1, &fvalue)) {
512 uint32_t value = bit_cast<uint32_t, float>(fvalue);
513 OS::PrintErr("%s: 0%u 0x%x %.8g\n", arg1, value, value, fvalue);
514 } else {
515 OS::PrintErr("%s unrecognized\n", arg1);
516 }
517 } else {
518 OS::PrintErr("printfloat <sreg or *addr>\n");
519 }
520 } else if ((strcmp(cmd, "pd") == 0) ||
521 (strcmp(cmd, "printdouble") == 0)) {
522 if (args == 2) {
523 double dvalue;
524 if (GetDValue(arg1, &dvalue)) {
525 uint64_t long_value = bit_cast<uint64_t, double>(dvalue);
526 OS::PrintErr("%s: %llu 0x%llx %.8g\n", arg1, long_value, long_value,
527 dvalue);
528 } else {
529 OS::PrintErr("%s unrecognized\n", arg1);
530 }
531 } else {
532 OS::PrintErr("printdouble <dreg or *addr>\n");
533 }
534 } else if ((strcmp(cmd, "po") == 0) ||
535 (strcmp(cmd, "printobject") == 0)) {
536 if (args == 2) {
537 uint32_t value;
538 // Make the dereferencing '*' optional.
539 if (((arg1[0] == '*') && GetValue(arg1 + 1, &value)) ||
540 GetValue(arg1, &value)) {
541 if (IsolateGroup::Current()->heap()->Contains(value)) {
542 OS::PrintErr("%s: \n", arg1);
543#if defined(DEBUG)
544 const Object& obj = Object::Handle(static_cast<ObjectPtr>(value));
545 obj.Print();
546#endif // defined(DEBUG)
547 } else {
548 OS::PrintErr("0x%x is not an object reference\n", value);
549 }
550 } else {
551 OS::PrintErr("%s unrecognized\n", arg1);
552 }
553 } else {
554 OS::PrintErr("printobject <*reg or *addr>\n");
555 }
556 } else if (strcmp(cmd, "disasm") == 0) {
557 uint32_t start = 0;
558 uint32_t end = 0;
559 if (args == 1) {
560 start = sim_->get_pc();
561 end = start + (10 * Instr::kInstrSize);
562 } else if (args == 2) {
563 if (GetValue(arg1, &start)) {
564 // No length parameter passed, assume 10 instructions.
565 if (Simulator::IsIllegalAddress(start)) {
566 // If start isn't a valid address, warn and use PC instead.
567 OS::PrintErr("First argument yields invalid address: 0x%x\n",
568 start);
569 OS::PrintErr("Using PC instead\n");
570 start = sim_->get_pc();
571 }
572 end = start + (10 * Instr::kInstrSize);
573 }
574 } else {
575 uint32_t length;
576 if (GetValue(arg1, &start) && GetValue(arg2, &length)) {
577 if (Simulator::IsIllegalAddress(start)) {
578 // If start isn't a valid address, warn and use PC instead.
579 OS::PrintErr("First argument yields invalid address: 0x%x\n",
580 start);
581 OS::PrintErr("Using PC instead\n");
582 start = sim_->get_pc();
583 }
584 end = start + (length * Instr::kInstrSize);
585 }
586 }
587 if ((start > 0) && (end > start)) {
588 if (FLAG_support_disassembler) {
589 Disassembler::Disassemble(start, end);
590 } else {
591 OS::PrintErr("Disassembler not supported in this mode.\n");
592 }
593 } else {
594 OS::PrintErr("disasm [<address> [<number_of_instructions>]]\n");
595 }
596 } else if (strcmp(cmd, "gdb") == 0) {
597 OS::PrintErr("relinquishing control to gdb\n");
598 OS::DebugBreak();
599 OS::PrintErr("regaining control from gdb\n");
600 } else if (strcmp(cmd, "break") == 0) {
601 if (args == 2) {
602 uint32_t addr;
603 if (GetValue(arg1, &addr)) {
604 if (!SetBreakpoint(reinterpret_cast<Instr*>(addr))) {
605 OS::PrintErr("setting breakpoint failed\n");
606 }
607 } else {
608 OS::PrintErr("%s unrecognized\n", arg1);
609 }
610 } else {
611 OS::PrintErr("break <addr>\n");
612 }
613 } else if (strcmp(cmd, "del") == 0) {
614 if (!DeleteBreakpoint(nullptr)) {
615 OS::PrintErr("deleting breakpoint failed\n");
616 }
617 } else if (strcmp(cmd, "flags") == 0) {
618 OS::PrintErr("APSR: ");
619 OS::PrintErr("N flag: %d; ", sim_->n_flag_);
620 OS::PrintErr("Z flag: %d; ", sim_->z_flag_);
621 OS::PrintErr("C flag: %d; ", sim_->c_flag_);
622 OS::PrintErr("V flag: %d\n", sim_->v_flag_);
623 OS::PrintErr("FPSCR: ");
624 OS::PrintErr("N flag: %d; ", sim_->fp_n_flag_);
625 OS::PrintErr("Z flag: %d; ", sim_->fp_z_flag_);
626 OS::PrintErr("C flag: %d; ", sim_->fp_c_flag_);
627 OS::PrintErr("V flag: %d\n", sim_->fp_v_flag_);
628 } else if (strcmp(cmd, "unstop") == 0) {
629 intptr_t stop_pc = sim_->get_pc() - Instr::kInstrSize;
630 Instr* stop_instr = reinterpret_cast<Instr*>(stop_pc);
631 if (stop_instr->IsSvc() || stop_instr->IsBkpt()) {
632 stop_instr->SetInstructionBits(Instr::kNopInstruction);
633 } else {
634 OS::PrintErr("Not at debugger stop.\n");
635 }
636 } else if (strcmp(cmd, "trace") == 0) {
637 if (FLAG_trace_sim_after == ULLONG_MAX) {
638 FLAG_trace_sim_after = sim_->get_icount();
639 OS::PrintErr("execution tracing on\n");
640 } else {
641 FLAG_trace_sim_after = ULLONG_MAX;
642 OS::PrintErr("execution tracing off\n");
643 }
644 } else if (strcmp(cmd, "bt") == 0) {
645 Thread* thread = reinterpret_cast<Thread*>(sim_->get_register(THR));
646 thread->set_execution_state(Thread::kThreadInVM);
647 PrintBacktrace();
648 thread->set_execution_state(Thread::kThreadInGenerated);
649 } else {
650 OS::PrintErr("Unknown command: %s\n", cmd);
651 }
652 }
653 delete[] line;
654 }
655
656 // Add all the breakpoints back to stop execution and enter the debugger
657 // shell when hit.
658 RedoBreakpoints();
659
660#undef COMMAND_SIZE
661#undef ARG_SIZE
662
663#undef STR
664#undef XSTR
665}
666
667char* SimulatorDebugger::ReadLine(const char* prompt) {
668 char* result = nullptr;
669 char line_buf[256];
670 intptr_t offset = 0;
671 bool keep_going = true;
672 OS::PrintErr("%s", prompt);
673 while (keep_going) {
674 if (fgets(line_buf, sizeof(line_buf), stdin) == nullptr) {
675 // fgets got an error. Just give up.
676 if (result != nullptr) {
677 delete[] result;
678 }
679 return nullptr;
680 }
681 intptr_t len = strlen(line_buf);
682 if (len > 1 && line_buf[len - 2] == '\\' && line_buf[len - 1] == '\n') {
683 // When we read a line that ends with a "\" we remove the escape and
684 // append the remainder.
685 line_buf[len - 2] = '\n';
686 line_buf[len - 1] = 0;
687 len -= 1;
688 } else if ((len > 0) && (line_buf[len - 1] == '\n')) {
689 // Since we read a new line we are done reading the line. This
690 // will exit the loop after copying this buffer into the result.
691 keep_going = false;
692 }
693 if (result == nullptr) {
694 // Allocate the initial result and make room for the terminating '\0'
695 result = new char[len + 1];
696 if (result == nullptr) {
697 // OOM, so cannot readline anymore.
698 return nullptr;
699 }
700 } else {
701 // Allocate a new result with enough room for the new addition.
702 intptr_t new_len = offset + len + 1;
703 char* new_result = new char[new_len];
704 if (new_result == nullptr) {
705 // OOM, free the buffer allocated so far and return nullptr.
706 delete[] result;
707 return nullptr;
708 } else {
709 // Copy the existing input into the new array and set the new
710 // array as the result.
711 memmove(new_result, result, offset);
712 delete[] result;
713 result = new_result;
714 }
715 }
716 // Copy the newly read line into the result.
717 memmove(result + offset, line_buf, len);
718 offset += len;
719 }
720 ASSERT(result != nullptr);
721 result[offset] = '\0';
722 return result;
723}
724
725void Simulator::Init() {}
726
727Simulator::Simulator() : exclusive_access_addr_(0), exclusive_access_value_(0) {
728 // Setup simulator support first. Some of this information is needed to
729 // setup the architecture state.
730 // We allocate the stack here, the size is computed as the sum of
731 // the size specified by the user and the buffer space needed for
732 // handling stack overflow exceptions. To be safe in potential
733 // stack underflows we also add some underflow buffer space.
734 stack_ =
735 new char[(OSThread::GetSpecifiedStackSize() +
736 OSThread::kStackSizeBufferMax + kSimulatorStackUnderflowSize)];
737 // Low address.
738 stack_limit_ = reinterpret_cast<uword>(stack_);
739 // Limit for StackOverflowError.
740 overflow_stack_limit_ = stack_limit_ + OSThread::kStackSizeBufferMax;
741 // High address.
742 stack_base_ = overflow_stack_limit_ + OSThread::GetSpecifiedStackSize();
743
744 pc_modified_ = false;
745 icount_ = 0;
746 break_pc_ = nullptr;
747 break_instr_ = 0;
748 last_setjmp_buffer_ = nullptr;
749
750 // Setup architecture state.
751 // All registers are initialized to zero to start with.
752 for (int i = 0; i < kNumberOfCpuRegisters; i++) {
753 registers_[i] = 0;
754 }
755 n_flag_ = false;
756 z_flag_ = false;
757 c_flag_ = false;
758 v_flag_ = false;
759
760 // The sp is initialized to point to the bottom (high address) of the
761 // allocated stack area.
762 registers_[SP] = stack_base();
763 // The lr and pc are initialized to a known bad value that will cause an
764 // access violation if the simulator ever tries to execute it.
765 registers_[PC] = kBadLR;
766 registers_[LR] = kBadLR;
767
768 // All double-precision registers are initialized to zero.
769 for (int i = 0; i < kNumberOfDRegisters; i++) {
770 dregisters_[i] = 0;
771 }
772 // Since VFP registers are overlapping, single-precision registers should
773 // already be initialized.
774 ASSERT(2 * kNumberOfDRegisters >= kNumberOfSRegisters);
775 for (int i = 0; i < kNumberOfSRegisters; i++) {
776 ASSERT(sregisters_[i] == 0.0);
777 }
778 fp_n_flag_ = false;
779 fp_z_flag_ = false;
780 fp_c_flag_ = false;
781 fp_v_flag_ = false;
782}
783
784Simulator::~Simulator() {
785 delete[] stack_;
786 Isolate* isolate = Isolate::Current();
787 if (isolate != nullptr) {
788 isolate->set_simulator(nullptr);
789 }
790}
791
792// When the generated code calls an external reference we need to catch that in
793// the simulator. The external reference will be a function compiled for the
794// host architecture. We need to call that function instead of trying to
795// execute it with the simulator. We do that by redirecting the external
796// reference to a svc (supervisor call) instruction that is handled by
797// the simulator. We write the original destination of the jump just at a known
798// offset from the svc instruction so the simulator knows what to call.
799class Redirection {
800 public:
801 uword address_of_svc_instruction() {
802 return reinterpret_cast<uword>(&svc_instruction_);
803 }
804
805 uword external_function() const { return external_function_; }
806
807 Simulator::CallKind call_kind() const { return call_kind_; }
808
809 int argument_count() const { return argument_count_; }
810
811 static Redirection* Get(uword external_function,
812 Simulator::CallKind call_kind,
813 int argument_count) {
814 MutexLocker ml(mutex_);
815
816 Redirection* old_head = list_.load(std::memory_order_relaxed);
817 for (Redirection* current = old_head; current != nullptr;
818 current = current->next_) {
819 if (current->external_function_ == external_function) return current;
820 }
821
822 Redirection* redirection =
823 new Redirection(external_function, call_kind, argument_count);
824 redirection->next_ = old_head;
825
826 // Use a memory fence to ensure all pending writes are written at the time
827 // of updating the list head, so the profiling thread always has a valid
828 // list to look at.
829 list_.store(redirection, std::memory_order_release);
830
831 return redirection;
832 }
833
834 static Redirection* FromSvcInstruction(Instr* svc_instruction) {
835 char* addr_of_svc = reinterpret_cast<char*>(svc_instruction);
836 char* addr_of_redirection =
837 addr_of_svc - OFFSET_OF(Redirection, svc_instruction_);
838 return reinterpret_cast<Redirection*>(addr_of_redirection);
839 }
840
841 // Please note that this function is called by the signal handler of the
842 // profiling thread. It can therefore run at any point in time and is not
843 // allowed to hold any locks - which is precisely the reason why the list is
844 // prepend-only and a memory fence is used when writing the list head [list_]!
845 static uword FunctionForRedirect(uword address_of_svc) {
846 for (Redirection* current = list_.load(std::memory_order_acquire);
847 current != nullptr; current = current->next_) {
848 if (current->address_of_svc_instruction() == address_of_svc) {
849 return current->external_function_;
850 }
851 }
852 return 0;
853 }
854
855 private:
856 Redirection(uword external_function,
857 Simulator::CallKind call_kind,
858 int argument_count)
859 : external_function_(external_function),
860 call_kind_(call_kind),
861 argument_count_(argument_count),
862 svc_instruction_(Instr::kSimulatorRedirectInstruction),
863 next_(nullptr) {}
864
865 uword external_function_;
866 Simulator::CallKind call_kind_;
867 int argument_count_;
868 uint32_t svc_instruction_;
869 Redirection* next_;
870 static std::atomic<Redirection*> list_;
871 static Mutex* mutex_;
872};
873
874std::atomic<Redirection*> Redirection::list_ = {nullptr};
875Mutex* Redirection::mutex_ = new Mutex();
876
877uword Simulator::RedirectExternalReference(uword function,
878 CallKind call_kind,
879 int argument_count) {
880 Redirection* redirection =
881 Redirection::Get(function, call_kind, argument_count);
882 return redirection->address_of_svc_instruction();
883}
884
885uword Simulator::FunctionForRedirect(uword redirect) {
886 return Redirection::FunctionForRedirect(redirect);
887}
888
889// Get the active Simulator for the current isolate.
890Simulator* Simulator::Current() {
891 Isolate* isolate = Isolate::Current();
892 Simulator* simulator = isolate->simulator();
893 if (simulator == nullptr) {
894 NoSafepointScope no_safepoint;
895 simulator = new Simulator();
896 isolate->set_simulator(simulator);
897 }
898 return simulator;
899}
900
901// Sets the register in the architecture state. It will also deal with updating
902// Simulator internal state for special registers such as PC.
903DART_FORCE_INLINE void Simulator::set_register(Register reg, int32_t value) {
904 ASSERT((reg >= 0) && (reg < kNumberOfCpuRegisters));
905 if (reg == PC) {
906 pc_modified_ = true;
907 }
908 registers_[reg] = value;
909}
910
911// Raw access to the PC register.
912DART_FORCE_INLINE void Simulator::set_pc(int32_t value) {
913 pc_modified_ = true;
914 registers_[PC] = value;
915}
916
917// Accessors for VFP register state.
918DART_FORCE_INLINE void Simulator::set_sregister(SRegister reg, float value) {
919 ASSERT((reg >= 0) && (reg < kNumberOfSRegisters));
920 sregisters_[reg] = bit_cast<int32_t, float>(value);
921}
922
923DART_FORCE_INLINE float Simulator::get_sregister(SRegister reg) const {
924 ASSERT((reg >= 0) && (reg < kNumberOfSRegisters));
925 return bit_cast<float, int32_t>(sregisters_[reg]);
926}
927
928DART_FORCE_INLINE void Simulator::set_dregister(DRegister reg, double value) {
929 ASSERT((reg >= 0) && (reg < kNumberOfDRegisters));
930 dregisters_[reg] = bit_cast<int64_t, double>(value);
931}
932
933DART_FORCE_INLINE double Simulator::get_dregister(DRegister reg) const {
934 ASSERT((reg >= 0) && (reg < kNumberOfDRegisters));
935 return bit_cast<double, int64_t>(dregisters_[reg]);
936}
937
938void Simulator::set_qregister(QRegister reg, const simd_value_t& value) {
939 ASSERT(TargetCPUFeatures::neon_supported());
940 ASSERT((reg >= 0) && (reg < kNumberOfQRegisters));
941 qregisters_[reg].data_[0] = value.data_[0];
942 qregisters_[reg].data_[1] = value.data_[1];
943 qregisters_[reg].data_[2] = value.data_[2];
944 qregisters_[reg].data_[3] = value.data_[3];
945}
946
947void Simulator::get_qregister(QRegister reg, simd_value_t* value) const {
948 ASSERT(TargetCPUFeatures::neon_supported());
949 // TODO(zra): Replace this test with an assert after we support
950 // 16 Q registers.
951 if ((reg >= 0) && (reg < kNumberOfQRegisters)) {
952 *value = qregisters_[reg];
953 }
954}
955
956void Simulator::set_sregister_bits(SRegister reg, int32_t value) {
957 ASSERT((reg >= 0) && (reg < kNumberOfSRegisters));
958 sregisters_[reg] = value;
959}
960
961int32_t Simulator::get_sregister_bits(SRegister reg) const {
962 ASSERT((reg >= 0) && (reg < kNumberOfSRegisters));
963 return sregisters_[reg];
964}
965
966void Simulator::set_dregister_bits(DRegister reg, int64_t value) {
967 ASSERT((reg >= 0) && (reg < kNumberOfDRegisters));
968 dregisters_[reg] = value;
969}
970
971int64_t Simulator::get_dregister_bits(DRegister reg) const {
972 ASSERT((reg >= 0) && (reg < kNumberOfDRegisters));
973 return dregisters_[reg];
974}
975
976void Simulator::HandleIllegalAccess(uword addr, Instr* instr) {
977 uword fault_pc = get_pc();
978 // The debugger will not be able to single step past this instruction, but
979 // it will be possible to disassemble the code and inspect registers.
980 char buffer[128];
981 snprintf(buffer, sizeof(buffer),
982 "illegal memory access at 0x%" Px ", pc=0x%" Px "\n", addr,
983 fault_pc);
984 SimulatorDebugger dbg(this);
985 dbg.Stop(instr, buffer);
986 // The debugger will return control in non-interactive mode.
987 FATAL("Cannot continue execution after illegal memory access.");
988}
989
990void Simulator::UnimplementedInstruction(Instr* instr) {
991 char buffer[64];
992 snprintf(buffer, sizeof(buffer), "Unimplemented instruction: pc=%p\n", instr);
993 SimulatorDebugger dbg(this);
994 dbg.Stop(instr, buffer);
995 FATAL("Cannot continue execution after unimplemented instruction.");
996}
997
998DART_FORCE_INLINE intptr_t Simulator::ReadW(uword addr, Instr* instr) {
999 return *reinterpret_cast<intptr_t*>(addr);
1000}
1001
1002DART_FORCE_INLINE void Simulator::WriteW(uword addr,
1003 intptr_t value,
1004 Instr* instr) {
1005 *reinterpret_cast<intptr_t*>(addr) = value;
1006}
1007
1008DART_FORCE_INLINE uint16_t Simulator::ReadHU(uword addr, Instr* instr) {
1009 return *reinterpret_cast<uint16_t*>(addr);
1010}
1011
1012DART_FORCE_INLINE int16_t Simulator::ReadH(uword addr, Instr* instr) {
1013 return *reinterpret_cast<int16_t*>(addr);
1014}
1015
1016DART_FORCE_INLINE void Simulator::WriteH(uword addr,
1017 uint16_t value,
1018 Instr* instr) {
1019 *reinterpret_cast<uint16_t*>(addr) = value;
1020}
1021
1022DART_FORCE_INLINE uint8_t Simulator::ReadBU(uword addr) {
1023 return *reinterpret_cast<uint8_t*>(addr);
1024}
1025
1026DART_FORCE_INLINE int8_t Simulator::ReadB(uword addr) {
1027 return *reinterpret_cast<int8_t*>(addr);
1028}
1029
1030DART_FORCE_INLINE void Simulator::WriteB(uword addr, uint8_t value) {
1031 *reinterpret_cast<uint8_t*>(addr) = value;
1032}
1033
1034void Simulator::ClearExclusive() {
1035 exclusive_access_addr_ = 0;
1036 exclusive_access_value_ = 0;
1037}
1038
1039intptr_t Simulator::ReadExclusiveW(uword addr, Instr* instr) {
1040 exclusive_access_addr_ = addr;
1041 exclusive_access_value_ = ReadW(addr, instr);
1042 return exclusive_access_value_;
1043}
1044
1045intptr_t Simulator::WriteExclusiveW(uword addr, intptr_t value, Instr* instr) {
1046 // In a well-formed code store-exclusive instruction should always follow
1047 // a corresponding load-exclusive instruction with the same address.
1048 ASSERT((exclusive_access_addr_ == 0) || (exclusive_access_addr_ == addr));
1049 if (exclusive_access_addr_ != addr) {
1050 return 1; // Failure.
1051 }
1052
1053 int32_t old_value = static_cast<uint32_t>(exclusive_access_value_);
1054 ClearExclusive();
1055
1056 auto atomic_addr = reinterpret_cast<RelaxedAtomic<int32_t>*>(addr);
1057 if (atomic_addr->compare_exchange_weak(old_value, value)) {
1058 return 0; // Success.
1059 }
1060 return 1; // Failure.
1061}
1062
1063bool Simulator::IsTracingExecution() const {
1064 return icount_ > FLAG_trace_sim_after;
1065}
1066
1067// Unsupported instructions use Format to print an error and stop execution.
1068void Simulator::Format(Instr* instr, const char* format) {
1069 OS::PrintErr("Simulator found unsupported instruction:\n 0x%p: %s\n", instr,
1070 format);
1071 UNIMPLEMENTED();
1072}
1073
1074// Checks if the current instruction should be executed based on its
1075// condition bits.
1076DART_FORCE_INLINE bool Simulator::ConditionallyExecute(Instr* instr) {
1077 switch (instr->ConditionField()) {
1078 case EQ:
1079 return z_flag_;
1080 case NE:
1081 return !z_flag_;
1082 case CS:
1083 return c_flag_;
1084 case CC:
1085 return !c_flag_;
1086 case MI:
1087 return n_flag_;
1088 case PL:
1089 return !n_flag_;
1090 case VS:
1091 return v_flag_;
1092 case VC:
1093 return !v_flag_;
1094 case HI:
1095 return c_flag_ && !z_flag_;
1096 case LS:
1097 return !c_flag_ || z_flag_;
1098 case GE:
1099 return n_flag_ == v_flag_;
1100 case LT:
1101 return n_flag_ != v_flag_;
1102 case GT:
1103 return !z_flag_ && (n_flag_ == v_flag_);
1104 case LE:
1105 return z_flag_ || (n_flag_ != v_flag_);
1106 case AL:
1107 return true;
1108 default:
1109 UNREACHABLE();
1110 }
1111 return false;
1112}
1113
1114// Calculate and set the Negative and Zero flags.
1115DART_FORCE_INLINE void Simulator::SetNZFlags(int32_t val) {
1116 n_flag_ = (val < 0);
1117 z_flag_ = (val == 0);
1118}
1119
1120// Set the Carry flag.
1121DART_FORCE_INLINE void Simulator::SetCFlag(bool val) {
1122 c_flag_ = val;
1123}
1124
1125// Set the oVerflow flag.
1126DART_FORCE_INLINE void Simulator::SetVFlag(bool val) {
1127 v_flag_ = val;
1128}
1129
1130// Calculate C flag value for additions (and subtractions with adjusted args).
1131DART_FORCE_INLINE bool Simulator::CarryFrom(int32_t left,
1132 int32_t right,
1133 int32_t carry) {
1134 uint64_t uleft = static_cast<uint32_t>(left);
1135 uint64_t uright = static_cast<uint32_t>(right);
1136 uint64_t ucarry = static_cast<uint32_t>(carry);
1137 return ((uleft + uright + ucarry) >> 32) != 0;
1138}
1139
1140// Calculate V flag value for additions (and subtractions with adjusted args).
1141DART_FORCE_INLINE bool Simulator::OverflowFrom(int32_t left,
1142 int32_t right,
1143 int32_t carry) {
1144 int64_t result = static_cast<int64_t>(left) + right + carry;
1145 return (result >> 31) != (result >> 32);
1146}
1147
1148// Addressing Mode 1 - Data-processing operands:
1149// Get the value based on the shifter_operand with register.
1150int32_t Simulator::GetShiftRm(Instr* instr, bool* carry_out) {
1151 Shift shift = instr->ShiftField();
1152 int shift_amount = instr->ShiftAmountField();
1153 int32_t result = get_register(instr->RmField());
1154 if (instr->Bit(4) == 0) {
1155 // by immediate
1156 if ((shift == ROR) && (shift_amount == 0)) {
1157 UnimplementedInstruction(instr);
1158 } else if (((shift == LSR) || (shift == ASR)) && (shift_amount == 0)) {
1159 shift_amount = 32;
1160 }
1161 switch (shift) {
1162 case ASR: {
1163 if (shift_amount == 0) {
1164 if (result < 0) {
1165 result = 0xffffffff;
1166 *carry_out = true;
1167 } else {
1168 result = 0;
1169 *carry_out = false;
1170 }
1171 } else {
1172 result >>= (shift_amount - 1);
1173 *carry_out = (result & 1) == 1;
1174 result >>= 1;
1175 }
1176 break;
1177 }
1178
1179 case LSL: {
1180 if (shift_amount == 0) {
1181 *carry_out = c_flag_;
1182 } else {
1183 result = static_cast<uint32_t>(result) << (shift_amount - 1);
1184 *carry_out = (result < 0);
1185 result = static_cast<uint32_t>(result) << 1;
1186 }
1187 break;
1188 }
1189
1190 case LSR: {
1191 if (shift_amount == 0) {
1192 result = 0;
1193 *carry_out = c_flag_;
1194 } else {
1195 uint32_t uresult = static_cast<uint32_t>(result);
1196 uresult >>= (shift_amount - 1);
1197 *carry_out = (uresult & 1) == 1;
1198 uresult >>= 1;
1199 result = static_cast<int32_t>(uresult);
1200 }
1201 break;
1202 }
1203
1204 case ROR: {
1205 UnimplementedInstruction(instr);
1206 break;
1207 }
1208
1209 default: {
1210 UNREACHABLE();
1211 break;
1212 }
1213 }
1214 } else {
1215 // by register
1216 Register rs = instr->RsField();
1217 shift_amount = get_register(rs) & 0xff;
1218 switch (shift) {
1219 case ASR: {
1220 if (shift_amount == 0) {
1221 *carry_out = c_flag_;
1222 } else if (shift_amount < 32) {
1223 result >>= (shift_amount - 1);
1224 *carry_out = (result & 1) == 1;
1225 result >>= 1;
1226 } else {
1227 ASSERT(shift_amount >= 32);
1228 if (result < 0) {
1229 *carry_out = true;
1230 result = 0xffffffff;
1231 } else {
1232 *carry_out = false;
1233 result = 0;
1234 }
1235 }
1236 break;
1237 }
1238
1239 case LSL: {
1240 if (shift_amount == 0) {
1241 *carry_out = c_flag_;
1242 } else if (shift_amount < 32) {
1243 result = static_cast<uint32_t>(result) << (shift_amount - 1);
1244 *carry_out = (result < 0);
1245 result = static_cast<uint32_t>(result) << 1;
1246 } else if (shift_amount == 32) {
1247 *carry_out = (result & 1) == 1;
1248 result = 0;
1249 } else {
1250 ASSERT(shift_amount > 32);
1251 *carry_out = false;
1252 result = 0;
1253 }
1254 break;
1255 }
1256
1257 case LSR: {
1258 if (shift_amount == 0) {
1259 *carry_out = c_flag_;
1260 } else if (shift_amount < 32) {
1261 uint32_t uresult = static_cast<uint32_t>(result);
1262 uresult >>= (shift_amount - 1);
1263 *carry_out = (uresult & 1) == 1;
1264 uresult >>= 1;
1265 result = static_cast<int32_t>(uresult);
1266 } else if (shift_amount == 32) {
1267 *carry_out = (result < 0);
1268 result = 0;
1269 } else {
1270 *carry_out = false;
1271 result = 0;
1272 }
1273 break;
1274 }
1275
1276 case ROR: {
1277 UnimplementedInstruction(instr);
1278 break;
1279 }
1280
1281 default: {
1282 UNREACHABLE();
1283 break;
1284 }
1285 }
1286 }
1287 return result;
1288}
1289
1290// Addressing Mode 1 - Data-processing operands:
1291// Get the value based on the shifter_operand with immediate.
1292DART_FORCE_INLINE int32_t Simulator::GetImm(Instr* instr, bool* carry_out) {
1293 uint8_t rotate = instr->RotateField() * 2;
1294 int32_t immed8 = instr->Immed8Field();
1295 int32_t imm = Utils::RotateRight(immed8, rotate);
1296 *carry_out = (rotate == 0) ? c_flag_ : (imm < 0);
1297 return imm;
1298}
1299
1300// Addressing Mode 4 - Load and Store Multiple
1301void Simulator::HandleRList(Instr* instr, bool load) {
1302 Register rn = instr->RnField();
1303 int32_t rn_val = get_register(rn);
1304 int rlist = instr->RlistField();
1305 int num_regs = Utils::CountOneBits32(static_cast<uint32_t>(rlist));
1306
1307 uword address = 0;
1308 uword end_address = 0;
1309 switch (instr->PUField()) {
1310 case 0: {
1311 // Print("da");
1312 address = rn_val - (num_regs * 4) + 4;
1313 end_address = rn_val + 4;
1314 rn_val = rn_val - (num_regs * 4);
1315 break;
1316 }
1317 case 1: {
1318 // Print("ia");
1319 address = rn_val;
1320 end_address = rn_val + (num_regs * 4);
1321 rn_val = rn_val + (num_regs * 4);
1322 break;
1323 }
1324 case 2: {
1325 // Print("db");
1326 address = rn_val - (num_regs * 4);
1327 end_address = rn_val;
1328 rn_val = address;
1329 break;
1330 }
1331 case 3: {
1332 // Print("ib");
1333 address = rn_val + 4;
1334 end_address = rn_val + (num_regs * 4) + 4;
1335 rn_val = rn_val + (num_regs * 4);
1336 break;
1337 }
1338 default: {
1339 UNREACHABLE();
1340 break;
1341 }
1342 }
1343 if (IsIllegalAddress(address)) {
1344 HandleIllegalAccess(address, instr);
1345 } else {
1346 if (instr->HasW()) {
1347 set_register(rn, rn_val);
1348 }
1349 int reg = 0;
1350 while (rlist != 0) {
1351 if ((rlist & 1) != 0) {
1352 if (load) {
1353 set_register(static_cast<Register>(reg), ReadW(address, instr));
1354 } else {
1355 WriteW(address, get_register(static_cast<Register>(reg)), instr);
1356 }
1357 address += 4;
1358 }
1359 reg++;
1360 rlist >>= 1;
1361 }
1362 ASSERT(end_address == address);
1363 }
1364}
1365
1366// Calls into the Dart runtime are based on this interface.
1367typedef void (*SimulatorRuntimeCall)(NativeArguments arguments);
1368
1369// Calls to leaf Dart runtime functions are based on this interface.
1370typedef int32_t (*SimulatorLeafRuntimeCall)(int32_t r0,
1371 int32_t r1,
1372 int32_t r2,
1373 int32_t r3,
1374 int32_t r4);
1375
1376// [target] has several different signatures that differ from
1377// SimulatorLeafRuntimeCall. We can call them all from here only because in
1378// IA32's calling convention a function can be called with extra arguments
1379// and the callee will see the first arguments and won't unbalance the stack.
1380NO_SANITIZE_UNDEFINED("function")
1381static int32_t InvokeLeafRuntime(SimulatorLeafRuntimeCall target,
1382 int32_t r0,
1383 int32_t r1,
1384 int32_t r2,
1385 int32_t r3,
1386 int32_t r4) {
1387 return target(r0, r1, r2, r3, r4);
1388}
1389
1390// Calls to leaf float Dart runtime functions are based on this interface.
1391typedef double (*SimulatorLeafFloatRuntimeCall)(double d0, double d1);
1392
1393// [target] has several different signatures that differ from
1394// SimulatorFloatLeafRuntimeCall. We can call them all from here only because
1395// IA32's calling convention a function can be called with extra arguments
1396// and the callee will see the first arguments and won't unbalance the stack.
1397NO_SANITIZE_UNDEFINED("function")
1398static double InvokeFloatLeafRuntime(SimulatorLeafFloatRuntimeCall target,
1399 double d0,
1400 double d1) {
1401 return target(d0, d1);
1402}
1403
1404// Calls to native Dart functions are based on this interface.
1405typedef void (*SimulatorNativeCallWrapper)(Dart_NativeArguments arguments,
1406 Dart_NativeFunction target);
1407
1408void Simulator::SupervisorCall(Instr* instr) {
1409 int svc = instr->SvcField();
1410 switch (svc) {
1411 case Instr::kSimulatorRedirectCode: {
1412 SimulatorSetjmpBuffer buffer(this);
1413
1414 if (!setjmp(buffer.buffer_)) {
1415 int32_t saved_lr = get_register(LR);
1416 Redirection* redirection = Redirection::FromSvcInstruction(instr);
1417 uword external = redirection->external_function();
1418 if (IsTracingExecution()) {
1419 THR_Print("Call to host function at 0x%" Pd "\n", external);
1420 }
1421 if (redirection->call_kind() == kRuntimeCall) {
1422 NativeArguments arguments;
1423 ASSERT(sizeof(NativeArguments) == 4 * kWordSize);
1424 arguments.thread_ = reinterpret_cast<Thread*>(get_register(R0));
1425 arguments.argc_tag_ = get_register(R1);
1426 arguments.argv_ = reinterpret_cast<ObjectPtr*>(get_register(R2));
1427 arguments.retval_ = reinterpret_cast<ObjectPtr*>(get_register(R3));
1428 SimulatorRuntimeCall target =
1429 reinterpret_cast<SimulatorRuntimeCall>(external);
1430 target(arguments);
1431 ClobberVolatileRegisters();
1432 } else if (redirection->call_kind() == kLeafRuntimeCall) {
1433 ASSERT((0 <= redirection->argument_count()) &&
1434 (redirection->argument_count() <= 5));
1435 int32_t r0 = get_register(R0);
1436 int32_t r1 = get_register(R1);
1437 int32_t r2 = get_register(R2);
1438 int32_t r3 = get_register(R3);
1439 int32_t r4 = *reinterpret_cast<int32_t*>(get_register(SP));
1440 SimulatorLeafRuntimeCall target =
1441 reinterpret_cast<SimulatorLeafRuntimeCall>(external);
1442 r0 = InvokeLeafRuntime(target, r0, r1, r2, r3, r4);
1443 ClobberVolatileRegisters();
1444 set_register(R0, r0); // Set returned result from function.
1445 } else if (redirection->call_kind() == kLeafFloatRuntimeCall) {
1446 ASSERT((0 <= redirection->argument_count()) &&
1447 (redirection->argument_count() <= 2));
1448 SimulatorLeafFloatRuntimeCall target =
1449 reinterpret_cast<SimulatorLeafFloatRuntimeCall>(external);
1450 if (TargetCPUFeatures::hardfp_supported()) {
1451 // If we're doing "hardfp", the double arguments are already in the
1452 // floating point registers.
1453 double d0 = get_dregister(D0);
1454 double d1 = get_dregister(D1);
1455 d0 = InvokeFloatLeafRuntime(target, d0, d1);
1456 ClobberVolatileRegisters();
1457 set_dregister(D0, d0);
1458 } else {
1459 // If we're not doing "hardfp", we must be doing "soft" or "softfp",
1460 // So take the double arguments from the integer registers.
1461 uint32_t r0 = get_register(R0);
1462 int32_t r1 = get_register(R1);
1463 uint32_t r2 = get_register(R2);
1464 int32_t r3 = get_register(R3);
1465 int64_t a0 = Utils::LowHighTo64Bits(r0, r1);
1466 int64_t a1 = Utils::LowHighTo64Bits(r2, r3);
1467 double d0 = bit_cast<double, int64_t>(a0);
1468 double d1 = bit_cast<double, int64_t>(a1);
1469 d0 = InvokeFloatLeafRuntime(target, d0, d1);
1470 ClobberVolatileRegisters();
1471 a0 = bit_cast<int64_t, double>(d0);
1472 r0 = Utils::Low32Bits(a0);
1473 r1 = Utils::High32Bits(a0);
1474 set_register(R0, r0);
1475 set_register(R1, r1);
1476 }
1477 } else {
1478 ASSERT(redirection->call_kind() == kNativeCallWrapper);
1479 SimulatorNativeCallWrapper wrapper =
1480 reinterpret_cast<SimulatorNativeCallWrapper>(external);
1481 Dart_NativeArguments arguments =
1482 reinterpret_cast<Dart_NativeArguments>(get_register(R0));
1483 Dart_NativeFunction target_func =
1484 reinterpret_cast<Dart_NativeFunction>(get_register(R1));
1485 wrapper(arguments, target_func);
1486 ClobberVolatileRegisters();
1487 }
1488
1489 // Return.
1490 set_pc(saved_lr);
1491 } else {
1492 // Coming via long jump from a throw. Continue to exception handler.
1493 }
1494
1495 break;
1496 }
1497 case Instr::kSimulatorBreakCode: {
1498 SimulatorDebugger dbg(this);
1499 dbg.Stop(instr, "breakpoint");
1500 break;
1501 }
1502 default: {
1503 UNREACHABLE();
1504 break;
1505 }
1506 }
1507}
1508
1509void Simulator::ClobberVolatileRegisters() {
1510 // Clear atomic reservation.
1511 exclusive_access_addr_ = exclusive_access_value_ = 0;
1512
1513 for (intptr_t i = 0; i < kNumberOfCpuRegisters; i++) {
1514 if ((kAbiVolatileCpuRegs & (1 << i)) != 0) {
1515 registers_[i] = icount_;
1516 }
1517 }
1518
1519 double zap_dvalue = static_cast<double>(icount_);
1520 for (int i = D0; i <= D7; i++) {
1521 set_dregister(static_cast<DRegister>(i), zap_dvalue);
1522 }
1523 // The above loop also zaps overlapping registers S2-S15.
1524 // Registers D8-D15 (overlapping with S16-S31) are preserved.
1525#if defined(VFPv3_D32)
1526 for (int i = D16; i <= D31; i++) {
1527 set_dregister(static_cast<DRegister>(i), zap_dvalue);
1528 }
1529#endif
1530}
1531
1532// Handle execution based on instruction types.
1533
1534// Instruction types 0 and 1 are both rolled into one function because they
1535// only differ in the handling of the shifter_operand.
1536DART_FORCE_INLINE void Simulator::DecodeType01(Instr* instr) {
1537 if (!instr->IsDataProcessing()) {
1538 // miscellaneous, multiply, sync primitives, extra loads and stores.
1539 if (instr->IsMiscellaneous()) {
1540 switch (instr->Bits(4, 3)) {
1541 case 1: {
1542 if (instr->Bits(21, 2) == 0x3) {
1543 // Format(instr, "clz'cond 'rd, 'rm");
1544 Register rm = instr->RmField();
1545 Register rd = instr->RdField();
1546 int32_t rm_val = get_register(rm);
1547 int32_t rd_val = 0;
1548 if (rm_val != 0) {
1549 while (rm_val > 0) {
1550 rd_val++;
1551 rm_val <<= 1;
1552 }
1553 } else {
1554 rd_val = 32;
1555 }
1556 set_register(rd, rd_val);
1557 } else {
1558 ASSERT(instr->Bits(21, 2) == 0x1);
1559 // Format(instr, "bx'cond 'rm");
1560 Register rm = instr->RmField();
1561 int32_t rm_val = get_register(rm);
1562 set_pc(rm_val);
1563 }
1564 break;
1565 }
1566 case 3: {
1567 ASSERT(instr->Bits(21, 2) == 0x1);
1568 // Format(instr, "blx'cond 'rm");
1569 Register rm = instr->RmField();
1570 int32_t rm_val = get_register(rm);
1571 intptr_t pc = get_pc();
1572 set_register(LR, pc + Instr::kInstrSize);
1573 set_pc(rm_val);
1574 break;
1575 }
1576 case 7: {
1577 if ((instr->Bits(21, 2) == 0x1) && (instr->ConditionField() == AL)) {
1578 // Format(instr, "bkpt #'imm12_4");
1579 SimulatorDebugger dbg(this);
1580 int32_t imm = instr->BkptField();
1581 char buffer[32];
1582 snprintf(buffer, sizeof(buffer), "bkpt #0x%x", imm);
1583 set_pc(get_pc() + Instr::kInstrSize);
1584 dbg.Stop(instr, buffer);
1585 } else {
1586 // Format(instr, "smc'cond");
1587 UnimplementedInstruction(instr);
1588 }
1589 break;
1590 }
1591 default: {
1592 UnimplementedInstruction(instr);
1593 break;
1594 }
1595 }
1596 } else if (instr->IsMultiplyOrSyncPrimitive()) {
1597 if (instr->Bit(24) == 0) {
1598 // multiply instructions.
1599 Register rn = instr->RnField();
1600 Register rd = instr->RdField();
1601 Register rs = instr->RsField();
1602 Register rm = instr->RmField();
1603 uint32_t rm_val = get_register(rm);
1604 uint32_t rs_val = get_register(rs);
1605 uint32_t rd_val = 0;
1606 switch (instr->Bits(21, 3)) {
1607 case 1:
1608 // Registers rd, rn, rm, ra are encoded as rn, rm, rs, rd.
1609 // Format(instr, "mla'cond's 'rn, 'rm, 'rs, 'rd");
1610 case 3: {
1611 // Registers rd, rn, rm, ra are encoded as rn, rm, rs, rd.
1612 // Format(instr, "mls'cond's 'rn, 'rm, 'rs, 'rd");
1613 rd_val = get_register(rd);
1614 FALL_THROUGH;
1615 }
1616 case 0: {
1617 // Registers rd, rn, rm are encoded as rn, rm, rs.
1618 // Format(instr, "mul'cond's 'rn, 'rm, 'rs");
1619 uint32_t alu_out = rm_val * rs_val;
1620 if (instr->Bits(21, 3) == 3) { // mls
1621 alu_out = -alu_out;
1622 }
1623 alu_out += rd_val;
1624 set_register(rn, alu_out);
1625 if (instr->HasS()) {
1626 SetNZFlags(alu_out);
1627 }
1628 break;
1629 }
1630 case 4:
1631 // Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
1632 // Format(instr, "umull'cond's 'rd, 'rn, 'rm, 'rs");
1633 case 6: {
1634 // Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
1635 // Format(instr, "smull'cond's 'rd, 'rn, 'rm, 'rs");
1636 int64_t result;
1637 if (instr->Bits(21, 3) == 4) { // umull
1638 uint64_t left_op = static_cast<uint32_t>(rm_val);
1639 uint64_t right_op = static_cast<uint32_t>(rs_val);
1640 result = left_op * right_op; // Unsigned multiplication.
1641 } else { // smull
1642 int64_t left_op = static_cast<int32_t>(rm_val);
1643 int64_t right_op = static_cast<int32_t>(rs_val);
1644 result = left_op * right_op; // Signed multiplication.
1645 }
1646 int32_t hi_res = Utils::High32Bits(result);
1647 int32_t lo_res = Utils::Low32Bits(result);
1648 set_register(rd, lo_res);
1649 set_register(rn, hi_res);
1650 if (instr->HasS()) {
1651 if (lo_res != 0) {
1652 // Collapse bits 0..31 into bit 32 so that 32-bit Z check works.
1653 hi_res |= 1;
1654 }
1655 ASSERT((result == 0) == (hi_res == 0)); // Z bit
1656 ASSERT(((result & (1LL << 63)) != 0) == (hi_res < 0)); // N bit
1657 SetNZFlags(hi_res);
1658 }
1659 break;
1660 }
1661 case 2:
1662 // Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
1663 // Format(instr, "umaal'cond's 'rd, 'rn, 'rm, 'rs");
1664 FALL_THROUGH;
1665 case 5:
1666 // Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
1667 // Format(instr, "umlal'cond's 'rd, 'rn, 'rm, 'rs");
1668 FALL_THROUGH;
1669 case 7: {
1670 // Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
1671 // Format(instr, "smlal'cond's 'rd, 'rn, 'rm, 'rs");
1672 int32_t rd_lo_val = get_register(rd);
1673 int32_t rd_hi_val = get_register(rn);
1674 uint32_t accum_lo = static_cast<uint32_t>(rd_lo_val);
1675 int32_t accum_hi = static_cast<int32_t>(rd_hi_val);
1676 int64_t accum = Utils::LowHighTo64Bits(accum_lo, accum_hi);
1677 int64_t result;
1678 if (instr->Bits(21, 3) == 5) { // umlal
1679 uint64_t left_op = static_cast<uint32_t>(rm_val);
1680 uint64_t right_op = static_cast<uint32_t>(rs_val);
1681 result = accum + left_op * right_op; // Unsigned multiplication.
1682 } else if (instr->Bits(21, 3) == 7) { // smlal
1683 int64_t left_op = static_cast<int32_t>(rm_val);
1684 int64_t right_op = static_cast<int32_t>(rs_val);
1685 result = accum + left_op * right_op; // Signed multiplication.
1686 } else {
1687 ASSERT(instr->Bits(21, 3) == 2); // umaal
1688 ASSERT(!instr->HasS());
1689 uint64_t left_op = static_cast<uint32_t>(rm_val);
1690 uint64_t right_op = static_cast<uint32_t>(rs_val);
1691 result = left_op * right_op + // Unsigned multiplication.
1692 static_cast<uint32_t>(rd_lo_val) +
1693 static_cast<uint32_t>(rd_hi_val);
1694 }
1695 int32_t hi_res = Utils::High32Bits(result);
1696 int32_t lo_res = Utils::Low32Bits(result);
1697 set_register(rd, lo_res);
1698 set_register(rn, hi_res);
1699 if (instr->HasS()) {
1700 if (lo_res != 0) {
1701 // Collapse bits 0..31 into bit 32 so that 32-bit Z check works.
1702 hi_res |= 1;
1703 }
1704 ASSERT((result == 0) == (hi_res == 0)); // Z bit
1705 ASSERT(((result & (1LL << 63)) != 0) == (hi_res < 0)); // N bit
1706 SetNZFlags(hi_res);
1707 }
1708 break;
1709 }
1710 default: {
1711 UnimplementedInstruction(instr);
1712 break;
1713 }
1714 }
1715 } else {
1716 // synchronization primitives
1717 Register rd = instr->RdField();
1718 Register rn = instr->RnField();
1719 uword addr = get_register(rn);
1720 switch (instr->Bits(20, 4)) {
1721 case 8: {
1722 // Format(instr, "strex'cond 'rd, 'rm, ['rn]");
1723 if (IsIllegalAddress(addr)) {
1724 HandleIllegalAccess(addr, instr);
1725 } else {
1726 Register rm = instr->RmField();
1727 set_register(rd, WriteExclusiveW(addr, get_register(rm), instr));
1728 }
1729 break;
1730 }
1731 case 9: {
1732 // Format(instr, "ldrex'cond 'rd, ['rn]");
1733 if (IsIllegalAddress(addr)) {
1734 HandleIllegalAccess(addr, instr);
1735 } else {
1736 set_register(rd, ReadExclusiveW(addr, instr));
1737 }
1738 break;
1739 }
1740 default: {
1741 UnimplementedInstruction(instr);
1742 break;
1743 }
1744 }
1745 }
1746 } else if (instr->Bit(25) == 1) {
1747 // 16-bit immediate loads, msr (immediate), and hints
1748 switch (instr->Bits(20, 5)) {
1749 case 16:
1750 case 20: {
1751 uint16_t imm16 = instr->MovwField();
1752 Register rd = instr->RdField();
1753 if (instr->Bit(22) == 0) {
1754 // Format(instr, "movw'cond 'rd, #'imm4_12");
1755 set_register(rd, imm16);
1756 } else {
1757 // Format(instr, "movt'cond 'rd, #'imm4_12");
1758 set_register(rd, (get_register(rd) & 0xffff) | (imm16 << 16));
1759 }
1760 break;
1761 }
1762 case 18: {
1763 if ((instr->Bits(16, 4) == 0) && (instr->Bits(0, 8) == 0)) {
1764 // Format(instr, "nop'cond");
1765 } else {
1766 UnimplementedInstruction(instr);
1767 }
1768 break;
1769 }
1770 default: {
1771 UnimplementedInstruction(instr);
1772 break;
1773 }
1774 }
1775 } else {
1776 // extra load/store instructions
1777 Register rd = instr->RdField();
1778 Register rn = instr->RnField();
1779 int32_t rn_val = get_register(rn);
1780 uword addr = 0;
1781 bool write_back = false;
1782 if (instr->Bit(22) == 0) {
1783 Register rm = instr->RmField();
1784 int32_t rm_val = get_register(rm);
1785 switch (instr->PUField()) {
1786 case 0: {
1787 // Format(instr, "'memop'cond'x 'rd2, ['rn], -'rm");
1788 ASSERT(!instr->HasW());
1789 addr = rn_val;
1790 rn_val -= rm_val;
1791 write_back = true;
1792 break;
1793 }
1794 case 1: {
1795 // Format(instr, "'memop'cond'x 'rd2, ['rn], +'rm");
1796 ASSERT(!instr->HasW());
1797 addr = rn_val;
1798 rn_val += rm_val;
1799 write_back = true;
1800 break;
1801 }
1802 case 2: {
1803 // Format(instr, "'memop'cond'x 'rd2, ['rn, -'rm]'w");
1804 rn_val -= rm_val;
1805 addr = rn_val;
1806 write_back = instr->HasW();
1807 break;
1808 }
1809 case 3: {
1810 // Format(instr, "'memop'cond'x 'rd2, ['rn, +'rm]'w");
1811 rn_val += rm_val;
1812 addr = rn_val;
1813 write_back = instr->HasW();
1814 break;
1815 }
1816 default: {
1817 // The PU field is a 2-bit field.
1818 UNREACHABLE();
1819 break;
1820 }
1821 }
1822 } else {
1823 int32_t imm_val = (instr->ImmedHField() << 4) | instr->ImmedLField();
1824 switch (instr->PUField()) {
1825 case 0: {
1826 // Format(instr, "'memop'cond'x 'rd2, ['rn], #-'off8");
1827 ASSERT(!instr->HasW());
1828 addr = rn_val;
1829 rn_val -= imm_val;
1830 write_back = true;
1831 break;
1832 }
1833 case 1: {
1834 // Format(instr, "'memop'cond'x 'rd2, ['rn], #+'off8");
1835 ASSERT(!instr->HasW());
1836 addr = rn_val;
1837 rn_val += imm_val;
1838 write_back = true;
1839 break;
1840 }
1841 case 2: {
1842 // Format(instr, "'memop'cond'x 'rd2, ['rn, #-'off8]'w");
1843 rn_val -= imm_val;
1844 addr = rn_val;
1845 write_back = instr->HasW();
1846 break;
1847 }
1848 case 3: {
1849 // Format(instr, "'memop'cond'x 'rd2, ['rn, #+'off8]'w");
1850 rn_val += imm_val;
1851 addr = rn_val;
1852 write_back = instr->HasW();
1853 break;
1854 }
1855 default: {
1856 // The PU field is a 2-bit field.
1857 UNREACHABLE();
1858 break;
1859 }
1860 }
1861 }
1862 if (IsIllegalAddress(addr)) {
1863 HandleIllegalAccess(addr, instr);
1864 } else {
1865 if (write_back) {
1866 ASSERT(rd != rn); // Unpredictable.
1867 set_register(rn, rn_val);
1868 }
1869 if (!instr->HasSign()) {
1870 if (instr->HasL()) {
1871 uint16_t val = ReadHU(addr, instr);
1872 set_register(rd, val);
1873 } else {
1874 uint16_t val = get_register(rd);
1875 WriteH(addr, val, instr);
1876 }
1877 } else if (instr->HasL()) {
1878 if (instr->HasH()) {
1879 int16_t val = ReadH(addr, instr);
1880 set_register(rd, val);
1881 } else {
1882 int8_t val = ReadB(addr);
1883 set_register(rd, val);
1884 }
1885 } else if ((rd & 1) == 0) {
1886 Register rd1 = static_cast<Register>(rd | 1);
1887 ASSERT(rd1 < kNumberOfCpuRegisters);
1888 if (instr->HasH()) {
1889 int32_t val_low = get_register(rd);
1890 int32_t val_high = get_register(rd1);
1891 WriteW(addr, val_low, instr);
1892 WriteW(addr + 4, val_high, instr);
1893 } else {
1894 int32_t val_low = ReadW(addr, instr);
1895 int32_t val_high = ReadW(addr + 4, instr);
1896 set_register(rd, val_low);
1897 set_register(rd1, val_high);
1898 }
1899 } else {
1900 UnimplementedInstruction(instr);
1901 }
1902 }
1903 }
1904 } else {
1905 Register rd = instr->RdField();
1906 Register rn = instr->RnField();
1907 uint32_t rn_val = get_register(rn);
1908 uint32_t shifter_operand = 0;
1909 bool shifter_carry_out = 0;
1910 if (instr->TypeField() == 0) {
1911 shifter_operand = GetShiftRm(instr, &shifter_carry_out);
1912 } else {
1913 ASSERT(instr->TypeField() == 1);
1914 shifter_operand = GetImm(instr, &shifter_carry_out);
1915 }
1916 uint32_t carry_in;
1917 uint32_t alu_out;
1918
1919 switch (instr->OpcodeField()) {
1920 case AND: {
1921 // Format(instr, "and'cond's 'rd, 'rn, 'shift_rm");
1922 // Format(instr, "and'cond's 'rd, 'rn, 'imm");
1923 alu_out = rn_val & shifter_operand;
1924 set_register(rd, alu_out);
1925 if (instr->HasS()) {
1926 SetNZFlags(alu_out);
1927 SetCFlag(shifter_carry_out);
1928 }
1929 break;
1930 }
1931
1932 case EOR: {
1933 // Format(instr, "eor'cond's 'rd, 'rn, 'shift_rm");
1934 // Format(instr, "eor'cond's 'rd, 'rn, 'imm");
1935 alu_out = rn_val ^ shifter_operand;
1936 set_register(rd, alu_out);
1937 if (instr->HasS()) {
1938 SetNZFlags(alu_out);
1939 SetCFlag(shifter_carry_out);
1940 }
1941 break;
1942 }
1943
1944 case SUB: {
1945 // Format(instr, "sub'cond's 'rd, 'rn, 'shift_rm");
1946 // Format(instr, "sub'cond's 'rd, 'rn, 'imm");
1947 alu_out = rn_val - shifter_operand;
1948 set_register(rd, alu_out);
1949 if (instr->HasS()) {
1950 SetNZFlags(alu_out);
1951 SetCFlag(CarryFrom(rn_val, ~shifter_operand, 1));
1952 SetVFlag(OverflowFrom(rn_val, ~shifter_operand, 1));
1953 }
1954 break;
1955 }
1956
1957 case RSB: {
1958 // Format(instr, "rsb'cond's 'rd, 'rn, 'shift_rm");
1959 // Format(instr, "rsb'cond's 'rd, 'rn, 'imm");
1960 alu_out = shifter_operand - rn_val;
1961 set_register(rd, alu_out);
1962 if (instr->HasS()) {
1963 SetNZFlags(alu_out);
1964 SetCFlag(CarryFrom(shifter_operand, ~rn_val, 1));
1965 SetVFlag(OverflowFrom(shifter_operand, ~rn_val, 1));
1966 }
1967 break;
1968 }
1969
1970 case ADD: {
1971 // Format(instr, "add'cond's 'rd, 'rn, 'shift_rm");
1972 // Format(instr, "add'cond's 'rd, 'rn, 'imm");
1973 alu_out = rn_val + shifter_operand;
1974 set_register(rd, alu_out);
1975 if (instr->HasS()) {
1976 SetNZFlags(alu_out);
1977 SetCFlag(CarryFrom(rn_val, shifter_operand, 0));
1978 SetVFlag(OverflowFrom(rn_val, shifter_operand, 0));
1979 }
1980 break;
1981 }
1982
1983 case ADC: {
1984 // Format(instr, "adc'cond's 'rd, 'rn, 'shift_rm");
1985 // Format(instr, "adc'cond's 'rd, 'rn, 'imm");
1986 carry_in = c_flag_ ? 1 : 0;
1987 alu_out = rn_val + shifter_operand + carry_in;
1988 set_register(rd, alu_out);
1989 if (instr->HasS()) {
1990 SetNZFlags(alu_out);
1991 SetCFlag(CarryFrom(rn_val, shifter_operand, carry_in));
1992 SetVFlag(OverflowFrom(rn_val, shifter_operand, carry_in));
1993 }
1994 break;
1995 }
1996
1997 case SBC: {
1998 // Format(instr, "sbc'cond's 'rd, 'rn, 'shift_rm");
1999 // Format(instr, "sbc'cond's 'rd, 'rn, 'imm");
2000 carry_in = c_flag_ ? 1 : 0;
2001 alu_out = rn_val + ~shifter_operand + carry_in;
2002 set_register(rd, alu_out);
2003 if (instr->HasS()) {
2004 SetNZFlags(alu_out);
2005 SetCFlag(CarryFrom(rn_val, ~shifter_operand, carry_in));
2006 SetVFlag(OverflowFrom(rn_val, ~shifter_operand, carry_in));
2007 }
2008 break;
2009 }
2010
2011 case RSC: {
2012 // Format(instr, "rsc'cond's 'rd, 'rn, 'shift_rm");
2013 // Format(instr, "rsc'cond's 'rd, 'rn, 'imm");
2014 carry_in = c_flag_ ? 1 : 0;
2015 alu_out = shifter_operand + ~rn_val + carry_in;
2016 set_register(rd, alu_out);
2017 if (instr->HasS()) {
2018 SetNZFlags(alu_out);
2019 SetCFlag(CarryFrom(shifter_operand, ~rn_val, carry_in));
2020 SetVFlag(OverflowFrom(shifter_operand, ~rn_val, carry_in));
2021 }
2022 break;
2023 }
2024
2025 case TST: {
2026 if (instr->HasS()) {
2027 // Format(instr, "tst'cond 'rn, 'shift_rm");
2028 // Format(instr, "tst'cond 'rn, 'imm");
2029 alu_out = rn_val & shifter_operand;
2030 SetNZFlags(alu_out);
2031 SetCFlag(shifter_carry_out);
2032 } else {
2033 UnimplementedInstruction(instr);
2034 }
2035 break;
2036 }
2037
2038 case TEQ: {
2039 if (instr->HasS()) {
2040 // Format(instr, "teq'cond 'rn, 'shift_rm");
2041 // Format(instr, "teq'cond 'rn, 'imm");
2042 alu_out = rn_val ^ shifter_operand;
2043 SetNZFlags(alu_out);
2044 SetCFlag(shifter_carry_out);
2045 } else {
2046 UnimplementedInstruction(instr);
2047 }
2048 break;
2049 }
2050
2051 case CMP: {
2052 if (instr->HasS()) {
2053 // Format(instr, "cmp'cond 'rn, 'shift_rm");
2054 // Format(instr, "cmp'cond 'rn, 'imm");
2055 alu_out = rn_val - shifter_operand;
2056 SetNZFlags(alu_out);
2057 SetCFlag(CarryFrom(rn_val, ~shifter_operand, 1));
2058 SetVFlag(OverflowFrom(rn_val, ~shifter_operand, 1));
2059 } else {
2060 UnimplementedInstruction(instr);
2061 }
2062 break;
2063 }
2064
2065 case CMN: {
2066 if (instr->HasS()) {
2067 // Format(instr, "cmn'cond 'rn, 'shift_rm");
2068 // Format(instr, "cmn'cond 'rn, 'imm");
2069 alu_out = rn_val + shifter_operand;
2070 SetNZFlags(alu_out);
2071 SetCFlag(CarryFrom(rn_val, shifter_operand, 0));
2072 SetVFlag(OverflowFrom(rn_val, shifter_operand, 0));
2073 } else {
2074 UnimplementedInstruction(instr);
2075 }
2076 break;
2077 }
2078
2079 case ORR: {
2080 // Format(instr, "orr'cond's 'rd, 'rn, 'shift_rm");
2081 // Format(instr, "orr'cond's 'rd, 'rn, 'imm");
2082 alu_out = rn_val | shifter_operand;
2083 set_register(rd, alu_out);
2084 if (instr->HasS()) {
2085 SetNZFlags(alu_out);
2086 SetCFlag(shifter_carry_out);
2087 }
2088 break;
2089 }
2090
2091 case MOV: {
2092 // Format(instr, "mov'cond's 'rd, 'shift_rm");
2093 // Format(instr, "mov'cond's 'rd, 'imm");
2094 alu_out = shifter_operand;
2095 set_register(rd, alu_out);
2096 if (instr->HasS()) {
2097 SetNZFlags(alu_out);
2098 SetCFlag(shifter_carry_out);
2099 }
2100 break;
2101 }
2102
2103 case BIC: {
2104 // Format(instr, "bic'cond's 'rd, 'rn, 'shift_rm");
2105 // Format(instr, "bic'cond's 'rd, 'rn, 'imm");
2106 alu_out = rn_val & ~shifter_operand;
2107 set_register(rd, alu_out);
2108 if (instr->HasS()) {
2109 SetNZFlags(alu_out);
2110 SetCFlag(shifter_carry_out);
2111 }
2112 break;
2113 }
2114
2115 case MVN: {
2116 // Format(instr, "mvn'cond's 'rd, 'shift_rm");
2117 // Format(instr, "mvn'cond's 'rd, 'imm");
2118 alu_out = ~shifter_operand;
2119 set_register(rd, alu_out);
2120 if (instr->HasS()) {
2121 SetNZFlags(alu_out);
2122 SetCFlag(shifter_carry_out);
2123 }
2124 break;
2125 }
2126
2127 default: {
2128 UNREACHABLE();
2129 break;
2130 }
2131 }
2132 }
2133}
2134
2135DART_FORCE_INLINE void Simulator::DecodeType2(Instr* instr) {
2136 Register rd = instr->RdField();
2137 Register rn = instr->RnField();
2138 int32_t rn_val = get_register(rn);
2139 int32_t im_val = instr->Offset12Field();
2140 uword addr = 0;
2141 bool write_back = false;
2142 switch (instr->PUField()) {
2143 case 0: {
2144 // Format(instr, "'memop'cond'b 'rd, ['rn], #-'off12");
2145 ASSERT(!instr->HasW());
2146 addr = rn_val;
2147 rn_val -= im_val;
2148 write_back = true;
2149 break;
2150 }
2151 case 1: {
2152 // Format(instr, "'memop'cond'b 'rd, ['rn], #+'off12");
2153 ASSERT(!instr->HasW());
2154 addr = rn_val;
2155 rn_val += im_val;
2156 write_back = true;
2157 break;
2158 }
2159 case 2: {
2160 // Format(instr, "'memop'cond'b 'rd, ['rn, #-'off12]'w");
2161 rn_val -= im_val;
2162 addr = rn_val;
2163 write_back = instr->HasW();
2164 break;
2165 }
2166 case 3: {
2167 // Format(instr, "'memop'cond'b 'rd, ['rn, #+'off12]'w");
2168 rn_val += im_val;
2169 addr = rn_val;
2170 write_back = instr->HasW();
2171 break;
2172 }
2173 default: {
2174 UNREACHABLE();
2175 break;
2176 }
2177 }
2178 if (IsIllegalAddress(addr)) {
2179 HandleIllegalAccess(addr, instr);
2180 } else {
2181 if (write_back) {
2182 ASSERT(rd != rn); // Unpredictable.
2183 set_register(rn, rn_val);
2184 }
2185 if (instr->HasB()) {
2186 if (instr->HasL()) {
2187 unsigned char val = ReadBU(addr);
2188 set_register(rd, val);
2189 } else {
2190 unsigned char val = get_register(rd);
2191 WriteB(addr, val);
2192 }
2193 } else {
2194 if (instr->HasL()) {
2195 set_register(rd, ReadW(addr, instr));
2196 } else {
2197 WriteW(addr, get_register(rd), instr);
2198 }
2199 }
2200 }
2201}
2202
2203void Simulator::DoDivision(Instr* instr) {
2204 const Register rd = instr->DivRdField();
2205 const Register rn = instr->DivRnField();
2206 const Register rm = instr->DivRmField();
2207
2208 if (!TargetCPUFeatures::integer_division_supported()) {
2209 UnimplementedInstruction(instr);
2210 return;
2211 }
2212
2213 // ARMv7-a does not trap on divide-by-zero. The destination register is just
2214 // set to 0.
2215 if (get_register(rm) == 0) {
2216 set_register(rd, 0);
2217 return;
2218 }
2219
2220 if (instr->IsDivUnsigned()) {
2221 // unsigned division.
2222 uint32_t rn_val = static_cast<uint32_t>(get_register(rn));
2223 uint32_t rm_val = static_cast<uint32_t>(get_register(rm));
2224 uint32_t result = rn_val / rm_val;
2225 set_register(rd, static_cast<int32_t>(result));
2226 } else {
2227 // signed division.
2228 int32_t rn_val = get_register(rn);
2229 int32_t rm_val = get_register(rm);
2230 int32_t result;
2231 if ((rn_val == static_cast<int32_t>(0x80000000)) &&
2232 (rm_val == static_cast<int32_t>(0xffffffff))) {
2233 result = 0x80000000;
2234 } else {
2235 result = rn_val / rm_val;
2236 }
2237 set_register(rd, result);
2238 }
2239}
2240
2241void Simulator::DecodeType3(Instr* instr) {
2242 if (instr->IsMedia()) {
2243 if (instr->IsDivision()) {
2244 DoDivision(instr);
2245 return;
2246 } else if (instr->IsRbit()) {
2247 // Format(instr, "rbit'cond 'rd, 'rm");
2248 Register rm = instr->RmField();
2249 Register rd = instr->RdField();
2250 set_register(rd, Utils::ReverseBits32(get_register(rm)));
2251 return;
2252 } else if (instr->IsBitFieldExtract()) {
2253 // Format(instr, "sbfx'cond 'rd, 'rn, 'lsb, 'width")
2254 const Register rd = instr->RdField();
2255 const Register rn = instr->BitFieldExtractRnField();
2256 const uint8_t width = instr->BitFieldExtractWidthField() + 1;
2257 const uint8_t lsb = instr->BitFieldExtractLSBField();
2258 const int32_t rn_val = get_register(rn);
2259 const uint32_t extracted_bitfield =
2260 ((rn_val >> lsb) & Utils::NBitMask(width));
2261 const uint32_t sign_extension =
2262 (instr->IsBitFieldExtractSignExtended() &&
2263 Utils::TestBit(extracted_bitfield, width - 1))
2264 ? ~Utils::NBitMask(width)
2265 : 0;
2266 set_register(rd, sign_extension | extracted_bitfield);
2267 } else {
2268 UNREACHABLE();
2269 }
2270 return;
2271 }
2272 Register rd = instr->RdField();
2273 Register rn = instr->RnField();
2274 int32_t rn_val = get_register(rn);
2275 bool shifter_carry_out = 0;
2276 int32_t shifter_operand = GetShiftRm(instr, &shifter_carry_out);
2277 uword addr = 0;
2278 bool write_back = false;
2279 switch (instr->PUField()) {
2280 case 0: {
2281 // Format(instr, "'memop'cond'b 'rd, ['rn], -'shift_rm");
2282 ASSERT(!instr->HasW());
2283 addr = rn_val;
2284 rn_val -= shifter_operand;
2285 write_back = true;
2286 break;
2287 }
2288 case 1: {
2289 // Format(instr, "'memop'cond'b 'rd, ['rn], +'shift_rm");
2290 ASSERT(!instr->HasW());
2291 addr = rn_val;
2292 rn_val += shifter_operand;
2293 write_back = true;
2294 break;
2295 }
2296 case 2: {
2297 // Format(instr, "'memop'cond'b 'rd, ['rn, -'shift_rm]'w");
2298 rn_val -= shifter_operand;
2299 addr = rn_val;
2300 write_back = instr->HasW();
2301 break;
2302 }
2303 case 3: {
2304 // Format(instr, "'memop'cond'b 'rd, ['rn, +'shift_rm]'w");
2305 rn_val += shifter_operand;
2306 addr = rn_val;
2307 write_back = instr->HasW();
2308 break;
2309 }
2310 default: {
2311 UNREACHABLE();
2312 break;
2313 }
2314 }
2315 if (IsIllegalAddress(addr)) {
2316 HandleIllegalAccess(addr, instr);
2317 } else {
2318 if (write_back) {
2319 ASSERT(rd != rn); // Unpredictable.
2320 set_register(rn, rn_val);
2321 }
2322 if (instr->HasB()) {
2323 if (instr->HasL()) {
2324 unsigned char val = ReadBU(addr);
2325 set_register(rd, val);
2326 } else {
2327 unsigned char val = get_register(rd);
2328 WriteB(addr, val);
2329 }
2330 } else {
2331 if (instr->HasL()) {
2332 set_register(rd, ReadW(addr, instr));
2333 } else {
2334 WriteW(addr, get_register(rd), instr);
2335 }
2336 }
2337 }
2338}
2339
2340void Simulator::DecodeType4(Instr* instr) {
2341 ASSERT(instr->Bit(22) == 0); // only allowed to be set in privileged mode
2342 if (instr->HasL()) {
2343 // Format(instr, "ldm'cond'pu 'rn'w, 'rlist");
2344 HandleRList(instr, true);
2345 } else {
2346 // Format(instr, "stm'cond'pu 'rn'w, 'rlist");
2347 HandleRList(instr, false);
2348 }
2349}
2350
2351void Simulator::DecodeType5(Instr* instr) {
2352 // Format(instr, "b'l'cond 'target");
2353 uint32_t off = (static_cast<uint32_t>(instr->SImmed24Field()) << 2) + 8;
2354 uint32_t pc = get_pc();
2355 if (instr->HasLink()) {
2356 set_register(LR, pc + Instr::kInstrSize);
2357 }
2358 set_pc(pc + off);
2359}
2360
2361void Simulator::DecodeType6(Instr* instr) {
2362 if (instr->IsVFPDoubleTransfer()) {
2363 Register rd = instr->RdField();
2364 Register rn = instr->RnField();
2365 if (instr->Bit(8) == 0) {
2366 SRegister sm = instr->SmField();
2367 SRegister sm1 = static_cast<SRegister>(sm + 1);
2368 ASSERT(sm1 < kNumberOfSRegisters);
2369 if (instr->Bit(20) == 1) {
2370 // Format(instr, "vmovrrs'cond 'rd, 'rn, {'sm', 'sm1}");
2371 set_register(rd, get_sregister_bits(sm));
2372 set_register(rn, get_sregister_bits(sm1));
2373 } else {
2374 // Format(instr, "vmovsrr'cond {'sm, 'sm1}, 'rd', 'rn");
2375 set_sregister_bits(sm, get_register(rd));
2376 set_sregister_bits(sm1, get_register(rn));
2377 }
2378 } else {
2379 DRegister dm = instr->DmField();
2380 if (instr->Bit(20) == 1) {
2381 // Format(instr, "vmovrrd'cond 'rd, 'rn, 'dm");
2382 int64_t dm_val = get_dregister_bits(dm);
2383 set_register(rd, Utils::Low32Bits(dm_val));
2384 set_register(rn, Utils::High32Bits(dm_val));
2385 } else {
2386 // Format(instr, "vmovdrr'cond 'dm, 'rd, 'rn");
2387 int64_t dm_val =
2388 Utils::LowHighTo64Bits(get_register(rd), get_register(rn));
2389 set_dregister_bits(dm, dm_val);
2390 }
2391 }
2392 } else if (instr->IsVFPLoadStore()) {
2393 Register rn = instr->RnField();
2394 int32_t addr = get_register(rn);
2395 int32_t imm_val = instr->Bits(0, 8) << 2;
2396 if (instr->Bit(23) == 1) {
2397 addr += imm_val;
2398 } else {
2399 addr -= imm_val;
2400 }
2401 if (IsIllegalAddress(addr)) {
2402 HandleIllegalAccess(addr, instr);
2403 } else {
2404 if (instr->Bit(8) == 0) {
2405 SRegister sd = instr->SdField();
2406 if (instr->Bit(20) == 1) { // vldrs
2407 // Format(instr, "vldrs'cond 'sd, ['rn, #+'off10]");
2408 // Format(instr, "vldrs'cond 'sd, ['rn, #-'off10]");
2409 set_sregister_bits(sd, ReadW(addr, instr));
2410 } else { // vstrs
2411 // Format(instr, "vstrs'cond 'sd, ['rn, #+'off10]");
2412 // Format(instr, "vstrs'cond 'sd, ['rn, #-'off10]");
2413 WriteW(addr, get_sregister_bits(sd), instr);
2414 }
2415 } else {
2416 DRegister dd = instr->DdField();
2417 if (instr->Bit(20) == 1) { // vldrd
2418 // Format(instr, "vldrd'cond 'dd, ['rn, #+'off10]");
2419 // Format(instr, "vldrd'cond 'dd, ['rn, #-'off10]");
2420 int64_t dd_val = Utils::LowHighTo64Bits(ReadW(addr, instr),
2421 ReadW(addr + 4, instr));
2422 set_dregister_bits(dd, dd_val);
2423 } else { // vstrd
2424 // Format(instr, "vstrd'cond 'dd, ['rn, #+'off10]");
2425 // Format(instr, "vstrd'cond 'dd, ['rn, #-'off10]");
2426 int64_t dd_val = get_dregister_bits(dd);
2427 WriteW(addr, Utils::Low32Bits(dd_val), instr);
2428 WriteW(addr + 4, Utils::High32Bits(dd_val), instr);
2429 }
2430 }
2431 }
2432 } else if (instr->IsVFPMultipleLoadStore()) {
2433 Register rn = instr->RnField();
2434 int32_t addr = get_register(rn);
2435 int32_t imm_val = instr->Bits(0, 8);
2436 if (instr->Bit(23) == 0) {
2437 addr -= (imm_val << 2);
2438 }
2439 if (instr->HasW()) {
2440 if (instr->Bit(23) == 1) {
2441 set_register(rn, addr + (imm_val << 2));
2442 } else {
2443 set_register(rn, addr); // already subtracted from addr
2444 }
2445 }
2446 if (IsIllegalAddress(addr)) {
2447 HandleIllegalAccess(addr, instr);
2448 } else {
2449 if (instr->Bit(8) == 0) {
2450 int32_t regs_cnt = imm_val;
2451 int32_t start = instr->Bit(22) | (instr->Bits(12, 4) << 1);
2452 for (int i = start; i < start + regs_cnt; i++) {
2453 SRegister sd = static_cast<SRegister>(i);
2454 if (instr->Bit(20) == 1) {
2455 // Format(instr, "vldms'cond'pu 'rn'w, 'slist");
2456 set_sregister_bits(sd, ReadW(addr, instr));
2457 } else {
2458 // Format(instr, "vstms'cond'pu 'rn'w, 'slist");
2459 WriteW(addr, get_sregister_bits(sd), instr);
2460 }
2461 addr += 4;
2462 }
2463 } else {
2464 int32_t regs_cnt = imm_val >> 1;
2465 int32_t start = (instr->Bit(22) << 4) | instr->Bits(12, 4);
2466 if ((regs_cnt <= 16) && (start + regs_cnt <= kNumberOfDRegisters)) {
2467 for (int i = start; i < start + regs_cnt; i++) {
2468 DRegister dd = static_cast<DRegister>(i);
2469 if (instr->Bit(20) == 1) {
2470 // Format(instr, "vldmd'cond'pu 'rn'w, 'dlist");
2471 int64_t dd_val = Utils::LowHighTo64Bits(ReadW(addr, instr),
2472 ReadW(addr + 4, instr));
2473 set_dregister_bits(dd, dd_val);
2474 } else {
2475 // Format(instr, "vstmd'cond'pu 'rn'w, 'dlist");
2476 int64_t dd_val = get_dregister_bits(dd);
2477 WriteW(addr, Utils::Low32Bits(dd_val), instr);
2478 WriteW(addr + 4, Utils::High32Bits(dd_val), instr);
2479 }
2480 addr += 8;
2481 }
2482 } else {
2483 UnimplementedInstruction(instr);
2484 }
2485 }
2486 }
2487 } else {
2488 UnimplementedInstruction(instr);
2489 }
2490}
2491
2492void Simulator::DecodeType7(Instr* instr) {
2493 if (instr->Bit(24) == 1) {
2494 // Format(instr, "svc #'svc");
2495 SupervisorCall(instr);
2496 } else if (instr->IsVFPDataProcessingOrSingleTransfer()) {
2497 if (instr->Bit(4) == 0) {
2498 // VFP Data Processing
2499 SRegister sd;
2500 SRegister sn;
2501 SRegister sm;
2502 DRegister dd;
2503 DRegister dn;
2504 DRegister dm;
2505 if (instr->Bit(8) == 0) {
2506 sd = instr->SdField();
2507 sn = instr->SnField();
2508 sm = instr->SmField();
2509 dd = kNoDRegister;
2510 dn = kNoDRegister;
2511 dm = kNoDRegister;
2512 } else {
2513 sd = kNoSRegister;
2514 sn = kNoSRegister;
2515 sm = kNoSRegister;
2516 dd = instr->DdField();
2517 dn = instr->DnField();
2518 dm = instr->DmField();
2519 }
2520 switch (instr->Bits(20, 4) & 0xb) {
2521 case 1: // vnmla, vnmls, vnmul
2522 default: {
2523 UnimplementedInstruction(instr);
2524 break;
2525 }
2526 case 0: { // vmla, vmls floating-point
2527 if (instr->Bit(8) == 0) {
2528 float addend = get_sregister(sn) * get_sregister(sm);
2529 float sd_val = get_sregister(sd);
2530 if (instr->Bit(6) == 0) {
2531 // Format(instr, "vmlas'cond 'sd, 'sn, 'sm");
2532 } else {
2533 // Format(instr, "vmlss'cond 'sd, 'sn, 'sm");
2534 addend = -addend;
2535 }
2536 set_sregister(sd, sd_val + addend);
2537 } else {
2538 double addend = get_dregister(dn) * get_dregister(dm);
2539 double dd_val = get_dregister(dd);
2540 if (instr->Bit(6) == 0) {
2541 // Format(instr, "vmlad'cond 'dd, 'dn, 'dm");
2542 } else {
2543 // Format(instr, "vmlsd'cond 'dd, 'dn, 'dm");
2544 addend = -addend;
2545 }
2546 set_dregister(dd, dd_val + addend);
2547 }
2548 break;
2549 }
2550 case 2: { // vmul
2551 if (instr->Bit(8) == 0) {
2552 // Format(instr, "vmuls'cond 'sd, 'sn, 'sm");
2553 set_sregister(sd, get_sregister(sn) * get_sregister(sm));
2554 } else {
2555 // Format(instr, "vmuld'cond 'dd, 'dn, 'dm");
2556 set_dregister(dd, get_dregister(dn) * get_dregister(dm));
2557 }
2558 break;
2559 }
2560 case 8: { // vdiv
2561 if (instr->Bit(8) == 0) {
2562 // Format(instr, "vdivs'cond 'sd, 'sn, 'sm");
2563 set_sregister(sd, get_sregister(sn) / get_sregister(sm));
2564 } else {
2565 // Format(instr, "vdivd'cond 'dd, 'dn, 'dm");
2566 set_dregister(dd, get_dregister(dn) / get_dregister(dm));
2567 }
2568 break;
2569 }
2570 case 3: { // vadd, vsub floating-point
2571 if (instr->Bit(8) == 0) {
2572 if (instr->Bit(6) == 0) {
2573 // Format(instr, "vadds'cond 'sd, 'sn, 'sm");
2574 set_sregister(sd, get_sregister(sn) + get_sregister(sm));
2575 } else {
2576 // Format(instr, "vsubs'cond 'sd, 'sn, 'sm");
2577 set_sregister(sd, get_sregister(sn) - get_sregister(sm));
2578 }
2579 } else {
2580 if (instr->Bit(6) == 0) {
2581 // Format(instr, "vaddd'cond 'dd, 'dn, 'dm");
2582 set_dregister(dd, get_dregister(dn) + get_dregister(dm));
2583 } else {
2584 // Format(instr, "vsubd'cond 'dd, 'dn, 'dm");
2585 set_dregister(dd, get_dregister(dn) - get_dregister(dm));
2586 }
2587 }
2588 break;
2589 }
2590 case 0xb: { // Other VFP data-processing instructions
2591 if (instr->Bit(6) == 0) { // vmov immediate
2592 if (instr->Bit(8) == 0) {
2593 // Format(instr, "vmovs'cond 'sd, #'immf");
2594 set_sregister(sd, instr->ImmFloatField());
2595 } else {
2596 // Format(instr, "vmovd'cond 'dd, #'immd");
2597 set_dregister(dd, instr->ImmDoubleField());
2598 }
2599 break;
2600 }
2601 switch (instr->Bits(16, 4)) {
2602 case 0: { // vmov immediate, vmov register, vabs
2603 switch (instr->Bits(6, 2)) {
2604 case 1: { // vmov register
2605 if (instr->Bit(8) == 0) {
2606 // Format(instr, "vmovs'cond 'sd, 'sm");
2607 set_sregister(sd, get_sregister(sm));
2608 } else {
2609 // Format(instr, "vmovd'cond 'dd, 'dm");
2610 set_dregister(dd, get_dregister(dm));
2611 }
2612 break;
2613 }
2614 case 3: { // vabs
2615 if (instr->Bit(8) == 0) {
2616 // Format(instr, "vabss'cond 'sd, 'sm");
2617 set_sregister(sd, fabsf(get_sregister(sm)));
2618 } else {
2619 // Format(instr, "vabsd'cond 'dd, 'dm");
2620 set_dregister(dd, fabs(get_dregister(dm)));
2621 }
2622 break;
2623 }
2624 default: {
2625 UnimplementedInstruction(instr);
2626 break;
2627 }
2628 }
2629 break;
2630 }
2631 case 1: { // vneg, vsqrt
2632 switch (instr->Bits(6, 2)) {
2633 case 1: { // vneg
2634 if (instr->Bit(8) == 0) {
2635 // Format(instr, "vnegs'cond 'sd, 'sm");
2636 set_sregister(sd, -get_sregister(sm));
2637 } else {
2638 // Format(instr, "vnegd'cond 'dd, 'dm");
2639 set_dregister(dd, -get_dregister(dm));
2640 }
2641 break;
2642 }
2643 case 3: { // vsqrt
2644 if (instr->Bit(8) == 0) {
2645 // Format(instr, "vsqrts'cond 'sd, 'sm");
2646 set_sregister(sd, sqrtf(get_sregister(sm)));
2647 } else {
2648 // Format(instr, "vsqrtd'cond 'dd, 'dm");
2649 set_dregister(dd, sqrt(get_dregister(dm)));
2650 }
2651 break;
2652 }
2653 default: {
2654 UnimplementedInstruction(instr);
2655 break;
2656 }
2657 }
2658 break;
2659 }
2660 case 4: // vcmp, vcmpe
2661 case 5: { // vcmp #0.0, vcmpe #0.0
2662 if (instr->Bit(7) == 1) { // vcmpe
2663 UnimplementedInstruction(instr);
2664 } else {
2665 fp_n_flag_ = false;
2666 fp_z_flag_ = false;
2667 fp_c_flag_ = false;
2668 fp_v_flag_ = false;
2669 if (instr->Bit(8) == 0) { // vcmps
2670 float sd_val = get_sregister(sd);
2671 float sm_val;
2672 if (instr->Bit(16) == 0) {
2673 // Format(instr, "vcmps'cond 'sd, 'sm");
2674 sm_val = get_sregister(sm);
2675 } else {
2676 // Format(instr, "vcmps'cond 'sd, #0.0");
2677 sm_val = 0.0f;
2678 }
2679 if (isnan(sd_val) || isnan(sm_val)) {
2680 fp_c_flag_ = true;
2681 fp_v_flag_ = true;
2682 } else if (sd_val == sm_val) {
2683 fp_z_flag_ = true;
2684 fp_c_flag_ = true;
2685 } else if (sd_val < sm_val) {
2686 fp_n_flag_ = true;
2687 } else {
2688 fp_c_flag_ = true;
2689 }
2690 } else { // vcmpd
2691 double dd_val = get_dregister(dd);
2692 double dm_val;
2693 if (instr->Bit(16) == 0) {
2694 // Format(instr, "vcmpd'cond 'dd, 'dm");
2695 dm_val = get_dregister(dm);
2696 } else {
2697 // Format(instr, "vcmpd'cond 'dd, #0.0");
2698 dm_val = 0.0;
2699 }
2700 if (isnan(dd_val) || isnan(dm_val)) {
2701 fp_c_flag_ = true;
2702 fp_v_flag_ = true;
2703 } else if (dd_val == dm_val) {
2704 fp_z_flag_ = true;
2705 fp_c_flag_ = true;
2706 } else if (dd_val < dm_val) {
2707 fp_n_flag_ = true;
2708 } else {
2709 fp_c_flag_ = true;
2710 }
2711 }
2712 }
2713 break;
2714 }
2715 case 7: { // vcvt between double-precision and single-precision
2716 if (instr->Bit(8) == 0) {
2717 // Format(instr, "vcvtds'cond 'dd, 'sm");
2718 dd = instr->DdField();
2719 set_dregister(dd, static_cast<double>(get_sregister(sm)));
2720 } else {
2721 // Format(instr, "vcvtsd'cond 'sd, 'dm");
2722 sd = instr->SdField();
2723 set_sregister(sd, static_cast<float>(get_dregister(dm)));
2724 }
2725 break;
2726 }
2727 case 8: { // vcvt, vcvtr between floating-point and integer
2728 sm = instr->SmField();
2729 int32_t sm_int = get_sregister_bits(sm);
2730 uint32_t ud_val = 0;
2731 int32_t id_val = 0;
2732 if (instr->Bit(7) == 0) { // vcvtsu, vcvtdu
2733 ud_val = static_cast<uint32_t>(sm_int);
2734 } else { // vcvtsi, vcvtdi
2735 id_val = sm_int;
2736 }
2737 if (instr->Bit(8) == 0) {
2738 float sd_val;
2739 if (instr->Bit(7) == 0) {
2740 // Format(instr, "vcvtsu'cond 'sd, 'sm");
2741 sd_val = static_cast<float>(ud_val);
2742 } else {
2743 // Format(instr, "vcvtsi'cond 'sd, 'sm");
2744 sd_val = static_cast<float>(id_val);
2745 }
2746 set_sregister(sd, sd_val);
2747 } else {
2748 double dd_val;
2749 if (instr->Bit(7) == 0) {
2750 // Format(instr, "vcvtdu'cond 'dd, 'sm");
2751 dd_val = static_cast<double>(ud_val);
2752 } else {
2753 // Format(instr, "vcvtdi'cond 'dd, 'sm");
2754 dd_val = static_cast<double>(id_val);
2755 }
2756 set_dregister(dd, dd_val);
2757 }
2758 break;
2759 }
2760 case 12:
2761 case 13: { // vcvt, vcvtr between floating-point and integer
2762 // We do not need to record exceptions in the FPSCR cumulative
2763 // flags, because we do not use them.
2764 if (instr->Bit(7) == 0) {
2765 // We only support round-to-zero mode
2766 UnimplementedInstruction(instr);
2767 break;
2768 }
2769 int32_t id_val = 0;
2770 uint32_t ud_val = 0;
2771 if (instr->Bit(8) == 0) {
2772 float sm_val = get_sregister(sm);
2773 if (instr->Bit(16) == 0) {
2774 // Format(instr, "vcvtus'cond 'sd, 'sm");
2775 if (sm_val >= static_cast<float>(INT32_MAX)) {
2776 ud_val = INT32_MAX;
2777 } else if (sm_val > 0.0) {
2778 ud_val = static_cast<uint32_t>(sm_val);
2779 }
2780 } else {
2781 // Format(instr, "vcvtis'cond 'sd, 'sm");
2782 if (sm_val <= static_cast<float>(INT32_MIN)) {
2783 id_val = INT32_MIN;
2784 } else if (sm_val >= static_cast<float>(INT32_MAX)) {
2785 id_val = INT32_MAX;
2786 } else {
2787 id_val = static_cast<int32_t>(sm_val);
2788 }
2789 ASSERT((id_val >= 0) || !(sm_val >= 0.0));
2790 }
2791 } else {
2792 sd = instr->SdField();
2793 double dm_val = get_dregister(dm);
2794 if (instr->Bit(16) == 0) {
2795 // Format(instr, "vcvtud'cond 'sd, 'dm");
2796 if (dm_val >= static_cast<double>(INT32_MAX)) {
2797 ud_val = INT32_MAX;
2798 } else if (dm_val > 0.0) {
2799 ud_val = static_cast<uint32_t>(dm_val);
2800 }
2801 } else {
2802 // Format(instr, "vcvtid'cond 'sd, 'dm");
2803 if (dm_val <= static_cast<double>(INT32_MIN)) {
2804 id_val = INT32_MIN;
2805 } else if (dm_val >= static_cast<double>(INT32_MAX)) {
2806 id_val = INT32_MAX;
2807 } else if (isnan(dm_val)) {
2808 id_val = 0;
2809 } else {
2810 id_val = static_cast<int32_t>(dm_val);
2811 }
2812 ASSERT((id_val >= 0) || !(dm_val >= 0.0));
2813 }
2814 }
2815 int32_t sd_val;
2816 if (instr->Bit(16) == 0) {
2817 sd_val = static_cast<int32_t>(ud_val);
2818 } else {
2819 sd_val = id_val;
2820 }
2821 set_sregister_bits(sd, sd_val);
2822 break;
2823 }
2824 case 2: // vcvtb, vcvtt
2825 case 3: // vcvtb, vcvtt
2826 case 9: // undefined
2827 case 10: // vcvt between floating-point and fixed-point
2828 case 11: // vcvt between floating-point and fixed-point
2829 case 14: // vcvt between floating-point and fixed-point
2830 case 15: // vcvt between floating-point and fixed-point
2831 default: {
2832 UnimplementedInstruction(instr);
2833 break;
2834 }
2835 }
2836 } break;
2837 }
2838 } else {
2839 // 8, 16, or 32-bit Transfer between ARM Core and VFP
2840 if ((instr->Bits(21, 3) == 0) && (instr->Bit(8) == 0)) {
2841 Register rd = instr->RdField();
2842 SRegister sn = instr->SnField();
2843 if (instr->Bit(20) == 0) {
2844 // Format(instr, "vmovs'cond 'sn, 'rd");
2845 set_sregister_bits(sn, get_register(rd));
2846 } else {
2847 // Format(instr, "vmovr'cond 'rd, 'sn");
2848 set_register(rd, get_sregister_bits(sn));
2849 }
2850 } else if ((instr->Bits(22, 3) == 0) && (instr->Bit(20) == 0) &&
2851 (instr->Bit(8) == 1) && (instr->Bits(5, 2) == 0)) {
2852 DRegister dn = instr->DnField();
2853 Register rd = instr->RdField();
2854 const int32_t src_value = get_register(rd);
2855 const int64_t dst_value = get_dregister_bits(dn);
2856 int32_t dst_lo = Utils::Low32Bits(dst_value);
2857 int32_t dst_hi = Utils::High32Bits(dst_value);
2858 if (instr->Bit(21) == 0) {
2859 // Format(instr, "vmovd'cond 'dn[0], 'rd");
2860 dst_lo = src_value;
2861 } else {
2862 // Format(instr, "vmovd'cond 'dn[1], 'rd");
2863 dst_hi = src_value;
2864 }
2865 set_dregister_bits(dn, Utils::LowHighTo64Bits(dst_lo, dst_hi));
2866 } else if ((instr->Bits(20, 4) == 0xf) && (instr->Bit(8) == 0)) {
2867 if (instr->Bits(12, 4) == 0xf) {
2868 // Format(instr, "vmrs'cond APSR, FPSCR");
2869 n_flag_ = fp_n_flag_;
2870 z_flag_ = fp_z_flag_;
2871 c_flag_ = fp_c_flag_;
2872 v_flag_ = fp_v_flag_;
2873 } else {
2874 // Format(instr, "vmrs'cond 'rd, FPSCR");
2875 const int32_t n_flag = fp_n_flag_ ? (1 << 31) : 0;
2876 const int32_t z_flag = fp_z_flag_ ? (1 << 30) : 0;
2877 const int32_t c_flag = fp_c_flag_ ? (1 << 29) : 0;
2878 const int32_t v_flag = fp_v_flag_ ? (1 << 28) : 0;
2879 set_register(instr->RdField(), n_flag | z_flag | c_flag | v_flag);
2880 }
2881 } else {
2882 UnimplementedInstruction(instr);
2883 }
2884 }
2885 } else {
2886 UnimplementedInstruction(instr);
2887 }
2888}
2889
2890static void simd_value_swap(simd_value_t* s1,
2891 int i1,
2892 simd_value_t* s2,
2893 int i2) {
2894 uint32_t tmp;
2895 tmp = s1->data_[i1].u;
2896 s1->data_[i1].u = s2->data_[i2].u;
2897 s2->data_[i2].u = tmp;
2898}
2899
2900static float vminf(float f1, float f2) {
2901 if (f1 == f2) {
2902 // take care of (-0.0) < 0.0, (they are equal according to minss)
2903 return signbit(f1) ? f1 : f2;
2904 }
2905 return f1 > f2 ? f2 : f1;
2906}
2907
2908static float vmaxf(float f1, float f2) {
2909 if (f1 == f2) {
2910 // take care of (-0.0) < 0.0, (they are equal according to minss)
2911 return signbit(f1) ? f2 : f1;
2912 }
2913 return f1 < f2 ? f2 : f1;
2914}
2915
2916void Simulator::DecodeSIMDDataProcessing(Instr* instr) {
2917 ASSERT(instr->ConditionField() == kSpecialCondition);
2918
2919 if (instr->Bit(6) == 1) {
2920 // Q = 1, Using 128-bit Q registers.
2921 const QRegister qd = instr->QdField();
2922 const QRegister qn = instr->QnField();
2923 const QRegister qm = instr->QmField();
2924 simd_value_t s8d;
2925 simd_value_t s8n;
2926 simd_value_t s8m;
2927
2928 get_qregister(qn, &s8n);
2929 get_qregister(qm, &s8m);
2930 int8_t* s8d_8 = reinterpret_cast<int8_t*>(&s8d);
2931 int8_t* s8n_8 = reinterpret_cast<int8_t*>(&s8n);
2932 int8_t* s8m_8 = reinterpret_cast<int8_t*>(&s8m);
2933 uint8_t* s8d_u8 = reinterpret_cast<uint8_t*>(&s8d);
2934 uint8_t* s8n_u8 = reinterpret_cast<uint8_t*>(&s8n);
2935 uint8_t* s8m_u8 = reinterpret_cast<uint8_t*>(&s8m);
2936 int16_t* s8d_16 = reinterpret_cast<int16_t*>(&s8d);
2937 int16_t* s8n_16 = reinterpret_cast<int16_t*>(&s8n);
2938 int16_t* s8m_16 = reinterpret_cast<int16_t*>(&s8m);
2939 uint16_t* s8d_u16 = reinterpret_cast<uint16_t*>(&s8d);
2940 uint16_t* s8n_u16 = reinterpret_cast<uint16_t*>(&s8n);
2941 uint16_t* s8m_u16 = reinterpret_cast<uint16_t*>(&s8m);
2942 int32_t* s8d_32 = reinterpret_cast<int32_t*>(&s8d);
2943 int32_t* s8n_32 = reinterpret_cast<int32_t*>(&s8n);
2944 int32_t* s8m_32 = reinterpret_cast<int32_t*>(&s8m);
2945 uint32_t* s8d_u32 = reinterpret_cast<uint32_t*>(&s8d);
2946 uint32_t* s8m_u32 = reinterpret_cast<uint32_t*>(&s8m);
2947 int64_t* s8d_64 = reinterpret_cast<int64_t*>(&s8d);
2948 int64_t* s8n_64 = reinterpret_cast<int64_t*>(&s8n);
2949 int64_t* s8m_64 = reinterpret_cast<int64_t*>(&s8m);
2950 uint64_t* s8d_u64 = reinterpret_cast<uint64_t*>(&s8d);
2951 uint64_t* s8m_u64 = reinterpret_cast<uint64_t*>(&s8m);
2952
2953 if ((instr->Bits(8, 4) == 8) && (instr->Bit(4) == 0) &&
2954 (instr->Bits(23, 2) == 0)) {
2955 // Uses q registers.
2956 // Format(instr, "vadd.'sz 'qd, 'qn, 'qm");
2957 const int size = instr->Bits(20, 2);
2958 if (size == 0) {
2959 for (int i = 0; i < 16; i++) {
2960 s8d_8[i] = s8n_8[i] + s8m_8[i];
2961 }
2962 } else if (size == 1) {
2963 for (int i = 0; i < 8; i++) {
2964 s8d_16[i] = s8n_16[i] + s8m_16[i];
2965 }
2966 } else if (size == 2) {
2967 for (int i = 0; i < 4; i++) {
2968 s8d.data_[i].u = s8n.data_[i].u + s8m.data_[i].u;
2969 }
2970 } else if (size == 3) {
2971 for (int i = 0; i < 2; i++) {
2972 s8d_64[i] = s8n_64[i] + s8m_64[i];
2973 }
2974 } else {
2975 UNREACHABLE();
2976 }
2977 } else if ((instr->Bits(8, 4) == 13) && (instr->Bit(4) == 0) &&
2978 (instr->Bits(23, 2) == 0) && (instr->Bit(21) == 0)) {
2979 // Format(instr, "vadd.F32 'qd, 'qn, 'qm");
2980 for (int i = 0; i < 4; i++) {
2981 s8d.data_[i].f = s8n.data_[i].f + s8m.data_[i].f;
2982 }
2983 } else if ((instr->Bits(8, 4) == 8) && (instr->Bit(4) == 0) &&
2984 (instr->Bits(23, 2) == 2)) {
2985 // Format(instr, "vsub.'sz 'qd, 'qn, 'qm");
2986 const int size = instr->Bits(20, 2);
2987 if (size == 0) {
2988 for (int i = 0; i < 16; i++) {
2989 s8d_8[i] = s8n_8[i] - s8m_8[i];
2990 }
2991 } else if (size == 1) {
2992 for (int i = 0; i < 8; i++) {
2993 s8d_16[i] = s8n_16[i] - s8m_16[i];
2994 }
2995 } else if (size == 2) {
2996 for (int i = 0; i < 4; i++) {
2997 s8d.data_[i].u = s8n.data_[i].u - s8m.data_[i].u;
2998 }
2999 } else if (size == 3) {
3000 for (int i = 0; i < 2; i++) {
3001 s8d_64[i] = s8n_64[i] - s8m_64[i];
3002 }
3003 } else {
3004 UNREACHABLE();
3005 }
3006 } else if ((instr->Bits(8, 4) == 13) && (instr->Bit(4) == 0) &&
3007 (instr->Bits(23, 2) == 0) && (instr->Bit(21) == 1)) {
3008 // Format(instr, "vsub.F32 'qd, 'qn, 'qm");
3009 for (int i = 0; i < 4; i++) {
3010 s8d.data_[i].f = s8n.data_[i].f - s8m.data_[i].f;
3011 }
3012 } else if ((instr->Bits(8, 4) == 9) && (instr->Bit(4) == 1) &&
3013 (instr->Bits(23, 2) == 0)) {
3014 // Format(instr, "vmul.'sz 'qd, 'qn, 'qm");
3015 const int size = instr->Bits(20, 2);
3016 if (size == 0) {
3017 for (int i = 0; i < 16; i++) {
3018 s8d_8[i] = s8n_8[i] * s8m_8[i];
3019 }
3020 } else if (size == 1) {
3021 for (int i = 0; i < 8; i++) {
3022 s8d_16[i] = s8n_16[i] * s8m_16[i];
3023 }
3024 } else if (size == 2) {
3025 for (int i = 0; i < 4; i++) {
3026 s8d.data_[i].u = s8n.data_[i].u * s8m.data_[i].u;
3027 }
3028 } else if (size == 3) {
3029 UnimplementedInstruction(instr);
3030 } else {
3031 UNREACHABLE();
3032 }
3033 } else if ((instr->Bits(8, 4) == 13) && (instr->Bit(4) == 1) &&
3034 (instr->Bits(23, 2) == 2) && (instr->Bit(21) == 0)) {
3035 // Format(instr, "vmul.F32 'qd, 'qn, 'qm");
3036 for (int i = 0; i < 4; i++) {
3037 s8d.data_[i].f = s8n.data_[i].f * s8m.data_[i].f;
3038 }
3039 } else if ((instr->Bits(8, 4) == 4) && (instr->Bit(4) == 0) &&
3040 (instr->Bit(23) == 0) && (instr->Bits(25, 3) == 1)) {
3041 // Format(instr, "vshlqu'sz 'qd, 'qm, 'qn");
3042 // Format(instr, "vshlqi'sz 'qd, 'qm, 'qn");
3043 const bool is_signed = instr->Bit(24) == 0;
3044 const int size = instr->Bits(20, 2);
3045 if (size == 0) {
3046 for (int i = 0; i < 16; i++) {
3047 int8_t shift = s8n_8[i];
3048 if (shift > 0) {
3049 s8d_u8[i] = s8m_u8[i] << shift;
3050 } else if (shift < 0) {
3051 if (is_signed) {
3052 s8d_8[i] = s8m_8[i] >> (-shift);
3053 } else {
3054 s8d_u8[i] = s8m_u8[i] >> (-shift);
3055 }
3056 }
3057 }
3058 } else if (size == 1) {
3059 for (int i = 0; i < 8; i++) {
3060 int8_t shift = s8n_8[i * 2];
3061 if (shift > 0) {
3062 s8d_u16[i] = s8m_u16[i] << shift;
3063 } else if (shift < 0) {
3064 if (is_signed) {
3065 s8d_16[i] = s8m_16[i] >> (-shift);
3066 } else {
3067 s8d_u16[i] = s8m_u16[i] >> (-shift);
3068 }
3069 }
3070 }
3071 } else if (size == 2) {
3072 for (int i = 0; i < 4; i++) {
3073 int8_t shift = s8n_8[i * 4];
3074 if (shift > 0) {
3075 s8d_u32[i] = s8m_u32[i] << shift;
3076 } else if (shift < 0) {
3077 if (is_signed) {
3078 s8d_32[i] = s8m_32[i] >> (-shift);
3079 } else {
3080 s8d_u32[i] = s8m_u32[i] >> (-shift);
3081 }
3082 }
3083 }
3084 } else {
3085 ASSERT(size == 3);
3086 for (int i = 0; i < 2; i++) {
3087 int8_t shift = s8n_8[i * 8];
3088 if (shift > 0) {
3089 s8d_u64[i] = s8m_u64[i] << shift;
3090 } else if (shift < 0) {
3091 if (is_signed) {
3092 s8d_64[i] = s8m_64[i] >> (-shift);
3093 } else {
3094 s8d_u64[i] = s8m_u64[i] >> (-shift);
3095 }
3096 }
3097 }
3098 }
3099 } else if ((instr->Bits(8, 4) == 1) && (instr->Bit(4) == 1) &&
3100 (instr->Bits(20, 2) == 0) && (instr->Bits(23, 2) == 2)) {
3101 // Format(instr, "veorq 'qd, 'qn, 'qm");
3102 for (int i = 0; i < 4; i++) {
3103 s8d.data_[i].u = s8n.data_[i].u ^ s8m.data_[i].u;
3104 }
3105 } else if ((instr->Bits(8, 4) == 1) && (instr->Bit(4) == 1) &&
3106 (instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 0)) {
3107 // Format(instr, "vornq 'qd, 'qn, 'qm");
3108 for (int i = 0; i < 4; i++) {
3109 s8d.data_[i].u = s8n.data_[i].u | ~s8m.data_[i].u;
3110 }
3111 } else if ((instr->Bits(8, 4) == 1) && (instr->Bit(4) == 1) &&
3112 (instr->Bits(20, 2) == 2) && (instr->Bits(23, 2) == 0)) {
3113 if (qm == qn) {
3114 // Format(instr, "vmovq 'qd, 'qm");
3115 for (int i = 0; i < 4; i++) {
3116 s8d.data_[i].u = s8m.data_[i].u;
3117 }
3118 } else {
3119 // Format(instr, "vorrq 'qd, 'qm");
3120 for (int i = 0; i < 4; i++) {
3121 s8d.data_[i].u = s8n.data_[i].u | s8m.data_[i].u;
3122 }
3123 }
3124 } else if ((instr->Bits(8, 4) == 1) && (instr->Bit(4) == 1) &&
3125 (instr->Bits(20, 2) == 0) && (instr->Bits(23, 2) == 0)) {
3126 // Format(instr, "vandq 'qd, 'qn, 'qm");
3127 for (int i = 0; i < 4; i++) {
3128 s8d.data_[i].u = s8n.data_[i].u & s8m.data_[i].u;
3129 }
3130 } else if ((instr->Bits(7, 5) == 11) && (instr->Bit(4) == 0) &&
3131 (instr->Bits(20, 2) == 3) && (instr->Bits(23, 5) == 7) &&
3132 (instr->Bits(16, 4) == 0)) {
3133 // Format(instr, "vmvnq 'qd, 'qm");
3134 for (int i = 0; i < 4; i++) {
3135 s8d.data_[i].u = ~s8m.data_[i].u;
3136 }
3137 } else if ((instr->Bits(8, 4) == 15) && (instr->Bit(4) == 0) &&
3138 (instr->Bits(20, 2) == 2) && (instr->Bits(23, 2) == 0)) {
3139 // Format(instr, "vminqs 'qd, 'qn, 'qm");
3140 for (int i = 0; i < 4; i++) {
3141 s8d.data_[i].f = vminf(s8n.data_[i].f, s8m.data_[i].f);
3142 }
3143 } else if ((instr->Bits(8, 4) == 15) && (instr->Bit(4) == 0) &&
3144 (instr->Bits(20, 2) == 0) && (instr->Bits(23, 2) == 0)) {
3145 // Format(instr, "vmaxqs 'qd, 'qn, 'qm");
3146 for (int i = 0; i < 4; i++) {
3147 s8d.data_[i].f = vmaxf(s8n.data_[i].f, s8m.data_[i].f);
3148 }
3149 } else if ((instr->Bits(8, 4) == 7) && (instr->Bit(4) == 0) &&
3150 (instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 3) &&
3151 (instr->Bit(7) == 0) && (instr->Bits(16, 4) == 9)) {
3152 // Format(instr, "vabsqs 'qd, 'qm");
3153 for (int i = 0; i < 4; i++) {
3154 s8d.data_[i].f = fabsf(s8m.data_[i].f);
3155 }
3156 } else if ((instr->Bits(8, 4) == 7) && (instr->Bit(4) == 0) &&
3157 (instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 3) &&
3158 (instr->Bit(7) == 1) && (instr->Bits(16, 4) == 9)) {
3159 // Format(instr, "vnegqs 'qd, 'qm");
3160 for (int i = 0; i < 4; i++) {
3161 s8d.data_[i].f = -s8m.data_[i].f;
3162 }
3163 } else if ((instr->Bits(7, 5) == 10) && (instr->Bit(4) == 0) &&
3164 (instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 3) &&
3165 (instr->Bits(16, 4) == 11)) {
3166 // Format(instr, "vrecpeq 'qd, 'qm");
3167 for (int i = 0; i < 4; i++) {
3168 s8d.data_[i].f = ReciprocalEstimate(s8m.data_[i].f);
3169 }
3170 } else if ((instr->Bits(8, 4) == 15) && (instr->Bit(4) == 1) &&
3171 (instr->Bits(20, 2) == 0) && (instr->Bits(23, 2) == 0)) {
3172 // Format(instr, "vrecpsq 'qd, 'qn, 'qm");
3173 for (int i = 0; i < 4; i++) {
3174 s8d.data_[i].f = ReciprocalStep(s8n.data_[i].f, s8m.data_[i].f);
3175 }
3176 } else if ((instr->Bits(8, 4) == 5) && (instr->Bit(4) == 0) &&
3177 (instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 3) &&
3178 (instr->Bit(7) == 1) && (instr->Bits(16, 4) == 11)) {
3179 // Format(instr, "vrsqrteqs 'qd, 'qm");
3180 for (int i = 0; i < 4; i++) {
3181 s8d.data_[i].f = ReciprocalSqrtEstimate(s8m.data_[i].f);
3182 }
3183 } else if ((instr->Bits(8, 4) == 15) && (instr->Bit(4) == 1) &&
3184 (instr->Bits(20, 2) == 2) && (instr->Bits(23, 2) == 0)) {
3185 // Format(instr, "vrsqrtsqs 'qd, 'qn, 'qm");
3186 for (int i = 0; i < 4; i++) {
3187 s8d.data_[i].f = ReciprocalSqrtStep(s8n.data_[i].f, s8m.data_[i].f);
3188 }
3189 } else if ((instr->Bits(8, 4) == 12) && (instr->Bit(4) == 0) &&
3190 (instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 3) &&
3191 (instr->Bit(7) == 0)) {
3192 DRegister dm = instr->DmField();
3193 int64_t dm_value = get_dregister_bits(dm);
3194 int32_t imm4 = instr->Bits(16, 4);
3195 int32_t idx;
3196 if ((imm4 & 1) != 0) {
3197 // Format(instr, "vdupb 'qd, 'dm['imm4_vdup]");
3198 int8_t* dm_b = reinterpret_cast<int8_t*>(&dm_value);
3199 idx = imm4 >> 1;
3200 int8_t val = dm_b[idx];
3201 for (int i = 0; i < 16; i++) {
3202 s8d_8[i] = val;
3203 }
3204 } else if ((imm4 & 2) != 0) {
3205 // Format(instr, "vduph 'qd, 'dm['imm4_vdup]");
3206 int16_t* dm_h = reinterpret_cast<int16_t*>(&dm_value);
3207 idx = imm4 >> 2;
3208 int16_t val = dm_h[idx];
3209 for (int i = 0; i < 8; i++) {
3210 s8d_16[i] = val;
3211 }
3212 } else if ((imm4 & 4) != 0) {
3213 // Format(instr, "vdupw 'qd, 'dm['imm4_vdup]");
3214 int32_t* dm_w = reinterpret_cast<int32_t*>(&dm_value);
3215 idx = imm4 >> 3;
3216 int32_t val = dm_w[idx];
3217 for (int i = 0; i < 4; i++) {
3218 s8d.data_[i].u = val;
3219 }
3220 } else {
3221 UnimplementedInstruction(instr);
3222 }
3223 } else if ((instr->Bits(8, 4) == 1) && (instr->Bit(4) == 0) &&
3224 (instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 3) &&
3225 (instr->Bit(7) == 1) && (instr->Bits(16, 4) == 10)) {
3226 // Format(instr, "vzipqw 'qd, 'qm");
3227 get_qregister(qd, &s8d);
3228
3229 // Interleave the elements with the low words in qd, and the high words
3230 // in qm.
3231 simd_value_swap(&s8d, 3, &s8m, 2);
3232 simd_value_swap(&s8d, 3, &s8m, 1);
3233 simd_value_swap(&s8d, 2, &s8m, 0);
3234 simd_value_swap(&s8d, 2, &s8d, 1);
3235
3236 set_qregister(qm, s8m); // Writes both qd and qm.
3237 } else if ((instr->Bits(8, 4) == 8) && (instr->Bit(4) == 1) &&
3238 (instr->Bits(23, 2) == 2)) {
3239 // Format(instr, "vceqq'sz 'qd, 'qn, 'qm");
3240 const int size = instr->Bits(20, 2);
3241 if (size == 0) {
3242 for (int i = 0; i < 16; i++) {
3243 s8d_8[i] = s8n_8[i] == s8m_8[i] ? 0xff : 0;
3244 }
3245 } else if (size == 1) {
3246 for (int i = 0; i < 8; i++) {
3247 s8d_16[i] = s8n_16[i] == s8m_16[i] ? 0xffff : 0;
3248 }
3249 } else if (size == 2) {
3250 for (int i = 0; i < 4; i++) {
3251 s8d.data_[i].u = s8n.data_[i].u == s8m.data_[i].u ? 0xffffffff : 0;
3252 }
3253 } else if (size == 3) {
3254 UnimplementedInstruction(instr);
3255 } else {
3256 UNREACHABLE();
3257 }
3258 } else if ((instr->Bits(8, 4) == 14) && (instr->Bit(4) == 0) &&
3259 (instr->Bits(20, 2) == 0) && (instr->Bits(23, 2) == 0)) {
3260 // Format(instr, "vceqqs 'qd, 'qn, 'qm");
3261 for (int i = 0; i < 4; i++) {
3262 s8d.data_[i].u = s8n.data_[i].f == s8m.data_[i].f ? 0xffffffff : 0;
3263 }
3264 } else if ((instr->Bits(8, 4) == 3) && (instr->Bit(4) == 1) &&
3265 (instr->Bits(23, 2) == 0)) {
3266 // Format(instr, "vcgeq'sz 'qd, 'qn, 'qm");
3267 const int size = instr->Bits(20, 2);
3268 if (size == 0) {
3269 for (int i = 0; i < 16; i++) {
3270 s8d_8[i] = s8n_8[i] >= s8m_8[i] ? 0xff : 0;
3271 }
3272 } else if (size == 1) {
3273 for (int i = 0; i < 8; i++) {
3274 s8d_16[i] = s8n_16[i] >= s8m_16[i] ? 0xffff : 0;
3275 }
3276 } else if (size == 2) {
3277 for (int i = 0; i < 4; i++) {
3278 s8d.data_[i].u = s8n_32[i] >= s8m_32[i] ? 0xffffffff : 0;
3279 }
3280 } else if (size == 3) {
3281 UnimplementedInstruction(instr);
3282 } else {
3283 UNREACHABLE();
3284 }
3285 } else if ((instr->Bits(8, 4) == 3) && (instr->Bit(4) == 1) &&
3286 (instr->Bits(23, 2) == 2)) {
3287 // Format(instr, "vcugeq'sz 'qd, 'qn, 'qm");
3288 const int size = instr->Bits(20, 2);
3289 if (size == 0) {
3290 for (int i = 0; i < 16; i++) {
3291 s8d_8[i] = s8n_u8[i] >= s8m_u8[i] ? 0xff : 0;
3292 }
3293 } else if (size == 1) {
3294 for (int i = 0; i < 8; i++) {
3295 s8d_16[i] = s8n_u16[i] >= s8m_u16[i] ? 0xffff : 0;
3296 }
3297 } else if (size == 2) {
3298 for (int i = 0; i < 4; i++) {
3299 s8d.data_[i].u = s8n.data_[i].u >= s8m.data_[i].u ? 0xffffffff : 0;
3300 }
3301 } else if (size == 3) {
3302 UnimplementedInstruction(instr);
3303 } else {
3304 UNREACHABLE();
3305 }
3306 } else if ((instr->Bits(8, 4) == 14) && (instr->Bit(4) == 0) &&
3307 (instr->Bits(20, 2) == 0) && (instr->Bits(23, 2) == 2)) {
3308 // Format(instr, "vcgeqs 'qd, 'qn, 'qm");
3309 for (int i = 0; i < 4; i++) {
3310 s8d.data_[i].u = s8n.data_[i].f >= s8m.data_[i].f ? 0xffffffff : 0;
3311 }
3312 } else if ((instr->Bits(8, 4) == 3) && (instr->Bit(4) == 0) &&
3313 (instr->Bits(23, 2) == 0)) {
3314 // Format(instr, "vcgtq'sz 'qd, 'qn, 'qm");
3315 const int size = instr->Bits(20, 2);
3316 if (size == 0) {
3317 for (int i = 0; i < 16; i++) {
3318 s8d_8[i] = s8n_8[i] > s8m_8[i] ? 0xff : 0;
3319 }
3320 } else if (size == 1) {
3321 for (int i = 0; i < 8; i++) {
3322 s8d_16[i] = s8n_16[i] > s8m_16[i] ? 0xffff : 0;
3323 }
3324 } else if (size == 2) {
3325 for (int i = 0; i < 4; i++) {
3326 s8d.data_[i].u = s8n_32[i] > s8m_32[i] ? 0xffffffff : 0;
3327 }
3328 } else if (size == 3) {
3329 UnimplementedInstruction(instr);
3330 } else {
3331 UNREACHABLE();
3332 }
3333 } else if ((instr->Bits(8, 4) == 3) && (instr->Bit(4) == 0) &&
3334 (instr->Bits(23, 2) == 2)) {
3335 // Format(instr, "vcugtq'sz 'qd, 'qn, 'qm");
3336 const int size = instr->Bits(20, 2);
3337 if (size == 0) {
3338 for (int i = 0; i < 16; i++) {
3339 s8d_8[i] = s8n_u8[i] > s8m_u8[i] ? 0xff : 0;
3340 }
3341 } else if (size == 1) {
3342 for (int i = 0; i < 8; i++) {
3343 s8d_16[i] = s8n_u16[i] > s8m_u16[i] ? 0xffff : 0;
3344 }
3345 } else if (size == 2) {
3346 for (int i = 0; i < 4; i++) {
3347 s8d.data_[i].u = s8n.data_[i].u > s8m.data_[i].u ? 0xffffffff : 0;
3348 }
3349 } else if (size == 3) {
3350 UnimplementedInstruction(instr);
3351 } else {
3352 UNREACHABLE();
3353 }
3354 } else if ((instr->Bits(8, 4) == 14) && (instr->Bit(4) == 0) &&
3355 (instr->Bits(20, 2) == 2) && (instr->Bits(23, 2) == 2)) {
3356 // Format(instr, "vcgtqs 'qd, 'qn, 'qm");
3357 for (int i = 0; i < 4; i++) {
3358 s8d.data_[i].u = s8n.data_[i].f > s8m.data_[i].f ? 0xffffffff : 0;
3359 }
3360 } else {
3361 UnimplementedInstruction(instr);
3362 }
3363
3364 set_qregister(qd, s8d);
3365 } else {
3366 // Q == 0, Uses 64-bit D registers.
3367 if ((instr->Bits(23, 2) == 3) && (instr->Bits(20, 2) == 3) &&
3368 (instr->Bits(10, 2) == 2) && (instr->Bit(4) == 0)) {
3369 // Format(instr, "vtbl 'dd, 'dtbllist, 'dm");
3370 DRegister dd = instr->DdField();
3371 DRegister dm = instr->DmField();
3372 int reg_count = instr->Bits(8, 2) + 1;
3373 int start = (instr->Bit(7) << 4) | instr->Bits(16, 4);
3374 int64_t table[4];
3375
3376 for (int i = 0; i < reg_count; i++) {
3377 DRegister d = static_cast<DRegister>(start + i);
3378 table[i] = get_dregister_bits(d);
3379 }
3380 for (int i = reg_count; i < 4; i++) {
3381 table[i] = 0;
3382 }
3383
3384 int64_t dm_value = get_dregister_bits(dm);
3385 int64_t result;
3386 int8_t* dm_bytes = reinterpret_cast<int8_t*>(&dm_value);
3387 int8_t* result_bytes = reinterpret_cast<int8_t*>(&result);
3388 int8_t* table_bytes = reinterpret_cast<int8_t*>(&table[0]);
3389 for (int i = 0; i < 8; i++) {
3390 int idx = dm_bytes[i];
3391 if ((idx >= 0) && (idx < 256)) {
3392 result_bytes[i] = table_bytes[idx];
3393 } else {
3394 result_bytes[i] = 0;
3395 }
3396 }
3397
3398 set_dregister_bits(dd, result);
3399 } else {
3400 UnimplementedInstruction(instr);
3401 }
3402 }
3403}
3404
3405// Executes the current instruction.
3406DART_FORCE_INLINE void Simulator::InstructionDecodeImpl(Instr* instr) {
3407 pc_modified_ = false;
3408 if (instr->ConditionField() == kSpecialCondition) {
3409 if (instr->InstructionBits() == static_cast<int32_t>(0xf57ff01f)) {
3410 // Format(instr, "clrex");
3411 ClearExclusive();
3412 } else if (instr->InstructionBits() ==
3413 static_cast<int32_t>(kDataMemoryBarrier)) {
3414 // Format(instr, "dmb ish");
3415 std::atomic_thread_fence(std::memory_order_seq_cst);
3416 } else {
3417 if (instr->IsSIMDDataProcessing()) {
3418 DecodeSIMDDataProcessing(instr);
3419 } else {
3420 UnimplementedInstruction(instr);
3421 }
3422 }
3423 } else if (ConditionallyExecute(instr)) {
3424 switch (instr->TypeField()) {
3425 case 0:
3426 case 1: {
3427 DecodeType01(instr);
3428 break;
3429 }
3430 case 2: {
3431 DecodeType2(instr);
3432 break;
3433 }
3434 case 3: {
3435 DecodeType3(instr);
3436 break;
3437 }
3438 case 4: {
3439 DecodeType4(instr);
3440 break;
3441 }
3442 case 5: {
3443 DecodeType5(instr);
3444 break;
3445 }
3446 case 6: {
3447 DecodeType6(instr);
3448 break;
3449 }
3450 case 7: {
3451 DecodeType7(instr);
3452 break;
3453 }
3454 default: {
3455 // Type field is three bits.
3456 UNREACHABLE();
3457 break;
3458 }
3459 }
3460 }
3461 if (!pc_modified_) {
3462 set_register(PC, reinterpret_cast<int32_t>(instr) + Instr::kInstrSize);
3463 }
3464}
3465
3466void Simulator::InstructionDecode(Instr* instr) {
3467 if (IsTracingExecution()) {
3468 THR_Print("%" Pu64 " ", icount_);
3469 const uword start = reinterpret_cast<uword>(instr);
3470 const uword end = start + Instr::kInstrSize;
3471 if (FLAG_support_disassembler) {
3472 Disassembler::Disassemble(start, end);
3473 } else {
3474 THR_Print("Disassembler not supported in this mode.\n");
3475 }
3476 }
3477 InstructionDecodeImpl(instr);
3478}
3479
3480void Simulator::Execute() {
3481 if (LIKELY(FLAG_stop_sim_at == ULLONG_MAX &&
3482 FLAG_trace_sim_after == ULLONG_MAX)) {
3483 ExecuteNoTrace();
3484 } else {
3485 ExecuteTrace();
3486 }
3487}
3488
3489void Simulator::ExecuteNoTrace() {
3490 // Get the PC to simulate. Cannot use the accessor here as we need the
3491 // raw PC value and not the one used as input to arithmetic instructions.
3492 uword program_counter = get_pc();
3493
3494 // Fast version of the dispatch loop without checking whether the simulator
3495 // should be stopping at a particular executed instruction.
3496 while (program_counter != kEndSimulatingPC) {
3497 Instr* instr = reinterpret_cast<Instr*>(program_counter);
3498 icount_++;
3499 InstructionDecodeImpl(instr);
3500 program_counter = get_pc();
3501 }
3502}
3503
3504void Simulator::ExecuteTrace() {
3505 // Get the PC to simulate. Cannot use the accessor here as we need the
3506 // raw PC value and not the one used as input to arithmetic instructions.
3507 uword program_counter = get_pc();
3508
3509 // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when
3510 // we reach the particular instruction count or address.
3511 while (program_counter != kEndSimulatingPC) {
3512 Instr* instr = reinterpret_cast<Instr*>(program_counter);
3513 icount_++;
3514 if (icount_ == FLAG_stop_sim_at) {
3515 SimulatorDebugger dbg(this);
3516 dbg.Stop(instr, "Instruction count reached");
3517 } else if (reinterpret_cast<uint64_t>(instr) == FLAG_stop_sim_at) {
3518 SimulatorDebugger dbg(this);
3519 dbg.Stop(instr, "Instruction address reached");
3520 } else if (IsIllegalAddress(program_counter)) {
3521 HandleIllegalAccess(program_counter, instr);
3522 } else {
3523 InstructionDecode(instr);
3524 }
3525 program_counter = get_pc();
3526 }
3527}
3528
3529int64_t Simulator::Call(int32_t entry,
3530 int32_t parameter0,
3531 int32_t parameter1,
3532 int32_t parameter2,
3533 int32_t parameter3,
3534 bool fp_return,
3535 bool fp_args) {
3536 // Save the SP register before the call so we can restore it.
3537 int32_t sp_before_call = get_register(SP);
3538
3539 // Setup parameters.
3540 if (fp_args) {
3541 set_sregister(S0, bit_cast<float, int32_t>(parameter0));
3542 set_sregister(S1, bit_cast<float, int32_t>(parameter1));
3543 set_sregister(S2, bit_cast<float, int32_t>(parameter2));
3544 set_sregister(S3, bit_cast<float, int32_t>(parameter3));
3545 } else {
3546 set_register(R0, parameter0);
3547 set_register(R1, parameter1);
3548 set_register(R2, parameter2);
3549 set_register(R3, parameter3);
3550 }
3551
3552 // Make sure the activation frames are properly aligned.
3553 int32_t stack_pointer = sp_before_call;
3554 if (OS::ActivationFrameAlignment() > 1) {
3555 stack_pointer =
3556 Utils::RoundDown(stack_pointer, OS::ActivationFrameAlignment());
3557 }
3558 set_register(SP, stack_pointer);
3559
3560 // Prepare to execute the code at entry.
3561 set_register(PC, entry);
3562 // Put down marker for end of simulation. The simulator will stop simulation
3563 // when the PC reaches this value. By saving the "end simulation" value into
3564 // the LR the simulation stops when returning to this call point.
3565 set_register(LR, kEndSimulatingPC);
3566
3567 // Remember the values of callee-saved registers.
3568 // The code below assumes that r9 is not used as sb (static base) in
3569 // simulator code and therefore is regarded as a callee-saved register.
3570 int32_t r4_val = get_register(R4);
3571 int32_t r5_val = get_register(R5);
3572 int32_t r6_val = get_register(R6);
3573 int32_t r7_val = get_register(R7);
3574 int32_t r8_val = get_register(R8);
3575#if !defined(DART_TARGET_OS_MACOS) && !defined(DART_TARGET_OS_MACOS_IOS)
3576 int32_t r9_val = get_register(R9);
3577#endif
3578 int32_t r10_val = get_register(R10);
3579 int32_t r11_val = get_register(R11);
3580
3581 double d8_val = 0.0;
3582 double d9_val = 0.0;
3583 double d10_val = 0.0;
3584 double d11_val = 0.0;
3585 double d12_val = 0.0;
3586 double d13_val = 0.0;
3587 double d14_val = 0.0;
3588 double d15_val = 0.0;
3589
3590 d8_val = get_dregister(D8);
3591 d9_val = get_dregister(D9);
3592 d10_val = get_dregister(D10);
3593 d11_val = get_dregister(D11);
3594 d12_val = get_dregister(D12);
3595 d13_val = get_dregister(D13);
3596 d14_val = get_dregister(D14);
3597 d15_val = get_dregister(D15);
3598
3599 // Setup the callee-saved registers with a known value. To be able to check
3600 // that they are preserved properly across dart execution.
3601 int32_t callee_saved_value = icount_;
3602 set_register(R4, callee_saved_value);
3603 set_register(R5, callee_saved_value);
3604 set_register(R6, callee_saved_value);
3605 set_register(R7, callee_saved_value);
3606 set_register(R8, callee_saved_value);
3607#if !defined(DART_TARGET_OS_MACOS) && !defined(DART_TARGET_OS_MACOS_IOS)
3608 set_register(R9, callee_saved_value);
3609#endif
3610 set_register(R10, callee_saved_value);
3611 set_register(R11, callee_saved_value);
3612
3613 double callee_saved_dvalue = 0.0;
3614 callee_saved_dvalue = static_cast<double>(icount_);
3615 set_dregister(D8, callee_saved_dvalue);
3616 set_dregister(D9, callee_saved_dvalue);
3617 set_dregister(D10, callee_saved_dvalue);
3618 set_dregister(D11, callee_saved_dvalue);
3619 set_dregister(D12, callee_saved_dvalue);
3620 set_dregister(D13, callee_saved_dvalue);
3621 set_dregister(D14, callee_saved_dvalue);
3622 set_dregister(D15, callee_saved_dvalue);
3623
3624 // Start the simulation
3625 Execute();
3626
3627 // Check that the callee-saved registers have been preserved.
3628 ASSERT(callee_saved_value == get_register(R4));
3629 ASSERT(callee_saved_value == get_register(R5));
3630 ASSERT(callee_saved_value == get_register(R6));
3631 ASSERT(callee_saved_value == get_register(R7));
3632 ASSERT(callee_saved_value == get_register(R8));
3633#if !defined(DART_TARGET_OS_MACOS) && !defined(DART_TARGET_OS_MACOS_IOS)
3634 ASSERT(callee_saved_value == get_register(R9));
3635#endif
3636 ASSERT(callee_saved_value == get_register(R10));
3637 ASSERT(callee_saved_value == get_register(R11));
3638
3639 ASSERT(callee_saved_dvalue == get_dregister(D8));
3640 ASSERT(callee_saved_dvalue == get_dregister(D9));
3641 ASSERT(callee_saved_dvalue == get_dregister(D10));
3642 ASSERT(callee_saved_dvalue == get_dregister(D11));
3643 ASSERT(callee_saved_dvalue == get_dregister(D12));
3644 ASSERT(callee_saved_dvalue == get_dregister(D13));
3645 ASSERT(callee_saved_dvalue == get_dregister(D14));
3646 ASSERT(callee_saved_dvalue == get_dregister(D15));
3647
3648 // Restore callee-saved registers with the original value.
3649 set_register(R4, r4_val);
3650 set_register(R5, r5_val);
3651 set_register(R6, r6_val);
3652 set_register(R7, r7_val);
3653 set_register(R8, r8_val);
3654#if !defined(DART_TARGET_OS_MACOS) && !defined(DART_TARGET_OS_MACOS_IOS)
3655 set_register(R9, r9_val);
3656#endif
3657 set_register(R10, r10_val);
3658 set_register(R11, r11_val);
3659
3660 set_dregister(D8, d8_val);
3661 set_dregister(D9, d9_val);
3662 set_dregister(D10, d10_val);
3663 set_dregister(D11, d11_val);
3664 set_dregister(D12, d12_val);
3665 set_dregister(D13, d13_val);
3666 set_dregister(D14, d14_val);
3667 set_dregister(D15, d15_val);
3668
3669 // Restore the SP register and return R1:R0.
3670 set_register(SP, sp_before_call);
3671 int64_t return_value;
3672 if (fp_return) {
3673 return_value = bit_cast<int64_t, double>(get_dregister(D0));
3674 } else {
3675 return_value = Utils::LowHighTo64Bits(get_register(R0), get_register(R1));
3676 }
3677 return return_value;
3678}
3679
3680void Simulator::JumpToFrame(uword pc, uword sp, uword fp, Thread* thread) {
3681 // Walk over all setjmp buffers (simulated --> C++ transitions)
3682 // and try to find the setjmp associated with the simulated stack pointer.
3683 SimulatorSetjmpBuffer* buf = last_setjmp_buffer();
3684 while (buf->link() != nullptr && buf->link()->sp() <= sp) {
3685 buf = buf->link();
3686 }
3687 ASSERT(buf != nullptr);
3688
3689 // The C++ caller has not cleaned up the stack memory of C++ frames.
3690 // Prepare for unwinding frames by destroying all the stack resources
3691 // in the previous C++ frames.
3692 StackResource::Unwind(thread);
3693
3694 // Keep the following code in sync with `StubCode::JumpToFrameStub()`.
3695
3696 // Unwind the C++ stack and continue simulation in the target frame.
3697 set_register(PC, static_cast<int32_t>(pc));
3698 set_register(SP, static_cast<int32_t>(sp));
3699 set_register(FP, static_cast<int32_t>(fp));
3700 set_register(THR, reinterpret_cast<uword>(thread));
3701 // Set the tag.
3702 thread->set_vm_tag(VMTag::kDartTagId);
3703 // Clear top exit frame.
3704 thread->set_top_exit_frame_info(0);
3705 // Restore pool pointer.
3706 int32_t code =
3707 *reinterpret_cast<int32_t*>(fp + kPcMarkerSlotFromFp * kWordSize);
3708 int32_t pp = FLAG_precompiled_mode
3709 ? static_cast<int32_t>(thread->global_object_pool())
3710 : *reinterpret_cast<int32_t*>(
3711 (code + Code::object_pool_offset() - kHeapObjectTag));
3712
3713 set_register(CODE_REG, code);
3714 set_register(PP, pp);
3715 if (FLAG_precompiled_mode) {
3716 set_register(DISPATCH_TABLE_REG,
3717 reinterpret_cast<int32_t>(thread->dispatch_table_array()));
3718 }
3719 buf->Longjmp();
3720}
3721
3722} // namespace dart
3723
3724#endif // defined(USING_SIMULATOR)
3725
3726#endif // defined TARGET_ARCH_ARM
3727

source code of dart_sdk/runtime/vm/simulator_arm.cc