blob: 0c91cb5512c94bce4adf210768a676cac5cc275b [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"
Ben Murdoch097c5b22016-05-18 11:27:45 +010019#include "src/runtime/runtime-utils.h"
Andrei Popescu31002712010-02-23 13:46:05 +000020
Andrei Popescu31002712010-02-23 13:46:05 +000021
22// Only build the simulator if not compiling for real MIPS hardware.
Steve Block44f0eee2011-05-26 01:26:41 +010023#if defined(USE_SIMULATOR)
Andrei Popescu31002712010-02-23 13:46:05 +000024
Steve Block44f0eee2011-05-26 01:26:41 +010025namespace v8 {
26namespace internal {
Andrei Popescu31002712010-02-23 13:46:05 +000027
Ben Murdoch257744e2011-11-30 15:57:28 +000028// Utils functions.
Andrei Popescu31002712010-02-23 13:46:05 +000029bool HaveSameSign(int32_t a, int32_t b) {
Steve Block44f0eee2011-05-26 01:26:41 +010030 return ((a ^ b) >= 0);
31}
32
33
34uint32_t get_fcsr_condition_bit(uint32_t cc) {
35 if (cc == 0) {
36 return 23;
37 } else {
38 return 24 + cc;
39 }
Andrei Popescu31002712010-02-23 13:46:05 +000040}
41
42
43// This macro provides a platform independent use of sscanf. The reason for
44// SScanF not being implemented in a platform independent was through
45// ::v8::internal::OS in the same way as SNPrintF is that the Windows C Run-Time
46// Library does not provide vsscanf.
47#define SScanF sscanf // NOLINT
48
Steve Block44f0eee2011-05-26 01:26:41 +010049// The MipsDebugger class is used by the simulator while debugging simulated
Andrei Popescu31002712010-02-23 13:46:05 +000050// code.
Steve Block44f0eee2011-05-26 01:26:41 +010051class MipsDebugger {
Andrei Popescu31002712010-02-23 13:46:05 +000052 public:
Ben Murdoch3ef787d2012-04-12 10:51:47 +010053 explicit MipsDebugger(Simulator* sim) : sim_(sim) { }
Steve Block44f0eee2011-05-26 01:26:41 +010054 ~MipsDebugger();
Andrei Popescu31002712010-02-23 13:46:05 +000055
56 void Stop(Instruction* instr);
57 void Debug();
Steve Block44f0eee2011-05-26 01:26:41 +010058 // Print all registers with a nice formatting.
59 void PrintAllRegs();
60 void PrintAllRegsIncludingFPU();
Andrei Popescu31002712010-02-23 13:46:05 +000061
62 private:
63 // We set the breakpoint code to 0xfffff to easily recognize it.
64 static const Instr kBreakpointInstr = SPECIAL | BREAK | 0xfffff << 6;
65 static const Instr kNopInstr = 0x0;
66
67 Simulator* sim_;
68
69 int32_t GetRegisterValue(int regnum);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000070 int32_t GetFPURegisterValue32(int regnum);
71 int64_t GetFPURegisterValue64(int regnum);
Steve Block44f0eee2011-05-26 01:26:41 +010072 float GetFPURegisterValueFloat(int regnum);
73 double GetFPURegisterValueDouble(int regnum);
Andrei Popescu31002712010-02-23 13:46:05 +000074 bool GetValue(const char* desc, int32_t* value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000075 bool GetValue(const char* desc, int64_t* value);
Andrei Popescu31002712010-02-23 13:46:05 +000076
77 // Set or delete a breakpoint. Returns true if successful.
78 bool SetBreakpoint(Instruction* breakpc);
79 bool DeleteBreakpoint(Instruction* breakpc);
80
81 // Undo and redo all breakpoints. This is needed to bracket disassembly and
82 // execution to skip past breakpoints when run from the debugger.
83 void UndoBreakpoints();
84 void RedoBreakpoints();
Andrei Popescu31002712010-02-23 13:46:05 +000085};
86
Steve Block44f0eee2011-05-26 01:26:41 +010087
88MipsDebugger::~MipsDebugger() {
Andrei Popescu31002712010-02-23 13:46:05 +000089}
90
Steve Block44f0eee2011-05-26 01:26:41 +010091
Andrei Popescu31002712010-02-23 13:46:05 +000092#ifdef GENERATED_CODE_COVERAGE
93static FILE* coverage_log = NULL;
94
95
96static void InitializeCoverage() {
97 char* file_name = getenv("V8_GENERATED_CODE_COVERAGE_LOG");
98 if (file_name != NULL) {
99 coverage_log = fopen(file_name, "aw+");
100 }
101}
102
103
Steve Block44f0eee2011-05-26 01:26:41 +0100104void MipsDebugger::Stop(Instruction* instr) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000105 // Get the stop code.
106 uint32_t code = instr->Bits(25, 6);
107 // Retrieve the encoded address, which comes just after this stop.
108 char** msg_address =
109 reinterpret_cast<char**>(sim_->get_pc() + Instr::kInstrSize);
110 char* msg = *msg_address;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000111 DCHECK(msg != NULL);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000112
113 // Update this stop description.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000114 if (!watched_stops_[code].desc) {
115 watched_stops_[code].desc = msg;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000116 }
117
118 if (strlen(msg) > 0) {
Andrei Popescu31002712010-02-23 13:46:05 +0000119 if (coverage_log != NULL) {
120 fprintf(coverage_log, "%s\n", str);
121 fflush(coverage_log);
122 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000123 // Overwrite the instruction and address with nops.
124 instr->SetInstructionBits(kNopInstr);
125 reinterpret_cast<Instr*>(msg_address)->SetInstructionBits(kNopInstr);
Andrei Popescu31002712010-02-23 13:46:05 +0000126 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000127 sim_->set_pc(sim_->get_pc() + 2 * Instruction::kInstructionSize);
Andrei Popescu31002712010-02-23 13:46:05 +0000128}
129
Steve Block44f0eee2011-05-26 01:26:41 +0100130
Ben Murdoch257744e2011-11-30 15:57:28 +0000131#else // GENERATED_CODE_COVERAGE
Andrei Popescu31002712010-02-23 13:46:05 +0000132
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000133#define UNSUPPORTED() printf("Sim: Unsupported instruction.\n");
Andrei Popescu31002712010-02-23 13:46:05 +0000134
135static void InitializeCoverage() {}
136
137
Steve Block44f0eee2011-05-26 01:26:41 +0100138void MipsDebugger::Stop(Instruction* instr) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000139 // Get the stop code.
140 uint32_t code = instr->Bits(25, 6);
141 // Retrieve the encoded address, which comes just after this stop.
142 char* msg = *reinterpret_cast<char**>(sim_->get_pc() +
143 Instruction::kInstrSize);
144 // Update this stop description.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000145 if (!sim_->watched_stops_[code].desc) {
146 sim_->watched_stops_[code].desc = msg;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000147 }
148 PrintF("Simulator hit %s (%u)\n", msg, code);
149 sim_->set_pc(sim_->get_pc() + 2 * Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +0000150 Debug();
151}
Steve Block6ded16b2010-05-10 14:33:55 +0100152#endif // GENERATED_CODE_COVERAGE
Andrei Popescu31002712010-02-23 13:46:05 +0000153
154
Steve Block44f0eee2011-05-26 01:26:41 +0100155int32_t MipsDebugger::GetRegisterValue(int regnum) {
Andrei Popescu31002712010-02-23 13:46:05 +0000156 if (regnum == kNumSimuRegisters) {
157 return sim_->get_pc();
158 } else {
159 return sim_->get_register(regnum);
160 }
161}
162
163
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000164int32_t MipsDebugger::GetFPURegisterValue32(int regnum) {
Steve Block44f0eee2011-05-26 01:26:41 +0100165 if (regnum == kNumFPURegisters) {
166 return sim_->get_pc();
167 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000168 return sim_->get_fpu_register_word(regnum);
Steve Block44f0eee2011-05-26 01:26:41 +0100169 }
170}
171
172
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000173int64_t MipsDebugger::GetFPURegisterValue64(int regnum) {
Steve Block44f0eee2011-05-26 01:26:41 +0100174 if (regnum == kNumFPURegisters) {
175 return sim_->get_pc();
176 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000177 return sim_->get_fpu_register(regnum);
Steve Block44f0eee2011-05-26 01:26:41 +0100178 }
179}
180
181
182float MipsDebugger::GetFPURegisterValueFloat(int regnum) {
183 if (regnum == kNumFPURegisters) {
184 return sim_->get_pc();
185 } else {
186 return sim_->get_fpu_register_float(regnum);
187 }
188}
189
190
191double MipsDebugger::GetFPURegisterValueDouble(int regnum) {
192 if (regnum == kNumFPURegisters) {
193 return sim_->get_pc();
194 } else {
195 return sim_->get_fpu_register_double(regnum);
196 }
197}
198
199
200bool MipsDebugger::GetValue(const char* desc, int32_t* value) {
Andrei Popescu31002712010-02-23 13:46:05 +0000201 int regnum = Registers::Number(desc);
Steve Block44f0eee2011-05-26 01:26:41 +0100202 int fpuregnum = FPURegisters::Number(desc);
203
Andrei Popescu31002712010-02-23 13:46:05 +0000204 if (regnum != kInvalidRegister) {
205 *value = GetRegisterValue(regnum);
206 return true;
Steve Block44f0eee2011-05-26 01:26:41 +0100207 } else if (fpuregnum != kInvalidFPURegister) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000208 *value = GetFPURegisterValue32(fpuregnum);
Steve Block44f0eee2011-05-26 01:26:41 +0100209 return true;
210 } else if (strncmp(desc, "0x", 2) == 0) {
211 return SScanF(desc, "%x", reinterpret_cast<uint32_t*>(value)) == 1;
Andrei Popescu31002712010-02-23 13:46:05 +0000212 } else {
213 return SScanF(desc, "%i", value) == 1;
214 }
215 return false;
216}
217
218
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000219bool MipsDebugger::GetValue(const char* desc, int64_t* value) {
220 int regnum = Registers::Number(desc);
221 int fpuregnum = FPURegisters::Number(desc);
222
223 if (regnum != kInvalidRegister) {
224 *value = GetRegisterValue(regnum);
225 return true;
226 } else if (fpuregnum != kInvalidFPURegister) {
227 *value = GetFPURegisterValue64(fpuregnum);
228 return true;
229 } else if (strncmp(desc, "0x", 2) == 0) {
230 return SScanF(desc + 2, "%" SCNx64,
231 reinterpret_cast<uint64_t*>(value)) == 1;
232 } else {
233 return SScanF(desc, "%" SCNu64, reinterpret_cast<uint64_t*>(value)) == 1;
234 }
235 return false;
236}
237
238
Steve Block44f0eee2011-05-26 01:26:41 +0100239bool MipsDebugger::SetBreakpoint(Instruction* breakpc) {
Andrei Popescu31002712010-02-23 13:46:05 +0000240 // Check if a breakpoint can be set. If not return without any side-effects.
241 if (sim_->break_pc_ != NULL) {
242 return false;
243 }
244
245 // Set the breakpoint.
246 sim_->break_pc_ = breakpc;
247 sim_->break_instr_ = breakpc->InstructionBits();
248 // Not setting the breakpoint instruction in the code itself. It will be set
249 // when the debugger shell continues.
250 return true;
251}
252
253
Steve Block44f0eee2011-05-26 01:26:41 +0100254bool MipsDebugger::DeleteBreakpoint(Instruction* breakpc) {
Andrei Popescu31002712010-02-23 13:46:05 +0000255 if (sim_->break_pc_ != NULL) {
256 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
257 }
258
259 sim_->break_pc_ = NULL;
260 sim_->break_instr_ = 0;
261 return true;
262}
263
264
Steve Block44f0eee2011-05-26 01:26:41 +0100265void MipsDebugger::UndoBreakpoints() {
Andrei Popescu31002712010-02-23 13:46:05 +0000266 if (sim_->break_pc_ != NULL) {
267 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
268 }
269}
270
271
Steve Block44f0eee2011-05-26 01:26:41 +0100272void MipsDebugger::RedoBreakpoints() {
Andrei Popescu31002712010-02-23 13:46:05 +0000273 if (sim_->break_pc_ != NULL) {
274 sim_->break_pc_->SetInstructionBits(kBreakpointInstr);
275 }
276}
277
Steve Block44f0eee2011-05-26 01:26:41 +0100278
279void MipsDebugger::PrintAllRegs() {
Andrei Popescu31002712010-02-23 13:46:05 +0000280#define REG_INFO(n) Registers::Name(n), GetRegisterValue(n), GetRegisterValue(n)
281
282 PrintF("\n");
Ben Murdoch257744e2011-11-30 15:57:28 +0000283 // at, v0, a0.
Andrei Popescu31002712010-02-23 13:46:05 +0000284 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
285 REG_INFO(1), REG_INFO(2), REG_INFO(4));
Ben Murdoch257744e2011-11-30 15:57:28 +0000286 // v1, a1.
Andrei Popescu31002712010-02-23 13:46:05 +0000287 PrintF("%26s\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
288 "", REG_INFO(3), REG_INFO(5));
Ben Murdoch257744e2011-11-30 15:57:28 +0000289 // a2.
Andrei Popescu31002712010-02-23 13:46:05 +0000290 PrintF("%26s\t%26s\t%3s: 0x%08x %10d\n", "", "", REG_INFO(6));
Ben Murdoch257744e2011-11-30 15:57:28 +0000291 // a3.
Andrei Popescu31002712010-02-23 13:46:05 +0000292 PrintF("%26s\t%26s\t%3s: 0x%08x %10d\n", "", "", REG_INFO(7));
293 PrintF("\n");
294 // t0-t7, s0-s7
295 for (int i = 0; i < 8; i++) {
296 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
297 REG_INFO(8+i), REG_INFO(16+i));
298 }
299 PrintF("\n");
Ben Murdoch257744e2011-11-30 15:57:28 +0000300 // t8, k0, LO.
Andrei Popescu31002712010-02-23 13:46:05 +0000301 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
302 REG_INFO(24), REG_INFO(26), REG_INFO(32));
Ben Murdoch257744e2011-11-30 15:57:28 +0000303 // t9, k1, HI.
Andrei Popescu31002712010-02-23 13:46:05 +0000304 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
305 REG_INFO(25), REG_INFO(27), REG_INFO(33));
Ben Murdoch257744e2011-11-30 15:57:28 +0000306 // sp, fp, gp.
Andrei Popescu31002712010-02-23 13:46:05 +0000307 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
308 REG_INFO(29), REG_INFO(30), REG_INFO(28));
Ben Murdoch257744e2011-11-30 15:57:28 +0000309 // pc.
Andrei Popescu31002712010-02-23 13:46:05 +0000310 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
311 REG_INFO(31), REG_INFO(34));
Steve Block44f0eee2011-05-26 01:26:41 +0100312
Andrei Popescu31002712010-02-23 13:46:05 +0000313#undef REG_INFO
Steve Block44f0eee2011-05-26 01:26:41 +0100314#undef FPU_REG_INFO
Andrei Popescu31002712010-02-23 13:46:05 +0000315}
316
Steve Block44f0eee2011-05-26 01:26:41 +0100317
318void MipsDebugger::PrintAllRegsIncludingFPU() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000319#define FPU_REG_INFO32(n) FPURegisters::Name(n), FPURegisters::Name(n+1), \
320 GetFPURegisterValue32(n+1), \
321 GetFPURegisterValue32(n), \
322 GetFPURegisterValueDouble(n)
323
324#define FPU_REG_INFO64(n) FPURegisters::Name(n), \
325 GetFPURegisterValue64(n), \
326 GetFPURegisterValueDouble(n)
Steve Block44f0eee2011-05-26 01:26:41 +0100327
328 PrintAllRegs();
329
330 PrintF("\n\n");
Ben Murdoch257744e2011-11-30 15:57:28 +0000331 // f0, f1, f2, ... f31.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000332 // This must be a compile-time switch,
333 // compiler will throw out warnings otherwise.
334 if (kFpuMode == kFP64) {
335 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(0) );
336 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(1) );
337 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(2) );
338 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(3) );
339 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(4) );
340 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(5) );
341 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(6) );
342 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(7) );
343 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(8) );
344 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(9) );
345 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(10));
346 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(11));
347 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(12));
348 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(13));
349 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(14));
350 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(15));
351 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(16));
352 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(17));
353 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(18));
354 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(19));
355 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(20));
356 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(21));
357 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(22));
358 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(23));
359 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(24));
360 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(25));
361 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(26));
362 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(27));
363 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(28));
364 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(29));
365 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(30));
366 PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(31));
367 } else {
368 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(0) );
369 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(2) );
370 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(4) );
371 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(6) );
372 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(8) );
373 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(10));
374 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(12));
375 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(14));
376 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(16));
377 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(18));
378 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(20));
379 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(22));
380 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(24));
381 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(26));
382 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(28));
383 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(30));
384 }
Steve Block44f0eee2011-05-26 01:26:41 +0100385
386#undef REG_INFO
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000387#undef FPU_REG_INFO32
388#undef FPU_REG_INFO64
Steve Block44f0eee2011-05-26 01:26:41 +0100389}
390
391
392void MipsDebugger::Debug() {
Andrei Popescu31002712010-02-23 13:46:05 +0000393 intptr_t last_pc = -1;
394 bool done = false;
395
396#define COMMAND_SIZE 63
397#define ARG_SIZE 255
398
399#define STR(a) #a
400#define XSTR(a) STR(a)
401
402 char cmd[COMMAND_SIZE + 1];
403 char arg1[ARG_SIZE + 1];
404 char arg2[ARG_SIZE + 1];
Steve Block44f0eee2011-05-26 01:26:41 +0100405 char* argv[3] = { cmd, arg1, arg2 };
Andrei Popescu31002712010-02-23 13:46:05 +0000406
Ben Murdoch257744e2011-11-30 15:57:28 +0000407 // Make sure to have a proper terminating character if reaching the limit.
Andrei Popescu31002712010-02-23 13:46:05 +0000408 cmd[COMMAND_SIZE] = 0;
409 arg1[ARG_SIZE] = 0;
410 arg2[ARG_SIZE] = 0;
411
412 // Undo all set breakpoints while running in the debugger shell. This will
413 // make them invisible to all commands.
414 UndoBreakpoints();
415
416 while (!done && (sim_->get_pc() != Simulator::end_sim_pc)) {
417 if (last_pc != sim_->get_pc()) {
418 disasm::NameConverter converter;
419 disasm::Disassembler dasm(converter);
Ben Murdoch257744e2011-11-30 15:57:28 +0000420 // Use a reasonably large buffer.
Andrei Popescu31002712010-02-23 13:46:05 +0000421 v8::internal::EmbeddedVector<char, 256> buffer;
422 dasm.InstructionDecode(buffer,
Ben Murdoch257744e2011-11-30 15:57:28 +0000423 reinterpret_cast<byte*>(sim_->get_pc()));
Andrei Popescu31002712010-02-23 13:46:05 +0000424 PrintF(" 0x%08x %s\n", sim_->get_pc(), buffer.start());
425 last_pc = sim_->get_pc();
426 }
427 char* line = ReadLine("sim> ");
428 if (line == NULL) {
429 break;
430 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100431 char* last_input = sim_->last_debugger_input();
432 if (strcmp(line, "\n") == 0 && last_input != NULL) {
433 line = last_input;
434 } else {
435 // Ownership is transferred to sim_;
436 sim_->set_last_debugger_input(line);
437 }
Andrei Popescu31002712010-02-23 13:46:05 +0000438 // Use sscanf to parse the individual parts of the command line. At the
439 // moment no command expects more than two parameters.
Steve Block44f0eee2011-05-26 01:26:41 +0100440 int argc = SScanF(line,
Andrei Popescu31002712010-02-23 13:46:05 +0000441 "%" XSTR(COMMAND_SIZE) "s "
442 "%" XSTR(ARG_SIZE) "s "
443 "%" XSTR(ARG_SIZE) "s",
444 cmd, arg1, arg2);
445 if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
Steve Block44f0eee2011-05-26 01:26:41 +0100446 Instruction* instr = reinterpret_cast<Instruction*>(sim_->get_pc());
447 if (!(instr->IsTrap()) ||
448 instr->InstructionBits() == rtCallRedirInstr) {
Andrei Popescu31002712010-02-23 13:46:05 +0000449 sim_->InstructionDecode(
Steve Block44f0eee2011-05-26 01:26:41 +0100450 reinterpret_cast<Instruction*>(sim_->get_pc()));
Andrei Popescu31002712010-02-23 13:46:05 +0000451 } else {
452 // Allow si to jump over generated breakpoints.
453 PrintF("/!\\ Jumping over generated breakpoint.\n");
Steve Block44f0eee2011-05-26 01:26:41 +0100454 sim_->set_pc(sim_->get_pc() + Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +0000455 }
456 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) {
457 // Execute the one instruction we broke at with breakpoints disabled.
458 sim_->InstructionDecode(reinterpret_cast<Instruction*>(sim_->get_pc()));
459 // Leave the debugger shell.
460 done = true;
461 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
Steve Block44f0eee2011-05-26 01:26:41 +0100462 if (argc == 2) {
Andrei Popescu31002712010-02-23 13:46:05 +0000463 if (strcmp(arg1, "all") == 0) {
464 PrintAllRegs();
Steve Block44f0eee2011-05-26 01:26:41 +0100465 } else if (strcmp(arg1, "allf") == 0) {
466 PrintAllRegsIncludingFPU();
Andrei Popescu31002712010-02-23 13:46:05 +0000467 } else {
Steve Block44f0eee2011-05-26 01:26:41 +0100468 int regnum = Registers::Number(arg1);
469 int fpuregnum = FPURegisters::Number(arg1);
470
471 if (regnum != kInvalidRegister) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000472 int32_t value;
Steve Block44f0eee2011-05-26 01:26:41 +0100473 value = GetRegisterValue(regnum);
Andrei Popescu31002712010-02-23 13:46:05 +0000474 PrintF("%s: 0x%08x %d \n", arg1, value, value);
Steve Block44f0eee2011-05-26 01:26:41 +0100475 } else if (fpuregnum != kInvalidFPURegister) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000476 if (IsFp64Mode()) {
477 int64_t value;
478 double dvalue;
479 value = GetFPURegisterValue64(fpuregnum);
480 dvalue = GetFPURegisterValueDouble(fpuregnum);
481 PrintF("%3s: 0x%016llx %16.4e\n",
482 FPURegisters::Name(fpuregnum), value, dvalue);
Steve Block44f0eee2011-05-26 01:26:41 +0100483 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000484 if (fpuregnum % 2 == 1) {
485 int32_t value;
486 float fvalue;
487 value = GetFPURegisterValue32(fpuregnum);
488 fvalue = GetFPURegisterValueFloat(fpuregnum);
489 PrintF("%s: 0x%08x %11.4e\n", arg1, value, fvalue);
490 } else {
491 double dfvalue;
492 int32_t lvalue1 = GetFPURegisterValue32(fpuregnum);
493 int32_t lvalue2 = GetFPURegisterValue32(fpuregnum + 1);
494 dfvalue = GetFPURegisterValueDouble(fpuregnum);
495 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n",
496 FPURegisters::Name(fpuregnum+1),
497 FPURegisters::Name(fpuregnum),
498 lvalue1,
499 lvalue2,
500 dfvalue);
501 }
Steve Block44f0eee2011-05-26 01:26:41 +0100502 }
Andrei Popescu31002712010-02-23 13:46:05 +0000503 } else {
504 PrintF("%s unrecognized\n", arg1);
505 }
506 }
507 } else {
Steve Block44f0eee2011-05-26 01:26:41 +0100508 if (argc == 3) {
509 if (strcmp(arg2, "single") == 0) {
510 int32_t value;
511 float fvalue;
512 int fpuregnum = FPURegisters::Number(arg1);
513
514 if (fpuregnum != kInvalidFPURegister) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000515 value = GetFPURegisterValue32(fpuregnum);
Steve Block44f0eee2011-05-26 01:26:41 +0100516 fvalue = GetFPURegisterValueFloat(fpuregnum);
517 PrintF("%s: 0x%08x %11.4e\n", arg1, value, fvalue);
518 } else {
519 PrintF("%s unrecognized\n", arg1);
520 }
521 } else {
522 PrintF("print <fpu register> single\n");
523 }
524 } else {
525 PrintF("print <register> or print <fpu register> single\n");
526 }
Andrei Popescu31002712010-02-23 13:46:05 +0000527 }
528 } else if ((strcmp(cmd, "po") == 0)
529 || (strcmp(cmd, "printobject") == 0)) {
Steve Block44f0eee2011-05-26 01:26:41 +0100530 if (argc == 2) {
Andrei Popescu31002712010-02-23 13:46:05 +0000531 int32_t value;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000532 OFStream os(stdout);
Andrei Popescu31002712010-02-23 13:46:05 +0000533 if (GetValue(arg1, &value)) {
534 Object* obj = reinterpret_cast<Object*>(value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000535 os << arg1 << ": \n";
Andrei Popescu31002712010-02-23 13:46:05 +0000536#ifdef DEBUG
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000537 obj->Print(os);
538 os << "\n";
Andrei Popescu31002712010-02-23 13:46:05 +0000539#else
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000540 os << Brief(obj) << "\n";
Andrei Popescu31002712010-02-23 13:46:05 +0000541#endif
542 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000543 os << arg1 << " unrecognized\n";
Andrei Popescu31002712010-02-23 13:46:05 +0000544 }
545 } else {
546 PrintF("printobject <value>\n");
547 }
Steve Block44f0eee2011-05-26 01:26:41 +0100548 } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0) {
549 int32_t* cur = NULL;
550 int32_t* end = NULL;
551 int next_arg = 1;
552
553 if (strcmp(cmd, "stack") == 0) {
554 cur = reinterpret_cast<int32_t*>(sim_->get_register(Simulator::sp));
Ben Murdoch257744e2011-11-30 15:57:28 +0000555 } else { // Command "mem".
Steve Block44f0eee2011-05-26 01:26:41 +0100556 int32_t value;
557 if (!GetValue(arg1, &value)) {
558 PrintF("%s unrecognized\n", arg1);
559 continue;
560 }
561 cur = reinterpret_cast<int32_t*>(value);
562 next_arg++;
563 }
564
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000565 // TODO(palfia): optimize this.
566 if (IsFp64Mode()) {
567 int64_t words;
568 if (argc == next_arg) {
Steve Block44f0eee2011-05-26 01:26:41 +0100569 words = 10;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000570 } else {
571 if (!GetValue(argv[next_arg], &words)) {
572 words = 10;
573 }
Steve Block44f0eee2011-05-26 01:26:41 +0100574 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000575 end = cur + words;
576 } else {
577 int32_t words;
578 if (argc == next_arg) {
579 words = 10;
580 } else {
581 if (!GetValue(argv[next_arg], &words)) {
582 words = 10;
583 }
584 }
585 end = cur + words;
Steve Block44f0eee2011-05-26 01:26:41 +0100586 }
Steve Block44f0eee2011-05-26 01:26:41 +0100587
588 while (cur < end) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000589 PrintF(" 0x%08x: 0x%08x %10d",
Steve Block44f0eee2011-05-26 01:26:41 +0100590 reinterpret_cast<intptr_t>(cur), *cur, *cur);
Ben Murdoch257744e2011-11-30 15:57:28 +0000591 HeapObject* obj = reinterpret_cast<HeapObject*>(*cur);
592 int value = *cur;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000593 Heap* current_heap = sim_->isolate_->heap();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100594 if (((value & 1) == 0) ||
595 current_heap->ContainsSlow(obj->address())) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000596 PrintF(" (");
597 if ((value & 1) == 0) {
598 PrintF("smi %d", value / 2);
599 } else {
600 obj->ShortPrint();
601 }
602 PrintF(")");
603 }
604 PrintF("\n");
Steve Block44f0eee2011-05-26 01:26:41 +0100605 cur++;
606 }
607
Ben Murdoch257744e2011-11-30 15:57:28 +0000608 } else if ((strcmp(cmd, "disasm") == 0) ||
609 (strcmp(cmd, "dpc") == 0) ||
610 (strcmp(cmd, "di") == 0)) {
Andrei Popescu31002712010-02-23 13:46:05 +0000611 disasm::NameConverter converter;
612 disasm::Disassembler dasm(converter);
Ben Murdoch257744e2011-11-30 15:57:28 +0000613 // Use a reasonably large buffer.
Andrei Popescu31002712010-02-23 13:46:05 +0000614 v8::internal::EmbeddedVector<char, 256> buffer;
615
Ben Murdoch257744e2011-11-30 15:57:28 +0000616 byte* cur = NULL;
617 byte* end = NULL;
Andrei Popescu31002712010-02-23 13:46:05 +0000618
Steve Block44f0eee2011-05-26 01:26:41 +0100619 if (argc == 1) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000620 cur = reinterpret_cast<byte*>(sim_->get_pc());
Steve Block44f0eee2011-05-26 01:26:41 +0100621 end = cur + (10 * Instruction::kInstrSize);
622 } else if (argc == 2) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000623 int regnum = Registers::Number(arg1);
624 if (regnum != kInvalidRegister || strncmp(arg1, "0x", 2) == 0) {
625 // The argument is an address or a register name.
626 int32_t value;
627 if (GetValue(arg1, &value)) {
628 cur = reinterpret_cast<byte*>(value);
629 // Disassemble 10 instructions at <arg1>.
630 end = cur + (10 * Instruction::kInstrSize);
631 }
632 } else {
633 // The argument is the number of instructions.
634 int32_t value;
635 if (GetValue(arg1, &value)) {
636 cur = reinterpret_cast<byte*>(sim_->get_pc());
637 // Disassemble <arg1> instructions.
638 end = cur + (value * Instruction::kInstrSize);
639 }
Andrei Popescu31002712010-02-23 13:46:05 +0000640 }
641 } else {
642 int32_t value1;
643 int32_t value2;
644 if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000645 cur = reinterpret_cast<byte*>(value1);
Steve Block44f0eee2011-05-26 01:26:41 +0100646 end = cur + (value2 * Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +0000647 }
648 }
649
650 while (cur < end) {
651 dasm.InstructionDecode(buffer, cur);
Steve Block44f0eee2011-05-26 01:26:41 +0100652 PrintF(" 0x%08x %s\n",
653 reinterpret_cast<intptr_t>(cur), buffer.start());
654 cur += Instruction::kInstrSize;
Andrei Popescu31002712010-02-23 13:46:05 +0000655 }
656 } else if (strcmp(cmd, "gdb") == 0) {
657 PrintF("relinquishing control to gdb\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000658 v8::base::OS::DebugBreak();
Andrei Popescu31002712010-02-23 13:46:05 +0000659 PrintF("regaining control from gdb\n");
660 } else if (strcmp(cmd, "break") == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +0100661 if (argc == 2) {
Andrei Popescu31002712010-02-23 13:46:05 +0000662 int32_t value;
663 if (GetValue(arg1, &value)) {
664 if (!SetBreakpoint(reinterpret_cast<Instruction*>(value))) {
665 PrintF("setting breakpoint failed\n");
666 }
667 } else {
668 PrintF("%s unrecognized\n", arg1);
669 }
670 } else {
671 PrintF("break <address>\n");
672 }
673 } else if (strcmp(cmd, "del") == 0) {
674 if (!DeleteBreakpoint(NULL)) {
675 PrintF("deleting breakpoint failed\n");
676 }
677 } else if (strcmp(cmd, "flags") == 0) {
678 PrintF("No flags on MIPS !\n");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000679 } else if (strcmp(cmd, "stop") == 0) {
680 int32_t value;
681 intptr_t stop_pc = sim_->get_pc() -
682 2 * Instruction::kInstrSize;
683 Instruction* stop_instr = reinterpret_cast<Instruction*>(stop_pc);
684 Instruction* msg_address =
685 reinterpret_cast<Instruction*>(stop_pc +
686 Instruction::kInstrSize);
687 if ((argc == 2) && (strcmp(arg1, "unstop") == 0)) {
688 // Remove the current stop.
689 if (sim_->IsStopInstruction(stop_instr)) {
690 stop_instr->SetInstructionBits(kNopInstr);
691 msg_address->SetInstructionBits(kNopInstr);
692 } else {
693 PrintF("Not at debugger stop.\n");
694 }
695 } else if (argc == 3) {
696 // Print information about all/the specified breakpoint(s).
697 if (strcmp(arg1, "info") == 0) {
698 if (strcmp(arg2, "all") == 0) {
699 PrintF("Stop information:\n");
700 for (uint32_t i = kMaxWatchpointCode + 1;
701 i <= kMaxStopCode;
702 i++) {
703 sim_->PrintStopInfo(i);
704 }
705 } else if (GetValue(arg2, &value)) {
706 sim_->PrintStopInfo(value);
707 } else {
708 PrintF("Unrecognized argument.\n");
709 }
710 } else if (strcmp(arg1, "enable") == 0) {
711 // Enable all/the specified breakpoint(s).
712 if (strcmp(arg2, "all") == 0) {
713 for (uint32_t i = kMaxWatchpointCode + 1;
714 i <= kMaxStopCode;
715 i++) {
716 sim_->EnableStop(i);
717 }
718 } else if (GetValue(arg2, &value)) {
719 sim_->EnableStop(value);
720 } else {
721 PrintF("Unrecognized argument.\n");
722 }
723 } else if (strcmp(arg1, "disable") == 0) {
724 // Disable all/the specified breakpoint(s).
725 if (strcmp(arg2, "all") == 0) {
726 for (uint32_t i = kMaxWatchpointCode + 1;
727 i <= kMaxStopCode;
728 i++) {
729 sim_->DisableStop(i);
730 }
731 } else if (GetValue(arg2, &value)) {
732 sim_->DisableStop(value);
733 } else {
734 PrintF("Unrecognized argument.\n");
735 }
736 }
737 } else {
738 PrintF("Wrong usage. Use help command for more information.\n");
739 }
Andrei Popescu31002712010-02-23 13:46:05 +0000740 } else if ((strcmp(cmd, "stat") == 0) || (strcmp(cmd, "st") == 0)) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000741 // Print registers and disassemble.
Andrei Popescu31002712010-02-23 13:46:05 +0000742 PrintAllRegs();
743 PrintF("\n");
744
745 disasm::NameConverter converter;
746 disasm::Disassembler dasm(converter);
Ben Murdoch257744e2011-11-30 15:57:28 +0000747 // Use a reasonably large buffer.
Andrei Popescu31002712010-02-23 13:46:05 +0000748 v8::internal::EmbeddedVector<char, 256> buffer;
749
Ben Murdoch257744e2011-11-30 15:57:28 +0000750 byte* cur = NULL;
751 byte* end = NULL;
Andrei Popescu31002712010-02-23 13:46:05 +0000752
Steve Block44f0eee2011-05-26 01:26:41 +0100753 if (argc == 1) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000754 cur = reinterpret_cast<byte*>(sim_->get_pc());
Steve Block44f0eee2011-05-26 01:26:41 +0100755 end = cur + (10 * Instruction::kInstrSize);
756 } else if (argc == 2) {
Andrei Popescu31002712010-02-23 13:46:05 +0000757 int32_t value;
758 if (GetValue(arg1, &value)) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000759 cur = reinterpret_cast<byte*>(value);
Andrei Popescu31002712010-02-23 13:46:05 +0000760 // no length parameter passed, assume 10 instructions
Steve Block44f0eee2011-05-26 01:26:41 +0100761 end = cur + (10 * Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +0000762 }
763 } else {
764 int32_t value1;
765 int32_t value2;
766 if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000767 cur = reinterpret_cast<byte*>(value1);
Steve Block44f0eee2011-05-26 01:26:41 +0100768 end = cur + (value2 * Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +0000769 }
770 }
771
772 while (cur < end) {
773 dasm.InstructionDecode(buffer, cur);
Steve Block44f0eee2011-05-26 01:26:41 +0100774 PrintF(" 0x%08x %s\n",
775 reinterpret_cast<intptr_t>(cur), buffer.start());
776 cur += Instruction::kInstrSize;
Andrei Popescu31002712010-02-23 13:46:05 +0000777 }
778 } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
779 PrintF("cont\n");
780 PrintF(" continue execution (alias 'c')\n");
781 PrintF("stepi\n");
782 PrintF(" step one instruction (alias 'si')\n");
783 PrintF("print <register>\n");
784 PrintF(" print register content (alias 'p')\n");
785 PrintF(" use register name 'all' to print all registers\n");
786 PrintF("printobject <register>\n");
787 PrintF(" print an object from a register (alias 'po')\n");
Steve Block44f0eee2011-05-26 01:26:41 +0100788 PrintF("stack [<words>]\n");
789 PrintF(" dump stack content, default dump 10 words)\n");
790 PrintF("mem <address> [<words>]\n");
791 PrintF(" dump memory content, default dump 10 words)\n");
Andrei Popescu31002712010-02-23 13:46:05 +0000792 PrintF("flags\n");
793 PrintF(" print flags\n");
794 PrintF("disasm [<instructions>]\n");
Ben Murdoch257744e2011-11-30 15:57:28 +0000795 PrintF("disasm [<address/register>]\n");
796 PrintF("disasm [[<address/register>] <instructions>]\n");
797 PrintF(" disassemble code, default is 10 instructions\n");
798 PrintF(" from pc (alias 'di')\n");
Andrei Popescu31002712010-02-23 13:46:05 +0000799 PrintF("gdb\n");
800 PrintF(" enter gdb\n");
801 PrintF("break <address>\n");
802 PrintF(" set a break point on the address\n");
803 PrintF("del\n");
804 PrintF(" delete the breakpoint\n");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000805 PrintF("stop feature:\n");
806 PrintF(" Description:\n");
807 PrintF(" Stops are debug instructions inserted by\n");
808 PrintF(" the Assembler::stop() function.\n");
809 PrintF(" When hitting a stop, the Simulator will\n");
810 PrintF(" stop and and give control to the Debugger.\n");
811 PrintF(" All stop codes are watched:\n");
812 PrintF(" - They can be enabled / disabled: the Simulator\n");
813 PrintF(" will / won't stop when hitting them.\n");
814 PrintF(" - The Simulator keeps track of how many times they \n");
815 PrintF(" are met. (See the info command.) Going over a\n");
816 PrintF(" disabled stop still increases its counter. \n");
817 PrintF(" Commands:\n");
818 PrintF(" stop info all/<code> : print infos about number <code>\n");
819 PrintF(" or all stop(s).\n");
820 PrintF(" stop enable/disable all/<code> : enables / disables\n");
821 PrintF(" all or number <code> stop(s)\n");
822 PrintF(" stop unstop\n");
823 PrintF(" ignore the stop instruction at the current location\n");
824 PrintF(" from now on\n");
Andrei Popescu31002712010-02-23 13:46:05 +0000825 } else {
826 PrintF("Unknown command: %s\n", cmd);
827 }
828 }
Andrei Popescu31002712010-02-23 13:46:05 +0000829 }
830
831 // Add all the breakpoints back to stop execution and enter the debugger
832 // shell when hit.
833 RedoBreakpoints();
834
835#undef COMMAND_SIZE
836#undef ARG_SIZE
837
838#undef STR
839#undef XSTR
840}
841
842
Steve Block44f0eee2011-05-26 01:26:41 +0100843static bool ICacheMatch(void* one, void* two) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000844 DCHECK((reinterpret_cast<intptr_t>(one) & CachePage::kPageMask) == 0);
845 DCHECK((reinterpret_cast<intptr_t>(two) & CachePage::kPageMask) == 0);
Steve Block44f0eee2011-05-26 01:26:41 +0100846 return one == two;
847}
Andrei Popescu31002712010-02-23 13:46:05 +0000848
849
Steve Block44f0eee2011-05-26 01:26:41 +0100850static uint32_t ICacheHash(void* key) {
851 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)) >> 2;
852}
853
854
855static bool AllOnOnePage(uintptr_t start, int size) {
856 intptr_t start_page = (start & ~CachePage::kPageMask);
857 intptr_t end_page = ((start + size) & ~CachePage::kPageMask);
858 return start_page == end_page;
859}
860
861
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100862void Simulator::set_last_debugger_input(char* input) {
863 DeleteArray(last_debugger_input_);
864 last_debugger_input_ = input;
865}
866
867
Steve Block44f0eee2011-05-26 01:26:41 +0100868void Simulator::FlushICache(v8::internal::HashMap* i_cache,
869 void* start_addr,
870 size_t size) {
871 intptr_t start = reinterpret_cast<intptr_t>(start_addr);
872 int intra_line = (start & CachePage::kLineMask);
873 start -= intra_line;
874 size += intra_line;
875 size = ((size - 1) | CachePage::kLineMask) + 1;
876 int offset = (start & CachePage::kPageMask);
877 while (!AllOnOnePage(start, size - 1)) {
878 int bytes_to_flush = CachePage::kPageSize - offset;
879 FlushOnePage(i_cache, start, bytes_to_flush);
880 start += bytes_to_flush;
881 size -= bytes_to_flush;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000882 DCHECK_EQ(0, start & CachePage::kPageMask);
Steve Block44f0eee2011-05-26 01:26:41 +0100883 offset = 0;
884 }
885 if (size != 0) {
886 FlushOnePage(i_cache, start, size);
887 }
888}
889
890
891CachePage* Simulator::GetCachePage(v8::internal::HashMap* i_cache, void* page) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000892 v8::internal::HashMap::Entry* entry =
893 i_cache->LookupOrInsert(page, ICacheHash(page));
Steve Block44f0eee2011-05-26 01:26:41 +0100894 if (entry->value == NULL) {
895 CachePage* new_page = new CachePage();
896 entry->value = new_page;
897 }
898 return reinterpret_cast<CachePage*>(entry->value);
899}
900
901
902// Flush from start up to and not including start + size.
903void Simulator::FlushOnePage(v8::internal::HashMap* i_cache,
904 intptr_t start,
905 int size) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000906 DCHECK(size <= CachePage::kPageSize);
907 DCHECK(AllOnOnePage(start, size - 1));
908 DCHECK((start & CachePage::kLineMask) == 0);
909 DCHECK((size & CachePage::kLineMask) == 0);
Steve Block44f0eee2011-05-26 01:26:41 +0100910 void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask));
911 int offset = (start & CachePage::kPageMask);
912 CachePage* cache_page = GetCachePage(i_cache, page);
913 char* valid_bytemap = cache_page->ValidityByte(offset);
914 memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift);
915}
916
917
918void Simulator::CheckICache(v8::internal::HashMap* i_cache,
919 Instruction* instr) {
920 intptr_t address = reinterpret_cast<intptr_t>(instr);
921 void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
922 void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask));
923 int offset = (address & CachePage::kPageMask);
924 CachePage* cache_page = GetCachePage(i_cache, page);
925 char* cache_valid_byte = cache_page->ValidityByte(offset);
926 bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID);
927 char* cached_line = cache_page->CachedData(offset & ~CachePage::kLineMask);
928 if (cache_hit) {
929 // Check that the data in memory matches the contents of the I-cache.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000930 CHECK_EQ(0, memcmp(reinterpret_cast<void*>(instr),
931 cache_page->CachedData(offset),
932 Instruction::kInstrSize));
Steve Block44f0eee2011-05-26 01:26:41 +0100933 } else {
934 // Cache miss. Load memory into the cache.
935 memcpy(cached_line, line, CachePage::kLineLength);
936 *cache_valid_byte = CachePage::LINE_VALID;
937 }
938}
Andrei Popescu31002712010-02-23 13:46:05 +0000939
940
Ben Murdoch257744e2011-11-30 15:57:28 +0000941void Simulator::Initialize(Isolate* isolate) {
942 if (isolate->simulator_initialized()) return;
943 isolate->set_simulator_initialized(true);
944 ::v8::internal::ExternalReference::set_redirector(isolate,
945 &RedirectExternalReference);
Andrei Popescu31002712010-02-23 13:46:05 +0000946}
947
948
Ben Murdoch257744e2011-11-30 15:57:28 +0000949Simulator::Simulator(Isolate* isolate) : isolate_(isolate) {
Steve Block44f0eee2011-05-26 01:26:41 +0100950 i_cache_ = isolate_->simulator_i_cache();
951 if (i_cache_ == NULL) {
952 i_cache_ = new v8::internal::HashMap(&ICacheMatch);
953 isolate_->set_simulator_i_cache(i_cache_);
954 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000955 Initialize(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100956 // Set up simulator support first. Some of this information is needed to
Andrei Popescu31002712010-02-23 13:46:05 +0000957 // setup the architecture state.
Steve Block44f0eee2011-05-26 01:26:41 +0100958 stack_ = reinterpret_cast<char*>(malloc(stack_size_));
Andrei Popescu31002712010-02-23 13:46:05 +0000959 pc_modified_ = false;
960 icount_ = 0;
Steve Block44f0eee2011-05-26 01:26:41 +0100961 break_count_ = 0;
Andrei Popescu31002712010-02-23 13:46:05 +0000962 break_pc_ = NULL;
963 break_instr_ = 0;
964
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100965 // Set up architecture state.
Andrei Popescu31002712010-02-23 13:46:05 +0000966 // All registers are initialized to zero to start with.
967 for (int i = 0; i < kNumSimuRegisters; i++) {
968 registers_[i] = 0;
969 }
Steve Block44f0eee2011-05-26 01:26:41 +0100970 for (int i = 0; i < kNumFPURegisters; i++) {
971 FPUregisters_[i] = 0;
972 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000973 if (IsMipsArchVariant(kMips32r6)) {
974 FCSR_ = kFCSRNaN2008FlagMask;
975 } else {
976 DCHECK(IsMipsArchVariant(kMips32r1) || IsMipsArchVariant(kMips32r2));
977 FCSR_ = 0;
978 }
Andrei Popescu31002712010-02-23 13:46:05 +0000979
980 // The sp is initialized to point to the bottom (high address) of the
981 // allocated stack area. To be safe in potential stack underflows we leave
982 // some buffer below.
Steve Block44f0eee2011-05-26 01:26:41 +0100983 registers_[sp] = reinterpret_cast<int32_t>(stack_) + stack_size_ - 64;
Andrei Popescu31002712010-02-23 13:46:05 +0000984 // The ra and pc are initialized to a known bad value that will cause an
985 // access violation if the simulator ever tries to execute it.
986 registers_[pc] = bad_ra;
987 registers_[ra] = bad_ra;
988 InitializeCoverage();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100989 last_debugger_input_ = NULL;
Andrei Popescu31002712010-02-23 13:46:05 +0000990}
991
992
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000993Simulator::~Simulator() { free(stack_); }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000994
995
Andrei Popescu31002712010-02-23 13:46:05 +0000996// When the generated code calls an external reference we need to catch that in
997// the simulator. The external reference will be a function compiled for the
998// host architecture. We need to call that function instead of trying to
999// execute it with the simulator. We do that by redirecting the external
1000// reference to a swi (software-interrupt) instruction that is handled by
1001// the simulator. We write the original destination of the jump just at a known
1002// offset from the swi instruction so the simulator knows what to call.
1003class Redirection {
1004 public:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001005 Redirection(Isolate* isolate, void* external_function,
1006 ExternalReference::Type type)
Andrei Popescu31002712010-02-23 13:46:05 +00001007 : external_function_(external_function),
1008 swi_instruction_(rtCallRedirInstr),
Steve Block44f0eee2011-05-26 01:26:41 +01001009 type_(type),
1010 next_(NULL) {
Steve Block44f0eee2011-05-26 01:26:41 +01001011 next_ = isolate->simulator_redirection();
1012 Simulator::current(isolate)->
1013 FlushICache(isolate->simulator_i_cache(),
1014 reinterpret_cast<void*>(&swi_instruction_),
1015 Instruction::kInstrSize);
1016 isolate->set_simulator_redirection(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001017 }
1018
1019 void* address_of_swi_instruction() {
1020 return reinterpret_cast<void*>(&swi_instruction_);
1021 }
1022
1023 void* external_function() { return external_function_; }
Steve Block44f0eee2011-05-26 01:26:41 +01001024 ExternalReference::Type type() { return type_; }
Andrei Popescu31002712010-02-23 13:46:05 +00001025
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001026 static Redirection* Get(Isolate* isolate, void* external_function,
Steve Block44f0eee2011-05-26 01:26:41 +01001027 ExternalReference::Type type) {
Steve Block44f0eee2011-05-26 01:26:41 +01001028 Redirection* current = isolate->simulator_redirection();
1029 for (; current != NULL; current = current->next_) {
Andrei Popescu31002712010-02-23 13:46:05 +00001030 if (current->external_function_ == external_function) return current;
1031 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001032 return new Redirection(isolate, external_function, type);
Andrei Popescu31002712010-02-23 13:46:05 +00001033 }
1034
1035 static Redirection* FromSwiInstruction(Instruction* swi_instruction) {
1036 char* addr_of_swi = reinterpret_cast<char*>(swi_instruction);
1037 char* addr_of_redirection =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001038 addr_of_swi - offsetof(Redirection, swi_instruction_);
Andrei Popescu31002712010-02-23 13:46:05 +00001039 return reinterpret_cast<Redirection*>(addr_of_redirection);
1040 }
1041
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001042 static void* ReverseRedirection(int32_t reg) {
1043 Redirection* redirection = FromSwiInstruction(
1044 reinterpret_cast<Instruction*>(reinterpret_cast<void*>(reg)));
1045 return redirection->external_function();
1046 }
1047
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001048 static void DeleteChain(Redirection* redirection) {
1049 while (redirection != nullptr) {
1050 Redirection* next = redirection->next_;
1051 delete redirection;
1052 redirection = next;
1053 }
1054 }
1055
Andrei Popescu31002712010-02-23 13:46:05 +00001056 private:
1057 void* external_function_;
1058 uint32_t swi_instruction_;
Steve Block44f0eee2011-05-26 01:26:41 +01001059 ExternalReference::Type type_;
Andrei Popescu31002712010-02-23 13:46:05 +00001060 Redirection* next_;
Andrei Popescu31002712010-02-23 13:46:05 +00001061};
1062
1063
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001064// static
1065void Simulator::TearDown(HashMap* i_cache, Redirection* first) {
1066 Redirection::DeleteChain(first);
1067 if (i_cache != nullptr) {
1068 for (HashMap::Entry* entry = i_cache->Start(); entry != nullptr;
1069 entry = i_cache->Next(entry)) {
1070 delete static_cast<CachePage*>(entry->value);
1071 }
1072 delete i_cache;
1073 }
1074}
1075
1076
1077void* Simulator::RedirectExternalReference(Isolate* isolate,
1078 void* external_function,
Steve Block44f0eee2011-05-26 01:26:41 +01001079 ExternalReference::Type type) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001080 Redirection* redirection = Redirection::Get(isolate, external_function, type);
Andrei Popescu31002712010-02-23 13:46:05 +00001081 return redirection->address_of_swi_instruction();
1082}
1083
1084
1085// Get the active Simulator for the current thread.
Steve Block44f0eee2011-05-26 01:26:41 +01001086Simulator* Simulator::current(Isolate* isolate) {
1087 v8::internal::Isolate::PerIsolateThreadData* isolate_data =
Ben Murdoch257744e2011-11-30 15:57:28 +00001088 isolate->FindOrAllocatePerThreadDataForThisThread();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001089 DCHECK(isolate_data != NULL);
1090 DCHECK(isolate_data != NULL);
Steve Block44f0eee2011-05-26 01:26:41 +01001091
1092 Simulator* sim = isolate_data->simulator();
Andrei Popescu31002712010-02-23 13:46:05 +00001093 if (sim == NULL) {
Steve Block44f0eee2011-05-26 01:26:41 +01001094 // TODO(146): delete the simulator object when a thread/isolate goes away.
Ben Murdoch257744e2011-11-30 15:57:28 +00001095 sim = new Simulator(isolate);
Steve Block44f0eee2011-05-26 01:26:41 +01001096 isolate_data->set_simulator(sim);
Andrei Popescu31002712010-02-23 13:46:05 +00001097 }
1098 return sim;
1099}
1100
1101
1102// Sets the register in the architecture state. It will also deal with updating
1103// Simulator internal state for special registers such as PC.
1104void Simulator::set_register(int reg, int32_t value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001105 DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
Andrei Popescu31002712010-02-23 13:46:05 +00001106 if (reg == pc) {
1107 pc_modified_ = true;
1108 }
1109
Ben Murdoch257744e2011-11-30 15:57:28 +00001110 // Zero register always holds 0.
Andrei Popescu31002712010-02-23 13:46:05 +00001111 registers_[reg] = (reg == 0) ? 0 : value;
1112}
1113
Steve Block44f0eee2011-05-26 01:26:41 +01001114
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001115void Simulator::set_dw_register(int reg, const int* dbl) {
1116 DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
1117 registers_[reg] = dbl[0];
1118 registers_[reg + 1] = dbl[1];
1119}
1120
1121
1122void Simulator::set_fpu_register(int fpureg, int64_t value) {
1123 DCHECK(IsFp64Mode());
1124 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
Andrei Popescu31002712010-02-23 13:46:05 +00001125 FPUregisters_[fpureg] = value;
1126}
1127
Steve Block44f0eee2011-05-26 01:26:41 +01001128
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001129void Simulator::set_fpu_register_word(int fpureg, int32_t value) {
1130 // Set ONLY lower 32-bits, leaving upper bits untouched.
1131 // TODO(plind): big endian issue.
1132 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1133 int32_t *pword = reinterpret_cast<int32_t*>(&FPUregisters_[fpureg]);
1134 *pword = value;
1135}
1136
1137
1138void Simulator::set_fpu_register_hi_word(int fpureg, int32_t value) {
1139 // Set ONLY upper 32-bits, leaving lower bits untouched.
1140 // TODO(plind): big endian issue.
1141 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1142 int32_t *phiword = (reinterpret_cast<int32_t*>(&FPUregisters_[fpureg])) + 1;
1143 *phiword = value;
1144}
1145
1146
Steve Block44f0eee2011-05-26 01:26:41 +01001147void Simulator::set_fpu_register_float(int fpureg, float value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001148 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1149 *bit_cast<float*>(&FPUregisters_[fpureg]) = value;
Steve Block44f0eee2011-05-26 01:26:41 +01001150}
1151
1152
Andrei Popescu31002712010-02-23 13:46:05 +00001153void Simulator::set_fpu_register_double(int fpureg, double value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001154 if (IsFp64Mode()) {
1155 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1156 *bit_cast<double*>(&FPUregisters_[fpureg]) = value;
1157 } else {
1158 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
1159 int64_t i64 = bit_cast<int64_t>(value);
1160 set_fpu_register_word(fpureg, i64 & 0xffffffff);
1161 set_fpu_register_word(fpureg + 1, i64 >> 32);
1162 }
Andrei Popescu31002712010-02-23 13:46:05 +00001163}
1164
1165
1166// Get the register from the architecture state. This function does handle
1167// the special case of accessing the PC register.
1168int32_t Simulator::get_register(int reg) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001169 DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
Andrei Popescu31002712010-02-23 13:46:05 +00001170 if (reg == 0)
1171 return 0;
1172 else
1173 return registers_[reg] + ((reg == pc) ? Instruction::kPCReadOffset : 0);
1174}
1175
Steve Block44f0eee2011-05-26 01:26:41 +01001176
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001177double Simulator::get_double_from_register_pair(int reg) {
1178 // TODO(plind): bad ABI stuff, refactor or remove.
1179 DCHECK((reg >= 0) && (reg < kNumSimuRegisters) && ((reg % 2) == 0));
1180
1181 double dm_val = 0.0;
1182 // Read the bits from the unsigned integer register_[] array
1183 // into the double precision floating point value and return it.
1184 char buffer[2 * sizeof(registers_[0])];
1185 memcpy(buffer, &registers_[reg], 2 * sizeof(registers_[0]));
1186 memcpy(&dm_val, buffer, 2 * sizeof(registers_[0]));
1187 return(dm_val);
1188}
1189
1190
1191int64_t Simulator::get_fpu_register(int fpureg) const {
1192 DCHECK(IsFp64Mode());
1193 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
Andrei Popescu31002712010-02-23 13:46:05 +00001194 return FPUregisters_[fpureg];
1195}
1196
Steve Block44f0eee2011-05-26 01:26:41 +01001197
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001198int32_t Simulator::get_fpu_register_word(int fpureg) const {
1199 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1200 return static_cast<int32_t>(FPUregisters_[fpureg] & 0xffffffff);
1201}
1202
1203
1204int32_t Simulator::get_fpu_register_signed_word(int fpureg) const {
1205 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1206 return static_cast<int32_t>(FPUregisters_[fpureg] & 0xffffffff);
1207}
1208
1209
1210int32_t Simulator::get_fpu_register_hi_word(int fpureg) const {
1211 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1212 return static_cast<int32_t>((FPUregisters_[fpureg] >> 32) & 0xffffffff);
Steve Block44f0eee2011-05-26 01:26:41 +01001213}
1214
1215
1216float Simulator::get_fpu_register_float(int fpureg) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001217 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1218 return *bit_cast<float*>(const_cast<int64_t*>(&FPUregisters_[fpureg]));
Steve Block44f0eee2011-05-26 01:26:41 +01001219}
1220
1221
Andrei Popescu31002712010-02-23 13:46:05 +00001222double Simulator::get_fpu_register_double(int fpureg) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001223 if (IsFp64Mode()) {
1224 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1225 return *bit_cast<double*>(&FPUregisters_[fpureg]);
1226 } else {
1227 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
1228 int64_t i64;
1229 i64 = static_cast<uint32_t>(get_fpu_register_word(fpureg));
1230 i64 |= static_cast<uint64_t>(get_fpu_register_word(fpureg + 1)) << 32;
1231 return bit_cast<double>(i64);
1232 }
Andrei Popescu31002712010-02-23 13:46:05 +00001233}
1234
Steve Block44f0eee2011-05-26 01:26:41 +01001235
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001236// Runtime FP routines take up to two double arguments and zero
1237// or one integer arguments. All are constructed here,
Ben Murdoch257744e2011-11-30 15:57:28 +00001238// from a0-a3 or f12 and f14.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001239void Simulator::GetFpArgs(double* x, double* y, int32_t* z) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001240 if (!IsMipsSoftFloatABI) {
1241 *x = get_fpu_register_double(12);
1242 *y = get_fpu_register_double(14);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001243 *z = get_register(a2);
Ben Murdoch257744e2011-11-30 15:57:28 +00001244 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001245 // TODO(plind): bad ABI stuff, refactor or remove.
Ben Murdoch257744e2011-11-30 15:57:28 +00001246 // We use a char buffer to get around the strict-aliasing rules which
1247 // otherwise allow the compiler to optimize away the copy.
1248 char buffer[sizeof(*x)];
1249 int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
1250
1251 // Registers a0 and a1 -> x.
1252 reg_buffer[0] = get_register(a0);
1253 reg_buffer[1] = get_register(a1);
1254 memcpy(x, buffer, sizeof(buffer));
Ben Murdoch257744e2011-11-30 15:57:28 +00001255 // Registers a2 and a3 -> y.
1256 reg_buffer[0] = get_register(a2);
1257 reg_buffer[1] = get_register(a3);
1258 memcpy(y, buffer, sizeof(buffer));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001259 // Register 2 -> z.
Ben Murdoch257744e2011-11-30 15:57:28 +00001260 reg_buffer[0] = get_register(a2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001261 memcpy(z, buffer, sizeof(*z));
Ben Murdoch257744e2011-11-30 15:57:28 +00001262 }
1263}
1264
1265
1266// The return value is either in v0/v1 or f0.
1267void Simulator::SetFpResult(const double& result) {
1268 if (!IsMipsSoftFloatABI) {
1269 set_fpu_register_double(0, result);
1270 } else {
1271 char buffer[2 * sizeof(registers_[0])];
1272 int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
1273 memcpy(buffer, &result, sizeof(buffer));
1274 // Copy result to v0 and v1.
1275 set_register(v0, reg_buffer[0]);
1276 set_register(v1, reg_buffer[1]);
1277 }
1278}
1279
1280
Steve Block44f0eee2011-05-26 01:26:41 +01001281// Helper functions for setting and testing the FCSR register's bits.
1282void Simulator::set_fcsr_bit(uint32_t cc, bool value) {
1283 if (value) {
1284 FCSR_ |= (1 << cc);
1285 } else {
1286 FCSR_ &= ~(1 << cc);
1287 }
1288}
1289
1290
1291bool Simulator::test_fcsr_bit(uint32_t cc) {
1292 return FCSR_ & (1 << cc);
1293}
1294
1295
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001296void Simulator::set_fcsr_rounding_mode(FPURoundingMode mode) {
1297 FCSR_ |= mode & kFPURoundingModeMask;
1298}
1299
1300
1301unsigned int Simulator::get_fcsr_rounding_mode() {
1302 return FCSR_ & kFPURoundingModeMask;
1303}
1304
1305
1306void Simulator::set_fpu_register_word_invalid_result(float original,
1307 float rounded) {
1308 if (FCSR_ & kFCSRNaN2008FlagMask) {
1309 double max_int32 = std::numeric_limits<int32_t>::max();
1310 double min_int32 = std::numeric_limits<int32_t>::min();
1311 if (std::isnan(original)) {
1312 set_fpu_register_word(fd_reg(), 0);
1313 } else if (rounded > max_int32) {
1314 set_fpu_register_word(fd_reg(), kFPUInvalidResult);
1315 } else if (rounded < min_int32) {
1316 set_fpu_register_word(fd_reg(), kFPUInvalidResultNegative);
1317 } else {
1318 UNREACHABLE();
1319 }
1320 } else {
1321 set_fpu_register_word(fd_reg(), kFPUInvalidResult);
1322 }
1323}
1324
1325
1326void Simulator::set_fpu_register_invalid_result(float original, float rounded) {
1327 if (FCSR_ & kFCSRNaN2008FlagMask) {
1328 double max_int32 = std::numeric_limits<int32_t>::max();
1329 double min_int32 = std::numeric_limits<int32_t>::min();
1330 if (std::isnan(original)) {
1331 set_fpu_register(fd_reg(), 0);
1332 } else if (rounded > max_int32) {
1333 set_fpu_register(fd_reg(), kFPUInvalidResult);
1334 } else if (rounded < min_int32) {
1335 set_fpu_register(fd_reg(), kFPUInvalidResultNegative);
1336 } else {
1337 UNREACHABLE();
1338 }
1339 } else {
1340 set_fpu_register(fd_reg(), kFPUInvalidResult);
1341 }
1342}
1343
1344
1345void Simulator::set_fpu_register_invalid_result64(float original,
1346 float rounded) {
1347 if (FCSR_ & kFCSRNaN2008FlagMask) {
1348 // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1349 // loading the most accurate representation into max_int64, which is 2^63.
1350 double max_int64 = std::numeric_limits<int64_t>::max();
1351 double min_int64 = std::numeric_limits<int64_t>::min();
1352 if (std::isnan(original)) {
1353 set_fpu_register(fd_reg(), 0);
1354 } else if (rounded >= max_int64) {
1355 set_fpu_register(fd_reg(), kFPU64InvalidResult);
1356 } else if (rounded < min_int64) {
1357 set_fpu_register(fd_reg(), kFPU64InvalidResultNegative);
1358 } else {
1359 UNREACHABLE();
1360 }
1361 } else {
1362 set_fpu_register(fd_reg(), kFPU64InvalidResult);
1363 }
1364}
1365
1366
1367void Simulator::set_fpu_register_word_invalid_result(double original,
1368 double rounded) {
1369 if (FCSR_ & kFCSRNaN2008FlagMask) {
1370 double max_int32 = std::numeric_limits<int32_t>::max();
1371 double min_int32 = std::numeric_limits<int32_t>::min();
1372 if (std::isnan(original)) {
1373 set_fpu_register_word(fd_reg(), 0);
1374 } else if (rounded > max_int32) {
1375 set_fpu_register_word(fd_reg(), kFPUInvalidResult);
1376 } else if (rounded < min_int32) {
1377 set_fpu_register_word(fd_reg(), kFPUInvalidResultNegative);
1378 } else {
1379 UNREACHABLE();
1380 }
1381 } else {
1382 set_fpu_register_word(fd_reg(), kFPUInvalidResult);
1383 }
1384}
1385
1386
1387void Simulator::set_fpu_register_invalid_result(double original,
1388 double rounded) {
1389 if (FCSR_ & kFCSRNaN2008FlagMask) {
1390 double max_int32 = std::numeric_limits<int32_t>::max();
1391 double min_int32 = std::numeric_limits<int32_t>::min();
1392 if (std::isnan(original)) {
1393 set_fpu_register(fd_reg(), 0);
1394 } else if (rounded > max_int32) {
1395 set_fpu_register(fd_reg(), kFPUInvalidResult);
1396 } else if (rounded < min_int32) {
1397 set_fpu_register(fd_reg(), kFPUInvalidResultNegative);
1398 } else {
1399 UNREACHABLE();
1400 }
1401 } else {
1402 set_fpu_register(fd_reg(), kFPUInvalidResult);
1403 }
1404}
1405
1406
1407void Simulator::set_fpu_register_invalid_result64(double original,
1408 double rounded) {
1409 if (FCSR_ & kFCSRNaN2008FlagMask) {
1410 // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1411 // loading the most accurate representation into max_int64, which is 2^63.
1412 double max_int64 = std::numeric_limits<int64_t>::max();
1413 double min_int64 = std::numeric_limits<int64_t>::min();
1414 if (std::isnan(original)) {
1415 set_fpu_register(fd_reg(), 0);
1416 } else if (rounded >= max_int64) {
1417 set_fpu_register(fd_reg(), kFPU64InvalidResult);
1418 } else if (rounded < min_int64) {
1419 set_fpu_register(fd_reg(), kFPU64InvalidResultNegative);
1420 } else {
1421 UNREACHABLE();
1422 }
1423 } else {
1424 set_fpu_register(fd_reg(), kFPU64InvalidResult);
1425 }
1426}
1427
1428
Steve Block44f0eee2011-05-26 01:26:41 +01001429// Sets the rounding error codes in FCSR based on the result of the rounding.
1430// Returns true if the operation was invalid.
1431bool Simulator::set_fcsr_round_error(double original, double rounded) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001432 bool ret = false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001433 double max_int32 = std::numeric_limits<int32_t>::max();
1434 double min_int32 = std::numeric_limits<int32_t>::min();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001435
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001436 if (!std::isfinite(original) || !std::isfinite(rounded)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001437 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1438 ret = true;
Steve Block44f0eee2011-05-26 01:26:41 +01001439 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001440
1441 if (original != rounded) {
1442 set_fcsr_bit(kFCSRInexactFlagBit, true);
1443 }
1444
1445 if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) {
1446 set_fcsr_bit(kFCSRUnderflowFlagBit, true);
1447 ret = true;
1448 }
1449
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001450 if (rounded > max_int32 || rounded < min_int32) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001451 set_fcsr_bit(kFCSROverflowFlagBit, true);
1452 // The reference is not really clear but it seems this is required:
1453 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1454 ret = true;
1455 }
1456
1457 return ret;
Steve Block44f0eee2011-05-26 01:26:41 +01001458}
1459
1460
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001461// Sets the rounding error codes in FCSR based on the result of the rounding.
1462// Returns true if the operation was invalid.
1463bool Simulator::set_fcsr_round64_error(double original, double rounded) {
1464 bool ret = false;
1465 // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1466 // loading the most accurate representation into max_int64, which is 2^63.
1467 double max_int64 = std::numeric_limits<int64_t>::max();
1468 double min_int64 = std::numeric_limits<int64_t>::min();
1469
1470 if (!std::isfinite(original) || !std::isfinite(rounded)) {
1471 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1472 ret = true;
1473 }
1474
1475 if (original != rounded) {
1476 set_fcsr_bit(kFCSRInexactFlagBit, true);
1477 }
1478
1479 if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) {
1480 set_fcsr_bit(kFCSRUnderflowFlagBit, true);
1481 ret = true;
1482 }
1483
1484 if (rounded >= max_int64 || rounded < min_int64) {
1485 set_fcsr_bit(kFCSROverflowFlagBit, true);
1486 // The reference is not really clear but it seems this is required:
1487 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1488 ret = true;
1489 }
1490
1491 return ret;
1492}
1493
1494
1495// Sets the rounding error codes in FCSR based on the result of the rounding.
1496// Returns true if the operation was invalid.
1497bool Simulator::set_fcsr_round_error(float original, float rounded) {
1498 bool ret = false;
1499 double max_int32 = std::numeric_limits<int32_t>::max();
1500 double min_int32 = std::numeric_limits<int32_t>::min();
1501
1502 if (!std::isfinite(original) || !std::isfinite(rounded)) {
1503 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1504 ret = true;
1505 }
1506
1507 if (original != rounded) {
1508 set_fcsr_bit(kFCSRInexactFlagBit, true);
1509 }
1510
1511 if (rounded < FLT_MIN && rounded > -FLT_MIN && rounded != 0) {
1512 set_fcsr_bit(kFCSRUnderflowFlagBit, true);
1513 ret = true;
1514 }
1515
1516 if (rounded > max_int32 || rounded < min_int32) {
1517 set_fcsr_bit(kFCSROverflowFlagBit, true);
1518 // The reference is not really clear but it seems this is required:
1519 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1520 ret = true;
1521 }
1522
1523 return ret;
1524}
1525
1526
1527// Sets the rounding error codes in FCSR based on the result of the rounding.
1528// Returns true if the operation was invalid.
1529bool Simulator::set_fcsr_round64_error(float original, float rounded) {
1530 bool ret = false;
1531 // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1532 // loading the most accurate representation into max_int64, which is 2^63.
1533 double max_int64 = std::numeric_limits<int64_t>::max();
1534 double min_int64 = std::numeric_limits<int64_t>::min();
1535
1536 if (!std::isfinite(original) || !std::isfinite(rounded)) {
1537 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1538 ret = true;
1539 }
1540
1541 if (original != rounded) {
1542 set_fcsr_bit(kFCSRInexactFlagBit, true);
1543 }
1544
1545 if (rounded < FLT_MIN && rounded > -FLT_MIN && rounded != 0) {
1546 set_fcsr_bit(kFCSRUnderflowFlagBit, true);
1547 ret = true;
1548 }
1549
1550 if (rounded >= max_int64 || rounded < min_int64) {
1551 set_fcsr_bit(kFCSROverflowFlagBit, true);
1552 // The reference is not really clear but it seems this is required:
1553 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1554 ret = true;
1555 }
1556
1557 return ret;
1558}
1559
1560
1561void Simulator::round_according_to_fcsr(double toRound, double& rounded,
1562 int32_t& rounded_int, double fs) {
1563 // 0 RN (round to nearest): Round a result to the nearest
1564 // representable value; if the result is exactly halfway between
1565 // two representable values, round to zero. Behave like round_w_d.
1566
1567 // 1 RZ (round toward zero): Round a result to the closest
1568 // representable value whose absolute value is less than or
1569 // equal to the infinitely accurate result. Behave like trunc_w_d.
1570
1571 // 2 RP (round up, or toward infinity): Round a result to the
1572 // next representable value up. Behave like ceil_w_d.
1573
1574 // 3 RD (round down, or toward −infinity): Round a result to
1575 // the next representable value down. Behave like floor_w_d.
1576 switch (get_fcsr_rounding_mode()) {
1577 case kRoundToNearest:
1578 rounded = std::floor(fs + 0.5);
1579 rounded_int = static_cast<int32_t>(rounded);
1580 if ((rounded_int & 1) != 0 && rounded_int - fs == 0.5) {
1581 // If the number is halfway between two integers,
1582 // round to the even one.
1583 rounded_int--;
1584 }
1585 break;
1586 case kRoundToZero:
1587 rounded = trunc(fs);
1588 rounded_int = static_cast<int32_t>(rounded);
1589 break;
1590 case kRoundToPlusInf:
1591 rounded = std::ceil(fs);
1592 rounded_int = static_cast<int32_t>(rounded);
1593 break;
1594 case kRoundToMinusInf:
1595 rounded = std::floor(fs);
1596 rounded_int = static_cast<int32_t>(rounded);
1597 break;
1598 }
1599}
1600
1601
1602void Simulator::round_according_to_fcsr(float toRound, float& rounded,
1603 int32_t& rounded_int, float fs) {
1604 // 0 RN (round to nearest): Round a result to the nearest
1605 // representable value; if the result is exactly halfway between
1606 // two representable values, round to zero. Behave like round_w_d.
1607
1608 // 1 RZ (round toward zero): Round a result to the closest
1609 // representable value whose absolute value is less than or
1610 // equal to the infinitely accurate result. Behave like trunc_w_d.
1611
1612 // 2 RP (round up, or toward infinity): Round a result to the
1613 // next representable value up. Behave like ceil_w_d.
1614
1615 // 3 RD (round down, or toward −infinity): Round a result to
1616 // the next representable value down. Behave like floor_w_d.
1617 switch (get_fcsr_rounding_mode()) {
1618 case kRoundToNearest:
1619 rounded = std::floor(fs + 0.5);
1620 rounded_int = static_cast<int32_t>(rounded);
1621 if ((rounded_int & 1) != 0 && rounded_int - fs == 0.5) {
1622 // If the number is halfway between two integers,
1623 // round to the even one.
1624 rounded_int--;
1625 }
1626 break;
1627 case kRoundToZero:
1628 rounded = trunc(fs);
1629 rounded_int = static_cast<int32_t>(rounded);
1630 break;
1631 case kRoundToPlusInf:
1632 rounded = std::ceil(fs);
1633 rounded_int = static_cast<int32_t>(rounded);
1634 break;
1635 case kRoundToMinusInf:
1636 rounded = std::floor(fs);
1637 rounded_int = static_cast<int32_t>(rounded);
1638 break;
1639 }
1640}
1641
1642
1643void Simulator::round64_according_to_fcsr(double toRound, double& rounded,
1644 int64_t& rounded_int, double fs) {
1645 // 0 RN (round to nearest): Round a result to the nearest
1646 // representable value; if the result is exactly halfway between
1647 // two representable values, round to zero. Behave like round_w_d.
1648
1649 // 1 RZ (round toward zero): Round a result to the closest
1650 // representable value whose absolute value is less than or.
1651 // equal to the infinitely accurate result. Behave like trunc_w_d.
1652
1653 // 2 RP (round up, or toward +infinity): Round a result to the
1654 // next representable value up. Behave like ceil_w_d.
1655
1656 // 3 RN (round down, or toward −infinity): Round a result to
1657 // the next representable value down. Behave like floor_w_d.
1658 switch (FCSR_ & 3) {
1659 case kRoundToNearest:
1660 rounded = std::floor(fs + 0.5);
1661 rounded_int = static_cast<int64_t>(rounded);
1662 if ((rounded_int & 1) != 0 && rounded_int - fs == 0.5) {
1663 // If the number is halfway between two integers,
1664 // round to the even one.
1665 rounded_int--;
1666 }
1667 break;
1668 case kRoundToZero:
1669 rounded = trunc(fs);
1670 rounded_int = static_cast<int64_t>(rounded);
1671 break;
1672 case kRoundToPlusInf:
1673 rounded = std::ceil(fs);
1674 rounded_int = static_cast<int64_t>(rounded);
1675 break;
1676 case kRoundToMinusInf:
1677 rounded = std::floor(fs);
1678 rounded_int = static_cast<int64_t>(rounded);
1679 break;
1680 }
1681}
1682
1683
1684void Simulator::round64_according_to_fcsr(float toRound, float& rounded,
1685 int64_t& rounded_int, float fs) {
1686 // 0 RN (round to nearest): Round a result to the nearest
1687 // representable value; if the result is exactly halfway between
1688 // two representable values, round to zero. Behave like round_w_d.
1689
1690 // 1 RZ (round toward zero): Round a result to the closest
1691 // representable value whose absolute value is less than or.
1692 // equal to the infinitely accurate result. Behave like trunc_w_d.
1693
1694 // 2 RP (round up, or toward +infinity): Round a result to the
1695 // next representable value up. Behave like ceil_w_d.
1696
1697 // 3 RN (round down, or toward −infinity): Round a result to
1698 // the next representable value down. Behave like floor_w_d.
1699 switch (FCSR_ & 3) {
1700 case kRoundToNearest:
1701 rounded = std::floor(fs + 0.5);
1702 rounded_int = static_cast<int64_t>(rounded);
1703 if ((rounded_int & 1) != 0 && rounded_int - fs == 0.5) {
1704 // If the number is halfway between two integers,
1705 // round to the even one.
1706 rounded_int--;
1707 }
1708 break;
1709 case kRoundToZero:
1710 rounded = trunc(fs);
1711 rounded_int = static_cast<int64_t>(rounded);
1712 break;
1713 case kRoundToPlusInf:
1714 rounded = std::ceil(fs);
1715 rounded_int = static_cast<int64_t>(rounded);
1716 break;
1717 case kRoundToMinusInf:
1718 rounded = std::floor(fs);
1719 rounded_int = static_cast<int64_t>(rounded);
1720 break;
1721 }
1722}
1723
1724
Andrei Popescu31002712010-02-23 13:46:05 +00001725// Raw access to the PC register.
1726void Simulator::set_pc(int32_t value) {
1727 pc_modified_ = true;
1728 registers_[pc] = value;
1729}
1730
Steve Block44f0eee2011-05-26 01:26:41 +01001731
1732bool Simulator::has_bad_pc() const {
1733 return ((registers_[pc] == bad_ra) || (registers_[pc] == end_sim_pc));
1734}
1735
1736
Andrei Popescu31002712010-02-23 13:46:05 +00001737// Raw access to the PC register without the special adjustment when reading.
1738int32_t Simulator::get_pc() const {
1739 return registers_[pc];
1740}
1741
1742
1743// The MIPS cannot do unaligned reads and writes. On some MIPS platforms an
1744// interrupt is caused. On others it does a funky rotation thing. For now we
1745// simply disallow unaligned reads, but at some point we may want to move to
1746// emulating the rotate behaviour. Note that simulator runs have the runtime
1747// system running directly on the host system and only generated code is
1748// executed in the simulator. Since the host is typically IA32 we will not
1749// get the correct MIPS-like behaviour on unaligned accesses.
1750
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001751void Simulator::TraceRegWr(int32_t value) {
1752 if (::v8::internal::FLAG_trace_sim) {
1753 SNPrintF(trace_buf_, "%08x", value);
1754 }
1755}
1756
1757
1758// TODO(plind): consider making icount_ printing a flag option.
1759void Simulator::TraceMemRd(int32_t addr, int32_t value) {
1760 if (::v8::internal::FLAG_trace_sim) {
1761 SNPrintF(trace_buf_, "%08x <-- [%08x] (%" PRIu64 ")", value, addr,
1762 icount_);
1763 }
1764}
1765
1766
1767void Simulator::TraceMemWr(int32_t addr, int32_t value, TraceType t) {
1768 if (::v8::internal::FLAG_trace_sim) {
1769 switch (t) {
1770 case BYTE:
1771 SNPrintF(trace_buf_, " %02x --> [%08x]",
1772 static_cast<int8_t>(value), addr);
1773 break;
1774 case HALF:
1775 SNPrintF(trace_buf_, " %04x --> [%08x]", static_cast<int16_t>(value),
1776 addr);
1777 break;
1778 case WORD:
1779 SNPrintF(trace_buf_, "%08x --> [%08x]", value, addr);
1780 break;
1781 }
1782 }
1783}
1784
1785
Andrei Popescu31002712010-02-23 13:46:05 +00001786int Simulator::ReadW(int32_t addr, Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +01001787 if (addr >=0 && addr < 0x400) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001788 // This has to be a NULL-dereference, drop into debugger.
Ben Murdoch589d6972011-11-30 16:04:58 +00001789 PrintF("Memory read from bad address: 0x%08x, pc=0x%08x\n",
1790 addr, reinterpret_cast<intptr_t>(instr));
Steve Block44f0eee2011-05-26 01:26:41 +01001791 MipsDebugger dbg(this);
1792 dbg.Debug();
1793 }
1794 if ((addr & kPointerAlignmentMask) == 0) {
Andrei Popescu31002712010-02-23 13:46:05 +00001795 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001796 TraceMemRd(addr, static_cast<int32_t>(*ptr));
Andrei Popescu31002712010-02-23 13:46:05 +00001797 return *ptr;
1798 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001799 PrintF("Unaligned read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1800 addr,
1801 reinterpret_cast<intptr_t>(instr));
Steve Block44f0eee2011-05-26 01:26:41 +01001802 MipsDebugger dbg(this);
1803 dbg.Debug();
Andrei Popescu31002712010-02-23 13:46:05 +00001804 return 0;
1805}
1806
1807
1808void Simulator::WriteW(int32_t addr, int value, Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +01001809 if (addr >= 0 && addr < 0x400) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001810 // This has to be a NULL-dereference, drop into debugger.
Ben Murdoch589d6972011-11-30 16:04:58 +00001811 PrintF("Memory write to bad address: 0x%08x, pc=0x%08x\n",
1812 addr, reinterpret_cast<intptr_t>(instr));
Steve Block44f0eee2011-05-26 01:26:41 +01001813 MipsDebugger dbg(this);
1814 dbg.Debug();
1815 }
1816 if ((addr & kPointerAlignmentMask) == 0) {
Andrei Popescu31002712010-02-23 13:46:05 +00001817 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001818 TraceMemWr(addr, value, WORD);
Andrei Popescu31002712010-02-23 13:46:05 +00001819 *ptr = value;
1820 return;
1821 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001822 PrintF("Unaligned write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1823 addr,
1824 reinterpret_cast<intptr_t>(instr));
Steve Block44f0eee2011-05-26 01:26:41 +01001825 MipsDebugger dbg(this);
1826 dbg.Debug();
Andrei Popescu31002712010-02-23 13:46:05 +00001827}
1828
1829
1830double Simulator::ReadD(int32_t addr, Instruction* instr) {
1831 if ((addr & kDoubleAlignmentMask) == 0) {
1832 double* ptr = reinterpret_cast<double*>(addr);
1833 return *ptr;
1834 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001835 PrintF("Unaligned (double) read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1836 addr,
1837 reinterpret_cast<intptr_t>(instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001838 base::OS::Abort();
Andrei Popescu31002712010-02-23 13:46:05 +00001839 return 0;
1840}
1841
1842
1843void Simulator::WriteD(int32_t addr, double value, Instruction* instr) {
1844 if ((addr & kDoubleAlignmentMask) == 0) {
1845 double* ptr = reinterpret_cast<double*>(addr);
1846 *ptr = value;
1847 return;
1848 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001849 PrintF("Unaligned (double) write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1850 addr,
1851 reinterpret_cast<intptr_t>(instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001852 base::OS::Abort();
Andrei Popescu31002712010-02-23 13:46:05 +00001853}
1854
1855
1856uint16_t Simulator::ReadHU(int32_t addr, Instruction* instr) {
1857 if ((addr & 1) == 0) {
1858 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001859 TraceMemRd(addr, static_cast<int32_t>(*ptr));
Andrei Popescu31002712010-02-23 13:46:05 +00001860 return *ptr;
1861 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001862 PrintF("Unaligned unsigned halfword read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1863 addr,
1864 reinterpret_cast<intptr_t>(instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001865 base::OS::Abort();
Andrei Popescu31002712010-02-23 13:46:05 +00001866 return 0;
1867}
1868
1869
1870int16_t Simulator::ReadH(int32_t addr, Instruction* instr) {
1871 if ((addr & 1) == 0) {
1872 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001873 TraceMemRd(addr, static_cast<int32_t>(*ptr));
Andrei Popescu31002712010-02-23 13:46:05 +00001874 return *ptr;
1875 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001876 PrintF("Unaligned signed halfword read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1877 addr,
1878 reinterpret_cast<intptr_t>(instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001879 base::OS::Abort();
Andrei Popescu31002712010-02-23 13:46:05 +00001880 return 0;
1881}
1882
1883
1884void Simulator::WriteH(int32_t addr, uint16_t value, Instruction* instr) {
1885 if ((addr & 1) == 0) {
1886 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001887 TraceMemWr(addr, value, HALF);
Andrei Popescu31002712010-02-23 13:46:05 +00001888 *ptr = value;
1889 return;
1890 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001891 PrintF("Unaligned unsigned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1892 addr,
1893 reinterpret_cast<intptr_t>(instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001894 base::OS::Abort();
Andrei Popescu31002712010-02-23 13:46:05 +00001895}
1896
1897
1898void Simulator::WriteH(int32_t addr, int16_t value, Instruction* instr) {
1899 if ((addr & 1) == 0) {
1900 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001901 TraceMemWr(addr, value, HALF);
Andrei Popescu31002712010-02-23 13:46:05 +00001902 *ptr = value;
1903 return;
1904 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001905 PrintF("Unaligned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1906 addr,
1907 reinterpret_cast<intptr_t>(instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001908 base::OS::Abort();
Andrei Popescu31002712010-02-23 13:46:05 +00001909}
1910
1911
1912uint32_t Simulator::ReadBU(int32_t addr) {
1913 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001914 TraceMemRd(addr, static_cast<int32_t>(*ptr));
Andrei Popescu31002712010-02-23 13:46:05 +00001915 return *ptr & 0xff;
1916}
1917
1918
1919int32_t Simulator::ReadB(int32_t addr) {
1920 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001921 TraceMemRd(addr, static_cast<int32_t>(*ptr));
Steve Block44f0eee2011-05-26 01:26:41 +01001922 return *ptr;
Andrei Popescu31002712010-02-23 13:46:05 +00001923}
1924
1925
1926void Simulator::WriteB(int32_t addr, uint8_t value) {
1927 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001928 TraceMemWr(addr, value, BYTE);
Andrei Popescu31002712010-02-23 13:46:05 +00001929 *ptr = value;
1930}
1931
1932
1933void Simulator::WriteB(int32_t addr, int8_t value) {
1934 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001935 TraceMemWr(addr, value, BYTE);
Andrei Popescu31002712010-02-23 13:46:05 +00001936 *ptr = value;
1937}
1938
1939
1940// Returns the limit of the stack area to enable checking for stack overflows.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001941uintptr_t Simulator::StackLimit(uintptr_t c_limit) const {
1942 // The simulator uses a separate JS stack. If we have exhausted the C stack,
1943 // we also drop down the JS limit to reflect the exhaustion on the JS stack.
1944 if (GetCurrentStackPosition() < c_limit) {
1945 return reinterpret_cast<uintptr_t>(get_sp());
1946 }
1947
1948 // Otherwise the limit is the JS stack. Leave a safety margin of 1024 bytes
1949 // to prevent overrunning the stack when pushing values.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001950 return reinterpret_cast<uintptr_t>(stack_) + 1024;
Andrei Popescu31002712010-02-23 13:46:05 +00001951}
1952
1953
1954// Unsupported instructions use Format to print an error and stop execution.
1955void Simulator::Format(Instruction* instr, const char* format) {
1956 PrintF("Simulator found unsupported instruction:\n 0x%08x: %s\n",
Steve Block44f0eee2011-05-26 01:26:41 +01001957 reinterpret_cast<intptr_t>(instr), format);
Andrei Popescu31002712010-02-23 13:46:05 +00001958 UNIMPLEMENTED_MIPS();
1959}
1960
1961
1962// Calls into the V8 runtime are based on this very simple interface.
1963// Note: To be able to return two values from some calls the code in runtime.cc
1964// uses the ObjectPair which is essentially two 32-bit values stuffed into a
1965// 64-bit value. With the code below we assume that all runtime calls return
Steve Block44f0eee2011-05-26 01:26:41 +01001966// 64 bits of result. If they don't, the v1 result register contains a bogus
Andrei Popescu31002712010-02-23 13:46:05 +00001967// value, which is fine because it is caller-saved.
1968typedef int64_t (*SimulatorRuntimeCall)(int32_t arg0,
1969 int32_t arg1,
1970 int32_t arg2,
Steve Block44f0eee2011-05-26 01:26:41 +01001971 int32_t arg3,
1972 int32_t arg4,
1973 int32_t arg5);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001974
Ben Murdoch097c5b22016-05-18 11:27:45 +01001975typedef ObjectTriple (*SimulatorRuntimeTripleCall)(int32_t arg0, int32_t arg1,
1976 int32_t arg2, int32_t arg3,
1977 int32_t arg4);
1978
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001979// These prototypes handle the four types of FP calls.
1980typedef int64_t (*SimulatorRuntimeCompareCall)(double darg0, double darg1);
1981typedef double (*SimulatorRuntimeFPFPCall)(double darg0, double darg1);
1982typedef double (*SimulatorRuntimeFPCall)(double darg0);
1983typedef double (*SimulatorRuntimeFPIntCall)(double darg0, int32_t arg0);
Andrei Popescu31002712010-02-23 13:46:05 +00001984
Ben Murdoch257744e2011-11-30 15:57:28 +00001985// This signature supports direct call in to API function native callback
1986// (refer to InvocationCallback in v8.h).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001987typedef void (*SimulatorRuntimeDirectApiCall)(int32_t arg0);
1988typedef void (*SimulatorRuntimeProfilingApiCall)(int32_t arg0, void* arg1);
Ben Murdoch257744e2011-11-30 15:57:28 +00001989
1990// This signature supports direct call to accessor getter callback.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001991typedef void (*SimulatorRuntimeDirectGetterCall)(int32_t arg0, int32_t arg1);
1992typedef void (*SimulatorRuntimeProfilingGetterCall)(
1993 int32_t arg0, int32_t arg1, void* arg2);
Ben Murdoch257744e2011-11-30 15:57:28 +00001994
Andrei Popescu31002712010-02-23 13:46:05 +00001995// Software interrupt instructions are used by the simulator to call into the
Steve Block44f0eee2011-05-26 01:26:41 +01001996// C-based V8 runtime. They are also used for debugging with simulator.
Andrei Popescu31002712010-02-23 13:46:05 +00001997void Simulator::SoftwareInterrupt(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +01001998 // There are several instructions that could get us here,
1999 // the break_ instruction, or several variants of traps. All
2000 // Are "SPECIAL" class opcode, and are distinuished by function.
2001 int32_t func = instr->FunctionFieldRaw();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002002 uint32_t code = (func == BREAK) ? instr->Bits(25, 6) : -1;
Steve Block44f0eee2011-05-26 01:26:41 +01002003
Andrei Popescu31002712010-02-23 13:46:05 +00002004 // We first check if we met a call_rt_redirected.
2005 if (instr->InstructionBits() == rtCallRedirInstr) {
2006 Redirection* redirection = Redirection::FromSwiInstruction(instr);
2007 int32_t arg0 = get_register(a0);
2008 int32_t arg1 = get_register(a1);
2009 int32_t arg2 = get_register(a2);
2010 int32_t arg3 = get_register(a3);
Steve Block44f0eee2011-05-26 01:26:41 +01002011
Steve Block44f0eee2011-05-26 01:26:41 +01002012 int32_t* stack_pointer = reinterpret_cast<int32_t*>(get_register(sp));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002013 // Args 4 and 5 are on the stack after the reserved space for args 0..3.
2014 int32_t arg4 = stack_pointer[4];
2015 int32_t arg5 = stack_pointer[5];
Ben Murdoch257744e2011-11-30 15:57:28 +00002016
2017 bool fp_call =
2018 (redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) ||
2019 (redirection->type() == ExternalReference::BUILTIN_COMPARE_CALL) ||
2020 (redirection->type() == ExternalReference::BUILTIN_FP_CALL) ||
2021 (redirection->type() == ExternalReference::BUILTIN_FP_INT_CALL);
2022
2023 if (!IsMipsSoftFloatABI) {
2024 // With the hard floating point calling convention, double
2025 // arguments are passed in FPU registers. Fetch the arguments
2026 // from there and call the builtin using soft floating point
2027 // convention.
2028 switch (redirection->type()) {
2029 case ExternalReference::BUILTIN_FP_FP_CALL:
2030 case ExternalReference::BUILTIN_COMPARE_CALL:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002031 if (IsFp64Mode()) {
2032 arg0 = get_fpu_register_word(f12);
2033 arg1 = get_fpu_register_hi_word(f12);
2034 arg2 = get_fpu_register_word(f14);
2035 arg3 = get_fpu_register_hi_word(f14);
2036 } else {
2037 arg0 = get_fpu_register_word(f12);
2038 arg1 = get_fpu_register_word(f13);
2039 arg2 = get_fpu_register_word(f14);
2040 arg3 = get_fpu_register_word(f15);
2041 }
Ben Murdoch257744e2011-11-30 15:57:28 +00002042 break;
2043 case ExternalReference::BUILTIN_FP_CALL:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002044 if (IsFp64Mode()) {
2045 arg0 = get_fpu_register_word(f12);
2046 arg1 = get_fpu_register_hi_word(f12);
2047 } else {
2048 arg0 = get_fpu_register_word(f12);
2049 arg1 = get_fpu_register_word(f13);
2050 }
Ben Murdoch257744e2011-11-30 15:57:28 +00002051 break;
2052 case ExternalReference::BUILTIN_FP_INT_CALL:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002053 if (IsFp64Mode()) {
2054 arg0 = get_fpu_register_word(f12);
2055 arg1 = get_fpu_register_hi_word(f12);
2056 } else {
2057 arg0 = get_fpu_register_word(f12);
2058 arg1 = get_fpu_register_word(f13);
2059 }
Ben Murdoch257744e2011-11-30 15:57:28 +00002060 arg2 = get_register(a2);
2061 break;
2062 default:
2063 break;
2064 }
2065 }
2066
Andrei Popescu31002712010-02-23 13:46:05 +00002067 // This is dodgy but it works because the C entry stubs are never moved.
2068 // See comment in codegen-arm.cc and bug 1242173.
2069 int32_t saved_ra = get_register(ra);
Steve Block44f0eee2011-05-26 01:26:41 +01002070
2071 intptr_t external =
Ben Murdoch257744e2011-11-30 15:57:28 +00002072 reinterpret_cast<intptr_t>(redirection->external_function());
Steve Block44f0eee2011-05-26 01:26:41 +01002073
2074 // Based on CpuFeatures::IsSupported(FPU), Mips will use either hardware
2075 // FPU, or gcc soft-float routines. Hardware FPU is simulated in this
2076 // simulator. Soft-float has additional abstraction of ExternalReference,
Ben Murdoch257744e2011-11-30 15:57:28 +00002077 // to support serialization.
2078 if (fp_call) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002079 double dval0, dval1; // one or two double parameters
2080 int32_t ival; // zero or one integer parameters
2081 int64_t iresult = 0; // integer return value
2082 double dresult = 0; // double return value
2083 GetFpArgs(&dval0, &dval1, &ival);
2084 SimulatorRuntimeCall generic_target =
2085 reinterpret_cast<SimulatorRuntimeCall>(external);
Ben Murdoch257744e2011-11-30 15:57:28 +00002086 if (::v8::internal::FLAG_trace_sim) {
Ben Murdoch257744e2011-11-30 15:57:28 +00002087 switch (redirection->type()) {
2088 case ExternalReference::BUILTIN_FP_FP_CALL:
2089 case ExternalReference::BUILTIN_COMPARE_CALL:
Ben Murdoch257744e2011-11-30 15:57:28 +00002090 PrintF("Call to host function at %p with args %f, %f",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002091 FUNCTION_ADDR(generic_target), dval0, dval1);
Ben Murdoch257744e2011-11-30 15:57:28 +00002092 break;
2093 case ExternalReference::BUILTIN_FP_CALL:
Ben Murdoch257744e2011-11-30 15:57:28 +00002094 PrintF("Call to host function at %p with arg %f",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002095 FUNCTION_ADDR(generic_target), dval0);
Ben Murdoch257744e2011-11-30 15:57:28 +00002096 break;
2097 case ExternalReference::BUILTIN_FP_INT_CALL:
Ben Murdoch257744e2011-11-30 15:57:28 +00002098 PrintF("Call to host function at %p with args %f, %d",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002099 FUNCTION_ADDR(generic_target), dval0, ival);
Ben Murdoch257744e2011-11-30 15:57:28 +00002100 break;
2101 default:
2102 UNREACHABLE();
2103 break;
Steve Block44f0eee2011-05-26 01:26:41 +01002104 }
Andrei Popescu31002712010-02-23 13:46:05 +00002105 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002106 switch (redirection->type()) {
2107 case ExternalReference::BUILTIN_COMPARE_CALL: {
2108 SimulatorRuntimeCompareCall target =
2109 reinterpret_cast<SimulatorRuntimeCompareCall>(external);
2110 iresult = target(dval0, dval1);
2111 set_register(v0, static_cast<int32_t>(iresult));
2112 set_register(v1, static_cast<int32_t>(iresult >> 32));
2113 break;
2114 }
2115 case ExternalReference::BUILTIN_FP_FP_CALL: {
2116 SimulatorRuntimeFPFPCall target =
2117 reinterpret_cast<SimulatorRuntimeFPFPCall>(external);
2118 dresult = target(dval0, dval1);
2119 SetFpResult(dresult);
2120 break;
2121 }
2122 case ExternalReference::BUILTIN_FP_CALL: {
2123 SimulatorRuntimeFPCall target =
2124 reinterpret_cast<SimulatorRuntimeFPCall>(external);
2125 dresult = target(dval0);
2126 SetFpResult(dresult);
2127 break;
2128 }
2129 case ExternalReference::BUILTIN_FP_INT_CALL: {
2130 SimulatorRuntimeFPIntCall target =
2131 reinterpret_cast<SimulatorRuntimeFPIntCall>(external);
2132 dresult = target(dval0, ival);
2133 SetFpResult(dresult);
2134 break;
2135 }
2136 default:
2137 UNREACHABLE();
2138 break;
2139 }
2140 if (::v8::internal::FLAG_trace_sim) {
2141 switch (redirection->type()) {
2142 case ExternalReference::BUILTIN_COMPARE_CALL:
2143 PrintF("Returned %08x\n", static_cast<int32_t>(iresult));
2144 break;
2145 case ExternalReference::BUILTIN_FP_FP_CALL:
2146 case ExternalReference::BUILTIN_FP_CALL:
2147 case ExternalReference::BUILTIN_FP_INT_CALL:
2148 PrintF("Returned %f\n", dresult);
2149 break;
2150 default:
2151 UNREACHABLE();
2152 break;
2153 }
Ben Murdoch257744e2011-11-30 15:57:28 +00002154 }
Steve Block44f0eee2011-05-26 01:26:41 +01002155 } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) {
Ben Murdoch257744e2011-11-30 15:57:28 +00002156 if (::v8::internal::FLAG_trace_sim) {
2157 PrintF("Call to host function at %p args %08x\n",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002158 reinterpret_cast<void*>(external), arg0);
Ben Murdoch257744e2011-11-30 15:57:28 +00002159 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002160 SimulatorRuntimeDirectApiCall target =
2161 reinterpret_cast<SimulatorRuntimeDirectApiCall>(external);
2162 target(arg0);
2163 } else if (
2164 redirection->type() == ExternalReference::PROFILING_API_CALL) {
Ben Murdoch257744e2011-11-30 15:57:28 +00002165 if (::v8::internal::FLAG_trace_sim) {
2166 PrintF("Call to host function at %p args %08x %08x\n",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002167 reinterpret_cast<void*>(external), arg0, arg1);
Ben Murdoch257744e2011-11-30 15:57:28 +00002168 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002169 SimulatorRuntimeProfilingApiCall target =
2170 reinterpret_cast<SimulatorRuntimeProfilingApiCall>(external);
2171 target(arg0, Redirection::ReverseRedirection(arg1));
2172 } else if (
2173 redirection->type() == ExternalReference::DIRECT_GETTER_CALL) {
2174 if (::v8::internal::FLAG_trace_sim) {
2175 PrintF("Call to host function at %p args %08x %08x\n",
2176 reinterpret_cast<void*>(external), arg0, arg1);
2177 }
2178 SimulatorRuntimeDirectGetterCall target =
2179 reinterpret_cast<SimulatorRuntimeDirectGetterCall>(external);
2180 target(arg0, arg1);
2181 } else if (
2182 redirection->type() == ExternalReference::PROFILING_GETTER_CALL) {
2183 if (::v8::internal::FLAG_trace_sim) {
2184 PrintF("Call to host function at %p args %08x %08x %08x\n",
2185 reinterpret_cast<void*>(external), arg0, arg1, arg2);
2186 }
2187 SimulatorRuntimeProfilingGetterCall target =
2188 reinterpret_cast<SimulatorRuntimeProfilingGetterCall>(external);
2189 target(arg0, arg1, Redirection::ReverseRedirection(arg2));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002190 } else if (redirection->type() == ExternalReference::BUILTIN_CALL_TRIPLE) {
2191 // builtin call returning ObjectTriple.
2192 SimulatorRuntimeTripleCall target =
2193 reinterpret_cast<SimulatorRuntimeTripleCall>(external);
2194 if (::v8::internal::FLAG_trace_sim) {
2195 PrintF(
2196 "Call to host triple returning runtime function %p "
2197 "args %08x, %08x, %08x, %08x, %08x\n",
2198 FUNCTION_ADDR(target), arg1, arg2, arg3, arg4, arg5);
2199 }
2200 // arg0 is a hidden argument pointing to the return location, so don't
2201 // pass it to the target function.
2202 ObjectTriple result = target(arg1, arg2, arg3, arg4, arg5);
2203 if (::v8::internal::FLAG_trace_sim) {
2204 PrintF("Returned { %p, %p, %p }\n", result.x, result.y, result.z);
2205 }
2206 // Return is passed back in address pointed to by hidden first argument.
2207 ObjectTriple* sim_result = reinterpret_cast<ObjectTriple*>(arg0);
2208 *sim_result = result;
2209 set_register(v0, arg0);
Andrei Popescu31002712010-02-23 13:46:05 +00002210 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002211 DCHECK(redirection->type() == ExternalReference::BUILTIN_CALL ||
2212 redirection->type() == ExternalReference::BUILTIN_CALL_PAIR);
Andrei Popescu31002712010-02-23 13:46:05 +00002213 SimulatorRuntimeCall target =
Ben Murdoch257744e2011-11-30 15:57:28 +00002214 reinterpret_cast<SimulatorRuntimeCall>(external);
2215 if (::v8::internal::FLAG_trace_sim) {
Andrei Popescu31002712010-02-23 13:46:05 +00002216 PrintF(
Ben Murdoch257744e2011-11-30 15:57:28 +00002217 "Call to host function at %p "
2218 "args %08x, %08x, %08x, %08x, %08x, %08x\n",
Andrei Popescu31002712010-02-23 13:46:05 +00002219 FUNCTION_ADDR(target),
2220 arg0,
2221 arg1,
2222 arg2,
Steve Block44f0eee2011-05-26 01:26:41 +01002223 arg3,
2224 arg4,
2225 arg5);
Andrei Popescu31002712010-02-23 13:46:05 +00002226 }
Steve Block44f0eee2011-05-26 01:26:41 +01002227 int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5);
2228 set_register(v0, static_cast<int32_t>(result));
2229 set_register(v1, static_cast<int32_t>(result >> 32));
2230 }
2231 if (::v8::internal::FLAG_trace_sim) {
2232 PrintF("Returned %08x : %08x\n", get_register(v1), get_register(v0));
Andrei Popescu31002712010-02-23 13:46:05 +00002233 }
2234 set_register(ra, saved_ra);
2235 set_pc(get_register(ra));
Steve Block44f0eee2011-05-26 01:26:41 +01002236
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002237 } else if (func == BREAK && code <= kMaxStopCode) {
2238 if (IsWatchpoint(code)) {
2239 PrintWatchpoint(code);
2240 } else {
2241 IncreaseStopCounter(code);
2242 HandleStop(code, instr);
2243 }
Andrei Popescu31002712010-02-23 13:46:05 +00002244 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01002245 // All remaining break_ codes, and all traps are handled here.
2246 MipsDebugger dbg(this);
Andrei Popescu31002712010-02-23 13:46:05 +00002247 dbg.Debug();
2248 }
2249}
2250
Steve Block44f0eee2011-05-26 01:26:41 +01002251
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002252// Stop helper functions.
2253bool Simulator::IsWatchpoint(uint32_t code) {
2254 return (code <= kMaxWatchpointCode);
2255}
2256
2257
2258void Simulator::PrintWatchpoint(uint32_t code) {
2259 MipsDebugger dbg(this);
2260 ++break_count_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002261 PrintF("\n---- break %d marker: %3d (instr count: %" PRIu64
2262 ") ----------"
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002263 "----------------------------------",
2264 code, break_count_, icount_);
2265 dbg.PrintAllRegs(); // Print registers and continue running.
2266}
2267
2268
2269void Simulator::HandleStop(uint32_t code, Instruction* instr) {
2270 // Stop if it is enabled, otherwise go on jumping over the stop
2271 // and the message address.
2272 if (IsEnabledStop(code)) {
2273 MipsDebugger dbg(this);
2274 dbg.Stop(instr);
2275 } else {
2276 set_pc(get_pc() + 2 * Instruction::kInstrSize);
2277 }
2278}
2279
2280
2281bool Simulator::IsStopInstruction(Instruction* instr) {
2282 int32_t func = instr->FunctionFieldRaw();
2283 uint32_t code = static_cast<uint32_t>(instr->Bits(25, 6));
2284 return (func == BREAK) && code > kMaxWatchpointCode && code <= kMaxStopCode;
2285}
2286
2287
2288bool Simulator::IsEnabledStop(uint32_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002289 DCHECK(code <= kMaxStopCode);
2290 DCHECK(code > kMaxWatchpointCode);
2291 return !(watched_stops_[code].count & kStopDisabledBit);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002292}
2293
2294
2295void Simulator::EnableStop(uint32_t code) {
2296 if (!IsEnabledStop(code)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002297 watched_stops_[code].count &= ~kStopDisabledBit;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002298 }
2299}
2300
2301
2302void Simulator::DisableStop(uint32_t code) {
2303 if (IsEnabledStop(code)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002304 watched_stops_[code].count |= kStopDisabledBit;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002305 }
2306}
2307
2308
2309void Simulator::IncreaseStopCounter(uint32_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002310 DCHECK(code <= kMaxStopCode);
2311 if ((watched_stops_[code].count & ~(1 << 31)) == 0x7fffffff) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002312 PrintF("Stop counter for code %i has overflowed.\n"
2313 "Enabling this code and reseting the counter to 0.\n", code);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002314 watched_stops_[code].count = 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002315 EnableStop(code);
2316 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002317 watched_stops_[code].count++;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002318 }
2319}
2320
2321
2322// Print a stop status.
2323void Simulator::PrintStopInfo(uint32_t code) {
2324 if (code <= kMaxWatchpointCode) {
2325 PrintF("That is a watchpoint, not a stop.\n");
2326 return;
2327 } else if (code > kMaxStopCode) {
2328 PrintF("Code too large, only %u stops can be used\n", kMaxStopCode + 1);
2329 return;
2330 }
2331 const char* state = IsEnabledStop(code) ? "Enabled" : "Disabled";
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002332 int32_t count = watched_stops_[code].count & ~kStopDisabledBit;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002333 // Don't print the state of unused breakpoints.
2334 if (count != 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002335 if (watched_stops_[code].desc) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002336 PrintF("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002337 code, code, state, count, watched_stops_[code].desc);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002338 } else {
2339 PrintF("stop %i - 0x%x: \t%s, \tcounter = %i\n",
2340 code, code, state, count);
2341 }
2342 }
2343}
2344
2345
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002346void Simulator::SignalException(Exception e) {
2347 V8_Fatal(__FILE__, __LINE__, "Error: Exception %i raised.",
2348 static_cast<int>(e));
2349}
2350
Ben Murdoch097c5b22016-05-18 11:27:45 +01002351// Min/Max template functions for Double and Single arguments.
2352
2353template <typename T>
2354static T FPAbs(T a);
2355
2356template <>
2357double FPAbs<double>(double a) {
2358 return fabs(a);
2359}
2360
2361template <>
2362float FPAbs<float>(float a) {
2363 return fabsf(a);
2364}
2365
2366template <typename T>
2367static bool FPUProcessNaNsAndZeros(T a, T b, MaxMinKind kind, T& result) {
2368 if (std::isnan(a) && std::isnan(b)) {
2369 result = a;
2370 } else if (std::isnan(a)) {
2371 result = b;
2372 } else if (std::isnan(b)) {
2373 result = a;
2374 } else if (b == a) {
2375 // Handle -0.0 == 0.0 case.
2376 // std::signbit() returns int 0 or 1 so substracting MaxMinKind::kMax
2377 // negates the result.
2378 result = std::signbit(b) - static_cast<int>(kind) ? b : a;
2379 } else {
2380 return false;
2381 }
2382 return true;
2383}
2384
2385template <typename T>
2386static T FPUMin(T a, T b) {
2387 T result;
2388 if (FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMin, result)) {
2389 return result;
2390 } else {
2391 return b < a ? b : a;
2392 }
2393}
2394
2395template <typename T>
2396static T FPUMax(T a, T b) {
2397 T result;
2398 if (FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMax, result)) {
2399 return result;
2400 } else {
2401 return b > a ? b : a;
2402 }
2403}
2404
2405template <typename T>
2406static T FPUMinA(T a, T b) {
2407 T result;
2408 if (!FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMin, result)) {
2409 if (FPAbs(a) < FPAbs(b)) {
2410 result = a;
2411 } else if (FPAbs(b) < FPAbs(a)) {
2412 result = b;
2413 } else {
2414 result = a < b ? a : b;
2415 }
2416 }
2417 return result;
2418}
2419
2420template <typename T>
2421static T FPUMaxA(T a, T b) {
2422 T result;
2423 if (!FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMin, result)) {
2424 if (FPAbs(a) > FPAbs(b)) {
2425 result = a;
2426 } else if (FPAbs(b) > FPAbs(a)) {
2427 result = b;
2428 } else {
2429 result = a > b ? a : b;
2430 }
2431 }
2432 return result;
2433}
2434
2435// Handle execution based on instruction types.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002436
2437void Simulator::DecodeTypeRegisterDRsType() {
2438 double ft, fs, fd;
2439 uint32_t cc, fcsr_cc;
2440 int64_t i64;
2441 fs = get_fpu_register_double(fs_reg());
2442 ft = (get_instr()->FunctionFieldRaw() != MOVF)
2443 ? get_fpu_register_double(ft_reg())
2444 : 0.0;
2445 fd = get_fpu_register_double(fd_reg());
2446 int64_t ft_int = bit_cast<int64_t>(ft);
2447 int64_t fd_int = bit_cast<int64_t>(fd);
2448 cc = get_instr()->FCccValue();
2449 fcsr_cc = get_fcsr_condition_bit(cc);
2450 switch (get_instr()->FunctionFieldRaw()) {
2451 case RINT: {
2452 DCHECK(IsMipsArchVariant(kMips32r6));
2453 double result, temp, temp_result;
2454 double upper = std::ceil(fs);
2455 double lower = std::floor(fs);
2456 switch (get_fcsr_rounding_mode()) {
2457 case kRoundToNearest:
2458 if (upper - fs < fs - lower) {
2459 result = upper;
2460 } else if (upper - fs > fs - lower) {
2461 result = lower;
2462 } else {
2463 temp_result = upper / 2;
2464 double reminder = modf(temp_result, &temp);
2465 if (reminder == 0) {
2466 result = upper;
2467 } else {
2468 result = lower;
2469 }
2470 }
2471 break;
2472 case kRoundToZero:
2473 result = (fs > 0 ? lower : upper);
2474 break;
2475 case kRoundToPlusInf:
2476 result = upper;
2477 break;
2478 case kRoundToMinusInf:
2479 result = lower;
2480 break;
2481 }
2482 set_fpu_register_double(fd_reg(), result);
2483 if (result != fs) {
2484 set_fcsr_bit(kFCSRInexactFlagBit, true);
2485 }
2486 break;
Andrei Popescu31002712010-02-23 13:46:05 +00002487 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002488 case SEL:
2489 DCHECK(IsMipsArchVariant(kMips32r6));
2490 set_fpu_register_double(fd_reg(), (fd_int & 0x1) == 0 ? fs : ft);
2491 break;
2492 case SELEQZ_C:
2493 DCHECK(IsMipsArchVariant(kMips32r6));
2494 set_fpu_register_double(fd_reg(), (ft_int & 0x1) == 0 ? fs : 0.0);
2495 break;
2496 case SELNEZ_C:
2497 DCHECK(IsMipsArchVariant(kMips32r6));
2498 set_fpu_register_double(fd_reg(), (ft_int & 0x1) != 0 ? fs : 0.0);
2499 break;
2500 case MOVZ_C: {
2501 DCHECK(IsMipsArchVariant(kMips32r2));
2502 if (rt() == 0) {
2503 set_fpu_register_double(fd_reg(), fs);
2504 }
2505 break;
2506 }
2507 case MOVN_C: {
2508 DCHECK(IsMipsArchVariant(kMips32r2));
2509 int32_t rt_reg = get_instr()->RtValue();
2510 int32_t rt = get_register(rt_reg);
2511 if (rt != 0) {
2512 set_fpu_register_double(fd_reg(), fs);
2513 }
2514 break;
2515 }
2516 case MOVF: {
2517 // Same function field for MOVT.D and MOVF.D
2518 uint32_t ft_cc = (ft_reg() >> 2) & 0x7;
2519 ft_cc = get_fcsr_condition_bit(ft_cc);
2520 if (get_instr()->Bit(16)) { // Read Tf bit.
2521 // MOVT.D
2522 if (test_fcsr_bit(ft_cc)) set_fpu_register_double(fd_reg(), fs);
2523 } else {
2524 // MOVF.D
2525 if (!test_fcsr_bit(ft_cc)) set_fpu_register_double(fd_reg(), fs);
2526 }
2527 break;
2528 }
2529 case MIN:
2530 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002531 set_fpu_register_double(fd_reg(), FPUMin(ft, fs));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002532 break;
2533 case MAX:
2534 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002535 set_fpu_register_double(fd_reg(), FPUMax(ft, fs));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002536 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +01002537 case MINA:
2538 DCHECK(IsMipsArchVariant(kMips32r6));
2539 set_fpu_register_double(fd_reg(), FPUMinA(ft, fs));
2540 break;
2541 case MAXA:
2542 DCHECK(IsMipsArchVariant(kMips32r6));
2543 set_fpu_register_double(fd_reg(), FPUMaxA(ft, fs));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002544 break;
2545 case ADD_D:
2546 set_fpu_register_double(fd_reg(), fs + ft);
2547 break;
2548 case SUB_D:
2549 set_fpu_register_double(fd_reg(), fs - ft);
2550 break;
2551 case MUL_D:
2552 set_fpu_register_double(fd_reg(), fs * ft);
2553 break;
2554 case DIV_D:
2555 set_fpu_register_double(fd_reg(), fs / ft);
2556 break;
2557 case ABS_D:
2558 set_fpu_register_double(fd_reg(), fabs(fs));
2559 break;
2560 case MOV_D:
2561 set_fpu_register_double(fd_reg(), fs);
2562 break;
2563 case NEG_D:
2564 set_fpu_register_double(fd_reg(), -fs);
2565 break;
2566 case SQRT_D:
2567 lazily_initialize_fast_sqrt(isolate_);
2568 set_fpu_register_double(fd_reg(), fast_sqrt(fs, isolate_));
2569 break;
2570 case RSQRT_D: {
2571 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2572 lazily_initialize_fast_sqrt(isolate_);
2573 double result = 1.0 / fast_sqrt(fs, isolate_);
2574 set_fpu_register_double(fd_reg(), result);
2575 break;
2576 }
2577 case RECIP_D: {
2578 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2579 double result = 1.0 / fs;
2580 set_fpu_register_double(fd_reg(), result);
2581 break;
2582 }
2583 case C_UN_D:
2584 set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft));
2585 break;
2586 case C_EQ_D:
2587 set_fcsr_bit(fcsr_cc, (fs == ft));
2588 break;
2589 case C_UEQ_D:
2590 set_fcsr_bit(fcsr_cc, (fs == ft) || (std::isnan(fs) || std::isnan(ft)));
2591 break;
2592 case C_OLT_D:
2593 set_fcsr_bit(fcsr_cc, (fs < ft));
2594 break;
2595 case C_ULT_D:
2596 set_fcsr_bit(fcsr_cc, (fs < ft) || (std::isnan(fs) || std::isnan(ft)));
2597 break;
2598 case C_OLE_D:
2599 set_fcsr_bit(fcsr_cc, (fs <= ft));
2600 break;
2601 case C_ULE_D:
2602 set_fcsr_bit(fcsr_cc, (fs <= ft) || (std::isnan(fs) || std::isnan(ft)));
2603 break;
2604 case CVT_W_D: { // Convert double to word.
2605 double rounded;
2606 int32_t result;
2607 round_according_to_fcsr(fs, rounded, result, fs);
2608 set_fpu_register_word(fd_reg(), result);
2609 if (set_fcsr_round_error(fs, rounded)) {
2610 set_fpu_register_word_invalid_result(fs, rounded);
2611 }
2612 } break;
2613 case ROUND_W_D: // Round double to word (round half to even).
2614 {
2615 double rounded = std::floor(fs + 0.5);
2616 int32_t result = static_cast<int32_t>(rounded);
2617 if ((result & 1) != 0 && result - fs == 0.5) {
2618 // If the number is halfway between two integers,
2619 // round to the even one.
2620 result--;
2621 }
2622 set_fpu_register_word(fd_reg(), result);
2623 if (set_fcsr_round_error(fs, rounded)) {
2624 set_fpu_register_word_invalid_result(fs, rounded);
2625 }
2626 } break;
2627 case TRUNC_W_D: // Truncate double to word (round towards 0).
2628 {
2629 double rounded = trunc(fs);
2630 int32_t result = static_cast<int32_t>(rounded);
2631 set_fpu_register_word(fd_reg(), result);
2632 if (set_fcsr_round_error(fs, rounded)) {
2633 set_fpu_register_word_invalid_result(fs, rounded);
2634 }
2635 } break;
2636 case FLOOR_W_D: // Round double to word towards negative infinity.
2637 {
2638 double rounded = std::floor(fs);
2639 int32_t result = static_cast<int32_t>(rounded);
2640 set_fpu_register_word(fd_reg(), result);
2641 if (set_fcsr_round_error(fs, rounded)) {
2642 set_fpu_register_word_invalid_result(fs, rounded);
2643 }
2644 } break;
2645 case CEIL_W_D: // Round double to word towards positive infinity.
2646 {
2647 double rounded = std::ceil(fs);
2648 int32_t result = static_cast<int32_t>(rounded);
2649 set_fpu_register_word(fd_reg(), result);
2650 if (set_fcsr_round_error(fs, rounded)) {
2651 set_fpu_register_word_invalid_result(fs, rounded);
2652 }
2653 } break;
2654 case CVT_S_D: // Convert double to float (single).
2655 set_fpu_register_float(fd_reg(), static_cast<float>(fs));
2656 break;
2657 case CVT_L_D: { // Mips32r2: Truncate double to 64-bit long-word.
2658 if (IsFp64Mode()) {
2659 int64_t result;
2660 double rounded;
2661 round64_according_to_fcsr(fs, rounded, result, fs);
2662 set_fpu_register(fd_reg(), result);
2663 if (set_fcsr_round64_error(fs, rounded)) {
2664 set_fpu_register_invalid_result64(fs, rounded);
2665 }
2666 } else {
2667 UNSUPPORTED();
2668 }
2669 break;
2670 break;
2671 }
2672 case TRUNC_L_D: { // Mips32r2 instruction.
2673 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2674 double rounded = trunc(fs);
2675 i64 = static_cast<int64_t>(rounded);
2676 if (IsFp64Mode()) {
2677 set_fpu_register(fd_reg(), i64);
2678 if (set_fcsr_round64_error(fs, rounded)) {
2679 set_fpu_register_invalid_result64(fs, rounded);
2680 }
2681 } else {
2682 UNSUPPORTED();
2683 }
2684 break;
2685 }
2686 case ROUND_L_D: { // Mips32r2 instruction.
2687 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2688 double rounded = std::floor(fs + 0.5);
2689 int64_t result = static_cast<int64_t>(rounded);
2690 if ((result & 1) != 0 && result - fs == 0.5) {
2691 // If the number is halfway between two integers,
2692 // round to the even one.
2693 result--;
2694 }
2695 int64_t i64 = static_cast<int64_t>(result);
2696 if (IsFp64Mode()) {
2697 set_fpu_register(fd_reg(), i64);
2698 if (set_fcsr_round64_error(fs, rounded)) {
2699 set_fpu_register_invalid_result64(fs, rounded);
2700 }
2701 } else {
2702 UNSUPPORTED();
2703 }
2704 break;
2705 }
2706 case FLOOR_L_D: { // Mips32r2 instruction.
2707 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2708 double rounded = std::floor(fs);
2709 int64_t i64 = static_cast<int64_t>(rounded);
2710 if (IsFp64Mode()) {
2711 set_fpu_register(fd_reg(), i64);
2712 if (set_fcsr_round64_error(fs, rounded)) {
2713 set_fpu_register_invalid_result64(fs, rounded);
2714 }
2715 } else {
2716 UNSUPPORTED();
2717 }
2718 break;
2719 }
2720 case CEIL_L_D: { // Mips32r2 instruction.
2721 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2722 double rounded = std::ceil(fs);
2723 int64_t i64 = static_cast<int64_t>(rounded);
2724 if (IsFp64Mode()) {
2725 set_fpu_register(fd_reg(), i64);
2726 if (set_fcsr_round64_error(fs, rounded)) {
2727 set_fpu_register_invalid_result64(fs, rounded);
2728 }
2729 } else {
2730 UNSUPPORTED();
2731 }
2732 break;
2733 }
2734 case CLASS_D: { // Mips32r6 instruction
2735 // Convert double input to uint64_t for easier bit manipulation
2736 uint64_t classed = bit_cast<uint64_t>(fs);
2737
2738 // Extracting sign, exponent and mantissa from the input double
2739 uint32_t sign = (classed >> 63) & 1;
2740 uint32_t exponent = (classed >> 52) & 0x00000000000007ff;
2741 uint64_t mantissa = classed & 0x000fffffffffffff;
2742 uint64_t result;
2743 double dResult;
2744
2745 // Setting flags if input double is negative infinity,
2746 // positive infinity, negative zero or positive zero
2747 bool negInf = (classed == 0xFFF0000000000000);
2748 bool posInf = (classed == 0x7FF0000000000000);
2749 bool negZero = (classed == 0x8000000000000000);
2750 bool posZero = (classed == 0x0000000000000000);
2751
2752 bool signalingNan;
2753 bool quietNan;
2754 bool negSubnorm;
2755 bool posSubnorm;
2756 bool negNorm;
2757 bool posNorm;
2758
2759 // Setting flags if double is NaN
2760 signalingNan = false;
2761 quietNan = false;
2762 if (!negInf && !posInf && exponent == 0x7ff) {
2763 quietNan = ((mantissa & 0x0008000000000000) != 0) &&
2764 ((mantissa & (0x0008000000000000 - 1)) == 0);
2765 signalingNan = !quietNan;
2766 }
2767
2768 // Setting flags if double is subnormal number
2769 posSubnorm = false;
2770 negSubnorm = false;
2771 if ((exponent == 0) && (mantissa != 0)) {
2772 DCHECK(sign == 0 || sign == 1);
2773 posSubnorm = (sign == 0);
2774 negSubnorm = (sign == 1);
2775 }
2776
2777 // Setting flags if double is normal number
2778 posNorm = false;
2779 negNorm = false;
2780 if (!posSubnorm && !negSubnorm && !posInf && !negInf && !signalingNan &&
2781 !quietNan && !negZero && !posZero) {
2782 DCHECK(sign == 0 || sign == 1);
2783 posNorm = (sign == 0);
2784 negNorm = (sign == 1);
2785 }
2786
2787 // Calculating result according to description of CLASS.D instruction
2788 result = (posZero << 9) | (posSubnorm << 8) | (posNorm << 7) |
2789 (posInf << 6) | (negZero << 5) | (negSubnorm << 4) |
2790 (negNorm << 3) | (negInf << 2) | (quietNan << 1) | signalingNan;
2791
2792 DCHECK(result != 0);
2793
2794 dResult = bit_cast<double>(result);
2795 set_fpu_register_double(fd_reg(), dResult);
2796
2797 break;
2798 }
2799 case C_F_D: {
2800 set_fcsr_bit(fcsr_cc, false);
2801 break;
2802 }
2803 default:
2804 UNREACHABLE();
Andrei Popescu31002712010-02-23 13:46:05 +00002805 }
2806}
2807
Steve Block44f0eee2011-05-26 01:26:41 +01002808
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002809void Simulator::DecodeTypeRegisterWRsType() {
2810 float fs = get_fpu_register_float(fs_reg());
2811 float ft = get_fpu_register_float(ft_reg());
2812 int32_t alu_out = 0x12345678;
2813 switch (get_instr()->FunctionFieldRaw()) {
2814 case CVT_S_W: // Convert word to float (single).
2815 alu_out = get_fpu_register_signed_word(fs_reg());
2816 set_fpu_register_float(fd_reg(), static_cast<float>(alu_out));
2817 break;
2818 case CVT_D_W: // Convert word to double.
2819 alu_out = get_fpu_register_signed_word(fs_reg());
2820 set_fpu_register_double(fd_reg(), static_cast<double>(alu_out));
2821 break;
2822 case CMP_AF:
2823 set_fpu_register_word(fd_reg(), 0);
2824 break;
2825 case CMP_UN:
2826 if (std::isnan(fs) || std::isnan(ft)) {
2827 set_fpu_register_word(fd_reg(), -1);
2828 } else {
2829 set_fpu_register_word(fd_reg(), 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002830 }
2831 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002832 case CMP_EQ:
2833 if (fs == ft) {
2834 set_fpu_register_word(fd_reg(), -1);
2835 } else {
2836 set_fpu_register_word(fd_reg(), 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002837 }
Andrei Popescu31002712010-02-23 13:46:05 +00002838 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002839 case CMP_UEQ:
2840 if ((fs == ft) || (std::isnan(fs) || std::isnan(ft))) {
2841 set_fpu_register_word(fd_reg(), -1);
2842 } else {
2843 set_fpu_register_word(fd_reg(), 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002844 }
Steve Block44f0eee2011-05-26 01:26:41 +01002845 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002846 case CMP_LT:
2847 if (fs < ft) {
2848 set_fpu_register_word(fd_reg(), -1);
2849 } else {
2850 set_fpu_register_word(fd_reg(), 0);
2851 }
2852 break;
2853 case CMP_ULT:
2854 if ((fs < ft) || (std::isnan(fs) || std::isnan(ft))) {
2855 set_fpu_register_word(fd_reg(), -1);
2856 } else {
2857 set_fpu_register_word(fd_reg(), 0);
2858 }
2859 break;
2860 case CMP_LE:
2861 if (fs <= ft) {
2862 set_fpu_register_word(fd_reg(), -1);
2863 } else {
2864 set_fpu_register_word(fd_reg(), 0);
2865 }
2866 break;
2867 case CMP_ULE:
2868 if ((fs <= ft) || (std::isnan(fs) || std::isnan(ft))) {
2869 set_fpu_register_word(fd_reg(), -1);
2870 } else {
2871 set_fpu_register_word(fd_reg(), 0);
2872 }
2873 break;
2874 case CMP_OR:
2875 if (!std::isnan(fs) && !std::isnan(ft)) {
2876 set_fpu_register_word(fd_reg(), -1);
2877 } else {
2878 set_fpu_register_word(fd_reg(), 0);
2879 }
2880 break;
2881 case CMP_UNE:
2882 if ((fs != ft) || (std::isnan(fs) || std::isnan(ft))) {
2883 set_fpu_register_word(fd_reg(), -1);
2884 } else {
2885 set_fpu_register_word(fd_reg(), 0);
2886 }
2887 break;
2888 case CMP_NE:
2889 if (fs != ft) {
2890 set_fpu_register_word(fd_reg(), -1);
2891 } else {
2892 set_fpu_register_word(fd_reg(), 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002893 }
Andrei Popescu31002712010-02-23 13:46:05 +00002894 break;
2895 default:
2896 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002897 }
Steve Block44f0eee2011-05-26 01:26:41 +01002898}
2899
2900
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002901void Simulator::DecodeTypeRegisterSRsType() {
2902 float fs, ft, fd;
2903 fs = get_fpu_register_float(fs_reg());
2904 ft = get_fpu_register_float(ft_reg());
2905 fd = get_fpu_register_float(fd_reg());
2906 int32_t ft_int = bit_cast<int32_t>(ft);
2907 int32_t fd_int = bit_cast<int32_t>(fd);
2908 uint32_t cc, fcsr_cc;
2909 cc = get_instr()->FCccValue();
2910 fcsr_cc = get_fcsr_condition_bit(cc);
2911 switch (get_instr()->FunctionFieldRaw()) {
2912 case RINT: {
2913 DCHECK(IsMipsArchVariant(kMips32r6));
2914 float result, temp_result;
2915 double temp;
2916 float upper = std::ceil(fs);
2917 float lower = std::floor(fs);
2918 switch (get_fcsr_rounding_mode()) {
2919 case kRoundToNearest:
2920 if (upper - fs < fs - lower) {
2921 result = upper;
2922 } else if (upper - fs > fs - lower) {
2923 result = lower;
2924 } else {
2925 temp_result = upper / 2;
2926 float reminder = modf(temp_result, &temp);
2927 if (reminder == 0) {
2928 result = upper;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002929 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002930 result = lower;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002931 }
Andrei Popescu31002712010-02-23 13:46:05 +00002932 }
2933 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002934 case kRoundToZero:
2935 result = (fs > 0 ? lower : upper);
2936 break;
2937 case kRoundToPlusInf:
2938 result = upper;
2939 break;
2940 case kRoundToMinusInf:
2941 result = lower;
2942 break;
2943 }
2944 set_fpu_register_float(fd_reg(), result);
2945 if (result != fs) {
2946 set_fcsr_bit(kFCSRInexactFlagBit, true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002947 }
2948 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002949 }
2950 case ADD_S:
2951 set_fpu_register_float(fd_reg(), fs + ft);
2952 break;
2953 case SUB_S:
2954 set_fpu_register_float(fd_reg(), fs - ft);
2955 break;
2956 case MUL_S:
2957 set_fpu_register_float(fd_reg(), fs * ft);
2958 break;
2959 case DIV_S:
2960 set_fpu_register_float(fd_reg(), fs / ft);
2961 break;
2962 case ABS_S:
2963 set_fpu_register_float(fd_reg(), fabs(fs));
2964 break;
2965 case MOV_S:
2966 set_fpu_register_float(fd_reg(), fs);
2967 break;
2968 case NEG_S:
2969 set_fpu_register_float(fd_reg(), -fs);
2970 break;
2971 case SQRT_S:
2972 lazily_initialize_fast_sqrt(isolate_);
2973 set_fpu_register_float(fd_reg(), fast_sqrt(fs, isolate_));
2974 break;
2975 case RSQRT_S: {
2976 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2977 lazily_initialize_fast_sqrt(isolate_);
2978 float result = 1.0 / fast_sqrt(fs, isolate_);
2979 set_fpu_register_float(fd_reg(), result);
2980 break;
2981 }
2982 case RECIP_S: {
2983 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2984 float result = 1.0 / fs;
2985 set_fpu_register_float(fd_reg(), result);
2986 break;
2987 }
2988 case C_F_D:
2989 set_fcsr_bit(fcsr_cc, false);
2990 break;
2991 case C_UN_D:
2992 set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft));
2993 break;
2994 case C_EQ_D:
2995 set_fcsr_bit(fcsr_cc, (fs == ft));
2996 break;
2997 case C_UEQ_D:
2998 set_fcsr_bit(fcsr_cc, (fs == ft) || (std::isnan(fs) || std::isnan(ft)));
2999 break;
3000 case C_OLT_D:
3001 set_fcsr_bit(fcsr_cc, (fs < ft));
3002 break;
3003 case C_ULT_D:
3004 set_fcsr_bit(fcsr_cc, (fs < ft) || (std::isnan(fs) || std::isnan(ft)));
3005 break;
3006 case C_OLE_D:
3007 set_fcsr_bit(fcsr_cc, (fs <= ft));
3008 break;
3009 case C_ULE_D:
3010 set_fcsr_bit(fcsr_cc, (fs <= ft) || (std::isnan(fs) || std::isnan(ft)));
3011 break;
3012 case CVT_D_S:
3013 set_fpu_register_double(fd_reg(), static_cast<double>(fs));
3014 break;
3015 case SEL:
3016 DCHECK(IsMipsArchVariant(kMips32r6));
3017 set_fpu_register_float(fd_reg(), (fd_int & 0x1) == 0 ? fs : ft);
3018 break;
3019 case CLASS_S: { // Mips32r6 instruction
3020 // Convert float input to uint32_t for easier bit manipulation
3021 float fs = get_fpu_register_float(fs_reg());
3022 uint32_t classed = bit_cast<uint32_t>(fs);
3023
3024 // Extracting sign, exponent and mantissa from the input float
3025 uint32_t sign = (classed >> 31) & 1;
3026 uint32_t exponent = (classed >> 23) & 0x000000ff;
3027 uint32_t mantissa = classed & 0x007fffff;
3028 uint32_t result;
3029 float fResult;
3030
3031 // Setting flags if input float is negative infinity,
3032 // positive infinity, negative zero or positive zero
3033 bool negInf = (classed == 0xFF800000);
3034 bool posInf = (classed == 0x7F800000);
3035 bool negZero = (classed == 0x80000000);
3036 bool posZero = (classed == 0x00000000);
3037
3038 bool signalingNan;
3039 bool quietNan;
3040 bool negSubnorm;
3041 bool posSubnorm;
3042 bool negNorm;
3043 bool posNorm;
3044
3045 // Setting flags if float is NaN
3046 signalingNan = false;
3047 quietNan = false;
3048 if (!negInf && !posInf && (exponent == 0xff)) {
3049 quietNan = ((mantissa & 0x00200000) == 0) &&
3050 ((mantissa & (0x00200000 - 1)) == 0);
3051 signalingNan = !quietNan;
3052 }
3053
3054 // Setting flags if float is subnormal number
3055 posSubnorm = false;
3056 negSubnorm = false;
3057 if ((exponent == 0) && (mantissa != 0)) {
3058 DCHECK(sign == 0 || sign == 1);
3059 posSubnorm = (sign == 0);
3060 negSubnorm = (sign == 1);
3061 }
3062
3063 // Setting flags if float is normal number
3064 posNorm = false;
3065 negNorm = false;
3066 if (!posSubnorm && !negSubnorm && !posInf && !negInf && !signalingNan &&
3067 !quietNan && !negZero && !posZero) {
3068 DCHECK(sign == 0 || sign == 1);
3069 posNorm = (sign == 0);
3070 negNorm = (sign == 1);
3071 }
3072
3073 // Calculating result according to description of CLASS.S instruction
3074 result = (posZero << 9) | (posSubnorm << 8) | (posNorm << 7) |
3075 (posInf << 6) | (negZero << 5) | (negSubnorm << 4) |
3076 (negNorm << 3) | (negInf << 2) | (quietNan << 1) | signalingNan;
3077
3078 DCHECK(result != 0);
3079
3080 fResult = bit_cast<float>(result);
3081 set_fpu_register_float(fd_reg(), fResult);
3082
3083 break;
3084 }
3085 case SELEQZ_C:
3086 DCHECK(IsMipsArchVariant(kMips32r6));
3087 set_fpu_register_float(fd_reg(), (ft_int & 0x1) == 0
3088 ? get_fpu_register_float(fs_reg())
3089 : 0.0);
3090 break;
3091 case SELNEZ_C:
3092 DCHECK(IsMipsArchVariant(kMips32r6));
3093 set_fpu_register_float(fd_reg(), (ft_int & 0x1) != 0
3094 ? get_fpu_register_float(fs_reg())
3095 : 0.0);
3096 break;
3097 case MOVZ_C: {
3098 DCHECK(IsMipsArchVariant(kMips32r2));
3099 if (rt() == 0) {
3100 set_fpu_register_float(fd_reg(), fs);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003101 }
Andrei Popescu31002712010-02-23 13:46:05 +00003102 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003103 }
3104 case MOVN_C: {
3105 DCHECK(IsMipsArchVariant(kMips32r2));
3106 if (rt() != 0) {
3107 set_fpu_register_float(fd_reg(), fs);
3108 }
3109 break;
3110 }
3111 case MOVF: {
3112 // Same function field for MOVT.D and MOVF.D
3113 uint32_t ft_cc = (ft_reg() >> 2) & 0x7;
3114 ft_cc = get_fcsr_condition_bit(ft_cc);
3115
3116 if (get_instr()->Bit(16)) { // Read Tf bit.
3117 // MOVT.D
3118 if (test_fcsr_bit(ft_cc)) set_fpu_register_float(fd_reg(), fs);
3119 } else {
3120 // MOVF.D
3121 if (!test_fcsr_bit(ft_cc)) set_fpu_register_float(fd_reg(), fs);
3122 }
3123 break;
3124 }
3125 case TRUNC_W_S: { // Truncate single to word (round towards 0).
3126 float rounded = trunc(fs);
3127 int32_t result = static_cast<int32_t>(rounded);
3128 set_fpu_register_word(fd_reg(), result);
3129 if (set_fcsr_round_error(fs, rounded)) {
3130 set_fpu_register_word_invalid_result(fs, rounded);
3131 }
3132 } break;
3133 case TRUNC_L_S: { // Mips32r2 instruction.
3134 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
3135 float rounded = trunc(fs);
3136 int64_t i64 = static_cast<int64_t>(rounded);
3137 if (IsFp64Mode()) {
3138 set_fpu_register(fd_reg(), i64);
3139 if (set_fcsr_round64_error(fs, rounded)) {
3140 set_fpu_register_invalid_result64(fs, rounded);
Andrei Popescu31002712010-02-23 13:46:05 +00003141 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003142 } else {
3143 UNSUPPORTED();
3144 }
3145 break;
3146 }
3147 case FLOOR_W_S: // Round double to word towards negative infinity.
3148 {
3149 float rounded = std::floor(fs);
3150 int32_t result = static_cast<int32_t>(rounded);
3151 set_fpu_register_word(fd_reg(), result);
3152 if (set_fcsr_round_error(fs, rounded)) {
3153 set_fpu_register_word_invalid_result(fs, rounded);
3154 }
3155 } break;
3156 case FLOOR_L_S: { // Mips32r2 instruction.
3157 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
3158 float rounded = std::floor(fs);
3159 int64_t i64 = static_cast<int64_t>(rounded);
3160 if (IsFp64Mode()) {
3161 set_fpu_register(fd_reg(), i64);
3162 if (set_fcsr_round64_error(fs, rounded)) {
3163 set_fpu_register_invalid_result64(fs, rounded);
Andrei Popescu31002712010-02-23 13:46:05 +00003164 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003165 } else {
3166 UNSUPPORTED();
3167 }
3168 break;
3169 }
3170 case ROUND_W_S: {
3171 float rounded = std::floor(fs + 0.5);
3172 int32_t result = static_cast<int32_t>(rounded);
3173 if ((result & 1) != 0 && result - fs == 0.5) {
3174 // If the number is halfway between two integers,
3175 // round to the even one.
3176 result--;
3177 }
3178 set_fpu_register_word(fd_reg(), result);
3179 if (set_fcsr_round_error(fs, rounded)) {
3180 set_fpu_register_word_invalid_result(fs, rounded);
3181 }
3182 break;
3183 }
3184 case ROUND_L_S: { // Mips32r2 instruction.
3185 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
3186 float rounded = std::floor(fs + 0.5);
3187 int64_t result = static_cast<int64_t>(rounded);
3188 if ((result & 1) != 0 && result - fs == 0.5) {
3189 // If the number is halfway between two integers,
3190 // round to the even one.
3191 result--;
3192 }
3193 int64_t i64 = static_cast<int64_t>(result);
3194 if (IsFp64Mode()) {
3195 set_fpu_register(fd_reg(), i64);
3196 if (set_fcsr_round64_error(fs, rounded)) {
3197 set_fpu_register_invalid_result64(fs, rounded);
Steve Block44f0eee2011-05-26 01:26:41 +01003198 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003199 } else {
3200 UNSUPPORTED();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003201 }
Andrei Popescu31002712010-02-23 13:46:05 +00003202 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003203 }
3204 case CEIL_W_S: // Round double to word towards positive infinity.
3205 {
3206 float rounded = std::ceil(fs);
3207 int32_t result = static_cast<int32_t>(rounded);
3208 set_fpu_register_word(fd_reg(), result);
3209 if (set_fcsr_round_error(fs, rounded)) {
3210 set_fpu_register_word_invalid_result(fs, rounded);
3211 }
3212 } break;
3213 case CEIL_L_S: { // Mips32r2 instruction.
3214 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
3215 float rounded = std::ceil(fs);
3216 int64_t i64 = static_cast<int64_t>(rounded);
3217 if (IsFp64Mode()) {
3218 set_fpu_register(fd_reg(), i64);
3219 if (set_fcsr_round64_error(fs, rounded)) {
3220 set_fpu_register_invalid_result64(fs, rounded);
3221 }
3222 } else {
3223 UNSUPPORTED();
Steve Block44f0eee2011-05-26 01:26:41 +01003224 }
3225 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003226 }
3227 case MIN:
3228 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch097c5b22016-05-18 11:27:45 +01003229 set_fpu_register_float(fd_reg(), FPUMin(ft, fs));
Andrei Popescu31002712010-02-23 13:46:05 +00003230 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003231 case MAX:
3232 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch097c5b22016-05-18 11:27:45 +01003233 set_fpu_register_float(fd_reg(), FPUMax(ft, fs));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003234 break;
3235 case MINA:
3236 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch097c5b22016-05-18 11:27:45 +01003237 set_fpu_register_float(fd_reg(), FPUMinA(ft, fs));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003238 break;
3239 case MAXA:
3240 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch097c5b22016-05-18 11:27:45 +01003241 set_fpu_register_float(fd_reg(), FPUMaxA(ft, fs));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003242 break;
3243 case CVT_L_S: {
3244 if (IsFp64Mode()) {
3245 int64_t result;
3246 float rounded;
3247 round64_according_to_fcsr(fs, rounded, result, fs);
3248 set_fpu_register(fd_reg(), result);
3249 if (set_fcsr_round64_error(fs, rounded)) {
3250 set_fpu_register_invalid_result64(fs, rounded);
3251 }
3252 } else {
3253 UNSUPPORTED();
3254 }
3255 break;
3256 }
3257 case CVT_W_S: {
3258 float rounded;
3259 int32_t result;
3260 round_according_to_fcsr(fs, rounded, result, fs);
3261 set_fpu_register_word(fd_reg(), result);
3262 if (set_fcsr_round_error(fs, rounded)) {
3263 set_fpu_register_word_invalid_result(fs, rounded);
3264 }
3265 break;
3266 }
Andrei Popescu31002712010-02-23 13:46:05 +00003267 default:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003268 // CVT_W_S CVT_L_S ROUND_W_S ROUND_L_S FLOOR_W_S FLOOR_L_S
3269 // CEIL_W_S CEIL_L_S CVT_PS_S are unimplemented.
3270 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003271 }
Andrei Popescu31002712010-02-23 13:46:05 +00003272}
3273
Steve Block44f0eee2011-05-26 01:26:41 +01003274
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003275void Simulator::DecodeTypeRegisterLRsType() {
3276 double fs = get_fpu_register_double(fs_reg());
3277 double ft = get_fpu_register_double(ft_reg());
3278 switch (get_instr()->FunctionFieldRaw()) {
3279 case CVT_D_L: // Mips32r2 instruction.
3280 // Watch the signs here, we want 2 32-bit vals
3281 // to make a sign-64.
3282 int64_t i64;
3283 if (IsFp64Mode()) {
3284 i64 = get_fpu_register(fs_reg());
3285 } else {
3286 i64 = static_cast<uint32_t>(get_fpu_register_word(fs_reg()));
3287 i64 |= static_cast<int64_t>(get_fpu_register_word(fs_reg() + 1)) << 32;
3288 }
3289 set_fpu_register_double(fd_reg(), static_cast<double>(i64));
3290 break;
3291 case CVT_S_L:
3292 if (IsFp64Mode()) {
3293 i64 = get_fpu_register(fs_reg());
3294 } else {
3295 i64 = static_cast<uint32_t>(get_fpu_register_word(fs_reg()));
3296 i64 |= static_cast<int64_t>(get_fpu_register_word(fs_reg() + 1)) << 32;
3297 }
3298 set_fpu_register_float(fd_reg(), static_cast<float>(i64));
3299 break;
3300 case CMP_AF: // Mips64r6 CMP.D instructions.
3301 set_fpu_register(fd_reg(), 0);
3302 break;
3303 case CMP_UN:
3304 if (std::isnan(fs) || std::isnan(ft)) {
3305 set_fpu_register(fd_reg(), -1);
3306 } else {
3307 set_fpu_register(fd_reg(), 0);
3308 }
3309 break;
3310 case CMP_EQ:
3311 if (fs == ft) {
3312 set_fpu_register(fd_reg(), -1);
3313 } else {
3314 set_fpu_register(fd_reg(), 0);
3315 }
3316 break;
3317 case CMP_UEQ:
3318 if ((fs == ft) || (std::isnan(fs) || std::isnan(ft))) {
3319 set_fpu_register(fd_reg(), -1);
3320 } else {
3321 set_fpu_register(fd_reg(), 0);
3322 }
3323 break;
3324 case CMP_LT:
3325 if (fs < ft) {
3326 set_fpu_register(fd_reg(), -1);
3327 } else {
3328 set_fpu_register(fd_reg(), 0);
3329 }
3330 break;
3331 case CMP_ULT:
3332 if ((fs < ft) || (std::isnan(fs) || std::isnan(ft))) {
3333 set_fpu_register(fd_reg(), -1);
3334 } else {
3335 set_fpu_register(fd_reg(), 0);
3336 }
3337 break;
3338 case CMP_LE:
3339 if (fs <= ft) {
3340 set_fpu_register(fd_reg(), -1);
3341 } else {
3342 set_fpu_register(fd_reg(), 0);
3343 }
3344 break;
3345 case CMP_ULE:
3346 if ((fs <= ft) || (std::isnan(fs) || std::isnan(ft))) {
3347 set_fpu_register(fd_reg(), -1);
3348 } else {
3349 set_fpu_register(fd_reg(), 0);
3350 }
3351 break;
3352 case CMP_OR:
3353 if (!std::isnan(fs) && !std::isnan(ft)) {
3354 set_fpu_register(fd_reg(), -1);
3355 } else {
3356 set_fpu_register(fd_reg(), 0);
3357 }
3358 break;
3359 case CMP_UNE:
3360 if ((fs != ft) || (std::isnan(fs) || std::isnan(ft))) {
3361 set_fpu_register(fd_reg(), -1);
3362 } else {
3363 set_fpu_register(fd_reg(), 0);
3364 }
3365 break;
3366 case CMP_NE:
3367 if (fs != ft && (!std::isnan(fs) && !std::isnan(ft))) {
3368 set_fpu_register(fd_reg(), -1);
3369 } else {
3370 set_fpu_register(fd_reg(), 0);
3371 }
3372 break;
3373 default:
3374 UNREACHABLE();
3375 }
3376}
3377
3378
3379void Simulator::DecodeTypeRegisterCOP1() {
3380 switch (get_instr()->RsFieldRaw()) {
3381 case CFC1:
3382 // At the moment only FCSR is supported.
3383 DCHECK(fs_reg() == kFCSRRegister);
3384 set_register(rt_reg(), FCSR_);
3385 break;
3386 case MFC1:
3387 set_register(rt_reg(), get_fpu_register_word(fs_reg()));
3388 break;
3389 case MFHC1:
Ben Murdoch097c5b22016-05-18 11:27:45 +01003390 if (IsFp64Mode()) {
3391 set_register(rt_reg(), get_fpu_register_hi_word(fs_reg()));
3392 } else {
3393 set_register(rt_reg(), get_fpu_register_word(fs_reg() + 1));
3394 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003395 break;
3396 case CTC1: {
3397 // At the moment only FCSR is supported.
3398 DCHECK(fs_reg() == kFCSRRegister);
3399 int32_t reg = registers_[rt_reg()];
3400 if (IsMipsArchVariant(kMips32r6)) {
3401 FCSR_ = reg | kFCSRNaN2008FlagMask;
3402 } else {
3403 DCHECK(IsMipsArchVariant(kMips32r1) || IsMipsArchVariant(kMips32r2));
3404 FCSR_ = reg & ~kFCSRNaN2008FlagMask;
3405 }
3406 break;
3407 }
3408 case MTC1:
3409 // Hardware writes upper 32-bits to zero on mtc1.
3410 set_fpu_register_hi_word(fs_reg(), 0);
3411 set_fpu_register_word(fs_reg(), registers_[rt_reg()]);
3412 break;
3413 case MTHC1:
Ben Murdoch097c5b22016-05-18 11:27:45 +01003414 if (IsFp64Mode()) {
3415 set_fpu_register_hi_word(fs_reg(), registers_[rt_reg()]);
3416 } else {
3417 set_fpu_register_word(fs_reg() + 1, registers_[rt_reg()]);
3418 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003419 break;
3420 case S: {
3421 DecodeTypeRegisterSRsType();
3422 break;
3423 }
3424 case D:
3425 DecodeTypeRegisterDRsType();
3426 break;
3427 case W:
3428 DecodeTypeRegisterWRsType();
3429 break;
3430 case L:
3431 DecodeTypeRegisterLRsType();
3432 break;
3433 case PS:
3434 // Not implemented.
3435 UNREACHABLE();
3436 default:
3437 UNREACHABLE();
3438 }
3439}
3440
3441
3442void Simulator::DecodeTypeRegisterCOP1X() {
3443 switch (get_instr()->FunctionFieldRaw()) {
3444 case MADD_D:
3445 double fr, ft, fs;
3446 fr = get_fpu_register_double(fr_reg());
3447 fs = get_fpu_register_double(fs_reg());
3448 ft = get_fpu_register_double(ft_reg());
3449 set_fpu_register_double(fd_reg(), fs * ft + fr);
3450 break;
3451 default:
3452 UNREACHABLE();
3453 }
3454}
3455
3456
3457void Simulator::DecodeTypeRegisterSPECIAL() {
3458 int64_t alu_out = 0x12345678;
3459 int64_t i64hilo = 0;
3460 uint64_t u64hilo = 0;
3461 bool do_interrupt = false;
3462
3463 switch (get_instr()->FunctionFieldRaw()) {
3464 case SELEQZ_S:
3465 DCHECK(IsMipsArchVariant(kMips32r6));
3466 set_register(rd_reg(), rt() == 0 ? rs() : 0);
3467 break;
3468 case SELNEZ_S:
3469 DCHECK(IsMipsArchVariant(kMips32r6));
3470 set_register(rd_reg(), rt() != 0 ? rs() : 0);
3471 break;
3472 case JR: {
3473 int32_t next_pc = rs();
3474 int32_t current_pc = get_pc();
3475 Instruction* branch_delay_instr =
3476 reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize);
3477 BranchDelayInstructionDecode(branch_delay_instr);
3478 set_pc(next_pc);
3479 pc_modified_ = true;
3480 break;
3481 }
3482 case JALR: {
3483 int32_t next_pc = rs();
3484 int32_t return_addr_reg = rd_reg();
3485 int32_t current_pc = get_pc();
3486 Instruction* branch_delay_instr =
3487 reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize);
3488 BranchDelayInstructionDecode(branch_delay_instr);
3489 set_register(return_addr_reg, current_pc + 2 * Instruction::kInstrSize);
3490 set_pc(next_pc);
3491 pc_modified_ = true;
3492 break;
3493 }
3494 case SLL:
3495 alu_out = rt() << sa();
3496 SetResult(rd_reg(), static_cast<int32_t>(alu_out));
3497 break;
3498 case SRL:
3499 if (rs_reg() == 0) {
3500 // Regular logical right shift of a word by a fixed number of
3501 // bits instruction. RS field is always equal to 0.
3502 alu_out = rt_u() >> sa();
3503 } else {
3504 // Logical right-rotate of a word by a fixed number of bits. This
3505 // is special case of SRL instruction, added in MIPS32 Release 2.
3506 // RS field is equal to 00001.
3507 alu_out = base::bits::RotateRight32(rt_u(), sa());
3508 }
3509 SetResult(rd_reg(), static_cast<int32_t>(alu_out));
3510 break;
3511 case SRA:
3512 alu_out = rt() >> sa();
3513 SetResult(rd_reg(), static_cast<int32_t>(alu_out));
3514 break;
3515 case SLLV:
3516 alu_out = rt() << rs();
3517 SetResult(rd_reg(), static_cast<int32_t>(alu_out));
3518 break;
3519 case SRLV:
3520 if (sa() == 0) {
3521 // Regular logical right-shift of a word by a variable number of
3522 // bits instruction. SA field is always equal to 0.
3523 alu_out = rt_u() >> rs();
3524 } else {
3525 // Logical right-rotate of a word by a variable number of bits.
3526 // This is special case od SRLV instruction, added in MIPS32
3527 // Release 2. SA field is equal to 00001.
3528 alu_out = base::bits::RotateRight32(rt_u(), rs_u());
3529 }
3530 SetResult(rd_reg(), static_cast<int32_t>(alu_out));
3531 break;
3532 case SRAV:
3533 SetResult(rd_reg(), rt() >> rs());
3534 break;
3535 case LSA: {
3536 DCHECK(IsMipsArchVariant(kMips32r6));
3537 int8_t sa = lsa_sa() + 1;
3538 int32_t _rt = rt();
3539 int32_t _rs = rs();
3540 int32_t res = _rs << sa;
3541 res += _rt;
3542 DCHECK_EQ(res, (rs() << (lsa_sa() + 1)) + rt());
3543 SetResult(rd_reg(), (rs() << (lsa_sa() + 1)) + rt());
3544 break;
3545 }
3546 case MFHI: // MFHI == CLZ on R6.
3547 if (!IsMipsArchVariant(kMips32r6)) {
3548 DCHECK(sa() == 0);
3549 alu_out = get_register(HI);
3550 } else {
3551 // MIPS spec: If no bits were set in GPR rs, the result written to
3552 // GPR rd is 32.
3553 DCHECK(sa() == 1);
3554 alu_out = base::bits::CountLeadingZeros32(rs_u());
3555 }
3556 SetResult(rd_reg(), static_cast<int32_t>(alu_out));
3557 break;
3558 case MFLO:
3559 alu_out = get_register(LO);
3560 SetResult(rd_reg(), static_cast<int32_t>(alu_out));
3561 break;
3562 // Instructions using HI and LO registers.
3563 case MULT:
3564 i64hilo = static_cast<int64_t>(rs()) * static_cast<int64_t>(rt());
3565 if (!IsMipsArchVariant(kMips32r6)) {
3566 set_register(LO, static_cast<int32_t>(i64hilo & 0xffffffff));
3567 set_register(HI, static_cast<int32_t>(i64hilo >> 32));
3568 } else {
3569 switch (sa()) {
3570 case MUL_OP:
3571 set_register(rd_reg(), static_cast<int32_t>(i64hilo & 0xffffffff));
3572 break;
3573 case MUH_OP:
3574 set_register(rd_reg(), static_cast<int32_t>(i64hilo >> 32));
3575 break;
3576 default:
3577 UNIMPLEMENTED_MIPS();
3578 break;
3579 }
3580 }
3581 break;
3582 case MULTU:
3583 u64hilo = static_cast<uint64_t>(rs_u()) * static_cast<uint64_t>(rt_u());
3584 if (!IsMipsArchVariant(kMips32r6)) {
3585 set_register(LO, static_cast<int32_t>(u64hilo & 0xffffffff));
3586 set_register(HI, static_cast<int32_t>(u64hilo >> 32));
3587 } else {
3588 switch (sa()) {
3589 case MUL_OP:
3590 set_register(rd_reg(), static_cast<int32_t>(u64hilo & 0xffffffff));
3591 break;
3592 case MUH_OP:
3593 set_register(rd_reg(), static_cast<int32_t>(u64hilo >> 32));
3594 break;
3595 default:
3596 UNIMPLEMENTED_MIPS();
3597 break;
3598 }
3599 }
3600 break;
3601 case DIV:
3602 if (IsMipsArchVariant(kMips32r6)) {
3603 switch (get_instr()->SaValue()) {
3604 case DIV_OP:
3605 if (rs() == INT_MIN && rt() == -1) {
3606 set_register(rd_reg(), INT_MIN);
3607 } else if (rt() != 0) {
3608 set_register(rd_reg(), rs() / rt());
3609 }
3610 break;
3611 case MOD_OP:
3612 if (rs() == INT_MIN && rt() == -1) {
3613 set_register(rd_reg(), 0);
3614 } else if (rt() != 0) {
3615 set_register(rd_reg(), rs() % rt());
3616 }
3617 break;
3618 default:
3619 UNIMPLEMENTED_MIPS();
3620 break;
3621 }
3622 } else {
3623 // Divide by zero and overflow was not checked in the
3624 // configuration step - div and divu do not raise exceptions. On
3625 // division by 0 the result will be UNPREDICTABLE. On overflow
3626 // (INT_MIN/-1), return INT_MIN which is what the hardware does.
3627 if (rs() == INT_MIN && rt() == -1) {
3628 set_register(LO, INT_MIN);
3629 set_register(HI, 0);
3630 } else if (rt() != 0) {
3631 set_register(LO, rs() / rt());
3632 set_register(HI, rs() % rt());
3633 }
3634 }
3635 break;
3636 case DIVU:
3637 if (IsMipsArchVariant(kMips32r6)) {
3638 switch (get_instr()->SaValue()) {
3639 case DIV_OP:
3640 if (rt_u() != 0) {
3641 set_register(rd_reg(), rs_u() / rt_u());
3642 }
3643 break;
3644 case MOD_OP:
3645 if (rt_u() != 0) {
3646 set_register(rd_reg(), rs_u() % rt_u());
3647 }
3648 break;
3649 default:
3650 UNIMPLEMENTED_MIPS();
3651 break;
3652 }
3653 } else {
3654 if (rt_u() != 0) {
3655 set_register(LO, rs_u() / rt_u());
3656 set_register(HI, rs_u() % rt_u());
3657 }
3658 }
3659 break;
3660 case ADD:
3661 if (HaveSameSign(rs(), rt())) {
3662 if (rs() > 0) {
3663 if (rs() <= (Registers::kMaxValue - rt())) {
3664 SignalException(kIntegerOverflow);
3665 }
3666 } else if (rs() < 0) {
3667 if (rs() >= (Registers::kMinValue - rt())) {
3668 SignalException(kIntegerUnderflow);
3669 }
3670 }
3671 }
3672 SetResult(rd_reg(), rs() + rt());
3673 break;
3674 case ADDU:
3675 SetResult(rd_reg(), rs() + rt());
3676 break;
3677 case SUB:
3678 if (!HaveSameSign(rs(), rt())) {
3679 if (rs() > 0) {
3680 if (rs() <= (Registers::kMaxValue + rt())) {
3681 SignalException(kIntegerOverflow);
3682 }
3683 } else if (rs() < 0) {
3684 if (rs() >= (Registers::kMinValue + rt())) {
3685 SignalException(kIntegerUnderflow);
3686 }
3687 }
3688 }
3689 SetResult(rd_reg(), rs() - rt());
3690 break;
3691 case SUBU:
3692 SetResult(rd_reg(), rs() - rt());
3693 break;
3694 case AND:
3695 SetResult(rd_reg(), rs() & rt());
3696 break;
3697 case OR:
3698 SetResult(rd_reg(), rs() | rt());
3699 break;
3700 case XOR:
3701 SetResult(rd_reg(), rs() ^ rt());
3702 break;
3703 case NOR:
3704 SetResult(rd_reg(), ~(rs() | rt()));
3705 break;
3706 case SLT:
3707 SetResult(rd_reg(), rs() < rt() ? 1 : 0);
3708 break;
3709 case SLTU:
3710 SetResult(rd_reg(), rs_u() < rt_u() ? 1 : 0);
3711 break;
3712 // Break and trap instructions.
3713 case BREAK:
3714 do_interrupt = true;
3715 break;
3716 case TGE:
3717 do_interrupt = rs() >= rt();
3718 break;
3719 case TGEU:
3720 do_interrupt = rs_u() >= rt_u();
3721 break;
3722 case TLT:
3723 do_interrupt = rs() < rt();
3724 break;
3725 case TLTU:
3726 do_interrupt = rs_u() < rt_u();
3727 break;
3728 case TEQ:
3729 do_interrupt = rs() == rt();
3730 break;
3731 case TNE:
3732 do_interrupt = rs() != rt();
3733 break;
3734 // Conditional moves.
3735 case MOVN:
3736 if (rt()) {
3737 set_register(rd_reg(), rs());
3738 TraceRegWr(rs());
3739 }
3740 break;
3741 case MOVCI: {
3742 uint32_t cc = get_instr()->FBccValue();
3743 uint32_t fcsr_cc = get_fcsr_condition_bit(cc);
3744 if (get_instr()->Bit(16)) { // Read Tf bit.
3745 if (test_fcsr_bit(fcsr_cc)) set_register(rd_reg(), rs());
3746 } else {
3747 if (!test_fcsr_bit(fcsr_cc)) set_register(rd_reg(), rs());
3748 }
3749 break;
3750 }
3751 case MOVZ:
3752 if (!rt()) {
3753 set_register(rd_reg(), rs());
3754 TraceRegWr(rs());
3755 }
3756 break;
3757 default:
3758 UNREACHABLE();
3759 }
3760 if (do_interrupt) {
3761 SoftwareInterrupt(get_instr());
3762 }
3763}
3764
3765
3766void Simulator::DecodeTypeRegisterSPECIAL2() {
3767 int32_t alu_out;
3768 switch (get_instr()->FunctionFieldRaw()) {
3769 case MUL:
3770 // Only the lower 32 bits are kept.
3771 alu_out = rs_u() * rt_u();
3772 // HI and LO are UNPREDICTABLE after the operation.
3773 set_register(LO, Unpredictable);
3774 set_register(HI, Unpredictable);
3775 break;
3776 case CLZ:
3777 // MIPS32 spec: If no bits were set in GPR rs, the result written to
3778 // GPR rd is 32.
3779 alu_out = base::bits::CountLeadingZeros32(rs_u());
3780 break;
3781 default:
3782 alu_out = 0x12345678;
3783 UNREACHABLE();
3784 }
3785 SetResult(rd_reg(), alu_out);
3786}
3787
3788
3789void Simulator::DecodeTypeRegisterSPECIAL3() {
3790 int32_t alu_out;
3791 switch (get_instr()->FunctionFieldRaw()) {
3792 case INS: { // Mips32r2 instruction.
3793 // Interpret rd field as 5-bit msb of insert.
3794 uint16_t msb = rd_reg();
3795 // Interpret sa field as 5-bit lsb of insert.
3796 uint16_t lsb = sa();
3797 uint16_t size = msb - lsb + 1;
3798 uint32_t mask = (1 << size) - 1;
3799 alu_out = (rt_u() & ~(mask << lsb)) | ((rs_u() & mask) << lsb);
3800 // Ins instr leaves result in Rt, rather than Rd.
3801 SetResult(rt_reg(), alu_out);
3802 break;
3803 }
3804 case EXT: { // Mips32r2 instruction.
3805 // Interpret rd field as 5-bit msb of extract.
3806 uint16_t msb = rd_reg();
3807 // Interpret sa field as 5-bit lsb of extract.
3808 uint16_t lsb = sa();
3809 uint16_t size = msb + 1;
3810 uint32_t mask = (1 << size) - 1;
3811 alu_out = (rs_u() & (mask << lsb)) >> lsb;
3812 SetResult(rt_reg(), alu_out);
3813 break;
3814 }
3815 case BSHFL: {
3816 int sa = get_instr()->SaFieldRaw() >> kSaShift;
3817 switch (sa) {
3818 case BITSWAP: {
3819 uint32_t input = static_cast<uint32_t>(rt());
3820 uint32_t output = 0;
3821 uint8_t i_byte, o_byte;
3822
3823 // Reverse the bit in byte for each individual byte
3824 for (int i = 0; i < 4; i++) {
3825 output = output >> 8;
3826 i_byte = input & 0xff;
3827
3828 // Fast way to reverse bits in byte
3829 // Devised by Sean Anderson, July 13, 2001
3830 o_byte = static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) |
3831 (i_byte * 0x8020LU & 0x88440LU)) *
3832 0x10101LU >>
3833 16);
3834
3835 output = output | (static_cast<uint32_t>(o_byte << 24));
3836 input = input >> 8;
3837 }
3838
3839 alu_out = static_cast<int32_t>(output);
3840 break;
3841 }
3842 case SEB:
3843 case SEH:
3844 case WSBH:
3845 alu_out = 0x12345678;
3846 UNREACHABLE();
3847 break;
3848 default: {
3849 const uint8_t bp = get_instr()->Bp2Value();
3850 sa >>= kBp2Bits;
3851 switch (sa) {
3852 case ALIGN: {
3853 if (bp == 0) {
3854 alu_out = static_cast<int32_t>(rt());
3855 } else {
3856 uint32_t rt_hi = rt() << (8 * bp);
3857 uint32_t rs_lo = rs() >> (8 * (4 - bp));
3858 alu_out = static_cast<int32_t>(rt_hi | rs_lo);
3859 }
3860 break;
3861 }
3862 default:
3863 alu_out = 0x12345678;
3864 UNREACHABLE();
3865 break;
3866 }
3867 }
3868 }
3869 SetResult(rd_reg(), alu_out);
3870 break;
3871 }
3872 default:
3873 UNREACHABLE();
3874 }
3875}
3876
3877
3878void Simulator::DecodeTypeRegister(Instruction* instr) {
3879 const Opcode op = instr->OpcodeFieldRaw();
3880
3881 // Set up the variables if needed before executing the instruction.
3882 // ConfigureTypeRegister(instr);
3883 set_instr(instr);
3884
3885 // ---------- Execution.
3886 switch (op) {
3887 case COP1:
3888 DecodeTypeRegisterCOP1();
3889 break;
3890 case COP1X:
3891 DecodeTypeRegisterCOP1X();
3892 break;
3893 case SPECIAL:
3894 DecodeTypeRegisterSPECIAL();
3895 break;
3896 case SPECIAL2:
3897 DecodeTypeRegisterSPECIAL2();
3898 break;
3899 case SPECIAL3:
3900 DecodeTypeRegisterSPECIAL3();
3901 break;
3902 default:
3903 UNREACHABLE();
3904 }
3905}
3906
3907
3908// Type 2: instructions using a 16, 21 or 26 bits immediate. (e.g. beq, beqc).
Andrei Popescu31002712010-02-23 13:46:05 +00003909void Simulator::DecodeTypeImmediate(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +01003910 // Instruction fields.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003911 Opcode op = instr->OpcodeFieldRaw();
3912 int32_t rs_reg = instr->RsValue();
3913 int32_t rs = get_register(instr->RsValue());
3914 uint32_t rs_u = static_cast<uint32_t>(rs);
3915 int32_t rt_reg = instr->RtValue(); // Destination register.
3916 int32_t rt = get_register(rt_reg);
3917 int16_t imm16 = instr->Imm16Value();
Andrei Popescu31002712010-02-23 13:46:05 +00003918
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003919 int32_t ft_reg = instr->FtValue(); // Destination register.
Andrei Popescu31002712010-02-23 13:46:05 +00003920
Steve Block44f0eee2011-05-26 01:26:41 +01003921 // Zero extended immediate.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003922 uint32_t oe_imm16 = 0xffff & imm16;
Steve Block44f0eee2011-05-26 01:26:41 +01003923 // Sign extended immediate.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003924 int32_t se_imm16 = imm16;
Andrei Popescu31002712010-02-23 13:46:05 +00003925
Andrei Popescu31002712010-02-23 13:46:05 +00003926 // Next pc.
3927 int32_t next_pc = bad_ra;
3928
Steve Block44f0eee2011-05-26 01:26:41 +01003929 // Used for conditional branch instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00003930 bool execute_branch_delay_instruction = false;
3931
Steve Block44f0eee2011-05-26 01:26:41 +01003932 // Used for arithmetic instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00003933 int32_t alu_out = 0;
Andrei Popescu31002712010-02-23 13:46:05 +00003934
Steve Block44f0eee2011-05-26 01:26:41 +01003935 // Used for memory instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00003936 int32_t addr = 0x0;
3937
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003938 // Branch instructions common part.
3939 auto BranchAndLinkHelper = [this, instr, &next_pc,
3940 &execute_branch_delay_instruction](
3941 bool do_branch) {
3942 execute_branch_delay_instruction = true;
3943 int32_t current_pc = get_pc();
3944 if (do_branch) {
3945 int16_t imm16 = instr->Imm16Value();
3946 next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
3947 set_register(31, current_pc + 2 * Instruction::kInstrSize);
3948 } else {
3949 next_pc = current_pc + 2 * Instruction::kInstrSize;
3950 }
3951 };
3952
3953 auto BranchHelper = [this, instr, &next_pc,
3954 &execute_branch_delay_instruction](bool do_branch) {
3955 execute_branch_delay_instruction = true;
3956 int32_t current_pc = get_pc();
3957 if (do_branch) {
3958 int16_t imm16 = instr->Imm16Value();
3959 next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
3960 } else {
3961 next_pc = current_pc + 2 * Instruction::kInstrSize;
3962 }
3963 };
3964
3965 auto BranchAndLinkCompactHelper = [this, instr, &next_pc](bool do_branch,
3966 int bits) {
3967 int32_t current_pc = get_pc();
3968 CheckForbiddenSlot(current_pc);
3969 if (do_branch) {
3970 int32_t imm = instr->ImmValue(bits);
3971 imm <<= 32 - bits;
3972 imm >>= 32 - bits;
3973 next_pc = current_pc + (imm << 2) + Instruction::kInstrSize;
3974 set_register(31, current_pc + Instruction::kInstrSize);
3975 }
3976 };
3977
3978 auto BranchCompactHelper = [&next_pc, this, instr](bool do_branch, int bits) {
3979 int32_t current_pc = get_pc();
3980 CheckForbiddenSlot(current_pc);
3981 if (do_branch) {
3982 int32_t imm = instr->ImmValue(bits);
3983 imm <<= 32 - bits;
3984 imm >>= 32 - bits;
3985 next_pc = get_pc() + (imm << 2) + Instruction::kInstrSize;
3986 }
3987 };
3988
3989
Andrei Popescu31002712010-02-23 13:46:05 +00003990 switch (op) {
Steve Block44f0eee2011-05-26 01:26:41 +01003991 // ------------- COP1. Coprocessor instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00003992 case COP1:
3993 switch (instr->RsFieldRaw()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003994 case BC1: { // Branch on coprocessor condition.
3995 // Floating point.
3996 uint32_t cc = instr->FBccValue();
3997 uint32_t fcsr_cc = get_fcsr_condition_bit(cc);
3998 uint32_t cc_value = test_fcsr_bit(fcsr_cc);
3999 bool do_branch = (instr->FBtrueValue()) ? cc_value : !cc_value;
4000 BranchHelper(do_branch);
Andrei Popescu31002712010-02-23 13:46:05 +00004001 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004002 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004003 case BC1EQZ:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004004 BranchHelper(!(get_fpu_register(ft_reg) & 0x1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004005 break;
4006 case BC1NEZ:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004007 BranchHelper(get_fpu_register(ft_reg) & 0x1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004008 break;
Andrei Popescu31002712010-02-23 13:46:05 +00004009 default:
4010 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004011 }
Andrei Popescu31002712010-02-23 13:46:05 +00004012 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00004013 // ------------- REGIMM class.
Andrei Popescu31002712010-02-23 13:46:05 +00004014 case REGIMM:
4015 switch (instr->RtFieldRaw()) {
4016 case BLTZ:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004017 BranchHelper(rs < 0);
Andrei Popescu31002712010-02-23 13:46:05 +00004018 break;
4019 case BGEZ:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004020 BranchHelper(rs >= 0);
4021 break;
4022 case BLTZAL:
4023 BranchAndLinkHelper(rs < 0);
Andrei Popescu31002712010-02-23 13:46:05 +00004024 break;
4025 case BGEZAL:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004026 BranchAndLinkHelper(rs >= 0);
Andrei Popescu31002712010-02-23 13:46:05 +00004027 break;
4028 default:
4029 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004030 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004031 break; // case REGIMM.
Ben Murdoch257744e2011-11-30 15:57:28 +00004032 // ------------- Branch instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00004033 // When comparing to zero, the encoding of rt field is always 0, so we don't
4034 // need to replace rt with zero.
4035 case BEQ:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004036 BranchHelper(rs == rt);
Andrei Popescu31002712010-02-23 13:46:05 +00004037 break;
4038 case BNE:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004039 BranchHelper(rs != rt);
Andrei Popescu31002712010-02-23 13:46:05 +00004040 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004041 case POP06: // BLEZALC, BGEZALC, BGEUC, BLEZ (pre-r6)
4042 if (IsMipsArchVariant(kMips32r6)) {
4043 if (rt_reg != 0) {
4044 if (rs_reg == 0) { // BLEZALC
4045 BranchAndLinkCompactHelper(rt <= 0, 16);
4046 } else {
4047 if (rs_reg == rt_reg) { // BGEZALC
4048 BranchAndLinkCompactHelper(rt >= 0, 16);
4049 } else { // BGEUC
4050 BranchCompactHelper(
4051 static_cast<uint32_t>(rs) >= static_cast<uint32_t>(rt), 16);
4052 }
4053 }
4054 } else { // BLEZ
4055 BranchHelper(rs <= 0);
4056 }
4057 } else { // BLEZ
4058 BranchHelper(rs <= 0);
4059 }
Andrei Popescu31002712010-02-23 13:46:05 +00004060 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004061 case POP07: // BGTZALC, BLTZALC, BLTUC, BGTZ (pre-r6)
4062 if (IsMipsArchVariant(kMips32r6)) {
4063 if (rt_reg != 0) {
4064 if (rs_reg == 0) { // BGTZALC
4065 BranchAndLinkCompactHelper(rt > 0, 16);
4066 } else {
4067 if (rt_reg == rs_reg) { // BLTZALC
4068 BranchAndLinkCompactHelper(rt < 0, 16);
4069 } else { // BLTUC
4070 BranchCompactHelper(
4071 static_cast<uint32_t>(rs) < static_cast<uint32_t>(rt), 16);
4072 }
4073 }
4074 } else { // BGTZ
4075 BranchHelper(rs > 0);
4076 }
4077 } else { // BGTZ
4078 BranchHelper(rs > 0);
4079 }
Andrei Popescu31002712010-02-23 13:46:05 +00004080 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004081 case POP26: // BLEZC, BGEZC, BGEC/BLEC / BLEZL (pre-r6)
4082 if (IsMipsArchVariant(kMips32r6)) {
4083 if (rt_reg != 0) {
4084 if (rs_reg == 0) { // BLEZC
4085 BranchCompactHelper(rt <= 0, 16);
4086 } else {
4087 if (rs_reg == rt_reg) { // BGEZC
4088 BranchCompactHelper(rt >= 0, 16);
4089 } else { // BGEC/BLEC
4090 BranchCompactHelper(rs >= rt, 16);
4091 }
4092 }
4093 }
4094 } else { // BLEZL
4095 BranchAndLinkHelper(rs <= 0);
4096 }
4097 break;
4098 case POP27: // BGTZC, BLTZC, BLTC/BGTC / BGTZL (pre-r6)
4099 if (IsMipsArchVariant(kMips32r6)) {
4100 if (rt_reg != 0) {
4101 if (rs_reg == 0) { // BGTZC
4102 BranchCompactHelper(rt > 0, 16);
4103 } else {
4104 if (rs_reg == rt_reg) { // BLTZC
4105 BranchCompactHelper(rt < 0, 16);
4106 } else { // BLTC/BGTC
4107 BranchCompactHelper(rs < rt, 16);
4108 }
4109 }
4110 }
4111 } else { // BGTZL
4112 BranchAndLinkHelper(rs > 0);
4113 }
4114 break;
4115 case POP66: // BEQZC, JIC
4116 if (rs_reg != 0) { // BEQZC
4117 BranchCompactHelper(rs == 0, 21);
4118 } else { // JIC
4119 next_pc = rt + imm16;
4120 }
4121 break;
4122 case POP76: // BNEZC, JIALC
4123 if (rs_reg != 0) { // BNEZC
4124 BranchCompactHelper(rs != 0, 21);
4125 } else { // JIALC
4126 set_register(31, get_pc() + Instruction::kInstrSize);
4127 next_pc = rt + imm16;
4128 }
4129 break;
4130 case BC:
4131 BranchCompactHelper(true, 26);
4132 break;
4133 case BALC:
4134 BranchAndLinkCompactHelper(true, 26);
4135 break;
4136 case POP10: // BOVC, BEQZALC, BEQC / ADDI (pre-r6)
4137 if (IsMipsArchVariant(kMips32r6)) {
4138 if (rs_reg >= rt_reg) { // BOVC
4139 if (HaveSameSign(rs, rt)) {
4140 if (rs > 0) {
4141 BranchCompactHelper(rs > Registers::kMaxValue - rt, 16);
4142 } else if (rs < 0) {
4143 BranchCompactHelper(rs < Registers::kMinValue - rt, 16);
4144 }
4145 }
4146 } else {
4147 if (rs_reg == 0) { // BEQZALC
4148 BranchAndLinkCompactHelper(rt == 0, 16);
4149 } else { // BEQC
4150 BranchCompactHelper(rt == rs, 16);
4151 }
4152 }
4153 } else { // ADDI
4154 if (HaveSameSign(rs, se_imm16)) {
4155 if (rs > 0) {
4156 if (rs <= Registers::kMaxValue - se_imm16) {
4157 SignalException(kIntegerOverflow);
4158 }
4159 } else if (rs < 0) {
4160 if (rs >= Registers::kMinValue - se_imm16) {
4161 SignalException(kIntegerUnderflow);
4162 }
4163 }
4164 }
4165 SetResult(rt_reg, rs + se_imm16);
4166 }
4167 break;
4168 case POP30: // BNVC, BNEZALC, BNEC / DADDI (pre-r6)
4169 if (IsMipsArchVariant(kMips32r6)) {
4170 if (rs_reg >= rt_reg) { // BNVC
4171 if (!HaveSameSign(rs, rt) || rs == 0 || rt == 0) {
4172 BranchCompactHelper(true, 16);
4173 } else {
4174 if (rs > 0) {
4175 BranchCompactHelper(rs <= Registers::kMaxValue - rt, 16);
4176 } else if (rs < 0) {
4177 BranchCompactHelper(rs >= Registers::kMinValue - rt, 16);
4178 }
4179 }
4180 } else {
4181 if (rs_reg == 0) { // BNEZALC
4182 BranchAndLinkCompactHelper(rt != 0, 16);
4183 } else { // BNEC
4184 BranchCompactHelper(rt != rs, 16);
4185 }
Andrei Popescu31002712010-02-23 13:46:05 +00004186 }
4187 }
Andrei Popescu31002712010-02-23 13:46:05 +00004188 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004189 // ------------- Arithmetic instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00004190 case ADDIU:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004191 SetResult(rt_reg, rs + se_imm16);
Andrei Popescu31002712010-02-23 13:46:05 +00004192 break;
4193 case SLTI:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004194 SetResult(rt_reg, rs < se_imm16 ? 1 : 0);
Andrei Popescu31002712010-02-23 13:46:05 +00004195 break;
4196 case SLTIU:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004197 SetResult(rt_reg, rs_u < static_cast<uint32_t>(se_imm16) ? 1 : 0);
Andrei Popescu31002712010-02-23 13:46:05 +00004198 break;
4199 case ANDI:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004200 SetResult(rt_reg, rs & oe_imm16);
Andrei Popescu31002712010-02-23 13:46:05 +00004201 break;
4202 case ORI:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004203 SetResult(rt_reg, rs | oe_imm16);
Andrei Popescu31002712010-02-23 13:46:05 +00004204 break;
4205 case XORI:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004206 SetResult(rt_reg, rs ^ oe_imm16);
Andrei Popescu31002712010-02-23 13:46:05 +00004207 break;
4208 case LUI:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004209 if (rs_reg != 0) {
4210 // AUI
4211 DCHECK(IsMipsArchVariant(kMips32r6));
4212 SetResult(rt_reg, rs + (se_imm16 << 16));
4213 } else {
4214 // LUI
4215 SetResult(rt_reg, oe_imm16 << 16);
4216 }
Andrei Popescu31002712010-02-23 13:46:05 +00004217 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00004218 // ------------- Memory instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00004219 case LB:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004220 set_register(rt_reg, ReadB(rs + se_imm16));
Andrei Popescu31002712010-02-23 13:46:05 +00004221 break;
Steve Block44f0eee2011-05-26 01:26:41 +01004222 case LH:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004223 set_register(rt_reg, ReadH(rs + se_imm16, instr));
Steve Block44f0eee2011-05-26 01:26:41 +01004224 break;
4225 case LWL: {
Ben Murdoch257744e2011-11-30 15:57:28 +00004226 // al_offset is offset of the effective address within an aligned word.
Steve Block44f0eee2011-05-26 01:26:41 +01004227 uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
4228 uint8_t byte_shift = kPointerAlignmentMask - al_offset;
4229 uint32_t mask = (1 << byte_shift * 8) - 1;
4230 addr = rs + se_imm16 - al_offset;
4231 alu_out = ReadW(addr, instr);
4232 alu_out <<= byte_shift * 8;
4233 alu_out |= rt & mask;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004234 set_register(rt_reg, alu_out);
Steve Block44f0eee2011-05-26 01:26:41 +01004235 break;
4236 }
Andrei Popescu31002712010-02-23 13:46:05 +00004237 case LW:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004238 set_register(rt_reg, ReadW(rs + se_imm16, instr));
Andrei Popescu31002712010-02-23 13:46:05 +00004239 break;
4240 case LBU:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004241 set_register(rt_reg, ReadBU(rs + se_imm16));
Andrei Popescu31002712010-02-23 13:46:05 +00004242 break;
Steve Block44f0eee2011-05-26 01:26:41 +01004243 case LHU:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004244 set_register(rt_reg, ReadHU(rs + se_imm16, instr));
Steve Block44f0eee2011-05-26 01:26:41 +01004245 break;
4246 case LWR: {
Ben Murdoch257744e2011-11-30 15:57:28 +00004247 // al_offset is offset of the effective address within an aligned word.
Steve Block44f0eee2011-05-26 01:26:41 +01004248 uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
4249 uint8_t byte_shift = kPointerAlignmentMask - al_offset;
4250 uint32_t mask = al_offset ? (~0 << (byte_shift + 1) * 8) : 0;
4251 addr = rs + se_imm16 - al_offset;
4252 alu_out = ReadW(addr, instr);
4253 alu_out = static_cast<uint32_t> (alu_out) >> al_offset * 8;
4254 alu_out |= rt & mask;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004255 set_register(rt_reg, alu_out);
Steve Block44f0eee2011-05-26 01:26:41 +01004256 break;
4257 }
Andrei Popescu31002712010-02-23 13:46:05 +00004258 case SB:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004259 WriteB(rs + se_imm16, static_cast<int8_t>(rt));
Andrei Popescu31002712010-02-23 13:46:05 +00004260 break;
Steve Block44f0eee2011-05-26 01:26:41 +01004261 case SH:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004262 WriteH(rs + se_imm16, static_cast<uint16_t>(rt), instr);
Steve Block44f0eee2011-05-26 01:26:41 +01004263 break;
4264 case SWL: {
4265 uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
4266 uint8_t byte_shift = kPointerAlignmentMask - al_offset;
4267 uint32_t mask = byte_shift ? (~0 << (al_offset + 1) * 8) : 0;
4268 addr = rs + se_imm16 - al_offset;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004269 // Value to be written in memory.
4270 uint32_t mem_value = ReadW(addr, instr) & mask;
Steve Block44f0eee2011-05-26 01:26:41 +01004271 mem_value |= static_cast<uint32_t>(rt) >> byte_shift * 8;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004272 WriteW(addr, mem_value, instr);
Steve Block44f0eee2011-05-26 01:26:41 +01004273 break;
4274 }
Andrei Popescu31002712010-02-23 13:46:05 +00004275 case SW:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004276 WriteW(rs + se_imm16, rt, instr);
Andrei Popescu31002712010-02-23 13:46:05 +00004277 break;
Steve Block44f0eee2011-05-26 01:26:41 +01004278 case SWR: {
4279 uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
4280 uint32_t mask = (1 << al_offset * 8) - 1;
4281 addr = rs + se_imm16 - al_offset;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004282 uint32_t mem_value = ReadW(addr, instr);
Steve Block44f0eee2011-05-26 01:26:41 +01004283 mem_value = (rt << al_offset * 8) | (mem_value & mask);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004284 WriteW(addr, mem_value, instr);
Steve Block44f0eee2011-05-26 01:26:41 +01004285 break;
4286 }
Andrei Popescu31002712010-02-23 13:46:05 +00004287 case LWC1:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004288 set_fpu_register_hi_word(ft_reg, 0);
4289 set_fpu_register_word(ft_reg, ReadW(rs + se_imm16, instr));
Andrei Popescu31002712010-02-23 13:46:05 +00004290 break;
4291 case LDC1:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004292 set_fpu_register_double(ft_reg, ReadD(rs + se_imm16, instr));
Andrei Popescu31002712010-02-23 13:46:05 +00004293 break;
4294 case SWC1:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004295 WriteW(rs + se_imm16, get_fpu_register_word(ft_reg), instr);
Andrei Popescu31002712010-02-23 13:46:05 +00004296 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004297 case SDC1:
4298 WriteD(rs + se_imm16, get_fpu_register_double(ft_reg), instr);
4299 break;
4300 // ------------- PC-Relative instructions.
4301 case PCREL: {
4302 // rt field: checking 5-bits.
4303 int32_t imm21 = instr->Imm21Value();
4304 int32_t current_pc = get_pc();
4305 uint8_t rt = (imm21 >> kImm16Bits);
4306 switch (rt) {
4307 case ALUIPC:
4308 addr = current_pc + (se_imm16 << 16);
4309 alu_out = static_cast<int64_t>(~0x0FFFF) & addr;
4310 break;
4311 case AUIPC:
4312 alu_out = current_pc + (se_imm16 << 16);
4313 break;
4314 default: {
4315 int32_t imm19 = instr->Imm19Value();
4316 // rt field: checking the most significant 2-bits.
4317 rt = (imm21 >> kImm19Bits);
4318 switch (rt) {
4319 case LWPC: {
4320 // Set sign.
4321 imm19 <<= (kOpcodeBits + kRsBits + 2);
4322 imm19 >>= (kOpcodeBits + kRsBits + 2);
4323 addr = current_pc + (imm19 << 2);
4324 uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
4325 alu_out = *ptr;
4326 break;
4327 }
4328 case ADDIUPC: {
4329 int32_t se_imm19 = imm19 | ((imm19 & 0x40000) ? 0xfff80000 : 0);
4330 alu_out = current_pc + (se_imm19 << 2);
4331 break;
4332 }
4333 default:
4334 UNREACHABLE();
4335 break;
4336 }
4337 }
4338 }
4339 set_register(rs_reg, alu_out);
4340 break;
4341 }
Andrei Popescu31002712010-02-23 13:46:05 +00004342 default:
4343 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004344 }
Andrei Popescu31002712010-02-23 13:46:05 +00004345
Andrei Popescu31002712010-02-23 13:46:05 +00004346 if (execute_branch_delay_instruction) {
4347 // Execute branch delay slot
4348 // We don't check for end_sim_pc. First it should not be met as the current
4349 // pc is valid. Secondly a jump should always execute its branch delay slot.
4350 Instruction* branch_delay_instr =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004351 reinterpret_cast<Instruction*>(get_pc() + Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +00004352 BranchDelayInstructionDecode(branch_delay_instr);
4353 }
4354
4355 // If needed update pc after the branch delay execution.
4356 if (next_pc != bad_ra) {
4357 set_pc(next_pc);
4358 }
4359}
4360
Steve Block44f0eee2011-05-26 01:26:41 +01004361
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004362// Type 3: instructions using a 26 bytes immediate. (e.g. j, jal).
Andrei Popescu31002712010-02-23 13:46:05 +00004363void Simulator::DecodeTypeJump(Instruction* instr) {
4364 // Get current pc.
4365 int32_t current_pc = get_pc();
4366 // Get unchanged bits of pc.
4367 int32_t pc_high_bits = current_pc & 0xf0000000;
Ben Murdoch257744e2011-11-30 15:57:28 +00004368 // Next pc.
Steve Block44f0eee2011-05-26 01:26:41 +01004369 int32_t next_pc = pc_high_bits | (instr->Imm26Value() << 2);
Andrei Popescu31002712010-02-23 13:46:05 +00004370
Ben Murdoch257744e2011-11-30 15:57:28 +00004371 // Execute branch delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00004372 // We don't check for end_sim_pc. First it should not be met as the current pc
4373 // is valid. Secondly a jump should always execute its branch delay slot.
4374 Instruction* branch_delay_instr =
Ben Murdoch257744e2011-11-30 15:57:28 +00004375 reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +00004376 BranchDelayInstructionDecode(branch_delay_instr);
4377
4378 // Update pc and ra if necessary.
4379 // Do this after the branch delay execution.
4380 if (instr->IsLinkingInstruction()) {
Ben Murdoch257744e2011-11-30 15:57:28 +00004381 set_register(31, current_pc + 2 * Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +00004382 }
4383 set_pc(next_pc);
4384 pc_modified_ = true;
4385}
4386
Steve Block44f0eee2011-05-26 01:26:41 +01004387
Andrei Popescu31002712010-02-23 13:46:05 +00004388// Executes the current instruction.
4389void Simulator::InstructionDecode(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +01004390 if (v8::internal::FLAG_check_icache) {
4391 CheckICache(isolate_->simulator_i_cache(), instr);
4392 }
Andrei Popescu31002712010-02-23 13:46:05 +00004393 pc_modified_ = false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004394 v8::internal::EmbeddedVector<char, 256> buffer;
Andrei Popescu31002712010-02-23 13:46:05 +00004395 if (::v8::internal::FLAG_trace_sim) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004396 SNPrintF(trace_buf_, "%s", "");
Andrei Popescu31002712010-02-23 13:46:05 +00004397 disasm::NameConverter converter;
4398 disasm::Disassembler dasm(converter);
Ben Murdoch257744e2011-11-30 15:57:28 +00004399 dasm.InstructionDecode(buffer, reinterpret_cast<byte*>(instr));
Andrei Popescu31002712010-02-23 13:46:05 +00004400 }
4401
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004402 switch (instr->InstructionType(Instruction::TypeChecks::EXTRA)) {
Andrei Popescu31002712010-02-23 13:46:05 +00004403 case Instruction::kRegisterType:
4404 DecodeTypeRegister(instr);
4405 break;
4406 case Instruction::kImmediateType:
4407 DecodeTypeImmediate(instr);
4408 break;
4409 case Instruction::kJumpType:
4410 DecodeTypeJump(instr);
4411 break;
4412 default:
4413 UNSUPPORTED();
4414 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004415 if (::v8::internal::FLAG_trace_sim) {
4416 PrintF(" 0x%08x %-44s %s\n", reinterpret_cast<intptr_t>(instr),
4417 buffer.start(), trace_buf_.start());
4418 }
Andrei Popescu31002712010-02-23 13:46:05 +00004419 if (!pc_modified_) {
4420 set_register(pc, reinterpret_cast<int32_t>(instr) +
Steve Block44f0eee2011-05-26 01:26:41 +01004421 Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +00004422 }
4423}
4424
4425
4426
4427void Simulator::Execute() {
4428 // Get the PC to simulate. Cannot use the accessor here as we need the
4429 // raw PC value and not the one used as input to arithmetic instructions.
4430 int program_counter = get_pc();
4431 if (::v8::internal::FLAG_stop_sim_at == 0) {
4432 // Fast version of the dispatch loop without checking whether the simulator
4433 // should be stopping at a particular executed instruction.
4434 while (program_counter != end_sim_pc) {
4435 Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
4436 icount_++;
4437 InstructionDecode(instr);
4438 program_counter = get_pc();
4439 }
4440 } else {
4441 // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when
4442 // we reach the particular instuction count.
4443 while (program_counter != end_sim_pc) {
4444 Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
4445 icount_++;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004446 if (icount_ == static_cast<uint64_t>(::v8::internal::FLAG_stop_sim_at)) {
Steve Block44f0eee2011-05-26 01:26:41 +01004447 MipsDebugger dbg(this);
Andrei Popescu31002712010-02-23 13:46:05 +00004448 dbg.Debug();
4449 } else {
4450 InstructionDecode(instr);
4451 }
4452 program_counter = get_pc();
4453 }
4454 }
4455}
4456
4457
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004458void Simulator::CallInternal(byte* entry) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004459 // Adjust JS-based stack limit to C-based stack limit.
4460 isolate_->stack_guard()->AdjustStackLimitForSimulator();
4461
Ben Murdoch257744e2011-11-30 15:57:28 +00004462 // Prepare to execute the code at entry.
Andrei Popescu31002712010-02-23 13:46:05 +00004463 set_register(pc, reinterpret_cast<int32_t>(entry));
4464 // Put down marker for end of simulation. The simulator will stop simulation
4465 // when the PC reaches this value. By saving the "end simulation" value into
4466 // the LR the simulation stops when returning to this call point.
4467 set_register(ra, end_sim_pc);
4468
4469 // Remember the values of callee-saved registers.
4470 // The code below assumes that r9 is not used as sb (static base) in
4471 // simulator code and therefore is regarded as a callee-saved register.
4472 int32_t s0_val = get_register(s0);
4473 int32_t s1_val = get_register(s1);
4474 int32_t s2_val = get_register(s2);
4475 int32_t s3_val = get_register(s3);
4476 int32_t s4_val = get_register(s4);
4477 int32_t s5_val = get_register(s5);
4478 int32_t s6_val = get_register(s6);
4479 int32_t s7_val = get_register(s7);
4480 int32_t gp_val = get_register(gp);
4481 int32_t sp_val = get_register(sp);
4482 int32_t fp_val = get_register(fp);
4483
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004484 // Set up the callee-saved registers with a known value. To be able to check
Andrei Popescu31002712010-02-23 13:46:05 +00004485 // that they are preserved properly across JS execution.
4486 int32_t callee_saved_value = icount_;
4487 set_register(s0, callee_saved_value);
4488 set_register(s1, callee_saved_value);
4489 set_register(s2, callee_saved_value);
4490 set_register(s3, callee_saved_value);
4491 set_register(s4, callee_saved_value);
4492 set_register(s5, callee_saved_value);
4493 set_register(s6, callee_saved_value);
4494 set_register(s7, callee_saved_value);
4495 set_register(gp, callee_saved_value);
4496 set_register(fp, callee_saved_value);
4497
Ben Murdoch257744e2011-11-30 15:57:28 +00004498 // Start the simulation.
Andrei Popescu31002712010-02-23 13:46:05 +00004499 Execute();
4500
4501 // Check that the callee-saved registers have been preserved.
4502 CHECK_EQ(callee_saved_value, get_register(s0));
4503 CHECK_EQ(callee_saved_value, get_register(s1));
4504 CHECK_EQ(callee_saved_value, get_register(s2));
4505 CHECK_EQ(callee_saved_value, get_register(s3));
4506 CHECK_EQ(callee_saved_value, get_register(s4));
4507 CHECK_EQ(callee_saved_value, get_register(s5));
4508 CHECK_EQ(callee_saved_value, get_register(s6));
4509 CHECK_EQ(callee_saved_value, get_register(s7));
4510 CHECK_EQ(callee_saved_value, get_register(gp));
4511 CHECK_EQ(callee_saved_value, get_register(fp));
4512
4513 // Restore callee-saved registers with the original value.
4514 set_register(s0, s0_val);
4515 set_register(s1, s1_val);
4516 set_register(s2, s2_val);
4517 set_register(s3, s3_val);
4518 set_register(s4, s4_val);
4519 set_register(s5, s5_val);
4520 set_register(s6, s6_val);
4521 set_register(s7, s7_val);
4522 set_register(gp, gp_val);
4523 set_register(sp, sp_val);
4524 set_register(fp, fp_val);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004525}
4526
4527
4528int32_t Simulator::Call(byte* entry, int argument_count, ...) {
4529 va_list parameters;
4530 va_start(parameters, argument_count);
4531 // Set up arguments.
4532
4533 // First four arguments passed in registers.
4534 DCHECK(argument_count >= 4);
4535 set_register(a0, va_arg(parameters, int32_t));
4536 set_register(a1, va_arg(parameters, int32_t));
4537 set_register(a2, va_arg(parameters, int32_t));
4538 set_register(a3, va_arg(parameters, int32_t));
4539
4540 // Remaining arguments passed on stack.
4541 int original_stack = get_register(sp);
4542 // Compute position of stack on entry to generated code.
4543 int entry_stack = (original_stack - (argument_count - 4) * sizeof(int32_t)
4544 - kCArgsSlotsSize);
4545 if (base::OS::ActivationFrameAlignment() != 0) {
4546 entry_stack &= -base::OS::ActivationFrameAlignment();
4547 }
4548 // Store remaining arguments on stack, from low to high memory.
4549 intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
4550 for (int i = 4; i < argument_count; i++) {
4551 stack_argument[i - 4 + kCArgSlotCount] = va_arg(parameters, int32_t);
4552 }
4553 va_end(parameters);
4554 set_register(sp, entry_stack);
4555
4556 CallInternal(entry);
Andrei Popescu31002712010-02-23 13:46:05 +00004557
4558 // Pop stack passed arguments.
4559 CHECK_EQ(entry_stack, get_register(sp));
4560 set_register(sp, original_stack);
4561
4562 int32_t result = get_register(v0);
4563 return result;
4564}
4565
4566
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004567double Simulator::CallFP(byte* entry, double d0, double d1) {
4568 if (!IsMipsSoftFloatABI) {
4569 set_fpu_register_double(f12, d0);
4570 set_fpu_register_double(f14, d1);
4571 } else {
4572 int buffer[2];
4573 DCHECK(sizeof(buffer[0]) * 2 == sizeof(d0));
4574 memcpy(buffer, &d0, sizeof(d0));
4575 set_dw_register(a0, buffer);
4576 memcpy(buffer, &d1, sizeof(d1));
4577 set_dw_register(a2, buffer);
4578 }
4579 CallInternal(entry);
4580 if (!IsMipsSoftFloatABI) {
4581 return get_fpu_register_double(f0);
4582 } else {
4583 return get_double_from_register_pair(v0);
4584 }
4585}
4586
4587
Andrei Popescu31002712010-02-23 13:46:05 +00004588uintptr_t Simulator::PushAddress(uintptr_t address) {
4589 int new_sp = get_register(sp) - sizeof(uintptr_t);
4590 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp);
4591 *stack_slot = address;
4592 set_register(sp, new_sp);
4593 return new_sp;
4594}
4595
4596
4597uintptr_t Simulator::PopAddress() {
4598 int current_sp = get_register(sp);
4599 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp);
4600 uintptr_t address = *stack_slot;
4601 set_register(sp, current_sp + sizeof(uintptr_t));
4602 return address;
4603}
4604
4605
4606#undef UNSUPPORTED
4607
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004608} // namespace internal
4609} // namespace v8
Andrei Popescu31002712010-02-23 13:46:05 +00004610
Steve Block44f0eee2011-05-26 01:26:41 +01004611#endif // USE_SIMULATOR
Andrei Popescu31002712010-02-23 13:46:05 +00004612
Leon Clarkef7060e22010-06-03 12:02:55 +01004613#endif // V8_TARGET_ARCH_MIPS