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