Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(216)

Side by Side Diff: src/mips/simulator-mips.cc

Issue 561072: MIPS port initial commit (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 10 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/mips/simulator-mips.h ('k') | src/mips/stub-cache-mips.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2010 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 #include <cstdarg>
30 #include "v8.h"
31
32 #include "disasm.h"
33 #include "assembler.h"
34 #include "globals.h" // Need the bit_cast
35 #include "mips/constants-mips.h"
36 #include "mips/simulator-mips.h"
37
38 namespace v8i = v8::internal;
39
40 #if !defined(__mips)
41
42 // Only build the simulator if not compiling for real MIPS hardware.
43 namespace assembler {
44 namespace mips {
45
46 using ::v8::internal::Object;
47 using ::v8::internal::PrintF;
48 using ::v8::internal::OS;
49 using ::v8::internal::ReadLine;
50 using ::v8::internal::DeleteArray;
51
52 // Utils functions
53 bool HaveSameSign(int32_t a, int32_t b) {
54 return ((a ^ b) > 0);
55 }
56
57
58 // This macro provides a platform independent use of sscanf. The reason for
59 // SScanF not being implemented in a platform independent was through
60 // ::v8::internal::OS in the same way as SNPrintF is that the Windows C Run-Time
61 // Library does not provide vsscanf.
62 #define SScanF sscanf // NOLINT
63
64 // The Debugger class is used by the simulator while debugging simulated MIPS
65 // code.
66 class Debugger {
67 public:
68 explicit Debugger(Simulator* sim);
69 ~Debugger();
70
71 void Stop(Instruction* instr);
72 void Debug();
73
74 private:
75 // We set the breakpoint code to 0xfffff to easily recognize it.
76 static const Instr kBreakpointInstr = SPECIAL | BREAK | 0xfffff << 6;
77 static const Instr kNopInstr = 0x0;
78
79 Simulator* sim_;
80
81 int32_t GetRegisterValue(int regnum);
82 bool GetValue(const char* desc, int32_t* value);
83
84 // Set or delete a breakpoint. Returns true if successful.
85 bool SetBreakpoint(Instruction* breakpc);
86 bool DeleteBreakpoint(Instruction* breakpc);
87
88 // Undo and redo all breakpoints. This is needed to bracket disassembly and
89 // execution to skip past breakpoints when run from the debugger.
90 void UndoBreakpoints();
91 void RedoBreakpoints();
92
93 // Print all registers with a nice formatting.
94 void PrintAllRegs();
95 };
96
97 Debugger::Debugger(Simulator* sim) {
98 sim_ = sim;
99 }
100
101 Debugger::~Debugger() {
102 }
103
104 #ifdef GENERATED_CODE_COVERAGE
105 static FILE* coverage_log = NULL;
106
107
108 static void InitializeCoverage() {
109 char* file_name = getenv("V8_GENERATED_CODE_COVERAGE_LOG");
110 if (file_name != NULL) {
111 coverage_log = fopen(file_name, "aw+");
112 }
113 }
114
115
116 void Debugger::Stop(Instruction* instr) {
117 UNIMPLEMENTED_MIPS();
118 char* str = reinterpret_cast<char*>(instr->InstructionBits());
119 if (strlen(str) > 0) {
120 if (coverage_log != NULL) {
121 fprintf(coverage_log, "%s\n", str);
122 fflush(coverage_log);
123 }
124 instr->SetInstructionBits(0x0); // Overwrite with nop.
125 }
126 sim_->set_pc(sim_->get_pc() + Instruction::kInstructionSize);
127 }
128
129 #else // ndef GENERATED_CODE_COVERAGE
130
131 #define UNSUPPORTED() printf("Unsupported instruction.\n");
132
133 static void InitializeCoverage() {}
134
135
136 void Debugger::Stop(Instruction* instr) {
137 const char* str = reinterpret_cast<char*>(instr->InstructionBits());
138 PrintF("Simulator hit %s\n", str);
139 sim_->set_pc(sim_->get_pc() + Instruction::kInstructionSize);
140 Debug();
141 }
142 #endif // def GENERATED_CODE_COVERAGE
143
144
145 int32_t Debugger::GetRegisterValue(int regnum) {
146 if (regnum == kNumSimuRegisters) {
147 return sim_->get_pc();
148 } else {
149 return sim_->get_register(regnum);
150 }
151 }
152
153
154 bool Debugger::GetValue(const char* desc, int32_t* value) {
155 int regnum = Registers::Number(desc);
156 if (regnum != kInvalidRegister) {
157 *value = GetRegisterValue(regnum);
158 return true;
159 } else {
160 return SScanF(desc, "%i", value) == 1;
161 }
162 return false;
163 }
164
165
166 bool Debugger::SetBreakpoint(Instruction* breakpc) {
167 // Check if a breakpoint can be set. If not return without any side-effects.
168 if (sim_->break_pc_ != NULL) {
169 return false;
170 }
171
172 // Set the breakpoint.
173 sim_->break_pc_ = breakpc;
174 sim_->break_instr_ = breakpc->InstructionBits();
175 // Not setting the breakpoint instruction in the code itself. It will be set
176 // when the debugger shell continues.
177 return true;
178 }
179
180
181 bool Debugger::DeleteBreakpoint(Instruction* breakpc) {
182 if (sim_->break_pc_ != NULL) {
183 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
184 }
185
186 sim_->break_pc_ = NULL;
187 sim_->break_instr_ = 0;
188 return true;
189 }
190
191
192 void Debugger::UndoBreakpoints() {
193 if (sim_->break_pc_ != NULL) {
194 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
195 }
196 }
197
198
199 void Debugger::RedoBreakpoints() {
200 if (sim_->break_pc_ != NULL) {
201 sim_->break_pc_->SetInstructionBits(kBreakpointInstr);
202 }
203 }
204
205 void Debugger::PrintAllRegs() {
206 #define REG_INFO(n) Registers::Name(n), GetRegisterValue(n), GetRegisterValue(n)
207
208 PrintF("\n");
209 // at, v0, a0
210 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
211 REG_INFO(1), REG_INFO(2), REG_INFO(4));
212 // v1, a1
213 PrintF("%26s\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
214 "", REG_INFO(3), REG_INFO(5));
215 // a2
216 PrintF("%26s\t%26s\t%3s: 0x%08x %10d\n", "", "", REG_INFO(6));
217 // a3
218 PrintF("%26s\t%26s\t%3s: 0x%08x %10d\n", "", "", REG_INFO(7));
219 PrintF("\n");
220 // t0-t7, s0-s7
221 for (int i = 0; i < 8; i++) {
222 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
223 REG_INFO(8+i), REG_INFO(16+i));
224 }
225 PrintF("\n");
226 // t8, k0, LO
227 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
228 REG_INFO(24), REG_INFO(26), REG_INFO(32));
229 // t9, k1, HI
230 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
231 REG_INFO(25), REG_INFO(27), REG_INFO(33));
232 // sp, fp, gp
233 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
234 REG_INFO(29), REG_INFO(30), REG_INFO(28));
235 // pc
236 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
237 REG_INFO(31), REG_INFO(34));
238 #undef REG_INFO
239 }
240
241 void Debugger::Debug() {
242 intptr_t last_pc = -1;
243 bool done = false;
244
245 #define COMMAND_SIZE 63
246 #define ARG_SIZE 255
247
248 #define STR(a) #a
249 #define XSTR(a) STR(a)
250
251 char cmd[COMMAND_SIZE + 1];
252 char arg1[ARG_SIZE + 1];
253 char arg2[ARG_SIZE + 1];
254
255 // make sure to have a proper terminating character if reaching the limit
256 cmd[COMMAND_SIZE] = 0;
257 arg1[ARG_SIZE] = 0;
258 arg2[ARG_SIZE] = 0;
259
260 // Undo all set breakpoints while running in the debugger shell. This will
261 // make them invisible to all commands.
262 UndoBreakpoints();
263
264 while (!done && (sim_->get_pc() != Simulator::end_sim_pc)) {
265 if (last_pc != sim_->get_pc()) {
266 disasm::NameConverter converter;
267 disasm::Disassembler dasm(converter);
268 // use a reasonably large buffer
269 v8::internal::EmbeddedVector<char, 256> buffer;
270 dasm.InstructionDecode(buffer,
271 reinterpret_cast<byte_*>(sim_->get_pc()));
272 PrintF(" 0x%08x %s\n", sim_->get_pc(), buffer.start());
273 last_pc = sim_->get_pc();
274 }
275 char* line = ReadLine("sim> ");
276 if (line == NULL) {
277 break;
278 } else {
279 // Use sscanf to parse the individual parts of the command line. At the
280 // moment no command expects more than two parameters.
281 int args = SScanF(line,
282 "%" XSTR(COMMAND_SIZE) "s "
283 "%" XSTR(ARG_SIZE) "s "
284 "%" XSTR(ARG_SIZE) "s",
285 cmd, arg1, arg2);
286 if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
287 if (!(reinterpret_cast<Instruction*>(sim_->get_pc())->IsTrap())) {
288 sim_->InstructionDecode(
289 reinterpret_cast<Instruction*>(sim_->get_pc()));
290 } else {
291 // Allow si to jump over generated breakpoints.
292 PrintF("/!\\ Jumping over generated breakpoint.\n");
293 sim_->set_pc(sim_->get_pc() + Instruction::kInstructionSize);
294 }
295 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) {
296 // Execute the one instruction we broke at with breakpoints disabled.
297 sim_->InstructionDecode(reinterpret_cast<Instruction*>(sim_->get_pc()));
298 // Leave the debugger shell.
299 done = true;
300 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
301 if (args == 2) {
302 int32_t value;
303 if (strcmp(arg1, "all") == 0) {
304 PrintAllRegs();
305 } else {
306 if (GetValue(arg1, &value)) {
307 PrintF("%s: 0x%08x %d \n", arg1, value, value);
308 } else {
309 PrintF("%s unrecognized\n", arg1);
310 }
311 }
312 } else {
313 PrintF("print <register>\n");
314 }
315 } else if ((strcmp(cmd, "po") == 0)
316 || (strcmp(cmd, "printobject") == 0)) {
317 if (args == 2) {
318 int32_t value;
319 if (GetValue(arg1, &value)) {
320 Object* obj = reinterpret_cast<Object*>(value);
321 PrintF("%s: \n", arg1);
322 #ifdef DEBUG
323 obj->PrintLn();
324 #else
325 obj->ShortPrint();
326 PrintF("\n");
327 #endif
328 } else {
329 PrintF("%s unrecognized\n", arg1);
330 }
331 } else {
332 PrintF("printobject <value>\n");
333 }
334 } else if ((strcmp(cmd, "disasm") == 0) || (strcmp(cmd, "dpc") == 0)) {
335 disasm::NameConverter converter;
336 disasm::Disassembler dasm(converter);
337 // use a reasonably large buffer
338 v8::internal::EmbeddedVector<char, 256> buffer;
339
340 byte_* cur = NULL;
341 byte_* end = NULL;
342
343 if (args == 1) {
344 cur = reinterpret_cast<byte_*>(sim_->get_pc());
345 end = cur + (10 * Instruction::kInstructionSize);
346 } else if (args == 2) {
347 int32_t value;
348 if (GetValue(arg1, &value)) {
349 cur = reinterpret_cast<byte_*>(value);
350 // no length parameter passed, assume 10 instructions
351 end = cur + (10 * Instruction::kInstructionSize);
352 }
353 } else {
354 int32_t value1;
355 int32_t value2;
356 if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
357 cur = reinterpret_cast<byte_*>(value1);
358 end = cur + (value2 * Instruction::kInstructionSize);
359 }
360 }
361
362 while (cur < end) {
363 dasm.InstructionDecode(buffer, cur);
364 PrintF(" 0x%08x %s\n", cur, buffer.start());
365 cur += Instruction::kInstructionSize;
366 }
367 } else if (strcmp(cmd, "gdb") == 0) {
368 PrintF("relinquishing control to gdb\n");
369 v8::internal::OS::DebugBreak();
370 PrintF("regaining control from gdb\n");
371 } else if (strcmp(cmd, "break") == 0) {
372 if (args == 2) {
373 int32_t value;
374 if (GetValue(arg1, &value)) {
375 if (!SetBreakpoint(reinterpret_cast<Instruction*>(value))) {
376 PrintF("setting breakpoint failed\n");
377 }
378 } else {
379 PrintF("%s unrecognized\n", arg1);
380 }
381 } else {
382 PrintF("break <address>\n");
383 }
384 } else if (strcmp(cmd, "del") == 0) {
385 if (!DeleteBreakpoint(NULL)) {
386 PrintF("deleting breakpoint failed\n");
387 }
388 } else if (strcmp(cmd, "flags") == 0) {
389 PrintF("No flags on MIPS !\n");
390 } else if (strcmp(cmd, "unstop") == 0) {
391 PrintF("Unstop command not implemented on MIPS.");
392 } else if ((strcmp(cmd, "stat") == 0) || (strcmp(cmd, "st") == 0)) {
393 // Print registers and disassemble
394 PrintAllRegs();
395 PrintF("\n");
396
397 disasm::NameConverter converter;
398 disasm::Disassembler dasm(converter);
399 // use a reasonably large buffer
400 v8::internal::EmbeddedVector<char, 256> buffer;
401
402 byte_* cur = NULL;
403 byte_* end = NULL;
404
405 if (args == 1) {
406 cur = reinterpret_cast<byte_*>(sim_->get_pc());
407 end = cur + (10 * Instruction::kInstructionSize);
408 } else if (args == 2) {
409 int32_t value;
410 if (GetValue(arg1, &value)) {
411 cur = reinterpret_cast<byte_*>(value);
412 // no length parameter passed, assume 10 instructions
413 end = cur + (10 * Instruction::kInstructionSize);
414 }
415 } else {
416 int32_t value1;
417 int32_t value2;
418 if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
419 cur = reinterpret_cast<byte_*>(value1);
420 end = cur + (value2 * Instruction::kInstructionSize);
421 }
422 }
423
424 while (cur < end) {
425 dasm.InstructionDecode(buffer, cur);
426 PrintF(" 0x%08x %s\n", cur, buffer.start());
427 cur += Instruction::kInstructionSize;
428 }
429 } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
430 PrintF("cont\n");
431 PrintF(" continue execution (alias 'c')\n");
432 PrintF("stepi\n");
433 PrintF(" step one instruction (alias 'si')\n");
434 PrintF("print <register>\n");
435 PrintF(" print register content (alias 'p')\n");
436 PrintF(" use register name 'all' to print all registers\n");
437 PrintF("printobject <register>\n");
438 PrintF(" print an object from a register (alias 'po')\n");
439 PrintF("flags\n");
440 PrintF(" print flags\n");
441 PrintF("disasm [<instructions>]\n");
442 PrintF("disasm [[<address>] <instructions>]\n");
443 PrintF(" disassemble code, default is 10 instructions from pc\n");
444 PrintF("gdb\n");
445 PrintF(" enter gdb\n");
446 PrintF("break <address>\n");
447 PrintF(" set a break point on the address\n");
448 PrintF("del\n");
449 PrintF(" delete the breakpoint\n");
450 PrintF("unstop\n");
451 PrintF(" ignore the stop instruction at the current location");
452 PrintF(" from now on\n");
453 } else {
454 PrintF("Unknown command: %s\n", cmd);
455 }
456 }
457 DeleteArray(line);
458 }
459
460 // Add all the breakpoints back to stop execution and enter the debugger
461 // shell when hit.
462 RedoBreakpoints();
463
464 #undef COMMAND_SIZE
465 #undef ARG_SIZE
466
467 #undef STR
468 #undef XSTR
469 }
470
471
472 // Create one simulator per thread and keep it in thread local storage.
473 static v8::internal::Thread::LocalStorageKey simulator_key;
474
475
476 bool Simulator::initialized_ = false;
477
478
479 void Simulator::Initialize() {
480 if (initialized_) return;
481 simulator_key = v8::internal::Thread::CreateThreadLocalKey();
482 initialized_ = true;
483 ::v8::internal::ExternalReference::set_redirector(&RedirectExternalReference);
484 }
485
486
487 Simulator::Simulator() {
488 Initialize();
489 // Setup simulator support first. Some of this information is needed to
490 // setup the architecture state.
491 size_t stack_size = 1 * 1024*1024; // allocate 1MB for stack
492 stack_ = reinterpret_cast<char*>(malloc(stack_size));
493 pc_modified_ = false;
494 icount_ = 0;
495 break_pc_ = NULL;
496 break_instr_ = 0;
497
498 // Setup architecture state.
499 // All registers are initialized to zero to start with.
500 for (int i = 0; i < kNumSimuRegisters; i++) {
501 registers_[i] = 0;
502 }
503
504 // The sp is initialized to point to the bottom (high address) of the
505 // allocated stack area. To be safe in potential stack underflows we leave
506 // some buffer below.
507 registers_[sp] = reinterpret_cast<int32_t>(stack_) + stack_size - 64;
508 // The ra and pc are initialized to a known bad value that will cause an
509 // access violation if the simulator ever tries to execute it.
510 registers_[pc] = bad_ra;
511 registers_[ra] = bad_ra;
512 InitializeCoverage();
513 }
514
515
516 // When the generated code calls an external reference we need to catch that in
517 // the simulator. The external reference will be a function compiled for the
518 // host architecture. We need to call that function instead of trying to
519 // execute it with the simulator. We do that by redirecting the external
520 // reference to a swi (software-interrupt) instruction that is handled by
521 // the simulator. We write the original destination of the jump just at a known
522 // offset from the swi instruction so the simulator knows what to call.
523 class Redirection {
524 public:
525 Redirection(void* external_function, bool fp_return)
526 : external_function_(external_function),
527 swi_instruction_(rtCallRedirInstr),
528 fp_return_(fp_return),
529 next_(list_) {
530 list_ = this;
531 }
532
533 void* address_of_swi_instruction() {
534 return reinterpret_cast<void*>(&swi_instruction_);
535 }
536
537 void* external_function() { return external_function_; }
538 bool fp_return() { return fp_return_; }
539
540 static Redirection* Get(void* external_function, bool fp_return) {
541 Redirection* current;
542 for (current = list_; current != NULL; current = current->next_) {
543 if (current->external_function_ == external_function) return current;
544 }
545 return new Redirection(external_function, fp_return);
546 }
547
548 static Redirection* FromSwiInstruction(Instruction* swi_instruction) {
549 char* addr_of_swi = reinterpret_cast<char*>(swi_instruction);
550 char* addr_of_redirection =
551 addr_of_swi - OFFSET_OF(Redirection, swi_instruction_);
552 return reinterpret_cast<Redirection*>(addr_of_redirection);
553 }
554
555 private:
556 void* external_function_;
557 uint32_t swi_instruction_;
558 bool fp_return_;
559 Redirection* next_;
560 static Redirection* list_;
561 };
562
563
564 Redirection* Redirection::list_ = NULL;
565
566
567 void* Simulator::RedirectExternalReference(void* external_function,
568 bool fp_return) {
569 Redirection* redirection = Redirection::Get(external_function, fp_return);
570 return redirection->address_of_swi_instruction();
571 }
572
573
574 // Get the active Simulator for the current thread.
575 Simulator* Simulator::current() {
576 Initialize();
577 Simulator* sim = reinterpret_cast<Simulator*>(
578 v8::internal::Thread::GetThreadLocal(simulator_key));
579 if (sim == NULL) {
580 // TODO(146): delete the simulator object when a thread goes away.
581 sim = new Simulator();
582 v8::internal::Thread::SetThreadLocal(simulator_key, sim);
583 }
584 return sim;
585 }
586
587
588 // Sets the register in the architecture state. It will also deal with updating
589 // Simulator internal state for special registers such as PC.
590 void Simulator::set_register(int reg, int32_t value) {
591 ASSERT((reg >= 0) && (reg < kNumSimuRegisters));
592 if (reg == pc) {
593 pc_modified_ = true;
594 }
595
596 // zero register always hold 0.
597 registers_[reg] = (reg == 0) ? 0 : value;
598 }
599
600 void Simulator::set_fpu_register(int fpureg, int32_t value) {
601 ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters));
602 FPUregisters_[fpureg] = value;
603 }
604
605 void Simulator::set_fpu_register_double(int fpureg, double value) {
606 ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
607 *v8i::bit_cast<double*, int32_t*>(&FPUregisters_[fpureg]) = value;
608 }
609
610
611 // Get the register from the architecture state. This function does handle
612 // the special case of accessing the PC register.
613 int32_t Simulator::get_register(int reg) const {
614 ASSERT((reg >= 0) && (reg < kNumSimuRegisters));
615 if (reg == 0)
616 return 0;
617 else
618 return registers_[reg] + ((reg == pc) ? Instruction::kPCReadOffset : 0);
619 }
620
621 int32_t Simulator::get_fpu_register(int fpureg) const {
622 ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters));
623 return FPUregisters_[fpureg];
624 }
625
626 double Simulator::get_fpu_register_double(int fpureg) const {
627 ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
628 return *v8i::bit_cast<double*, int32_t*>(
629 const_cast<int32_t*>(&FPUregisters_[fpureg]));
630 }
631
632 // Raw access to the PC register.
633 void Simulator::set_pc(int32_t value) {
634 pc_modified_ = true;
635 registers_[pc] = value;
636 }
637
638 // Raw access to the PC register without the special adjustment when reading.
639 int32_t Simulator::get_pc() const {
640 return registers_[pc];
641 }
642
643
644 // The MIPS cannot do unaligned reads and writes. On some MIPS platforms an
645 // interrupt is caused. On others it does a funky rotation thing. For now we
646 // simply disallow unaligned reads, but at some point we may want to move to
647 // emulating the rotate behaviour. Note that simulator runs have the runtime
648 // system running directly on the host system and only generated code is
649 // executed in the simulator. Since the host is typically IA32 we will not
650 // get the correct MIPS-like behaviour on unaligned accesses.
651
652 int Simulator::ReadW(int32_t addr, Instruction* instr) {
653 if ((addr & v8i::kPointerAlignmentMask) == 0) {
654 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
655 return *ptr;
656 }
657 PrintF("Unaligned read at 0x%08x, pc=%p\n", addr, instr);
658 OS::Abort();
659 return 0;
660 }
661
662
663 void Simulator::WriteW(int32_t addr, int value, Instruction* instr) {
664 if ((addr & v8i::kPointerAlignmentMask) == 0) {
665 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
666 *ptr = value;
667 return;
668 }
669 PrintF("Unaligned write at 0x%08x, pc=%p\n", addr, instr);
670 OS::Abort();
671 }
672
673
674 double Simulator::ReadD(int32_t addr, Instruction* instr) {
675 if ((addr & kDoubleAlignmentMask) == 0) {
676 double* ptr = reinterpret_cast<double*>(addr);
677 return *ptr;
678 }
679 PrintF("Unaligned read at 0x%08x, pc=%p\n", addr, instr);
680 OS::Abort();
681 return 0;
682 }
683
684
685 void Simulator::WriteD(int32_t addr, double value, Instruction* instr) {
686 if ((addr & kDoubleAlignmentMask) == 0) {
687 double* ptr = reinterpret_cast<double*>(addr);
688 *ptr = value;
689 return;
690 }
691 PrintF("Unaligned write at 0x%08x, pc=%p\n", addr, instr);
692 OS::Abort();
693 }
694
695
696 uint16_t Simulator::ReadHU(int32_t addr, Instruction* instr) {
697 if ((addr & 1) == 0) {
698 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
699 return *ptr;
700 }
701 PrintF("Unaligned unsigned halfword read at 0x%08x, pc=%p\n", addr, instr);
702 OS::Abort();
703 return 0;
704 }
705
706
707 int16_t Simulator::ReadH(int32_t addr, Instruction* instr) {
708 if ((addr & 1) == 0) {
709 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
710 return *ptr;
711 }
712 PrintF("Unaligned signed halfword read at 0x%08x, pc=%p\n", addr, instr);
713 OS::Abort();
714 return 0;
715 }
716
717
718 void Simulator::WriteH(int32_t addr, uint16_t value, Instruction* instr) {
719 if ((addr & 1) == 0) {
720 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
721 *ptr = value;
722 return;
723 }
724 PrintF("Unaligned unsigned halfword write at 0x%08x, pc=%p\n", addr, instr);
725 OS::Abort();
726 }
727
728
729 void Simulator::WriteH(int32_t addr, int16_t value, Instruction* instr) {
730 if ((addr & 1) == 0) {
731 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
732 *ptr = value;
733 return;
734 }
735 PrintF("Unaligned halfword write at 0x%08x, pc=%p\n", addr, instr);
736 OS::Abort();
737 }
738
739
740 uint32_t Simulator::ReadBU(int32_t addr) {
741 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
742 return *ptr & 0xff;
743 }
744
745
746 int32_t Simulator::ReadB(int32_t addr) {
747 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
748 return ((*ptr << 24) >> 24) & 0xff;
749 }
750
751
752 void Simulator::WriteB(int32_t addr, uint8_t value) {
753 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
754 *ptr = value;
755 }
756
757
758 void Simulator::WriteB(int32_t addr, int8_t value) {
759 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
760 *ptr = value;
761 }
762
763
764 // Returns the limit of the stack area to enable checking for stack overflows.
765 uintptr_t Simulator::StackLimit() const {
766 // Leave a safety margin of 256 bytes to prevent overrunning the stack when
767 // pushing values.
768 return reinterpret_cast<uintptr_t>(stack_) + 256;
769 }
770
771
772 // Unsupported instructions use Format to print an error and stop execution.
773 void Simulator::Format(Instruction* instr, const char* format) {
774 PrintF("Simulator found unsupported instruction:\n 0x%08x: %s\n",
775 instr, format);
776 UNIMPLEMENTED_MIPS();
777 }
778
779
780 // Calls into the V8 runtime are based on this very simple interface.
781 // Note: To be able to return two values from some calls the code in runtime.cc
782 // uses the ObjectPair which is essentially two 32-bit values stuffed into a
783 // 64-bit value. With the code below we assume that all runtime calls return
784 // 64 bits of result. If they don't, the r1 result register contains a bogus
785 // value, which is fine because it is caller-saved.
786 typedef int64_t (*SimulatorRuntimeCall)(int32_t arg0,
787 int32_t arg1,
788 int32_t arg2,
789 int32_t arg3);
790 typedef double (*SimulatorRuntimeFPCall)(double fparg0,
791 double fparg1);
792
793
794 // Software interrupt instructions are used by the simulator to call into the
795 // C-based V8 runtime.
796 void Simulator::SoftwareInterrupt(Instruction* instr) {
797 // We first check if we met a call_rt_redirected.
798 if (instr->InstructionBits() == rtCallRedirInstr) {
799 Redirection* redirection = Redirection::FromSwiInstruction(instr);
800 int32_t arg0 = get_register(a0);
801 int32_t arg1 = get_register(a1);
802 int32_t arg2 = get_register(a2);
803 int32_t arg3 = get_register(a3);
804 // fp args are (not always) in f12 and f14.
805 // See MIPS conventions for more details.
806 double fparg0 = get_fpu_register_double(f12);
807 double fparg1 = get_fpu_register_double(f14);
808 // This is dodgy but it works because the C entry stubs are never moved.
809 // See comment in codegen-arm.cc and bug 1242173.
810 int32_t saved_ra = get_register(ra);
811 if (redirection->fp_return()) {
812 intptr_t external =
813 reinterpret_cast<intptr_t>(redirection->external_function());
814 SimulatorRuntimeFPCall target =
815 reinterpret_cast<SimulatorRuntimeFPCall>(external);
816 if (::v8::internal::FLAG_trace_sim) {
817 PrintF("Call to host function at %p with args %f, %f\n",
818 FUNCTION_ADDR(target), fparg0, fparg1);
819 }
820 double result = target(fparg0, fparg1);
821 set_fpu_register_double(f0, result);
822 } else {
823 intptr_t external =
824 reinterpret_cast<int32_t>(redirection->external_function());
825 SimulatorRuntimeCall target =
826 reinterpret_cast<SimulatorRuntimeCall>(external);
827 if (::v8::internal::FLAG_trace_sim) {
828 PrintF(
829 "Call to host function at %p with args %08x, %08x, %08x, %08x\n",
830 FUNCTION_ADDR(target),
831 arg0,
832 arg1,
833 arg2,
834 arg3);
835 }
836 int64_t result = target(arg0, arg1, arg2, arg3);
837 int32_t lo_res = static_cast<int32_t>(result);
838 int32_t hi_res = static_cast<int32_t>(result >> 32);
839 if (::v8::internal::FLAG_trace_sim) {
840 PrintF("Returned %08x\n", lo_res);
841 }
842 set_register(v0, lo_res);
843 set_register(v1, hi_res);
844 }
845 set_register(ra, saved_ra);
846 set_pc(get_register(ra));
847 } else {
848 Debugger dbg(this);
849 dbg.Debug();
850 }
851 }
852
853 void Simulator::SignalExceptions() {
854 for (int i = 1; i < kNumExceptions; i++) {
855 if (exceptions[i] != 0) {
856 V8_Fatal(__FILE__, __LINE__, "Error: Exception %i raised.", i);
857 }
858 }
859 }
860
861 // Handle execution based on instruction types.
862 void Simulator::DecodeTypeRegister(Instruction* instr) {
863 // Instruction fields
864 Opcode op = instr->OpcodeFieldRaw();
865 int32_t rs_reg = instr->RsField();
866 int32_t rs = get_register(rs_reg);
867 uint32_t rs_u = static_cast<uint32_t>(rs);
868 int32_t rt_reg = instr->RtField();
869 int32_t rt = get_register(rt_reg);
870 uint32_t rt_u = static_cast<uint32_t>(rt);
871 int32_t rd_reg = instr->RdField();
872 uint32_t sa = instr->SaField();
873
874 int32_t fs_reg= instr->FsField();
875
876 // ALU output
877 // It should not be used as is. Instructions using it should always initialize
878 // it first.
879 int32_t alu_out = 0x12345678;
880 // Output or temporary for floating point.
881 double fp_out = 0.0;
882
883 // For break and trap instructions.
884 bool do_interrupt = false;
885
886 // For jr and jalr
887 // Get current pc.
888 int32_t current_pc = get_pc();
889 // Next pc
890 int32_t next_pc = 0;
891
892 // ---------- Configuration
893 switch (op) {
894 case COP1: // Coprocessor instructions
895 switch (instr->RsFieldRaw()) {
896 case BC1: // branch on coprocessor condition
897 UNREACHABLE();
898 break;
899 case MFC1:
900 alu_out = get_fpu_register(fs_reg);
901 break;
902 case MFHC1:
903 fp_out = get_fpu_register_double(fs_reg);
904 alu_out = *v8i::bit_cast<int32_t*, double*>(&fp_out);
905 break;
906 case MTC1:
907 case MTHC1:
908 // Do the store in the execution step.
909 break;
910 case S:
911 case D:
912 case W:
913 case L:
914 case PS:
915 // Do everything in the execution step.
916 break;
917 default:
918 UNIMPLEMENTED_MIPS();
919 };
920 break;
921 case SPECIAL:
922 switch (instr->FunctionFieldRaw()) {
923 case JR:
924 case JALR:
925 next_pc = get_register(instr->RsField());
926 break;
927 case SLL:
928 alu_out = rt << sa;
929 break;
930 case SRL:
931 alu_out = rt_u >> sa;
932 break;
933 case SRA:
934 alu_out = rt >> sa;
935 break;
936 case SLLV:
937 alu_out = rt << rs;
938 break;
939 case SRLV:
940 alu_out = rt_u >> rs;
941 break;
942 case SRAV:
943 alu_out = rt >> rs;
944 break;
945 case MFHI:
946 alu_out = get_register(HI);
947 break;
948 case MFLO:
949 alu_out = get_register(LO);
950 break;
951 case MULT:
952 UNIMPLEMENTED_MIPS();
953 break;
954 case MULTU:
955 UNIMPLEMENTED_MIPS();
956 break;
957 case DIV:
958 case DIVU:
959 exceptions[kDivideByZero] = rt == 0;
960 break;
961 case ADD:
962 if (HaveSameSign(rs, rt)) {
963 if (rs > 0) {
964 exceptions[kIntegerOverflow] = rs > (Registers::kMaxValue - rt);
965 } else if (rs < 0) {
966 exceptions[kIntegerUnderflow] = rs < (Registers::kMinValue - rt);
967 }
968 }
969 alu_out = rs + rt;
970 break;
971 case ADDU:
972 alu_out = rs + rt;
973 break;
974 case SUB:
975 if (!HaveSameSign(rs, rt)) {
976 if (rs > 0) {
977 exceptions[kIntegerOverflow] = rs > (Registers::kMaxValue + rt);
978 } else if (rs < 0) {
979 exceptions[kIntegerUnderflow] = rs < (Registers::kMinValue + rt);
980 }
981 }
982 alu_out = rs - rt;
983 break;
984 case SUBU:
985 alu_out = rs - rt;
986 break;
987 case AND:
988 alu_out = rs & rt;
989 break;
990 case OR:
991 alu_out = rs | rt;
992 break;
993 case XOR:
994 alu_out = rs ^ rt;
995 break;
996 case NOR:
997 alu_out = ~(rs | rt);
998 break;
999 case SLT:
1000 alu_out = rs < rt ? 1 : 0;
1001 break;
1002 case SLTU:
1003 alu_out = rs_u < rt_u ? 1 : 0;
1004 break;
1005 // Break and trap instructions
1006 case BREAK:
1007 do_interrupt = true;
1008 break;
1009 case TGE:
1010 do_interrupt = rs >= rt;
1011 break;
1012 case TGEU:
1013 do_interrupt = rs_u >= rt_u;
1014 break;
1015 case TLT:
1016 do_interrupt = rs < rt;
1017 break;
1018 case TLTU:
1019 do_interrupt = rs_u < rt_u;
1020 break;
1021 case TEQ:
1022 do_interrupt = rs == rt;
1023 break;
1024 case TNE:
1025 do_interrupt = rs != rt;
1026 break;
1027 default:
1028 UNREACHABLE();
1029 };
1030 break;
1031 case SPECIAL2:
1032 switch (instr->FunctionFieldRaw()) {
1033 case MUL:
1034 alu_out = rs_u * rt_u; // Only the lower 32 bits are kept.
1035 break;
1036 default:
1037 UNREACHABLE();
1038 }
1039 break;
1040 default:
1041 UNREACHABLE();
1042 };
1043
1044 // ---------- Raise exceptions triggered.
1045 SignalExceptions();
1046
1047 // ---------- Execution
1048 switch (op) {
1049 case COP1:
1050 switch (instr->RsFieldRaw()) {
1051 case BC1: // branch on coprocessor condition
1052 UNREACHABLE();
1053 break;
1054 case MFC1:
1055 case MFHC1:
1056 set_register(rt_reg, alu_out);
1057 break;
1058 case MTC1:
1059 // We don't need to set the higher bits to 0, because MIPS ISA says
1060 // they are in an unpredictable state after executing MTC1.
1061 FPUregisters_[fs_reg] = registers_[rt_reg];
1062 FPUregisters_[fs_reg+1] = Unpredictable;
1063 break;
1064 case MTHC1:
1065 // Here we need to keep the lower bits unchanged.
1066 FPUregisters_[fs_reg+1] = registers_[rt_reg];
1067 break;
1068 case S:
1069 switch (instr->FunctionFieldRaw()) {
1070 case CVT_D_S:
1071 case CVT_W_S:
1072 case CVT_L_S:
1073 case CVT_PS_S:
1074 UNIMPLEMENTED_MIPS();
1075 break;
1076 default:
1077 UNREACHABLE();
1078 }
1079 break;
1080 case D:
1081 switch (instr->FunctionFieldRaw()) {
1082 case CVT_S_D:
1083 case CVT_W_D:
1084 case CVT_L_D:
1085 UNIMPLEMENTED_MIPS();
1086 break;
1087 default:
1088 UNREACHABLE();
1089 }
1090 break;
1091 case W:
1092 switch (instr->FunctionFieldRaw()) {
1093 case CVT_S_W:
1094 UNIMPLEMENTED_MIPS();
1095 break;
1096 case CVT_D_W: // Convert word to double.
1097 set_fpu_register(rd_reg, static_cast<double>(rs));
1098 break;
1099 default:
1100 UNREACHABLE();
1101 };
1102 break;
1103 case L:
1104 switch (instr->FunctionFieldRaw()) {
1105 case CVT_S_L:
1106 case CVT_D_L:
1107 UNIMPLEMENTED_MIPS();
1108 break;
1109 default:
1110 UNREACHABLE();
1111 }
1112 break;
1113 case PS:
1114 break;
1115 default:
1116 UNREACHABLE();
1117 };
1118 break;
1119 case SPECIAL:
1120 switch (instr->FunctionFieldRaw()) {
1121 case JR: {
1122 Instruction* branch_delay_instr = reinterpret_cast<Instruction*>(
1123 current_pc+Instruction::kInstructionSize);
1124 BranchDelayInstructionDecode(branch_delay_instr);
1125 set_pc(next_pc);
1126 pc_modified_ = true;
1127 break;
1128 }
1129 case JALR: {
1130 Instruction* branch_delay_instr = reinterpret_cast<Instruction*>(
1131 current_pc+Instruction::kInstructionSize);
1132 BranchDelayInstructionDecode(branch_delay_instr);
1133 set_register(31, current_pc + 2* Instruction::kInstructionSize);
1134 set_pc(next_pc);
1135 pc_modified_ = true;
1136 break;
1137 }
1138 // Instructions using HI and LO registers.
1139 case MULT:
1140 case MULTU:
1141 break;
1142 case DIV:
1143 // Divide by zero was checked in the configuration step.
1144 set_register(LO, rs / rt);
1145 set_register(HI, rs % rt);
1146 break;
1147 case DIVU:
1148 set_register(LO, rs_u / rt_u);
1149 set_register(HI, rs_u % rt_u);
1150 break;
1151 // Break and trap instructions
1152 case BREAK:
1153 case TGE:
1154 case TGEU:
1155 case TLT:
1156 case TLTU:
1157 case TEQ:
1158 case TNE:
1159 if (do_interrupt) {
1160 SoftwareInterrupt(instr);
1161 }
1162 break;
1163 default: // For other special opcodes we do the default operation.
1164 set_register(rd_reg, alu_out);
1165 };
1166 break;
1167 case SPECIAL2:
1168 switch (instr->FunctionFieldRaw()) {
1169 case MUL:
1170 set_register(rd_reg, alu_out);
1171 // HI and LO are UNPREDICTABLE after the operation.
1172 set_register(LO, Unpredictable);
1173 set_register(HI, Unpredictable);
1174 break;
1175 default:
1176 UNREACHABLE();
1177 }
1178 break;
1179 // Unimplemented opcodes raised an error in the configuration step before,
1180 // so we can use the default here to set the destination register in common
1181 // cases.
1182 default:
1183 set_register(rd_reg, alu_out);
1184 };
1185 }
1186
1187 // Type 2: instructions using a 16 bytes immediate. (eg: addi, beq)
1188 void Simulator::DecodeTypeImmediate(Instruction* instr) {
1189 // Instruction fields
1190 Opcode op = instr->OpcodeFieldRaw();
1191 int32_t rs = get_register(instr->RsField());
1192 uint32_t rs_u = static_cast<uint32_t>(rs);
1193 int32_t rt_reg = instr->RtField(); // destination register
1194 int32_t rt = get_register(rt_reg);
1195 int16_t imm16 = instr->Imm16Field();
1196
1197 int32_t ft_reg = instr->FtField(); // destination register
1198 int32_t ft = get_register(ft_reg);
1199
1200 // zero extended immediate
1201 uint32_t oe_imm16 = 0xffff & imm16;
1202 // sign extended immediate
1203 int32_t se_imm16 = imm16;
1204
1205 // Get current pc.
1206 int32_t current_pc = get_pc();
1207 // Next pc.
1208 int32_t next_pc = bad_ra;
1209
1210 // Used for conditional branch instructions
1211 bool do_branch = false;
1212 bool execute_branch_delay_instruction = false;
1213
1214 // Used for arithmetic instructions
1215 int32_t alu_out = 0;
1216 // Floating point
1217 double fp_out = 0.0;
1218
1219 // Used for memory instructions
1220 int32_t addr = 0x0;
1221
1222 // ---------- Configuration (and execution for REGIMM)
1223 switch (op) {
1224 // ------------- COP1. Coprocessor instructions
1225 case COP1:
1226 switch (instr->RsFieldRaw()) {
1227 case BC1: // branch on coprocessor condition
1228 UNIMPLEMENTED_MIPS();
1229 break;
1230 default:
1231 UNREACHABLE();
1232 };
1233 break;
1234 // ------------- REGIMM class
1235 case REGIMM:
1236 switch (instr->RtFieldRaw()) {
1237 case BLTZ:
1238 do_branch = (rs < 0);
1239 break;
1240 case BLTZAL:
1241 do_branch = rs < 0;
1242 break;
1243 case BGEZ:
1244 do_branch = rs >= 0;
1245 break;
1246 case BGEZAL:
1247 do_branch = rs >= 0;
1248 break;
1249 default:
1250 UNREACHABLE();
1251 };
1252 switch (instr->RtFieldRaw()) {
1253 case BLTZ:
1254 case BLTZAL:
1255 case BGEZ:
1256 case BGEZAL:
1257 // Branch instructions common part.
1258 execute_branch_delay_instruction = true;
1259 // Set next_pc
1260 if (do_branch) {
1261 next_pc = current_pc + (imm16 << 2) + Instruction::kInstructionSize;
1262 if (instr->IsLinkingInstruction()) {
1263 set_register(31, current_pc + kBranchReturnOffset);
1264 }
1265 } else {
1266 next_pc = current_pc + kBranchReturnOffset;
1267 }
1268 default:
1269 break;
1270 };
1271 break; // case REGIMM
1272 // ------------- Branch instructions
1273 // When comparing to zero, the encoding of rt field is always 0, so we don't
1274 // need to replace rt with zero.
1275 case BEQ:
1276 do_branch = (rs == rt);
1277 break;
1278 case BNE:
1279 do_branch = rs != rt;
1280 break;
1281 case BLEZ:
1282 do_branch = rs <= 0;
1283 break;
1284 case BGTZ:
1285 do_branch = rs > 0;
1286 break;
1287 // ------------- Arithmetic instructions
1288 case ADDI:
1289 if (HaveSameSign(rs, se_imm16)) {
1290 if (rs > 0) {
1291 exceptions[kIntegerOverflow] = rs > (Registers::kMaxValue - se_imm16);
1292 } else if (rs < 0) {
1293 exceptions[kIntegerUnderflow] =
1294 rs < (Registers::kMinValue - se_imm16);
1295 }
1296 }
1297 alu_out = rs + se_imm16;
1298 break;
1299 case ADDIU:
1300 alu_out = rs + se_imm16;
1301 break;
1302 case SLTI:
1303 alu_out = (rs < se_imm16) ? 1 : 0;
1304 break;
1305 case SLTIU:
1306 alu_out = (rs_u < static_cast<uint32_t>(se_imm16)) ? 1 : 0;
1307 break;
1308 case ANDI:
1309 alu_out = rs & oe_imm16;
1310 break;
1311 case ORI:
1312 alu_out = rs | oe_imm16;
1313 break;
1314 case XORI:
1315 alu_out = rs ^ oe_imm16;
1316 break;
1317 case LUI:
1318 alu_out = (oe_imm16 << 16);
1319 break;
1320 // ------------- Memory instructions
1321 case LB:
1322 addr = rs + se_imm16;
1323 alu_out = ReadB(addr);
1324 break;
1325 case LW:
1326 addr = rs + se_imm16;
1327 alu_out = ReadW(addr, instr);
1328 break;
1329 case LBU:
1330 addr = rs + se_imm16;
1331 alu_out = ReadBU(addr);
1332 break;
1333 case SB:
1334 addr = rs + se_imm16;
1335 break;
1336 case SW:
1337 addr = rs + se_imm16;
1338 break;
1339 case LWC1:
1340 addr = rs + se_imm16;
1341 alu_out = ReadW(addr, instr);
1342 break;
1343 case LDC1:
1344 addr = rs + se_imm16;
1345 fp_out = ReadD(addr, instr);
1346 break;
1347 case SWC1:
1348 case SDC1:
1349 addr = rs + se_imm16;
1350 break;
1351 default:
1352 UNREACHABLE();
1353 };
1354
1355 // ---------- Raise exceptions triggered.
1356 SignalExceptions();
1357
1358 // ---------- Execution
1359 switch (op) {
1360 // ------------- Branch instructions
1361 case BEQ:
1362 case BNE:
1363 case BLEZ:
1364 case BGTZ:
1365 // Branch instructions common part.
1366 execute_branch_delay_instruction = true;
1367 // Set next_pc
1368 if (do_branch) {
1369 next_pc = current_pc + (imm16 << 2) + Instruction::kInstructionSize;
1370 if (instr->IsLinkingInstruction()) {
1371 set_register(31, current_pc + 2* Instruction::kInstructionSize);
1372 }
1373 } else {
1374 next_pc = current_pc + 2 * Instruction::kInstructionSize;
1375 }
1376 break;
1377 // ------------- Arithmetic instructions
1378 case ADDI:
1379 case ADDIU:
1380 case SLTI:
1381 case SLTIU:
1382 case ANDI:
1383 case ORI:
1384 case XORI:
1385 case LUI:
1386 set_register(rt_reg, alu_out);
1387 break;
1388 // ------------- Memory instructions
1389 case LB:
1390 case LW:
1391 case LBU:
1392 set_register(rt_reg, alu_out);
1393 break;
1394 case SB:
1395 WriteB(addr, static_cast<int8_t>(rt));
1396 break;
1397 case SW:
1398 WriteW(addr, rt, instr);
1399 break;
1400 case LWC1:
1401 set_fpu_register(ft_reg, alu_out);
1402 break;
1403 case LDC1:
1404 set_fpu_register_double(ft_reg, fp_out);
1405 break;
1406 case SWC1:
1407 addr = rs + se_imm16;
1408 WriteW(addr, get_fpu_register(ft_reg), instr);
1409 break;
1410 case SDC1:
1411 addr = rs + se_imm16;
1412 WriteD(addr, ft, instr);
1413 break;
1414 default:
1415 break;
1416 };
1417
1418
1419 if (execute_branch_delay_instruction) {
1420 // Execute branch delay slot
1421 // We don't check for end_sim_pc. First it should not be met as the current
1422 // pc is valid. Secondly a jump should always execute its branch delay slot.
1423 Instruction* branch_delay_instr =
1424 reinterpret_cast<Instruction*>(current_pc+Instruction::kInstructionSize);
1425 BranchDelayInstructionDecode(branch_delay_instr);
1426 }
1427
1428 // If needed update pc after the branch delay execution.
1429 if (next_pc != bad_ra) {
1430 set_pc(next_pc);
1431 }
1432 }
1433
1434 // Type 3: instructions using a 26 bytes immediate. (eg: j, jal)
1435 void Simulator::DecodeTypeJump(Instruction* instr) {
1436 // Get current pc.
1437 int32_t current_pc = get_pc();
1438 // Get unchanged bits of pc.
1439 int32_t pc_high_bits = current_pc & 0xf0000000;
1440 // Next pc
1441 int32_t next_pc = pc_high_bits | (instr->Imm26Field() << 2);
1442
1443 // Execute branch delay slot
1444 // We don't check for end_sim_pc. First it should not be met as the current pc
1445 // is valid. Secondly a jump should always execute its branch delay slot.
1446 Instruction* branch_delay_instr =
1447 reinterpret_cast<Instruction*>(current_pc+Instruction::kInstructionSize);
1448 BranchDelayInstructionDecode(branch_delay_instr);
1449
1450 // Update pc and ra if necessary.
1451 // Do this after the branch delay execution.
1452 if (instr->IsLinkingInstruction()) {
1453 set_register(31, current_pc + 2* Instruction::kInstructionSize);
1454 }
1455 set_pc(next_pc);
1456 pc_modified_ = true;
1457 }
1458
1459 // Executes the current instruction.
1460 void Simulator::InstructionDecode(Instruction* instr) {
1461 pc_modified_ = false;
1462 if (::v8::internal::FLAG_trace_sim) {
1463 disasm::NameConverter converter;
1464 disasm::Disassembler dasm(converter);
1465 // use a reasonably large buffer
1466 v8::internal::EmbeddedVector<char, 256> buffer;
1467 dasm.InstructionDecode(buffer,
1468 reinterpret_cast<byte_*>(instr));
1469 PrintF(" 0x%08x %s\n", instr, buffer.start());
1470 }
1471
1472 switch (instr->InstructionType()) {
1473 case Instruction::kRegisterType:
1474 DecodeTypeRegister(instr);
1475 break;
1476 case Instruction::kImmediateType:
1477 DecodeTypeImmediate(instr);
1478 break;
1479 case Instruction::kJumpType:
1480 DecodeTypeJump(instr);
1481 break;
1482 default:
1483 UNSUPPORTED();
1484 }
1485 if (!pc_modified_) {
1486 set_register(pc, reinterpret_cast<int32_t>(instr) +
1487 Instruction::kInstructionSize);
1488 }
1489 }
1490
1491
1492
1493 void Simulator::Execute() {
1494 // Get the PC to simulate. Cannot use the accessor here as we need the
1495 // raw PC value and not the one used as input to arithmetic instructions.
1496 int program_counter = get_pc();
1497 if (::v8::internal::FLAG_stop_sim_at == 0) {
1498 // Fast version of the dispatch loop without checking whether the simulator
1499 // should be stopping at a particular executed instruction.
1500 while (program_counter != end_sim_pc) {
1501 Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
1502 icount_++;
1503 InstructionDecode(instr);
1504 program_counter = get_pc();
1505 }
1506 } else {
1507 // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when
1508 // we reach the particular instuction count.
1509 while (program_counter != end_sim_pc) {
1510 Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
1511 icount_++;
1512 if (icount_ == ::v8::internal::FLAG_stop_sim_at) {
1513 Debugger dbg(this);
1514 dbg.Debug();
1515 } else {
1516 InstructionDecode(instr);
1517 }
1518 program_counter = get_pc();
1519 }
1520 }
1521 }
1522
1523
1524 int32_t Simulator::Call(byte_* entry, int argument_count, ...) {
1525 va_list parameters;
1526 va_start(parameters, argument_count);
1527 // Setup arguments
1528
1529 // First four arguments passed in registers.
1530 ASSERT(argument_count >= 4);
1531 set_register(a0, va_arg(parameters, int32_t));
1532 set_register(a1, va_arg(parameters, int32_t));
1533 set_register(a2, va_arg(parameters, int32_t));
1534 set_register(a3, va_arg(parameters, int32_t));
1535
1536 // Remaining arguments passed on stack.
1537 int original_stack = get_register(sp);
1538 // Compute position of stack on entry to generated code.
1539 int entry_stack = (original_stack - (argument_count - 4) * sizeof(int32_t)
1540 - kArgsSlotsSize);
1541 if (OS::ActivationFrameAlignment() != 0) {
1542 entry_stack &= -OS::ActivationFrameAlignment();
1543 }
1544 // Store remaining arguments on stack, from low to high memory.
1545 intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
1546 for (int i = 4; i < argument_count; i++) {
1547 stack_argument[i - 4 + kArgsSlotsNum] = va_arg(parameters, int32_t);
1548 }
1549 va_end(parameters);
1550 set_register(sp, entry_stack);
1551
1552 // Prepare to execute the code at entry
1553 set_register(pc, reinterpret_cast<int32_t>(entry));
1554 // Put down marker for end of simulation. The simulator will stop simulation
1555 // when the PC reaches this value. By saving the "end simulation" value into
1556 // the LR the simulation stops when returning to this call point.
1557 set_register(ra, end_sim_pc);
1558
1559 // Remember the values of callee-saved registers.
1560 // The code below assumes that r9 is not used as sb (static base) in
1561 // simulator code and therefore is regarded as a callee-saved register.
1562 int32_t s0_val = get_register(s0);
1563 int32_t s1_val = get_register(s1);
1564 int32_t s2_val = get_register(s2);
1565 int32_t s3_val = get_register(s3);
1566 int32_t s4_val = get_register(s4);
1567 int32_t s5_val = get_register(s5);
1568 int32_t s6_val = get_register(s6);
1569 int32_t s7_val = get_register(s7);
1570 int32_t gp_val = get_register(gp);
1571 int32_t sp_val = get_register(sp);
1572 int32_t fp_val = get_register(fp);
1573
1574 // Setup the callee-saved registers with a known value. To be able to check
1575 // that they are preserved properly across JS execution.
1576 int32_t callee_saved_value = icount_;
1577 set_register(s0, callee_saved_value);
1578 set_register(s1, callee_saved_value);
1579 set_register(s2, callee_saved_value);
1580 set_register(s3, callee_saved_value);
1581 set_register(s4, callee_saved_value);
1582 set_register(s5, callee_saved_value);
1583 set_register(s6, callee_saved_value);
1584 set_register(s7, callee_saved_value);
1585 set_register(gp, callee_saved_value);
1586 set_register(fp, callee_saved_value);
1587
1588 // Start the simulation
1589 Execute();
1590
1591 // Check that the callee-saved registers have been preserved.
1592 CHECK_EQ(callee_saved_value, get_register(s0));
1593 CHECK_EQ(callee_saved_value, get_register(s1));
1594 CHECK_EQ(callee_saved_value, get_register(s2));
1595 CHECK_EQ(callee_saved_value, get_register(s3));
1596 CHECK_EQ(callee_saved_value, get_register(s4));
1597 CHECK_EQ(callee_saved_value, get_register(s5));
1598 CHECK_EQ(callee_saved_value, get_register(s6));
1599 CHECK_EQ(callee_saved_value, get_register(s7));
1600 CHECK_EQ(callee_saved_value, get_register(gp));
1601 CHECK_EQ(callee_saved_value, get_register(fp));
1602
1603 // Restore callee-saved registers with the original value.
1604 set_register(s0, s0_val);
1605 set_register(s1, s1_val);
1606 set_register(s2, s2_val);
1607 set_register(s3, s3_val);
1608 set_register(s4, s4_val);
1609 set_register(s5, s5_val);
1610 set_register(s6, s6_val);
1611 set_register(s7, s7_val);
1612 set_register(gp, gp_val);
1613 set_register(sp, sp_val);
1614 set_register(fp, fp_val);
1615
1616 // Pop stack passed arguments.
1617 CHECK_EQ(entry_stack, get_register(sp));
1618 set_register(sp, original_stack);
1619
1620 int32_t result = get_register(v0);
1621 return result;
1622 }
1623
1624
1625 uintptr_t Simulator::PushAddress(uintptr_t address) {
1626 int new_sp = get_register(sp) - sizeof(uintptr_t);
1627 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp);
1628 *stack_slot = address;
1629 set_register(sp, new_sp);
1630 return new_sp;
1631 }
1632
1633
1634 uintptr_t Simulator::PopAddress() {
1635 int current_sp = get_register(sp);
1636 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp);
1637 uintptr_t address = *stack_slot;
1638 set_register(sp, current_sp + sizeof(uintptr_t));
1639 return address;
1640 }
1641
1642
1643 #undef UNSUPPORTED
1644
1645 } } // namespace assembler::mips
1646
1647 #endif // !defined(__mips)
1648
OLDNEW
« no previous file with comments | « src/mips/simulator-mips.h ('k') | src/mips/stub-cache-mips.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698