blob: fabca67062fab264b5c9dff0192c308c18e67b9f [file] [log] [blame]
Ben Murdoch257744e2011-11-30 15:57:28 +00001// Copyright 2011 the V8 project authors. All rights reserved.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
Andrei Popescu31002712010-02-23 13:46:05 +00004
Steve Block44f0eee2011-05-26 01:26:41 +01005#include <limits.h>
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006#include <stdarg.h>
7#include <stdlib.h>
8#include <cmath>
Andrei Popescu31002712010-02-23 13:46:05 +00009
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010#include "src/v8.h"
Leon Clarkef7060e22010-06-03 12:02:55 +010011
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012#if V8_TARGET_ARCH_MIPS
13
14#include "src/assembler.h"
15#include "src/base/bits.h"
16#include "src/disasm.h"
17#include "src/mips/constants-mips.h"
18#include "src/mips/simulator-mips.h"
19#include "src/ostreams.h"
Andrei Popescu31002712010-02-23 13:46:05 +000020
Andrei Popescu31002712010-02-23 13:46:05 +000021
22// Only build the simulator if not compiling for real MIPS hardware.
Steve Block44f0eee2011-05-26 01:26:41 +010023#if defined(USE_SIMULATOR)
Andrei Popescu31002712010-02-23 13:46:05 +000024
Steve Block44f0eee2011-05-26 01:26:41 +010025namespace v8 {
26namespace internal {
Andrei Popescu31002712010-02-23 13:46:05 +000027
Ben Murdoch257744e2011-11-30 15:57:28 +000028// Utils functions.
Andrei Popescu31002712010-02-23 13:46:05 +000029bool HaveSameSign(int32_t a, int32_t b) {
Steve Block44f0eee2011-05-26 01:26:41 +010030 return ((a ^ b) >= 0);
31}
32
33
34uint32_t get_fcsr_condition_bit(uint32_t cc) {
35 if (cc == 0) {
36 return 23;
37 } else {
38 return 24 + cc;
39 }
Andrei Popescu31002712010-02-23 13:46:05 +000040}
41
42
43// This macro provides a platform independent use of sscanf. The reason for
44// SScanF not being implemented in a platform independent was through
45// ::v8::internal::OS in the same way as SNPrintF is that the Windows C Run-Time
46// Library does not provide vsscanf.
47#define SScanF sscanf // NOLINT
48
Steve Block44f0eee2011-05-26 01:26:41 +010049// The MipsDebugger class is used by the simulator while debugging simulated
Andrei Popescu31002712010-02-23 13:46:05 +000050// code.
Steve Block44f0eee2011-05-26 01:26:41 +010051class MipsDebugger {
Andrei Popescu31002712010-02-23 13:46:05 +000052 public:
Ben Murdoch3ef787d2012-04-12 10:51:47 +010053 explicit MipsDebugger(Simulator* sim) : sim_(sim) { }
Steve Block44f0eee2011-05-26 01:26:41 +010054 ~MipsDebugger();
Andrei Popescu31002712010-02-23 13:46:05 +000055
56 void Stop(Instruction* instr);
57 void Debug();
Steve Block44f0eee2011-05-26 01:26:41 +010058 // Print all registers with a nice formatting.
59 void PrintAllRegs();
60 void PrintAllRegsIncludingFPU();
Andrei Popescu31002712010-02-23 13:46:05 +000061
62 private:
63 // We set the breakpoint code to 0xfffff to easily recognize it.
64 static const Instr kBreakpointInstr = SPECIAL | BREAK | 0xfffff << 6;
65 static const Instr kNopInstr = 0x0;
66
67 Simulator* sim_;
68
69 int32_t GetRegisterValue(int regnum);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000070 int32_t GetFPURegisterValue32(int regnum);
71 int64_t GetFPURegisterValue64(int regnum);
Steve Block44f0eee2011-05-26 01:26:41 +010072 float GetFPURegisterValueFloat(int regnum);
73 double GetFPURegisterValueDouble(int regnum);
Andrei Popescu31002712010-02-23 13:46:05 +000074 bool GetValue(const char* desc, int32_t* value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000075 bool GetValue(const char* desc, int64_t* value);
Andrei Popescu31002712010-02-23 13:46:05 +000076
77 // Set or delete a breakpoint. Returns true if successful.
78 bool SetBreakpoint(Instruction* breakpc);
79 bool DeleteBreakpoint(Instruction* breakpc);
80
81 // Undo and redo all breakpoints. This is needed to bracket disassembly and
82 // execution to skip past breakpoints when run from the debugger.
83 void UndoBreakpoints();
84 void RedoBreakpoints();
Andrei Popescu31002712010-02-23 13:46:05 +000085};
86
Steve Block44f0eee2011-05-26 01:26:41 +010087
88MipsDebugger::~MipsDebugger() {
Andrei Popescu31002712010-02-23 13:46:05 +000089}
90
Steve Block44f0eee2011-05-26 01:26:41 +010091
Andrei Popescu31002712010-02-23 13:46:05 +000092#ifdef GENERATED_CODE_COVERAGE
93static FILE* coverage_log = NULL;
94
95
96static void InitializeCoverage() {
97 char* file_name = getenv("V8_GENERATED_CODE_COVERAGE_LOG");
98 if (file_name != NULL) {
99 coverage_log = fopen(file_name, "aw+");
100 }
101}
102
103
Steve Block44f0eee2011-05-26 01:26:41 +0100104void MipsDebugger::Stop(Instruction* instr) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000105 // Get the stop code.
106 uint32_t code = instr->Bits(25, 6);
107 // Retrieve the encoded address, which comes just after this stop.
108 char** msg_address =
109 reinterpret_cast<char**>(sim_->get_pc() + Instr::kInstrSize);
110 char* msg = *msg_address;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000111 DCHECK(msg != NULL);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000112
113 // Update this stop description.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000114 if (!watched_stops_[code].desc) {
115 watched_stops_[code].desc = msg;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000116 }
117
118 if (strlen(msg) > 0) {
Andrei Popescu31002712010-02-23 13:46:05 +0000119 if (coverage_log != NULL) {
120 fprintf(coverage_log, "%s\n", str);
121 fflush(coverage_log);
122 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000123 // Overwrite the instruction and address with nops.
124 instr->SetInstructionBits(kNopInstr);
125 reinterpret_cast<Instr*>(msg_address)->SetInstructionBits(kNopInstr);
Andrei Popescu31002712010-02-23 13:46:05 +0000126 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000127 sim_->set_pc(sim_->get_pc() + 2 * Instruction::kInstructionSize);
Andrei Popescu31002712010-02-23 13:46:05 +0000128}
129
Steve Block44f0eee2011-05-26 01:26:41 +0100130
Ben Murdoch257744e2011-11-30 15:57:28 +0000131#else // GENERATED_CODE_COVERAGE
Andrei Popescu31002712010-02-23 13:46:05 +0000132
133#define UNSUPPORTED() printf("Unsupported instruction.\n");
134
135static void InitializeCoverage() {}
136
137
Steve Block44f0eee2011-05-26 01:26:41 +0100138void MipsDebugger::Stop(Instruction* instr) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000139 // Get the stop code.
140 uint32_t code = instr->Bits(25, 6);
141 // Retrieve the encoded address, which comes just after this stop.
142 char* msg = *reinterpret_cast<char**>(sim_->get_pc() +
143 Instruction::kInstrSize);
144 // Update this stop description.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000145 if (!sim_->watched_stops_[code].desc) {
146 sim_->watched_stops_[code].desc = msg;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000147 }
148 PrintF("Simulator hit %s (%u)\n", msg, code);
149 sim_->set_pc(sim_->get_pc() + 2 * Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +0000150 Debug();
151}
Steve Block6ded16b2010-05-10 14:33:55 +0100152#endif // GENERATED_CODE_COVERAGE
Andrei Popescu31002712010-02-23 13:46:05 +0000153
154
Steve Block44f0eee2011-05-26 01:26:41 +0100155int32_t MipsDebugger::GetRegisterValue(int regnum) {
Andrei Popescu31002712010-02-23 13:46:05 +0000156 if (regnum == kNumSimuRegisters) {
157 return sim_->get_pc();
158 } else {
159 return sim_->get_register(regnum);
160 }
161}
162
163
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000164int32_t MipsDebugger::GetFPURegisterValue32(int regnum) {
Steve Block44f0eee2011-05-26 01:26:41 +0100165 if (regnum == kNumFPURegisters) {
166 return sim_->get_pc();
167 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000168 return sim_->get_fpu_register_word(regnum);
Steve Block44f0eee2011-05-26 01:26:41 +0100169 }
170}
171
172
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000173int64_t MipsDebugger::GetFPURegisterValue64(int regnum) {
Steve Block44f0eee2011-05-26 01:26:41 +0100174 if (regnum == kNumFPURegisters) {
175 return sim_->get_pc();
176 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000177 return sim_->get_fpu_register(regnum);
Steve Block44f0eee2011-05-26 01:26:41 +0100178 }
179}
180
181
182float MipsDebugger::GetFPURegisterValueFloat(int regnum) {
183 if (regnum == kNumFPURegisters) {
184 return sim_->get_pc();
185 } else {
186 return sim_->get_fpu_register_float(regnum);
187 }
188}
189
190
191double MipsDebugger::GetFPURegisterValueDouble(int regnum) {
192 if (regnum == kNumFPURegisters) {
193 return sim_->get_pc();
194 } else {
195 return sim_->get_fpu_register_double(regnum);
196 }
197}
198
199
200bool MipsDebugger::GetValue(const char* desc, int32_t* value) {
Andrei Popescu31002712010-02-23 13:46:05 +0000201 int regnum = Registers::Number(desc);
Steve Block44f0eee2011-05-26 01:26:41 +0100202 int fpuregnum = FPURegisters::Number(desc);
203
Andrei Popescu31002712010-02-23 13:46:05 +0000204 if (regnum != kInvalidRegister) {
205 *value = GetRegisterValue(regnum);
206 return true;
Steve Block44f0eee2011-05-26 01:26:41 +0100207 } else if (fpuregnum != kInvalidFPURegister) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000208 *value = GetFPURegisterValue32(fpuregnum);
Steve Block44f0eee2011-05-26 01:26:41 +0100209 return true;
210 } else if (strncmp(desc, "0x", 2) == 0) {
211 return SScanF(desc, "%x", reinterpret_cast<uint32_t*>(value)) == 1;
Andrei Popescu31002712010-02-23 13:46:05 +0000212 } else {
213 return SScanF(desc, "%i", value) == 1;
214 }
215 return false;
216}
217
218
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000219bool MipsDebugger::GetValue(const char* desc, int64_t* value) {
220 int regnum = Registers::Number(desc);
221 int fpuregnum = FPURegisters::Number(desc);
222
223 if (regnum != kInvalidRegister) {
224 *value = GetRegisterValue(regnum);
225 return true;
226 } else if (fpuregnum != kInvalidFPURegister) {
227 *value = GetFPURegisterValue64(fpuregnum);
228 return true;
229 } else if (strncmp(desc, "0x", 2) == 0) {
230 return SScanF(desc + 2, "%" SCNx64,
231 reinterpret_cast<uint64_t*>(value)) == 1;
232 } else {
233 return SScanF(desc, "%" SCNu64, reinterpret_cast<uint64_t*>(value)) == 1;
234 }
235 return false;
236}
237
238
Steve Block44f0eee2011-05-26 01:26:41 +0100239bool MipsDebugger::SetBreakpoint(Instruction* breakpc) {
Andrei Popescu31002712010-02-23 13:46:05 +0000240 // Check if a breakpoint can be set. If not return without any side-effects.
241 if (sim_->break_pc_ != NULL) {
242 return false;
243 }
244
245 // Set the breakpoint.
246 sim_->break_pc_ = breakpc;
247 sim_->break_instr_ = breakpc->InstructionBits();
248 // Not setting the breakpoint instruction in the code itself. It will be set
249 // when the debugger shell continues.
250 return true;
251}
252
253
Steve Block44f0eee2011-05-26 01:26:41 +0100254bool MipsDebugger::DeleteBreakpoint(Instruction* breakpc) {
Andrei Popescu31002712010-02-23 13:46:05 +0000255 if (sim_->break_pc_ != NULL) {
256 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
257 }
258
259 sim_->break_pc_ = NULL;
260 sim_->break_instr_ = 0;
261 return true;
262}
263
264
Steve Block44f0eee2011-05-26 01:26:41 +0100265void MipsDebugger::UndoBreakpoints() {
Andrei Popescu31002712010-02-23 13:46:05 +0000266 if (sim_->break_pc_ != NULL) {
267 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
268 }
269}
270
271
Steve Block44f0eee2011-05-26 01:26:41 +0100272void MipsDebugger::RedoBreakpoints() {
Andrei Popescu31002712010-02-23 13:46:05 +0000273 if (sim_->break_pc_ != NULL) {
274 sim_->break_pc_->SetInstructionBits(kBreakpointInstr);
275 }
276}
277
Steve Block44f0eee2011-05-26 01:26:41 +0100278
279void MipsDebugger::PrintAllRegs() {
Andrei Popescu31002712010-02-23 13:46:05 +0000280#define REG_INFO(n) Registers::Name(n), GetRegisterValue(n), GetRegisterValue(n)
281
282 PrintF("\n");
Ben Murdoch257744e2011-11-30 15:57:28 +0000283 // at, v0, a0.
Andrei Popescu31002712010-02-23 13:46:05 +0000284 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
285 REG_INFO(1), REG_INFO(2), REG_INFO(4));
Ben Murdoch257744e2011-11-30 15:57:28 +0000286 // v1, a1.
Andrei Popescu31002712010-02-23 13:46:05 +0000287 PrintF("%26s\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
288 "", REG_INFO(3), REG_INFO(5));
Ben Murdoch257744e2011-11-30 15:57:28 +0000289 // a2.
Andrei Popescu31002712010-02-23 13:46:05 +0000290 PrintF("%26s\t%26s\t%3s: 0x%08x %10d\n", "", "", REG_INFO(6));
Ben Murdoch257744e2011-11-30 15:57:28 +0000291 // a3.
Andrei Popescu31002712010-02-23 13:46:05 +0000292 PrintF("%26s\t%26s\t%3s: 0x%08x %10d\n", "", "", REG_INFO(7));
293 PrintF("\n");
294 // t0-t7, s0-s7
295 for (int i = 0; i < 8; i++) {
296 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
297 REG_INFO(8+i), REG_INFO(16+i));
298 }
299 PrintF("\n");
Ben Murdoch257744e2011-11-30 15:57:28 +0000300 // t8, k0, LO.
Andrei Popescu31002712010-02-23 13:46:05 +0000301 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
302 REG_INFO(24), REG_INFO(26), REG_INFO(32));
Ben Murdoch257744e2011-11-30 15:57:28 +0000303 // t9, k1, HI.
Andrei Popescu31002712010-02-23 13:46:05 +0000304 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
305 REG_INFO(25), REG_INFO(27), REG_INFO(33));
Ben Murdoch257744e2011-11-30 15:57:28 +0000306 // sp, fp, gp.
Andrei Popescu31002712010-02-23 13:46:05 +0000307 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
308 REG_INFO(29), REG_INFO(30), REG_INFO(28));
Ben Murdoch257744e2011-11-30 15:57:28 +0000309 // pc.
Andrei Popescu31002712010-02-23 13:46:05 +0000310 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
311 REG_INFO(31), REG_INFO(34));
Steve Block44f0eee2011-05-26 01:26:41 +0100312
Andrei Popescu31002712010-02-23 13:46:05 +0000313#undef REG_INFO
Steve Block44f0eee2011-05-26 01:26:41 +0100314#undef FPU_REG_INFO
Andrei Popescu31002712010-02-23 13:46:05 +0000315}
316
Steve Block44f0eee2011-05-26 01:26:41 +0100317
318void MipsDebugger::PrintAllRegsIncludingFPU() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000319#define FPU_REG_INFO32(n) FPURegisters::Name(n), FPURegisters::Name(n+1), \
320 GetFPURegisterValue32(n+1), \
321 GetFPURegisterValue32(n), \
322 GetFPURegisterValueDouble(n)
323
324#define FPU_REG_INFO64(n) FPURegisters::Name(n), \
325 GetFPURegisterValue64(n), \
326 GetFPURegisterValueDouble(n)
Steve Block44f0eee2011-05-26 01:26:41 +0100327
328 PrintAllRegs();
329
330 PrintF("\n\n");
Ben Murdoch257744e2011-11-30 15:57:28 +0000331 // f0, f1, f2, ... f31.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000332 // This must be a compile-time switch,
333 // compiler will throw out warnings otherwise.
334 if (kFpuMode == kFP64) {
335 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(0) );
336 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(1) );
337 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(2) );
338 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(3) );
339 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(4) );
340 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(5) );
341 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(6) );
342 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(7) );
343 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(8) );
344 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(9) );
345 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(10));
346 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(11));
347 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(12));
348 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(13));
349 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(14));
350 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(15));
351 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(16));
352 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(17));
353 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(18));
354 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(19));
355 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(20));
356 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(21));
357 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(22));
358 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(23));
359 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(24));
360 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(25));
361 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(26));
362 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(27));
363 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(28));
364 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(29));
365 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(30));
366 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(31));
367 } else {
368 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(0) );
369 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(2) );
370 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(4) );
371 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(6) );
372 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(8) );
373 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(10));
374 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(12));
375 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(14));
376 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(16));
377 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(18));
378 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(20));
379 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(22));
380 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(24));
381 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(26));
382 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(28));
383 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(30));
384 }
Steve Block44f0eee2011-05-26 01:26:41 +0100385
386#undef REG_INFO
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000387#undef FPU_REG_INFO32
388#undef FPU_REG_INFO64
Steve Block44f0eee2011-05-26 01:26:41 +0100389}
390
391
392void MipsDebugger::Debug() {
Andrei Popescu31002712010-02-23 13:46:05 +0000393 intptr_t last_pc = -1;
394 bool done = false;
395
396#define COMMAND_SIZE 63
397#define ARG_SIZE 255
398
399#define STR(a) #a
400#define XSTR(a) STR(a)
401
402 char cmd[COMMAND_SIZE + 1];
403 char arg1[ARG_SIZE + 1];
404 char arg2[ARG_SIZE + 1];
Steve Block44f0eee2011-05-26 01:26:41 +0100405 char* argv[3] = { cmd, arg1, arg2 };
Andrei Popescu31002712010-02-23 13:46:05 +0000406
Ben Murdoch257744e2011-11-30 15:57:28 +0000407 // Make sure to have a proper terminating character if reaching the limit.
Andrei Popescu31002712010-02-23 13:46:05 +0000408 cmd[COMMAND_SIZE] = 0;
409 arg1[ARG_SIZE] = 0;
410 arg2[ARG_SIZE] = 0;
411
412 // Undo all set breakpoints while running in the debugger shell. This will
413 // make them invisible to all commands.
414 UndoBreakpoints();
415
416 while (!done && (sim_->get_pc() != Simulator::end_sim_pc)) {
417 if (last_pc != sim_->get_pc()) {
418 disasm::NameConverter converter;
419 disasm::Disassembler dasm(converter);
Ben Murdoch257744e2011-11-30 15:57:28 +0000420 // Use a reasonably large buffer.
Andrei Popescu31002712010-02-23 13:46:05 +0000421 v8::internal::EmbeddedVector<char, 256> buffer;
422 dasm.InstructionDecode(buffer,
Ben Murdoch257744e2011-11-30 15:57:28 +0000423 reinterpret_cast<byte*>(sim_->get_pc()));
Andrei Popescu31002712010-02-23 13:46:05 +0000424 PrintF(" 0x%08x %s\n", sim_->get_pc(), buffer.start());
425 last_pc = sim_->get_pc();
426 }
427 char* line = ReadLine("sim> ");
428 if (line == NULL) {
429 break;
430 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100431 char* last_input = sim_->last_debugger_input();
432 if (strcmp(line, "\n") == 0 && last_input != NULL) {
433 line = last_input;
434 } else {
435 // Ownership is transferred to sim_;
436 sim_->set_last_debugger_input(line);
437 }
Andrei Popescu31002712010-02-23 13:46:05 +0000438 // Use sscanf to parse the individual parts of the command line. At the
439 // moment no command expects more than two parameters.
Steve Block44f0eee2011-05-26 01:26:41 +0100440 int argc = SScanF(line,
Andrei Popescu31002712010-02-23 13:46:05 +0000441 "%" XSTR(COMMAND_SIZE) "s "
442 "%" XSTR(ARG_SIZE) "s "
443 "%" XSTR(ARG_SIZE) "s",
444 cmd, arg1, arg2);
445 if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
Steve Block44f0eee2011-05-26 01:26:41 +0100446 Instruction* instr = reinterpret_cast<Instruction*>(sim_->get_pc());
447 if (!(instr->IsTrap()) ||
448 instr->InstructionBits() == rtCallRedirInstr) {
Andrei Popescu31002712010-02-23 13:46:05 +0000449 sim_->InstructionDecode(
Steve Block44f0eee2011-05-26 01:26:41 +0100450 reinterpret_cast<Instruction*>(sim_->get_pc()));
Andrei Popescu31002712010-02-23 13:46:05 +0000451 } else {
452 // Allow si to jump over generated breakpoints.
453 PrintF("/!\\ Jumping over generated breakpoint.\n");
Steve Block44f0eee2011-05-26 01:26:41 +0100454 sim_->set_pc(sim_->get_pc() + Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +0000455 }
456 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) {
457 // Execute the one instruction we broke at with breakpoints disabled.
458 sim_->InstructionDecode(reinterpret_cast<Instruction*>(sim_->get_pc()));
459 // Leave the debugger shell.
460 done = true;
461 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
Steve Block44f0eee2011-05-26 01:26:41 +0100462 if (argc == 2) {
Andrei Popescu31002712010-02-23 13:46:05 +0000463 if (strcmp(arg1, "all") == 0) {
464 PrintAllRegs();
Steve Block44f0eee2011-05-26 01:26:41 +0100465 } else if (strcmp(arg1, "allf") == 0) {
466 PrintAllRegsIncludingFPU();
Andrei Popescu31002712010-02-23 13:46:05 +0000467 } else {
Steve Block44f0eee2011-05-26 01:26:41 +0100468 int regnum = Registers::Number(arg1);
469 int fpuregnum = FPURegisters::Number(arg1);
470
471 if (regnum != kInvalidRegister) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000472 int32_t value;
Steve Block44f0eee2011-05-26 01:26:41 +0100473 value = GetRegisterValue(regnum);
Andrei Popescu31002712010-02-23 13:46:05 +0000474 PrintF("%s: 0x%08x %d \n", arg1, value, value);
Steve Block44f0eee2011-05-26 01:26:41 +0100475 } else if (fpuregnum != kInvalidFPURegister) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000476 if (IsFp64Mode()) {
477 int64_t value;
478 double dvalue;
479 value = GetFPURegisterValue64(fpuregnum);
480 dvalue = GetFPURegisterValueDouble(fpuregnum);
481 PrintF("%3s: 0x%016llx %16.4e\n",
482 FPURegisters::Name(fpuregnum), value, dvalue);
Steve Block44f0eee2011-05-26 01:26:41 +0100483 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000484 if (fpuregnum % 2 == 1) {
485 int32_t value;
486 float fvalue;
487 value = GetFPURegisterValue32(fpuregnum);
488 fvalue = GetFPURegisterValueFloat(fpuregnum);
489 PrintF("%s: 0x%08x %11.4e\n", arg1, value, fvalue);
490 } else {
491 double dfvalue;
492 int32_t lvalue1 = GetFPURegisterValue32(fpuregnum);
493 int32_t lvalue2 = GetFPURegisterValue32(fpuregnum + 1);
494 dfvalue = GetFPURegisterValueDouble(fpuregnum);
495 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n",
496 FPURegisters::Name(fpuregnum+1),
497 FPURegisters::Name(fpuregnum),
498 lvalue1,
499 lvalue2,
500 dfvalue);
501 }
Steve Block44f0eee2011-05-26 01:26:41 +0100502 }
Andrei Popescu31002712010-02-23 13:46:05 +0000503 } else {
504 PrintF("%s unrecognized\n", arg1);
505 }
506 }
507 } else {
Steve Block44f0eee2011-05-26 01:26:41 +0100508 if (argc == 3) {
509 if (strcmp(arg2, "single") == 0) {
510 int32_t value;
511 float fvalue;
512 int fpuregnum = FPURegisters::Number(arg1);
513
514 if (fpuregnum != kInvalidFPURegister) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000515 value = GetFPURegisterValue32(fpuregnum);
Steve Block44f0eee2011-05-26 01:26:41 +0100516 fvalue = GetFPURegisterValueFloat(fpuregnum);
517 PrintF("%s: 0x%08x %11.4e\n", arg1, value, fvalue);
518 } else {
519 PrintF("%s unrecognized\n", arg1);
520 }
521 } else {
522 PrintF("print <fpu register> single\n");
523 }
524 } else {
525 PrintF("print <register> or print <fpu register> single\n");
526 }
Andrei Popescu31002712010-02-23 13:46:05 +0000527 }
528 } else if ((strcmp(cmd, "po") == 0)
529 || (strcmp(cmd, "printobject") == 0)) {
Steve Block44f0eee2011-05-26 01:26:41 +0100530 if (argc == 2) {
Andrei Popescu31002712010-02-23 13:46:05 +0000531 int32_t value;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000532 OFStream os(stdout);
Andrei Popescu31002712010-02-23 13:46:05 +0000533 if (GetValue(arg1, &value)) {
534 Object* obj = reinterpret_cast<Object*>(value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000535 os << arg1 << ": \n";
Andrei Popescu31002712010-02-23 13:46:05 +0000536#ifdef DEBUG
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000537 obj->Print(os);
538 os << "\n";
Andrei Popescu31002712010-02-23 13:46:05 +0000539#else
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000540 os << Brief(obj) << "\n";
Andrei Popescu31002712010-02-23 13:46:05 +0000541#endif
542 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000543 os << arg1 << " unrecognized\n";
Andrei Popescu31002712010-02-23 13:46:05 +0000544 }
545 } else {
546 PrintF("printobject <value>\n");
547 }
Steve Block44f0eee2011-05-26 01:26:41 +0100548 } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0) {
549 int32_t* cur = NULL;
550 int32_t* end = NULL;
551 int next_arg = 1;
552
553 if (strcmp(cmd, "stack") == 0) {
554 cur = reinterpret_cast<int32_t*>(sim_->get_register(Simulator::sp));
Ben Murdoch257744e2011-11-30 15:57:28 +0000555 } else { // Command "mem".
Steve Block44f0eee2011-05-26 01:26:41 +0100556 int32_t value;
557 if (!GetValue(arg1, &value)) {
558 PrintF("%s unrecognized\n", arg1);
559 continue;
560 }
561 cur = reinterpret_cast<int32_t*>(value);
562 next_arg++;
563 }
564
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000565 // TODO(palfia): optimize this.
566 if (IsFp64Mode()) {
567 int64_t words;
568 if (argc == next_arg) {
Steve Block44f0eee2011-05-26 01:26:41 +0100569 words = 10;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000570 } else {
571 if (!GetValue(argv[next_arg], &words)) {
572 words = 10;
573 }
Steve Block44f0eee2011-05-26 01:26:41 +0100574 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000575 end = cur + words;
576 } else {
577 int32_t words;
578 if (argc == next_arg) {
579 words = 10;
580 } else {
581 if (!GetValue(argv[next_arg], &words)) {
582 words = 10;
583 }
584 }
585 end = cur + words;
Steve Block44f0eee2011-05-26 01:26:41 +0100586 }
Steve Block44f0eee2011-05-26 01:26:41 +0100587
588 while (cur < end) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000589 PrintF(" 0x%08x: 0x%08x %10d",
Steve Block44f0eee2011-05-26 01:26:41 +0100590 reinterpret_cast<intptr_t>(cur), *cur, *cur);
Ben Murdoch257744e2011-11-30 15:57:28 +0000591 HeapObject* obj = reinterpret_cast<HeapObject*>(*cur);
592 int value = *cur;
593 Heap* current_heap = v8::internal::Isolate::Current()->heap();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000594 if (((value & 1) == 0) || current_heap->Contains(obj)) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000595 PrintF(" (");
596 if ((value & 1) == 0) {
597 PrintF("smi %d", value / 2);
598 } else {
599 obj->ShortPrint();
600 }
601 PrintF(")");
602 }
603 PrintF("\n");
Steve Block44f0eee2011-05-26 01:26:41 +0100604 cur++;
605 }
606
Ben Murdoch257744e2011-11-30 15:57:28 +0000607 } else if ((strcmp(cmd, "disasm") == 0) ||
608 (strcmp(cmd, "dpc") == 0) ||
609 (strcmp(cmd, "di") == 0)) {
Andrei Popescu31002712010-02-23 13:46:05 +0000610 disasm::NameConverter converter;
611 disasm::Disassembler dasm(converter);
Ben Murdoch257744e2011-11-30 15:57:28 +0000612 // Use a reasonably large buffer.
Andrei Popescu31002712010-02-23 13:46:05 +0000613 v8::internal::EmbeddedVector<char, 256> buffer;
614
Ben Murdoch257744e2011-11-30 15:57:28 +0000615 byte* cur = NULL;
616 byte* end = NULL;
Andrei Popescu31002712010-02-23 13:46:05 +0000617
Steve Block44f0eee2011-05-26 01:26:41 +0100618 if (argc == 1) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000619 cur = reinterpret_cast<byte*>(sim_->get_pc());
Steve Block44f0eee2011-05-26 01:26:41 +0100620 end = cur + (10 * Instruction::kInstrSize);
621 } else if (argc == 2) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000622 int regnum = Registers::Number(arg1);
623 if (regnum != kInvalidRegister || strncmp(arg1, "0x", 2) == 0) {
624 // The argument is an address or a register name.
625 int32_t value;
626 if (GetValue(arg1, &value)) {
627 cur = reinterpret_cast<byte*>(value);
628 // Disassemble 10 instructions at <arg1>.
629 end = cur + (10 * Instruction::kInstrSize);
630 }
631 } else {
632 // The argument is the number of instructions.
633 int32_t value;
634 if (GetValue(arg1, &value)) {
635 cur = reinterpret_cast<byte*>(sim_->get_pc());
636 // Disassemble <arg1> instructions.
637 end = cur + (value * Instruction::kInstrSize);
638 }
Andrei Popescu31002712010-02-23 13:46:05 +0000639 }
640 } else {
641 int32_t value1;
642 int32_t value2;
643 if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000644 cur = reinterpret_cast<byte*>(value1);
Steve Block44f0eee2011-05-26 01:26:41 +0100645 end = cur + (value2 * Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +0000646 }
647 }
648
649 while (cur < end) {
650 dasm.InstructionDecode(buffer, cur);
Steve Block44f0eee2011-05-26 01:26:41 +0100651 PrintF(" 0x%08x %s\n",
652 reinterpret_cast<intptr_t>(cur), buffer.start());
653 cur += Instruction::kInstrSize;
Andrei Popescu31002712010-02-23 13:46:05 +0000654 }
655 } else if (strcmp(cmd, "gdb") == 0) {
656 PrintF("relinquishing control to gdb\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000657 v8::base::OS::DebugBreak();
Andrei Popescu31002712010-02-23 13:46:05 +0000658 PrintF("regaining control from gdb\n");
659 } else if (strcmp(cmd, "break") == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +0100660 if (argc == 2) {
Andrei Popescu31002712010-02-23 13:46:05 +0000661 int32_t value;
662 if (GetValue(arg1, &value)) {
663 if (!SetBreakpoint(reinterpret_cast<Instruction*>(value))) {
664 PrintF("setting breakpoint failed\n");
665 }
666 } else {
667 PrintF("%s unrecognized\n", arg1);
668 }
669 } else {
670 PrintF("break <address>\n");
671 }
672 } else if (strcmp(cmd, "del") == 0) {
673 if (!DeleteBreakpoint(NULL)) {
674 PrintF("deleting breakpoint failed\n");
675 }
676 } else if (strcmp(cmd, "flags") == 0) {
677 PrintF("No flags on MIPS !\n");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000678 } else if (strcmp(cmd, "stop") == 0) {
679 int32_t value;
680 intptr_t stop_pc = sim_->get_pc() -
681 2 * Instruction::kInstrSize;
682 Instruction* stop_instr = reinterpret_cast<Instruction*>(stop_pc);
683 Instruction* msg_address =
684 reinterpret_cast<Instruction*>(stop_pc +
685 Instruction::kInstrSize);
686 if ((argc == 2) && (strcmp(arg1, "unstop") == 0)) {
687 // Remove the current stop.
688 if (sim_->IsStopInstruction(stop_instr)) {
689 stop_instr->SetInstructionBits(kNopInstr);
690 msg_address->SetInstructionBits(kNopInstr);
691 } else {
692 PrintF("Not at debugger stop.\n");
693 }
694 } else if (argc == 3) {
695 // Print information about all/the specified breakpoint(s).
696 if (strcmp(arg1, "info") == 0) {
697 if (strcmp(arg2, "all") == 0) {
698 PrintF("Stop information:\n");
699 for (uint32_t i = kMaxWatchpointCode + 1;
700 i <= kMaxStopCode;
701 i++) {
702 sim_->PrintStopInfo(i);
703 }
704 } else if (GetValue(arg2, &value)) {
705 sim_->PrintStopInfo(value);
706 } else {
707 PrintF("Unrecognized argument.\n");
708 }
709 } else if (strcmp(arg1, "enable") == 0) {
710 // Enable all/the specified breakpoint(s).
711 if (strcmp(arg2, "all") == 0) {
712 for (uint32_t i = kMaxWatchpointCode + 1;
713 i <= kMaxStopCode;
714 i++) {
715 sim_->EnableStop(i);
716 }
717 } else if (GetValue(arg2, &value)) {
718 sim_->EnableStop(value);
719 } else {
720 PrintF("Unrecognized argument.\n");
721 }
722 } else if (strcmp(arg1, "disable") == 0) {
723 // Disable all/the specified breakpoint(s).
724 if (strcmp(arg2, "all") == 0) {
725 for (uint32_t i = kMaxWatchpointCode + 1;
726 i <= kMaxStopCode;
727 i++) {
728 sim_->DisableStop(i);
729 }
730 } else if (GetValue(arg2, &value)) {
731 sim_->DisableStop(value);
732 } else {
733 PrintF("Unrecognized argument.\n");
734 }
735 }
736 } else {
737 PrintF("Wrong usage. Use help command for more information.\n");
738 }
Andrei Popescu31002712010-02-23 13:46:05 +0000739 } else if ((strcmp(cmd, "stat") == 0) || (strcmp(cmd, "st") == 0)) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000740 // Print registers and disassemble.
Andrei Popescu31002712010-02-23 13:46:05 +0000741 PrintAllRegs();
742 PrintF("\n");
743
744 disasm::NameConverter converter;
745 disasm::Disassembler dasm(converter);
Ben Murdoch257744e2011-11-30 15:57:28 +0000746 // Use a reasonably large buffer.
Andrei Popescu31002712010-02-23 13:46:05 +0000747 v8::internal::EmbeddedVector<char, 256> buffer;
748
Ben Murdoch257744e2011-11-30 15:57:28 +0000749 byte* cur = NULL;
750 byte* end = NULL;
Andrei Popescu31002712010-02-23 13:46:05 +0000751
Steve Block44f0eee2011-05-26 01:26:41 +0100752 if (argc == 1) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000753 cur = reinterpret_cast<byte*>(sim_->get_pc());
Steve Block44f0eee2011-05-26 01:26:41 +0100754 end = cur + (10 * Instruction::kInstrSize);
755 } else if (argc == 2) {
Andrei Popescu31002712010-02-23 13:46:05 +0000756 int32_t value;
757 if (GetValue(arg1, &value)) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000758 cur = reinterpret_cast<byte*>(value);
Andrei Popescu31002712010-02-23 13:46:05 +0000759 // no length parameter passed, assume 10 instructions
Steve Block44f0eee2011-05-26 01:26:41 +0100760 end = cur + (10 * Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +0000761 }
762 } else {
763 int32_t value1;
764 int32_t value2;
765 if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000766 cur = reinterpret_cast<byte*>(value1);
Steve Block44f0eee2011-05-26 01:26:41 +0100767 end = cur + (value2 * Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +0000768 }
769 }
770
771 while (cur < end) {
772 dasm.InstructionDecode(buffer, cur);
Steve Block44f0eee2011-05-26 01:26:41 +0100773 PrintF(" 0x%08x %s\n",
774 reinterpret_cast<intptr_t>(cur), buffer.start());
775 cur += Instruction::kInstrSize;
Andrei Popescu31002712010-02-23 13:46:05 +0000776 }
777 } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
778 PrintF("cont\n");
779 PrintF(" continue execution (alias 'c')\n");
780 PrintF("stepi\n");
781 PrintF(" step one instruction (alias 'si')\n");
782 PrintF("print <register>\n");
783 PrintF(" print register content (alias 'p')\n");
784 PrintF(" use register name 'all' to print all registers\n");
785 PrintF("printobject <register>\n");
786 PrintF(" print an object from a register (alias 'po')\n");
Steve Block44f0eee2011-05-26 01:26:41 +0100787 PrintF("stack [<words>]\n");
788 PrintF(" dump stack content, default dump 10 words)\n");
789 PrintF("mem <address> [<words>]\n");
790 PrintF(" dump memory content, default dump 10 words)\n");
Andrei Popescu31002712010-02-23 13:46:05 +0000791 PrintF("flags\n");
792 PrintF(" print flags\n");
793 PrintF("disasm [<instructions>]\n");
Ben Murdoch257744e2011-11-30 15:57:28 +0000794 PrintF("disasm [<address/register>]\n");
795 PrintF("disasm [[<address/register>] <instructions>]\n");
796 PrintF(" disassemble code, default is 10 instructions\n");
797 PrintF(" from pc (alias 'di')\n");
Andrei Popescu31002712010-02-23 13:46:05 +0000798 PrintF("gdb\n");
799 PrintF(" enter gdb\n");
800 PrintF("break <address>\n");
801 PrintF(" set a break point on the address\n");
802 PrintF("del\n");
803 PrintF(" delete the breakpoint\n");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000804 PrintF("stop feature:\n");
805 PrintF(" Description:\n");
806 PrintF(" Stops are debug instructions inserted by\n");
807 PrintF(" the Assembler::stop() function.\n");
808 PrintF(" When hitting a stop, the Simulator will\n");
809 PrintF(" stop and and give control to the Debugger.\n");
810 PrintF(" All stop codes are watched:\n");
811 PrintF(" - They can be enabled / disabled: the Simulator\n");
812 PrintF(" will / won't stop when hitting them.\n");
813 PrintF(" - The Simulator keeps track of how many times they \n");
814 PrintF(" are met. (See the info command.) Going over a\n");
815 PrintF(" disabled stop still increases its counter. \n");
816 PrintF(" Commands:\n");
817 PrintF(" stop info all/<code> : print infos about number <code>\n");
818 PrintF(" or all stop(s).\n");
819 PrintF(" stop enable/disable all/<code> : enables / disables\n");
820 PrintF(" all or number <code> stop(s)\n");
821 PrintF(" stop unstop\n");
822 PrintF(" ignore the stop instruction at the current location\n");
823 PrintF(" from now on\n");
Andrei Popescu31002712010-02-23 13:46:05 +0000824 } else {
825 PrintF("Unknown command: %s\n", cmd);
826 }
827 }
Andrei Popescu31002712010-02-23 13:46:05 +0000828 }
829
830 // Add all the breakpoints back to stop execution and enter the debugger
831 // shell when hit.
832 RedoBreakpoints();
833
834#undef COMMAND_SIZE
835#undef ARG_SIZE
836
837#undef STR
838#undef XSTR
839}
840
841
Steve Block44f0eee2011-05-26 01:26:41 +0100842static bool ICacheMatch(void* one, void* two) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000843 DCHECK((reinterpret_cast<intptr_t>(one) & CachePage::kPageMask) == 0);
844 DCHECK((reinterpret_cast<intptr_t>(two) & CachePage::kPageMask) == 0);
Steve Block44f0eee2011-05-26 01:26:41 +0100845 return one == two;
846}
Andrei Popescu31002712010-02-23 13:46:05 +0000847
848
Steve Block44f0eee2011-05-26 01:26:41 +0100849static uint32_t ICacheHash(void* key) {
850 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)) >> 2;
851}
852
853
854static bool AllOnOnePage(uintptr_t start, int size) {
855 intptr_t start_page = (start & ~CachePage::kPageMask);
856 intptr_t end_page = ((start + size) & ~CachePage::kPageMask);
857 return start_page == end_page;
858}
859
860
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100861void Simulator::set_last_debugger_input(char* input) {
862 DeleteArray(last_debugger_input_);
863 last_debugger_input_ = input;
864}
865
866
Steve Block44f0eee2011-05-26 01:26:41 +0100867void Simulator::FlushICache(v8::internal::HashMap* i_cache,
868 void* start_addr,
869 size_t size) {
870 intptr_t start = reinterpret_cast<intptr_t>(start_addr);
871 int intra_line = (start & CachePage::kLineMask);
872 start -= intra_line;
873 size += intra_line;
874 size = ((size - 1) | CachePage::kLineMask) + 1;
875 int offset = (start & CachePage::kPageMask);
876 while (!AllOnOnePage(start, size - 1)) {
877 int bytes_to_flush = CachePage::kPageSize - offset;
878 FlushOnePage(i_cache, start, bytes_to_flush);
879 start += bytes_to_flush;
880 size -= bytes_to_flush;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000881 DCHECK_EQ(0, start & CachePage::kPageMask);
Steve Block44f0eee2011-05-26 01:26:41 +0100882 offset = 0;
883 }
884 if (size != 0) {
885 FlushOnePage(i_cache, start, size);
886 }
887}
888
889
890CachePage* Simulator::GetCachePage(v8::internal::HashMap* i_cache, void* page) {
891 v8::internal::HashMap::Entry* entry = i_cache->Lookup(page,
Ben Murdoch257744e2011-11-30 15:57:28 +0000892 ICacheHash(page),
893 true);
Steve Block44f0eee2011-05-26 01:26:41 +0100894 if (entry->value == NULL) {
895 CachePage* new_page = new CachePage();
896 entry->value = new_page;
897 }
898 return reinterpret_cast<CachePage*>(entry->value);
899}
900
901
902// Flush from start up to and not including start + size.
903void Simulator::FlushOnePage(v8::internal::HashMap* i_cache,
904 intptr_t start,
905 int size) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000906 DCHECK(size <= CachePage::kPageSize);
907 DCHECK(AllOnOnePage(start, size - 1));
908 DCHECK((start & CachePage::kLineMask) == 0);
909 DCHECK((size & CachePage::kLineMask) == 0);
Steve Block44f0eee2011-05-26 01:26:41 +0100910 void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask));
911 int offset = (start & CachePage::kPageMask);
912 CachePage* cache_page = GetCachePage(i_cache, page);
913 char* valid_bytemap = cache_page->ValidityByte(offset);
914 memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift);
915}
916
917
918void Simulator::CheckICache(v8::internal::HashMap* i_cache,
919 Instruction* instr) {
920 intptr_t address = reinterpret_cast<intptr_t>(instr);
921 void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
922 void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask));
923 int offset = (address & CachePage::kPageMask);
924 CachePage* cache_page = GetCachePage(i_cache, page);
925 char* cache_valid_byte = cache_page->ValidityByte(offset);
926 bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID);
927 char* cached_line = cache_page->CachedData(offset & ~CachePage::kLineMask);
928 if (cache_hit) {
929 // Check that the data in memory matches the contents of the I-cache.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000930 CHECK_EQ(0, memcmp(reinterpret_cast<void*>(instr),
931 cache_page->CachedData(offset),
932 Instruction::kInstrSize));
Steve Block44f0eee2011-05-26 01:26:41 +0100933 } else {
934 // Cache miss. Load memory into the cache.
935 memcpy(cached_line, line, CachePage::kLineLength);
936 *cache_valid_byte = CachePage::LINE_VALID;
937 }
938}
Andrei Popescu31002712010-02-23 13:46:05 +0000939
940
Ben Murdoch257744e2011-11-30 15:57:28 +0000941void Simulator::Initialize(Isolate* isolate) {
942 if (isolate->simulator_initialized()) return;
943 isolate->set_simulator_initialized(true);
944 ::v8::internal::ExternalReference::set_redirector(isolate,
945 &RedirectExternalReference);
Andrei Popescu31002712010-02-23 13:46:05 +0000946}
947
948
Ben Murdoch257744e2011-11-30 15:57:28 +0000949Simulator::Simulator(Isolate* isolate) : isolate_(isolate) {
Steve Block44f0eee2011-05-26 01:26:41 +0100950 i_cache_ = isolate_->simulator_i_cache();
951 if (i_cache_ == NULL) {
952 i_cache_ = new v8::internal::HashMap(&ICacheMatch);
953 isolate_->set_simulator_i_cache(i_cache_);
954 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000955 Initialize(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100956 // Set up simulator support first. Some of this information is needed to
Andrei Popescu31002712010-02-23 13:46:05 +0000957 // setup the architecture state.
Steve Block44f0eee2011-05-26 01:26:41 +0100958 stack_ = reinterpret_cast<char*>(malloc(stack_size_));
Andrei Popescu31002712010-02-23 13:46:05 +0000959 pc_modified_ = false;
960 icount_ = 0;
Steve Block44f0eee2011-05-26 01:26:41 +0100961 break_count_ = 0;
Andrei Popescu31002712010-02-23 13:46:05 +0000962 break_pc_ = NULL;
963 break_instr_ = 0;
964
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100965 // Set up architecture state.
Andrei Popescu31002712010-02-23 13:46:05 +0000966 // All registers are initialized to zero to start with.
967 for (int i = 0; i < kNumSimuRegisters; i++) {
968 registers_[i] = 0;
969 }
Steve Block44f0eee2011-05-26 01:26:41 +0100970 for (int i = 0; i < kNumFPURegisters; i++) {
971 FPUregisters_[i] = 0;
972 }
973 FCSR_ = 0;
Andrei Popescu31002712010-02-23 13:46:05 +0000974
975 // The sp is initialized to point to the bottom (high address) of the
976 // allocated stack area. To be safe in potential stack underflows we leave
977 // some buffer below.
Steve Block44f0eee2011-05-26 01:26:41 +0100978 registers_[sp] = reinterpret_cast<int32_t>(stack_) + stack_size_ - 64;
Andrei Popescu31002712010-02-23 13:46:05 +0000979 // The ra and pc are initialized to a known bad value that will cause an
980 // access violation if the simulator ever tries to execute it.
981 registers_[pc] = bad_ra;
982 registers_[ra] = bad_ra;
983 InitializeCoverage();
Steve Block44f0eee2011-05-26 01:26:41 +0100984 for (int i = 0; i < kNumExceptions; i++) {
985 exceptions[i] = 0;
986 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100987
988 last_debugger_input_ = NULL;
Andrei Popescu31002712010-02-23 13:46:05 +0000989}
990
991
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000992Simulator::~Simulator() {
993}
994
995
Andrei Popescu31002712010-02-23 13:46:05 +0000996// When the generated code calls an external reference we need to catch that in
997// the simulator. The external reference will be a function compiled for the
998// host architecture. We need to call that function instead of trying to
999// execute it with the simulator. We do that by redirecting the external
1000// reference to a swi (software-interrupt) instruction that is handled by
1001// the simulator. We write the original destination of the jump just at a known
1002// offset from the swi instruction so the simulator knows what to call.
1003class Redirection {
1004 public:
Steve Block44f0eee2011-05-26 01:26:41 +01001005 Redirection(void* external_function, ExternalReference::Type type)
Andrei Popescu31002712010-02-23 13:46:05 +00001006 : external_function_(external_function),
1007 swi_instruction_(rtCallRedirInstr),
Steve Block44f0eee2011-05-26 01:26:41 +01001008 type_(type),
1009 next_(NULL) {
1010 Isolate* isolate = Isolate::Current();
1011 next_ = isolate->simulator_redirection();
1012 Simulator::current(isolate)->
1013 FlushICache(isolate->simulator_i_cache(),
1014 reinterpret_cast<void*>(&swi_instruction_),
1015 Instruction::kInstrSize);
1016 isolate->set_simulator_redirection(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001017 }
1018
1019 void* address_of_swi_instruction() {
1020 return reinterpret_cast<void*>(&swi_instruction_);
1021 }
1022
1023 void* external_function() { return external_function_; }
Steve Block44f0eee2011-05-26 01:26:41 +01001024 ExternalReference::Type type() { return type_; }
Andrei Popescu31002712010-02-23 13:46:05 +00001025
Steve Block44f0eee2011-05-26 01:26:41 +01001026 static Redirection* Get(void* external_function,
1027 ExternalReference::Type type) {
1028 Isolate* isolate = Isolate::Current();
1029 Redirection* current = isolate->simulator_redirection();
1030 for (; current != NULL; current = current->next_) {
Andrei Popescu31002712010-02-23 13:46:05 +00001031 if (current->external_function_ == external_function) return current;
1032 }
Steve Block44f0eee2011-05-26 01:26:41 +01001033 return new Redirection(external_function, type);
Andrei Popescu31002712010-02-23 13:46:05 +00001034 }
1035
1036 static Redirection* FromSwiInstruction(Instruction* swi_instruction) {
1037 char* addr_of_swi = reinterpret_cast<char*>(swi_instruction);
1038 char* addr_of_redirection =
1039 addr_of_swi - OFFSET_OF(Redirection, swi_instruction_);
1040 return reinterpret_cast<Redirection*>(addr_of_redirection);
1041 }
1042
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001043 static void* ReverseRedirection(int32_t reg) {
1044 Redirection* redirection = FromSwiInstruction(
1045 reinterpret_cast<Instruction*>(reinterpret_cast<void*>(reg)));
1046 return redirection->external_function();
1047 }
1048
Andrei Popescu31002712010-02-23 13:46:05 +00001049 private:
1050 void* external_function_;
1051 uint32_t swi_instruction_;
Steve Block44f0eee2011-05-26 01:26:41 +01001052 ExternalReference::Type type_;
Andrei Popescu31002712010-02-23 13:46:05 +00001053 Redirection* next_;
Andrei Popescu31002712010-02-23 13:46:05 +00001054};
1055
1056
Andrei Popescu31002712010-02-23 13:46:05 +00001057void* Simulator::RedirectExternalReference(void* external_function,
Steve Block44f0eee2011-05-26 01:26:41 +01001058 ExternalReference::Type type) {
1059 Redirection* redirection = Redirection::Get(external_function, type);
Andrei Popescu31002712010-02-23 13:46:05 +00001060 return redirection->address_of_swi_instruction();
1061}
1062
1063
1064// Get the active Simulator for the current thread.
Steve Block44f0eee2011-05-26 01:26:41 +01001065Simulator* Simulator::current(Isolate* isolate) {
1066 v8::internal::Isolate::PerIsolateThreadData* isolate_data =
Ben Murdoch257744e2011-11-30 15:57:28 +00001067 isolate->FindOrAllocatePerThreadDataForThisThread();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001068 DCHECK(isolate_data != NULL);
1069 DCHECK(isolate_data != NULL);
Steve Block44f0eee2011-05-26 01:26:41 +01001070
1071 Simulator* sim = isolate_data->simulator();
Andrei Popescu31002712010-02-23 13:46:05 +00001072 if (sim == NULL) {
Steve Block44f0eee2011-05-26 01:26:41 +01001073 // TODO(146): delete the simulator object when a thread/isolate goes away.
Ben Murdoch257744e2011-11-30 15:57:28 +00001074 sim = new Simulator(isolate);
Steve Block44f0eee2011-05-26 01:26:41 +01001075 isolate_data->set_simulator(sim);
Andrei Popescu31002712010-02-23 13:46:05 +00001076 }
1077 return sim;
1078}
1079
1080
1081// Sets the register in the architecture state. It will also deal with updating
1082// Simulator internal state for special registers such as PC.
1083void Simulator::set_register(int reg, int32_t value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001084 DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
Andrei Popescu31002712010-02-23 13:46:05 +00001085 if (reg == pc) {
1086 pc_modified_ = true;
1087 }
1088
Ben Murdoch257744e2011-11-30 15:57:28 +00001089 // Zero register always holds 0.
Andrei Popescu31002712010-02-23 13:46:05 +00001090 registers_[reg] = (reg == 0) ? 0 : value;
1091}
1092
Steve Block44f0eee2011-05-26 01:26:41 +01001093
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001094void Simulator::set_dw_register(int reg, const int* dbl) {
1095 DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
1096 registers_[reg] = dbl[0];
1097 registers_[reg + 1] = dbl[1];
1098}
1099
1100
1101void Simulator::set_fpu_register(int fpureg, int64_t value) {
1102 DCHECK(IsFp64Mode());
1103 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
Andrei Popescu31002712010-02-23 13:46:05 +00001104 FPUregisters_[fpureg] = value;
1105}
1106
Steve Block44f0eee2011-05-26 01:26:41 +01001107
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001108void Simulator::set_fpu_register_word(int fpureg, int32_t value) {
1109 // Set ONLY lower 32-bits, leaving upper bits untouched.
1110 // TODO(plind): big endian issue.
1111 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1112 int32_t *pword = reinterpret_cast<int32_t*>(&FPUregisters_[fpureg]);
1113 *pword = value;
1114}
1115
1116
1117void Simulator::set_fpu_register_hi_word(int fpureg, int32_t value) {
1118 // Set ONLY upper 32-bits, leaving lower bits untouched.
1119 // TODO(plind): big endian issue.
1120 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1121 int32_t *phiword = (reinterpret_cast<int32_t*>(&FPUregisters_[fpureg])) + 1;
1122 *phiword = value;
1123}
1124
1125
Steve Block44f0eee2011-05-26 01:26:41 +01001126void Simulator::set_fpu_register_float(int fpureg, float value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001127 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1128 *bit_cast<float*>(&FPUregisters_[fpureg]) = value;
Steve Block44f0eee2011-05-26 01:26:41 +01001129}
1130
1131
Andrei Popescu31002712010-02-23 13:46:05 +00001132void Simulator::set_fpu_register_double(int fpureg, double value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001133 if (IsFp64Mode()) {
1134 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1135 *bit_cast<double*>(&FPUregisters_[fpureg]) = value;
1136 } else {
1137 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
1138 int64_t i64 = bit_cast<int64_t>(value);
1139 set_fpu_register_word(fpureg, i64 & 0xffffffff);
1140 set_fpu_register_word(fpureg + 1, i64 >> 32);
1141 }
Andrei Popescu31002712010-02-23 13:46:05 +00001142}
1143
1144
1145// Get the register from the architecture state. This function does handle
1146// the special case of accessing the PC register.
1147int32_t Simulator::get_register(int reg) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001148 DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
Andrei Popescu31002712010-02-23 13:46:05 +00001149 if (reg == 0)
1150 return 0;
1151 else
1152 return registers_[reg] + ((reg == pc) ? Instruction::kPCReadOffset : 0);
1153}
1154
Steve Block44f0eee2011-05-26 01:26:41 +01001155
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001156double Simulator::get_double_from_register_pair(int reg) {
1157 // TODO(plind): bad ABI stuff, refactor or remove.
1158 DCHECK((reg >= 0) && (reg < kNumSimuRegisters) && ((reg % 2) == 0));
1159
1160 double dm_val = 0.0;
1161 // Read the bits from the unsigned integer register_[] array
1162 // into the double precision floating point value and return it.
1163 char buffer[2 * sizeof(registers_[0])];
1164 memcpy(buffer, &registers_[reg], 2 * sizeof(registers_[0]));
1165 memcpy(&dm_val, buffer, 2 * sizeof(registers_[0]));
1166 return(dm_val);
1167}
1168
1169
1170int64_t Simulator::get_fpu_register(int fpureg) const {
1171 DCHECK(IsFp64Mode());
1172 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
Andrei Popescu31002712010-02-23 13:46:05 +00001173 return FPUregisters_[fpureg];
1174}
1175
Steve Block44f0eee2011-05-26 01:26:41 +01001176
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001177int32_t Simulator::get_fpu_register_word(int fpureg) const {
1178 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1179 return static_cast<int32_t>(FPUregisters_[fpureg] & 0xffffffff);
1180}
1181
1182
1183int32_t Simulator::get_fpu_register_signed_word(int fpureg) const {
1184 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1185 return static_cast<int32_t>(FPUregisters_[fpureg] & 0xffffffff);
1186}
1187
1188
1189int32_t Simulator::get_fpu_register_hi_word(int fpureg) const {
1190 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1191 return static_cast<int32_t>((FPUregisters_[fpureg] >> 32) & 0xffffffff);
Steve Block44f0eee2011-05-26 01:26:41 +01001192}
1193
1194
1195float Simulator::get_fpu_register_float(int fpureg) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001196 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1197 return *bit_cast<float*>(const_cast<int64_t*>(&FPUregisters_[fpureg]));
Steve Block44f0eee2011-05-26 01:26:41 +01001198}
1199
1200
Andrei Popescu31002712010-02-23 13:46:05 +00001201double Simulator::get_fpu_register_double(int fpureg) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001202 if (IsFp64Mode()) {
1203 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1204 return *bit_cast<double*>(&FPUregisters_[fpureg]);
1205 } else {
1206 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
1207 int64_t i64;
1208 i64 = static_cast<uint32_t>(get_fpu_register_word(fpureg));
1209 i64 |= static_cast<uint64_t>(get_fpu_register_word(fpureg + 1)) << 32;
1210 return bit_cast<double>(i64);
1211 }
Andrei Popescu31002712010-02-23 13:46:05 +00001212}
1213
Steve Block44f0eee2011-05-26 01:26:41 +01001214
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001215// Runtime FP routines take up to two double arguments and zero
1216// or one integer arguments. All are constructed here,
Ben Murdoch257744e2011-11-30 15:57:28 +00001217// from a0-a3 or f12 and f14.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001218void Simulator::GetFpArgs(double* x, double* y, int32_t* z) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001219 if (!IsMipsSoftFloatABI) {
1220 *x = get_fpu_register_double(12);
1221 *y = get_fpu_register_double(14);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001222 *z = get_register(a2);
Ben Murdoch257744e2011-11-30 15:57:28 +00001223 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001224 // TODO(plind): bad ABI stuff, refactor or remove.
Ben Murdoch257744e2011-11-30 15:57:28 +00001225 // We use a char buffer to get around the strict-aliasing rules which
1226 // otherwise allow the compiler to optimize away the copy.
1227 char buffer[sizeof(*x)];
1228 int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
1229
1230 // Registers a0 and a1 -> x.
1231 reg_buffer[0] = get_register(a0);
1232 reg_buffer[1] = get_register(a1);
1233 memcpy(x, buffer, sizeof(buffer));
Ben Murdoch257744e2011-11-30 15:57:28 +00001234 // Registers a2 and a3 -> y.
1235 reg_buffer[0] = get_register(a2);
1236 reg_buffer[1] = get_register(a3);
1237 memcpy(y, buffer, sizeof(buffer));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001238 // Register 2 -> z.
Ben Murdoch257744e2011-11-30 15:57:28 +00001239 reg_buffer[0] = get_register(a2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001240 memcpy(z, buffer, sizeof(*z));
Ben Murdoch257744e2011-11-30 15:57:28 +00001241 }
1242}
1243
1244
1245// The return value is either in v0/v1 or f0.
1246void Simulator::SetFpResult(const double& result) {
1247 if (!IsMipsSoftFloatABI) {
1248 set_fpu_register_double(0, result);
1249 } else {
1250 char buffer[2 * sizeof(registers_[0])];
1251 int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
1252 memcpy(buffer, &result, sizeof(buffer));
1253 // Copy result to v0 and v1.
1254 set_register(v0, reg_buffer[0]);
1255 set_register(v1, reg_buffer[1]);
1256 }
1257}
1258
1259
Steve Block44f0eee2011-05-26 01:26:41 +01001260// Helper functions for setting and testing the FCSR register's bits.
1261void Simulator::set_fcsr_bit(uint32_t cc, bool value) {
1262 if (value) {
1263 FCSR_ |= (1 << cc);
1264 } else {
1265 FCSR_ &= ~(1 << cc);
1266 }
1267}
1268
1269
1270bool Simulator::test_fcsr_bit(uint32_t cc) {
1271 return FCSR_ & (1 << cc);
1272}
1273
1274
1275// Sets the rounding error codes in FCSR based on the result of the rounding.
1276// Returns true if the operation was invalid.
1277bool Simulator::set_fcsr_round_error(double original, double rounded) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001278 bool ret = false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001279 double max_int32 = std::numeric_limits<int32_t>::max();
1280 double min_int32 = std::numeric_limits<int32_t>::min();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001281
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001282 if (!std::isfinite(original) || !std::isfinite(rounded)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001283 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1284 ret = true;
Steve Block44f0eee2011-05-26 01:26:41 +01001285 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001286
1287 if (original != rounded) {
1288 set_fcsr_bit(kFCSRInexactFlagBit, true);
1289 }
1290
1291 if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) {
1292 set_fcsr_bit(kFCSRUnderflowFlagBit, true);
1293 ret = true;
1294 }
1295
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001296 if (rounded > max_int32 || rounded < min_int32) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001297 set_fcsr_bit(kFCSROverflowFlagBit, true);
1298 // The reference is not really clear but it seems this is required:
1299 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1300 ret = true;
1301 }
1302
1303 return ret;
Steve Block44f0eee2011-05-26 01:26:41 +01001304}
1305
1306
Andrei Popescu31002712010-02-23 13:46:05 +00001307// Raw access to the PC register.
1308void Simulator::set_pc(int32_t value) {
1309 pc_modified_ = true;
1310 registers_[pc] = value;
1311}
1312
Steve Block44f0eee2011-05-26 01:26:41 +01001313
1314bool Simulator::has_bad_pc() const {
1315 return ((registers_[pc] == bad_ra) || (registers_[pc] == end_sim_pc));
1316}
1317
1318
Andrei Popescu31002712010-02-23 13:46:05 +00001319// Raw access to the PC register without the special adjustment when reading.
1320int32_t Simulator::get_pc() const {
1321 return registers_[pc];
1322}
1323
1324
1325// The MIPS cannot do unaligned reads and writes. On some MIPS platforms an
1326// interrupt is caused. On others it does a funky rotation thing. For now we
1327// simply disallow unaligned reads, but at some point we may want to move to
1328// emulating the rotate behaviour. Note that simulator runs have the runtime
1329// system running directly on the host system and only generated code is
1330// executed in the simulator. Since the host is typically IA32 we will not
1331// get the correct MIPS-like behaviour on unaligned accesses.
1332
1333int Simulator::ReadW(int32_t addr, Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +01001334 if (addr >=0 && addr < 0x400) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001335 // This has to be a NULL-dereference, drop into debugger.
Ben Murdoch589d6972011-11-30 16:04:58 +00001336 PrintF("Memory read from bad address: 0x%08x, pc=0x%08x\n",
1337 addr, reinterpret_cast<intptr_t>(instr));
Steve Block44f0eee2011-05-26 01:26:41 +01001338 MipsDebugger dbg(this);
1339 dbg.Debug();
1340 }
1341 if ((addr & kPointerAlignmentMask) == 0) {
Andrei Popescu31002712010-02-23 13:46:05 +00001342 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
1343 return *ptr;
1344 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001345 PrintF("Unaligned read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1346 addr,
1347 reinterpret_cast<intptr_t>(instr));
Steve Block44f0eee2011-05-26 01:26:41 +01001348 MipsDebugger dbg(this);
1349 dbg.Debug();
Andrei Popescu31002712010-02-23 13:46:05 +00001350 return 0;
1351}
1352
1353
1354void Simulator::WriteW(int32_t addr, int value, Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +01001355 if (addr >= 0 && addr < 0x400) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001356 // This has to be a NULL-dereference, drop into debugger.
Ben Murdoch589d6972011-11-30 16:04:58 +00001357 PrintF("Memory write to bad address: 0x%08x, pc=0x%08x\n",
1358 addr, reinterpret_cast<intptr_t>(instr));
Steve Block44f0eee2011-05-26 01:26:41 +01001359 MipsDebugger dbg(this);
1360 dbg.Debug();
1361 }
1362 if ((addr & kPointerAlignmentMask) == 0) {
Andrei Popescu31002712010-02-23 13:46:05 +00001363 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
1364 *ptr = value;
1365 return;
1366 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001367 PrintF("Unaligned write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1368 addr,
1369 reinterpret_cast<intptr_t>(instr));
Steve Block44f0eee2011-05-26 01:26:41 +01001370 MipsDebugger dbg(this);
1371 dbg.Debug();
Andrei Popescu31002712010-02-23 13:46:05 +00001372}
1373
1374
1375double Simulator::ReadD(int32_t addr, Instruction* instr) {
1376 if ((addr & kDoubleAlignmentMask) == 0) {
1377 double* ptr = reinterpret_cast<double*>(addr);
1378 return *ptr;
1379 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001380 PrintF("Unaligned (double) read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1381 addr,
1382 reinterpret_cast<intptr_t>(instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001383 base::OS::Abort();
Andrei Popescu31002712010-02-23 13:46:05 +00001384 return 0;
1385}
1386
1387
1388void Simulator::WriteD(int32_t addr, double value, Instruction* instr) {
1389 if ((addr & kDoubleAlignmentMask) == 0) {
1390 double* ptr = reinterpret_cast<double*>(addr);
1391 *ptr = value;
1392 return;
1393 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001394 PrintF("Unaligned (double) write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1395 addr,
1396 reinterpret_cast<intptr_t>(instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001397 base::OS::Abort();
Andrei Popescu31002712010-02-23 13:46:05 +00001398}
1399
1400
1401uint16_t Simulator::ReadHU(int32_t addr, Instruction* instr) {
1402 if ((addr & 1) == 0) {
1403 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1404 return *ptr;
1405 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001406 PrintF("Unaligned unsigned halfword read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1407 addr,
1408 reinterpret_cast<intptr_t>(instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001409 base::OS::Abort();
Andrei Popescu31002712010-02-23 13:46:05 +00001410 return 0;
1411}
1412
1413
1414int16_t Simulator::ReadH(int32_t addr, Instruction* instr) {
1415 if ((addr & 1) == 0) {
1416 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
1417 return *ptr;
1418 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001419 PrintF("Unaligned signed halfword read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1420 addr,
1421 reinterpret_cast<intptr_t>(instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001422 base::OS::Abort();
Andrei Popescu31002712010-02-23 13:46:05 +00001423 return 0;
1424}
1425
1426
1427void Simulator::WriteH(int32_t addr, uint16_t value, Instruction* instr) {
1428 if ((addr & 1) == 0) {
1429 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1430 *ptr = value;
1431 return;
1432 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001433 PrintF("Unaligned unsigned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1434 addr,
1435 reinterpret_cast<intptr_t>(instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001436 base::OS::Abort();
Andrei Popescu31002712010-02-23 13:46:05 +00001437}
1438
1439
1440void Simulator::WriteH(int32_t addr, int16_t value, Instruction* instr) {
1441 if ((addr & 1) == 0) {
1442 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
1443 *ptr = value;
1444 return;
1445 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001446 PrintF("Unaligned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1447 addr,
1448 reinterpret_cast<intptr_t>(instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001449 base::OS::Abort();
Andrei Popescu31002712010-02-23 13:46:05 +00001450}
1451
1452
1453uint32_t Simulator::ReadBU(int32_t addr) {
1454 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1455 return *ptr & 0xff;
1456}
1457
1458
1459int32_t Simulator::ReadB(int32_t addr) {
1460 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
Steve Block44f0eee2011-05-26 01:26:41 +01001461 return *ptr;
Andrei Popescu31002712010-02-23 13:46:05 +00001462}
1463
1464
1465void Simulator::WriteB(int32_t addr, uint8_t value) {
1466 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1467 *ptr = value;
1468}
1469
1470
1471void Simulator::WriteB(int32_t addr, int8_t value) {
1472 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
1473 *ptr = value;
1474}
1475
1476
1477// Returns the limit of the stack area to enable checking for stack overflows.
1478uintptr_t Simulator::StackLimit() const {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001479 // Leave a safety margin of 1024 bytes to prevent overrunning the stack when
Andrei Popescu31002712010-02-23 13:46:05 +00001480 // pushing values.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001481 return reinterpret_cast<uintptr_t>(stack_) + 1024;
Andrei Popescu31002712010-02-23 13:46:05 +00001482}
1483
1484
1485// Unsupported instructions use Format to print an error and stop execution.
1486void Simulator::Format(Instruction* instr, const char* format) {
1487 PrintF("Simulator found unsupported instruction:\n 0x%08x: %s\n",
Steve Block44f0eee2011-05-26 01:26:41 +01001488 reinterpret_cast<intptr_t>(instr), format);
Andrei Popescu31002712010-02-23 13:46:05 +00001489 UNIMPLEMENTED_MIPS();
1490}
1491
1492
1493// Calls into the V8 runtime are based on this very simple interface.
1494// Note: To be able to return two values from some calls the code in runtime.cc
1495// uses the ObjectPair which is essentially two 32-bit values stuffed into a
1496// 64-bit value. With the code below we assume that all runtime calls return
Steve Block44f0eee2011-05-26 01:26:41 +01001497// 64 bits of result. If they don't, the v1 result register contains a bogus
Andrei Popescu31002712010-02-23 13:46:05 +00001498// value, which is fine because it is caller-saved.
1499typedef int64_t (*SimulatorRuntimeCall)(int32_t arg0,
1500 int32_t arg1,
1501 int32_t arg2,
Steve Block44f0eee2011-05-26 01:26:41 +01001502 int32_t arg3,
1503 int32_t arg4,
1504 int32_t arg5);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001505
1506// These prototypes handle the four types of FP calls.
1507typedef int64_t (*SimulatorRuntimeCompareCall)(double darg0, double darg1);
1508typedef double (*SimulatorRuntimeFPFPCall)(double darg0, double darg1);
1509typedef double (*SimulatorRuntimeFPCall)(double darg0);
1510typedef double (*SimulatorRuntimeFPIntCall)(double darg0, int32_t arg0);
Andrei Popescu31002712010-02-23 13:46:05 +00001511
Ben Murdoch257744e2011-11-30 15:57:28 +00001512// This signature supports direct call in to API function native callback
1513// (refer to InvocationCallback in v8.h).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001514typedef void (*SimulatorRuntimeDirectApiCall)(int32_t arg0);
1515typedef void (*SimulatorRuntimeProfilingApiCall)(int32_t arg0, void* arg1);
Ben Murdoch257744e2011-11-30 15:57:28 +00001516
1517// This signature supports direct call to accessor getter callback.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001518typedef void (*SimulatorRuntimeDirectGetterCall)(int32_t arg0, int32_t arg1);
1519typedef void (*SimulatorRuntimeProfilingGetterCall)(
1520 int32_t arg0, int32_t arg1, void* arg2);
Ben Murdoch257744e2011-11-30 15:57:28 +00001521
Andrei Popescu31002712010-02-23 13:46:05 +00001522// Software interrupt instructions are used by the simulator to call into the
Steve Block44f0eee2011-05-26 01:26:41 +01001523// C-based V8 runtime. They are also used for debugging with simulator.
Andrei Popescu31002712010-02-23 13:46:05 +00001524void Simulator::SoftwareInterrupt(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +01001525 // There are several instructions that could get us here,
1526 // the break_ instruction, or several variants of traps. All
1527 // Are "SPECIAL" class opcode, and are distinuished by function.
1528 int32_t func = instr->FunctionFieldRaw();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001529 uint32_t code = (func == BREAK) ? instr->Bits(25, 6) : -1;
Steve Block44f0eee2011-05-26 01:26:41 +01001530
Andrei Popescu31002712010-02-23 13:46:05 +00001531 // We first check if we met a call_rt_redirected.
1532 if (instr->InstructionBits() == rtCallRedirInstr) {
1533 Redirection* redirection = Redirection::FromSwiInstruction(instr);
1534 int32_t arg0 = get_register(a0);
1535 int32_t arg1 = get_register(a1);
1536 int32_t arg2 = get_register(a2);
1537 int32_t arg3 = get_register(a3);
Steve Block44f0eee2011-05-26 01:26:41 +01001538
Steve Block44f0eee2011-05-26 01:26:41 +01001539 int32_t* stack_pointer = reinterpret_cast<int32_t*>(get_register(sp));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001540 // Args 4 and 5 are on the stack after the reserved space for args 0..3.
1541 int32_t arg4 = stack_pointer[4];
1542 int32_t arg5 = stack_pointer[5];
Ben Murdoch257744e2011-11-30 15:57:28 +00001543
1544 bool fp_call =
1545 (redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) ||
1546 (redirection->type() == ExternalReference::BUILTIN_COMPARE_CALL) ||
1547 (redirection->type() == ExternalReference::BUILTIN_FP_CALL) ||
1548 (redirection->type() == ExternalReference::BUILTIN_FP_INT_CALL);
1549
1550 if (!IsMipsSoftFloatABI) {
1551 // With the hard floating point calling convention, double
1552 // arguments are passed in FPU registers. Fetch the arguments
1553 // from there and call the builtin using soft floating point
1554 // convention.
1555 switch (redirection->type()) {
1556 case ExternalReference::BUILTIN_FP_FP_CALL:
1557 case ExternalReference::BUILTIN_COMPARE_CALL:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001558 if (IsFp64Mode()) {
1559 arg0 = get_fpu_register_word(f12);
1560 arg1 = get_fpu_register_hi_word(f12);
1561 arg2 = get_fpu_register_word(f14);
1562 arg3 = get_fpu_register_hi_word(f14);
1563 } else {
1564 arg0 = get_fpu_register_word(f12);
1565 arg1 = get_fpu_register_word(f13);
1566 arg2 = get_fpu_register_word(f14);
1567 arg3 = get_fpu_register_word(f15);
1568 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001569 break;
1570 case ExternalReference::BUILTIN_FP_CALL:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001571 if (IsFp64Mode()) {
1572 arg0 = get_fpu_register_word(f12);
1573 arg1 = get_fpu_register_hi_word(f12);
1574 } else {
1575 arg0 = get_fpu_register_word(f12);
1576 arg1 = get_fpu_register_word(f13);
1577 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001578 break;
1579 case ExternalReference::BUILTIN_FP_INT_CALL:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001580 if (IsFp64Mode()) {
1581 arg0 = get_fpu_register_word(f12);
1582 arg1 = get_fpu_register_hi_word(f12);
1583 } else {
1584 arg0 = get_fpu_register_word(f12);
1585 arg1 = get_fpu_register_word(f13);
1586 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001587 arg2 = get_register(a2);
1588 break;
1589 default:
1590 break;
1591 }
1592 }
1593
Andrei Popescu31002712010-02-23 13:46:05 +00001594 // This is dodgy but it works because the C entry stubs are never moved.
1595 // See comment in codegen-arm.cc and bug 1242173.
1596 int32_t saved_ra = get_register(ra);
Steve Block44f0eee2011-05-26 01:26:41 +01001597
1598 intptr_t external =
Ben Murdoch257744e2011-11-30 15:57:28 +00001599 reinterpret_cast<intptr_t>(redirection->external_function());
Steve Block44f0eee2011-05-26 01:26:41 +01001600
1601 // Based on CpuFeatures::IsSupported(FPU), Mips will use either hardware
1602 // FPU, or gcc soft-float routines. Hardware FPU is simulated in this
1603 // simulator. Soft-float has additional abstraction of ExternalReference,
Ben Murdoch257744e2011-11-30 15:57:28 +00001604 // to support serialization.
1605 if (fp_call) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001606 double dval0, dval1; // one or two double parameters
1607 int32_t ival; // zero or one integer parameters
1608 int64_t iresult = 0; // integer return value
1609 double dresult = 0; // double return value
1610 GetFpArgs(&dval0, &dval1, &ival);
1611 SimulatorRuntimeCall generic_target =
1612 reinterpret_cast<SimulatorRuntimeCall>(external);
Ben Murdoch257744e2011-11-30 15:57:28 +00001613 if (::v8::internal::FLAG_trace_sim) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001614 switch (redirection->type()) {
1615 case ExternalReference::BUILTIN_FP_FP_CALL:
1616 case ExternalReference::BUILTIN_COMPARE_CALL:
Ben Murdoch257744e2011-11-30 15:57:28 +00001617 PrintF("Call to host function at %p with args %f, %f",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001618 FUNCTION_ADDR(generic_target), dval0, dval1);
Ben Murdoch257744e2011-11-30 15:57:28 +00001619 break;
1620 case ExternalReference::BUILTIN_FP_CALL:
Ben Murdoch257744e2011-11-30 15:57:28 +00001621 PrintF("Call to host function at %p with arg %f",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001622 FUNCTION_ADDR(generic_target), dval0);
Ben Murdoch257744e2011-11-30 15:57:28 +00001623 break;
1624 case ExternalReference::BUILTIN_FP_INT_CALL:
Ben Murdoch257744e2011-11-30 15:57:28 +00001625 PrintF("Call to host function at %p with args %f, %d",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001626 FUNCTION_ADDR(generic_target), dval0, ival);
Ben Murdoch257744e2011-11-30 15:57:28 +00001627 break;
1628 default:
1629 UNREACHABLE();
1630 break;
Steve Block44f0eee2011-05-26 01:26:41 +01001631 }
Andrei Popescu31002712010-02-23 13:46:05 +00001632 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001633 switch (redirection->type()) {
1634 case ExternalReference::BUILTIN_COMPARE_CALL: {
1635 SimulatorRuntimeCompareCall target =
1636 reinterpret_cast<SimulatorRuntimeCompareCall>(external);
1637 iresult = target(dval0, dval1);
1638 set_register(v0, static_cast<int32_t>(iresult));
1639 set_register(v1, static_cast<int32_t>(iresult >> 32));
1640 break;
1641 }
1642 case ExternalReference::BUILTIN_FP_FP_CALL: {
1643 SimulatorRuntimeFPFPCall target =
1644 reinterpret_cast<SimulatorRuntimeFPFPCall>(external);
1645 dresult = target(dval0, dval1);
1646 SetFpResult(dresult);
1647 break;
1648 }
1649 case ExternalReference::BUILTIN_FP_CALL: {
1650 SimulatorRuntimeFPCall target =
1651 reinterpret_cast<SimulatorRuntimeFPCall>(external);
1652 dresult = target(dval0);
1653 SetFpResult(dresult);
1654 break;
1655 }
1656 case ExternalReference::BUILTIN_FP_INT_CALL: {
1657 SimulatorRuntimeFPIntCall target =
1658 reinterpret_cast<SimulatorRuntimeFPIntCall>(external);
1659 dresult = target(dval0, ival);
1660 SetFpResult(dresult);
1661 break;
1662 }
1663 default:
1664 UNREACHABLE();
1665 break;
1666 }
1667 if (::v8::internal::FLAG_trace_sim) {
1668 switch (redirection->type()) {
1669 case ExternalReference::BUILTIN_COMPARE_CALL:
1670 PrintF("Returned %08x\n", static_cast<int32_t>(iresult));
1671 break;
1672 case ExternalReference::BUILTIN_FP_FP_CALL:
1673 case ExternalReference::BUILTIN_FP_CALL:
1674 case ExternalReference::BUILTIN_FP_INT_CALL:
1675 PrintF("Returned %f\n", dresult);
1676 break;
1677 default:
1678 UNREACHABLE();
1679 break;
1680 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001681 }
Steve Block44f0eee2011-05-26 01:26:41 +01001682 } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001683 if (::v8::internal::FLAG_trace_sim) {
1684 PrintF("Call to host function at %p args %08x\n",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001685 reinterpret_cast<void*>(external), arg0);
Ben Murdoch257744e2011-11-30 15:57:28 +00001686 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001687 SimulatorRuntimeDirectApiCall target =
1688 reinterpret_cast<SimulatorRuntimeDirectApiCall>(external);
1689 target(arg0);
1690 } else if (
1691 redirection->type() == ExternalReference::PROFILING_API_CALL) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001692 if (::v8::internal::FLAG_trace_sim) {
1693 PrintF("Call to host function at %p args %08x %08x\n",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001694 reinterpret_cast<void*>(external), arg0, arg1);
Ben Murdoch257744e2011-11-30 15:57:28 +00001695 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001696 SimulatorRuntimeProfilingApiCall target =
1697 reinterpret_cast<SimulatorRuntimeProfilingApiCall>(external);
1698 target(arg0, Redirection::ReverseRedirection(arg1));
1699 } else if (
1700 redirection->type() == ExternalReference::DIRECT_GETTER_CALL) {
1701 if (::v8::internal::FLAG_trace_sim) {
1702 PrintF("Call to host function at %p args %08x %08x\n",
1703 reinterpret_cast<void*>(external), arg0, arg1);
1704 }
1705 SimulatorRuntimeDirectGetterCall target =
1706 reinterpret_cast<SimulatorRuntimeDirectGetterCall>(external);
1707 target(arg0, arg1);
1708 } else if (
1709 redirection->type() == ExternalReference::PROFILING_GETTER_CALL) {
1710 if (::v8::internal::FLAG_trace_sim) {
1711 PrintF("Call to host function at %p args %08x %08x %08x\n",
1712 reinterpret_cast<void*>(external), arg0, arg1, arg2);
1713 }
1714 SimulatorRuntimeProfilingGetterCall target =
1715 reinterpret_cast<SimulatorRuntimeProfilingGetterCall>(external);
1716 target(arg0, arg1, Redirection::ReverseRedirection(arg2));
Andrei Popescu31002712010-02-23 13:46:05 +00001717 } else {
Andrei Popescu31002712010-02-23 13:46:05 +00001718 SimulatorRuntimeCall target =
Ben Murdoch257744e2011-11-30 15:57:28 +00001719 reinterpret_cast<SimulatorRuntimeCall>(external);
1720 if (::v8::internal::FLAG_trace_sim) {
Andrei Popescu31002712010-02-23 13:46:05 +00001721 PrintF(
Ben Murdoch257744e2011-11-30 15:57:28 +00001722 "Call to host function at %p "
1723 "args %08x, %08x, %08x, %08x, %08x, %08x\n",
Andrei Popescu31002712010-02-23 13:46:05 +00001724 FUNCTION_ADDR(target),
1725 arg0,
1726 arg1,
1727 arg2,
Steve Block44f0eee2011-05-26 01:26:41 +01001728 arg3,
1729 arg4,
1730 arg5);
Andrei Popescu31002712010-02-23 13:46:05 +00001731 }
Steve Block44f0eee2011-05-26 01:26:41 +01001732 int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5);
1733 set_register(v0, static_cast<int32_t>(result));
1734 set_register(v1, static_cast<int32_t>(result >> 32));
1735 }
1736 if (::v8::internal::FLAG_trace_sim) {
1737 PrintF("Returned %08x : %08x\n", get_register(v1), get_register(v0));
Andrei Popescu31002712010-02-23 13:46:05 +00001738 }
1739 set_register(ra, saved_ra);
1740 set_pc(get_register(ra));
Steve Block44f0eee2011-05-26 01:26:41 +01001741
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001742 } else if (func == BREAK && code <= kMaxStopCode) {
1743 if (IsWatchpoint(code)) {
1744 PrintWatchpoint(code);
1745 } else {
1746 IncreaseStopCounter(code);
1747 HandleStop(code, instr);
1748 }
Andrei Popescu31002712010-02-23 13:46:05 +00001749 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01001750 // All remaining break_ codes, and all traps are handled here.
1751 MipsDebugger dbg(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001752 dbg.Debug();
1753 }
1754}
1755
Steve Block44f0eee2011-05-26 01:26:41 +01001756
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001757// Stop helper functions.
1758bool Simulator::IsWatchpoint(uint32_t code) {
1759 return (code <= kMaxWatchpointCode);
1760}
1761
1762
1763void Simulator::PrintWatchpoint(uint32_t code) {
1764 MipsDebugger dbg(this);
1765 ++break_count_;
1766 PrintF("\n---- break %d marker: %3d (instr count: %8d) ----------"
1767 "----------------------------------",
1768 code, break_count_, icount_);
1769 dbg.PrintAllRegs(); // Print registers and continue running.
1770}
1771
1772
1773void Simulator::HandleStop(uint32_t code, Instruction* instr) {
1774 // Stop if it is enabled, otherwise go on jumping over the stop
1775 // and the message address.
1776 if (IsEnabledStop(code)) {
1777 MipsDebugger dbg(this);
1778 dbg.Stop(instr);
1779 } else {
1780 set_pc(get_pc() + 2 * Instruction::kInstrSize);
1781 }
1782}
1783
1784
1785bool Simulator::IsStopInstruction(Instruction* instr) {
1786 int32_t func = instr->FunctionFieldRaw();
1787 uint32_t code = static_cast<uint32_t>(instr->Bits(25, 6));
1788 return (func == BREAK) && code > kMaxWatchpointCode && code <= kMaxStopCode;
1789}
1790
1791
1792bool Simulator::IsEnabledStop(uint32_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001793 DCHECK(code <= kMaxStopCode);
1794 DCHECK(code > kMaxWatchpointCode);
1795 return !(watched_stops_[code].count & kStopDisabledBit);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001796}
1797
1798
1799void Simulator::EnableStop(uint32_t code) {
1800 if (!IsEnabledStop(code)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001801 watched_stops_[code].count &= ~kStopDisabledBit;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001802 }
1803}
1804
1805
1806void Simulator::DisableStop(uint32_t code) {
1807 if (IsEnabledStop(code)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001808 watched_stops_[code].count |= kStopDisabledBit;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001809 }
1810}
1811
1812
1813void Simulator::IncreaseStopCounter(uint32_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001814 DCHECK(code <= kMaxStopCode);
1815 if ((watched_stops_[code].count & ~(1 << 31)) == 0x7fffffff) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001816 PrintF("Stop counter for code %i has overflowed.\n"
1817 "Enabling this code and reseting the counter to 0.\n", code);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001818 watched_stops_[code].count = 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001819 EnableStop(code);
1820 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001821 watched_stops_[code].count++;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001822 }
1823}
1824
1825
1826// Print a stop status.
1827void Simulator::PrintStopInfo(uint32_t code) {
1828 if (code <= kMaxWatchpointCode) {
1829 PrintF("That is a watchpoint, not a stop.\n");
1830 return;
1831 } else if (code > kMaxStopCode) {
1832 PrintF("Code too large, only %u stops can be used\n", kMaxStopCode + 1);
1833 return;
1834 }
1835 const char* state = IsEnabledStop(code) ? "Enabled" : "Disabled";
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001836 int32_t count = watched_stops_[code].count & ~kStopDisabledBit;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001837 // Don't print the state of unused breakpoints.
1838 if (count != 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001839 if (watched_stops_[code].desc) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001840 PrintF("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001841 code, code, state, count, watched_stops_[code].desc);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001842 } else {
1843 PrintF("stop %i - 0x%x: \t%s, \tcounter = %i\n",
1844 code, code, state, count);
1845 }
1846 }
1847}
1848
1849
Andrei Popescu31002712010-02-23 13:46:05 +00001850void Simulator::SignalExceptions() {
1851 for (int i = 1; i < kNumExceptions; i++) {
1852 if (exceptions[i] != 0) {
1853 V8_Fatal(__FILE__, __LINE__, "Error: Exception %i raised.", i);
1854 }
1855 }
1856}
1857
Steve Block44f0eee2011-05-26 01:26:41 +01001858
Andrei Popescu31002712010-02-23 13:46:05 +00001859// Handle execution based on instruction types.
Andrei Popescu31002712010-02-23 13:46:05 +00001860
Steve Block44f0eee2011-05-26 01:26:41 +01001861void Simulator::ConfigureTypeRegister(Instruction* instr,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001862 int32_t* alu_out,
1863 int64_t* i64hilo,
1864 uint64_t* u64hilo,
1865 int32_t* next_pc,
1866 int32_t* return_addr_reg,
1867 bool* do_interrupt) {
Steve Block44f0eee2011-05-26 01:26:41 +01001868 // Every local variable declared here needs to be const.
1869 // This is to make sure that changed values are sent back to
1870 // DecodeTypeRegister correctly.
Andrei Popescu31002712010-02-23 13:46:05 +00001871
Steve Block44f0eee2011-05-26 01:26:41 +01001872 // Instruction fields.
1873 const Opcode op = instr->OpcodeFieldRaw();
1874 const int32_t rs_reg = instr->RsValue();
1875 const int32_t rs = get_register(rs_reg);
1876 const uint32_t rs_u = static_cast<uint32_t>(rs);
1877 const int32_t rt_reg = instr->RtValue();
1878 const int32_t rt = get_register(rt_reg);
1879 const uint32_t rt_u = static_cast<uint32_t>(rt);
1880 const int32_t rd_reg = instr->RdValue();
1881 const uint32_t sa = instr->SaValue();
Andrei Popescu31002712010-02-23 13:46:05 +00001882
Steve Block44f0eee2011-05-26 01:26:41 +01001883 const int32_t fs_reg = instr->FsValue();
Andrei Popescu31002712010-02-23 13:46:05 +00001884
Andrei Popescu31002712010-02-23 13:46:05 +00001885
Ben Murdoch257744e2011-11-30 15:57:28 +00001886 // ---------- Configuration.
Andrei Popescu31002712010-02-23 13:46:05 +00001887 switch (op) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001888 case COP1: // Coprocessor instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00001889 switch (instr->RsFieldRaw()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001890 case CFC1:
1891 // At the moment only FCSR is supported.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001892 DCHECK(fs_reg == kFCSRRegister);
1893 *alu_out = FCSR_;
Steve Block44f0eee2011-05-26 01:26:41 +01001894 break;
Andrei Popescu31002712010-02-23 13:46:05 +00001895 case MFC1:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001896 *alu_out = get_fpu_register_word(fs_reg);
Andrei Popescu31002712010-02-23 13:46:05 +00001897 break;
1898 case MFHC1:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001899 *alu_out = get_fpu_register_hi_word(fs_reg);
Andrei Popescu31002712010-02-23 13:46:05 +00001900 break;
Steve Block44f0eee2011-05-26 01:26:41 +01001901 case CTC1:
Andrei Popescu31002712010-02-23 13:46:05 +00001902 case MTC1:
1903 case MTHC1:
Andrei Popescu31002712010-02-23 13:46:05 +00001904 case S:
1905 case D:
1906 case W:
1907 case L:
1908 case PS:
1909 // Do everything in the execution step.
1910 break;
1911 default:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001912 // BC1 BC1EQZ BC1NEZ handled in DecodeTypeImmed, should never come here.
1913 UNREACHABLE();
1914 }
1915 break;
1916 case COP1X:
Andrei Popescu31002712010-02-23 13:46:05 +00001917 break;
1918 case SPECIAL:
1919 switch (instr->FunctionFieldRaw()) {
1920 case JR:
1921 case JALR:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001922 *next_pc = get_register(instr->RsValue());
1923 *return_addr_reg = instr->RdValue();
Andrei Popescu31002712010-02-23 13:46:05 +00001924 break;
1925 case SLL:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001926 *alu_out = rt << sa;
Andrei Popescu31002712010-02-23 13:46:05 +00001927 break;
1928 case SRL:
Steve Block44f0eee2011-05-26 01:26:41 +01001929 if (rs_reg == 0) {
1930 // Regular logical right shift of a word by a fixed number of
1931 // bits instruction. RS field is always equal to 0.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001932 *alu_out = rt_u >> sa;
Steve Block44f0eee2011-05-26 01:26:41 +01001933 } else {
1934 // Logical right-rotate of a word by a fixed number of bits. This
1935 // is special case of SRL instruction, added in MIPS32 Release 2.
Ben Murdoch257744e2011-11-30 15:57:28 +00001936 // RS field is equal to 00001.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001937 *alu_out = (rt_u >> sa) | (rt_u << (32 - sa));
Steve Block44f0eee2011-05-26 01:26:41 +01001938 }
Andrei Popescu31002712010-02-23 13:46:05 +00001939 break;
1940 case SRA:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001941 *alu_out = rt >> sa;
Andrei Popescu31002712010-02-23 13:46:05 +00001942 break;
1943 case SLLV:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001944 *alu_out = rt << rs;
Andrei Popescu31002712010-02-23 13:46:05 +00001945 break;
1946 case SRLV:
Steve Block44f0eee2011-05-26 01:26:41 +01001947 if (sa == 0) {
1948 // Regular logical right-shift of a word by a variable number of
1949 // bits instruction. SA field is always equal to 0.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001950 *alu_out = rt_u >> rs;
Steve Block44f0eee2011-05-26 01:26:41 +01001951 } else {
1952 // Logical right-rotate of a word by a variable number of bits.
1953 // This is special case od SRLV instruction, added in MIPS32
Ben Murdoch257744e2011-11-30 15:57:28 +00001954 // Release 2. SA field is equal to 00001.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001955 *alu_out = (rt_u >> rs_u) | (rt_u << (32 - rs_u));
Steve Block44f0eee2011-05-26 01:26:41 +01001956 }
Andrei Popescu31002712010-02-23 13:46:05 +00001957 break;
1958 case SRAV:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001959 *alu_out = rt >> rs;
Andrei Popescu31002712010-02-23 13:46:05 +00001960 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001961 case MFHI: // MFHI == CLZ on R6.
1962 if (!IsMipsArchVariant(kMips32r6)) {
1963 DCHECK(instr->SaValue() == 0);
1964 *alu_out = get_register(HI);
1965 } else {
1966 // MIPS spec: If no bits were set in GPR rs, the result written to
1967 // GPR rd is 32.
1968 DCHECK(instr->SaValue() == 1);
1969 *alu_out = base::bits::CountLeadingZeros32(rs_u);
1970 }
Andrei Popescu31002712010-02-23 13:46:05 +00001971 break;
1972 case MFLO:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001973 *alu_out = get_register(LO);
Andrei Popescu31002712010-02-23 13:46:05 +00001974 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001975 case MULT: // MULT == MUL_MUH.
1976 if (!IsMipsArchVariant(kMips32r6)) {
1977 *i64hilo = static_cast<int64_t>(rs) * static_cast<int64_t>(rt);
1978 } else {
1979 switch (instr->SaValue()) {
1980 case MUL_OP:
1981 case MUH_OP:
1982 *i64hilo = static_cast<int64_t>(rs) * static_cast<int64_t>(rt);
1983 break;
1984 default:
1985 UNIMPLEMENTED_MIPS();
1986 break;
1987 }
1988 }
Andrei Popescu31002712010-02-23 13:46:05 +00001989 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001990 case MULTU: // MULTU == MUL_MUH_U.
1991 if (!IsMipsArchVariant(kMips32r6)) {
1992 *u64hilo = static_cast<uint64_t>(rs_u) *
1993 static_cast<uint64_t>(rt_u);
1994 } else {
1995 switch (instr->SaValue()) {
1996 case MUL_OP:
1997 case MUH_OP:
1998 *u64hilo = static_cast<uint64_t>(rs_u) *
1999 static_cast<uint64_t>(rt_u);
2000 break;
2001 default:
2002 UNIMPLEMENTED_MIPS();
2003 break;
2004 }
2005 }
Andrei Popescu31002712010-02-23 13:46:05 +00002006 break;
Andrei Popescu31002712010-02-23 13:46:05 +00002007 case ADD:
2008 if (HaveSameSign(rs, rt)) {
2009 if (rs > 0) {
2010 exceptions[kIntegerOverflow] = rs > (Registers::kMaxValue - rt);
2011 } else if (rs < 0) {
2012 exceptions[kIntegerUnderflow] = rs < (Registers::kMinValue - rt);
2013 }
2014 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002015 *alu_out = rs + rt;
Andrei Popescu31002712010-02-23 13:46:05 +00002016 break;
2017 case ADDU:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002018 *alu_out = rs + rt;
Andrei Popescu31002712010-02-23 13:46:05 +00002019 break;
2020 case SUB:
2021 if (!HaveSameSign(rs, rt)) {
2022 if (rs > 0) {
2023 exceptions[kIntegerOverflow] = rs > (Registers::kMaxValue + rt);
2024 } else if (rs < 0) {
2025 exceptions[kIntegerUnderflow] = rs < (Registers::kMinValue + rt);
2026 }
2027 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002028 *alu_out = rs - rt;
Andrei Popescu31002712010-02-23 13:46:05 +00002029 break;
2030 case SUBU:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002031 *alu_out = rs - rt;
Andrei Popescu31002712010-02-23 13:46:05 +00002032 break;
2033 case AND:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002034 *alu_out = rs & rt;
Andrei Popescu31002712010-02-23 13:46:05 +00002035 break;
2036 case OR:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002037 *alu_out = rs | rt;
Andrei Popescu31002712010-02-23 13:46:05 +00002038 break;
2039 case XOR:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002040 *alu_out = rs ^ rt;
Andrei Popescu31002712010-02-23 13:46:05 +00002041 break;
2042 case NOR:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002043 *alu_out = ~(rs | rt);
Andrei Popescu31002712010-02-23 13:46:05 +00002044 break;
2045 case SLT:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002046 *alu_out = rs < rt ? 1 : 0;
Andrei Popescu31002712010-02-23 13:46:05 +00002047 break;
2048 case SLTU:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002049 *alu_out = rs_u < rt_u ? 1 : 0;
Andrei Popescu31002712010-02-23 13:46:05 +00002050 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00002051 // Break and trap instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00002052 case BREAK:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002053 *do_interrupt = true;
Andrei Popescu31002712010-02-23 13:46:05 +00002054 break;
2055 case TGE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002056 *do_interrupt = rs >= rt;
Andrei Popescu31002712010-02-23 13:46:05 +00002057 break;
2058 case TGEU:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002059 *do_interrupt = rs_u >= rt_u;
Andrei Popescu31002712010-02-23 13:46:05 +00002060 break;
2061 case TLT:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002062 *do_interrupt = rs < rt;
Andrei Popescu31002712010-02-23 13:46:05 +00002063 break;
2064 case TLTU:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002065 *do_interrupt = rs_u < rt_u;
Andrei Popescu31002712010-02-23 13:46:05 +00002066 break;
2067 case TEQ:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002068 *do_interrupt = rs == rt;
Andrei Popescu31002712010-02-23 13:46:05 +00002069 break;
2070 case TNE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002071 *do_interrupt = rs != rt;
Andrei Popescu31002712010-02-23 13:46:05 +00002072 break;
Steve Block44f0eee2011-05-26 01:26:41 +01002073 case MOVN:
2074 case MOVZ:
2075 case MOVCI:
2076 // No action taken on decode.
2077 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00002078 case DIV:
2079 case DIVU:
2080 // div and divu never raise exceptions.
2081 break;
Andrei Popescu31002712010-02-23 13:46:05 +00002082 default:
2083 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002084 }
Andrei Popescu31002712010-02-23 13:46:05 +00002085 break;
2086 case SPECIAL2:
2087 switch (instr->FunctionFieldRaw()) {
2088 case MUL:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002089 *alu_out = rs_u * rt_u; // Only the lower 32 bits are kept.
Andrei Popescu31002712010-02-23 13:46:05 +00002090 break;
Steve Block44f0eee2011-05-26 01:26:41 +01002091 case CLZ:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002092 // MIPS32 spec: If no bits were set in GPR rs, the result written to
2093 // GPR rd is 32.
2094 *alu_out = base::bits::CountLeadingZeros32(rs_u);
Steve Block44f0eee2011-05-26 01:26:41 +01002095 break;
Andrei Popescu31002712010-02-23 13:46:05 +00002096 default:
2097 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002098 }
Steve Block44f0eee2011-05-26 01:26:41 +01002099 break;
2100 case SPECIAL3:
2101 switch (instr->FunctionFieldRaw()) {
2102 case INS: { // Mips32r2 instruction.
Ben Murdoch257744e2011-11-30 15:57:28 +00002103 // Interpret rd field as 5-bit msb of insert.
Steve Block44f0eee2011-05-26 01:26:41 +01002104 uint16_t msb = rd_reg;
2105 // Interpret sa field as 5-bit lsb of insert.
2106 uint16_t lsb = sa;
2107 uint16_t size = msb - lsb + 1;
2108 uint32_t mask = (1 << size) - 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002109 *alu_out = (rt_u & ~(mask << lsb)) | ((rs_u & mask) << lsb);
Steve Block44f0eee2011-05-26 01:26:41 +01002110 break;
2111 }
2112 case EXT: { // Mips32r2 instruction.
Ben Murdoch257744e2011-11-30 15:57:28 +00002113 // Interpret rd field as 5-bit msb of extract.
Steve Block44f0eee2011-05-26 01:26:41 +01002114 uint16_t msb = rd_reg;
2115 // Interpret sa field as 5-bit lsb of extract.
2116 uint16_t lsb = sa;
2117 uint16_t size = msb + 1;
2118 uint32_t mask = (1 << size) - 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002119 *alu_out = (rs_u & (mask << lsb)) >> lsb;
Steve Block44f0eee2011-05-26 01:26:41 +01002120 break;
2121 }
2122 default:
2123 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002124 }
Andrei Popescu31002712010-02-23 13:46:05 +00002125 break;
2126 default:
2127 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002128 }
Steve Block44f0eee2011-05-26 01:26:41 +01002129}
2130
2131
2132void Simulator::DecodeTypeRegister(Instruction* instr) {
2133 // Instruction fields.
2134 const Opcode op = instr->OpcodeFieldRaw();
2135 const int32_t rs_reg = instr->RsValue();
2136 const int32_t rs = get_register(rs_reg);
2137 const uint32_t rs_u = static_cast<uint32_t>(rs);
2138 const int32_t rt_reg = instr->RtValue();
2139 const int32_t rt = get_register(rt_reg);
2140 const uint32_t rt_u = static_cast<uint32_t>(rt);
2141 const int32_t rd_reg = instr->RdValue();
2142
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002143 const int32_t fr_reg = instr->FrValue();
Steve Block44f0eee2011-05-26 01:26:41 +01002144 const int32_t fs_reg = instr->FsValue();
2145 const int32_t ft_reg = instr->FtValue();
2146 const int32_t fd_reg = instr->FdValue();
2147 int64_t i64hilo = 0;
2148 uint64_t u64hilo = 0;
2149
Ben Murdoch257744e2011-11-30 15:57:28 +00002150 // ALU output.
Steve Block44f0eee2011-05-26 01:26:41 +01002151 // It should not be used as is. Instructions using it should always
2152 // initialize it first.
2153 int32_t alu_out = 0x12345678;
2154
2155 // For break and trap instructions.
2156 bool do_interrupt = false;
2157
Ben Murdoch257744e2011-11-30 15:57:28 +00002158 // For jr and jalr.
Steve Block44f0eee2011-05-26 01:26:41 +01002159 // Get current pc.
2160 int32_t current_pc = get_pc();
2161 // Next pc
2162 int32_t next_pc = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002163 int32_t return_addr_reg = 31;
Steve Block44f0eee2011-05-26 01:26:41 +01002164
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002165 // Set up the variables if needed before executing the instruction.
Steve Block44f0eee2011-05-26 01:26:41 +01002166 ConfigureTypeRegister(instr,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002167 &alu_out,
2168 &i64hilo,
2169 &u64hilo,
2170 &next_pc,
2171 &return_addr_reg,
2172 &do_interrupt);
Andrei Popescu31002712010-02-23 13:46:05 +00002173
2174 // ---------- Raise exceptions triggered.
2175 SignalExceptions();
2176
Ben Murdoch257744e2011-11-30 15:57:28 +00002177 // ---------- Execution.
Andrei Popescu31002712010-02-23 13:46:05 +00002178 switch (op) {
2179 case COP1:
2180 switch (instr->RsFieldRaw()) {
Steve Block44f0eee2011-05-26 01:26:41 +01002181 case CFC1:
2182 set_register(rt_reg, alu_out);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002183 break;
Andrei Popescu31002712010-02-23 13:46:05 +00002184 case MFC1:
Andrei Popescu31002712010-02-23 13:46:05 +00002185 set_register(rt_reg, alu_out);
2186 break;
Steve Block44f0eee2011-05-26 01:26:41 +01002187 case MFHC1:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002188 set_register(rt_reg, alu_out);
Steve Block44f0eee2011-05-26 01:26:41 +01002189 break;
2190 case CTC1:
2191 // At the moment only FCSR is supported.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002192 DCHECK(fs_reg == kFCSRRegister);
Steve Block44f0eee2011-05-26 01:26:41 +01002193 FCSR_ = registers_[rt_reg];
2194 break;
Andrei Popescu31002712010-02-23 13:46:05 +00002195 case MTC1:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002196 // Hardware writes upper 32-bits to zero on mtc1.
2197 set_fpu_register_hi_word(fs_reg, 0);
2198 set_fpu_register_word(fs_reg, registers_[rt_reg]);
Andrei Popescu31002712010-02-23 13:46:05 +00002199 break;
2200 case MTHC1:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002201 set_fpu_register_hi_word(fs_reg, registers_[rt_reg]);
Andrei Popescu31002712010-02-23 13:46:05 +00002202 break;
2203 case S:
Steve Block44f0eee2011-05-26 01:26:41 +01002204 float f;
Andrei Popescu31002712010-02-23 13:46:05 +00002205 switch (instr->FunctionFieldRaw()) {
2206 case CVT_D_S:
Steve Block44f0eee2011-05-26 01:26:41 +01002207 f = get_fpu_register_float(fs_reg);
2208 set_fpu_register_double(fd_reg, static_cast<double>(f));
2209 break;
Andrei Popescu31002712010-02-23 13:46:05 +00002210 default:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002211 // CVT_W_S CVT_L_S TRUNC_W_S ROUND_W_S ROUND_L_S FLOOR_W_S FLOOR_L_S
2212 // CEIL_W_S CEIL_L_S CVT_PS_S are unimplemented.
Andrei Popescu31002712010-02-23 13:46:05 +00002213 UNREACHABLE();
2214 }
2215 break;
2216 case D:
Steve Block44f0eee2011-05-26 01:26:41 +01002217 double ft, fs;
2218 uint32_t cc, fcsr_cc;
2219 int64_t i64;
2220 fs = get_fpu_register_double(fs_reg);
2221 ft = get_fpu_register_double(ft_reg);
2222 cc = instr->FCccValue();
2223 fcsr_cc = get_fcsr_condition_bit(cc);
Andrei Popescu31002712010-02-23 13:46:05 +00002224 switch (instr->FunctionFieldRaw()) {
Steve Block44f0eee2011-05-26 01:26:41 +01002225 case ADD_D:
2226 set_fpu_register_double(fd_reg, fs + ft);
2227 break;
2228 case SUB_D:
2229 set_fpu_register_double(fd_reg, fs - ft);
2230 break;
2231 case MUL_D:
2232 set_fpu_register_double(fd_reg, fs * ft);
2233 break;
2234 case DIV_D:
2235 set_fpu_register_double(fd_reg, fs / ft);
2236 break;
2237 case ABS_D:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002238 set_fpu_register_double(fd_reg, fabs(fs));
Steve Block44f0eee2011-05-26 01:26:41 +01002239 break;
2240 case MOV_D:
2241 set_fpu_register_double(fd_reg, fs);
2242 break;
2243 case NEG_D:
2244 set_fpu_register_double(fd_reg, -fs);
2245 break;
2246 case SQRT_D:
2247 set_fpu_register_double(fd_reg, sqrt(fs));
2248 break;
2249 case C_UN_D:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002250 set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft));
Steve Block44f0eee2011-05-26 01:26:41 +01002251 break;
2252 case C_EQ_D:
2253 set_fcsr_bit(fcsr_cc, (fs == ft));
2254 break;
2255 case C_UEQ_D:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002256 set_fcsr_bit(fcsr_cc,
2257 (fs == ft) || (std::isnan(fs) || std::isnan(ft)));
Steve Block44f0eee2011-05-26 01:26:41 +01002258 break;
2259 case C_OLT_D:
2260 set_fcsr_bit(fcsr_cc, (fs < ft));
2261 break;
2262 case C_ULT_D:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002263 set_fcsr_bit(fcsr_cc,
2264 (fs < ft) || (std::isnan(fs) || std::isnan(ft)));
Steve Block44f0eee2011-05-26 01:26:41 +01002265 break;
2266 case C_OLE_D:
2267 set_fcsr_bit(fcsr_cc, (fs <= ft));
2268 break;
2269 case C_ULE_D:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002270 set_fcsr_bit(fcsr_cc,
2271 (fs <= ft) || (std::isnan(fs) || std::isnan(ft)));
Steve Block44f0eee2011-05-26 01:26:41 +01002272 break;
2273 case CVT_W_D: // Convert double to word.
2274 // Rounding modes are not yet supported.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002275 DCHECK((FCSR_ & 3) == 0);
Steve Block44f0eee2011-05-26 01:26:41 +01002276 // In rounding mode 0 it should behave like ROUND.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002277 case ROUND_W_D: // Round double to word (round half to even).
Steve Block44f0eee2011-05-26 01:26:41 +01002278 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002279 double rounded = std::floor(fs + 0.5);
Steve Block44f0eee2011-05-26 01:26:41 +01002280 int32_t result = static_cast<int32_t>(rounded);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002281 if ((result & 1) != 0 && result - fs == 0.5) {
2282 // If the number is halfway between two integers,
2283 // round to the even one.
2284 result--;
2285 }
2286 set_fpu_register_word(fd_reg, result);
Steve Block44f0eee2011-05-26 01:26:41 +01002287 if (set_fcsr_round_error(fs, rounded)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002288 set_fpu_register_word(fd_reg, kFPUInvalidResult);
Steve Block44f0eee2011-05-26 01:26:41 +01002289 }
2290 }
2291 break;
2292 case TRUNC_W_D: // Truncate double to word (round towards 0).
2293 {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002294 double rounded = trunc(fs);
2295 int32_t result = static_cast<int32_t>(rounded);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002296 set_fpu_register_word(fd_reg, result);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002297 if (set_fcsr_round_error(fs, rounded)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002298 set_fpu_register_word(fd_reg, kFPUInvalidResult);
Steve Block44f0eee2011-05-26 01:26:41 +01002299 }
2300 }
2301 break;
2302 case FLOOR_W_D: // Round double to word towards negative infinity.
2303 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002304 double rounded = std::floor(fs);
Steve Block44f0eee2011-05-26 01:26:41 +01002305 int32_t result = static_cast<int32_t>(rounded);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002306 set_fpu_register_word(fd_reg, result);
Steve Block44f0eee2011-05-26 01:26:41 +01002307 if (set_fcsr_round_error(fs, rounded)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002308 set_fpu_register_word(fd_reg, kFPUInvalidResult);
Steve Block44f0eee2011-05-26 01:26:41 +01002309 }
2310 }
2311 break;
2312 case CEIL_W_D: // Round double to word towards positive infinity.
2313 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002314 double rounded = std::ceil(fs);
Steve Block44f0eee2011-05-26 01:26:41 +01002315 int32_t result = static_cast<int32_t>(rounded);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002316 set_fpu_register_word(fd_reg, result);
Steve Block44f0eee2011-05-26 01:26:41 +01002317 if (set_fcsr_round_error(fs, rounded)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002318 set_fpu_register_word(fd_reg, kFPUInvalidResult);
Steve Block44f0eee2011-05-26 01:26:41 +01002319 }
2320 }
2321 break;
2322 case CVT_S_D: // Convert double to float (single).
2323 set_fpu_register_float(fd_reg, static_cast<float>(fs));
2324 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002325 case CVT_L_D: { // Mips32r2: Truncate double to 64-bit long-word.
2326 double rounded = trunc(fs);
2327 i64 = static_cast<int64_t>(rounded);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002328 if (IsFp64Mode()) {
2329 set_fpu_register(fd_reg, i64);
2330 } else {
2331 set_fpu_register_word(fd_reg, i64 & 0xffffffff);
2332 set_fpu_register_word(fd_reg + 1, i64 >> 32);
2333 }
Steve Block44f0eee2011-05-26 01:26:41 +01002334 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002335 }
2336 case TRUNC_L_D: { // Mips32r2 instruction.
2337 double rounded = trunc(fs);
2338 i64 = static_cast<int64_t>(rounded);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002339 if (IsFp64Mode()) {
2340 set_fpu_register(fd_reg, i64);
2341 } else {
2342 set_fpu_register_word(fd_reg, i64 & 0xffffffff);
2343 set_fpu_register_word(fd_reg + 1, i64 >> 32);
2344 }
Steve Block44f0eee2011-05-26 01:26:41 +01002345 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002346 }
Steve Block44f0eee2011-05-26 01:26:41 +01002347 case ROUND_L_D: { // Mips32r2 instruction.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002348 double rounded =
2349 fs > 0 ? std::floor(fs + 0.5) : std::ceil(fs - 0.5);
Steve Block44f0eee2011-05-26 01:26:41 +01002350 i64 = static_cast<int64_t>(rounded);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002351 if (IsFp64Mode()) {
2352 set_fpu_register(fd_reg, i64);
2353 } else {
2354 set_fpu_register_word(fd_reg, i64 & 0xffffffff);
2355 set_fpu_register_word(fd_reg + 1, i64 >> 32);
2356 }
Steve Block44f0eee2011-05-26 01:26:41 +01002357 break;
2358 }
2359 case FLOOR_L_D: // Mips32r2 instruction.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002360 i64 = static_cast<int64_t>(std::floor(fs));
2361 if (IsFp64Mode()) {
2362 set_fpu_register(fd_reg, i64);
2363 } else {
2364 set_fpu_register_word(fd_reg, i64 & 0xffffffff);
2365 set_fpu_register_word(fd_reg + 1, i64 >> 32);
2366 }
Steve Block44f0eee2011-05-26 01:26:41 +01002367 break;
2368 case CEIL_L_D: // Mips32r2 instruction.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002369 i64 = static_cast<int64_t>(std::ceil(fs));
2370 if (IsFp64Mode()) {
2371 set_fpu_register(fd_reg, i64);
2372 } else {
2373 set_fpu_register_word(fd_reg, i64 & 0xffffffff);
2374 set_fpu_register_word(fd_reg + 1, i64 >> 32);
2375 }
Steve Block44f0eee2011-05-26 01:26:41 +01002376 break;
2377 case C_F_D:
Andrei Popescu31002712010-02-23 13:46:05 +00002378 UNIMPLEMENTED_MIPS();
2379 break;
2380 default:
2381 UNREACHABLE();
2382 }
2383 break;
2384 case W:
2385 switch (instr->FunctionFieldRaw()) {
Steve Block44f0eee2011-05-26 01:26:41 +01002386 case CVT_S_W: // Convert word to float (single).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002387 alu_out = get_fpu_register_signed_word(fs_reg);
Steve Block44f0eee2011-05-26 01:26:41 +01002388 set_fpu_register_float(fd_reg, static_cast<float>(alu_out));
Andrei Popescu31002712010-02-23 13:46:05 +00002389 break;
2390 case CVT_D_W: // Convert word to double.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002391 alu_out = get_fpu_register_signed_word(fs_reg);
Steve Block44f0eee2011-05-26 01:26:41 +01002392 set_fpu_register_double(fd_reg, static_cast<double>(alu_out));
Andrei Popescu31002712010-02-23 13:46:05 +00002393 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002394 default: // Mips64r6 CMP.S instructions unimplemented.
Andrei Popescu31002712010-02-23 13:46:05 +00002395 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002396 }
Andrei Popescu31002712010-02-23 13:46:05 +00002397 break;
2398 case L:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002399 fs = get_fpu_register_double(fs_reg);
2400 ft = get_fpu_register_double(ft_reg);
Andrei Popescu31002712010-02-23 13:46:05 +00002401 switch (instr->FunctionFieldRaw()) {
Steve Block44f0eee2011-05-26 01:26:41 +01002402 case CVT_D_L: // Mips32r2 instruction.
2403 // Watch the signs here, we want 2 32-bit vals
2404 // to make a sign-64.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002405 if (IsFp64Mode()) {
2406 i64 = get_fpu_register(fs_reg);
2407 } else {
2408 i64 = static_cast<uint32_t>(get_fpu_register_word(fs_reg));
2409 i64 |= static_cast<int64_t>(
2410 get_fpu_register_word(fs_reg + 1)) << 32;
2411 }
Steve Block44f0eee2011-05-26 01:26:41 +01002412 set_fpu_register_double(fd_reg, static_cast<double>(i64));
2413 break;
Andrei Popescu31002712010-02-23 13:46:05 +00002414 case CVT_S_L:
Andrei Popescu31002712010-02-23 13:46:05 +00002415 UNIMPLEMENTED_MIPS();
2416 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002417 case CMP_AF: // Mips64r6 CMP.D instructions.
2418 UNIMPLEMENTED_MIPS();
2419 break;
2420 case CMP_UN:
2421 if (std::isnan(fs) || std::isnan(ft)) {
2422 set_fpu_register(fd_reg, -1);
2423 } else {
2424 set_fpu_register(fd_reg, 0);
2425 }
2426 break;
2427 case CMP_EQ:
2428 if (fs == ft) {
2429 set_fpu_register(fd_reg, -1);
2430 } else {
2431 set_fpu_register(fd_reg, 0);
2432 }
2433 break;
2434 case CMP_UEQ:
2435 if ((fs == ft) || (std::isnan(fs) || std::isnan(ft))) {
2436 set_fpu_register(fd_reg, -1);
2437 } else {
2438 set_fpu_register(fd_reg, 0);
2439 }
2440 break;
2441 case CMP_LT:
2442 if (fs < ft) {
2443 set_fpu_register(fd_reg, -1);
2444 } else {
2445 set_fpu_register(fd_reg, 0);
2446 }
2447 break;
2448 case CMP_ULT:
2449 if ((fs < ft) || (std::isnan(fs) || std::isnan(ft))) {
2450 set_fpu_register(fd_reg, -1);
2451 } else {
2452 set_fpu_register(fd_reg, 0);
2453 }
2454 break;
2455 case CMP_LE:
2456 if (fs <= ft) {
2457 set_fpu_register(fd_reg, -1);
2458 } else {
2459 set_fpu_register(fd_reg, 0);
2460 }
2461 break;
2462 case CMP_ULE:
2463 if ((fs <= ft) || (std::isnan(fs) || std::isnan(ft))) {
2464 set_fpu_register(fd_reg, -1);
2465 } else {
2466 set_fpu_register(fd_reg, 0);
2467 }
2468 break;
2469 default: // CMP_OR CMP_UNE CMP_NE UNIMPLEMENTED.
Andrei Popescu31002712010-02-23 13:46:05 +00002470 UNREACHABLE();
2471 }
2472 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002473 default:
2474 UNREACHABLE();
2475 }
2476 break;
2477 case COP1X:
2478 switch (instr->FunctionFieldRaw()) {
2479 case MADD_D:
2480 double fr, ft, fs;
2481 fr = get_fpu_register_double(fr_reg);
2482 fs = get_fpu_register_double(fs_reg);
2483 ft = get_fpu_register_double(ft_reg);
2484 set_fpu_register_double(fd_reg, fs * ft + fr);
Andrei Popescu31002712010-02-23 13:46:05 +00002485 break;
2486 default:
2487 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002488 }
Andrei Popescu31002712010-02-23 13:46:05 +00002489 break;
2490 case SPECIAL:
2491 switch (instr->FunctionFieldRaw()) {
2492 case JR: {
2493 Instruction* branch_delay_instr = reinterpret_cast<Instruction*>(
Steve Block44f0eee2011-05-26 01:26:41 +01002494 current_pc+Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +00002495 BranchDelayInstructionDecode(branch_delay_instr);
2496 set_pc(next_pc);
2497 pc_modified_ = true;
2498 break;
2499 }
2500 case JALR: {
2501 Instruction* branch_delay_instr = reinterpret_cast<Instruction*>(
Steve Block44f0eee2011-05-26 01:26:41 +01002502 current_pc+Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +00002503 BranchDelayInstructionDecode(branch_delay_instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002504 set_register(return_addr_reg,
2505 current_pc + 2 * Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +00002506 set_pc(next_pc);
2507 pc_modified_ = true;
2508 break;
2509 }
2510 // Instructions using HI and LO registers.
2511 case MULT:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002512 if (!IsMipsArchVariant(kMips32r6)) {
2513 set_register(LO, static_cast<int32_t>(i64hilo & 0xffffffff));
2514 set_register(HI, static_cast<int32_t>(i64hilo >> 32));
2515 } else {
2516 switch (instr->SaValue()) {
2517 case MUL_OP:
2518 set_register(rd_reg,
2519 static_cast<int32_t>(i64hilo & 0xffffffff));
2520 break;
2521 case MUH_OP:
2522 set_register(rd_reg, static_cast<int32_t>(i64hilo >> 32));
2523 break;
2524 default:
2525 UNIMPLEMENTED_MIPS();
2526 break;
2527 }
2528 }
Steve Block44f0eee2011-05-26 01:26:41 +01002529 break;
Andrei Popescu31002712010-02-23 13:46:05 +00002530 case MULTU:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002531 if (!IsMipsArchVariant(kMips32r6)) {
2532 set_register(LO, static_cast<int32_t>(u64hilo & 0xffffffff));
2533 set_register(HI, static_cast<int32_t>(u64hilo >> 32));
2534 } else {
2535 switch (instr->SaValue()) {
2536 case MUL_OP:
2537 set_register(rd_reg,
2538 static_cast<int32_t>(u64hilo & 0xffffffff));
2539 break;
2540 case MUH_OP:
2541 set_register(rd_reg, static_cast<int32_t>(u64hilo >> 32));
2542 break;
2543 default:
2544 UNIMPLEMENTED_MIPS();
2545 break;
2546 }
2547 }
Andrei Popescu31002712010-02-23 13:46:05 +00002548 break;
2549 case DIV:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002550 if (IsMipsArchVariant(kMips32r6)) {
2551 switch (instr->SaValue()) {
2552 case DIV_OP:
2553 if (rs == INT_MIN && rt == -1) {
2554 set_register(rd_reg, INT_MIN);
2555 } else if (rt != 0) {
2556 set_register(rd_reg, rs / rt);
2557 }
2558 break;
2559 case MOD_OP:
2560 if (rs == INT_MIN && rt == -1) {
2561 set_register(rd_reg, 0);
2562 } else if (rt != 0) {
2563 set_register(rd_reg, rs % rt);
2564 }
2565 break;
2566 default:
2567 UNIMPLEMENTED_MIPS();
2568 break;
2569 }
2570 } else {
2571 // Divide by zero and overflow was not checked in the
2572 // configuration step - div and divu do not raise exceptions. On
2573 // division by 0 the result will be UNPREDICTABLE. On overflow
2574 // (INT_MIN/-1), return INT_MIN which is what the hardware does.
2575 if (rs == INT_MIN && rt == -1) {
2576 set_register(LO, INT_MIN);
2577 set_register(HI, 0);
2578 } else if (rt != 0) {
2579 set_register(LO, rs / rt);
2580 set_register(HI, rs % rt);
2581 }
Ben Murdoch257744e2011-11-30 15:57:28 +00002582 }
Andrei Popescu31002712010-02-23 13:46:05 +00002583 break;
2584 case DIVU:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002585 if (IsMipsArchVariant(kMips32r6)) {
2586 switch (instr->SaValue()) {
2587 case DIV_OP:
2588 if (rt_u != 0) {
2589 set_register(rd_reg, rs_u / rt_u);
2590 }
2591 break;
2592 case MOD_OP:
2593 if (rt_u != 0) {
2594 set_register(rd_reg, rs_u % rt_u);
2595 }
2596 break;
2597 default:
2598 UNIMPLEMENTED_MIPS();
2599 break;
2600 }
2601 } else {
2602 if (rt_u != 0) {
2603 set_register(LO, rs_u / rt_u);
2604 set_register(HI, rs_u % rt_u);
2605 }
Ben Murdoch257744e2011-11-30 15:57:28 +00002606 }
Andrei Popescu31002712010-02-23 13:46:05 +00002607 break;
Steve Block44f0eee2011-05-26 01:26:41 +01002608 // Break and trap instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00002609 case BREAK:
2610 case TGE:
2611 case TGEU:
2612 case TLT:
2613 case TLTU:
2614 case TEQ:
2615 case TNE:
2616 if (do_interrupt) {
2617 SoftwareInterrupt(instr);
2618 }
2619 break;
Steve Block44f0eee2011-05-26 01:26:41 +01002620 // Conditional moves.
2621 case MOVN:
2622 if (rt) set_register(rd_reg, rs);
2623 break;
2624 case MOVCI: {
Ben Murdoch257744e2011-11-30 15:57:28 +00002625 uint32_t cc = instr->FBccValue();
Steve Block44f0eee2011-05-26 01:26:41 +01002626 uint32_t fcsr_cc = get_fcsr_condition_bit(cc);
Ben Murdoch257744e2011-11-30 15:57:28 +00002627 if (instr->Bit(16)) { // Read Tf bit.
Steve Block44f0eee2011-05-26 01:26:41 +01002628 if (test_fcsr_bit(fcsr_cc)) set_register(rd_reg, rs);
2629 } else {
2630 if (!test_fcsr_bit(fcsr_cc)) set_register(rd_reg, rs);
2631 }
2632 break;
2633 }
2634 case MOVZ:
2635 if (!rt) set_register(rd_reg, rs);
2636 break;
Andrei Popescu31002712010-02-23 13:46:05 +00002637 default: // For other special opcodes we do the default operation.
2638 set_register(rd_reg, alu_out);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002639 }
Andrei Popescu31002712010-02-23 13:46:05 +00002640 break;
2641 case SPECIAL2:
2642 switch (instr->FunctionFieldRaw()) {
2643 case MUL:
2644 set_register(rd_reg, alu_out);
2645 // HI and LO are UNPREDICTABLE after the operation.
2646 set_register(LO, Unpredictable);
2647 set_register(HI, Unpredictable);
2648 break;
Steve Block44f0eee2011-05-26 01:26:41 +01002649 default: // For other special2 opcodes we do the default operation.
2650 set_register(rd_reg, alu_out);
2651 }
2652 break;
2653 case SPECIAL3:
2654 switch (instr->FunctionFieldRaw()) {
2655 case INS:
2656 // Ins instr leaves result in Rt, rather than Rd.
2657 set_register(rt_reg, alu_out);
2658 break;
2659 case EXT:
2660 // Ext instr leaves result in Rt, rather than Rd.
2661 set_register(rt_reg, alu_out);
2662 break;
Andrei Popescu31002712010-02-23 13:46:05 +00002663 default:
2664 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002665 }
Andrei Popescu31002712010-02-23 13:46:05 +00002666 break;
2667 // Unimplemented opcodes raised an error in the configuration step before,
2668 // so we can use the default here to set the destination register in common
2669 // cases.
2670 default:
2671 set_register(rd_reg, alu_out);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002672 }
Andrei Popescu31002712010-02-23 13:46:05 +00002673}
2674
Steve Block44f0eee2011-05-26 01:26:41 +01002675
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002676// Type 2: instructions using a 16 bytes immediate. (e.g. addi, beq).
Andrei Popescu31002712010-02-23 13:46:05 +00002677void Simulator::DecodeTypeImmediate(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +01002678 // Instruction fields.
Andrei Popescu31002712010-02-23 13:46:05 +00002679 Opcode op = instr->OpcodeFieldRaw();
Steve Block44f0eee2011-05-26 01:26:41 +01002680 int32_t rs = get_register(instr->RsValue());
Andrei Popescu31002712010-02-23 13:46:05 +00002681 uint32_t rs_u = static_cast<uint32_t>(rs);
Ben Murdoch257744e2011-11-30 15:57:28 +00002682 int32_t rt_reg = instr->RtValue(); // Destination register.
Andrei Popescu31002712010-02-23 13:46:05 +00002683 int32_t rt = get_register(rt_reg);
Steve Block44f0eee2011-05-26 01:26:41 +01002684 int16_t imm16 = instr->Imm16Value();
Andrei Popescu31002712010-02-23 13:46:05 +00002685
Ben Murdoch257744e2011-11-30 15:57:28 +00002686 int32_t ft_reg = instr->FtValue(); // Destination register.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002687 int64_t ft;
Andrei Popescu31002712010-02-23 13:46:05 +00002688
Steve Block44f0eee2011-05-26 01:26:41 +01002689 // Zero extended immediate.
Andrei Popescu31002712010-02-23 13:46:05 +00002690 uint32_t oe_imm16 = 0xffff & imm16;
Steve Block44f0eee2011-05-26 01:26:41 +01002691 // Sign extended immediate.
Andrei Popescu31002712010-02-23 13:46:05 +00002692 int32_t se_imm16 = imm16;
2693
2694 // Get current pc.
2695 int32_t current_pc = get_pc();
2696 // Next pc.
2697 int32_t next_pc = bad_ra;
2698
Steve Block44f0eee2011-05-26 01:26:41 +01002699 // Used for conditional branch instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00002700 bool do_branch = false;
2701 bool execute_branch_delay_instruction = false;
2702
Steve Block44f0eee2011-05-26 01:26:41 +01002703 // Used for arithmetic instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00002704 int32_t alu_out = 0;
Steve Block44f0eee2011-05-26 01:26:41 +01002705 // Floating point.
Andrei Popescu31002712010-02-23 13:46:05 +00002706 double fp_out = 0.0;
Steve Block44f0eee2011-05-26 01:26:41 +01002707 uint32_t cc, cc_value, fcsr_cc;
Andrei Popescu31002712010-02-23 13:46:05 +00002708
Steve Block44f0eee2011-05-26 01:26:41 +01002709 // Used for memory instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00002710 int32_t addr = 0x0;
Ben Murdoch257744e2011-11-30 15:57:28 +00002711 // Value to be written in memory.
Steve Block44f0eee2011-05-26 01:26:41 +01002712 uint32_t mem_value = 0x0;
Andrei Popescu31002712010-02-23 13:46:05 +00002713
Ben Murdoch257744e2011-11-30 15:57:28 +00002714 // ---------- Configuration (and execution for REGIMM).
Andrei Popescu31002712010-02-23 13:46:05 +00002715 switch (op) {
Steve Block44f0eee2011-05-26 01:26:41 +01002716 // ------------- COP1. Coprocessor instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00002717 case COP1:
2718 switch (instr->RsFieldRaw()) {
Steve Block44f0eee2011-05-26 01:26:41 +01002719 case BC1: // Branch on coprocessor condition.
2720 cc = instr->FBccValue();
2721 fcsr_cc = get_fcsr_condition_bit(cc);
2722 cc_value = test_fcsr_bit(fcsr_cc);
2723 do_branch = (instr->FBtrueValue()) ? cc_value : !cc_value;
2724 execute_branch_delay_instruction = true;
Ben Murdoch257744e2011-11-30 15:57:28 +00002725 // Set next_pc.
Steve Block44f0eee2011-05-26 01:26:41 +01002726 if (do_branch) {
2727 next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
2728 } else {
2729 next_pc = current_pc + kBranchReturnOffset;
2730 }
Andrei Popescu31002712010-02-23 13:46:05 +00002731 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002732 case BC1EQZ:
2733 ft = get_fpu_register(ft_reg);
2734 do_branch = (ft & 0x1) ? false : true;
2735 execute_branch_delay_instruction = true;
2736 // Set next_pc.
2737 if (do_branch) {
2738 next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
2739 } else {
2740 next_pc = current_pc + kBranchReturnOffset;
2741 }
2742 break;
2743 case BC1NEZ:
2744 ft = get_fpu_register(ft_reg);
2745 do_branch = (ft & 0x1) ? true : false;
2746 execute_branch_delay_instruction = true;
2747 // Set next_pc.
2748 if (do_branch) {
2749 next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
2750 } else {
2751 next_pc = current_pc + kBranchReturnOffset;
2752 }
2753 break;
Andrei Popescu31002712010-02-23 13:46:05 +00002754 default:
2755 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002756 }
Andrei Popescu31002712010-02-23 13:46:05 +00002757 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00002758 // ------------- REGIMM class.
Andrei Popescu31002712010-02-23 13:46:05 +00002759 case REGIMM:
2760 switch (instr->RtFieldRaw()) {
2761 case BLTZ:
2762 do_branch = (rs < 0);
2763 break;
2764 case BLTZAL:
2765 do_branch = rs < 0;
2766 break;
2767 case BGEZ:
2768 do_branch = rs >= 0;
2769 break;
2770 case BGEZAL:
2771 do_branch = rs >= 0;
2772 break;
2773 default:
2774 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002775 }
Andrei Popescu31002712010-02-23 13:46:05 +00002776 switch (instr->RtFieldRaw()) {
2777 case BLTZ:
2778 case BLTZAL:
2779 case BGEZ:
2780 case BGEZAL:
2781 // Branch instructions common part.
2782 execute_branch_delay_instruction = true;
Ben Murdoch257744e2011-11-30 15:57:28 +00002783 // Set next_pc.
Andrei Popescu31002712010-02-23 13:46:05 +00002784 if (do_branch) {
Steve Block44f0eee2011-05-26 01:26:41 +01002785 next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
Andrei Popescu31002712010-02-23 13:46:05 +00002786 if (instr->IsLinkingInstruction()) {
2787 set_register(31, current_pc + kBranchReturnOffset);
2788 }
2789 } else {
2790 next_pc = current_pc + kBranchReturnOffset;
2791 }
2792 default:
2793 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002794 }
Ben Murdoch257744e2011-11-30 15:57:28 +00002795 break; // case REGIMM.
2796 // ------------- Branch instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00002797 // When comparing to zero, the encoding of rt field is always 0, so we don't
2798 // need to replace rt with zero.
2799 case BEQ:
2800 do_branch = (rs == rt);
2801 break;
2802 case BNE:
2803 do_branch = rs != rt;
2804 break;
2805 case BLEZ:
2806 do_branch = rs <= 0;
2807 break;
2808 case BGTZ:
2809 do_branch = rs > 0;
2810 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00002811 // ------------- Arithmetic instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00002812 case ADDI:
2813 if (HaveSameSign(rs, se_imm16)) {
2814 if (rs > 0) {
2815 exceptions[kIntegerOverflow] = rs > (Registers::kMaxValue - se_imm16);
2816 } else if (rs < 0) {
2817 exceptions[kIntegerUnderflow] =
2818 rs < (Registers::kMinValue - se_imm16);
2819 }
2820 }
2821 alu_out = rs + se_imm16;
2822 break;
2823 case ADDIU:
2824 alu_out = rs + se_imm16;
2825 break;
2826 case SLTI:
2827 alu_out = (rs < se_imm16) ? 1 : 0;
2828 break;
2829 case SLTIU:
2830 alu_out = (rs_u < static_cast<uint32_t>(se_imm16)) ? 1 : 0;
2831 break;
2832 case ANDI:
2833 alu_out = rs & oe_imm16;
2834 break;
2835 case ORI:
2836 alu_out = rs | oe_imm16;
2837 break;
2838 case XORI:
2839 alu_out = rs ^ oe_imm16;
2840 break;
2841 case LUI:
2842 alu_out = (oe_imm16 << 16);
2843 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00002844 // ------------- Memory instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00002845 case LB:
2846 addr = rs + se_imm16;
2847 alu_out = ReadB(addr);
2848 break;
Steve Block44f0eee2011-05-26 01:26:41 +01002849 case LH:
2850 addr = rs + se_imm16;
2851 alu_out = ReadH(addr, instr);
2852 break;
2853 case LWL: {
Ben Murdoch257744e2011-11-30 15:57:28 +00002854 // al_offset is offset of the effective address within an aligned word.
Steve Block44f0eee2011-05-26 01:26:41 +01002855 uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
2856 uint8_t byte_shift = kPointerAlignmentMask - al_offset;
2857 uint32_t mask = (1 << byte_shift * 8) - 1;
2858 addr = rs + se_imm16 - al_offset;
2859 alu_out = ReadW(addr, instr);
2860 alu_out <<= byte_shift * 8;
2861 alu_out |= rt & mask;
2862 break;
2863 }
Andrei Popescu31002712010-02-23 13:46:05 +00002864 case LW:
2865 addr = rs + se_imm16;
2866 alu_out = ReadW(addr, instr);
2867 break;
2868 case LBU:
2869 addr = rs + se_imm16;
2870 alu_out = ReadBU(addr);
2871 break;
Steve Block44f0eee2011-05-26 01:26:41 +01002872 case LHU:
2873 addr = rs + se_imm16;
2874 alu_out = ReadHU(addr, instr);
2875 break;
2876 case LWR: {
Ben Murdoch257744e2011-11-30 15:57:28 +00002877 // al_offset is offset of the effective address within an aligned word.
Steve Block44f0eee2011-05-26 01:26:41 +01002878 uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
2879 uint8_t byte_shift = kPointerAlignmentMask - al_offset;
2880 uint32_t mask = al_offset ? (~0 << (byte_shift + 1) * 8) : 0;
2881 addr = rs + se_imm16 - al_offset;
2882 alu_out = ReadW(addr, instr);
2883 alu_out = static_cast<uint32_t> (alu_out) >> al_offset * 8;
2884 alu_out |= rt & mask;
2885 break;
2886 }
Andrei Popescu31002712010-02-23 13:46:05 +00002887 case SB:
2888 addr = rs + se_imm16;
2889 break;
Steve Block44f0eee2011-05-26 01:26:41 +01002890 case SH:
2891 addr = rs + se_imm16;
2892 break;
2893 case SWL: {
2894 uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
2895 uint8_t byte_shift = kPointerAlignmentMask - al_offset;
2896 uint32_t mask = byte_shift ? (~0 << (al_offset + 1) * 8) : 0;
2897 addr = rs + se_imm16 - al_offset;
2898 mem_value = ReadW(addr, instr) & mask;
2899 mem_value |= static_cast<uint32_t>(rt) >> byte_shift * 8;
2900 break;
2901 }
Andrei Popescu31002712010-02-23 13:46:05 +00002902 case SW:
2903 addr = rs + se_imm16;
2904 break;
Steve Block44f0eee2011-05-26 01:26:41 +01002905 case SWR: {
2906 uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
2907 uint32_t mask = (1 << al_offset * 8) - 1;
2908 addr = rs + se_imm16 - al_offset;
2909 mem_value = ReadW(addr, instr);
2910 mem_value = (rt << al_offset * 8) | (mem_value & mask);
2911 break;
2912 }
Andrei Popescu31002712010-02-23 13:46:05 +00002913 case LWC1:
2914 addr = rs + se_imm16;
2915 alu_out = ReadW(addr, instr);
2916 break;
2917 case LDC1:
2918 addr = rs + se_imm16;
2919 fp_out = ReadD(addr, instr);
2920 break;
2921 case SWC1:
2922 case SDC1:
2923 addr = rs + se_imm16;
2924 break;
2925 default:
2926 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002927 }
Andrei Popescu31002712010-02-23 13:46:05 +00002928
2929 // ---------- Raise exceptions triggered.
2930 SignalExceptions();
2931
Ben Murdoch257744e2011-11-30 15:57:28 +00002932 // ---------- Execution.
Andrei Popescu31002712010-02-23 13:46:05 +00002933 switch (op) {
Ben Murdoch257744e2011-11-30 15:57:28 +00002934 // ------------- Branch instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00002935 case BEQ:
2936 case BNE:
2937 case BLEZ:
2938 case BGTZ:
2939 // Branch instructions common part.
2940 execute_branch_delay_instruction = true;
Ben Murdoch257744e2011-11-30 15:57:28 +00002941 // Set next_pc.
Andrei Popescu31002712010-02-23 13:46:05 +00002942 if (do_branch) {
Steve Block44f0eee2011-05-26 01:26:41 +01002943 next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
Andrei Popescu31002712010-02-23 13:46:05 +00002944 if (instr->IsLinkingInstruction()) {
Steve Block44f0eee2011-05-26 01:26:41 +01002945 set_register(31, current_pc + 2* Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +00002946 }
2947 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01002948 next_pc = current_pc + 2 * Instruction::kInstrSize;
Andrei Popescu31002712010-02-23 13:46:05 +00002949 }
2950 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00002951 // ------------- Arithmetic instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00002952 case ADDI:
2953 case ADDIU:
2954 case SLTI:
2955 case SLTIU:
2956 case ANDI:
2957 case ORI:
2958 case XORI:
2959 case LUI:
2960 set_register(rt_reg, alu_out);
2961 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00002962 // ------------- Memory instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00002963 case LB:
Steve Block44f0eee2011-05-26 01:26:41 +01002964 case LH:
2965 case LWL:
Andrei Popescu31002712010-02-23 13:46:05 +00002966 case LW:
2967 case LBU:
Steve Block44f0eee2011-05-26 01:26:41 +01002968 case LHU:
2969 case LWR:
Andrei Popescu31002712010-02-23 13:46:05 +00002970 set_register(rt_reg, alu_out);
2971 break;
2972 case SB:
2973 WriteB(addr, static_cast<int8_t>(rt));
2974 break;
Steve Block44f0eee2011-05-26 01:26:41 +01002975 case SH:
2976 WriteH(addr, static_cast<uint16_t>(rt), instr);
2977 break;
2978 case SWL:
2979 WriteW(addr, mem_value, instr);
2980 break;
Andrei Popescu31002712010-02-23 13:46:05 +00002981 case SW:
2982 WriteW(addr, rt, instr);
2983 break;
Steve Block44f0eee2011-05-26 01:26:41 +01002984 case SWR:
2985 WriteW(addr, mem_value, instr);
2986 break;
Andrei Popescu31002712010-02-23 13:46:05 +00002987 case LWC1:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002988 set_fpu_register_hi_word(ft_reg, 0);
2989 set_fpu_register_word(ft_reg, alu_out);
Andrei Popescu31002712010-02-23 13:46:05 +00002990 break;
2991 case LDC1:
2992 set_fpu_register_double(ft_reg, fp_out);
2993 break;
2994 case SWC1:
2995 addr = rs + se_imm16;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002996 WriteW(addr, get_fpu_register_word(ft_reg), instr);
Andrei Popescu31002712010-02-23 13:46:05 +00002997 break;
2998 case SDC1:
2999 addr = rs + se_imm16;
Steve Block44f0eee2011-05-26 01:26:41 +01003000 WriteD(addr, get_fpu_register_double(ft_reg), instr);
Andrei Popescu31002712010-02-23 13:46:05 +00003001 break;
3002 default:
3003 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003004 }
Andrei Popescu31002712010-02-23 13:46:05 +00003005
3006
3007 if (execute_branch_delay_instruction) {
3008 // Execute branch delay slot
3009 // We don't check for end_sim_pc. First it should not be met as the current
3010 // pc is valid. Secondly a jump should always execute its branch delay slot.
3011 Instruction* branch_delay_instr =
Steve Block44f0eee2011-05-26 01:26:41 +01003012 reinterpret_cast<Instruction*>(current_pc+Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +00003013 BranchDelayInstructionDecode(branch_delay_instr);
3014 }
3015
3016 // If needed update pc after the branch delay execution.
3017 if (next_pc != bad_ra) {
3018 set_pc(next_pc);
3019 }
3020}
3021
Steve Block44f0eee2011-05-26 01:26:41 +01003022
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003023// Type 3: instructions using a 26 bytes immediate. (e.g. j, jal).
Andrei Popescu31002712010-02-23 13:46:05 +00003024void Simulator::DecodeTypeJump(Instruction* instr) {
3025 // Get current pc.
3026 int32_t current_pc = get_pc();
3027 // Get unchanged bits of pc.
3028 int32_t pc_high_bits = current_pc & 0xf0000000;
Ben Murdoch257744e2011-11-30 15:57:28 +00003029 // Next pc.
Steve Block44f0eee2011-05-26 01:26:41 +01003030 int32_t next_pc = pc_high_bits | (instr->Imm26Value() << 2);
Andrei Popescu31002712010-02-23 13:46:05 +00003031
Ben Murdoch257744e2011-11-30 15:57:28 +00003032 // Execute branch delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00003033 // We don't check for end_sim_pc. First it should not be met as the current pc
3034 // is valid. Secondly a jump should always execute its branch delay slot.
3035 Instruction* branch_delay_instr =
Ben Murdoch257744e2011-11-30 15:57:28 +00003036 reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +00003037 BranchDelayInstructionDecode(branch_delay_instr);
3038
3039 // Update pc and ra if necessary.
3040 // Do this after the branch delay execution.
3041 if (instr->IsLinkingInstruction()) {
Ben Murdoch257744e2011-11-30 15:57:28 +00003042 set_register(31, current_pc + 2 * Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +00003043 }
3044 set_pc(next_pc);
3045 pc_modified_ = true;
3046}
3047
Steve Block44f0eee2011-05-26 01:26:41 +01003048
Andrei Popescu31002712010-02-23 13:46:05 +00003049// Executes the current instruction.
3050void Simulator::InstructionDecode(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +01003051 if (v8::internal::FLAG_check_icache) {
3052 CheckICache(isolate_->simulator_i_cache(), instr);
3053 }
Andrei Popescu31002712010-02-23 13:46:05 +00003054 pc_modified_ = false;
3055 if (::v8::internal::FLAG_trace_sim) {
3056 disasm::NameConverter converter;
3057 disasm::Disassembler dasm(converter);
Ben Murdoch257744e2011-11-30 15:57:28 +00003058 // Use a reasonably large buffer.
Andrei Popescu31002712010-02-23 13:46:05 +00003059 v8::internal::EmbeddedVector<char, 256> buffer;
Ben Murdoch257744e2011-11-30 15:57:28 +00003060 dasm.InstructionDecode(buffer, reinterpret_cast<byte*>(instr));
Steve Block44f0eee2011-05-26 01:26:41 +01003061 PrintF(" 0x%08x %s\n", reinterpret_cast<intptr_t>(instr),
Ben Murdoch257744e2011-11-30 15:57:28 +00003062 buffer.start());
Andrei Popescu31002712010-02-23 13:46:05 +00003063 }
3064
3065 switch (instr->InstructionType()) {
3066 case Instruction::kRegisterType:
3067 DecodeTypeRegister(instr);
3068 break;
3069 case Instruction::kImmediateType:
3070 DecodeTypeImmediate(instr);
3071 break;
3072 case Instruction::kJumpType:
3073 DecodeTypeJump(instr);
3074 break;
3075 default:
3076 UNSUPPORTED();
3077 }
3078 if (!pc_modified_) {
3079 set_register(pc, reinterpret_cast<int32_t>(instr) +
Steve Block44f0eee2011-05-26 01:26:41 +01003080 Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +00003081 }
3082}
3083
3084
3085
3086void Simulator::Execute() {
3087 // Get the PC to simulate. Cannot use the accessor here as we need the
3088 // raw PC value and not the one used as input to arithmetic instructions.
3089 int program_counter = get_pc();
3090 if (::v8::internal::FLAG_stop_sim_at == 0) {
3091 // Fast version of the dispatch loop without checking whether the simulator
3092 // should be stopping at a particular executed instruction.
3093 while (program_counter != end_sim_pc) {
3094 Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
3095 icount_++;
3096 InstructionDecode(instr);
3097 program_counter = get_pc();
3098 }
3099 } else {
3100 // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when
3101 // we reach the particular instuction count.
3102 while (program_counter != end_sim_pc) {
3103 Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
3104 icount_++;
3105 if (icount_ == ::v8::internal::FLAG_stop_sim_at) {
Steve Block44f0eee2011-05-26 01:26:41 +01003106 MipsDebugger dbg(this);
Andrei Popescu31002712010-02-23 13:46:05 +00003107 dbg.Debug();
3108 } else {
3109 InstructionDecode(instr);
3110 }
3111 program_counter = get_pc();
3112 }
3113 }
3114}
3115
3116
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003117void Simulator::CallInternal(byte* entry) {
Ben Murdoch257744e2011-11-30 15:57:28 +00003118 // Prepare to execute the code at entry.
Andrei Popescu31002712010-02-23 13:46:05 +00003119 set_register(pc, reinterpret_cast<int32_t>(entry));
3120 // Put down marker for end of simulation. The simulator will stop simulation
3121 // when the PC reaches this value. By saving the "end simulation" value into
3122 // the LR the simulation stops when returning to this call point.
3123 set_register(ra, end_sim_pc);
3124
3125 // Remember the values of callee-saved registers.
3126 // The code below assumes that r9 is not used as sb (static base) in
3127 // simulator code and therefore is regarded as a callee-saved register.
3128 int32_t s0_val = get_register(s0);
3129 int32_t s1_val = get_register(s1);
3130 int32_t s2_val = get_register(s2);
3131 int32_t s3_val = get_register(s3);
3132 int32_t s4_val = get_register(s4);
3133 int32_t s5_val = get_register(s5);
3134 int32_t s6_val = get_register(s6);
3135 int32_t s7_val = get_register(s7);
3136 int32_t gp_val = get_register(gp);
3137 int32_t sp_val = get_register(sp);
3138 int32_t fp_val = get_register(fp);
3139
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003140 // Set up the callee-saved registers with a known value. To be able to check
Andrei Popescu31002712010-02-23 13:46:05 +00003141 // that they are preserved properly across JS execution.
3142 int32_t callee_saved_value = icount_;
3143 set_register(s0, callee_saved_value);
3144 set_register(s1, callee_saved_value);
3145 set_register(s2, callee_saved_value);
3146 set_register(s3, callee_saved_value);
3147 set_register(s4, callee_saved_value);
3148 set_register(s5, callee_saved_value);
3149 set_register(s6, callee_saved_value);
3150 set_register(s7, callee_saved_value);
3151 set_register(gp, callee_saved_value);
3152 set_register(fp, callee_saved_value);
3153
Ben Murdoch257744e2011-11-30 15:57:28 +00003154 // Start the simulation.
Andrei Popescu31002712010-02-23 13:46:05 +00003155 Execute();
3156
3157 // Check that the callee-saved registers have been preserved.
3158 CHECK_EQ(callee_saved_value, get_register(s0));
3159 CHECK_EQ(callee_saved_value, get_register(s1));
3160 CHECK_EQ(callee_saved_value, get_register(s2));
3161 CHECK_EQ(callee_saved_value, get_register(s3));
3162 CHECK_EQ(callee_saved_value, get_register(s4));
3163 CHECK_EQ(callee_saved_value, get_register(s5));
3164 CHECK_EQ(callee_saved_value, get_register(s6));
3165 CHECK_EQ(callee_saved_value, get_register(s7));
3166 CHECK_EQ(callee_saved_value, get_register(gp));
3167 CHECK_EQ(callee_saved_value, get_register(fp));
3168
3169 // Restore callee-saved registers with the original value.
3170 set_register(s0, s0_val);
3171 set_register(s1, s1_val);
3172 set_register(s2, s2_val);
3173 set_register(s3, s3_val);
3174 set_register(s4, s4_val);
3175 set_register(s5, s5_val);
3176 set_register(s6, s6_val);
3177 set_register(s7, s7_val);
3178 set_register(gp, gp_val);
3179 set_register(sp, sp_val);
3180 set_register(fp, fp_val);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003181}
3182
3183
3184int32_t Simulator::Call(byte* entry, int argument_count, ...) {
3185 va_list parameters;
3186 va_start(parameters, argument_count);
3187 // Set up arguments.
3188
3189 // First four arguments passed in registers.
3190 DCHECK(argument_count >= 4);
3191 set_register(a0, va_arg(parameters, int32_t));
3192 set_register(a1, va_arg(parameters, int32_t));
3193 set_register(a2, va_arg(parameters, int32_t));
3194 set_register(a3, va_arg(parameters, int32_t));
3195
3196 // Remaining arguments passed on stack.
3197 int original_stack = get_register(sp);
3198 // Compute position of stack on entry to generated code.
3199 int entry_stack = (original_stack - (argument_count - 4) * sizeof(int32_t)
3200 - kCArgsSlotsSize);
3201 if (base::OS::ActivationFrameAlignment() != 0) {
3202 entry_stack &= -base::OS::ActivationFrameAlignment();
3203 }
3204 // Store remaining arguments on stack, from low to high memory.
3205 intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
3206 for (int i = 4; i < argument_count; i++) {
3207 stack_argument[i - 4 + kCArgSlotCount] = va_arg(parameters, int32_t);
3208 }
3209 va_end(parameters);
3210 set_register(sp, entry_stack);
3211
3212 CallInternal(entry);
Andrei Popescu31002712010-02-23 13:46:05 +00003213
3214 // Pop stack passed arguments.
3215 CHECK_EQ(entry_stack, get_register(sp));
3216 set_register(sp, original_stack);
3217
3218 int32_t result = get_register(v0);
3219 return result;
3220}
3221
3222
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003223double Simulator::CallFP(byte* entry, double d0, double d1) {
3224 if (!IsMipsSoftFloatABI) {
3225 set_fpu_register_double(f12, d0);
3226 set_fpu_register_double(f14, d1);
3227 } else {
3228 int buffer[2];
3229 DCHECK(sizeof(buffer[0]) * 2 == sizeof(d0));
3230 memcpy(buffer, &d0, sizeof(d0));
3231 set_dw_register(a0, buffer);
3232 memcpy(buffer, &d1, sizeof(d1));
3233 set_dw_register(a2, buffer);
3234 }
3235 CallInternal(entry);
3236 if (!IsMipsSoftFloatABI) {
3237 return get_fpu_register_double(f0);
3238 } else {
3239 return get_double_from_register_pair(v0);
3240 }
3241}
3242
3243
Andrei Popescu31002712010-02-23 13:46:05 +00003244uintptr_t Simulator::PushAddress(uintptr_t address) {
3245 int new_sp = get_register(sp) - sizeof(uintptr_t);
3246 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp);
3247 *stack_slot = address;
3248 set_register(sp, new_sp);
3249 return new_sp;
3250}
3251
3252
3253uintptr_t Simulator::PopAddress() {
3254 int current_sp = get_register(sp);
3255 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp);
3256 uintptr_t address = *stack_slot;
3257 set_register(sp, current_sp + sizeof(uintptr_t));
3258 return address;
3259}
3260
3261
3262#undef UNSUPPORTED
3263
Steve Block44f0eee2011-05-26 01:26:41 +01003264} } // namespace v8::internal
Andrei Popescu31002712010-02-23 13:46:05 +00003265
Steve Block44f0eee2011-05-26 01:26:41 +01003266#endif // USE_SIMULATOR
Andrei Popescu31002712010-02-23 13:46:05 +00003267
Leon Clarkef7060e22010-06-03 12:02:55 +01003268#endif // V8_TARGET_ARCH_MIPS