blob: f31ce7ea48a117437b3acb1b01ed4dbc76049427 [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
Ben Murdoch589d6972011-11-30 16:04:58 +000036#include "cpu.h"
Andrei Popescu31002712010-02-23 13:46:05 +000037#include "disasm.h"
38#include "assembler.h"
Ben Murdoch257744e2011-11-30 15:57:28 +000039#include "globals.h" // Need the BitCast.
Andrei Popescu31002712010-02-23 13:46:05 +000040#include "mips/constants-mips.h"
41#include "mips/simulator-mips.h"
42
Andrei Popescu31002712010-02-23 13:46:05 +000043
44// Only build the simulator if not compiling for real MIPS hardware.
Steve Block44f0eee2011-05-26 01:26:41 +010045#if defined(USE_SIMULATOR)
Andrei Popescu31002712010-02-23 13:46:05 +000046
Steve Block44f0eee2011-05-26 01:26:41 +010047namespace v8 {
48namespace internal {
Andrei Popescu31002712010-02-23 13:46:05 +000049
Ben Murdoch257744e2011-11-30 15:57:28 +000050// Utils functions.
Andrei Popescu31002712010-02-23 13:46:05 +000051bool HaveSameSign(int32_t a, int32_t b) {
Steve Block44f0eee2011-05-26 01:26:41 +010052 return ((a ^ b) >= 0);
53}
54
55
56uint32_t get_fcsr_condition_bit(uint32_t cc) {
57 if (cc == 0) {
58 return 23;
59 } else {
60 return 24 + cc;
61 }
Andrei Popescu31002712010-02-23 13:46:05 +000062}
63
64
65// This macro provides a platform independent use of sscanf. The reason for
66// SScanF not being implemented in a platform independent was through
67// ::v8::internal::OS in the same way as SNPrintF is that the Windows C Run-Time
68// Library does not provide vsscanf.
69#define SScanF sscanf // NOLINT
70
Steve Block44f0eee2011-05-26 01:26:41 +010071// The MipsDebugger class is used by the simulator while debugging simulated
Andrei Popescu31002712010-02-23 13:46:05 +000072// code.
Steve Block44f0eee2011-05-26 01:26:41 +010073class MipsDebugger {
Andrei Popescu31002712010-02-23 13:46:05 +000074 public:
Ben Murdoch3ef787d2012-04-12 10:51:47 +010075 explicit MipsDebugger(Simulator* sim) : sim_(sim) { }
Steve Block44f0eee2011-05-26 01:26:41 +010076 ~MipsDebugger();
Andrei Popescu31002712010-02-23 13:46:05 +000077
78 void Stop(Instruction* instr);
79 void Debug();
Steve Block44f0eee2011-05-26 01:26:41 +010080 // Print all registers with a nice formatting.
81 void PrintAllRegs();
82 void PrintAllRegsIncludingFPU();
Andrei Popescu31002712010-02-23 13:46:05 +000083
84 private:
85 // We set the breakpoint code to 0xfffff to easily recognize it.
86 static const Instr kBreakpointInstr = SPECIAL | BREAK | 0xfffff << 6;
87 static const Instr kNopInstr = 0x0;
88
89 Simulator* sim_;
90
91 int32_t GetRegisterValue(int regnum);
Steve Block44f0eee2011-05-26 01:26:41 +010092 int32_t GetFPURegisterValueInt(int regnum);
93 int64_t GetFPURegisterValueLong(int regnum);
94 float GetFPURegisterValueFloat(int regnum);
95 double GetFPURegisterValueDouble(int regnum);
Andrei Popescu31002712010-02-23 13:46:05 +000096 bool GetValue(const char* desc, int32_t* value);
97
98 // Set or delete a breakpoint. Returns true if successful.
99 bool SetBreakpoint(Instruction* breakpc);
100 bool DeleteBreakpoint(Instruction* breakpc);
101
102 // Undo and redo all breakpoints. This is needed to bracket disassembly and
103 // execution to skip past breakpoints when run from the debugger.
104 void UndoBreakpoints();
105 void RedoBreakpoints();
Andrei Popescu31002712010-02-23 13:46:05 +0000106};
107
Steve Block44f0eee2011-05-26 01:26:41 +0100108
109MipsDebugger::~MipsDebugger() {
Andrei Popescu31002712010-02-23 13:46:05 +0000110}
111
Steve Block44f0eee2011-05-26 01:26:41 +0100112
Andrei Popescu31002712010-02-23 13:46:05 +0000113#ifdef GENERATED_CODE_COVERAGE
114static FILE* coverage_log = NULL;
115
116
117static void InitializeCoverage() {
118 char* file_name = getenv("V8_GENERATED_CODE_COVERAGE_LOG");
119 if (file_name != NULL) {
120 coverage_log = fopen(file_name, "aw+");
121 }
122}
123
124
Steve Block44f0eee2011-05-26 01:26:41 +0100125void MipsDebugger::Stop(Instruction* instr) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000126 // Get the stop code.
127 uint32_t code = instr->Bits(25, 6);
128 // Retrieve the encoded address, which comes just after this stop.
129 char** msg_address =
130 reinterpret_cast<char**>(sim_->get_pc() + Instr::kInstrSize);
131 char* msg = *msg_address;
132 ASSERT(msg != NULL);
133
134 // Update this stop description.
135 if (!watched_stops[code].desc) {
136 watched_stops[code].desc = msg;
137 }
138
139 if (strlen(msg) > 0) {
Andrei Popescu31002712010-02-23 13:46:05 +0000140 if (coverage_log != NULL) {
141 fprintf(coverage_log, "%s\n", str);
142 fflush(coverage_log);
143 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000144 // Overwrite the instruction and address with nops.
145 instr->SetInstructionBits(kNopInstr);
146 reinterpret_cast<Instr*>(msg_address)->SetInstructionBits(kNopInstr);
Andrei Popescu31002712010-02-23 13:46:05 +0000147 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000148 sim_->set_pc(sim_->get_pc() + 2 * Instruction::kInstructionSize);
Andrei Popescu31002712010-02-23 13:46:05 +0000149}
150
Steve Block44f0eee2011-05-26 01:26:41 +0100151
Ben Murdoch257744e2011-11-30 15:57:28 +0000152#else // GENERATED_CODE_COVERAGE
Andrei Popescu31002712010-02-23 13:46:05 +0000153
154#define UNSUPPORTED() printf("Unsupported instruction.\n");
155
156static void InitializeCoverage() {}
157
158
Steve Block44f0eee2011-05-26 01:26:41 +0100159void MipsDebugger::Stop(Instruction* instr) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000160 // Get the stop code.
161 uint32_t code = instr->Bits(25, 6);
162 // Retrieve the encoded address, which comes just after this stop.
163 char* msg = *reinterpret_cast<char**>(sim_->get_pc() +
164 Instruction::kInstrSize);
165 // Update this stop description.
166 if (!sim_->watched_stops[code].desc) {
167 sim_->watched_stops[code].desc = msg;
168 }
169 PrintF("Simulator hit %s (%u)\n", msg, code);
170 sim_->set_pc(sim_->get_pc() + 2 * Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +0000171 Debug();
172}
Steve Block6ded16b2010-05-10 14:33:55 +0100173#endif // GENERATED_CODE_COVERAGE
Andrei Popescu31002712010-02-23 13:46:05 +0000174
175
Steve Block44f0eee2011-05-26 01:26:41 +0100176int32_t MipsDebugger::GetRegisterValue(int regnum) {
Andrei Popescu31002712010-02-23 13:46:05 +0000177 if (regnum == kNumSimuRegisters) {
178 return sim_->get_pc();
179 } else {
180 return sim_->get_register(regnum);
181 }
182}
183
184
Steve Block44f0eee2011-05-26 01:26:41 +0100185int32_t MipsDebugger::GetFPURegisterValueInt(int regnum) {
186 if (regnum == kNumFPURegisters) {
187 return sim_->get_pc();
188 } else {
189 return sim_->get_fpu_register(regnum);
190 }
191}
192
193
194int64_t MipsDebugger::GetFPURegisterValueLong(int regnum) {
195 if (regnum == kNumFPURegisters) {
196 return sim_->get_pc();
197 } else {
198 return sim_->get_fpu_register_long(regnum);
199 }
200}
201
202
203float MipsDebugger::GetFPURegisterValueFloat(int regnum) {
204 if (regnum == kNumFPURegisters) {
205 return sim_->get_pc();
206 } else {
207 return sim_->get_fpu_register_float(regnum);
208 }
209}
210
211
212double MipsDebugger::GetFPURegisterValueDouble(int regnum) {
213 if (regnum == kNumFPURegisters) {
214 return sim_->get_pc();
215 } else {
216 return sim_->get_fpu_register_double(regnum);
217 }
218}
219
220
221bool MipsDebugger::GetValue(const char* desc, int32_t* value) {
Andrei Popescu31002712010-02-23 13:46:05 +0000222 int regnum = Registers::Number(desc);
Steve Block44f0eee2011-05-26 01:26:41 +0100223 int fpuregnum = FPURegisters::Number(desc);
224
Andrei Popescu31002712010-02-23 13:46:05 +0000225 if (regnum != kInvalidRegister) {
226 *value = GetRegisterValue(regnum);
227 return true;
Steve Block44f0eee2011-05-26 01:26:41 +0100228 } else if (fpuregnum != kInvalidFPURegister) {
229 *value = GetFPURegisterValueInt(fpuregnum);
230 return true;
231 } else if (strncmp(desc, "0x", 2) == 0) {
232 return SScanF(desc, "%x", reinterpret_cast<uint32_t*>(value)) == 1;
Andrei Popescu31002712010-02-23 13:46:05 +0000233 } else {
234 return SScanF(desc, "%i", value) == 1;
235 }
236 return false;
237}
238
239
Steve Block44f0eee2011-05-26 01:26:41 +0100240bool MipsDebugger::SetBreakpoint(Instruction* breakpc) {
Andrei Popescu31002712010-02-23 13:46:05 +0000241 // Check if a breakpoint can be set. If not return without any side-effects.
242 if (sim_->break_pc_ != NULL) {
243 return false;
244 }
245
246 // Set the breakpoint.
247 sim_->break_pc_ = breakpc;
248 sim_->break_instr_ = breakpc->InstructionBits();
249 // Not setting the breakpoint instruction in the code itself. It will be set
250 // when the debugger shell continues.
251 return true;
252}
253
254
Steve Block44f0eee2011-05-26 01:26:41 +0100255bool MipsDebugger::DeleteBreakpoint(Instruction* breakpc) {
Andrei Popescu31002712010-02-23 13:46:05 +0000256 if (sim_->break_pc_ != NULL) {
257 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
258 }
259
260 sim_->break_pc_ = NULL;
261 sim_->break_instr_ = 0;
262 return true;
263}
264
265
Steve Block44f0eee2011-05-26 01:26:41 +0100266void MipsDebugger::UndoBreakpoints() {
Andrei Popescu31002712010-02-23 13:46:05 +0000267 if (sim_->break_pc_ != NULL) {
268 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
269 }
270}
271
272
Steve Block44f0eee2011-05-26 01:26:41 +0100273void MipsDebugger::RedoBreakpoints() {
Andrei Popescu31002712010-02-23 13:46:05 +0000274 if (sim_->break_pc_ != NULL) {
275 sim_->break_pc_->SetInstructionBits(kBreakpointInstr);
276 }
277}
278
Steve Block44f0eee2011-05-26 01:26:41 +0100279
280void MipsDebugger::PrintAllRegs() {
Andrei Popescu31002712010-02-23 13:46:05 +0000281#define REG_INFO(n) Registers::Name(n), GetRegisterValue(n), GetRegisterValue(n)
282
283 PrintF("\n");
Ben Murdoch257744e2011-11-30 15:57:28 +0000284 // at, v0, a0.
Andrei Popescu31002712010-02-23 13:46:05 +0000285 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
286 REG_INFO(1), REG_INFO(2), REG_INFO(4));
Ben Murdoch257744e2011-11-30 15:57:28 +0000287 // v1, a1.
Andrei Popescu31002712010-02-23 13:46:05 +0000288 PrintF("%26s\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
289 "", REG_INFO(3), REG_INFO(5));
Ben Murdoch257744e2011-11-30 15:57:28 +0000290 // a2.
Andrei Popescu31002712010-02-23 13:46:05 +0000291 PrintF("%26s\t%26s\t%3s: 0x%08x %10d\n", "", "", REG_INFO(6));
Ben Murdoch257744e2011-11-30 15:57:28 +0000292 // a3.
Andrei Popescu31002712010-02-23 13:46:05 +0000293 PrintF("%26s\t%26s\t%3s: 0x%08x %10d\n", "", "", REG_INFO(7));
294 PrintF("\n");
295 // t0-t7, s0-s7
296 for (int i = 0; i < 8; i++) {
297 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
298 REG_INFO(8+i), REG_INFO(16+i));
299 }
300 PrintF("\n");
Ben Murdoch257744e2011-11-30 15:57:28 +0000301 // t8, k0, LO.
Andrei Popescu31002712010-02-23 13:46:05 +0000302 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
303 REG_INFO(24), REG_INFO(26), REG_INFO(32));
Ben Murdoch257744e2011-11-30 15:57:28 +0000304 // t9, k1, HI.
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(25), REG_INFO(27), REG_INFO(33));
Ben Murdoch257744e2011-11-30 15:57:28 +0000307 // sp, fp, gp.
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(29), REG_INFO(30), REG_INFO(28));
Ben Murdoch257744e2011-11-30 15:57:28 +0000310 // pc.
Andrei Popescu31002712010-02-23 13:46:05 +0000311 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
312 REG_INFO(31), REG_INFO(34));
Steve Block44f0eee2011-05-26 01:26:41 +0100313
Andrei Popescu31002712010-02-23 13:46:05 +0000314#undef REG_INFO
Steve Block44f0eee2011-05-26 01:26:41 +0100315#undef FPU_REG_INFO
Andrei Popescu31002712010-02-23 13:46:05 +0000316}
317
Steve Block44f0eee2011-05-26 01:26:41 +0100318
319void MipsDebugger::PrintAllRegsIncludingFPU() {
320#define FPU_REG_INFO(n) FPURegisters::Name(n), FPURegisters::Name(n+1), \
321 GetFPURegisterValueInt(n+1), \
322 GetFPURegisterValueInt(n), \
323 GetFPURegisterValueDouble(n)
324
325 PrintAllRegs();
326
327 PrintF("\n\n");
Ben Murdoch257744e2011-11-30 15:57:28 +0000328 // f0, f1, f2, ... f31.
Steve Block44f0eee2011-05-26 01:26:41 +0100329 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(0) );
330 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(2) );
331 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(4) );
332 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(6) );
333 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(8) );
334 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(10));
335 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(12));
336 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(14));
337 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(16));
338 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(18));
339 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(20));
340 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(22));
341 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(24));
342 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(26));
343 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(28));
344 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(30));
345
346#undef REG_INFO
347#undef FPU_REG_INFO
348}
349
350
351void MipsDebugger::Debug() {
Andrei Popescu31002712010-02-23 13:46:05 +0000352 intptr_t last_pc = -1;
353 bool done = false;
354
355#define COMMAND_SIZE 63
356#define ARG_SIZE 255
357
358#define STR(a) #a
359#define XSTR(a) STR(a)
360
361 char cmd[COMMAND_SIZE + 1];
362 char arg1[ARG_SIZE + 1];
363 char arg2[ARG_SIZE + 1];
Steve Block44f0eee2011-05-26 01:26:41 +0100364 char* argv[3] = { cmd, arg1, arg2 };
Andrei Popescu31002712010-02-23 13:46:05 +0000365
Ben Murdoch257744e2011-11-30 15:57:28 +0000366 // Make sure to have a proper terminating character if reaching the limit.
Andrei Popescu31002712010-02-23 13:46:05 +0000367 cmd[COMMAND_SIZE] = 0;
368 arg1[ARG_SIZE] = 0;
369 arg2[ARG_SIZE] = 0;
370
371 // Undo all set breakpoints while running in the debugger shell. This will
372 // make them invisible to all commands.
373 UndoBreakpoints();
374
375 while (!done && (sim_->get_pc() != Simulator::end_sim_pc)) {
376 if (last_pc != sim_->get_pc()) {
377 disasm::NameConverter converter;
378 disasm::Disassembler dasm(converter);
Ben Murdoch257744e2011-11-30 15:57:28 +0000379 // Use a reasonably large buffer.
Andrei Popescu31002712010-02-23 13:46:05 +0000380 v8::internal::EmbeddedVector<char, 256> buffer;
381 dasm.InstructionDecode(buffer,
Ben Murdoch257744e2011-11-30 15:57:28 +0000382 reinterpret_cast<byte*>(sim_->get_pc()));
Andrei Popescu31002712010-02-23 13:46:05 +0000383 PrintF(" 0x%08x %s\n", sim_->get_pc(), buffer.start());
384 last_pc = sim_->get_pc();
385 }
386 char* line = ReadLine("sim> ");
387 if (line == NULL) {
388 break;
389 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100390 char* last_input = sim_->last_debugger_input();
391 if (strcmp(line, "\n") == 0 && last_input != NULL) {
392 line = last_input;
393 } else {
394 // Ownership is transferred to sim_;
395 sim_->set_last_debugger_input(line);
396 }
Andrei Popescu31002712010-02-23 13:46:05 +0000397 // Use sscanf to parse the individual parts of the command line. At the
398 // moment no command expects more than two parameters.
Steve Block44f0eee2011-05-26 01:26:41 +0100399 int argc = SScanF(line,
Andrei Popescu31002712010-02-23 13:46:05 +0000400 "%" XSTR(COMMAND_SIZE) "s "
401 "%" XSTR(ARG_SIZE) "s "
402 "%" XSTR(ARG_SIZE) "s",
403 cmd, arg1, arg2);
404 if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
Steve Block44f0eee2011-05-26 01:26:41 +0100405 Instruction* instr = reinterpret_cast<Instruction*>(sim_->get_pc());
406 if (!(instr->IsTrap()) ||
407 instr->InstructionBits() == rtCallRedirInstr) {
Andrei Popescu31002712010-02-23 13:46:05 +0000408 sim_->InstructionDecode(
Steve Block44f0eee2011-05-26 01:26:41 +0100409 reinterpret_cast<Instruction*>(sim_->get_pc()));
Andrei Popescu31002712010-02-23 13:46:05 +0000410 } else {
411 // Allow si to jump over generated breakpoints.
412 PrintF("/!\\ Jumping over generated breakpoint.\n");
Steve Block44f0eee2011-05-26 01:26:41 +0100413 sim_->set_pc(sim_->get_pc() + Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +0000414 }
415 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) {
416 // Execute the one instruction we broke at with breakpoints disabled.
417 sim_->InstructionDecode(reinterpret_cast<Instruction*>(sim_->get_pc()));
418 // Leave the debugger shell.
419 done = true;
420 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
Steve Block44f0eee2011-05-26 01:26:41 +0100421 if (argc == 2) {
Andrei Popescu31002712010-02-23 13:46:05 +0000422 int32_t value;
Steve Block44f0eee2011-05-26 01:26:41 +0100423 float fvalue;
Andrei Popescu31002712010-02-23 13:46:05 +0000424 if (strcmp(arg1, "all") == 0) {
425 PrintAllRegs();
Steve Block44f0eee2011-05-26 01:26:41 +0100426 } else if (strcmp(arg1, "allf") == 0) {
427 PrintAllRegsIncludingFPU();
Andrei Popescu31002712010-02-23 13:46:05 +0000428 } else {
Steve Block44f0eee2011-05-26 01:26:41 +0100429 int regnum = Registers::Number(arg1);
430 int fpuregnum = FPURegisters::Number(arg1);
431
432 if (regnum != kInvalidRegister) {
433 value = GetRegisterValue(regnum);
Andrei Popescu31002712010-02-23 13:46:05 +0000434 PrintF("%s: 0x%08x %d \n", arg1, value, value);
Steve Block44f0eee2011-05-26 01:26:41 +0100435 } else if (fpuregnum != kInvalidFPURegister) {
436 if (fpuregnum % 2 == 1) {
437 value = GetFPURegisterValueInt(fpuregnum);
438 fvalue = GetFPURegisterValueFloat(fpuregnum);
439 PrintF("%s: 0x%08x %11.4e\n", arg1, value, fvalue);
440 } else {
441 double dfvalue;
442 int32_t lvalue1 = GetFPURegisterValueInt(fpuregnum);
443 int32_t lvalue2 = GetFPURegisterValueInt(fpuregnum + 1);
444 dfvalue = GetFPURegisterValueDouble(fpuregnum);
445 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n",
446 FPURegisters::Name(fpuregnum+1),
447 FPURegisters::Name(fpuregnum),
448 lvalue1,
449 lvalue2,
450 dfvalue);
451 }
Andrei Popescu31002712010-02-23 13:46:05 +0000452 } else {
453 PrintF("%s unrecognized\n", arg1);
454 }
455 }
456 } else {
Steve Block44f0eee2011-05-26 01:26:41 +0100457 if (argc == 3) {
458 if (strcmp(arg2, "single") == 0) {
459 int32_t value;
460 float fvalue;
461 int fpuregnum = FPURegisters::Number(arg1);
462
463 if (fpuregnum != kInvalidFPURegister) {
464 value = GetFPURegisterValueInt(fpuregnum);
465 fvalue = GetFPURegisterValueFloat(fpuregnum);
466 PrintF("%s: 0x%08x %11.4e\n", arg1, value, fvalue);
467 } else {
468 PrintF("%s unrecognized\n", arg1);
469 }
470 } else {
471 PrintF("print <fpu register> single\n");
472 }
473 } else {
474 PrintF("print <register> or print <fpu register> single\n");
475 }
Andrei Popescu31002712010-02-23 13:46:05 +0000476 }
477 } else if ((strcmp(cmd, "po") == 0)
478 || (strcmp(cmd, "printobject") == 0)) {
Steve Block44f0eee2011-05-26 01:26:41 +0100479 if (argc == 2) {
Andrei Popescu31002712010-02-23 13:46:05 +0000480 int32_t value;
481 if (GetValue(arg1, &value)) {
482 Object* obj = reinterpret_cast<Object*>(value);
483 PrintF("%s: \n", arg1);
484#ifdef DEBUG
485 obj->PrintLn();
486#else
487 obj->ShortPrint();
488 PrintF("\n");
489#endif
490 } else {
491 PrintF("%s unrecognized\n", arg1);
492 }
493 } else {
494 PrintF("printobject <value>\n");
495 }
Steve Block44f0eee2011-05-26 01:26:41 +0100496 } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0) {
497 int32_t* cur = NULL;
498 int32_t* end = NULL;
499 int next_arg = 1;
500
501 if (strcmp(cmd, "stack") == 0) {
502 cur = reinterpret_cast<int32_t*>(sim_->get_register(Simulator::sp));
Ben Murdoch257744e2011-11-30 15:57:28 +0000503 } else { // Command "mem".
Steve Block44f0eee2011-05-26 01:26:41 +0100504 int32_t value;
505 if (!GetValue(arg1, &value)) {
506 PrintF("%s unrecognized\n", arg1);
507 continue;
508 }
509 cur = reinterpret_cast<int32_t*>(value);
510 next_arg++;
511 }
512
513 int32_t words;
514 if (argc == next_arg) {
515 words = 10;
516 } else if (argc == next_arg + 1) {
517 if (!GetValue(argv[next_arg], &words)) {
518 words = 10;
519 }
520 }
521 end = cur + words;
522
523 while (cur < end) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000524 PrintF(" 0x%08x: 0x%08x %10d",
Steve Block44f0eee2011-05-26 01:26:41 +0100525 reinterpret_cast<intptr_t>(cur), *cur, *cur);
Ben Murdoch257744e2011-11-30 15:57:28 +0000526 HeapObject* obj = reinterpret_cast<HeapObject*>(*cur);
527 int value = *cur;
528 Heap* current_heap = v8::internal::Isolate::Current()->heap();
529 if (current_heap->Contains(obj) || ((value & 1) == 0)) {
530 PrintF(" (");
531 if ((value & 1) == 0) {
532 PrintF("smi %d", value / 2);
533 } else {
534 obj->ShortPrint();
535 }
536 PrintF(")");
537 }
538 PrintF("\n");
Steve Block44f0eee2011-05-26 01:26:41 +0100539 cur++;
540 }
541
Ben Murdoch257744e2011-11-30 15:57:28 +0000542 } else if ((strcmp(cmd, "disasm") == 0) ||
543 (strcmp(cmd, "dpc") == 0) ||
544 (strcmp(cmd, "di") == 0)) {
Andrei Popescu31002712010-02-23 13:46:05 +0000545 disasm::NameConverter converter;
546 disasm::Disassembler dasm(converter);
Ben Murdoch257744e2011-11-30 15:57:28 +0000547 // Use a reasonably large buffer.
Andrei Popescu31002712010-02-23 13:46:05 +0000548 v8::internal::EmbeddedVector<char, 256> buffer;
549
Ben Murdoch257744e2011-11-30 15:57:28 +0000550 byte* cur = NULL;
551 byte* end = NULL;
Andrei Popescu31002712010-02-23 13:46:05 +0000552
Steve Block44f0eee2011-05-26 01:26:41 +0100553 if (argc == 1) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000554 cur = reinterpret_cast<byte*>(sim_->get_pc());
Steve Block44f0eee2011-05-26 01:26:41 +0100555 end = cur + (10 * Instruction::kInstrSize);
556 } else if (argc == 2) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000557 int regnum = Registers::Number(arg1);
558 if (regnum != kInvalidRegister || strncmp(arg1, "0x", 2) == 0) {
559 // The argument is an address or a register name.
560 int32_t value;
561 if (GetValue(arg1, &value)) {
562 cur = reinterpret_cast<byte*>(value);
563 // Disassemble 10 instructions at <arg1>.
564 end = cur + (10 * Instruction::kInstrSize);
565 }
566 } else {
567 // The argument is the number of instructions.
568 int32_t value;
569 if (GetValue(arg1, &value)) {
570 cur = reinterpret_cast<byte*>(sim_->get_pc());
571 // Disassemble <arg1> instructions.
572 end = cur + (value * Instruction::kInstrSize);
573 }
Andrei Popescu31002712010-02-23 13:46:05 +0000574 }
575 } else {
576 int32_t value1;
577 int32_t value2;
578 if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000579 cur = reinterpret_cast<byte*>(value1);
Steve Block44f0eee2011-05-26 01:26:41 +0100580 end = cur + (value2 * Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +0000581 }
582 }
583
584 while (cur < end) {
585 dasm.InstructionDecode(buffer, cur);
Steve Block44f0eee2011-05-26 01:26:41 +0100586 PrintF(" 0x%08x %s\n",
587 reinterpret_cast<intptr_t>(cur), buffer.start());
588 cur += Instruction::kInstrSize;
Andrei Popescu31002712010-02-23 13:46:05 +0000589 }
590 } else if (strcmp(cmd, "gdb") == 0) {
591 PrintF("relinquishing control to gdb\n");
592 v8::internal::OS::DebugBreak();
593 PrintF("regaining control from gdb\n");
594 } else if (strcmp(cmd, "break") == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +0100595 if (argc == 2) {
Andrei Popescu31002712010-02-23 13:46:05 +0000596 int32_t value;
597 if (GetValue(arg1, &value)) {
598 if (!SetBreakpoint(reinterpret_cast<Instruction*>(value))) {
599 PrintF("setting breakpoint failed\n");
600 }
601 } else {
602 PrintF("%s unrecognized\n", arg1);
603 }
604 } else {
605 PrintF("break <address>\n");
606 }
607 } else if (strcmp(cmd, "del") == 0) {
608 if (!DeleteBreakpoint(NULL)) {
609 PrintF("deleting breakpoint failed\n");
610 }
611 } else if (strcmp(cmd, "flags") == 0) {
612 PrintF("No flags on MIPS !\n");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000613 } else if (strcmp(cmd, "stop") == 0) {
614 int32_t value;
615 intptr_t stop_pc = sim_->get_pc() -
616 2 * Instruction::kInstrSize;
617 Instruction* stop_instr = reinterpret_cast<Instruction*>(stop_pc);
618 Instruction* msg_address =
619 reinterpret_cast<Instruction*>(stop_pc +
620 Instruction::kInstrSize);
621 if ((argc == 2) && (strcmp(arg1, "unstop") == 0)) {
622 // Remove the current stop.
623 if (sim_->IsStopInstruction(stop_instr)) {
624 stop_instr->SetInstructionBits(kNopInstr);
625 msg_address->SetInstructionBits(kNopInstr);
626 } else {
627 PrintF("Not at debugger stop.\n");
628 }
629 } else if (argc == 3) {
630 // Print information about all/the specified breakpoint(s).
631 if (strcmp(arg1, "info") == 0) {
632 if (strcmp(arg2, "all") == 0) {
633 PrintF("Stop information:\n");
634 for (uint32_t i = kMaxWatchpointCode + 1;
635 i <= kMaxStopCode;
636 i++) {
637 sim_->PrintStopInfo(i);
638 }
639 } else if (GetValue(arg2, &value)) {
640 sim_->PrintStopInfo(value);
641 } else {
642 PrintF("Unrecognized argument.\n");
643 }
644 } else if (strcmp(arg1, "enable") == 0) {
645 // Enable all/the specified breakpoint(s).
646 if (strcmp(arg2, "all") == 0) {
647 for (uint32_t i = kMaxWatchpointCode + 1;
648 i <= kMaxStopCode;
649 i++) {
650 sim_->EnableStop(i);
651 }
652 } else if (GetValue(arg2, &value)) {
653 sim_->EnableStop(value);
654 } else {
655 PrintF("Unrecognized argument.\n");
656 }
657 } else if (strcmp(arg1, "disable") == 0) {
658 // Disable all/the specified breakpoint(s).
659 if (strcmp(arg2, "all") == 0) {
660 for (uint32_t i = kMaxWatchpointCode + 1;
661 i <= kMaxStopCode;
662 i++) {
663 sim_->DisableStop(i);
664 }
665 } else if (GetValue(arg2, &value)) {
666 sim_->DisableStop(value);
667 } else {
668 PrintF("Unrecognized argument.\n");
669 }
670 }
671 } else {
672 PrintF("Wrong usage. Use help command for more information.\n");
673 }
Andrei Popescu31002712010-02-23 13:46:05 +0000674 } else if ((strcmp(cmd, "stat") == 0) || (strcmp(cmd, "st") == 0)) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000675 // Print registers and disassemble.
Andrei Popescu31002712010-02-23 13:46:05 +0000676 PrintAllRegs();
677 PrintF("\n");
678
679 disasm::NameConverter converter;
680 disasm::Disassembler dasm(converter);
Ben Murdoch257744e2011-11-30 15:57:28 +0000681 // Use a reasonably large buffer.
Andrei Popescu31002712010-02-23 13:46:05 +0000682 v8::internal::EmbeddedVector<char, 256> buffer;
683
Ben Murdoch257744e2011-11-30 15:57:28 +0000684 byte* cur = NULL;
685 byte* end = NULL;
Andrei Popescu31002712010-02-23 13:46:05 +0000686
Steve Block44f0eee2011-05-26 01:26:41 +0100687 if (argc == 1) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000688 cur = reinterpret_cast<byte*>(sim_->get_pc());
Steve Block44f0eee2011-05-26 01:26:41 +0100689 end = cur + (10 * Instruction::kInstrSize);
690 } else if (argc == 2) {
Andrei Popescu31002712010-02-23 13:46:05 +0000691 int32_t value;
692 if (GetValue(arg1, &value)) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000693 cur = reinterpret_cast<byte*>(value);
Andrei Popescu31002712010-02-23 13:46:05 +0000694 // no length parameter passed, assume 10 instructions
Steve Block44f0eee2011-05-26 01:26:41 +0100695 end = cur + (10 * Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +0000696 }
697 } else {
698 int32_t value1;
699 int32_t value2;
700 if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000701 cur = reinterpret_cast<byte*>(value1);
Steve Block44f0eee2011-05-26 01:26:41 +0100702 end = cur + (value2 * Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +0000703 }
704 }
705
706 while (cur < end) {
707 dasm.InstructionDecode(buffer, cur);
Steve Block44f0eee2011-05-26 01:26:41 +0100708 PrintF(" 0x%08x %s\n",
709 reinterpret_cast<intptr_t>(cur), buffer.start());
710 cur += Instruction::kInstrSize;
Andrei Popescu31002712010-02-23 13:46:05 +0000711 }
712 } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
713 PrintF("cont\n");
714 PrintF(" continue execution (alias 'c')\n");
715 PrintF("stepi\n");
716 PrintF(" step one instruction (alias 'si')\n");
717 PrintF("print <register>\n");
718 PrintF(" print register content (alias 'p')\n");
719 PrintF(" use register name 'all' to print all registers\n");
720 PrintF("printobject <register>\n");
721 PrintF(" print an object from a register (alias 'po')\n");
Steve Block44f0eee2011-05-26 01:26:41 +0100722 PrintF("stack [<words>]\n");
723 PrintF(" dump stack content, default dump 10 words)\n");
724 PrintF("mem <address> [<words>]\n");
725 PrintF(" dump memory content, default dump 10 words)\n");
Andrei Popescu31002712010-02-23 13:46:05 +0000726 PrintF("flags\n");
727 PrintF(" print flags\n");
728 PrintF("disasm [<instructions>]\n");
Ben Murdoch257744e2011-11-30 15:57:28 +0000729 PrintF("disasm [<address/register>]\n");
730 PrintF("disasm [[<address/register>] <instructions>]\n");
731 PrintF(" disassemble code, default is 10 instructions\n");
732 PrintF(" from pc (alias 'di')\n");
Andrei Popescu31002712010-02-23 13:46:05 +0000733 PrintF("gdb\n");
734 PrintF(" enter gdb\n");
735 PrintF("break <address>\n");
736 PrintF(" set a break point on the address\n");
737 PrintF("del\n");
738 PrintF(" delete the breakpoint\n");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000739 PrintF("stop feature:\n");
740 PrintF(" Description:\n");
741 PrintF(" Stops are debug instructions inserted by\n");
742 PrintF(" the Assembler::stop() function.\n");
743 PrintF(" When hitting a stop, the Simulator will\n");
744 PrintF(" stop and and give control to the Debugger.\n");
745 PrintF(" All stop codes are watched:\n");
746 PrintF(" - They can be enabled / disabled: the Simulator\n");
747 PrintF(" will / won't stop when hitting them.\n");
748 PrintF(" - The Simulator keeps track of how many times they \n");
749 PrintF(" are met. (See the info command.) Going over a\n");
750 PrintF(" disabled stop still increases its counter. \n");
751 PrintF(" Commands:\n");
752 PrintF(" stop info all/<code> : print infos about number <code>\n");
753 PrintF(" or all stop(s).\n");
754 PrintF(" stop enable/disable all/<code> : enables / disables\n");
755 PrintF(" all or number <code> stop(s)\n");
756 PrintF(" stop unstop\n");
757 PrintF(" ignore the stop instruction at the current location\n");
758 PrintF(" from now on\n");
Andrei Popescu31002712010-02-23 13:46:05 +0000759 } else {
760 PrintF("Unknown command: %s\n", cmd);
761 }
762 }
Andrei Popescu31002712010-02-23 13:46:05 +0000763 }
764
765 // Add all the breakpoints back to stop execution and enter the debugger
766 // shell when hit.
767 RedoBreakpoints();
768
769#undef COMMAND_SIZE
770#undef ARG_SIZE
771
772#undef STR
773#undef XSTR
774}
775
776
Steve Block44f0eee2011-05-26 01:26:41 +0100777static bool ICacheMatch(void* one, void* two) {
778 ASSERT((reinterpret_cast<intptr_t>(one) & CachePage::kPageMask) == 0);
779 ASSERT((reinterpret_cast<intptr_t>(two) & CachePage::kPageMask) == 0);
780 return one == two;
781}
Andrei Popescu31002712010-02-23 13:46:05 +0000782
783
Steve Block44f0eee2011-05-26 01:26:41 +0100784static uint32_t ICacheHash(void* key) {
785 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)) >> 2;
786}
787
788
789static bool AllOnOnePage(uintptr_t start, int size) {
790 intptr_t start_page = (start & ~CachePage::kPageMask);
791 intptr_t end_page = ((start + size) & ~CachePage::kPageMask);
792 return start_page == end_page;
793}
794
795
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100796void Simulator::set_last_debugger_input(char* input) {
797 DeleteArray(last_debugger_input_);
798 last_debugger_input_ = input;
799}
800
801
Steve Block44f0eee2011-05-26 01:26:41 +0100802void Simulator::FlushICache(v8::internal::HashMap* i_cache,
803 void* start_addr,
804 size_t size) {
805 intptr_t start = reinterpret_cast<intptr_t>(start_addr);
806 int intra_line = (start & CachePage::kLineMask);
807 start -= intra_line;
808 size += intra_line;
809 size = ((size - 1) | CachePage::kLineMask) + 1;
810 int offset = (start & CachePage::kPageMask);
811 while (!AllOnOnePage(start, size - 1)) {
812 int bytes_to_flush = CachePage::kPageSize - offset;
813 FlushOnePage(i_cache, start, bytes_to_flush);
814 start += bytes_to_flush;
815 size -= bytes_to_flush;
816 ASSERT_EQ(0, start & CachePage::kPageMask);
817 offset = 0;
818 }
819 if (size != 0) {
820 FlushOnePage(i_cache, start, size);
821 }
822}
823
824
825CachePage* Simulator::GetCachePage(v8::internal::HashMap* i_cache, void* page) {
826 v8::internal::HashMap::Entry* entry = i_cache->Lookup(page,
Ben Murdoch257744e2011-11-30 15:57:28 +0000827 ICacheHash(page),
828 true);
Steve Block44f0eee2011-05-26 01:26:41 +0100829 if (entry->value == NULL) {
830 CachePage* new_page = new CachePage();
831 entry->value = new_page;
832 }
833 return reinterpret_cast<CachePage*>(entry->value);
834}
835
836
837// Flush from start up to and not including start + size.
838void Simulator::FlushOnePage(v8::internal::HashMap* i_cache,
839 intptr_t start,
840 int size) {
841 ASSERT(size <= CachePage::kPageSize);
842 ASSERT(AllOnOnePage(start, size - 1));
843 ASSERT((start & CachePage::kLineMask) == 0);
844 ASSERT((size & CachePage::kLineMask) == 0);
845 void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask));
846 int offset = (start & CachePage::kPageMask);
847 CachePage* cache_page = GetCachePage(i_cache, page);
848 char* valid_bytemap = cache_page->ValidityByte(offset);
849 memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift);
850}
851
852
853void Simulator::CheckICache(v8::internal::HashMap* i_cache,
854 Instruction* instr) {
855 intptr_t address = reinterpret_cast<intptr_t>(instr);
856 void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
857 void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask));
858 int offset = (address & CachePage::kPageMask);
859 CachePage* cache_page = GetCachePage(i_cache, page);
860 char* cache_valid_byte = cache_page->ValidityByte(offset);
861 bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID);
862 char* cached_line = cache_page->CachedData(offset & ~CachePage::kLineMask);
863 if (cache_hit) {
864 // Check that the data in memory matches the contents of the I-cache.
865 CHECK(memcmp(reinterpret_cast<void*>(instr),
866 cache_page->CachedData(offset),
867 Instruction::kInstrSize) == 0);
868 } else {
869 // Cache miss. Load memory into the cache.
870 memcpy(cached_line, line, CachePage::kLineLength);
871 *cache_valid_byte = CachePage::LINE_VALID;
872 }
873}
Andrei Popescu31002712010-02-23 13:46:05 +0000874
875
Ben Murdoch257744e2011-11-30 15:57:28 +0000876void Simulator::Initialize(Isolate* isolate) {
877 if (isolate->simulator_initialized()) return;
878 isolate->set_simulator_initialized(true);
879 ::v8::internal::ExternalReference::set_redirector(isolate,
880 &RedirectExternalReference);
Andrei Popescu31002712010-02-23 13:46:05 +0000881}
882
883
Ben Murdoch257744e2011-11-30 15:57:28 +0000884Simulator::Simulator(Isolate* isolate) : isolate_(isolate) {
Steve Block44f0eee2011-05-26 01:26:41 +0100885 i_cache_ = isolate_->simulator_i_cache();
886 if (i_cache_ == NULL) {
887 i_cache_ = new v8::internal::HashMap(&ICacheMatch);
888 isolate_->set_simulator_i_cache(i_cache_);
889 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000890 Initialize(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100891 // Set up simulator support first. Some of this information is needed to
Andrei Popescu31002712010-02-23 13:46:05 +0000892 // setup the architecture state.
Steve Block44f0eee2011-05-26 01:26:41 +0100893 stack_ = reinterpret_cast<char*>(malloc(stack_size_));
Andrei Popescu31002712010-02-23 13:46:05 +0000894 pc_modified_ = false;
895 icount_ = 0;
Steve Block44f0eee2011-05-26 01:26:41 +0100896 break_count_ = 0;
Andrei Popescu31002712010-02-23 13:46:05 +0000897 break_pc_ = NULL;
898 break_instr_ = 0;
899
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100900 // Set up architecture state.
Andrei Popescu31002712010-02-23 13:46:05 +0000901 // All registers are initialized to zero to start with.
902 for (int i = 0; i < kNumSimuRegisters; i++) {
903 registers_[i] = 0;
904 }
Steve Block44f0eee2011-05-26 01:26:41 +0100905 for (int i = 0; i < kNumFPURegisters; i++) {
906 FPUregisters_[i] = 0;
907 }
908 FCSR_ = 0;
Andrei Popescu31002712010-02-23 13:46:05 +0000909
910 // The sp is initialized to point to the bottom (high address) of the
911 // allocated stack area. To be safe in potential stack underflows we leave
912 // some buffer below.
Steve Block44f0eee2011-05-26 01:26:41 +0100913 registers_[sp] = reinterpret_cast<int32_t>(stack_) + stack_size_ - 64;
Andrei Popescu31002712010-02-23 13:46:05 +0000914 // The ra and pc are initialized to a known bad value that will cause an
915 // access violation if the simulator ever tries to execute it.
916 registers_[pc] = bad_ra;
917 registers_[ra] = bad_ra;
918 InitializeCoverage();
Steve Block44f0eee2011-05-26 01:26:41 +0100919 for (int i = 0; i < kNumExceptions; i++) {
920 exceptions[i] = 0;
921 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100922
923 last_debugger_input_ = NULL;
Andrei Popescu31002712010-02-23 13:46:05 +0000924}
925
926
927// When the generated code calls an external reference we need to catch that in
928// the simulator. The external reference will be a function compiled for the
929// host architecture. We need to call that function instead of trying to
930// execute it with the simulator. We do that by redirecting the external
931// reference to a swi (software-interrupt) instruction that is handled by
932// the simulator. We write the original destination of the jump just at a known
933// offset from the swi instruction so the simulator knows what to call.
934class Redirection {
935 public:
Steve Block44f0eee2011-05-26 01:26:41 +0100936 Redirection(void* external_function, ExternalReference::Type type)
Andrei Popescu31002712010-02-23 13:46:05 +0000937 : external_function_(external_function),
938 swi_instruction_(rtCallRedirInstr),
Steve Block44f0eee2011-05-26 01:26:41 +0100939 type_(type),
940 next_(NULL) {
941 Isolate* isolate = Isolate::Current();
942 next_ = isolate->simulator_redirection();
943 Simulator::current(isolate)->
944 FlushICache(isolate->simulator_i_cache(),
945 reinterpret_cast<void*>(&swi_instruction_),
946 Instruction::kInstrSize);
947 isolate->set_simulator_redirection(this);
Andrei Popescu31002712010-02-23 13:46:05 +0000948 }
949
950 void* address_of_swi_instruction() {
951 return reinterpret_cast<void*>(&swi_instruction_);
952 }
953
954 void* external_function() { return external_function_; }
Steve Block44f0eee2011-05-26 01:26:41 +0100955 ExternalReference::Type type() { return type_; }
Andrei Popescu31002712010-02-23 13:46:05 +0000956
Steve Block44f0eee2011-05-26 01:26:41 +0100957 static Redirection* Get(void* external_function,
958 ExternalReference::Type type) {
959 Isolate* isolate = Isolate::Current();
960 Redirection* current = isolate->simulator_redirection();
961 for (; current != NULL; current = current->next_) {
Andrei Popescu31002712010-02-23 13:46:05 +0000962 if (current->external_function_ == external_function) return current;
963 }
Steve Block44f0eee2011-05-26 01:26:41 +0100964 return new Redirection(external_function, type);
Andrei Popescu31002712010-02-23 13:46:05 +0000965 }
966
967 static Redirection* FromSwiInstruction(Instruction* swi_instruction) {
968 char* addr_of_swi = reinterpret_cast<char*>(swi_instruction);
969 char* addr_of_redirection =
970 addr_of_swi - OFFSET_OF(Redirection, swi_instruction_);
971 return reinterpret_cast<Redirection*>(addr_of_redirection);
972 }
973
974 private:
975 void* external_function_;
976 uint32_t swi_instruction_;
Steve Block44f0eee2011-05-26 01:26:41 +0100977 ExternalReference::Type type_;
Andrei Popescu31002712010-02-23 13:46:05 +0000978 Redirection* next_;
Andrei Popescu31002712010-02-23 13:46:05 +0000979};
980
981
Andrei Popescu31002712010-02-23 13:46:05 +0000982void* Simulator::RedirectExternalReference(void* external_function,
Steve Block44f0eee2011-05-26 01:26:41 +0100983 ExternalReference::Type type) {
984 Redirection* redirection = Redirection::Get(external_function, type);
Andrei Popescu31002712010-02-23 13:46:05 +0000985 return redirection->address_of_swi_instruction();
986}
987
988
989// Get the active Simulator for the current thread.
Steve Block44f0eee2011-05-26 01:26:41 +0100990Simulator* Simulator::current(Isolate* isolate) {
991 v8::internal::Isolate::PerIsolateThreadData* isolate_data =
Ben Murdoch257744e2011-11-30 15:57:28 +0000992 isolate->FindOrAllocatePerThreadDataForThisThread();
993 ASSERT(isolate_data != NULL);
Steve Block44f0eee2011-05-26 01:26:41 +0100994 ASSERT(isolate_data != NULL);
995
996 Simulator* sim = isolate_data->simulator();
Andrei Popescu31002712010-02-23 13:46:05 +0000997 if (sim == NULL) {
Steve Block44f0eee2011-05-26 01:26:41 +0100998 // TODO(146): delete the simulator object when a thread/isolate goes away.
Ben Murdoch257744e2011-11-30 15:57:28 +0000999 sim = new Simulator(isolate);
Steve Block44f0eee2011-05-26 01:26:41 +01001000 isolate_data->set_simulator(sim);
Andrei Popescu31002712010-02-23 13:46:05 +00001001 }
1002 return sim;
1003}
1004
1005
1006// Sets the register in the architecture state. It will also deal with updating
1007// Simulator internal state for special registers such as PC.
1008void Simulator::set_register(int reg, int32_t value) {
1009 ASSERT((reg >= 0) && (reg < kNumSimuRegisters));
1010 if (reg == pc) {
1011 pc_modified_ = true;
1012 }
1013
Ben Murdoch257744e2011-11-30 15:57:28 +00001014 // Zero register always holds 0.
Andrei Popescu31002712010-02-23 13:46:05 +00001015 registers_[reg] = (reg == 0) ? 0 : value;
1016}
1017
Steve Block44f0eee2011-05-26 01:26:41 +01001018
Andrei Popescu31002712010-02-23 13:46:05 +00001019void Simulator::set_fpu_register(int fpureg, int32_t value) {
1020 ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters));
1021 FPUregisters_[fpureg] = value;
1022}
1023
Steve Block44f0eee2011-05-26 01:26:41 +01001024
1025void Simulator::set_fpu_register_float(int fpureg, float value) {
1026 ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters));
1027 *BitCast<float*>(&FPUregisters_[fpureg]) = value;
1028}
1029
1030
Andrei Popescu31002712010-02-23 13:46:05 +00001031void Simulator::set_fpu_register_double(int fpureg, double value) {
1032 ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
Steve Block44f0eee2011-05-26 01:26:41 +01001033 *BitCast<double*>(&FPUregisters_[fpureg]) = value;
Andrei Popescu31002712010-02-23 13:46:05 +00001034}
1035
1036
1037// Get the register from the architecture state. This function does handle
1038// the special case of accessing the PC register.
1039int32_t Simulator::get_register(int reg) const {
1040 ASSERT((reg >= 0) && (reg < kNumSimuRegisters));
1041 if (reg == 0)
1042 return 0;
1043 else
1044 return registers_[reg] + ((reg == pc) ? Instruction::kPCReadOffset : 0);
1045}
1046
Steve Block44f0eee2011-05-26 01:26:41 +01001047
Andrei Popescu31002712010-02-23 13:46:05 +00001048int32_t Simulator::get_fpu_register(int fpureg) const {
1049 ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters));
1050 return FPUregisters_[fpureg];
1051}
1052
Steve Block44f0eee2011-05-26 01:26:41 +01001053
1054int64_t Simulator::get_fpu_register_long(int fpureg) const {
1055 ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
1056 return *BitCast<int64_t*>(
1057 const_cast<int32_t*>(&FPUregisters_[fpureg]));
1058}
1059
1060
1061float Simulator::get_fpu_register_float(int fpureg) const {
1062 ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters));
1063 return *BitCast<float*>(
1064 const_cast<int32_t*>(&FPUregisters_[fpureg]));
1065}
1066
1067
Andrei Popescu31002712010-02-23 13:46:05 +00001068double Simulator::get_fpu_register_double(int fpureg) const {
1069 ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
Steve Block44f0eee2011-05-26 01:26:41 +01001070 return *BitCast<double*>(const_cast<int32_t*>(&FPUregisters_[fpureg]));
Andrei Popescu31002712010-02-23 13:46:05 +00001071}
1072
Steve Block44f0eee2011-05-26 01:26:41 +01001073
Ben Murdoch257744e2011-11-30 15:57:28 +00001074// For use in calls that take two double values, constructed either
1075// from a0-a3 or f12 and f14.
1076void Simulator::GetFpArgs(double* x, double* y) {
1077 if (!IsMipsSoftFloatABI) {
1078 *x = get_fpu_register_double(12);
1079 *y = get_fpu_register_double(14);
1080 } else {
1081 // We use a char buffer to get around the strict-aliasing rules which
1082 // otherwise allow the compiler to optimize away the copy.
1083 char buffer[sizeof(*x)];
1084 int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
1085
1086 // Registers a0 and a1 -> x.
1087 reg_buffer[0] = get_register(a0);
1088 reg_buffer[1] = get_register(a1);
1089 memcpy(x, buffer, sizeof(buffer));
1090
1091 // Registers a2 and a3 -> y.
1092 reg_buffer[0] = get_register(a2);
1093 reg_buffer[1] = get_register(a3);
1094 memcpy(y, buffer, sizeof(buffer));
1095 }
1096}
1097
1098
1099// For use in calls that take one double value, constructed either
1100// from a0 and a1 or f12.
1101void Simulator::GetFpArgs(double* x) {
1102 if (!IsMipsSoftFloatABI) {
1103 *x = get_fpu_register_double(12);
1104 } else {
1105 // We use a char buffer to get around the strict-aliasing rules which
1106 // otherwise allow the compiler to optimize away the copy.
1107 char buffer[sizeof(*x)];
1108 int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
1109 // Registers a0 and a1 -> x.
1110 reg_buffer[0] = get_register(a0);
1111 reg_buffer[1] = get_register(a1);
1112 memcpy(x, buffer, sizeof(buffer));
1113 }
1114}
1115
1116
1117// For use in calls that take one double value constructed either
1118// from a0 and a1 or f12 and one integer value.
1119void Simulator::GetFpArgs(double* x, int32_t* y) {
1120 if (!IsMipsSoftFloatABI) {
1121 *x = get_fpu_register_double(12);
1122 *y = get_register(a2);
1123 } else {
1124 // We use a char buffer to get around the strict-aliasing rules which
1125 // otherwise allow the compiler to optimize away the copy.
1126 char buffer[sizeof(*x)];
1127 int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
1128 // Registers 0 and 1 -> x.
1129 reg_buffer[0] = get_register(a0);
1130 reg_buffer[1] = get_register(a1);
1131 memcpy(x, buffer, sizeof(buffer));
1132
1133 // Register 2 -> y.
1134 reg_buffer[0] = get_register(a2);
1135 memcpy(y, buffer, sizeof(*y));
1136 }
1137}
1138
1139
1140// The return value is either in v0/v1 or f0.
1141void Simulator::SetFpResult(const double& result) {
1142 if (!IsMipsSoftFloatABI) {
1143 set_fpu_register_double(0, result);
1144 } else {
1145 char buffer[2 * sizeof(registers_[0])];
1146 int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
1147 memcpy(buffer, &result, sizeof(buffer));
1148 // Copy result to v0 and v1.
1149 set_register(v0, reg_buffer[0]);
1150 set_register(v1, reg_buffer[1]);
1151 }
1152}
1153
1154
Steve Block44f0eee2011-05-26 01:26:41 +01001155// Helper functions for setting and testing the FCSR register's bits.
1156void Simulator::set_fcsr_bit(uint32_t cc, bool value) {
1157 if (value) {
1158 FCSR_ |= (1 << cc);
1159 } else {
1160 FCSR_ &= ~(1 << cc);
1161 }
1162}
1163
1164
1165bool Simulator::test_fcsr_bit(uint32_t cc) {
1166 return FCSR_ & (1 << cc);
1167}
1168
1169
1170// Sets the rounding error codes in FCSR based on the result of the rounding.
1171// Returns true if the operation was invalid.
1172bool Simulator::set_fcsr_round_error(double original, double rounded) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001173 bool ret = false;
1174
1175 if (!isfinite(original) || !isfinite(rounded)) {
1176 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1177 ret = true;
Steve Block44f0eee2011-05-26 01:26:41 +01001178 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001179
1180 if (original != rounded) {
1181 set_fcsr_bit(kFCSRInexactFlagBit, true);
1182 }
1183
1184 if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) {
1185 set_fcsr_bit(kFCSRUnderflowFlagBit, true);
1186 ret = true;
1187 }
1188
1189 if (rounded > INT_MAX || rounded < INT_MIN) {
1190 set_fcsr_bit(kFCSROverflowFlagBit, true);
1191 // The reference is not really clear but it seems this is required:
1192 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1193 ret = true;
1194 }
1195
1196 return ret;
Steve Block44f0eee2011-05-26 01:26:41 +01001197}
1198
1199
Andrei Popescu31002712010-02-23 13:46:05 +00001200// Raw access to the PC register.
1201void Simulator::set_pc(int32_t value) {
1202 pc_modified_ = true;
1203 registers_[pc] = value;
1204}
1205
Steve Block44f0eee2011-05-26 01:26:41 +01001206
1207bool Simulator::has_bad_pc() const {
1208 return ((registers_[pc] == bad_ra) || (registers_[pc] == end_sim_pc));
1209}
1210
1211
Andrei Popescu31002712010-02-23 13:46:05 +00001212// Raw access to the PC register without the special adjustment when reading.
1213int32_t Simulator::get_pc() const {
1214 return registers_[pc];
1215}
1216
1217
1218// The MIPS cannot do unaligned reads and writes. On some MIPS platforms an
1219// interrupt is caused. On others it does a funky rotation thing. For now we
1220// simply disallow unaligned reads, but at some point we may want to move to
1221// emulating the rotate behaviour. Note that simulator runs have the runtime
1222// system running directly on the host system and only generated code is
1223// executed in the simulator. Since the host is typically IA32 we will not
1224// get the correct MIPS-like behaviour on unaligned accesses.
1225
1226int Simulator::ReadW(int32_t addr, Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +01001227 if (addr >=0 && addr < 0x400) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001228 // This has to be a NULL-dereference, drop into debugger.
Ben Murdoch589d6972011-11-30 16:04:58 +00001229 PrintF("Memory read from bad address: 0x%08x, pc=0x%08x\n",
1230 addr, reinterpret_cast<intptr_t>(instr));
Steve Block44f0eee2011-05-26 01:26:41 +01001231 MipsDebugger dbg(this);
1232 dbg.Debug();
1233 }
1234 if ((addr & kPointerAlignmentMask) == 0) {
Andrei Popescu31002712010-02-23 13:46:05 +00001235 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
1236 return *ptr;
1237 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001238 PrintF("Unaligned read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1239 addr,
1240 reinterpret_cast<intptr_t>(instr));
Steve Block44f0eee2011-05-26 01:26:41 +01001241 MipsDebugger dbg(this);
1242 dbg.Debug();
Andrei Popescu31002712010-02-23 13:46:05 +00001243 return 0;
1244}
1245
1246
1247void Simulator::WriteW(int32_t addr, int value, Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +01001248 if (addr >= 0 && addr < 0x400) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001249 // This has to be a NULL-dereference, drop into debugger.
Ben Murdoch589d6972011-11-30 16:04:58 +00001250 PrintF("Memory write to bad address: 0x%08x, pc=0x%08x\n",
1251 addr, reinterpret_cast<intptr_t>(instr));
Steve Block44f0eee2011-05-26 01:26:41 +01001252 MipsDebugger dbg(this);
1253 dbg.Debug();
1254 }
1255 if ((addr & kPointerAlignmentMask) == 0) {
Andrei Popescu31002712010-02-23 13:46:05 +00001256 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
1257 *ptr = value;
1258 return;
1259 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001260 PrintF("Unaligned write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1261 addr,
1262 reinterpret_cast<intptr_t>(instr));
Steve Block44f0eee2011-05-26 01:26:41 +01001263 MipsDebugger dbg(this);
1264 dbg.Debug();
Andrei Popescu31002712010-02-23 13:46:05 +00001265}
1266
1267
1268double Simulator::ReadD(int32_t addr, Instruction* instr) {
1269 if ((addr & kDoubleAlignmentMask) == 0) {
1270 double* ptr = reinterpret_cast<double*>(addr);
1271 return *ptr;
1272 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001273 PrintF("Unaligned (double) read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1274 addr,
1275 reinterpret_cast<intptr_t>(instr));
Andrei Popescu31002712010-02-23 13:46:05 +00001276 OS::Abort();
1277 return 0;
1278}
1279
1280
1281void Simulator::WriteD(int32_t addr, double value, Instruction* instr) {
1282 if ((addr & kDoubleAlignmentMask) == 0) {
1283 double* ptr = reinterpret_cast<double*>(addr);
1284 *ptr = value;
1285 return;
1286 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001287 PrintF("Unaligned (double) write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1288 addr,
1289 reinterpret_cast<intptr_t>(instr));
Andrei Popescu31002712010-02-23 13:46:05 +00001290 OS::Abort();
1291}
1292
1293
1294uint16_t Simulator::ReadHU(int32_t addr, Instruction* instr) {
1295 if ((addr & 1) == 0) {
1296 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1297 return *ptr;
1298 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001299 PrintF("Unaligned unsigned halfword read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1300 addr,
1301 reinterpret_cast<intptr_t>(instr));
Andrei Popescu31002712010-02-23 13:46:05 +00001302 OS::Abort();
1303 return 0;
1304}
1305
1306
1307int16_t Simulator::ReadH(int32_t addr, Instruction* instr) {
1308 if ((addr & 1) == 0) {
1309 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
1310 return *ptr;
1311 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001312 PrintF("Unaligned signed halfword read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1313 addr,
1314 reinterpret_cast<intptr_t>(instr));
Andrei Popescu31002712010-02-23 13:46:05 +00001315 OS::Abort();
1316 return 0;
1317}
1318
1319
1320void Simulator::WriteH(int32_t addr, uint16_t value, Instruction* instr) {
1321 if ((addr & 1) == 0) {
1322 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1323 *ptr = value;
1324 return;
1325 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001326 PrintF("Unaligned unsigned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1327 addr,
1328 reinterpret_cast<intptr_t>(instr));
Andrei Popescu31002712010-02-23 13:46:05 +00001329 OS::Abort();
1330}
1331
1332
1333void Simulator::WriteH(int32_t addr, int16_t value, Instruction* instr) {
1334 if ((addr & 1) == 0) {
1335 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
1336 *ptr = value;
1337 return;
1338 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001339 PrintF("Unaligned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1340 addr,
1341 reinterpret_cast<intptr_t>(instr));
Andrei Popescu31002712010-02-23 13:46:05 +00001342 OS::Abort();
1343}
1344
1345
1346uint32_t Simulator::ReadBU(int32_t addr) {
1347 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1348 return *ptr & 0xff;
1349}
1350
1351
1352int32_t Simulator::ReadB(int32_t addr) {
1353 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
Steve Block44f0eee2011-05-26 01:26:41 +01001354 return *ptr;
Andrei Popescu31002712010-02-23 13:46:05 +00001355}
1356
1357
1358void Simulator::WriteB(int32_t addr, uint8_t value) {
1359 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1360 *ptr = value;
1361}
1362
1363
1364void Simulator::WriteB(int32_t addr, int8_t value) {
1365 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
1366 *ptr = value;
1367}
1368
1369
1370// Returns the limit of the stack area to enable checking for stack overflows.
1371uintptr_t Simulator::StackLimit() const {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001372 // Leave a safety margin of 1024 bytes to prevent overrunning the stack when
Andrei Popescu31002712010-02-23 13:46:05 +00001373 // pushing values.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001374 return reinterpret_cast<uintptr_t>(stack_) + 1024;
Andrei Popescu31002712010-02-23 13:46:05 +00001375}
1376
1377
1378// Unsupported instructions use Format to print an error and stop execution.
1379void Simulator::Format(Instruction* instr, const char* format) {
1380 PrintF("Simulator found unsupported instruction:\n 0x%08x: %s\n",
Steve Block44f0eee2011-05-26 01:26:41 +01001381 reinterpret_cast<intptr_t>(instr), format);
Andrei Popescu31002712010-02-23 13:46:05 +00001382 UNIMPLEMENTED_MIPS();
1383}
1384
1385
1386// Calls into the V8 runtime are based on this very simple interface.
1387// Note: To be able to return two values from some calls the code in runtime.cc
1388// uses the ObjectPair which is essentially two 32-bit values stuffed into a
1389// 64-bit value. With the code below we assume that all runtime calls return
Steve Block44f0eee2011-05-26 01:26:41 +01001390// 64 bits of result. If they don't, the v1 result register contains a bogus
Andrei Popescu31002712010-02-23 13:46:05 +00001391// value, which is fine because it is caller-saved.
1392typedef int64_t (*SimulatorRuntimeCall)(int32_t arg0,
1393 int32_t arg1,
1394 int32_t arg2,
Steve Block44f0eee2011-05-26 01:26:41 +01001395 int32_t arg3,
1396 int32_t arg4,
1397 int32_t arg5);
1398typedef double (*SimulatorRuntimeFPCall)(int32_t arg0,
1399 int32_t arg1,
1400 int32_t arg2,
1401 int32_t arg3);
Andrei Popescu31002712010-02-23 13:46:05 +00001402
Ben Murdoch257744e2011-11-30 15:57:28 +00001403// This signature supports direct call in to API function native callback
1404// (refer to InvocationCallback in v8.h).
1405typedef v8::Handle<v8::Value> (*SimulatorRuntimeDirectApiCall)(int32_t arg0);
1406
1407// This signature supports direct call to accessor getter callback.
1408typedef v8::Handle<v8::Value> (*SimulatorRuntimeDirectGetterCall)(int32_t arg0,
1409 int32_t arg1);
1410
Andrei Popescu31002712010-02-23 13:46:05 +00001411// Software interrupt instructions are used by the simulator to call into the
Steve Block44f0eee2011-05-26 01:26:41 +01001412// C-based V8 runtime. They are also used for debugging with simulator.
Andrei Popescu31002712010-02-23 13:46:05 +00001413void Simulator::SoftwareInterrupt(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +01001414 // There are several instructions that could get us here,
1415 // the break_ instruction, or several variants of traps. All
1416 // Are "SPECIAL" class opcode, and are distinuished by function.
1417 int32_t func = instr->FunctionFieldRaw();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001418 uint32_t code = (func == BREAK) ? instr->Bits(25, 6) : -1;
Steve Block44f0eee2011-05-26 01:26:41 +01001419
Andrei Popescu31002712010-02-23 13:46:05 +00001420 // We first check if we met a call_rt_redirected.
1421 if (instr->InstructionBits() == rtCallRedirInstr) {
1422 Redirection* redirection = Redirection::FromSwiInstruction(instr);
1423 int32_t arg0 = get_register(a0);
1424 int32_t arg1 = get_register(a1);
1425 int32_t arg2 = get_register(a2);
1426 int32_t arg3 = get_register(a3);
Steve Block44f0eee2011-05-26 01:26:41 +01001427
Steve Block44f0eee2011-05-26 01:26:41 +01001428 int32_t* stack_pointer = reinterpret_cast<int32_t*>(get_register(sp));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001429 // Args 4 and 5 are on the stack after the reserved space for args 0..3.
1430 int32_t arg4 = stack_pointer[4];
1431 int32_t arg5 = stack_pointer[5];
Ben Murdoch257744e2011-11-30 15:57:28 +00001432
1433 bool fp_call =
1434 (redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) ||
1435 (redirection->type() == ExternalReference::BUILTIN_COMPARE_CALL) ||
1436 (redirection->type() == ExternalReference::BUILTIN_FP_CALL) ||
1437 (redirection->type() == ExternalReference::BUILTIN_FP_INT_CALL);
1438
1439 if (!IsMipsSoftFloatABI) {
1440 // With the hard floating point calling convention, double
1441 // arguments are passed in FPU registers. Fetch the arguments
1442 // from there and call the builtin using soft floating point
1443 // convention.
1444 switch (redirection->type()) {
1445 case ExternalReference::BUILTIN_FP_FP_CALL:
1446 case ExternalReference::BUILTIN_COMPARE_CALL:
1447 arg0 = get_fpu_register(f12);
1448 arg1 = get_fpu_register(f13);
1449 arg2 = get_fpu_register(f14);
1450 arg3 = get_fpu_register(f15);
1451 break;
1452 case ExternalReference::BUILTIN_FP_CALL:
1453 arg0 = get_fpu_register(f12);
1454 arg1 = get_fpu_register(f13);
1455 break;
1456 case ExternalReference::BUILTIN_FP_INT_CALL:
1457 arg0 = get_fpu_register(f12);
1458 arg1 = get_fpu_register(f13);
1459 arg2 = get_register(a2);
1460 break;
1461 default:
1462 break;
1463 }
1464 }
1465
Andrei Popescu31002712010-02-23 13:46:05 +00001466 // This is dodgy but it works because the C entry stubs are never moved.
1467 // See comment in codegen-arm.cc and bug 1242173.
1468 int32_t saved_ra = get_register(ra);
Steve Block44f0eee2011-05-26 01:26:41 +01001469
1470 intptr_t external =
Ben Murdoch257744e2011-11-30 15:57:28 +00001471 reinterpret_cast<intptr_t>(redirection->external_function());
Steve Block44f0eee2011-05-26 01:26:41 +01001472
1473 // Based on CpuFeatures::IsSupported(FPU), Mips will use either hardware
1474 // FPU, or gcc soft-float routines. Hardware FPU is simulated in this
1475 // simulator. Soft-float has additional abstraction of ExternalReference,
Ben Murdoch257744e2011-11-30 15:57:28 +00001476 // to support serialization.
1477 if (fp_call) {
Andrei Popescu31002712010-02-23 13:46:05 +00001478 SimulatorRuntimeFPCall target =
Ben Murdoch257744e2011-11-30 15:57:28 +00001479 reinterpret_cast<SimulatorRuntimeFPCall>(external);
1480 if (::v8::internal::FLAG_trace_sim) {
1481 double dval0, dval1;
1482 int32_t ival;
1483 switch (redirection->type()) {
1484 case ExternalReference::BUILTIN_FP_FP_CALL:
1485 case ExternalReference::BUILTIN_COMPARE_CALL:
1486 GetFpArgs(&dval0, &dval1);
1487 PrintF("Call to host function at %p with args %f, %f",
1488 FUNCTION_ADDR(target), dval0, dval1);
1489 break;
1490 case ExternalReference::BUILTIN_FP_CALL:
1491 GetFpArgs(&dval0);
1492 PrintF("Call to host function at %p with arg %f",
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001493 FUNCTION_ADDR(target), dval0);
Ben Murdoch257744e2011-11-30 15:57:28 +00001494 break;
1495 case ExternalReference::BUILTIN_FP_INT_CALL:
1496 GetFpArgs(&dval0, &ival);
1497 PrintF("Call to host function at %p with args %f, %d",
1498 FUNCTION_ADDR(target), dval0, ival);
1499 break;
1500 default:
1501 UNREACHABLE();
1502 break;
Steve Block44f0eee2011-05-26 01:26:41 +01001503 }
Andrei Popescu31002712010-02-23 13:46:05 +00001504 }
Steve Block44f0eee2011-05-26 01:26:41 +01001505 double result = target(arg0, arg1, arg2, arg3);
Ben Murdoch257744e2011-11-30 15:57:28 +00001506 if (redirection->type() != ExternalReference::BUILTIN_COMPARE_CALL) {
1507 SetFpResult(result);
1508 } else {
1509 int32_t gpreg_pair[2];
1510 memcpy(&gpreg_pair[0], &result, 2 * sizeof(int32_t));
1511 set_register(v0, gpreg_pair[0]);
1512 set_register(v1, gpreg_pair[1]);
1513 }
Steve Block44f0eee2011-05-26 01:26:41 +01001514 } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001515 // See DirectCEntryStub::GenerateCall for explanation of register usage.
1516 SimulatorRuntimeDirectApiCall target =
1517 reinterpret_cast<SimulatorRuntimeDirectApiCall>(external);
1518 if (::v8::internal::FLAG_trace_sim) {
1519 PrintF("Call to host function at %p args %08x\n",
1520 FUNCTION_ADDR(target), arg1);
1521 }
1522 v8::Handle<v8::Value> result = target(arg1);
1523 *(reinterpret_cast<int*>(arg0)) = (int32_t) *result;
1524 set_register(v0, arg0);
Steve Block44f0eee2011-05-26 01:26:41 +01001525 } else if (redirection->type() == ExternalReference::DIRECT_GETTER_CALL) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001526 // See DirectCEntryStub::GenerateCall for explanation of register usage.
1527 SimulatorRuntimeDirectGetterCall target =
1528 reinterpret_cast<SimulatorRuntimeDirectGetterCall>(external);
1529 if (::v8::internal::FLAG_trace_sim) {
1530 PrintF("Call to host function at %p args %08x %08x\n",
1531 FUNCTION_ADDR(target), arg1, arg2);
1532 }
1533 v8::Handle<v8::Value> result = target(arg1, arg2);
1534 *(reinterpret_cast<int*>(arg0)) = (int32_t) *result;
1535 set_register(v0, arg0);
Andrei Popescu31002712010-02-23 13:46:05 +00001536 } else {
Andrei Popescu31002712010-02-23 13:46:05 +00001537 SimulatorRuntimeCall target =
Ben Murdoch257744e2011-11-30 15:57:28 +00001538 reinterpret_cast<SimulatorRuntimeCall>(external);
1539 if (::v8::internal::FLAG_trace_sim) {
Andrei Popescu31002712010-02-23 13:46:05 +00001540 PrintF(
Ben Murdoch257744e2011-11-30 15:57:28 +00001541 "Call to host function at %p "
1542 "args %08x, %08x, %08x, %08x, %08x, %08x\n",
Andrei Popescu31002712010-02-23 13:46:05 +00001543 FUNCTION_ADDR(target),
1544 arg0,
1545 arg1,
1546 arg2,
Steve Block44f0eee2011-05-26 01:26:41 +01001547 arg3,
1548 arg4,
1549 arg5);
Andrei Popescu31002712010-02-23 13:46:05 +00001550 }
Steve Block44f0eee2011-05-26 01:26:41 +01001551 int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5);
1552 set_register(v0, static_cast<int32_t>(result));
1553 set_register(v1, static_cast<int32_t>(result >> 32));
1554 }
1555 if (::v8::internal::FLAG_trace_sim) {
1556 PrintF("Returned %08x : %08x\n", get_register(v1), get_register(v0));
Andrei Popescu31002712010-02-23 13:46:05 +00001557 }
1558 set_register(ra, saved_ra);
1559 set_pc(get_register(ra));
Steve Block44f0eee2011-05-26 01:26:41 +01001560
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001561 } else if (func == BREAK && code <= kMaxStopCode) {
1562 if (IsWatchpoint(code)) {
1563 PrintWatchpoint(code);
1564 } else {
1565 IncreaseStopCounter(code);
1566 HandleStop(code, instr);
1567 }
Andrei Popescu31002712010-02-23 13:46:05 +00001568 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01001569 // All remaining break_ codes, and all traps are handled here.
1570 MipsDebugger dbg(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001571 dbg.Debug();
1572 }
1573}
1574
Steve Block44f0eee2011-05-26 01:26:41 +01001575
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001576// Stop helper functions.
1577bool Simulator::IsWatchpoint(uint32_t code) {
1578 return (code <= kMaxWatchpointCode);
1579}
1580
1581
1582void Simulator::PrintWatchpoint(uint32_t code) {
1583 MipsDebugger dbg(this);
1584 ++break_count_;
1585 PrintF("\n---- break %d marker: %3d (instr count: %8d) ----------"
1586 "----------------------------------",
1587 code, break_count_, icount_);
1588 dbg.PrintAllRegs(); // Print registers and continue running.
1589}
1590
1591
1592void Simulator::HandleStop(uint32_t code, Instruction* instr) {
1593 // Stop if it is enabled, otherwise go on jumping over the stop
1594 // and the message address.
1595 if (IsEnabledStop(code)) {
1596 MipsDebugger dbg(this);
1597 dbg.Stop(instr);
1598 } else {
1599 set_pc(get_pc() + 2 * Instruction::kInstrSize);
1600 }
1601}
1602
1603
1604bool Simulator::IsStopInstruction(Instruction* instr) {
1605 int32_t func = instr->FunctionFieldRaw();
1606 uint32_t code = static_cast<uint32_t>(instr->Bits(25, 6));
1607 return (func == BREAK) && code > kMaxWatchpointCode && code <= kMaxStopCode;
1608}
1609
1610
1611bool Simulator::IsEnabledStop(uint32_t code) {
1612 ASSERT(code <= kMaxStopCode);
1613 ASSERT(code > kMaxWatchpointCode);
1614 return !(watched_stops[code].count & kStopDisabledBit);
1615}
1616
1617
1618void Simulator::EnableStop(uint32_t code) {
1619 if (!IsEnabledStop(code)) {
1620 watched_stops[code].count &= ~kStopDisabledBit;
1621 }
1622}
1623
1624
1625void Simulator::DisableStop(uint32_t code) {
1626 if (IsEnabledStop(code)) {
1627 watched_stops[code].count |= kStopDisabledBit;
1628 }
1629}
1630
1631
1632void Simulator::IncreaseStopCounter(uint32_t code) {
1633 ASSERT(code <= kMaxStopCode);
1634 if ((watched_stops[code].count & ~(1 << 31)) == 0x7fffffff) {
1635 PrintF("Stop counter for code %i has overflowed.\n"
1636 "Enabling this code and reseting the counter to 0.\n", code);
1637 watched_stops[code].count = 0;
1638 EnableStop(code);
1639 } else {
1640 watched_stops[code].count++;
1641 }
1642}
1643
1644
1645// Print a stop status.
1646void Simulator::PrintStopInfo(uint32_t code) {
1647 if (code <= kMaxWatchpointCode) {
1648 PrintF("That is a watchpoint, not a stop.\n");
1649 return;
1650 } else if (code > kMaxStopCode) {
1651 PrintF("Code too large, only %u stops can be used\n", kMaxStopCode + 1);
1652 return;
1653 }
1654 const char* state = IsEnabledStop(code) ? "Enabled" : "Disabled";
1655 int32_t count = watched_stops[code].count & ~kStopDisabledBit;
1656 // Don't print the state of unused breakpoints.
1657 if (count != 0) {
1658 if (watched_stops[code].desc) {
1659 PrintF("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n",
1660 code, code, state, count, watched_stops[code].desc);
1661 } else {
1662 PrintF("stop %i - 0x%x: \t%s, \tcounter = %i\n",
1663 code, code, state, count);
1664 }
1665 }
1666}
1667
1668
Andrei Popescu31002712010-02-23 13:46:05 +00001669void Simulator::SignalExceptions() {
1670 for (int i = 1; i < kNumExceptions; i++) {
1671 if (exceptions[i] != 0) {
1672 V8_Fatal(__FILE__, __LINE__, "Error: Exception %i raised.", i);
1673 }
1674 }
1675}
1676
Steve Block44f0eee2011-05-26 01:26:41 +01001677
Andrei Popescu31002712010-02-23 13:46:05 +00001678// Handle execution based on instruction types.
Andrei Popescu31002712010-02-23 13:46:05 +00001679
Steve Block44f0eee2011-05-26 01:26:41 +01001680void Simulator::ConfigureTypeRegister(Instruction* instr,
1681 int32_t& alu_out,
1682 int64_t& i64hilo,
1683 uint64_t& u64hilo,
1684 int32_t& next_pc,
1685 bool& do_interrupt) {
1686 // Every local variable declared here needs to be const.
1687 // This is to make sure that changed values are sent back to
1688 // DecodeTypeRegister correctly.
Andrei Popescu31002712010-02-23 13:46:05 +00001689
Steve Block44f0eee2011-05-26 01:26:41 +01001690 // Instruction fields.
1691 const Opcode op = instr->OpcodeFieldRaw();
1692 const int32_t rs_reg = instr->RsValue();
1693 const int32_t rs = get_register(rs_reg);
1694 const uint32_t rs_u = static_cast<uint32_t>(rs);
1695 const int32_t rt_reg = instr->RtValue();
1696 const int32_t rt = get_register(rt_reg);
1697 const uint32_t rt_u = static_cast<uint32_t>(rt);
1698 const int32_t rd_reg = instr->RdValue();
1699 const uint32_t sa = instr->SaValue();
Andrei Popescu31002712010-02-23 13:46:05 +00001700
Steve Block44f0eee2011-05-26 01:26:41 +01001701 const int32_t fs_reg = instr->FsValue();
Andrei Popescu31002712010-02-23 13:46:05 +00001702
Andrei Popescu31002712010-02-23 13:46:05 +00001703
Ben Murdoch257744e2011-11-30 15:57:28 +00001704 // ---------- Configuration.
Andrei Popescu31002712010-02-23 13:46:05 +00001705 switch (op) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001706 case COP1: // Coprocessor instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00001707 switch (instr->RsFieldRaw()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001708 case BC1: // Handled in DecodeTypeImmed, should never come here.
Andrei Popescu31002712010-02-23 13:46:05 +00001709 UNREACHABLE();
1710 break;
Steve Block44f0eee2011-05-26 01:26:41 +01001711 case CFC1:
1712 // At the moment only FCSR is supported.
1713 ASSERT(fs_reg == kFCSRRegister);
1714 alu_out = FCSR_;
1715 break;
Andrei Popescu31002712010-02-23 13:46:05 +00001716 case MFC1:
1717 alu_out = get_fpu_register(fs_reg);
1718 break;
1719 case MFHC1:
Steve Block44f0eee2011-05-26 01:26:41 +01001720 UNIMPLEMENTED_MIPS();
Andrei Popescu31002712010-02-23 13:46:05 +00001721 break;
Steve Block44f0eee2011-05-26 01:26:41 +01001722 case CTC1:
Andrei Popescu31002712010-02-23 13:46:05 +00001723 case MTC1:
1724 case MTHC1:
1725 // Do the store in the execution step.
1726 break;
1727 case S:
1728 case D:
1729 case W:
1730 case L:
1731 case PS:
1732 // Do everything in the execution step.
1733 break;
1734 default:
1735 UNIMPLEMENTED_MIPS();
1736 };
1737 break;
1738 case SPECIAL:
1739 switch (instr->FunctionFieldRaw()) {
1740 case JR:
1741 case JALR:
Steve Block44f0eee2011-05-26 01:26:41 +01001742 next_pc = get_register(instr->RsValue());
Andrei Popescu31002712010-02-23 13:46:05 +00001743 break;
1744 case SLL:
1745 alu_out = rt << sa;
1746 break;
1747 case SRL:
Steve Block44f0eee2011-05-26 01:26:41 +01001748 if (rs_reg == 0) {
1749 // Regular logical right shift of a word by a fixed number of
1750 // bits instruction. RS field is always equal to 0.
1751 alu_out = rt_u >> sa;
1752 } else {
1753 // Logical right-rotate of a word by a fixed number of bits. This
1754 // is special case of SRL instruction, added in MIPS32 Release 2.
Ben Murdoch257744e2011-11-30 15:57:28 +00001755 // RS field is equal to 00001.
Steve Block44f0eee2011-05-26 01:26:41 +01001756 alu_out = (rt_u >> sa) | (rt_u << (32 - sa));
1757 }
Andrei Popescu31002712010-02-23 13:46:05 +00001758 break;
1759 case SRA:
1760 alu_out = rt >> sa;
1761 break;
1762 case SLLV:
1763 alu_out = rt << rs;
1764 break;
1765 case SRLV:
Steve Block44f0eee2011-05-26 01:26:41 +01001766 if (sa == 0) {
1767 // Regular logical right-shift of a word by a variable number of
1768 // bits instruction. SA field is always equal to 0.
1769 alu_out = rt_u >> rs;
1770 } else {
1771 // Logical right-rotate of a word by a variable number of bits.
1772 // This is special case od SRLV instruction, added in MIPS32
Ben Murdoch257744e2011-11-30 15:57:28 +00001773 // Release 2. SA field is equal to 00001.
Steve Block44f0eee2011-05-26 01:26:41 +01001774 alu_out = (rt_u >> rs_u) | (rt_u << (32 - rs_u));
1775 }
Andrei Popescu31002712010-02-23 13:46:05 +00001776 break;
1777 case SRAV:
1778 alu_out = rt >> rs;
1779 break;
1780 case MFHI:
1781 alu_out = get_register(HI);
1782 break;
1783 case MFLO:
1784 alu_out = get_register(LO);
1785 break;
1786 case MULT:
Steve Block44f0eee2011-05-26 01:26:41 +01001787 i64hilo = static_cast<int64_t>(rs) * static_cast<int64_t>(rt);
Andrei Popescu31002712010-02-23 13:46:05 +00001788 break;
1789 case MULTU:
Steve Block44f0eee2011-05-26 01:26:41 +01001790 u64hilo = static_cast<uint64_t>(rs_u) * static_cast<uint64_t>(rt_u);
Andrei Popescu31002712010-02-23 13:46:05 +00001791 break;
Andrei Popescu31002712010-02-23 13:46:05 +00001792 case ADD:
1793 if (HaveSameSign(rs, rt)) {
1794 if (rs > 0) {
1795 exceptions[kIntegerOverflow] = rs > (Registers::kMaxValue - rt);
1796 } else if (rs < 0) {
1797 exceptions[kIntegerUnderflow] = rs < (Registers::kMinValue - rt);
1798 }
1799 }
1800 alu_out = rs + rt;
1801 break;
1802 case ADDU:
1803 alu_out = rs + rt;
1804 break;
1805 case SUB:
1806 if (!HaveSameSign(rs, rt)) {
1807 if (rs > 0) {
1808 exceptions[kIntegerOverflow] = rs > (Registers::kMaxValue + rt);
1809 } else if (rs < 0) {
1810 exceptions[kIntegerUnderflow] = rs < (Registers::kMinValue + rt);
1811 }
1812 }
1813 alu_out = rs - rt;
1814 break;
1815 case SUBU:
1816 alu_out = rs - rt;
1817 break;
1818 case AND:
1819 alu_out = rs & rt;
1820 break;
1821 case OR:
1822 alu_out = rs | rt;
1823 break;
1824 case XOR:
1825 alu_out = rs ^ rt;
1826 break;
1827 case NOR:
1828 alu_out = ~(rs | rt);
1829 break;
1830 case SLT:
1831 alu_out = rs < rt ? 1 : 0;
1832 break;
1833 case SLTU:
1834 alu_out = rs_u < rt_u ? 1 : 0;
1835 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00001836 // Break and trap instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00001837 case BREAK:
Steve Block44f0eee2011-05-26 01:26:41 +01001838
Andrei Popescu31002712010-02-23 13:46:05 +00001839 do_interrupt = true;
1840 break;
1841 case TGE:
1842 do_interrupt = rs >= rt;
1843 break;
1844 case TGEU:
1845 do_interrupt = rs_u >= rt_u;
1846 break;
1847 case TLT:
1848 do_interrupt = rs < rt;
1849 break;
1850 case TLTU:
1851 do_interrupt = rs_u < rt_u;
1852 break;
1853 case TEQ:
1854 do_interrupt = rs == rt;
1855 break;
1856 case TNE:
1857 do_interrupt = rs != rt;
1858 break;
Steve Block44f0eee2011-05-26 01:26:41 +01001859 case MOVN:
1860 case MOVZ:
1861 case MOVCI:
1862 // No action taken on decode.
1863 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00001864 case DIV:
1865 case DIVU:
1866 // div and divu never raise exceptions.
1867 break;
Andrei Popescu31002712010-02-23 13:46:05 +00001868 default:
1869 UNREACHABLE();
1870 };
1871 break;
1872 case SPECIAL2:
1873 switch (instr->FunctionFieldRaw()) {
1874 case MUL:
1875 alu_out = rs_u * rt_u; // Only the lower 32 bits are kept.
1876 break;
Steve Block44f0eee2011-05-26 01:26:41 +01001877 case CLZ:
1878 alu_out = __builtin_clz(rs_u);
1879 break;
Andrei Popescu31002712010-02-23 13:46:05 +00001880 default:
1881 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +01001882 };
1883 break;
1884 case SPECIAL3:
1885 switch (instr->FunctionFieldRaw()) {
1886 case INS: { // Mips32r2 instruction.
Ben Murdoch257744e2011-11-30 15:57:28 +00001887 // Interpret rd field as 5-bit msb of insert.
Steve Block44f0eee2011-05-26 01:26:41 +01001888 uint16_t msb = rd_reg;
1889 // Interpret sa field as 5-bit lsb of insert.
1890 uint16_t lsb = sa;
1891 uint16_t size = msb - lsb + 1;
1892 uint32_t mask = (1 << size) - 1;
1893 alu_out = (rt_u & ~(mask << lsb)) | ((rs_u & mask) << lsb);
1894 break;
1895 }
1896 case EXT: { // Mips32r2 instruction.
Ben Murdoch257744e2011-11-30 15:57:28 +00001897 // Interpret rd field as 5-bit msb of extract.
Steve Block44f0eee2011-05-26 01:26:41 +01001898 uint16_t msb = rd_reg;
1899 // Interpret sa field as 5-bit lsb of extract.
1900 uint16_t lsb = sa;
1901 uint16_t size = msb + 1;
1902 uint32_t mask = (1 << size) - 1;
1903 alu_out = (rs_u & (mask << lsb)) >> lsb;
1904 break;
1905 }
1906 default:
1907 UNREACHABLE();
1908 };
Andrei Popescu31002712010-02-23 13:46:05 +00001909 break;
1910 default:
1911 UNREACHABLE();
1912 };
Steve Block44f0eee2011-05-26 01:26:41 +01001913}
1914
1915
1916void Simulator::DecodeTypeRegister(Instruction* instr) {
1917 // Instruction fields.
1918 const Opcode op = instr->OpcodeFieldRaw();
1919 const int32_t rs_reg = instr->RsValue();
1920 const int32_t rs = get_register(rs_reg);
1921 const uint32_t rs_u = static_cast<uint32_t>(rs);
1922 const int32_t rt_reg = instr->RtValue();
1923 const int32_t rt = get_register(rt_reg);
1924 const uint32_t rt_u = static_cast<uint32_t>(rt);
1925 const int32_t rd_reg = instr->RdValue();
1926
1927 const int32_t fs_reg = instr->FsValue();
1928 const int32_t ft_reg = instr->FtValue();
1929 const int32_t fd_reg = instr->FdValue();
1930 int64_t i64hilo = 0;
1931 uint64_t u64hilo = 0;
1932
Ben Murdoch257744e2011-11-30 15:57:28 +00001933 // ALU output.
Steve Block44f0eee2011-05-26 01:26:41 +01001934 // It should not be used as is. Instructions using it should always
1935 // initialize it first.
1936 int32_t alu_out = 0x12345678;
1937
1938 // For break and trap instructions.
1939 bool do_interrupt = false;
1940
Ben Murdoch257744e2011-11-30 15:57:28 +00001941 // For jr and jalr.
Steve Block44f0eee2011-05-26 01:26:41 +01001942 // Get current pc.
1943 int32_t current_pc = get_pc();
1944 // Next pc
1945 int32_t next_pc = 0;
1946
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001947 // Set up the variables if needed before executing the instruction.
Steve Block44f0eee2011-05-26 01:26:41 +01001948 ConfigureTypeRegister(instr,
1949 alu_out,
1950 i64hilo,
1951 u64hilo,
1952 next_pc,
1953 do_interrupt);
Andrei Popescu31002712010-02-23 13:46:05 +00001954
1955 // ---------- Raise exceptions triggered.
1956 SignalExceptions();
1957
Ben Murdoch257744e2011-11-30 15:57:28 +00001958 // ---------- Execution.
Andrei Popescu31002712010-02-23 13:46:05 +00001959 switch (op) {
1960 case COP1:
1961 switch (instr->RsFieldRaw()) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001962 case BC1: // Branch on coprocessor condition.
Andrei Popescu31002712010-02-23 13:46:05 +00001963 UNREACHABLE();
1964 break;
Steve Block44f0eee2011-05-26 01:26:41 +01001965 case CFC1:
1966 set_register(rt_reg, alu_out);
Andrei Popescu31002712010-02-23 13:46:05 +00001967 case MFC1:
Andrei Popescu31002712010-02-23 13:46:05 +00001968 set_register(rt_reg, alu_out);
1969 break;
Steve Block44f0eee2011-05-26 01:26:41 +01001970 case MFHC1:
1971 UNIMPLEMENTED_MIPS();
1972 break;
1973 case CTC1:
1974 // At the moment only FCSR is supported.
1975 ASSERT(fs_reg == kFCSRRegister);
1976 FCSR_ = registers_[rt_reg];
1977 break;
Andrei Popescu31002712010-02-23 13:46:05 +00001978 case MTC1:
Andrei Popescu31002712010-02-23 13:46:05 +00001979 FPUregisters_[fs_reg] = registers_[rt_reg];
Andrei Popescu31002712010-02-23 13:46:05 +00001980 break;
1981 case MTHC1:
Steve Block44f0eee2011-05-26 01:26:41 +01001982 UNIMPLEMENTED_MIPS();
Andrei Popescu31002712010-02-23 13:46:05 +00001983 break;
1984 case S:
Steve Block44f0eee2011-05-26 01:26:41 +01001985 float f;
Andrei Popescu31002712010-02-23 13:46:05 +00001986 switch (instr->FunctionFieldRaw()) {
1987 case CVT_D_S:
Steve Block44f0eee2011-05-26 01:26:41 +01001988 f = get_fpu_register_float(fs_reg);
1989 set_fpu_register_double(fd_reg, static_cast<double>(f));
1990 break;
Andrei Popescu31002712010-02-23 13:46:05 +00001991 case CVT_W_S:
1992 case CVT_L_S:
Steve Block44f0eee2011-05-26 01:26:41 +01001993 case TRUNC_W_S:
1994 case TRUNC_L_S:
1995 case ROUND_W_S:
1996 case ROUND_L_S:
1997 case FLOOR_W_S:
1998 case FLOOR_L_S:
1999 case CEIL_W_S:
2000 case CEIL_L_S:
Andrei Popescu31002712010-02-23 13:46:05 +00002001 case CVT_PS_S:
2002 UNIMPLEMENTED_MIPS();
2003 break;
2004 default:
2005 UNREACHABLE();
2006 }
2007 break;
2008 case D:
Steve Block44f0eee2011-05-26 01:26:41 +01002009 double ft, fs;
2010 uint32_t cc, fcsr_cc;
2011 int64_t i64;
2012 fs = get_fpu_register_double(fs_reg);
2013 ft = get_fpu_register_double(ft_reg);
2014 cc = instr->FCccValue();
2015 fcsr_cc = get_fcsr_condition_bit(cc);
Andrei Popescu31002712010-02-23 13:46:05 +00002016 switch (instr->FunctionFieldRaw()) {
Steve Block44f0eee2011-05-26 01:26:41 +01002017 case ADD_D:
2018 set_fpu_register_double(fd_reg, fs + ft);
2019 break;
2020 case SUB_D:
2021 set_fpu_register_double(fd_reg, fs - ft);
2022 break;
2023 case MUL_D:
2024 set_fpu_register_double(fd_reg, fs * ft);
2025 break;
2026 case DIV_D:
2027 set_fpu_register_double(fd_reg, fs / ft);
2028 break;
2029 case ABS_D:
2030 set_fpu_register_double(fd_reg, fs < 0 ? -fs : fs);
2031 break;
2032 case MOV_D:
2033 set_fpu_register_double(fd_reg, fs);
2034 break;
2035 case NEG_D:
2036 set_fpu_register_double(fd_reg, -fs);
2037 break;
2038 case SQRT_D:
2039 set_fpu_register_double(fd_reg, sqrt(fs));
2040 break;
2041 case C_UN_D:
2042 set_fcsr_bit(fcsr_cc, isnan(fs) || isnan(ft));
2043 break;
2044 case C_EQ_D:
2045 set_fcsr_bit(fcsr_cc, (fs == ft));
2046 break;
2047 case C_UEQ_D:
2048 set_fcsr_bit(fcsr_cc, (fs == ft) || (isnan(fs) || isnan(ft)));
2049 break;
2050 case C_OLT_D:
2051 set_fcsr_bit(fcsr_cc, (fs < ft));
2052 break;
2053 case C_ULT_D:
2054 set_fcsr_bit(fcsr_cc, (fs < ft) || (isnan(fs) || isnan(ft)));
2055 break;
2056 case C_OLE_D:
2057 set_fcsr_bit(fcsr_cc, (fs <= ft));
2058 break;
2059 case C_ULE_D:
2060 set_fcsr_bit(fcsr_cc, (fs <= ft) || (isnan(fs) || isnan(ft)));
2061 break;
2062 case CVT_W_D: // Convert double to word.
2063 // Rounding modes are not yet supported.
2064 ASSERT((FCSR_ & 3) == 0);
2065 // In rounding mode 0 it should behave like ROUND.
2066 case ROUND_W_D: // Round double to word.
2067 {
2068 double rounded = fs > 0 ? floor(fs + 0.5) : ceil(fs - 0.5);
2069 int32_t result = static_cast<int32_t>(rounded);
2070 set_fpu_register(fd_reg, result);
2071 if (set_fcsr_round_error(fs, rounded)) {
2072 set_fpu_register(fd_reg, kFPUInvalidResult);
2073 }
2074 }
2075 break;
2076 case TRUNC_W_D: // Truncate double to word (round towards 0).
2077 {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002078 double rounded = trunc(fs);
2079 int32_t result = static_cast<int32_t>(rounded);
Steve Block44f0eee2011-05-26 01:26:41 +01002080 set_fpu_register(fd_reg, result);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002081 if (set_fcsr_round_error(fs, rounded)) {
Steve Block44f0eee2011-05-26 01:26:41 +01002082 set_fpu_register(fd_reg, kFPUInvalidResult);
2083 }
2084 }
2085 break;
2086 case FLOOR_W_D: // Round double to word towards negative infinity.
2087 {
2088 double rounded = floor(fs);
2089 int32_t result = static_cast<int32_t>(rounded);
2090 set_fpu_register(fd_reg, result);
2091 if (set_fcsr_round_error(fs, rounded)) {
2092 set_fpu_register(fd_reg, kFPUInvalidResult);
2093 }
2094 }
2095 break;
2096 case CEIL_W_D: // Round double to word towards positive infinity.
2097 {
2098 double rounded = ceil(fs);
2099 int32_t result = static_cast<int32_t>(rounded);
2100 set_fpu_register(fd_reg, result);
2101 if (set_fcsr_round_error(fs, rounded)) {
2102 set_fpu_register(fd_reg, kFPUInvalidResult);
2103 }
2104 }
2105 break;
2106 case CVT_S_D: // Convert double to float (single).
2107 set_fpu_register_float(fd_reg, static_cast<float>(fs));
2108 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002109 case CVT_L_D: { // Mips32r2: Truncate double to 64-bit long-word.
2110 double rounded = trunc(fs);
2111 i64 = static_cast<int64_t>(rounded);
Steve Block44f0eee2011-05-26 01:26:41 +01002112 set_fpu_register(fd_reg, i64 & 0xffffffff);
2113 set_fpu_register(fd_reg + 1, i64 >> 32);
2114 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002115 }
2116 case TRUNC_L_D: { // Mips32r2 instruction.
2117 double rounded = trunc(fs);
2118 i64 = static_cast<int64_t>(rounded);
Steve Block44f0eee2011-05-26 01:26:41 +01002119 set_fpu_register(fd_reg, i64 & 0xffffffff);
2120 set_fpu_register(fd_reg + 1, i64 >> 32);
2121 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002122 }
Steve Block44f0eee2011-05-26 01:26:41 +01002123 case ROUND_L_D: { // Mips32r2 instruction.
2124 double rounded = fs > 0 ? floor(fs + 0.5) : ceil(fs - 0.5);
2125 i64 = static_cast<int64_t>(rounded);
2126 set_fpu_register(fd_reg, i64 & 0xffffffff);
2127 set_fpu_register(fd_reg + 1, i64 >> 32);
2128 break;
2129 }
2130 case FLOOR_L_D: // Mips32r2 instruction.
2131 i64 = static_cast<int64_t>(floor(fs));
2132 set_fpu_register(fd_reg, i64 & 0xffffffff);
2133 set_fpu_register(fd_reg + 1, i64 >> 32);
2134 break;
2135 case CEIL_L_D: // Mips32r2 instruction.
2136 i64 = static_cast<int64_t>(ceil(fs));
2137 set_fpu_register(fd_reg, i64 & 0xffffffff);
2138 set_fpu_register(fd_reg + 1, i64 >> 32);
2139 break;
2140 case C_F_D:
Andrei Popescu31002712010-02-23 13:46:05 +00002141 UNIMPLEMENTED_MIPS();
2142 break;
2143 default:
2144 UNREACHABLE();
2145 }
2146 break;
2147 case W:
2148 switch (instr->FunctionFieldRaw()) {
Steve Block44f0eee2011-05-26 01:26:41 +01002149 case CVT_S_W: // Convert word to float (single).
2150 alu_out = get_fpu_register(fs_reg);
2151 set_fpu_register_float(fd_reg, static_cast<float>(alu_out));
Andrei Popescu31002712010-02-23 13:46:05 +00002152 break;
2153 case CVT_D_W: // Convert word to double.
Steve Block44f0eee2011-05-26 01:26:41 +01002154 alu_out = get_fpu_register(fs_reg);
2155 set_fpu_register_double(fd_reg, static_cast<double>(alu_out));
Andrei Popescu31002712010-02-23 13:46:05 +00002156 break;
2157 default:
2158 UNREACHABLE();
2159 };
2160 break;
2161 case L:
2162 switch (instr->FunctionFieldRaw()) {
Steve Block44f0eee2011-05-26 01:26:41 +01002163 case CVT_D_L: // Mips32r2 instruction.
2164 // Watch the signs here, we want 2 32-bit vals
2165 // to make a sign-64.
2166 i64 = (uint32_t) get_fpu_register(fs_reg);
2167 i64 |= ((int64_t) get_fpu_register(fs_reg + 1) << 32);
2168 set_fpu_register_double(fd_reg, static_cast<double>(i64));
2169 break;
Andrei Popescu31002712010-02-23 13:46:05 +00002170 case CVT_S_L:
Andrei Popescu31002712010-02-23 13:46:05 +00002171 UNIMPLEMENTED_MIPS();
2172 break;
2173 default:
2174 UNREACHABLE();
2175 }
2176 break;
2177 case PS:
2178 break;
2179 default:
2180 UNREACHABLE();
2181 };
2182 break;
2183 case SPECIAL:
2184 switch (instr->FunctionFieldRaw()) {
2185 case JR: {
2186 Instruction* branch_delay_instr = reinterpret_cast<Instruction*>(
Steve Block44f0eee2011-05-26 01:26:41 +01002187 current_pc+Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +00002188 BranchDelayInstructionDecode(branch_delay_instr);
2189 set_pc(next_pc);
2190 pc_modified_ = true;
2191 break;
2192 }
2193 case JALR: {
2194 Instruction* branch_delay_instr = reinterpret_cast<Instruction*>(
Steve Block44f0eee2011-05-26 01:26:41 +01002195 current_pc+Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +00002196 BranchDelayInstructionDecode(branch_delay_instr);
Ben Murdoch257744e2011-11-30 15:57:28 +00002197 set_register(31, current_pc + 2 * Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +00002198 set_pc(next_pc);
2199 pc_modified_ = true;
2200 break;
2201 }
2202 // Instructions using HI and LO registers.
2203 case MULT:
Steve Block44f0eee2011-05-26 01:26:41 +01002204 set_register(LO, static_cast<int32_t>(i64hilo & 0xffffffff));
2205 set_register(HI, static_cast<int32_t>(i64hilo >> 32));
2206 break;
Andrei Popescu31002712010-02-23 13:46:05 +00002207 case MULTU:
Steve Block44f0eee2011-05-26 01:26:41 +01002208 set_register(LO, static_cast<int32_t>(u64hilo & 0xffffffff));
2209 set_register(HI, static_cast<int32_t>(u64hilo >> 32));
Andrei Popescu31002712010-02-23 13:46:05 +00002210 break;
2211 case DIV:
Ben Murdoch257744e2011-11-30 15:57:28 +00002212 // Divide by zero was not checked in the configuration step - div and
2213 // divu do not raise exceptions. On division by 0, the result will
2214 // be UNPREDICTABLE.
2215 if (rt != 0) {
2216 set_register(LO, rs / rt);
2217 set_register(HI, rs % rt);
2218 }
Andrei Popescu31002712010-02-23 13:46:05 +00002219 break;
2220 case DIVU:
Ben Murdoch257744e2011-11-30 15:57:28 +00002221 if (rt_u != 0) {
2222 set_register(LO, rs_u / rt_u);
2223 set_register(HI, rs_u % rt_u);
2224 }
Andrei Popescu31002712010-02-23 13:46:05 +00002225 break;
Steve Block44f0eee2011-05-26 01:26:41 +01002226 // Break and trap instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00002227 case BREAK:
2228 case TGE:
2229 case TGEU:
2230 case TLT:
2231 case TLTU:
2232 case TEQ:
2233 case TNE:
2234 if (do_interrupt) {
2235 SoftwareInterrupt(instr);
2236 }
2237 break;
Steve Block44f0eee2011-05-26 01:26:41 +01002238 // Conditional moves.
2239 case MOVN:
2240 if (rt) set_register(rd_reg, rs);
2241 break;
2242 case MOVCI: {
Ben Murdoch257744e2011-11-30 15:57:28 +00002243 uint32_t cc = instr->FBccValue();
Steve Block44f0eee2011-05-26 01:26:41 +01002244 uint32_t fcsr_cc = get_fcsr_condition_bit(cc);
Ben Murdoch257744e2011-11-30 15:57:28 +00002245 if (instr->Bit(16)) { // Read Tf bit.
Steve Block44f0eee2011-05-26 01:26:41 +01002246 if (test_fcsr_bit(fcsr_cc)) set_register(rd_reg, rs);
2247 } else {
2248 if (!test_fcsr_bit(fcsr_cc)) set_register(rd_reg, rs);
2249 }
2250 break;
2251 }
2252 case MOVZ:
2253 if (!rt) set_register(rd_reg, rs);
2254 break;
Andrei Popescu31002712010-02-23 13:46:05 +00002255 default: // For other special opcodes we do the default operation.
2256 set_register(rd_reg, alu_out);
2257 };
2258 break;
2259 case SPECIAL2:
2260 switch (instr->FunctionFieldRaw()) {
2261 case MUL:
2262 set_register(rd_reg, alu_out);
2263 // HI and LO are UNPREDICTABLE after the operation.
2264 set_register(LO, Unpredictable);
2265 set_register(HI, Unpredictable);
2266 break;
Steve Block44f0eee2011-05-26 01:26:41 +01002267 default: // For other special2 opcodes we do the default operation.
2268 set_register(rd_reg, alu_out);
2269 }
2270 break;
2271 case SPECIAL3:
2272 switch (instr->FunctionFieldRaw()) {
2273 case INS:
2274 // Ins instr leaves result in Rt, rather than Rd.
2275 set_register(rt_reg, alu_out);
2276 break;
2277 case EXT:
2278 // Ext instr leaves result in Rt, rather than Rd.
2279 set_register(rt_reg, alu_out);
2280 break;
Andrei Popescu31002712010-02-23 13:46:05 +00002281 default:
2282 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +01002283 };
Andrei Popescu31002712010-02-23 13:46:05 +00002284 break;
2285 // Unimplemented opcodes raised an error in the configuration step before,
2286 // so we can use the default here to set the destination register in common
2287 // cases.
2288 default:
2289 set_register(rd_reg, alu_out);
2290 };
2291}
2292
Steve Block44f0eee2011-05-26 01:26:41 +01002293
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002294// Type 2: instructions using a 16 bytes immediate. (e.g. addi, beq).
Andrei Popescu31002712010-02-23 13:46:05 +00002295void Simulator::DecodeTypeImmediate(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +01002296 // Instruction fields.
Andrei Popescu31002712010-02-23 13:46:05 +00002297 Opcode op = instr->OpcodeFieldRaw();
Steve Block44f0eee2011-05-26 01:26:41 +01002298 int32_t rs = get_register(instr->RsValue());
Andrei Popescu31002712010-02-23 13:46:05 +00002299 uint32_t rs_u = static_cast<uint32_t>(rs);
Ben Murdoch257744e2011-11-30 15:57:28 +00002300 int32_t rt_reg = instr->RtValue(); // Destination register.
Andrei Popescu31002712010-02-23 13:46:05 +00002301 int32_t rt = get_register(rt_reg);
Steve Block44f0eee2011-05-26 01:26:41 +01002302 int16_t imm16 = instr->Imm16Value();
Andrei Popescu31002712010-02-23 13:46:05 +00002303
Ben Murdoch257744e2011-11-30 15:57:28 +00002304 int32_t ft_reg = instr->FtValue(); // Destination register.
Andrei Popescu31002712010-02-23 13:46:05 +00002305
Steve Block44f0eee2011-05-26 01:26:41 +01002306 // Zero extended immediate.
Andrei Popescu31002712010-02-23 13:46:05 +00002307 uint32_t oe_imm16 = 0xffff & imm16;
Steve Block44f0eee2011-05-26 01:26:41 +01002308 // Sign extended immediate.
Andrei Popescu31002712010-02-23 13:46:05 +00002309 int32_t se_imm16 = imm16;
2310
2311 // Get current pc.
2312 int32_t current_pc = get_pc();
2313 // Next pc.
2314 int32_t next_pc = bad_ra;
2315
Steve Block44f0eee2011-05-26 01:26:41 +01002316 // Used for conditional branch instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00002317 bool do_branch = false;
2318 bool execute_branch_delay_instruction = false;
2319
Steve Block44f0eee2011-05-26 01:26:41 +01002320 // Used for arithmetic instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00002321 int32_t alu_out = 0;
Steve Block44f0eee2011-05-26 01:26:41 +01002322 // Floating point.
Andrei Popescu31002712010-02-23 13:46:05 +00002323 double fp_out = 0.0;
Steve Block44f0eee2011-05-26 01:26:41 +01002324 uint32_t cc, cc_value, fcsr_cc;
Andrei Popescu31002712010-02-23 13:46:05 +00002325
Steve Block44f0eee2011-05-26 01:26:41 +01002326 // Used for memory instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00002327 int32_t addr = 0x0;
Ben Murdoch257744e2011-11-30 15:57:28 +00002328 // Value to be written in memory.
Steve Block44f0eee2011-05-26 01:26:41 +01002329 uint32_t mem_value = 0x0;
Andrei Popescu31002712010-02-23 13:46:05 +00002330
Ben Murdoch257744e2011-11-30 15:57:28 +00002331 // ---------- Configuration (and execution for REGIMM).
Andrei Popescu31002712010-02-23 13:46:05 +00002332 switch (op) {
Steve Block44f0eee2011-05-26 01:26:41 +01002333 // ------------- COP1. Coprocessor instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00002334 case COP1:
2335 switch (instr->RsFieldRaw()) {
Steve Block44f0eee2011-05-26 01:26:41 +01002336 case BC1: // Branch on coprocessor condition.
2337 cc = instr->FBccValue();
2338 fcsr_cc = get_fcsr_condition_bit(cc);
2339 cc_value = test_fcsr_bit(fcsr_cc);
2340 do_branch = (instr->FBtrueValue()) ? cc_value : !cc_value;
2341 execute_branch_delay_instruction = true;
Ben Murdoch257744e2011-11-30 15:57:28 +00002342 // Set next_pc.
Steve Block44f0eee2011-05-26 01:26:41 +01002343 if (do_branch) {
2344 next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
2345 } else {
2346 next_pc = current_pc + kBranchReturnOffset;
2347 }
Andrei Popescu31002712010-02-23 13:46:05 +00002348 break;
2349 default:
2350 UNREACHABLE();
2351 };
2352 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00002353 // ------------- REGIMM class.
Andrei Popescu31002712010-02-23 13:46:05 +00002354 case REGIMM:
2355 switch (instr->RtFieldRaw()) {
2356 case BLTZ:
2357 do_branch = (rs < 0);
2358 break;
2359 case BLTZAL:
2360 do_branch = rs < 0;
2361 break;
2362 case BGEZ:
2363 do_branch = rs >= 0;
2364 break;
2365 case BGEZAL:
2366 do_branch = rs >= 0;
2367 break;
2368 default:
2369 UNREACHABLE();
2370 };
2371 switch (instr->RtFieldRaw()) {
2372 case BLTZ:
2373 case BLTZAL:
2374 case BGEZ:
2375 case BGEZAL:
2376 // Branch instructions common part.
2377 execute_branch_delay_instruction = true;
Ben Murdoch257744e2011-11-30 15:57:28 +00002378 // Set next_pc.
Andrei Popescu31002712010-02-23 13:46:05 +00002379 if (do_branch) {
Steve Block44f0eee2011-05-26 01:26:41 +01002380 next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
Andrei Popescu31002712010-02-23 13:46:05 +00002381 if (instr->IsLinkingInstruction()) {
2382 set_register(31, current_pc + kBranchReturnOffset);
2383 }
2384 } else {
2385 next_pc = current_pc + kBranchReturnOffset;
2386 }
2387 default:
2388 break;
2389 };
Ben Murdoch257744e2011-11-30 15:57:28 +00002390 break; // case REGIMM.
2391 // ------------- Branch instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00002392 // When comparing to zero, the encoding of rt field is always 0, so we don't
2393 // need to replace rt with zero.
2394 case BEQ:
2395 do_branch = (rs == rt);
2396 break;
2397 case BNE:
2398 do_branch = rs != rt;
2399 break;
2400 case BLEZ:
2401 do_branch = rs <= 0;
2402 break;
2403 case BGTZ:
2404 do_branch = rs > 0;
2405 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00002406 // ------------- Arithmetic instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00002407 case ADDI:
2408 if (HaveSameSign(rs, se_imm16)) {
2409 if (rs > 0) {
2410 exceptions[kIntegerOverflow] = rs > (Registers::kMaxValue - se_imm16);
2411 } else if (rs < 0) {
2412 exceptions[kIntegerUnderflow] =
2413 rs < (Registers::kMinValue - se_imm16);
2414 }
2415 }
2416 alu_out = rs + se_imm16;
2417 break;
2418 case ADDIU:
2419 alu_out = rs + se_imm16;
2420 break;
2421 case SLTI:
2422 alu_out = (rs < se_imm16) ? 1 : 0;
2423 break;
2424 case SLTIU:
2425 alu_out = (rs_u < static_cast<uint32_t>(se_imm16)) ? 1 : 0;
2426 break;
2427 case ANDI:
2428 alu_out = rs & oe_imm16;
2429 break;
2430 case ORI:
2431 alu_out = rs | oe_imm16;
2432 break;
2433 case XORI:
2434 alu_out = rs ^ oe_imm16;
2435 break;
2436 case LUI:
2437 alu_out = (oe_imm16 << 16);
2438 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00002439 // ------------- Memory instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00002440 case LB:
2441 addr = rs + se_imm16;
2442 alu_out = ReadB(addr);
2443 break;
Steve Block44f0eee2011-05-26 01:26:41 +01002444 case LH:
2445 addr = rs + se_imm16;
2446 alu_out = ReadH(addr, instr);
2447 break;
2448 case LWL: {
Ben Murdoch257744e2011-11-30 15:57:28 +00002449 // al_offset is offset of the effective address within an aligned word.
Steve Block44f0eee2011-05-26 01:26:41 +01002450 uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
2451 uint8_t byte_shift = kPointerAlignmentMask - al_offset;
2452 uint32_t mask = (1 << byte_shift * 8) - 1;
2453 addr = rs + se_imm16 - al_offset;
2454 alu_out = ReadW(addr, instr);
2455 alu_out <<= byte_shift * 8;
2456 alu_out |= rt & mask;
2457 break;
2458 }
Andrei Popescu31002712010-02-23 13:46:05 +00002459 case LW:
2460 addr = rs + se_imm16;
2461 alu_out = ReadW(addr, instr);
2462 break;
2463 case LBU:
2464 addr = rs + se_imm16;
2465 alu_out = ReadBU(addr);
2466 break;
Steve Block44f0eee2011-05-26 01:26:41 +01002467 case LHU:
2468 addr = rs + se_imm16;
2469 alu_out = ReadHU(addr, instr);
2470 break;
2471 case LWR: {
Ben Murdoch257744e2011-11-30 15:57:28 +00002472 // al_offset is offset of the effective address within an aligned word.
Steve Block44f0eee2011-05-26 01:26:41 +01002473 uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
2474 uint8_t byte_shift = kPointerAlignmentMask - al_offset;
2475 uint32_t mask = al_offset ? (~0 << (byte_shift + 1) * 8) : 0;
2476 addr = rs + se_imm16 - al_offset;
2477 alu_out = ReadW(addr, instr);
2478 alu_out = static_cast<uint32_t> (alu_out) >> al_offset * 8;
2479 alu_out |= rt & mask;
2480 break;
2481 }
Andrei Popescu31002712010-02-23 13:46:05 +00002482 case SB:
2483 addr = rs + se_imm16;
2484 break;
Steve Block44f0eee2011-05-26 01:26:41 +01002485 case SH:
2486 addr = rs + se_imm16;
2487 break;
2488 case SWL: {
2489 uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
2490 uint8_t byte_shift = kPointerAlignmentMask - al_offset;
2491 uint32_t mask = byte_shift ? (~0 << (al_offset + 1) * 8) : 0;
2492 addr = rs + se_imm16 - al_offset;
2493 mem_value = ReadW(addr, instr) & mask;
2494 mem_value |= static_cast<uint32_t>(rt) >> byte_shift * 8;
2495 break;
2496 }
Andrei Popescu31002712010-02-23 13:46:05 +00002497 case SW:
2498 addr = rs + se_imm16;
2499 break;
Steve Block44f0eee2011-05-26 01:26:41 +01002500 case SWR: {
2501 uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
2502 uint32_t mask = (1 << al_offset * 8) - 1;
2503 addr = rs + se_imm16 - al_offset;
2504 mem_value = ReadW(addr, instr);
2505 mem_value = (rt << al_offset * 8) | (mem_value & mask);
2506 break;
2507 }
Andrei Popescu31002712010-02-23 13:46:05 +00002508 case LWC1:
2509 addr = rs + se_imm16;
2510 alu_out = ReadW(addr, instr);
2511 break;
2512 case LDC1:
2513 addr = rs + se_imm16;
2514 fp_out = ReadD(addr, instr);
2515 break;
2516 case SWC1:
2517 case SDC1:
2518 addr = rs + se_imm16;
2519 break;
2520 default:
2521 UNREACHABLE();
2522 };
2523
2524 // ---------- Raise exceptions triggered.
2525 SignalExceptions();
2526
Ben Murdoch257744e2011-11-30 15:57:28 +00002527 // ---------- Execution.
Andrei Popescu31002712010-02-23 13:46:05 +00002528 switch (op) {
Ben Murdoch257744e2011-11-30 15:57:28 +00002529 // ------------- Branch instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00002530 case BEQ:
2531 case BNE:
2532 case BLEZ:
2533 case BGTZ:
2534 // Branch instructions common part.
2535 execute_branch_delay_instruction = true;
Ben Murdoch257744e2011-11-30 15:57:28 +00002536 // Set next_pc.
Andrei Popescu31002712010-02-23 13:46:05 +00002537 if (do_branch) {
Steve Block44f0eee2011-05-26 01:26:41 +01002538 next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
Andrei Popescu31002712010-02-23 13:46:05 +00002539 if (instr->IsLinkingInstruction()) {
Steve Block44f0eee2011-05-26 01:26:41 +01002540 set_register(31, current_pc + 2* Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +00002541 }
2542 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01002543 next_pc = current_pc + 2 * Instruction::kInstrSize;
Andrei Popescu31002712010-02-23 13:46:05 +00002544 }
2545 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00002546 // ------------- Arithmetic instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00002547 case ADDI:
2548 case ADDIU:
2549 case SLTI:
2550 case SLTIU:
2551 case ANDI:
2552 case ORI:
2553 case XORI:
2554 case LUI:
2555 set_register(rt_reg, alu_out);
2556 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00002557 // ------------- Memory instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00002558 case LB:
Steve Block44f0eee2011-05-26 01:26:41 +01002559 case LH:
2560 case LWL:
Andrei Popescu31002712010-02-23 13:46:05 +00002561 case LW:
2562 case LBU:
Steve Block44f0eee2011-05-26 01:26:41 +01002563 case LHU:
2564 case LWR:
Andrei Popescu31002712010-02-23 13:46:05 +00002565 set_register(rt_reg, alu_out);
2566 break;
2567 case SB:
2568 WriteB(addr, static_cast<int8_t>(rt));
2569 break;
Steve Block44f0eee2011-05-26 01:26:41 +01002570 case SH:
2571 WriteH(addr, static_cast<uint16_t>(rt), instr);
2572 break;
2573 case SWL:
2574 WriteW(addr, mem_value, instr);
2575 break;
Andrei Popescu31002712010-02-23 13:46:05 +00002576 case SW:
2577 WriteW(addr, rt, instr);
2578 break;
Steve Block44f0eee2011-05-26 01:26:41 +01002579 case SWR:
2580 WriteW(addr, mem_value, instr);
2581 break;
Andrei Popescu31002712010-02-23 13:46:05 +00002582 case LWC1:
2583 set_fpu_register(ft_reg, alu_out);
2584 break;
2585 case LDC1:
2586 set_fpu_register_double(ft_reg, fp_out);
2587 break;
2588 case SWC1:
2589 addr = rs + se_imm16;
2590 WriteW(addr, get_fpu_register(ft_reg), instr);
2591 break;
2592 case SDC1:
2593 addr = rs + se_imm16;
Steve Block44f0eee2011-05-26 01:26:41 +01002594 WriteD(addr, get_fpu_register_double(ft_reg), instr);
Andrei Popescu31002712010-02-23 13:46:05 +00002595 break;
2596 default:
2597 break;
2598 };
2599
2600
2601 if (execute_branch_delay_instruction) {
2602 // Execute branch delay slot
2603 // We don't check for end_sim_pc. First it should not be met as the current
2604 // pc is valid. Secondly a jump should always execute its branch delay slot.
2605 Instruction* branch_delay_instr =
Steve Block44f0eee2011-05-26 01:26:41 +01002606 reinterpret_cast<Instruction*>(current_pc+Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +00002607 BranchDelayInstructionDecode(branch_delay_instr);
2608 }
2609
2610 // If needed update pc after the branch delay execution.
2611 if (next_pc != bad_ra) {
2612 set_pc(next_pc);
2613 }
2614}
2615
Steve Block44f0eee2011-05-26 01:26:41 +01002616
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002617// Type 3: instructions using a 26 bytes immediate. (e.g. j, jal).
Andrei Popescu31002712010-02-23 13:46:05 +00002618void Simulator::DecodeTypeJump(Instruction* instr) {
2619 // Get current pc.
2620 int32_t current_pc = get_pc();
2621 // Get unchanged bits of pc.
2622 int32_t pc_high_bits = current_pc & 0xf0000000;
Ben Murdoch257744e2011-11-30 15:57:28 +00002623 // Next pc.
Steve Block44f0eee2011-05-26 01:26:41 +01002624 int32_t next_pc = pc_high_bits | (instr->Imm26Value() << 2);
Andrei Popescu31002712010-02-23 13:46:05 +00002625
Ben Murdoch257744e2011-11-30 15:57:28 +00002626 // Execute branch delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00002627 // We don't check for end_sim_pc. First it should not be met as the current pc
2628 // is valid. Secondly a jump should always execute its branch delay slot.
2629 Instruction* branch_delay_instr =
Ben Murdoch257744e2011-11-30 15:57:28 +00002630 reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +00002631 BranchDelayInstructionDecode(branch_delay_instr);
2632
2633 // Update pc and ra if necessary.
2634 // Do this after the branch delay execution.
2635 if (instr->IsLinkingInstruction()) {
Ben Murdoch257744e2011-11-30 15:57:28 +00002636 set_register(31, current_pc + 2 * Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +00002637 }
2638 set_pc(next_pc);
2639 pc_modified_ = true;
2640}
2641
Steve Block44f0eee2011-05-26 01:26:41 +01002642
Andrei Popescu31002712010-02-23 13:46:05 +00002643// Executes the current instruction.
2644void Simulator::InstructionDecode(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +01002645 if (v8::internal::FLAG_check_icache) {
2646 CheckICache(isolate_->simulator_i_cache(), instr);
2647 }
Andrei Popescu31002712010-02-23 13:46:05 +00002648 pc_modified_ = false;
2649 if (::v8::internal::FLAG_trace_sim) {
2650 disasm::NameConverter converter;
2651 disasm::Disassembler dasm(converter);
Ben Murdoch257744e2011-11-30 15:57:28 +00002652 // Use a reasonably large buffer.
Andrei Popescu31002712010-02-23 13:46:05 +00002653 v8::internal::EmbeddedVector<char, 256> buffer;
Ben Murdoch257744e2011-11-30 15:57:28 +00002654 dasm.InstructionDecode(buffer, reinterpret_cast<byte*>(instr));
Steve Block44f0eee2011-05-26 01:26:41 +01002655 PrintF(" 0x%08x %s\n", reinterpret_cast<intptr_t>(instr),
Ben Murdoch257744e2011-11-30 15:57:28 +00002656 buffer.start());
Andrei Popescu31002712010-02-23 13:46:05 +00002657 }
2658
2659 switch (instr->InstructionType()) {
2660 case Instruction::kRegisterType:
2661 DecodeTypeRegister(instr);
2662 break;
2663 case Instruction::kImmediateType:
2664 DecodeTypeImmediate(instr);
2665 break;
2666 case Instruction::kJumpType:
2667 DecodeTypeJump(instr);
2668 break;
2669 default:
2670 UNSUPPORTED();
2671 }
2672 if (!pc_modified_) {
2673 set_register(pc, reinterpret_cast<int32_t>(instr) +
Steve Block44f0eee2011-05-26 01:26:41 +01002674 Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +00002675 }
2676}
2677
2678
2679
2680void Simulator::Execute() {
2681 // Get the PC to simulate. Cannot use the accessor here as we need the
2682 // raw PC value and not the one used as input to arithmetic instructions.
2683 int program_counter = get_pc();
2684 if (::v8::internal::FLAG_stop_sim_at == 0) {
2685 // Fast version of the dispatch loop without checking whether the simulator
2686 // should be stopping at a particular executed instruction.
2687 while (program_counter != end_sim_pc) {
2688 Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
2689 icount_++;
2690 InstructionDecode(instr);
2691 program_counter = get_pc();
2692 }
2693 } else {
2694 // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when
2695 // we reach the particular instuction count.
2696 while (program_counter != end_sim_pc) {
2697 Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
2698 icount_++;
2699 if (icount_ == ::v8::internal::FLAG_stop_sim_at) {
Steve Block44f0eee2011-05-26 01:26:41 +01002700 MipsDebugger dbg(this);
Andrei Popescu31002712010-02-23 13:46:05 +00002701 dbg.Debug();
2702 } else {
2703 InstructionDecode(instr);
2704 }
2705 program_counter = get_pc();
2706 }
2707 }
2708}
2709
2710
Ben Murdoch257744e2011-11-30 15:57:28 +00002711int32_t Simulator::Call(byte* entry, int argument_count, ...) {
Andrei Popescu31002712010-02-23 13:46:05 +00002712 va_list parameters;
2713 va_start(parameters, argument_count);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002714 // Set up arguments.
Andrei Popescu31002712010-02-23 13:46:05 +00002715
2716 // First four arguments passed in registers.
2717 ASSERT(argument_count >= 4);
2718 set_register(a0, va_arg(parameters, int32_t));
2719 set_register(a1, va_arg(parameters, int32_t));
2720 set_register(a2, va_arg(parameters, int32_t));
2721 set_register(a3, va_arg(parameters, int32_t));
2722
2723 // Remaining arguments passed on stack.
2724 int original_stack = get_register(sp);
2725 // Compute position of stack on entry to generated code.
2726 int entry_stack = (original_stack - (argument_count - 4) * sizeof(int32_t)
Steve Block44f0eee2011-05-26 01:26:41 +01002727 - kCArgsSlotsSize);
Andrei Popescu31002712010-02-23 13:46:05 +00002728 if (OS::ActivationFrameAlignment() != 0) {
2729 entry_stack &= -OS::ActivationFrameAlignment();
2730 }
2731 // Store remaining arguments on stack, from low to high memory.
2732 intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
2733 for (int i = 4; i < argument_count; i++) {
Ben Murdoch589d6972011-11-30 16:04:58 +00002734 stack_argument[i - 4 + kCArgSlotCount] = va_arg(parameters, int32_t);
Andrei Popescu31002712010-02-23 13:46:05 +00002735 }
2736 va_end(parameters);
2737 set_register(sp, entry_stack);
2738
Ben Murdoch257744e2011-11-30 15:57:28 +00002739 // Prepare to execute the code at entry.
Andrei Popescu31002712010-02-23 13:46:05 +00002740 set_register(pc, reinterpret_cast<int32_t>(entry));
2741 // Put down marker for end of simulation. The simulator will stop simulation
2742 // when the PC reaches this value. By saving the "end simulation" value into
2743 // the LR the simulation stops when returning to this call point.
2744 set_register(ra, end_sim_pc);
2745
2746 // Remember the values of callee-saved registers.
2747 // The code below assumes that r9 is not used as sb (static base) in
2748 // simulator code and therefore is regarded as a callee-saved register.
2749 int32_t s0_val = get_register(s0);
2750 int32_t s1_val = get_register(s1);
2751 int32_t s2_val = get_register(s2);
2752 int32_t s3_val = get_register(s3);
2753 int32_t s4_val = get_register(s4);
2754 int32_t s5_val = get_register(s5);
2755 int32_t s6_val = get_register(s6);
2756 int32_t s7_val = get_register(s7);
2757 int32_t gp_val = get_register(gp);
2758 int32_t sp_val = get_register(sp);
2759 int32_t fp_val = get_register(fp);
2760
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002761 // Set up the callee-saved registers with a known value. To be able to check
Andrei Popescu31002712010-02-23 13:46:05 +00002762 // that they are preserved properly across JS execution.
2763 int32_t callee_saved_value = icount_;
2764 set_register(s0, callee_saved_value);
2765 set_register(s1, callee_saved_value);
2766 set_register(s2, callee_saved_value);
2767 set_register(s3, callee_saved_value);
2768 set_register(s4, callee_saved_value);
2769 set_register(s5, callee_saved_value);
2770 set_register(s6, callee_saved_value);
2771 set_register(s7, callee_saved_value);
2772 set_register(gp, callee_saved_value);
2773 set_register(fp, callee_saved_value);
2774
Ben Murdoch257744e2011-11-30 15:57:28 +00002775 // Start the simulation.
Andrei Popescu31002712010-02-23 13:46:05 +00002776 Execute();
2777
2778 // Check that the callee-saved registers have been preserved.
2779 CHECK_EQ(callee_saved_value, get_register(s0));
2780 CHECK_EQ(callee_saved_value, get_register(s1));
2781 CHECK_EQ(callee_saved_value, get_register(s2));
2782 CHECK_EQ(callee_saved_value, get_register(s3));
2783 CHECK_EQ(callee_saved_value, get_register(s4));
2784 CHECK_EQ(callee_saved_value, get_register(s5));
2785 CHECK_EQ(callee_saved_value, get_register(s6));
2786 CHECK_EQ(callee_saved_value, get_register(s7));
2787 CHECK_EQ(callee_saved_value, get_register(gp));
2788 CHECK_EQ(callee_saved_value, get_register(fp));
2789
2790 // Restore callee-saved registers with the original value.
2791 set_register(s0, s0_val);
2792 set_register(s1, s1_val);
2793 set_register(s2, s2_val);
2794 set_register(s3, s3_val);
2795 set_register(s4, s4_val);
2796 set_register(s5, s5_val);
2797 set_register(s6, s6_val);
2798 set_register(s7, s7_val);
2799 set_register(gp, gp_val);
2800 set_register(sp, sp_val);
2801 set_register(fp, fp_val);
2802
2803 // Pop stack passed arguments.
2804 CHECK_EQ(entry_stack, get_register(sp));
2805 set_register(sp, original_stack);
2806
2807 int32_t result = get_register(v0);
2808 return result;
2809}
2810
2811
2812uintptr_t Simulator::PushAddress(uintptr_t address) {
2813 int new_sp = get_register(sp) - sizeof(uintptr_t);
2814 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp);
2815 *stack_slot = address;
2816 set_register(sp, new_sp);
2817 return new_sp;
2818}
2819
2820
2821uintptr_t Simulator::PopAddress() {
2822 int current_sp = get_register(sp);
2823 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp);
2824 uintptr_t address = *stack_slot;
2825 set_register(sp, current_sp + sizeof(uintptr_t));
2826 return address;
2827}
2828
2829
2830#undef UNSUPPORTED
2831
Steve Block44f0eee2011-05-26 01:26:41 +01002832} } // namespace v8::internal
Andrei Popescu31002712010-02-23 13:46:05 +00002833
Steve Block44f0eee2011-05-26 01:26:41 +01002834#endif // USE_SIMULATOR
Andrei Popescu31002712010-02-23 13:46:05 +00002835
Leon Clarkef7060e22010-06-03 12:02:55 +01002836#endif // V8_TARGET_ARCH_MIPS