blob: aa4224a54c23fe7ab002d6f75a7faa7f72f5970d [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#if V8_TARGET_ARCH_MIPS
11
12#include "src/assembler.h"
13#include "src/base/bits.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014#include "src/codegen.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015#include "src/disasm.h"
16#include "src/mips/constants-mips.h"
17#include "src/mips/simulator-mips.h"
18#include "src/ostreams.h"
Andrei Popescu31002712010-02-23 13:46:05 +000019
Andrei Popescu31002712010-02-23 13:46:05 +000020
21// Only build the simulator if not compiling for real MIPS hardware.
Steve Block44f0eee2011-05-26 01:26:41 +010022#if defined(USE_SIMULATOR)
Andrei Popescu31002712010-02-23 13:46:05 +000023
Steve Block44f0eee2011-05-26 01:26:41 +010024namespace v8 {
25namespace internal {
Andrei Popescu31002712010-02-23 13:46:05 +000026
Ben Murdoch257744e2011-11-30 15:57:28 +000027// Utils functions.
Andrei Popescu31002712010-02-23 13:46:05 +000028bool HaveSameSign(int32_t a, int32_t b) {
Steve Block44f0eee2011-05-26 01:26:41 +010029 return ((a ^ b) >= 0);
30}
31
32
33uint32_t get_fcsr_condition_bit(uint32_t cc) {
34 if (cc == 0) {
35 return 23;
36 } else {
37 return 24 + cc;
38 }
Andrei Popescu31002712010-02-23 13:46:05 +000039}
40
41
42// This macro provides a platform independent use of sscanf. The reason for
43// SScanF not being implemented in a platform independent was through
44// ::v8::internal::OS in the same way as SNPrintF is that the Windows C Run-Time
45// Library does not provide vsscanf.
46#define SScanF sscanf // NOLINT
47
Steve Block44f0eee2011-05-26 01:26:41 +010048// The MipsDebugger class is used by the simulator while debugging simulated
Andrei Popescu31002712010-02-23 13:46:05 +000049// code.
Steve Block44f0eee2011-05-26 01:26:41 +010050class MipsDebugger {
Andrei Popescu31002712010-02-23 13:46:05 +000051 public:
Ben Murdoch3ef787d2012-04-12 10:51:47 +010052 explicit MipsDebugger(Simulator* sim) : sim_(sim) { }
Steve Block44f0eee2011-05-26 01:26:41 +010053 ~MipsDebugger();
Andrei Popescu31002712010-02-23 13:46:05 +000054
55 void Stop(Instruction* instr);
56 void Debug();
Steve Block44f0eee2011-05-26 01:26:41 +010057 // Print all registers with a nice formatting.
58 void PrintAllRegs();
59 void PrintAllRegsIncludingFPU();
Andrei Popescu31002712010-02-23 13:46:05 +000060
61 private:
62 // We set the breakpoint code to 0xfffff to easily recognize it.
63 static const Instr kBreakpointInstr = SPECIAL | BREAK | 0xfffff << 6;
64 static const Instr kNopInstr = 0x0;
65
66 Simulator* sim_;
67
68 int32_t GetRegisterValue(int regnum);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000069 int32_t GetFPURegisterValue32(int regnum);
70 int64_t GetFPURegisterValue64(int regnum);
Steve Block44f0eee2011-05-26 01:26:41 +010071 float GetFPURegisterValueFloat(int regnum);
72 double GetFPURegisterValueDouble(int regnum);
Andrei Popescu31002712010-02-23 13:46:05 +000073 bool GetValue(const char* desc, int32_t* value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000074 bool GetValue(const char* desc, int64_t* value);
Andrei Popescu31002712010-02-23 13:46:05 +000075
76 // Set or delete a breakpoint. Returns true if successful.
77 bool SetBreakpoint(Instruction* breakpc);
78 bool DeleteBreakpoint(Instruction* breakpc);
79
80 // Undo and redo all breakpoints. This is needed to bracket disassembly and
81 // execution to skip past breakpoints when run from the debugger.
82 void UndoBreakpoints();
83 void RedoBreakpoints();
Andrei Popescu31002712010-02-23 13:46:05 +000084};
85
Steve Block44f0eee2011-05-26 01:26:41 +010086
87MipsDebugger::~MipsDebugger() {
Andrei Popescu31002712010-02-23 13:46:05 +000088}
89
Steve Block44f0eee2011-05-26 01:26:41 +010090
Andrei Popescu31002712010-02-23 13:46:05 +000091#ifdef GENERATED_CODE_COVERAGE
92static FILE* coverage_log = NULL;
93
94
95static void InitializeCoverage() {
96 char* file_name = getenv("V8_GENERATED_CODE_COVERAGE_LOG");
97 if (file_name != NULL) {
98 coverage_log = fopen(file_name, "aw+");
99 }
100}
101
102
Steve Block44f0eee2011-05-26 01:26:41 +0100103void MipsDebugger::Stop(Instruction* instr) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000104 // Get the stop code.
105 uint32_t code = instr->Bits(25, 6);
106 // Retrieve the encoded address, which comes just after this stop.
107 char** msg_address =
108 reinterpret_cast<char**>(sim_->get_pc() + Instr::kInstrSize);
109 char* msg = *msg_address;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000110 DCHECK(msg != NULL);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000111
112 // Update this stop description.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000113 if (!watched_stops_[code].desc) {
114 watched_stops_[code].desc = msg;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000115 }
116
117 if (strlen(msg) > 0) {
Andrei Popescu31002712010-02-23 13:46:05 +0000118 if (coverage_log != NULL) {
119 fprintf(coverage_log, "%s\n", str);
120 fflush(coverage_log);
121 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000122 // Overwrite the instruction and address with nops.
123 instr->SetInstructionBits(kNopInstr);
124 reinterpret_cast<Instr*>(msg_address)->SetInstructionBits(kNopInstr);
Andrei Popescu31002712010-02-23 13:46:05 +0000125 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000126 sim_->set_pc(sim_->get_pc() + 2 * Instruction::kInstructionSize);
Andrei Popescu31002712010-02-23 13:46:05 +0000127}
128
Steve Block44f0eee2011-05-26 01:26:41 +0100129
Ben Murdoch257744e2011-11-30 15:57:28 +0000130#else // GENERATED_CODE_COVERAGE
Andrei Popescu31002712010-02-23 13:46:05 +0000131
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000132#define UNSUPPORTED() printf("Sim: Unsupported instruction.\n");
Andrei Popescu31002712010-02-23 13:46:05 +0000133
134static void InitializeCoverage() {}
135
136
Steve Block44f0eee2011-05-26 01:26:41 +0100137void MipsDebugger::Stop(Instruction* instr) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000138 // Get the stop code.
139 uint32_t code = instr->Bits(25, 6);
140 // Retrieve the encoded address, which comes just after this stop.
141 char* msg = *reinterpret_cast<char**>(sim_->get_pc() +
142 Instruction::kInstrSize);
143 // Update this stop description.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000144 if (!sim_->watched_stops_[code].desc) {
145 sim_->watched_stops_[code].desc = msg;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000146 }
147 PrintF("Simulator hit %s (%u)\n", msg, code);
148 sim_->set_pc(sim_->get_pc() + 2 * Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +0000149 Debug();
150}
Steve Block6ded16b2010-05-10 14:33:55 +0100151#endif // GENERATED_CODE_COVERAGE
Andrei Popescu31002712010-02-23 13:46:05 +0000152
153
Steve Block44f0eee2011-05-26 01:26:41 +0100154int32_t MipsDebugger::GetRegisterValue(int regnum) {
Andrei Popescu31002712010-02-23 13:46:05 +0000155 if (regnum == kNumSimuRegisters) {
156 return sim_->get_pc();
157 } else {
158 return sim_->get_register(regnum);
159 }
160}
161
162
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000163int32_t MipsDebugger::GetFPURegisterValue32(int regnum) {
Steve Block44f0eee2011-05-26 01:26:41 +0100164 if (regnum == kNumFPURegisters) {
165 return sim_->get_pc();
166 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000167 return sim_->get_fpu_register_word(regnum);
Steve Block44f0eee2011-05-26 01:26:41 +0100168 }
169}
170
171
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000172int64_t MipsDebugger::GetFPURegisterValue64(int regnum) {
Steve Block44f0eee2011-05-26 01:26:41 +0100173 if (regnum == kNumFPURegisters) {
174 return sim_->get_pc();
175 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000176 return sim_->get_fpu_register(regnum);
Steve Block44f0eee2011-05-26 01:26:41 +0100177 }
178}
179
180
181float MipsDebugger::GetFPURegisterValueFloat(int regnum) {
182 if (regnum == kNumFPURegisters) {
183 return sim_->get_pc();
184 } else {
185 return sim_->get_fpu_register_float(regnum);
186 }
187}
188
189
190double MipsDebugger::GetFPURegisterValueDouble(int regnum) {
191 if (regnum == kNumFPURegisters) {
192 return sim_->get_pc();
193 } else {
194 return sim_->get_fpu_register_double(regnum);
195 }
196}
197
198
199bool MipsDebugger::GetValue(const char* desc, int32_t* value) {
Andrei Popescu31002712010-02-23 13:46:05 +0000200 int regnum = Registers::Number(desc);
Steve Block44f0eee2011-05-26 01:26:41 +0100201 int fpuregnum = FPURegisters::Number(desc);
202
Andrei Popescu31002712010-02-23 13:46:05 +0000203 if (regnum != kInvalidRegister) {
204 *value = GetRegisterValue(regnum);
205 return true;
Steve Block44f0eee2011-05-26 01:26:41 +0100206 } else if (fpuregnum != kInvalidFPURegister) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000207 *value = GetFPURegisterValue32(fpuregnum);
Steve Block44f0eee2011-05-26 01:26:41 +0100208 return true;
209 } else if (strncmp(desc, "0x", 2) == 0) {
210 return SScanF(desc, "%x", reinterpret_cast<uint32_t*>(value)) == 1;
Andrei Popescu31002712010-02-23 13:46:05 +0000211 } else {
212 return SScanF(desc, "%i", value) == 1;
213 }
214 return false;
215}
216
217
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000218bool MipsDebugger::GetValue(const char* desc, int64_t* value) {
219 int regnum = Registers::Number(desc);
220 int fpuregnum = FPURegisters::Number(desc);
221
222 if (regnum != kInvalidRegister) {
223 *value = GetRegisterValue(regnum);
224 return true;
225 } else if (fpuregnum != kInvalidFPURegister) {
226 *value = GetFPURegisterValue64(fpuregnum);
227 return true;
228 } else if (strncmp(desc, "0x", 2) == 0) {
229 return SScanF(desc + 2, "%" SCNx64,
230 reinterpret_cast<uint64_t*>(value)) == 1;
231 } else {
232 return SScanF(desc, "%" SCNu64, reinterpret_cast<uint64_t*>(value)) == 1;
233 }
234 return false;
235}
236
237
Steve Block44f0eee2011-05-26 01:26:41 +0100238bool MipsDebugger::SetBreakpoint(Instruction* breakpc) {
Andrei Popescu31002712010-02-23 13:46:05 +0000239 // Check if a breakpoint can be set. If not return without any side-effects.
240 if (sim_->break_pc_ != NULL) {
241 return false;
242 }
243
244 // Set the breakpoint.
245 sim_->break_pc_ = breakpc;
246 sim_->break_instr_ = breakpc->InstructionBits();
247 // Not setting the breakpoint instruction in the code itself. It will be set
248 // when the debugger shell continues.
249 return true;
250}
251
252
Steve Block44f0eee2011-05-26 01:26:41 +0100253bool MipsDebugger::DeleteBreakpoint(Instruction* breakpc) {
Andrei Popescu31002712010-02-23 13:46:05 +0000254 if (sim_->break_pc_ != NULL) {
255 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
256 }
257
258 sim_->break_pc_ = NULL;
259 sim_->break_instr_ = 0;
260 return true;
261}
262
263
Steve Block44f0eee2011-05-26 01:26:41 +0100264void MipsDebugger::UndoBreakpoints() {
Andrei Popescu31002712010-02-23 13:46:05 +0000265 if (sim_->break_pc_ != NULL) {
266 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
267 }
268}
269
270
Steve Block44f0eee2011-05-26 01:26:41 +0100271void MipsDebugger::RedoBreakpoints() {
Andrei Popescu31002712010-02-23 13:46:05 +0000272 if (sim_->break_pc_ != NULL) {
273 sim_->break_pc_->SetInstructionBits(kBreakpointInstr);
274 }
275}
276
Steve Block44f0eee2011-05-26 01:26:41 +0100277
278void MipsDebugger::PrintAllRegs() {
Andrei Popescu31002712010-02-23 13:46:05 +0000279#define REG_INFO(n) Registers::Name(n), GetRegisterValue(n), GetRegisterValue(n)
280
281 PrintF("\n");
Ben Murdoch257744e2011-11-30 15:57:28 +0000282 // at, v0, a0.
Andrei Popescu31002712010-02-23 13:46:05 +0000283 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
284 REG_INFO(1), REG_INFO(2), REG_INFO(4));
Ben Murdoch257744e2011-11-30 15:57:28 +0000285 // v1, a1.
Andrei Popescu31002712010-02-23 13:46:05 +0000286 PrintF("%26s\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
287 "", REG_INFO(3), REG_INFO(5));
Ben Murdoch257744e2011-11-30 15:57:28 +0000288 // a2.
Andrei Popescu31002712010-02-23 13:46:05 +0000289 PrintF("%26s\t%26s\t%3s: 0x%08x %10d\n", "", "", REG_INFO(6));
Ben Murdoch257744e2011-11-30 15:57:28 +0000290 // a3.
Andrei Popescu31002712010-02-23 13:46:05 +0000291 PrintF("%26s\t%26s\t%3s: 0x%08x %10d\n", "", "", REG_INFO(7));
292 PrintF("\n");
293 // t0-t7, s0-s7
294 for (int i = 0; i < 8; i++) {
295 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
296 REG_INFO(8+i), REG_INFO(16+i));
297 }
298 PrintF("\n");
Ben Murdoch257744e2011-11-30 15:57:28 +0000299 // t8, k0, LO.
Andrei Popescu31002712010-02-23 13:46:05 +0000300 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
301 REG_INFO(24), REG_INFO(26), REG_INFO(32));
Ben Murdoch257744e2011-11-30 15:57:28 +0000302 // t9, k1, HI.
Andrei Popescu31002712010-02-23 13:46:05 +0000303 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
304 REG_INFO(25), REG_INFO(27), REG_INFO(33));
Ben Murdoch257744e2011-11-30 15:57:28 +0000305 // sp, fp, gp.
Andrei Popescu31002712010-02-23 13:46:05 +0000306 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
307 REG_INFO(29), REG_INFO(30), REG_INFO(28));
Ben Murdoch257744e2011-11-30 15:57:28 +0000308 // pc.
Andrei Popescu31002712010-02-23 13:46:05 +0000309 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
310 REG_INFO(31), REG_INFO(34));
Steve Block44f0eee2011-05-26 01:26:41 +0100311
Andrei Popescu31002712010-02-23 13:46:05 +0000312#undef REG_INFO
Steve Block44f0eee2011-05-26 01:26:41 +0100313#undef FPU_REG_INFO
Andrei Popescu31002712010-02-23 13:46:05 +0000314}
315
Steve Block44f0eee2011-05-26 01:26:41 +0100316
317void MipsDebugger::PrintAllRegsIncludingFPU() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000318#define FPU_REG_INFO32(n) FPURegisters::Name(n), FPURegisters::Name(n+1), \
319 GetFPURegisterValue32(n+1), \
320 GetFPURegisterValue32(n), \
321 GetFPURegisterValueDouble(n)
322
323#define FPU_REG_INFO64(n) FPURegisters::Name(n), \
324 GetFPURegisterValue64(n), \
325 GetFPURegisterValueDouble(n)
Steve Block44f0eee2011-05-26 01:26:41 +0100326
327 PrintAllRegs();
328
329 PrintF("\n\n");
Ben Murdoch257744e2011-11-30 15:57:28 +0000330 // f0, f1, f2, ... f31.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000331 // This must be a compile-time switch,
332 // compiler will throw out warnings otherwise.
333 if (kFpuMode == kFP64) {
334 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(0) );
335 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(1) );
336 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(2) );
337 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(3) );
338 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(4) );
339 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(5) );
340 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(6) );
341 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(7) );
342 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(8) );
343 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(9) );
344 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(10));
345 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(11));
346 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(12));
347 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(13));
348 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(14));
349 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(15));
350 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(16));
351 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(17));
352 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(18));
353 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(19));
354 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(20));
355 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(21));
356 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(22));
357 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(23));
358 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(24));
359 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(25));
360 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(26));
361 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(27));
362 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(28));
363 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(29));
364 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(30));
365 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(31));
366 } else {
367 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(0) );
368 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(2) );
369 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(4) );
370 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(6) );
371 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(8) );
372 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(10));
373 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(12));
374 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(14));
375 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(16));
376 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(18));
377 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(20));
378 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(22));
379 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(24));
380 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(26));
381 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(28));
382 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(30));
383 }
Steve Block44f0eee2011-05-26 01:26:41 +0100384
385#undef REG_INFO
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000386#undef FPU_REG_INFO32
387#undef FPU_REG_INFO64
Steve Block44f0eee2011-05-26 01:26:41 +0100388}
389
390
391void MipsDebugger::Debug() {
Andrei Popescu31002712010-02-23 13:46:05 +0000392 intptr_t last_pc = -1;
393 bool done = false;
394
395#define COMMAND_SIZE 63
396#define ARG_SIZE 255
397
398#define STR(a) #a
399#define XSTR(a) STR(a)
400
401 char cmd[COMMAND_SIZE + 1];
402 char arg1[ARG_SIZE + 1];
403 char arg2[ARG_SIZE + 1];
Steve Block44f0eee2011-05-26 01:26:41 +0100404 char* argv[3] = { cmd, arg1, arg2 };
Andrei Popescu31002712010-02-23 13:46:05 +0000405
Ben Murdoch257744e2011-11-30 15:57:28 +0000406 // Make sure to have a proper terminating character if reaching the limit.
Andrei Popescu31002712010-02-23 13:46:05 +0000407 cmd[COMMAND_SIZE] = 0;
408 arg1[ARG_SIZE] = 0;
409 arg2[ARG_SIZE] = 0;
410
411 // Undo all set breakpoints while running in the debugger shell. This will
412 // make them invisible to all commands.
413 UndoBreakpoints();
414
415 while (!done && (sim_->get_pc() != Simulator::end_sim_pc)) {
416 if (last_pc != sim_->get_pc()) {
417 disasm::NameConverter converter;
418 disasm::Disassembler dasm(converter);
Ben Murdoch257744e2011-11-30 15:57:28 +0000419 // Use a reasonably large buffer.
Andrei Popescu31002712010-02-23 13:46:05 +0000420 v8::internal::EmbeddedVector<char, 256> buffer;
421 dasm.InstructionDecode(buffer,
Ben Murdoch257744e2011-11-30 15:57:28 +0000422 reinterpret_cast<byte*>(sim_->get_pc()));
Andrei Popescu31002712010-02-23 13:46:05 +0000423 PrintF(" 0x%08x %s\n", sim_->get_pc(), buffer.start());
424 last_pc = sim_->get_pc();
425 }
426 char* line = ReadLine("sim> ");
427 if (line == NULL) {
428 break;
429 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100430 char* last_input = sim_->last_debugger_input();
431 if (strcmp(line, "\n") == 0 && last_input != NULL) {
432 line = last_input;
433 } else {
434 // Ownership is transferred to sim_;
435 sim_->set_last_debugger_input(line);
436 }
Andrei Popescu31002712010-02-23 13:46:05 +0000437 // Use sscanf to parse the individual parts of the command line. At the
438 // moment no command expects more than two parameters.
Steve Block44f0eee2011-05-26 01:26:41 +0100439 int argc = SScanF(line,
Andrei Popescu31002712010-02-23 13:46:05 +0000440 "%" XSTR(COMMAND_SIZE) "s "
441 "%" XSTR(ARG_SIZE) "s "
442 "%" XSTR(ARG_SIZE) "s",
443 cmd, arg1, arg2);
444 if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
Steve Block44f0eee2011-05-26 01:26:41 +0100445 Instruction* instr = reinterpret_cast<Instruction*>(sim_->get_pc());
446 if (!(instr->IsTrap()) ||
447 instr->InstructionBits() == rtCallRedirInstr) {
Andrei Popescu31002712010-02-23 13:46:05 +0000448 sim_->InstructionDecode(
Steve Block44f0eee2011-05-26 01:26:41 +0100449 reinterpret_cast<Instruction*>(sim_->get_pc()));
Andrei Popescu31002712010-02-23 13:46:05 +0000450 } else {
451 // Allow si to jump over generated breakpoints.
452 PrintF("/!\\ Jumping over generated breakpoint.\n");
Steve Block44f0eee2011-05-26 01:26:41 +0100453 sim_->set_pc(sim_->get_pc() + Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +0000454 }
455 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) {
456 // Execute the one instruction we broke at with breakpoints disabled.
457 sim_->InstructionDecode(reinterpret_cast<Instruction*>(sim_->get_pc()));
458 // Leave the debugger shell.
459 done = true;
460 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
Steve Block44f0eee2011-05-26 01:26:41 +0100461 if (argc == 2) {
Andrei Popescu31002712010-02-23 13:46:05 +0000462 if (strcmp(arg1, "all") == 0) {
463 PrintAllRegs();
Steve Block44f0eee2011-05-26 01:26:41 +0100464 } else if (strcmp(arg1, "allf") == 0) {
465 PrintAllRegsIncludingFPU();
Andrei Popescu31002712010-02-23 13:46:05 +0000466 } else {
Steve Block44f0eee2011-05-26 01:26:41 +0100467 int regnum = Registers::Number(arg1);
468 int fpuregnum = FPURegisters::Number(arg1);
469
470 if (regnum != kInvalidRegister) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000471 int32_t value;
Steve Block44f0eee2011-05-26 01:26:41 +0100472 value = GetRegisterValue(regnum);
Andrei Popescu31002712010-02-23 13:46:05 +0000473 PrintF("%s: 0x%08x %d \n", arg1, value, value);
Steve Block44f0eee2011-05-26 01:26:41 +0100474 } else if (fpuregnum != kInvalidFPURegister) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000475 if (IsFp64Mode()) {
476 int64_t value;
477 double dvalue;
478 value = GetFPURegisterValue64(fpuregnum);
479 dvalue = GetFPURegisterValueDouble(fpuregnum);
480 PrintF("%3s: 0x%016llx %16.4e\n",
481 FPURegisters::Name(fpuregnum), value, dvalue);
Steve Block44f0eee2011-05-26 01:26:41 +0100482 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000483 if (fpuregnum % 2 == 1) {
484 int32_t value;
485 float fvalue;
486 value = GetFPURegisterValue32(fpuregnum);
487 fvalue = GetFPURegisterValueFloat(fpuregnum);
488 PrintF("%s: 0x%08x %11.4e\n", arg1, value, fvalue);
489 } else {
490 double dfvalue;
491 int32_t lvalue1 = GetFPURegisterValue32(fpuregnum);
492 int32_t lvalue2 = GetFPURegisterValue32(fpuregnum + 1);
493 dfvalue = GetFPURegisterValueDouble(fpuregnum);
494 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n",
495 FPURegisters::Name(fpuregnum+1),
496 FPURegisters::Name(fpuregnum),
497 lvalue1,
498 lvalue2,
499 dfvalue);
500 }
Steve Block44f0eee2011-05-26 01:26:41 +0100501 }
Andrei Popescu31002712010-02-23 13:46:05 +0000502 } else {
503 PrintF("%s unrecognized\n", arg1);
504 }
505 }
506 } else {
Steve Block44f0eee2011-05-26 01:26:41 +0100507 if (argc == 3) {
508 if (strcmp(arg2, "single") == 0) {
509 int32_t value;
510 float fvalue;
511 int fpuregnum = FPURegisters::Number(arg1);
512
513 if (fpuregnum != kInvalidFPURegister) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000514 value = GetFPURegisterValue32(fpuregnum);
Steve Block44f0eee2011-05-26 01:26:41 +0100515 fvalue = GetFPURegisterValueFloat(fpuregnum);
516 PrintF("%s: 0x%08x %11.4e\n", arg1, value, fvalue);
517 } else {
518 PrintF("%s unrecognized\n", arg1);
519 }
520 } else {
521 PrintF("print <fpu register> single\n");
522 }
523 } else {
524 PrintF("print <register> or print <fpu register> single\n");
525 }
Andrei Popescu31002712010-02-23 13:46:05 +0000526 }
527 } else if ((strcmp(cmd, "po") == 0)
528 || (strcmp(cmd, "printobject") == 0)) {
Steve Block44f0eee2011-05-26 01:26:41 +0100529 if (argc == 2) {
Andrei Popescu31002712010-02-23 13:46:05 +0000530 int32_t value;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000531 OFStream os(stdout);
Andrei Popescu31002712010-02-23 13:46:05 +0000532 if (GetValue(arg1, &value)) {
533 Object* obj = reinterpret_cast<Object*>(value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000534 os << arg1 << ": \n";
Andrei Popescu31002712010-02-23 13:46:05 +0000535#ifdef DEBUG
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000536 obj->Print(os);
537 os << "\n";
Andrei Popescu31002712010-02-23 13:46:05 +0000538#else
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000539 os << Brief(obj) << "\n";
Andrei Popescu31002712010-02-23 13:46:05 +0000540#endif
541 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000542 os << arg1 << " unrecognized\n";
Andrei Popescu31002712010-02-23 13:46:05 +0000543 }
544 } else {
545 PrintF("printobject <value>\n");
546 }
Steve Block44f0eee2011-05-26 01:26:41 +0100547 } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0) {
548 int32_t* cur = NULL;
549 int32_t* end = NULL;
550 int next_arg = 1;
551
552 if (strcmp(cmd, "stack") == 0) {
553 cur = reinterpret_cast<int32_t*>(sim_->get_register(Simulator::sp));
Ben Murdoch257744e2011-11-30 15:57:28 +0000554 } else { // Command "mem".
Steve Block44f0eee2011-05-26 01:26:41 +0100555 int32_t value;
556 if (!GetValue(arg1, &value)) {
557 PrintF("%s unrecognized\n", arg1);
558 continue;
559 }
560 cur = reinterpret_cast<int32_t*>(value);
561 next_arg++;
562 }
563
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000564 // TODO(palfia): optimize this.
565 if (IsFp64Mode()) {
566 int64_t words;
567 if (argc == next_arg) {
Steve Block44f0eee2011-05-26 01:26:41 +0100568 words = 10;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000569 } else {
570 if (!GetValue(argv[next_arg], &words)) {
571 words = 10;
572 }
Steve Block44f0eee2011-05-26 01:26:41 +0100573 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000574 end = cur + words;
575 } else {
576 int32_t words;
577 if (argc == next_arg) {
578 words = 10;
579 } else {
580 if (!GetValue(argv[next_arg], &words)) {
581 words = 10;
582 }
583 }
584 end = cur + words;
Steve Block44f0eee2011-05-26 01:26:41 +0100585 }
Steve Block44f0eee2011-05-26 01:26:41 +0100586
587 while (cur < end) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000588 PrintF(" 0x%08x: 0x%08x %10d",
Steve Block44f0eee2011-05-26 01:26:41 +0100589 reinterpret_cast<intptr_t>(cur), *cur, *cur);
Ben Murdoch257744e2011-11-30 15:57:28 +0000590 HeapObject* obj = reinterpret_cast<HeapObject*>(*cur);
591 int value = *cur;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000592 Heap* current_heap = sim_->isolate_->heap();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000593 if (((value & 1) == 0) || current_heap->Contains(obj)) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000594 PrintF(" (");
595 if ((value & 1) == 0) {
596 PrintF("smi %d", value / 2);
597 } else {
598 obj->ShortPrint();
599 }
600 PrintF(")");
601 }
602 PrintF("\n");
Steve Block44f0eee2011-05-26 01:26:41 +0100603 cur++;
604 }
605
Ben Murdoch257744e2011-11-30 15:57:28 +0000606 } else if ((strcmp(cmd, "disasm") == 0) ||
607 (strcmp(cmd, "dpc") == 0) ||
608 (strcmp(cmd, "di") == 0)) {
Andrei Popescu31002712010-02-23 13:46:05 +0000609 disasm::NameConverter converter;
610 disasm::Disassembler dasm(converter);
Ben Murdoch257744e2011-11-30 15:57:28 +0000611 // Use a reasonably large buffer.
Andrei Popescu31002712010-02-23 13:46:05 +0000612 v8::internal::EmbeddedVector<char, 256> buffer;
613
Ben Murdoch257744e2011-11-30 15:57:28 +0000614 byte* cur = NULL;
615 byte* end = NULL;
Andrei Popescu31002712010-02-23 13:46:05 +0000616
Steve Block44f0eee2011-05-26 01:26:41 +0100617 if (argc == 1) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000618 cur = reinterpret_cast<byte*>(sim_->get_pc());
Steve Block44f0eee2011-05-26 01:26:41 +0100619 end = cur + (10 * Instruction::kInstrSize);
620 } else if (argc == 2) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000621 int regnum = Registers::Number(arg1);
622 if (regnum != kInvalidRegister || strncmp(arg1, "0x", 2) == 0) {
623 // The argument is an address or a register name.
624 int32_t value;
625 if (GetValue(arg1, &value)) {
626 cur = reinterpret_cast<byte*>(value);
627 // Disassemble 10 instructions at <arg1>.
628 end = cur + (10 * Instruction::kInstrSize);
629 }
630 } else {
631 // The argument is the number of instructions.
632 int32_t value;
633 if (GetValue(arg1, &value)) {
634 cur = reinterpret_cast<byte*>(sim_->get_pc());
635 // Disassemble <arg1> instructions.
636 end = cur + (value * Instruction::kInstrSize);
637 }
Andrei Popescu31002712010-02-23 13:46:05 +0000638 }
639 } else {
640 int32_t value1;
641 int32_t value2;
642 if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000643 cur = reinterpret_cast<byte*>(value1);
Steve Block44f0eee2011-05-26 01:26:41 +0100644 end = cur + (value2 * Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +0000645 }
646 }
647
648 while (cur < end) {
649 dasm.InstructionDecode(buffer, cur);
Steve Block44f0eee2011-05-26 01:26:41 +0100650 PrintF(" 0x%08x %s\n",
651 reinterpret_cast<intptr_t>(cur), buffer.start());
652 cur += Instruction::kInstrSize;
Andrei Popescu31002712010-02-23 13:46:05 +0000653 }
654 } else if (strcmp(cmd, "gdb") == 0) {
655 PrintF("relinquishing control to gdb\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000656 v8::base::OS::DebugBreak();
Andrei Popescu31002712010-02-23 13:46:05 +0000657 PrintF("regaining control from gdb\n");
658 } else if (strcmp(cmd, "break") == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +0100659 if (argc == 2) {
Andrei Popescu31002712010-02-23 13:46:05 +0000660 int32_t value;
661 if (GetValue(arg1, &value)) {
662 if (!SetBreakpoint(reinterpret_cast<Instruction*>(value))) {
663 PrintF("setting breakpoint failed\n");
664 }
665 } else {
666 PrintF("%s unrecognized\n", arg1);
667 }
668 } else {
669 PrintF("break <address>\n");
670 }
671 } else if (strcmp(cmd, "del") == 0) {
672 if (!DeleteBreakpoint(NULL)) {
673 PrintF("deleting breakpoint failed\n");
674 }
675 } else if (strcmp(cmd, "flags") == 0) {
676 PrintF("No flags on MIPS !\n");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000677 } else if (strcmp(cmd, "stop") == 0) {
678 int32_t value;
679 intptr_t stop_pc = sim_->get_pc() -
680 2 * Instruction::kInstrSize;
681 Instruction* stop_instr = reinterpret_cast<Instruction*>(stop_pc);
682 Instruction* msg_address =
683 reinterpret_cast<Instruction*>(stop_pc +
684 Instruction::kInstrSize);
685 if ((argc == 2) && (strcmp(arg1, "unstop") == 0)) {
686 // Remove the current stop.
687 if (sim_->IsStopInstruction(stop_instr)) {
688 stop_instr->SetInstructionBits(kNopInstr);
689 msg_address->SetInstructionBits(kNopInstr);
690 } else {
691 PrintF("Not at debugger stop.\n");
692 }
693 } else if (argc == 3) {
694 // Print information about all/the specified breakpoint(s).
695 if (strcmp(arg1, "info") == 0) {
696 if (strcmp(arg2, "all") == 0) {
697 PrintF("Stop information:\n");
698 for (uint32_t i = kMaxWatchpointCode + 1;
699 i <= kMaxStopCode;
700 i++) {
701 sim_->PrintStopInfo(i);
702 }
703 } else if (GetValue(arg2, &value)) {
704 sim_->PrintStopInfo(value);
705 } else {
706 PrintF("Unrecognized argument.\n");
707 }
708 } else if (strcmp(arg1, "enable") == 0) {
709 // Enable all/the specified breakpoint(s).
710 if (strcmp(arg2, "all") == 0) {
711 for (uint32_t i = kMaxWatchpointCode + 1;
712 i <= kMaxStopCode;
713 i++) {
714 sim_->EnableStop(i);
715 }
716 } else if (GetValue(arg2, &value)) {
717 sim_->EnableStop(value);
718 } else {
719 PrintF("Unrecognized argument.\n");
720 }
721 } else if (strcmp(arg1, "disable") == 0) {
722 // Disable all/the specified breakpoint(s).
723 if (strcmp(arg2, "all") == 0) {
724 for (uint32_t i = kMaxWatchpointCode + 1;
725 i <= kMaxStopCode;
726 i++) {
727 sim_->DisableStop(i);
728 }
729 } else if (GetValue(arg2, &value)) {
730 sim_->DisableStop(value);
731 } else {
732 PrintF("Unrecognized argument.\n");
733 }
734 }
735 } else {
736 PrintF("Wrong usage. Use help command for more information.\n");
737 }
Andrei Popescu31002712010-02-23 13:46:05 +0000738 } else if ((strcmp(cmd, "stat") == 0) || (strcmp(cmd, "st") == 0)) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000739 // Print registers and disassemble.
Andrei Popescu31002712010-02-23 13:46:05 +0000740 PrintAllRegs();
741 PrintF("\n");
742
743 disasm::NameConverter converter;
744 disasm::Disassembler dasm(converter);
Ben Murdoch257744e2011-11-30 15:57:28 +0000745 // Use a reasonably large buffer.
Andrei Popescu31002712010-02-23 13:46:05 +0000746 v8::internal::EmbeddedVector<char, 256> buffer;
747
Ben Murdoch257744e2011-11-30 15:57:28 +0000748 byte* cur = NULL;
749 byte* end = NULL;
Andrei Popescu31002712010-02-23 13:46:05 +0000750
Steve Block44f0eee2011-05-26 01:26:41 +0100751 if (argc == 1) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000752 cur = reinterpret_cast<byte*>(sim_->get_pc());
Steve Block44f0eee2011-05-26 01:26:41 +0100753 end = cur + (10 * Instruction::kInstrSize);
754 } else if (argc == 2) {
Andrei Popescu31002712010-02-23 13:46:05 +0000755 int32_t value;
756 if (GetValue(arg1, &value)) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000757 cur = reinterpret_cast<byte*>(value);
Andrei Popescu31002712010-02-23 13:46:05 +0000758 // no length parameter passed, assume 10 instructions
Steve Block44f0eee2011-05-26 01:26:41 +0100759 end = cur + (10 * Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +0000760 }
761 } else {
762 int32_t value1;
763 int32_t value2;
764 if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000765 cur = reinterpret_cast<byte*>(value1);
Steve Block44f0eee2011-05-26 01:26:41 +0100766 end = cur + (value2 * Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +0000767 }
768 }
769
770 while (cur < end) {
771 dasm.InstructionDecode(buffer, cur);
Steve Block44f0eee2011-05-26 01:26:41 +0100772 PrintF(" 0x%08x %s\n",
773 reinterpret_cast<intptr_t>(cur), buffer.start());
774 cur += Instruction::kInstrSize;
Andrei Popescu31002712010-02-23 13:46:05 +0000775 }
776 } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
777 PrintF("cont\n");
778 PrintF(" continue execution (alias 'c')\n");
779 PrintF("stepi\n");
780 PrintF(" step one instruction (alias 'si')\n");
781 PrintF("print <register>\n");
782 PrintF(" print register content (alias 'p')\n");
783 PrintF(" use register name 'all' to print all registers\n");
784 PrintF("printobject <register>\n");
785 PrintF(" print an object from a register (alias 'po')\n");
Steve Block44f0eee2011-05-26 01:26:41 +0100786 PrintF("stack [<words>]\n");
787 PrintF(" dump stack content, default dump 10 words)\n");
788 PrintF("mem <address> [<words>]\n");
789 PrintF(" dump memory content, default dump 10 words)\n");
Andrei Popescu31002712010-02-23 13:46:05 +0000790 PrintF("flags\n");
791 PrintF(" print flags\n");
792 PrintF("disasm [<instructions>]\n");
Ben Murdoch257744e2011-11-30 15:57:28 +0000793 PrintF("disasm [<address/register>]\n");
794 PrintF("disasm [[<address/register>] <instructions>]\n");
795 PrintF(" disassemble code, default is 10 instructions\n");
796 PrintF(" from pc (alias 'di')\n");
Andrei Popescu31002712010-02-23 13:46:05 +0000797 PrintF("gdb\n");
798 PrintF(" enter gdb\n");
799 PrintF("break <address>\n");
800 PrintF(" set a break point on the address\n");
801 PrintF("del\n");
802 PrintF(" delete the breakpoint\n");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000803 PrintF("stop feature:\n");
804 PrintF(" Description:\n");
805 PrintF(" Stops are debug instructions inserted by\n");
806 PrintF(" the Assembler::stop() function.\n");
807 PrintF(" When hitting a stop, the Simulator will\n");
808 PrintF(" stop and and give control to the Debugger.\n");
809 PrintF(" All stop codes are watched:\n");
810 PrintF(" - They can be enabled / disabled: the Simulator\n");
811 PrintF(" will / won't stop when hitting them.\n");
812 PrintF(" - The Simulator keeps track of how many times they \n");
813 PrintF(" are met. (See the info command.) Going over a\n");
814 PrintF(" disabled stop still increases its counter. \n");
815 PrintF(" Commands:\n");
816 PrintF(" stop info all/<code> : print infos about number <code>\n");
817 PrintF(" or all stop(s).\n");
818 PrintF(" stop enable/disable all/<code> : enables / disables\n");
819 PrintF(" all or number <code> stop(s)\n");
820 PrintF(" stop unstop\n");
821 PrintF(" ignore the stop instruction at the current location\n");
822 PrintF(" from now on\n");
Andrei Popescu31002712010-02-23 13:46:05 +0000823 } else {
824 PrintF("Unknown command: %s\n", cmd);
825 }
826 }
Andrei Popescu31002712010-02-23 13:46:05 +0000827 }
828
829 // Add all the breakpoints back to stop execution and enter the debugger
830 // shell when hit.
831 RedoBreakpoints();
832
833#undef COMMAND_SIZE
834#undef ARG_SIZE
835
836#undef STR
837#undef XSTR
838}
839
840
Steve Block44f0eee2011-05-26 01:26:41 +0100841static bool ICacheMatch(void* one, void* two) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000842 DCHECK((reinterpret_cast<intptr_t>(one) & CachePage::kPageMask) == 0);
843 DCHECK((reinterpret_cast<intptr_t>(two) & CachePage::kPageMask) == 0);
Steve Block44f0eee2011-05-26 01:26:41 +0100844 return one == two;
845}
Andrei Popescu31002712010-02-23 13:46:05 +0000846
847
Steve Block44f0eee2011-05-26 01:26:41 +0100848static uint32_t ICacheHash(void* key) {
849 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)) >> 2;
850}
851
852
853static bool AllOnOnePage(uintptr_t start, int size) {
854 intptr_t start_page = (start & ~CachePage::kPageMask);
855 intptr_t end_page = ((start + size) & ~CachePage::kPageMask);
856 return start_page == end_page;
857}
858
859
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100860void Simulator::set_last_debugger_input(char* input) {
861 DeleteArray(last_debugger_input_);
862 last_debugger_input_ = input;
863}
864
865
Steve Block44f0eee2011-05-26 01:26:41 +0100866void Simulator::FlushICache(v8::internal::HashMap* i_cache,
867 void* start_addr,
868 size_t size) {
869 intptr_t start = reinterpret_cast<intptr_t>(start_addr);
870 int intra_line = (start & CachePage::kLineMask);
871 start -= intra_line;
872 size += intra_line;
873 size = ((size - 1) | CachePage::kLineMask) + 1;
874 int offset = (start & CachePage::kPageMask);
875 while (!AllOnOnePage(start, size - 1)) {
876 int bytes_to_flush = CachePage::kPageSize - offset;
877 FlushOnePage(i_cache, start, bytes_to_flush);
878 start += bytes_to_flush;
879 size -= bytes_to_flush;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000880 DCHECK_EQ(0, start & CachePage::kPageMask);
Steve Block44f0eee2011-05-26 01:26:41 +0100881 offset = 0;
882 }
883 if (size != 0) {
884 FlushOnePage(i_cache, start, size);
885 }
886}
887
888
889CachePage* Simulator::GetCachePage(v8::internal::HashMap* i_cache, void* page) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000890 v8::internal::HashMap::Entry* entry =
891 i_cache->LookupOrInsert(page, ICacheHash(page));
Steve Block44f0eee2011-05-26 01:26:41 +0100892 if (entry->value == NULL) {
893 CachePage* new_page = new CachePage();
894 entry->value = new_page;
895 }
896 return reinterpret_cast<CachePage*>(entry->value);
897}
898
899
900// Flush from start up to and not including start + size.
901void Simulator::FlushOnePage(v8::internal::HashMap* i_cache,
902 intptr_t start,
903 int size) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000904 DCHECK(size <= CachePage::kPageSize);
905 DCHECK(AllOnOnePage(start, size - 1));
906 DCHECK((start & CachePage::kLineMask) == 0);
907 DCHECK((size & CachePage::kLineMask) == 0);
Steve Block44f0eee2011-05-26 01:26:41 +0100908 void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask));
909 int offset = (start & CachePage::kPageMask);
910 CachePage* cache_page = GetCachePage(i_cache, page);
911 char* valid_bytemap = cache_page->ValidityByte(offset);
912 memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift);
913}
914
915
916void Simulator::CheckICache(v8::internal::HashMap* i_cache,
917 Instruction* instr) {
918 intptr_t address = reinterpret_cast<intptr_t>(instr);
919 void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
920 void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask));
921 int offset = (address & CachePage::kPageMask);
922 CachePage* cache_page = GetCachePage(i_cache, page);
923 char* cache_valid_byte = cache_page->ValidityByte(offset);
924 bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID);
925 char* cached_line = cache_page->CachedData(offset & ~CachePage::kLineMask);
926 if (cache_hit) {
927 // Check that the data in memory matches the contents of the I-cache.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000928 CHECK_EQ(0, memcmp(reinterpret_cast<void*>(instr),
929 cache_page->CachedData(offset),
930 Instruction::kInstrSize));
Steve Block44f0eee2011-05-26 01:26:41 +0100931 } else {
932 // Cache miss. Load memory into the cache.
933 memcpy(cached_line, line, CachePage::kLineLength);
934 *cache_valid_byte = CachePage::LINE_VALID;
935 }
936}
Andrei Popescu31002712010-02-23 13:46:05 +0000937
938
Ben Murdoch257744e2011-11-30 15:57:28 +0000939void Simulator::Initialize(Isolate* isolate) {
940 if (isolate->simulator_initialized()) return;
941 isolate->set_simulator_initialized(true);
942 ::v8::internal::ExternalReference::set_redirector(isolate,
943 &RedirectExternalReference);
Andrei Popescu31002712010-02-23 13:46:05 +0000944}
945
946
Ben Murdoch257744e2011-11-30 15:57:28 +0000947Simulator::Simulator(Isolate* isolate) : isolate_(isolate) {
Steve Block44f0eee2011-05-26 01:26:41 +0100948 i_cache_ = isolate_->simulator_i_cache();
949 if (i_cache_ == NULL) {
950 i_cache_ = new v8::internal::HashMap(&ICacheMatch);
951 isolate_->set_simulator_i_cache(i_cache_);
952 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000953 Initialize(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100954 // Set up simulator support first. Some of this information is needed to
Andrei Popescu31002712010-02-23 13:46:05 +0000955 // setup the architecture state.
Steve Block44f0eee2011-05-26 01:26:41 +0100956 stack_ = reinterpret_cast<char*>(malloc(stack_size_));
Andrei Popescu31002712010-02-23 13:46:05 +0000957 pc_modified_ = false;
958 icount_ = 0;
Steve Block44f0eee2011-05-26 01:26:41 +0100959 break_count_ = 0;
Andrei Popescu31002712010-02-23 13:46:05 +0000960 break_pc_ = NULL;
961 break_instr_ = 0;
962
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100963 // Set up architecture state.
Andrei Popescu31002712010-02-23 13:46:05 +0000964 // All registers are initialized to zero to start with.
965 for (int i = 0; i < kNumSimuRegisters; i++) {
966 registers_[i] = 0;
967 }
Steve Block44f0eee2011-05-26 01:26:41 +0100968 for (int i = 0; i < kNumFPURegisters; i++) {
969 FPUregisters_[i] = 0;
970 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000971 if (IsMipsArchVariant(kMips32r6)) {
972 FCSR_ = kFCSRNaN2008FlagMask;
973 } else {
974 DCHECK(IsMipsArchVariant(kMips32r1) || IsMipsArchVariant(kMips32r2));
975 FCSR_ = 0;
976 }
Andrei Popescu31002712010-02-23 13:46:05 +0000977
978 // The sp is initialized to point to the bottom (high address) of the
979 // allocated stack area. To be safe in potential stack underflows we leave
980 // some buffer below.
Steve Block44f0eee2011-05-26 01:26:41 +0100981 registers_[sp] = reinterpret_cast<int32_t>(stack_) + stack_size_ - 64;
Andrei Popescu31002712010-02-23 13:46:05 +0000982 // The ra and pc are initialized to a known bad value that will cause an
983 // access violation if the simulator ever tries to execute it.
984 registers_[pc] = bad_ra;
985 registers_[ra] = bad_ra;
986 InitializeCoverage();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100987 last_debugger_input_ = NULL;
Andrei Popescu31002712010-02-23 13:46:05 +0000988}
989
990
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000991Simulator::~Simulator() { free(stack_); }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000992
993
Andrei Popescu31002712010-02-23 13:46:05 +0000994// When the generated code calls an external reference we need to catch that in
995// the simulator. The external reference will be a function compiled for the
996// host architecture. We need to call that function instead of trying to
997// execute it with the simulator. We do that by redirecting the external
998// reference to a swi (software-interrupt) instruction that is handled by
999// the simulator. We write the original destination of the jump just at a known
1000// offset from the swi instruction so the simulator knows what to call.
1001class Redirection {
1002 public:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001003 Redirection(Isolate* isolate, void* external_function,
1004 ExternalReference::Type type)
Andrei Popescu31002712010-02-23 13:46:05 +00001005 : external_function_(external_function),
1006 swi_instruction_(rtCallRedirInstr),
Steve Block44f0eee2011-05-26 01:26:41 +01001007 type_(type),
1008 next_(NULL) {
Steve Block44f0eee2011-05-26 01:26:41 +01001009 next_ = isolate->simulator_redirection();
1010 Simulator::current(isolate)->
1011 FlushICache(isolate->simulator_i_cache(),
1012 reinterpret_cast<void*>(&swi_instruction_),
1013 Instruction::kInstrSize);
1014 isolate->set_simulator_redirection(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001015 }
1016
1017 void* address_of_swi_instruction() {
1018 return reinterpret_cast<void*>(&swi_instruction_);
1019 }
1020
1021 void* external_function() { return external_function_; }
Steve Block44f0eee2011-05-26 01:26:41 +01001022 ExternalReference::Type type() { return type_; }
Andrei Popescu31002712010-02-23 13:46:05 +00001023
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001024 static Redirection* Get(Isolate* isolate, void* external_function,
Steve Block44f0eee2011-05-26 01:26:41 +01001025 ExternalReference::Type type) {
Steve Block44f0eee2011-05-26 01:26:41 +01001026 Redirection* current = isolate->simulator_redirection();
1027 for (; current != NULL; current = current->next_) {
Andrei Popescu31002712010-02-23 13:46:05 +00001028 if (current->external_function_ == external_function) return current;
1029 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001030 return new Redirection(isolate, external_function, type);
Andrei Popescu31002712010-02-23 13:46:05 +00001031 }
1032
1033 static Redirection* FromSwiInstruction(Instruction* swi_instruction) {
1034 char* addr_of_swi = reinterpret_cast<char*>(swi_instruction);
1035 char* addr_of_redirection =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001036 addr_of_swi - offsetof(Redirection, swi_instruction_);
Andrei Popescu31002712010-02-23 13:46:05 +00001037 return reinterpret_cast<Redirection*>(addr_of_redirection);
1038 }
1039
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001040 static void* ReverseRedirection(int32_t reg) {
1041 Redirection* redirection = FromSwiInstruction(
1042 reinterpret_cast<Instruction*>(reinterpret_cast<void*>(reg)));
1043 return redirection->external_function();
1044 }
1045
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001046 static void DeleteChain(Redirection* redirection) {
1047 while (redirection != nullptr) {
1048 Redirection* next = redirection->next_;
1049 delete redirection;
1050 redirection = next;
1051 }
1052 }
1053
Andrei Popescu31002712010-02-23 13:46:05 +00001054 private:
1055 void* external_function_;
1056 uint32_t swi_instruction_;
Steve Block44f0eee2011-05-26 01:26:41 +01001057 ExternalReference::Type type_;
Andrei Popescu31002712010-02-23 13:46:05 +00001058 Redirection* next_;
Andrei Popescu31002712010-02-23 13:46:05 +00001059};
1060
1061
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001062// static
1063void Simulator::TearDown(HashMap* i_cache, Redirection* first) {
1064 Redirection::DeleteChain(first);
1065 if (i_cache != nullptr) {
1066 for (HashMap::Entry* entry = i_cache->Start(); entry != nullptr;
1067 entry = i_cache->Next(entry)) {
1068 delete static_cast<CachePage*>(entry->value);
1069 }
1070 delete i_cache;
1071 }
1072}
1073
1074
1075void* Simulator::RedirectExternalReference(Isolate* isolate,
1076 void* external_function,
Steve Block44f0eee2011-05-26 01:26:41 +01001077 ExternalReference::Type type) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001078 Redirection* redirection = Redirection::Get(isolate, external_function, type);
Andrei Popescu31002712010-02-23 13:46:05 +00001079 return redirection->address_of_swi_instruction();
1080}
1081
1082
1083// Get the active Simulator for the current thread.
Steve Block44f0eee2011-05-26 01:26:41 +01001084Simulator* Simulator::current(Isolate* isolate) {
1085 v8::internal::Isolate::PerIsolateThreadData* isolate_data =
Ben Murdoch257744e2011-11-30 15:57:28 +00001086 isolate->FindOrAllocatePerThreadDataForThisThread();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001087 DCHECK(isolate_data != NULL);
1088 DCHECK(isolate_data != NULL);
Steve Block44f0eee2011-05-26 01:26:41 +01001089
1090 Simulator* sim = isolate_data->simulator();
Andrei Popescu31002712010-02-23 13:46:05 +00001091 if (sim == NULL) {
Steve Block44f0eee2011-05-26 01:26:41 +01001092 // TODO(146): delete the simulator object when a thread/isolate goes away.
Ben Murdoch257744e2011-11-30 15:57:28 +00001093 sim = new Simulator(isolate);
Steve Block44f0eee2011-05-26 01:26:41 +01001094 isolate_data->set_simulator(sim);
Andrei Popescu31002712010-02-23 13:46:05 +00001095 }
1096 return sim;
1097}
1098
1099
1100// Sets the register in the architecture state. It will also deal with updating
1101// Simulator internal state for special registers such as PC.
1102void Simulator::set_register(int reg, int32_t value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001103 DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
Andrei Popescu31002712010-02-23 13:46:05 +00001104 if (reg == pc) {
1105 pc_modified_ = true;
1106 }
1107
Ben Murdoch257744e2011-11-30 15:57:28 +00001108 // Zero register always holds 0.
Andrei Popescu31002712010-02-23 13:46:05 +00001109 registers_[reg] = (reg == 0) ? 0 : value;
1110}
1111
Steve Block44f0eee2011-05-26 01:26:41 +01001112
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001113void Simulator::set_dw_register(int reg, const int* dbl) {
1114 DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
1115 registers_[reg] = dbl[0];
1116 registers_[reg + 1] = dbl[1];
1117}
1118
1119
1120void Simulator::set_fpu_register(int fpureg, int64_t value) {
1121 DCHECK(IsFp64Mode());
1122 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
Andrei Popescu31002712010-02-23 13:46:05 +00001123 FPUregisters_[fpureg] = value;
1124}
1125
Steve Block44f0eee2011-05-26 01:26:41 +01001126
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001127void Simulator::set_fpu_register_word(int fpureg, int32_t value) {
1128 // Set ONLY lower 32-bits, leaving upper bits untouched.
1129 // TODO(plind): big endian issue.
1130 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1131 int32_t *pword = reinterpret_cast<int32_t*>(&FPUregisters_[fpureg]);
1132 *pword = value;
1133}
1134
1135
1136void Simulator::set_fpu_register_hi_word(int fpureg, int32_t value) {
1137 // Set ONLY upper 32-bits, leaving lower bits untouched.
1138 // TODO(plind): big endian issue.
1139 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1140 int32_t *phiword = (reinterpret_cast<int32_t*>(&FPUregisters_[fpureg])) + 1;
1141 *phiword = value;
1142}
1143
1144
Steve Block44f0eee2011-05-26 01:26:41 +01001145void Simulator::set_fpu_register_float(int fpureg, float value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001146 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1147 *bit_cast<float*>(&FPUregisters_[fpureg]) = value;
Steve Block44f0eee2011-05-26 01:26:41 +01001148}
1149
1150
Andrei Popescu31002712010-02-23 13:46:05 +00001151void Simulator::set_fpu_register_double(int fpureg, double value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001152 if (IsFp64Mode()) {
1153 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1154 *bit_cast<double*>(&FPUregisters_[fpureg]) = value;
1155 } else {
1156 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
1157 int64_t i64 = bit_cast<int64_t>(value);
1158 set_fpu_register_word(fpureg, i64 & 0xffffffff);
1159 set_fpu_register_word(fpureg + 1, i64 >> 32);
1160 }
Andrei Popescu31002712010-02-23 13:46:05 +00001161}
1162
1163
1164// Get the register from the architecture state. This function does handle
1165// the special case of accessing the PC register.
1166int32_t Simulator::get_register(int reg) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001167 DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
Andrei Popescu31002712010-02-23 13:46:05 +00001168 if (reg == 0)
1169 return 0;
1170 else
1171 return registers_[reg] + ((reg == pc) ? Instruction::kPCReadOffset : 0);
1172}
1173
Steve Block44f0eee2011-05-26 01:26:41 +01001174
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001175double Simulator::get_double_from_register_pair(int reg) {
1176 // TODO(plind): bad ABI stuff, refactor or remove.
1177 DCHECK((reg >= 0) && (reg < kNumSimuRegisters) && ((reg % 2) == 0));
1178
1179 double dm_val = 0.0;
1180 // Read the bits from the unsigned integer register_[] array
1181 // into the double precision floating point value and return it.
1182 char buffer[2 * sizeof(registers_[0])];
1183 memcpy(buffer, &registers_[reg], 2 * sizeof(registers_[0]));
1184 memcpy(&dm_val, buffer, 2 * sizeof(registers_[0]));
1185 return(dm_val);
1186}
1187
1188
1189int64_t Simulator::get_fpu_register(int fpureg) const {
1190 DCHECK(IsFp64Mode());
1191 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
Andrei Popescu31002712010-02-23 13:46:05 +00001192 return FPUregisters_[fpureg];
1193}
1194
Steve Block44f0eee2011-05-26 01:26:41 +01001195
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001196int32_t Simulator::get_fpu_register_word(int fpureg) const {
1197 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1198 return static_cast<int32_t>(FPUregisters_[fpureg] & 0xffffffff);
1199}
1200
1201
1202int32_t Simulator::get_fpu_register_signed_word(int fpureg) const {
1203 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1204 return static_cast<int32_t>(FPUregisters_[fpureg] & 0xffffffff);
1205}
1206
1207
1208int32_t Simulator::get_fpu_register_hi_word(int fpureg) const {
1209 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1210 return static_cast<int32_t>((FPUregisters_[fpureg] >> 32) & 0xffffffff);
Steve Block44f0eee2011-05-26 01:26:41 +01001211}
1212
1213
1214float Simulator::get_fpu_register_float(int fpureg) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001215 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1216 return *bit_cast<float*>(const_cast<int64_t*>(&FPUregisters_[fpureg]));
Steve Block44f0eee2011-05-26 01:26:41 +01001217}
1218
1219
Andrei Popescu31002712010-02-23 13:46:05 +00001220double Simulator::get_fpu_register_double(int fpureg) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001221 if (IsFp64Mode()) {
1222 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1223 return *bit_cast<double*>(&FPUregisters_[fpureg]);
1224 } else {
1225 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
1226 int64_t i64;
1227 i64 = static_cast<uint32_t>(get_fpu_register_word(fpureg));
1228 i64 |= static_cast<uint64_t>(get_fpu_register_word(fpureg + 1)) << 32;
1229 return bit_cast<double>(i64);
1230 }
Andrei Popescu31002712010-02-23 13:46:05 +00001231}
1232
Steve Block44f0eee2011-05-26 01:26:41 +01001233
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001234// Runtime FP routines take up to two double arguments and zero
1235// or one integer arguments. All are constructed here,
Ben Murdoch257744e2011-11-30 15:57:28 +00001236// from a0-a3 or f12 and f14.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001237void Simulator::GetFpArgs(double* x, double* y, int32_t* z) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001238 if (!IsMipsSoftFloatABI) {
1239 *x = get_fpu_register_double(12);
1240 *y = get_fpu_register_double(14);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001241 *z = get_register(a2);
Ben Murdoch257744e2011-11-30 15:57:28 +00001242 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001243 // TODO(plind): bad ABI stuff, refactor or remove.
Ben Murdoch257744e2011-11-30 15:57:28 +00001244 // We use a char buffer to get around the strict-aliasing rules which
1245 // otherwise allow the compiler to optimize away the copy.
1246 char buffer[sizeof(*x)];
1247 int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
1248
1249 // Registers a0 and a1 -> x.
1250 reg_buffer[0] = get_register(a0);
1251 reg_buffer[1] = get_register(a1);
1252 memcpy(x, buffer, sizeof(buffer));
Ben Murdoch257744e2011-11-30 15:57:28 +00001253 // Registers a2 and a3 -> y.
1254 reg_buffer[0] = get_register(a2);
1255 reg_buffer[1] = get_register(a3);
1256 memcpy(y, buffer, sizeof(buffer));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001257 // Register 2 -> z.
Ben Murdoch257744e2011-11-30 15:57:28 +00001258 reg_buffer[0] = get_register(a2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001259 memcpy(z, buffer, sizeof(*z));
Ben Murdoch257744e2011-11-30 15:57:28 +00001260 }
1261}
1262
1263
1264// The return value is either in v0/v1 or f0.
1265void Simulator::SetFpResult(const double& result) {
1266 if (!IsMipsSoftFloatABI) {
1267 set_fpu_register_double(0, result);
1268 } else {
1269 char buffer[2 * sizeof(registers_[0])];
1270 int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
1271 memcpy(buffer, &result, sizeof(buffer));
1272 // Copy result to v0 and v1.
1273 set_register(v0, reg_buffer[0]);
1274 set_register(v1, reg_buffer[1]);
1275 }
1276}
1277
1278
Steve Block44f0eee2011-05-26 01:26:41 +01001279// Helper functions for setting and testing the FCSR register's bits.
1280void Simulator::set_fcsr_bit(uint32_t cc, bool value) {
1281 if (value) {
1282 FCSR_ |= (1 << cc);
1283 } else {
1284 FCSR_ &= ~(1 << cc);
1285 }
1286}
1287
1288
1289bool Simulator::test_fcsr_bit(uint32_t cc) {
1290 return FCSR_ & (1 << cc);
1291}
1292
1293
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001294void Simulator::set_fcsr_rounding_mode(FPURoundingMode mode) {
1295 FCSR_ |= mode & kFPURoundingModeMask;
1296}
1297
1298
1299unsigned int Simulator::get_fcsr_rounding_mode() {
1300 return FCSR_ & kFPURoundingModeMask;
1301}
1302
1303
1304void Simulator::set_fpu_register_word_invalid_result(float original,
1305 float rounded) {
1306 if (FCSR_ & kFCSRNaN2008FlagMask) {
1307 double max_int32 = std::numeric_limits<int32_t>::max();
1308 double min_int32 = std::numeric_limits<int32_t>::min();
1309 if (std::isnan(original)) {
1310 set_fpu_register_word(fd_reg(), 0);
1311 } else if (rounded > max_int32) {
1312 set_fpu_register_word(fd_reg(), kFPUInvalidResult);
1313 } else if (rounded < min_int32) {
1314 set_fpu_register_word(fd_reg(), kFPUInvalidResultNegative);
1315 } else {
1316 UNREACHABLE();
1317 }
1318 } else {
1319 set_fpu_register_word(fd_reg(), kFPUInvalidResult);
1320 }
1321}
1322
1323
1324void Simulator::set_fpu_register_invalid_result(float original, float rounded) {
1325 if (FCSR_ & kFCSRNaN2008FlagMask) {
1326 double max_int32 = std::numeric_limits<int32_t>::max();
1327 double min_int32 = std::numeric_limits<int32_t>::min();
1328 if (std::isnan(original)) {
1329 set_fpu_register(fd_reg(), 0);
1330 } else if (rounded > max_int32) {
1331 set_fpu_register(fd_reg(), kFPUInvalidResult);
1332 } else if (rounded < min_int32) {
1333 set_fpu_register(fd_reg(), kFPUInvalidResultNegative);
1334 } else {
1335 UNREACHABLE();
1336 }
1337 } else {
1338 set_fpu_register(fd_reg(), kFPUInvalidResult);
1339 }
1340}
1341
1342
1343void Simulator::set_fpu_register_invalid_result64(float original,
1344 float rounded) {
1345 if (FCSR_ & kFCSRNaN2008FlagMask) {
1346 // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1347 // loading the most accurate representation into max_int64, which is 2^63.
1348 double max_int64 = std::numeric_limits<int64_t>::max();
1349 double min_int64 = std::numeric_limits<int64_t>::min();
1350 if (std::isnan(original)) {
1351 set_fpu_register(fd_reg(), 0);
1352 } else if (rounded >= max_int64) {
1353 set_fpu_register(fd_reg(), kFPU64InvalidResult);
1354 } else if (rounded < min_int64) {
1355 set_fpu_register(fd_reg(), kFPU64InvalidResultNegative);
1356 } else {
1357 UNREACHABLE();
1358 }
1359 } else {
1360 set_fpu_register(fd_reg(), kFPU64InvalidResult);
1361 }
1362}
1363
1364
1365void Simulator::set_fpu_register_word_invalid_result(double original,
1366 double rounded) {
1367 if (FCSR_ & kFCSRNaN2008FlagMask) {
1368 double max_int32 = std::numeric_limits<int32_t>::max();
1369 double min_int32 = std::numeric_limits<int32_t>::min();
1370 if (std::isnan(original)) {
1371 set_fpu_register_word(fd_reg(), 0);
1372 } else if (rounded > max_int32) {
1373 set_fpu_register_word(fd_reg(), kFPUInvalidResult);
1374 } else if (rounded < min_int32) {
1375 set_fpu_register_word(fd_reg(), kFPUInvalidResultNegative);
1376 } else {
1377 UNREACHABLE();
1378 }
1379 } else {
1380 set_fpu_register_word(fd_reg(), kFPUInvalidResult);
1381 }
1382}
1383
1384
1385void Simulator::set_fpu_register_invalid_result(double original,
1386 double rounded) {
1387 if (FCSR_ & kFCSRNaN2008FlagMask) {
1388 double max_int32 = std::numeric_limits<int32_t>::max();
1389 double min_int32 = std::numeric_limits<int32_t>::min();
1390 if (std::isnan(original)) {
1391 set_fpu_register(fd_reg(), 0);
1392 } else if (rounded > max_int32) {
1393 set_fpu_register(fd_reg(), kFPUInvalidResult);
1394 } else if (rounded < min_int32) {
1395 set_fpu_register(fd_reg(), kFPUInvalidResultNegative);
1396 } else {
1397 UNREACHABLE();
1398 }
1399 } else {
1400 set_fpu_register(fd_reg(), kFPUInvalidResult);
1401 }
1402}
1403
1404
1405void Simulator::set_fpu_register_invalid_result64(double original,
1406 double rounded) {
1407 if (FCSR_ & kFCSRNaN2008FlagMask) {
1408 // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1409 // loading the most accurate representation into max_int64, which is 2^63.
1410 double max_int64 = std::numeric_limits<int64_t>::max();
1411 double min_int64 = std::numeric_limits<int64_t>::min();
1412 if (std::isnan(original)) {
1413 set_fpu_register(fd_reg(), 0);
1414 } else if (rounded >= max_int64) {
1415 set_fpu_register(fd_reg(), kFPU64InvalidResult);
1416 } else if (rounded < min_int64) {
1417 set_fpu_register(fd_reg(), kFPU64InvalidResultNegative);
1418 } else {
1419 UNREACHABLE();
1420 }
1421 } else {
1422 set_fpu_register(fd_reg(), kFPU64InvalidResult);
1423 }
1424}
1425
1426
Steve Block44f0eee2011-05-26 01:26:41 +01001427// Sets the rounding error codes in FCSR based on the result of the rounding.
1428// Returns true if the operation was invalid.
1429bool Simulator::set_fcsr_round_error(double original, double rounded) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001430 bool ret = false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001431 double max_int32 = std::numeric_limits<int32_t>::max();
1432 double min_int32 = std::numeric_limits<int32_t>::min();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001433
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001434 if (!std::isfinite(original) || !std::isfinite(rounded)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001435 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1436 ret = true;
Steve Block44f0eee2011-05-26 01:26:41 +01001437 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001438
1439 if (original != rounded) {
1440 set_fcsr_bit(kFCSRInexactFlagBit, true);
1441 }
1442
1443 if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) {
1444 set_fcsr_bit(kFCSRUnderflowFlagBit, true);
1445 ret = true;
1446 }
1447
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001448 if (rounded > max_int32 || rounded < min_int32) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001449 set_fcsr_bit(kFCSROverflowFlagBit, true);
1450 // The reference is not really clear but it seems this is required:
1451 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1452 ret = true;
1453 }
1454
1455 return ret;
Steve Block44f0eee2011-05-26 01:26:41 +01001456}
1457
1458
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001459// Sets the rounding error codes in FCSR based on the result of the rounding.
1460// Returns true if the operation was invalid.
1461bool Simulator::set_fcsr_round64_error(double original, double rounded) {
1462 bool ret = false;
1463 // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1464 // loading the most accurate representation into max_int64, which is 2^63.
1465 double max_int64 = std::numeric_limits<int64_t>::max();
1466 double min_int64 = std::numeric_limits<int64_t>::min();
1467
1468 if (!std::isfinite(original) || !std::isfinite(rounded)) {
1469 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1470 ret = true;
1471 }
1472
1473 if (original != rounded) {
1474 set_fcsr_bit(kFCSRInexactFlagBit, true);
1475 }
1476
1477 if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) {
1478 set_fcsr_bit(kFCSRUnderflowFlagBit, true);
1479 ret = true;
1480 }
1481
1482 if (rounded >= max_int64 || rounded < min_int64) {
1483 set_fcsr_bit(kFCSROverflowFlagBit, true);
1484 // The reference is not really clear but it seems this is required:
1485 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1486 ret = true;
1487 }
1488
1489 return ret;
1490}
1491
1492
1493// Sets the rounding error codes in FCSR based on the result of the rounding.
1494// Returns true if the operation was invalid.
1495bool Simulator::set_fcsr_round_error(float original, float rounded) {
1496 bool ret = false;
1497 double max_int32 = std::numeric_limits<int32_t>::max();
1498 double min_int32 = std::numeric_limits<int32_t>::min();
1499
1500 if (!std::isfinite(original) || !std::isfinite(rounded)) {
1501 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1502 ret = true;
1503 }
1504
1505 if (original != rounded) {
1506 set_fcsr_bit(kFCSRInexactFlagBit, true);
1507 }
1508
1509 if (rounded < FLT_MIN && rounded > -FLT_MIN && rounded != 0) {
1510 set_fcsr_bit(kFCSRUnderflowFlagBit, true);
1511 ret = true;
1512 }
1513
1514 if (rounded > max_int32 || rounded < min_int32) {
1515 set_fcsr_bit(kFCSROverflowFlagBit, true);
1516 // The reference is not really clear but it seems this is required:
1517 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1518 ret = true;
1519 }
1520
1521 return ret;
1522}
1523
1524
1525// Sets the rounding error codes in FCSR based on the result of the rounding.
1526// Returns true if the operation was invalid.
1527bool Simulator::set_fcsr_round64_error(float original, float rounded) {
1528 bool ret = false;
1529 // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1530 // loading the most accurate representation into max_int64, which is 2^63.
1531 double max_int64 = std::numeric_limits<int64_t>::max();
1532 double min_int64 = std::numeric_limits<int64_t>::min();
1533
1534 if (!std::isfinite(original) || !std::isfinite(rounded)) {
1535 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1536 ret = true;
1537 }
1538
1539 if (original != rounded) {
1540 set_fcsr_bit(kFCSRInexactFlagBit, true);
1541 }
1542
1543 if (rounded < FLT_MIN && rounded > -FLT_MIN && rounded != 0) {
1544 set_fcsr_bit(kFCSRUnderflowFlagBit, true);
1545 ret = true;
1546 }
1547
1548 if (rounded >= max_int64 || rounded < min_int64) {
1549 set_fcsr_bit(kFCSROverflowFlagBit, true);
1550 // The reference is not really clear but it seems this is required:
1551 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1552 ret = true;
1553 }
1554
1555 return ret;
1556}
1557
1558
1559void Simulator::round_according_to_fcsr(double toRound, double& rounded,
1560 int32_t& rounded_int, double fs) {
1561 // 0 RN (round to nearest): Round a result to the nearest
1562 // representable value; if the result is exactly halfway between
1563 // two representable values, round to zero. Behave like round_w_d.
1564
1565 // 1 RZ (round toward zero): Round a result to the closest
1566 // representable value whose absolute value is less than or
1567 // equal to the infinitely accurate result. Behave like trunc_w_d.
1568
1569 // 2 RP (round up, or toward infinity): Round a result to the
1570 // next representable value up. Behave like ceil_w_d.
1571
1572 // 3 RD (round down, or toward −infinity): Round a result to
1573 // the next representable value down. Behave like floor_w_d.
1574 switch (get_fcsr_rounding_mode()) {
1575 case kRoundToNearest:
1576 rounded = std::floor(fs + 0.5);
1577 rounded_int = static_cast<int32_t>(rounded);
1578 if ((rounded_int & 1) != 0 && rounded_int - fs == 0.5) {
1579 // If the number is halfway between two integers,
1580 // round to the even one.
1581 rounded_int--;
1582 }
1583 break;
1584 case kRoundToZero:
1585 rounded = trunc(fs);
1586 rounded_int = static_cast<int32_t>(rounded);
1587 break;
1588 case kRoundToPlusInf:
1589 rounded = std::ceil(fs);
1590 rounded_int = static_cast<int32_t>(rounded);
1591 break;
1592 case kRoundToMinusInf:
1593 rounded = std::floor(fs);
1594 rounded_int = static_cast<int32_t>(rounded);
1595 break;
1596 }
1597}
1598
1599
1600void Simulator::round_according_to_fcsr(float toRound, float& rounded,
1601 int32_t& rounded_int, float fs) {
1602 // 0 RN (round to nearest): Round a result to the nearest
1603 // representable value; if the result is exactly halfway between
1604 // two representable values, round to zero. Behave like round_w_d.
1605
1606 // 1 RZ (round toward zero): Round a result to the closest
1607 // representable value whose absolute value is less than or
1608 // equal to the infinitely accurate result. Behave like trunc_w_d.
1609
1610 // 2 RP (round up, or toward infinity): Round a result to the
1611 // next representable value up. Behave like ceil_w_d.
1612
1613 // 3 RD (round down, or toward −infinity): Round a result to
1614 // the next representable value down. Behave like floor_w_d.
1615 switch (get_fcsr_rounding_mode()) {
1616 case kRoundToNearest:
1617 rounded = std::floor(fs + 0.5);
1618 rounded_int = static_cast<int32_t>(rounded);
1619 if ((rounded_int & 1) != 0 && rounded_int - fs == 0.5) {
1620 // If the number is halfway between two integers,
1621 // round to the even one.
1622 rounded_int--;
1623 }
1624 break;
1625 case kRoundToZero:
1626 rounded = trunc(fs);
1627 rounded_int = static_cast<int32_t>(rounded);
1628 break;
1629 case kRoundToPlusInf:
1630 rounded = std::ceil(fs);
1631 rounded_int = static_cast<int32_t>(rounded);
1632 break;
1633 case kRoundToMinusInf:
1634 rounded = std::floor(fs);
1635 rounded_int = static_cast<int32_t>(rounded);
1636 break;
1637 }
1638}
1639
1640
1641void Simulator::round64_according_to_fcsr(double toRound, double& rounded,
1642 int64_t& rounded_int, double fs) {
1643 // 0 RN (round to nearest): Round a result to the nearest
1644 // representable value; if the result is exactly halfway between
1645 // two representable values, round to zero. Behave like round_w_d.
1646
1647 // 1 RZ (round toward zero): Round a result to the closest
1648 // representable value whose absolute value is less than or.
1649 // equal to the infinitely accurate result. Behave like trunc_w_d.
1650
1651 // 2 RP (round up, or toward +infinity): Round a result to the
1652 // next representable value up. Behave like ceil_w_d.
1653
1654 // 3 RN (round down, or toward −infinity): Round a result to
1655 // the next representable value down. Behave like floor_w_d.
1656 switch (FCSR_ & 3) {
1657 case kRoundToNearest:
1658 rounded = std::floor(fs + 0.5);
1659 rounded_int = static_cast<int64_t>(rounded);
1660 if ((rounded_int & 1) != 0 && rounded_int - fs == 0.5) {
1661 // If the number is halfway between two integers,
1662 // round to the even one.
1663 rounded_int--;
1664 }
1665 break;
1666 case kRoundToZero:
1667 rounded = trunc(fs);
1668 rounded_int = static_cast<int64_t>(rounded);
1669 break;
1670 case kRoundToPlusInf:
1671 rounded = std::ceil(fs);
1672 rounded_int = static_cast<int64_t>(rounded);
1673 break;
1674 case kRoundToMinusInf:
1675 rounded = std::floor(fs);
1676 rounded_int = static_cast<int64_t>(rounded);
1677 break;
1678 }
1679}
1680
1681
1682void Simulator::round64_according_to_fcsr(float toRound, float& rounded,
1683 int64_t& rounded_int, float fs) {
1684 // 0 RN (round to nearest): Round a result to the nearest
1685 // representable value; if the result is exactly halfway between
1686 // two representable values, round to zero. Behave like round_w_d.
1687
1688 // 1 RZ (round toward zero): Round a result to the closest
1689 // representable value whose absolute value is less than or.
1690 // equal to the infinitely accurate result. Behave like trunc_w_d.
1691
1692 // 2 RP (round up, or toward +infinity): Round a result to the
1693 // next representable value up. Behave like ceil_w_d.
1694
1695 // 3 RN (round down, or toward −infinity): Round a result to
1696 // the next representable value down. Behave like floor_w_d.
1697 switch (FCSR_ & 3) {
1698 case kRoundToNearest:
1699 rounded = std::floor(fs + 0.5);
1700 rounded_int = static_cast<int64_t>(rounded);
1701 if ((rounded_int & 1) != 0 && rounded_int - fs == 0.5) {
1702 // If the number is halfway between two integers,
1703 // round to the even one.
1704 rounded_int--;
1705 }
1706 break;
1707 case kRoundToZero:
1708 rounded = trunc(fs);
1709 rounded_int = static_cast<int64_t>(rounded);
1710 break;
1711 case kRoundToPlusInf:
1712 rounded = std::ceil(fs);
1713 rounded_int = static_cast<int64_t>(rounded);
1714 break;
1715 case kRoundToMinusInf:
1716 rounded = std::floor(fs);
1717 rounded_int = static_cast<int64_t>(rounded);
1718 break;
1719 }
1720}
1721
1722
Andrei Popescu31002712010-02-23 13:46:05 +00001723// Raw access to the PC register.
1724void Simulator::set_pc(int32_t value) {
1725 pc_modified_ = true;
1726 registers_[pc] = value;
1727}
1728
Steve Block44f0eee2011-05-26 01:26:41 +01001729
1730bool Simulator::has_bad_pc() const {
1731 return ((registers_[pc] == bad_ra) || (registers_[pc] == end_sim_pc));
1732}
1733
1734
Andrei Popescu31002712010-02-23 13:46:05 +00001735// Raw access to the PC register without the special adjustment when reading.
1736int32_t Simulator::get_pc() const {
1737 return registers_[pc];
1738}
1739
1740
1741// The MIPS cannot do unaligned reads and writes. On some MIPS platforms an
1742// interrupt is caused. On others it does a funky rotation thing. For now we
1743// simply disallow unaligned reads, but at some point we may want to move to
1744// emulating the rotate behaviour. Note that simulator runs have the runtime
1745// system running directly on the host system and only generated code is
1746// executed in the simulator. Since the host is typically IA32 we will not
1747// get the correct MIPS-like behaviour on unaligned accesses.
1748
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001749void Simulator::TraceRegWr(int32_t value) {
1750 if (::v8::internal::FLAG_trace_sim) {
1751 SNPrintF(trace_buf_, "%08x", value);
1752 }
1753}
1754
1755
1756// TODO(plind): consider making icount_ printing a flag option.
1757void Simulator::TraceMemRd(int32_t addr, int32_t value) {
1758 if (::v8::internal::FLAG_trace_sim) {
1759 SNPrintF(trace_buf_, "%08x <-- [%08x] (%" PRIu64 ")", value, addr,
1760 icount_);
1761 }
1762}
1763
1764
1765void Simulator::TraceMemWr(int32_t addr, int32_t value, TraceType t) {
1766 if (::v8::internal::FLAG_trace_sim) {
1767 switch (t) {
1768 case BYTE:
1769 SNPrintF(trace_buf_, " %02x --> [%08x]",
1770 static_cast<int8_t>(value), addr);
1771 break;
1772 case HALF:
1773 SNPrintF(trace_buf_, " %04x --> [%08x]", static_cast<int16_t>(value),
1774 addr);
1775 break;
1776 case WORD:
1777 SNPrintF(trace_buf_, "%08x --> [%08x]", value, addr);
1778 break;
1779 }
1780 }
1781}
1782
1783
Andrei Popescu31002712010-02-23 13:46:05 +00001784int Simulator::ReadW(int32_t addr, Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +01001785 if (addr >=0 && addr < 0x400) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001786 // This has to be a NULL-dereference, drop into debugger.
Ben Murdoch589d6972011-11-30 16:04:58 +00001787 PrintF("Memory read from bad address: 0x%08x, pc=0x%08x\n",
1788 addr, reinterpret_cast<intptr_t>(instr));
Steve Block44f0eee2011-05-26 01:26:41 +01001789 MipsDebugger dbg(this);
1790 dbg.Debug();
1791 }
1792 if ((addr & kPointerAlignmentMask) == 0) {
Andrei Popescu31002712010-02-23 13:46:05 +00001793 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001794 TraceMemRd(addr, static_cast<int32_t>(*ptr));
Andrei Popescu31002712010-02-23 13:46:05 +00001795 return *ptr;
1796 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001797 PrintF("Unaligned read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1798 addr,
1799 reinterpret_cast<intptr_t>(instr));
Steve Block44f0eee2011-05-26 01:26:41 +01001800 MipsDebugger dbg(this);
1801 dbg.Debug();
Andrei Popescu31002712010-02-23 13:46:05 +00001802 return 0;
1803}
1804
1805
1806void Simulator::WriteW(int32_t addr, int value, Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +01001807 if (addr >= 0 && addr < 0x400) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001808 // This has to be a NULL-dereference, drop into debugger.
Ben Murdoch589d6972011-11-30 16:04:58 +00001809 PrintF("Memory write to bad address: 0x%08x, pc=0x%08x\n",
1810 addr, reinterpret_cast<intptr_t>(instr));
Steve Block44f0eee2011-05-26 01:26:41 +01001811 MipsDebugger dbg(this);
1812 dbg.Debug();
1813 }
1814 if ((addr & kPointerAlignmentMask) == 0) {
Andrei Popescu31002712010-02-23 13:46:05 +00001815 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001816 TraceMemWr(addr, value, WORD);
Andrei Popescu31002712010-02-23 13:46:05 +00001817 *ptr = value;
1818 return;
1819 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001820 PrintF("Unaligned write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1821 addr,
1822 reinterpret_cast<intptr_t>(instr));
Steve Block44f0eee2011-05-26 01:26:41 +01001823 MipsDebugger dbg(this);
1824 dbg.Debug();
Andrei Popescu31002712010-02-23 13:46:05 +00001825}
1826
1827
1828double Simulator::ReadD(int32_t addr, Instruction* instr) {
1829 if ((addr & kDoubleAlignmentMask) == 0) {
1830 double* ptr = reinterpret_cast<double*>(addr);
1831 return *ptr;
1832 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001833 PrintF("Unaligned (double) read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1834 addr,
1835 reinterpret_cast<intptr_t>(instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001836 base::OS::Abort();
Andrei Popescu31002712010-02-23 13:46:05 +00001837 return 0;
1838}
1839
1840
1841void Simulator::WriteD(int32_t addr, double value, Instruction* instr) {
1842 if ((addr & kDoubleAlignmentMask) == 0) {
1843 double* ptr = reinterpret_cast<double*>(addr);
1844 *ptr = value;
1845 return;
1846 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001847 PrintF("Unaligned (double) write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1848 addr,
1849 reinterpret_cast<intptr_t>(instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001850 base::OS::Abort();
Andrei Popescu31002712010-02-23 13:46:05 +00001851}
1852
1853
1854uint16_t Simulator::ReadHU(int32_t addr, Instruction* instr) {
1855 if ((addr & 1) == 0) {
1856 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001857 TraceMemRd(addr, static_cast<int32_t>(*ptr));
Andrei Popescu31002712010-02-23 13:46:05 +00001858 return *ptr;
1859 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001860 PrintF("Unaligned unsigned halfword read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1861 addr,
1862 reinterpret_cast<intptr_t>(instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001863 base::OS::Abort();
Andrei Popescu31002712010-02-23 13:46:05 +00001864 return 0;
1865}
1866
1867
1868int16_t Simulator::ReadH(int32_t addr, Instruction* instr) {
1869 if ((addr & 1) == 0) {
1870 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001871 TraceMemRd(addr, static_cast<int32_t>(*ptr));
Andrei Popescu31002712010-02-23 13:46:05 +00001872 return *ptr;
1873 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001874 PrintF("Unaligned signed halfword read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1875 addr,
1876 reinterpret_cast<intptr_t>(instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001877 base::OS::Abort();
Andrei Popescu31002712010-02-23 13:46:05 +00001878 return 0;
1879}
1880
1881
1882void Simulator::WriteH(int32_t addr, uint16_t value, Instruction* instr) {
1883 if ((addr & 1) == 0) {
1884 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001885 TraceMemWr(addr, value, HALF);
Andrei Popescu31002712010-02-23 13:46:05 +00001886 *ptr = value;
1887 return;
1888 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001889 PrintF("Unaligned unsigned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1890 addr,
1891 reinterpret_cast<intptr_t>(instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001892 base::OS::Abort();
Andrei Popescu31002712010-02-23 13:46:05 +00001893}
1894
1895
1896void Simulator::WriteH(int32_t addr, int16_t value, Instruction* instr) {
1897 if ((addr & 1) == 0) {
1898 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001899 TraceMemWr(addr, value, HALF);
Andrei Popescu31002712010-02-23 13:46:05 +00001900 *ptr = value;
1901 return;
1902 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001903 PrintF("Unaligned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1904 addr,
1905 reinterpret_cast<intptr_t>(instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001906 base::OS::Abort();
Andrei Popescu31002712010-02-23 13:46:05 +00001907}
1908
1909
1910uint32_t Simulator::ReadBU(int32_t addr) {
1911 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001912 TraceMemRd(addr, static_cast<int32_t>(*ptr));
Andrei Popescu31002712010-02-23 13:46:05 +00001913 return *ptr & 0xff;
1914}
1915
1916
1917int32_t Simulator::ReadB(int32_t addr) {
1918 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001919 TraceMemRd(addr, static_cast<int32_t>(*ptr));
Steve Block44f0eee2011-05-26 01:26:41 +01001920 return *ptr;
Andrei Popescu31002712010-02-23 13:46:05 +00001921}
1922
1923
1924void Simulator::WriteB(int32_t addr, uint8_t value) {
1925 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001926 TraceMemWr(addr, value, BYTE);
Andrei Popescu31002712010-02-23 13:46:05 +00001927 *ptr = value;
1928}
1929
1930
1931void Simulator::WriteB(int32_t addr, int8_t value) {
1932 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001933 TraceMemWr(addr, value, BYTE);
Andrei Popescu31002712010-02-23 13:46:05 +00001934 *ptr = value;
1935}
1936
1937
1938// Returns the limit of the stack area to enable checking for stack overflows.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001939uintptr_t Simulator::StackLimit(uintptr_t c_limit) const {
1940 // The simulator uses a separate JS stack. If we have exhausted the C stack,
1941 // we also drop down the JS limit to reflect the exhaustion on the JS stack.
1942 if (GetCurrentStackPosition() < c_limit) {
1943 return reinterpret_cast<uintptr_t>(get_sp());
1944 }
1945
1946 // Otherwise the limit is the JS stack. Leave a safety margin of 1024 bytes
1947 // to prevent overrunning the stack when pushing values.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001948 return reinterpret_cast<uintptr_t>(stack_) + 1024;
Andrei Popescu31002712010-02-23 13:46:05 +00001949}
1950
1951
1952// Unsupported instructions use Format to print an error and stop execution.
1953void Simulator::Format(Instruction* instr, const char* format) {
1954 PrintF("Simulator found unsupported instruction:\n 0x%08x: %s\n",
Steve Block44f0eee2011-05-26 01:26:41 +01001955 reinterpret_cast<intptr_t>(instr), format);
Andrei Popescu31002712010-02-23 13:46:05 +00001956 UNIMPLEMENTED_MIPS();
1957}
1958
1959
1960// Calls into the V8 runtime are based on this very simple interface.
1961// Note: To be able to return two values from some calls the code in runtime.cc
1962// uses the ObjectPair which is essentially two 32-bit values stuffed into a
1963// 64-bit value. With the code below we assume that all runtime calls return
Steve Block44f0eee2011-05-26 01:26:41 +01001964// 64 bits of result. If they don't, the v1 result register contains a bogus
Andrei Popescu31002712010-02-23 13:46:05 +00001965// value, which is fine because it is caller-saved.
1966typedef int64_t (*SimulatorRuntimeCall)(int32_t arg0,
1967 int32_t arg1,
1968 int32_t arg2,
Steve Block44f0eee2011-05-26 01:26:41 +01001969 int32_t arg3,
1970 int32_t arg4,
1971 int32_t arg5);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001972
1973// These prototypes handle the four types of FP calls.
1974typedef int64_t (*SimulatorRuntimeCompareCall)(double darg0, double darg1);
1975typedef double (*SimulatorRuntimeFPFPCall)(double darg0, double darg1);
1976typedef double (*SimulatorRuntimeFPCall)(double darg0);
1977typedef double (*SimulatorRuntimeFPIntCall)(double darg0, int32_t arg0);
Andrei Popescu31002712010-02-23 13:46:05 +00001978
Ben Murdoch257744e2011-11-30 15:57:28 +00001979// This signature supports direct call in to API function native callback
1980// (refer to InvocationCallback in v8.h).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001981typedef void (*SimulatorRuntimeDirectApiCall)(int32_t arg0);
1982typedef void (*SimulatorRuntimeProfilingApiCall)(int32_t arg0, void* arg1);
Ben Murdoch257744e2011-11-30 15:57:28 +00001983
1984// This signature supports direct call to accessor getter callback.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001985typedef void (*SimulatorRuntimeDirectGetterCall)(int32_t arg0, int32_t arg1);
1986typedef void (*SimulatorRuntimeProfilingGetterCall)(
1987 int32_t arg0, int32_t arg1, void* arg2);
Ben Murdoch257744e2011-11-30 15:57:28 +00001988
Andrei Popescu31002712010-02-23 13:46:05 +00001989// Software interrupt instructions are used by the simulator to call into the
Steve Block44f0eee2011-05-26 01:26:41 +01001990// C-based V8 runtime. They are also used for debugging with simulator.
Andrei Popescu31002712010-02-23 13:46:05 +00001991void Simulator::SoftwareInterrupt(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +01001992 // There are several instructions that could get us here,
1993 // the break_ instruction, or several variants of traps. All
1994 // Are "SPECIAL" class opcode, and are distinuished by function.
1995 int32_t func = instr->FunctionFieldRaw();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001996 uint32_t code = (func == BREAK) ? instr->Bits(25, 6) : -1;
Steve Block44f0eee2011-05-26 01:26:41 +01001997
Andrei Popescu31002712010-02-23 13:46:05 +00001998 // We first check if we met a call_rt_redirected.
1999 if (instr->InstructionBits() == rtCallRedirInstr) {
2000 Redirection* redirection = Redirection::FromSwiInstruction(instr);
2001 int32_t arg0 = get_register(a0);
2002 int32_t arg1 = get_register(a1);
2003 int32_t arg2 = get_register(a2);
2004 int32_t arg3 = get_register(a3);
Steve Block44f0eee2011-05-26 01:26:41 +01002005
Steve Block44f0eee2011-05-26 01:26:41 +01002006 int32_t* stack_pointer = reinterpret_cast<int32_t*>(get_register(sp));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002007 // Args 4 and 5 are on the stack after the reserved space for args 0..3.
2008 int32_t arg4 = stack_pointer[4];
2009 int32_t arg5 = stack_pointer[5];
Ben Murdoch257744e2011-11-30 15:57:28 +00002010
2011 bool fp_call =
2012 (redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) ||
2013 (redirection->type() == ExternalReference::BUILTIN_COMPARE_CALL) ||
2014 (redirection->type() == ExternalReference::BUILTIN_FP_CALL) ||
2015 (redirection->type() == ExternalReference::BUILTIN_FP_INT_CALL);
2016
2017 if (!IsMipsSoftFloatABI) {
2018 // With the hard floating point calling convention, double
2019 // arguments are passed in FPU registers. Fetch the arguments
2020 // from there and call the builtin using soft floating point
2021 // convention.
2022 switch (redirection->type()) {
2023 case ExternalReference::BUILTIN_FP_FP_CALL:
2024 case ExternalReference::BUILTIN_COMPARE_CALL:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002025 if (IsFp64Mode()) {
2026 arg0 = get_fpu_register_word(f12);
2027 arg1 = get_fpu_register_hi_word(f12);
2028 arg2 = get_fpu_register_word(f14);
2029 arg3 = get_fpu_register_hi_word(f14);
2030 } else {
2031 arg0 = get_fpu_register_word(f12);
2032 arg1 = get_fpu_register_word(f13);
2033 arg2 = get_fpu_register_word(f14);
2034 arg3 = get_fpu_register_word(f15);
2035 }
Ben Murdoch257744e2011-11-30 15:57:28 +00002036 break;
2037 case ExternalReference::BUILTIN_FP_CALL:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002038 if (IsFp64Mode()) {
2039 arg0 = get_fpu_register_word(f12);
2040 arg1 = get_fpu_register_hi_word(f12);
2041 } else {
2042 arg0 = get_fpu_register_word(f12);
2043 arg1 = get_fpu_register_word(f13);
2044 }
Ben Murdoch257744e2011-11-30 15:57:28 +00002045 break;
2046 case ExternalReference::BUILTIN_FP_INT_CALL:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002047 if (IsFp64Mode()) {
2048 arg0 = get_fpu_register_word(f12);
2049 arg1 = get_fpu_register_hi_word(f12);
2050 } else {
2051 arg0 = get_fpu_register_word(f12);
2052 arg1 = get_fpu_register_word(f13);
2053 }
Ben Murdoch257744e2011-11-30 15:57:28 +00002054 arg2 = get_register(a2);
2055 break;
2056 default:
2057 break;
2058 }
2059 }
2060
Andrei Popescu31002712010-02-23 13:46:05 +00002061 // This is dodgy but it works because the C entry stubs are never moved.
2062 // See comment in codegen-arm.cc and bug 1242173.
2063 int32_t saved_ra = get_register(ra);
Steve Block44f0eee2011-05-26 01:26:41 +01002064
2065 intptr_t external =
Ben Murdoch257744e2011-11-30 15:57:28 +00002066 reinterpret_cast<intptr_t>(redirection->external_function());
Steve Block44f0eee2011-05-26 01:26:41 +01002067
2068 // Based on CpuFeatures::IsSupported(FPU), Mips will use either hardware
2069 // FPU, or gcc soft-float routines. Hardware FPU is simulated in this
2070 // simulator. Soft-float has additional abstraction of ExternalReference,
Ben Murdoch257744e2011-11-30 15:57:28 +00002071 // to support serialization.
2072 if (fp_call) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002073 double dval0, dval1; // one or two double parameters
2074 int32_t ival; // zero or one integer parameters
2075 int64_t iresult = 0; // integer return value
2076 double dresult = 0; // double return value
2077 GetFpArgs(&dval0, &dval1, &ival);
2078 SimulatorRuntimeCall generic_target =
2079 reinterpret_cast<SimulatorRuntimeCall>(external);
Ben Murdoch257744e2011-11-30 15:57:28 +00002080 if (::v8::internal::FLAG_trace_sim) {
Ben Murdoch257744e2011-11-30 15:57:28 +00002081 switch (redirection->type()) {
2082 case ExternalReference::BUILTIN_FP_FP_CALL:
2083 case ExternalReference::BUILTIN_COMPARE_CALL:
Ben Murdoch257744e2011-11-30 15:57:28 +00002084 PrintF("Call to host function at %p with args %f, %f",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002085 FUNCTION_ADDR(generic_target), dval0, dval1);
Ben Murdoch257744e2011-11-30 15:57:28 +00002086 break;
2087 case ExternalReference::BUILTIN_FP_CALL:
Ben Murdoch257744e2011-11-30 15:57:28 +00002088 PrintF("Call to host function at %p with arg %f",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002089 FUNCTION_ADDR(generic_target), dval0);
Ben Murdoch257744e2011-11-30 15:57:28 +00002090 break;
2091 case ExternalReference::BUILTIN_FP_INT_CALL:
Ben Murdoch257744e2011-11-30 15:57:28 +00002092 PrintF("Call to host function at %p with args %f, %d",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002093 FUNCTION_ADDR(generic_target), dval0, ival);
Ben Murdoch257744e2011-11-30 15:57:28 +00002094 break;
2095 default:
2096 UNREACHABLE();
2097 break;
Steve Block44f0eee2011-05-26 01:26:41 +01002098 }
Andrei Popescu31002712010-02-23 13:46:05 +00002099 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002100 switch (redirection->type()) {
2101 case ExternalReference::BUILTIN_COMPARE_CALL: {
2102 SimulatorRuntimeCompareCall target =
2103 reinterpret_cast<SimulatorRuntimeCompareCall>(external);
2104 iresult = target(dval0, dval1);
2105 set_register(v0, static_cast<int32_t>(iresult));
2106 set_register(v1, static_cast<int32_t>(iresult >> 32));
2107 break;
2108 }
2109 case ExternalReference::BUILTIN_FP_FP_CALL: {
2110 SimulatorRuntimeFPFPCall target =
2111 reinterpret_cast<SimulatorRuntimeFPFPCall>(external);
2112 dresult = target(dval0, dval1);
2113 SetFpResult(dresult);
2114 break;
2115 }
2116 case ExternalReference::BUILTIN_FP_CALL: {
2117 SimulatorRuntimeFPCall target =
2118 reinterpret_cast<SimulatorRuntimeFPCall>(external);
2119 dresult = target(dval0);
2120 SetFpResult(dresult);
2121 break;
2122 }
2123 case ExternalReference::BUILTIN_FP_INT_CALL: {
2124 SimulatorRuntimeFPIntCall target =
2125 reinterpret_cast<SimulatorRuntimeFPIntCall>(external);
2126 dresult = target(dval0, ival);
2127 SetFpResult(dresult);
2128 break;
2129 }
2130 default:
2131 UNREACHABLE();
2132 break;
2133 }
2134 if (::v8::internal::FLAG_trace_sim) {
2135 switch (redirection->type()) {
2136 case ExternalReference::BUILTIN_COMPARE_CALL:
2137 PrintF("Returned %08x\n", static_cast<int32_t>(iresult));
2138 break;
2139 case ExternalReference::BUILTIN_FP_FP_CALL:
2140 case ExternalReference::BUILTIN_FP_CALL:
2141 case ExternalReference::BUILTIN_FP_INT_CALL:
2142 PrintF("Returned %f\n", dresult);
2143 break;
2144 default:
2145 UNREACHABLE();
2146 break;
2147 }
Ben Murdoch257744e2011-11-30 15:57:28 +00002148 }
Steve Block44f0eee2011-05-26 01:26:41 +01002149 } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) {
Ben Murdoch257744e2011-11-30 15:57:28 +00002150 if (::v8::internal::FLAG_trace_sim) {
2151 PrintF("Call to host function at %p args %08x\n",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002152 reinterpret_cast<void*>(external), arg0);
Ben Murdoch257744e2011-11-30 15:57:28 +00002153 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002154 SimulatorRuntimeDirectApiCall target =
2155 reinterpret_cast<SimulatorRuntimeDirectApiCall>(external);
2156 target(arg0);
2157 } else if (
2158 redirection->type() == ExternalReference::PROFILING_API_CALL) {
Ben Murdoch257744e2011-11-30 15:57:28 +00002159 if (::v8::internal::FLAG_trace_sim) {
2160 PrintF("Call to host function at %p args %08x %08x\n",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002161 reinterpret_cast<void*>(external), arg0, arg1);
Ben Murdoch257744e2011-11-30 15:57:28 +00002162 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002163 SimulatorRuntimeProfilingApiCall target =
2164 reinterpret_cast<SimulatorRuntimeProfilingApiCall>(external);
2165 target(arg0, Redirection::ReverseRedirection(arg1));
2166 } else if (
2167 redirection->type() == ExternalReference::DIRECT_GETTER_CALL) {
2168 if (::v8::internal::FLAG_trace_sim) {
2169 PrintF("Call to host function at %p args %08x %08x\n",
2170 reinterpret_cast<void*>(external), arg0, arg1);
2171 }
2172 SimulatorRuntimeDirectGetterCall target =
2173 reinterpret_cast<SimulatorRuntimeDirectGetterCall>(external);
2174 target(arg0, arg1);
2175 } else if (
2176 redirection->type() == ExternalReference::PROFILING_GETTER_CALL) {
2177 if (::v8::internal::FLAG_trace_sim) {
2178 PrintF("Call to host function at %p args %08x %08x %08x\n",
2179 reinterpret_cast<void*>(external), arg0, arg1, arg2);
2180 }
2181 SimulatorRuntimeProfilingGetterCall target =
2182 reinterpret_cast<SimulatorRuntimeProfilingGetterCall>(external);
2183 target(arg0, arg1, Redirection::ReverseRedirection(arg2));
Andrei Popescu31002712010-02-23 13:46:05 +00002184 } else {
Andrei Popescu31002712010-02-23 13:46:05 +00002185 SimulatorRuntimeCall target =
Ben Murdoch257744e2011-11-30 15:57:28 +00002186 reinterpret_cast<SimulatorRuntimeCall>(external);
2187 if (::v8::internal::FLAG_trace_sim) {
Andrei Popescu31002712010-02-23 13:46:05 +00002188 PrintF(
Ben Murdoch257744e2011-11-30 15:57:28 +00002189 "Call to host function at %p "
2190 "args %08x, %08x, %08x, %08x, %08x, %08x\n",
Andrei Popescu31002712010-02-23 13:46:05 +00002191 FUNCTION_ADDR(target),
2192 arg0,
2193 arg1,
2194 arg2,
Steve Block44f0eee2011-05-26 01:26:41 +01002195 arg3,
2196 arg4,
2197 arg5);
Andrei Popescu31002712010-02-23 13:46:05 +00002198 }
Steve Block44f0eee2011-05-26 01:26:41 +01002199 int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5);
2200 set_register(v0, static_cast<int32_t>(result));
2201 set_register(v1, static_cast<int32_t>(result >> 32));
2202 }
2203 if (::v8::internal::FLAG_trace_sim) {
2204 PrintF("Returned %08x : %08x\n", get_register(v1), get_register(v0));
Andrei Popescu31002712010-02-23 13:46:05 +00002205 }
2206 set_register(ra, saved_ra);
2207 set_pc(get_register(ra));
Steve Block44f0eee2011-05-26 01:26:41 +01002208
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002209 } else if (func == BREAK && code <= kMaxStopCode) {
2210 if (IsWatchpoint(code)) {
2211 PrintWatchpoint(code);
2212 } else {
2213 IncreaseStopCounter(code);
2214 HandleStop(code, instr);
2215 }
Andrei Popescu31002712010-02-23 13:46:05 +00002216 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01002217 // All remaining break_ codes, and all traps are handled here.
2218 MipsDebugger dbg(this);
Andrei Popescu31002712010-02-23 13:46:05 +00002219 dbg.Debug();
2220 }
2221}
2222
Steve Block44f0eee2011-05-26 01:26:41 +01002223
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002224// Stop helper functions.
2225bool Simulator::IsWatchpoint(uint32_t code) {
2226 return (code <= kMaxWatchpointCode);
2227}
2228
2229
2230void Simulator::PrintWatchpoint(uint32_t code) {
2231 MipsDebugger dbg(this);
2232 ++break_count_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002233 PrintF("\n---- break %d marker: %3d (instr count: %" PRIu64
2234 ") ----------"
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002235 "----------------------------------",
2236 code, break_count_, icount_);
2237 dbg.PrintAllRegs(); // Print registers and continue running.
2238}
2239
2240
2241void Simulator::HandleStop(uint32_t code, Instruction* instr) {
2242 // Stop if it is enabled, otherwise go on jumping over the stop
2243 // and the message address.
2244 if (IsEnabledStop(code)) {
2245 MipsDebugger dbg(this);
2246 dbg.Stop(instr);
2247 } else {
2248 set_pc(get_pc() + 2 * Instruction::kInstrSize);
2249 }
2250}
2251
2252
2253bool Simulator::IsStopInstruction(Instruction* instr) {
2254 int32_t func = instr->FunctionFieldRaw();
2255 uint32_t code = static_cast<uint32_t>(instr->Bits(25, 6));
2256 return (func == BREAK) && code > kMaxWatchpointCode && code <= kMaxStopCode;
2257}
2258
2259
2260bool Simulator::IsEnabledStop(uint32_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002261 DCHECK(code <= kMaxStopCode);
2262 DCHECK(code > kMaxWatchpointCode);
2263 return !(watched_stops_[code].count & kStopDisabledBit);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002264}
2265
2266
2267void Simulator::EnableStop(uint32_t code) {
2268 if (!IsEnabledStop(code)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002269 watched_stops_[code].count &= ~kStopDisabledBit;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002270 }
2271}
2272
2273
2274void Simulator::DisableStop(uint32_t code) {
2275 if (IsEnabledStop(code)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002276 watched_stops_[code].count |= kStopDisabledBit;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002277 }
2278}
2279
2280
2281void Simulator::IncreaseStopCounter(uint32_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002282 DCHECK(code <= kMaxStopCode);
2283 if ((watched_stops_[code].count & ~(1 << 31)) == 0x7fffffff) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002284 PrintF("Stop counter for code %i has overflowed.\n"
2285 "Enabling this code and reseting the counter to 0.\n", code);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002286 watched_stops_[code].count = 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002287 EnableStop(code);
2288 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002289 watched_stops_[code].count++;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002290 }
2291}
2292
2293
2294// Print a stop status.
2295void Simulator::PrintStopInfo(uint32_t code) {
2296 if (code <= kMaxWatchpointCode) {
2297 PrintF("That is a watchpoint, not a stop.\n");
2298 return;
2299 } else if (code > kMaxStopCode) {
2300 PrintF("Code too large, only %u stops can be used\n", kMaxStopCode + 1);
2301 return;
2302 }
2303 const char* state = IsEnabledStop(code) ? "Enabled" : "Disabled";
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002304 int32_t count = watched_stops_[code].count & ~kStopDisabledBit;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002305 // Don't print the state of unused breakpoints.
2306 if (count != 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002307 if (watched_stops_[code].desc) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002308 PrintF("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002309 code, code, state, count, watched_stops_[code].desc);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002310 } else {
2311 PrintF("stop %i - 0x%x: \t%s, \tcounter = %i\n",
2312 code, code, state, count);
2313 }
2314 }
2315}
2316
2317
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002318void Simulator::SignalException(Exception e) {
2319 V8_Fatal(__FILE__, __LINE__, "Error: Exception %i raised.",
2320 static_cast<int>(e));
2321}
2322
2323
2324void Simulator::DecodeTypeRegisterDRsType() {
2325 double ft, fs, fd;
2326 uint32_t cc, fcsr_cc;
2327 int64_t i64;
2328 fs = get_fpu_register_double(fs_reg());
2329 ft = (get_instr()->FunctionFieldRaw() != MOVF)
2330 ? get_fpu_register_double(ft_reg())
2331 : 0.0;
2332 fd = get_fpu_register_double(fd_reg());
2333 int64_t ft_int = bit_cast<int64_t>(ft);
2334 int64_t fd_int = bit_cast<int64_t>(fd);
2335 cc = get_instr()->FCccValue();
2336 fcsr_cc = get_fcsr_condition_bit(cc);
2337 switch (get_instr()->FunctionFieldRaw()) {
2338 case RINT: {
2339 DCHECK(IsMipsArchVariant(kMips32r6));
2340 double result, temp, temp_result;
2341 double upper = std::ceil(fs);
2342 double lower = std::floor(fs);
2343 switch (get_fcsr_rounding_mode()) {
2344 case kRoundToNearest:
2345 if (upper - fs < fs - lower) {
2346 result = upper;
2347 } else if (upper - fs > fs - lower) {
2348 result = lower;
2349 } else {
2350 temp_result = upper / 2;
2351 double reminder = modf(temp_result, &temp);
2352 if (reminder == 0) {
2353 result = upper;
2354 } else {
2355 result = lower;
2356 }
2357 }
2358 break;
2359 case kRoundToZero:
2360 result = (fs > 0 ? lower : upper);
2361 break;
2362 case kRoundToPlusInf:
2363 result = upper;
2364 break;
2365 case kRoundToMinusInf:
2366 result = lower;
2367 break;
2368 }
2369 set_fpu_register_double(fd_reg(), result);
2370 if (result != fs) {
2371 set_fcsr_bit(kFCSRInexactFlagBit, true);
2372 }
2373 break;
Andrei Popescu31002712010-02-23 13:46:05 +00002374 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002375 case SEL:
2376 DCHECK(IsMipsArchVariant(kMips32r6));
2377 set_fpu_register_double(fd_reg(), (fd_int & 0x1) == 0 ? fs : ft);
2378 break;
2379 case SELEQZ_C:
2380 DCHECK(IsMipsArchVariant(kMips32r6));
2381 set_fpu_register_double(fd_reg(), (ft_int & 0x1) == 0 ? fs : 0.0);
2382 break;
2383 case SELNEZ_C:
2384 DCHECK(IsMipsArchVariant(kMips32r6));
2385 set_fpu_register_double(fd_reg(), (ft_int & 0x1) != 0 ? fs : 0.0);
2386 break;
2387 case MOVZ_C: {
2388 DCHECK(IsMipsArchVariant(kMips32r2));
2389 if (rt() == 0) {
2390 set_fpu_register_double(fd_reg(), fs);
2391 }
2392 break;
2393 }
2394 case MOVN_C: {
2395 DCHECK(IsMipsArchVariant(kMips32r2));
2396 int32_t rt_reg = get_instr()->RtValue();
2397 int32_t rt = get_register(rt_reg);
2398 if (rt != 0) {
2399 set_fpu_register_double(fd_reg(), fs);
2400 }
2401 break;
2402 }
2403 case MOVF: {
2404 // Same function field for MOVT.D and MOVF.D
2405 uint32_t ft_cc = (ft_reg() >> 2) & 0x7;
2406 ft_cc = get_fcsr_condition_bit(ft_cc);
2407 if (get_instr()->Bit(16)) { // Read Tf bit.
2408 // MOVT.D
2409 if (test_fcsr_bit(ft_cc)) set_fpu_register_double(fd_reg(), fs);
2410 } else {
2411 // MOVF.D
2412 if (!test_fcsr_bit(ft_cc)) set_fpu_register_double(fd_reg(), fs);
2413 }
2414 break;
2415 }
2416 case MIN:
2417 DCHECK(IsMipsArchVariant(kMips32r6));
2418 fs = get_fpu_register_double(fs_reg());
2419 if (std::isnan(fs) && std::isnan(ft)) {
2420 set_fpu_register_double(fd_reg(), fs);
2421 } else if (std::isnan(fs) && !std::isnan(ft)) {
2422 set_fpu_register_double(fd_reg(), ft);
2423 } else if (!std::isnan(fs) && std::isnan(ft)) {
2424 set_fpu_register_double(fd_reg(), fs);
2425 } else {
2426 set_fpu_register_double(fd_reg(), (fs >= ft) ? ft : fs);
2427 }
2428 break;
2429 case MINA:
2430 DCHECK(IsMipsArchVariant(kMips32r6));
2431 fs = get_fpu_register_double(fs_reg());
2432 if (std::isnan(fs) && std::isnan(ft)) {
2433 set_fpu_register_double(fd_reg(), fs);
2434 } else if (std::isnan(fs) && !std::isnan(ft)) {
2435 set_fpu_register_double(fd_reg(), ft);
2436 } else if (!std::isnan(fs) && std::isnan(ft)) {
2437 set_fpu_register_double(fd_reg(), fs);
2438 } else {
2439 double result;
2440 if (fabs(fs) > fabs(ft)) {
2441 result = ft;
2442 } else if (fabs(fs) < fabs(ft)) {
2443 result = fs;
2444 } else {
2445 result = (fs < ft ? fs : ft);
2446 }
2447 set_fpu_register_double(fd_reg(), result);
2448 }
2449 break;
2450 case MAXA:
2451 DCHECK(IsMipsArchVariant(kMips32r6));
2452 fs = get_fpu_register_double(fs_reg());
2453 if (std::isnan(fs) && std::isnan(ft)) {
2454 set_fpu_register_double(fd_reg(), fs);
2455 } else if (std::isnan(fs) && !std::isnan(ft)) {
2456 set_fpu_register_double(fd_reg(), ft);
2457 } else if (!std::isnan(fs) && std::isnan(ft)) {
2458 set_fpu_register_double(fd_reg(), fs);
2459 } else {
2460 double result;
2461 if (fabs(fs) < fabs(ft)) {
2462 result = ft;
2463 } else if (fabs(fs) > fabs(ft)) {
2464 result = fs;
2465 } else {
2466 result = (fs > ft ? fs : ft);
2467 }
2468 set_fpu_register_double(fd_reg(), result);
2469 }
2470 break;
2471 case MAX:
2472 DCHECK(IsMipsArchVariant(kMips32r6));
2473 fs = get_fpu_register_double(fs_reg());
2474 if (std::isnan(fs) && std::isnan(ft)) {
2475 set_fpu_register_double(fd_reg(), fs);
2476 } else if (std::isnan(fs) && !std::isnan(ft)) {
2477 set_fpu_register_double(fd_reg(), ft);
2478 } else if (!std::isnan(fs) && std::isnan(ft)) {
2479 set_fpu_register_double(fd_reg(), fs);
2480 } else {
2481 set_fpu_register_double(fd_reg(), (fs <= ft) ? ft : fs);
2482 }
2483 break;
2484 break;
2485 case ADD_D:
2486 set_fpu_register_double(fd_reg(), fs + ft);
2487 break;
2488 case SUB_D:
2489 set_fpu_register_double(fd_reg(), fs - ft);
2490 break;
2491 case MUL_D:
2492 set_fpu_register_double(fd_reg(), fs * ft);
2493 break;
2494 case DIV_D:
2495 set_fpu_register_double(fd_reg(), fs / ft);
2496 break;
2497 case ABS_D:
2498 set_fpu_register_double(fd_reg(), fabs(fs));
2499 break;
2500 case MOV_D:
2501 set_fpu_register_double(fd_reg(), fs);
2502 break;
2503 case NEG_D:
2504 set_fpu_register_double(fd_reg(), -fs);
2505 break;
2506 case SQRT_D:
2507 lazily_initialize_fast_sqrt(isolate_);
2508 set_fpu_register_double(fd_reg(), fast_sqrt(fs, isolate_));
2509 break;
2510 case RSQRT_D: {
2511 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2512 lazily_initialize_fast_sqrt(isolate_);
2513 double result = 1.0 / fast_sqrt(fs, isolate_);
2514 set_fpu_register_double(fd_reg(), result);
2515 break;
2516 }
2517 case RECIP_D: {
2518 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2519 double result = 1.0 / fs;
2520 set_fpu_register_double(fd_reg(), result);
2521 break;
2522 }
2523 case C_UN_D:
2524 set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft));
2525 break;
2526 case C_EQ_D:
2527 set_fcsr_bit(fcsr_cc, (fs == ft));
2528 break;
2529 case C_UEQ_D:
2530 set_fcsr_bit(fcsr_cc, (fs == ft) || (std::isnan(fs) || std::isnan(ft)));
2531 break;
2532 case C_OLT_D:
2533 set_fcsr_bit(fcsr_cc, (fs < ft));
2534 break;
2535 case C_ULT_D:
2536 set_fcsr_bit(fcsr_cc, (fs < ft) || (std::isnan(fs) || std::isnan(ft)));
2537 break;
2538 case C_OLE_D:
2539 set_fcsr_bit(fcsr_cc, (fs <= ft));
2540 break;
2541 case C_ULE_D:
2542 set_fcsr_bit(fcsr_cc, (fs <= ft) || (std::isnan(fs) || std::isnan(ft)));
2543 break;
2544 case CVT_W_D: { // Convert double to word.
2545 double rounded;
2546 int32_t result;
2547 round_according_to_fcsr(fs, rounded, result, fs);
2548 set_fpu_register_word(fd_reg(), result);
2549 if (set_fcsr_round_error(fs, rounded)) {
2550 set_fpu_register_word_invalid_result(fs, rounded);
2551 }
2552 } break;
2553 case ROUND_W_D: // Round double to word (round half to even).
2554 {
2555 double rounded = std::floor(fs + 0.5);
2556 int32_t result = static_cast<int32_t>(rounded);
2557 if ((result & 1) != 0 && result - fs == 0.5) {
2558 // If the number is halfway between two integers,
2559 // round to the even one.
2560 result--;
2561 }
2562 set_fpu_register_word(fd_reg(), result);
2563 if (set_fcsr_round_error(fs, rounded)) {
2564 set_fpu_register_word_invalid_result(fs, rounded);
2565 }
2566 } break;
2567 case TRUNC_W_D: // Truncate double to word (round towards 0).
2568 {
2569 double rounded = trunc(fs);
2570 int32_t result = static_cast<int32_t>(rounded);
2571 set_fpu_register_word(fd_reg(), result);
2572 if (set_fcsr_round_error(fs, rounded)) {
2573 set_fpu_register_word_invalid_result(fs, rounded);
2574 }
2575 } break;
2576 case FLOOR_W_D: // Round double to word towards negative infinity.
2577 {
2578 double rounded = std::floor(fs);
2579 int32_t result = static_cast<int32_t>(rounded);
2580 set_fpu_register_word(fd_reg(), result);
2581 if (set_fcsr_round_error(fs, rounded)) {
2582 set_fpu_register_word_invalid_result(fs, rounded);
2583 }
2584 } break;
2585 case CEIL_W_D: // Round double to word towards positive infinity.
2586 {
2587 double rounded = std::ceil(fs);
2588 int32_t result = static_cast<int32_t>(rounded);
2589 set_fpu_register_word(fd_reg(), result);
2590 if (set_fcsr_round_error(fs, rounded)) {
2591 set_fpu_register_word_invalid_result(fs, rounded);
2592 }
2593 } break;
2594 case CVT_S_D: // Convert double to float (single).
2595 set_fpu_register_float(fd_reg(), static_cast<float>(fs));
2596 break;
2597 case CVT_L_D: { // Mips32r2: Truncate double to 64-bit long-word.
2598 if (IsFp64Mode()) {
2599 int64_t result;
2600 double rounded;
2601 round64_according_to_fcsr(fs, rounded, result, fs);
2602 set_fpu_register(fd_reg(), result);
2603 if (set_fcsr_round64_error(fs, rounded)) {
2604 set_fpu_register_invalid_result64(fs, rounded);
2605 }
2606 } else {
2607 UNSUPPORTED();
2608 }
2609 break;
2610 break;
2611 }
2612 case TRUNC_L_D: { // Mips32r2 instruction.
2613 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2614 double rounded = trunc(fs);
2615 i64 = static_cast<int64_t>(rounded);
2616 if (IsFp64Mode()) {
2617 set_fpu_register(fd_reg(), i64);
2618 if (set_fcsr_round64_error(fs, rounded)) {
2619 set_fpu_register_invalid_result64(fs, rounded);
2620 }
2621 } else {
2622 UNSUPPORTED();
2623 }
2624 break;
2625 }
2626 case ROUND_L_D: { // Mips32r2 instruction.
2627 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2628 double rounded = std::floor(fs + 0.5);
2629 int64_t result = static_cast<int64_t>(rounded);
2630 if ((result & 1) != 0 && result - fs == 0.5) {
2631 // If the number is halfway between two integers,
2632 // round to the even one.
2633 result--;
2634 }
2635 int64_t i64 = static_cast<int64_t>(result);
2636 if (IsFp64Mode()) {
2637 set_fpu_register(fd_reg(), i64);
2638 if (set_fcsr_round64_error(fs, rounded)) {
2639 set_fpu_register_invalid_result64(fs, rounded);
2640 }
2641 } else {
2642 UNSUPPORTED();
2643 }
2644 break;
2645 }
2646 case FLOOR_L_D: { // Mips32r2 instruction.
2647 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2648 double rounded = std::floor(fs);
2649 int64_t i64 = static_cast<int64_t>(rounded);
2650 if (IsFp64Mode()) {
2651 set_fpu_register(fd_reg(), i64);
2652 if (set_fcsr_round64_error(fs, rounded)) {
2653 set_fpu_register_invalid_result64(fs, rounded);
2654 }
2655 } else {
2656 UNSUPPORTED();
2657 }
2658 break;
2659 }
2660 case CEIL_L_D: { // Mips32r2 instruction.
2661 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2662 double rounded = std::ceil(fs);
2663 int64_t i64 = static_cast<int64_t>(rounded);
2664 if (IsFp64Mode()) {
2665 set_fpu_register(fd_reg(), i64);
2666 if (set_fcsr_round64_error(fs, rounded)) {
2667 set_fpu_register_invalid_result64(fs, rounded);
2668 }
2669 } else {
2670 UNSUPPORTED();
2671 }
2672 break;
2673 }
2674 case CLASS_D: { // Mips32r6 instruction
2675 // Convert double input to uint64_t for easier bit manipulation
2676 uint64_t classed = bit_cast<uint64_t>(fs);
2677
2678 // Extracting sign, exponent and mantissa from the input double
2679 uint32_t sign = (classed >> 63) & 1;
2680 uint32_t exponent = (classed >> 52) & 0x00000000000007ff;
2681 uint64_t mantissa = classed & 0x000fffffffffffff;
2682 uint64_t result;
2683 double dResult;
2684
2685 // Setting flags if input double is negative infinity,
2686 // positive infinity, negative zero or positive zero
2687 bool negInf = (classed == 0xFFF0000000000000);
2688 bool posInf = (classed == 0x7FF0000000000000);
2689 bool negZero = (classed == 0x8000000000000000);
2690 bool posZero = (classed == 0x0000000000000000);
2691
2692 bool signalingNan;
2693 bool quietNan;
2694 bool negSubnorm;
2695 bool posSubnorm;
2696 bool negNorm;
2697 bool posNorm;
2698
2699 // Setting flags if double is NaN
2700 signalingNan = false;
2701 quietNan = false;
2702 if (!negInf && !posInf && exponent == 0x7ff) {
2703 quietNan = ((mantissa & 0x0008000000000000) != 0) &&
2704 ((mantissa & (0x0008000000000000 - 1)) == 0);
2705 signalingNan = !quietNan;
2706 }
2707
2708 // Setting flags if double is subnormal number
2709 posSubnorm = false;
2710 negSubnorm = false;
2711 if ((exponent == 0) && (mantissa != 0)) {
2712 DCHECK(sign == 0 || sign == 1);
2713 posSubnorm = (sign == 0);
2714 negSubnorm = (sign == 1);
2715 }
2716
2717 // Setting flags if double is normal number
2718 posNorm = false;
2719 negNorm = false;
2720 if (!posSubnorm && !negSubnorm && !posInf && !negInf && !signalingNan &&
2721 !quietNan && !negZero && !posZero) {
2722 DCHECK(sign == 0 || sign == 1);
2723 posNorm = (sign == 0);
2724 negNorm = (sign == 1);
2725 }
2726
2727 // Calculating result according to description of CLASS.D instruction
2728 result = (posZero << 9) | (posSubnorm << 8) | (posNorm << 7) |
2729 (posInf << 6) | (negZero << 5) | (negSubnorm << 4) |
2730 (negNorm << 3) | (negInf << 2) | (quietNan << 1) | signalingNan;
2731
2732 DCHECK(result != 0);
2733
2734 dResult = bit_cast<double>(result);
2735 set_fpu_register_double(fd_reg(), dResult);
2736
2737 break;
2738 }
2739 case C_F_D: {
2740 set_fcsr_bit(fcsr_cc, false);
2741 break;
2742 }
2743 default:
2744 UNREACHABLE();
Andrei Popescu31002712010-02-23 13:46:05 +00002745 }
2746}
2747
Steve Block44f0eee2011-05-26 01:26:41 +01002748
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002749void Simulator::DecodeTypeRegisterWRsType() {
2750 float fs = get_fpu_register_float(fs_reg());
2751 float ft = get_fpu_register_float(ft_reg());
2752 int32_t alu_out = 0x12345678;
2753 switch (get_instr()->FunctionFieldRaw()) {
2754 case CVT_S_W: // Convert word to float (single).
2755 alu_out = get_fpu_register_signed_word(fs_reg());
2756 set_fpu_register_float(fd_reg(), static_cast<float>(alu_out));
2757 break;
2758 case CVT_D_W: // Convert word to double.
2759 alu_out = get_fpu_register_signed_word(fs_reg());
2760 set_fpu_register_double(fd_reg(), static_cast<double>(alu_out));
2761 break;
2762 case CMP_AF:
2763 set_fpu_register_word(fd_reg(), 0);
2764 break;
2765 case CMP_UN:
2766 if (std::isnan(fs) || std::isnan(ft)) {
2767 set_fpu_register_word(fd_reg(), -1);
2768 } else {
2769 set_fpu_register_word(fd_reg(), 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002770 }
2771 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002772 case CMP_EQ:
2773 if (fs == ft) {
2774 set_fpu_register_word(fd_reg(), -1);
2775 } else {
2776 set_fpu_register_word(fd_reg(), 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002777 }
Andrei Popescu31002712010-02-23 13:46:05 +00002778 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002779 case CMP_UEQ:
2780 if ((fs == ft) || (std::isnan(fs) || std::isnan(ft))) {
2781 set_fpu_register_word(fd_reg(), -1);
2782 } else {
2783 set_fpu_register_word(fd_reg(), 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002784 }
Steve Block44f0eee2011-05-26 01:26:41 +01002785 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002786 case CMP_LT:
2787 if (fs < ft) {
2788 set_fpu_register_word(fd_reg(), -1);
2789 } else {
2790 set_fpu_register_word(fd_reg(), 0);
2791 }
2792 break;
2793 case CMP_ULT:
2794 if ((fs < ft) || (std::isnan(fs) || std::isnan(ft))) {
2795 set_fpu_register_word(fd_reg(), -1);
2796 } else {
2797 set_fpu_register_word(fd_reg(), 0);
2798 }
2799 break;
2800 case CMP_LE:
2801 if (fs <= ft) {
2802 set_fpu_register_word(fd_reg(), -1);
2803 } else {
2804 set_fpu_register_word(fd_reg(), 0);
2805 }
2806 break;
2807 case CMP_ULE:
2808 if ((fs <= ft) || (std::isnan(fs) || std::isnan(ft))) {
2809 set_fpu_register_word(fd_reg(), -1);
2810 } else {
2811 set_fpu_register_word(fd_reg(), 0);
2812 }
2813 break;
2814 case CMP_OR:
2815 if (!std::isnan(fs) && !std::isnan(ft)) {
2816 set_fpu_register_word(fd_reg(), -1);
2817 } else {
2818 set_fpu_register_word(fd_reg(), 0);
2819 }
2820 break;
2821 case CMP_UNE:
2822 if ((fs != ft) || (std::isnan(fs) || std::isnan(ft))) {
2823 set_fpu_register_word(fd_reg(), -1);
2824 } else {
2825 set_fpu_register_word(fd_reg(), 0);
2826 }
2827 break;
2828 case CMP_NE:
2829 if (fs != ft) {
2830 set_fpu_register_word(fd_reg(), -1);
2831 } else {
2832 set_fpu_register_word(fd_reg(), 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002833 }
Andrei Popescu31002712010-02-23 13:46:05 +00002834 break;
2835 default:
2836 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002837 }
Steve Block44f0eee2011-05-26 01:26:41 +01002838}
2839
2840
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002841void Simulator::DecodeTypeRegisterSRsType() {
2842 float fs, ft, fd;
2843 fs = get_fpu_register_float(fs_reg());
2844 ft = get_fpu_register_float(ft_reg());
2845 fd = get_fpu_register_float(fd_reg());
2846 int32_t ft_int = bit_cast<int32_t>(ft);
2847 int32_t fd_int = bit_cast<int32_t>(fd);
2848 uint32_t cc, fcsr_cc;
2849 cc = get_instr()->FCccValue();
2850 fcsr_cc = get_fcsr_condition_bit(cc);
2851 switch (get_instr()->FunctionFieldRaw()) {
2852 case RINT: {
2853 DCHECK(IsMipsArchVariant(kMips32r6));
2854 float result, temp_result;
2855 double temp;
2856 float upper = std::ceil(fs);
2857 float lower = std::floor(fs);
2858 switch (get_fcsr_rounding_mode()) {
2859 case kRoundToNearest:
2860 if (upper - fs < fs - lower) {
2861 result = upper;
2862 } else if (upper - fs > fs - lower) {
2863 result = lower;
2864 } else {
2865 temp_result = upper / 2;
2866 float reminder = modf(temp_result, &temp);
2867 if (reminder == 0) {
2868 result = upper;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002869 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002870 result = lower;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002871 }
Andrei Popescu31002712010-02-23 13:46:05 +00002872 }
2873 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002874 case kRoundToZero:
2875 result = (fs > 0 ? lower : upper);
2876 break;
2877 case kRoundToPlusInf:
2878 result = upper;
2879 break;
2880 case kRoundToMinusInf:
2881 result = lower;
2882 break;
2883 }
2884 set_fpu_register_float(fd_reg(), result);
2885 if (result != fs) {
2886 set_fcsr_bit(kFCSRInexactFlagBit, true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002887 }
2888 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002889 }
2890 case ADD_S:
2891 set_fpu_register_float(fd_reg(), fs + ft);
2892 break;
2893 case SUB_S:
2894 set_fpu_register_float(fd_reg(), fs - ft);
2895 break;
2896 case MUL_S:
2897 set_fpu_register_float(fd_reg(), fs * ft);
2898 break;
2899 case DIV_S:
2900 set_fpu_register_float(fd_reg(), fs / ft);
2901 break;
2902 case ABS_S:
2903 set_fpu_register_float(fd_reg(), fabs(fs));
2904 break;
2905 case MOV_S:
2906 set_fpu_register_float(fd_reg(), fs);
2907 break;
2908 case NEG_S:
2909 set_fpu_register_float(fd_reg(), -fs);
2910 break;
2911 case SQRT_S:
2912 lazily_initialize_fast_sqrt(isolate_);
2913 set_fpu_register_float(fd_reg(), fast_sqrt(fs, isolate_));
2914 break;
2915 case RSQRT_S: {
2916 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2917 lazily_initialize_fast_sqrt(isolate_);
2918 float result = 1.0 / fast_sqrt(fs, isolate_);
2919 set_fpu_register_float(fd_reg(), result);
2920 break;
2921 }
2922 case RECIP_S: {
2923 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2924 float result = 1.0 / fs;
2925 set_fpu_register_float(fd_reg(), result);
2926 break;
2927 }
2928 case C_F_D:
2929 set_fcsr_bit(fcsr_cc, false);
2930 break;
2931 case C_UN_D:
2932 set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft));
2933 break;
2934 case C_EQ_D:
2935 set_fcsr_bit(fcsr_cc, (fs == ft));
2936 break;
2937 case C_UEQ_D:
2938 set_fcsr_bit(fcsr_cc, (fs == ft) || (std::isnan(fs) || std::isnan(ft)));
2939 break;
2940 case C_OLT_D:
2941 set_fcsr_bit(fcsr_cc, (fs < ft));
2942 break;
2943 case C_ULT_D:
2944 set_fcsr_bit(fcsr_cc, (fs < ft) || (std::isnan(fs) || std::isnan(ft)));
2945 break;
2946 case C_OLE_D:
2947 set_fcsr_bit(fcsr_cc, (fs <= ft));
2948 break;
2949 case C_ULE_D:
2950 set_fcsr_bit(fcsr_cc, (fs <= ft) || (std::isnan(fs) || std::isnan(ft)));
2951 break;
2952 case CVT_D_S:
2953 set_fpu_register_double(fd_reg(), static_cast<double>(fs));
2954 break;
2955 case SEL:
2956 DCHECK(IsMipsArchVariant(kMips32r6));
2957 set_fpu_register_float(fd_reg(), (fd_int & 0x1) == 0 ? fs : ft);
2958 break;
2959 case CLASS_S: { // Mips32r6 instruction
2960 // Convert float input to uint32_t for easier bit manipulation
2961 float fs = get_fpu_register_float(fs_reg());
2962 uint32_t classed = bit_cast<uint32_t>(fs);
2963
2964 // Extracting sign, exponent and mantissa from the input float
2965 uint32_t sign = (classed >> 31) & 1;
2966 uint32_t exponent = (classed >> 23) & 0x000000ff;
2967 uint32_t mantissa = classed & 0x007fffff;
2968 uint32_t result;
2969 float fResult;
2970
2971 // Setting flags if input float is negative infinity,
2972 // positive infinity, negative zero or positive zero
2973 bool negInf = (classed == 0xFF800000);
2974 bool posInf = (classed == 0x7F800000);
2975 bool negZero = (classed == 0x80000000);
2976 bool posZero = (classed == 0x00000000);
2977
2978 bool signalingNan;
2979 bool quietNan;
2980 bool negSubnorm;
2981 bool posSubnorm;
2982 bool negNorm;
2983 bool posNorm;
2984
2985 // Setting flags if float is NaN
2986 signalingNan = false;
2987 quietNan = false;
2988 if (!negInf && !posInf && (exponent == 0xff)) {
2989 quietNan = ((mantissa & 0x00200000) == 0) &&
2990 ((mantissa & (0x00200000 - 1)) == 0);
2991 signalingNan = !quietNan;
2992 }
2993
2994 // Setting flags if float is subnormal number
2995 posSubnorm = false;
2996 negSubnorm = false;
2997 if ((exponent == 0) && (mantissa != 0)) {
2998 DCHECK(sign == 0 || sign == 1);
2999 posSubnorm = (sign == 0);
3000 negSubnorm = (sign == 1);
3001 }
3002
3003 // Setting flags if float is normal number
3004 posNorm = false;
3005 negNorm = false;
3006 if (!posSubnorm && !negSubnorm && !posInf && !negInf && !signalingNan &&
3007 !quietNan && !negZero && !posZero) {
3008 DCHECK(sign == 0 || sign == 1);
3009 posNorm = (sign == 0);
3010 negNorm = (sign == 1);
3011 }
3012
3013 // Calculating result according to description of CLASS.S instruction
3014 result = (posZero << 9) | (posSubnorm << 8) | (posNorm << 7) |
3015 (posInf << 6) | (negZero << 5) | (negSubnorm << 4) |
3016 (negNorm << 3) | (negInf << 2) | (quietNan << 1) | signalingNan;
3017
3018 DCHECK(result != 0);
3019
3020 fResult = bit_cast<float>(result);
3021 set_fpu_register_float(fd_reg(), fResult);
3022
3023 break;
3024 }
3025 case SELEQZ_C:
3026 DCHECK(IsMipsArchVariant(kMips32r6));
3027 set_fpu_register_float(fd_reg(), (ft_int & 0x1) == 0
3028 ? get_fpu_register_float(fs_reg())
3029 : 0.0);
3030 break;
3031 case SELNEZ_C:
3032 DCHECK(IsMipsArchVariant(kMips32r6));
3033 set_fpu_register_float(fd_reg(), (ft_int & 0x1) != 0
3034 ? get_fpu_register_float(fs_reg())
3035 : 0.0);
3036 break;
3037 case MOVZ_C: {
3038 DCHECK(IsMipsArchVariant(kMips32r2));
3039 if (rt() == 0) {
3040 set_fpu_register_float(fd_reg(), fs);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003041 }
Andrei Popescu31002712010-02-23 13:46:05 +00003042 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003043 }
3044 case MOVN_C: {
3045 DCHECK(IsMipsArchVariant(kMips32r2));
3046 if (rt() != 0) {
3047 set_fpu_register_float(fd_reg(), fs);
3048 }
3049 break;
3050 }
3051 case MOVF: {
3052 // Same function field for MOVT.D and MOVF.D
3053 uint32_t ft_cc = (ft_reg() >> 2) & 0x7;
3054 ft_cc = get_fcsr_condition_bit(ft_cc);
3055
3056 if (get_instr()->Bit(16)) { // Read Tf bit.
3057 // MOVT.D
3058 if (test_fcsr_bit(ft_cc)) set_fpu_register_float(fd_reg(), fs);
3059 } else {
3060 // MOVF.D
3061 if (!test_fcsr_bit(ft_cc)) set_fpu_register_float(fd_reg(), fs);
3062 }
3063 break;
3064 }
3065 case TRUNC_W_S: { // Truncate single to word (round towards 0).
3066 float rounded = trunc(fs);
3067 int32_t result = static_cast<int32_t>(rounded);
3068 set_fpu_register_word(fd_reg(), result);
3069 if (set_fcsr_round_error(fs, rounded)) {
3070 set_fpu_register_word_invalid_result(fs, rounded);
3071 }
3072 } break;
3073 case TRUNC_L_S: { // Mips32r2 instruction.
3074 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
3075 float rounded = trunc(fs);
3076 int64_t i64 = static_cast<int64_t>(rounded);
3077 if (IsFp64Mode()) {
3078 set_fpu_register(fd_reg(), i64);
3079 if (set_fcsr_round64_error(fs, rounded)) {
3080 set_fpu_register_invalid_result64(fs, rounded);
Andrei Popescu31002712010-02-23 13:46:05 +00003081 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003082 } else {
3083 UNSUPPORTED();
3084 }
3085 break;
3086 }
3087 case FLOOR_W_S: // Round double to word towards negative infinity.
3088 {
3089 float rounded = std::floor(fs);
3090 int32_t result = static_cast<int32_t>(rounded);
3091 set_fpu_register_word(fd_reg(), result);
3092 if (set_fcsr_round_error(fs, rounded)) {
3093 set_fpu_register_word_invalid_result(fs, rounded);
3094 }
3095 } break;
3096 case FLOOR_L_S: { // Mips32r2 instruction.
3097 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
3098 float rounded = std::floor(fs);
3099 int64_t i64 = static_cast<int64_t>(rounded);
3100 if (IsFp64Mode()) {
3101 set_fpu_register(fd_reg(), i64);
3102 if (set_fcsr_round64_error(fs, rounded)) {
3103 set_fpu_register_invalid_result64(fs, rounded);
Andrei Popescu31002712010-02-23 13:46:05 +00003104 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003105 } else {
3106 UNSUPPORTED();
3107 }
3108 break;
3109 }
3110 case ROUND_W_S: {
3111 float rounded = std::floor(fs + 0.5);
3112 int32_t result = static_cast<int32_t>(rounded);
3113 if ((result & 1) != 0 && result - fs == 0.5) {
3114 // If the number is halfway between two integers,
3115 // round to the even one.
3116 result--;
3117 }
3118 set_fpu_register_word(fd_reg(), result);
3119 if (set_fcsr_round_error(fs, rounded)) {
3120 set_fpu_register_word_invalid_result(fs, rounded);
3121 }
3122 break;
3123 }
3124 case ROUND_L_S: { // Mips32r2 instruction.
3125 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
3126 float rounded = std::floor(fs + 0.5);
3127 int64_t result = static_cast<int64_t>(rounded);
3128 if ((result & 1) != 0 && result - fs == 0.5) {
3129 // If the number is halfway between two integers,
3130 // round to the even one.
3131 result--;
3132 }
3133 int64_t i64 = static_cast<int64_t>(result);
3134 if (IsFp64Mode()) {
3135 set_fpu_register(fd_reg(), i64);
3136 if (set_fcsr_round64_error(fs, rounded)) {
3137 set_fpu_register_invalid_result64(fs, rounded);
Steve Block44f0eee2011-05-26 01:26:41 +01003138 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003139 } else {
3140 UNSUPPORTED();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003141 }
Andrei Popescu31002712010-02-23 13:46:05 +00003142 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003143 }
3144 case CEIL_W_S: // Round double to word towards positive infinity.
3145 {
3146 float rounded = std::ceil(fs);
3147 int32_t result = static_cast<int32_t>(rounded);
3148 set_fpu_register_word(fd_reg(), result);
3149 if (set_fcsr_round_error(fs, rounded)) {
3150 set_fpu_register_word_invalid_result(fs, rounded);
3151 }
3152 } break;
3153 case CEIL_L_S: { // Mips32r2 instruction.
3154 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
3155 float rounded = std::ceil(fs);
3156 int64_t i64 = static_cast<int64_t>(rounded);
3157 if (IsFp64Mode()) {
3158 set_fpu_register(fd_reg(), i64);
3159 if (set_fcsr_round64_error(fs, rounded)) {
3160 set_fpu_register_invalid_result64(fs, rounded);
3161 }
3162 } else {
3163 UNSUPPORTED();
Steve Block44f0eee2011-05-26 01:26:41 +01003164 }
3165 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003166 }
3167 case MIN:
3168 DCHECK(IsMipsArchVariant(kMips32r6));
3169 fs = get_fpu_register_float(fs_reg());
3170 if (std::isnan(fs) && std::isnan(ft)) {
3171 set_fpu_register_float(fd_reg(), fs);
3172 } else if (std::isnan(fs) && !std::isnan(ft)) {
3173 set_fpu_register_float(fd_reg(), ft);
3174 } else if (!std::isnan(fs) && std::isnan(ft)) {
3175 set_fpu_register_float(fd_reg(), fs);
3176 } else {
3177 set_fpu_register_float(fd_reg(), (fs >= ft) ? ft : fs);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003178 }
Andrei Popescu31002712010-02-23 13:46:05 +00003179 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003180 case MAX:
3181 DCHECK(IsMipsArchVariant(kMips32r6));
3182 fs = get_fpu_register_float(fs_reg());
3183 if (std::isnan(fs) && std::isnan(ft)) {
3184 set_fpu_register_float(fd_reg(), fs);
3185 } else if (std::isnan(fs) && !std::isnan(ft)) {
3186 set_fpu_register_float(fd_reg(), ft);
3187 } else if (!std::isnan(fs) && std::isnan(ft)) {
3188 set_fpu_register_float(fd_reg(), fs);
3189 } else {
3190 set_fpu_register_float(fd_reg(), (fs <= ft) ? ft : fs);
3191 }
3192 break;
3193 case MINA:
3194 DCHECK(IsMipsArchVariant(kMips32r6));
3195 fs = get_fpu_register_float(fs_reg());
3196 if (std::isnan(fs) && std::isnan(ft)) {
3197 set_fpu_register_float(fd_reg(), fs);
3198 } else if (std::isnan(fs) && !std::isnan(ft)) {
3199 set_fpu_register_float(fd_reg(), ft);
3200 } else if (!std::isnan(fs) && std::isnan(ft)) {
3201 set_fpu_register_float(fd_reg(), fs);
3202 } else {
3203 float result;
3204 if (fabs(fs) > fabs(ft)) {
3205 result = ft;
3206 } else if (fabs(fs) < fabs(ft)) {
3207 result = fs;
3208 } else {
3209 result = (fs < ft ? fs : ft);
3210 }
3211 set_fpu_register_float(fd_reg(), result);
3212 }
3213 break;
3214 case MAXA:
3215 DCHECK(IsMipsArchVariant(kMips32r6));
3216 fs = get_fpu_register_float(fs_reg());
3217 if (std::isnan(fs) && std::isnan(ft)) {
3218 set_fpu_register_float(fd_reg(), fs);
3219 } else if (std::isnan(fs) && !std::isnan(ft)) {
3220 set_fpu_register_float(fd_reg(), ft);
3221 } else if (!std::isnan(fs) && std::isnan(ft)) {
3222 set_fpu_register_float(fd_reg(), fs);
3223 } else {
3224 float result;
3225 if (fabs(fs) < fabs(ft)) {
3226 result = ft;
3227 } else if (fabs(fs) > fabs(ft)) {
3228 result = fs;
3229 } else {
3230 result = (fs > ft ? fs : ft);
3231 }
3232 set_fpu_register_float(fd_reg(), result);
3233 }
3234 break;
3235 case CVT_L_S: {
3236 if (IsFp64Mode()) {
3237 int64_t result;
3238 float rounded;
3239 round64_according_to_fcsr(fs, rounded, result, fs);
3240 set_fpu_register(fd_reg(), result);
3241 if (set_fcsr_round64_error(fs, rounded)) {
3242 set_fpu_register_invalid_result64(fs, rounded);
3243 }
3244 } else {
3245 UNSUPPORTED();
3246 }
3247 break;
3248 }
3249 case CVT_W_S: {
3250 float rounded;
3251 int32_t result;
3252 round_according_to_fcsr(fs, rounded, result, fs);
3253 set_fpu_register_word(fd_reg(), result);
3254 if (set_fcsr_round_error(fs, rounded)) {
3255 set_fpu_register_word_invalid_result(fs, rounded);
3256 }
3257 break;
3258 }
Andrei Popescu31002712010-02-23 13:46:05 +00003259 default:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003260 // CVT_W_S CVT_L_S ROUND_W_S ROUND_L_S FLOOR_W_S FLOOR_L_S
3261 // CEIL_W_S CEIL_L_S CVT_PS_S are unimplemented.
3262 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003263 }
Andrei Popescu31002712010-02-23 13:46:05 +00003264}
3265
Steve Block44f0eee2011-05-26 01:26:41 +01003266
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003267void Simulator::DecodeTypeRegisterLRsType() {
3268 double fs = get_fpu_register_double(fs_reg());
3269 double ft = get_fpu_register_double(ft_reg());
3270 switch (get_instr()->FunctionFieldRaw()) {
3271 case CVT_D_L: // Mips32r2 instruction.
3272 // Watch the signs here, we want 2 32-bit vals
3273 // to make a sign-64.
3274 int64_t i64;
3275 if (IsFp64Mode()) {
3276 i64 = get_fpu_register(fs_reg());
3277 } else {
3278 i64 = static_cast<uint32_t>(get_fpu_register_word(fs_reg()));
3279 i64 |= static_cast<int64_t>(get_fpu_register_word(fs_reg() + 1)) << 32;
3280 }
3281 set_fpu_register_double(fd_reg(), static_cast<double>(i64));
3282 break;
3283 case CVT_S_L:
3284 if (IsFp64Mode()) {
3285 i64 = get_fpu_register(fs_reg());
3286 } else {
3287 i64 = static_cast<uint32_t>(get_fpu_register_word(fs_reg()));
3288 i64 |= static_cast<int64_t>(get_fpu_register_word(fs_reg() + 1)) << 32;
3289 }
3290 set_fpu_register_float(fd_reg(), static_cast<float>(i64));
3291 break;
3292 case CMP_AF: // Mips64r6 CMP.D instructions.
3293 set_fpu_register(fd_reg(), 0);
3294 break;
3295 case CMP_UN:
3296 if (std::isnan(fs) || std::isnan(ft)) {
3297 set_fpu_register(fd_reg(), -1);
3298 } else {
3299 set_fpu_register(fd_reg(), 0);
3300 }
3301 break;
3302 case CMP_EQ:
3303 if (fs == ft) {
3304 set_fpu_register(fd_reg(), -1);
3305 } else {
3306 set_fpu_register(fd_reg(), 0);
3307 }
3308 break;
3309 case CMP_UEQ:
3310 if ((fs == ft) || (std::isnan(fs) || std::isnan(ft))) {
3311 set_fpu_register(fd_reg(), -1);
3312 } else {
3313 set_fpu_register(fd_reg(), 0);
3314 }
3315 break;
3316 case CMP_LT:
3317 if (fs < ft) {
3318 set_fpu_register(fd_reg(), -1);
3319 } else {
3320 set_fpu_register(fd_reg(), 0);
3321 }
3322 break;
3323 case CMP_ULT:
3324 if ((fs < ft) || (std::isnan(fs) || std::isnan(ft))) {
3325 set_fpu_register(fd_reg(), -1);
3326 } else {
3327 set_fpu_register(fd_reg(), 0);
3328 }
3329 break;
3330 case CMP_LE:
3331 if (fs <= ft) {
3332 set_fpu_register(fd_reg(), -1);
3333 } else {
3334 set_fpu_register(fd_reg(), 0);
3335 }
3336 break;
3337 case CMP_ULE:
3338 if ((fs <= ft) || (std::isnan(fs) || std::isnan(ft))) {
3339 set_fpu_register(fd_reg(), -1);
3340 } else {
3341 set_fpu_register(fd_reg(), 0);
3342 }
3343 break;
3344 case CMP_OR:
3345 if (!std::isnan(fs) && !std::isnan(ft)) {
3346 set_fpu_register(fd_reg(), -1);
3347 } else {
3348 set_fpu_register(fd_reg(), 0);
3349 }
3350 break;
3351 case CMP_UNE:
3352 if ((fs != ft) || (std::isnan(fs) || std::isnan(ft))) {
3353 set_fpu_register(fd_reg(), -1);
3354 } else {
3355 set_fpu_register(fd_reg(), 0);
3356 }
3357 break;
3358 case CMP_NE:
3359 if (fs != ft && (!std::isnan(fs) && !std::isnan(ft))) {
3360 set_fpu_register(fd_reg(), -1);
3361 } else {
3362 set_fpu_register(fd_reg(), 0);
3363 }
3364 break;
3365 default:
3366 UNREACHABLE();
3367 }
3368}
3369
3370
3371void Simulator::DecodeTypeRegisterCOP1() {
3372 switch (get_instr()->RsFieldRaw()) {
3373 case CFC1:
3374 // At the moment only FCSR is supported.
3375 DCHECK(fs_reg() == kFCSRRegister);
3376 set_register(rt_reg(), FCSR_);
3377 break;
3378 case MFC1:
3379 set_register(rt_reg(), get_fpu_register_word(fs_reg()));
3380 break;
3381 case MFHC1:
3382 set_register(rt_reg(), get_fpu_register_hi_word(fs_reg()));
3383 break;
3384 case CTC1: {
3385 // At the moment only FCSR is supported.
3386 DCHECK(fs_reg() == kFCSRRegister);
3387 int32_t reg = registers_[rt_reg()];
3388 if (IsMipsArchVariant(kMips32r6)) {
3389 FCSR_ = reg | kFCSRNaN2008FlagMask;
3390 } else {
3391 DCHECK(IsMipsArchVariant(kMips32r1) || IsMipsArchVariant(kMips32r2));
3392 FCSR_ = reg & ~kFCSRNaN2008FlagMask;
3393 }
3394 break;
3395 }
3396 case MTC1:
3397 // Hardware writes upper 32-bits to zero on mtc1.
3398 set_fpu_register_hi_word(fs_reg(), 0);
3399 set_fpu_register_word(fs_reg(), registers_[rt_reg()]);
3400 break;
3401 case MTHC1:
3402 set_fpu_register_hi_word(fs_reg(), registers_[rt_reg()]);
3403 break;
3404 case S: {
3405 DecodeTypeRegisterSRsType();
3406 break;
3407 }
3408 case D:
3409 DecodeTypeRegisterDRsType();
3410 break;
3411 case W:
3412 DecodeTypeRegisterWRsType();
3413 break;
3414 case L:
3415 DecodeTypeRegisterLRsType();
3416 break;
3417 case PS:
3418 // Not implemented.
3419 UNREACHABLE();
3420 default:
3421 UNREACHABLE();
3422 }
3423}
3424
3425
3426void Simulator::DecodeTypeRegisterCOP1X() {
3427 switch (get_instr()->FunctionFieldRaw()) {
3428 case MADD_D:
3429 double fr, ft, fs;
3430 fr = get_fpu_register_double(fr_reg());
3431 fs = get_fpu_register_double(fs_reg());
3432 ft = get_fpu_register_double(ft_reg());
3433 set_fpu_register_double(fd_reg(), fs * ft + fr);
3434 break;
3435 default:
3436 UNREACHABLE();
3437 }
3438}
3439
3440
3441void Simulator::DecodeTypeRegisterSPECIAL() {
3442 int64_t alu_out = 0x12345678;
3443 int64_t i64hilo = 0;
3444 uint64_t u64hilo = 0;
3445 bool do_interrupt = false;
3446
3447 switch (get_instr()->FunctionFieldRaw()) {
3448 case SELEQZ_S:
3449 DCHECK(IsMipsArchVariant(kMips32r6));
3450 set_register(rd_reg(), rt() == 0 ? rs() : 0);
3451 break;
3452 case SELNEZ_S:
3453 DCHECK(IsMipsArchVariant(kMips32r6));
3454 set_register(rd_reg(), rt() != 0 ? rs() : 0);
3455 break;
3456 case JR: {
3457 int32_t next_pc = rs();
3458 int32_t current_pc = get_pc();
3459 Instruction* branch_delay_instr =
3460 reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize);
3461 BranchDelayInstructionDecode(branch_delay_instr);
3462 set_pc(next_pc);
3463 pc_modified_ = true;
3464 break;
3465 }
3466 case JALR: {
3467 int32_t next_pc = rs();
3468 int32_t return_addr_reg = rd_reg();
3469 int32_t current_pc = get_pc();
3470 Instruction* branch_delay_instr =
3471 reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize);
3472 BranchDelayInstructionDecode(branch_delay_instr);
3473 set_register(return_addr_reg, current_pc + 2 * Instruction::kInstrSize);
3474 set_pc(next_pc);
3475 pc_modified_ = true;
3476 break;
3477 }
3478 case SLL:
3479 alu_out = rt() << sa();
3480 SetResult(rd_reg(), static_cast<int32_t>(alu_out));
3481 break;
3482 case SRL:
3483 if (rs_reg() == 0) {
3484 // Regular logical right shift of a word by a fixed number of
3485 // bits instruction. RS field is always equal to 0.
3486 alu_out = rt_u() >> sa();
3487 } else {
3488 // Logical right-rotate of a word by a fixed number of bits. This
3489 // is special case of SRL instruction, added in MIPS32 Release 2.
3490 // RS field is equal to 00001.
3491 alu_out = base::bits::RotateRight32(rt_u(), sa());
3492 }
3493 SetResult(rd_reg(), static_cast<int32_t>(alu_out));
3494 break;
3495 case SRA:
3496 alu_out = rt() >> sa();
3497 SetResult(rd_reg(), static_cast<int32_t>(alu_out));
3498 break;
3499 case SLLV:
3500 alu_out = rt() << rs();
3501 SetResult(rd_reg(), static_cast<int32_t>(alu_out));
3502 break;
3503 case SRLV:
3504 if (sa() == 0) {
3505 // Regular logical right-shift of a word by a variable number of
3506 // bits instruction. SA field is always equal to 0.
3507 alu_out = rt_u() >> rs();
3508 } else {
3509 // Logical right-rotate of a word by a variable number of bits.
3510 // This is special case od SRLV instruction, added in MIPS32
3511 // Release 2. SA field is equal to 00001.
3512 alu_out = base::bits::RotateRight32(rt_u(), rs_u());
3513 }
3514 SetResult(rd_reg(), static_cast<int32_t>(alu_out));
3515 break;
3516 case SRAV:
3517 SetResult(rd_reg(), rt() >> rs());
3518 break;
3519 case LSA: {
3520 DCHECK(IsMipsArchVariant(kMips32r6));
3521 int8_t sa = lsa_sa() + 1;
3522 int32_t _rt = rt();
3523 int32_t _rs = rs();
3524 int32_t res = _rs << sa;
3525 res += _rt;
3526 DCHECK_EQ(res, (rs() << (lsa_sa() + 1)) + rt());
3527 SetResult(rd_reg(), (rs() << (lsa_sa() + 1)) + rt());
3528 break;
3529 }
3530 case MFHI: // MFHI == CLZ on R6.
3531 if (!IsMipsArchVariant(kMips32r6)) {
3532 DCHECK(sa() == 0);
3533 alu_out = get_register(HI);
3534 } else {
3535 // MIPS spec: If no bits were set in GPR rs, the result written to
3536 // GPR rd is 32.
3537 DCHECK(sa() == 1);
3538 alu_out = base::bits::CountLeadingZeros32(rs_u());
3539 }
3540 SetResult(rd_reg(), static_cast<int32_t>(alu_out));
3541 break;
3542 case MFLO:
3543 alu_out = get_register(LO);
3544 SetResult(rd_reg(), static_cast<int32_t>(alu_out));
3545 break;
3546 // Instructions using HI and LO registers.
3547 case MULT:
3548 i64hilo = static_cast<int64_t>(rs()) * static_cast<int64_t>(rt());
3549 if (!IsMipsArchVariant(kMips32r6)) {
3550 set_register(LO, static_cast<int32_t>(i64hilo & 0xffffffff));
3551 set_register(HI, static_cast<int32_t>(i64hilo >> 32));
3552 } else {
3553 switch (sa()) {
3554 case MUL_OP:
3555 set_register(rd_reg(), static_cast<int32_t>(i64hilo & 0xffffffff));
3556 break;
3557 case MUH_OP:
3558 set_register(rd_reg(), static_cast<int32_t>(i64hilo >> 32));
3559 break;
3560 default:
3561 UNIMPLEMENTED_MIPS();
3562 break;
3563 }
3564 }
3565 break;
3566 case MULTU:
3567 u64hilo = static_cast<uint64_t>(rs_u()) * static_cast<uint64_t>(rt_u());
3568 if (!IsMipsArchVariant(kMips32r6)) {
3569 set_register(LO, static_cast<int32_t>(u64hilo & 0xffffffff));
3570 set_register(HI, static_cast<int32_t>(u64hilo >> 32));
3571 } else {
3572 switch (sa()) {
3573 case MUL_OP:
3574 set_register(rd_reg(), static_cast<int32_t>(u64hilo & 0xffffffff));
3575 break;
3576 case MUH_OP:
3577 set_register(rd_reg(), static_cast<int32_t>(u64hilo >> 32));
3578 break;
3579 default:
3580 UNIMPLEMENTED_MIPS();
3581 break;
3582 }
3583 }
3584 break;
3585 case DIV:
3586 if (IsMipsArchVariant(kMips32r6)) {
3587 switch (get_instr()->SaValue()) {
3588 case DIV_OP:
3589 if (rs() == INT_MIN && rt() == -1) {
3590 set_register(rd_reg(), INT_MIN);
3591 } else if (rt() != 0) {
3592 set_register(rd_reg(), rs() / rt());
3593 }
3594 break;
3595 case MOD_OP:
3596 if (rs() == INT_MIN && rt() == -1) {
3597 set_register(rd_reg(), 0);
3598 } else if (rt() != 0) {
3599 set_register(rd_reg(), rs() % rt());
3600 }
3601 break;
3602 default:
3603 UNIMPLEMENTED_MIPS();
3604 break;
3605 }
3606 } else {
3607 // Divide by zero and overflow was not checked in the
3608 // configuration step - div and divu do not raise exceptions. On
3609 // division by 0 the result will be UNPREDICTABLE. On overflow
3610 // (INT_MIN/-1), return INT_MIN which is what the hardware does.
3611 if (rs() == INT_MIN && rt() == -1) {
3612 set_register(LO, INT_MIN);
3613 set_register(HI, 0);
3614 } else if (rt() != 0) {
3615 set_register(LO, rs() / rt());
3616 set_register(HI, rs() % rt());
3617 }
3618 }
3619 break;
3620 case DIVU:
3621 if (IsMipsArchVariant(kMips32r6)) {
3622 switch (get_instr()->SaValue()) {
3623 case DIV_OP:
3624 if (rt_u() != 0) {
3625 set_register(rd_reg(), rs_u() / rt_u());
3626 }
3627 break;
3628 case MOD_OP:
3629 if (rt_u() != 0) {
3630 set_register(rd_reg(), rs_u() % rt_u());
3631 }
3632 break;
3633 default:
3634 UNIMPLEMENTED_MIPS();
3635 break;
3636 }
3637 } else {
3638 if (rt_u() != 0) {
3639 set_register(LO, rs_u() / rt_u());
3640 set_register(HI, rs_u() % rt_u());
3641 }
3642 }
3643 break;
3644 case ADD:
3645 if (HaveSameSign(rs(), rt())) {
3646 if (rs() > 0) {
3647 if (rs() <= (Registers::kMaxValue - rt())) {
3648 SignalException(kIntegerOverflow);
3649 }
3650 } else if (rs() < 0) {
3651 if (rs() >= (Registers::kMinValue - rt())) {
3652 SignalException(kIntegerUnderflow);
3653 }
3654 }
3655 }
3656 SetResult(rd_reg(), rs() + rt());
3657 break;
3658 case ADDU:
3659 SetResult(rd_reg(), rs() + rt());
3660 break;
3661 case SUB:
3662 if (!HaveSameSign(rs(), rt())) {
3663 if (rs() > 0) {
3664 if (rs() <= (Registers::kMaxValue + rt())) {
3665 SignalException(kIntegerOverflow);
3666 }
3667 } else if (rs() < 0) {
3668 if (rs() >= (Registers::kMinValue + rt())) {
3669 SignalException(kIntegerUnderflow);
3670 }
3671 }
3672 }
3673 SetResult(rd_reg(), rs() - rt());
3674 break;
3675 case SUBU:
3676 SetResult(rd_reg(), rs() - rt());
3677 break;
3678 case AND:
3679 SetResult(rd_reg(), rs() & rt());
3680 break;
3681 case OR:
3682 SetResult(rd_reg(), rs() | rt());
3683 break;
3684 case XOR:
3685 SetResult(rd_reg(), rs() ^ rt());
3686 break;
3687 case NOR:
3688 SetResult(rd_reg(), ~(rs() | rt()));
3689 break;
3690 case SLT:
3691 SetResult(rd_reg(), rs() < rt() ? 1 : 0);
3692 break;
3693 case SLTU:
3694 SetResult(rd_reg(), rs_u() < rt_u() ? 1 : 0);
3695 break;
3696 // Break and trap instructions.
3697 case BREAK:
3698 do_interrupt = true;
3699 break;
3700 case TGE:
3701 do_interrupt = rs() >= rt();
3702 break;
3703 case TGEU:
3704 do_interrupt = rs_u() >= rt_u();
3705 break;
3706 case TLT:
3707 do_interrupt = rs() < rt();
3708 break;
3709 case TLTU:
3710 do_interrupt = rs_u() < rt_u();
3711 break;
3712 case TEQ:
3713 do_interrupt = rs() == rt();
3714 break;
3715 case TNE:
3716 do_interrupt = rs() != rt();
3717 break;
3718 // Conditional moves.
3719 case MOVN:
3720 if (rt()) {
3721 set_register(rd_reg(), rs());
3722 TraceRegWr(rs());
3723 }
3724 break;
3725 case MOVCI: {
3726 uint32_t cc = get_instr()->FBccValue();
3727 uint32_t fcsr_cc = get_fcsr_condition_bit(cc);
3728 if (get_instr()->Bit(16)) { // Read Tf bit.
3729 if (test_fcsr_bit(fcsr_cc)) set_register(rd_reg(), rs());
3730 } else {
3731 if (!test_fcsr_bit(fcsr_cc)) set_register(rd_reg(), rs());
3732 }
3733 break;
3734 }
3735 case MOVZ:
3736 if (!rt()) {
3737 set_register(rd_reg(), rs());
3738 TraceRegWr(rs());
3739 }
3740 break;
3741 default:
3742 UNREACHABLE();
3743 }
3744 if (do_interrupt) {
3745 SoftwareInterrupt(get_instr());
3746 }
3747}
3748
3749
3750void Simulator::DecodeTypeRegisterSPECIAL2() {
3751 int32_t alu_out;
3752 switch (get_instr()->FunctionFieldRaw()) {
3753 case MUL:
3754 // Only the lower 32 bits are kept.
3755 alu_out = rs_u() * rt_u();
3756 // HI and LO are UNPREDICTABLE after the operation.
3757 set_register(LO, Unpredictable);
3758 set_register(HI, Unpredictable);
3759 break;
3760 case CLZ:
3761 // MIPS32 spec: If no bits were set in GPR rs, the result written to
3762 // GPR rd is 32.
3763 alu_out = base::bits::CountLeadingZeros32(rs_u());
3764 break;
3765 default:
3766 alu_out = 0x12345678;
3767 UNREACHABLE();
3768 }
3769 SetResult(rd_reg(), alu_out);
3770}
3771
3772
3773void Simulator::DecodeTypeRegisterSPECIAL3() {
3774 int32_t alu_out;
3775 switch (get_instr()->FunctionFieldRaw()) {
3776 case INS: { // Mips32r2 instruction.
3777 // Interpret rd field as 5-bit msb of insert.
3778 uint16_t msb = rd_reg();
3779 // Interpret sa field as 5-bit lsb of insert.
3780 uint16_t lsb = sa();
3781 uint16_t size = msb - lsb + 1;
3782 uint32_t mask = (1 << size) - 1;
3783 alu_out = (rt_u() & ~(mask << lsb)) | ((rs_u() & mask) << lsb);
3784 // Ins instr leaves result in Rt, rather than Rd.
3785 SetResult(rt_reg(), alu_out);
3786 break;
3787 }
3788 case EXT: { // Mips32r2 instruction.
3789 // Interpret rd field as 5-bit msb of extract.
3790 uint16_t msb = rd_reg();
3791 // Interpret sa field as 5-bit lsb of extract.
3792 uint16_t lsb = sa();
3793 uint16_t size = msb + 1;
3794 uint32_t mask = (1 << size) - 1;
3795 alu_out = (rs_u() & (mask << lsb)) >> lsb;
3796 SetResult(rt_reg(), alu_out);
3797 break;
3798 }
3799 case BSHFL: {
3800 int sa = get_instr()->SaFieldRaw() >> kSaShift;
3801 switch (sa) {
3802 case BITSWAP: {
3803 uint32_t input = static_cast<uint32_t>(rt());
3804 uint32_t output = 0;
3805 uint8_t i_byte, o_byte;
3806
3807 // Reverse the bit in byte for each individual byte
3808 for (int i = 0; i < 4; i++) {
3809 output = output >> 8;
3810 i_byte = input & 0xff;
3811
3812 // Fast way to reverse bits in byte
3813 // Devised by Sean Anderson, July 13, 2001
3814 o_byte = static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) |
3815 (i_byte * 0x8020LU & 0x88440LU)) *
3816 0x10101LU >>
3817 16);
3818
3819 output = output | (static_cast<uint32_t>(o_byte << 24));
3820 input = input >> 8;
3821 }
3822
3823 alu_out = static_cast<int32_t>(output);
3824 break;
3825 }
3826 case SEB:
3827 case SEH:
3828 case WSBH:
3829 alu_out = 0x12345678;
3830 UNREACHABLE();
3831 break;
3832 default: {
3833 const uint8_t bp = get_instr()->Bp2Value();
3834 sa >>= kBp2Bits;
3835 switch (sa) {
3836 case ALIGN: {
3837 if (bp == 0) {
3838 alu_out = static_cast<int32_t>(rt());
3839 } else {
3840 uint32_t rt_hi = rt() << (8 * bp);
3841 uint32_t rs_lo = rs() >> (8 * (4 - bp));
3842 alu_out = static_cast<int32_t>(rt_hi | rs_lo);
3843 }
3844 break;
3845 }
3846 default:
3847 alu_out = 0x12345678;
3848 UNREACHABLE();
3849 break;
3850 }
3851 }
3852 }
3853 SetResult(rd_reg(), alu_out);
3854 break;
3855 }
3856 default:
3857 UNREACHABLE();
3858 }
3859}
3860
3861
3862void Simulator::DecodeTypeRegister(Instruction* instr) {
3863 const Opcode op = instr->OpcodeFieldRaw();
3864
3865 // Set up the variables if needed before executing the instruction.
3866 // ConfigureTypeRegister(instr);
3867 set_instr(instr);
3868
3869 // ---------- Execution.
3870 switch (op) {
3871 case COP1:
3872 DecodeTypeRegisterCOP1();
3873 break;
3874 case COP1X:
3875 DecodeTypeRegisterCOP1X();
3876 break;
3877 case SPECIAL:
3878 DecodeTypeRegisterSPECIAL();
3879 break;
3880 case SPECIAL2:
3881 DecodeTypeRegisterSPECIAL2();
3882 break;
3883 case SPECIAL3:
3884 DecodeTypeRegisterSPECIAL3();
3885 break;
3886 default:
3887 UNREACHABLE();
3888 }
3889}
3890
3891
3892// Type 2: instructions using a 16, 21 or 26 bits immediate. (e.g. beq, beqc).
Andrei Popescu31002712010-02-23 13:46:05 +00003893void Simulator::DecodeTypeImmediate(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +01003894 // Instruction fields.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003895 Opcode op = instr->OpcodeFieldRaw();
3896 int32_t rs_reg = instr->RsValue();
3897 int32_t rs = get_register(instr->RsValue());
3898 uint32_t rs_u = static_cast<uint32_t>(rs);
3899 int32_t rt_reg = instr->RtValue(); // Destination register.
3900 int32_t rt = get_register(rt_reg);
3901 int16_t imm16 = instr->Imm16Value();
Andrei Popescu31002712010-02-23 13:46:05 +00003902
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003903 int32_t ft_reg = instr->FtValue(); // Destination register.
Andrei Popescu31002712010-02-23 13:46:05 +00003904
Steve Block44f0eee2011-05-26 01:26:41 +01003905 // Zero extended immediate.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003906 uint32_t oe_imm16 = 0xffff & imm16;
Steve Block44f0eee2011-05-26 01:26:41 +01003907 // Sign extended immediate.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003908 int32_t se_imm16 = imm16;
Andrei Popescu31002712010-02-23 13:46:05 +00003909
Andrei Popescu31002712010-02-23 13:46:05 +00003910 // Next pc.
3911 int32_t next_pc = bad_ra;
3912
Steve Block44f0eee2011-05-26 01:26:41 +01003913 // Used for conditional branch instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00003914 bool execute_branch_delay_instruction = false;
3915
Steve Block44f0eee2011-05-26 01:26:41 +01003916 // Used for arithmetic instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00003917 int32_t alu_out = 0;
Andrei Popescu31002712010-02-23 13:46:05 +00003918
Steve Block44f0eee2011-05-26 01:26:41 +01003919 // Used for memory instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00003920 int32_t addr = 0x0;
3921
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003922 // Branch instructions common part.
3923 auto BranchAndLinkHelper = [this, instr, &next_pc,
3924 &execute_branch_delay_instruction](
3925 bool do_branch) {
3926 execute_branch_delay_instruction = true;
3927 int32_t current_pc = get_pc();
3928 if (do_branch) {
3929 int16_t imm16 = instr->Imm16Value();
3930 next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
3931 set_register(31, current_pc + 2 * Instruction::kInstrSize);
3932 } else {
3933 next_pc = current_pc + 2 * Instruction::kInstrSize;
3934 }
3935 };
3936
3937 auto BranchHelper = [this, instr, &next_pc,
3938 &execute_branch_delay_instruction](bool do_branch) {
3939 execute_branch_delay_instruction = true;
3940 int32_t current_pc = get_pc();
3941 if (do_branch) {
3942 int16_t imm16 = instr->Imm16Value();
3943 next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
3944 } else {
3945 next_pc = current_pc + 2 * Instruction::kInstrSize;
3946 }
3947 };
3948
3949 auto BranchAndLinkCompactHelper = [this, instr, &next_pc](bool do_branch,
3950 int bits) {
3951 int32_t current_pc = get_pc();
3952 CheckForbiddenSlot(current_pc);
3953 if (do_branch) {
3954 int32_t imm = instr->ImmValue(bits);
3955 imm <<= 32 - bits;
3956 imm >>= 32 - bits;
3957 next_pc = current_pc + (imm << 2) + Instruction::kInstrSize;
3958 set_register(31, current_pc + Instruction::kInstrSize);
3959 }
3960 };
3961
3962 auto BranchCompactHelper = [&next_pc, this, instr](bool do_branch, int bits) {
3963 int32_t current_pc = get_pc();
3964 CheckForbiddenSlot(current_pc);
3965 if (do_branch) {
3966 int32_t imm = instr->ImmValue(bits);
3967 imm <<= 32 - bits;
3968 imm >>= 32 - bits;
3969 next_pc = get_pc() + (imm << 2) + Instruction::kInstrSize;
3970 }
3971 };
3972
3973
Andrei Popescu31002712010-02-23 13:46:05 +00003974 switch (op) {
Steve Block44f0eee2011-05-26 01:26:41 +01003975 // ------------- COP1. Coprocessor instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00003976 case COP1:
3977 switch (instr->RsFieldRaw()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003978 case BC1: { // Branch on coprocessor condition.
3979 // Floating point.
3980 uint32_t cc = instr->FBccValue();
3981 uint32_t fcsr_cc = get_fcsr_condition_bit(cc);
3982 uint32_t cc_value = test_fcsr_bit(fcsr_cc);
3983 bool do_branch = (instr->FBtrueValue()) ? cc_value : !cc_value;
3984 BranchHelper(do_branch);
Andrei Popescu31002712010-02-23 13:46:05 +00003985 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003986 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003987 case BC1EQZ:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003988 BranchHelper(!(get_fpu_register(ft_reg) & 0x1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003989 break;
3990 case BC1NEZ:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003991 BranchHelper(get_fpu_register(ft_reg) & 0x1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003992 break;
Andrei Popescu31002712010-02-23 13:46:05 +00003993 default:
3994 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003995 }
Andrei Popescu31002712010-02-23 13:46:05 +00003996 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00003997 // ------------- REGIMM class.
Andrei Popescu31002712010-02-23 13:46:05 +00003998 case REGIMM:
3999 switch (instr->RtFieldRaw()) {
4000 case BLTZ:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004001 BranchHelper(rs < 0);
Andrei Popescu31002712010-02-23 13:46:05 +00004002 break;
4003 case BGEZ:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004004 BranchHelper(rs >= 0);
4005 break;
4006 case BLTZAL:
4007 BranchAndLinkHelper(rs < 0);
Andrei Popescu31002712010-02-23 13:46:05 +00004008 break;
4009 case BGEZAL:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004010 BranchAndLinkHelper(rs >= 0);
Andrei Popescu31002712010-02-23 13:46:05 +00004011 break;
4012 default:
4013 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004014 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004015 break; // case REGIMM.
Ben Murdoch257744e2011-11-30 15:57:28 +00004016 // ------------- Branch instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00004017 // When comparing to zero, the encoding of rt field is always 0, so we don't
4018 // need to replace rt with zero.
4019 case BEQ:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004020 BranchHelper(rs == rt);
Andrei Popescu31002712010-02-23 13:46:05 +00004021 break;
4022 case BNE:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004023 BranchHelper(rs != rt);
Andrei Popescu31002712010-02-23 13:46:05 +00004024 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004025 case POP06: // BLEZALC, BGEZALC, BGEUC, BLEZ (pre-r6)
4026 if (IsMipsArchVariant(kMips32r6)) {
4027 if (rt_reg != 0) {
4028 if (rs_reg == 0) { // BLEZALC
4029 BranchAndLinkCompactHelper(rt <= 0, 16);
4030 } else {
4031 if (rs_reg == rt_reg) { // BGEZALC
4032 BranchAndLinkCompactHelper(rt >= 0, 16);
4033 } else { // BGEUC
4034 BranchCompactHelper(
4035 static_cast<uint32_t>(rs) >= static_cast<uint32_t>(rt), 16);
4036 }
4037 }
4038 } else { // BLEZ
4039 BranchHelper(rs <= 0);
4040 }
4041 } else { // BLEZ
4042 BranchHelper(rs <= 0);
4043 }
Andrei Popescu31002712010-02-23 13:46:05 +00004044 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004045 case POP07: // BGTZALC, BLTZALC, BLTUC, BGTZ (pre-r6)
4046 if (IsMipsArchVariant(kMips32r6)) {
4047 if (rt_reg != 0) {
4048 if (rs_reg == 0) { // BGTZALC
4049 BranchAndLinkCompactHelper(rt > 0, 16);
4050 } else {
4051 if (rt_reg == rs_reg) { // BLTZALC
4052 BranchAndLinkCompactHelper(rt < 0, 16);
4053 } else { // BLTUC
4054 BranchCompactHelper(
4055 static_cast<uint32_t>(rs) < static_cast<uint32_t>(rt), 16);
4056 }
4057 }
4058 } else { // BGTZ
4059 BranchHelper(rs > 0);
4060 }
4061 } else { // BGTZ
4062 BranchHelper(rs > 0);
4063 }
Andrei Popescu31002712010-02-23 13:46:05 +00004064 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004065 case POP26: // BLEZC, BGEZC, BGEC/BLEC / BLEZL (pre-r6)
4066 if (IsMipsArchVariant(kMips32r6)) {
4067 if (rt_reg != 0) {
4068 if (rs_reg == 0) { // BLEZC
4069 BranchCompactHelper(rt <= 0, 16);
4070 } else {
4071 if (rs_reg == rt_reg) { // BGEZC
4072 BranchCompactHelper(rt >= 0, 16);
4073 } else { // BGEC/BLEC
4074 BranchCompactHelper(rs >= rt, 16);
4075 }
4076 }
4077 }
4078 } else { // BLEZL
4079 BranchAndLinkHelper(rs <= 0);
4080 }
4081 break;
4082 case POP27: // BGTZC, BLTZC, BLTC/BGTC / BGTZL (pre-r6)
4083 if (IsMipsArchVariant(kMips32r6)) {
4084 if (rt_reg != 0) {
4085 if (rs_reg == 0) { // BGTZC
4086 BranchCompactHelper(rt > 0, 16);
4087 } else {
4088 if (rs_reg == rt_reg) { // BLTZC
4089 BranchCompactHelper(rt < 0, 16);
4090 } else { // BLTC/BGTC
4091 BranchCompactHelper(rs < rt, 16);
4092 }
4093 }
4094 }
4095 } else { // BGTZL
4096 BranchAndLinkHelper(rs > 0);
4097 }
4098 break;
4099 case POP66: // BEQZC, JIC
4100 if (rs_reg != 0) { // BEQZC
4101 BranchCompactHelper(rs == 0, 21);
4102 } else { // JIC
4103 next_pc = rt + imm16;
4104 }
4105 break;
4106 case POP76: // BNEZC, JIALC
4107 if (rs_reg != 0) { // BNEZC
4108 BranchCompactHelper(rs != 0, 21);
4109 } else { // JIALC
4110 set_register(31, get_pc() + Instruction::kInstrSize);
4111 next_pc = rt + imm16;
4112 }
4113 break;
4114 case BC:
4115 BranchCompactHelper(true, 26);
4116 break;
4117 case BALC:
4118 BranchAndLinkCompactHelper(true, 26);
4119 break;
4120 case POP10: // BOVC, BEQZALC, BEQC / ADDI (pre-r6)
4121 if (IsMipsArchVariant(kMips32r6)) {
4122 if (rs_reg >= rt_reg) { // BOVC
4123 if (HaveSameSign(rs, rt)) {
4124 if (rs > 0) {
4125 BranchCompactHelper(rs > Registers::kMaxValue - rt, 16);
4126 } else if (rs < 0) {
4127 BranchCompactHelper(rs < Registers::kMinValue - rt, 16);
4128 }
4129 }
4130 } else {
4131 if (rs_reg == 0) { // BEQZALC
4132 BranchAndLinkCompactHelper(rt == 0, 16);
4133 } else { // BEQC
4134 BranchCompactHelper(rt == rs, 16);
4135 }
4136 }
4137 } else { // ADDI
4138 if (HaveSameSign(rs, se_imm16)) {
4139 if (rs > 0) {
4140 if (rs <= Registers::kMaxValue - se_imm16) {
4141 SignalException(kIntegerOverflow);
4142 }
4143 } else if (rs < 0) {
4144 if (rs >= Registers::kMinValue - se_imm16) {
4145 SignalException(kIntegerUnderflow);
4146 }
4147 }
4148 }
4149 SetResult(rt_reg, rs + se_imm16);
4150 }
4151 break;
4152 case POP30: // BNVC, BNEZALC, BNEC / DADDI (pre-r6)
4153 if (IsMipsArchVariant(kMips32r6)) {
4154 if (rs_reg >= rt_reg) { // BNVC
4155 if (!HaveSameSign(rs, rt) || rs == 0 || rt == 0) {
4156 BranchCompactHelper(true, 16);
4157 } else {
4158 if (rs > 0) {
4159 BranchCompactHelper(rs <= Registers::kMaxValue - rt, 16);
4160 } else if (rs < 0) {
4161 BranchCompactHelper(rs >= Registers::kMinValue - rt, 16);
4162 }
4163 }
4164 } else {
4165 if (rs_reg == 0) { // BNEZALC
4166 BranchAndLinkCompactHelper(rt != 0, 16);
4167 } else { // BNEC
4168 BranchCompactHelper(rt != rs, 16);
4169 }
Andrei Popescu31002712010-02-23 13:46:05 +00004170 }
4171 }
Andrei Popescu31002712010-02-23 13:46:05 +00004172 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004173 // ------------- Arithmetic instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00004174 case ADDIU:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004175 SetResult(rt_reg, rs + se_imm16);
Andrei Popescu31002712010-02-23 13:46:05 +00004176 break;
4177 case SLTI:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004178 SetResult(rt_reg, rs < se_imm16 ? 1 : 0);
Andrei Popescu31002712010-02-23 13:46:05 +00004179 break;
4180 case SLTIU:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004181 SetResult(rt_reg, rs_u < static_cast<uint32_t>(se_imm16) ? 1 : 0);
Andrei Popescu31002712010-02-23 13:46:05 +00004182 break;
4183 case ANDI:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004184 SetResult(rt_reg, rs & oe_imm16);
Andrei Popescu31002712010-02-23 13:46:05 +00004185 break;
4186 case ORI:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004187 SetResult(rt_reg, rs | oe_imm16);
Andrei Popescu31002712010-02-23 13:46:05 +00004188 break;
4189 case XORI:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004190 SetResult(rt_reg, rs ^ oe_imm16);
Andrei Popescu31002712010-02-23 13:46:05 +00004191 break;
4192 case LUI:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004193 if (rs_reg != 0) {
4194 // AUI
4195 DCHECK(IsMipsArchVariant(kMips32r6));
4196 SetResult(rt_reg, rs + (se_imm16 << 16));
4197 } else {
4198 // LUI
4199 SetResult(rt_reg, oe_imm16 << 16);
4200 }
Andrei Popescu31002712010-02-23 13:46:05 +00004201 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00004202 // ------------- Memory instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00004203 case LB:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004204 set_register(rt_reg, ReadB(rs + se_imm16));
Andrei Popescu31002712010-02-23 13:46:05 +00004205 break;
Steve Block44f0eee2011-05-26 01:26:41 +01004206 case LH:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004207 set_register(rt_reg, ReadH(rs + se_imm16, instr));
Steve Block44f0eee2011-05-26 01:26:41 +01004208 break;
4209 case LWL: {
Ben Murdoch257744e2011-11-30 15:57:28 +00004210 // al_offset is offset of the effective address within an aligned word.
Steve Block44f0eee2011-05-26 01:26:41 +01004211 uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
4212 uint8_t byte_shift = kPointerAlignmentMask - al_offset;
4213 uint32_t mask = (1 << byte_shift * 8) - 1;
4214 addr = rs + se_imm16 - al_offset;
4215 alu_out = ReadW(addr, instr);
4216 alu_out <<= byte_shift * 8;
4217 alu_out |= rt & mask;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004218 set_register(rt_reg, alu_out);
Steve Block44f0eee2011-05-26 01:26:41 +01004219 break;
4220 }
Andrei Popescu31002712010-02-23 13:46:05 +00004221 case LW:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004222 set_register(rt_reg, ReadW(rs + se_imm16, instr));
Andrei Popescu31002712010-02-23 13:46:05 +00004223 break;
4224 case LBU:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004225 set_register(rt_reg, ReadBU(rs + se_imm16));
Andrei Popescu31002712010-02-23 13:46:05 +00004226 break;
Steve Block44f0eee2011-05-26 01:26:41 +01004227 case LHU:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004228 set_register(rt_reg, ReadHU(rs + se_imm16, instr));
Steve Block44f0eee2011-05-26 01:26:41 +01004229 break;
4230 case LWR: {
Ben Murdoch257744e2011-11-30 15:57:28 +00004231 // al_offset is offset of the effective address within an aligned word.
Steve Block44f0eee2011-05-26 01:26:41 +01004232 uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
4233 uint8_t byte_shift = kPointerAlignmentMask - al_offset;
4234 uint32_t mask = al_offset ? (~0 << (byte_shift + 1) * 8) : 0;
4235 addr = rs + se_imm16 - al_offset;
4236 alu_out = ReadW(addr, instr);
4237 alu_out = static_cast<uint32_t> (alu_out) >> al_offset * 8;
4238 alu_out |= rt & mask;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004239 set_register(rt_reg, alu_out);
Steve Block44f0eee2011-05-26 01:26:41 +01004240 break;
4241 }
Andrei Popescu31002712010-02-23 13:46:05 +00004242 case SB:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004243 WriteB(rs + se_imm16, static_cast<int8_t>(rt));
Andrei Popescu31002712010-02-23 13:46:05 +00004244 break;
Steve Block44f0eee2011-05-26 01:26:41 +01004245 case SH:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004246 WriteH(rs + se_imm16, static_cast<uint16_t>(rt), instr);
Steve Block44f0eee2011-05-26 01:26:41 +01004247 break;
4248 case SWL: {
4249 uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
4250 uint8_t byte_shift = kPointerAlignmentMask - al_offset;
4251 uint32_t mask = byte_shift ? (~0 << (al_offset + 1) * 8) : 0;
4252 addr = rs + se_imm16 - al_offset;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004253 // Value to be written in memory.
4254 uint32_t mem_value = ReadW(addr, instr) & mask;
Steve Block44f0eee2011-05-26 01:26:41 +01004255 mem_value |= static_cast<uint32_t>(rt) >> byte_shift * 8;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004256 WriteW(addr, mem_value, instr);
Steve Block44f0eee2011-05-26 01:26:41 +01004257 break;
4258 }
Andrei Popescu31002712010-02-23 13:46:05 +00004259 case SW:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004260 WriteW(rs + se_imm16, rt, instr);
Andrei Popescu31002712010-02-23 13:46:05 +00004261 break;
Steve Block44f0eee2011-05-26 01:26:41 +01004262 case SWR: {
4263 uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
4264 uint32_t mask = (1 << al_offset * 8) - 1;
4265 addr = rs + se_imm16 - al_offset;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004266 uint32_t mem_value = ReadW(addr, instr);
Steve Block44f0eee2011-05-26 01:26:41 +01004267 mem_value = (rt << al_offset * 8) | (mem_value & mask);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004268 WriteW(addr, mem_value, instr);
Steve Block44f0eee2011-05-26 01:26:41 +01004269 break;
4270 }
Andrei Popescu31002712010-02-23 13:46:05 +00004271 case LWC1:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004272 set_fpu_register_hi_word(ft_reg, 0);
4273 set_fpu_register_word(ft_reg, ReadW(rs + se_imm16, instr));
Andrei Popescu31002712010-02-23 13:46:05 +00004274 break;
4275 case LDC1:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004276 set_fpu_register_double(ft_reg, ReadD(rs + se_imm16, instr));
Andrei Popescu31002712010-02-23 13:46:05 +00004277 break;
4278 case SWC1:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004279 WriteW(rs + se_imm16, get_fpu_register_word(ft_reg), instr);
Andrei Popescu31002712010-02-23 13:46:05 +00004280 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004281 case SDC1:
4282 WriteD(rs + se_imm16, get_fpu_register_double(ft_reg), instr);
4283 break;
4284 // ------------- PC-Relative instructions.
4285 case PCREL: {
4286 // rt field: checking 5-bits.
4287 int32_t imm21 = instr->Imm21Value();
4288 int32_t current_pc = get_pc();
4289 uint8_t rt = (imm21 >> kImm16Bits);
4290 switch (rt) {
4291 case ALUIPC:
4292 addr = current_pc + (se_imm16 << 16);
4293 alu_out = static_cast<int64_t>(~0x0FFFF) & addr;
4294 break;
4295 case AUIPC:
4296 alu_out = current_pc + (se_imm16 << 16);
4297 break;
4298 default: {
4299 int32_t imm19 = instr->Imm19Value();
4300 // rt field: checking the most significant 2-bits.
4301 rt = (imm21 >> kImm19Bits);
4302 switch (rt) {
4303 case LWPC: {
4304 // Set sign.
4305 imm19 <<= (kOpcodeBits + kRsBits + 2);
4306 imm19 >>= (kOpcodeBits + kRsBits + 2);
4307 addr = current_pc + (imm19 << 2);
4308 uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
4309 alu_out = *ptr;
4310 break;
4311 }
4312 case ADDIUPC: {
4313 int32_t se_imm19 = imm19 | ((imm19 & 0x40000) ? 0xfff80000 : 0);
4314 alu_out = current_pc + (se_imm19 << 2);
4315 break;
4316 }
4317 default:
4318 UNREACHABLE();
4319 break;
4320 }
4321 }
4322 }
4323 set_register(rs_reg, alu_out);
4324 break;
4325 }
Andrei Popescu31002712010-02-23 13:46:05 +00004326 default:
4327 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004328 }
Andrei Popescu31002712010-02-23 13:46:05 +00004329
Andrei Popescu31002712010-02-23 13:46:05 +00004330 if (execute_branch_delay_instruction) {
4331 // Execute branch delay slot
4332 // We don't check for end_sim_pc. First it should not be met as the current
4333 // pc is valid. Secondly a jump should always execute its branch delay slot.
4334 Instruction* branch_delay_instr =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004335 reinterpret_cast<Instruction*>(get_pc() + Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +00004336 BranchDelayInstructionDecode(branch_delay_instr);
4337 }
4338
4339 // If needed update pc after the branch delay execution.
4340 if (next_pc != bad_ra) {
4341 set_pc(next_pc);
4342 }
4343}
4344
Steve Block44f0eee2011-05-26 01:26:41 +01004345
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004346// Type 3: instructions using a 26 bytes immediate. (e.g. j, jal).
Andrei Popescu31002712010-02-23 13:46:05 +00004347void Simulator::DecodeTypeJump(Instruction* instr) {
4348 // Get current pc.
4349 int32_t current_pc = get_pc();
4350 // Get unchanged bits of pc.
4351 int32_t pc_high_bits = current_pc & 0xf0000000;
Ben Murdoch257744e2011-11-30 15:57:28 +00004352 // Next pc.
Steve Block44f0eee2011-05-26 01:26:41 +01004353 int32_t next_pc = pc_high_bits | (instr->Imm26Value() << 2);
Andrei Popescu31002712010-02-23 13:46:05 +00004354
Ben Murdoch257744e2011-11-30 15:57:28 +00004355 // Execute branch delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00004356 // We don't check for end_sim_pc. First it should not be met as the current pc
4357 // is valid. Secondly a jump should always execute its branch delay slot.
4358 Instruction* branch_delay_instr =
Ben Murdoch257744e2011-11-30 15:57:28 +00004359 reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +00004360 BranchDelayInstructionDecode(branch_delay_instr);
4361
4362 // Update pc and ra if necessary.
4363 // Do this after the branch delay execution.
4364 if (instr->IsLinkingInstruction()) {
Ben Murdoch257744e2011-11-30 15:57:28 +00004365 set_register(31, current_pc + 2 * Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +00004366 }
4367 set_pc(next_pc);
4368 pc_modified_ = true;
4369}
4370
Steve Block44f0eee2011-05-26 01:26:41 +01004371
Andrei Popescu31002712010-02-23 13:46:05 +00004372// Executes the current instruction.
4373void Simulator::InstructionDecode(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +01004374 if (v8::internal::FLAG_check_icache) {
4375 CheckICache(isolate_->simulator_i_cache(), instr);
4376 }
Andrei Popescu31002712010-02-23 13:46:05 +00004377 pc_modified_ = false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004378 v8::internal::EmbeddedVector<char, 256> buffer;
Andrei Popescu31002712010-02-23 13:46:05 +00004379 if (::v8::internal::FLAG_trace_sim) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004380 SNPrintF(trace_buf_, "%s", "");
Andrei Popescu31002712010-02-23 13:46:05 +00004381 disasm::NameConverter converter;
4382 disasm::Disassembler dasm(converter);
Ben Murdoch257744e2011-11-30 15:57:28 +00004383 dasm.InstructionDecode(buffer, reinterpret_cast<byte*>(instr));
Andrei Popescu31002712010-02-23 13:46:05 +00004384 }
4385
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004386 switch (instr->InstructionType(Instruction::TypeChecks::EXTRA)) {
Andrei Popescu31002712010-02-23 13:46:05 +00004387 case Instruction::kRegisterType:
4388 DecodeTypeRegister(instr);
4389 break;
4390 case Instruction::kImmediateType:
4391 DecodeTypeImmediate(instr);
4392 break;
4393 case Instruction::kJumpType:
4394 DecodeTypeJump(instr);
4395 break;
4396 default:
4397 UNSUPPORTED();
4398 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004399 if (::v8::internal::FLAG_trace_sim) {
4400 PrintF(" 0x%08x %-44s %s\n", reinterpret_cast<intptr_t>(instr),
4401 buffer.start(), trace_buf_.start());
4402 }
Andrei Popescu31002712010-02-23 13:46:05 +00004403 if (!pc_modified_) {
4404 set_register(pc, reinterpret_cast<int32_t>(instr) +
Steve Block44f0eee2011-05-26 01:26:41 +01004405 Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +00004406 }
4407}
4408
4409
4410
4411void Simulator::Execute() {
4412 // Get the PC to simulate. Cannot use the accessor here as we need the
4413 // raw PC value and not the one used as input to arithmetic instructions.
4414 int program_counter = get_pc();
4415 if (::v8::internal::FLAG_stop_sim_at == 0) {
4416 // Fast version of the dispatch loop without checking whether the simulator
4417 // should be stopping at a particular executed instruction.
4418 while (program_counter != end_sim_pc) {
4419 Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
4420 icount_++;
4421 InstructionDecode(instr);
4422 program_counter = get_pc();
4423 }
4424 } else {
4425 // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when
4426 // we reach the particular instuction count.
4427 while (program_counter != end_sim_pc) {
4428 Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
4429 icount_++;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004430 if (icount_ == static_cast<uint64_t>(::v8::internal::FLAG_stop_sim_at)) {
Steve Block44f0eee2011-05-26 01:26:41 +01004431 MipsDebugger dbg(this);
Andrei Popescu31002712010-02-23 13:46:05 +00004432 dbg.Debug();
4433 } else {
4434 InstructionDecode(instr);
4435 }
4436 program_counter = get_pc();
4437 }
4438 }
4439}
4440
4441
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004442void Simulator::CallInternal(byte* entry) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004443 // Adjust JS-based stack limit to C-based stack limit.
4444 isolate_->stack_guard()->AdjustStackLimitForSimulator();
4445
Ben Murdoch257744e2011-11-30 15:57:28 +00004446 // Prepare to execute the code at entry.
Andrei Popescu31002712010-02-23 13:46:05 +00004447 set_register(pc, reinterpret_cast<int32_t>(entry));
4448 // Put down marker for end of simulation. The simulator will stop simulation
4449 // when the PC reaches this value. By saving the "end simulation" value into
4450 // the LR the simulation stops when returning to this call point.
4451 set_register(ra, end_sim_pc);
4452
4453 // Remember the values of callee-saved registers.
4454 // The code below assumes that r9 is not used as sb (static base) in
4455 // simulator code and therefore is regarded as a callee-saved register.
4456 int32_t s0_val = get_register(s0);
4457 int32_t s1_val = get_register(s1);
4458 int32_t s2_val = get_register(s2);
4459 int32_t s3_val = get_register(s3);
4460 int32_t s4_val = get_register(s4);
4461 int32_t s5_val = get_register(s5);
4462 int32_t s6_val = get_register(s6);
4463 int32_t s7_val = get_register(s7);
4464 int32_t gp_val = get_register(gp);
4465 int32_t sp_val = get_register(sp);
4466 int32_t fp_val = get_register(fp);
4467
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004468 // Set up the callee-saved registers with a known value. To be able to check
Andrei Popescu31002712010-02-23 13:46:05 +00004469 // that they are preserved properly across JS execution.
4470 int32_t callee_saved_value = icount_;
4471 set_register(s0, callee_saved_value);
4472 set_register(s1, callee_saved_value);
4473 set_register(s2, callee_saved_value);
4474 set_register(s3, callee_saved_value);
4475 set_register(s4, callee_saved_value);
4476 set_register(s5, callee_saved_value);
4477 set_register(s6, callee_saved_value);
4478 set_register(s7, callee_saved_value);
4479 set_register(gp, callee_saved_value);
4480 set_register(fp, callee_saved_value);
4481
Ben Murdoch257744e2011-11-30 15:57:28 +00004482 // Start the simulation.
Andrei Popescu31002712010-02-23 13:46:05 +00004483 Execute();
4484
4485 // Check that the callee-saved registers have been preserved.
4486 CHECK_EQ(callee_saved_value, get_register(s0));
4487 CHECK_EQ(callee_saved_value, get_register(s1));
4488 CHECK_EQ(callee_saved_value, get_register(s2));
4489 CHECK_EQ(callee_saved_value, get_register(s3));
4490 CHECK_EQ(callee_saved_value, get_register(s4));
4491 CHECK_EQ(callee_saved_value, get_register(s5));
4492 CHECK_EQ(callee_saved_value, get_register(s6));
4493 CHECK_EQ(callee_saved_value, get_register(s7));
4494 CHECK_EQ(callee_saved_value, get_register(gp));
4495 CHECK_EQ(callee_saved_value, get_register(fp));
4496
4497 // Restore callee-saved registers with the original value.
4498 set_register(s0, s0_val);
4499 set_register(s1, s1_val);
4500 set_register(s2, s2_val);
4501 set_register(s3, s3_val);
4502 set_register(s4, s4_val);
4503 set_register(s5, s5_val);
4504 set_register(s6, s6_val);
4505 set_register(s7, s7_val);
4506 set_register(gp, gp_val);
4507 set_register(sp, sp_val);
4508 set_register(fp, fp_val);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004509}
4510
4511
4512int32_t Simulator::Call(byte* entry, int argument_count, ...) {
4513 va_list parameters;
4514 va_start(parameters, argument_count);
4515 // Set up arguments.
4516
4517 // First four arguments passed in registers.
4518 DCHECK(argument_count >= 4);
4519 set_register(a0, va_arg(parameters, int32_t));
4520 set_register(a1, va_arg(parameters, int32_t));
4521 set_register(a2, va_arg(parameters, int32_t));
4522 set_register(a3, va_arg(parameters, int32_t));
4523
4524 // Remaining arguments passed on stack.
4525 int original_stack = get_register(sp);
4526 // Compute position of stack on entry to generated code.
4527 int entry_stack = (original_stack - (argument_count - 4) * sizeof(int32_t)
4528 - kCArgsSlotsSize);
4529 if (base::OS::ActivationFrameAlignment() != 0) {
4530 entry_stack &= -base::OS::ActivationFrameAlignment();
4531 }
4532 // Store remaining arguments on stack, from low to high memory.
4533 intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
4534 for (int i = 4; i < argument_count; i++) {
4535 stack_argument[i - 4 + kCArgSlotCount] = va_arg(parameters, int32_t);
4536 }
4537 va_end(parameters);
4538 set_register(sp, entry_stack);
4539
4540 CallInternal(entry);
Andrei Popescu31002712010-02-23 13:46:05 +00004541
4542 // Pop stack passed arguments.
4543 CHECK_EQ(entry_stack, get_register(sp));
4544 set_register(sp, original_stack);
4545
4546 int32_t result = get_register(v0);
4547 return result;
4548}
4549
4550
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004551double Simulator::CallFP(byte* entry, double d0, double d1) {
4552 if (!IsMipsSoftFloatABI) {
4553 set_fpu_register_double(f12, d0);
4554 set_fpu_register_double(f14, d1);
4555 } else {
4556 int buffer[2];
4557 DCHECK(sizeof(buffer[0]) * 2 == sizeof(d0));
4558 memcpy(buffer, &d0, sizeof(d0));
4559 set_dw_register(a0, buffer);
4560 memcpy(buffer, &d1, sizeof(d1));
4561 set_dw_register(a2, buffer);
4562 }
4563 CallInternal(entry);
4564 if (!IsMipsSoftFloatABI) {
4565 return get_fpu_register_double(f0);
4566 } else {
4567 return get_double_from_register_pair(v0);
4568 }
4569}
4570
4571
Andrei Popescu31002712010-02-23 13:46:05 +00004572uintptr_t Simulator::PushAddress(uintptr_t address) {
4573 int new_sp = get_register(sp) - sizeof(uintptr_t);
4574 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp);
4575 *stack_slot = address;
4576 set_register(sp, new_sp);
4577 return new_sp;
4578}
4579
4580
4581uintptr_t Simulator::PopAddress() {
4582 int current_sp = get_register(sp);
4583 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp);
4584 uintptr_t address = *stack_slot;
4585 set_register(sp, current_sp + sizeof(uintptr_t));
4586 return address;
4587}
4588
4589
4590#undef UNSUPPORTED
4591
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004592} // namespace internal
4593} // namespace v8
Andrei Popescu31002712010-02-23 13:46:05 +00004594
Steve Block44f0eee2011-05-26 01:26:41 +01004595#endif // USE_SIMULATOR
Andrei Popescu31002712010-02-23 13:46:05 +00004596
Leon Clarkef7060e22010-06-03 12:02:55 +01004597#endif // V8_TARGET_ARCH_MIPS