OLD | NEW |
| (Empty) |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 #include <setjmp.h> // NOLINT | |
6 #include <stdlib.h> | |
7 | |
8 #include "vm/globals.h" | |
9 #if defined(TARGET_ARCH_MIPS) | |
10 | |
11 // Only build the simulator if not compiling for real MIPS hardware. | |
12 #if defined(USING_SIMULATOR) | |
13 | |
14 #include "vm/simulator.h" | |
15 | |
16 #include "vm/assembler.h" | |
17 #include "vm/constants_mips.h" | |
18 #include "vm/disassembler.h" | |
19 #include "vm/lockers.h" | |
20 #include "vm/native_arguments.h" | |
21 #include "vm/stack_frame.h" | |
22 #include "vm/os_thread.h" | |
23 | |
24 namespace dart { | |
25 | |
26 DEFINE_FLAG(uint64_t, | |
27 trace_sim_after, | |
28 ULLONG_MAX, | |
29 "Trace simulator execution after instruction count reached."); | |
30 DEFINE_FLAG(uint64_t, | |
31 stop_sim_at, | |
32 ULLONG_MAX, | |
33 "Instruction address or instruction count to stop simulator at."); | |
34 | |
35 | |
36 // This macro provides a platform independent use of sscanf. The reason for | |
37 // SScanF not being implemented in a platform independent way through | |
38 // OS in the same way as SNPrint is that the Windows C Run-Time | |
39 // Library does not provide vsscanf. | |
40 #define SScanF sscanf // NOLINT | |
41 | |
42 | |
43 // SimulatorSetjmpBuffer are linked together, and the last created one | |
44 // is referenced by the Simulator. When an exception is thrown, the exception | |
45 // runtime looks at where to jump and finds the corresponding | |
46 // SimulatorSetjmpBuffer based on the stack pointer of the exception handler. | |
47 // The runtime then does a Longjmp on that buffer to return to the simulator. | |
48 class SimulatorSetjmpBuffer { | |
49 public: | |
50 void Longjmp() { | |
51 // "This" is now the last setjmp buffer. | |
52 simulator_->set_last_setjmp_buffer(this); | |
53 longjmp(buffer_, 1); | |
54 } | |
55 | |
56 explicit SimulatorSetjmpBuffer(Simulator* sim) { | |
57 simulator_ = sim; | |
58 link_ = sim->last_setjmp_buffer(); | |
59 sim->set_last_setjmp_buffer(this); | |
60 sp_ = static_cast<uword>(sim->get_register(SP)); | |
61 } | |
62 | |
63 ~SimulatorSetjmpBuffer() { | |
64 ASSERT(simulator_->last_setjmp_buffer() == this); | |
65 simulator_->set_last_setjmp_buffer(link_); | |
66 } | |
67 | |
68 SimulatorSetjmpBuffer* link() { return link_; } | |
69 | |
70 uword sp() { return sp_; } | |
71 | |
72 private: | |
73 uword sp_; | |
74 Simulator* simulator_; | |
75 SimulatorSetjmpBuffer* link_; | |
76 jmp_buf buffer_; | |
77 | |
78 friend class Simulator; | |
79 }; | |
80 | |
81 | |
82 // The SimulatorDebugger class is used by the simulator while debugging | |
83 // simulated MIPS code. | |
84 class SimulatorDebugger { | |
85 public: | |
86 explicit SimulatorDebugger(Simulator* sim); | |
87 ~SimulatorDebugger(); | |
88 | |
89 void Stop(Instr* instr, const char* message); | |
90 void Debug(); | |
91 char* ReadLine(const char* prompt); | |
92 | |
93 private: | |
94 Simulator* sim_; | |
95 | |
96 bool GetValue(char* desc, uint32_t* value); | |
97 bool GetFValue(char* desc, double* value); | |
98 bool GetDValue(char* desc, double* value); | |
99 | |
100 static TokenPosition GetApproximateTokenIndex(const Code& code, uword pc); | |
101 | |
102 static void PrintDartFrame(uword pc, | |
103 uword fp, | |
104 uword sp, | |
105 const Function& function, | |
106 TokenPosition token_pos, | |
107 bool is_optimized, | |
108 bool is_inlined); | |
109 void PrintBacktrace(); | |
110 | |
111 // Set or delete a breakpoint. Returns true if successful. | |
112 bool SetBreakpoint(Instr* breakpc); | |
113 bool DeleteBreakpoint(Instr* breakpc); | |
114 | |
115 // Undo and redo all breakpoints. This is needed to bracket disassembly and | |
116 // execution to skip past breakpoints when run from the debugger. | |
117 void UndoBreakpoints(); | |
118 void RedoBreakpoints(); | |
119 }; | |
120 | |
121 | |
122 SimulatorDebugger::SimulatorDebugger(Simulator* sim) { | |
123 sim_ = sim; | |
124 } | |
125 | |
126 | |
127 SimulatorDebugger::~SimulatorDebugger() {} | |
128 | |
129 | |
130 void SimulatorDebugger::Stop(Instr* instr, const char* message) { | |
131 OS::Print("Simulator hit %s\n", message); | |
132 Debug(); | |
133 } | |
134 | |
135 | |
136 static Register LookupCpuRegisterByName(const char* name) { | |
137 static const char* kNames[] = { | |
138 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", | |
139 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", | |
140 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", | |
141 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", | |
142 | |
143 "zr", "at", "v0", "v1", "a0", "a1", "a2", "a3", | |
144 "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", | |
145 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", | |
146 "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra"}; | |
147 static const Register kRegisters[] = { | |
148 R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, | |
149 R11, R12, R13, R14, R15, R16, R17, R18, R19, R20, R21, | |
150 R22, R23, R24, R25, R26, R27, R28, R29, R30, R31, | |
151 | |
152 ZR, AT, V0, V1, A0, A1, A2, A3, T0, T1, T2, | |
153 T3, T4, T5, T6, T7, S0, S1, S2, S3, S4, S5, | |
154 S6, S7, T8, T9, K0, K1, GP, SP, FP, RA}; | |
155 ASSERT(ARRAY_SIZE(kNames) == ARRAY_SIZE(kRegisters)); | |
156 for (unsigned i = 0; i < ARRAY_SIZE(kNames); i++) { | |
157 if (strcmp(kNames[i], name) == 0) { | |
158 return kRegisters[i]; | |
159 } | |
160 } | |
161 return kNoRegister; | |
162 } | |
163 | |
164 | |
165 static FRegister LookupFRegisterByName(const char* name) { | |
166 int reg_nr = -1; | |
167 bool ok = SScanF(name, "f%d", ®_nr); | |
168 if (ok && (0 <= reg_nr) && (reg_nr < kNumberOfFRegisters)) { | |
169 return static_cast<FRegister>(reg_nr); | |
170 } | |
171 return kNoFRegister; | |
172 } | |
173 | |
174 | |
175 bool SimulatorDebugger::GetValue(char* desc, uint32_t* value) { | |
176 Register reg = LookupCpuRegisterByName(desc); | |
177 if (reg != kNoRegister) { | |
178 *value = sim_->get_register(reg); | |
179 return true; | |
180 } | |
181 if (desc[0] == '*') { | |
182 uint32_t addr; | |
183 if (GetValue(desc + 1, &addr)) { | |
184 if (Simulator::IsIllegalAddress(addr)) { | |
185 return false; | |
186 } | |
187 *value = *(reinterpret_cast<uint32_t*>(addr)); | |
188 return true; | |
189 } | |
190 } | |
191 if (strcmp("pc", desc) == 0) { | |
192 *value = sim_->get_pc(); | |
193 return true; | |
194 } | |
195 bool retval = SScanF(desc, "0x%x", value) == 1; | |
196 if (!retval) { | |
197 retval = SScanF(desc, "%x", value) == 1; | |
198 } | |
199 return retval; | |
200 } | |
201 | |
202 | |
203 bool SimulatorDebugger::GetFValue(char* desc, double* value) { | |
204 FRegister freg = LookupFRegisterByName(desc); | |
205 if (freg != kNoFRegister) { | |
206 *value = sim_->get_fregister(freg); | |
207 return true; | |
208 } | |
209 if (desc[0] == '*') { | |
210 uint32_t addr; | |
211 if (GetValue(desc + 1, &addr)) { | |
212 if (Simulator::IsIllegalAddress(addr)) { | |
213 return false; | |
214 } | |
215 *value = *(reinterpret_cast<float*>(addr)); | |
216 return true; | |
217 } | |
218 } | |
219 return false; | |
220 } | |
221 | |
222 | |
223 bool SimulatorDebugger::GetDValue(char* desc, double* value) { | |
224 FRegister freg = LookupFRegisterByName(desc); | |
225 if (freg != kNoFRegister) { | |
226 *value = sim_->get_fregister_double(freg); | |
227 return true; | |
228 } | |
229 if (desc[0] == '*') { | |
230 uint32_t addr; | |
231 if (GetValue(desc + 1, &addr)) { | |
232 if (Simulator::IsIllegalAddress(addr)) { | |
233 return false; | |
234 } | |
235 *value = *(reinterpret_cast<double*>(addr)); | |
236 return true; | |
237 } | |
238 } | |
239 return false; | |
240 } | |
241 | |
242 | |
243 TokenPosition SimulatorDebugger::GetApproximateTokenIndex(const Code& code, | |
244 uword pc) { | |
245 TokenPosition token_pos = TokenPosition::kNoSource; | |
246 uword pc_offset = pc - code.PayloadStart(); | |
247 const PcDescriptors& descriptors = | |
248 PcDescriptors::Handle(code.pc_descriptors()); | |
249 PcDescriptors::Iterator iter(descriptors, RawPcDescriptors::kAnyKind); | |
250 while (iter.MoveNext()) { | |
251 if (iter.PcOffset() == pc_offset) { | |
252 return iter.TokenPos(); | |
253 } else if (!token_pos.IsReal() && (iter.PcOffset() > pc_offset)) { | |
254 token_pos = iter.TokenPos(); | |
255 } | |
256 } | |
257 return token_pos; | |
258 } | |
259 | |
260 | |
261 void SimulatorDebugger::PrintDartFrame(uword pc, | |
262 uword fp, | |
263 uword sp, | |
264 const Function& function, | |
265 TokenPosition token_pos, | |
266 bool is_optimized, | |
267 bool is_inlined) { | |
268 const Script& script = Script::Handle(function.script()); | |
269 const String& func_name = String::Handle(function.QualifiedScrubbedName()); | |
270 const String& url = String::Handle(script.url()); | |
271 intptr_t line = -1; | |
272 intptr_t column = -1; | |
273 if (token_pos.IsReal()) { | |
274 script.GetTokenLocation(token_pos, &line, &column); | |
275 } | |
276 OS::Print( | |
277 "pc=0x%" Px " fp=0x%" Px " sp=0x%" Px " %s%s (%s:%" Pd ":%" Pd ")\n", pc, | |
278 fp, sp, is_optimized ? (is_inlined ? "inlined " : "optimized ") : "", | |
279 func_name.ToCString(), url.ToCString(), line, column); | |
280 } | |
281 | |
282 | |
283 void SimulatorDebugger::PrintBacktrace() { | |
284 StackFrameIterator frames( | |
285 sim_->get_register(FP), sim_->get_register(SP), sim_->get_pc(), | |
286 StackFrameIterator::kDontValidateFrames, Thread::Current(), | |
287 StackFrameIterator::kNoCrossThreadIteration); | |
288 StackFrame* frame = frames.NextFrame(); | |
289 ASSERT(frame != NULL); | |
290 Function& function = Function::Handle(); | |
291 Function& inlined_function = Function::Handle(); | |
292 Code& code = Code::Handle(); | |
293 Code& unoptimized_code = Code::Handle(); | |
294 while (frame != NULL) { | |
295 if (frame->IsDartFrame()) { | |
296 code = frame->LookupDartCode(); | |
297 function = code.function(); | |
298 if (code.is_optimized()) { | |
299 // For optimized frames, extract all the inlined functions if any | |
300 // into the stack trace. | |
301 InlinedFunctionsIterator it(code, frame->pc()); | |
302 while (!it.Done()) { | |
303 // Print each inlined frame with its pc in the corresponding | |
304 // unoptimized frame. | |
305 inlined_function = it.function(); | |
306 unoptimized_code = it.code(); | |
307 uword unoptimized_pc = it.pc(); | |
308 it.Advance(); | |
309 if (!it.Done()) { | |
310 PrintDartFrame( | |
311 unoptimized_pc, frame->fp(), frame->sp(), inlined_function, | |
312 GetApproximateTokenIndex(unoptimized_code, unoptimized_pc), | |
313 true, true); | |
314 } | |
315 } | |
316 // Print the optimized inlining frame below. | |
317 } | |
318 PrintDartFrame(frame->pc(), frame->fp(), frame->sp(), function, | |
319 GetApproximateTokenIndex(code, frame->pc()), | |
320 code.is_optimized(), false); | |
321 } else { | |
322 OS::Print("pc=0x%" Px " fp=0x%" Px " sp=0x%" Px " %s frame\n", | |
323 frame->pc(), frame->fp(), frame->sp(), | |
324 frame->IsEntryFrame() | |
325 ? "entry" | |
326 : frame->IsExitFrame() | |
327 ? "exit" | |
328 : frame->IsStubFrame() ? "stub" : "invalid"); | |
329 } | |
330 frame = frames.NextFrame(); | |
331 } | |
332 } | |
333 | |
334 | |
335 bool SimulatorDebugger::SetBreakpoint(Instr* breakpc) { | |
336 // Check if a breakpoint can be set. If not return without any side-effects. | |
337 if (sim_->break_pc_ != NULL) { | |
338 return false; | |
339 } | |
340 | |
341 // Set the breakpoint. | |
342 sim_->break_pc_ = breakpc; | |
343 sim_->break_instr_ = breakpc->InstructionBits(); | |
344 // Not setting the breakpoint instruction in the code itself. It will be set | |
345 // when the debugger shell continues. | |
346 return true; | |
347 } | |
348 | |
349 | |
350 bool SimulatorDebugger::DeleteBreakpoint(Instr* breakpc) { | |
351 if (sim_->break_pc_ != NULL) { | |
352 sim_->break_pc_->SetInstructionBits(sim_->break_instr_); | |
353 } | |
354 | |
355 sim_->break_pc_ = NULL; | |
356 sim_->break_instr_ = 0; | |
357 return true; | |
358 } | |
359 | |
360 | |
361 void SimulatorDebugger::UndoBreakpoints() { | |
362 if (sim_->break_pc_ != NULL) { | |
363 sim_->break_pc_->SetInstructionBits(sim_->break_instr_); | |
364 } | |
365 } | |
366 | |
367 | |
368 void SimulatorDebugger::RedoBreakpoints() { | |
369 if (sim_->break_pc_ != NULL) { | |
370 sim_->break_pc_->SetInstructionBits(Instr::kSimulatorBreakpointInstruction); | |
371 } | |
372 } | |
373 | |
374 | |
375 void SimulatorDebugger::Debug() { | |
376 intptr_t last_pc = -1; | |
377 bool done = false; | |
378 | |
379 #define COMMAND_SIZE 63 | |
380 #define ARG_SIZE 255 | |
381 | |
382 #define STR(a) #a | |
383 #define XSTR(a) STR(a) | |
384 | |
385 char cmd[COMMAND_SIZE + 1]; | |
386 char arg1[ARG_SIZE + 1]; | |
387 char arg2[ARG_SIZE + 1]; | |
388 | |
389 // make sure to have a proper terminating character if reaching the limit | |
390 cmd[COMMAND_SIZE] = 0; | |
391 arg1[ARG_SIZE] = 0; | |
392 arg2[ARG_SIZE] = 0; | |
393 | |
394 // Undo all set breakpoints while running in the debugger shell. This will | |
395 // make them invisible to all commands. | |
396 UndoBreakpoints(); | |
397 | |
398 while (!done) { | |
399 if (last_pc != sim_->get_pc()) { | |
400 last_pc = sim_->get_pc(); | |
401 if (Simulator::IsIllegalAddress(last_pc)) { | |
402 OS::Print("pc is out of bounds: 0x%" Px "\n", last_pc); | |
403 } else { | |
404 if (FLAG_support_disassembler) { | |
405 Disassembler::Disassemble(last_pc, last_pc + Instr::kInstrSize); | |
406 } else { | |
407 OS::Print("Disassembler not supported in this mode.\n"); | |
408 } | |
409 } | |
410 } | |
411 char* line = ReadLine("sim> "); | |
412 if (line == NULL) { | |
413 FATAL("ReadLine failed"); | |
414 } else { | |
415 // Use sscanf to parse the individual parts of the command line. At the | |
416 // moment no command expects more than two parameters. | |
417 int args = SScanF(line, | |
418 "%" XSTR(COMMAND_SIZE) "s " | |
419 "%" XSTR(ARG_SIZE) "s " | |
420 "%" XSTR(ARG_SIZE) "s", | |
421 cmd, arg1, arg2); | |
422 if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) { | |
423 OS::Print( | |
424 "c/cont -- continue execution\n" | |
425 "disasm -- disassemble instrs at current pc location\n" | |
426 " other variants are:\n" | |
427 " disasm <address>\n" | |
428 " disasm <address> <number_of_instructions>\n" | |
429 " by default 10 instrs are disassembled\n" | |
430 "del -- delete breakpoints\n" | |
431 "gdb -- transfer control to gdb\n" | |
432 "h/help -- print this help string\n" | |
433 "break <address> -- set break point at specified address\n" | |
434 "p/print <reg or icount or value or *addr> -- print integer\n" | |
435 "pf/printfloat <freg or *addr> -- print float value\n" | |
436 "po/printobject <*reg or *addr> -- print object\n" | |
437 "si/stepi -- single step an instruction\n" | |
438 "trace -- toggle execution tracing mode\n" | |
439 "bt -- print backtrace\n" | |
440 "unstop -- if current pc is a stop instr make it a nop\n" | |
441 "q/quit -- Quit the debugger and exit the program\n"); | |
442 } else if ((strcmp(cmd, "quit") == 0) || (strcmp(cmd, "q") == 0)) { | |
443 OS::Print("Quitting\n"); | |
444 OS::Exit(0); | |
445 } else if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) { | |
446 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc())); | |
447 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) { | |
448 // Execute the one instruction we broke at with breakpoints disabled. | |
449 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc())); | |
450 // Leave the debugger shell. | |
451 done = true; | |
452 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) { | |
453 if (args == 2) { | |
454 uint32_t value; | |
455 if (strcmp(arg1, "icount") == 0) { | |
456 const uint64_t icount = sim_->get_icount(); | |
457 OS::Print("icount: %" Pu64 " 0x%" Px64 "\n", icount, icount); | |
458 } else if (GetValue(arg1, &value)) { | |
459 OS::Print("%s: %u 0x%x\n", arg1, value, value); | |
460 } else { | |
461 OS::Print("%s unrecognized\n", arg1); | |
462 } | |
463 } else { | |
464 OS::Print("print <reg or icount or value or *addr>\n"); | |
465 } | |
466 } else if ((strcmp(cmd, "pf") == 0) || (strcmp(cmd, "printfloat") == 0)) { | |
467 if (args == 2) { | |
468 double dvalue; | |
469 if (GetFValue(arg1, &dvalue)) { | |
470 uint64_t long_value = bit_cast<uint64_t, double>(dvalue); | |
471 OS::Print("%s: %llu 0x%llx %.8g\n", arg1, long_value, long_value, | |
472 dvalue); | |
473 } else { | |
474 OS::Print("%s unrecognized\n", arg1); | |
475 } | |
476 } else { | |
477 OS::Print("printfloat <dreg or *addr>\n"); | |
478 } | |
479 } else if ((strcmp(cmd, "pd") == 0) || | |
480 (strcmp(cmd, "printdouble") == 0)) { | |
481 if (args == 2) { | |
482 double dvalue; | |
483 if (GetDValue(arg1, &dvalue)) { | |
484 uint64_t long_value = bit_cast<uint64_t, double>(dvalue); | |
485 OS::Print("%s: %llu 0x%llx %.8g\n", arg1, long_value, long_value, | |
486 dvalue); | |
487 } else { | |
488 OS::Print("%s unrecognized\n", arg1); | |
489 } | |
490 } else { | |
491 OS::Print("printfloat <dreg or *addr>\n"); | |
492 } | |
493 } else if ((strcmp(cmd, "po") == 0) || | |
494 (strcmp(cmd, "printobject") == 0)) { | |
495 if (args == 2) { | |
496 uint32_t value; | |
497 // Make the dereferencing '*' optional. | |
498 if (((arg1[0] == '*') && GetValue(arg1 + 1, &value)) || | |
499 GetValue(arg1, &value)) { | |
500 if (Isolate::Current()->heap()->Contains(value)) { | |
501 OS::Print("%s: \n", arg1); | |
502 #if defined(DEBUG) | |
503 const Object& obj = | |
504 Object::Handle(reinterpret_cast<RawObject*>(value)); | |
505 obj.Print(); | |
506 #endif // defined(DEBUG) | |
507 } else { | |
508 OS::Print("0x%x is not an object reference\n", value); | |
509 } | |
510 } else { | |
511 OS::Print("%s unrecognized\n", arg1); | |
512 } | |
513 } else { | |
514 OS::Print("printobject <*reg or *addr>\n"); | |
515 } | |
516 } else if (strcmp(cmd, "disasm") == 0) { | |
517 uint32_t start = 0; | |
518 uint32_t end = 0; | |
519 if (args == 1) { | |
520 start = sim_->get_pc(); | |
521 end = start + (10 * Instr::kInstrSize); | |
522 } else if (args == 2) { | |
523 if (GetValue(arg1, &start)) { | |
524 // No length parameter passed, assume 10 instructions. | |
525 if (Simulator::IsIllegalAddress(start)) { | |
526 // If start isn't a valid address, warn and use PC instead. | |
527 OS::Print("First argument yields invalid address: 0x%x\n", start); | |
528 OS::Print("Using PC instead\n"); | |
529 start = sim_->get_pc(); | |
530 } | |
531 end = start + (10 * Instr::kInstrSize); | |
532 } | |
533 } else { | |
534 uint32_t length; | |
535 if (GetValue(arg1, &start) && GetValue(arg2, &length)) { | |
536 if (Simulator::IsIllegalAddress(start)) { | |
537 // If start isn't a valid address, warn and use PC instead. | |
538 OS::Print("First argument yields invalid address: 0x%x\n", start); | |
539 OS::Print("Using PC instead\n"); | |
540 start = sim_->get_pc(); | |
541 } | |
542 end = start + (length * Instr::kInstrSize); | |
543 } | |
544 } | |
545 if ((start > 0) && (end > start)) { | |
546 if (FLAG_support_disassembler) { | |
547 Disassembler::Disassemble(start, end); | |
548 } else { | |
549 OS::Print("Disassembler not supported in this mode.\n"); | |
550 } | |
551 } else { | |
552 OS::Print("disasm [<address> [<number_of_instructions>]]\n"); | |
553 } | |
554 } else if (strcmp(cmd, "gdb") == 0) { | |
555 OS::Print("relinquishing control to gdb\n"); | |
556 OS::DebugBreak(); | |
557 OS::Print("regaining control from gdb\n"); | |
558 } else if (strcmp(cmd, "break") == 0) { | |
559 if (args == 2) { | |
560 uint32_t addr; | |
561 if (GetValue(arg1, &addr)) { | |
562 if (!SetBreakpoint(reinterpret_cast<Instr*>(addr))) { | |
563 OS::Print("setting breakpoint failed\n"); | |
564 } | |
565 } else { | |
566 OS::Print("%s unrecognized\n", arg1); | |
567 } | |
568 } else { | |
569 OS::Print("break <addr>\n"); | |
570 } | |
571 } else if (strcmp(cmd, "del") == 0) { | |
572 if (!DeleteBreakpoint(NULL)) { | |
573 OS::Print("deleting breakpoint failed\n"); | |
574 } | |
575 } else if (strcmp(cmd, "unstop") == 0) { | |
576 intptr_t stop_pc = sim_->get_pc() - Instr::kInstrSize; | |
577 Instr* stop_instr = reinterpret_cast<Instr*>(stop_pc); | |
578 if (stop_instr->IsBreakPoint()) { | |
579 stop_instr->SetInstructionBits(Instr::kNopInstruction); | |
580 } else { | |
581 OS::Print("Not at debugger stop.\n"); | |
582 } | |
583 } else if (strcmp(cmd, "trace") == 0) { | |
584 if (FLAG_trace_sim_after == ULLONG_MAX) { | |
585 FLAG_trace_sim_after = sim_->get_icount(); | |
586 OS::Print("execution tracing on\n"); | |
587 } else { | |
588 FLAG_trace_sim_after = ULLONG_MAX; | |
589 OS::Print("execution tracing off\n"); | |
590 } | |
591 } else if (strcmp(cmd, "bt") == 0) { | |
592 PrintBacktrace(); | |
593 } else { | |
594 OS::Print("Unknown command: %s\n", cmd); | |
595 } | |
596 } | |
597 delete[] line; | |
598 } | |
599 | |
600 // Add all the breakpoints back to stop execution and enter the debugger | |
601 // shell when hit. | |
602 RedoBreakpoints(); | |
603 | |
604 #undef COMMAND_SIZE | |
605 #undef ARG_SIZE | |
606 | |
607 #undef STR | |
608 #undef XSTR | |
609 } | |
610 | |
611 | |
612 char* SimulatorDebugger::ReadLine(const char* prompt) { | |
613 char* result = NULL; | |
614 char line_buf[256]; | |
615 intptr_t offset = 0; | |
616 bool keep_going = true; | |
617 OS::Print("%s", prompt); | |
618 while (keep_going) { | |
619 if (fgets(line_buf, sizeof(line_buf), stdin) == NULL) { | |
620 // fgets got an error. Just give up. | |
621 if (result != NULL) { | |
622 delete[] result; | |
623 } | |
624 return NULL; | |
625 } | |
626 intptr_t len = strlen(line_buf); | |
627 if (len > 1 && line_buf[len - 2] == '\\' && line_buf[len - 1] == '\n') { | |
628 // When we read a line that ends with a "\" we remove the escape and | |
629 // append the remainder. | |
630 line_buf[len - 2] = '\n'; | |
631 line_buf[len - 1] = 0; | |
632 len -= 1; | |
633 } else if ((len > 0) && (line_buf[len - 1] == '\n')) { | |
634 // Since we read a new line we are done reading the line. This | |
635 // will exit the loop after copying this buffer into the result. | |
636 keep_going = false; | |
637 } | |
638 if (result == NULL) { | |
639 // Allocate the initial result and make room for the terminating '\0' | |
640 result = new char[len + 1]; | |
641 if (result == NULL) { | |
642 // OOM, so cannot readline anymore. | |
643 return NULL; | |
644 } | |
645 } else { | |
646 // Allocate a new result with enough room for the new addition. | |
647 intptr_t new_len = offset + len + 1; | |
648 char* new_result = new char[new_len]; | |
649 if (new_result == NULL) { | |
650 // OOM, free the buffer allocated so far and return NULL. | |
651 delete[] result; | |
652 return NULL; | |
653 } else { | |
654 // Copy the existing input into the new array and set the new | |
655 // array as the result. | |
656 memmove(new_result, result, offset); | |
657 delete[] result; | |
658 result = new_result; | |
659 } | |
660 } | |
661 // Copy the newly read line into the result. | |
662 memmove(result + offset, line_buf, len); | |
663 offset += len; | |
664 } | |
665 ASSERT(result != NULL); | |
666 result[offset] = '\0'; | |
667 return result; | |
668 } | |
669 | |
670 | |
671 // Synchronization primitives support. | |
672 Mutex* Simulator::exclusive_access_lock_ = NULL; | |
673 Simulator::AddressTag Simulator::exclusive_access_state_[kNumAddressTags] = { | |
674 {NULL, 0}}; | |
675 int Simulator::next_address_tag_ = 0; | |
676 | |
677 | |
678 void Simulator::InitOnce() { | |
679 // Setup exclusive access state lock. | |
680 exclusive_access_lock_ = new Mutex(); | |
681 } | |
682 | |
683 | |
684 Simulator::Simulator() { | |
685 // Setup simulator support first. Some of this information is needed to | |
686 // setup the architecture state. | |
687 // We allocate the stack here, the size is computed as the sum of | |
688 // the size specified by the user and the buffer space needed for | |
689 // handling stack overflow exceptions. To be safe in potential | |
690 // stack underflows we also add some underflow buffer space. | |
691 stack_ = | |
692 new char[(OSThread::GetSpecifiedStackSize() + OSThread::kStackSizeBuffer + | |
693 kSimulatorStackUnderflowSize)]; | |
694 icount_ = 0; | |
695 delay_slot_ = false; | |
696 break_pc_ = NULL; | |
697 break_instr_ = 0; | |
698 last_setjmp_buffer_ = NULL; | |
699 top_exit_frame_info_ = 0; | |
700 | |
701 // Setup architecture state. | |
702 // All registers are initialized to zero to start with. | |
703 for (int i = 0; i < kNumberOfCpuRegisters; i++) { | |
704 registers_[i] = 0; | |
705 } | |
706 pc_ = 0; | |
707 // The sp is initialized to point to the bottom (high address) of the | |
708 // allocated stack area. | |
709 registers_[SP] = StackTop(); | |
710 | |
711 // All double-precision registers are initialized to zero. | |
712 for (int i = 0; i < kNumberOfFRegisters; i++) { | |
713 fregisters_[i] = 0.0; | |
714 } | |
715 fcsr_ = 0; | |
716 } | |
717 | |
718 | |
719 Simulator::~Simulator() { | |
720 delete[] stack_; | |
721 Isolate* isolate = Isolate::Current(); | |
722 if (isolate != NULL) { | |
723 isolate->set_simulator(NULL); | |
724 } | |
725 } | |
726 | |
727 | |
728 // When the generated code calls an external reference we need to catch that in | |
729 // the simulator. The external reference will be a function compiled for the | |
730 // host architecture. We need to call that function instead of trying to | |
731 // execute it with the simulator. We do that by redirecting the external | |
732 // reference to a break instruction with code 2 that is handled by | |
733 // the simulator. We write the original destination of the jump just at a known | |
734 // offset from the break instruction so the simulator knows what to call. | |
735 class Redirection { | |
736 public: | |
737 uword address_of_break_instruction() { | |
738 return reinterpret_cast<uword>(&break_instruction_); | |
739 } | |
740 | |
741 uword external_function() const { return external_function_; } | |
742 | |
743 Simulator::CallKind call_kind() const { return call_kind_; } | |
744 | |
745 int argument_count() const { return argument_count_; } | |
746 | |
747 static Redirection* Get(uword external_function, | |
748 Simulator::CallKind call_kind, | |
749 int argument_count) { | |
750 Redirection* current; | |
751 for (current = list_; current != NULL; current = current->next_) { | |
752 if (current->external_function_ == external_function) return current; | |
753 } | |
754 return new Redirection(external_function, call_kind, argument_count); | |
755 } | |
756 | |
757 static Redirection* FromBreakInstruction(Instr* break_instruction) { | |
758 char* addr_of_break = reinterpret_cast<char*>(break_instruction); | |
759 char* addr_of_redirection = | |
760 addr_of_break - OFFSET_OF(Redirection, break_instruction_); | |
761 return reinterpret_cast<Redirection*>(addr_of_redirection); | |
762 } | |
763 | |
764 static uword FunctionForRedirect(uword address_of_break) { | |
765 Redirection* current; | |
766 for (current = list_; current != NULL; current = current->next_) { | |
767 if (current->address_of_break_instruction() == address_of_break) { | |
768 return current->external_function_; | |
769 } | |
770 } | |
771 return 0; | |
772 } | |
773 | |
774 private: | |
775 Redirection(uword external_function, | |
776 Simulator::CallKind call_kind, | |
777 int argument_count) | |
778 : external_function_(external_function), | |
779 call_kind_(call_kind), | |
780 argument_count_(argument_count), | |
781 break_instruction_(Instr::kSimulatorRedirectInstruction), | |
782 next_(list_) { | |
783 // Atomically prepend this element to the front of the global list. | |
784 // Note: Since elements are never removed, there is no ABA issue. | |
785 Redirection* list_head = list_; | |
786 do { | |
787 next_ = list_head; | |
788 list_head = | |
789 reinterpret_cast<Redirection*>(AtomicOperations::CompareAndSwapWord( | |
790 reinterpret_cast<uword*>(&list_), reinterpret_cast<uword>(next_), | |
791 reinterpret_cast<uword>(this))); | |
792 } while (list_head != next_); | |
793 } | |
794 | |
795 uword external_function_; | |
796 Simulator::CallKind call_kind_; | |
797 int argument_count_; | |
798 uint32_t break_instruction_; | |
799 Redirection* next_; | |
800 static Redirection* list_; | |
801 }; | |
802 | |
803 | |
804 Redirection* Redirection::list_ = NULL; | |
805 | |
806 | |
807 uword Simulator::RedirectExternalReference(uword function, | |
808 CallKind call_kind, | |
809 int argument_count) { | |
810 Redirection* redirection = | |
811 Redirection::Get(function, call_kind, argument_count); | |
812 return redirection->address_of_break_instruction(); | |
813 } | |
814 | |
815 | |
816 uword Simulator::FunctionForRedirect(uword redirect) { | |
817 return Redirection::FunctionForRedirect(redirect); | |
818 } | |
819 | |
820 | |
821 // Get the active Simulator for the current isolate. | |
822 Simulator* Simulator::Current() { | |
823 Simulator* simulator = Isolate::Current()->simulator(); | |
824 if (simulator == NULL) { | |
825 simulator = new Simulator(); | |
826 Isolate::Current()->set_simulator(simulator); | |
827 } | |
828 return simulator; | |
829 } | |
830 | |
831 | |
832 // Sets the register in the architecture state. | |
833 void Simulator::set_register(Register reg, int32_t value) { | |
834 if (reg != R0) { | |
835 registers_[reg] = value; | |
836 } | |
837 } | |
838 | |
839 | |
840 void Simulator::set_fregister(FRegister reg, int32_t value) { | |
841 ASSERT(reg >= 0); | |
842 ASSERT(reg < kNumberOfFRegisters); | |
843 fregisters_[reg] = value; | |
844 } | |
845 | |
846 | |
847 void Simulator::set_fregister_float(FRegister reg, float value) { | |
848 ASSERT(reg >= 0); | |
849 ASSERT(reg < kNumberOfFRegisters); | |
850 fregisters_[reg] = bit_cast<int32_t, float>(value); | |
851 } | |
852 | |
853 | |
854 void Simulator::set_fregister_long(FRegister reg, int64_t value) { | |
855 ASSERT(reg >= 0); | |
856 ASSERT(reg < kNumberOfFRegisters); | |
857 ASSERT((reg & 1) == 0); | |
858 fregisters_[reg] = Utils::Low32Bits(value); | |
859 fregisters_[reg + 1] = Utils::High32Bits(value); | |
860 } | |
861 | |
862 | |
863 void Simulator::set_fregister_double(FRegister reg, double value) { | |
864 const int64_t ival = bit_cast<int64_t, double>(value); | |
865 set_fregister_long(reg, ival); | |
866 } | |
867 | |
868 | |
869 void Simulator::set_dregister_bits(DRegister reg, int64_t value) { | |
870 ASSERT(reg >= 0); | |
871 ASSERT(reg < kNumberOfDRegisters); | |
872 FRegister lo = static_cast<FRegister>(reg * 2); | |
873 FRegister hi = static_cast<FRegister>((reg * 2) + 1); | |
874 set_fregister(lo, Utils::Low32Bits(value)); | |
875 set_fregister(hi, Utils::High32Bits(value)); | |
876 } | |
877 | |
878 | |
879 void Simulator::set_dregister(DRegister reg, double value) { | |
880 ASSERT(reg >= 0); | |
881 ASSERT(reg < kNumberOfDRegisters); | |
882 set_dregister_bits(reg, bit_cast<int64_t, double>(value)); | |
883 } | |
884 | |
885 | |
886 // Get the register from the architecture state. | |
887 int32_t Simulator::get_register(Register reg) const { | |
888 if (reg == R0) { | |
889 return 0; | |
890 } | |
891 return registers_[reg]; | |
892 } | |
893 | |
894 | |
895 int32_t Simulator::get_fregister(FRegister reg) const { | |
896 ASSERT((reg >= 0) && (reg < kNumberOfFRegisters)); | |
897 return fregisters_[reg]; | |
898 } | |
899 | |
900 | |
901 float Simulator::get_fregister_float(FRegister reg) const { | |
902 ASSERT(reg >= 0); | |
903 ASSERT(reg < kNumberOfFRegisters); | |
904 return bit_cast<float, int32_t>(fregisters_[reg]); | |
905 } | |
906 | |
907 | |
908 int64_t Simulator::get_fregister_long(FRegister reg) const { | |
909 ASSERT(reg >= 0); | |
910 ASSERT(reg < kNumberOfFRegisters); | |
911 ASSERT((reg & 1) == 0); | |
912 const int32_t low = fregisters_[reg]; | |
913 const int32_t high = fregisters_[reg + 1]; | |
914 const int64_t value = Utils::LowHighTo64Bits(low, high); | |
915 return value; | |
916 } | |
917 | |
918 | |
919 double Simulator::get_fregister_double(FRegister reg) const { | |
920 ASSERT(reg >= 0); | |
921 ASSERT(reg < kNumberOfFRegisters); | |
922 ASSERT((reg & 1) == 0); | |
923 const int64_t value = get_fregister_long(reg); | |
924 return bit_cast<double, int64_t>(value); | |
925 } | |
926 | |
927 | |
928 int64_t Simulator::get_dregister_bits(DRegister reg) const { | |
929 ASSERT(reg >= 0); | |
930 ASSERT(reg < kNumberOfDRegisters); | |
931 FRegister lo = static_cast<FRegister>(reg * 2); | |
932 FRegister hi = static_cast<FRegister>((reg * 2) + 1); | |
933 return Utils::LowHighTo64Bits(get_fregister(lo), get_fregister(hi)); | |
934 } | |
935 | |
936 | |
937 double Simulator::get_dregister(DRegister reg) const { | |
938 ASSERT(reg >= 0); | |
939 ASSERT(reg < kNumberOfDRegisters); | |
940 const int64_t value = get_dregister_bits(reg); | |
941 return bit_cast<double, int64_t>(value); | |
942 } | |
943 | |
944 | |
945 void Simulator::UnimplementedInstruction(Instr* instr) { | |
946 char buffer[64]; | |
947 snprintf(buffer, sizeof(buffer), "Unimplemented instruction: pc=%p\n", instr); | |
948 SimulatorDebugger dbg(this); | |
949 dbg.Stop(instr, buffer); | |
950 FATAL("Cannot continue execution after unimplemented instruction."); | |
951 } | |
952 | |
953 | |
954 void Simulator::HandleIllegalAccess(uword addr, Instr* instr) { | |
955 uword fault_pc = get_pc(); | |
956 // The debugger will not be able to single step past this instruction, but | |
957 // it will be possible to disassemble the code and inspect registers. | |
958 char buffer[128]; | |
959 snprintf(buffer, sizeof(buffer), | |
960 "illegal memory access at 0x%" Px ", pc=0x%" Px "\n", addr, | |
961 fault_pc); | |
962 SimulatorDebugger dbg(this); | |
963 dbg.Stop(instr, buffer); | |
964 // The debugger will return control in non-interactive mode. | |
965 FATAL("Cannot continue execution after illegal memory access."); | |
966 } | |
967 | |
968 | |
969 void Simulator::UnalignedAccess(const char* msg, uword addr, Instr* instr) { | |
970 // The debugger will not be able to single step past this instruction, but | |
971 // it will be possible to disassemble the code and inspect registers. | |
972 char buffer[128]; | |
973 snprintf(buffer, sizeof(buffer), "pc=%p, unaligned %s at 0x%" Px "\n", instr, | |
974 msg, addr); | |
975 SimulatorDebugger dbg(this); | |
976 dbg.Stop(instr, buffer); | |
977 // The debugger will return control in non-interactive mode. | |
978 FATAL("Cannot continue execution after unaligned access."); | |
979 } | |
980 | |
981 | |
982 // Returns the top of the stack area to enable checking for stack pointer | |
983 // validity. | |
984 uword Simulator::StackTop() const { | |
985 // To be safe in potential stack underflows we leave some buffer above and | |
986 // set the stack top. | |
987 return StackBase() + | |
988 (OSThread::GetSpecifiedStackSize() + OSThread::kStackSizeBuffer); | |
989 } | |
990 | |
991 | |
992 bool Simulator::IsTracingExecution() const { | |
993 return icount_ > FLAG_trace_sim_after; | |
994 } | |
995 | |
996 | |
997 void Simulator::Format(Instr* instr, const char* format) { | |
998 OS::PrintErr("Simulator - unknown instruction: %s\n", format); | |
999 UNIMPLEMENTED(); | |
1000 } | |
1001 | |
1002 | |
1003 int8_t Simulator::ReadB(uword addr) { | |
1004 int8_t* ptr = reinterpret_cast<int8_t*>(addr); | |
1005 return *ptr; | |
1006 } | |
1007 | |
1008 | |
1009 uint8_t Simulator::ReadBU(uword addr) { | |
1010 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); | |
1011 return *ptr; | |
1012 } | |
1013 | |
1014 | |
1015 int16_t Simulator::ReadH(uword addr, Instr* instr) { | |
1016 if ((addr & 1) == 0) { | |
1017 int16_t* ptr = reinterpret_cast<int16_t*>(addr); | |
1018 return *ptr; | |
1019 } | |
1020 UnalignedAccess("signed halfword read", addr, instr); | |
1021 return 0; | |
1022 } | |
1023 | |
1024 | |
1025 uint16_t Simulator::ReadHU(uword addr, Instr* instr) { | |
1026 if ((addr & 1) == 0) { | |
1027 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); | |
1028 return *ptr; | |
1029 } | |
1030 UnalignedAccess("unsigned halfword read", addr, instr); | |
1031 return 0; | |
1032 } | |
1033 | |
1034 | |
1035 intptr_t Simulator::ReadW(uword addr, Instr* instr) { | |
1036 if ((addr & 3) == 0) { | |
1037 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); | |
1038 return *ptr; | |
1039 } | |
1040 UnalignedAccess("read", addr, instr); | |
1041 return 0; | |
1042 } | |
1043 | |
1044 | |
1045 void Simulator::WriteB(uword addr, uint8_t value) { | |
1046 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); | |
1047 *ptr = value; | |
1048 } | |
1049 | |
1050 | |
1051 void Simulator::WriteH(uword addr, uint16_t value, Instr* instr) { | |
1052 if ((addr & 1) == 0) { | |
1053 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); | |
1054 *ptr = value; | |
1055 return; | |
1056 } | |
1057 UnalignedAccess("halfword write", addr, instr); | |
1058 } | |
1059 | |
1060 | |
1061 void Simulator::WriteW(uword addr, intptr_t value, Instr* instr) { | |
1062 if ((addr & 3) == 0) { | |
1063 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); | |
1064 *ptr = value; | |
1065 return; | |
1066 } | |
1067 UnalignedAccess("write", addr, instr); | |
1068 } | |
1069 | |
1070 | |
1071 double Simulator::ReadD(uword addr, Instr* instr) { | |
1072 if ((addr & 7) == 0) { | |
1073 double* ptr = reinterpret_cast<double*>(addr); | |
1074 return *ptr; | |
1075 } | |
1076 UnalignedAccess("double-precision floating point read", addr, instr); | |
1077 return 0.0; | |
1078 } | |
1079 | |
1080 | |
1081 void Simulator::WriteD(uword addr, double value, Instr* instr) { | |
1082 if ((addr & 7) == 0) { | |
1083 double* ptr = reinterpret_cast<double*>(addr); | |
1084 *ptr = value; | |
1085 return; | |
1086 } | |
1087 UnalignedAccess("double-precision floating point write", addr, instr); | |
1088 } | |
1089 | |
1090 | |
1091 // Synchronization primitives support. | |
1092 void Simulator::SetExclusiveAccess(uword addr) { | |
1093 Thread* thread = Thread::Current(); | |
1094 ASSERT(thread != NULL); | |
1095 DEBUG_ASSERT(exclusive_access_lock_->IsOwnedByCurrentThread()); | |
1096 int i = 0; | |
1097 // Find an entry for this thread in the exclusive access state. | |
1098 while ((i < kNumAddressTags) && | |
1099 (exclusive_access_state_[i].thread != thread)) { | |
1100 i++; | |
1101 } | |
1102 // Round-robin replacement of previously used entries. | |
1103 if (i == kNumAddressTags) { | |
1104 i = next_address_tag_; | |
1105 if (++next_address_tag_ == kNumAddressTags) { | |
1106 next_address_tag_ = 0; | |
1107 } | |
1108 exclusive_access_state_[i].thread = thread; | |
1109 } | |
1110 // Remember the address being reserved. | |
1111 exclusive_access_state_[i].addr = addr; | |
1112 } | |
1113 | |
1114 | |
1115 bool Simulator::HasExclusiveAccessAndOpen(uword addr) { | |
1116 Thread* thread = Thread::Current(); | |
1117 ASSERT(thread != NULL); | |
1118 ASSERT(addr != 0); | |
1119 DEBUG_ASSERT(exclusive_access_lock_->IsOwnedByCurrentThread()); | |
1120 bool result = false; | |
1121 for (int i = 0; i < kNumAddressTags; i++) { | |
1122 if (exclusive_access_state_[i].thread == thread) { | |
1123 // Check whether the current thread's address reservation matches. | |
1124 if (exclusive_access_state_[i].addr == addr) { | |
1125 result = true; | |
1126 } | |
1127 exclusive_access_state_[i].addr = 0; | |
1128 } else if (exclusive_access_state_[i].addr == addr) { | |
1129 // Other threads with matching address lose their reservations. | |
1130 exclusive_access_state_[i].addr = 0; | |
1131 } | |
1132 } | |
1133 return result; | |
1134 } | |
1135 | |
1136 | |
1137 void Simulator::ClearExclusive() { | |
1138 MutexLocker ml(exclusive_access_lock_); | |
1139 // Remove the reservation for this thread. | |
1140 SetExclusiveAccess(0); | |
1141 } | |
1142 | |
1143 | |
1144 intptr_t Simulator::ReadExclusiveW(uword addr, Instr* instr) { | |
1145 MutexLocker ml(exclusive_access_lock_); | |
1146 SetExclusiveAccess(addr); | |
1147 return ReadW(addr, instr); | |
1148 } | |
1149 | |
1150 | |
1151 intptr_t Simulator::WriteExclusiveW(uword addr, intptr_t value, Instr* instr) { | |
1152 MutexLocker ml(exclusive_access_lock_); | |
1153 bool write_allowed = HasExclusiveAccessAndOpen(addr); | |
1154 if (write_allowed) { | |
1155 WriteW(addr, value, instr); | |
1156 return 1; // Success. | |
1157 } | |
1158 return 0; // Failure. | |
1159 } | |
1160 | |
1161 | |
1162 uword Simulator::CompareExchange(uword* address, | |
1163 uword compare_value, | |
1164 uword new_value) { | |
1165 MutexLocker ml(exclusive_access_lock_); | |
1166 // We do not get a reservation as it would be guaranteed to be found when | |
1167 // writing below. No other thread is able to make a reservation while we | |
1168 // hold the lock. | |
1169 uword value = *address; | |
1170 if (value == compare_value) { | |
1171 *address = new_value; | |
1172 // Same effect on exclusive access state as a successful SC. | |
1173 HasExclusiveAccessAndOpen(reinterpret_cast<uword>(address)); | |
1174 } else { | |
1175 // Same effect on exclusive access state as an LL. | |
1176 SetExclusiveAccess(reinterpret_cast<uword>(address)); | |
1177 } | |
1178 return value; | |
1179 } | |
1180 | |
1181 | |
1182 uint32_t Simulator::CompareExchangeUint32(uint32_t* address, | |
1183 uint32_t compare_value, | |
1184 uint32_t new_value) { | |
1185 COMPILE_ASSERT(sizeof(uword) == sizeof(uint32_t)); | |
1186 return CompareExchange(reinterpret_cast<uword*>(address), | |
1187 static_cast<uword>(compare_value), | |
1188 static_cast<uword>(new_value)); | |
1189 } | |
1190 | |
1191 | |
1192 // Calls into the Dart runtime are based on this interface. | |
1193 typedef void (*SimulatorRuntimeCall)(NativeArguments arguments); | |
1194 | |
1195 // Calls to leaf Dart runtime functions are based on this interface. | |
1196 typedef int32_t (*SimulatorLeafRuntimeCall)(int32_t r0, | |
1197 int32_t r1, | |
1198 int32_t r2, | |
1199 int32_t r3); | |
1200 | |
1201 // Calls to leaf float Dart runtime functions are based on this interface. | |
1202 typedef double (*SimulatorLeafFloatRuntimeCall)(double d0, double d1); | |
1203 | |
1204 // Calls to native Dart functions are based on this interface. | |
1205 typedef void (*SimulatorBootstrapNativeCall)(NativeArguments* arguments); | |
1206 typedef void (*SimulatorNativeCall)(NativeArguments* arguments, uword target); | |
1207 | |
1208 | |
1209 void Simulator::DoBreak(Instr* instr) { | |
1210 ASSERT(instr->OpcodeField() == SPECIAL); | |
1211 ASSERT(instr->FunctionField() == BREAK); | |
1212 if (instr->BreakCodeField() == Instr::kStopMessageCode) { | |
1213 SimulatorDebugger dbg(this); | |
1214 const char* message = *reinterpret_cast<const char**>( | |
1215 reinterpret_cast<intptr_t>(instr) - Instr::kInstrSize); | |
1216 set_pc(get_pc() + Instr::kInstrSize); | |
1217 dbg.Stop(instr, message); | |
1218 // Adjust for extra pc increment. | |
1219 set_pc(get_pc() - Instr::kInstrSize); | |
1220 } else if (instr->BreakCodeField() == Instr::kSimulatorRedirectCode) { | |
1221 SimulatorSetjmpBuffer buffer(this); | |
1222 | |
1223 if (!setjmp(buffer.buffer_)) { | |
1224 int32_t saved_ra = get_register(RA); | |
1225 Redirection* redirection = Redirection::FromBreakInstruction(instr); | |
1226 uword external = redirection->external_function(); | |
1227 if (IsTracingExecution()) { | |
1228 THR_Print("Call to host function at 0x%" Pd "\n", external); | |
1229 } | |
1230 | |
1231 if ((redirection->call_kind() == kRuntimeCall) || | |
1232 (redirection->call_kind() == kBootstrapNativeCall) || | |
1233 (redirection->call_kind() == kNativeCall)) { | |
1234 // Set the top_exit_frame_info of this simulator to the native stack. | |
1235 set_top_exit_frame_info(Thread::GetCurrentStackPointer()); | |
1236 } | |
1237 if (redirection->call_kind() == kRuntimeCall) { | |
1238 NativeArguments arguments; | |
1239 ASSERT(sizeof(NativeArguments) == 4 * kWordSize); | |
1240 arguments.thread_ = reinterpret_cast<Thread*>(get_register(A0)); | |
1241 arguments.argc_tag_ = get_register(A1); | |
1242 arguments.argv_ = reinterpret_cast<RawObject**>(get_register(A2)); | |
1243 arguments.retval_ = reinterpret_cast<RawObject**>(get_register(A3)); | |
1244 SimulatorRuntimeCall target = | |
1245 reinterpret_cast<SimulatorRuntimeCall>(external); | |
1246 target(arguments); | |
1247 set_register(V0, icount_); // Zap result registers from void function. | |
1248 set_register(V1, icount_); | |
1249 } else if (redirection->call_kind() == kLeafRuntimeCall) { | |
1250 int32_t a0 = get_register(A0); | |
1251 int32_t a1 = get_register(A1); | |
1252 int32_t a2 = get_register(A2); | |
1253 int32_t a3 = get_register(A3); | |
1254 SimulatorLeafRuntimeCall target = | |
1255 reinterpret_cast<SimulatorLeafRuntimeCall>(external); | |
1256 a0 = target(a0, a1, a2, a3); | |
1257 set_register(V0, a0); // Set returned result from function. | |
1258 set_register(V1, icount_); // Zap second result register. | |
1259 } else if (redirection->call_kind() == kLeafFloatRuntimeCall) { | |
1260 ASSERT((0 <= redirection->argument_count()) && | |
1261 (redirection->argument_count() <= 2)); | |
1262 // double values are passed and returned in floating point registers. | |
1263 SimulatorLeafFloatRuntimeCall target = | |
1264 reinterpret_cast<SimulatorLeafFloatRuntimeCall>(external); | |
1265 double d0 = 0.0; | |
1266 double d6 = get_fregister_double(F12); | |
1267 double d7 = get_fregister_double(F14); | |
1268 d0 = target(d6, d7); | |
1269 set_fregister_double(F0, d0); | |
1270 } else if (redirection->call_kind() == kBootstrapNativeCall) { | |
1271 ASSERT(redirection->argument_count() == 1); | |
1272 NativeArguments* arguments; | |
1273 arguments = reinterpret_cast<NativeArguments*>(get_register(A0)); | |
1274 SimulatorBootstrapNativeCall target = | |
1275 reinterpret_cast<SimulatorBootstrapNativeCall>(external); | |
1276 target(arguments); | |
1277 set_register(V0, icount_); // Zap result register from void function. | |
1278 set_register(V1, icount_); | |
1279 } else { | |
1280 ASSERT(redirection->call_kind() == kNativeCall); | |
1281 NativeArguments* arguments; | |
1282 arguments = reinterpret_cast<NativeArguments*>(get_register(A0)); | |
1283 uword target_func = get_register(A1); | |
1284 SimulatorNativeCall target = | |
1285 reinterpret_cast<SimulatorNativeCall>(external); | |
1286 target(arguments, target_func); | |
1287 set_register(V0, icount_); // Zap result register from void function. | |
1288 set_register(V1, icount_); | |
1289 } | |
1290 set_top_exit_frame_info(0); | |
1291 | |
1292 // Zap caller-saved registers, since the actual runtime call could have | |
1293 // used them. | |
1294 set_register(T0, icount_); | |
1295 set_register(T1, icount_); | |
1296 set_register(T2, icount_); | |
1297 set_register(T3, icount_); | |
1298 set_register(T4, icount_); | |
1299 set_register(T5, icount_); | |
1300 set_register(T6, icount_); | |
1301 set_register(T7, icount_); | |
1302 set_register(T8, icount_); | |
1303 set_register(T9, icount_); | |
1304 | |
1305 set_register(A0, icount_); | |
1306 set_register(A1, icount_); | |
1307 set_register(A2, icount_); | |
1308 set_register(A3, icount_); | |
1309 set_register(TMP, icount_); | |
1310 set_register(RA, icount_); | |
1311 | |
1312 // Zap floating point registers. | |
1313 int32_t zap_dvalue = icount_; | |
1314 for (int i = F4; i <= F18; i++) { | |
1315 set_fregister(static_cast<FRegister>(i), zap_dvalue); | |
1316 } | |
1317 | |
1318 // Return. Subtract to account for pc_ increment after return. | |
1319 set_pc(saved_ra - Instr::kInstrSize); | |
1320 } else { | |
1321 // Coming via long jump from a throw. Continue to exception handler. | |
1322 set_top_exit_frame_info(0); | |
1323 // Adjust for extra pc increment. | |
1324 set_pc(get_pc() - Instr::kInstrSize); | |
1325 } | |
1326 } else if (instr->BreakCodeField() == Instr::kSimulatorBreakCode) { | |
1327 SimulatorDebugger dbg(this); | |
1328 dbg.Stop(instr, "breakpoint"); | |
1329 // Adjust for extra pc increment. | |
1330 set_pc(get_pc() - Instr::kInstrSize); | |
1331 } else { | |
1332 SimulatorDebugger dbg(this); | |
1333 set_pc(get_pc() + Instr::kInstrSize); | |
1334 char buffer[32]; | |
1335 snprintf(buffer, sizeof(buffer), "break #0x%x", instr->BreakCodeField()); | |
1336 dbg.Stop(instr, buffer); | |
1337 // Adjust for extra pc increment. | |
1338 set_pc(get_pc() - Instr::kInstrSize); | |
1339 } | |
1340 } | |
1341 | |
1342 | |
1343 void Simulator::DecodeSpecial(Instr* instr) { | |
1344 ASSERT(instr->OpcodeField() == SPECIAL); | |
1345 switch (instr->FunctionField()) { | |
1346 case ADDU: { | |
1347 ASSERT(instr->SaField() == 0); | |
1348 // Format(instr, "addu 'rd, 'rs, 'rt"); | |
1349 int32_t rs_val = get_register(instr->RsField()); | |
1350 int32_t rt_val = get_register(instr->RtField()); | |
1351 set_register(instr->RdField(), rs_val + rt_val); | |
1352 break; | |
1353 } | |
1354 case AND: { | |
1355 ASSERT(instr->SaField() == 0); | |
1356 // Format(instr, "and 'rd, 'rs, 'rt"); | |
1357 int32_t rs_val = get_register(instr->RsField()); | |
1358 int32_t rt_val = get_register(instr->RtField()); | |
1359 set_register(instr->RdField(), rs_val & rt_val); | |
1360 break; | |
1361 } | |
1362 case BREAK: { | |
1363 DoBreak(instr); | |
1364 break; | |
1365 } | |
1366 case DIV: { | |
1367 ASSERT(instr->RdField() == 0); | |
1368 ASSERT(instr->SaField() == 0); | |
1369 // Format(instr, "div 'rs, 'rt"); | |
1370 int32_t rs_val = get_register(instr->RsField()); | |
1371 int32_t rt_val = get_register(instr->RtField()); | |
1372 if (rt_val == 0) { | |
1373 // Results are unpredictable, but there is no arithmetic exception. | |
1374 set_hi_register(icount_); | |
1375 set_lo_register(icount_); | |
1376 break; | |
1377 } | |
1378 | |
1379 if ((rs_val == static_cast<int32_t>(0x80000000)) && | |
1380 (rt_val == static_cast<int32_t>(0xffffffff))) { | |
1381 set_lo_register(0x80000000); | |
1382 set_hi_register(0); | |
1383 } else { | |
1384 set_lo_register(rs_val / rt_val); | |
1385 set_hi_register(rs_val % rt_val); | |
1386 } | |
1387 break; | |
1388 } | |
1389 case DIVU: { | |
1390 ASSERT(instr->RdField() == 0); | |
1391 ASSERT(instr->SaField() == 0); | |
1392 // Format(instr, "divu 'rs, 'rt"); | |
1393 uint32_t rs_val = get_register(instr->RsField()); | |
1394 uint32_t rt_val = get_register(instr->RtField()); | |
1395 if (rt_val == 0) { | |
1396 // Results are unpredictable, but there is no arithmetic exception. | |
1397 set_hi_register(icount_); | |
1398 set_lo_register(icount_); | |
1399 break; | |
1400 } | |
1401 set_lo_register(rs_val / rt_val); | |
1402 set_hi_register(rs_val % rt_val); | |
1403 break; | |
1404 } | |
1405 case JALR: { | |
1406 ASSERT(instr->RtField() == R0); | |
1407 ASSERT(instr->RsField() != instr->RdField()); | |
1408 ASSERT(!delay_slot_); | |
1409 // Format(instr, "jalr'hint 'rd, rs"); | |
1410 set_register(instr->RdField(), pc_ + 2 * Instr::kInstrSize); | |
1411 uword next_pc = get_register(instr->RsField()); | |
1412 ExecuteDelaySlot(); | |
1413 // Set return address to be the instruction after the delay slot. | |
1414 pc_ = next_pc - Instr::kInstrSize; // Account for regular PC increment. | |
1415 break; | |
1416 } | |
1417 case JR: { | |
1418 ASSERT(instr->RtField() == R0); | |
1419 ASSERT(instr->RdField() == R0); | |
1420 ASSERT(!delay_slot_); | |
1421 // Format(instr, "jr'hint 'rs"); | |
1422 uword next_pc = get_register(instr->RsField()); | |
1423 ExecuteDelaySlot(); | |
1424 pc_ = next_pc - Instr::kInstrSize; // Account for regular PC increment. | |
1425 break; | |
1426 } | |
1427 case MFHI: { | |
1428 ASSERT(instr->RsField() == 0); | |
1429 ASSERT(instr->RtField() == 0); | |
1430 ASSERT(instr->SaField() == 0); | |
1431 // Format(instr, "mfhi 'rd"); | |
1432 set_register(instr->RdField(), get_hi_register()); | |
1433 break; | |
1434 } | |
1435 case MFLO: { | |
1436 ASSERT(instr->RsField() == 0); | |
1437 ASSERT(instr->RtField() == 0); | |
1438 ASSERT(instr->SaField() == 0); | |
1439 // Format(instr, "mflo 'rd"); | |
1440 set_register(instr->RdField(), get_lo_register()); | |
1441 break; | |
1442 } | |
1443 case MOVCI: { | |
1444 ASSERT(instr->SaField() == 0); | |
1445 ASSERT(instr->Bit(17) == 0); | |
1446 int32_t rs_val = get_register(instr->RsField()); | |
1447 uint32_t cc, fcsr_cc, test, status; | |
1448 cc = instr->Bits(18, 3); | |
1449 fcsr_cc = get_fcsr_condition_bit(cc); | |
1450 test = instr->Bit(16); | |
1451 status = test_fcsr_bit(fcsr_cc); | |
1452 if (test == status) { | |
1453 set_register(instr->RdField(), rs_val); | |
1454 } | |
1455 break; | |
1456 } | |
1457 case MOVN: { | |
1458 ASSERT(instr->SaField() == 0); | |
1459 // Format(instr, "movn 'rd, 'rs, 'rt"); | |
1460 int32_t rt_val = get_register(instr->RtField()); | |
1461 int32_t rs_val = get_register(instr->RsField()); | |
1462 if (rt_val != 0) { | |
1463 set_register(instr->RdField(), rs_val); | |
1464 } | |
1465 break; | |
1466 } | |
1467 case MOVZ: { | |
1468 ASSERT(instr->SaField() == 0); | |
1469 // Format(instr, "movz 'rd, 'rs, 'rt"); | |
1470 int32_t rt_val = get_register(instr->RtField()); | |
1471 int32_t rs_val = get_register(instr->RsField()); | |
1472 if (rt_val == 0) { | |
1473 set_register(instr->RdField(), rs_val); | |
1474 } | |
1475 break; | |
1476 } | |
1477 case MTHI: { | |
1478 ASSERT(instr->RtField() == 0); | |
1479 ASSERT(instr->RdField() == 0); | |
1480 ASSERT(instr->SaField() == 0); | |
1481 // Format(instr, "mthi 'rd"); | |
1482 set_hi_register(get_register(instr->RsField())); | |
1483 break; | |
1484 } | |
1485 case MTLO: { | |
1486 ASSERT(instr->RtField() == 0); | |
1487 ASSERT(instr->RdField() == 0); | |
1488 ASSERT(instr->SaField() == 0); | |
1489 // Format(instr, "mflo 'rd"); | |
1490 set_lo_register(get_register(instr->RsField())); | |
1491 break; | |
1492 } | |
1493 case MULT: { | |
1494 ASSERT(instr->RdField() == 0); | |
1495 ASSERT(instr->SaField() == 0); | |
1496 // Format(instr, "mult 'rs, 'rt"); | |
1497 int64_t rs = get_register(instr->RsField()); | |
1498 int64_t rt = get_register(instr->RtField()); | |
1499 int64_t res = rs * rt; | |
1500 set_hi_register(Utils::High32Bits(res)); | |
1501 set_lo_register(Utils::Low32Bits(res)); | |
1502 break; | |
1503 } | |
1504 case MULTU: { | |
1505 ASSERT(instr->RdField() == 0); | |
1506 ASSERT(instr->SaField() == 0); | |
1507 // Format(instr, "multu 'rs, 'rt"); | |
1508 uint64_t rs = static_cast<uint32_t>(get_register(instr->RsField())); | |
1509 uint64_t rt = static_cast<uint32_t>(get_register(instr->RtField())); | |
1510 uint64_t res = rs * rt; | |
1511 set_hi_register(Utils::High32Bits(res)); | |
1512 set_lo_register(Utils::Low32Bits(res)); | |
1513 break; | |
1514 } | |
1515 case NOR: { | |
1516 ASSERT(instr->SaField() == 0); | |
1517 // Format(instr, "nor 'rd, 'rs, 'rt"); | |
1518 int32_t rs_val = get_register(instr->RsField()); | |
1519 int32_t rt_val = get_register(instr->RtField()); | |
1520 set_register(instr->RdField(), ~(rs_val | rt_val)); | |
1521 break; | |
1522 } | |
1523 case OR: { | |
1524 ASSERT(instr->SaField() == 0); | |
1525 // Format(instr, "or 'rd, 'rs, 'rt"); | |
1526 int32_t rs_val = get_register(instr->RsField()); | |
1527 int32_t rt_val = get_register(instr->RtField()); | |
1528 set_register(instr->RdField(), rs_val | rt_val); | |
1529 break; | |
1530 } | |
1531 case SLL: { | |
1532 ASSERT(instr->RsField() == 0); | |
1533 if ((instr->RdField() == R0) && (instr->RtField() == R0) && | |
1534 (instr->SaField() == 0)) { | |
1535 // Format(instr, "nop"); | |
1536 // Nothing to be done for NOP. | |
1537 } else { | |
1538 int32_t rt_val = get_register(instr->RtField()); | |
1539 int sa = instr->SaField(); | |
1540 set_register(instr->RdField(), rt_val << sa); | |
1541 } | |
1542 break; | |
1543 } | |
1544 case SLLV: { | |
1545 ASSERT(instr->SaField() == 0); | |
1546 // Format(instr, "sllv 'rd, 'rt, 'rs"); | |
1547 int32_t rt_val = get_register(instr->RtField()); | |
1548 int32_t rs_val = get_register(instr->RsField()); | |
1549 set_register(instr->RdField(), rt_val << (rs_val & 0x1f)); | |
1550 break; | |
1551 } | |
1552 case SLT: { | |
1553 ASSERT(instr->SaField() == 0); | |
1554 // Format(instr, "slt 'rd, 'rs, 'rt"); | |
1555 int32_t rs_val = get_register(instr->RsField()); | |
1556 int32_t rt_val = get_register(instr->RtField()); | |
1557 set_register(instr->RdField(), rs_val < rt_val ? 1 : 0); | |
1558 break; | |
1559 } | |
1560 case SLTU: { | |
1561 ASSERT(instr->SaField() == 0); | |
1562 // Format(instr, "sltu 'rd, 'rs, 'rt"); | |
1563 uint32_t rs_val = static_cast<uint32_t>(get_register(instr->RsField())); | |
1564 uint32_t rt_val = static_cast<uint32_t>(get_register(instr->RtField())); | |
1565 set_register(instr->RdField(), rs_val < rt_val ? 1 : 0); | |
1566 break; | |
1567 } | |
1568 case SRA: { | |
1569 ASSERT(instr->RsField() == 0); | |
1570 // Format(instr, "sra 'rd, 'rt, 'sa"); | |
1571 int32_t rt_val = get_register(instr->RtField()); | |
1572 int32_t sa = instr->SaField(); | |
1573 set_register(instr->RdField(), rt_val >> sa); | |
1574 break; | |
1575 } | |
1576 case SRAV: { | |
1577 ASSERT(instr->SaField() == 0); | |
1578 // Format(instr, "srav 'rd, 'rt, 'rs"); | |
1579 int32_t rt_val = get_register(instr->RtField()); | |
1580 int32_t rs_val = get_register(instr->RsField()); | |
1581 set_register(instr->RdField(), rt_val >> (rs_val & 0x1f)); | |
1582 break; | |
1583 } | |
1584 case SRL: { | |
1585 ASSERT(instr->RsField() == 0); | |
1586 // Format(instr, "srl 'rd, 'rt, 'sa"); | |
1587 uint32_t rt_val = get_register(instr->RtField()); | |
1588 uint32_t sa = instr->SaField(); | |
1589 set_register(instr->RdField(), rt_val >> sa); | |
1590 break; | |
1591 } | |
1592 case SRLV: { | |
1593 ASSERT(instr->SaField() == 0); | |
1594 // Format(instr, "srlv 'rd, 'rt, 'rs"); | |
1595 uint32_t rt_val = get_register(instr->RtField()); | |
1596 uint32_t rs_val = get_register(instr->RsField()); | |
1597 set_register(instr->RdField(), rt_val >> (rs_val & 0x1f)); | |
1598 break; | |
1599 } | |
1600 case SUBU: { | |
1601 ASSERT(instr->SaField() == 0); | |
1602 // Format(instr, "subu 'rd, 'rs, 'rt"); | |
1603 int32_t rs_val = get_register(instr->RsField()); | |
1604 int32_t rt_val = get_register(instr->RtField()); | |
1605 set_register(instr->RdField(), rs_val - rt_val); | |
1606 break; | |
1607 } | |
1608 case XOR: { | |
1609 ASSERT(instr->SaField() == 0); | |
1610 // Format(instr, "xor 'rd, 'rs, 'rt"); | |
1611 int32_t rs_val = get_register(instr->RsField()); | |
1612 int32_t rt_val = get_register(instr->RtField()); | |
1613 set_register(instr->RdField(), rs_val ^ rt_val); | |
1614 break; | |
1615 } | |
1616 default: { | |
1617 OS::PrintErr("DecodeSpecial: 0x%x\n", instr->InstructionBits()); | |
1618 UnimplementedInstruction(instr); | |
1619 break; | |
1620 } | |
1621 } | |
1622 } | |
1623 | |
1624 | |
1625 void Simulator::DecodeSpecial2(Instr* instr) { | |
1626 ASSERT(instr->OpcodeField() == SPECIAL2); | |
1627 switch (instr->FunctionField()) { | |
1628 case MADD: { | |
1629 ASSERT(instr->RdField() == 0); | |
1630 ASSERT(instr->SaField() == 0); | |
1631 // Format(instr, "madd 'rs, 'rt"); | |
1632 uint32_t lo = get_lo_register(); | |
1633 int32_t hi = get_hi_register(); | |
1634 int64_t accum = Utils::LowHighTo64Bits(lo, hi); | |
1635 int64_t rs = get_register(instr->RsField()); | |
1636 int64_t rt = get_register(instr->RtField()); | |
1637 int64_t res = accum + rs * rt; | |
1638 set_hi_register(Utils::High32Bits(res)); | |
1639 set_lo_register(Utils::Low32Bits(res)); | |
1640 break; | |
1641 } | |
1642 case MADDU: { | |
1643 ASSERT(instr->RdField() == 0); | |
1644 ASSERT(instr->SaField() == 0); | |
1645 // Format(instr, "maddu 'rs, 'rt"); | |
1646 uint32_t lo = get_lo_register(); | |
1647 uint32_t hi = get_hi_register(); | |
1648 uint64_t accum = Utils::LowHighTo64Bits(lo, hi); | |
1649 uint64_t rs = static_cast<uint32_t>(get_register(instr->RsField())); | |
1650 uint64_t rt = static_cast<uint32_t>(get_register(instr->RtField())); | |
1651 uint64_t res = accum + rs * rt; | |
1652 set_hi_register(Utils::High32Bits(res)); | |
1653 set_lo_register(Utils::Low32Bits(res)); | |
1654 break; | |
1655 } | |
1656 case CLO: { | |
1657 ASSERT(instr->SaField() == 0); | |
1658 ASSERT(instr->RtField() == instr->RdField()); | |
1659 // Format(instr, "clo 'rd, 'rs"); | |
1660 int32_t rs_val = get_register(instr->RsField()); | |
1661 int32_t bitcount = 0; | |
1662 while (rs_val < 0) { | |
1663 bitcount++; | |
1664 rs_val <<= 1; | |
1665 } | |
1666 set_register(instr->RdField(), bitcount); | |
1667 break; | |
1668 } | |
1669 case CLZ: { | |
1670 ASSERT(instr->SaField() == 0); | |
1671 ASSERT(instr->RtField() == instr->RdField()); | |
1672 // Format(instr, "clz 'rd, 'rs"); | |
1673 int32_t rs_val = get_register(instr->RsField()); | |
1674 int32_t bitcount = 0; | |
1675 if (rs_val != 0) { | |
1676 while (rs_val > 0) { | |
1677 bitcount++; | |
1678 rs_val <<= 1; | |
1679 } | |
1680 } else { | |
1681 bitcount = 32; | |
1682 } | |
1683 set_register(instr->RdField(), bitcount); | |
1684 break; | |
1685 } | |
1686 default: { | |
1687 OS::PrintErr("DecodeSpecial2: 0x%x\n", instr->InstructionBits()); | |
1688 UnimplementedInstruction(instr); | |
1689 break; | |
1690 } | |
1691 } | |
1692 } | |
1693 | |
1694 | |
1695 void Simulator::DoBranch(Instr* instr, bool taken, bool likely) { | |
1696 ASSERT(!delay_slot_); | |
1697 int32_t imm_val = instr->SImmField() << 2; | |
1698 | |
1699 uword next_pc; | |
1700 if (taken) { | |
1701 // imm_val is added to the address of the instruction following the branch. | |
1702 next_pc = pc_ + imm_val + Instr::kInstrSize; | |
1703 if (likely) { | |
1704 ExecuteDelaySlot(); | |
1705 } | |
1706 } else { | |
1707 next_pc = pc_ + (2 * Instr::kInstrSize); // Next after delay slot. | |
1708 } | |
1709 if (!likely) { | |
1710 ExecuteDelaySlot(); | |
1711 } | |
1712 pc_ = next_pc - Instr::kInstrSize; | |
1713 | |
1714 return; | |
1715 } | |
1716 | |
1717 | |
1718 void Simulator::DecodeRegImm(Instr* instr) { | |
1719 ASSERT(instr->OpcodeField() == REGIMM); | |
1720 switch (instr->RegImmFnField()) { | |
1721 case BGEZ: { | |
1722 // Format(instr, "bgez 'rs, 'dest"); | |
1723 int32_t rs_val = get_register(instr->RsField()); | |
1724 DoBranch(instr, rs_val >= 0, false); | |
1725 break; | |
1726 } | |
1727 case BGEZAL: { | |
1728 int32_t rs_val = get_register(instr->RsField()); | |
1729 // Return address is one after the delay slot. | |
1730 set_register(RA, pc_ + (2 * Instr::kInstrSize)); | |
1731 DoBranch(instr, rs_val >= 0, false); | |
1732 break; | |
1733 } | |
1734 case BLTZAL: { | |
1735 int32_t rs_val = get_register(instr->RsField()); | |
1736 // Return address is one after the delay slot. | |
1737 set_register(RA, pc_ + (2 * Instr::kInstrSize)); | |
1738 DoBranch(instr, rs_val < 0, false); | |
1739 break; | |
1740 } | |
1741 case BGEZL: { | |
1742 // Format(instr, "bgezl 'rs, 'dest"); | |
1743 int32_t rs_val = get_register(instr->RsField()); | |
1744 DoBranch(instr, rs_val >= 0, true); | |
1745 break; | |
1746 } | |
1747 case BLTZ: { | |
1748 // Format(instr, "bltz 'rs, 'dest"); | |
1749 int32_t rs_val = get_register(instr->RsField()); | |
1750 DoBranch(instr, rs_val < 0, false); | |
1751 break; | |
1752 } | |
1753 case BLTZL: { | |
1754 // Format(instr, "bltzl 'rs, 'dest"); | |
1755 int32_t rs_val = get_register(instr->RsField()); | |
1756 DoBranch(instr, rs_val < 0, true); | |
1757 break; | |
1758 } | |
1759 default: { | |
1760 OS::PrintErr("DecodeRegImm: 0x%x\n", instr->InstructionBits()); | |
1761 UnimplementedInstruction(instr); | |
1762 break; | |
1763 } | |
1764 } | |
1765 } | |
1766 | |
1767 | |
1768 void Simulator::DecodeCop1(Instr* instr) { | |
1769 ASSERT(instr->OpcodeField() == COP1); | |
1770 if (instr->HasFormat()) { | |
1771 // If the rs field is a valid format, then the function field identifies the | |
1772 // instruction. | |
1773 double fs_val = get_fregister_double(instr->FsField()); | |
1774 double ft_val = get_fregister_double(instr->FtField()); | |
1775 uint32_t cc, fcsr_cc; | |
1776 cc = instr->FpuCCField(); | |
1777 fcsr_cc = get_fcsr_condition_bit(cc); | |
1778 switch (instr->Cop1FunctionField()) { | |
1779 case COP1_ADD: { | |
1780 // Format(instr, "add.'fmt 'fd, 'fs, 'ft"); | |
1781 ASSERT(instr->FormatField() == FMT_D); // Only D supported. | |
1782 set_fregister_double(instr->FdField(), fs_val + ft_val); | |
1783 break; | |
1784 } | |
1785 case COP1_SUB: { | |
1786 // Format(instr, "sub.'fmt 'fd, 'fs, 'ft"); | |
1787 ASSERT(instr->FormatField() == FMT_D); // Only D supported. | |
1788 set_fregister_double(instr->FdField(), fs_val - ft_val); | |
1789 break; | |
1790 } | |
1791 case COP1_MUL: { | |
1792 // Format(instr, "mul.'fmt 'fd, 'fs, 'ft"); | |
1793 ASSERT(instr->FormatField() == FMT_D); // Only D supported. | |
1794 set_fregister_double(instr->FdField(), fs_val * ft_val); | |
1795 break; | |
1796 } | |
1797 case COP1_DIV: { | |
1798 // Format(instr, "div.'fmt 'fd, 'fs, 'ft"); | |
1799 ASSERT(instr->FormatField() == FMT_D); // Only D supported. | |
1800 set_fregister_double(instr->FdField(), fs_val / ft_val); | |
1801 break; | |
1802 } | |
1803 case COP1_SQRT: { | |
1804 // Format(instr, "sqrt.'fmt 'fd, 'fs"); | |
1805 ASSERT(instr->FormatField() == FMT_D); // Only D supported. | |
1806 set_fregister_double(instr->FdField(), sqrt(fs_val)); | |
1807 break; | |
1808 } | |
1809 case COP1_MOV: { | |
1810 // Format(instr, "mov.'fmt 'fd, 'fs"); | |
1811 ASSERT(instr->FormatField() == FMT_D); // Only D supported. | |
1812 set_fregister_double(instr->FdField(), fs_val); | |
1813 break; | |
1814 } | |
1815 case COP1_NEG: { | |
1816 // Format(instr, "neg.'fmt 'fd, 'fs"); | |
1817 ASSERT(instr->FormatField() == FMT_D); | |
1818 set_fregister_double(instr->FdField(), -fs_val); | |
1819 break; | |
1820 } | |
1821 case COP1_C_F: { | |
1822 ASSERT(instr->FormatField() == FMT_D); // Only D supported. | |
1823 ASSERT(instr->FdField() == F0); | |
1824 set_fcsr_bit(fcsr_cc, false); | |
1825 break; | |
1826 } | |
1827 case COP1_C_UN: { | |
1828 ASSERT(instr->FormatField() == FMT_D); // Only D supported. | |
1829 ASSERT(instr->FdField() == F0); | |
1830 set_fcsr_bit(fcsr_cc, isnan(fs_val) || isnan(ft_val)); | |
1831 break; | |
1832 } | |
1833 case COP1_C_EQ: { | |
1834 ASSERT(instr->FormatField() == FMT_D); // Only D supported. | |
1835 ASSERT(instr->FdField() == F0); | |
1836 set_fcsr_bit(fcsr_cc, (fs_val == ft_val)); | |
1837 break; | |
1838 } | |
1839 case COP1_C_UEQ: { | |
1840 ASSERT(instr->FormatField() == FMT_D); // Only D supported. | |
1841 ASSERT(instr->FdField() == F0); | |
1842 set_fcsr_bit(fcsr_cc, | |
1843 (fs_val == ft_val) || isnan(fs_val) || isnan(ft_val)); | |
1844 break; | |
1845 } | |
1846 case COP1_C_OLT: { | |
1847 ASSERT(instr->FormatField() == FMT_D); // Only D supported. | |
1848 ASSERT(instr->FdField() == F0); | |
1849 set_fcsr_bit(fcsr_cc, (fs_val < ft_val)); | |
1850 break; | |
1851 } | |
1852 case COP1_C_ULT: { | |
1853 ASSERT(instr->FormatField() == FMT_D); // Only D supported. | |
1854 ASSERT(instr->FdField() == F0); | |
1855 set_fcsr_bit(fcsr_cc, | |
1856 (fs_val < ft_val) || isnan(fs_val) || isnan(ft_val)); | |
1857 break; | |
1858 } | |
1859 case COP1_C_OLE: { | |
1860 ASSERT(instr->FormatField() == FMT_D); // Only D supported. | |
1861 ASSERT(instr->FdField() == F0); | |
1862 set_fcsr_bit(fcsr_cc, (fs_val <= ft_val)); | |
1863 break; | |
1864 } | |
1865 case COP1_C_ULE: { | |
1866 ASSERT(instr->FormatField() == FMT_D); // Only D supported. | |
1867 ASSERT(instr->FdField() == F0); | |
1868 set_fcsr_bit(fcsr_cc, | |
1869 (fs_val <= ft_val) || isnan(fs_val) || isnan(ft_val)); | |
1870 break; | |
1871 } | |
1872 case COP1_TRUNC_W: { | |
1873 switch (instr->FormatField()) { | |
1874 case FMT_D: { | |
1875 double fs_dbl = get_fregister_double(instr->FsField()); | |
1876 int32_t fs_int; | |
1877 if (isnan(fs_dbl) || isinf(fs_dbl) || (fs_dbl > kMaxInt32) || | |
1878 (fs_dbl < kMinInt32)) { | |
1879 fs_int = kMaxInt32; | |
1880 } else { | |
1881 fs_int = static_cast<int32_t>(fs_dbl); | |
1882 } | |
1883 set_fregister(instr->FdField(), fs_int); | |
1884 break; | |
1885 } | |
1886 default: { | |
1887 OS::PrintErr("DecodeCop1: 0x%x\n", instr->InstructionBits()); | |
1888 UnimplementedInstruction(instr); | |
1889 break; | |
1890 } | |
1891 } | |
1892 break; | |
1893 } | |
1894 case COP1_CVT_D: { | |
1895 switch (instr->FormatField()) { | |
1896 case FMT_W: { | |
1897 int32_t fs_int = get_fregister(instr->FsField()); | |
1898 double fs_dbl = static_cast<double>(fs_int); | |
1899 set_fregister_double(instr->FdField(), fs_dbl); | |
1900 break; | |
1901 } | |
1902 case FMT_S: { | |
1903 float fs_flt = get_fregister_float(instr->FsField()); | |
1904 double fs_dbl = static_cast<double>(fs_flt); | |
1905 set_fregister_double(instr->FdField(), fs_dbl); | |
1906 break; | |
1907 } | |
1908 default: { | |
1909 OS::PrintErr("DecodeCop1: 0x%x\n", instr->InstructionBits()); | |
1910 UnimplementedInstruction(instr); | |
1911 break; | |
1912 } | |
1913 } | |
1914 break; | |
1915 } | |
1916 case COP1_CVT_S: { | |
1917 switch (instr->FormatField()) { | |
1918 case FMT_D: { | |
1919 double fs_dbl = get_fregister_double(instr->FsField()); | |
1920 float fs_flt = static_cast<float>(fs_dbl); | |
1921 set_fregister_float(instr->FdField(), fs_flt); | |
1922 break; | |
1923 } | |
1924 default: { | |
1925 OS::PrintErr("DecodeCop1: 0x%x\n", instr->InstructionBits()); | |
1926 UnimplementedInstruction(instr); | |
1927 break; | |
1928 } | |
1929 } | |
1930 break; | |
1931 } | |
1932 default: { | |
1933 OS::PrintErr("DecodeCop1: 0x%x\n", instr->InstructionBits()); | |
1934 UnimplementedInstruction(instr); | |
1935 break; | |
1936 } | |
1937 } | |
1938 } else { | |
1939 // If the rs field isn't a valid format, then it must be a sub-op. | |
1940 switch (instr->Cop1SubField()) { | |
1941 case COP1_MF: { | |
1942 // Format(instr, "mfc1 'rt, 'fs"); | |
1943 ASSERT(instr->Bits(0, 11) == 0); | |
1944 int32_t fs_val = get_fregister(instr->FsField()); | |
1945 set_register(instr->RtField(), fs_val); | |
1946 break; | |
1947 } | |
1948 case COP1_MT: { | |
1949 // Format(instr, "mtc1 'rt, 'fs"); | |
1950 ASSERT(instr->Bits(0, 11) == 0); | |
1951 int32_t rt_val = get_register(instr->RtField()); | |
1952 set_fregister(instr->FsField(), rt_val); | |
1953 break; | |
1954 } | |
1955 case COP1_BC: { | |
1956 ASSERT(instr->Bit(17) == 0); | |
1957 uint32_t cc, fcsr_cc; | |
1958 cc = instr->Bits(18, 3); | |
1959 fcsr_cc = get_fcsr_condition_bit(cc); | |
1960 if (instr->Bit(16) == 1) { // Branch on true. | |
1961 DoBranch(instr, test_fcsr_bit(fcsr_cc), false); | |
1962 } else { // Branch on false. | |
1963 DoBranch(instr, !test_fcsr_bit(fcsr_cc), false); | |
1964 } | |
1965 break; | |
1966 } | |
1967 default: { | |
1968 OS::PrintErr("DecodeCop1: 0x%x\n", instr->InstructionBits()); | |
1969 UnimplementedInstruction(instr); | |
1970 break; | |
1971 } | |
1972 } | |
1973 } | |
1974 } | |
1975 | |
1976 | |
1977 void Simulator::InstructionDecode(Instr* instr) { | |
1978 if (IsTracingExecution()) { | |
1979 THR_Print("%" Pu64 " ", icount_); | |
1980 const uword start = reinterpret_cast<uword>(instr); | |
1981 const uword end = start + Instr::kInstrSize; | |
1982 if (FLAG_support_disassembler) { | |
1983 Disassembler::Disassemble(start, end); | |
1984 } else { | |
1985 THR_Print("Disassembler not supported in this mode.\n"); | |
1986 } | |
1987 } | |
1988 | |
1989 switch (instr->OpcodeField()) { | |
1990 case SPECIAL: { | |
1991 DecodeSpecial(instr); | |
1992 break; | |
1993 } | |
1994 case SPECIAL2: { | |
1995 DecodeSpecial2(instr); | |
1996 break; | |
1997 } | |
1998 case REGIMM: { | |
1999 DecodeRegImm(instr); | |
2000 break; | |
2001 } | |
2002 case COP1: { | |
2003 DecodeCop1(instr); | |
2004 break; | |
2005 } | |
2006 case ADDIU: { | |
2007 // Format(instr, "addiu 'rt, 'rs, 'imms"); | |
2008 int32_t rs_val = get_register(instr->RsField()); | |
2009 int32_t imm_val = instr->SImmField(); | |
2010 int32_t res = rs_val + imm_val; | |
2011 // Rt is set even on overflow. | |
2012 set_register(instr->RtField(), res); | |
2013 break; | |
2014 } | |
2015 case ANDI: { | |
2016 // Format(instr, "andi 'rt, 'rs, 'immu"); | |
2017 int32_t rs_val = get_register(instr->RsField()); | |
2018 set_register(instr->RtField(), rs_val & instr->UImmField()); | |
2019 break; | |
2020 } | |
2021 case BEQ: { | |
2022 // Format(instr, "beq 'rs, 'rt, 'dest"); | |
2023 int32_t rs_val = get_register(instr->RsField()); | |
2024 int32_t rt_val = get_register(instr->RtField()); | |
2025 DoBranch(instr, rs_val == rt_val, false); | |
2026 break; | |
2027 } | |
2028 case BEQL: { | |
2029 // Format(instr, "beql 'rs, 'rt, 'dest"); | |
2030 int32_t rs_val = get_register(instr->RsField()); | |
2031 int32_t rt_val = get_register(instr->RtField()); | |
2032 DoBranch(instr, rs_val == rt_val, true); | |
2033 break; | |
2034 } | |
2035 case BGTZ: { | |
2036 ASSERT(instr->RtField() == R0); | |
2037 // Format(instr, "bgtz 'rs, 'dest"); | |
2038 int32_t rs_val = get_register(instr->RsField()); | |
2039 DoBranch(instr, rs_val > 0, false); | |
2040 break; | |
2041 } | |
2042 case BGTZL: { | |
2043 ASSERT(instr->RtField() == R0); | |
2044 // Format(instr, "bgtzl 'rs, 'dest"); | |
2045 int32_t rs_val = get_register(instr->RsField()); | |
2046 DoBranch(instr, rs_val > 0, true); | |
2047 break; | |
2048 } | |
2049 case BLEZ: { | |
2050 ASSERT(instr->RtField() == R0); | |
2051 // Format(instr, "blez 'rs, 'dest"); | |
2052 int32_t rs_val = get_register(instr->RsField()); | |
2053 DoBranch(instr, rs_val <= 0, false); | |
2054 break; | |
2055 } | |
2056 case BLEZL: { | |
2057 ASSERT(instr->RtField() == R0); | |
2058 // Format(instr, "blezl 'rs, 'dest"); | |
2059 int32_t rs_val = get_register(instr->RsField()); | |
2060 DoBranch(instr, rs_val <= 0, true); | |
2061 break; | |
2062 } | |
2063 case BNE: { | |
2064 // Format(instr, "bne 'rs, 'rt, 'dest"); | |
2065 int32_t rs_val = get_register(instr->RsField()); | |
2066 int32_t rt_val = get_register(instr->RtField()); | |
2067 DoBranch(instr, rs_val != rt_val, false); | |
2068 break; | |
2069 } | |
2070 case BNEL: { | |
2071 // Format(instr, "bnel 'rs, 'rt, 'dest"); | |
2072 int32_t rs_val = get_register(instr->RsField()); | |
2073 int32_t rt_val = get_register(instr->RtField()); | |
2074 DoBranch(instr, rs_val != rt_val, true); | |
2075 break; | |
2076 } | |
2077 case LB: { | |
2078 // Format(instr, "lb 'rt, 'imms('rs)"); | |
2079 int32_t base_val = get_register(instr->RsField()); | |
2080 int32_t imm_val = instr->SImmField(); | |
2081 uword addr = base_val + imm_val; | |
2082 if (Simulator::IsIllegalAddress(addr)) { | |
2083 HandleIllegalAccess(addr, instr); | |
2084 } else { | |
2085 int32_t res = ReadB(addr); | |
2086 set_register(instr->RtField(), res); | |
2087 } | |
2088 break; | |
2089 } | |
2090 case LBU: { | |
2091 // Format(instr, "lbu 'rt, 'imms('rs)"); | |
2092 int32_t base_val = get_register(instr->RsField()); | |
2093 int32_t imm_val = instr->SImmField(); | |
2094 uword addr = base_val + imm_val; | |
2095 if (Simulator::IsIllegalAddress(addr)) { | |
2096 HandleIllegalAccess(addr, instr); | |
2097 } else { | |
2098 uint32_t res = ReadBU(addr); | |
2099 set_register(instr->RtField(), res); | |
2100 } | |
2101 break; | |
2102 } | |
2103 case LDC1: { | |
2104 // Format(instr, "ldc1 'ft, 'imms('rs)"); | |
2105 int32_t base_val = get_register(instr->RsField()); | |
2106 int32_t imm_val = instr->SImmField(); | |
2107 uword addr = base_val + imm_val; | |
2108 if (Simulator::IsIllegalAddress(addr)) { | |
2109 HandleIllegalAccess(addr, instr); | |
2110 } else { | |
2111 double value = ReadD(addr, instr); | |
2112 set_fregister_double(instr->FtField(), value); | |
2113 } | |
2114 break; | |
2115 } | |
2116 case LH: { | |
2117 // Format(instr, "lh 'rt, 'imms('rs)"); | |
2118 int32_t base_val = get_register(instr->RsField()); | |
2119 int32_t imm_val = instr->SImmField(); | |
2120 uword addr = base_val + imm_val; | |
2121 if (Simulator::IsIllegalAddress(addr)) { | |
2122 HandleIllegalAccess(addr, instr); | |
2123 } else { | |
2124 int32_t res = ReadH(addr, instr); | |
2125 set_register(instr->RtField(), res); | |
2126 } | |
2127 break; | |
2128 } | |
2129 case LHU: { | |
2130 // Format(instr, "lhu 'rt, 'imms('rs)"); | |
2131 int32_t base_val = get_register(instr->RsField()); | |
2132 int32_t imm_val = instr->SImmField(); | |
2133 uword addr = base_val + imm_val; | |
2134 if (Simulator::IsIllegalAddress(addr)) { | |
2135 HandleIllegalAccess(addr, instr); | |
2136 } else { | |
2137 int32_t res = ReadHU(addr, instr); | |
2138 set_register(instr->RtField(), res); | |
2139 } | |
2140 break; | |
2141 } | |
2142 case LUI: { | |
2143 ASSERT(instr->RsField() == 0); | |
2144 set_register(instr->RtField(), instr->UImmField() << 16); | |
2145 break; | |
2146 } | |
2147 case LL: { | |
2148 // Format(instr, "ll 'rt, 'imms('rs)"); | |
2149 int32_t base_val = get_register(instr->RsField()); | |
2150 int32_t imm_val = instr->SImmField(); | |
2151 uword addr = base_val + imm_val; | |
2152 if (Simulator::IsIllegalAddress(addr)) { | |
2153 HandleIllegalAccess(addr, instr); | |
2154 } else { | |
2155 int32_t res = ReadExclusiveW(addr, instr); | |
2156 set_register(instr->RtField(), res); | |
2157 } | |
2158 break; | |
2159 } | |
2160 case LW: { | |
2161 // Format(instr, "lw 'rt, 'imms('rs)"); | |
2162 int32_t base_val = get_register(instr->RsField()); | |
2163 int32_t imm_val = instr->SImmField(); | |
2164 uword addr = base_val + imm_val; | |
2165 if (Simulator::IsIllegalAddress(addr)) { | |
2166 HandleIllegalAccess(addr, instr); | |
2167 } else { | |
2168 int32_t res = ReadW(addr, instr); | |
2169 set_register(instr->RtField(), res); | |
2170 } | |
2171 break; | |
2172 } | |
2173 case LWC1: { | |
2174 // Format(instr, "lwc1 'ft, 'imms('rs)"); | |
2175 int32_t base_val = get_register(instr->RsField()); | |
2176 int32_t imm_val = instr->SImmField(); | |
2177 uword addr = base_val + imm_val; | |
2178 if (Simulator::IsIllegalAddress(addr)) { | |
2179 HandleIllegalAccess(addr, instr); | |
2180 } else { | |
2181 int32_t value = ReadW(addr, instr); | |
2182 set_fregister(instr->FtField(), value); | |
2183 } | |
2184 break; | |
2185 } | |
2186 case ORI: { | |
2187 // Format(instr, "ori 'rt, 'rs, 'immu"); | |
2188 int32_t rs_val = get_register(instr->RsField()); | |
2189 set_register(instr->RtField(), rs_val | instr->UImmField()); | |
2190 break; | |
2191 } | |
2192 case SB: { | |
2193 // Format(instr, "sb 'rt, 'imms('rs)"); | |
2194 int32_t rt_val = get_register(instr->RtField()); | |
2195 int32_t base_val = get_register(instr->RsField()); | |
2196 int32_t imm_val = instr->SImmField(); | |
2197 uword addr = base_val + imm_val; | |
2198 if (Simulator::IsIllegalAddress(addr)) { | |
2199 HandleIllegalAccess(addr, instr); | |
2200 } else { | |
2201 WriteB(addr, rt_val & 0xff); | |
2202 } | |
2203 break; | |
2204 } | |
2205 case SC: { | |
2206 // Format(instr, "sc 'rt, 'imms('rs)"); | |
2207 int32_t rt_val = get_register(instr->RtField()); | |
2208 int32_t base_val = get_register(instr->RsField()); | |
2209 int32_t imm_val = instr->SImmField(); | |
2210 uword addr = base_val + imm_val; | |
2211 if (Simulator::IsIllegalAddress(addr)) { | |
2212 HandleIllegalAccess(addr, instr); | |
2213 } else { | |
2214 intptr_t status = WriteExclusiveW(addr, rt_val, instr); | |
2215 set_register(instr->RtField(), status); | |
2216 } | |
2217 break; | |
2218 } | |
2219 case SLTI: { | |
2220 // Format(instr, "slti 'rt, 'rs, 'imms"); | |
2221 int32_t rs_val = get_register(instr->RsField()); | |
2222 int32_t imm_val = instr->SImmField(); | |
2223 set_register(instr->RtField(), rs_val < imm_val ? 1 : 0); | |
2224 break; | |
2225 } | |
2226 case SLTIU: { | |
2227 // Format(instr, "sltiu 'rt, 'rs, 'imms"); | |
2228 uint32_t rs_val = get_register(instr->RsField()); | |
2229 int32_t imm_val = instr->SImmField(); // Sign extend to 32-bit. | |
2230 uint32_t immu_val = static_cast<uint32_t>(imm_val); // Treat as unsigned. | |
2231 set_register(instr->RtField(), rs_val < immu_val ? 1 : 0); | |
2232 break; | |
2233 } | |
2234 case SDC1: { | |
2235 // Format(instr, "sdc1 'ft, 'imms('rs)"); | |
2236 int32_t base_val = get_register(instr->RsField()); | |
2237 int32_t imm_val = instr->SImmField(); | |
2238 uword addr = base_val + imm_val; | |
2239 if (Simulator::IsIllegalAddress(addr)) { | |
2240 HandleIllegalAccess(addr, instr); | |
2241 } else { | |
2242 double value = get_fregister_double(instr->FtField()); | |
2243 WriteD(addr, value, instr); | |
2244 } | |
2245 break; | |
2246 } | |
2247 case SH: { | |
2248 // Format(instr, "sh 'rt, 'imms('rs)"); | |
2249 int32_t rt_val = get_register(instr->RtField()); | |
2250 int32_t base_val = get_register(instr->RsField()); | |
2251 int32_t imm_val = instr->SImmField(); | |
2252 uword addr = base_val + imm_val; | |
2253 if (Simulator::IsIllegalAddress(addr)) { | |
2254 HandleIllegalAccess(addr, instr); | |
2255 } else { | |
2256 WriteH(addr, rt_val & 0xffff, instr); | |
2257 } | |
2258 break; | |
2259 } | |
2260 case SW: { | |
2261 // Format(instr, "sw 'rt, 'imms('rs)"); | |
2262 int32_t rt_val = get_register(instr->RtField()); | |
2263 int32_t base_val = get_register(instr->RsField()); | |
2264 int32_t imm_val = instr->SImmField(); | |
2265 uword addr = base_val + imm_val; | |
2266 if (Simulator::IsIllegalAddress(addr)) { | |
2267 HandleIllegalAccess(addr, instr); | |
2268 } else { | |
2269 WriteW(addr, rt_val, instr); | |
2270 } | |
2271 break; | |
2272 } | |
2273 case SWC1: { | |
2274 // Format(instr, "swc1 'ft, 'imms('rs)"); | |
2275 int32_t base_val = get_register(instr->RsField()); | |
2276 int32_t imm_val = instr->SImmField(); | |
2277 uword addr = base_val + imm_val; | |
2278 if (Simulator::IsIllegalAddress(addr)) { | |
2279 HandleIllegalAccess(addr, instr); | |
2280 } else { | |
2281 int32_t value = get_fregister(instr->FtField()); | |
2282 WriteW(addr, value, instr); | |
2283 } | |
2284 break; | |
2285 } | |
2286 case XORI: { | |
2287 // Format(instr, "xori 'rt, 'rs, 'immu"); | |
2288 int32_t rs_val = get_register(instr->RsField()); | |
2289 set_register(instr->RtField(), rs_val ^ instr->UImmField()); | |
2290 break; | |
2291 break; | |
2292 } | |
2293 default: { | |
2294 OS::PrintErr("Undecoded instruction: 0x%x at %p\n", | |
2295 instr->InstructionBits(), instr); | |
2296 UnimplementedInstruction(instr); | |
2297 break; | |
2298 } | |
2299 } | |
2300 pc_ += Instr::kInstrSize; | |
2301 } | |
2302 | |
2303 | |
2304 void Simulator::ExecuteDelaySlot() { | |
2305 ASSERT(pc_ != kEndSimulatingPC); | |
2306 delay_slot_ = true; | |
2307 icount_++; | |
2308 Instr* instr = Instr::At(pc_ + Instr::kInstrSize); | |
2309 if (FLAG_stop_sim_at != ULLONG_MAX) { | |
2310 if (icount_ == FLAG_stop_sim_at) { | |
2311 SimulatorDebugger dbg(this); | |
2312 dbg.Stop(instr, "Instruction count reached"); | |
2313 } else if (reinterpret_cast<uint64_t>(instr) == FLAG_stop_sim_at) { | |
2314 SimulatorDebugger dbg(this); | |
2315 dbg.Stop(instr, "Instruction address reached"); | |
2316 } | |
2317 } | |
2318 InstructionDecode(instr); | |
2319 delay_slot_ = false; | |
2320 } | |
2321 | |
2322 | |
2323 void Simulator::Execute() { | |
2324 if (FLAG_stop_sim_at == ULLONG_MAX) { | |
2325 // Fast version of the dispatch loop without checking whether the simulator | |
2326 // should be stopping at a particular executed instruction. | |
2327 while (pc_ != kEndSimulatingPC) { | |
2328 icount_++; | |
2329 Instr* instr = Instr::At(pc_); | |
2330 if (IsIllegalAddress(pc_)) { | |
2331 HandleIllegalAccess(pc_, instr); | |
2332 } else { | |
2333 InstructionDecode(instr); | |
2334 } | |
2335 } | |
2336 } else { | |
2337 // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when | |
2338 // we reach the particular instruction count or address. | |
2339 while (pc_ != kEndSimulatingPC) { | |
2340 Instr* instr = Instr::At(pc_); | |
2341 icount_++; | |
2342 if (icount_ == FLAG_stop_sim_at) { | |
2343 SimulatorDebugger dbg(this); | |
2344 dbg.Stop(instr, "Instruction count reached"); | |
2345 } else if (reinterpret_cast<uint64_t>(instr) == FLAG_stop_sim_at) { | |
2346 SimulatorDebugger dbg(this); | |
2347 dbg.Stop(instr, "Instruction address reached"); | |
2348 } else if (IsIllegalAddress(pc_)) { | |
2349 HandleIllegalAccess(pc_, instr); | |
2350 } else { | |
2351 InstructionDecode(instr); | |
2352 } | |
2353 } | |
2354 } | |
2355 } | |
2356 | |
2357 | |
2358 int64_t Simulator::Call(int32_t entry, | |
2359 int32_t parameter0, | |
2360 int32_t parameter1, | |
2361 int32_t parameter2, | |
2362 int32_t parameter3, | |
2363 bool fp_return, | |
2364 bool fp_args) { | |
2365 // Save the SP register before the call so we can restore it. | |
2366 int32_t sp_before_call = get_register(SP); | |
2367 | |
2368 // Setup parameters. | |
2369 if (fp_args) { | |
2370 set_fregister(F0, parameter0); | |
2371 set_fregister(F1, parameter1); | |
2372 set_fregister(F2, parameter2); | |
2373 set_fregister(F3, parameter3); | |
2374 } else { | |
2375 set_register(A0, parameter0); | |
2376 set_register(A1, parameter1); | |
2377 set_register(A2, parameter2); | |
2378 set_register(A3, parameter3); | |
2379 } | |
2380 | |
2381 // Make sure the activation frames are properly aligned. | |
2382 int32_t stack_pointer = sp_before_call; | |
2383 if (OS::ActivationFrameAlignment() > 1) { | |
2384 stack_pointer = | |
2385 Utils::RoundDown(stack_pointer, OS::ActivationFrameAlignment()); | |
2386 } | |
2387 set_register(SP, stack_pointer); | |
2388 | |
2389 // Prepare to execute the code at entry. | |
2390 set_pc(entry); | |
2391 // Put down marker for end of simulation. The simulator will stop simulation | |
2392 // when the PC reaches this value. By saving the "end simulation" value into | |
2393 // RA the simulation stops when returning to this call point. | |
2394 set_register(RA, kEndSimulatingPC); | |
2395 | |
2396 // Remember the values of callee-saved registers. | |
2397 // The code below assumes that r9 is not used as sb (static base) in | |
2398 // simulator code and therefore is regarded as a callee-saved register. | |
2399 int32_t r16_val = get_register(R16); | |
2400 int32_t r17_val = get_register(R17); | |
2401 int32_t r18_val = get_register(R18); | |
2402 int32_t r19_val = get_register(R19); | |
2403 int32_t r20_val = get_register(R20); | |
2404 int32_t r21_val = get_register(R21); | |
2405 int32_t r22_val = get_register(R22); | |
2406 int32_t r23_val = get_register(R23); | |
2407 | |
2408 double d10_val = get_dregister(D10); | |
2409 double d11_val = get_dregister(D11); | |
2410 double d12_val = get_dregister(D12); | |
2411 double d13_val = get_dregister(D13); | |
2412 double d14_val = get_dregister(D14); | |
2413 double d15_val = get_dregister(D15); | |
2414 | |
2415 // Setup the callee-saved registers with a known value. To be able to check | |
2416 // that they are preserved properly across dart execution. | |
2417 int32_t callee_saved_value = icount_; | |
2418 set_register(R16, callee_saved_value); | |
2419 set_register(R17, callee_saved_value); | |
2420 set_register(R18, callee_saved_value); | |
2421 set_register(R19, callee_saved_value); | |
2422 set_register(R20, callee_saved_value); | |
2423 set_register(R21, callee_saved_value); | |
2424 set_register(R22, callee_saved_value); | |
2425 set_register(R23, callee_saved_value); | |
2426 | |
2427 set_dregister_bits(D10, callee_saved_value); | |
2428 set_dregister_bits(D11, callee_saved_value); | |
2429 set_dregister_bits(D12, callee_saved_value); | |
2430 set_dregister_bits(D13, callee_saved_value); | |
2431 set_dregister_bits(D14, callee_saved_value); | |
2432 set_dregister_bits(D15, callee_saved_value); | |
2433 | |
2434 // Start the simulation | |
2435 Execute(); | |
2436 | |
2437 // Check that the callee-saved registers have been preserved. | |
2438 ASSERT(callee_saved_value == get_register(R16)); | |
2439 ASSERT(callee_saved_value == get_register(R17)); | |
2440 ASSERT(callee_saved_value == get_register(R18)); | |
2441 ASSERT(callee_saved_value == get_register(R19)); | |
2442 ASSERT(callee_saved_value == get_register(R20)); | |
2443 ASSERT(callee_saved_value == get_register(R21)); | |
2444 ASSERT(callee_saved_value == get_register(R22)); | |
2445 ASSERT(callee_saved_value == get_register(R23)); | |
2446 | |
2447 ASSERT(callee_saved_value == get_dregister_bits(D10)); | |
2448 ASSERT(callee_saved_value == get_dregister_bits(D11)); | |
2449 ASSERT(callee_saved_value == get_dregister_bits(D12)); | |
2450 ASSERT(callee_saved_value == get_dregister_bits(D13)); | |
2451 ASSERT(callee_saved_value == get_dregister_bits(D14)); | |
2452 ASSERT(callee_saved_value == get_dregister_bits(D15)); | |
2453 | |
2454 // Restore callee-saved registers with the original value. | |
2455 set_register(R16, r16_val); | |
2456 set_register(R17, r17_val); | |
2457 set_register(R18, r18_val); | |
2458 set_register(R19, r19_val); | |
2459 set_register(R20, r20_val); | |
2460 set_register(R21, r21_val); | |
2461 set_register(R22, r22_val); | |
2462 set_register(R23, r23_val); | |
2463 | |
2464 set_dregister(D10, d10_val); | |
2465 set_dregister(D11, d11_val); | |
2466 set_dregister(D12, d12_val); | |
2467 set_dregister(D13, d13_val); | |
2468 set_dregister(D14, d14_val); | |
2469 set_dregister(D15, d15_val); | |
2470 | |
2471 // Restore the SP register and return V1:V0. | |
2472 set_register(SP, sp_before_call); | |
2473 int64_t return_value; | |
2474 if (fp_return) { | |
2475 return_value = Utils::LowHighTo64Bits(get_fregister(F0), get_fregister(F1)); | |
2476 } else { | |
2477 return_value = Utils::LowHighTo64Bits(get_register(V0), get_register(V1)); | |
2478 } | |
2479 return return_value; | |
2480 } | |
2481 | |
2482 | |
2483 void Simulator::JumpToFrame(uword pc, uword sp, uword fp, Thread* thread) { | |
2484 // Walk over all setjmp buffers (simulated --> C++ transitions) | |
2485 // and try to find the setjmp associated with the simulated stack pointer. | |
2486 SimulatorSetjmpBuffer* buf = last_setjmp_buffer(); | |
2487 while (buf->link() != NULL && buf->link()->sp() <= sp) { | |
2488 buf = buf->link(); | |
2489 } | |
2490 ASSERT(buf != NULL); | |
2491 | |
2492 // The C++ caller has not cleaned up the stack memory of C++ frames. | |
2493 // Prepare for unwinding frames by destroying all the stack resources | |
2494 // in the previous C++ frames. | |
2495 StackResource::Unwind(thread); | |
2496 | |
2497 // Unwind the C++ stack and continue simulation in the target frame. | |
2498 set_pc(static_cast<int32_t>(pc)); | |
2499 set_register(SP, static_cast<int32_t>(sp)); | |
2500 set_register(FP, static_cast<int32_t>(fp)); | |
2501 set_register(THR, reinterpret_cast<int32_t>(thread)); | |
2502 // Set the tag. | |
2503 thread->set_vm_tag(VMTag::kDartTagId); | |
2504 // Clear top exit frame. | |
2505 thread->set_top_exit_frame_info(0); | |
2506 // Restore pool pointer. | |
2507 int32_t code = | |
2508 *reinterpret_cast<int32_t*>(fp + kPcMarkerSlotFromFp * kWordSize); | |
2509 int32_t pp = *reinterpret_cast<int32_t*>(code + Code::object_pool_offset() - | |
2510 kHeapObjectTag); | |
2511 set_register(CODE_REG, code); | |
2512 set_register(PP, pp); | |
2513 buf->Longjmp(); | |
2514 } | |
2515 | |
2516 } // namespace dart | |
2517 | |
2518 #endif // defined(USING_SIMULATOR) | |
2519 | |
2520 #endif // defined TARGET_ARCH_MIPS | |
OLD | NEW |