OLD | NEW |
| (Empty) |
1 // Copyright 2008 the V8 project authors. All rights reserved. | |
2 // Redistribution and use in source and binary forms, with or without | |
3 // modification, are permitted provided that the following conditions are | |
4 // met: | |
5 // | |
6 // * Redistributions of source code must retain the above copyright | |
7 // notice, this list of conditions and the following disclaimer. | |
8 // * Redistributions in binary form must reproduce the above | |
9 // copyright notice, this list of conditions and the following | |
10 // disclaimer in the documentation and/or other materials provided | |
11 // with the distribution. | |
12 // * Neither the name of Google Inc. nor the names of its | |
13 // contributors may be used to endorse or promote products derived | |
14 // from this software without specific prior written permission. | |
15 // | |
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
27 | |
28 #include <stdlib.h> | |
29 | |
30 #include "v8.h" | |
31 | |
32 #include "disasm.h" | |
33 #include "constants-arm.h" | |
34 #include "simulator-arm.h" | |
35 | |
36 #if !defined(__arm__) | |
37 | |
38 // Only build the simulator if not compiling for real ARM hardware. | |
39 namespace assembler { namespace arm { | |
40 | |
41 using ::v8::internal::Object; | |
42 using ::v8::internal::PrintF; | |
43 using ::v8::internal::OS; | |
44 using ::v8::internal::ReadLine; | |
45 using ::v8::internal::DeleteArray; | |
46 | |
47 // This macro provides a platform independent use of sscanf. The reason for | |
48 // SScanF not being implemented in a platform independent was through | |
49 // ::v8::internal::OS in the same way as SNPrintF is that the Windows C Run-Time | |
50 // Library does not provide vsscanf. | |
51 #define SScanF sscanf // NOLINT | |
52 | |
53 // The Debugger class is used by the simulator while debugging simulated ARM | |
54 // code. | |
55 class Debugger { | |
56 public: | |
57 explicit Debugger(Simulator* sim); | |
58 ~Debugger(); | |
59 | |
60 void Stop(Instr* instr); | |
61 void Debug(); | |
62 | |
63 private: | |
64 static const instr_t kBreakpointInstr = | |
65 ((AL << 28) | (7 << 25) | (1 << 24) | break_point); | |
66 static const instr_t kNopInstr = | |
67 ((AL << 28) | (13 << 21)); | |
68 | |
69 Simulator* sim_; | |
70 | |
71 bool GetValue(char* desc, int32_t* value); | |
72 | |
73 // Set or delete a breakpoint. Returns true if successful. | |
74 bool SetBreakpoint(Instr* breakpc); | |
75 bool DeleteBreakpoint(Instr* breakpc); | |
76 | |
77 // Undo and redo all breakpoints. This is needed to bracket disassembly and | |
78 // execution to skip past breakpoints when run from the debugger. | |
79 void UndoBreakpoints(); | |
80 void RedoBreakpoints(); | |
81 }; | |
82 | |
83 | |
84 Debugger::Debugger(Simulator* sim) { | |
85 sim_ = sim; | |
86 } | |
87 | |
88 | |
89 Debugger::~Debugger() { | |
90 } | |
91 | |
92 | |
93 | |
94 #ifdef GENERATED_CODE_COVERAGE | |
95 static FILE* coverage_log = NULL; | |
96 | |
97 | |
98 static void InitializeCoverage() { | |
99 char* file_name = getenv("V8_GENERATED_CODE_COVERAGE_LOG"); | |
100 if (file_name != NULL) { | |
101 coverage_log = fopen(file_name, "aw+"); | |
102 } | |
103 } | |
104 | |
105 | |
106 void Debugger::Stop(Instr* instr) { | |
107 char* str = reinterpret_cast<char*>(instr->InstructionBits() & 0x0fffffff); | |
108 if (strlen(str) > 0) { | |
109 if (coverage_log != NULL) { | |
110 fprintf(coverage_log, "%s\n", str); | |
111 fflush(coverage_log); | |
112 } | |
113 instr->SetInstructionBits(0xe1a00000); // Overwrite with nop. | |
114 } | |
115 sim_->set_pc(sim_->get_pc() + Instr::kInstrSize); | |
116 } | |
117 | |
118 #else // ndef GENERATED_CODE_COVERAGE | |
119 | |
120 static void InitializeCoverage() { | |
121 } | |
122 | |
123 | |
124 void Debugger::Stop(Instr* instr) { | |
125 const char* str = (const char*)(instr->InstructionBits() & 0x0fffffff); | |
126 PrintF("Simulator hit %s\n", str); | |
127 sim_->set_pc(sim_->get_pc() + Instr::kInstrSize); | |
128 Debug(); | |
129 } | |
130 #endif | |
131 | |
132 | |
133 static const char* reg_names[] = { "r0", "r1", "r2", "r3", | |
134 "r4", "r5", "r6", "r7", | |
135 "r8", "r9", "r10", "r11", | |
136 "r12", "r13", "r14", "r15", | |
137 "pc", "lr", "sp", "ip", | |
138 "fp", "sl", ""}; | |
139 | |
140 static int reg_nums[] = { 0, 1, 2, 3, | |
141 4, 5, 6, 7, | |
142 8, 9, 10, 11, | |
143 12, 13, 14, 15, | |
144 15, 14, 13, 12, | |
145 11, 10}; | |
146 | |
147 | |
148 static int RegNameToRegNum(char* name) { | |
149 int reg = 0; | |
150 while (*reg_names[reg] != 0) { | |
151 if (strcmp(reg_names[reg], name) == 0) { | |
152 return reg_nums[reg]; | |
153 } | |
154 reg++; | |
155 } | |
156 return -1; | |
157 } | |
158 | |
159 | |
160 bool Debugger::GetValue(char* desc, int32_t* value) { | |
161 int regnum = RegNameToRegNum(desc); | |
162 if (regnum >= 0) { | |
163 if (regnum == 15) { | |
164 *value = sim_->get_pc(); | |
165 } else { | |
166 *value = sim_->get_register(regnum); | |
167 } | |
168 return true; | |
169 } else { | |
170 return SScanF(desc, "%i", value) == 1; | |
171 } | |
172 return false; | |
173 } | |
174 | |
175 | |
176 bool Debugger::SetBreakpoint(Instr* breakpc) { | |
177 // Check if a breakpoint can be set. If not return without any side-effects. | |
178 if (sim_->break_pc_ != NULL) { | |
179 return false; | |
180 } | |
181 | |
182 // Set the breakpoint. | |
183 sim_->break_pc_ = breakpc; | |
184 sim_->break_instr_ = breakpc->InstructionBits(); | |
185 // Not setting the breakpoint instruction in the code itself. It will be set | |
186 // when the debugger shell continues. | |
187 return true; | |
188 } | |
189 | |
190 | |
191 bool Debugger::DeleteBreakpoint(Instr* breakpc) { | |
192 if (sim_->break_pc_ != NULL) { | |
193 sim_->break_pc_->SetInstructionBits(sim_->break_instr_); | |
194 } | |
195 | |
196 sim_->break_pc_ = NULL; | |
197 sim_->break_instr_ = 0; | |
198 return true; | |
199 } | |
200 | |
201 | |
202 void Debugger::UndoBreakpoints() { | |
203 if (sim_->break_pc_ != NULL) { | |
204 sim_->break_pc_->SetInstructionBits(sim_->break_instr_); | |
205 } | |
206 } | |
207 | |
208 | |
209 void Debugger::RedoBreakpoints() { | |
210 if (sim_->break_pc_ != NULL) { | |
211 sim_->break_pc_->SetInstructionBits(kBreakpointInstr); | |
212 } | |
213 } | |
214 | |
215 | |
216 void Debugger::Debug() { | |
217 intptr_t last_pc = -1; | |
218 bool done = false; | |
219 | |
220 #define COMMAND_SIZE 63 | |
221 #define ARG_SIZE 255 | |
222 | |
223 #define STR(a) #a | |
224 #define XSTR(a) STR(a) | |
225 | |
226 char cmd[COMMAND_SIZE + 1]; | |
227 char arg1[ARG_SIZE + 1]; | |
228 char arg2[ARG_SIZE + 1]; | |
229 | |
230 // make sure to have a proper terminating character if reaching the limit | |
231 cmd[COMMAND_SIZE] = 0; | |
232 arg1[ARG_SIZE] = 0; | |
233 arg2[ARG_SIZE] = 0; | |
234 | |
235 // Undo all set breakpoints while running in the debugger shell. This will | |
236 // make them invisible to all commands. | |
237 UndoBreakpoints(); | |
238 | |
239 while (!done) { | |
240 if (last_pc != sim_->get_pc()) { | |
241 disasm::NameConverter converter; | |
242 disasm::Disassembler dasm(converter); | |
243 // use a reasonably large buffer | |
244 v8::internal::EmbeddedVector<char, 256> buffer; | |
245 dasm.InstructionDecode(buffer, | |
246 reinterpret_cast<byte*>(sim_->get_pc())); | |
247 PrintF(" 0x%x %s\n", sim_->get_pc(), buffer.start()); | |
248 last_pc = sim_->get_pc(); | |
249 } | |
250 char* line = ReadLine("sim> "); | |
251 if (line == NULL) { | |
252 break; | |
253 } else { | |
254 // Use sscanf to parse the individual parts of the command line. At the | |
255 // moment no command expects more than two parameters. | |
256 int args = SScanF(line, | |
257 "%" XSTR(COMMAND_SIZE) "s " | |
258 "%" XSTR(ARG_SIZE) "s " | |
259 "%" XSTR(ARG_SIZE) "s", | |
260 cmd, arg1, arg2); | |
261 if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) { | |
262 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc())); | |
263 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) { | |
264 // Execute the one instruction we broke at with breakpoints disabled. | |
265 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc())); | |
266 // Leave the debugger shell. | |
267 done = true; | |
268 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) { | |
269 if (args == 2) { | |
270 int32_t value; | |
271 if (GetValue(arg1, &value)) { | |
272 PrintF("%s: %d 0x%x\n", arg1, value, value); | |
273 } else { | |
274 PrintF("%s unrecognized\n", arg1); | |
275 } | |
276 } else { | |
277 PrintF("print value\n"); | |
278 } | |
279 } else if ((strcmp(cmd, "po") == 0) | |
280 || (strcmp(cmd, "printobject") == 0)) { | |
281 if (args == 2) { | |
282 int32_t value; | |
283 if (GetValue(arg1, &value)) { | |
284 Object* obj = reinterpret_cast<Object*>(value); | |
285 USE(obj); | |
286 PrintF("%s: \n", arg1); | |
287 #if defined(DEBUG) | |
288 obj->PrintLn(); | |
289 #endif // defined(DEBUG) | |
290 } else { | |
291 PrintF("%s unrecognized\n", arg1); | |
292 } | |
293 } else { | |
294 PrintF("printobject value\n"); | |
295 } | |
296 } else if (strcmp(cmd, "disasm") == 0) { | |
297 disasm::NameConverter converter; | |
298 disasm::Disassembler dasm(converter); | |
299 // use a reasonably large buffer | |
300 v8::internal::EmbeddedVector<char, 256> buffer; | |
301 | |
302 byte* cur = NULL; | |
303 byte* end = NULL; | |
304 | |
305 if (args == 1) { | |
306 cur = reinterpret_cast<byte*>(sim_->get_pc()); | |
307 end = cur + (10 * Instr::kInstrSize); | |
308 } else if (args == 2) { | |
309 int32_t value; | |
310 if (GetValue(arg1, &value)) { | |
311 cur = reinterpret_cast<byte*>(value); | |
312 // no length parameter passed, assume 10 instructions | |
313 end = cur + (10 * Instr::kInstrSize); | |
314 } | |
315 } else { | |
316 int32_t value1; | |
317 int32_t value2; | |
318 if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) { | |
319 cur = reinterpret_cast<byte*>(value1); | |
320 end = cur + (value2 * Instr::kInstrSize); | |
321 } | |
322 } | |
323 | |
324 while (cur < end) { | |
325 dasm.InstructionDecode(buffer, cur); | |
326 PrintF(" 0x%x %s\n", cur, buffer.start()); | |
327 cur += Instr::kInstrSize; | |
328 } | |
329 } else if (strcmp(cmd, "gdb") == 0) { | |
330 PrintF("relinquishing control to gdb\n"); | |
331 v8::internal::OS::DebugBreak(); | |
332 PrintF("regaining control from gdb\n"); | |
333 } else if (strcmp(cmd, "break") == 0) { | |
334 if (args == 2) { | |
335 int32_t value; | |
336 if (GetValue(arg1, &value)) { | |
337 if (!SetBreakpoint(reinterpret_cast<Instr*>(value))) { | |
338 PrintF("setting breakpoint failed\n"); | |
339 } | |
340 } else { | |
341 PrintF("%s unrecognized\n", arg1); | |
342 } | |
343 } else { | |
344 PrintF("break addr\n"); | |
345 } | |
346 } else if (strcmp(cmd, "del") == 0) { | |
347 if (!DeleteBreakpoint(NULL)) { | |
348 PrintF("deleting breakpoint failed\n"); | |
349 } | |
350 } else if (strcmp(cmd, "flags") == 0) { | |
351 PrintF("N flag: %d; ", sim_->n_flag_); | |
352 PrintF("Z flag: %d; ", sim_->z_flag_); | |
353 PrintF("C flag: %d; ", sim_->c_flag_); | |
354 PrintF("V flag: %d\n", sim_->v_flag_); | |
355 } else if (strcmp(cmd, "unstop") == 0) { | |
356 intptr_t stop_pc = sim_->get_pc() - Instr::kInstrSize; | |
357 Instr* stop_instr = reinterpret_cast<Instr*>(stop_pc); | |
358 if (stop_instr->ConditionField() == special_condition) { | |
359 stop_instr->SetInstructionBits(kNopInstr); | |
360 } else { | |
361 PrintF("Not at debugger stop."); | |
362 } | |
363 } else { | |
364 PrintF("Unknown command: %s\n", cmd); | |
365 } | |
366 } | |
367 DeleteArray(line); | |
368 } | |
369 | |
370 // Add all the breakpoints back to stop execution and enter the debugger | |
371 // shell when hit. | |
372 RedoBreakpoints(); | |
373 | |
374 #undef COMMAND_SIZE | |
375 #undef ARG_SIZE | |
376 | |
377 #undef STR | |
378 #undef XSTR | |
379 } | |
380 | |
381 | |
382 Simulator::Simulator() { | |
383 // Setup simulator support first. Some of this information is needed to | |
384 // setup the architecture state. | |
385 size_t stack_size = 1 * 1024*1024; // allocate 1MB for stack | |
386 stack_ = reinterpret_cast<char*>(malloc(stack_size)); | |
387 pc_modified_ = false; | |
388 icount_ = 0; | |
389 break_pc_ = NULL; | |
390 break_instr_ = 0; | |
391 | |
392 // Setup architecture state. | |
393 // All registers are initialized to zero to start with. | |
394 for (int i = 0; i < num_registers; i++) { | |
395 registers_[i] = 0; | |
396 } | |
397 n_flag_ = false; | |
398 z_flag_ = false; | |
399 c_flag_ = false; | |
400 v_flag_ = false; | |
401 | |
402 // The sp is initialized to point to the bottom (high address) of the | |
403 // allocated stack area. To be safe in potential stack underflows we leave | |
404 // some buffer below. | |
405 registers_[sp] = reinterpret_cast<int32_t>(stack_) + stack_size - 64; | |
406 // The lr and pc are initialized to a known bad value that will cause an | |
407 // access violation if the simulator ever tries to execute it. | |
408 registers_[pc] = bad_lr; | |
409 registers_[lr] = bad_lr; | |
410 InitializeCoverage(); | |
411 } | |
412 | |
413 | |
414 // Create one simulator per thread and keep it in thread local storage. | |
415 static v8::internal::Thread::LocalStorageKey simulator_key = | |
416 v8::internal::Thread::CreateThreadLocalKey(); | |
417 | |
418 // Get the active Simulator for the current thread. | |
419 Simulator* Simulator::current() { | |
420 Simulator* sim = reinterpret_cast<Simulator*>( | |
421 v8::internal::Thread::GetThreadLocal(simulator_key)); | |
422 if (sim == NULL) { | |
423 // TODO(146): delete the simulator object when a thread goes away. | |
424 sim = new Simulator(); | |
425 v8::internal::Thread::SetThreadLocal(simulator_key, sim); | |
426 } | |
427 return sim; | |
428 } | |
429 | |
430 | |
431 // Sets the register in the architecture state. It will also deal with updating | |
432 // Simulator internal state for special registers such as PC. | |
433 void Simulator::set_register(int reg, int32_t value) { | |
434 ASSERT((reg >= 0) && (reg < num_registers)); | |
435 if (reg == pc) { | |
436 pc_modified_ = true; | |
437 } | |
438 registers_[reg] = value; | |
439 } | |
440 | |
441 | |
442 // Get the register from the architecture state. This function does handle | |
443 // the special case of accessing the PC register. | |
444 int32_t Simulator::get_register(int reg) const { | |
445 ASSERT((reg >= 0) && (reg < num_registers)); | |
446 return registers_[reg] + ((reg == pc) ? Instr::kPCReadOffset : 0); | |
447 } | |
448 | |
449 | |
450 // Raw access to the PC register. | |
451 void Simulator::set_pc(int32_t value) { | |
452 pc_modified_ = true; | |
453 registers_[pc] = value; | |
454 } | |
455 | |
456 | |
457 // Raw access to the PC register without the special adjustment when reading. | |
458 int32_t Simulator::get_pc() const { | |
459 return registers_[pc]; | |
460 } | |
461 | |
462 | |
463 // For use in calls that take two double values, constructed from r0, r1, r2 | |
464 // and r3. | |
465 void Simulator::GetFpArgs(double* x, double* y) { | |
466 // We use a char buffer to get around the strict-aliasing rules which | |
467 // otherwise allow the compiler to optimize away the copy. | |
468 char buffer[2 * sizeof(registers_[0])]; | |
469 // Registers 0 and 1 -> x. | |
470 memcpy(buffer, registers_, sizeof(buffer)); | |
471 memcpy(x, buffer, sizeof(buffer)); | |
472 // Registers 2 and 3 -> y. | |
473 memcpy(buffer, registers_ + 2, sizeof(buffer)); | |
474 memcpy(y, buffer, sizeof(buffer)); | |
475 } | |
476 | |
477 | |
478 void Simulator::SetFpResult(const double& result) { | |
479 char buffer[2 * sizeof(registers_[0])]; | |
480 memcpy(buffer, &result, sizeof(buffer)); | |
481 // result -> registers 0 and 1. | |
482 memcpy(registers_, buffer, sizeof(buffer)); | |
483 } | |
484 | |
485 | |
486 void Simulator::TrashCallerSaveRegisters() { | |
487 // We don't trash the registers with the return value. | |
488 registers_[2] = 0x50Bad4U; | |
489 registers_[3] = 0x50Bad4U; | |
490 registers_[12] = 0x50Bad4U; | |
491 } | |
492 | |
493 | |
494 // The ARM cannot do unaligned reads and writes. On some ARM platforms an | |
495 // interrupt is caused. On others it does a funky rotation thing. For now we | |
496 // simply disallow unaligned reads, but at some point we may want to move to | |
497 // emulating the rotate behaviour. Note that simulator runs have the runtime | |
498 // system running directly on the host system and only generated code is | |
499 // executed in the simulator. Since the host is typically IA32 we will not | |
500 // get the correct ARM-like behaviour on unaligned accesses. | |
501 | |
502 int Simulator::ReadW(int32_t addr, Instr* instr) { | |
503 if ((addr & 3) == 0) { | |
504 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); | |
505 return *ptr; | |
506 } | |
507 PrintF("Unaligned read at %x\n", addr); | |
508 UNIMPLEMENTED(); | |
509 return 0; | |
510 } | |
511 | |
512 | |
513 void Simulator::WriteW(int32_t addr, int value, Instr* instr) { | |
514 if ((addr & 3) == 0) { | |
515 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); | |
516 *ptr = value; | |
517 return; | |
518 } | |
519 PrintF("Unaligned write at %x, pc=%p\n", addr, instr); | |
520 UNIMPLEMENTED(); | |
521 } | |
522 | |
523 | |
524 uint16_t Simulator::ReadHU(int32_t addr, Instr* instr) { | |
525 if ((addr & 1) == 0) { | |
526 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); | |
527 return *ptr; | |
528 } | |
529 PrintF("Unaligned read at %x, pc=%p\n", addr, instr); | |
530 UNIMPLEMENTED(); | |
531 return 0; | |
532 } | |
533 | |
534 | |
535 int16_t Simulator::ReadH(int32_t addr, Instr* instr) { | |
536 if ((addr & 1) == 0) { | |
537 int16_t* ptr = reinterpret_cast<int16_t*>(addr); | |
538 return *ptr; | |
539 } | |
540 PrintF("Unaligned read at %x\n", addr); | |
541 UNIMPLEMENTED(); | |
542 return 0; | |
543 } | |
544 | |
545 | |
546 void Simulator::WriteH(int32_t addr, uint16_t value, Instr* instr) { | |
547 if ((addr & 1) == 0) { | |
548 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); | |
549 *ptr = value; | |
550 return; | |
551 } | |
552 PrintF("Unaligned write at %x, pc=%p\n", addr, instr); | |
553 UNIMPLEMENTED(); | |
554 } | |
555 | |
556 | |
557 void Simulator::WriteH(int32_t addr, int16_t value, Instr* instr) { | |
558 if ((addr & 1) == 0) { | |
559 int16_t* ptr = reinterpret_cast<int16_t*>(addr); | |
560 *ptr = value; | |
561 return; | |
562 } | |
563 PrintF("Unaligned write at %x, pc=%p\n", addr, instr); | |
564 UNIMPLEMENTED(); | |
565 } | |
566 | |
567 | |
568 uint8_t Simulator::ReadBU(int32_t addr) { | |
569 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); | |
570 return *ptr; | |
571 } | |
572 | |
573 | |
574 int8_t Simulator::ReadB(int32_t addr) { | |
575 int8_t* ptr = reinterpret_cast<int8_t*>(addr); | |
576 return *ptr; | |
577 } | |
578 | |
579 | |
580 void Simulator::WriteB(int32_t addr, uint8_t value) { | |
581 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); | |
582 *ptr = value; | |
583 } | |
584 | |
585 | |
586 void Simulator::WriteB(int32_t addr, int8_t value) { | |
587 int8_t* ptr = reinterpret_cast<int8_t*>(addr); | |
588 *ptr = value; | |
589 } | |
590 | |
591 | |
592 // Returns the limit of the stack area to enable checking for stack overflows. | |
593 uintptr_t Simulator::StackLimit() const { | |
594 // Leave a safety margin of 256 bytes to prevent overrunning the stack when | |
595 // pushing values. | |
596 return reinterpret_cast<uintptr_t>(stack_) + 256; | |
597 } | |
598 | |
599 | |
600 // Unsupported instructions use Format to print an error and stop execution. | |
601 void Simulator::Format(Instr* instr, const char* format) { | |
602 PrintF("Simulator found unsupported instruction:\n 0x%x: %s\n", | |
603 instr, format); | |
604 UNIMPLEMENTED(); | |
605 } | |
606 | |
607 | |
608 // Checks if the current instruction should be executed based on its | |
609 // condition bits. | |
610 bool Simulator::ConditionallyExecute(Instr* instr) { | |
611 switch (instr->ConditionField()) { | |
612 case EQ: return z_flag_; | |
613 case NE: return !z_flag_; | |
614 case CS: return c_flag_; | |
615 case CC: return !c_flag_; | |
616 case MI: return n_flag_; | |
617 case PL: return !n_flag_; | |
618 case VS: return v_flag_; | |
619 case VC: return !v_flag_; | |
620 case HI: return c_flag_ && !z_flag_; | |
621 case LS: return !c_flag_ || z_flag_; | |
622 case GE: return n_flag_ == v_flag_; | |
623 case LT: return n_flag_ != v_flag_; | |
624 case GT: return !z_flag_ && (n_flag_ == v_flag_); | |
625 case LE: return z_flag_ || (n_flag_ != v_flag_); | |
626 case AL: return true; | |
627 default: UNREACHABLE(); | |
628 } | |
629 return false; | |
630 } | |
631 | |
632 | |
633 // Calculate and set the Negative and Zero flags. | |
634 void Simulator::SetNZFlags(int32_t val) { | |
635 n_flag_ = (val < 0); | |
636 z_flag_ = (val == 0); | |
637 } | |
638 | |
639 | |
640 // Set the Carry flag. | |
641 void Simulator::SetCFlag(bool val) { | |
642 c_flag_ = val; | |
643 } | |
644 | |
645 | |
646 // Set the oVerflow flag. | |
647 void Simulator::SetVFlag(bool val) { | |
648 v_flag_ = val; | |
649 } | |
650 | |
651 | |
652 // Calculate C flag value for additions. | |
653 bool Simulator::CarryFrom(int32_t left, int32_t right) { | |
654 uint32_t uleft = static_cast<uint32_t>(left); | |
655 uint32_t uright = static_cast<uint32_t>(right); | |
656 uint32_t urest = 0xffffffffU - uleft; | |
657 | |
658 return (uright > urest); | |
659 } | |
660 | |
661 | |
662 // Calculate C flag value for subtractions. | |
663 bool Simulator::BorrowFrom(int32_t left, int32_t right) { | |
664 uint32_t uleft = static_cast<uint32_t>(left); | |
665 uint32_t uright = static_cast<uint32_t>(right); | |
666 | |
667 return (uright > uleft); | |
668 } | |
669 | |
670 | |
671 // Calculate V flag value for additions and subtractions. | |
672 bool Simulator::OverflowFrom(int32_t alu_out, | |
673 int32_t left, int32_t right, bool addition) { | |
674 bool overflow; | |
675 if (addition) { | |
676 // operands have the same sign | |
677 overflow = ((left >= 0 && right >= 0) || (left < 0 && right < 0)) | |
678 // and operands and result have different sign | |
679 && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0)); | |
680 } else { | |
681 // operands have different signs | |
682 overflow = ((left < 0 && right >= 0) || (left >= 0 && right < 0)) | |
683 // and first operand and result have different signs | |
684 && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0)); | |
685 } | |
686 return overflow; | |
687 } | |
688 | |
689 | |
690 // Addressing Mode 1 - Data-processing operands: | |
691 // Get the value based on the shifter_operand with register. | |
692 int32_t Simulator::GetShiftRm(Instr* instr, bool* carry_out) { | |
693 Shift shift = instr->ShiftField(); | |
694 int shift_amount = instr->ShiftAmountField(); | |
695 int32_t result = get_register(instr->RmField()); | |
696 if (instr->Bit(4) == 0) { | |
697 // by immediate | |
698 if ((shift == ROR) && (shift_amount == 0)) { | |
699 UNIMPLEMENTED(); | |
700 return result; | |
701 } else if (((shift == LSR) || (shift == ASR)) && (shift_amount == 0)) { | |
702 shift_amount = 32; | |
703 } | |
704 switch (shift) { | |
705 case ASR: { | |
706 if (shift_amount == 0) { | |
707 if (result < 0) { | |
708 result = 0xffffffff; | |
709 *carry_out = true; | |
710 } else { | |
711 result = 0; | |
712 *carry_out = false; | |
713 } | |
714 } else { | |
715 result >>= (shift_amount - 1); | |
716 *carry_out = (result & 1) == 1; | |
717 result >>= 1; | |
718 } | |
719 break; | |
720 } | |
721 | |
722 case LSL: { | |
723 if (shift_amount == 0) { | |
724 *carry_out = c_flag_; | |
725 } else { | |
726 result <<= (shift_amount - 1); | |
727 *carry_out = (result < 0); | |
728 result <<= 1; | |
729 } | |
730 break; | |
731 } | |
732 | |
733 case LSR: { | |
734 if (shift_amount == 0) { | |
735 result = 0; | |
736 *carry_out = c_flag_; | |
737 } else { | |
738 uint32_t uresult = static_cast<uint32_t>(result); | |
739 uresult >>= (shift_amount - 1); | |
740 *carry_out = (uresult & 1) == 1; | |
741 uresult >>= 1; | |
742 result = static_cast<int32_t>(uresult); | |
743 } | |
744 break; | |
745 } | |
746 | |
747 case ROR: { | |
748 UNIMPLEMENTED(); | |
749 break; | |
750 } | |
751 | |
752 default: { | |
753 UNREACHABLE(); | |
754 break; | |
755 } | |
756 } | |
757 } else { | |
758 // by register | |
759 int rs = instr->RsField(); | |
760 shift_amount = get_register(rs) &0xff; | |
761 switch (shift) { | |
762 case ASR: { | |
763 if (shift_amount == 0) { | |
764 *carry_out = c_flag_; | |
765 } else if (shift_amount < 32) { | |
766 result >>= (shift_amount - 1); | |
767 *carry_out = (result & 1) == 1; | |
768 result >>= 1; | |
769 } else { | |
770 ASSERT(shift_amount >= 32); | |
771 if (result < 0) { | |
772 *carry_out = true; | |
773 result = 0xffffffff; | |
774 } else { | |
775 *carry_out = false; | |
776 result = 0; | |
777 } | |
778 } | |
779 break; | |
780 } | |
781 | |
782 case LSL: { | |
783 if (shift_amount == 0) { | |
784 *carry_out = c_flag_; | |
785 } else if (shift_amount < 32) { | |
786 result <<= (shift_amount - 1); | |
787 *carry_out = (result < 0); | |
788 result <<= 1; | |
789 } else if (shift_amount == 32) { | |
790 *carry_out = (result & 1) == 1; | |
791 result = 0; | |
792 } else { | |
793 ASSERT(shift_amount > 32); | |
794 *carry_out = false; | |
795 result = 0; | |
796 } | |
797 break; | |
798 } | |
799 | |
800 case LSR: { | |
801 if (shift_amount == 0) { | |
802 *carry_out = c_flag_; | |
803 } else if (shift_amount < 32) { | |
804 uint32_t uresult = static_cast<uint32_t>(result); | |
805 uresult >>= (shift_amount - 1); | |
806 *carry_out = (uresult & 1) == 1; | |
807 uresult >>= 1; | |
808 result = static_cast<int32_t>(uresult); | |
809 } else if (shift_amount == 32) { | |
810 *carry_out = (result < 0); | |
811 result = 0; | |
812 } else { | |
813 *carry_out = false; | |
814 result = 0; | |
815 } | |
816 break; | |
817 } | |
818 | |
819 case ROR: { | |
820 UNIMPLEMENTED(); | |
821 break; | |
822 } | |
823 | |
824 default: { | |
825 UNREACHABLE(); | |
826 break; | |
827 } | |
828 } | |
829 } | |
830 return result; | |
831 } | |
832 | |
833 | |
834 // Addressing Mode 1 - Data-processing operands: | |
835 // Get the value based on the shifter_operand with immediate. | |
836 int32_t Simulator::GetImm(Instr* instr, bool* carry_out) { | |
837 int rotate = instr->RotateField() * 2; | |
838 int immed8 = instr->Immed8Field(); | |
839 int imm = (immed8 >> rotate) | (immed8 << (32 - rotate)); | |
840 *carry_out = (rotate == 0) ? c_flag_ : (imm < 0); | |
841 return imm; | |
842 } | |
843 | |
844 | |
845 static int count_bits(int bit_vector) { | |
846 int count = 0; | |
847 while (bit_vector != 0) { | |
848 if ((bit_vector & 1) != 0) { | |
849 count++; | |
850 } | |
851 bit_vector >>= 1; | |
852 } | |
853 return count; | |
854 } | |
855 | |
856 | |
857 // Addressing Mode 4 - Load and Store Multiple | |
858 void Simulator::HandleRList(Instr* instr, bool load) { | |
859 int rn = instr->RnField(); | |
860 int32_t rn_val = get_register(rn); | |
861 int rlist = instr->RlistField(); | |
862 int num_regs = count_bits(rlist); | |
863 | |
864 intptr_t start_address = 0; | |
865 intptr_t end_address = 0; | |
866 switch (instr->PUField()) { | |
867 case 0: { | |
868 // Print("da"); | |
869 UNIMPLEMENTED(); | |
870 break; | |
871 } | |
872 case 1: { | |
873 // Print("ia"); | |
874 start_address = rn_val; | |
875 end_address = rn_val + (num_regs * 4) - 4; | |
876 rn_val = rn_val + (num_regs * 4); | |
877 break; | |
878 } | |
879 case 2: { | |
880 // Print("db"); | |
881 start_address = rn_val - (num_regs * 4); | |
882 end_address = rn_val - 4; | |
883 rn_val = start_address; | |
884 break; | |
885 } | |
886 case 3: { | |
887 // Print("ib"); | |
888 UNIMPLEMENTED(); | |
889 break; | |
890 } | |
891 default: { | |
892 UNREACHABLE(); | |
893 break; | |
894 } | |
895 } | |
896 if (instr->HasW()) { | |
897 set_register(rn, rn_val); | |
898 } | |
899 intptr_t* address = reinterpret_cast<intptr_t*>(start_address); | |
900 int reg = 0; | |
901 while (rlist != 0) { | |
902 if ((rlist & 1) != 0) { | |
903 if (load) { | |
904 set_register(reg, *address); | |
905 } else { | |
906 *address = get_register(reg); | |
907 } | |
908 address += 1; | |
909 } | |
910 reg++; | |
911 rlist >>= 1; | |
912 } | |
913 ASSERT(end_address == ((intptr_t)address) - 4); | |
914 } | |
915 | |
916 | |
917 // Calls into the V8 runtime are based on this very simple interface. | |
918 // Note: To be able to return two values from some calls the code in runtime.cc | |
919 // uses the ObjectPair which is essentially two 32-bit values stuffed into a | |
920 // 64-bit value. With the code below we assume that all runtime calls return | |
921 // 64 bits of result. If they don't, the r1 result register contains a bogus | |
922 // value, which is fine because it is caller-saved. | |
923 typedef int64_t (*SimulatorRuntimeCall)(intptr_t arg0, intptr_t arg1); | |
924 | |
925 | |
926 // Software interrupt instructions are used by the simulator to call into the | |
927 // C-based V8 runtime. | |
928 void Simulator::SoftwareInterrupt(Instr* instr) { | |
929 int swi = instr->SwiField(); | |
930 switch (swi) { | |
931 case call_rt_r5: { | |
932 SimulatorRuntimeCall target = | |
933 reinterpret_cast<SimulatorRuntimeCall>(get_register(r5)); | |
934 intptr_t arg0 = get_register(r0); | |
935 intptr_t arg1 = get_register(r1); | |
936 int64_t result = target(arg0, arg1); | |
937 int32_t lo_res = static_cast<int32_t>(result); | |
938 int32_t hi_res = static_cast<int32_t>(result >> 32); | |
939 set_register(r0, lo_res); | |
940 set_register(r1, hi_res); | |
941 set_pc(reinterpret_cast<int32_t>(instr) + Instr::kInstrSize); | |
942 break; | |
943 } | |
944 case call_rt_r2: { | |
945 SimulatorRuntimeCall target = | |
946 reinterpret_cast<SimulatorRuntimeCall>(get_register(r2)); | |
947 intptr_t arg0 = get_register(r0); | |
948 intptr_t arg1 = get_register(r1); | |
949 int64_t result = target(arg0, arg1); | |
950 int32_t lo_res = static_cast<int32_t>(result); | |
951 int32_t hi_res = static_cast<int32_t>(result >> 32); | |
952 set_register(r0, lo_res); | |
953 set_register(r1, hi_res); | |
954 set_pc(reinterpret_cast<int32_t>(instr) + Instr::kInstrSize); | |
955 break; | |
956 } | |
957 case break_point: { | |
958 Debugger dbg(this); | |
959 dbg.Debug(); | |
960 break; | |
961 } | |
962 { | |
963 double x, y, z; | |
964 case simulator_fp_add: | |
965 GetFpArgs(&x, &y); | |
966 z = x + y; | |
967 SetFpResult(z); | |
968 TrashCallerSaveRegisters(); | |
969 set_pc(reinterpret_cast<int32_t>(instr) + Instr::kInstrSize); | |
970 break; | |
971 case simulator_fp_sub: | |
972 GetFpArgs(&x, &y); | |
973 z = x - y; | |
974 SetFpResult(z); | |
975 TrashCallerSaveRegisters(); | |
976 set_pc(reinterpret_cast<int32_t>(instr) + Instr::kInstrSize); | |
977 break; | |
978 case simulator_fp_mul: | |
979 GetFpArgs(&x, &y); | |
980 z = x * y; | |
981 SetFpResult(z); | |
982 TrashCallerSaveRegisters(); | |
983 set_pc(reinterpret_cast<int32_t>(instr) + Instr::kInstrSize); | |
984 break; | |
985 } | |
986 default: { | |
987 UNREACHABLE(); | |
988 break; | |
989 } | |
990 } | |
991 } | |
992 | |
993 | |
994 // Handle execution based on instruction types. | |
995 | |
996 // Instruction types 0 and 1 are both rolled into one function because they | |
997 // only differ in the handling of the shifter_operand. | |
998 void Simulator::DecodeType01(Instr* instr) { | |
999 int type = instr->TypeField(); | |
1000 if ((type == 0) && instr->IsSpecialType0()) { | |
1001 // multiply instruction or extra loads and stores | |
1002 if (instr->Bits(7, 4) == 9) { | |
1003 if (instr->Bit(24) == 0) { | |
1004 // multiply instructions | |
1005 int rd = instr->RdField(); | |
1006 int rm = instr->RmField(); | |
1007 int rs = instr->RsField(); | |
1008 int32_t rs_val = get_register(rs); | |
1009 int32_t rm_val = get_register(rm); | |
1010 if (instr->Bit(23) == 0) { | |
1011 if (instr->Bit(21) == 0) { | |
1012 // Format(instr, "mul'cond's 'rd, 'rm, 'rs"); | |
1013 int32_t alu_out = rm_val * rs_val; | |
1014 set_register(rd, alu_out); | |
1015 if (instr->HasS()) { | |
1016 SetNZFlags(alu_out); | |
1017 } | |
1018 } else { | |
1019 Format(instr, "mla'cond's 'rd, 'rm, 'rs, 'rn"); | |
1020 } | |
1021 } else { | |
1022 // Format(instr, "'um'al'cond's 'rn, 'rd, 'rs, 'rm"); | |
1023 int rn = instr->RnField(); | |
1024 int32_t hi_res = 0; | |
1025 int32_t lo_res = 0; | |
1026 if (instr->Bit(22) == 0) { | |
1027 // signed multiply | |
1028 UNIMPLEMENTED(); | |
1029 } else { | |
1030 // unsigned multiply | |
1031 uint64_t left_op = rm_val; | |
1032 uint64_t right_op = rs_val; | |
1033 uint64_t result = left_op * right_op; | |
1034 hi_res = static_cast<int32_t>(result >> 32); | |
1035 lo_res = static_cast<int32_t>(result & 0xffffffff); | |
1036 } | |
1037 set_register(rn, hi_res); | |
1038 set_register(rd, lo_res); | |
1039 if (instr->HasS()) { | |
1040 UNIMPLEMENTED(); | |
1041 } | |
1042 } | |
1043 } else { | |
1044 UNIMPLEMENTED(); // not used by V8 | |
1045 } | |
1046 } else { | |
1047 // extra load/store instructions | |
1048 int rd = instr->RdField(); | |
1049 int rn = instr->RnField(); | |
1050 int32_t rn_val = get_register(rn); | |
1051 int32_t addr = 0; | |
1052 if (instr->Bit(22) == 0) { | |
1053 int rm = instr->RmField(); | |
1054 int32_t rm_val = get_register(rm); | |
1055 switch (instr->PUField()) { | |
1056 case 0: { | |
1057 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], -'rm"); | |
1058 ASSERT(!instr->HasW()); | |
1059 addr = rn_val; | |
1060 rn_val -= rm_val; | |
1061 set_register(rn, rn_val); | |
1062 break; | |
1063 } | |
1064 case 1: { | |
1065 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], +'rm"); | |
1066 ASSERT(!instr->HasW()); | |
1067 addr = rn_val; | |
1068 rn_val += rm_val; | |
1069 set_register(rn, rn_val); | |
1070 break; | |
1071 } | |
1072 case 2: { | |
1073 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, -'rm]'w"); | |
1074 rn_val -= rm_val; | |
1075 addr = rn_val; | |
1076 if (instr->HasW()) { | |
1077 set_register(rn, rn_val); | |
1078 } | |
1079 break; | |
1080 } | |
1081 case 3: { | |
1082 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, +'rm]'w"); | |
1083 rn_val += rm_val; | |
1084 addr = rn_val; | |
1085 if (instr->HasW()) { | |
1086 set_register(rn, rn_val); | |
1087 } | |
1088 break; | |
1089 } | |
1090 default: { | |
1091 // The PU field is a 2-bit field. | |
1092 UNREACHABLE(); | |
1093 break; | |
1094 } | |
1095 } | |
1096 } else { | |
1097 int32_t imm_val = (instr->ImmedHField() << 4) | instr->ImmedLField(); | |
1098 switch (instr->PUField()) { | |
1099 case 0: { | |
1100 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], #-'off8"); | |
1101 ASSERT(!instr->HasW()); | |
1102 addr = rn_val; | |
1103 rn_val -= imm_val; | |
1104 set_register(rn, rn_val); | |
1105 break; | |
1106 } | |
1107 case 1: { | |
1108 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], #+'off8"); | |
1109 ASSERT(!instr->HasW()); | |
1110 addr = rn_val; | |
1111 rn_val += imm_val; | |
1112 set_register(rn, rn_val); | |
1113 break; | |
1114 } | |
1115 case 2: { | |
1116 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, #-'off8]'w"); | |
1117 rn_val -= imm_val; | |
1118 addr = rn_val; | |
1119 if (instr->HasW()) { | |
1120 set_register(rn, rn_val); | |
1121 } | |
1122 break; | |
1123 } | |
1124 case 3: { | |
1125 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, #+'off8]'w"); | |
1126 rn_val += imm_val; | |
1127 addr = rn_val; | |
1128 if (instr->HasW()) { | |
1129 set_register(rn, rn_val); | |
1130 } | |
1131 break; | |
1132 } | |
1133 default: { | |
1134 // The PU field is a 2-bit field. | |
1135 UNREACHABLE(); | |
1136 break; | |
1137 } | |
1138 } | |
1139 } | |
1140 if (instr->HasH()) { | |
1141 if (instr->HasSign()) { | |
1142 if (instr->HasL()) { | |
1143 int16_t val = ReadH(addr, instr); | |
1144 set_register(rd, val); | |
1145 } else { | |
1146 int16_t val = get_register(rd); | |
1147 WriteH(addr, val, instr); | |
1148 } | |
1149 } else { | |
1150 if (instr->HasL()) { | |
1151 uint16_t val = ReadHU(addr, instr); | |
1152 set_register(rd, val); | |
1153 } else { | |
1154 uint16_t val = get_register(rd); | |
1155 WriteH(addr, val, instr); | |
1156 } | |
1157 } | |
1158 } else { | |
1159 // signed byte loads | |
1160 ASSERT(instr->HasSign()); | |
1161 ASSERT(instr->HasL()); | |
1162 int8_t val = ReadB(addr); | |
1163 set_register(rd, val); | |
1164 } | |
1165 return; | |
1166 } | |
1167 } else { | |
1168 int rd = instr->RdField(); | |
1169 int rn = instr->RnField(); | |
1170 int32_t rn_val = get_register(rn); | |
1171 int32_t shifter_operand = 0; | |
1172 bool shifter_carry_out = 0; | |
1173 if (type == 0) { | |
1174 shifter_operand = GetShiftRm(instr, &shifter_carry_out); | |
1175 } else { | |
1176 ASSERT(instr->TypeField() == 1); | |
1177 shifter_operand = GetImm(instr, &shifter_carry_out); | |
1178 } | |
1179 int32_t alu_out; | |
1180 | |
1181 switch (instr->OpcodeField()) { | |
1182 case AND: { | |
1183 // Format(instr, "and'cond's 'rd, 'rn, 'shift_rm"); | |
1184 // Format(instr, "and'cond's 'rd, 'rn, 'imm"); | |
1185 alu_out = rn_val & shifter_operand; | |
1186 set_register(rd, alu_out); | |
1187 if (instr->HasS()) { | |
1188 SetNZFlags(alu_out); | |
1189 SetCFlag(shifter_carry_out); | |
1190 } | |
1191 break; | |
1192 } | |
1193 | |
1194 case EOR: { | |
1195 // Format(instr, "eor'cond's 'rd, 'rn, 'shift_rm"); | |
1196 // Format(instr, "eor'cond's 'rd, 'rn, 'imm"); | |
1197 alu_out = rn_val ^ shifter_operand; | |
1198 set_register(rd, alu_out); | |
1199 if (instr->HasS()) { | |
1200 SetNZFlags(alu_out); | |
1201 SetCFlag(shifter_carry_out); | |
1202 } | |
1203 break; | |
1204 } | |
1205 | |
1206 case SUB: { | |
1207 // Format(instr, "sub'cond's 'rd, 'rn, 'shift_rm"); | |
1208 // Format(instr, "sub'cond's 'rd, 'rn, 'imm"); | |
1209 alu_out = rn_val - shifter_operand; | |
1210 set_register(rd, alu_out); | |
1211 if (instr->HasS()) { | |
1212 SetNZFlags(alu_out); | |
1213 SetCFlag(!BorrowFrom(rn_val, shifter_operand)); | |
1214 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, false)); | |
1215 } | |
1216 break; | |
1217 } | |
1218 | |
1219 case RSB: { | |
1220 // Format(instr, "rsb'cond's 'rd, 'rn, 'shift_rm"); | |
1221 // Format(instr, "rsb'cond's 'rd, 'rn, 'imm"); | |
1222 alu_out = shifter_operand - rn_val; | |
1223 set_register(rd, alu_out); | |
1224 if (instr->HasS()) { | |
1225 SetNZFlags(alu_out); | |
1226 SetCFlag(!BorrowFrom(shifter_operand, rn_val)); | |
1227 SetVFlag(OverflowFrom(alu_out, shifter_operand, rn_val, false)); | |
1228 } | |
1229 break; | |
1230 } | |
1231 | |
1232 case ADD: { | |
1233 // Format(instr, "add'cond's 'rd, 'rn, 'shift_rm"); | |
1234 // Format(instr, "add'cond's 'rd, 'rn, 'imm"); | |
1235 alu_out = rn_val + shifter_operand; | |
1236 set_register(rd, alu_out); | |
1237 if (instr->HasS()) { | |
1238 SetNZFlags(alu_out); | |
1239 SetCFlag(CarryFrom(rn_val, shifter_operand)); | |
1240 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, true)); | |
1241 } | |
1242 break; | |
1243 } | |
1244 | |
1245 case ADC: { | |
1246 Format(instr, "adc'cond's 'rd, 'rn, 'shift_rm"); | |
1247 Format(instr, "adc'cond's 'rd, 'rn, 'imm"); | |
1248 break; | |
1249 } | |
1250 | |
1251 case SBC: { | |
1252 Format(instr, "sbc'cond's 'rd, 'rn, 'shift_rm"); | |
1253 Format(instr, "sbc'cond's 'rd, 'rn, 'imm"); | |
1254 break; | |
1255 } | |
1256 | |
1257 case RSC: { | |
1258 Format(instr, "rsc'cond's 'rd, 'rn, 'shift_rm"); | |
1259 Format(instr, "rsc'cond's 'rd, 'rn, 'imm"); | |
1260 break; | |
1261 } | |
1262 | |
1263 case TST: { | |
1264 if (instr->HasS()) { | |
1265 // Format(instr, "tst'cond 'rn, 'shift_rm"); | |
1266 // Format(instr, "tst'cond 'rn, 'imm"); | |
1267 alu_out = rn_val & shifter_operand; | |
1268 SetNZFlags(alu_out); | |
1269 SetCFlag(shifter_carry_out); | |
1270 } else { | |
1271 UNIMPLEMENTED(); | |
1272 } | |
1273 break; | |
1274 } | |
1275 | |
1276 case TEQ: { | |
1277 if (instr->HasS()) { | |
1278 // Format(instr, "teq'cond 'rn, 'shift_rm"); | |
1279 // Format(instr, "teq'cond 'rn, 'imm"); | |
1280 alu_out = rn_val ^ shifter_operand; | |
1281 SetNZFlags(alu_out); | |
1282 SetCFlag(shifter_carry_out); | |
1283 } else { | |
1284 UNIMPLEMENTED(); | |
1285 } | |
1286 break; | |
1287 } | |
1288 | |
1289 case CMP: { | |
1290 if (instr->HasS()) { | |
1291 // Format(instr, "cmp'cond 'rn, 'shift_rm"); | |
1292 // Format(instr, "cmp'cond 'rn, 'imm"); | |
1293 alu_out = rn_val - shifter_operand; | |
1294 SetNZFlags(alu_out); | |
1295 SetCFlag(!BorrowFrom(rn_val, shifter_operand)); | |
1296 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, false)); | |
1297 } else { | |
1298 UNIMPLEMENTED(); | |
1299 } | |
1300 break; | |
1301 } | |
1302 | |
1303 case CMN: { | |
1304 if (instr->HasS()) { | |
1305 Format(instr, "cmn'cond 'rn, 'shift_rm"); | |
1306 Format(instr, "cmn'cond 'rn, 'imm"); | |
1307 } else { | |
1308 UNIMPLEMENTED(); | |
1309 } | |
1310 break; | |
1311 } | |
1312 | |
1313 case ORR: { | |
1314 // Format(instr, "orr'cond's 'rd, 'rn, 'shift_rm"); | |
1315 // Format(instr, "orr'cond's 'rd, 'rn, 'imm"); | |
1316 alu_out = rn_val | shifter_operand; | |
1317 set_register(rd, alu_out); | |
1318 if (instr->HasS()) { | |
1319 SetNZFlags(alu_out); | |
1320 SetCFlag(shifter_carry_out); | |
1321 } | |
1322 break; | |
1323 } | |
1324 | |
1325 case MOV: { | |
1326 // Format(instr, "mov'cond's 'rd, 'shift_rm"); | |
1327 // Format(instr, "mov'cond's 'rd, 'imm"); | |
1328 alu_out = shifter_operand; | |
1329 set_register(rd, alu_out); | |
1330 if (instr->HasS()) { | |
1331 SetNZFlags(alu_out); | |
1332 SetCFlag(shifter_carry_out); | |
1333 } | |
1334 break; | |
1335 } | |
1336 | |
1337 case BIC: { | |
1338 // Format(instr, "bic'cond's 'rd, 'rn, 'shift_rm"); | |
1339 // Format(instr, "bic'cond's 'rd, 'rn, 'imm"); | |
1340 alu_out = rn_val & ~shifter_operand; | |
1341 set_register(rd, alu_out); | |
1342 if (instr->HasS()) { | |
1343 SetNZFlags(alu_out); | |
1344 SetCFlag(shifter_carry_out); | |
1345 } | |
1346 break; | |
1347 } | |
1348 | |
1349 case MVN: { | |
1350 // Format(instr, "mvn'cond's 'rd, 'shift_rm"); | |
1351 // Format(instr, "mvn'cond's 'rd, 'imm"); | |
1352 alu_out = ~shifter_operand; | |
1353 set_register(rd, alu_out); | |
1354 if (instr->HasS()) { | |
1355 SetNZFlags(alu_out); | |
1356 SetCFlag(shifter_carry_out); | |
1357 } | |
1358 break; | |
1359 } | |
1360 | |
1361 default: { | |
1362 UNREACHABLE(); | |
1363 break; | |
1364 } | |
1365 } | |
1366 } | |
1367 } | |
1368 | |
1369 | |
1370 void Simulator::DecodeType2(Instr* instr) { | |
1371 int rd = instr->RdField(); | |
1372 int rn = instr->RnField(); | |
1373 int32_t rn_val = get_register(rn); | |
1374 int32_t im_val = instr->Offset12Field(); | |
1375 int32_t addr = 0; | |
1376 switch (instr->PUField()) { | |
1377 case 0: { | |
1378 // Format(instr, "'memop'cond'b 'rd, ['rn], #-'off12"); | |
1379 ASSERT(!instr->HasW()); | |
1380 addr = rn_val; | |
1381 rn_val -= im_val; | |
1382 set_register(rn, rn_val); | |
1383 break; | |
1384 } | |
1385 case 1: { | |
1386 // Format(instr, "'memop'cond'b 'rd, ['rn], #+'off12"); | |
1387 ASSERT(!instr->HasW()); | |
1388 addr = rn_val; | |
1389 rn_val += im_val; | |
1390 set_register(rn, rn_val); | |
1391 break; | |
1392 } | |
1393 case 2: { | |
1394 // Format(instr, "'memop'cond'b 'rd, ['rn, #-'off12]'w"); | |
1395 rn_val -= im_val; | |
1396 addr = rn_val; | |
1397 if (instr->HasW()) { | |
1398 set_register(rn, rn_val); | |
1399 } | |
1400 break; | |
1401 } | |
1402 case 3: { | |
1403 // Format(instr, "'memop'cond'b 'rd, ['rn, #+'off12]'w"); | |
1404 rn_val += im_val; | |
1405 addr = rn_val; | |
1406 if (instr->HasW()) { | |
1407 set_register(rn, rn_val); | |
1408 } | |
1409 break; | |
1410 } | |
1411 default: { | |
1412 UNREACHABLE(); | |
1413 break; | |
1414 } | |
1415 } | |
1416 if (instr->HasB()) { | |
1417 if (instr->HasL()) { | |
1418 byte val = ReadBU(addr); | |
1419 set_register(rd, val); | |
1420 } else { | |
1421 byte val = get_register(rd); | |
1422 WriteB(addr, val); | |
1423 } | |
1424 } else { | |
1425 if (instr->HasL()) { | |
1426 set_register(rd, ReadW(addr, instr)); | |
1427 } else { | |
1428 WriteW(addr, get_register(rd), instr); | |
1429 } | |
1430 } | |
1431 } | |
1432 | |
1433 | |
1434 void Simulator::DecodeType3(Instr* instr) { | |
1435 int rd = instr->RdField(); | |
1436 int rn = instr->RnField(); | |
1437 int32_t rn_val = get_register(rn); | |
1438 bool shifter_carry_out = 0; | |
1439 int32_t shifter_operand = GetShiftRm(instr, &shifter_carry_out); | |
1440 int32_t addr = 0; | |
1441 switch (instr->PUField()) { | |
1442 case 0: { | |
1443 ASSERT(!instr->HasW()); | |
1444 Format(instr, "'memop'cond'b 'rd, ['rn], -'shift_rm"); | |
1445 break; | |
1446 } | |
1447 case 1: { | |
1448 ASSERT(!instr->HasW()); | |
1449 Format(instr, "'memop'cond'b 'rd, ['rn], +'shift_rm"); | |
1450 break; | |
1451 } | |
1452 case 2: { | |
1453 // Format(instr, "'memop'cond'b 'rd, ['rn, -'shift_rm]'w"); | |
1454 addr = rn_val - shifter_operand; | |
1455 if (instr->HasW()) { | |
1456 set_register(rn, addr); | |
1457 } | |
1458 break; | |
1459 } | |
1460 case 3: { | |
1461 // Format(instr, "'memop'cond'b 'rd, ['rn, +'shift_rm]'w"); | |
1462 addr = rn_val + shifter_operand; | |
1463 if (instr->HasW()) { | |
1464 set_register(rn, addr); | |
1465 } | |
1466 break; | |
1467 } | |
1468 default: { | |
1469 UNREACHABLE(); | |
1470 break; | |
1471 } | |
1472 } | |
1473 if (instr->HasB()) { | |
1474 UNIMPLEMENTED(); | |
1475 } else { | |
1476 if (instr->HasL()) { | |
1477 set_register(rd, ReadW(addr, instr)); | |
1478 } else { | |
1479 WriteW(addr, get_register(rd), instr); | |
1480 } | |
1481 } | |
1482 } | |
1483 | |
1484 | |
1485 void Simulator::DecodeType4(Instr* instr) { | |
1486 ASSERT(instr->Bit(22) == 0); // only allowed to be set in privileged mode | |
1487 if (instr->HasL()) { | |
1488 // Format(instr, "ldm'cond'pu 'rn'w, 'rlist"); | |
1489 HandleRList(instr, true); | |
1490 } else { | |
1491 // Format(instr, "stm'cond'pu 'rn'w, 'rlist"); | |
1492 HandleRList(instr, false); | |
1493 } | |
1494 } | |
1495 | |
1496 | |
1497 void Simulator::DecodeType5(Instr* instr) { | |
1498 // Format(instr, "b'l'cond 'target"); | |
1499 int off = (instr->SImmed24Field() << 2) + 8; | |
1500 intptr_t pc = get_pc(); | |
1501 if (instr->HasLink()) { | |
1502 set_register(lr, pc + Instr::kInstrSize); | |
1503 } | |
1504 set_pc(pc+off); | |
1505 } | |
1506 | |
1507 | |
1508 void Simulator::DecodeType6(Instr* instr) { | |
1509 UNIMPLEMENTED(); | |
1510 } | |
1511 | |
1512 | |
1513 void Simulator::DecodeType7(Instr* instr) { | |
1514 if (instr->Bit(24) == 1) { | |
1515 // Format(instr, "swi 'swi"); | |
1516 SoftwareInterrupt(instr); | |
1517 } else { | |
1518 UNIMPLEMENTED(); | |
1519 } | |
1520 } | |
1521 | |
1522 | |
1523 // Executes the current instruction. | |
1524 void Simulator::InstructionDecode(Instr* instr) { | |
1525 pc_modified_ = false; | |
1526 if (instr->ConditionField() == special_condition) { | |
1527 Debugger dbg(this); | |
1528 dbg.Stop(instr); | |
1529 return; | |
1530 } | |
1531 if (::v8::internal::FLAG_trace_sim) { | |
1532 disasm::NameConverter converter; | |
1533 disasm::Disassembler dasm(converter); | |
1534 // use a reasonably large buffer | |
1535 v8::internal::EmbeddedVector<char, 256> buffer; | |
1536 dasm.InstructionDecode(buffer, | |
1537 reinterpret_cast<byte*>(instr)); | |
1538 PrintF(" 0x%x %s\n", instr, buffer.start()); | |
1539 } | |
1540 if (ConditionallyExecute(instr)) { | |
1541 switch (instr->TypeField()) { | |
1542 case 0: | |
1543 case 1: { | |
1544 DecodeType01(instr); | |
1545 break; | |
1546 } | |
1547 case 2: { | |
1548 DecodeType2(instr); | |
1549 break; | |
1550 } | |
1551 case 3: { | |
1552 DecodeType3(instr); | |
1553 break; | |
1554 } | |
1555 case 4: { | |
1556 DecodeType4(instr); | |
1557 break; | |
1558 } | |
1559 case 5: { | |
1560 DecodeType5(instr); | |
1561 break; | |
1562 } | |
1563 case 6: { | |
1564 DecodeType6(instr); | |
1565 break; | |
1566 } | |
1567 case 7: { | |
1568 DecodeType7(instr); | |
1569 break; | |
1570 } | |
1571 default: { | |
1572 UNIMPLEMENTED(); | |
1573 break; | |
1574 } | |
1575 } | |
1576 } | |
1577 if (!pc_modified_) { | |
1578 set_register(pc, reinterpret_cast<int32_t>(instr) + Instr::kInstrSize); | |
1579 } | |
1580 } | |
1581 | |
1582 | |
1583 // | |
1584 void Simulator::Execute() { | |
1585 // Get the PC to simulate. Cannot use the accessor here as we need the | |
1586 // raw PC value and not the one used as input to arithmetic instructions. | |
1587 int program_counter = get_pc(); | |
1588 | |
1589 if (::v8::internal::FLAG_stop_sim_at == 0) { | |
1590 // Fast version of the dispatch loop without checking whether the simulator | |
1591 // should be stopping at a particular executed instruction. | |
1592 while (program_counter != end_sim_pc) { | |
1593 Instr* instr = reinterpret_cast<Instr*>(program_counter); | |
1594 icount_++; | |
1595 InstructionDecode(instr); | |
1596 program_counter = get_pc(); | |
1597 } | |
1598 } else { | |
1599 // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when | |
1600 // we reach the particular instuction count. | |
1601 while (program_counter != end_sim_pc) { | |
1602 Instr* instr = reinterpret_cast<Instr*>(program_counter); | |
1603 icount_++; | |
1604 if (icount_ == ::v8::internal::FLAG_stop_sim_at) { | |
1605 Debugger dbg(this); | |
1606 dbg.Debug(); | |
1607 } else { | |
1608 InstructionDecode(instr); | |
1609 } | |
1610 program_counter = get_pc(); | |
1611 } | |
1612 } | |
1613 } | |
1614 | |
1615 | |
1616 Object* Simulator::Call(int32_t entry, int32_t p0, int32_t p1, int32_t p2, | |
1617 int32_t p3, int32_t p4) { | |
1618 // Setup parameters | |
1619 set_register(r0, p0); | |
1620 set_register(r1, p1); | |
1621 set_register(r2, p2); | |
1622 set_register(r3, p3); | |
1623 intptr_t* stack_pointer = reinterpret_cast<intptr_t*>(get_register(sp)); | |
1624 *(--stack_pointer) = p4; | |
1625 set_register(sp, reinterpret_cast<int32_t>(stack_pointer)); | |
1626 | |
1627 // Prepare to execute the code at entry | |
1628 set_register(pc, entry); | |
1629 // Put down marker for end of simulation. The simulator will stop simulation | |
1630 // when the PC reaches this value. By saving the "end simulation" value into | |
1631 // the LR the simulation stops when returning to this call point. | |
1632 set_register(lr, end_sim_pc); | |
1633 | |
1634 // Remember the values of callee-saved registers. | |
1635 // The code below assumes that r9 is not used as sb (static base) in | |
1636 // simulator code and therefore is regarded as a callee-saved register. | |
1637 int32_t r4_val = get_register(r4); | |
1638 int32_t r5_val = get_register(r5); | |
1639 int32_t r6_val = get_register(r6); | |
1640 int32_t r7_val = get_register(r7); | |
1641 int32_t r8_val = get_register(r8); | |
1642 int32_t r9_val = get_register(r9); | |
1643 int32_t r10_val = get_register(r10); | |
1644 int32_t r11_val = get_register(r11); | |
1645 | |
1646 // Setup the callee-saved registers with a known value. To be able to check | |
1647 // that they are preserved properly across JS execution. | |
1648 int32_t callee_saved_value = icount_; | |
1649 set_register(r4, callee_saved_value); | |
1650 set_register(r5, callee_saved_value); | |
1651 set_register(r6, callee_saved_value); | |
1652 set_register(r7, callee_saved_value); | |
1653 set_register(r8, callee_saved_value); | |
1654 set_register(r9, callee_saved_value); | |
1655 set_register(r10, callee_saved_value); | |
1656 set_register(r11, callee_saved_value); | |
1657 | |
1658 // Start the simulation | |
1659 Execute(); | |
1660 | |
1661 // Check that the callee-saved registers have been preserved. | |
1662 CHECK_EQ(get_register(r4), callee_saved_value); | |
1663 CHECK_EQ(get_register(r5), callee_saved_value); | |
1664 CHECK_EQ(get_register(r6), callee_saved_value); | |
1665 CHECK_EQ(get_register(r7), callee_saved_value); | |
1666 CHECK_EQ(get_register(r8), callee_saved_value); | |
1667 CHECK_EQ(get_register(r9), callee_saved_value); | |
1668 CHECK_EQ(get_register(r10), callee_saved_value); | |
1669 CHECK_EQ(get_register(r11), callee_saved_value); | |
1670 | |
1671 // Restore callee-saved registers with the original value. | |
1672 set_register(r4, r4_val); | |
1673 set_register(r5, r5_val); | |
1674 set_register(r6, r6_val); | |
1675 set_register(r7, r7_val); | |
1676 set_register(r8, r8_val); | |
1677 set_register(r9, r9_val); | |
1678 set_register(r10, r10_val); | |
1679 set_register(r11, r11_val); | |
1680 | |
1681 int result = get_register(r0); | |
1682 return reinterpret_cast<Object*>(result); | |
1683 } | |
1684 | |
1685 } } // namespace assembler::arm | |
1686 | |
1687 #endif // !defined(__arm__) | |
OLD | NEW |