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