blob: 30e12e75b1bd3bff66715244d07297720973c6fb [file] [log] [blame]
Ben Murdoch257744e2011-11-30 15:57:28 +00001// Copyright 2011 the V8 project authors. All rights reserved.
Andrei Popescu31002712010-02-23 13:46:05 +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>
Steve Block44f0eee2011-05-26 01:26:41 +010029#include <math.h>
30#include <limits.h>
Andrei Popescu31002712010-02-23 13:46:05 +000031#include <cstdarg>
32#include "v8.h"
33
Leon Clarkef7060e22010-06-03 12:02:55 +010034#if defined(V8_TARGET_ARCH_MIPS)
35
Andrei Popescu31002712010-02-23 13:46:05 +000036#include "disasm.h"
37#include "assembler.h"
Ben Murdoch257744e2011-11-30 15:57:28 +000038#include "globals.h" // Need the BitCast.
Andrei Popescu31002712010-02-23 13:46:05 +000039#include "mips/constants-mips.h"
40#include "mips/simulator-mips.h"
41
Andrei Popescu31002712010-02-23 13:46:05 +000042
43// Only build the simulator if not compiling for real MIPS hardware.
Steve Block44f0eee2011-05-26 01:26:41 +010044#if defined(USE_SIMULATOR)
Andrei Popescu31002712010-02-23 13:46:05 +000045
Steve Block44f0eee2011-05-26 01:26:41 +010046namespace v8 {
47namespace internal {
Andrei Popescu31002712010-02-23 13:46:05 +000048
Ben Murdoch257744e2011-11-30 15:57:28 +000049// Utils functions.
Andrei Popescu31002712010-02-23 13:46:05 +000050bool HaveSameSign(int32_t a, int32_t b) {
Steve Block44f0eee2011-05-26 01:26:41 +010051 return ((a ^ b) >= 0);
52}
53
54
55uint32_t get_fcsr_condition_bit(uint32_t cc) {
56 if (cc == 0) {
57 return 23;
58 } else {
59 return 24 + cc;
60 }
Andrei Popescu31002712010-02-23 13:46:05 +000061}
62
63
64// This macro provides a platform independent use of sscanf. The reason for
65// SScanF not being implemented in a platform independent was through
66// ::v8::internal::OS in the same way as SNPrintF is that the Windows C Run-Time
67// Library does not provide vsscanf.
68#define SScanF sscanf // NOLINT
69
Steve Block44f0eee2011-05-26 01:26:41 +010070// The MipsDebugger class is used by the simulator while debugging simulated
Andrei Popescu31002712010-02-23 13:46:05 +000071// code.
Steve Block44f0eee2011-05-26 01:26:41 +010072class MipsDebugger {
Andrei Popescu31002712010-02-23 13:46:05 +000073 public:
Steve Block44f0eee2011-05-26 01:26:41 +010074 explicit MipsDebugger(Simulator* sim);
75 ~MipsDebugger();
Andrei Popescu31002712010-02-23 13:46:05 +000076
77 void Stop(Instruction* instr);
78 void Debug();
Steve Block44f0eee2011-05-26 01:26:41 +010079 // Print all registers with a nice formatting.
80 void PrintAllRegs();
81 void PrintAllRegsIncludingFPU();
Andrei Popescu31002712010-02-23 13:46:05 +000082
83 private:
84 // We set the breakpoint code to 0xfffff to easily recognize it.
85 static const Instr kBreakpointInstr = SPECIAL | BREAK | 0xfffff << 6;
86 static const Instr kNopInstr = 0x0;
87
88 Simulator* sim_;
89
90 int32_t GetRegisterValue(int regnum);
Steve Block44f0eee2011-05-26 01:26:41 +010091 int32_t GetFPURegisterValueInt(int regnum);
92 int64_t GetFPURegisterValueLong(int regnum);
93 float GetFPURegisterValueFloat(int regnum);
94 double GetFPURegisterValueDouble(int regnum);
Andrei Popescu31002712010-02-23 13:46:05 +000095 bool GetValue(const char* desc, int32_t* value);
96
97 // Set or delete a breakpoint. Returns true if successful.
98 bool SetBreakpoint(Instruction* breakpc);
99 bool DeleteBreakpoint(Instruction* breakpc);
100
101 // Undo and redo all breakpoints. This is needed to bracket disassembly and
102 // execution to skip past breakpoints when run from the debugger.
103 void UndoBreakpoints();
104 void RedoBreakpoints();
Andrei Popescu31002712010-02-23 13:46:05 +0000105};
106
Steve Block44f0eee2011-05-26 01:26:41 +0100107MipsDebugger::MipsDebugger(Simulator* sim) {
Andrei Popescu31002712010-02-23 13:46:05 +0000108 sim_ = sim;
109}
110
Steve Block44f0eee2011-05-26 01:26:41 +0100111
112MipsDebugger::~MipsDebugger() {
Andrei Popescu31002712010-02-23 13:46:05 +0000113}
114
Steve Block44f0eee2011-05-26 01:26:41 +0100115
Andrei Popescu31002712010-02-23 13:46:05 +0000116#ifdef GENERATED_CODE_COVERAGE
117static FILE* coverage_log = NULL;
118
119
120static void InitializeCoverage() {
121 char* file_name = getenv("V8_GENERATED_CODE_COVERAGE_LOG");
122 if (file_name != NULL) {
123 coverage_log = fopen(file_name, "aw+");
124 }
125}
126
127
Steve Block44f0eee2011-05-26 01:26:41 +0100128void MipsDebugger::Stop(Instruction* instr) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000129 // Get the stop code.
130 uint32_t code = instr->Bits(25, 6);
131 // Retrieve the encoded address, which comes just after this stop.
132 char** msg_address =
133 reinterpret_cast<char**>(sim_->get_pc() + Instr::kInstrSize);
134 char* msg = *msg_address;
135 ASSERT(msg != NULL);
136
137 // Update this stop description.
138 if (!watched_stops[code].desc) {
139 watched_stops[code].desc = msg;
140 }
141
142 if (strlen(msg) > 0) {
Andrei Popescu31002712010-02-23 13:46:05 +0000143 if (coverage_log != NULL) {
144 fprintf(coverage_log, "%s\n", str);
145 fflush(coverage_log);
146 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000147 // Overwrite the instruction and address with nops.
148 instr->SetInstructionBits(kNopInstr);
149 reinterpret_cast<Instr*>(msg_address)->SetInstructionBits(kNopInstr);
Andrei Popescu31002712010-02-23 13:46:05 +0000150 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000151 sim_->set_pc(sim_->get_pc() + 2 * Instruction::kInstructionSize);
Andrei Popescu31002712010-02-23 13:46:05 +0000152}
153
Steve Block44f0eee2011-05-26 01:26:41 +0100154
Ben Murdoch257744e2011-11-30 15:57:28 +0000155#else // GENERATED_CODE_COVERAGE
Andrei Popescu31002712010-02-23 13:46:05 +0000156
157#define UNSUPPORTED() printf("Unsupported instruction.\n");
158
159static void InitializeCoverage() {}
160
161
Steve Block44f0eee2011-05-26 01:26:41 +0100162void MipsDebugger::Stop(Instruction* instr) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000163 // Get the stop code.
164 uint32_t code = instr->Bits(25, 6);
165 // Retrieve the encoded address, which comes just after this stop.
166 char* msg = *reinterpret_cast<char**>(sim_->get_pc() +
167 Instruction::kInstrSize);
168 // Update this stop description.
169 if (!sim_->watched_stops[code].desc) {
170 sim_->watched_stops[code].desc = msg;
171 }
172 PrintF("Simulator hit %s (%u)\n", msg, code);
173 sim_->set_pc(sim_->get_pc() + 2 * Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +0000174 Debug();
175}
Steve Block6ded16b2010-05-10 14:33:55 +0100176#endif // GENERATED_CODE_COVERAGE
Andrei Popescu31002712010-02-23 13:46:05 +0000177
178
Steve Block44f0eee2011-05-26 01:26:41 +0100179int32_t MipsDebugger::GetRegisterValue(int regnum) {
Andrei Popescu31002712010-02-23 13:46:05 +0000180 if (regnum == kNumSimuRegisters) {
181 return sim_->get_pc();
182 } else {
183 return sim_->get_register(regnum);
184 }
185}
186
187
Steve Block44f0eee2011-05-26 01:26:41 +0100188int32_t MipsDebugger::GetFPURegisterValueInt(int regnum) {
189 if (regnum == kNumFPURegisters) {
190 return sim_->get_pc();
191 } else {
192 return sim_->get_fpu_register(regnum);
193 }
194}
195
196
197int64_t MipsDebugger::GetFPURegisterValueLong(int regnum) {
198 if (regnum == kNumFPURegisters) {
199 return sim_->get_pc();
200 } else {
201 return sim_->get_fpu_register_long(regnum);
202 }
203}
204
205
206float MipsDebugger::GetFPURegisterValueFloat(int regnum) {
207 if (regnum == kNumFPURegisters) {
208 return sim_->get_pc();
209 } else {
210 return sim_->get_fpu_register_float(regnum);
211 }
212}
213
214
215double MipsDebugger::GetFPURegisterValueDouble(int regnum) {
216 if (regnum == kNumFPURegisters) {
217 return sim_->get_pc();
218 } else {
219 return sim_->get_fpu_register_double(regnum);
220 }
221}
222
223
224bool MipsDebugger::GetValue(const char* desc, int32_t* value) {
Andrei Popescu31002712010-02-23 13:46:05 +0000225 int regnum = Registers::Number(desc);
Steve Block44f0eee2011-05-26 01:26:41 +0100226 int fpuregnum = FPURegisters::Number(desc);
227
Andrei Popescu31002712010-02-23 13:46:05 +0000228 if (regnum != kInvalidRegister) {
229 *value = GetRegisterValue(regnum);
230 return true;
Steve Block44f0eee2011-05-26 01:26:41 +0100231 } else if (fpuregnum != kInvalidFPURegister) {
232 *value = GetFPURegisterValueInt(fpuregnum);
233 return true;
234 } else if (strncmp(desc, "0x", 2) == 0) {
235 return SScanF(desc, "%x", reinterpret_cast<uint32_t*>(value)) == 1;
Andrei Popescu31002712010-02-23 13:46:05 +0000236 } else {
237 return SScanF(desc, "%i", value) == 1;
238 }
239 return false;
240}
241
242
Steve Block44f0eee2011-05-26 01:26:41 +0100243bool MipsDebugger::SetBreakpoint(Instruction* breakpc) {
Andrei Popescu31002712010-02-23 13:46:05 +0000244 // Check if a breakpoint can be set. If not return without any side-effects.
245 if (sim_->break_pc_ != NULL) {
246 return false;
247 }
248
249 // Set the breakpoint.
250 sim_->break_pc_ = breakpc;
251 sim_->break_instr_ = breakpc->InstructionBits();
252 // Not setting the breakpoint instruction in the code itself. It will be set
253 // when the debugger shell continues.
254 return true;
255}
256
257
Steve Block44f0eee2011-05-26 01:26:41 +0100258bool MipsDebugger::DeleteBreakpoint(Instruction* breakpc) {
Andrei Popescu31002712010-02-23 13:46:05 +0000259 if (sim_->break_pc_ != NULL) {
260 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
261 }
262
263 sim_->break_pc_ = NULL;
264 sim_->break_instr_ = 0;
265 return true;
266}
267
268
Steve Block44f0eee2011-05-26 01:26:41 +0100269void MipsDebugger::UndoBreakpoints() {
Andrei Popescu31002712010-02-23 13:46:05 +0000270 if (sim_->break_pc_ != NULL) {
271 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
272 }
273}
274
275
Steve Block44f0eee2011-05-26 01:26:41 +0100276void MipsDebugger::RedoBreakpoints() {
Andrei Popescu31002712010-02-23 13:46:05 +0000277 if (sim_->break_pc_ != NULL) {
278 sim_->break_pc_->SetInstructionBits(kBreakpointInstr);
279 }
280}
281
Steve Block44f0eee2011-05-26 01:26:41 +0100282
283void MipsDebugger::PrintAllRegs() {
Andrei Popescu31002712010-02-23 13:46:05 +0000284#define REG_INFO(n) Registers::Name(n), GetRegisterValue(n), GetRegisterValue(n)
285
286 PrintF("\n");
Ben Murdoch257744e2011-11-30 15:57:28 +0000287 // at, v0, a0.
Andrei Popescu31002712010-02-23 13:46:05 +0000288 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
289 REG_INFO(1), REG_INFO(2), REG_INFO(4));
Ben Murdoch257744e2011-11-30 15:57:28 +0000290 // v1, a1.
Andrei Popescu31002712010-02-23 13:46:05 +0000291 PrintF("%26s\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
292 "", REG_INFO(3), REG_INFO(5));
Ben Murdoch257744e2011-11-30 15:57:28 +0000293 // a2.
Andrei Popescu31002712010-02-23 13:46:05 +0000294 PrintF("%26s\t%26s\t%3s: 0x%08x %10d\n", "", "", REG_INFO(6));
Ben Murdoch257744e2011-11-30 15:57:28 +0000295 // a3.
Andrei Popescu31002712010-02-23 13:46:05 +0000296 PrintF("%26s\t%26s\t%3s: 0x%08x %10d\n", "", "", REG_INFO(7));
297 PrintF("\n");
298 // t0-t7, s0-s7
299 for (int i = 0; i < 8; i++) {
300 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
301 REG_INFO(8+i), REG_INFO(16+i));
302 }
303 PrintF("\n");
Ben Murdoch257744e2011-11-30 15:57:28 +0000304 // t8, k0, LO.
Andrei Popescu31002712010-02-23 13:46:05 +0000305 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
306 REG_INFO(24), REG_INFO(26), REG_INFO(32));
Ben Murdoch257744e2011-11-30 15:57:28 +0000307 // t9, k1, HI.
Andrei Popescu31002712010-02-23 13:46:05 +0000308 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
309 REG_INFO(25), REG_INFO(27), REG_INFO(33));
Ben Murdoch257744e2011-11-30 15:57:28 +0000310 // sp, fp, gp.
Andrei Popescu31002712010-02-23 13:46:05 +0000311 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
312 REG_INFO(29), REG_INFO(30), REG_INFO(28));
Ben Murdoch257744e2011-11-30 15:57:28 +0000313 // pc.
Andrei Popescu31002712010-02-23 13:46:05 +0000314 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
315 REG_INFO(31), REG_INFO(34));
Steve Block44f0eee2011-05-26 01:26:41 +0100316
Andrei Popescu31002712010-02-23 13:46:05 +0000317#undef REG_INFO
Steve Block44f0eee2011-05-26 01:26:41 +0100318#undef FPU_REG_INFO
Andrei Popescu31002712010-02-23 13:46:05 +0000319}
320
Steve Block44f0eee2011-05-26 01:26:41 +0100321
322void MipsDebugger::PrintAllRegsIncludingFPU() {
323#define FPU_REG_INFO(n) FPURegisters::Name(n), FPURegisters::Name(n+1), \
324 GetFPURegisterValueInt(n+1), \
325 GetFPURegisterValueInt(n), \
326 GetFPURegisterValueDouble(n)
327
328 PrintAllRegs();
329
330 PrintF("\n\n");
Ben Murdoch257744e2011-11-30 15:57:28 +0000331 // f0, f1, f2, ... f31.
Steve Block44f0eee2011-05-26 01:26:41 +0100332 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(0) );
333 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(2) );
334 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(4) );
335 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(6) );
336 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(8) );
337 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(10));
338 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(12));
339 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(14));
340 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(16));
341 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(18));
342 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(20));
343 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(22));
344 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(24));
345 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(26));
346 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(28));
347 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(30));
348
349#undef REG_INFO
350#undef FPU_REG_INFO
351}
352
353
354void MipsDebugger::Debug() {
Andrei Popescu31002712010-02-23 13:46:05 +0000355 intptr_t last_pc = -1;
356 bool done = false;
357
358#define COMMAND_SIZE 63
359#define ARG_SIZE 255
360
361#define STR(a) #a
362#define XSTR(a) STR(a)
363
364 char cmd[COMMAND_SIZE + 1];
365 char arg1[ARG_SIZE + 1];
366 char arg2[ARG_SIZE + 1];
Steve Block44f0eee2011-05-26 01:26:41 +0100367 char* argv[3] = { cmd, arg1, arg2 };
Andrei Popescu31002712010-02-23 13:46:05 +0000368
Ben Murdoch257744e2011-11-30 15:57:28 +0000369 // Make sure to have a proper terminating character if reaching the limit.
Andrei Popescu31002712010-02-23 13:46:05 +0000370 cmd[COMMAND_SIZE] = 0;
371 arg1[ARG_SIZE] = 0;
372 arg2[ARG_SIZE] = 0;
373
374 // Undo all set breakpoints while running in the debugger shell. This will
375 // make them invisible to all commands.
376 UndoBreakpoints();
377
378 while (!done && (sim_->get_pc() != Simulator::end_sim_pc)) {
379 if (last_pc != sim_->get_pc()) {
380 disasm::NameConverter converter;
381 disasm::Disassembler dasm(converter);
Ben Murdoch257744e2011-11-30 15:57:28 +0000382 // Use a reasonably large buffer.
Andrei Popescu31002712010-02-23 13:46:05 +0000383 v8::internal::EmbeddedVector<char, 256> buffer;
384 dasm.InstructionDecode(buffer,
Ben Murdoch257744e2011-11-30 15:57:28 +0000385 reinterpret_cast<byte*>(sim_->get_pc()));
Andrei Popescu31002712010-02-23 13:46:05 +0000386 PrintF(" 0x%08x %s\n", sim_->get_pc(), buffer.start());
387 last_pc = sim_->get_pc();
388 }
389 char* line = ReadLine("sim> ");
390 if (line == NULL) {
391 break;
392 } else {
393 // Use sscanf to parse the individual parts of the command line. At the
394 // moment no command expects more than two parameters.
Steve Block44f0eee2011-05-26 01:26:41 +0100395 int argc = SScanF(line,
Andrei Popescu31002712010-02-23 13:46:05 +0000396 "%" XSTR(COMMAND_SIZE) "s "
397 "%" XSTR(ARG_SIZE) "s "
398 "%" XSTR(ARG_SIZE) "s",
399 cmd, arg1, arg2);
400 if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
Steve Block44f0eee2011-05-26 01:26:41 +0100401 Instruction* instr = reinterpret_cast<Instruction*>(sim_->get_pc());
402 if (!(instr->IsTrap()) ||
403 instr->InstructionBits() == rtCallRedirInstr) {
Andrei Popescu31002712010-02-23 13:46:05 +0000404 sim_->InstructionDecode(
Steve Block44f0eee2011-05-26 01:26:41 +0100405 reinterpret_cast<Instruction*>(sim_->get_pc()));
Andrei Popescu31002712010-02-23 13:46:05 +0000406 } else {
407 // Allow si to jump over generated breakpoints.
408 PrintF("/!\\ Jumping over generated breakpoint.\n");
Steve Block44f0eee2011-05-26 01:26:41 +0100409 sim_->set_pc(sim_->get_pc() + Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +0000410 }
411 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) {
412 // Execute the one instruction we broke at with breakpoints disabled.
413 sim_->InstructionDecode(reinterpret_cast<Instruction*>(sim_->get_pc()));
414 // Leave the debugger shell.
415 done = true;
416 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
Steve Block44f0eee2011-05-26 01:26:41 +0100417 if (argc == 2) {
Andrei Popescu31002712010-02-23 13:46:05 +0000418 int32_t value;
Steve Block44f0eee2011-05-26 01:26:41 +0100419 float fvalue;
Andrei Popescu31002712010-02-23 13:46:05 +0000420 if (strcmp(arg1, "all") == 0) {
421 PrintAllRegs();
Steve Block44f0eee2011-05-26 01:26:41 +0100422 } else if (strcmp(arg1, "allf") == 0) {
423 PrintAllRegsIncludingFPU();
Andrei Popescu31002712010-02-23 13:46:05 +0000424 } else {
Steve Block44f0eee2011-05-26 01:26:41 +0100425 int regnum = Registers::Number(arg1);
426 int fpuregnum = FPURegisters::Number(arg1);
427
428 if (regnum != kInvalidRegister) {
429 value = GetRegisterValue(regnum);
Andrei Popescu31002712010-02-23 13:46:05 +0000430 PrintF("%s: 0x%08x %d \n", arg1, value, value);
Steve Block44f0eee2011-05-26 01:26:41 +0100431 } else if (fpuregnum != kInvalidFPURegister) {
432 if (fpuregnum % 2 == 1) {
433 value = GetFPURegisterValueInt(fpuregnum);
434 fvalue = GetFPURegisterValueFloat(fpuregnum);
435 PrintF("%s: 0x%08x %11.4e\n", arg1, value, fvalue);
436 } else {
437 double dfvalue;
438 int32_t lvalue1 = GetFPURegisterValueInt(fpuregnum);
439 int32_t lvalue2 = GetFPURegisterValueInt(fpuregnum + 1);
440 dfvalue = GetFPURegisterValueDouble(fpuregnum);
441 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n",
442 FPURegisters::Name(fpuregnum+1),
443 FPURegisters::Name(fpuregnum),
444 lvalue1,
445 lvalue2,
446 dfvalue);
447 }
Andrei Popescu31002712010-02-23 13:46:05 +0000448 } else {
449 PrintF("%s unrecognized\n", arg1);
450 }
451 }
452 } else {
Steve Block44f0eee2011-05-26 01:26:41 +0100453 if (argc == 3) {
454 if (strcmp(arg2, "single") == 0) {
455 int32_t value;
456 float fvalue;
457 int fpuregnum = FPURegisters::Number(arg1);
458
459 if (fpuregnum != kInvalidFPURegister) {
460 value = GetFPURegisterValueInt(fpuregnum);
461 fvalue = GetFPURegisterValueFloat(fpuregnum);
462 PrintF("%s: 0x%08x %11.4e\n", arg1, value, fvalue);
463 } else {
464 PrintF("%s unrecognized\n", arg1);
465 }
466 } else {
467 PrintF("print <fpu register> single\n");
468 }
469 } else {
470 PrintF("print <register> or print <fpu register> single\n");
471 }
Andrei Popescu31002712010-02-23 13:46:05 +0000472 }
473 } else if ((strcmp(cmd, "po") == 0)
474 || (strcmp(cmd, "printobject") == 0)) {
Steve Block44f0eee2011-05-26 01:26:41 +0100475 if (argc == 2) {
Andrei Popescu31002712010-02-23 13:46:05 +0000476 int32_t value;
477 if (GetValue(arg1, &value)) {
478 Object* obj = reinterpret_cast<Object*>(value);
479 PrintF("%s: \n", arg1);
480#ifdef DEBUG
481 obj->PrintLn();
482#else
483 obj->ShortPrint();
484 PrintF("\n");
485#endif
486 } else {
487 PrintF("%s unrecognized\n", arg1);
488 }
489 } else {
490 PrintF("printobject <value>\n");
491 }
Steve Block44f0eee2011-05-26 01:26:41 +0100492 } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0) {
493 int32_t* cur = NULL;
494 int32_t* end = NULL;
495 int next_arg = 1;
496
497 if (strcmp(cmd, "stack") == 0) {
498 cur = reinterpret_cast<int32_t*>(sim_->get_register(Simulator::sp));
Ben Murdoch257744e2011-11-30 15:57:28 +0000499 } else { // Command "mem".
Steve Block44f0eee2011-05-26 01:26:41 +0100500 int32_t value;
501 if (!GetValue(arg1, &value)) {
502 PrintF("%s unrecognized\n", arg1);
503 continue;
504 }
505 cur = reinterpret_cast<int32_t*>(value);
506 next_arg++;
507 }
508
509 int32_t words;
510 if (argc == next_arg) {
511 words = 10;
512 } else if (argc == next_arg + 1) {
513 if (!GetValue(argv[next_arg], &words)) {
514 words = 10;
515 }
516 }
517 end = cur + words;
518
519 while (cur < end) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000520 PrintF(" 0x%08x: 0x%08x %10d",
Steve Block44f0eee2011-05-26 01:26:41 +0100521 reinterpret_cast<intptr_t>(cur), *cur, *cur);
Ben Murdoch257744e2011-11-30 15:57:28 +0000522 HeapObject* obj = reinterpret_cast<HeapObject*>(*cur);
523 int value = *cur;
524 Heap* current_heap = v8::internal::Isolate::Current()->heap();
525 if (current_heap->Contains(obj) || ((value & 1) == 0)) {
526 PrintF(" (");
527 if ((value & 1) == 0) {
528 PrintF("smi %d", value / 2);
529 } else {
530 obj->ShortPrint();
531 }
532 PrintF(")");
533 }
534 PrintF("\n");
Steve Block44f0eee2011-05-26 01:26:41 +0100535 cur++;
536 }
537
Ben Murdoch257744e2011-11-30 15:57:28 +0000538 } else if ((strcmp(cmd, "disasm") == 0) ||
539 (strcmp(cmd, "dpc") == 0) ||
540 (strcmp(cmd, "di") == 0)) {
Andrei Popescu31002712010-02-23 13:46:05 +0000541 disasm::NameConverter converter;
542 disasm::Disassembler dasm(converter);
Ben Murdoch257744e2011-11-30 15:57:28 +0000543 // Use a reasonably large buffer.
Andrei Popescu31002712010-02-23 13:46:05 +0000544 v8::internal::EmbeddedVector<char, 256> buffer;
545
Ben Murdoch257744e2011-11-30 15:57:28 +0000546 byte* cur = NULL;
547 byte* end = NULL;
Andrei Popescu31002712010-02-23 13:46:05 +0000548
Steve Block44f0eee2011-05-26 01:26:41 +0100549 if (argc == 1) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000550 cur = reinterpret_cast<byte*>(sim_->get_pc());
Steve Block44f0eee2011-05-26 01:26:41 +0100551 end = cur + (10 * Instruction::kInstrSize);
552 } else if (argc == 2) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000553 int regnum = Registers::Number(arg1);
554 if (regnum != kInvalidRegister || strncmp(arg1, "0x", 2) == 0) {
555 // The argument is an address or a register name.
556 int32_t value;
557 if (GetValue(arg1, &value)) {
558 cur = reinterpret_cast<byte*>(value);
559 // Disassemble 10 instructions at <arg1>.
560 end = cur + (10 * Instruction::kInstrSize);
561 }
562 } else {
563 // The argument is the number of instructions.
564 int32_t value;
565 if (GetValue(arg1, &value)) {
566 cur = reinterpret_cast<byte*>(sim_->get_pc());
567 // Disassemble <arg1> instructions.
568 end = cur + (value * Instruction::kInstrSize);
569 }
Andrei Popescu31002712010-02-23 13:46:05 +0000570 }
571 } else {
572 int32_t value1;
573 int32_t value2;
574 if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000575 cur = reinterpret_cast<byte*>(value1);
Steve Block44f0eee2011-05-26 01:26:41 +0100576 end = cur + (value2 * Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +0000577 }
578 }
579
580 while (cur < end) {
581 dasm.InstructionDecode(buffer, cur);
Steve Block44f0eee2011-05-26 01:26:41 +0100582 PrintF(" 0x%08x %s\n",
583 reinterpret_cast<intptr_t>(cur), buffer.start());
584 cur += Instruction::kInstrSize;
Andrei Popescu31002712010-02-23 13:46:05 +0000585 }
586 } else if (strcmp(cmd, "gdb") == 0) {
587 PrintF("relinquishing control to gdb\n");
588 v8::internal::OS::DebugBreak();
589 PrintF("regaining control from gdb\n");
590 } else if (strcmp(cmd, "break") == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +0100591 if (argc == 2) {
Andrei Popescu31002712010-02-23 13:46:05 +0000592 int32_t value;
593 if (GetValue(arg1, &value)) {
594 if (!SetBreakpoint(reinterpret_cast<Instruction*>(value))) {
595 PrintF("setting breakpoint failed\n");
596 }
597 } else {
598 PrintF("%s unrecognized\n", arg1);
599 }
600 } else {
601 PrintF("break <address>\n");
602 }
603 } else if (strcmp(cmd, "del") == 0) {
604 if (!DeleteBreakpoint(NULL)) {
605 PrintF("deleting breakpoint failed\n");
606 }
607 } else if (strcmp(cmd, "flags") == 0) {
608 PrintF("No flags on MIPS !\n");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000609 } else if (strcmp(cmd, "stop") == 0) {
610 int32_t value;
611 intptr_t stop_pc = sim_->get_pc() -
612 2 * Instruction::kInstrSize;
613 Instruction* stop_instr = reinterpret_cast<Instruction*>(stop_pc);
614 Instruction* msg_address =
615 reinterpret_cast<Instruction*>(stop_pc +
616 Instruction::kInstrSize);
617 if ((argc == 2) && (strcmp(arg1, "unstop") == 0)) {
618 // Remove the current stop.
619 if (sim_->IsStopInstruction(stop_instr)) {
620 stop_instr->SetInstructionBits(kNopInstr);
621 msg_address->SetInstructionBits(kNopInstr);
622 } else {
623 PrintF("Not at debugger stop.\n");
624 }
625 } else if (argc == 3) {
626 // Print information about all/the specified breakpoint(s).
627 if (strcmp(arg1, "info") == 0) {
628 if (strcmp(arg2, "all") == 0) {
629 PrintF("Stop information:\n");
630 for (uint32_t i = kMaxWatchpointCode + 1;
631 i <= kMaxStopCode;
632 i++) {
633 sim_->PrintStopInfo(i);
634 }
635 } else if (GetValue(arg2, &value)) {
636 sim_->PrintStopInfo(value);
637 } else {
638 PrintF("Unrecognized argument.\n");
639 }
640 } else if (strcmp(arg1, "enable") == 0) {
641 // Enable all/the specified breakpoint(s).
642 if (strcmp(arg2, "all") == 0) {
643 for (uint32_t i = kMaxWatchpointCode + 1;
644 i <= kMaxStopCode;
645 i++) {
646 sim_->EnableStop(i);
647 }
648 } else if (GetValue(arg2, &value)) {
649 sim_->EnableStop(value);
650 } else {
651 PrintF("Unrecognized argument.\n");
652 }
653 } else if (strcmp(arg1, "disable") == 0) {
654 // Disable all/the specified breakpoint(s).
655 if (strcmp(arg2, "all") == 0) {
656 for (uint32_t i = kMaxWatchpointCode + 1;
657 i <= kMaxStopCode;
658 i++) {
659 sim_->DisableStop(i);
660 }
661 } else if (GetValue(arg2, &value)) {
662 sim_->DisableStop(value);
663 } else {
664 PrintF("Unrecognized argument.\n");
665 }
666 }
667 } else {
668 PrintF("Wrong usage. Use help command for more information.\n");
669 }
Andrei Popescu31002712010-02-23 13:46:05 +0000670 } else if ((strcmp(cmd, "stat") == 0) || (strcmp(cmd, "st") == 0)) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000671 // Print registers and disassemble.
Andrei Popescu31002712010-02-23 13:46:05 +0000672 PrintAllRegs();
673 PrintF("\n");
674
675 disasm::NameConverter converter;
676 disasm::Disassembler dasm(converter);
Ben Murdoch257744e2011-11-30 15:57:28 +0000677 // Use a reasonably large buffer.
Andrei Popescu31002712010-02-23 13:46:05 +0000678 v8::internal::EmbeddedVector<char, 256> buffer;
679
Ben Murdoch257744e2011-11-30 15:57:28 +0000680 byte* cur = NULL;
681 byte* end = NULL;
Andrei Popescu31002712010-02-23 13:46:05 +0000682
Steve Block44f0eee2011-05-26 01:26:41 +0100683 if (argc == 1) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000684 cur = reinterpret_cast<byte*>(sim_->get_pc());
Steve Block44f0eee2011-05-26 01:26:41 +0100685 end = cur + (10 * Instruction::kInstrSize);
686 } else if (argc == 2) {
Andrei Popescu31002712010-02-23 13:46:05 +0000687 int32_t value;
688 if (GetValue(arg1, &value)) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000689 cur = reinterpret_cast<byte*>(value);
Andrei Popescu31002712010-02-23 13:46:05 +0000690 // no length parameter passed, assume 10 instructions
Steve Block44f0eee2011-05-26 01:26:41 +0100691 end = cur + (10 * Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +0000692 }
693 } else {
694 int32_t value1;
695 int32_t value2;
696 if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000697 cur = reinterpret_cast<byte*>(value1);
Steve Block44f0eee2011-05-26 01:26:41 +0100698 end = cur + (value2 * Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +0000699 }
700 }
701
702 while (cur < end) {
703 dasm.InstructionDecode(buffer, cur);
Steve Block44f0eee2011-05-26 01:26:41 +0100704 PrintF(" 0x%08x %s\n",
705 reinterpret_cast<intptr_t>(cur), buffer.start());
706 cur += Instruction::kInstrSize;
Andrei Popescu31002712010-02-23 13:46:05 +0000707 }
708 } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
709 PrintF("cont\n");
710 PrintF(" continue execution (alias 'c')\n");
711 PrintF("stepi\n");
712 PrintF(" step one instruction (alias 'si')\n");
713 PrintF("print <register>\n");
714 PrintF(" print register content (alias 'p')\n");
715 PrintF(" use register name 'all' to print all registers\n");
716 PrintF("printobject <register>\n");
717 PrintF(" print an object from a register (alias 'po')\n");
Steve Block44f0eee2011-05-26 01:26:41 +0100718 PrintF("stack [<words>]\n");
719 PrintF(" dump stack content, default dump 10 words)\n");
720 PrintF("mem <address> [<words>]\n");
721 PrintF(" dump memory content, default dump 10 words)\n");
Andrei Popescu31002712010-02-23 13:46:05 +0000722 PrintF("flags\n");
723 PrintF(" print flags\n");
724 PrintF("disasm [<instructions>]\n");
Ben Murdoch257744e2011-11-30 15:57:28 +0000725 PrintF("disasm [<address/register>]\n");
726 PrintF("disasm [[<address/register>] <instructions>]\n");
727 PrintF(" disassemble code, default is 10 instructions\n");
728 PrintF(" from pc (alias 'di')\n");
Andrei Popescu31002712010-02-23 13:46:05 +0000729 PrintF("gdb\n");
730 PrintF(" enter gdb\n");
731 PrintF("break <address>\n");
732 PrintF(" set a break point on the address\n");
733 PrintF("del\n");
734 PrintF(" delete the breakpoint\n");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000735 PrintF("stop feature:\n");
736 PrintF(" Description:\n");
737 PrintF(" Stops are debug instructions inserted by\n");
738 PrintF(" the Assembler::stop() function.\n");
739 PrintF(" When hitting a stop, the Simulator will\n");
740 PrintF(" stop and and give control to the Debugger.\n");
741 PrintF(" All stop codes are watched:\n");
742 PrintF(" - They can be enabled / disabled: the Simulator\n");
743 PrintF(" will / won't stop when hitting them.\n");
744 PrintF(" - The Simulator keeps track of how many times they \n");
745 PrintF(" are met. (See the info command.) Going over a\n");
746 PrintF(" disabled stop still increases its counter. \n");
747 PrintF(" Commands:\n");
748 PrintF(" stop info all/<code> : print infos about number <code>\n");
749 PrintF(" or all stop(s).\n");
750 PrintF(" stop enable/disable all/<code> : enables / disables\n");
751 PrintF(" all or number <code> stop(s)\n");
752 PrintF(" stop unstop\n");
753 PrintF(" ignore the stop instruction at the current location\n");
754 PrintF(" from now on\n");
Andrei Popescu31002712010-02-23 13:46:05 +0000755 } else {
756 PrintF("Unknown command: %s\n", cmd);
757 }
758 }
759 DeleteArray(line);
760 }
761
762 // Add all the breakpoints back to stop execution and enter the debugger
763 // shell when hit.
764 RedoBreakpoints();
765
766#undef COMMAND_SIZE
767#undef ARG_SIZE
768
769#undef STR
770#undef XSTR
771}
772
773
Steve Block44f0eee2011-05-26 01:26:41 +0100774static bool ICacheMatch(void* one, void* two) {
775 ASSERT((reinterpret_cast<intptr_t>(one) & CachePage::kPageMask) == 0);
776 ASSERT((reinterpret_cast<intptr_t>(two) & CachePage::kPageMask) == 0);
777 return one == two;
778}
Andrei Popescu31002712010-02-23 13:46:05 +0000779
780
Steve Block44f0eee2011-05-26 01:26:41 +0100781static uint32_t ICacheHash(void* key) {
782 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)) >> 2;
783}
784
785
786static bool AllOnOnePage(uintptr_t start, int size) {
787 intptr_t start_page = (start & ~CachePage::kPageMask);
788 intptr_t end_page = ((start + size) & ~CachePage::kPageMask);
789 return start_page == end_page;
790}
791
792
793void Simulator::FlushICache(v8::internal::HashMap* i_cache,
794 void* start_addr,
795 size_t size) {
796 intptr_t start = reinterpret_cast<intptr_t>(start_addr);
797 int intra_line = (start & CachePage::kLineMask);
798 start -= intra_line;
799 size += intra_line;
800 size = ((size - 1) | CachePage::kLineMask) + 1;
801 int offset = (start & CachePage::kPageMask);
802 while (!AllOnOnePage(start, size - 1)) {
803 int bytes_to_flush = CachePage::kPageSize - offset;
804 FlushOnePage(i_cache, start, bytes_to_flush);
805 start += bytes_to_flush;
806 size -= bytes_to_flush;
807 ASSERT_EQ(0, start & CachePage::kPageMask);
808 offset = 0;
809 }
810 if (size != 0) {
811 FlushOnePage(i_cache, start, size);
812 }
813}
814
815
816CachePage* Simulator::GetCachePage(v8::internal::HashMap* i_cache, void* page) {
817 v8::internal::HashMap::Entry* entry = i_cache->Lookup(page,
Ben Murdoch257744e2011-11-30 15:57:28 +0000818 ICacheHash(page),
819 true);
Steve Block44f0eee2011-05-26 01:26:41 +0100820 if (entry->value == NULL) {
821 CachePage* new_page = new CachePage();
822 entry->value = new_page;
823 }
824 return reinterpret_cast<CachePage*>(entry->value);
825}
826
827
828// Flush from start up to and not including start + size.
829void Simulator::FlushOnePage(v8::internal::HashMap* i_cache,
830 intptr_t start,
831 int size) {
832 ASSERT(size <= CachePage::kPageSize);
833 ASSERT(AllOnOnePage(start, size - 1));
834 ASSERT((start & CachePage::kLineMask) == 0);
835 ASSERT((size & CachePage::kLineMask) == 0);
836 void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask));
837 int offset = (start & CachePage::kPageMask);
838 CachePage* cache_page = GetCachePage(i_cache, page);
839 char* valid_bytemap = cache_page->ValidityByte(offset);
840 memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift);
841}
842
843
844void Simulator::CheckICache(v8::internal::HashMap* i_cache,
845 Instruction* instr) {
846 intptr_t address = reinterpret_cast<intptr_t>(instr);
847 void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
848 void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask));
849 int offset = (address & CachePage::kPageMask);
850 CachePage* cache_page = GetCachePage(i_cache, page);
851 char* cache_valid_byte = cache_page->ValidityByte(offset);
852 bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID);
853 char* cached_line = cache_page->CachedData(offset & ~CachePage::kLineMask);
854 if (cache_hit) {
855 // Check that the data in memory matches the contents of the I-cache.
856 CHECK(memcmp(reinterpret_cast<void*>(instr),
857 cache_page->CachedData(offset),
858 Instruction::kInstrSize) == 0);
859 } else {
860 // Cache miss. Load memory into the cache.
861 memcpy(cached_line, line, CachePage::kLineLength);
862 *cache_valid_byte = CachePage::LINE_VALID;
863 }
864}
Andrei Popescu31002712010-02-23 13:46:05 +0000865
866
Ben Murdoch257744e2011-11-30 15:57:28 +0000867void Simulator::Initialize(Isolate* isolate) {
868 if (isolate->simulator_initialized()) return;
869 isolate->set_simulator_initialized(true);
870 ::v8::internal::ExternalReference::set_redirector(isolate,
871 &RedirectExternalReference);
Andrei Popescu31002712010-02-23 13:46:05 +0000872}
873
874
Ben Murdoch257744e2011-11-30 15:57:28 +0000875Simulator::Simulator(Isolate* isolate) : isolate_(isolate) {
Steve Block44f0eee2011-05-26 01:26:41 +0100876 i_cache_ = isolate_->simulator_i_cache();
877 if (i_cache_ == NULL) {
878 i_cache_ = new v8::internal::HashMap(&ICacheMatch);
879 isolate_->set_simulator_i_cache(i_cache_);
880 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000881 Initialize(isolate);
Andrei Popescu31002712010-02-23 13:46:05 +0000882 // Setup simulator support first. Some of this information is needed to
883 // setup the architecture state.
Steve Block44f0eee2011-05-26 01:26:41 +0100884 stack_ = reinterpret_cast<char*>(malloc(stack_size_));
Andrei Popescu31002712010-02-23 13:46:05 +0000885 pc_modified_ = false;
886 icount_ = 0;
Steve Block44f0eee2011-05-26 01:26:41 +0100887 break_count_ = 0;
Andrei Popescu31002712010-02-23 13:46:05 +0000888 break_pc_ = NULL;
889 break_instr_ = 0;
890
891 // Setup architecture state.
892 // All registers are initialized to zero to start with.
893 for (int i = 0; i < kNumSimuRegisters; i++) {
894 registers_[i] = 0;
895 }
Steve Block44f0eee2011-05-26 01:26:41 +0100896 for (int i = 0; i < kNumFPURegisters; i++) {
897 FPUregisters_[i] = 0;
898 }
899 FCSR_ = 0;
Andrei Popescu31002712010-02-23 13:46:05 +0000900
901 // The sp is initialized to point to the bottom (high address) of the
902 // allocated stack area. To be safe in potential stack underflows we leave
903 // some buffer below.
Steve Block44f0eee2011-05-26 01:26:41 +0100904 registers_[sp] = reinterpret_cast<int32_t>(stack_) + stack_size_ - 64;
Andrei Popescu31002712010-02-23 13:46:05 +0000905 // The ra and pc are initialized to a known bad value that will cause an
906 // access violation if the simulator ever tries to execute it.
907 registers_[pc] = bad_ra;
908 registers_[ra] = bad_ra;
909 InitializeCoverage();
Steve Block44f0eee2011-05-26 01:26:41 +0100910 for (int i = 0; i < kNumExceptions; i++) {
911 exceptions[i] = 0;
912 }
Andrei Popescu31002712010-02-23 13:46:05 +0000913}
914
915
916// When the generated code calls an external reference we need to catch that in
917// the simulator. The external reference will be a function compiled for the
918// host architecture. We need to call that function instead of trying to
919// execute it with the simulator. We do that by redirecting the external
920// reference to a swi (software-interrupt) instruction that is handled by
921// the simulator. We write the original destination of the jump just at a known
922// offset from the swi instruction so the simulator knows what to call.
923class Redirection {
924 public:
Steve Block44f0eee2011-05-26 01:26:41 +0100925 Redirection(void* external_function, ExternalReference::Type type)
Andrei Popescu31002712010-02-23 13:46:05 +0000926 : external_function_(external_function),
927 swi_instruction_(rtCallRedirInstr),
Steve Block44f0eee2011-05-26 01:26:41 +0100928 type_(type),
929 next_(NULL) {
930 Isolate* isolate = Isolate::Current();
931 next_ = isolate->simulator_redirection();
932 Simulator::current(isolate)->
933 FlushICache(isolate->simulator_i_cache(),
934 reinterpret_cast<void*>(&swi_instruction_),
935 Instruction::kInstrSize);
936 isolate->set_simulator_redirection(this);
Andrei Popescu31002712010-02-23 13:46:05 +0000937 }
938
939 void* address_of_swi_instruction() {
940 return reinterpret_cast<void*>(&swi_instruction_);
941 }
942
943 void* external_function() { return external_function_; }
Steve Block44f0eee2011-05-26 01:26:41 +0100944 ExternalReference::Type type() { return type_; }
Andrei Popescu31002712010-02-23 13:46:05 +0000945
Steve Block44f0eee2011-05-26 01:26:41 +0100946 static Redirection* Get(void* external_function,
947 ExternalReference::Type type) {
948 Isolate* isolate = Isolate::Current();
949 Redirection* current = isolate->simulator_redirection();
950 for (; current != NULL; current = current->next_) {
Andrei Popescu31002712010-02-23 13:46:05 +0000951 if (current->external_function_ == external_function) return current;
952 }
Steve Block44f0eee2011-05-26 01:26:41 +0100953 return new Redirection(external_function, type);
Andrei Popescu31002712010-02-23 13:46:05 +0000954 }
955
956 static Redirection* FromSwiInstruction(Instruction* swi_instruction) {
957 char* addr_of_swi = reinterpret_cast<char*>(swi_instruction);
958 char* addr_of_redirection =
959 addr_of_swi - OFFSET_OF(Redirection, swi_instruction_);
960 return reinterpret_cast<Redirection*>(addr_of_redirection);
961 }
962
963 private:
964 void* external_function_;
965 uint32_t swi_instruction_;
Steve Block44f0eee2011-05-26 01:26:41 +0100966 ExternalReference::Type type_;
Andrei Popescu31002712010-02-23 13:46:05 +0000967 Redirection* next_;
Andrei Popescu31002712010-02-23 13:46:05 +0000968};
969
970
Andrei Popescu31002712010-02-23 13:46:05 +0000971void* Simulator::RedirectExternalReference(void* external_function,
Steve Block44f0eee2011-05-26 01:26:41 +0100972 ExternalReference::Type type) {
973 Redirection* redirection = Redirection::Get(external_function, type);
Andrei Popescu31002712010-02-23 13:46:05 +0000974 return redirection->address_of_swi_instruction();
975}
976
977
978// Get the active Simulator for the current thread.
Steve Block44f0eee2011-05-26 01:26:41 +0100979Simulator* Simulator::current(Isolate* isolate) {
980 v8::internal::Isolate::PerIsolateThreadData* isolate_data =
Ben Murdoch257744e2011-11-30 15:57:28 +0000981 isolate->FindOrAllocatePerThreadDataForThisThread();
982 ASSERT(isolate_data != NULL);
Steve Block44f0eee2011-05-26 01:26:41 +0100983 ASSERT(isolate_data != NULL);
984
985 Simulator* sim = isolate_data->simulator();
Andrei Popescu31002712010-02-23 13:46:05 +0000986 if (sim == NULL) {
Steve Block44f0eee2011-05-26 01:26:41 +0100987 // TODO(146): delete the simulator object when a thread/isolate goes away.
Ben Murdoch257744e2011-11-30 15:57:28 +0000988 sim = new Simulator(isolate);
Steve Block44f0eee2011-05-26 01:26:41 +0100989 isolate_data->set_simulator(sim);
Andrei Popescu31002712010-02-23 13:46:05 +0000990 }
991 return sim;
992}
993
994
995// Sets the register in the architecture state. It will also deal with updating
996// Simulator internal state for special registers such as PC.
997void Simulator::set_register(int reg, int32_t value) {
998 ASSERT((reg >= 0) && (reg < kNumSimuRegisters));
999 if (reg == pc) {
1000 pc_modified_ = true;
1001 }
1002
Ben Murdoch257744e2011-11-30 15:57:28 +00001003 // Zero register always holds 0.
Andrei Popescu31002712010-02-23 13:46:05 +00001004 registers_[reg] = (reg == 0) ? 0 : value;
1005}
1006
Steve Block44f0eee2011-05-26 01:26:41 +01001007
Andrei Popescu31002712010-02-23 13:46:05 +00001008void Simulator::set_fpu_register(int fpureg, int32_t value) {
1009 ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters));
1010 FPUregisters_[fpureg] = value;
1011}
1012
Steve Block44f0eee2011-05-26 01:26:41 +01001013
1014void Simulator::set_fpu_register_float(int fpureg, float value) {
1015 ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters));
1016 *BitCast<float*>(&FPUregisters_[fpureg]) = value;
1017}
1018
1019
Andrei Popescu31002712010-02-23 13:46:05 +00001020void Simulator::set_fpu_register_double(int fpureg, double value) {
1021 ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
Steve Block44f0eee2011-05-26 01:26:41 +01001022 *BitCast<double*>(&FPUregisters_[fpureg]) = value;
Andrei Popescu31002712010-02-23 13:46:05 +00001023}
1024
1025
1026// Get the register from the architecture state. This function does handle
1027// the special case of accessing the PC register.
1028int32_t Simulator::get_register(int reg) const {
1029 ASSERT((reg >= 0) && (reg < kNumSimuRegisters));
1030 if (reg == 0)
1031 return 0;
1032 else
1033 return registers_[reg] + ((reg == pc) ? Instruction::kPCReadOffset : 0);
1034}
1035
Steve Block44f0eee2011-05-26 01:26:41 +01001036
Andrei Popescu31002712010-02-23 13:46:05 +00001037int32_t Simulator::get_fpu_register(int fpureg) const {
1038 ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters));
1039 return FPUregisters_[fpureg];
1040}
1041
Steve Block44f0eee2011-05-26 01:26:41 +01001042
1043int64_t Simulator::get_fpu_register_long(int fpureg) const {
1044 ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
1045 return *BitCast<int64_t*>(
1046 const_cast<int32_t*>(&FPUregisters_[fpureg]));
1047}
1048
1049
1050float Simulator::get_fpu_register_float(int fpureg) const {
1051 ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters));
1052 return *BitCast<float*>(
1053 const_cast<int32_t*>(&FPUregisters_[fpureg]));
1054}
1055
1056
Andrei Popescu31002712010-02-23 13:46:05 +00001057double Simulator::get_fpu_register_double(int fpureg) const {
1058 ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
Steve Block44f0eee2011-05-26 01:26:41 +01001059 return *BitCast<double*>(const_cast<int32_t*>(&FPUregisters_[fpureg]));
Andrei Popescu31002712010-02-23 13:46:05 +00001060}
1061
Steve Block44f0eee2011-05-26 01:26:41 +01001062
Ben Murdoch257744e2011-11-30 15:57:28 +00001063// For use in calls that take two double values, constructed either
1064// from a0-a3 or f12 and f14.
1065void Simulator::GetFpArgs(double* x, double* y) {
1066 if (!IsMipsSoftFloatABI) {
1067 *x = get_fpu_register_double(12);
1068 *y = get_fpu_register_double(14);
1069 } else {
1070 // We use a char buffer to get around the strict-aliasing rules which
1071 // otherwise allow the compiler to optimize away the copy.
1072 char buffer[sizeof(*x)];
1073 int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
1074
1075 // Registers a0 and a1 -> x.
1076 reg_buffer[0] = get_register(a0);
1077 reg_buffer[1] = get_register(a1);
1078 memcpy(x, buffer, sizeof(buffer));
1079
1080 // Registers a2 and a3 -> y.
1081 reg_buffer[0] = get_register(a2);
1082 reg_buffer[1] = get_register(a3);
1083 memcpy(y, buffer, sizeof(buffer));
1084 }
1085}
1086
1087
1088// For use in calls that take one double value, constructed either
1089// from a0 and a1 or f12.
1090void Simulator::GetFpArgs(double* x) {
1091 if (!IsMipsSoftFloatABI) {
1092 *x = get_fpu_register_double(12);
1093 } else {
1094 // We use a char buffer to get around the strict-aliasing rules which
1095 // otherwise allow the compiler to optimize away the copy.
1096 char buffer[sizeof(*x)];
1097 int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
1098 // Registers a0 and a1 -> x.
1099 reg_buffer[0] = get_register(a0);
1100 reg_buffer[1] = get_register(a1);
1101 memcpy(x, buffer, sizeof(buffer));
1102 }
1103}
1104
1105
1106// For use in calls that take one double value constructed either
1107// from a0 and a1 or f12 and one integer value.
1108void Simulator::GetFpArgs(double* x, int32_t* y) {
1109 if (!IsMipsSoftFloatABI) {
1110 *x = get_fpu_register_double(12);
1111 *y = get_register(a2);
1112 } else {
1113 // We use a char buffer to get around the strict-aliasing rules which
1114 // otherwise allow the compiler to optimize away the copy.
1115 char buffer[sizeof(*x)];
1116 int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
1117 // Registers 0 and 1 -> x.
1118 reg_buffer[0] = get_register(a0);
1119 reg_buffer[1] = get_register(a1);
1120 memcpy(x, buffer, sizeof(buffer));
1121
1122 // Register 2 -> y.
1123 reg_buffer[0] = get_register(a2);
1124 memcpy(y, buffer, sizeof(*y));
1125 }
1126}
1127
1128
1129// The return value is either in v0/v1 or f0.
1130void Simulator::SetFpResult(const double& result) {
1131 if (!IsMipsSoftFloatABI) {
1132 set_fpu_register_double(0, result);
1133 } else {
1134 char buffer[2 * sizeof(registers_[0])];
1135 int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
1136 memcpy(buffer, &result, sizeof(buffer));
1137 // Copy result to v0 and v1.
1138 set_register(v0, reg_buffer[0]);
1139 set_register(v1, reg_buffer[1]);
1140 }
1141}
1142
1143
Steve Block44f0eee2011-05-26 01:26:41 +01001144// Helper functions for setting and testing the FCSR register's bits.
1145void Simulator::set_fcsr_bit(uint32_t cc, bool value) {
1146 if (value) {
1147 FCSR_ |= (1 << cc);
1148 } else {
1149 FCSR_ &= ~(1 << cc);
1150 }
1151}
1152
1153
1154bool Simulator::test_fcsr_bit(uint32_t cc) {
1155 return FCSR_ & (1 << cc);
1156}
1157
1158
1159// Sets the rounding error codes in FCSR based on the result of the rounding.
1160// Returns true if the operation was invalid.
1161bool Simulator::set_fcsr_round_error(double original, double rounded) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001162 bool ret = false;
1163
1164 if (!isfinite(original) || !isfinite(rounded)) {
1165 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1166 ret = true;
Steve Block44f0eee2011-05-26 01:26:41 +01001167 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001168
1169 if (original != rounded) {
1170 set_fcsr_bit(kFCSRInexactFlagBit, true);
1171 }
1172
1173 if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) {
1174 set_fcsr_bit(kFCSRUnderflowFlagBit, true);
1175 ret = true;
1176 }
1177
1178 if (rounded > INT_MAX || rounded < INT_MIN) {
1179 set_fcsr_bit(kFCSROverflowFlagBit, true);
1180 // The reference is not really clear but it seems this is required:
1181 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1182 ret = true;
1183 }
1184
1185 return ret;
Steve Block44f0eee2011-05-26 01:26:41 +01001186}
1187
1188
Andrei Popescu31002712010-02-23 13:46:05 +00001189// Raw access to the PC register.
1190void Simulator::set_pc(int32_t value) {
1191 pc_modified_ = true;
1192 registers_[pc] = value;
1193}
1194
Steve Block44f0eee2011-05-26 01:26:41 +01001195
1196bool Simulator::has_bad_pc() const {
1197 return ((registers_[pc] == bad_ra) || (registers_[pc] == end_sim_pc));
1198}
1199
1200
Andrei Popescu31002712010-02-23 13:46:05 +00001201// Raw access to the PC register without the special adjustment when reading.
1202int32_t Simulator::get_pc() const {
1203 return registers_[pc];
1204}
1205
1206
1207// The MIPS cannot do unaligned reads and writes. On some MIPS platforms an
1208// interrupt is caused. On others it does a funky rotation thing. For now we
1209// simply disallow unaligned reads, but at some point we may want to move to
1210// emulating the rotate behaviour. Note that simulator runs have the runtime
1211// system running directly on the host system and only generated code is
1212// executed in the simulator. Since the host is typically IA32 we will not
1213// get the correct MIPS-like behaviour on unaligned accesses.
1214
1215int Simulator::ReadW(int32_t addr, Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +01001216 if (addr >=0 && addr < 0x400) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001217 // This has to be a NULL-dereference, drop into debugger.
Steve Block44f0eee2011-05-26 01:26:41 +01001218 MipsDebugger dbg(this);
1219 dbg.Debug();
1220 }
1221 if ((addr & kPointerAlignmentMask) == 0) {
Andrei Popescu31002712010-02-23 13:46:05 +00001222 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
1223 return *ptr;
1224 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001225 PrintF("Unaligned read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1226 addr,
1227 reinterpret_cast<intptr_t>(instr));
Steve Block44f0eee2011-05-26 01:26:41 +01001228 MipsDebugger dbg(this);
1229 dbg.Debug();
Andrei Popescu31002712010-02-23 13:46:05 +00001230 return 0;
1231}
1232
1233
1234void Simulator::WriteW(int32_t addr, int value, Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +01001235 if (addr >= 0 && addr < 0x400) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001236 // This has to be a NULL-dereference, drop into debugger.
Steve Block44f0eee2011-05-26 01:26:41 +01001237 MipsDebugger dbg(this);
1238 dbg.Debug();
1239 }
1240 if ((addr & kPointerAlignmentMask) == 0) {
Andrei Popescu31002712010-02-23 13:46:05 +00001241 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
1242 *ptr = value;
1243 return;
1244 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001245 PrintF("Unaligned write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1246 addr,
1247 reinterpret_cast<intptr_t>(instr));
Steve Block44f0eee2011-05-26 01:26:41 +01001248 MipsDebugger dbg(this);
1249 dbg.Debug();
Andrei Popescu31002712010-02-23 13:46:05 +00001250}
1251
1252
1253double Simulator::ReadD(int32_t addr, Instruction* instr) {
1254 if ((addr & kDoubleAlignmentMask) == 0) {
1255 double* ptr = reinterpret_cast<double*>(addr);
1256 return *ptr;
1257 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001258 PrintF("Unaligned (double) read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1259 addr,
1260 reinterpret_cast<intptr_t>(instr));
Andrei Popescu31002712010-02-23 13:46:05 +00001261 OS::Abort();
1262 return 0;
1263}
1264
1265
1266void Simulator::WriteD(int32_t addr, double value, Instruction* instr) {
1267 if ((addr & kDoubleAlignmentMask) == 0) {
1268 double* ptr = reinterpret_cast<double*>(addr);
1269 *ptr = value;
1270 return;
1271 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001272 PrintF("Unaligned (double) write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1273 addr,
1274 reinterpret_cast<intptr_t>(instr));
Andrei Popescu31002712010-02-23 13:46:05 +00001275 OS::Abort();
1276}
1277
1278
1279uint16_t Simulator::ReadHU(int32_t addr, Instruction* instr) {
1280 if ((addr & 1) == 0) {
1281 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1282 return *ptr;
1283 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001284 PrintF("Unaligned unsigned halfword read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1285 addr,
1286 reinterpret_cast<intptr_t>(instr));
Andrei Popescu31002712010-02-23 13:46:05 +00001287 OS::Abort();
1288 return 0;
1289}
1290
1291
1292int16_t Simulator::ReadH(int32_t addr, Instruction* instr) {
1293 if ((addr & 1) == 0) {
1294 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
1295 return *ptr;
1296 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001297 PrintF("Unaligned signed halfword read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1298 addr,
1299 reinterpret_cast<intptr_t>(instr));
Andrei Popescu31002712010-02-23 13:46:05 +00001300 OS::Abort();
1301 return 0;
1302}
1303
1304
1305void Simulator::WriteH(int32_t addr, uint16_t value, Instruction* instr) {
1306 if ((addr & 1) == 0) {
1307 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1308 *ptr = value;
1309 return;
1310 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001311 PrintF("Unaligned unsigned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1312 addr,
1313 reinterpret_cast<intptr_t>(instr));
Andrei Popescu31002712010-02-23 13:46:05 +00001314 OS::Abort();
1315}
1316
1317
1318void Simulator::WriteH(int32_t addr, int16_t value, Instruction* instr) {
1319 if ((addr & 1) == 0) {
1320 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
1321 *ptr = value;
1322 return;
1323 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001324 PrintF("Unaligned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1325 addr,
1326 reinterpret_cast<intptr_t>(instr));
Andrei Popescu31002712010-02-23 13:46:05 +00001327 OS::Abort();
1328}
1329
1330
1331uint32_t Simulator::ReadBU(int32_t addr) {
1332 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1333 return *ptr & 0xff;
1334}
1335
1336
1337int32_t Simulator::ReadB(int32_t addr) {
1338 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
Steve Block44f0eee2011-05-26 01:26:41 +01001339 return *ptr;
Andrei Popescu31002712010-02-23 13:46:05 +00001340}
1341
1342
1343void Simulator::WriteB(int32_t addr, uint8_t value) {
1344 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1345 *ptr = value;
1346}
1347
1348
1349void Simulator::WriteB(int32_t addr, int8_t value) {
1350 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
1351 *ptr = value;
1352}
1353
1354
1355// Returns the limit of the stack area to enable checking for stack overflows.
1356uintptr_t Simulator::StackLimit() const {
1357 // Leave a safety margin of 256 bytes to prevent overrunning the stack when
1358 // pushing values.
1359 return reinterpret_cast<uintptr_t>(stack_) + 256;
1360}
1361
1362
1363// Unsupported instructions use Format to print an error and stop execution.
1364void Simulator::Format(Instruction* instr, const char* format) {
1365 PrintF("Simulator found unsupported instruction:\n 0x%08x: %s\n",
Steve Block44f0eee2011-05-26 01:26:41 +01001366 reinterpret_cast<intptr_t>(instr), format);
Andrei Popescu31002712010-02-23 13:46:05 +00001367 UNIMPLEMENTED_MIPS();
1368}
1369
1370
1371// Calls into the V8 runtime are based on this very simple interface.
1372// Note: To be able to return two values from some calls the code in runtime.cc
1373// uses the ObjectPair which is essentially two 32-bit values stuffed into a
1374// 64-bit value. With the code below we assume that all runtime calls return
Steve Block44f0eee2011-05-26 01:26:41 +01001375// 64 bits of result. If they don't, the v1 result register contains a bogus
Andrei Popescu31002712010-02-23 13:46:05 +00001376// value, which is fine because it is caller-saved.
1377typedef int64_t (*SimulatorRuntimeCall)(int32_t arg0,
1378 int32_t arg1,
1379 int32_t arg2,
Steve Block44f0eee2011-05-26 01:26:41 +01001380 int32_t arg3,
1381 int32_t arg4,
1382 int32_t arg5);
1383typedef double (*SimulatorRuntimeFPCall)(int32_t arg0,
1384 int32_t arg1,
1385 int32_t arg2,
1386 int32_t arg3);
Andrei Popescu31002712010-02-23 13:46:05 +00001387
Ben Murdoch257744e2011-11-30 15:57:28 +00001388// This signature supports direct call in to API function native callback
1389// (refer to InvocationCallback in v8.h).
1390typedef v8::Handle<v8::Value> (*SimulatorRuntimeDirectApiCall)(int32_t arg0);
1391
1392// This signature supports direct call to accessor getter callback.
1393typedef v8::Handle<v8::Value> (*SimulatorRuntimeDirectGetterCall)(int32_t arg0,
1394 int32_t arg1);
1395
Andrei Popescu31002712010-02-23 13:46:05 +00001396// Software interrupt instructions are used by the simulator to call into the
Steve Block44f0eee2011-05-26 01:26:41 +01001397// C-based V8 runtime. They are also used for debugging with simulator.
Andrei Popescu31002712010-02-23 13:46:05 +00001398void Simulator::SoftwareInterrupt(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +01001399 // There are several instructions that could get us here,
1400 // the break_ instruction, or several variants of traps. All
1401 // Are "SPECIAL" class opcode, and are distinuished by function.
1402 int32_t func = instr->FunctionFieldRaw();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001403 uint32_t code = (func == BREAK) ? instr->Bits(25, 6) : -1;
Steve Block44f0eee2011-05-26 01:26:41 +01001404
Andrei Popescu31002712010-02-23 13:46:05 +00001405 // We first check if we met a call_rt_redirected.
1406 if (instr->InstructionBits() == rtCallRedirInstr) {
1407 Redirection* redirection = Redirection::FromSwiInstruction(instr);
1408 int32_t arg0 = get_register(a0);
1409 int32_t arg1 = get_register(a1);
1410 int32_t arg2 = get_register(a2);
1411 int32_t arg3 = get_register(a3);
Steve Block44f0eee2011-05-26 01:26:41 +01001412 int32_t arg4 = 0;
1413 int32_t arg5 = 0;
1414
1415 // Need to check if sp is valid before assigning arg4, arg5.
1416 // This is a fix for cctest test-api/CatchStackOverflow which causes
1417 // the stack to overflow. For some reason arm doesn't need this
1418 // stack check here.
1419 int32_t* stack_pointer = reinterpret_cast<int32_t*>(get_register(sp));
1420 int32_t* stack = reinterpret_cast<int32_t*>(stack_);
Ben Murdoch257744e2011-11-30 15:57:28 +00001421 if (stack_pointer >= stack && stack_pointer < stack + stack_size_ - 5) {
1422 // Args 4 and 5 are on the stack after the reserved space for args 0..3.
1423 arg4 = stack_pointer[4];
1424 arg5 = stack_pointer[5];
Steve Block44f0eee2011-05-26 01:26:41 +01001425 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001426
1427 bool fp_call =
1428 (redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) ||
1429 (redirection->type() == ExternalReference::BUILTIN_COMPARE_CALL) ||
1430 (redirection->type() == ExternalReference::BUILTIN_FP_CALL) ||
1431 (redirection->type() == ExternalReference::BUILTIN_FP_INT_CALL);
1432
1433 if (!IsMipsSoftFloatABI) {
1434 // With the hard floating point calling convention, double
1435 // arguments are passed in FPU registers. Fetch the arguments
1436 // from there and call the builtin using soft floating point
1437 // convention.
1438 switch (redirection->type()) {
1439 case ExternalReference::BUILTIN_FP_FP_CALL:
1440 case ExternalReference::BUILTIN_COMPARE_CALL:
1441 arg0 = get_fpu_register(f12);
1442 arg1 = get_fpu_register(f13);
1443 arg2 = get_fpu_register(f14);
1444 arg3 = get_fpu_register(f15);
1445 break;
1446 case ExternalReference::BUILTIN_FP_CALL:
1447 arg0 = get_fpu_register(f12);
1448 arg1 = get_fpu_register(f13);
1449 break;
1450 case ExternalReference::BUILTIN_FP_INT_CALL:
1451 arg0 = get_fpu_register(f12);
1452 arg1 = get_fpu_register(f13);
1453 arg2 = get_register(a2);
1454 break;
1455 default:
1456 break;
1457 }
1458 }
1459
Andrei Popescu31002712010-02-23 13:46:05 +00001460 // This is dodgy but it works because the C entry stubs are never moved.
1461 // See comment in codegen-arm.cc and bug 1242173.
1462 int32_t saved_ra = get_register(ra);
Steve Block44f0eee2011-05-26 01:26:41 +01001463
1464 intptr_t external =
Ben Murdoch257744e2011-11-30 15:57:28 +00001465 reinterpret_cast<intptr_t>(redirection->external_function());
Steve Block44f0eee2011-05-26 01:26:41 +01001466
1467 // Based on CpuFeatures::IsSupported(FPU), Mips will use either hardware
1468 // FPU, or gcc soft-float routines. Hardware FPU is simulated in this
1469 // simulator. Soft-float has additional abstraction of ExternalReference,
Ben Murdoch257744e2011-11-30 15:57:28 +00001470 // to support serialization.
1471 if (fp_call) {
Andrei Popescu31002712010-02-23 13:46:05 +00001472 SimulatorRuntimeFPCall target =
Ben Murdoch257744e2011-11-30 15:57:28 +00001473 reinterpret_cast<SimulatorRuntimeFPCall>(external);
1474 if (::v8::internal::FLAG_trace_sim) {
1475 double dval0, dval1;
1476 int32_t ival;
1477 switch (redirection->type()) {
1478 case ExternalReference::BUILTIN_FP_FP_CALL:
1479 case ExternalReference::BUILTIN_COMPARE_CALL:
1480 GetFpArgs(&dval0, &dval1);
1481 PrintF("Call to host function at %p with args %f, %f",
1482 FUNCTION_ADDR(target), dval0, dval1);
1483 break;
1484 case ExternalReference::BUILTIN_FP_CALL:
1485 GetFpArgs(&dval0);
1486 PrintF("Call to host function at %p with arg %f",
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001487 FUNCTION_ADDR(target), dval0);
Ben Murdoch257744e2011-11-30 15:57:28 +00001488 break;
1489 case ExternalReference::BUILTIN_FP_INT_CALL:
1490 GetFpArgs(&dval0, &ival);
1491 PrintF("Call to host function at %p with args %f, %d",
1492 FUNCTION_ADDR(target), dval0, ival);
1493 break;
1494 default:
1495 UNREACHABLE();
1496 break;
Steve Block44f0eee2011-05-26 01:26:41 +01001497 }
Andrei Popescu31002712010-02-23 13:46:05 +00001498 }
Steve Block44f0eee2011-05-26 01:26:41 +01001499 double result = target(arg0, arg1, arg2, arg3);
Ben Murdoch257744e2011-11-30 15:57:28 +00001500 if (redirection->type() != ExternalReference::BUILTIN_COMPARE_CALL) {
1501 SetFpResult(result);
1502 } else {
1503 int32_t gpreg_pair[2];
1504 memcpy(&gpreg_pair[0], &result, 2 * sizeof(int32_t));
1505 set_register(v0, gpreg_pair[0]);
1506 set_register(v1, gpreg_pair[1]);
1507 }
Steve Block44f0eee2011-05-26 01:26:41 +01001508 } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001509 // See DirectCEntryStub::GenerateCall for explanation of register usage.
1510 SimulatorRuntimeDirectApiCall target =
1511 reinterpret_cast<SimulatorRuntimeDirectApiCall>(external);
1512 if (::v8::internal::FLAG_trace_sim) {
1513 PrintF("Call to host function at %p args %08x\n",
1514 FUNCTION_ADDR(target), arg1);
1515 }
1516 v8::Handle<v8::Value> result = target(arg1);
1517 *(reinterpret_cast<int*>(arg0)) = (int32_t) *result;
1518 set_register(v0, arg0);
Steve Block44f0eee2011-05-26 01:26:41 +01001519 } else if (redirection->type() == ExternalReference::DIRECT_GETTER_CALL) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001520 // See DirectCEntryStub::GenerateCall for explanation of register usage.
1521 SimulatorRuntimeDirectGetterCall target =
1522 reinterpret_cast<SimulatorRuntimeDirectGetterCall>(external);
1523 if (::v8::internal::FLAG_trace_sim) {
1524 PrintF("Call to host function at %p args %08x %08x\n",
1525 FUNCTION_ADDR(target), arg1, arg2);
1526 }
1527 v8::Handle<v8::Value> result = target(arg1, arg2);
1528 *(reinterpret_cast<int*>(arg0)) = (int32_t) *result;
1529 set_register(v0, arg0);
Andrei Popescu31002712010-02-23 13:46:05 +00001530 } else {
Andrei Popescu31002712010-02-23 13:46:05 +00001531 SimulatorRuntimeCall target =
Ben Murdoch257744e2011-11-30 15:57:28 +00001532 reinterpret_cast<SimulatorRuntimeCall>(external);
1533 if (::v8::internal::FLAG_trace_sim) {
Andrei Popescu31002712010-02-23 13:46:05 +00001534 PrintF(
Ben Murdoch257744e2011-11-30 15:57:28 +00001535 "Call to host function at %p "
1536 "args %08x, %08x, %08x, %08x, %08x, %08x\n",
Andrei Popescu31002712010-02-23 13:46:05 +00001537 FUNCTION_ADDR(target),
1538 arg0,
1539 arg1,
1540 arg2,
Steve Block44f0eee2011-05-26 01:26:41 +01001541 arg3,
1542 arg4,
1543 arg5);
Andrei Popescu31002712010-02-23 13:46:05 +00001544 }
Steve Block44f0eee2011-05-26 01:26:41 +01001545 int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5);
1546 set_register(v0, static_cast<int32_t>(result));
1547 set_register(v1, static_cast<int32_t>(result >> 32));
1548 }
1549 if (::v8::internal::FLAG_trace_sim) {
1550 PrintF("Returned %08x : %08x\n", get_register(v1), get_register(v0));
Andrei Popescu31002712010-02-23 13:46:05 +00001551 }
1552 set_register(ra, saved_ra);
1553 set_pc(get_register(ra));
Steve Block44f0eee2011-05-26 01:26:41 +01001554
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001555 } else if (func == BREAK && code <= kMaxStopCode) {
1556 if (IsWatchpoint(code)) {
1557 PrintWatchpoint(code);
1558 } else {
1559 IncreaseStopCounter(code);
1560 HandleStop(code, instr);
1561 }
Andrei Popescu31002712010-02-23 13:46:05 +00001562 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01001563 // All remaining break_ codes, and all traps are handled here.
1564 MipsDebugger dbg(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001565 dbg.Debug();
1566 }
1567}
1568
Steve Block44f0eee2011-05-26 01:26:41 +01001569
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001570// Stop helper functions.
1571bool Simulator::IsWatchpoint(uint32_t code) {
1572 return (code <= kMaxWatchpointCode);
1573}
1574
1575
1576void Simulator::PrintWatchpoint(uint32_t code) {
1577 MipsDebugger dbg(this);
1578 ++break_count_;
1579 PrintF("\n---- break %d marker: %3d (instr count: %8d) ----------"
1580 "----------------------------------",
1581 code, break_count_, icount_);
1582 dbg.PrintAllRegs(); // Print registers and continue running.
1583}
1584
1585
1586void Simulator::HandleStop(uint32_t code, Instruction* instr) {
1587 // Stop if it is enabled, otherwise go on jumping over the stop
1588 // and the message address.
1589 if (IsEnabledStop(code)) {
1590 MipsDebugger dbg(this);
1591 dbg.Stop(instr);
1592 } else {
1593 set_pc(get_pc() + 2 * Instruction::kInstrSize);
1594 }
1595}
1596
1597
1598bool Simulator::IsStopInstruction(Instruction* instr) {
1599 int32_t func = instr->FunctionFieldRaw();
1600 uint32_t code = static_cast<uint32_t>(instr->Bits(25, 6));
1601 return (func == BREAK) && code > kMaxWatchpointCode && code <= kMaxStopCode;
1602}
1603
1604
1605bool Simulator::IsEnabledStop(uint32_t code) {
1606 ASSERT(code <= kMaxStopCode);
1607 ASSERT(code > kMaxWatchpointCode);
1608 return !(watched_stops[code].count & kStopDisabledBit);
1609}
1610
1611
1612void Simulator::EnableStop(uint32_t code) {
1613 if (!IsEnabledStop(code)) {
1614 watched_stops[code].count &= ~kStopDisabledBit;
1615 }
1616}
1617
1618
1619void Simulator::DisableStop(uint32_t code) {
1620 if (IsEnabledStop(code)) {
1621 watched_stops[code].count |= kStopDisabledBit;
1622 }
1623}
1624
1625
1626void Simulator::IncreaseStopCounter(uint32_t code) {
1627 ASSERT(code <= kMaxStopCode);
1628 if ((watched_stops[code].count & ~(1 << 31)) == 0x7fffffff) {
1629 PrintF("Stop counter for code %i has overflowed.\n"
1630 "Enabling this code and reseting the counter to 0.\n", code);
1631 watched_stops[code].count = 0;
1632 EnableStop(code);
1633 } else {
1634 watched_stops[code].count++;
1635 }
1636}
1637
1638
1639// Print a stop status.
1640void Simulator::PrintStopInfo(uint32_t code) {
1641 if (code <= kMaxWatchpointCode) {
1642 PrintF("That is a watchpoint, not a stop.\n");
1643 return;
1644 } else if (code > kMaxStopCode) {
1645 PrintF("Code too large, only %u stops can be used\n", kMaxStopCode + 1);
1646 return;
1647 }
1648 const char* state = IsEnabledStop(code) ? "Enabled" : "Disabled";
1649 int32_t count = watched_stops[code].count & ~kStopDisabledBit;
1650 // Don't print the state of unused breakpoints.
1651 if (count != 0) {
1652 if (watched_stops[code].desc) {
1653 PrintF("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n",
1654 code, code, state, count, watched_stops[code].desc);
1655 } else {
1656 PrintF("stop %i - 0x%x: \t%s, \tcounter = %i\n",
1657 code, code, state, count);
1658 }
1659 }
1660}
1661
1662
Andrei Popescu31002712010-02-23 13:46:05 +00001663void Simulator::SignalExceptions() {
1664 for (int i = 1; i < kNumExceptions; i++) {
1665 if (exceptions[i] != 0) {
1666 V8_Fatal(__FILE__, __LINE__, "Error: Exception %i raised.", i);
1667 }
1668 }
1669}
1670
Steve Block44f0eee2011-05-26 01:26:41 +01001671
Andrei Popescu31002712010-02-23 13:46:05 +00001672// Handle execution based on instruction types.
Andrei Popescu31002712010-02-23 13:46:05 +00001673
Steve Block44f0eee2011-05-26 01:26:41 +01001674void Simulator::ConfigureTypeRegister(Instruction* instr,
1675 int32_t& alu_out,
1676 int64_t& i64hilo,
1677 uint64_t& u64hilo,
1678 int32_t& next_pc,
1679 bool& do_interrupt) {
1680 // Every local variable declared here needs to be const.
1681 // This is to make sure that changed values are sent back to
1682 // DecodeTypeRegister correctly.
Andrei Popescu31002712010-02-23 13:46:05 +00001683
Steve Block44f0eee2011-05-26 01:26:41 +01001684 // Instruction fields.
1685 const Opcode op = instr->OpcodeFieldRaw();
1686 const int32_t rs_reg = instr->RsValue();
1687 const int32_t rs = get_register(rs_reg);
1688 const uint32_t rs_u = static_cast<uint32_t>(rs);
1689 const int32_t rt_reg = instr->RtValue();
1690 const int32_t rt = get_register(rt_reg);
1691 const uint32_t rt_u = static_cast<uint32_t>(rt);
1692 const int32_t rd_reg = instr->RdValue();
1693 const uint32_t sa = instr->SaValue();
Andrei Popescu31002712010-02-23 13:46:05 +00001694
Steve Block44f0eee2011-05-26 01:26:41 +01001695 const int32_t fs_reg = instr->FsValue();
Andrei Popescu31002712010-02-23 13:46:05 +00001696
Andrei Popescu31002712010-02-23 13:46:05 +00001697
Ben Murdoch257744e2011-11-30 15:57:28 +00001698 // ---------- Configuration.
Andrei Popescu31002712010-02-23 13:46:05 +00001699 switch (op) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001700 case COP1: // Coprocessor instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00001701 switch (instr->RsFieldRaw()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001702 case BC1: // Handled in DecodeTypeImmed, should never come here.
Andrei Popescu31002712010-02-23 13:46:05 +00001703 UNREACHABLE();
1704 break;
Steve Block44f0eee2011-05-26 01:26:41 +01001705 case CFC1:
1706 // At the moment only FCSR is supported.
1707 ASSERT(fs_reg == kFCSRRegister);
1708 alu_out = FCSR_;
1709 break;
Andrei Popescu31002712010-02-23 13:46:05 +00001710 case MFC1:
1711 alu_out = get_fpu_register(fs_reg);
1712 break;
1713 case MFHC1:
Steve Block44f0eee2011-05-26 01:26:41 +01001714 UNIMPLEMENTED_MIPS();
Andrei Popescu31002712010-02-23 13:46:05 +00001715 break;
Steve Block44f0eee2011-05-26 01:26:41 +01001716 case CTC1:
Andrei Popescu31002712010-02-23 13:46:05 +00001717 case MTC1:
1718 case MTHC1:
1719 // Do the store in the execution step.
1720 break;
1721 case S:
1722 case D:
1723 case W:
1724 case L:
1725 case PS:
1726 // Do everything in the execution step.
1727 break;
1728 default:
1729 UNIMPLEMENTED_MIPS();
1730 };
1731 break;
1732 case SPECIAL:
1733 switch (instr->FunctionFieldRaw()) {
1734 case JR:
1735 case JALR:
Steve Block44f0eee2011-05-26 01:26:41 +01001736 next_pc = get_register(instr->RsValue());
Andrei Popescu31002712010-02-23 13:46:05 +00001737 break;
1738 case SLL:
1739 alu_out = rt << sa;
1740 break;
1741 case SRL:
Steve Block44f0eee2011-05-26 01:26:41 +01001742 if (rs_reg == 0) {
1743 // Regular logical right shift of a word by a fixed number of
1744 // bits instruction. RS field is always equal to 0.
1745 alu_out = rt_u >> sa;
1746 } else {
1747 // Logical right-rotate of a word by a fixed number of bits. This
1748 // is special case of SRL instruction, added in MIPS32 Release 2.
Ben Murdoch257744e2011-11-30 15:57:28 +00001749 // RS field is equal to 00001.
Steve Block44f0eee2011-05-26 01:26:41 +01001750 alu_out = (rt_u >> sa) | (rt_u << (32 - sa));
1751 }
Andrei Popescu31002712010-02-23 13:46:05 +00001752 break;
1753 case SRA:
1754 alu_out = rt >> sa;
1755 break;
1756 case SLLV:
1757 alu_out = rt << rs;
1758 break;
1759 case SRLV:
Steve Block44f0eee2011-05-26 01:26:41 +01001760 if (sa == 0) {
1761 // Regular logical right-shift of a word by a variable number of
1762 // bits instruction. SA field is always equal to 0.
1763 alu_out = rt_u >> rs;
1764 } else {
1765 // Logical right-rotate of a word by a variable number of bits.
1766 // This is special case od SRLV instruction, added in MIPS32
Ben Murdoch257744e2011-11-30 15:57:28 +00001767 // Release 2. SA field is equal to 00001.
Steve Block44f0eee2011-05-26 01:26:41 +01001768 alu_out = (rt_u >> rs_u) | (rt_u << (32 - rs_u));
1769 }
Andrei Popescu31002712010-02-23 13:46:05 +00001770 break;
1771 case SRAV:
1772 alu_out = rt >> rs;
1773 break;
1774 case MFHI:
1775 alu_out = get_register(HI);
1776 break;
1777 case MFLO:
1778 alu_out = get_register(LO);
1779 break;
1780 case MULT:
Steve Block44f0eee2011-05-26 01:26:41 +01001781 i64hilo = static_cast<int64_t>(rs) * static_cast<int64_t>(rt);
Andrei Popescu31002712010-02-23 13:46:05 +00001782 break;
1783 case MULTU:
Steve Block44f0eee2011-05-26 01:26:41 +01001784 u64hilo = static_cast<uint64_t>(rs_u) * static_cast<uint64_t>(rt_u);
Andrei Popescu31002712010-02-23 13:46:05 +00001785 break;
Andrei Popescu31002712010-02-23 13:46:05 +00001786 case ADD:
1787 if (HaveSameSign(rs, rt)) {
1788 if (rs > 0) {
1789 exceptions[kIntegerOverflow] = rs > (Registers::kMaxValue - rt);
1790 } else if (rs < 0) {
1791 exceptions[kIntegerUnderflow] = rs < (Registers::kMinValue - rt);
1792 }
1793 }
1794 alu_out = rs + rt;
1795 break;
1796 case ADDU:
1797 alu_out = rs + rt;
1798 break;
1799 case SUB:
1800 if (!HaveSameSign(rs, rt)) {
1801 if (rs > 0) {
1802 exceptions[kIntegerOverflow] = rs > (Registers::kMaxValue + rt);
1803 } else if (rs < 0) {
1804 exceptions[kIntegerUnderflow] = rs < (Registers::kMinValue + rt);
1805 }
1806 }
1807 alu_out = rs - rt;
1808 break;
1809 case SUBU:
1810 alu_out = rs - rt;
1811 break;
1812 case AND:
1813 alu_out = rs & rt;
1814 break;
1815 case OR:
1816 alu_out = rs | rt;
1817 break;
1818 case XOR:
1819 alu_out = rs ^ rt;
1820 break;
1821 case NOR:
1822 alu_out = ~(rs | rt);
1823 break;
1824 case SLT:
1825 alu_out = rs < rt ? 1 : 0;
1826 break;
1827 case SLTU:
1828 alu_out = rs_u < rt_u ? 1 : 0;
1829 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00001830 // Break and trap instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00001831 case BREAK:
Steve Block44f0eee2011-05-26 01:26:41 +01001832
Andrei Popescu31002712010-02-23 13:46:05 +00001833 do_interrupt = true;
1834 break;
1835 case TGE:
1836 do_interrupt = rs >= rt;
1837 break;
1838 case TGEU:
1839 do_interrupt = rs_u >= rt_u;
1840 break;
1841 case TLT:
1842 do_interrupt = rs < rt;
1843 break;
1844 case TLTU:
1845 do_interrupt = rs_u < rt_u;
1846 break;
1847 case TEQ:
1848 do_interrupt = rs == rt;
1849 break;
1850 case TNE:
1851 do_interrupt = rs != rt;
1852 break;
Steve Block44f0eee2011-05-26 01:26:41 +01001853 case MOVN:
1854 case MOVZ:
1855 case MOVCI:
1856 // No action taken on decode.
1857 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00001858 case DIV:
1859 case DIVU:
1860 // div and divu never raise exceptions.
1861 break;
Andrei Popescu31002712010-02-23 13:46:05 +00001862 default:
1863 UNREACHABLE();
1864 };
1865 break;
1866 case SPECIAL2:
1867 switch (instr->FunctionFieldRaw()) {
1868 case MUL:
1869 alu_out = rs_u * rt_u; // Only the lower 32 bits are kept.
1870 break;
Steve Block44f0eee2011-05-26 01:26:41 +01001871 case CLZ:
1872 alu_out = __builtin_clz(rs_u);
1873 break;
Andrei Popescu31002712010-02-23 13:46:05 +00001874 default:
1875 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +01001876 };
1877 break;
1878 case SPECIAL3:
1879 switch (instr->FunctionFieldRaw()) {
1880 case INS: { // Mips32r2 instruction.
Ben Murdoch257744e2011-11-30 15:57:28 +00001881 // Interpret rd field as 5-bit msb of insert.
Steve Block44f0eee2011-05-26 01:26:41 +01001882 uint16_t msb = rd_reg;
1883 // Interpret sa field as 5-bit lsb of insert.
1884 uint16_t lsb = sa;
1885 uint16_t size = msb - lsb + 1;
1886 uint32_t mask = (1 << size) - 1;
1887 alu_out = (rt_u & ~(mask << lsb)) | ((rs_u & mask) << lsb);
1888 break;
1889 }
1890 case EXT: { // Mips32r2 instruction.
Ben Murdoch257744e2011-11-30 15:57:28 +00001891 // Interpret rd field as 5-bit msb of extract.
Steve Block44f0eee2011-05-26 01:26:41 +01001892 uint16_t msb = rd_reg;
1893 // Interpret sa field as 5-bit lsb of extract.
1894 uint16_t lsb = sa;
1895 uint16_t size = msb + 1;
1896 uint32_t mask = (1 << size) - 1;
1897 alu_out = (rs_u & (mask << lsb)) >> lsb;
1898 break;
1899 }
1900 default:
1901 UNREACHABLE();
1902 };
Andrei Popescu31002712010-02-23 13:46:05 +00001903 break;
1904 default:
1905 UNREACHABLE();
1906 };
Steve Block44f0eee2011-05-26 01:26:41 +01001907}
1908
1909
1910void Simulator::DecodeTypeRegister(Instruction* instr) {
1911 // Instruction fields.
1912 const Opcode op = instr->OpcodeFieldRaw();
1913 const int32_t rs_reg = instr->RsValue();
1914 const int32_t rs = get_register(rs_reg);
1915 const uint32_t rs_u = static_cast<uint32_t>(rs);
1916 const int32_t rt_reg = instr->RtValue();
1917 const int32_t rt = get_register(rt_reg);
1918 const uint32_t rt_u = static_cast<uint32_t>(rt);
1919 const int32_t rd_reg = instr->RdValue();
1920
1921 const int32_t fs_reg = instr->FsValue();
1922 const int32_t ft_reg = instr->FtValue();
1923 const int32_t fd_reg = instr->FdValue();
1924 int64_t i64hilo = 0;
1925 uint64_t u64hilo = 0;
1926
Ben Murdoch257744e2011-11-30 15:57:28 +00001927 // ALU output.
Steve Block44f0eee2011-05-26 01:26:41 +01001928 // It should not be used as is. Instructions using it should always
1929 // initialize it first.
1930 int32_t alu_out = 0x12345678;
1931
1932 // For break and trap instructions.
1933 bool do_interrupt = false;
1934
Ben Murdoch257744e2011-11-30 15:57:28 +00001935 // For jr and jalr.
Steve Block44f0eee2011-05-26 01:26:41 +01001936 // Get current pc.
1937 int32_t current_pc = get_pc();
1938 // Next pc
1939 int32_t next_pc = 0;
1940
1941 // Setup the variables if needed before executing the instruction.
1942 ConfigureTypeRegister(instr,
1943 alu_out,
1944 i64hilo,
1945 u64hilo,
1946 next_pc,
1947 do_interrupt);
Andrei Popescu31002712010-02-23 13:46:05 +00001948
1949 // ---------- Raise exceptions triggered.
1950 SignalExceptions();
1951
Ben Murdoch257744e2011-11-30 15:57:28 +00001952 // ---------- Execution.
Andrei Popescu31002712010-02-23 13:46:05 +00001953 switch (op) {
1954 case COP1:
1955 switch (instr->RsFieldRaw()) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001956 case BC1: // Branch on coprocessor condition.
Andrei Popescu31002712010-02-23 13:46:05 +00001957 UNREACHABLE();
1958 break;
Steve Block44f0eee2011-05-26 01:26:41 +01001959 case CFC1:
1960 set_register(rt_reg, alu_out);
Andrei Popescu31002712010-02-23 13:46:05 +00001961 case MFC1:
Andrei Popescu31002712010-02-23 13:46:05 +00001962 set_register(rt_reg, alu_out);
1963 break;
Steve Block44f0eee2011-05-26 01:26:41 +01001964 case MFHC1:
1965 UNIMPLEMENTED_MIPS();
1966 break;
1967 case CTC1:
1968 // At the moment only FCSR is supported.
1969 ASSERT(fs_reg == kFCSRRegister);
1970 FCSR_ = registers_[rt_reg];
1971 break;
Andrei Popescu31002712010-02-23 13:46:05 +00001972 case MTC1:
Andrei Popescu31002712010-02-23 13:46:05 +00001973 FPUregisters_[fs_reg] = registers_[rt_reg];
Andrei Popescu31002712010-02-23 13:46:05 +00001974 break;
1975 case MTHC1:
Steve Block44f0eee2011-05-26 01:26:41 +01001976 UNIMPLEMENTED_MIPS();
Andrei Popescu31002712010-02-23 13:46:05 +00001977 break;
1978 case S:
Steve Block44f0eee2011-05-26 01:26:41 +01001979 float f;
Andrei Popescu31002712010-02-23 13:46:05 +00001980 switch (instr->FunctionFieldRaw()) {
1981 case CVT_D_S:
Steve Block44f0eee2011-05-26 01:26:41 +01001982 f = get_fpu_register_float(fs_reg);
1983 set_fpu_register_double(fd_reg, static_cast<double>(f));
1984 break;
Andrei Popescu31002712010-02-23 13:46:05 +00001985 case CVT_W_S:
1986 case CVT_L_S:
Steve Block44f0eee2011-05-26 01:26:41 +01001987 case TRUNC_W_S:
1988 case TRUNC_L_S:
1989 case ROUND_W_S:
1990 case ROUND_L_S:
1991 case FLOOR_W_S:
1992 case FLOOR_L_S:
1993 case CEIL_W_S:
1994 case CEIL_L_S:
Andrei Popescu31002712010-02-23 13:46:05 +00001995 case CVT_PS_S:
1996 UNIMPLEMENTED_MIPS();
1997 break;
1998 default:
1999 UNREACHABLE();
2000 }
2001 break;
2002 case D:
Steve Block44f0eee2011-05-26 01:26:41 +01002003 double ft, fs;
2004 uint32_t cc, fcsr_cc;
2005 int64_t i64;
2006 fs = get_fpu_register_double(fs_reg);
2007 ft = get_fpu_register_double(ft_reg);
2008 cc = instr->FCccValue();
2009 fcsr_cc = get_fcsr_condition_bit(cc);
Andrei Popescu31002712010-02-23 13:46:05 +00002010 switch (instr->FunctionFieldRaw()) {
Steve Block44f0eee2011-05-26 01:26:41 +01002011 case ADD_D:
2012 set_fpu_register_double(fd_reg, fs + ft);
2013 break;
2014 case SUB_D:
2015 set_fpu_register_double(fd_reg, fs - ft);
2016 break;
2017 case MUL_D:
2018 set_fpu_register_double(fd_reg, fs * ft);
2019 break;
2020 case DIV_D:
2021 set_fpu_register_double(fd_reg, fs / ft);
2022 break;
2023 case ABS_D:
2024 set_fpu_register_double(fd_reg, fs < 0 ? -fs : fs);
2025 break;
2026 case MOV_D:
2027 set_fpu_register_double(fd_reg, fs);
2028 break;
2029 case NEG_D:
2030 set_fpu_register_double(fd_reg, -fs);
2031 break;
2032 case SQRT_D:
2033 set_fpu_register_double(fd_reg, sqrt(fs));
2034 break;
2035 case C_UN_D:
2036 set_fcsr_bit(fcsr_cc, isnan(fs) || isnan(ft));
2037 break;
2038 case C_EQ_D:
2039 set_fcsr_bit(fcsr_cc, (fs == ft));
2040 break;
2041 case C_UEQ_D:
2042 set_fcsr_bit(fcsr_cc, (fs == ft) || (isnan(fs) || isnan(ft)));
2043 break;
2044 case C_OLT_D:
2045 set_fcsr_bit(fcsr_cc, (fs < ft));
2046 break;
2047 case C_ULT_D:
2048 set_fcsr_bit(fcsr_cc, (fs < ft) || (isnan(fs) || isnan(ft)));
2049 break;
2050 case C_OLE_D:
2051 set_fcsr_bit(fcsr_cc, (fs <= ft));
2052 break;
2053 case C_ULE_D:
2054 set_fcsr_bit(fcsr_cc, (fs <= ft) || (isnan(fs) || isnan(ft)));
2055 break;
2056 case CVT_W_D: // Convert double to word.
2057 // Rounding modes are not yet supported.
2058 ASSERT((FCSR_ & 3) == 0);
2059 // In rounding mode 0 it should behave like ROUND.
2060 case ROUND_W_D: // Round double to word.
2061 {
2062 double rounded = fs > 0 ? floor(fs + 0.5) : ceil(fs - 0.5);
2063 int32_t result = static_cast<int32_t>(rounded);
2064 set_fpu_register(fd_reg, result);
2065 if (set_fcsr_round_error(fs, rounded)) {
2066 set_fpu_register(fd_reg, kFPUInvalidResult);
2067 }
2068 }
2069 break;
2070 case TRUNC_W_D: // Truncate double to word (round towards 0).
2071 {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002072 double rounded = trunc(fs);
2073 int32_t result = static_cast<int32_t>(rounded);
Steve Block44f0eee2011-05-26 01:26:41 +01002074 set_fpu_register(fd_reg, result);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002075 if (set_fcsr_round_error(fs, rounded)) {
Steve Block44f0eee2011-05-26 01:26:41 +01002076 set_fpu_register(fd_reg, kFPUInvalidResult);
2077 }
2078 }
2079 break;
2080 case FLOOR_W_D: // Round double to word towards negative infinity.
2081 {
2082 double rounded = floor(fs);
2083 int32_t result = static_cast<int32_t>(rounded);
2084 set_fpu_register(fd_reg, result);
2085 if (set_fcsr_round_error(fs, rounded)) {
2086 set_fpu_register(fd_reg, kFPUInvalidResult);
2087 }
2088 }
2089 break;
2090 case CEIL_W_D: // Round double to word towards positive infinity.
2091 {
2092 double rounded = ceil(fs);
2093 int32_t result = static_cast<int32_t>(rounded);
2094 set_fpu_register(fd_reg, result);
2095 if (set_fcsr_round_error(fs, rounded)) {
2096 set_fpu_register(fd_reg, kFPUInvalidResult);
2097 }
2098 }
2099 break;
2100 case CVT_S_D: // Convert double to float (single).
2101 set_fpu_register_float(fd_reg, static_cast<float>(fs));
2102 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002103 case CVT_L_D: { // Mips32r2: Truncate double to 64-bit long-word.
2104 double rounded = trunc(fs);
2105 i64 = static_cast<int64_t>(rounded);
Steve Block44f0eee2011-05-26 01:26:41 +01002106 set_fpu_register(fd_reg, i64 & 0xffffffff);
2107 set_fpu_register(fd_reg + 1, i64 >> 32);
2108 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002109 }
2110 case TRUNC_L_D: { // Mips32r2 instruction.
2111 double rounded = trunc(fs);
2112 i64 = static_cast<int64_t>(rounded);
Steve Block44f0eee2011-05-26 01:26:41 +01002113 set_fpu_register(fd_reg, i64 & 0xffffffff);
2114 set_fpu_register(fd_reg + 1, i64 >> 32);
2115 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002116 }
Steve Block44f0eee2011-05-26 01:26:41 +01002117 case ROUND_L_D: { // Mips32r2 instruction.
2118 double rounded = fs > 0 ? floor(fs + 0.5) : ceil(fs - 0.5);
2119 i64 = static_cast<int64_t>(rounded);
2120 set_fpu_register(fd_reg, i64 & 0xffffffff);
2121 set_fpu_register(fd_reg + 1, i64 >> 32);
2122 break;
2123 }
2124 case FLOOR_L_D: // Mips32r2 instruction.
2125 i64 = static_cast<int64_t>(floor(fs));
2126 set_fpu_register(fd_reg, i64 & 0xffffffff);
2127 set_fpu_register(fd_reg + 1, i64 >> 32);
2128 break;
2129 case CEIL_L_D: // Mips32r2 instruction.
2130 i64 = static_cast<int64_t>(ceil(fs));
2131 set_fpu_register(fd_reg, i64 & 0xffffffff);
2132 set_fpu_register(fd_reg + 1, i64 >> 32);
2133 break;
2134 case C_F_D:
Andrei Popescu31002712010-02-23 13:46:05 +00002135 UNIMPLEMENTED_MIPS();
2136 break;
2137 default:
2138 UNREACHABLE();
2139 }
2140 break;
2141 case W:
2142 switch (instr->FunctionFieldRaw()) {
Steve Block44f0eee2011-05-26 01:26:41 +01002143 case CVT_S_W: // Convert word to float (single).
2144 alu_out = get_fpu_register(fs_reg);
2145 set_fpu_register_float(fd_reg, static_cast<float>(alu_out));
Andrei Popescu31002712010-02-23 13:46:05 +00002146 break;
2147 case CVT_D_W: // Convert word to double.
Steve Block44f0eee2011-05-26 01:26:41 +01002148 alu_out = get_fpu_register(fs_reg);
2149 set_fpu_register_double(fd_reg, static_cast<double>(alu_out));
Andrei Popescu31002712010-02-23 13:46:05 +00002150 break;
2151 default:
2152 UNREACHABLE();
2153 };
2154 break;
2155 case L:
2156 switch (instr->FunctionFieldRaw()) {
Steve Block44f0eee2011-05-26 01:26:41 +01002157 case CVT_D_L: // Mips32r2 instruction.
2158 // Watch the signs here, we want 2 32-bit vals
2159 // to make a sign-64.
2160 i64 = (uint32_t) get_fpu_register(fs_reg);
2161 i64 |= ((int64_t) get_fpu_register(fs_reg + 1) << 32);
2162 set_fpu_register_double(fd_reg, static_cast<double>(i64));
2163 break;
Andrei Popescu31002712010-02-23 13:46:05 +00002164 case CVT_S_L:
Andrei Popescu31002712010-02-23 13:46:05 +00002165 UNIMPLEMENTED_MIPS();
2166 break;
2167 default:
2168 UNREACHABLE();
2169 }
2170 break;
2171 case PS:
2172 break;
2173 default:
2174 UNREACHABLE();
2175 };
2176 break;
2177 case SPECIAL:
2178 switch (instr->FunctionFieldRaw()) {
2179 case JR: {
2180 Instruction* branch_delay_instr = reinterpret_cast<Instruction*>(
Steve Block44f0eee2011-05-26 01:26:41 +01002181 current_pc+Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +00002182 BranchDelayInstructionDecode(branch_delay_instr);
2183 set_pc(next_pc);
2184 pc_modified_ = true;
2185 break;
2186 }
2187 case JALR: {
2188 Instruction* branch_delay_instr = reinterpret_cast<Instruction*>(
Steve Block44f0eee2011-05-26 01:26:41 +01002189 current_pc+Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +00002190 BranchDelayInstructionDecode(branch_delay_instr);
Ben Murdoch257744e2011-11-30 15:57:28 +00002191 set_register(31, current_pc + 2 * Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +00002192 set_pc(next_pc);
2193 pc_modified_ = true;
2194 break;
2195 }
2196 // Instructions using HI and LO registers.
2197 case MULT:
Steve Block44f0eee2011-05-26 01:26:41 +01002198 set_register(LO, static_cast<int32_t>(i64hilo & 0xffffffff));
2199 set_register(HI, static_cast<int32_t>(i64hilo >> 32));
2200 break;
Andrei Popescu31002712010-02-23 13:46:05 +00002201 case MULTU:
Steve Block44f0eee2011-05-26 01:26:41 +01002202 set_register(LO, static_cast<int32_t>(u64hilo & 0xffffffff));
2203 set_register(HI, static_cast<int32_t>(u64hilo >> 32));
Andrei Popescu31002712010-02-23 13:46:05 +00002204 break;
2205 case DIV:
Ben Murdoch257744e2011-11-30 15:57:28 +00002206 // Divide by zero was not checked in the configuration step - div and
2207 // divu do not raise exceptions. On division by 0, the result will
2208 // be UNPREDICTABLE.
2209 if (rt != 0) {
2210 set_register(LO, rs / rt);
2211 set_register(HI, rs % rt);
2212 }
Andrei Popescu31002712010-02-23 13:46:05 +00002213 break;
2214 case DIVU:
Ben Murdoch257744e2011-11-30 15:57:28 +00002215 if (rt_u != 0) {
2216 set_register(LO, rs_u / rt_u);
2217 set_register(HI, rs_u % rt_u);
2218 }
Andrei Popescu31002712010-02-23 13:46:05 +00002219 break;
Steve Block44f0eee2011-05-26 01:26:41 +01002220 // Break and trap instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00002221 case BREAK:
2222 case TGE:
2223 case TGEU:
2224 case TLT:
2225 case TLTU:
2226 case TEQ:
2227 case TNE:
2228 if (do_interrupt) {
2229 SoftwareInterrupt(instr);
2230 }
2231 break;
Steve Block44f0eee2011-05-26 01:26:41 +01002232 // Conditional moves.
2233 case MOVN:
2234 if (rt) set_register(rd_reg, rs);
2235 break;
2236 case MOVCI: {
Ben Murdoch257744e2011-11-30 15:57:28 +00002237 uint32_t cc = instr->FBccValue();
Steve Block44f0eee2011-05-26 01:26:41 +01002238 uint32_t fcsr_cc = get_fcsr_condition_bit(cc);
Ben Murdoch257744e2011-11-30 15:57:28 +00002239 if (instr->Bit(16)) { // Read Tf bit.
Steve Block44f0eee2011-05-26 01:26:41 +01002240 if (test_fcsr_bit(fcsr_cc)) set_register(rd_reg, rs);
2241 } else {
2242 if (!test_fcsr_bit(fcsr_cc)) set_register(rd_reg, rs);
2243 }
2244 break;
2245 }
2246 case MOVZ:
2247 if (!rt) set_register(rd_reg, rs);
2248 break;
Andrei Popescu31002712010-02-23 13:46:05 +00002249 default: // For other special opcodes we do the default operation.
2250 set_register(rd_reg, alu_out);
2251 };
2252 break;
2253 case SPECIAL2:
2254 switch (instr->FunctionFieldRaw()) {
2255 case MUL:
2256 set_register(rd_reg, alu_out);
2257 // HI and LO are UNPREDICTABLE after the operation.
2258 set_register(LO, Unpredictable);
2259 set_register(HI, Unpredictable);
2260 break;
Steve Block44f0eee2011-05-26 01:26:41 +01002261 default: // For other special2 opcodes we do the default operation.
2262 set_register(rd_reg, alu_out);
2263 }
2264 break;
2265 case SPECIAL3:
2266 switch (instr->FunctionFieldRaw()) {
2267 case INS:
2268 // Ins instr leaves result in Rt, rather than Rd.
2269 set_register(rt_reg, alu_out);
2270 break;
2271 case EXT:
2272 // Ext instr leaves result in Rt, rather than Rd.
2273 set_register(rt_reg, alu_out);
2274 break;
Andrei Popescu31002712010-02-23 13:46:05 +00002275 default:
2276 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +01002277 };
Andrei Popescu31002712010-02-23 13:46:05 +00002278 break;
2279 // Unimplemented opcodes raised an error in the configuration step before,
2280 // so we can use the default here to set the destination register in common
2281 // cases.
2282 default:
2283 set_register(rd_reg, alu_out);
2284 };
2285}
2286
Steve Block44f0eee2011-05-26 01:26:41 +01002287
Ben Murdoch257744e2011-11-30 15:57:28 +00002288// Type 2: instructions using a 16 bytes immediate. (eg: addi, beq).
Andrei Popescu31002712010-02-23 13:46:05 +00002289void Simulator::DecodeTypeImmediate(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +01002290 // Instruction fields.
Andrei Popescu31002712010-02-23 13:46:05 +00002291 Opcode op = instr->OpcodeFieldRaw();
Steve Block44f0eee2011-05-26 01:26:41 +01002292 int32_t rs = get_register(instr->RsValue());
Andrei Popescu31002712010-02-23 13:46:05 +00002293 uint32_t rs_u = static_cast<uint32_t>(rs);
Ben Murdoch257744e2011-11-30 15:57:28 +00002294 int32_t rt_reg = instr->RtValue(); // Destination register.
Andrei Popescu31002712010-02-23 13:46:05 +00002295 int32_t rt = get_register(rt_reg);
Steve Block44f0eee2011-05-26 01:26:41 +01002296 int16_t imm16 = instr->Imm16Value();
Andrei Popescu31002712010-02-23 13:46:05 +00002297
Ben Murdoch257744e2011-11-30 15:57:28 +00002298 int32_t ft_reg = instr->FtValue(); // Destination register.
Andrei Popescu31002712010-02-23 13:46:05 +00002299
Steve Block44f0eee2011-05-26 01:26:41 +01002300 // Zero extended immediate.
Andrei Popescu31002712010-02-23 13:46:05 +00002301 uint32_t oe_imm16 = 0xffff & imm16;
Steve Block44f0eee2011-05-26 01:26:41 +01002302 // Sign extended immediate.
Andrei Popescu31002712010-02-23 13:46:05 +00002303 int32_t se_imm16 = imm16;
2304
2305 // Get current pc.
2306 int32_t current_pc = get_pc();
2307 // Next pc.
2308 int32_t next_pc = bad_ra;
2309
Steve Block44f0eee2011-05-26 01:26:41 +01002310 // Used for conditional branch instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00002311 bool do_branch = false;
2312 bool execute_branch_delay_instruction = false;
2313
Steve Block44f0eee2011-05-26 01:26:41 +01002314 // Used for arithmetic instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00002315 int32_t alu_out = 0;
Steve Block44f0eee2011-05-26 01:26:41 +01002316 // Floating point.
Andrei Popescu31002712010-02-23 13:46:05 +00002317 double fp_out = 0.0;
Steve Block44f0eee2011-05-26 01:26:41 +01002318 uint32_t cc, cc_value, fcsr_cc;
Andrei Popescu31002712010-02-23 13:46:05 +00002319
Steve Block44f0eee2011-05-26 01:26:41 +01002320 // Used for memory instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00002321 int32_t addr = 0x0;
Ben Murdoch257744e2011-11-30 15:57:28 +00002322 // Value to be written in memory.
Steve Block44f0eee2011-05-26 01:26:41 +01002323 uint32_t mem_value = 0x0;
Andrei Popescu31002712010-02-23 13:46:05 +00002324
Ben Murdoch257744e2011-11-30 15:57:28 +00002325 // ---------- Configuration (and execution for REGIMM).
Andrei Popescu31002712010-02-23 13:46:05 +00002326 switch (op) {
Steve Block44f0eee2011-05-26 01:26:41 +01002327 // ------------- COP1. Coprocessor instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00002328 case COP1:
2329 switch (instr->RsFieldRaw()) {
Steve Block44f0eee2011-05-26 01:26:41 +01002330 case BC1: // Branch on coprocessor condition.
2331 cc = instr->FBccValue();
2332 fcsr_cc = get_fcsr_condition_bit(cc);
2333 cc_value = test_fcsr_bit(fcsr_cc);
2334 do_branch = (instr->FBtrueValue()) ? cc_value : !cc_value;
2335 execute_branch_delay_instruction = true;
Ben Murdoch257744e2011-11-30 15:57:28 +00002336 // Set next_pc.
Steve Block44f0eee2011-05-26 01:26:41 +01002337 if (do_branch) {
2338 next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
2339 } else {
2340 next_pc = current_pc + kBranchReturnOffset;
2341 }
Andrei Popescu31002712010-02-23 13:46:05 +00002342 break;
2343 default:
2344 UNREACHABLE();
2345 };
2346 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00002347 // ------------- REGIMM class.
Andrei Popescu31002712010-02-23 13:46:05 +00002348 case REGIMM:
2349 switch (instr->RtFieldRaw()) {
2350 case BLTZ:
2351 do_branch = (rs < 0);
2352 break;
2353 case BLTZAL:
2354 do_branch = rs < 0;
2355 break;
2356 case BGEZ:
2357 do_branch = rs >= 0;
2358 break;
2359 case BGEZAL:
2360 do_branch = rs >= 0;
2361 break;
2362 default:
2363 UNREACHABLE();
2364 };
2365 switch (instr->RtFieldRaw()) {
2366 case BLTZ:
2367 case BLTZAL:
2368 case BGEZ:
2369 case BGEZAL:
2370 // Branch instructions common part.
2371 execute_branch_delay_instruction = true;
Ben Murdoch257744e2011-11-30 15:57:28 +00002372 // Set next_pc.
Andrei Popescu31002712010-02-23 13:46:05 +00002373 if (do_branch) {
Steve Block44f0eee2011-05-26 01:26:41 +01002374 next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
Andrei Popescu31002712010-02-23 13:46:05 +00002375 if (instr->IsLinkingInstruction()) {
2376 set_register(31, current_pc + kBranchReturnOffset);
2377 }
2378 } else {
2379 next_pc = current_pc + kBranchReturnOffset;
2380 }
2381 default:
2382 break;
2383 };
Ben Murdoch257744e2011-11-30 15:57:28 +00002384 break; // case REGIMM.
2385 // ------------- Branch instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00002386 // When comparing to zero, the encoding of rt field is always 0, so we don't
2387 // need to replace rt with zero.
2388 case BEQ:
2389 do_branch = (rs == rt);
2390 break;
2391 case BNE:
2392 do_branch = rs != rt;
2393 break;
2394 case BLEZ:
2395 do_branch = rs <= 0;
2396 break;
2397 case BGTZ:
2398 do_branch = rs > 0;
2399 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00002400 // ------------- Arithmetic instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00002401 case ADDI:
2402 if (HaveSameSign(rs, se_imm16)) {
2403 if (rs > 0) {
2404 exceptions[kIntegerOverflow] = rs > (Registers::kMaxValue - se_imm16);
2405 } else if (rs < 0) {
2406 exceptions[kIntegerUnderflow] =
2407 rs < (Registers::kMinValue - se_imm16);
2408 }
2409 }
2410 alu_out = rs + se_imm16;
2411 break;
2412 case ADDIU:
2413 alu_out = rs + se_imm16;
2414 break;
2415 case SLTI:
2416 alu_out = (rs < se_imm16) ? 1 : 0;
2417 break;
2418 case SLTIU:
2419 alu_out = (rs_u < static_cast<uint32_t>(se_imm16)) ? 1 : 0;
2420 break;
2421 case ANDI:
2422 alu_out = rs & oe_imm16;
2423 break;
2424 case ORI:
2425 alu_out = rs | oe_imm16;
2426 break;
2427 case XORI:
2428 alu_out = rs ^ oe_imm16;
2429 break;
2430 case LUI:
2431 alu_out = (oe_imm16 << 16);
2432 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00002433 // ------------- Memory instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00002434 case LB:
2435 addr = rs + se_imm16;
2436 alu_out = ReadB(addr);
2437 break;
Steve Block44f0eee2011-05-26 01:26:41 +01002438 case LH:
2439 addr = rs + se_imm16;
2440 alu_out = ReadH(addr, instr);
2441 break;
2442 case LWL: {
Ben Murdoch257744e2011-11-30 15:57:28 +00002443 // al_offset is offset of the effective address within an aligned word.
Steve Block44f0eee2011-05-26 01:26:41 +01002444 uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
2445 uint8_t byte_shift = kPointerAlignmentMask - al_offset;
2446 uint32_t mask = (1 << byte_shift * 8) - 1;
2447 addr = rs + se_imm16 - al_offset;
2448 alu_out = ReadW(addr, instr);
2449 alu_out <<= byte_shift * 8;
2450 alu_out |= rt & mask;
2451 break;
2452 }
Andrei Popescu31002712010-02-23 13:46:05 +00002453 case LW:
2454 addr = rs + se_imm16;
2455 alu_out = ReadW(addr, instr);
2456 break;
2457 case LBU:
2458 addr = rs + se_imm16;
2459 alu_out = ReadBU(addr);
2460 break;
Steve Block44f0eee2011-05-26 01:26:41 +01002461 case LHU:
2462 addr = rs + se_imm16;
2463 alu_out = ReadHU(addr, instr);
2464 break;
2465 case LWR: {
Ben Murdoch257744e2011-11-30 15:57:28 +00002466 // al_offset is offset of the effective address within an aligned word.
Steve Block44f0eee2011-05-26 01:26:41 +01002467 uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
2468 uint8_t byte_shift = kPointerAlignmentMask - al_offset;
2469 uint32_t mask = al_offset ? (~0 << (byte_shift + 1) * 8) : 0;
2470 addr = rs + se_imm16 - al_offset;
2471 alu_out = ReadW(addr, instr);
2472 alu_out = static_cast<uint32_t> (alu_out) >> al_offset * 8;
2473 alu_out |= rt & mask;
2474 break;
2475 }
Andrei Popescu31002712010-02-23 13:46:05 +00002476 case SB:
2477 addr = rs + se_imm16;
2478 break;
Steve Block44f0eee2011-05-26 01:26:41 +01002479 case SH:
2480 addr = rs + se_imm16;
2481 break;
2482 case SWL: {
2483 uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
2484 uint8_t byte_shift = kPointerAlignmentMask - al_offset;
2485 uint32_t mask = byte_shift ? (~0 << (al_offset + 1) * 8) : 0;
2486 addr = rs + se_imm16 - al_offset;
2487 mem_value = ReadW(addr, instr) & mask;
2488 mem_value |= static_cast<uint32_t>(rt) >> byte_shift * 8;
2489 break;
2490 }
Andrei Popescu31002712010-02-23 13:46:05 +00002491 case SW:
2492 addr = rs + se_imm16;
2493 break;
Steve Block44f0eee2011-05-26 01:26:41 +01002494 case SWR: {
2495 uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
2496 uint32_t mask = (1 << al_offset * 8) - 1;
2497 addr = rs + se_imm16 - al_offset;
2498 mem_value = ReadW(addr, instr);
2499 mem_value = (rt << al_offset * 8) | (mem_value & mask);
2500 break;
2501 }
Andrei Popescu31002712010-02-23 13:46:05 +00002502 case LWC1:
2503 addr = rs + se_imm16;
2504 alu_out = ReadW(addr, instr);
2505 break;
2506 case LDC1:
2507 addr = rs + se_imm16;
2508 fp_out = ReadD(addr, instr);
2509 break;
2510 case SWC1:
2511 case SDC1:
2512 addr = rs + se_imm16;
2513 break;
2514 default:
2515 UNREACHABLE();
2516 };
2517
2518 // ---------- Raise exceptions triggered.
2519 SignalExceptions();
2520
Ben Murdoch257744e2011-11-30 15:57:28 +00002521 // ---------- Execution.
Andrei Popescu31002712010-02-23 13:46:05 +00002522 switch (op) {
Ben Murdoch257744e2011-11-30 15:57:28 +00002523 // ------------- Branch instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00002524 case BEQ:
2525 case BNE:
2526 case BLEZ:
2527 case BGTZ:
2528 // Branch instructions common part.
2529 execute_branch_delay_instruction = true;
Ben Murdoch257744e2011-11-30 15:57:28 +00002530 // Set next_pc.
Andrei Popescu31002712010-02-23 13:46:05 +00002531 if (do_branch) {
Steve Block44f0eee2011-05-26 01:26:41 +01002532 next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
Andrei Popescu31002712010-02-23 13:46:05 +00002533 if (instr->IsLinkingInstruction()) {
Steve Block44f0eee2011-05-26 01:26:41 +01002534 set_register(31, current_pc + 2* Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +00002535 }
2536 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01002537 next_pc = current_pc + 2 * Instruction::kInstrSize;
Andrei Popescu31002712010-02-23 13:46:05 +00002538 }
2539 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00002540 // ------------- Arithmetic instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00002541 case ADDI:
2542 case ADDIU:
2543 case SLTI:
2544 case SLTIU:
2545 case ANDI:
2546 case ORI:
2547 case XORI:
2548 case LUI:
2549 set_register(rt_reg, alu_out);
2550 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00002551 // ------------- Memory instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00002552 case LB:
Steve Block44f0eee2011-05-26 01:26:41 +01002553 case LH:
2554 case LWL:
Andrei Popescu31002712010-02-23 13:46:05 +00002555 case LW:
2556 case LBU:
Steve Block44f0eee2011-05-26 01:26:41 +01002557 case LHU:
2558 case LWR:
Andrei Popescu31002712010-02-23 13:46:05 +00002559 set_register(rt_reg, alu_out);
2560 break;
2561 case SB:
2562 WriteB(addr, static_cast<int8_t>(rt));
2563 break;
Steve Block44f0eee2011-05-26 01:26:41 +01002564 case SH:
2565 WriteH(addr, static_cast<uint16_t>(rt), instr);
2566 break;
2567 case SWL:
2568 WriteW(addr, mem_value, instr);
2569 break;
Andrei Popescu31002712010-02-23 13:46:05 +00002570 case SW:
2571 WriteW(addr, rt, instr);
2572 break;
Steve Block44f0eee2011-05-26 01:26:41 +01002573 case SWR:
2574 WriteW(addr, mem_value, instr);
2575 break;
Andrei Popescu31002712010-02-23 13:46:05 +00002576 case LWC1:
2577 set_fpu_register(ft_reg, alu_out);
2578 break;
2579 case LDC1:
2580 set_fpu_register_double(ft_reg, fp_out);
2581 break;
2582 case SWC1:
2583 addr = rs + se_imm16;
2584 WriteW(addr, get_fpu_register(ft_reg), instr);
2585 break;
2586 case SDC1:
2587 addr = rs + se_imm16;
Steve Block44f0eee2011-05-26 01:26:41 +01002588 WriteD(addr, get_fpu_register_double(ft_reg), instr);
Andrei Popescu31002712010-02-23 13:46:05 +00002589 break;
2590 default:
2591 break;
2592 };
2593
2594
2595 if (execute_branch_delay_instruction) {
2596 // Execute branch delay slot
2597 // We don't check for end_sim_pc. First it should not be met as the current
2598 // pc is valid. Secondly a jump should always execute its branch delay slot.
2599 Instruction* branch_delay_instr =
Steve Block44f0eee2011-05-26 01:26:41 +01002600 reinterpret_cast<Instruction*>(current_pc+Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +00002601 BranchDelayInstructionDecode(branch_delay_instr);
2602 }
2603
2604 // If needed update pc after the branch delay execution.
2605 if (next_pc != bad_ra) {
2606 set_pc(next_pc);
2607 }
2608}
2609
Steve Block44f0eee2011-05-26 01:26:41 +01002610
Ben Murdoch257744e2011-11-30 15:57:28 +00002611// Type 3: instructions using a 26 bytes immediate. (eg: j, jal).
Andrei Popescu31002712010-02-23 13:46:05 +00002612void Simulator::DecodeTypeJump(Instruction* instr) {
2613 // Get current pc.
2614 int32_t current_pc = get_pc();
2615 // Get unchanged bits of pc.
2616 int32_t pc_high_bits = current_pc & 0xf0000000;
Ben Murdoch257744e2011-11-30 15:57:28 +00002617 // Next pc.
Steve Block44f0eee2011-05-26 01:26:41 +01002618 int32_t next_pc = pc_high_bits | (instr->Imm26Value() << 2);
Andrei Popescu31002712010-02-23 13:46:05 +00002619
Ben Murdoch257744e2011-11-30 15:57:28 +00002620 // Execute branch delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00002621 // We don't check for end_sim_pc. First it should not be met as the current pc
2622 // is valid. Secondly a jump should always execute its branch delay slot.
2623 Instruction* branch_delay_instr =
Ben Murdoch257744e2011-11-30 15:57:28 +00002624 reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +00002625 BranchDelayInstructionDecode(branch_delay_instr);
2626
2627 // Update pc and ra if necessary.
2628 // Do this after the branch delay execution.
2629 if (instr->IsLinkingInstruction()) {
Ben Murdoch257744e2011-11-30 15:57:28 +00002630 set_register(31, current_pc + 2 * Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +00002631 }
2632 set_pc(next_pc);
2633 pc_modified_ = true;
2634}
2635
Steve Block44f0eee2011-05-26 01:26:41 +01002636
Andrei Popescu31002712010-02-23 13:46:05 +00002637// Executes the current instruction.
2638void Simulator::InstructionDecode(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +01002639 if (v8::internal::FLAG_check_icache) {
2640 CheckICache(isolate_->simulator_i_cache(), instr);
2641 }
Andrei Popescu31002712010-02-23 13:46:05 +00002642 pc_modified_ = false;
2643 if (::v8::internal::FLAG_trace_sim) {
2644 disasm::NameConverter converter;
2645 disasm::Disassembler dasm(converter);
Ben Murdoch257744e2011-11-30 15:57:28 +00002646 // Use a reasonably large buffer.
Andrei Popescu31002712010-02-23 13:46:05 +00002647 v8::internal::EmbeddedVector<char, 256> buffer;
Ben Murdoch257744e2011-11-30 15:57:28 +00002648 dasm.InstructionDecode(buffer, reinterpret_cast<byte*>(instr));
Steve Block44f0eee2011-05-26 01:26:41 +01002649 PrintF(" 0x%08x %s\n", reinterpret_cast<intptr_t>(instr),
Ben Murdoch257744e2011-11-30 15:57:28 +00002650 buffer.start());
Andrei Popescu31002712010-02-23 13:46:05 +00002651 }
2652
2653 switch (instr->InstructionType()) {
2654 case Instruction::kRegisterType:
2655 DecodeTypeRegister(instr);
2656 break;
2657 case Instruction::kImmediateType:
2658 DecodeTypeImmediate(instr);
2659 break;
2660 case Instruction::kJumpType:
2661 DecodeTypeJump(instr);
2662 break;
2663 default:
2664 UNSUPPORTED();
2665 }
2666 if (!pc_modified_) {
2667 set_register(pc, reinterpret_cast<int32_t>(instr) +
Steve Block44f0eee2011-05-26 01:26:41 +01002668 Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +00002669 }
2670}
2671
2672
2673
2674void Simulator::Execute() {
2675 // Get the PC to simulate. Cannot use the accessor here as we need the
2676 // raw PC value and not the one used as input to arithmetic instructions.
2677 int program_counter = get_pc();
2678 if (::v8::internal::FLAG_stop_sim_at == 0) {
2679 // Fast version of the dispatch loop without checking whether the simulator
2680 // should be stopping at a particular executed instruction.
2681 while (program_counter != end_sim_pc) {
2682 Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
2683 icount_++;
2684 InstructionDecode(instr);
2685 program_counter = get_pc();
2686 }
2687 } else {
2688 // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when
2689 // we reach the particular instuction count.
2690 while (program_counter != end_sim_pc) {
2691 Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
2692 icount_++;
2693 if (icount_ == ::v8::internal::FLAG_stop_sim_at) {
Steve Block44f0eee2011-05-26 01:26:41 +01002694 MipsDebugger dbg(this);
Andrei Popescu31002712010-02-23 13:46:05 +00002695 dbg.Debug();
2696 } else {
2697 InstructionDecode(instr);
2698 }
2699 program_counter = get_pc();
2700 }
2701 }
2702}
2703
2704
Ben Murdoch257744e2011-11-30 15:57:28 +00002705int32_t Simulator::Call(byte* entry, int argument_count, ...) {
Andrei Popescu31002712010-02-23 13:46:05 +00002706 va_list parameters;
2707 va_start(parameters, argument_count);
Ben Murdoch257744e2011-11-30 15:57:28 +00002708 // Setup arguments.
Andrei Popescu31002712010-02-23 13:46:05 +00002709
2710 // First four arguments passed in registers.
2711 ASSERT(argument_count >= 4);
2712 set_register(a0, va_arg(parameters, int32_t));
2713 set_register(a1, va_arg(parameters, int32_t));
2714 set_register(a2, va_arg(parameters, int32_t));
2715 set_register(a3, va_arg(parameters, int32_t));
2716
2717 // Remaining arguments passed on stack.
2718 int original_stack = get_register(sp);
2719 // Compute position of stack on entry to generated code.
2720 int entry_stack = (original_stack - (argument_count - 4) * sizeof(int32_t)
Steve Block44f0eee2011-05-26 01:26:41 +01002721 - kCArgsSlotsSize);
Andrei Popescu31002712010-02-23 13:46:05 +00002722 if (OS::ActivationFrameAlignment() != 0) {
2723 entry_stack &= -OS::ActivationFrameAlignment();
2724 }
2725 // Store remaining arguments on stack, from low to high memory.
2726 intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
2727 for (int i = 4; i < argument_count; i++) {
2728 stack_argument[i - 4 + kArgsSlotsNum] = va_arg(parameters, int32_t);
2729 }
2730 va_end(parameters);
2731 set_register(sp, entry_stack);
2732
Ben Murdoch257744e2011-11-30 15:57:28 +00002733 // Prepare to execute the code at entry.
Andrei Popescu31002712010-02-23 13:46:05 +00002734 set_register(pc, reinterpret_cast<int32_t>(entry));
2735 // Put down marker for end of simulation. The simulator will stop simulation
2736 // when the PC reaches this value. By saving the "end simulation" value into
2737 // the LR the simulation stops when returning to this call point.
2738 set_register(ra, end_sim_pc);
2739
2740 // Remember the values of callee-saved registers.
2741 // The code below assumes that r9 is not used as sb (static base) in
2742 // simulator code and therefore is regarded as a callee-saved register.
2743 int32_t s0_val = get_register(s0);
2744 int32_t s1_val = get_register(s1);
2745 int32_t s2_val = get_register(s2);
2746 int32_t s3_val = get_register(s3);
2747 int32_t s4_val = get_register(s4);
2748 int32_t s5_val = get_register(s5);
2749 int32_t s6_val = get_register(s6);
2750 int32_t s7_val = get_register(s7);
2751 int32_t gp_val = get_register(gp);
2752 int32_t sp_val = get_register(sp);
2753 int32_t fp_val = get_register(fp);
2754
2755 // Setup the callee-saved registers with a known value. To be able to check
2756 // that they are preserved properly across JS execution.
2757 int32_t callee_saved_value = icount_;
2758 set_register(s0, callee_saved_value);
2759 set_register(s1, callee_saved_value);
2760 set_register(s2, callee_saved_value);
2761 set_register(s3, callee_saved_value);
2762 set_register(s4, callee_saved_value);
2763 set_register(s5, callee_saved_value);
2764 set_register(s6, callee_saved_value);
2765 set_register(s7, callee_saved_value);
2766 set_register(gp, callee_saved_value);
2767 set_register(fp, callee_saved_value);
2768
Ben Murdoch257744e2011-11-30 15:57:28 +00002769 // Start the simulation.
Andrei Popescu31002712010-02-23 13:46:05 +00002770 Execute();
2771
2772 // Check that the callee-saved registers have been preserved.
2773 CHECK_EQ(callee_saved_value, get_register(s0));
2774 CHECK_EQ(callee_saved_value, get_register(s1));
2775 CHECK_EQ(callee_saved_value, get_register(s2));
2776 CHECK_EQ(callee_saved_value, get_register(s3));
2777 CHECK_EQ(callee_saved_value, get_register(s4));
2778 CHECK_EQ(callee_saved_value, get_register(s5));
2779 CHECK_EQ(callee_saved_value, get_register(s6));
2780 CHECK_EQ(callee_saved_value, get_register(s7));
2781 CHECK_EQ(callee_saved_value, get_register(gp));
2782 CHECK_EQ(callee_saved_value, get_register(fp));
2783
2784 // Restore callee-saved registers with the original value.
2785 set_register(s0, s0_val);
2786 set_register(s1, s1_val);
2787 set_register(s2, s2_val);
2788 set_register(s3, s3_val);
2789 set_register(s4, s4_val);
2790 set_register(s5, s5_val);
2791 set_register(s6, s6_val);
2792 set_register(s7, s7_val);
2793 set_register(gp, gp_val);
2794 set_register(sp, sp_val);
2795 set_register(fp, fp_val);
2796
2797 // Pop stack passed arguments.
2798 CHECK_EQ(entry_stack, get_register(sp));
2799 set_register(sp, original_stack);
2800
2801 int32_t result = get_register(v0);
2802 return result;
2803}
2804
2805
2806uintptr_t Simulator::PushAddress(uintptr_t address) {
2807 int new_sp = get_register(sp) - sizeof(uintptr_t);
2808 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp);
2809 *stack_slot = address;
2810 set_register(sp, new_sp);
2811 return new_sp;
2812}
2813
2814
2815uintptr_t Simulator::PopAddress() {
2816 int current_sp = get_register(sp);
2817 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp);
2818 uintptr_t address = *stack_slot;
2819 set_register(sp, current_sp + sizeof(uintptr_t));
2820 return address;
2821}
2822
2823
2824#undef UNSUPPORTED
2825
Steve Block44f0eee2011-05-26 01:26:41 +01002826} } // namespace v8::internal
Andrei Popescu31002712010-02-23 13:46:05 +00002827
Steve Block44f0eee2011-05-26 01:26:41 +01002828#endif // USE_SIMULATOR
Andrei Popescu31002712010-02-23 13:46:05 +00002829
Leon Clarkef7060e22010-06-03 12:02:55 +01002830#endif // V8_TARGET_ARCH_MIPS