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

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

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

Powered by Google App Engine
This is Rietveld 408576698