1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <stdarg.h>
6 #include <stdlib.h>
7 #include <cmath>
8
9 #if V8_TARGET_ARCH_PPC
10
11 #include "src/assembler.h"
12 #include "src/base/bits.h"
13 #include "src/codegen.h"
14 #include "src/disasm.h"
15 #include "src/macro-assembler.h"
16 #include "src/ostreams.h"
17 #include "src/ppc/constants-ppc.h"
18 #include "src/ppc/frame-constants-ppc.h"
19 #include "src/ppc/simulator-ppc.h"
20 #include "src/runtime/runtime-utils.h"
21
22 #if defined(USE_SIMULATOR)
23
24 // Only build the simulator if not compiling for real PPC hardware.
25 namespace v8 {
26 namespace internal {
27
28 const auto GetRegConfig = RegisterConfiguration::Default;
29
30 // static
31 base::LazyInstance<Simulator::GlobalMonitor>::type Simulator::global_monitor_ =
32 LAZY_INSTANCE_INITIALIZER;
33
34 // This macro provides a platform independent use of sscanf. The reason for
35 // SScanF not being implemented in a platform independent way through
36 // ::v8::internal::OS in the same way as SNPrintF is that the
37 // Windows C Run-Time Library does not provide vsscanf.
38 #define SScanF sscanf // NOLINT
39
40 // The PPCDebugger class is used by the simulator while debugging simulated
41 // PowerPC code.
42 class PPCDebugger {
43 public:
PPCDebugger(Simulator * sim)44 explicit PPCDebugger(Simulator* sim) : sim_(sim) {}
45
46 void Stop(Instruction* instr);
47 void Debug();
48
49 private:
50 static const Instr kBreakpointInstr = (TWI | 0x1F * B21);
51 static const Instr kNopInstr = (ORI); // ori, 0,0,0
52
53 Simulator* sim_;
54
55 intptr_t GetRegisterValue(int regnum);
56 double GetRegisterPairDoubleValue(int regnum);
57 double GetFPDoubleRegisterValue(int regnum);
58 bool GetValue(const char* desc, intptr_t* value);
59 bool GetFPDoubleValue(const char* desc, double* value);
60
61 // Set or delete a breakpoint. Returns true if successful.
62 bool SetBreakpoint(Instruction* break_pc);
63 bool DeleteBreakpoint(Instruction* break_pc);
64
65 // Undo and redo all breakpoints. This is needed to bracket disassembly and
66 // execution to skip past breakpoints when run from the debugger.
67 void UndoBreakpoints();
68 void RedoBreakpoints();
69 };
70
Stop(Instruction * instr)71 void PPCDebugger::Stop(Instruction* instr) {
72 // Get the stop code.
73 // use of kStopCodeMask not right on PowerPC
74 uint32_t code = instr->SvcValue() & kStopCodeMask;
75 // Retrieve the encoded address, which comes just after this stop.
76 char* msg = *reinterpret_cast<char**>(sim_->get_pc() + kInstrSize);
77 // Update this stop description.
78 if (sim_->isWatchedStop(code) && !sim_->watched_stops_[code].desc) {
79 sim_->watched_stops_[code].desc = msg;
80 }
81 // Print the stop message and code if it is not the default code.
82 if (code != kMaxStopCode) {
83 PrintF("Simulator hit stop %u: %s\n", code, msg);
84 } else {
85 PrintF("Simulator hit %s\n", msg);
86 }
87 sim_->set_pc(sim_->get_pc() + kInstrSize + kPointerSize);
88 Debug();
89 }
90
GetRegisterValue(int regnum)91 intptr_t PPCDebugger::GetRegisterValue(int regnum) {
92 return sim_->get_register(regnum);
93 }
94
95
GetRegisterPairDoubleValue(int regnum)96 double PPCDebugger::GetRegisterPairDoubleValue(int regnum) {
97 return sim_->get_double_from_register_pair(regnum);
98 }
99
100
GetFPDoubleRegisterValue(int regnum)101 double PPCDebugger::GetFPDoubleRegisterValue(int regnum) {
102 return sim_->get_double_from_d_register(regnum);
103 }
104
105
GetValue(const char * desc,intptr_t * value)106 bool PPCDebugger::GetValue(const char* desc, intptr_t* value) {
107 int regnum = Registers::Number(desc);
108 if (regnum != kNoRegister) {
109 *value = GetRegisterValue(regnum);
110 return true;
111 } else {
112 if (strncmp(desc, "0x", 2) == 0) {
113 return SScanF(desc + 2, "%" V8PRIxPTR,
114 reinterpret_cast<uintptr_t*>(value)) == 1;
115 } else {
116 return SScanF(desc, "%" V8PRIuPTR, reinterpret_cast<uintptr_t*>(value)) ==
117 1;
118 }
119 }
120 return false;
121 }
122
123
GetFPDoubleValue(const char * desc,double * value)124 bool PPCDebugger::GetFPDoubleValue(const char* desc, double* value) {
125 int regnum = DoubleRegisters::Number(desc);
126 if (regnum != kNoRegister) {
127 *value = sim_->get_double_from_d_register(regnum);
128 return true;
129 }
130 return false;
131 }
132
133
SetBreakpoint(Instruction * break_pc)134 bool PPCDebugger::SetBreakpoint(Instruction* break_pc) {
135 // Check if a breakpoint can be set. If not return without any side-effects.
136 if (sim_->break_pc_ != nullptr) {
137 return false;
138 }
139
140 // Set the breakpoint.
141 sim_->break_pc_ = break_pc;
142 sim_->break_instr_ = break_pc->InstructionBits();
143 // Not setting the breakpoint instruction in the code itself. It will be set
144 // when the debugger shell continues.
145 return true;
146 }
147
148
DeleteBreakpoint(Instruction * break_pc)149 bool PPCDebugger::DeleteBreakpoint(Instruction* break_pc) {
150 if (sim_->break_pc_ != nullptr) {
151 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
152 }
153
154 sim_->break_pc_ = nullptr;
155 sim_->break_instr_ = 0;
156 return true;
157 }
158
159
UndoBreakpoints()160 void PPCDebugger::UndoBreakpoints() {
161 if (sim_->break_pc_ != nullptr) {
162 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
163 }
164 }
165
166
RedoBreakpoints()167 void PPCDebugger::RedoBreakpoints() {
168 if (sim_->break_pc_ != nullptr) {
169 sim_->break_pc_->SetInstructionBits(kBreakpointInstr);
170 }
171 }
172
173
Debug()174 void PPCDebugger::Debug() {
175 intptr_t last_pc = -1;
176 bool done = false;
177
178 #define COMMAND_SIZE 63
179 #define ARG_SIZE 255
180
181 #define STR(a) #a
182 #define XSTR(a) STR(a)
183
184 char cmd[COMMAND_SIZE + 1];
185 char arg1[ARG_SIZE + 1];
186 char arg2[ARG_SIZE + 1];
187 char* argv[3] = {cmd, arg1, arg2};
188
189 // make sure to have a proper terminating character if reaching the limit
190 cmd[COMMAND_SIZE] = 0;
191 arg1[ARG_SIZE] = 0;
192 arg2[ARG_SIZE] = 0;
193
194 // Undo all set breakpoints while running in the debugger shell. This will
195 // make them invisible to all commands.
196 UndoBreakpoints();
197 // Disable tracing while simulating
198 bool trace = ::v8::internal::FLAG_trace_sim;
199 ::v8::internal::FLAG_trace_sim = false;
200
201 while (!done && !sim_->has_bad_pc()) {
202 if (last_pc != sim_->get_pc()) {
203 disasm::NameConverter converter;
204 disasm::Disassembler dasm(converter);
205 // use a reasonably large buffer
206 v8::internal::EmbeddedVector<char, 256> buffer;
207 dasm.InstructionDecode(buffer, reinterpret_cast<byte*>(sim_->get_pc()));
208 PrintF(" 0x%08" V8PRIxPTR " %s\n", sim_->get_pc(), buffer.start());
209 last_pc = sim_->get_pc();
210 }
211 char* line = ReadLine("sim> ");
212 if (line == nullptr) {
213 break;
214 } else {
215 char* last_input = sim_->last_debugger_input();
216 if (strcmp(line, "\n") == 0 && last_input != nullptr) {
217 line = last_input;
218 } else {
219 // Ownership is transferred to sim_;
220 sim_->set_last_debugger_input(line);
221 }
222 // Use sscanf to parse the individual parts of the command line. At the
223 // moment no command expects more than two parameters.
224 int argc = SScanF(line,
225 "%" XSTR(COMMAND_SIZE) "s "
226 "%" XSTR(ARG_SIZE) "s "
227 "%" XSTR(ARG_SIZE) "s",
228 cmd, arg1, arg2);
229 if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
230 intptr_t value;
231
232 // If at a breakpoint, proceed past it.
233 if ((reinterpret_cast<Instruction*>(sim_->get_pc()))
234 ->InstructionBits() == 0x7D821008) {
235 sim_->set_pc(sim_->get_pc() + kInstrSize);
236 } else {
237 sim_->ExecuteInstruction(
238 reinterpret_cast<Instruction*>(sim_->get_pc()));
239 }
240
241 if (argc == 2 && last_pc != sim_->get_pc() && GetValue(arg1, &value)) {
242 for (int i = 1; i < value; i++) {
243 disasm::NameConverter converter;
244 disasm::Disassembler dasm(converter);
245 // use a reasonably large buffer
246 v8::internal::EmbeddedVector<char, 256> buffer;
247 dasm.InstructionDecode(buffer,
248 reinterpret_cast<byte*>(sim_->get_pc()));
249 PrintF(" 0x%08" V8PRIxPTR " %s\n", sim_->get_pc(),
250 buffer.start());
251 sim_->ExecuteInstruction(
252 reinterpret_cast<Instruction*>(sim_->get_pc()));
253 }
254 }
255 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) {
256 // If at a breakpoint, proceed past it.
257 if ((reinterpret_cast<Instruction*>(sim_->get_pc()))
258 ->InstructionBits() == 0x7D821008) {
259 sim_->set_pc(sim_->get_pc() + kInstrSize);
260 } else {
261 // Execute the one instruction we broke at with breakpoints disabled.
262 sim_->ExecuteInstruction(
263 reinterpret_cast<Instruction*>(sim_->get_pc()));
264 }
265 // Leave the debugger shell.
266 done = true;
267 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
268 if (argc == 2 || (argc == 3 && strcmp(arg2, "fp") == 0)) {
269 intptr_t value;
270 double dvalue;
271 if (strcmp(arg1, "all") == 0) {
272 for (int i = 0; i < kNumRegisters; i++) {
273 value = GetRegisterValue(i);
274 PrintF(" %3s: %08" V8PRIxPTR,
275 GetRegConfig()->GetGeneralRegisterName(i), value);
276 if ((argc == 3 && strcmp(arg2, "fp") == 0) && i < 8 &&
277 (i % 2) == 0) {
278 dvalue = GetRegisterPairDoubleValue(i);
279 PrintF(" (%f)\n", dvalue);
280 } else if (i != 0 && !((i + 1) & 3)) {
281 PrintF("\n");
282 }
283 }
284 PrintF(" pc: %08" V8PRIxPTR " lr: %08" V8PRIxPTR
285 " "
286 "ctr: %08" V8PRIxPTR " xer: %08x cr: %08x\n",
287 sim_->special_reg_pc_, sim_->special_reg_lr_,
288 sim_->special_reg_ctr_, sim_->special_reg_xer_,
289 sim_->condition_reg_);
290 } else if (strcmp(arg1, "alld") == 0) {
291 for (int i = 0; i < kNumRegisters; i++) {
292 value = GetRegisterValue(i);
293 PrintF(" %3s: %08" V8PRIxPTR " %11" V8PRIdPTR,
294 GetRegConfig()->GetGeneralRegisterName(i), value, value);
295 if ((argc == 3 && strcmp(arg2, "fp") == 0) && i < 8 &&
296 (i % 2) == 0) {
297 dvalue = GetRegisterPairDoubleValue(i);
298 PrintF(" (%f)\n", dvalue);
299 } else if (!((i + 1) % 2)) {
300 PrintF("\n");
301 }
302 }
303 PrintF(" pc: %08" V8PRIxPTR " lr: %08" V8PRIxPTR
304 " "
305 "ctr: %08" V8PRIxPTR " xer: %08x cr: %08x\n",
306 sim_->special_reg_pc_, sim_->special_reg_lr_,
307 sim_->special_reg_ctr_, sim_->special_reg_xer_,
308 sim_->condition_reg_);
309 } else if (strcmp(arg1, "allf") == 0) {
310 for (int i = 0; i < DoubleRegister::kNumRegisters; i++) {
311 dvalue = GetFPDoubleRegisterValue(i);
312 uint64_t as_words = bit_cast<uint64_t>(dvalue);
313 PrintF("%3s: %f 0x%08x %08x\n",
314 GetRegConfig()->GetDoubleRegisterName(i), dvalue,
315 static_cast<uint32_t>(as_words >> 32),
316 static_cast<uint32_t>(as_words & 0xFFFFFFFF));
317 }
318 } else if (arg1[0] == 'r' &&
319 (arg1[1] >= '0' && arg1[1] <= '9' &&
320 (arg1[2] == '\0' || (arg1[2] >= '0' && arg1[2] <= '9' &&
321 arg1[3] == '\0')))) {
322 int regnum = strtoul(&arg1[1], 0, 10);
323 if (regnum != kNoRegister) {
324 value = GetRegisterValue(regnum);
325 PrintF("%s: 0x%08" V8PRIxPTR " %" V8PRIdPTR "\n", arg1, value,
326 value);
327 } else {
328 PrintF("%s unrecognized\n", arg1);
329 }
330 } else {
331 if (GetValue(arg1, &value)) {
332 PrintF("%s: 0x%08" V8PRIxPTR " %" V8PRIdPTR "\n", arg1, value,
333 value);
334 } else if (GetFPDoubleValue(arg1, &dvalue)) {
335 uint64_t as_words = bit_cast<uint64_t>(dvalue);
336 PrintF("%s: %f 0x%08x %08x\n", arg1, dvalue,
337 static_cast<uint32_t>(as_words >> 32),
338 static_cast<uint32_t>(as_words & 0xFFFFFFFF));
339 } else {
340 PrintF("%s unrecognized\n", arg1);
341 }
342 }
343 } else {
344 PrintF("print <register>\n");
345 }
346 } else if ((strcmp(cmd, "po") == 0) ||
347 (strcmp(cmd, "printobject") == 0)) {
348 if (argc == 2) {
349 intptr_t value;
350 StdoutStream os;
351 if (GetValue(arg1, &value)) {
352 Object* obj = reinterpret_cast<Object*>(value);
353 os << arg1 << ": \n";
354 #ifdef DEBUG
355 obj->Print(os);
356 os << "\n";
357 #else
358 os << Brief(obj) << "\n";
359 #endif
360 } else {
361 os << arg1 << " unrecognized\n";
362 }
363 } else {
364 PrintF("printobject <value>\n");
365 }
366 } else if (strcmp(cmd, "setpc") == 0) {
367 intptr_t value;
368
369 if (!GetValue(arg1, &value)) {
370 PrintF("%s unrecognized\n", arg1);
371 continue;
372 }
373 sim_->set_pc(value);
374 } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0) {
375 intptr_t* cur = nullptr;
376 intptr_t* end = nullptr;
377 int next_arg = 1;
378
379 if (strcmp(cmd, "stack") == 0) {
380 cur = reinterpret_cast<intptr_t*>(sim_->get_register(Simulator::sp));
381 } else { // "mem"
382 intptr_t value;
383 if (!GetValue(arg1, &value)) {
384 PrintF("%s unrecognized\n", arg1);
385 continue;
386 }
387 cur = reinterpret_cast<intptr_t*>(value);
388 next_arg++;
389 }
390
391 intptr_t words; // likely inaccurate variable name for 64bit
392 if (argc == next_arg) {
393 words = 10;
394 } else {
395 if (!GetValue(argv[next_arg], &words)) {
396 words = 10;
397 }
398 }
399 end = cur + words;
400
401 while (cur < end) {
402 PrintF(" 0x%08" V8PRIxPTR ": 0x%08" V8PRIxPTR " %10" V8PRIdPTR,
403 reinterpret_cast<intptr_t>(cur), *cur, *cur);
404 HeapObject* obj = reinterpret_cast<HeapObject*>(*cur);
405 intptr_t value = *cur;
406 Heap* current_heap = sim_->isolate_->heap();
407 if (((value & 1) == 0) ||
408 current_heap->ContainsSlow(obj->address())) {
409 PrintF(" (");
410 if ((value & 1) == 0) {
411 PrintF("smi %d", PlatformSmiTagging::SmiToInt(obj));
412 } else {
413 obj->ShortPrint();
414 }
415 PrintF(")");
416 }
417 PrintF("\n");
418 cur++;
419 }
420 } else if (strcmp(cmd, "disasm") == 0 || strcmp(cmd, "di") == 0) {
421 disasm::NameConverter converter;
422 disasm::Disassembler dasm(converter);
423 // use a reasonably large buffer
424 v8::internal::EmbeddedVector<char, 256> buffer;
425
426 byte* prev = nullptr;
427 byte* cur = nullptr;
428 byte* end = nullptr;
429
430 if (argc == 1) {
431 cur = reinterpret_cast<byte*>(sim_->get_pc());
432 end = cur + (10 * kInstrSize);
433 } else if (argc == 2) {
434 int regnum = Registers::Number(arg1);
435 if (regnum != kNoRegister || strncmp(arg1, "0x", 2) == 0) {
436 // The argument is an address or a register name.
437 intptr_t value;
438 if (GetValue(arg1, &value)) {
439 cur = reinterpret_cast<byte*>(value);
440 // Disassemble 10 instructions at <arg1>.
441 end = cur + (10 * kInstrSize);
442 }
443 } else {
444 // The argument is the number of instructions.
445 intptr_t value;
446 if (GetValue(arg1, &value)) {
447 cur = reinterpret_cast<byte*>(sim_->get_pc());
448 // Disassemble <arg1> instructions.
449 end = cur + (value * kInstrSize);
450 }
451 }
452 } else {
453 intptr_t value1;
454 intptr_t value2;
455 if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
456 cur = reinterpret_cast<byte*>(value1);
457 end = cur + (value2 * kInstrSize);
458 }
459 }
460
461 while (cur < end) {
462 prev = cur;
463 cur += dasm.InstructionDecode(buffer, cur);
464 PrintF(" 0x%08" V8PRIxPTR " %s\n", reinterpret_cast<intptr_t>(prev),
465 buffer.start());
466 }
467 } else if (strcmp(cmd, "gdb") == 0) {
468 PrintF("relinquishing control to gdb\n");
469 v8::base::OS::DebugBreak();
470 PrintF("regaining control from gdb\n");
471 } else if (strcmp(cmd, "break") == 0) {
472 if (argc == 2) {
473 intptr_t value;
474 if (GetValue(arg1, &value)) {
475 if (!SetBreakpoint(reinterpret_cast<Instruction*>(value))) {
476 PrintF("setting breakpoint failed\n");
477 }
478 } else {
479 PrintF("%s unrecognized\n", arg1);
480 }
481 } else {
482 PrintF("break <address>\n");
483 }
484 } else if (strcmp(cmd, "del") == 0) {
485 if (!DeleteBreakpoint(nullptr)) {
486 PrintF("deleting breakpoint failed\n");
487 }
488 } else if (strcmp(cmd, "cr") == 0) {
489 PrintF("Condition reg: %08x\n", sim_->condition_reg_);
490 } else if (strcmp(cmd, "lr") == 0) {
491 PrintF("Link reg: %08" V8PRIxPTR "\n", sim_->special_reg_lr_);
492 } else if (strcmp(cmd, "ctr") == 0) {
493 PrintF("Ctr reg: %08" V8PRIxPTR "\n", sim_->special_reg_ctr_);
494 } else if (strcmp(cmd, "xer") == 0) {
495 PrintF("XER: %08x\n", sim_->special_reg_xer_);
496 } else if (strcmp(cmd, "fpscr") == 0) {
497 PrintF("FPSCR: %08x\n", sim_->fp_condition_reg_);
498 } else if (strcmp(cmd, "stop") == 0) {
499 intptr_t value;
500 intptr_t stop_pc = sim_->get_pc() - (kInstrSize + kPointerSize);
501 Instruction* stop_instr = reinterpret_cast<Instruction*>(stop_pc);
502 Instruction* msg_address =
503 reinterpret_cast<Instruction*>(stop_pc + kInstrSize);
504 if ((argc == 2) && (strcmp(arg1, "unstop") == 0)) {
505 // Remove the current stop.
506 if (sim_->isStopInstruction(stop_instr)) {
507 stop_instr->SetInstructionBits(kNopInstr);
508 msg_address->SetInstructionBits(kNopInstr);
509 } else {
510 PrintF("Not at debugger stop.\n");
511 }
512 } else if (argc == 3) {
513 // Print information about all/the specified breakpoint(s).
514 if (strcmp(arg1, "info") == 0) {
515 if (strcmp(arg2, "all") == 0) {
516 PrintF("Stop information:\n");
517 for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) {
518 sim_->PrintStopInfo(i);
519 }
520 } else if (GetValue(arg2, &value)) {
521 sim_->PrintStopInfo(value);
522 } else {
523 PrintF("Unrecognized argument.\n");
524 }
525 } else if (strcmp(arg1, "enable") == 0) {
526 // Enable all/the specified breakpoint(s).
527 if (strcmp(arg2, "all") == 0) {
528 for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) {
529 sim_->EnableStop(i);
530 }
531 } else if (GetValue(arg2, &value)) {
532 sim_->EnableStop(value);
533 } else {
534 PrintF("Unrecognized argument.\n");
535 }
536 } else if (strcmp(arg1, "disable") == 0) {
537 // Disable all/the specified breakpoint(s).
538 if (strcmp(arg2, "all") == 0) {
539 for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) {
540 sim_->DisableStop(i);
541 }
542 } else if (GetValue(arg2, &value)) {
543 sim_->DisableStop(value);
544 } else {
545 PrintF("Unrecognized argument.\n");
546 }
547 }
548 } else {
549 PrintF("Wrong usage. Use help command for more information.\n");
550 }
551 } else if ((strcmp(cmd, "t") == 0) || strcmp(cmd, "trace") == 0) {
552 ::v8::internal::FLAG_trace_sim = !::v8::internal::FLAG_trace_sim;
553 PrintF("Trace of executed instructions is %s\n",
554 ::v8::internal::FLAG_trace_sim ? "on" : "off");
555 } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
556 PrintF("cont\n");
557 PrintF(" continue execution (alias 'c')\n");
558 PrintF("stepi [num instructions]\n");
559 PrintF(" step one/num instruction(s) (alias 'si')\n");
560 PrintF("print <register>\n");
561 PrintF(" print register content (alias 'p')\n");
562 PrintF(" use register name 'all' to display all integer registers\n");
563 PrintF(
564 " use register name 'alld' to display integer registers "
565 "with decimal values\n");
566 PrintF(" use register name 'rN' to display register number 'N'\n");
567 PrintF(" add argument 'fp' to print register pair double values\n");
568 PrintF(
569 " use register name 'allf' to display floating-point "
570 "registers\n");
571 PrintF("printobject <register>\n");
572 PrintF(" print an object from a register (alias 'po')\n");
573 PrintF("cr\n");
574 PrintF(" print condition register\n");
575 PrintF("lr\n");
576 PrintF(" print link register\n");
577 PrintF("ctr\n");
578 PrintF(" print ctr register\n");
579 PrintF("xer\n");
580 PrintF(" print XER\n");
581 PrintF("fpscr\n");
582 PrintF(" print FPSCR\n");
583 PrintF("stack [<num words>]\n");
584 PrintF(" dump stack content, default dump 10 words)\n");
585 PrintF("mem <address> [<num words>]\n");
586 PrintF(" dump memory content, default dump 10 words)\n");
587 PrintF("disasm [<instructions>]\n");
588 PrintF("disasm [<address/register>]\n");
589 PrintF("disasm [[<address/register>] <instructions>]\n");
590 PrintF(" disassemble code, default is 10 instructions\n");
591 PrintF(" from pc (alias 'di')\n");
592 PrintF("gdb\n");
593 PrintF(" enter gdb\n");
594 PrintF("break <address>\n");
595 PrintF(" set a break point on the address\n");
596 PrintF("del\n");
597 PrintF(" delete the breakpoint\n");
598 PrintF("trace (alias 't')\n");
599 PrintF(" toogle the tracing of all executed statements\n");
600 PrintF("stop feature:\n");
601 PrintF(" Description:\n");
602 PrintF(" Stops are debug instructions inserted by\n");
603 PrintF(" the Assembler::stop() function.\n");
604 PrintF(" When hitting a stop, the Simulator will\n");
605 PrintF(" stop and give control to the PPCDebugger.\n");
606 PrintF(" The first %d stop codes are watched:\n",
607 Simulator::kNumOfWatchedStops);
608 PrintF(" - They can be enabled / disabled: the Simulator\n");
609 PrintF(" will / won't stop when hitting them.\n");
610 PrintF(" - The Simulator keeps track of how many times they \n");
611 PrintF(" are met. (See the info command.) Going over a\n");
612 PrintF(" disabled stop still increases its counter. \n");
613 PrintF(" Commands:\n");
614 PrintF(" stop info all/<code> : print infos about number <code>\n");
615 PrintF(" or all stop(s).\n");
616 PrintF(" stop enable/disable all/<code> : enables / disables\n");
617 PrintF(" all or number <code> stop(s)\n");
618 PrintF(" stop unstop\n");
619 PrintF(" ignore the stop instruction at the current location\n");
620 PrintF(" from now on\n");
621 } else {
622 PrintF("Unknown command: %s\n", cmd);
623 }
624 }
625 }
626
627 // Add all the breakpoints back to stop execution and enter the debugger
628 // shell when hit.
629 RedoBreakpoints();
630 // Restore tracing
631 ::v8::internal::FLAG_trace_sim = trace;
632
633 #undef COMMAND_SIZE
634 #undef ARG_SIZE
635
636 #undef STR
637 #undef XSTR
638 }
639
ICacheMatch(void * one,void * two)640 bool Simulator::ICacheMatch(void* one, void* two) {
641 DCHECK_EQ(reinterpret_cast<intptr_t>(one) & CachePage::kPageMask, 0);
642 DCHECK_EQ(reinterpret_cast<intptr_t>(two) & CachePage::kPageMask, 0);
643 return one == two;
644 }
645
646
ICacheHash(void * key)647 static uint32_t ICacheHash(void* key) {
648 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)) >> 2;
649 }
650
651
AllOnOnePage(uintptr_t start,int size)652 static bool AllOnOnePage(uintptr_t start, int size) {
653 intptr_t start_page = (start & ~CachePage::kPageMask);
654 intptr_t end_page = ((start + size) & ~CachePage::kPageMask);
655 return start_page == end_page;
656 }
657
658
set_last_debugger_input(char * input)659 void Simulator::set_last_debugger_input(char* input) {
660 DeleteArray(last_debugger_input_);
661 last_debugger_input_ = input;
662 }
663
SetRedirectInstruction(Instruction * instruction)664 void Simulator::SetRedirectInstruction(Instruction* instruction) {
665 instruction->SetInstructionBits(rtCallRedirInstr | kCallRtRedirected);
666 }
667
FlushICache(base::CustomMatcherHashMap * i_cache,void * start_addr,size_t size)668 void Simulator::FlushICache(base::CustomMatcherHashMap* i_cache,
669 void* start_addr, size_t size) {
670 intptr_t start = reinterpret_cast<intptr_t>(start_addr);
671 int intra_line = (start & CachePage::kLineMask);
672 start -= intra_line;
673 size += intra_line;
674 size = ((size - 1) | CachePage::kLineMask) + 1;
675 int offset = (start & CachePage::kPageMask);
676 while (!AllOnOnePage(start, size - 1)) {
677 int bytes_to_flush = CachePage::kPageSize - offset;
678 FlushOnePage(i_cache, start, bytes_to_flush);
679 start += bytes_to_flush;
680 size -= bytes_to_flush;
681 DCHECK_EQ(0, static_cast<int>(start & CachePage::kPageMask));
682 offset = 0;
683 }
684 if (size != 0) {
685 FlushOnePage(i_cache, start, size);
686 }
687 }
688
GetCachePage(base::CustomMatcherHashMap * i_cache,void * page)689 CachePage* Simulator::GetCachePage(base::CustomMatcherHashMap* i_cache,
690 void* page) {
691 base::HashMap::Entry* entry = i_cache->LookupOrInsert(page, ICacheHash(page));
692 if (entry->value == nullptr) {
693 CachePage* new_page = new CachePage();
694 entry->value = new_page;
695 }
696 return reinterpret_cast<CachePage*>(entry->value);
697 }
698
699
700 // Flush from start up to and not including start + size.
FlushOnePage(base::CustomMatcherHashMap * i_cache,intptr_t start,int size)701 void Simulator::FlushOnePage(base::CustomMatcherHashMap* i_cache,
702 intptr_t start, int size) {
703 DCHECK_LE(size, CachePage::kPageSize);
704 DCHECK(AllOnOnePage(start, size - 1));
705 DCHECK_EQ(start & CachePage::kLineMask, 0);
706 DCHECK_EQ(size & CachePage::kLineMask, 0);
707 void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask));
708 int offset = (start & CachePage::kPageMask);
709 CachePage* cache_page = GetCachePage(i_cache, page);
710 char* valid_bytemap = cache_page->ValidityByte(offset);
711 memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift);
712 }
713
CheckICache(base::CustomMatcherHashMap * i_cache,Instruction * instr)714 void Simulator::CheckICache(base::CustomMatcherHashMap* i_cache,
715 Instruction* instr) {
716 intptr_t address = reinterpret_cast<intptr_t>(instr);
717 void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
718 void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask));
719 int offset = (address & CachePage::kPageMask);
720 CachePage* cache_page = GetCachePage(i_cache, page);
721 char* cache_valid_byte = cache_page->ValidityByte(offset);
722 bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID);
723 char* cached_line = cache_page->CachedData(offset & ~CachePage::kLineMask);
724 if (cache_hit) {
725 // Check that the data in memory matches the contents of the I-cache.
726 CHECK_EQ(0, memcmp(reinterpret_cast<void*>(instr),
727 cache_page->CachedData(offset), kInstrSize));
728 } else {
729 // Cache miss. Load memory into the cache.
730 memcpy(cached_line, line, CachePage::kLineLength);
731 *cache_valid_byte = CachePage::LINE_VALID;
732 }
733 }
734
735
Simulator(Isolate * isolate)736 Simulator::Simulator(Isolate* isolate) : isolate_(isolate) {
737 // Set up simulator support first. Some of this information is needed to
738 // setup the architecture state.
739 #if V8_TARGET_ARCH_PPC64
740 size_t stack_size = FLAG_sim_stack_size * KB;
741 #else
742 size_t stack_size = MB; // allocate 1MB for stack
743 #endif
744 stack_size += 2 * stack_protection_size_;
745 stack_ = reinterpret_cast<char*>(malloc(stack_size));
746 pc_modified_ = false;
747 icount_ = 0;
748 break_pc_ = nullptr;
749 break_instr_ = 0;
750
751 // Set up architecture state.
752 // All registers are initialized to zero to start with.
753 for (int i = 0; i < kNumGPRs; i++) {
754 registers_[i] = 0;
755 }
756 condition_reg_ = 0;
757 fp_condition_reg_ = 0;
758 special_reg_pc_ = 0;
759 special_reg_lr_ = 0;
760 special_reg_ctr_ = 0;
761
762 // Initializing FP registers.
763 for (int i = 0; i < kNumFPRs; i++) {
764 fp_registers_[i] = 0.0;
765 }
766
767 // The sp is initialized to point to the bottom (high address) of the
768 // allocated stack area. To be safe in potential stack underflows we leave
769 // some buffer below.
770 registers_[sp] =
771 reinterpret_cast<intptr_t>(stack_) + stack_size - stack_protection_size_;
772
773 last_debugger_input_ = nullptr;
774 }
775
~Simulator()776 Simulator::~Simulator() {
777 global_monitor_.Pointer()->RemoveProcessor(&global_monitor_processor_);
778 free(stack_);
779 }
780
781
782 // Get the active Simulator for the current thread.
current(Isolate * isolate)783 Simulator* Simulator::current(Isolate* isolate) {
784 v8::internal::Isolate::PerIsolateThreadData* isolate_data =
785 isolate->FindOrAllocatePerThreadDataForThisThread();
786 DCHECK_NOT_NULL(isolate_data);
787
788 Simulator* sim = isolate_data->simulator();
789 if (sim == nullptr) {
790 // TODO(146): delete the simulator object when a thread/isolate goes away.
791 sim = new Simulator(isolate);
792 isolate_data->set_simulator(sim);
793 }
794 return sim;
795 }
796
797
798 // Sets the register in the architecture state.
set_register(int reg,intptr_t value)799 void Simulator::set_register(int reg, intptr_t value) {
800 DCHECK((reg >= 0) && (reg < kNumGPRs));
801 registers_[reg] = value;
802 }
803
804
805 // Get the register from the architecture state.
get_register(int reg) const806 intptr_t Simulator::get_register(int reg) const {
807 DCHECK((reg >= 0) && (reg < kNumGPRs));
808 // Stupid code added to avoid bug in GCC.
809 // See: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43949
810 if (reg >= kNumGPRs) return 0;
811 // End stupid code.
812 return registers_[reg];
813 }
814
815
get_double_from_register_pair(int reg)816 double Simulator::get_double_from_register_pair(int reg) {
817 DCHECK((reg >= 0) && (reg < kNumGPRs) && ((reg % 2) == 0));
818
819 double dm_val = 0.0;
820 #if !V8_TARGET_ARCH_PPC64 // doesn't make sense in 64bit mode
821 // Read the bits from the unsigned integer register_[] array
822 // into the double precision floating point value and return it.
823 char buffer[sizeof(fp_registers_[0])];
824 memcpy(buffer, ®isters_[reg], 2 * sizeof(registers_[0]));
825 memcpy(&dm_val, buffer, 2 * sizeof(registers_[0]));
826 #endif
827 return (dm_val);
828 }
829
830
831 // Raw access to the PC register.
set_pc(intptr_t value)832 void Simulator::set_pc(intptr_t value) {
833 pc_modified_ = true;
834 special_reg_pc_ = value;
835 }
836
837
has_bad_pc() const838 bool Simulator::has_bad_pc() const {
839 return ((special_reg_pc_ == bad_lr) || (special_reg_pc_ == end_sim_pc));
840 }
841
842
843 // Raw access to the PC register without the special adjustment when reading.
get_pc() const844 intptr_t Simulator::get_pc() const { return special_reg_pc_; }
845
846
847 // Runtime FP routines take:
848 // - two double arguments
849 // - one double argument and zero or one integer arguments.
850 // All are consructed here from d1, d2 and r3.
GetFpArgs(double * x,double * y,intptr_t * z)851 void Simulator::GetFpArgs(double* x, double* y, intptr_t* z) {
852 *x = get_double_from_d_register(1);
853 *y = get_double_from_d_register(2);
854 *z = get_register(3);
855 }
856
857
858 // The return value is in d1.
SetFpResult(const double & result)859 void Simulator::SetFpResult(const double& result) {
860 set_d_register_from_double(1, result);
861 }
862
863
TrashCallerSaveRegisters()864 void Simulator::TrashCallerSaveRegisters() {
865 // We don't trash the registers with the return value.
866 #if 0 // A good idea to trash volatile registers, needs to be done
867 registers_[2] = 0x50BAD4U;
868 registers_[3] = 0x50BAD4U;
869 registers_[12] = 0x50BAD4U;
870 #endif
871 }
872
873
ReadWU(intptr_t addr,Instruction * instr)874 uint32_t Simulator::ReadWU(intptr_t addr, Instruction* instr) {
875 // All supported PPC targets allow unaligned accesses, so we don't need to
876 // check the alignment here.
877 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
878 local_monitor_.NotifyLoad(addr);
879 uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
880 return *ptr;
881 }
882
ReadExWU(intptr_t addr,Instruction * instr)883 uint32_t Simulator::ReadExWU(intptr_t addr, Instruction* instr) {
884 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
885 local_monitor_.NotifyLoadExcl(addr, TransactionSize::Word);
886 global_monitor_.Pointer()->NotifyLoadExcl_Locked(addr,
887 &global_monitor_processor_);
888 uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
889 return *ptr;
890 }
891
ReadW(intptr_t addr,Instruction * instr)892 int32_t Simulator::ReadW(intptr_t addr, Instruction* instr) {
893 // All supported PPC targets allow unaligned accesses, so we don't need to
894 // check the alignment here.
895 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
896 local_monitor_.NotifyLoad(addr);
897 int32_t* ptr = reinterpret_cast<int32_t*>(addr);
898 return *ptr;
899 }
900
901
WriteW(intptr_t addr,uint32_t value,Instruction * instr)902 void Simulator::WriteW(intptr_t addr, uint32_t value, Instruction* instr) {
903 // All supported PPC targets allow unaligned accesses, so we don't need to
904 // check the alignment here.
905 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
906 local_monitor_.NotifyStore(addr);
907 global_monitor_.Pointer()->NotifyStore_Locked(addr,
908 &global_monitor_processor_);
909 uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
910 *ptr = value;
911 return;
912 }
913
WriteExW(intptr_t addr,uint32_t value,Instruction * instr)914 int Simulator::WriteExW(intptr_t addr, uint32_t value, Instruction* instr) {
915 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
916 if (local_monitor_.NotifyStoreExcl(addr, TransactionSize::Word) &&
917 global_monitor_.Pointer()->NotifyStoreExcl_Locked(
918 addr, &global_monitor_processor_)) {
919 uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
920 *ptr = value;
921 return 0;
922 } else {
923 return 1;
924 }
925 }
926
WriteW(intptr_t addr,int32_t value,Instruction * instr)927 void Simulator::WriteW(intptr_t addr, int32_t value, Instruction* instr) {
928 // All supported PPC targets allow unaligned accesses, so we don't need to
929 // check the alignment here.
930 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
931 local_monitor_.NotifyStore(addr);
932 global_monitor_.Pointer()->NotifyStore_Locked(addr,
933 &global_monitor_processor_);
934 int32_t* ptr = reinterpret_cast<int32_t*>(addr);
935 *ptr = value;
936 return;
937 }
938
ReadHU(intptr_t addr,Instruction * instr)939 uint16_t Simulator::ReadHU(intptr_t addr, Instruction* instr) {
940 // All supported PPC targets allow unaligned accesses, so we don't need to
941 // check the alignment here.
942 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
943 local_monitor_.NotifyLoad(addr);
944 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
945 return *ptr;
946 }
947
ReadExHU(intptr_t addr,Instruction * instr)948 uint16_t Simulator::ReadExHU(intptr_t addr, Instruction* instr) {
949 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
950 local_monitor_.NotifyLoadExcl(addr, TransactionSize::HalfWord);
951 global_monitor_.Pointer()->NotifyLoadExcl_Locked(addr,
952 &global_monitor_processor_);
953 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
954 return *ptr;
955 }
956
ReadH(intptr_t addr,Instruction * instr)957 int16_t Simulator::ReadH(intptr_t addr, Instruction* instr) {
958 // All supported PPC targets allow unaligned accesses, so we don't need to
959 // check the alignment here.
960 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
961 local_monitor_.NotifyLoad(addr);
962 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
963 return *ptr;
964 }
965
966
WriteH(intptr_t addr,uint16_t value,Instruction * instr)967 void Simulator::WriteH(intptr_t addr, uint16_t value, Instruction* instr) {
968 // All supported PPC targets allow unaligned accesses, so we don't need to
969 // check the alignment here.
970 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
971 local_monitor_.NotifyStore(addr);
972 global_monitor_.Pointer()->NotifyStore_Locked(addr,
973 &global_monitor_processor_);
974 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
975 *ptr = value;
976 return;
977 }
978
979
WriteH(intptr_t addr,int16_t value,Instruction * instr)980 void Simulator::WriteH(intptr_t addr, int16_t value, Instruction* instr) {
981 // All supported PPC targets allow unaligned accesses, so we don't need to
982 // check the alignment here.
983 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
984 local_monitor_.NotifyStore(addr);
985 global_monitor_.Pointer()->NotifyStore_Locked(addr,
986 &global_monitor_processor_);
987 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
988 *ptr = value;
989 return;
990 }
991
WriteExH(intptr_t addr,uint16_t value,Instruction * instr)992 int Simulator::WriteExH(intptr_t addr, uint16_t value, Instruction* instr) {
993 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
994 if (local_monitor_.NotifyStoreExcl(addr, TransactionSize::HalfWord) &&
995 global_monitor_.Pointer()->NotifyStoreExcl_Locked(
996 addr, &global_monitor_processor_)) {
997 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
998 *ptr = value;
999 return 0;
1000 } else {
1001 return 1;
1002 }
1003 }
1004
ReadBU(intptr_t addr)1005 uint8_t Simulator::ReadBU(intptr_t addr) {
1006 // All supported PPC targets allow unaligned accesses, so we don't need to
1007 // check the alignment here.
1008 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
1009 local_monitor_.NotifyLoad(addr);
1010 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1011 return *ptr;
1012 }
1013
1014
ReadB(intptr_t addr)1015 int8_t Simulator::ReadB(intptr_t addr) {
1016 // All supported PPC targets allow unaligned accesses, so we don't need to
1017 // check the alignment here.
1018 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
1019 local_monitor_.NotifyLoad(addr);
1020 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
1021 return *ptr;
1022 }
1023
ReadExBU(intptr_t addr)1024 uint8_t Simulator::ReadExBU(intptr_t addr) {
1025 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
1026 local_monitor_.NotifyLoadExcl(addr, TransactionSize::Byte);
1027 global_monitor_.Pointer()->NotifyLoadExcl_Locked(addr,
1028 &global_monitor_processor_);
1029 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1030 return *ptr;
1031 }
1032
WriteB(intptr_t addr,uint8_t value)1033 void Simulator::WriteB(intptr_t addr, uint8_t value) {
1034 // All supported PPC targets allow unaligned accesses, so we don't need to
1035 // check the alignment here.
1036 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
1037 local_monitor_.NotifyStore(addr);
1038 global_monitor_.Pointer()->NotifyStore_Locked(addr,
1039 &global_monitor_processor_);
1040 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1041 *ptr = value;
1042 }
1043
1044
WriteB(intptr_t addr,int8_t value)1045 void Simulator::WriteB(intptr_t addr, int8_t value) {
1046 // All supported PPC targets allow unaligned accesses, so we don't need to
1047 // check the alignment here.
1048 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
1049 local_monitor_.NotifyStore(addr);
1050 global_monitor_.Pointer()->NotifyStore_Locked(addr,
1051 &global_monitor_processor_);
1052 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
1053 *ptr = value;
1054 }
1055
WriteExB(intptr_t addr,uint8_t value)1056 int Simulator::WriteExB(intptr_t addr, uint8_t value) {
1057 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
1058 if (local_monitor_.NotifyStoreExcl(addr, TransactionSize::Byte) &&
1059 global_monitor_.Pointer()->NotifyStoreExcl_Locked(
1060 addr, &global_monitor_processor_)) {
1061 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1062 *ptr = value;
1063 return 0;
1064 } else {
1065 return 1;
1066 }
1067 }
1068
ReadDW(intptr_t addr)1069 intptr_t* Simulator::ReadDW(intptr_t addr) {
1070 // All supported PPC targets allow unaligned accesses, so we don't need to
1071 // check the alignment here.
1072 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
1073 local_monitor_.NotifyLoad(addr);
1074 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
1075 return ptr;
1076 }
1077
1078
WriteDW(intptr_t addr,int64_t value)1079 void Simulator::WriteDW(intptr_t addr, int64_t value) {
1080 // All supported PPC targets allow unaligned accesses, so we don't need to
1081 // check the alignment here.
1082 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
1083 local_monitor_.NotifyStore(addr);
1084 global_monitor_.Pointer()->NotifyStore_Locked(addr,
1085 &global_monitor_processor_);
1086 int64_t* ptr = reinterpret_cast<int64_t*>(addr);
1087 *ptr = value;
1088 return;
1089 }
1090
1091
1092 // Returns the limit of the stack area to enable checking for stack overflows.
StackLimit(uintptr_t c_limit) const1093 uintptr_t Simulator::StackLimit(uintptr_t c_limit) const {
1094 // The simulator uses a separate JS stack. If we have exhausted the C stack,
1095 // we also drop down the JS limit to reflect the exhaustion on the JS stack.
1096 if (GetCurrentStackPosition() < c_limit) {
1097 return reinterpret_cast<uintptr_t>(get_sp());
1098 }
1099
1100 // Otherwise the limit is the JS stack. Leave a safety margin to prevent
1101 // overrunning the stack when pushing values.
1102 return reinterpret_cast<uintptr_t>(stack_) + stack_protection_size_;
1103 }
1104
1105
1106 // Unsupported instructions use Format to print an error and stop execution.
Format(Instruction * instr,const char * format)1107 void Simulator::Format(Instruction* instr, const char* format) {
1108 PrintF("Simulator found unsupported instruction:\n 0x%08" V8PRIxPTR ": %s\n",
1109 reinterpret_cast<intptr_t>(instr), format);
1110 UNIMPLEMENTED();
1111 }
1112
1113
1114 // Calculate C flag value for additions.
CarryFrom(int32_t left,int32_t right,int32_t carry)1115 bool Simulator::CarryFrom(int32_t left, int32_t right, int32_t carry) {
1116 uint32_t uleft = static_cast<uint32_t>(left);
1117 uint32_t uright = static_cast<uint32_t>(right);
1118 uint32_t urest = 0xFFFFFFFFU - uleft;
1119
1120 return (uright > urest) ||
1121 (carry && (((uright + 1) > urest) || (uright > (urest - 1))));
1122 }
1123
1124
1125 // Calculate C flag value for subtractions.
BorrowFrom(int32_t left,int32_t right)1126 bool Simulator::BorrowFrom(int32_t left, int32_t right) {
1127 uint32_t uleft = static_cast<uint32_t>(left);
1128 uint32_t uright = static_cast<uint32_t>(right);
1129
1130 return (uright > uleft);
1131 }
1132
1133
1134 // Calculate V flag value for additions and subtractions.
OverflowFrom(int32_t alu_out,int32_t left,int32_t right,bool addition)1135 bool Simulator::OverflowFrom(int32_t alu_out, int32_t left, int32_t right,
1136 bool addition) {
1137 bool overflow;
1138 if (addition) {
1139 // operands have the same sign
1140 overflow = ((left >= 0 && right >= 0) || (left < 0 && right < 0))
1141 // and operands and result have different sign
1142 &&
1143 ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
1144 } else {
1145 // operands have different signs
1146 overflow = ((left < 0 && right >= 0) || (left >= 0 && right < 0))
1147 // and first operand and result have different signs
1148 &&
1149 ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
1150 }
1151 return overflow;
1152 }
1153
1154
1155 #if V8_TARGET_ARCH_PPC64
decodeObjectPair(ObjectPair * pair,intptr_t * x,intptr_t * y)1156 static void decodeObjectPair(ObjectPair* pair, intptr_t* x, intptr_t* y) {
1157 *x = reinterpret_cast<intptr_t>(pair->x);
1158 *y = reinterpret_cast<intptr_t>(pair->y);
1159 }
1160 #else
decodeObjectPair(ObjectPair * pair,intptr_t * x,intptr_t * y)1161 static void decodeObjectPair(ObjectPair* pair, intptr_t* x, intptr_t* y) {
1162 #if V8_TARGET_BIG_ENDIAN
1163 *x = static_cast<int32_t>(*pair >> 32);
1164 *y = static_cast<int32_t>(*pair);
1165 #else
1166 *x = static_cast<int32_t>(*pair);
1167 *y = static_cast<int32_t>(*pair >> 32);
1168 #endif
1169 }
1170 #endif
1171
1172 // Calls into the V8 runtime.
1173 typedef intptr_t (*SimulatorRuntimeCall)(intptr_t arg0, intptr_t arg1,
1174 intptr_t arg2, intptr_t arg3,
1175 intptr_t arg4, intptr_t arg5,
1176 intptr_t arg6, intptr_t arg7,
1177 intptr_t arg8);
1178 typedef ObjectPair (*SimulatorRuntimePairCall)(intptr_t arg0, intptr_t arg1,
1179 intptr_t arg2, intptr_t arg3,
1180 intptr_t arg4, intptr_t arg5);
1181
1182 // These prototypes handle the four types of FP calls.
1183 typedef int (*SimulatorRuntimeCompareCall)(double darg0, double darg1);
1184 typedef double (*SimulatorRuntimeFPFPCall)(double darg0, double darg1);
1185 typedef double (*SimulatorRuntimeFPCall)(double darg0);
1186 typedef double (*SimulatorRuntimeFPIntCall)(double darg0, intptr_t arg0);
1187
1188 // This signature supports direct call in to API function native callback
1189 // (refer to InvocationCallback in v8.h).
1190 typedef void (*SimulatorRuntimeDirectApiCall)(intptr_t arg0);
1191 typedef void (*SimulatorRuntimeProfilingApiCall)(intptr_t arg0, void* arg1);
1192
1193 // This signature supports direct call to accessor getter callback.
1194 typedef void (*SimulatorRuntimeDirectGetterCall)(intptr_t arg0, intptr_t arg1);
1195 typedef void (*SimulatorRuntimeProfilingGetterCall)(intptr_t arg0,
1196 intptr_t arg1, void* arg2);
1197
1198 // Software interrupt instructions are used by the simulator to call into the
1199 // C-based V8 runtime.
SoftwareInterrupt(Instruction * instr)1200 void Simulator::SoftwareInterrupt(Instruction* instr) {
1201 int svc = instr->SvcValue();
1202 switch (svc) {
1203 case kCallRtRedirected: {
1204 // Check if stack is aligned. Error if not aligned is reported below to
1205 // include information on the function called.
1206 bool stack_aligned =
1207 (get_register(sp) & (::v8::internal::FLAG_sim_stack_alignment - 1)) ==
1208 0;
1209 Redirection* redirection = Redirection::FromInstruction(instr);
1210 const int kArgCount = 9;
1211 const int kRegisterArgCount = 8;
1212 int arg0_regnum = 3;
1213 intptr_t result_buffer = 0;
1214 bool uses_result_buffer =
1215 (redirection->type() == ExternalReference::BUILTIN_CALL_PAIR &&
1216 !ABI_RETURNS_OBJECT_PAIRS_IN_REGS);
1217 if (uses_result_buffer) {
1218 result_buffer = get_register(r3);
1219 arg0_regnum++;
1220 }
1221 intptr_t arg[kArgCount];
1222 // First eight arguments in registers r3-r10.
1223 for (int i = 0; i < kRegisterArgCount; i++) {
1224 arg[i] = get_register(arg0_regnum + i);
1225 }
1226 intptr_t* stack_pointer = reinterpret_cast<intptr_t*>(get_register(sp));
1227 // Remaining argument on stack
1228 arg[kRegisterArgCount] = stack_pointer[kStackFrameExtraParamSlot];
1229 STATIC_ASSERT(kArgCount == kRegisterArgCount + 1);
1230 STATIC_ASSERT(kMaxCParameters == 9);
1231 bool fp_call =
1232 (redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) ||
1233 (redirection->type() == ExternalReference::BUILTIN_COMPARE_CALL) ||
1234 (redirection->type() == ExternalReference::BUILTIN_FP_CALL) ||
1235 (redirection->type() == ExternalReference::BUILTIN_FP_INT_CALL);
1236 // This is dodgy but it works because the C entry stubs are never moved.
1237 // See comment in codegen-arm.cc and bug 1242173.
1238 intptr_t saved_lr = special_reg_lr_;
1239 intptr_t external =
1240 reinterpret_cast<intptr_t>(redirection->external_function());
1241 if (fp_call) {
1242 double dval0, dval1; // one or two double parameters
1243 intptr_t ival; // zero or one integer parameters
1244 int iresult = 0; // integer return value
1245 double dresult = 0; // double return value
1246 GetFpArgs(&dval0, &dval1, &ival);
1247 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
1248 SimulatorRuntimeCall generic_target =
1249 reinterpret_cast<SimulatorRuntimeCall>(external);
1250 switch (redirection->type()) {
1251 case ExternalReference::BUILTIN_FP_FP_CALL:
1252 case ExternalReference::BUILTIN_COMPARE_CALL:
1253 PrintF("Call to host function at %p with args %f, %f",
1254 reinterpret_cast<void*>(FUNCTION_ADDR(generic_target)),
1255 dval0, dval1);
1256 break;
1257 case ExternalReference::BUILTIN_FP_CALL:
1258 PrintF("Call to host function at %p with arg %f",
1259 reinterpret_cast<void*>(FUNCTION_ADDR(generic_target)),
1260 dval0);
1261 break;
1262 case ExternalReference::BUILTIN_FP_INT_CALL:
1263 PrintF("Call to host function at %p with args %f, %" V8PRIdPTR,
1264 reinterpret_cast<void*>(FUNCTION_ADDR(generic_target)),
1265 dval0, ival);
1266 break;
1267 default:
1268 UNREACHABLE();
1269 break;
1270 }
1271 if (!stack_aligned) {
1272 PrintF(" with unaligned stack %08" V8PRIxPTR "\n",
1273 get_register(sp));
1274 }
1275 PrintF("\n");
1276 }
1277 CHECK(stack_aligned);
1278 switch (redirection->type()) {
1279 case ExternalReference::BUILTIN_COMPARE_CALL: {
1280 SimulatorRuntimeCompareCall target =
1281 reinterpret_cast<SimulatorRuntimeCompareCall>(external);
1282 iresult = target(dval0, dval1);
1283 set_register(r3, iresult);
1284 break;
1285 }
1286 case ExternalReference::BUILTIN_FP_FP_CALL: {
1287 SimulatorRuntimeFPFPCall target =
1288 reinterpret_cast<SimulatorRuntimeFPFPCall>(external);
1289 dresult = target(dval0, dval1);
1290 SetFpResult(dresult);
1291 break;
1292 }
1293 case ExternalReference::BUILTIN_FP_CALL: {
1294 SimulatorRuntimeFPCall target =
1295 reinterpret_cast<SimulatorRuntimeFPCall>(external);
1296 dresult = target(dval0);
1297 SetFpResult(dresult);
1298 break;
1299 }
1300 case ExternalReference::BUILTIN_FP_INT_CALL: {
1301 SimulatorRuntimeFPIntCall target =
1302 reinterpret_cast<SimulatorRuntimeFPIntCall>(external);
1303 dresult = target(dval0, ival);
1304 SetFpResult(dresult);
1305 break;
1306 }
1307 default:
1308 UNREACHABLE();
1309 break;
1310 }
1311 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
1312 switch (redirection->type()) {
1313 case ExternalReference::BUILTIN_COMPARE_CALL:
1314 PrintF("Returned %08x\n", iresult);
1315 break;
1316 case ExternalReference::BUILTIN_FP_FP_CALL:
1317 case ExternalReference::BUILTIN_FP_CALL:
1318 case ExternalReference::BUILTIN_FP_INT_CALL:
1319 PrintF("Returned %f\n", dresult);
1320 break;
1321 default:
1322 UNREACHABLE();
1323 break;
1324 }
1325 }
1326 } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) {
1327 // See callers of MacroAssembler::CallApiFunctionAndReturn for
1328 // explanation of register usage.
1329 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
1330 PrintF("Call to host function at %p args %08" V8PRIxPTR,
1331 reinterpret_cast<void*>(external), arg[0]);
1332 if (!stack_aligned) {
1333 PrintF(" with unaligned stack %08" V8PRIxPTR "\n",
1334 get_register(sp));
1335 }
1336 PrintF("\n");
1337 }
1338 CHECK(stack_aligned);
1339 SimulatorRuntimeDirectApiCall target =
1340 reinterpret_cast<SimulatorRuntimeDirectApiCall>(external);
1341 target(arg[0]);
1342 } else if (redirection->type() == ExternalReference::PROFILING_API_CALL) {
1343 // See callers of MacroAssembler::CallApiFunctionAndReturn for
1344 // explanation of register usage.
1345 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
1346 PrintF("Call to host function at %p args %08" V8PRIxPTR
1347 " %08" V8PRIxPTR,
1348 reinterpret_cast<void*>(external), arg[0], arg[1]);
1349 if (!stack_aligned) {
1350 PrintF(" with unaligned stack %08" V8PRIxPTR "\n",
1351 get_register(sp));
1352 }
1353 PrintF("\n");
1354 }
1355 CHECK(stack_aligned);
1356 SimulatorRuntimeProfilingApiCall target =
1357 reinterpret_cast<SimulatorRuntimeProfilingApiCall>(external);
1358 target(arg[0], Redirection::ReverseRedirection(arg[1]));
1359 } else if (redirection->type() == ExternalReference::DIRECT_GETTER_CALL) {
1360 // See callers of MacroAssembler::CallApiFunctionAndReturn for
1361 // explanation of register usage.
1362 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
1363 PrintF("Call to host function at %p args %08" V8PRIxPTR
1364 " %08" V8PRIxPTR,
1365 reinterpret_cast<void*>(external), arg[0], arg[1]);
1366 if (!stack_aligned) {
1367 PrintF(" with unaligned stack %08" V8PRIxPTR "\n",
1368 get_register(sp));
1369 }
1370 PrintF("\n");
1371 }
1372 CHECK(stack_aligned);
1373 SimulatorRuntimeDirectGetterCall target =
1374 reinterpret_cast<SimulatorRuntimeDirectGetterCall>(external);
1375 if (!ABI_PASSES_HANDLES_IN_REGS) {
1376 arg[0] = *(reinterpret_cast<intptr_t*>(arg[0]));
1377 }
1378 target(arg[0], arg[1]);
1379 } else if (redirection->type() ==
1380 ExternalReference::PROFILING_GETTER_CALL) {
1381 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
1382 PrintF("Call to host function at %p args %08" V8PRIxPTR
1383 " %08" V8PRIxPTR " %08" V8PRIxPTR,
1384 reinterpret_cast<void*>(external), arg[0], arg[1], arg[2]);
1385 if (!stack_aligned) {
1386 PrintF(" with unaligned stack %08" V8PRIxPTR "\n",
1387 get_register(sp));
1388 }
1389 PrintF("\n");
1390 }
1391 CHECK(stack_aligned);
1392 SimulatorRuntimeProfilingGetterCall target =
1393 reinterpret_cast<SimulatorRuntimeProfilingGetterCall>(external);
1394 if (!ABI_PASSES_HANDLES_IN_REGS) {
1395 arg[0] = *(reinterpret_cast<intptr_t*>(arg[0]));
1396 }
1397 target(arg[0], arg[1], Redirection::ReverseRedirection(arg[2]));
1398 } else {
1399 // builtin call.
1400 if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
1401 SimulatorRuntimeCall target =
1402 reinterpret_cast<SimulatorRuntimeCall>(external);
1403 PrintF(
1404 "Call to host function at %p,\n"
1405 "\t\t\t\targs %08" V8PRIxPTR ", %08" V8PRIxPTR ", %08" V8PRIxPTR
1406 ", %08" V8PRIxPTR ", %08" V8PRIxPTR ", %08" V8PRIxPTR
1407 ", %08" V8PRIxPTR ", %08" V8PRIxPTR ", %08" V8PRIxPTR,
1408 reinterpret_cast<void*>(FUNCTION_ADDR(target)), arg[0], arg[1],
1409 arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8]);
1410 if (!stack_aligned) {
1411 PrintF(" with unaligned stack %08" V8PRIxPTR "\n",
1412 get_register(sp));
1413 }
1414 PrintF("\n");
1415 }
1416 CHECK(stack_aligned);
1417 if (redirection->type() == ExternalReference::BUILTIN_CALL_PAIR) {
1418 SimulatorRuntimePairCall target =
1419 reinterpret_cast<SimulatorRuntimePairCall>(external);
1420 ObjectPair result =
1421 target(arg[0], arg[1], arg[2], arg[3], arg[4], arg[5]);
1422 intptr_t x;
1423 intptr_t y;
1424 decodeObjectPair(&result, &x, &y);
1425 if (::v8::internal::FLAG_trace_sim) {
1426 PrintF("Returned {%08" V8PRIxPTR ", %08" V8PRIxPTR "}\n", x, y);
1427 }
1428 if (ABI_RETURNS_OBJECT_PAIRS_IN_REGS) {
1429 set_register(r3, x);
1430 set_register(r4, y);
1431 } else {
1432 memcpy(reinterpret_cast<void*>(result_buffer), &result,
1433 sizeof(ObjectPair));
1434 set_register(r3, result_buffer);
1435 }
1436 } else {
1437 DCHECK(redirection->type() == ExternalReference::BUILTIN_CALL);
1438 SimulatorRuntimeCall target =
1439 reinterpret_cast<SimulatorRuntimeCall>(external);
1440 intptr_t result = target(arg[0], arg[1], arg[2], arg[3], arg[4],
1441 arg[5], arg[6], arg[7], arg[8]);
1442 if (::v8::internal::FLAG_trace_sim) {
1443 PrintF("Returned %08" V8PRIxPTR "\n", result);
1444 }
1445 set_register(r3, result);
1446 }
1447 }
1448 set_pc(saved_lr);
1449 break;
1450 }
1451 case kBreakpoint: {
1452 PPCDebugger dbg(this);
1453 dbg.Debug();
1454 break;
1455 }
1456 // stop uses all codes greater than 1 << 23.
1457 default: {
1458 if (svc >= (1 << 23)) {
1459 uint32_t code = svc & kStopCodeMask;
1460 if (isWatchedStop(code)) {
1461 IncreaseStopCounter(code);
1462 }
1463 // Stop if it is enabled, otherwise go on jumping over the stop
1464 // and the message address.
1465 if (isEnabledStop(code)) {
1466 PPCDebugger dbg(this);
1467 dbg.Stop(instr);
1468 } else {
1469 set_pc(get_pc() + kInstrSize + kPointerSize);
1470 }
1471 } else {
1472 // This is not a valid svc code.
1473 UNREACHABLE();
1474 break;
1475 }
1476 }
1477 }
1478 }
1479
1480
1481 // Stop helper functions.
isStopInstruction(Instruction * instr)1482 bool Simulator::isStopInstruction(Instruction* instr) {
1483 return (instr->Bits(27, 24) == 0xF) && (instr->SvcValue() >= kStopCode);
1484 }
1485
1486
isWatchedStop(uint32_t code)1487 bool Simulator::isWatchedStop(uint32_t code) {
1488 DCHECK_LE(code, kMaxStopCode);
1489 return code < kNumOfWatchedStops;
1490 }
1491
1492
isEnabledStop(uint32_t code)1493 bool Simulator::isEnabledStop(uint32_t code) {
1494 DCHECK_LE(code, kMaxStopCode);
1495 // Unwatched stops are always enabled.
1496 return !isWatchedStop(code) ||
1497 !(watched_stops_[code].count & kStopDisabledBit);
1498 }
1499
1500
EnableStop(uint32_t code)1501 void Simulator::EnableStop(uint32_t code) {
1502 DCHECK(isWatchedStop(code));
1503 if (!isEnabledStop(code)) {
1504 watched_stops_[code].count &= ~kStopDisabledBit;
1505 }
1506 }
1507
1508
DisableStop(uint32_t code)1509 void Simulator::DisableStop(uint32_t code) {
1510 DCHECK(isWatchedStop(code));
1511 if (isEnabledStop(code)) {
1512 watched_stops_[code].count |= kStopDisabledBit;
1513 }
1514 }
1515
1516
IncreaseStopCounter(uint32_t code)1517 void Simulator::IncreaseStopCounter(uint32_t code) {
1518 DCHECK_LE(code, kMaxStopCode);
1519 DCHECK(isWatchedStop(code));
1520 if ((watched_stops_[code].count & ~(1 << 31)) == 0x7FFFFFFF) {
1521 PrintF(
1522 "Stop counter for code %i has overflowed.\n"
1523 "Enabling this code and reseting the counter to 0.\n",
1524 code);
1525 watched_stops_[code].count = 0;
1526 EnableStop(code);
1527 } else {
1528 watched_stops_[code].count++;
1529 }
1530 }
1531
1532
1533 // Print a stop status.
PrintStopInfo(uint32_t code)1534 void Simulator::PrintStopInfo(uint32_t code) {
1535 DCHECK_LE(code, kMaxStopCode);
1536 if (!isWatchedStop(code)) {
1537 PrintF("Stop not watched.");
1538 } else {
1539 const char* state = isEnabledStop(code) ? "Enabled" : "Disabled";
1540 int32_t count = watched_stops_[code].count & ~kStopDisabledBit;
1541 // Don't print the state of unused breakpoints.
1542 if (count != 0) {
1543 if (watched_stops_[code].desc) {
1544 PrintF("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n", code, code,
1545 state, count, watched_stops_[code].desc);
1546 } else {
1547 PrintF("stop %i - 0x%x: \t%s, \tcounter = %i\n", code, code, state,
1548 count);
1549 }
1550 }
1551 }
1552 }
1553
1554
SetCR0(intptr_t result,bool setSO)1555 void Simulator::SetCR0(intptr_t result, bool setSO) {
1556 int bf = 0;
1557 if (result < 0) {
1558 bf |= 0x80000000;
1559 }
1560 if (result > 0) {
1561 bf |= 0x40000000;
1562 }
1563 if (result == 0) {
1564 bf |= 0x20000000;
1565 }
1566 if (setSO) {
1567 bf |= 0x10000000;
1568 }
1569 condition_reg_ = (condition_reg_ & ~0xF0000000) | bf;
1570 }
1571
1572
ExecuteBranchConditional(Instruction * instr,BCType type)1573 void Simulator::ExecuteBranchConditional(Instruction* instr, BCType type) {
1574 int bo = instr->Bits(25, 21) << 21;
1575 int condition_bit = instr->Bits(20, 16);
1576 int condition_mask = 0x80000000 >> condition_bit;
1577 switch (bo) {
1578 case DCBNZF: // Decrement CTR; branch if CTR != 0 and condition false
1579 case DCBEZF: // Decrement CTR; branch if CTR == 0 and condition false
1580 UNIMPLEMENTED();
1581 case BF: { // Branch if condition false
1582 if (condition_reg_ & condition_mask) return;
1583 break;
1584 }
1585 case DCBNZT: // Decrement CTR; branch if CTR != 0 and condition true
1586 case DCBEZT: // Decrement CTR; branch if CTR == 0 and condition true
1587 UNIMPLEMENTED();
1588 case BT: { // Branch if condition true
1589 if (!(condition_reg_ & condition_mask)) return;
1590 break;
1591 }
1592 case DCBNZ: // Decrement CTR; branch if CTR != 0
1593 case DCBEZ: // Decrement CTR; branch if CTR == 0
1594 special_reg_ctr_ -= 1;
1595 if ((special_reg_ctr_ == 0) != (bo == DCBEZ)) return;
1596 break;
1597 case BA: { // Branch always
1598 break;
1599 }
1600 default:
1601 UNIMPLEMENTED(); // Invalid encoding
1602 }
1603
1604 intptr_t old_pc = get_pc();
1605
1606 switch (type) {
1607 case BC_OFFSET: {
1608 int offset = (instr->Bits(15, 2) << 18) >> 16;
1609 set_pc(old_pc + offset);
1610 break;
1611 }
1612 case BC_LINK_REG:
1613 set_pc(special_reg_lr_);
1614 break;
1615 case BC_CTR_REG:
1616 set_pc(special_reg_ctr_);
1617 break;
1618 }
1619
1620 if (instr->Bit(0) == 1) { // LK flag set
1621 special_reg_lr_ = old_pc + 4;
1622 }
1623 }
1624
ExecuteGeneric(Instruction * instr)1625 void Simulator::ExecuteGeneric(Instruction* instr) {
1626 uint32_t opcode = instr->OpcodeBase();
1627 switch (opcode) {
1628 case SUBFIC: {
1629 int rt = instr->RTValue();
1630 int ra = instr->RAValue();
1631 intptr_t ra_val = get_register(ra);
1632 int32_t im_val = instr->Bits(15, 0);
1633 im_val = SIGN_EXT_IMM16(im_val);
1634 intptr_t alu_out = im_val - ra_val;
1635 set_register(rt, alu_out);
1636 // todo - handle RC bit
1637 break;
1638 }
1639 case CMPLI: {
1640 int ra = instr->RAValue();
1641 uint32_t im_val = instr->Bits(15, 0);
1642 int cr = instr->Bits(25, 23);
1643 uint32_t bf = 0;
1644 #if V8_TARGET_ARCH_PPC64
1645 int L = instr->Bit(21);
1646 if (L) {
1647 #endif
1648 uintptr_t ra_val = get_register(ra);
1649 if (ra_val < im_val) {
1650 bf |= 0x80000000;
1651 }
1652 if (ra_val > im_val) {
1653 bf |= 0x40000000;
1654 }
1655 if (ra_val == im_val) {
1656 bf |= 0x20000000;
1657 }
1658 #if V8_TARGET_ARCH_PPC64
1659 } else {
1660 uint32_t ra_val = get_register(ra);
1661 if (ra_val < im_val) {
1662 bf |= 0x80000000;
1663 }
1664 if (ra_val > im_val) {
1665 bf |= 0x40000000;
1666 }
1667 if (ra_val == im_val) {
1668 bf |= 0x20000000;
1669 }
1670 }
1671 #endif
1672 uint32_t condition_mask = 0xF0000000U >> (cr * 4);
1673 uint32_t condition = bf >> (cr * 4);
1674 condition_reg_ = (condition_reg_ & ~condition_mask) | condition;
1675 break;
1676 }
1677 case CMPI: {
1678 int ra = instr->RAValue();
1679 int32_t im_val = instr->Bits(15, 0);
1680 im_val = SIGN_EXT_IMM16(im_val);
1681 int cr = instr->Bits(25, 23);
1682 uint32_t bf = 0;
1683 #if V8_TARGET_ARCH_PPC64
1684 int L = instr->Bit(21);
1685 if (L) {
1686 #endif
1687 intptr_t ra_val = get_register(ra);
1688 if (ra_val < im_val) {
1689 bf |= 0x80000000;
1690 }
1691 if (ra_val > im_val) {
1692 bf |= 0x40000000;
1693 }
1694 if (ra_val == im_val) {
1695 bf |= 0x20000000;
1696 }
1697 #if V8_TARGET_ARCH_PPC64
1698 } else {
1699 int32_t ra_val = get_register(ra);
1700 if (ra_val < im_val) {
1701 bf |= 0x80000000;
1702 }
1703 if (ra_val > im_val) {
1704 bf |= 0x40000000;
1705 }
1706 if (ra_val == im_val) {
1707 bf |= 0x20000000;
1708 }
1709 }
1710 #endif
1711 uint32_t condition_mask = 0xF0000000U >> (cr * 4);
1712 uint32_t condition = bf >> (cr * 4);
1713 condition_reg_ = (condition_reg_ & ~condition_mask) | condition;
1714 break;
1715 }
1716 case ADDIC: {
1717 int rt = instr->RTValue();
1718 int ra = instr->RAValue();
1719 uintptr_t ra_val = get_register(ra);
1720 uintptr_t im_val = SIGN_EXT_IMM16(instr->Bits(15, 0));
1721 uintptr_t alu_out = ra_val + im_val;
1722 // Check overflow
1723 if (~ra_val < im_val) {
1724 special_reg_xer_ = (special_reg_xer_ & ~0xF0000000) | 0x20000000;
1725 } else {
1726 special_reg_xer_ &= ~0xF0000000;
1727 }
1728 set_register(rt, alu_out);
1729 break;
1730 }
1731 case ADDI: {
1732 int rt = instr->RTValue();
1733 int ra = instr->RAValue();
1734 int32_t im_val = SIGN_EXT_IMM16(instr->Bits(15, 0));
1735 intptr_t alu_out;
1736 if (ra == 0) {
1737 alu_out = im_val;
1738 } else {
1739 intptr_t ra_val = get_register(ra);
1740 alu_out = ra_val + im_val;
1741 }
1742 set_register(rt, alu_out);
1743 // todo - handle RC bit
1744 break;
1745 }
1746 case ADDIS: {
1747 int rt = instr->RTValue();
1748 int ra = instr->RAValue();
1749 int32_t im_val = (instr->Bits(15, 0) << 16);
1750 intptr_t alu_out;
1751 if (ra == 0) { // treat r0 as zero
1752 alu_out = im_val;
1753 } else {
1754 intptr_t ra_val = get_register(ra);
1755 alu_out = ra_val + im_val;
1756 }
1757 set_register(rt, alu_out);
1758 break;
1759 }
1760 case BCX: {
1761 ExecuteBranchConditional(instr, BC_OFFSET);
1762 break;
1763 }
1764 case BX: {
1765 int offset = (instr->Bits(25, 2) << 8) >> 6;
1766 if (instr->Bit(0) == 1) { // LK flag set
1767 special_reg_lr_ = get_pc() + 4;
1768 }
1769 set_pc(get_pc() + offset);
1770 // todo - AA flag
1771 break;
1772 }
1773 case MCRF:
1774 UNIMPLEMENTED(); // Not used by V8.
1775 case BCLRX:
1776 ExecuteBranchConditional(instr, BC_LINK_REG);
1777 break;
1778 case BCCTRX:
1779 ExecuteBranchConditional(instr, BC_CTR_REG);
1780 break;
1781 case CRNOR:
1782 case RFI:
1783 case CRANDC:
1784 UNIMPLEMENTED();
1785 case ISYNC: {
1786 // todo - simulate isync
1787 break;
1788 }
1789 case CRXOR: {
1790 int bt = instr->Bits(25, 21);
1791 int ba = instr->Bits(20, 16);
1792 int bb = instr->Bits(15, 11);
1793 int ba_val = ((0x80000000 >> ba) & condition_reg_) == 0 ? 0 : 1;
1794 int bb_val = ((0x80000000 >> bb) & condition_reg_) == 0 ? 0 : 1;
1795 int bt_val = ba_val ^ bb_val;
1796 bt_val = bt_val << (31 - bt); // shift bit to correct destination
1797 condition_reg_ &= ~(0x80000000 >> bt);
1798 condition_reg_ |= bt_val;
1799 break;
1800 }
1801 case CREQV: {
1802 int bt = instr->Bits(25, 21);
1803 int ba = instr->Bits(20, 16);
1804 int bb = instr->Bits(15, 11);
1805 int ba_val = ((0x80000000 >> ba) & condition_reg_) == 0 ? 0 : 1;
1806 int bb_val = ((0x80000000 >> bb) & condition_reg_) == 0 ? 0 : 1;
1807 int bt_val = 1 - (ba_val ^ bb_val);
1808 bt_val = bt_val << (31 - bt); // shift bit to correct destination
1809 condition_reg_ &= ~(0x80000000 >> bt);
1810 condition_reg_ |= bt_val;
1811 break;
1812 }
1813 case CRNAND:
1814 case CRAND:
1815 case CRORC:
1816 case CROR: {
1817 UNIMPLEMENTED(); // Not used by V8.
1818 break;
1819 }
1820 case RLWIMIX: {
1821 int ra = instr->RAValue();
1822 int rs = instr->RSValue();
1823 uint32_t rs_val = get_register(rs);
1824 int32_t ra_val = get_register(ra);
1825 int sh = instr->Bits(15, 11);
1826 int mb = instr->Bits(10, 6);
1827 int me = instr->Bits(5, 1);
1828 uint32_t result = base::bits::RotateLeft32(rs_val, sh);
1829 int mask = 0;
1830 if (mb < me + 1) {
1831 int bit = 0x80000000 >> mb;
1832 for (; mb <= me; mb++) {
1833 mask |= bit;
1834 bit >>= 1;
1835 }
1836 } else if (mb == me + 1) {
1837 mask = 0xFFFFFFFF;
1838 } else { // mb > me+1
1839 int bit = 0x80000000 >> (me + 1); // needs to be tested
1840 mask = 0xFFFFFFFF;
1841 for (; me < mb; me++) {
1842 mask ^= bit;
1843 bit >>= 1;
1844 }
1845 }
1846 result &= mask;
1847 ra_val &= ~mask;
1848 result |= ra_val;
1849 set_register(ra, result);
1850 if (instr->Bit(0)) { // RC bit set
1851 SetCR0(result);
1852 }
1853 break;
1854 }
1855 case RLWINMX:
1856 case RLWNMX: {
1857 int ra = instr->RAValue();
1858 int rs = instr->RSValue();
1859 uint32_t rs_val = get_register(rs);
1860 int sh = 0;
1861 if (opcode == RLWINMX) {
1862 sh = instr->Bits(15, 11);
1863 } else {
1864 int rb = instr->RBValue();
1865 uint32_t rb_val = get_register(rb);
1866 sh = (rb_val & 0x1F);
1867 }
1868 int mb = instr->Bits(10, 6);
1869 int me = instr->Bits(5, 1);
1870 uint32_t result = base::bits::RotateLeft32(rs_val, sh);
1871 int mask = 0;
1872 if (mb < me + 1) {
1873 int bit = 0x80000000 >> mb;
1874 for (; mb <= me; mb++) {
1875 mask |= bit;
1876 bit >>= 1;
1877 }
1878 } else if (mb == me + 1) {
1879 mask = 0xFFFFFFFF;
1880 } else { // mb > me+1
1881 int bit = 0x80000000 >> (me + 1); // needs to be tested
1882 mask = 0xFFFFFFFF;
1883 for (; me < mb; me++) {
1884 mask ^= bit;
1885 bit >>= 1;
1886 }
1887 }
1888 result &= mask;
1889 set_register(ra, result);
1890 if (instr->Bit(0)) { // RC bit set
1891 SetCR0(result);
1892 }
1893 break;
1894 }
1895 case ORI: {
1896 int rs = instr->RSValue();
1897 int ra = instr->RAValue();
1898 intptr_t rs_val = get_register(rs);
1899 uint32_t im_val = instr->Bits(15, 0);
1900 intptr_t alu_out = rs_val | im_val;
1901 set_register(ra, alu_out);
1902 break;
1903 }
1904 case ORIS: {
1905 int rs = instr->RSValue();
1906 int ra = instr->RAValue();
1907 intptr_t rs_val = get_register(rs);
1908 uint32_t im_val = instr->Bits(15, 0);
1909 intptr_t alu_out = rs_val | (im_val << 16);
1910 set_register(ra, alu_out);
1911 break;
1912 }
1913 case XORI: {
1914 int rs = instr->RSValue();
1915 int ra = instr->RAValue();
1916 intptr_t rs_val = get_register(rs);
1917 uint32_t im_val = instr->Bits(15, 0);
1918 intptr_t alu_out = rs_val ^ im_val;
1919 set_register(ra, alu_out);
1920 // todo - set condition based SO bit
1921 break;
1922 }
1923 case XORIS: {
1924 int rs = instr->RSValue();
1925 int ra = instr->RAValue();
1926 intptr_t rs_val = get_register(rs);
1927 uint32_t im_val = instr->Bits(15, 0);
1928 intptr_t alu_out = rs_val ^ (im_val << 16);
1929 set_register(ra, alu_out);
1930 break;
1931 }
1932 case ANDIx: {
1933 int rs = instr->RSValue();
1934 int ra = instr->RAValue();
1935 intptr_t rs_val = get_register(rs);
1936 uint32_t im_val = instr->Bits(15, 0);
1937 intptr_t alu_out = rs_val & im_val;
1938 set_register(ra, alu_out);
1939 SetCR0(alu_out);
1940 break;
1941 }
1942 case ANDISx: {
1943 int rs = instr->RSValue();
1944 int ra = instr->RAValue();
1945 intptr_t rs_val = get_register(rs);
1946 uint32_t im_val = instr->Bits(15, 0);
1947 intptr_t alu_out = rs_val & (im_val << 16);
1948 set_register(ra, alu_out);
1949 SetCR0(alu_out);
1950 break;
1951 }
1952 case SRWX: {
1953 int rs = instr->RSValue();
1954 int ra = instr->RAValue();
1955 int rb = instr->RBValue();
1956 uint32_t rs_val = get_register(rs);
1957 uintptr_t rb_val = get_register(rb) & 0x3F;
1958 intptr_t result = (rb_val > 31) ? 0 : rs_val >> rb_val;
1959 set_register(ra, result);
1960 if (instr->Bit(0)) { // RC bit set
1961 SetCR0(result);
1962 }
1963 break;
1964 }
1965 #if V8_TARGET_ARCH_PPC64
1966 case SRDX: {
1967 int rs = instr->RSValue();
1968 int ra = instr->RAValue();
1969 int rb = instr->RBValue();
1970 uintptr_t rs_val = get_register(rs);
1971 uintptr_t rb_val = get_register(rb) & 0x7F;
1972 intptr_t result = (rb_val > 63) ? 0 : rs_val >> rb_val;
1973 set_register(ra, result);
1974 if (instr->Bit(0)) { // RC bit set
1975 SetCR0(result);
1976 }
1977 break;
1978 }
1979 #endif
1980 case MODUW: {
1981 int rt = instr->RTValue();
1982 int ra = instr->RAValue();
1983 int rb = instr->RBValue();
1984 uint32_t ra_val = get_register(ra);
1985 uint32_t rb_val = get_register(rb);
1986 uint32_t alu_out = (rb_val == 0) ? -1 : ra_val % rb_val;
1987 set_register(rt, alu_out);
1988 break;
1989 }
1990 #if V8_TARGET_ARCH_PPC64
1991 case MODUD: {
1992 int rt = instr->RTValue();
1993 int ra = instr->RAValue();
1994 int rb = instr->RBValue();
1995 uint64_t ra_val = get_register(ra);
1996 uint64_t rb_val = get_register(rb);
1997 uint64_t alu_out = (rb_val == 0) ? -1 : ra_val % rb_val;
1998 set_register(rt, alu_out);
1999 break;
2000 }
2001 #endif
2002 case MODSW: {
2003 int rt = instr->RTValue();
2004 int ra = instr->RAValue();
2005 int rb = instr->RBValue();
2006 int32_t ra_val = get_register(ra);
2007 int32_t rb_val = get_register(rb);
2008 bool overflow = (ra_val == kMinInt && rb_val == -1);
2009 // result is undefined if divisor is zero or if operation
2010 // is 0x80000000 / -1.
2011 int32_t alu_out = (rb_val == 0 || overflow) ? -1 : ra_val % rb_val;
2012 set_register(rt, alu_out);
2013 break;
2014 }
2015 #if V8_TARGET_ARCH_PPC64
2016 case MODSD: {
2017 int rt = instr->RTValue();
2018 int ra = instr->RAValue();
2019 int rb = instr->RBValue();
2020 int64_t ra_val = get_register(ra);
2021 int64_t rb_val = get_register(rb);
2022 int64_t one = 1; // work-around gcc
2023 int64_t kMinLongLong = (one << 63);
2024 // result is undefined if divisor is zero or if operation
2025 // is 0x80000000_00000000 / -1.
2026 int64_t alu_out =
2027 (rb_val == 0 || (ra_val == kMinLongLong && rb_val == -1))
2028 ? -1
2029 : ra_val % rb_val;
2030 set_register(rt, alu_out);
2031 break;
2032 }
2033 #endif
2034 case SRAW: {
2035 int rs = instr->RSValue();
2036 int ra = instr->RAValue();
2037 int rb = instr->RBValue();
2038 int32_t rs_val = get_register(rs);
2039 intptr_t rb_val = get_register(rb) & 0x3F;
2040 intptr_t result = (rb_val > 31) ? rs_val >> 31 : rs_val >> rb_val;
2041 set_register(ra, result);
2042 if (instr->Bit(0)) { // RC bit set
2043 SetCR0(result);
2044 }
2045 break;
2046 }
2047 #if V8_TARGET_ARCH_PPC64
2048 case SRAD: {
2049 int rs = instr->RSValue();
2050 int ra = instr->RAValue();
2051 int rb = instr->RBValue();
2052 intptr_t rs_val = get_register(rs);
2053 intptr_t rb_val = get_register(rb) & 0x7F;
2054 intptr_t result = (rb_val > 63) ? rs_val >> 63 : rs_val >> rb_val;
2055 set_register(ra, result);
2056 if (instr->Bit(0)) { // RC bit set
2057 SetCR0(result);
2058 }
2059 break;
2060 }
2061 #endif
2062 case SRAWIX: {
2063 int ra = instr->RAValue();
2064 int rs = instr->RSValue();
2065 int sh = instr->Bits(15, 11);
2066 int32_t rs_val = get_register(rs);
2067 intptr_t result = rs_val >> sh;
2068 set_register(ra, result);
2069 if (instr->Bit(0)) { // RC bit set
2070 SetCR0(result);
2071 }
2072 break;
2073 }
2074 #if V8_TARGET_ARCH_PPC64
2075 case EXTSW: {
2076 const int shift = kBitsPerPointer - 32;
2077 int ra = instr->RAValue();
2078 int rs = instr->RSValue();
2079 intptr_t rs_val = get_register(rs);
2080 intptr_t ra_val = (rs_val << shift) >> shift;
2081 set_register(ra, ra_val);
2082 if (instr->Bit(0)) { // RC bit set
2083 SetCR0(ra_val);
2084 }
2085 break;
2086 }
2087 #endif
2088 case EXTSH: {
2089 const int shift = kBitsPerPointer - 16;
2090 int ra = instr->RAValue();
2091 int rs = instr->RSValue();
2092 intptr_t rs_val = get_register(rs);
2093 intptr_t ra_val = (rs_val << shift) >> shift;
2094 set_register(ra, ra_val);
2095 if (instr->Bit(0)) { // RC bit set
2096 SetCR0(ra_val);
2097 }
2098 break;
2099 }
2100 case EXTSB: {
2101 const int shift = kBitsPerPointer - 8;
2102 int ra = instr->RAValue();
2103 int rs = instr->RSValue();
2104 intptr_t rs_val = get_register(rs);
2105 intptr_t ra_val = (rs_val << shift) >> shift;
2106 set_register(ra, ra_val);
2107 if (instr->Bit(0)) { // RC bit set
2108 SetCR0(ra_val);
2109 }
2110 break;
2111 }
2112 case LFSUX:
2113 case LFSX: {
2114 int frt = instr->RTValue();
2115 int ra = instr->RAValue();
2116 int rb = instr->RBValue();
2117 intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
2118 intptr_t rb_val = get_register(rb);
2119 int32_t val = ReadW(ra_val + rb_val, instr);
2120 float* fptr = reinterpret_cast<float*>(&val);
2121 #if V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64
2122 // Conversion using double changes sNan to qNan on ia32/x64
2123 if ((val & 0x7F800000) == 0x7F800000) {
2124 int64_t dval = static_cast<int64_t>(val);
2125 dval = ((dval & 0xC0000000) << 32) | ((dval & 0x40000000) << 31) |
2126 ((dval & 0x40000000) << 30) | ((dval & 0x7FFFFFFF) << 29) | 0x0;
2127 set_d_register(frt, dval);
2128 } else {
2129 set_d_register_from_double(frt, static_cast<double>(*fptr));
2130 }
2131 #else
2132 set_d_register_from_double(frt, static_cast<double>(*fptr));
2133 #endif
2134 if (opcode == LFSUX) {
2135 DCHECK_NE(ra, 0);
2136 set_register(ra, ra_val + rb_val);
2137 }
2138 break;
2139 }
2140 case LFDUX:
2141 case LFDX: {
2142 int frt = instr->RTValue();
2143 int ra = instr->RAValue();
2144 int rb = instr->RBValue();
2145 intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
2146 intptr_t rb_val = get_register(rb);
2147 int64_t* dptr = reinterpret_cast<int64_t*>(ReadDW(ra_val + rb_val));
2148 set_d_register(frt, *dptr);
2149 if (opcode == LFDUX) {
2150 DCHECK_NE(ra, 0);
2151 set_register(ra, ra_val + rb_val);
2152 }
2153 break;
2154 }
2155 case STFSUX: V8_FALLTHROUGH;
2156 case STFSX: {
2157 int frs = instr->RSValue();
2158 int ra = instr->RAValue();
2159 int rb = instr->RBValue();
2160 intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
2161 intptr_t rb_val = get_register(rb);
2162 float frs_val = static_cast<float>(get_double_from_d_register(frs));
2163 int32_t* p = reinterpret_cast<int32_t*>(&frs_val);
2164 #if V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64
2165 // Conversion using double changes sNan to qNan on ia32/x64
2166 int32_t sval = 0;
2167 int64_t dval = get_d_register(frs);
2168 if ((dval & 0x7FF0000000000000) == 0x7FF0000000000000) {
2169 sval = ((dval & 0xC000000000000000) >> 32) |
2170 ((dval & 0x07FFFFFFE0000000) >> 29);
2171 p = &sval;
2172 } else {
2173 p = reinterpret_cast<int32_t*>(&frs_val);
2174 }
2175 #else
2176 p = reinterpret_cast<int32_t*>(&frs_val);
2177 #endif
2178 WriteW(ra_val + rb_val, *p, instr);
2179 if (opcode == STFSUX) {
2180 DCHECK_NE(ra, 0);
2181 set_register(ra, ra_val + rb_val);
2182 }
2183 break;
2184 }
2185 case STFDUX: V8_FALLTHROUGH;
2186 case STFDX: {
2187 int frs = instr->RSValue();
2188 int ra = instr->RAValue();
2189 int rb = instr->RBValue();
2190 intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
2191 intptr_t rb_val = get_register(rb);
2192 int64_t frs_val = get_d_register(frs);
2193 WriteDW(ra_val + rb_val, frs_val);
2194 if (opcode == STFDUX) {
2195 DCHECK_NE(ra, 0);
2196 set_register(ra, ra_val + rb_val);
2197 }
2198 break;
2199 }
2200 case POPCNTW: {
2201 int rs = instr->RSValue();
2202 int ra = instr->RAValue();
2203 uintptr_t rs_val = get_register(rs);
2204 uintptr_t count = 0;
2205 int n = 0;
2206 uintptr_t bit = 0x80000000;
2207 for (; n < 32; n++) {
2208 if (bit & rs_val) count++;
2209 bit >>= 1;
2210 }
2211 set_register(ra, count);
2212 break;
2213 }
2214 #if V8_TARGET_ARCH_PPC64
2215 case POPCNTD: {
2216 int rs = instr->RSValue();
2217 int ra = instr->RAValue();
2218 uintptr_t rs_val = get_register(rs);
2219 uintptr_t count = 0;
2220 int n = 0;
2221 uintptr_t bit = 0x8000000000000000UL;
2222 for (; n < 64; n++) {
2223 if (bit & rs_val) count++;
2224 bit >>= 1;
2225 }
2226 set_register(ra, count);
2227 break;
2228 }
2229 #endif
2230 case SYNC: {
2231 // todo - simulate sync
2232 break;
2233 }
2234 case ICBI: {
2235 // todo - simulate icbi
2236 break;
2237 }
2238
2239 case LWZU:
2240 case LWZ: {
2241 int ra = instr->RAValue();
2242 int rt = instr->RTValue();
2243 intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
2244 int offset = SIGN_EXT_IMM16(instr->Bits(15, 0));
2245 set_register(rt, ReadWU(ra_val + offset, instr));
2246 if (opcode == LWZU) {
2247 DCHECK_NE(ra, 0);
2248 set_register(ra, ra_val + offset);
2249 }
2250 break;
2251 }
2252
2253 case LBZU:
2254 case LBZ: {
2255 int ra = instr->RAValue();
2256 int rt = instr->RTValue();
2257 intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
2258 int offset = SIGN_EXT_IMM16(instr->Bits(15, 0));
2259 set_register(rt, ReadB(ra_val + offset) & 0xFF);
2260 if (opcode == LBZU) {
2261 DCHECK_NE(ra, 0);
2262 set_register(ra, ra_val + offset);
2263 }
2264 break;
2265 }
2266
2267 case STWU:
2268 case STW: {
2269 int ra = instr->RAValue();
2270 int rs = instr->RSValue();
2271 intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
2272 int32_t rs_val = get_register(rs);
2273 int offset = SIGN_EXT_IMM16(instr->Bits(15, 0));
2274 WriteW(ra_val + offset, rs_val, instr);
2275 if (opcode == STWU) {
2276 DCHECK_NE(ra, 0);
2277 set_register(ra, ra_val + offset);
2278 }
2279 break;
2280 }
2281 case SRADIX: {
2282 int ra = instr->RAValue();
2283 int rs = instr->RSValue();
2284 int sh = (instr->Bits(15, 11) | (instr->Bit(1) << 5));
2285 intptr_t rs_val = get_register(rs);
2286 intptr_t result = rs_val >> sh;
2287 set_register(ra, result);
2288 if (instr->Bit(0)) { // RC bit set
2289 SetCR0(result);
2290 }
2291 break;
2292 }
2293 case STBCX: {
2294 int rs = instr->RSValue();
2295 int ra = instr->RAValue();
2296 int rb = instr->RBValue();
2297 intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
2298 int8_t rs_val = get_register(rs);
2299 intptr_t rb_val = get_register(rb);
2300 SetCR0(WriteExB(ra_val + rb_val, rs_val));
2301 break;
2302 }
2303 case STHCX: {
2304 int rs = instr->RSValue();
2305 int ra = instr->RAValue();
2306 int rb = instr->RBValue();
2307 intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
2308 int16_t rs_val = get_register(rs);
2309 intptr_t rb_val = get_register(rb);
2310 SetCR0(WriteExH(ra_val + rb_val, rs_val, instr));
2311 break;
2312 }
2313 case STWCX: {
2314 int rs = instr->RSValue();
2315 int ra = instr->RAValue();
2316 int rb = instr->RBValue();
2317 intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
2318 int32_t rs_val = get_register(rs);
2319 intptr_t rb_val = get_register(rb);
2320 SetCR0(WriteExW(ra_val + rb_val, rs_val, instr));
2321 break;
2322 }
2323 case TW: {
2324 // used for call redirection in simulation mode
2325 SoftwareInterrupt(instr);
2326 break;
2327 }
2328 case CMP: {
2329 int ra = instr->RAValue();
2330 int rb = instr->RBValue();
2331 int cr = instr->Bits(25, 23);
2332 uint32_t bf = 0;
2333 #if V8_TARGET_ARCH_PPC64
2334 int L = instr->Bit(21);
2335 if (L) {
2336 #endif
2337 intptr_t ra_val = get_register(ra);
2338 intptr_t rb_val = get_register(rb);
2339 if (ra_val < rb_val) {
2340 bf |= 0x80000000;
2341 }
2342 if (ra_val > rb_val) {
2343 bf |= 0x40000000;
2344 }
2345 if (ra_val == rb_val) {
2346 bf |= 0x20000000;
2347 }
2348 #if V8_TARGET_ARCH_PPC64
2349 } else {
2350 int32_t ra_val = get_register(ra);
2351 int32_t rb_val = get_register(rb);
2352 if (ra_val < rb_val) {
2353 bf |= 0x80000000;
2354 }
2355 if (ra_val > rb_val) {
2356 bf |= 0x40000000;
2357 }
2358 if (ra_val == rb_val) {
2359 bf |= 0x20000000;
2360 }
2361 }
2362 #endif
2363 uint32_t condition_mask = 0xF0000000U >> (cr * 4);
2364 uint32_t condition = bf >> (cr * 4);
2365 condition_reg_ = (condition_reg_ & ~condition_mask) | condition;
2366 break;
2367 }
2368 case SUBFCX: {
2369 int rt = instr->RTValue();
2370 int ra = instr->RAValue();
2371 int rb = instr->RBValue();
2372 // int oe = instr->Bit(10);
2373 uintptr_t ra_val = get_register(ra);
2374 uintptr_t rb_val = get_register(rb);
2375 uintptr_t alu_out = ~ra_val + rb_val + 1;
2376 // Set carry
2377 if (ra_val <= rb_val) {
2378 special_reg_xer_ = (special_reg_xer_ & ~0xF0000000) | 0x20000000;
2379 } else {
2380 special_reg_xer_ &= ~0xF0000000;
2381 }
2382 set_register(rt, alu_out);
2383 if (instr->Bit(0)) { // RC bit set
2384 SetCR0(alu_out);
2385 }
2386 // todo - handle OE bit
2387 break;
2388 }
2389 case SUBFEX: {
2390 int rt = instr->RTValue();
2391 int ra = instr->RAValue();
2392 int rb = instr->RBValue();
2393 // int oe = instr->Bit(10);
2394 uintptr_t ra_val = get_register(ra);
2395 uintptr_t rb_val = get_register(rb);
2396 uintptr_t alu_out = ~ra_val + rb_val;
2397 if (special_reg_xer_ & 0x20000000) {
2398 alu_out += 1;
2399 }
2400 set_register(rt, alu_out);
2401 if (instr->Bit(0)) { // RC bit set
2402 SetCR0(static_cast<intptr_t>(alu_out));
2403 }
2404 // todo - handle OE bit
2405 break;
2406 }
2407 case ADDCX: {
2408 int rt = instr->RTValue();
2409 int ra = instr->RAValue();
2410 int rb = instr->RBValue();
2411 // int oe = instr->Bit(10);
2412 uintptr_t ra_val = get_register(ra);
2413 uintptr_t rb_val = get_register(rb);
2414 uintptr_t alu_out = ra_val + rb_val;
2415 // Set carry
2416 if (~ra_val < rb_val) {
2417 special_reg_xer_ = (special_reg_xer_ & ~0xF0000000) | 0x20000000;
2418 } else {
2419 special_reg_xer_ &= ~0xF0000000;
2420 }
2421 set_register(rt, alu_out);
2422 if (instr->Bit(0)) { // RC bit set
2423 SetCR0(static_cast<intptr_t>(alu_out));
2424 }
2425 // todo - handle OE bit
2426 break;
2427 }
2428 case ADDEX: {
2429 int rt = instr->RTValue();
2430 int ra = instr->RAValue();
2431 int rb = instr->RBValue();
2432 // int oe = instr->Bit(10);
2433 uintptr_t ra_val = get_register(ra);
2434 uintptr_t rb_val = get_register(rb);
2435 uintptr_t alu_out = ra_val + rb_val;
2436 if (special_reg_xer_ & 0x20000000) {
2437 alu_out += 1;
2438 }
2439 set_register(rt, alu_out);
2440 if (instr->Bit(0)) { // RC bit set
2441 SetCR0(static_cast<intptr_t>(alu_out));
2442 }
2443 // todo - handle OE bit
2444 break;
2445 }
2446 case MULHWX: {
2447 int rt = instr->RTValue();
2448 int ra = instr->RAValue();
2449 int rb = instr->RBValue();
2450 int32_t ra_val = (get_register(ra) & 0xFFFFFFFF);
2451 int32_t rb_val = (get_register(rb) & 0xFFFFFFFF);
2452 int64_t alu_out = (int64_t)ra_val * (int64_t)rb_val;
2453 alu_out >>= 32;
2454 set_register(rt, alu_out);
2455 if (instr->Bit(0)) { // RC bit set
2456 SetCR0(static_cast<intptr_t>(alu_out));
2457 }
2458 break;
2459 }
2460 case MULHWUX: {
2461 int rt = instr->RTValue();
2462 int ra = instr->RAValue();
2463 int rb = instr->RBValue();
2464 uint32_t ra_val = (get_register(ra) & 0xFFFFFFFF);
2465 uint32_t rb_val = (get_register(rb) & 0xFFFFFFFF);
2466 uint64_t alu_out = (uint64_t)ra_val * (uint64_t)rb_val;
2467 alu_out >>= 32;
2468 set_register(rt, alu_out);
2469 if (instr->Bit(0)) { // RC bit set
2470 SetCR0(static_cast<intptr_t>(alu_out));
2471 }
2472 break;
2473 }
2474 case NEGX: {
2475 int rt = instr->RTValue();
2476 int ra = instr->RAValue();
2477 intptr_t ra_val = get_register(ra);
2478 intptr_t alu_out = 1 + ~ra_val;
2479 #if V8_TARGET_ARCH_PPC64
2480 intptr_t one = 1; // work-around gcc
2481 intptr_t kOverflowVal = (one << 63);
2482 #else
2483 intptr_t kOverflowVal = kMinInt;
2484 #endif
2485 set_register(rt, alu_out);
2486 if (instr->Bit(10)) { // OE bit set
2487 if (ra_val == kOverflowVal) {
2488 special_reg_xer_ |= 0xC0000000; // set SO,OV
2489 } else {
2490 special_reg_xer_ &= ~0x40000000; // clear OV
2491 }
2492 }
2493 if (instr->Bit(0)) { // RC bit set
2494 bool setSO = (special_reg_xer_ & 0x80000000);
2495 SetCR0(alu_out, setSO);
2496 }
2497 break;
2498 }
2499 case SLWX: {
2500 int rs = instr->RSValue();
2501 int ra = instr->RAValue();
2502 int rb = instr->RBValue();
2503 uint32_t rs_val = get_register(rs);
2504 uintptr_t rb_val = get_register(rb) & 0x3F;
2505 uint32_t result = (rb_val > 31) ? 0 : rs_val << rb_val;
2506 set_register(ra, result);
2507 if (instr->Bit(0)) { // RC bit set
2508 SetCR0(result);
2509 }
2510 break;
2511 }
2512 #if V8_TARGET_ARCH_PPC64
2513 case SLDX: {
2514 int rs = instr->RSValue();
2515 int ra = instr->RAValue();
2516 int rb = instr->RBValue();
2517 uintptr_t rs_val = get_register(rs);
2518 uintptr_t rb_val = get_register(rb) & 0x7F;
2519 uintptr_t result = (rb_val > 63) ? 0 : rs_val << rb_val;
2520 set_register(ra, result);
2521 if (instr->Bit(0)) { // RC bit set
2522 SetCR0(result);
2523 }
2524 break;
2525 }
2526 case MFVSRD: {
2527 DCHECK(!instr->Bit(0));
2528 int frt = instr->RTValue();
2529 int ra = instr->RAValue();
2530 int64_t frt_val = get_d_register(frt);
2531 set_register(ra, frt_val);
2532 break;
2533 }
2534 case MFVSRWZ: {
2535 DCHECK(!instr->Bit(0));
2536 int frt = instr->RTValue();
2537 int ra = instr->RAValue();
2538 int64_t frt_val = get_d_register(frt);
2539 set_register(ra, static_cast<uint32_t>(frt_val));
2540 break;
2541 }
2542 case MTVSRD: {
2543 DCHECK(!instr->Bit(0));
2544 int frt = instr->RTValue();
2545 int ra = instr->RAValue();
2546 int64_t ra_val = get_register(ra);
2547 set_d_register(frt, ra_val);
2548 break;
2549 }
2550 case MTVSRWA: {
2551 DCHECK(!instr->Bit(0));
2552 int frt = instr->RTValue();
2553 int ra = instr->RAValue();
2554 int64_t ra_val = static_cast<int32_t>(get_register(ra));
2555 set_d_register(frt, ra_val);
2556 break;
2557 }
2558 case MTVSRWZ: {
2559 DCHECK(!instr->Bit(0));
2560 int frt = instr->RTValue();
2561 int ra = instr->RAValue();
2562 uint64_t ra_val = static_cast<uint32_t>(get_register(ra));
2563 set_d_register(frt, ra_val);
2564 break;
2565 }
2566 #endif
2567 case CNTLZWX: {
2568 int rs = instr->RSValue();
2569 int ra = instr->RAValue();
2570 uintptr_t rs_val = get_register(rs);
2571 uintptr_t count = 0;
2572 int n = 0;
2573 uintptr_t bit = 0x80000000;
2574 for (; n < 32; n++) {
2575 if (bit & rs_val) break;
2576 count++;
2577 bit >>= 1;
2578 }
2579 set_register(ra, count);
2580 if (instr->Bit(0)) { // RC Bit set
2581 int bf = 0;
2582 if (count > 0) {
2583 bf |= 0x40000000;
2584 }
2585 if (count == 0) {
2586 bf |= 0x20000000;
2587 }
2588 condition_reg_ = (condition_reg_ & ~0xF0000000) | bf;
2589 }
2590 break;
2591 }
2592 #if V8_TARGET_ARCH_PPC64
2593 case CNTLZDX: {
2594 int rs = instr->RSValue();
2595 int ra = instr->RAValue();
2596 uintptr_t rs_val = get_register(rs);
2597 uintptr_t count = 0;
2598 int n = 0;
2599 uintptr_t bit = 0x8000000000000000UL;
2600 for (; n < 64; n++) {
2601 if (bit & rs_val) break;
2602 count++;
2603 bit >>= 1;
2604 }
2605 set_register(ra, count);
2606 if (instr->Bit(0)) { // RC Bit set
2607 int bf = 0;
2608 if (count > 0) {
2609 bf |= 0x40000000;
2610 }
2611 if (count == 0) {
2612 bf |= 0x20000000;
2613 }
2614 condition_reg_ = (condition_reg_ & ~0xF0000000) | bf;
2615 }
2616 break;
2617 }
2618 #endif
2619 case ANDX: {
2620 int rs = instr->RSValue();
2621 int ra = instr->RAValue();
2622 int rb = instr->RBValue();
2623 intptr_t rs_val = get_register(rs);
2624 intptr_t rb_val = get_register(rb);
2625 intptr_t alu_out = rs_val & rb_val;
2626 set_register(ra, alu_out);
2627 if (instr->Bit(0)) { // RC Bit set
2628 SetCR0(alu_out);
2629 }
2630 break;
2631 }
2632 case ANDCX: {
2633 int rs = instr->RSValue();
2634 int ra = instr->RAValue();
2635 int rb = instr->RBValue();
2636 intptr_t rs_val = get_register(rs);
2637 intptr_t rb_val = get_register(rb);
2638 intptr_t alu_out = rs_val & ~rb_val;
2639 set_register(ra, alu_out);
2640 if (instr->Bit(0)) { // RC Bit set
2641 SetCR0(alu_out);
2642 }
2643 break;
2644 }
2645 case CMPL: {
2646 int ra = instr->RAValue();
2647 int rb = instr->RBValue();
2648 int cr = instr->Bits(25, 23);
2649 uint32_t bf = 0;
2650 #if V8_TARGET_ARCH_PPC64
2651 int L = instr->Bit(21);
2652 if (L) {
2653 #endif
2654 uintptr_t ra_val = get_register(ra);
2655 uintptr_t rb_val = get_register(rb);
2656 if (ra_val < rb_val) {
2657 bf |= 0x80000000;
2658 }
2659 if (ra_val > rb_val) {
2660 bf |= 0x40000000;
2661 }
2662 if (ra_val == rb_val) {
2663 bf |= 0x20000000;
2664 }
2665 #if V8_TARGET_ARCH_PPC64
2666 } else {
2667 uint32_t ra_val = get_register(ra);
2668 uint32_t rb_val = get_register(rb);
2669 if (ra_val < rb_val) {
2670 bf |= 0x80000000;
2671 }
2672 if (ra_val > rb_val) {
2673 bf |= 0x40000000;
2674 }
2675 if (ra_val == rb_val) {
2676 bf |= 0x20000000;
2677 }
2678 }
2679 #endif
2680 uint32_t condition_mask = 0xF0000000U >> (cr * 4);
2681 uint32_t condition = bf >> (cr * 4);
2682 condition_reg_ = (condition_reg_ & ~condition_mask) | condition;
2683 break;
2684 }
2685 case SUBFX: {
2686 int rt = instr->RTValue();
2687 int ra = instr->RAValue();
2688 int rb = instr->RBValue();
2689 // int oe = instr->Bit(10);
2690 intptr_t ra_val = get_register(ra);
2691 intptr_t rb_val = get_register(rb);
2692 intptr_t alu_out = rb_val - ra_val;
2693 // todo - figure out underflow
2694 set_register(rt, alu_out);
2695 if (instr->Bit(0)) { // RC Bit set
2696 SetCR0(alu_out);
2697 }
2698 // todo - handle OE bit
2699 break;
2700 }
2701 case ADDZEX: {
2702 int rt = instr->RTValue();
2703 int ra = instr->RAValue();
2704 intptr_t ra_val = get_register(ra);
2705 if (special_reg_xer_ & 0x20000000) {
2706 ra_val += 1;
2707 }
2708 set_register(rt, ra_val);
2709 if (instr->Bit(0)) { // RC bit set
2710 SetCR0(ra_val);
2711 }
2712 // todo - handle OE bit
2713 break;
2714 }
2715 case NORX: {
2716 int rs = instr->RSValue();
2717 int ra = instr->RAValue();
2718 int rb = instr->RBValue();
2719 intptr_t rs_val = get_register(rs);
2720 intptr_t rb_val = get_register(rb);
2721 intptr_t alu_out = ~(rs_val | rb_val);
2722 set_register(ra, alu_out);
2723 if (instr->Bit(0)) { // RC bit set
2724 SetCR0(alu_out);
2725 }
2726 break;
2727 }
2728 case MULLW: {
2729 int rt = instr->RTValue();
2730 int ra = instr->RAValue();
2731 int rb = instr->RBValue();
2732 int32_t ra_val = (get_register(ra) & 0xFFFFFFFF);
2733 int32_t rb_val = (get_register(rb) & 0xFFFFFFFF);
2734 int32_t alu_out = ra_val * rb_val;
2735 set_register(rt, alu_out);
2736 if (instr->Bit(0)) { // RC bit set
2737 SetCR0(alu_out);
2738 }
2739 // todo - handle OE bit
2740 break;
2741 }
2742 #if V8_TARGET_ARCH_PPC64
2743 case MULLD: {
2744 int rt = instr->RTValue();
2745 int ra = instr->RAValue();
2746 int rb = instr->RBValue();
2747 int64_t ra_val = get_register(ra);
2748 int64_t rb_val = get_register(rb);
2749 int64_t alu_out = ra_val * rb_val;
2750 set_register(rt, alu_out);
2751 if (instr->Bit(0)) { // RC bit set
2752 SetCR0(alu_out);
2753 }
2754 // todo - handle OE bit
2755 break;
2756 }
2757 #endif
2758 case DIVW: {
2759 int rt = instr->RTValue();
2760 int ra = instr->RAValue();
2761 int rb = instr->RBValue();
2762 int32_t ra_val = get_register(ra);
2763 int32_t rb_val = get_register(rb);
2764 bool overflow = (ra_val == kMinInt && rb_val == -1);
2765 // result is undefined if divisor is zero or if operation
2766 // is 0x80000000 / -1.
2767 int32_t alu_out = (rb_val == 0 || overflow) ? -1 : ra_val / rb_val;
2768 set_register(rt, alu_out);
2769 if (instr->Bit(10)) { // OE bit set
2770 if (overflow) {
2771 special_reg_xer_ |= 0xC0000000; // set SO,OV
2772 } else {
2773 special_reg_xer_ &= ~0x40000000; // clear OV
2774 }
2775 }
2776 if (instr->Bit(0)) { // RC bit set
2777 bool setSO = (special_reg_xer_ & 0x80000000);
2778 SetCR0(alu_out, setSO);
2779 }
2780 break;
2781 }
2782 case DIVWU: {
2783 int rt = instr->RTValue();
2784 int ra = instr->RAValue();
2785 int rb = instr->RBValue();
2786 uint32_t ra_val = get_register(ra);
2787 uint32_t rb_val = get_register(rb);
2788 bool overflow = (rb_val == 0);
2789 // result is undefined if divisor is zero
2790 uint32_t alu_out = (overflow) ? -1 : ra_val / rb_val;
2791 set_register(rt, alu_out);
2792 if (instr->Bit(10)) { // OE bit set
2793 if (overflow) {
2794 special_reg_xer_ |= 0xC0000000; // set SO,OV
2795 } else {
2796 special_reg_xer_ &= ~0x40000000; // clear OV
2797 }
2798 }
2799 if (instr->Bit(0)) { // RC bit set
2800 bool setSO = (special_reg_xer_ & 0x80000000);
2801 SetCR0(alu_out, setSO);
2802 }
2803 break;
2804 }
2805 #if V8_TARGET_ARCH_PPC64
2806 case DIVD: {
2807 int rt = instr->RTValue();
2808 int ra = instr->RAValue();
2809 int rb = instr->RBValue();
2810 int64_t ra_val = get_register(ra);
2811 int64_t rb_val = get_register(rb);
2812 int64_t one = 1; // work-around gcc
2813 int64_t kMinLongLong = (one << 63);
2814 // result is undefined if divisor is zero or if operation
2815 // is 0x80000000_00000000 / -1.
2816 int64_t alu_out =
2817 (rb_val == 0 || (ra_val == kMinLongLong && rb_val == -1))
2818 ? -1
2819 : ra_val / rb_val;
2820 set_register(rt, alu_out);
2821 if (instr->Bit(0)) { // RC bit set
2822 SetCR0(alu_out);
2823 }
2824 // todo - handle OE bit
2825 break;
2826 }
2827 case DIVDU: {
2828 int rt = instr->RTValue();
2829 int ra = instr->RAValue();
2830 int rb = instr->RBValue();
2831 uint64_t ra_val = get_register(ra);
2832 uint64_t rb_val = get_register(rb);
2833 // result is undefined if divisor is zero
2834 uint64_t alu_out = (rb_val == 0) ? -1 : ra_val / rb_val;
2835 set_register(rt, alu_out);
2836 if (instr->Bit(0)) { // RC bit set
2837 SetCR0(alu_out);
2838 }
2839 // todo - handle OE bit
2840 break;
2841 }
2842 #endif
2843 case ADDX: {
2844 int rt = instr->RTValue();
2845 int ra = instr->RAValue();
2846 int rb = instr->RBValue();
2847 // int oe = instr->Bit(10);
2848 intptr_t ra_val = get_register(ra);
2849 intptr_t rb_val = get_register(rb);
2850 intptr_t alu_out = ra_val + rb_val;
2851 set_register(rt, alu_out);
2852 if (instr->Bit(0)) { // RC bit set
2853 SetCR0(alu_out);
2854 }
2855 // todo - handle OE bit
2856 break;
2857 }
2858 case XORX: {
2859 int rs = instr->RSValue();
2860 int ra = instr->RAValue();
2861 int rb = instr->RBValue();
2862 intptr_t rs_val = get_register(rs);
2863 intptr_t rb_val = get_register(rb);
2864 intptr_t alu_out = rs_val ^ rb_val;
2865 set_register(ra, alu_out);
2866 if (instr->Bit(0)) { // RC bit set
2867 SetCR0(alu_out);
2868 }
2869 break;
2870 }
2871 case ORX: {
2872 int rs = instr->RSValue();
2873 int ra = instr->RAValue();
2874 int rb = instr->RBValue();
2875 intptr_t rs_val = get_register(rs);
2876 intptr_t rb_val = get_register(rb);
2877 intptr_t alu_out = rs_val | rb_val;
2878 set_register(ra, alu_out);
2879 if (instr->Bit(0)) { // RC bit set
2880 SetCR0(alu_out);
2881 }
2882 break;
2883 }
2884 case ORC: {
2885 int rs = instr->RSValue();
2886 int ra = instr->RAValue();
2887 int rb = instr->RBValue();
2888 intptr_t rs_val = get_register(rs);
2889 intptr_t rb_val = get_register(rb);
2890 intptr_t alu_out = rs_val | ~rb_val;
2891 set_register(ra, alu_out);
2892 if (instr->Bit(0)) { // RC bit set
2893 SetCR0(alu_out);
2894 }
2895 break;
2896 }
2897 case MFSPR: {
2898 int rt = instr->RTValue();
2899 int spr = instr->Bits(20, 11);
2900 if (spr != 256) {
2901 UNIMPLEMENTED(); // Only LRLR supported
2902 }
2903 set_register(rt, special_reg_lr_);
2904 break;
2905 }
2906 case MTSPR: {
2907 int rt = instr->RTValue();
2908 intptr_t rt_val = get_register(rt);
2909 int spr = instr->Bits(20, 11);
2910 if (spr == 256) {
2911 special_reg_lr_ = rt_val;
2912 } else if (spr == 288) {
2913 special_reg_ctr_ = rt_val;
2914 } else if (spr == 32) {
2915 special_reg_xer_ = rt_val;
2916 } else {
2917 UNIMPLEMENTED(); // Only LR supported
2918 }
2919 break;
2920 }
2921 case MFCR: {
2922 int rt = instr->RTValue();
2923 set_register(rt, condition_reg_);
2924 break;
2925 }
2926 case STWUX:
2927 case STWX: {
2928 int rs = instr->RSValue();
2929 int ra = instr->RAValue();
2930 int rb = instr->RBValue();
2931 intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
2932 int32_t rs_val = get_register(rs);
2933 intptr_t rb_val = get_register(rb);
2934 WriteW(ra_val + rb_val, rs_val, instr);
2935 if (opcode == STWUX) {
2936 DCHECK_NE(ra, 0);
2937 set_register(ra, ra_val + rb_val);
2938 }
2939 break;
2940 }
2941 case STBUX:
2942 case STBX: {
2943 int rs = instr->RSValue();
2944 int ra = instr->RAValue();
2945 int rb = instr->RBValue();
2946 intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
2947 int8_t rs_val = get_register(rs);
2948 intptr_t rb_val = get_register(rb);
2949 WriteB(ra_val + rb_val, rs_val);
2950 if (opcode == STBUX) {
2951 DCHECK_NE(ra, 0);
2952 set_register(ra, ra_val + rb_val);
2953 }
2954 break;
2955 }
2956 case STHUX:
2957 case STHX: {
2958 int rs = instr->RSValue();
2959 int ra = instr->RAValue();
2960 int rb = instr->RBValue();
2961 intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
2962 int16_t rs_val = get_register(rs);
2963 intptr_t rb_val = get_register(rb);
2964 WriteH(ra_val + rb_val, rs_val, instr);
2965 if (opcode == STHUX) {
2966 DCHECK_NE(ra, 0);
2967 set_register(ra, ra_val + rb_val);
2968 }
2969 break;
2970 }
2971 case LWZX:
2972 case LWZUX: {
2973 int rt = instr->RTValue();
2974 int ra = instr->RAValue();
2975 int rb = instr->RBValue();
2976 intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
2977 intptr_t rb_val = get_register(rb);
2978 set_register(rt, ReadWU(ra_val + rb_val, instr));
2979 if (opcode == LWZUX) {
2980 DCHECK(ra != 0 && ra != rt);
2981 set_register(ra, ra_val + rb_val);
2982 }
2983 break;
2984 }
2985 #if V8_TARGET_ARCH_PPC64
2986 case LWAX: {
2987 int rt = instr->RTValue();
2988 int ra = instr->RAValue();
2989 int rb = instr->RBValue();
2990 intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
2991 intptr_t rb_val = get_register(rb);
2992 set_register(rt, ReadW(ra_val + rb_val, instr));
2993 break;
2994 }
2995 case LDX:
2996 case LDUX: {
2997 int rt = instr->RTValue();
2998 int ra = instr->RAValue();
2999 int rb = instr->RBValue();
3000 intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
3001 intptr_t rb_val = get_register(rb);
3002 intptr_t* result = ReadDW(ra_val + rb_val);
3003 set_register(rt, *result);
3004 if (opcode == LDUX) {
3005 DCHECK(ra != 0 && ra != rt);
3006 set_register(ra, ra_val + rb_val);
3007 }
3008 break;
3009 }
3010 case STDX:
3011 case STDUX: {
3012 int rs = instr->RSValue();
3013 int ra = instr->RAValue();
3014 int rb = instr->RBValue();
3015 intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
3016 intptr_t rs_val = get_register(rs);
3017 intptr_t rb_val = get_register(rb);
3018 WriteDW(ra_val + rb_val, rs_val);
3019 if (opcode == STDUX) {
3020 DCHECK_NE(ra, 0);
3021 set_register(ra, ra_val + rb_val);
3022 }
3023 break;
3024 }
3025 #endif
3026 case LBZX:
3027 case LBZUX: {
3028 int rt = instr->RTValue();
3029 int ra = instr->RAValue();
3030 int rb = instr->RBValue();
3031 intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
3032 intptr_t rb_val = get_register(rb);
3033 set_register(rt, ReadBU(ra_val + rb_val) & 0xFF);
3034 if (opcode == LBZUX) {
3035 DCHECK(ra != 0 && ra != rt);
3036 set_register(ra, ra_val + rb_val);
3037 }
3038 break;
3039 }
3040 case LHZX:
3041 case LHZUX: {
3042 int rt = instr->RTValue();
3043 int ra = instr->RAValue();
3044 int rb = instr->RBValue();
3045 intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
3046 intptr_t rb_val = get_register(rb);
3047 set_register(rt, ReadHU(ra_val + rb_val, instr) & 0xFFFF);
3048 if (opcode == LHZUX) {
3049 DCHECK(ra != 0 && ra != rt);
3050 set_register(ra, ra_val + rb_val);
3051 }
3052 break;
3053 }
3054 case LHAX: {
3055 int rt = instr->RTValue();
3056 int ra = instr->RAValue();
3057 int rb = instr->RBValue();
3058 intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
3059 intptr_t rb_val = get_register(rb);
3060 set_register(rt, ReadH(ra_val + rb_val, instr));
3061 break;
3062 }
3063 case LBARX: {
3064 int rt = instr->RTValue();
3065 int ra = instr->RAValue();
3066 int rb = instr->RBValue();
3067 intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
3068 intptr_t rb_val = get_register(rb);
3069 set_register(rt, ReadExBU(ra_val + rb_val) & 0xFF);
3070 break;
3071 }
3072 case LHARX: {
3073 int rt = instr->RTValue();
3074 int ra = instr->RAValue();
3075 int rb = instr->RBValue();
3076 intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
3077 intptr_t rb_val = get_register(rb);
3078 set_register(rt, ReadExHU(ra_val + rb_val, instr));
3079 break;
3080 }
3081 case LWARX: {
3082 int rt = instr->RTValue();
3083 int ra = instr->RAValue();
3084 int rb = instr->RBValue();
3085 intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
3086 intptr_t rb_val = get_register(rb);
3087 set_register(rt, ReadExWU(ra_val + rb_val, instr));
3088 break;
3089 }
3090 case DCBF: {
3091 // todo - simulate dcbf
3092 break;
3093 }
3094 case ISEL: {
3095 int rt = instr->RTValue();
3096 int ra = instr->RAValue();
3097 int rb = instr->RBValue();
3098 int condition_bit = instr->RCValue();
3099 int condition_mask = 0x80000000 >> condition_bit;
3100 intptr_t ra_val = (ra == 0) ? 0 : get_register(ra);
3101 intptr_t rb_val = get_register(rb);
3102 intptr_t value = (condition_reg_ & condition_mask) ? ra_val : rb_val;
3103 set_register(rt, value);
3104 break;
3105 }
3106
3107 case STBU:
3108 case STB: {
3109 int ra = instr->RAValue();
3110 int rs = instr->RSValue();
3111 intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
3112 int8_t rs_val = get_register(rs);
3113 int offset = SIGN_EXT_IMM16(instr->Bits(15, 0));
3114 WriteB(ra_val + offset, rs_val);
3115 if (opcode == STBU) {
3116 DCHECK_NE(ra, 0);
3117 set_register(ra, ra_val + offset);
3118 }
3119 break;
3120 }
3121
3122 case LHZU:
3123 case LHZ: {
3124 int ra = instr->RAValue();
3125 int rt = instr->RTValue();
3126 intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
3127 int offset = SIGN_EXT_IMM16(instr->Bits(15, 0));
3128 uintptr_t result = ReadHU(ra_val + offset, instr) & 0xFFFF;
3129 set_register(rt, result);
3130 if (opcode == LHZU) {
3131 set_register(ra, ra_val + offset);
3132 }
3133 break;
3134 }
3135
3136 case LHA:
3137 case LHAU: {
3138 int ra = instr->RAValue();
3139 int rt = instr->RTValue();
3140 intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
3141 int offset = SIGN_EXT_IMM16(instr->Bits(15, 0));
3142 intptr_t result = ReadH(ra_val + offset, instr);
3143 set_register(rt, result);
3144 if (opcode == LHAU) {
3145 set_register(ra, ra_val + offset);
3146 }
3147 break;
3148 }
3149
3150 case STHU:
3151 case STH: {
3152 int ra = instr->RAValue();
3153 int rs = instr->RSValue();
3154 intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
3155 int16_t rs_val = get_register(rs);
3156 int offset = SIGN_EXT_IMM16(instr->Bits(15, 0));
3157 WriteH(ra_val + offset, rs_val, instr);
3158 if (opcode == STHU) {
3159 DCHECK_NE(ra, 0);
3160 set_register(ra, ra_val + offset);
3161 }
3162 break;
3163 }
3164
3165 case LMW:
3166 case STMW: {
3167 UNIMPLEMENTED();
3168 break;
3169 }
3170
3171 case LFSU:
3172 case LFS: {
3173 int frt = instr->RTValue();
3174 int ra = instr->RAValue();
3175 int32_t offset = SIGN_EXT_IMM16(instr->Bits(15, 0));
3176 intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
3177 int32_t val = ReadW(ra_val + offset, instr);
3178 float* fptr = reinterpret_cast<float*>(&val);
3179 #if V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64
3180 // Conversion using double changes sNan to qNan on ia32/x64
3181 if ((val & 0x7F800000) == 0x7F800000) {
3182 int64_t dval = static_cast<int64_t>(val);
3183 dval = ((dval & 0xC0000000) << 32) | ((dval & 0x40000000) << 31) |
3184 ((dval & 0x40000000) << 30) | ((dval & 0x7FFFFFFF) << 29) | 0x0;
3185 set_d_register(frt, dval);
3186 } else {
3187 set_d_register_from_double(frt, static_cast<double>(*fptr));
3188 }
3189 #else
3190 set_d_register_from_double(frt, static_cast<double>(*fptr));
3191 #endif
3192 if (opcode == LFSU) {
3193 DCHECK_NE(ra, 0);
3194 set_register(ra, ra_val + offset);
3195 }
3196 break;
3197 }
3198
3199 case LFDU:
3200 case LFD: {
3201 int frt = instr->RTValue();
3202 int ra = instr->RAValue();
3203 int32_t offset = SIGN_EXT_IMM16(instr->Bits(15, 0));
3204 intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
3205 int64_t* dptr = reinterpret_cast<int64_t*>(ReadDW(ra_val + offset));
3206 set_d_register(frt, *dptr);
3207 if (opcode == LFDU) {
3208 DCHECK_NE(ra, 0);
3209 set_register(ra, ra_val + offset);
3210 }
3211 break;
3212 }
3213
3214 case STFSU: V8_FALLTHROUGH;
3215 case STFS: {
3216 int frs = instr->RSValue();
3217 int ra = instr->RAValue();
3218 int32_t offset = SIGN_EXT_IMM16(instr->Bits(15, 0));
3219 intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
3220 float frs_val = static_cast<float>(get_double_from_d_register(frs));
3221 int32_t* p;
3222 #if V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64
3223 // Conversion using double changes sNan to qNan on ia32/x64
3224 int32_t sval = 0;
3225 int64_t dval = get_d_register(frs);
3226 if ((dval & 0x7FF0000000000000) == 0x7FF0000000000000) {
3227 sval = ((dval & 0xC000000000000000) >> 32) |
3228 ((dval & 0x07FFFFFFE0000000) >> 29);
3229 p = &sval;
3230 } else {
3231 p = reinterpret_cast<int32_t*>(&frs_val);
3232 }
3233 #else
3234 p = reinterpret_cast<int32_t*>(&frs_val);
3235 #endif
3236 WriteW(ra_val + offset, *p, instr);
3237 if (opcode == STFSU) {
3238 DCHECK_NE(ra, 0);
3239 set_register(ra, ra_val + offset);
3240 }
3241 break;
3242 }
3243 case STFDU:
3244 case STFD: {
3245 int frs = instr->RSValue();
3246 int ra = instr->RAValue();
3247 int32_t offset = SIGN_EXT_IMM16(instr->Bits(15, 0));
3248 intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
3249 int64_t frs_val = get_d_register(frs);
3250 WriteDW(ra_val + offset, frs_val);
3251 if (opcode == STFDU) {
3252 DCHECK_NE(ra, 0);
3253 set_register(ra, ra_val + offset);
3254 }
3255 break;
3256 }
3257
3258 case FCFIDS: {
3259 // fcfids
3260 int frt = instr->RTValue();
3261 int frb = instr->RBValue();
3262 int64_t frb_val = get_d_register(frb);
3263 double frt_val = static_cast<float>(frb_val);
3264 set_d_register_from_double(frt, frt_val);
3265 return;
3266 }
3267 case FCFIDUS: {
3268 // fcfidus
3269 int frt = instr->RTValue();
3270 int frb = instr->RBValue();
3271 uint64_t frb_val = get_d_register(frb);
3272 double frt_val = static_cast<float>(frb_val);
3273 set_d_register_from_double(frt, frt_val);
3274 return;
3275 }
3276
3277 case FDIV: {
3278 int frt = instr->RTValue();
3279 int fra = instr->RAValue();
3280 int frb = instr->RBValue();
3281 double fra_val = get_double_from_d_register(fra);
3282 double frb_val = get_double_from_d_register(frb);
3283 double frt_val = fra_val / frb_val;
3284 set_d_register_from_double(frt, frt_val);
3285 return;
3286 }
3287 case FSUB: {
3288 int frt = instr->RTValue();
3289 int fra = instr->RAValue();
3290 int frb = instr->RBValue();
3291 double fra_val = get_double_from_d_register(fra);
3292 double frb_val = get_double_from_d_register(frb);
3293 double frt_val = fra_val - frb_val;
3294 set_d_register_from_double(frt, frt_val);
3295 return;
3296 }
3297 case FADD: {
3298 int frt = instr->RTValue();
3299 int fra = instr->RAValue();
3300 int frb = instr->RBValue();
3301 double fra_val = get_double_from_d_register(fra);
3302 double frb_val = get_double_from_d_register(frb);
3303 double frt_val = fra_val + frb_val;
3304 set_d_register_from_double(frt, frt_val);
3305 return;
3306 }
3307 case FSQRT: {
3308 lazily_initialize_fast_sqrt(isolate_);
3309 int frt = instr->RTValue();
3310 int frb = instr->RBValue();
3311 double frb_val = get_double_from_d_register(frb);
3312 double frt_val = fast_sqrt(frb_val, isolate_);
3313 set_d_register_from_double(frt, frt_val);
3314 return;
3315 }
3316 case FSEL: {
3317 int frt = instr->RTValue();
3318 int fra = instr->RAValue();
3319 int frb = instr->RBValue();
3320 int frc = instr->RCValue();
3321 double fra_val = get_double_from_d_register(fra);
3322 double frb_val = get_double_from_d_register(frb);
3323 double frc_val = get_double_from_d_register(frc);
3324 double frt_val = ((fra_val >= 0.0) ? frc_val : frb_val);
3325 set_d_register_from_double(frt, frt_val);
3326 return;
3327 }
3328 case FMUL: {
3329 int frt = instr->RTValue();
3330 int fra = instr->RAValue();
3331 int frc = instr->RCValue();
3332 double fra_val = get_double_from_d_register(fra);
3333 double frc_val = get_double_from_d_register(frc);
3334 double frt_val = fra_val * frc_val;
3335 set_d_register_from_double(frt, frt_val);
3336 return;
3337 }
3338 case FMSUB: {
3339 int frt = instr->RTValue();
3340 int fra = instr->RAValue();
3341 int frb = instr->RBValue();
3342 int frc = instr->RCValue();
3343 double fra_val = get_double_from_d_register(fra);
3344 double frb_val = get_double_from_d_register(frb);
3345 double frc_val = get_double_from_d_register(frc);
3346 double frt_val = (fra_val * frc_val) - frb_val;
3347 set_d_register_from_double(frt, frt_val);
3348 return;
3349 }
3350 case FMADD: {
3351 int frt = instr->RTValue();
3352 int fra = instr->RAValue();
3353 int frb = instr->RBValue();
3354 int frc = instr->RCValue();
3355 double fra_val = get_double_from_d_register(fra);
3356 double frb_val = get_double_from_d_register(frb);
3357 double frc_val = get_double_from_d_register(frc);
3358 double frt_val = (fra_val * frc_val) + frb_val;
3359 set_d_register_from_double(frt, frt_val);
3360 return;
3361 }
3362 case FCMPU: {
3363 int fra = instr->RAValue();
3364 int frb = instr->RBValue();
3365 double fra_val = get_double_from_d_register(fra);
3366 double frb_val = get_double_from_d_register(frb);
3367 int cr = instr->Bits(25, 23);
3368 int bf = 0;
3369 if (fra_val < frb_val) {
3370 bf |= 0x80000000;
3371 }
3372 if (fra_val > frb_val) {
3373 bf |= 0x40000000;
3374 }
3375 if (fra_val == frb_val) {
3376 bf |= 0x20000000;
3377 }
3378 if (std::isunordered(fra_val, frb_val)) {
3379 bf |= 0x10000000;
3380 }
3381 int condition_mask = 0xF0000000 >> (cr * 4);
3382 int condition = bf >> (cr * 4);
3383 condition_reg_ = (condition_reg_ & ~condition_mask) | condition;
3384 return;
3385 }
3386 case FRIN: {
3387 int frt = instr->RTValue();
3388 int frb = instr->RBValue();
3389 double frb_val = get_double_from_d_register(frb);
3390 double frt_val = std::round(frb_val);
3391 set_d_register_from_double(frt, frt_val);
3392 if (instr->Bit(0)) { // RC bit set
3393 // UNIMPLEMENTED();
3394 }
3395 return;
3396 }
3397 case FRIZ: {
3398 int frt = instr->RTValue();
3399 int frb = instr->RBValue();
3400 double frb_val = get_double_from_d_register(frb);
3401 double frt_val = std::trunc(frb_val);
3402 set_d_register_from_double(frt, frt_val);
3403 if (instr->Bit(0)) { // RC bit set
3404 // UNIMPLEMENTED();
3405 }
3406 return;
3407 }
3408 case FRIP: {
3409 int frt = instr->RTValue();
3410 int frb = instr->RBValue();
3411 double frb_val = get_double_from_d_register(frb);
3412 double frt_val = std::ceil(frb_val);
3413 set_d_register_from_double(frt, frt_val);
3414 if (instr->Bit(0)) { // RC bit set
3415 // UNIMPLEMENTED();
3416 }
3417 return;
3418 }
3419 case FRIM: {
3420 int frt = instr->RTValue();
3421 int frb = instr->RBValue();
3422 double frb_val = get_double_from_d_register(frb);
3423 double frt_val = std::floor(frb_val);
3424 set_d_register_from_double(frt, frt_val);
3425 if (instr->Bit(0)) { // RC bit set
3426 // UNIMPLEMENTED();
3427 }
3428 return;
3429 }
3430 case FRSP: {
3431 int frt = instr->RTValue();
3432 int frb = instr->RBValue();
3433 // frsp round 8-byte double-precision value to
3434 // single-precision value
3435 double frb_val = get_double_from_d_register(frb);
3436 double frt_val = static_cast<float>(frb_val);
3437 set_d_register_from_double(frt, frt_val);
3438 if (instr->Bit(0)) { // RC bit set
3439 // UNIMPLEMENTED();
3440 }
3441 return;
3442 }
3443 case FCFID: {
3444 int frt = instr->RTValue();
3445 int frb = instr->RBValue();
3446 int64_t frb_val = get_d_register(frb);
3447 double frt_val = static_cast<double>(frb_val);
3448 set_d_register_from_double(frt, frt_val);
3449 return;
3450 }
3451 case FCFIDU: {
3452 int frt = instr->RTValue();
3453 int frb = instr->RBValue();
3454 uint64_t frb_val = get_d_register(frb);
3455 double frt_val = static_cast<double>(frb_val);
3456 set_d_register_from_double(frt, frt_val);
3457 return;
3458 }
3459 case FCTID:
3460 case FCTIDZ: {
3461 int frt = instr->RTValue();
3462 int frb = instr->RBValue();
3463 double frb_val = get_double_from_d_register(frb);
3464 int mode = (opcode == FCTIDZ) ? kRoundToZero
3465 : (fp_condition_reg_ & kFPRoundingModeMask);
3466 int64_t frt_val;
3467 int64_t one = 1; // work-around gcc
3468 int64_t kMinVal = (one << 63);
3469 int64_t kMaxVal = kMinVal - 1;
3470 bool invalid_convert = false;
3471
3472 if (std::isnan(frb_val)) {
3473 frt_val = kMinVal;
3474 invalid_convert = true;
3475 } else {
3476 switch (mode) {
3477 case kRoundToZero:
3478 frb_val = std::trunc(frb_val);
3479 break;
3480 case kRoundToPlusInf:
3481 frb_val = std::ceil(frb_val);
3482 break;
3483 case kRoundToMinusInf:
3484 frb_val = std::floor(frb_val);
3485 break;
3486 default:
3487 UNIMPLEMENTED(); // Not used by V8.
3488 break;
3489 }
3490 if (frb_val < static_cast<double>(kMinVal)) {
3491 frt_val = kMinVal;
3492 invalid_convert = true;
3493 } else if (frb_val >= static_cast<double>(kMaxVal)) {
3494 frt_val = kMaxVal;
3495 invalid_convert = true;
3496 } else {
3497 frt_val = (int64_t)frb_val;
3498 }
3499 }
3500 set_d_register(frt, frt_val);
3501 if (invalid_convert) SetFPSCR(VXCVI);
3502 return;
3503 }
3504 case FCTIDU:
3505 case FCTIDUZ: {
3506 int frt = instr->RTValue();
3507 int frb = instr->RBValue();
3508 double frb_val = get_double_from_d_register(frb);
3509 int mode = (opcode == FCTIDUZ)
3510 ? kRoundToZero
3511 : (fp_condition_reg_ & kFPRoundingModeMask);
3512 uint64_t frt_val;
3513 uint64_t kMinVal = 0;
3514 uint64_t kMaxVal = kMinVal - 1;
3515 bool invalid_convert = false;
3516
3517 if (std::isnan(frb_val)) {
3518 frt_val = kMinVal;
3519 invalid_convert = true;
3520 } else {
3521 switch (mode) {
3522 case kRoundToZero:
3523 frb_val = std::trunc(frb_val);
3524 break;
3525 case kRoundToPlusInf:
3526 frb_val = std::ceil(frb_val);
3527 break;
3528 case kRoundToMinusInf:
3529 frb_val = std::floor(frb_val);
3530 break;
3531 default:
3532 UNIMPLEMENTED(); // Not used by V8.
3533 break;
3534 }
3535 if (frb_val < static_cast<double>(kMinVal)) {
3536 frt_val = kMinVal;
3537 invalid_convert = true;
3538 } else if (frb_val >= static_cast<double>(kMaxVal)) {
3539 frt_val = kMaxVal;
3540 invalid_convert = true;
3541 } else {
3542 frt_val = (uint64_t)frb_val;
3543 }
3544 }
3545 set_d_register(frt, frt_val);
3546 if (invalid_convert) SetFPSCR(VXCVI);
3547 return;
3548 }
3549 case FCTIW:
3550 case FCTIWZ: {
3551 int frt = instr->RTValue();
3552 int frb = instr->RBValue();
3553 double frb_val = get_double_from_d_register(frb);
3554 int mode = (opcode == FCTIWZ) ? kRoundToZero
3555 : (fp_condition_reg_ & kFPRoundingModeMask);
3556 int64_t frt_val;
3557 int64_t kMinVal = kMinInt;
3558 int64_t kMaxVal = kMaxInt;
3559
3560 if (std::isnan(frb_val)) {
3561 frt_val = kMinVal;
3562 } else {
3563 switch (mode) {
3564 case kRoundToZero:
3565 frb_val = std::trunc(frb_val);
3566 break;
3567 case kRoundToPlusInf:
3568 frb_val = std::ceil(frb_val);
3569 break;
3570 case kRoundToMinusInf:
3571 frb_val = std::floor(frb_val);
3572 break;
3573 case kRoundToNearest: {
3574 double orig = frb_val;
3575 frb_val = lround(frb_val);
3576 // Round to even if exactly halfway. (lround rounds up)
3577 if (std::fabs(frb_val - orig) == 0.5 && ((int64_t)frb_val % 2)) {
3578 frb_val += ((frb_val > 0) ? -1.0 : 1.0);
3579 }
3580 break;
3581 }
3582 default:
3583 UNIMPLEMENTED(); // Not used by V8.
3584 break;
3585 }
3586 if (frb_val < kMinVal) {
3587 frt_val = kMinVal;
3588 } else if (frb_val > kMaxVal) {
3589 frt_val = kMaxVal;
3590 } else {
3591 frt_val = (int64_t)frb_val;
3592 }
3593 }
3594 set_d_register(frt, frt_val);
3595 return;
3596 }
3597 case FNEG: {
3598 int frt = instr->RTValue();
3599 int frb = instr->RBValue();
3600 double frb_val = get_double_from_d_register(frb);
3601 double frt_val = -frb_val;
3602 set_d_register_from_double(frt, frt_val);
3603 return;
3604 }
3605 case FMR: {
3606 int frt = instr->RTValue();
3607 int frb = instr->RBValue();
3608 int64_t frb_val = get_d_register(frb);
3609 set_d_register(frt, frb_val);
3610 return;
3611 }
3612 case MTFSFI: {
3613 int bf = instr->Bits(25, 23);
3614 int imm = instr->Bits(15, 12);
3615 int fp_condition_mask = 0xF0000000 >> (bf * 4);
3616 fp_condition_reg_ &= ~fp_condition_mask;
3617 fp_condition_reg_ |= (imm << (28 - (bf * 4)));
3618 if (instr->Bit(0)) { // RC bit set
3619 condition_reg_ &= 0xF0FFFFFF;
3620 condition_reg_ |= (imm << 23);
3621 }
3622 return;
3623 }
3624 case MTFSF: {
3625 int frb = instr->RBValue();
3626 int64_t frb_dval = get_d_register(frb);
3627 int32_t frb_ival = static_cast<int32_t>((frb_dval)&0xFFFFFFFF);
3628 int l = instr->Bits(25, 25);
3629 if (l == 1) {
3630 fp_condition_reg_ = frb_ival;
3631 } else {
3632 UNIMPLEMENTED();
3633 }
3634 if (instr->Bit(0)) { // RC bit set
3635 UNIMPLEMENTED();
3636 // int w = instr->Bits(16, 16);
3637 // int flm = instr->Bits(24, 17);
3638 }
3639 return;
3640 }
3641 case MFFS: {
3642 int frt = instr->RTValue();
3643 int64_t lval = static_cast<int64_t>(fp_condition_reg_);
3644 set_d_register(frt, lval);
3645 return;
3646 }
3647 case MCRFS: {
3648 int bf = instr->Bits(25, 23);
3649 int bfa = instr->Bits(20, 18);
3650 int cr_shift = (7 - bf) * CRWIDTH;
3651 int fp_shift = (7 - bfa) * CRWIDTH;
3652 int field_val = (fp_condition_reg_ >> fp_shift) & 0xF;
3653 condition_reg_ &= ~(0x0F << cr_shift);
3654 condition_reg_ |= (field_val << cr_shift);
3655 // Clear copied exception bits
3656 switch (bfa) {
3657 case 5:
3658 ClearFPSCR(VXSOFT);
3659 ClearFPSCR(VXSQRT);
3660 ClearFPSCR(VXCVI);
3661 break;
3662 default:
3663 UNIMPLEMENTED();
3664 break;
3665 }
3666 return;
3667 }
3668 case MTFSB0: {
3669 int bt = instr->Bits(25, 21);
3670 ClearFPSCR(bt);
3671 if (instr->Bit(0)) { // RC bit set
3672 UNIMPLEMENTED();
3673 }
3674 return;
3675 }
3676 case MTFSB1: {
3677 int bt = instr->Bits(25, 21);
3678 SetFPSCR(bt);
3679 if (instr->Bit(0)) { // RC bit set
3680 UNIMPLEMENTED();
3681 }
3682 return;
3683 }
3684 case FABS: {
3685 int frt = instr->RTValue();
3686 int frb = instr->RBValue();
3687 double frb_val = get_double_from_d_register(frb);
3688 double frt_val = std::fabs(frb_val);
3689 set_d_register_from_double(frt, frt_val);
3690 return;
3691 }
3692
3693
3694 #if V8_TARGET_ARCH_PPC64
3695 case RLDICL: {
3696 int ra = instr->RAValue();
3697 int rs = instr->RSValue();
3698 uintptr_t rs_val = get_register(rs);
3699 int sh = (instr->Bits(15, 11) | (instr->Bit(1) << 5));
3700 int mb = (instr->Bits(10, 6) | (instr->Bit(5) << 5));
3701 DCHECK(sh >= 0 && sh <= 63);
3702 DCHECK(mb >= 0 && mb <= 63);
3703 uintptr_t result = base::bits::RotateLeft64(rs_val, sh);
3704 uintptr_t mask = 0xFFFFFFFFFFFFFFFF >> mb;
3705 result &= mask;
3706 set_register(ra, result);
3707 if (instr->Bit(0)) { // RC bit set
3708 SetCR0(result);
3709 }
3710 return;
3711 }
3712 case RLDICR: {
3713 int ra = instr->RAValue();
3714 int rs = instr->RSValue();
3715 uintptr_t rs_val = get_register(rs);
3716 int sh = (instr->Bits(15, 11) | (instr->Bit(1) << 5));
3717 int me = (instr->Bits(10, 6) | (instr->Bit(5) << 5));
3718 DCHECK(sh >= 0 && sh <= 63);
3719 DCHECK(me >= 0 && me <= 63);
3720 uintptr_t result = base::bits::RotateLeft64(rs_val, sh);
3721 uintptr_t mask = 0xFFFFFFFFFFFFFFFF << (63 - me);
3722 result &= mask;
3723 set_register(ra, result);
3724 if (instr->Bit(0)) { // RC bit set
3725 SetCR0(result);
3726 }
3727 return;
3728 }
3729 case RLDIC: {
3730 int ra = instr->RAValue();
3731 int rs = instr->RSValue();
3732 uintptr_t rs_val = get_register(rs);
3733 int sh = (instr->Bits(15, 11) | (instr->Bit(1) << 5));
3734 int mb = (instr->Bits(10, 6) | (instr->Bit(5) << 5));
3735 DCHECK(sh >= 0 && sh <= 63);
3736 DCHECK(mb >= 0 && mb <= 63);
3737 uintptr_t result = base::bits::RotateLeft64(rs_val, sh);
3738 uintptr_t mask = (0xFFFFFFFFFFFFFFFF >> mb) & (0xFFFFFFFFFFFFFFFF << sh);
3739 result &= mask;
3740 set_register(ra, result);
3741 if (instr->Bit(0)) { // RC bit set
3742 SetCR0(result);
3743 }
3744 return;
3745 }
3746 case RLDIMI: {
3747 int ra = instr->RAValue();
3748 int rs = instr->RSValue();
3749 uintptr_t rs_val = get_register(rs);
3750 intptr_t ra_val = get_register(ra);
3751 int sh = (instr->Bits(15, 11) | (instr->Bit(1) << 5));
3752 int mb = (instr->Bits(10, 6) | (instr->Bit(5) << 5));
3753 int me = 63 - sh;
3754 uintptr_t result = base::bits::RotateLeft64(rs_val, sh);
3755 uintptr_t mask = 0;
3756 if (mb < me + 1) {
3757 uintptr_t bit = 0x8000000000000000 >> mb;
3758 for (; mb <= me; mb++) {
3759 mask |= bit;
3760 bit >>= 1;
3761 }
3762 } else if (mb == me + 1) {
3763 mask = 0xFFFFFFFFFFFFFFFF;
3764 } else { // mb > me+1
3765 uintptr_t bit = 0x8000000000000000 >> (me + 1); // needs to be tested
3766 mask = 0xFFFFFFFFFFFFFFFF;
3767 for (; me < mb; me++) {
3768 mask ^= bit;
3769 bit >>= 1;
3770 }
3771 }
3772 result &= mask;
3773 ra_val &= ~mask;
3774 result |= ra_val;
3775 set_register(ra, result);
3776 if (instr->Bit(0)) { // RC bit set
3777 SetCR0(result);
3778 }
3779 return;
3780 }
3781 case RLDCL: {
3782 int ra = instr->RAValue();
3783 int rs = instr->RSValue();
3784 int rb = instr->RBValue();
3785 uintptr_t rs_val = get_register(rs);
3786 uintptr_t rb_val = get_register(rb);
3787 int sh = (rb_val & 0x3F);
3788 int mb = (instr->Bits(10, 6) | (instr->Bit(5) << 5));
3789 DCHECK(sh >= 0 && sh <= 63);
3790 DCHECK(mb >= 0 && mb <= 63);
3791 uintptr_t result = base::bits::RotateLeft64(rs_val, sh);
3792 uintptr_t mask = 0xFFFFFFFFFFFFFFFF >> mb;
3793 result &= mask;
3794 set_register(ra, result);
3795 if (instr->Bit(0)) { // RC bit set
3796 SetCR0(result);
3797 }
3798 return;
3799 }
3800
3801 case LD:
3802 case LDU:
3803 case LWA: {
3804 int ra = instr->RAValue();
3805 int rt = instr->RTValue();
3806 int64_t ra_val = ra == 0 ? 0 : get_register(ra);
3807 int offset = SIGN_EXT_IMM16(instr->Bits(15, 0) & ~3);
3808 switch (instr->Bits(1, 0)) {
3809 case 0: { // ld
3810 intptr_t* result = ReadDW(ra_val + offset);
3811 set_register(rt, *result);
3812 break;
3813 }
3814 case 1: { // ldu
3815 intptr_t* result = ReadDW(ra_val + offset);
3816 set_register(rt, *result);
3817 DCHECK_NE(ra, 0);
3818 set_register(ra, ra_val + offset);
3819 break;
3820 }
3821 case 2: { // lwa
3822 intptr_t result = ReadW(ra_val + offset, instr);
3823 set_register(rt, result);
3824 break;
3825 }
3826 }
3827 break;
3828 }
3829
3830 case STD:
3831 case STDU: {
3832 int ra = instr->RAValue();
3833 int rs = instr->RSValue();
3834 int64_t ra_val = ra == 0 ? 0 : get_register(ra);
3835 int64_t rs_val = get_register(rs);
3836 int offset = SIGN_EXT_IMM16(instr->Bits(15, 0) & ~3);
3837 WriteDW(ra_val + offset, rs_val);
3838 if (opcode == STDU) {
3839 DCHECK_NE(ra, 0);
3840 set_register(ra, ra_val + offset);
3841 }
3842 break;
3843 }
3844 #endif
3845
3846 case XSADDDP: {
3847 int frt = instr->RTValue();
3848 int fra = instr->RAValue();
3849 int frb = instr->RBValue();
3850 double fra_val = get_double_from_d_register(fra);
3851 double frb_val = get_double_from_d_register(frb);
3852 double frt_val = fra_val + frb_val;
3853 set_d_register_from_double(frt, frt_val);
3854 return;
3855 }
3856 case XSSUBDP: {
3857 int frt = instr->RTValue();
3858 int fra = instr->RAValue();
3859 int frb = instr->RBValue();
3860 double fra_val = get_double_from_d_register(fra);
3861 double frb_val = get_double_from_d_register(frb);
3862 double frt_val = fra_val - frb_val;
3863 set_d_register_from_double(frt, frt_val);
3864 return;
3865 }
3866 case XSMULDP: {
3867 int frt = instr->RTValue();
3868 int fra = instr->RAValue();
3869 int frb = instr->RBValue();
3870 double fra_val = get_double_from_d_register(fra);
3871 double frb_val = get_double_from_d_register(frb);
3872 double frt_val = fra_val * frb_val;
3873 set_d_register_from_double(frt, frt_val);
3874 return;
3875 }
3876 case XSDIVDP: {
3877 int frt = instr->RTValue();
3878 int fra = instr->RAValue();
3879 int frb = instr->RBValue();
3880 double fra_val = get_double_from_d_register(fra);
3881 double frb_val = get_double_from_d_register(frb);
3882 double frt_val = fra_val / frb_val;
3883 set_d_register_from_double(frt, frt_val);
3884 return;
3885 }
3886
3887 default: {
3888 UNIMPLEMENTED();
3889 break;
3890 }
3891 }
3892 } // NOLINT
3893
3894
Trace(Instruction * instr)3895 void Simulator::Trace(Instruction* instr) {
3896 disasm::NameConverter converter;
3897 disasm::Disassembler dasm(converter);
3898 // use a reasonably large buffer
3899 v8::internal::EmbeddedVector<char, 256> buffer;
3900 dasm.InstructionDecode(buffer, reinterpret_cast<byte*>(instr));
3901 PrintF("%05d %08" V8PRIxPTR " %s\n", icount_,
3902 reinterpret_cast<intptr_t>(instr), buffer.start());
3903 }
3904
3905
3906 // Executes the current instruction.
ExecuteInstruction(Instruction * instr)3907 void Simulator::ExecuteInstruction(Instruction* instr) {
3908 if (v8::internal::FLAG_check_icache) {
3909 CheckICache(i_cache(), instr);
3910 }
3911 pc_modified_ = false;
3912 if (::v8::internal::FLAG_trace_sim) {
3913 Trace(instr);
3914 }
3915 uint32_t opcode = instr->OpcodeField();
3916 if (opcode == TWI) {
3917 SoftwareInterrupt(instr);
3918 } else {
3919 ExecuteGeneric(instr);
3920 }
3921 if (!pc_modified_) {
3922 set_pc(reinterpret_cast<intptr_t>(instr) + kInstrSize);
3923 }
3924 }
3925
Execute()3926 void Simulator::Execute() {
3927 // Get the PC to simulate. Cannot use the accessor here as we need the
3928 // raw PC value and not the one used as input to arithmetic instructions.
3929 intptr_t program_counter = get_pc();
3930
3931 if (::v8::internal::FLAG_stop_sim_at == 0) {
3932 // Fast version of the dispatch loop without checking whether the simulator
3933 // should be stopping at a particular executed instruction.
3934 while (program_counter != end_sim_pc) {
3935 Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
3936 icount_++;
3937 ExecuteInstruction(instr);
3938 program_counter = get_pc();
3939 }
3940 } else {
3941 // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when
3942 // we reach the particular instruction count.
3943 while (program_counter != end_sim_pc) {
3944 Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
3945 icount_++;
3946 if (icount_ == ::v8::internal::FLAG_stop_sim_at) {
3947 PPCDebugger dbg(this);
3948 dbg.Debug();
3949 } else {
3950 ExecuteInstruction(instr);
3951 }
3952 program_counter = get_pc();
3953 }
3954 }
3955 }
3956
CallInternal(Address entry)3957 void Simulator::CallInternal(Address entry) {
3958 // Adjust JS-based stack limit to C-based stack limit.
3959 isolate_->stack_guard()->AdjustStackLimitForSimulator();
3960
3961 // Prepare to execute the code at entry
3962 if (ABI_USES_FUNCTION_DESCRIPTORS) {
3963 // entry is the function descriptor
3964 set_pc(*(reinterpret_cast<intptr_t*>(entry)));
3965 } else {
3966 // entry is the instruction address
3967 set_pc(static_cast<intptr_t>(entry));
3968 }
3969
3970 if (ABI_CALL_VIA_IP) {
3971 // Put target address in ip (for JS prologue).
3972 set_register(r12, get_pc());
3973 }
3974
3975 // Put down marker for end of simulation. The simulator will stop simulation
3976 // when the PC reaches this value. By saving the "end simulation" value into
3977 // the LR the simulation stops when returning to this call point.
3978 special_reg_lr_ = end_sim_pc;
3979
3980 // Remember the values of non-volatile registers.
3981 intptr_t r2_val = get_register(r2);
3982 intptr_t r13_val = get_register(r13);
3983 intptr_t r14_val = get_register(r14);
3984 intptr_t r15_val = get_register(r15);
3985 intptr_t r16_val = get_register(r16);
3986 intptr_t r17_val = get_register(r17);
3987 intptr_t r18_val = get_register(r18);
3988 intptr_t r19_val = get_register(r19);
3989 intptr_t r20_val = get_register(r20);
3990 intptr_t r21_val = get_register(r21);
3991 intptr_t r22_val = get_register(r22);
3992 intptr_t r23_val = get_register(r23);
3993 intptr_t r24_val = get_register(r24);
3994 intptr_t r25_val = get_register(r25);
3995 intptr_t r26_val = get_register(r26);
3996 intptr_t r27_val = get_register(r27);
3997 intptr_t r28_val = get_register(r28);
3998 intptr_t r29_val = get_register(r29);
3999 intptr_t r30_val = get_register(r30);
4000 intptr_t r31_val = get_register(fp);
4001
4002 // Set up the non-volatile registers with a known value. To be able to check
4003 // that they are preserved properly across JS execution.
4004 intptr_t callee_saved_value = icount_;
4005 set_register(r2, callee_saved_value);
4006 set_register(r13, callee_saved_value);
4007 set_register(r14, callee_saved_value);
4008 set_register(r15, callee_saved_value);
4009 set_register(r16, callee_saved_value);
4010 set_register(r17, callee_saved_value);
4011 set_register(r18, callee_saved_value);
4012 set_register(r19, callee_saved_value);
4013 set_register(r20, callee_saved_value);
4014 set_register(r21, callee_saved_value);
4015 set_register(r22, callee_saved_value);
4016 set_register(r23, callee_saved_value);
4017 set_register(r24, callee_saved_value);
4018 set_register(r25, callee_saved_value);
4019 set_register(r26, callee_saved_value);
4020 set_register(r27, callee_saved_value);
4021 set_register(r28, callee_saved_value);
4022 set_register(r29, callee_saved_value);
4023 set_register(r30, callee_saved_value);
4024 set_register(fp, callee_saved_value);
4025
4026 // Start the simulation
4027 Execute();
4028
4029 // Check that the non-volatile registers have been preserved.
4030 if (ABI_TOC_REGISTER != 2) {
4031 CHECK_EQ(callee_saved_value, get_register(r2));
4032 }
4033 if (ABI_TOC_REGISTER != 13) {
4034 CHECK_EQ(callee_saved_value, get_register(r13));
4035 }
4036 CHECK_EQ(callee_saved_value, get_register(r14));
4037 CHECK_EQ(callee_saved_value, get_register(r15));
4038 CHECK_EQ(callee_saved_value, get_register(r16));
4039 CHECK_EQ(callee_saved_value, get_register(r17));
4040 CHECK_EQ(callee_saved_value, get_register(r18));
4041 CHECK_EQ(callee_saved_value, get_register(r19));
4042 CHECK_EQ(callee_saved_value, get_register(r20));
4043 CHECK_EQ(callee_saved_value, get_register(r21));
4044 CHECK_EQ(callee_saved_value, get_register(r22));
4045 CHECK_EQ(callee_saved_value, get_register(r23));
4046 CHECK_EQ(callee_saved_value, get_register(r24));
4047 CHECK_EQ(callee_saved_value, get_register(r25));
4048 CHECK_EQ(callee_saved_value, get_register(r26));
4049 CHECK_EQ(callee_saved_value, get_register(r27));
4050 CHECK_EQ(callee_saved_value, get_register(r28));
4051 CHECK_EQ(callee_saved_value, get_register(r29));
4052 CHECK_EQ(callee_saved_value, get_register(r30));
4053 CHECK_EQ(callee_saved_value, get_register(fp));
4054
4055 // Restore non-volatile registers with the original value.
4056 set_register(r2, r2_val);
4057 set_register(r13, r13_val);
4058 set_register(r14, r14_val);
4059 set_register(r15, r15_val);
4060 set_register(r16, r16_val);
4061 set_register(r17, r17_val);
4062 set_register(r18, r18_val);
4063 set_register(r19, r19_val);
4064 set_register(r20, r20_val);
4065 set_register(r21, r21_val);
4066 set_register(r22, r22_val);
4067 set_register(r23, r23_val);
4068 set_register(r24, r24_val);
4069 set_register(r25, r25_val);
4070 set_register(r26, r26_val);
4071 set_register(r27, r27_val);
4072 set_register(r28, r28_val);
4073 set_register(r29, r29_val);
4074 set_register(r30, r30_val);
4075 set_register(fp, r31_val);
4076 }
4077
CallImpl(Address entry,int argument_count,const intptr_t * arguments)4078 intptr_t Simulator::CallImpl(Address entry, int argument_count,
4079 const intptr_t* arguments) {
4080 // Set up arguments
4081
4082 // First eight arguments passed in registers r3-r10.
4083 int reg_arg_count = std::min(8, argument_count);
4084 int stack_arg_count = argument_count - reg_arg_count;
4085 for (int i = 0; i < reg_arg_count; i++) {
4086 set_register(i + 3, arguments[i]);
4087 }
4088
4089 // Remaining arguments passed on stack.
4090 intptr_t original_stack = get_register(sp);
4091 // Compute position of stack on entry to generated code.
4092 intptr_t entry_stack =
4093 (original_stack -
4094 (kNumRequiredStackFrameSlots + stack_arg_count) * sizeof(intptr_t));
4095 if (base::OS::ActivationFrameAlignment() != 0) {
4096 entry_stack &= -base::OS::ActivationFrameAlignment();
4097 }
4098 // Store remaining arguments on stack, from low to high memory.
4099 // +2 is a hack for the LR slot + old SP on PPC
4100 intptr_t* stack_argument =
4101 reinterpret_cast<intptr_t*>(entry_stack) + kStackFrameExtraParamSlot;
4102 memcpy(stack_argument, arguments + reg_arg_count,
4103 stack_arg_count * sizeof(*arguments));
4104 set_register(sp, entry_stack);
4105
4106 CallInternal(entry);
4107
4108 // Pop stack passed arguments.
4109 CHECK_EQ(entry_stack, get_register(sp));
4110 set_register(sp, original_stack);
4111
4112 return get_register(r3);
4113 }
4114
CallFP(Address entry,double d0,double d1)4115 void Simulator::CallFP(Address entry, double d0, double d1) {
4116 set_d_register_from_double(1, d0);
4117 set_d_register_from_double(2, d1);
4118 CallInternal(entry);
4119 }
4120
CallFPReturnsInt(Address entry,double d0,double d1)4121 int32_t Simulator::CallFPReturnsInt(Address entry, double d0, double d1) {
4122 CallFP(entry, d0, d1);
4123 int32_t result = get_register(r3);
4124 return result;
4125 }
4126
CallFPReturnsDouble(Address entry,double d0,double d1)4127 double Simulator::CallFPReturnsDouble(Address entry, double d0, double d1) {
4128 CallFP(entry, d0, d1);
4129 return get_double_from_d_register(1);
4130 }
4131
4132
PushAddress(uintptr_t address)4133 uintptr_t Simulator::PushAddress(uintptr_t address) {
4134 uintptr_t new_sp = get_register(sp) - sizeof(uintptr_t);
4135 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp);
4136 *stack_slot = address;
4137 set_register(sp, new_sp);
4138 return new_sp;
4139 }
4140
4141
PopAddress()4142 uintptr_t Simulator::PopAddress() {
4143 uintptr_t current_sp = get_register(sp);
4144 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp);
4145 uintptr_t address = *stack_slot;
4146 set_register(sp, current_sp + sizeof(uintptr_t));
4147 return address;
4148 }
4149
LocalMonitor()4150 Simulator::LocalMonitor::LocalMonitor()
4151 : access_state_(MonitorAccess::Open),
4152 tagged_addr_(0),
4153 size_(TransactionSize::None) {}
4154
Clear()4155 void Simulator::LocalMonitor::Clear() {
4156 access_state_ = MonitorAccess::Open;
4157 tagged_addr_ = 0;
4158 size_ = TransactionSize::None;
4159 }
4160
NotifyLoad(int32_t addr)4161 void Simulator::LocalMonitor::NotifyLoad(int32_t addr) {
4162 if (access_state_ == MonitorAccess::Exclusive) {
4163 // A load could cause a cache eviction which will affect the monitor. As a
4164 // result, it's most strict to unconditionally clear the local monitor on
4165 // load.
4166 Clear();
4167 }
4168 }
4169
NotifyLoadExcl(int32_t addr,TransactionSize size)4170 void Simulator::LocalMonitor::NotifyLoadExcl(int32_t addr,
4171 TransactionSize size) {
4172 access_state_ = MonitorAccess::Exclusive;
4173 tagged_addr_ = addr;
4174 size_ = size;
4175 }
4176
NotifyStore(int32_t addr)4177 void Simulator::LocalMonitor::NotifyStore(int32_t addr) {
4178 if (access_state_ == MonitorAccess::Exclusive) {
4179 // A store could cause a cache eviction which will affect the
4180 // monitor. As a result, it's most strict to unconditionally clear the
4181 // local monitor on store.
4182 Clear();
4183 }
4184 }
4185
NotifyStoreExcl(int32_t addr,TransactionSize size)4186 bool Simulator::LocalMonitor::NotifyStoreExcl(int32_t addr,
4187 TransactionSize size) {
4188 if (access_state_ == MonitorAccess::Exclusive) {
4189 if (addr == tagged_addr_ && size_ == size) {
4190 Clear();
4191 return true;
4192 } else {
4193 Clear();
4194 return false;
4195 }
4196 } else {
4197 DCHECK(access_state_ == MonitorAccess::Open);
4198 return false;
4199 }
4200 }
4201
Processor()4202 Simulator::GlobalMonitor::Processor::Processor()
4203 : access_state_(MonitorAccess::Open),
4204 tagged_addr_(0),
4205 next_(nullptr),
4206 prev_(nullptr) {}
4207
Clear_Locked()4208 void Simulator::GlobalMonitor::Processor::Clear_Locked() {
4209 access_state_ = MonitorAccess::Open;
4210 tagged_addr_ = 0;
4211 }
NotifyLoadExcl_Locked(int32_t addr)4212 void Simulator::GlobalMonitor::Processor::NotifyLoadExcl_Locked(int32_t addr) {
4213 access_state_ = MonitorAccess::Exclusive;
4214 tagged_addr_ = addr;
4215 }
4216
NotifyStore_Locked(int32_t addr,bool is_requesting_processor)4217 void Simulator::GlobalMonitor::Processor::NotifyStore_Locked(
4218 int32_t addr, bool is_requesting_processor) {
4219 if (access_state_ == MonitorAccess::Exclusive) {
4220 // It is possible that a store caused a cache eviction,
4221 // which can affect the montior, so conservatively,
4222 // we always clear the monitor.
4223 Clear_Locked();
4224 }
4225 }
4226
NotifyStoreExcl_Locked(int32_t addr,bool is_requesting_processor)4227 bool Simulator::GlobalMonitor::Processor::NotifyStoreExcl_Locked(
4228 int32_t addr, bool is_requesting_processor) {
4229 if (access_state_ == MonitorAccess::Exclusive) {
4230 if (is_requesting_processor) {
4231 if (addr == tagged_addr_) {
4232 Clear_Locked();
4233 return true;
4234 }
4235 } else if (addr == tagged_addr_) {
4236 Clear_Locked();
4237 return false;
4238 }
4239 }
4240 return false;
4241 }
4242
GlobalMonitor()4243 Simulator::GlobalMonitor::GlobalMonitor() : head_(nullptr) {}
4244
NotifyLoadExcl_Locked(int32_t addr,Processor * processor)4245 void Simulator::GlobalMonitor::NotifyLoadExcl_Locked(int32_t addr,
4246 Processor* processor) {
4247 processor->NotifyLoadExcl_Locked(addr);
4248 PrependProcessor_Locked(processor);
4249 }
4250
NotifyStore_Locked(int32_t addr,Processor * processor)4251 void Simulator::GlobalMonitor::NotifyStore_Locked(int32_t addr,
4252 Processor* processor) {
4253 // Notify each processor of the store operation.
4254 for (Processor* iter = head_; iter; iter = iter->next_) {
4255 bool is_requesting_processor = iter == processor;
4256 iter->NotifyStore_Locked(addr, is_requesting_processor);
4257 }
4258 }
4259
NotifyStoreExcl_Locked(int32_t addr,Processor * processor)4260 bool Simulator::GlobalMonitor::NotifyStoreExcl_Locked(int32_t addr,
4261 Processor* processor) {
4262 DCHECK(IsProcessorInLinkedList_Locked(processor));
4263 if (processor->NotifyStoreExcl_Locked(addr, true)) {
4264 // Notify the other processors that this StoreExcl succeeded.
4265 for (Processor* iter = head_; iter; iter = iter->next_) {
4266 if (iter != processor) {
4267 iter->NotifyStoreExcl_Locked(addr, false);
4268 }
4269 }
4270 return true;
4271 } else {
4272 return false;
4273 }
4274 }
4275
IsProcessorInLinkedList_Locked(Processor * processor) const4276 bool Simulator::GlobalMonitor::IsProcessorInLinkedList_Locked(
4277 Processor* processor) const {
4278 return head_ == processor || processor->next_ || processor->prev_;
4279 }
4280
PrependProcessor_Locked(Processor * processor)4281 void Simulator::GlobalMonitor::PrependProcessor_Locked(Processor* processor) {
4282 if (IsProcessorInLinkedList_Locked(processor)) {
4283 return;
4284 }
4285
4286 if (head_) {
4287 head_->prev_ = processor;
4288 }
4289 processor->prev_ = nullptr;
4290 processor->next_ = head_;
4291 head_ = processor;
4292 }
4293
RemoveProcessor(Processor * processor)4294 void Simulator::GlobalMonitor::RemoveProcessor(Processor* processor) {
4295 base::LockGuard<base::Mutex> lock_guard(&mutex);
4296 if (!IsProcessorInLinkedList_Locked(processor)) {
4297 return;
4298 }
4299
4300 if (processor->prev_) {
4301 processor->prev_->next_ = processor->next_;
4302 } else {
4303 head_ = processor->next_;
4304 }
4305 if (processor->next_) {
4306 processor->next_->prev_ = processor->prev_;
4307 }
4308 processor->prev_ = nullptr;
4309 processor->next_ = nullptr;
4310 }
4311
4312 } // namespace internal
4313 } // namespace v8
4314
4315 #endif // USE_SIMULATOR
4316 #endif // V8_TARGET_ARCH_PPC
4317