blob: 71dcda276646a2bed2257d4d2166b40f82b1a8d2 [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 Murdochc5610432016-08-08 18:44:38 +0100589 PrintF(" 0x%08" PRIxPTR ": 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);
Ben Murdochc5610432016-08-08 18:44:38 +0100652 PrintF(" 0x%08" PRIxPTR " %s\n", reinterpret_cast<intptr_t>(cur),
653 buffer.start());
Steve Block44f0eee2011-05-26 01:26:41 +0100654 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);
Ben Murdochc5610432016-08-08 18:44:38 +0100774 PrintF(" 0x%08" PRIxPTR " %s\n", reinterpret_cast<intptr_t>(cur),
775 buffer.start());
Steve Block44f0eee2011-05-26 01:26:41 +0100776 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
Ben Murdoch61f157c2016-09-16 13:49:30 +0100867void Simulator::FlushICache(base::HashMap* i_cache, void* start_addr,
Steve Block44f0eee2011-05-26 01:26:41 +0100868 size_t size) {
869 intptr_t start = reinterpret_cast<intptr_t>(start_addr);
870 int intra_line = (start & CachePage::kLineMask);
871 start -= intra_line;
872 size += intra_line;
873 size = ((size - 1) | CachePage::kLineMask) + 1;
874 int offset = (start & CachePage::kPageMask);
875 while (!AllOnOnePage(start, size - 1)) {
876 int bytes_to_flush = CachePage::kPageSize - offset;
877 FlushOnePage(i_cache, start, bytes_to_flush);
878 start += bytes_to_flush;
879 size -= bytes_to_flush;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000880 DCHECK_EQ(0, start & CachePage::kPageMask);
Steve Block44f0eee2011-05-26 01:26:41 +0100881 offset = 0;
882 }
883 if (size != 0) {
884 FlushOnePage(i_cache, start, size);
885 }
886}
887
Ben Murdoch61f157c2016-09-16 13:49:30 +0100888CachePage* Simulator::GetCachePage(base::HashMap* i_cache, void* page) {
889 base::HashMap::Entry* entry = i_cache->LookupOrInsert(page, ICacheHash(page));
Steve Block44f0eee2011-05-26 01:26:41 +0100890 if (entry->value == NULL) {
891 CachePage* new_page = new CachePage();
892 entry->value = new_page;
893 }
894 return reinterpret_cast<CachePage*>(entry->value);
895}
896
897
898// Flush from start up to and not including start + size.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100899void Simulator::FlushOnePage(base::HashMap* i_cache, intptr_t start, int size) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000900 DCHECK(size <= CachePage::kPageSize);
901 DCHECK(AllOnOnePage(start, size - 1));
902 DCHECK((start & CachePage::kLineMask) == 0);
903 DCHECK((size & CachePage::kLineMask) == 0);
Steve Block44f0eee2011-05-26 01:26:41 +0100904 void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask));
905 int offset = (start & CachePage::kPageMask);
906 CachePage* cache_page = GetCachePage(i_cache, page);
907 char* valid_bytemap = cache_page->ValidityByte(offset);
908 memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift);
909}
910
Ben Murdoch61f157c2016-09-16 13:49:30 +0100911void Simulator::CheckICache(base::HashMap* i_cache, Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100912 intptr_t address = reinterpret_cast<intptr_t>(instr);
913 void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
914 void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask));
915 int offset = (address & CachePage::kPageMask);
916 CachePage* cache_page = GetCachePage(i_cache, page);
917 char* cache_valid_byte = cache_page->ValidityByte(offset);
918 bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID);
919 char* cached_line = cache_page->CachedData(offset & ~CachePage::kLineMask);
920 if (cache_hit) {
921 // Check that the data in memory matches the contents of the I-cache.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000922 CHECK_EQ(0, memcmp(reinterpret_cast<void*>(instr),
923 cache_page->CachedData(offset),
924 Instruction::kInstrSize));
Steve Block44f0eee2011-05-26 01:26:41 +0100925 } else {
926 // Cache miss. Load memory into the cache.
927 memcpy(cached_line, line, CachePage::kLineLength);
928 *cache_valid_byte = CachePage::LINE_VALID;
929 }
930}
Andrei Popescu31002712010-02-23 13:46:05 +0000931
932
Ben Murdoch257744e2011-11-30 15:57:28 +0000933void Simulator::Initialize(Isolate* isolate) {
934 if (isolate->simulator_initialized()) return;
935 isolate->set_simulator_initialized(true);
936 ::v8::internal::ExternalReference::set_redirector(isolate,
937 &RedirectExternalReference);
Andrei Popescu31002712010-02-23 13:46:05 +0000938}
939
940
Ben Murdoch257744e2011-11-30 15:57:28 +0000941Simulator::Simulator(Isolate* isolate) : isolate_(isolate) {
Steve Block44f0eee2011-05-26 01:26:41 +0100942 i_cache_ = isolate_->simulator_i_cache();
943 if (i_cache_ == NULL) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100944 i_cache_ = new base::HashMap(&ICacheMatch);
Steve Block44f0eee2011-05-26 01:26:41 +0100945 isolate_->set_simulator_i_cache(i_cache_);
946 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000947 Initialize(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100948 // Set up simulator support first. Some of this information is needed to
Andrei Popescu31002712010-02-23 13:46:05 +0000949 // setup the architecture state.
Steve Block44f0eee2011-05-26 01:26:41 +0100950 stack_ = reinterpret_cast<char*>(malloc(stack_size_));
Andrei Popescu31002712010-02-23 13:46:05 +0000951 pc_modified_ = false;
952 icount_ = 0;
Steve Block44f0eee2011-05-26 01:26:41 +0100953 break_count_ = 0;
Andrei Popescu31002712010-02-23 13:46:05 +0000954 break_pc_ = NULL;
955 break_instr_ = 0;
956
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100957 // Set up architecture state.
Andrei Popescu31002712010-02-23 13:46:05 +0000958 // All registers are initialized to zero to start with.
959 for (int i = 0; i < kNumSimuRegisters; i++) {
960 registers_[i] = 0;
961 }
Steve Block44f0eee2011-05-26 01:26:41 +0100962 for (int i = 0; i < kNumFPURegisters; i++) {
963 FPUregisters_[i] = 0;
964 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000965 if (IsMipsArchVariant(kMips32r6)) {
966 FCSR_ = kFCSRNaN2008FlagMask;
967 } else {
968 DCHECK(IsMipsArchVariant(kMips32r1) || IsMipsArchVariant(kMips32r2));
969 FCSR_ = 0;
970 }
Andrei Popescu31002712010-02-23 13:46:05 +0000971
972 // The sp is initialized to point to the bottom (high address) of the
973 // allocated stack area. To be safe in potential stack underflows we leave
974 // some buffer below.
Steve Block44f0eee2011-05-26 01:26:41 +0100975 registers_[sp] = reinterpret_cast<int32_t>(stack_) + stack_size_ - 64;
Andrei Popescu31002712010-02-23 13:46:05 +0000976 // The ra and pc are initialized to a known bad value that will cause an
977 // access violation if the simulator ever tries to execute it.
978 registers_[pc] = bad_ra;
979 registers_[ra] = bad_ra;
980 InitializeCoverage();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100981 last_debugger_input_ = NULL;
Andrei Popescu31002712010-02-23 13:46:05 +0000982}
983
984
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000985Simulator::~Simulator() { free(stack_); }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000986
987
Andrei Popescu31002712010-02-23 13:46:05 +0000988// When the generated code calls an external reference we need to catch that in
989// the simulator. The external reference will be a function compiled for the
990// host architecture. We need to call that function instead of trying to
991// execute it with the simulator. We do that by redirecting the external
992// reference to a swi (software-interrupt) instruction that is handled by
993// the simulator. We write the original destination of the jump just at a known
994// offset from the swi instruction so the simulator knows what to call.
995class Redirection {
996 public:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000997 Redirection(Isolate* isolate, void* external_function,
998 ExternalReference::Type type)
Andrei Popescu31002712010-02-23 13:46:05 +0000999 : external_function_(external_function),
1000 swi_instruction_(rtCallRedirInstr),
Steve Block44f0eee2011-05-26 01:26:41 +01001001 type_(type),
1002 next_(NULL) {
Steve Block44f0eee2011-05-26 01:26:41 +01001003 next_ = isolate->simulator_redirection();
1004 Simulator::current(isolate)->
1005 FlushICache(isolate->simulator_i_cache(),
1006 reinterpret_cast<void*>(&swi_instruction_),
1007 Instruction::kInstrSize);
1008 isolate->set_simulator_redirection(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001009 }
1010
1011 void* address_of_swi_instruction() {
1012 return reinterpret_cast<void*>(&swi_instruction_);
1013 }
1014
1015 void* external_function() { return external_function_; }
Steve Block44f0eee2011-05-26 01:26:41 +01001016 ExternalReference::Type type() { return type_; }
Andrei Popescu31002712010-02-23 13:46:05 +00001017
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001018 static Redirection* Get(Isolate* isolate, void* external_function,
Steve Block44f0eee2011-05-26 01:26:41 +01001019 ExternalReference::Type type) {
Steve Block44f0eee2011-05-26 01:26:41 +01001020 Redirection* current = isolate->simulator_redirection();
1021 for (; current != NULL; current = current->next_) {
Andrei Popescu31002712010-02-23 13:46:05 +00001022 if (current->external_function_ == external_function) return current;
1023 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001024 return new Redirection(isolate, external_function, type);
Andrei Popescu31002712010-02-23 13:46:05 +00001025 }
1026
1027 static Redirection* FromSwiInstruction(Instruction* swi_instruction) {
1028 char* addr_of_swi = reinterpret_cast<char*>(swi_instruction);
1029 char* addr_of_redirection =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001030 addr_of_swi - offsetof(Redirection, swi_instruction_);
Andrei Popescu31002712010-02-23 13:46:05 +00001031 return reinterpret_cast<Redirection*>(addr_of_redirection);
1032 }
1033
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001034 static void* ReverseRedirection(int32_t reg) {
1035 Redirection* redirection = FromSwiInstruction(
1036 reinterpret_cast<Instruction*>(reinterpret_cast<void*>(reg)));
1037 return redirection->external_function();
1038 }
1039
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001040 static void DeleteChain(Redirection* redirection) {
1041 while (redirection != nullptr) {
1042 Redirection* next = redirection->next_;
1043 delete redirection;
1044 redirection = next;
1045 }
1046 }
1047
Andrei Popescu31002712010-02-23 13:46:05 +00001048 private:
1049 void* external_function_;
1050 uint32_t swi_instruction_;
Steve Block44f0eee2011-05-26 01:26:41 +01001051 ExternalReference::Type type_;
Andrei Popescu31002712010-02-23 13:46:05 +00001052 Redirection* next_;
Andrei Popescu31002712010-02-23 13:46:05 +00001053};
1054
1055
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001056// static
Ben Murdoch61f157c2016-09-16 13:49:30 +01001057void Simulator::TearDown(base::HashMap* i_cache, Redirection* first) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001058 Redirection::DeleteChain(first);
1059 if (i_cache != nullptr) {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001060 for (base::HashMap::Entry* entry = i_cache->Start(); entry != nullptr;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001061 entry = i_cache->Next(entry)) {
1062 delete static_cast<CachePage*>(entry->value);
1063 }
1064 delete i_cache;
1065 }
1066}
1067
1068
1069void* Simulator::RedirectExternalReference(Isolate* isolate,
1070 void* external_function,
Steve Block44f0eee2011-05-26 01:26:41 +01001071 ExternalReference::Type type) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001072 Redirection* redirection = Redirection::Get(isolate, external_function, type);
Andrei Popescu31002712010-02-23 13:46:05 +00001073 return redirection->address_of_swi_instruction();
1074}
1075
1076
1077// Get the active Simulator for the current thread.
Steve Block44f0eee2011-05-26 01:26:41 +01001078Simulator* Simulator::current(Isolate* isolate) {
1079 v8::internal::Isolate::PerIsolateThreadData* isolate_data =
Ben Murdoch257744e2011-11-30 15:57:28 +00001080 isolate->FindOrAllocatePerThreadDataForThisThread();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001081 DCHECK(isolate_data != NULL);
1082 DCHECK(isolate_data != NULL);
Steve Block44f0eee2011-05-26 01:26:41 +01001083
1084 Simulator* sim = isolate_data->simulator();
Andrei Popescu31002712010-02-23 13:46:05 +00001085 if (sim == NULL) {
Steve Block44f0eee2011-05-26 01:26:41 +01001086 // TODO(146): delete the simulator object when a thread/isolate goes away.
Ben Murdoch257744e2011-11-30 15:57:28 +00001087 sim = new Simulator(isolate);
Steve Block44f0eee2011-05-26 01:26:41 +01001088 isolate_data->set_simulator(sim);
Andrei Popescu31002712010-02-23 13:46:05 +00001089 }
1090 return sim;
1091}
1092
1093
1094// Sets the register in the architecture state. It will also deal with updating
1095// Simulator internal state for special registers such as PC.
1096void Simulator::set_register(int reg, int32_t value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001097 DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
Andrei Popescu31002712010-02-23 13:46:05 +00001098 if (reg == pc) {
1099 pc_modified_ = true;
1100 }
1101
Ben Murdoch257744e2011-11-30 15:57:28 +00001102 // Zero register always holds 0.
Andrei Popescu31002712010-02-23 13:46:05 +00001103 registers_[reg] = (reg == 0) ? 0 : value;
1104}
1105
Steve Block44f0eee2011-05-26 01:26:41 +01001106
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001107void Simulator::set_dw_register(int reg, const int* dbl) {
1108 DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
1109 registers_[reg] = dbl[0];
1110 registers_[reg + 1] = dbl[1];
1111}
1112
1113
1114void Simulator::set_fpu_register(int fpureg, int64_t value) {
1115 DCHECK(IsFp64Mode());
1116 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
Andrei Popescu31002712010-02-23 13:46:05 +00001117 FPUregisters_[fpureg] = value;
1118}
1119
Steve Block44f0eee2011-05-26 01:26:41 +01001120
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001121void Simulator::set_fpu_register_word(int fpureg, int32_t value) {
1122 // Set ONLY lower 32-bits, leaving upper bits untouched.
1123 // TODO(plind): big endian issue.
1124 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1125 int32_t *pword = reinterpret_cast<int32_t*>(&FPUregisters_[fpureg]);
1126 *pword = value;
1127}
1128
1129
1130void Simulator::set_fpu_register_hi_word(int fpureg, int32_t value) {
1131 // Set ONLY upper 32-bits, leaving lower bits untouched.
1132 // TODO(plind): big endian issue.
1133 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1134 int32_t *phiword = (reinterpret_cast<int32_t*>(&FPUregisters_[fpureg])) + 1;
1135 *phiword = value;
1136}
1137
1138
Steve Block44f0eee2011-05-26 01:26:41 +01001139void Simulator::set_fpu_register_float(int fpureg, float value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001140 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1141 *bit_cast<float*>(&FPUregisters_[fpureg]) = value;
Steve Block44f0eee2011-05-26 01:26:41 +01001142}
1143
1144
Andrei Popescu31002712010-02-23 13:46:05 +00001145void Simulator::set_fpu_register_double(int fpureg, double value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001146 if (IsFp64Mode()) {
1147 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1148 *bit_cast<double*>(&FPUregisters_[fpureg]) = value;
1149 } else {
1150 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
1151 int64_t i64 = bit_cast<int64_t>(value);
1152 set_fpu_register_word(fpureg, i64 & 0xffffffff);
1153 set_fpu_register_word(fpureg + 1, i64 >> 32);
1154 }
Andrei Popescu31002712010-02-23 13:46:05 +00001155}
1156
1157
1158// Get the register from the architecture state. This function does handle
1159// the special case of accessing the PC register.
1160int32_t Simulator::get_register(int reg) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001161 DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
Andrei Popescu31002712010-02-23 13:46:05 +00001162 if (reg == 0)
1163 return 0;
1164 else
1165 return registers_[reg] + ((reg == pc) ? Instruction::kPCReadOffset : 0);
1166}
1167
Steve Block44f0eee2011-05-26 01:26:41 +01001168
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001169double Simulator::get_double_from_register_pair(int reg) {
1170 // TODO(plind): bad ABI stuff, refactor or remove.
1171 DCHECK((reg >= 0) && (reg < kNumSimuRegisters) && ((reg % 2) == 0));
1172
1173 double dm_val = 0.0;
1174 // Read the bits from the unsigned integer register_[] array
1175 // into the double precision floating point value and return it.
1176 char buffer[2 * sizeof(registers_[0])];
1177 memcpy(buffer, &registers_[reg], 2 * sizeof(registers_[0]));
1178 memcpy(&dm_val, buffer, 2 * sizeof(registers_[0]));
1179 return(dm_val);
1180}
1181
1182
1183int64_t Simulator::get_fpu_register(int fpureg) const {
1184 DCHECK(IsFp64Mode());
1185 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
Andrei Popescu31002712010-02-23 13:46:05 +00001186 return FPUregisters_[fpureg];
1187}
1188
Steve Block44f0eee2011-05-26 01:26:41 +01001189
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001190int32_t Simulator::get_fpu_register_word(int fpureg) const {
1191 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1192 return static_cast<int32_t>(FPUregisters_[fpureg] & 0xffffffff);
1193}
1194
1195
1196int32_t Simulator::get_fpu_register_signed_word(int fpureg) const {
1197 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1198 return static_cast<int32_t>(FPUregisters_[fpureg] & 0xffffffff);
1199}
1200
1201
1202int32_t Simulator::get_fpu_register_hi_word(int fpureg) const {
1203 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1204 return static_cast<int32_t>((FPUregisters_[fpureg] >> 32) & 0xffffffff);
Steve Block44f0eee2011-05-26 01:26:41 +01001205}
1206
1207
1208float Simulator::get_fpu_register_float(int fpureg) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001209 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1210 return *bit_cast<float*>(const_cast<int64_t*>(&FPUregisters_[fpureg]));
Steve Block44f0eee2011-05-26 01:26:41 +01001211}
1212
1213
Andrei Popescu31002712010-02-23 13:46:05 +00001214double Simulator::get_fpu_register_double(int fpureg) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001215 if (IsFp64Mode()) {
1216 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1217 return *bit_cast<double*>(&FPUregisters_[fpureg]);
1218 } else {
1219 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
1220 int64_t i64;
1221 i64 = static_cast<uint32_t>(get_fpu_register_word(fpureg));
1222 i64 |= static_cast<uint64_t>(get_fpu_register_word(fpureg + 1)) << 32;
1223 return bit_cast<double>(i64);
1224 }
Andrei Popescu31002712010-02-23 13:46:05 +00001225}
1226
Steve Block44f0eee2011-05-26 01:26:41 +01001227
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001228// Runtime FP routines take up to two double arguments and zero
1229// or one integer arguments. All are constructed here,
Ben Murdoch257744e2011-11-30 15:57:28 +00001230// from a0-a3 or f12 and f14.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001231void Simulator::GetFpArgs(double* x, double* y, int32_t* z) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001232 if (!IsMipsSoftFloatABI) {
1233 *x = get_fpu_register_double(12);
1234 *y = get_fpu_register_double(14);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001235 *z = get_register(a2);
Ben Murdoch257744e2011-11-30 15:57:28 +00001236 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001237 // TODO(plind): bad ABI stuff, refactor or remove.
Ben Murdoch257744e2011-11-30 15:57:28 +00001238 // We use a char buffer to get around the strict-aliasing rules which
1239 // otherwise allow the compiler to optimize away the copy.
1240 char buffer[sizeof(*x)];
1241 int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
1242
1243 // Registers a0 and a1 -> x.
1244 reg_buffer[0] = get_register(a0);
1245 reg_buffer[1] = get_register(a1);
1246 memcpy(x, buffer, sizeof(buffer));
Ben Murdoch257744e2011-11-30 15:57:28 +00001247 // Registers a2 and a3 -> y.
1248 reg_buffer[0] = get_register(a2);
1249 reg_buffer[1] = get_register(a3);
1250 memcpy(y, buffer, sizeof(buffer));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001251 // Register 2 -> z.
Ben Murdoch257744e2011-11-30 15:57:28 +00001252 reg_buffer[0] = get_register(a2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001253 memcpy(z, buffer, sizeof(*z));
Ben Murdoch257744e2011-11-30 15:57:28 +00001254 }
1255}
1256
1257
1258// The return value is either in v0/v1 or f0.
1259void Simulator::SetFpResult(const double& result) {
1260 if (!IsMipsSoftFloatABI) {
1261 set_fpu_register_double(0, result);
1262 } else {
1263 char buffer[2 * sizeof(registers_[0])];
1264 int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
1265 memcpy(buffer, &result, sizeof(buffer));
1266 // Copy result to v0 and v1.
1267 set_register(v0, reg_buffer[0]);
1268 set_register(v1, reg_buffer[1]);
1269 }
1270}
1271
1272
Steve Block44f0eee2011-05-26 01:26:41 +01001273// Helper functions for setting and testing the FCSR register's bits.
1274void Simulator::set_fcsr_bit(uint32_t cc, bool value) {
1275 if (value) {
1276 FCSR_ |= (1 << cc);
1277 } else {
1278 FCSR_ &= ~(1 << cc);
1279 }
1280}
1281
1282
1283bool Simulator::test_fcsr_bit(uint32_t cc) {
1284 return FCSR_ & (1 << cc);
1285}
1286
1287
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001288void Simulator::set_fcsr_rounding_mode(FPURoundingMode mode) {
1289 FCSR_ |= mode & kFPURoundingModeMask;
1290}
1291
1292
1293unsigned int Simulator::get_fcsr_rounding_mode() {
1294 return FCSR_ & kFPURoundingModeMask;
1295}
1296
1297
1298void Simulator::set_fpu_register_word_invalid_result(float original,
1299 float rounded) {
1300 if (FCSR_ & kFCSRNaN2008FlagMask) {
1301 double max_int32 = std::numeric_limits<int32_t>::max();
1302 double min_int32 = std::numeric_limits<int32_t>::min();
1303 if (std::isnan(original)) {
1304 set_fpu_register_word(fd_reg(), 0);
1305 } else if (rounded > max_int32) {
1306 set_fpu_register_word(fd_reg(), kFPUInvalidResult);
1307 } else if (rounded < min_int32) {
1308 set_fpu_register_word(fd_reg(), kFPUInvalidResultNegative);
1309 } else {
1310 UNREACHABLE();
1311 }
1312 } else {
1313 set_fpu_register_word(fd_reg(), kFPUInvalidResult);
1314 }
1315}
1316
1317
1318void Simulator::set_fpu_register_invalid_result(float original, float rounded) {
1319 if (FCSR_ & kFCSRNaN2008FlagMask) {
1320 double max_int32 = std::numeric_limits<int32_t>::max();
1321 double min_int32 = std::numeric_limits<int32_t>::min();
1322 if (std::isnan(original)) {
1323 set_fpu_register(fd_reg(), 0);
1324 } else if (rounded > max_int32) {
1325 set_fpu_register(fd_reg(), kFPUInvalidResult);
1326 } else if (rounded < min_int32) {
1327 set_fpu_register(fd_reg(), kFPUInvalidResultNegative);
1328 } else {
1329 UNREACHABLE();
1330 }
1331 } else {
1332 set_fpu_register(fd_reg(), kFPUInvalidResult);
1333 }
1334}
1335
1336
1337void Simulator::set_fpu_register_invalid_result64(float original,
1338 float rounded) {
1339 if (FCSR_ & kFCSRNaN2008FlagMask) {
1340 // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1341 // loading the most accurate representation into max_int64, which is 2^63.
1342 double max_int64 = std::numeric_limits<int64_t>::max();
1343 double min_int64 = std::numeric_limits<int64_t>::min();
1344 if (std::isnan(original)) {
1345 set_fpu_register(fd_reg(), 0);
1346 } else if (rounded >= max_int64) {
1347 set_fpu_register(fd_reg(), kFPU64InvalidResult);
1348 } else if (rounded < min_int64) {
1349 set_fpu_register(fd_reg(), kFPU64InvalidResultNegative);
1350 } else {
1351 UNREACHABLE();
1352 }
1353 } else {
1354 set_fpu_register(fd_reg(), kFPU64InvalidResult);
1355 }
1356}
1357
1358
1359void Simulator::set_fpu_register_word_invalid_result(double original,
1360 double rounded) {
1361 if (FCSR_ & kFCSRNaN2008FlagMask) {
1362 double max_int32 = std::numeric_limits<int32_t>::max();
1363 double min_int32 = std::numeric_limits<int32_t>::min();
1364 if (std::isnan(original)) {
1365 set_fpu_register_word(fd_reg(), 0);
1366 } else if (rounded > max_int32) {
1367 set_fpu_register_word(fd_reg(), kFPUInvalidResult);
1368 } else if (rounded < min_int32) {
1369 set_fpu_register_word(fd_reg(), kFPUInvalidResultNegative);
1370 } else {
1371 UNREACHABLE();
1372 }
1373 } else {
1374 set_fpu_register_word(fd_reg(), kFPUInvalidResult);
1375 }
1376}
1377
1378
1379void Simulator::set_fpu_register_invalid_result(double original,
1380 double rounded) {
1381 if (FCSR_ & kFCSRNaN2008FlagMask) {
1382 double max_int32 = std::numeric_limits<int32_t>::max();
1383 double min_int32 = std::numeric_limits<int32_t>::min();
1384 if (std::isnan(original)) {
1385 set_fpu_register(fd_reg(), 0);
1386 } else if (rounded > max_int32) {
1387 set_fpu_register(fd_reg(), kFPUInvalidResult);
1388 } else if (rounded < min_int32) {
1389 set_fpu_register(fd_reg(), kFPUInvalidResultNegative);
1390 } else {
1391 UNREACHABLE();
1392 }
1393 } else {
1394 set_fpu_register(fd_reg(), kFPUInvalidResult);
1395 }
1396}
1397
1398
1399void Simulator::set_fpu_register_invalid_result64(double original,
1400 double rounded) {
1401 if (FCSR_ & kFCSRNaN2008FlagMask) {
1402 // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1403 // loading the most accurate representation into max_int64, which is 2^63.
1404 double max_int64 = std::numeric_limits<int64_t>::max();
1405 double min_int64 = std::numeric_limits<int64_t>::min();
1406 if (std::isnan(original)) {
1407 set_fpu_register(fd_reg(), 0);
1408 } else if (rounded >= max_int64) {
1409 set_fpu_register(fd_reg(), kFPU64InvalidResult);
1410 } else if (rounded < min_int64) {
1411 set_fpu_register(fd_reg(), kFPU64InvalidResultNegative);
1412 } else {
1413 UNREACHABLE();
1414 }
1415 } else {
1416 set_fpu_register(fd_reg(), kFPU64InvalidResult);
1417 }
1418}
1419
1420
Steve Block44f0eee2011-05-26 01:26:41 +01001421// Sets the rounding error codes in FCSR based on the result of the rounding.
1422// Returns true if the operation was invalid.
1423bool Simulator::set_fcsr_round_error(double original, double rounded) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001424 bool ret = false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001425 double max_int32 = std::numeric_limits<int32_t>::max();
1426 double min_int32 = std::numeric_limits<int32_t>::min();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001427
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001428 if (!std::isfinite(original) || !std::isfinite(rounded)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001429 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1430 ret = true;
Steve Block44f0eee2011-05-26 01:26:41 +01001431 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001432
1433 if (original != rounded) {
1434 set_fcsr_bit(kFCSRInexactFlagBit, true);
1435 }
1436
1437 if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) {
1438 set_fcsr_bit(kFCSRUnderflowFlagBit, true);
1439 ret = true;
1440 }
1441
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001442 if (rounded > max_int32 || rounded < min_int32) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001443 set_fcsr_bit(kFCSROverflowFlagBit, true);
1444 // The reference is not really clear but it seems this is required:
1445 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1446 ret = true;
1447 }
1448
1449 return ret;
Steve Block44f0eee2011-05-26 01:26:41 +01001450}
1451
1452
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001453// Sets the rounding error codes in FCSR based on the result of the rounding.
1454// Returns true if the operation was invalid.
1455bool Simulator::set_fcsr_round64_error(double original, double rounded) {
1456 bool ret = false;
1457 // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1458 // loading the most accurate representation into max_int64, which is 2^63.
1459 double max_int64 = std::numeric_limits<int64_t>::max();
1460 double min_int64 = std::numeric_limits<int64_t>::min();
1461
1462 if (!std::isfinite(original) || !std::isfinite(rounded)) {
1463 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1464 ret = true;
1465 }
1466
1467 if (original != rounded) {
1468 set_fcsr_bit(kFCSRInexactFlagBit, true);
1469 }
1470
1471 if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) {
1472 set_fcsr_bit(kFCSRUnderflowFlagBit, true);
1473 ret = true;
1474 }
1475
1476 if (rounded >= max_int64 || rounded < min_int64) {
1477 set_fcsr_bit(kFCSROverflowFlagBit, true);
1478 // The reference is not really clear but it seems this is required:
1479 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1480 ret = true;
1481 }
1482
1483 return ret;
1484}
1485
1486
1487// Sets the rounding error codes in FCSR based on the result of the rounding.
1488// Returns true if the operation was invalid.
1489bool Simulator::set_fcsr_round_error(float original, float rounded) {
1490 bool ret = false;
1491 double max_int32 = std::numeric_limits<int32_t>::max();
1492 double min_int32 = std::numeric_limits<int32_t>::min();
1493
1494 if (!std::isfinite(original) || !std::isfinite(rounded)) {
1495 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1496 ret = true;
1497 }
1498
1499 if (original != rounded) {
1500 set_fcsr_bit(kFCSRInexactFlagBit, true);
1501 }
1502
1503 if (rounded < FLT_MIN && rounded > -FLT_MIN && rounded != 0) {
1504 set_fcsr_bit(kFCSRUnderflowFlagBit, true);
1505 ret = true;
1506 }
1507
1508 if (rounded > max_int32 || rounded < min_int32) {
1509 set_fcsr_bit(kFCSROverflowFlagBit, true);
1510 // The reference is not really clear but it seems this is required:
1511 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1512 ret = true;
1513 }
1514
1515 return ret;
1516}
1517
1518
1519// Sets the rounding error codes in FCSR based on the result of the rounding.
1520// Returns true if the operation was invalid.
1521bool Simulator::set_fcsr_round64_error(float original, float rounded) {
1522 bool ret = false;
1523 // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1524 // loading the most accurate representation into max_int64, which is 2^63.
1525 double max_int64 = std::numeric_limits<int64_t>::max();
1526 double min_int64 = std::numeric_limits<int64_t>::min();
1527
1528 if (!std::isfinite(original) || !std::isfinite(rounded)) {
1529 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1530 ret = true;
1531 }
1532
1533 if (original != rounded) {
1534 set_fcsr_bit(kFCSRInexactFlagBit, true);
1535 }
1536
1537 if (rounded < FLT_MIN && rounded > -FLT_MIN && rounded != 0) {
1538 set_fcsr_bit(kFCSRUnderflowFlagBit, true);
1539 ret = true;
1540 }
1541
1542 if (rounded >= max_int64 || rounded < min_int64) {
1543 set_fcsr_bit(kFCSROverflowFlagBit, true);
1544 // The reference is not really clear but it seems this is required:
1545 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1546 ret = true;
1547 }
1548
1549 return ret;
1550}
1551
1552
1553void Simulator::round_according_to_fcsr(double toRound, double& rounded,
1554 int32_t& rounded_int, double fs) {
1555 // 0 RN (round to nearest): Round a result to the nearest
1556 // representable value; if the result is exactly halfway between
1557 // two representable values, round to zero. Behave like round_w_d.
1558
1559 // 1 RZ (round toward zero): Round a result to the closest
1560 // representable value whose absolute value is less than or
1561 // equal to the infinitely accurate result. Behave like trunc_w_d.
1562
1563 // 2 RP (round up, or toward infinity): Round a result to the
1564 // next representable value up. Behave like ceil_w_d.
1565
1566 // 3 RD (round down, or toward −infinity): Round a result to
1567 // the next representable value down. Behave like floor_w_d.
1568 switch (get_fcsr_rounding_mode()) {
1569 case kRoundToNearest:
1570 rounded = std::floor(fs + 0.5);
1571 rounded_int = static_cast<int32_t>(rounded);
1572 if ((rounded_int & 1) != 0 && rounded_int - fs == 0.5) {
1573 // If the number is halfway between two integers,
1574 // round to the even one.
1575 rounded_int--;
1576 }
1577 break;
1578 case kRoundToZero:
1579 rounded = trunc(fs);
1580 rounded_int = static_cast<int32_t>(rounded);
1581 break;
1582 case kRoundToPlusInf:
1583 rounded = std::ceil(fs);
1584 rounded_int = static_cast<int32_t>(rounded);
1585 break;
1586 case kRoundToMinusInf:
1587 rounded = std::floor(fs);
1588 rounded_int = static_cast<int32_t>(rounded);
1589 break;
1590 }
1591}
1592
1593
1594void Simulator::round_according_to_fcsr(float toRound, float& rounded,
1595 int32_t& rounded_int, float fs) {
1596 // 0 RN (round to nearest): Round a result to the nearest
1597 // representable value; if the result is exactly halfway between
1598 // two representable values, round to zero. Behave like round_w_d.
1599
1600 // 1 RZ (round toward zero): Round a result to the closest
1601 // representable value whose absolute value is less than or
1602 // equal to the infinitely accurate result. Behave like trunc_w_d.
1603
1604 // 2 RP (round up, or toward infinity): Round a result to the
1605 // next representable value up. Behave like ceil_w_d.
1606
1607 // 3 RD (round down, or toward −infinity): Round a result to
1608 // the next representable value down. Behave like floor_w_d.
1609 switch (get_fcsr_rounding_mode()) {
1610 case kRoundToNearest:
1611 rounded = std::floor(fs + 0.5);
1612 rounded_int = static_cast<int32_t>(rounded);
1613 if ((rounded_int & 1) != 0 && rounded_int - fs == 0.5) {
1614 // If the number is halfway between two integers,
1615 // round to the even one.
1616 rounded_int--;
1617 }
1618 break;
1619 case kRoundToZero:
1620 rounded = trunc(fs);
1621 rounded_int = static_cast<int32_t>(rounded);
1622 break;
1623 case kRoundToPlusInf:
1624 rounded = std::ceil(fs);
1625 rounded_int = static_cast<int32_t>(rounded);
1626 break;
1627 case kRoundToMinusInf:
1628 rounded = std::floor(fs);
1629 rounded_int = static_cast<int32_t>(rounded);
1630 break;
1631 }
1632}
1633
1634
1635void Simulator::round64_according_to_fcsr(double toRound, double& rounded,
1636 int64_t& rounded_int, double fs) {
1637 // 0 RN (round to nearest): Round a result to the nearest
1638 // representable value; if the result is exactly halfway between
1639 // two representable values, round to zero. Behave like round_w_d.
1640
1641 // 1 RZ (round toward zero): Round a result to the closest
1642 // representable value whose absolute value is less than or.
1643 // equal to the infinitely accurate result. Behave like trunc_w_d.
1644
1645 // 2 RP (round up, or toward +infinity): Round a result to the
1646 // next representable value up. Behave like ceil_w_d.
1647
1648 // 3 RN (round down, or toward −infinity): Round a result to
1649 // the next representable value down. Behave like floor_w_d.
1650 switch (FCSR_ & 3) {
1651 case kRoundToNearest:
1652 rounded = std::floor(fs + 0.5);
1653 rounded_int = static_cast<int64_t>(rounded);
1654 if ((rounded_int & 1) != 0 && rounded_int - fs == 0.5) {
1655 // If the number is halfway between two integers,
1656 // round to the even one.
1657 rounded_int--;
1658 }
1659 break;
1660 case kRoundToZero:
1661 rounded = trunc(fs);
1662 rounded_int = static_cast<int64_t>(rounded);
1663 break;
1664 case kRoundToPlusInf:
1665 rounded = std::ceil(fs);
1666 rounded_int = static_cast<int64_t>(rounded);
1667 break;
1668 case kRoundToMinusInf:
1669 rounded = std::floor(fs);
1670 rounded_int = static_cast<int64_t>(rounded);
1671 break;
1672 }
1673}
1674
1675
1676void Simulator::round64_according_to_fcsr(float toRound, float& rounded,
1677 int64_t& rounded_int, float fs) {
1678 // 0 RN (round to nearest): Round a result to the nearest
1679 // representable value; if the result is exactly halfway between
1680 // two representable values, round to zero. Behave like round_w_d.
1681
1682 // 1 RZ (round toward zero): Round a result to the closest
1683 // representable value whose absolute value is less than or.
1684 // equal to the infinitely accurate result. Behave like trunc_w_d.
1685
1686 // 2 RP (round up, or toward +infinity): Round a result to the
1687 // next representable value up. Behave like ceil_w_d.
1688
1689 // 3 RN (round down, or toward −infinity): Round a result to
1690 // the next representable value down. Behave like floor_w_d.
1691 switch (FCSR_ & 3) {
1692 case kRoundToNearest:
1693 rounded = std::floor(fs + 0.5);
1694 rounded_int = static_cast<int64_t>(rounded);
1695 if ((rounded_int & 1) != 0 && rounded_int - fs == 0.5) {
1696 // If the number is halfway between two integers,
1697 // round to the even one.
1698 rounded_int--;
1699 }
1700 break;
1701 case kRoundToZero:
1702 rounded = trunc(fs);
1703 rounded_int = static_cast<int64_t>(rounded);
1704 break;
1705 case kRoundToPlusInf:
1706 rounded = std::ceil(fs);
1707 rounded_int = static_cast<int64_t>(rounded);
1708 break;
1709 case kRoundToMinusInf:
1710 rounded = std::floor(fs);
1711 rounded_int = static_cast<int64_t>(rounded);
1712 break;
1713 }
1714}
1715
1716
Andrei Popescu31002712010-02-23 13:46:05 +00001717// Raw access to the PC register.
1718void Simulator::set_pc(int32_t value) {
1719 pc_modified_ = true;
1720 registers_[pc] = value;
1721}
1722
Steve Block44f0eee2011-05-26 01:26:41 +01001723
1724bool Simulator::has_bad_pc() const {
1725 return ((registers_[pc] == bad_ra) || (registers_[pc] == end_sim_pc));
1726}
1727
1728
Andrei Popescu31002712010-02-23 13:46:05 +00001729// Raw access to the PC register without the special adjustment when reading.
1730int32_t Simulator::get_pc() const {
1731 return registers_[pc];
1732}
1733
1734
1735// The MIPS cannot do unaligned reads and writes. On some MIPS platforms an
1736// interrupt is caused. On others it does a funky rotation thing. For now we
1737// simply disallow unaligned reads, but at some point we may want to move to
1738// emulating the rotate behaviour. Note that simulator runs have the runtime
1739// system running directly on the host system and only generated code is
1740// executed in the simulator. Since the host is typically IA32 we will not
1741// get the correct MIPS-like behaviour on unaligned accesses.
1742
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001743void Simulator::TraceRegWr(int32_t value) {
1744 if (::v8::internal::FLAG_trace_sim) {
1745 SNPrintF(trace_buf_, "%08x", value);
1746 }
1747}
1748
1749
1750// TODO(plind): consider making icount_ printing a flag option.
1751void Simulator::TraceMemRd(int32_t addr, int32_t value) {
1752 if (::v8::internal::FLAG_trace_sim) {
1753 SNPrintF(trace_buf_, "%08x <-- [%08x] (%" PRIu64 ")", value, addr,
1754 icount_);
1755 }
1756}
1757
1758
1759void Simulator::TraceMemWr(int32_t addr, int32_t value, TraceType t) {
1760 if (::v8::internal::FLAG_trace_sim) {
1761 switch (t) {
1762 case BYTE:
1763 SNPrintF(trace_buf_, " %02x --> [%08x]",
1764 static_cast<int8_t>(value), addr);
1765 break;
1766 case HALF:
1767 SNPrintF(trace_buf_, " %04x --> [%08x]", static_cast<int16_t>(value),
1768 addr);
1769 break;
1770 case WORD:
1771 SNPrintF(trace_buf_, "%08x --> [%08x]", value, addr);
1772 break;
1773 }
1774 }
1775}
1776
1777
Andrei Popescu31002712010-02-23 13:46:05 +00001778int Simulator::ReadW(int32_t addr, Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +01001779 if (addr >=0 && addr < 0x400) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001780 // This has to be a NULL-dereference, drop into debugger.
Ben Murdochc5610432016-08-08 18:44:38 +01001781 PrintF("Memory read from bad address: 0x%08x, pc=0x%08" PRIxPTR "\n", addr,
1782 reinterpret_cast<intptr_t>(instr));
Steve Block44f0eee2011-05-26 01:26:41 +01001783 MipsDebugger dbg(this);
1784 dbg.Debug();
1785 }
Ben Murdochc5610432016-08-08 18:44:38 +01001786 if ((addr & kPointerAlignmentMask) == 0 || IsMipsArchVariant(kMips32r6)) {
Andrei Popescu31002712010-02-23 13:46:05 +00001787 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001788 TraceMemRd(addr, static_cast<int32_t>(*ptr));
Andrei Popescu31002712010-02-23 13:46:05 +00001789 return *ptr;
1790 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001791 PrintF("Unaligned read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1792 addr,
1793 reinterpret_cast<intptr_t>(instr));
Steve Block44f0eee2011-05-26 01:26:41 +01001794 MipsDebugger dbg(this);
1795 dbg.Debug();
Andrei Popescu31002712010-02-23 13:46:05 +00001796 return 0;
1797}
1798
1799
1800void Simulator::WriteW(int32_t addr, int value, Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +01001801 if (addr >= 0 && addr < 0x400) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001802 // This has to be a NULL-dereference, drop into debugger.
Ben Murdochc5610432016-08-08 18:44:38 +01001803 PrintF("Memory write to bad address: 0x%08x, pc=0x%08" PRIxPTR "\n", addr,
1804 reinterpret_cast<intptr_t>(instr));
Steve Block44f0eee2011-05-26 01:26:41 +01001805 MipsDebugger dbg(this);
1806 dbg.Debug();
1807 }
Ben Murdochc5610432016-08-08 18:44:38 +01001808 if ((addr & kPointerAlignmentMask) == 0 || IsMipsArchVariant(kMips32r6)) {
Andrei Popescu31002712010-02-23 13:46:05 +00001809 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001810 TraceMemWr(addr, value, WORD);
Andrei Popescu31002712010-02-23 13:46:05 +00001811 *ptr = value;
1812 return;
1813 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001814 PrintF("Unaligned write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1815 addr,
1816 reinterpret_cast<intptr_t>(instr));
Steve Block44f0eee2011-05-26 01:26:41 +01001817 MipsDebugger dbg(this);
1818 dbg.Debug();
Andrei Popescu31002712010-02-23 13:46:05 +00001819}
1820
1821
1822double Simulator::ReadD(int32_t addr, Instruction* instr) {
Ben Murdochc5610432016-08-08 18:44:38 +01001823 if ((addr & kDoubleAlignmentMask) == 0 || IsMipsArchVariant(kMips32r6)) {
Andrei Popescu31002712010-02-23 13:46:05 +00001824 double* ptr = reinterpret_cast<double*>(addr);
1825 return *ptr;
1826 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001827 PrintF("Unaligned (double) read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1828 addr,
1829 reinterpret_cast<intptr_t>(instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001830 base::OS::Abort();
Andrei Popescu31002712010-02-23 13:46:05 +00001831 return 0;
1832}
1833
1834
1835void Simulator::WriteD(int32_t addr, double value, Instruction* instr) {
Ben Murdochc5610432016-08-08 18:44:38 +01001836 if ((addr & kDoubleAlignmentMask) == 0 || IsMipsArchVariant(kMips32r6)) {
Andrei Popescu31002712010-02-23 13:46:05 +00001837 double* ptr = reinterpret_cast<double*>(addr);
1838 *ptr = value;
1839 return;
1840 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001841 PrintF("Unaligned (double) write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1842 addr,
1843 reinterpret_cast<intptr_t>(instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001844 base::OS::Abort();
Andrei Popescu31002712010-02-23 13:46:05 +00001845}
1846
1847
1848uint16_t Simulator::ReadHU(int32_t addr, Instruction* instr) {
Ben Murdochc5610432016-08-08 18:44:38 +01001849 if ((addr & 1) == 0 || IsMipsArchVariant(kMips32r6)) {
Andrei Popescu31002712010-02-23 13:46:05 +00001850 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001851 TraceMemRd(addr, static_cast<int32_t>(*ptr));
Andrei Popescu31002712010-02-23 13:46:05 +00001852 return *ptr;
1853 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001854 PrintF("Unaligned unsigned halfword read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1855 addr,
1856 reinterpret_cast<intptr_t>(instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001857 base::OS::Abort();
Andrei Popescu31002712010-02-23 13:46:05 +00001858 return 0;
1859}
1860
1861
1862int16_t Simulator::ReadH(int32_t addr, Instruction* instr) {
Ben Murdochc5610432016-08-08 18:44:38 +01001863 if ((addr & 1) == 0 || IsMipsArchVariant(kMips32r6)) {
Andrei Popescu31002712010-02-23 13:46:05 +00001864 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001865 TraceMemRd(addr, static_cast<int32_t>(*ptr));
Andrei Popescu31002712010-02-23 13:46:05 +00001866 return *ptr;
1867 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001868 PrintF("Unaligned signed halfword read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1869 addr,
1870 reinterpret_cast<intptr_t>(instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001871 base::OS::Abort();
Andrei Popescu31002712010-02-23 13:46:05 +00001872 return 0;
1873}
1874
1875
1876void Simulator::WriteH(int32_t addr, uint16_t value, Instruction* instr) {
Ben Murdochc5610432016-08-08 18:44:38 +01001877 if ((addr & 1) == 0 || IsMipsArchVariant(kMips32r6)) {
Andrei Popescu31002712010-02-23 13:46:05 +00001878 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001879 TraceMemWr(addr, value, HALF);
Andrei Popescu31002712010-02-23 13:46:05 +00001880 *ptr = value;
1881 return;
1882 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001883 PrintF("Unaligned unsigned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1884 addr,
1885 reinterpret_cast<intptr_t>(instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001886 base::OS::Abort();
Andrei Popescu31002712010-02-23 13:46:05 +00001887}
1888
1889
1890void Simulator::WriteH(int32_t addr, int16_t value, Instruction* instr) {
Ben Murdochc5610432016-08-08 18:44:38 +01001891 if ((addr & 1) == 0 || IsMipsArchVariant(kMips32r6)) {
Andrei Popescu31002712010-02-23 13:46:05 +00001892 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001893 TraceMemWr(addr, value, HALF);
Andrei Popescu31002712010-02-23 13:46:05 +00001894 *ptr = value;
1895 return;
1896 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001897 PrintF("Unaligned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1898 addr,
1899 reinterpret_cast<intptr_t>(instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001900 base::OS::Abort();
Andrei Popescu31002712010-02-23 13:46:05 +00001901}
1902
1903
1904uint32_t Simulator::ReadBU(int32_t addr) {
1905 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001906 TraceMemRd(addr, static_cast<int32_t>(*ptr));
Andrei Popescu31002712010-02-23 13:46:05 +00001907 return *ptr & 0xff;
1908}
1909
1910
1911int32_t Simulator::ReadB(int32_t addr) {
1912 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001913 TraceMemRd(addr, static_cast<int32_t>(*ptr));
Steve Block44f0eee2011-05-26 01:26:41 +01001914 return *ptr;
Andrei Popescu31002712010-02-23 13:46:05 +00001915}
1916
1917
1918void Simulator::WriteB(int32_t addr, uint8_t value) {
1919 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001920 TraceMemWr(addr, value, BYTE);
Andrei Popescu31002712010-02-23 13:46:05 +00001921 *ptr = value;
1922}
1923
1924
1925void Simulator::WriteB(int32_t addr, int8_t value) {
1926 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001927 TraceMemWr(addr, value, BYTE);
Andrei Popescu31002712010-02-23 13:46:05 +00001928 *ptr = value;
1929}
1930
1931
1932// Returns the limit of the stack area to enable checking for stack overflows.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001933uintptr_t Simulator::StackLimit(uintptr_t c_limit) const {
1934 // The simulator uses a separate JS stack. If we have exhausted the C stack,
1935 // we also drop down the JS limit to reflect the exhaustion on the JS stack.
1936 if (GetCurrentStackPosition() < c_limit) {
1937 return reinterpret_cast<uintptr_t>(get_sp());
1938 }
1939
1940 // Otherwise the limit is the JS stack. Leave a safety margin of 1024 bytes
1941 // to prevent overrunning the stack when pushing values.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001942 return reinterpret_cast<uintptr_t>(stack_) + 1024;
Andrei Popescu31002712010-02-23 13:46:05 +00001943}
1944
1945
1946// Unsupported instructions use Format to print an error and stop execution.
1947void Simulator::Format(Instruction* instr, const char* format) {
Ben Murdochc5610432016-08-08 18:44:38 +01001948 PrintF("Simulator found unsupported instruction:\n 0x%08" PRIxPTR ": %s\n",
Steve Block44f0eee2011-05-26 01:26:41 +01001949 reinterpret_cast<intptr_t>(instr), format);
Andrei Popescu31002712010-02-23 13:46:05 +00001950 UNIMPLEMENTED_MIPS();
1951}
1952
1953
1954// Calls into the V8 runtime are based on this very simple interface.
1955// Note: To be able to return two values from some calls the code in runtime.cc
1956// uses the ObjectPair which is essentially two 32-bit values stuffed into a
1957// 64-bit value. With the code below we assume that all runtime calls return
Steve Block44f0eee2011-05-26 01:26:41 +01001958// 64 bits of result. If they don't, the v1 result register contains a bogus
Andrei Popescu31002712010-02-23 13:46:05 +00001959// value, which is fine because it is caller-saved.
1960typedef int64_t (*SimulatorRuntimeCall)(int32_t arg0,
1961 int32_t arg1,
1962 int32_t arg2,
Steve Block44f0eee2011-05-26 01:26:41 +01001963 int32_t arg3,
1964 int32_t arg4,
1965 int32_t arg5);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001966
Ben Murdoch097c5b22016-05-18 11:27:45 +01001967typedef ObjectTriple (*SimulatorRuntimeTripleCall)(int32_t arg0, int32_t arg1,
1968 int32_t arg2, int32_t arg3,
1969 int32_t arg4);
1970
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001971// These prototypes handle the four types of FP calls.
1972typedef int64_t (*SimulatorRuntimeCompareCall)(double darg0, double darg1);
1973typedef double (*SimulatorRuntimeFPFPCall)(double darg0, double darg1);
1974typedef double (*SimulatorRuntimeFPCall)(double darg0);
1975typedef double (*SimulatorRuntimeFPIntCall)(double darg0, int32_t arg0);
Andrei Popescu31002712010-02-23 13:46:05 +00001976
Ben Murdoch257744e2011-11-30 15:57:28 +00001977// This signature supports direct call in to API function native callback
1978// (refer to InvocationCallback in v8.h).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001979typedef void (*SimulatorRuntimeDirectApiCall)(int32_t arg0);
1980typedef void (*SimulatorRuntimeProfilingApiCall)(int32_t arg0, void* arg1);
Ben Murdoch257744e2011-11-30 15:57:28 +00001981
1982// This signature supports direct call to accessor getter callback.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001983typedef void (*SimulatorRuntimeDirectGetterCall)(int32_t arg0, int32_t arg1);
1984typedef void (*SimulatorRuntimeProfilingGetterCall)(
1985 int32_t arg0, int32_t arg1, void* arg2);
Ben Murdoch257744e2011-11-30 15:57:28 +00001986
Andrei Popescu31002712010-02-23 13:46:05 +00001987// Software interrupt instructions are used by the simulator to call into the
Steve Block44f0eee2011-05-26 01:26:41 +01001988// C-based V8 runtime. They are also used for debugging with simulator.
Andrei Popescu31002712010-02-23 13:46:05 +00001989void Simulator::SoftwareInterrupt(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +01001990 // There are several instructions that could get us here,
1991 // the break_ instruction, or several variants of traps. All
1992 // Are "SPECIAL" class opcode, and are distinuished by function.
1993 int32_t func = instr->FunctionFieldRaw();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001994 uint32_t code = (func == BREAK) ? instr->Bits(25, 6) : -1;
Steve Block44f0eee2011-05-26 01:26:41 +01001995
Andrei Popescu31002712010-02-23 13:46:05 +00001996 // We first check if we met a call_rt_redirected.
1997 if (instr->InstructionBits() == rtCallRedirInstr) {
1998 Redirection* redirection = Redirection::FromSwiInstruction(instr);
1999 int32_t arg0 = get_register(a0);
2000 int32_t arg1 = get_register(a1);
2001 int32_t arg2 = get_register(a2);
2002 int32_t arg3 = get_register(a3);
Steve Block44f0eee2011-05-26 01:26:41 +01002003
Steve Block44f0eee2011-05-26 01:26:41 +01002004 int32_t* stack_pointer = reinterpret_cast<int32_t*>(get_register(sp));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002005 // Args 4 and 5 are on the stack after the reserved space for args 0..3.
2006 int32_t arg4 = stack_pointer[4];
2007 int32_t arg5 = stack_pointer[5];
Ben Murdoch257744e2011-11-30 15:57:28 +00002008
2009 bool fp_call =
2010 (redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) ||
2011 (redirection->type() == ExternalReference::BUILTIN_COMPARE_CALL) ||
2012 (redirection->type() == ExternalReference::BUILTIN_FP_CALL) ||
2013 (redirection->type() == ExternalReference::BUILTIN_FP_INT_CALL);
2014
2015 if (!IsMipsSoftFloatABI) {
2016 // With the hard floating point calling convention, double
2017 // arguments are passed in FPU registers. Fetch the arguments
2018 // from there and call the builtin using soft floating point
2019 // convention.
2020 switch (redirection->type()) {
2021 case ExternalReference::BUILTIN_FP_FP_CALL:
2022 case ExternalReference::BUILTIN_COMPARE_CALL:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002023 if (IsFp64Mode()) {
2024 arg0 = get_fpu_register_word(f12);
2025 arg1 = get_fpu_register_hi_word(f12);
2026 arg2 = get_fpu_register_word(f14);
2027 arg3 = get_fpu_register_hi_word(f14);
2028 } else {
2029 arg0 = get_fpu_register_word(f12);
2030 arg1 = get_fpu_register_word(f13);
2031 arg2 = get_fpu_register_word(f14);
2032 arg3 = get_fpu_register_word(f15);
2033 }
Ben Murdoch257744e2011-11-30 15:57:28 +00002034 break;
2035 case ExternalReference::BUILTIN_FP_CALL:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002036 if (IsFp64Mode()) {
2037 arg0 = get_fpu_register_word(f12);
2038 arg1 = get_fpu_register_hi_word(f12);
2039 } else {
2040 arg0 = get_fpu_register_word(f12);
2041 arg1 = get_fpu_register_word(f13);
2042 }
Ben Murdoch257744e2011-11-30 15:57:28 +00002043 break;
2044 case ExternalReference::BUILTIN_FP_INT_CALL:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002045 if (IsFp64Mode()) {
2046 arg0 = get_fpu_register_word(f12);
2047 arg1 = get_fpu_register_hi_word(f12);
2048 } else {
2049 arg0 = get_fpu_register_word(f12);
2050 arg1 = get_fpu_register_word(f13);
2051 }
Ben Murdoch257744e2011-11-30 15:57:28 +00002052 arg2 = get_register(a2);
2053 break;
2054 default:
2055 break;
2056 }
2057 }
2058
Andrei Popescu31002712010-02-23 13:46:05 +00002059 // This is dodgy but it works because the C entry stubs are never moved.
2060 // See comment in codegen-arm.cc and bug 1242173.
2061 int32_t saved_ra = get_register(ra);
Steve Block44f0eee2011-05-26 01:26:41 +01002062
2063 intptr_t external =
Ben Murdoch257744e2011-11-30 15:57:28 +00002064 reinterpret_cast<intptr_t>(redirection->external_function());
Steve Block44f0eee2011-05-26 01:26:41 +01002065
2066 // Based on CpuFeatures::IsSupported(FPU), Mips will use either hardware
2067 // FPU, or gcc soft-float routines. Hardware FPU is simulated in this
2068 // simulator. Soft-float has additional abstraction of ExternalReference,
Ben Murdoch257744e2011-11-30 15:57:28 +00002069 // to support serialization.
2070 if (fp_call) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002071 double dval0, dval1; // one or two double parameters
2072 int32_t ival; // zero or one integer parameters
2073 int64_t iresult = 0; // integer return value
2074 double dresult = 0; // double return value
2075 GetFpArgs(&dval0, &dval1, &ival);
2076 SimulatorRuntimeCall generic_target =
2077 reinterpret_cast<SimulatorRuntimeCall>(external);
Ben Murdoch257744e2011-11-30 15:57:28 +00002078 if (::v8::internal::FLAG_trace_sim) {
Ben Murdoch257744e2011-11-30 15:57:28 +00002079 switch (redirection->type()) {
2080 case ExternalReference::BUILTIN_FP_FP_CALL:
2081 case ExternalReference::BUILTIN_COMPARE_CALL:
Ben Murdoch257744e2011-11-30 15:57:28 +00002082 PrintF("Call to host function at %p with args %f, %f",
Ben Murdoch61f157c2016-09-16 13:49:30 +01002083 static_cast<void*>(FUNCTION_ADDR(generic_target)), dval0,
2084 dval1);
Ben Murdoch257744e2011-11-30 15:57:28 +00002085 break;
2086 case ExternalReference::BUILTIN_FP_CALL:
Ben Murdoch257744e2011-11-30 15:57:28 +00002087 PrintF("Call to host function at %p with arg %f",
Ben Murdoch61f157c2016-09-16 13:49:30 +01002088 static_cast<void*>(FUNCTION_ADDR(generic_target)), dval0);
Ben Murdoch257744e2011-11-30 15:57:28 +00002089 break;
2090 case ExternalReference::BUILTIN_FP_INT_CALL:
Ben Murdoch257744e2011-11-30 15:57:28 +00002091 PrintF("Call to host function at %p with args %f, %d",
Ben Murdoch61f157c2016-09-16 13:49:30 +01002092 static_cast<void*>(FUNCTION_ADDR(generic_target)), dval0,
2093 ival);
Ben Murdoch257744e2011-11-30 15:57:28 +00002094 break;
2095 default:
2096 UNREACHABLE();
2097 break;
Steve Block44f0eee2011-05-26 01:26:41 +01002098 }
Andrei Popescu31002712010-02-23 13:46:05 +00002099 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002100 switch (redirection->type()) {
2101 case ExternalReference::BUILTIN_COMPARE_CALL: {
2102 SimulatorRuntimeCompareCall target =
2103 reinterpret_cast<SimulatorRuntimeCompareCall>(external);
2104 iresult = target(dval0, dval1);
2105 set_register(v0, static_cast<int32_t>(iresult));
2106 set_register(v1, static_cast<int32_t>(iresult >> 32));
2107 break;
2108 }
2109 case ExternalReference::BUILTIN_FP_FP_CALL: {
2110 SimulatorRuntimeFPFPCall target =
2111 reinterpret_cast<SimulatorRuntimeFPFPCall>(external);
2112 dresult = target(dval0, dval1);
2113 SetFpResult(dresult);
2114 break;
2115 }
2116 case ExternalReference::BUILTIN_FP_CALL: {
2117 SimulatorRuntimeFPCall target =
2118 reinterpret_cast<SimulatorRuntimeFPCall>(external);
2119 dresult = target(dval0);
2120 SetFpResult(dresult);
2121 break;
2122 }
2123 case ExternalReference::BUILTIN_FP_INT_CALL: {
2124 SimulatorRuntimeFPIntCall target =
2125 reinterpret_cast<SimulatorRuntimeFPIntCall>(external);
2126 dresult = target(dval0, ival);
2127 SetFpResult(dresult);
2128 break;
2129 }
2130 default:
2131 UNREACHABLE();
2132 break;
2133 }
2134 if (::v8::internal::FLAG_trace_sim) {
2135 switch (redirection->type()) {
2136 case ExternalReference::BUILTIN_COMPARE_CALL:
2137 PrintF("Returned %08x\n", static_cast<int32_t>(iresult));
2138 break;
2139 case ExternalReference::BUILTIN_FP_FP_CALL:
2140 case ExternalReference::BUILTIN_FP_CALL:
2141 case ExternalReference::BUILTIN_FP_INT_CALL:
2142 PrintF("Returned %f\n", dresult);
2143 break;
2144 default:
2145 UNREACHABLE();
2146 break;
2147 }
Ben Murdoch257744e2011-11-30 15:57:28 +00002148 }
Steve Block44f0eee2011-05-26 01:26:41 +01002149 } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) {
Ben Murdoch257744e2011-11-30 15:57:28 +00002150 if (::v8::internal::FLAG_trace_sim) {
2151 PrintF("Call to host function at %p args %08x\n",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002152 reinterpret_cast<void*>(external), arg0);
Ben Murdoch257744e2011-11-30 15:57:28 +00002153 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002154 SimulatorRuntimeDirectApiCall target =
2155 reinterpret_cast<SimulatorRuntimeDirectApiCall>(external);
2156 target(arg0);
2157 } else if (
2158 redirection->type() == ExternalReference::PROFILING_API_CALL) {
Ben Murdoch257744e2011-11-30 15:57:28 +00002159 if (::v8::internal::FLAG_trace_sim) {
2160 PrintF("Call to host function at %p args %08x %08x\n",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002161 reinterpret_cast<void*>(external), arg0, arg1);
Ben Murdoch257744e2011-11-30 15:57:28 +00002162 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002163 SimulatorRuntimeProfilingApiCall target =
2164 reinterpret_cast<SimulatorRuntimeProfilingApiCall>(external);
2165 target(arg0, Redirection::ReverseRedirection(arg1));
2166 } else if (
2167 redirection->type() == ExternalReference::DIRECT_GETTER_CALL) {
2168 if (::v8::internal::FLAG_trace_sim) {
2169 PrintF("Call to host function at %p args %08x %08x\n",
2170 reinterpret_cast<void*>(external), arg0, arg1);
2171 }
2172 SimulatorRuntimeDirectGetterCall target =
2173 reinterpret_cast<SimulatorRuntimeDirectGetterCall>(external);
2174 target(arg0, arg1);
2175 } else if (
2176 redirection->type() == ExternalReference::PROFILING_GETTER_CALL) {
2177 if (::v8::internal::FLAG_trace_sim) {
2178 PrintF("Call to host function at %p args %08x %08x %08x\n",
2179 reinterpret_cast<void*>(external), arg0, arg1, arg2);
2180 }
2181 SimulatorRuntimeProfilingGetterCall target =
2182 reinterpret_cast<SimulatorRuntimeProfilingGetterCall>(external);
2183 target(arg0, arg1, Redirection::ReverseRedirection(arg2));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002184 } else if (redirection->type() == ExternalReference::BUILTIN_CALL_TRIPLE) {
2185 // builtin call returning ObjectTriple.
2186 SimulatorRuntimeTripleCall target =
2187 reinterpret_cast<SimulatorRuntimeTripleCall>(external);
2188 if (::v8::internal::FLAG_trace_sim) {
2189 PrintF(
2190 "Call to host triple returning runtime function %p "
2191 "args %08x, %08x, %08x, %08x, %08x\n",
Ben Murdoch61f157c2016-09-16 13:49:30 +01002192 static_cast<void*>(FUNCTION_ADDR(target)), arg1, arg2, arg3, arg4,
2193 arg5);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002194 }
2195 // arg0 is a hidden argument pointing to the return location, so don't
2196 // pass it to the target function.
2197 ObjectTriple result = target(arg1, arg2, arg3, arg4, arg5);
2198 if (::v8::internal::FLAG_trace_sim) {
Ben Murdoch61f157c2016-09-16 13:49:30 +01002199 PrintF("Returned { %p, %p, %p }\n", static_cast<void*>(result.x),
2200 static_cast<void*>(result.y), static_cast<void*>(result.z));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002201 }
2202 // Return is passed back in address pointed to by hidden first argument.
2203 ObjectTriple* sim_result = reinterpret_cast<ObjectTriple*>(arg0);
2204 *sim_result = result;
2205 set_register(v0, arg0);
Andrei Popescu31002712010-02-23 13:46:05 +00002206 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002207 DCHECK(redirection->type() == ExternalReference::BUILTIN_CALL ||
2208 redirection->type() == ExternalReference::BUILTIN_CALL_PAIR);
Andrei Popescu31002712010-02-23 13:46:05 +00002209 SimulatorRuntimeCall target =
Ben Murdoch257744e2011-11-30 15:57:28 +00002210 reinterpret_cast<SimulatorRuntimeCall>(external);
2211 if (::v8::internal::FLAG_trace_sim) {
Andrei Popescu31002712010-02-23 13:46:05 +00002212 PrintF(
Ben Murdoch257744e2011-11-30 15:57:28 +00002213 "Call to host function at %p "
2214 "args %08x, %08x, %08x, %08x, %08x, %08x\n",
Ben Murdoch61f157c2016-09-16 13:49:30 +01002215 static_cast<void*>(FUNCTION_ADDR(target)), arg0, arg1, arg2, arg3,
2216 arg4, arg5);
Andrei Popescu31002712010-02-23 13:46:05 +00002217 }
Steve Block44f0eee2011-05-26 01:26:41 +01002218 int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5);
2219 set_register(v0, static_cast<int32_t>(result));
2220 set_register(v1, static_cast<int32_t>(result >> 32));
2221 }
2222 if (::v8::internal::FLAG_trace_sim) {
2223 PrintF("Returned %08x : %08x\n", get_register(v1), get_register(v0));
Andrei Popescu31002712010-02-23 13:46:05 +00002224 }
2225 set_register(ra, saved_ra);
2226 set_pc(get_register(ra));
Steve Block44f0eee2011-05-26 01:26:41 +01002227
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002228 } else if (func == BREAK && code <= kMaxStopCode) {
2229 if (IsWatchpoint(code)) {
2230 PrintWatchpoint(code);
2231 } else {
2232 IncreaseStopCounter(code);
2233 HandleStop(code, instr);
2234 }
Andrei Popescu31002712010-02-23 13:46:05 +00002235 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01002236 // All remaining break_ codes, and all traps are handled here.
2237 MipsDebugger dbg(this);
Andrei Popescu31002712010-02-23 13:46:05 +00002238 dbg.Debug();
2239 }
2240}
2241
Steve Block44f0eee2011-05-26 01:26:41 +01002242
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002243// Stop helper functions.
2244bool Simulator::IsWatchpoint(uint32_t code) {
2245 return (code <= kMaxWatchpointCode);
2246}
2247
2248
2249void Simulator::PrintWatchpoint(uint32_t code) {
2250 MipsDebugger dbg(this);
2251 ++break_count_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002252 PrintF("\n---- break %d marker: %3d (instr count: %" PRIu64
2253 ") ----------"
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002254 "----------------------------------",
2255 code, break_count_, icount_);
2256 dbg.PrintAllRegs(); // Print registers and continue running.
2257}
2258
2259
2260void Simulator::HandleStop(uint32_t code, Instruction* instr) {
2261 // Stop if it is enabled, otherwise go on jumping over the stop
2262 // and the message address.
2263 if (IsEnabledStop(code)) {
2264 MipsDebugger dbg(this);
2265 dbg.Stop(instr);
2266 } else {
2267 set_pc(get_pc() + 2 * Instruction::kInstrSize);
2268 }
2269}
2270
2271
2272bool Simulator::IsStopInstruction(Instruction* instr) {
2273 int32_t func = instr->FunctionFieldRaw();
2274 uint32_t code = static_cast<uint32_t>(instr->Bits(25, 6));
2275 return (func == BREAK) && code > kMaxWatchpointCode && code <= kMaxStopCode;
2276}
2277
2278
2279bool Simulator::IsEnabledStop(uint32_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002280 DCHECK(code <= kMaxStopCode);
2281 DCHECK(code > kMaxWatchpointCode);
2282 return !(watched_stops_[code].count & kStopDisabledBit);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002283}
2284
2285
2286void Simulator::EnableStop(uint32_t code) {
2287 if (!IsEnabledStop(code)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002288 watched_stops_[code].count &= ~kStopDisabledBit;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002289 }
2290}
2291
2292
2293void Simulator::DisableStop(uint32_t code) {
2294 if (IsEnabledStop(code)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002295 watched_stops_[code].count |= kStopDisabledBit;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002296 }
2297}
2298
2299
2300void Simulator::IncreaseStopCounter(uint32_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002301 DCHECK(code <= kMaxStopCode);
2302 if ((watched_stops_[code].count & ~(1 << 31)) == 0x7fffffff) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002303 PrintF("Stop counter for code %i has overflowed.\n"
2304 "Enabling this code and reseting the counter to 0.\n", code);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002305 watched_stops_[code].count = 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002306 EnableStop(code);
2307 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002308 watched_stops_[code].count++;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002309 }
2310}
2311
2312
2313// Print a stop status.
2314void Simulator::PrintStopInfo(uint32_t code) {
2315 if (code <= kMaxWatchpointCode) {
2316 PrintF("That is a watchpoint, not a stop.\n");
2317 return;
2318 } else if (code > kMaxStopCode) {
2319 PrintF("Code too large, only %u stops can be used\n", kMaxStopCode + 1);
2320 return;
2321 }
2322 const char* state = IsEnabledStop(code) ? "Enabled" : "Disabled";
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002323 int32_t count = watched_stops_[code].count & ~kStopDisabledBit;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002324 // Don't print the state of unused breakpoints.
2325 if (count != 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002326 if (watched_stops_[code].desc) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002327 PrintF("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002328 code, code, state, count, watched_stops_[code].desc);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002329 } else {
2330 PrintF("stop %i - 0x%x: \t%s, \tcounter = %i\n",
2331 code, code, state, count);
2332 }
2333 }
2334}
2335
2336
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002337void Simulator::SignalException(Exception e) {
2338 V8_Fatal(__FILE__, __LINE__, "Error: Exception %i raised.",
2339 static_cast<int>(e));
2340}
2341
Ben Murdoch097c5b22016-05-18 11:27:45 +01002342// Min/Max template functions for Double and Single arguments.
2343
2344template <typename T>
2345static T FPAbs(T a);
2346
2347template <>
2348double FPAbs<double>(double a) {
2349 return fabs(a);
2350}
2351
2352template <>
2353float FPAbs<float>(float a) {
2354 return fabsf(a);
2355}
2356
2357template <typename T>
2358static bool FPUProcessNaNsAndZeros(T a, T b, MaxMinKind kind, T& result) {
2359 if (std::isnan(a) && std::isnan(b)) {
2360 result = a;
2361 } else if (std::isnan(a)) {
2362 result = b;
2363 } else if (std::isnan(b)) {
2364 result = a;
2365 } else if (b == a) {
2366 // Handle -0.0 == 0.0 case.
2367 // std::signbit() returns int 0 or 1 so substracting MaxMinKind::kMax
2368 // negates the result.
2369 result = std::signbit(b) - static_cast<int>(kind) ? b : a;
2370 } else {
2371 return false;
2372 }
2373 return true;
2374}
2375
2376template <typename T>
2377static T FPUMin(T a, T b) {
2378 T result;
2379 if (FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMin, result)) {
2380 return result;
2381 } else {
2382 return b < a ? b : a;
2383 }
2384}
2385
2386template <typename T>
2387static T FPUMax(T a, T b) {
2388 T result;
2389 if (FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMax, result)) {
2390 return result;
2391 } else {
2392 return b > a ? b : a;
2393 }
2394}
2395
2396template <typename T>
2397static T FPUMinA(T a, T b) {
2398 T result;
2399 if (!FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMin, result)) {
2400 if (FPAbs(a) < FPAbs(b)) {
2401 result = a;
2402 } else if (FPAbs(b) < FPAbs(a)) {
2403 result = b;
2404 } else {
2405 result = a < b ? a : b;
2406 }
2407 }
2408 return result;
2409}
2410
2411template <typename T>
2412static T FPUMaxA(T a, T b) {
2413 T result;
2414 if (!FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMin, result)) {
2415 if (FPAbs(a) > FPAbs(b)) {
2416 result = a;
2417 } else if (FPAbs(b) > FPAbs(a)) {
2418 result = b;
2419 } else {
2420 result = a > b ? a : b;
2421 }
2422 }
2423 return result;
2424}
2425
2426// Handle execution based on instruction types.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002427
2428void Simulator::DecodeTypeRegisterDRsType() {
2429 double ft, fs, fd;
2430 uint32_t cc, fcsr_cc;
2431 int64_t i64;
2432 fs = get_fpu_register_double(fs_reg());
2433 ft = (get_instr()->FunctionFieldRaw() != MOVF)
2434 ? get_fpu_register_double(ft_reg())
2435 : 0.0;
2436 fd = get_fpu_register_double(fd_reg());
2437 int64_t ft_int = bit_cast<int64_t>(ft);
2438 int64_t fd_int = bit_cast<int64_t>(fd);
2439 cc = get_instr()->FCccValue();
2440 fcsr_cc = get_fcsr_condition_bit(cc);
2441 switch (get_instr()->FunctionFieldRaw()) {
2442 case RINT: {
2443 DCHECK(IsMipsArchVariant(kMips32r6));
2444 double result, temp, temp_result;
2445 double upper = std::ceil(fs);
2446 double lower = std::floor(fs);
2447 switch (get_fcsr_rounding_mode()) {
2448 case kRoundToNearest:
2449 if (upper - fs < fs - lower) {
2450 result = upper;
2451 } else if (upper - fs > fs - lower) {
2452 result = lower;
2453 } else {
2454 temp_result = upper / 2;
2455 double reminder = modf(temp_result, &temp);
2456 if (reminder == 0) {
2457 result = upper;
2458 } else {
2459 result = lower;
2460 }
2461 }
2462 break;
2463 case kRoundToZero:
2464 result = (fs > 0 ? lower : upper);
2465 break;
2466 case kRoundToPlusInf:
2467 result = upper;
2468 break;
2469 case kRoundToMinusInf:
2470 result = lower;
2471 break;
2472 }
2473 set_fpu_register_double(fd_reg(), result);
2474 if (result != fs) {
2475 set_fcsr_bit(kFCSRInexactFlagBit, true);
2476 }
2477 break;
Andrei Popescu31002712010-02-23 13:46:05 +00002478 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002479 case SEL:
2480 DCHECK(IsMipsArchVariant(kMips32r6));
2481 set_fpu_register_double(fd_reg(), (fd_int & 0x1) == 0 ? fs : ft);
2482 break;
2483 case SELEQZ_C:
2484 DCHECK(IsMipsArchVariant(kMips32r6));
2485 set_fpu_register_double(fd_reg(), (ft_int & 0x1) == 0 ? fs : 0.0);
2486 break;
2487 case SELNEZ_C:
2488 DCHECK(IsMipsArchVariant(kMips32r6));
2489 set_fpu_register_double(fd_reg(), (ft_int & 0x1) != 0 ? fs : 0.0);
2490 break;
2491 case MOVZ_C: {
2492 DCHECK(IsMipsArchVariant(kMips32r2));
2493 if (rt() == 0) {
2494 set_fpu_register_double(fd_reg(), fs);
2495 }
2496 break;
2497 }
2498 case MOVN_C: {
2499 DCHECK(IsMipsArchVariant(kMips32r2));
2500 int32_t rt_reg = get_instr()->RtValue();
2501 int32_t rt = get_register(rt_reg);
2502 if (rt != 0) {
2503 set_fpu_register_double(fd_reg(), fs);
2504 }
2505 break;
2506 }
2507 case MOVF: {
2508 // Same function field for MOVT.D and MOVF.D
2509 uint32_t ft_cc = (ft_reg() >> 2) & 0x7;
2510 ft_cc = get_fcsr_condition_bit(ft_cc);
2511 if (get_instr()->Bit(16)) { // Read Tf bit.
2512 // MOVT.D
2513 if (test_fcsr_bit(ft_cc)) set_fpu_register_double(fd_reg(), fs);
2514 } else {
2515 // MOVF.D
2516 if (!test_fcsr_bit(ft_cc)) set_fpu_register_double(fd_reg(), fs);
2517 }
2518 break;
2519 }
2520 case MIN:
2521 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002522 set_fpu_register_double(fd_reg(), FPUMin(ft, fs));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002523 break;
2524 case MAX:
2525 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002526 set_fpu_register_double(fd_reg(), FPUMax(ft, fs));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002527 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +01002528 case MINA:
2529 DCHECK(IsMipsArchVariant(kMips32r6));
2530 set_fpu_register_double(fd_reg(), FPUMinA(ft, fs));
2531 break;
2532 case MAXA:
2533 DCHECK(IsMipsArchVariant(kMips32r6));
2534 set_fpu_register_double(fd_reg(), FPUMaxA(ft, fs));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002535 break;
2536 case ADD_D:
2537 set_fpu_register_double(fd_reg(), fs + ft);
2538 break;
2539 case SUB_D:
2540 set_fpu_register_double(fd_reg(), fs - ft);
2541 break;
2542 case MUL_D:
2543 set_fpu_register_double(fd_reg(), fs * ft);
2544 break;
2545 case DIV_D:
2546 set_fpu_register_double(fd_reg(), fs / ft);
2547 break;
2548 case ABS_D:
2549 set_fpu_register_double(fd_reg(), fabs(fs));
2550 break;
2551 case MOV_D:
2552 set_fpu_register_double(fd_reg(), fs);
2553 break;
2554 case NEG_D:
2555 set_fpu_register_double(fd_reg(), -fs);
2556 break;
2557 case SQRT_D:
2558 lazily_initialize_fast_sqrt(isolate_);
2559 set_fpu_register_double(fd_reg(), fast_sqrt(fs, isolate_));
2560 break;
2561 case RSQRT_D: {
2562 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2563 lazily_initialize_fast_sqrt(isolate_);
2564 double result = 1.0 / fast_sqrt(fs, isolate_);
2565 set_fpu_register_double(fd_reg(), result);
2566 break;
2567 }
2568 case RECIP_D: {
2569 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2570 double result = 1.0 / fs;
2571 set_fpu_register_double(fd_reg(), result);
2572 break;
2573 }
2574 case C_UN_D:
2575 set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft));
2576 break;
2577 case C_EQ_D:
2578 set_fcsr_bit(fcsr_cc, (fs == ft));
2579 break;
2580 case C_UEQ_D:
2581 set_fcsr_bit(fcsr_cc, (fs == ft) || (std::isnan(fs) || std::isnan(ft)));
2582 break;
2583 case C_OLT_D:
2584 set_fcsr_bit(fcsr_cc, (fs < ft));
2585 break;
2586 case C_ULT_D:
2587 set_fcsr_bit(fcsr_cc, (fs < ft) || (std::isnan(fs) || std::isnan(ft)));
2588 break;
2589 case C_OLE_D:
2590 set_fcsr_bit(fcsr_cc, (fs <= ft));
2591 break;
2592 case C_ULE_D:
2593 set_fcsr_bit(fcsr_cc, (fs <= ft) || (std::isnan(fs) || std::isnan(ft)));
2594 break;
2595 case CVT_W_D: { // Convert double to word.
2596 double rounded;
2597 int32_t result;
2598 round_according_to_fcsr(fs, rounded, result, fs);
2599 set_fpu_register_word(fd_reg(), result);
2600 if (set_fcsr_round_error(fs, rounded)) {
2601 set_fpu_register_word_invalid_result(fs, rounded);
2602 }
2603 } break;
2604 case ROUND_W_D: // Round double to word (round half to even).
2605 {
2606 double rounded = std::floor(fs + 0.5);
2607 int32_t result = static_cast<int32_t>(rounded);
2608 if ((result & 1) != 0 && result - fs == 0.5) {
2609 // If the number is halfway between two integers,
2610 // round to the even one.
2611 result--;
2612 }
2613 set_fpu_register_word(fd_reg(), result);
2614 if (set_fcsr_round_error(fs, rounded)) {
2615 set_fpu_register_word_invalid_result(fs, rounded);
2616 }
2617 } break;
2618 case TRUNC_W_D: // Truncate double to word (round towards 0).
2619 {
2620 double rounded = trunc(fs);
2621 int32_t result = static_cast<int32_t>(rounded);
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 FLOOR_W_D: // Round double to word towards negative infinity.
2628 {
2629 double rounded = std::floor(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 CEIL_W_D: // Round double to word towards positive infinity.
2637 {
2638 double rounded = std::ceil(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 CVT_S_D: // Convert double to float (single).
2646 set_fpu_register_float(fd_reg(), static_cast<float>(fs));
2647 break;
2648 case CVT_L_D: { // Mips32r2: Truncate double to 64-bit long-word.
2649 if (IsFp64Mode()) {
2650 int64_t result;
2651 double rounded;
2652 round64_according_to_fcsr(fs, rounded, result, fs);
2653 set_fpu_register(fd_reg(), result);
2654 if (set_fcsr_round64_error(fs, rounded)) {
2655 set_fpu_register_invalid_result64(fs, rounded);
2656 }
2657 } else {
2658 UNSUPPORTED();
2659 }
2660 break;
2661 break;
2662 }
2663 case TRUNC_L_D: { // Mips32r2 instruction.
2664 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2665 double rounded = trunc(fs);
2666 i64 = static_cast<int64_t>(rounded);
2667 if (IsFp64Mode()) {
2668 set_fpu_register(fd_reg(), i64);
2669 if (set_fcsr_round64_error(fs, rounded)) {
2670 set_fpu_register_invalid_result64(fs, rounded);
2671 }
2672 } else {
2673 UNSUPPORTED();
2674 }
2675 break;
2676 }
2677 case ROUND_L_D: { // Mips32r2 instruction.
2678 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2679 double rounded = std::floor(fs + 0.5);
2680 int64_t result = static_cast<int64_t>(rounded);
2681 if ((result & 1) != 0 && result - fs == 0.5) {
2682 // If the number is halfway between two integers,
2683 // round to the even one.
2684 result--;
2685 }
2686 int64_t i64 = static_cast<int64_t>(result);
2687 if (IsFp64Mode()) {
2688 set_fpu_register(fd_reg(), i64);
2689 if (set_fcsr_round64_error(fs, rounded)) {
2690 set_fpu_register_invalid_result64(fs, rounded);
2691 }
2692 } else {
2693 UNSUPPORTED();
2694 }
2695 break;
2696 }
2697 case FLOOR_L_D: { // Mips32r2 instruction.
2698 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2699 double rounded = std::floor(fs);
2700 int64_t i64 = static_cast<int64_t>(rounded);
2701 if (IsFp64Mode()) {
2702 set_fpu_register(fd_reg(), i64);
2703 if (set_fcsr_round64_error(fs, rounded)) {
2704 set_fpu_register_invalid_result64(fs, rounded);
2705 }
2706 } else {
2707 UNSUPPORTED();
2708 }
2709 break;
2710 }
2711 case CEIL_L_D: { // Mips32r2 instruction.
2712 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2713 double rounded = std::ceil(fs);
2714 int64_t i64 = static_cast<int64_t>(rounded);
2715 if (IsFp64Mode()) {
2716 set_fpu_register(fd_reg(), i64);
2717 if (set_fcsr_round64_error(fs, rounded)) {
2718 set_fpu_register_invalid_result64(fs, rounded);
2719 }
2720 } else {
2721 UNSUPPORTED();
2722 }
2723 break;
2724 }
2725 case CLASS_D: { // Mips32r6 instruction
2726 // Convert double input to uint64_t for easier bit manipulation
2727 uint64_t classed = bit_cast<uint64_t>(fs);
2728
2729 // Extracting sign, exponent and mantissa from the input double
2730 uint32_t sign = (classed >> 63) & 1;
2731 uint32_t exponent = (classed >> 52) & 0x00000000000007ff;
2732 uint64_t mantissa = classed & 0x000fffffffffffff;
2733 uint64_t result;
2734 double dResult;
2735
2736 // Setting flags if input double is negative infinity,
2737 // positive infinity, negative zero or positive zero
2738 bool negInf = (classed == 0xFFF0000000000000);
2739 bool posInf = (classed == 0x7FF0000000000000);
2740 bool negZero = (classed == 0x8000000000000000);
2741 bool posZero = (classed == 0x0000000000000000);
2742
2743 bool signalingNan;
2744 bool quietNan;
2745 bool negSubnorm;
2746 bool posSubnorm;
2747 bool negNorm;
2748 bool posNorm;
2749
2750 // Setting flags if double is NaN
2751 signalingNan = false;
2752 quietNan = false;
2753 if (!negInf && !posInf && exponent == 0x7ff) {
2754 quietNan = ((mantissa & 0x0008000000000000) != 0) &&
2755 ((mantissa & (0x0008000000000000 - 1)) == 0);
2756 signalingNan = !quietNan;
2757 }
2758
2759 // Setting flags if double is subnormal number
2760 posSubnorm = false;
2761 negSubnorm = false;
2762 if ((exponent == 0) && (mantissa != 0)) {
2763 DCHECK(sign == 0 || sign == 1);
2764 posSubnorm = (sign == 0);
2765 negSubnorm = (sign == 1);
2766 }
2767
2768 // Setting flags if double is normal number
2769 posNorm = false;
2770 negNorm = false;
2771 if (!posSubnorm && !negSubnorm && !posInf && !negInf && !signalingNan &&
2772 !quietNan && !negZero && !posZero) {
2773 DCHECK(sign == 0 || sign == 1);
2774 posNorm = (sign == 0);
2775 negNorm = (sign == 1);
2776 }
2777
2778 // Calculating result according to description of CLASS.D instruction
2779 result = (posZero << 9) | (posSubnorm << 8) | (posNorm << 7) |
2780 (posInf << 6) | (negZero << 5) | (negSubnorm << 4) |
2781 (negNorm << 3) | (negInf << 2) | (quietNan << 1) | signalingNan;
2782
2783 DCHECK(result != 0);
2784
2785 dResult = bit_cast<double>(result);
2786 set_fpu_register_double(fd_reg(), dResult);
2787
2788 break;
2789 }
2790 case C_F_D: {
2791 set_fcsr_bit(fcsr_cc, false);
2792 break;
2793 }
2794 default:
2795 UNREACHABLE();
Andrei Popescu31002712010-02-23 13:46:05 +00002796 }
2797}
2798
Steve Block44f0eee2011-05-26 01:26:41 +01002799
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002800void Simulator::DecodeTypeRegisterWRsType() {
2801 float fs = get_fpu_register_float(fs_reg());
2802 float ft = get_fpu_register_float(ft_reg());
2803 int32_t alu_out = 0x12345678;
2804 switch (get_instr()->FunctionFieldRaw()) {
2805 case CVT_S_W: // Convert word to float (single).
2806 alu_out = get_fpu_register_signed_word(fs_reg());
2807 set_fpu_register_float(fd_reg(), static_cast<float>(alu_out));
2808 break;
2809 case CVT_D_W: // Convert word to double.
2810 alu_out = get_fpu_register_signed_word(fs_reg());
2811 set_fpu_register_double(fd_reg(), static_cast<double>(alu_out));
2812 break;
2813 case CMP_AF:
2814 set_fpu_register_word(fd_reg(), 0);
2815 break;
2816 case CMP_UN:
2817 if (std::isnan(fs) || std::isnan(ft)) {
2818 set_fpu_register_word(fd_reg(), -1);
2819 } else {
2820 set_fpu_register_word(fd_reg(), 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002821 }
2822 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002823 case CMP_EQ:
2824 if (fs == ft) {
2825 set_fpu_register_word(fd_reg(), -1);
2826 } else {
2827 set_fpu_register_word(fd_reg(), 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002828 }
Andrei Popescu31002712010-02-23 13:46:05 +00002829 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002830 case CMP_UEQ:
2831 if ((fs == ft) || (std::isnan(fs) || std::isnan(ft))) {
2832 set_fpu_register_word(fd_reg(), -1);
2833 } else {
2834 set_fpu_register_word(fd_reg(), 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002835 }
Steve Block44f0eee2011-05-26 01:26:41 +01002836 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002837 case CMP_LT:
2838 if (fs < ft) {
2839 set_fpu_register_word(fd_reg(), -1);
2840 } else {
2841 set_fpu_register_word(fd_reg(), 0);
2842 }
2843 break;
2844 case CMP_ULT:
2845 if ((fs < ft) || (std::isnan(fs) || std::isnan(ft))) {
2846 set_fpu_register_word(fd_reg(), -1);
2847 } else {
2848 set_fpu_register_word(fd_reg(), 0);
2849 }
2850 break;
2851 case CMP_LE:
2852 if (fs <= ft) {
2853 set_fpu_register_word(fd_reg(), -1);
2854 } else {
2855 set_fpu_register_word(fd_reg(), 0);
2856 }
2857 break;
2858 case CMP_ULE:
2859 if ((fs <= ft) || (std::isnan(fs) || std::isnan(ft))) {
2860 set_fpu_register_word(fd_reg(), -1);
2861 } else {
2862 set_fpu_register_word(fd_reg(), 0);
2863 }
2864 break;
2865 case CMP_OR:
2866 if (!std::isnan(fs) && !std::isnan(ft)) {
2867 set_fpu_register_word(fd_reg(), -1);
2868 } else {
2869 set_fpu_register_word(fd_reg(), 0);
2870 }
2871 break;
2872 case CMP_UNE:
2873 if ((fs != ft) || (std::isnan(fs) || std::isnan(ft))) {
2874 set_fpu_register_word(fd_reg(), -1);
2875 } else {
2876 set_fpu_register_word(fd_reg(), 0);
2877 }
2878 break;
2879 case CMP_NE:
2880 if (fs != ft) {
2881 set_fpu_register_word(fd_reg(), -1);
2882 } else {
2883 set_fpu_register_word(fd_reg(), 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002884 }
Andrei Popescu31002712010-02-23 13:46:05 +00002885 break;
2886 default:
2887 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002888 }
Steve Block44f0eee2011-05-26 01:26:41 +01002889}
2890
2891
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002892void Simulator::DecodeTypeRegisterSRsType() {
2893 float fs, ft, fd;
2894 fs = get_fpu_register_float(fs_reg());
2895 ft = get_fpu_register_float(ft_reg());
2896 fd = get_fpu_register_float(fd_reg());
2897 int32_t ft_int = bit_cast<int32_t>(ft);
2898 int32_t fd_int = bit_cast<int32_t>(fd);
2899 uint32_t cc, fcsr_cc;
2900 cc = get_instr()->FCccValue();
2901 fcsr_cc = get_fcsr_condition_bit(cc);
2902 switch (get_instr()->FunctionFieldRaw()) {
2903 case RINT: {
2904 DCHECK(IsMipsArchVariant(kMips32r6));
2905 float result, temp_result;
2906 double temp;
2907 float upper = std::ceil(fs);
2908 float lower = std::floor(fs);
2909 switch (get_fcsr_rounding_mode()) {
2910 case kRoundToNearest:
2911 if (upper - fs < fs - lower) {
2912 result = upper;
2913 } else if (upper - fs > fs - lower) {
2914 result = lower;
2915 } else {
2916 temp_result = upper / 2;
2917 float reminder = modf(temp_result, &temp);
2918 if (reminder == 0) {
2919 result = upper;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002920 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002921 result = lower;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002922 }
Andrei Popescu31002712010-02-23 13:46:05 +00002923 }
2924 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002925 case kRoundToZero:
2926 result = (fs > 0 ? lower : upper);
2927 break;
2928 case kRoundToPlusInf:
2929 result = upper;
2930 break;
2931 case kRoundToMinusInf:
2932 result = lower;
2933 break;
2934 }
2935 set_fpu_register_float(fd_reg(), result);
2936 if (result != fs) {
2937 set_fcsr_bit(kFCSRInexactFlagBit, true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002938 }
2939 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002940 }
2941 case ADD_S:
2942 set_fpu_register_float(fd_reg(), fs + ft);
2943 break;
2944 case SUB_S:
2945 set_fpu_register_float(fd_reg(), fs - ft);
2946 break;
2947 case MUL_S:
2948 set_fpu_register_float(fd_reg(), fs * ft);
2949 break;
2950 case DIV_S:
2951 set_fpu_register_float(fd_reg(), fs / ft);
2952 break;
2953 case ABS_S:
2954 set_fpu_register_float(fd_reg(), fabs(fs));
2955 break;
2956 case MOV_S:
2957 set_fpu_register_float(fd_reg(), fs);
2958 break;
2959 case NEG_S:
2960 set_fpu_register_float(fd_reg(), -fs);
2961 break;
2962 case SQRT_S:
2963 lazily_initialize_fast_sqrt(isolate_);
2964 set_fpu_register_float(fd_reg(), fast_sqrt(fs, isolate_));
2965 break;
2966 case RSQRT_S: {
2967 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2968 lazily_initialize_fast_sqrt(isolate_);
2969 float result = 1.0 / fast_sqrt(fs, isolate_);
2970 set_fpu_register_float(fd_reg(), result);
2971 break;
2972 }
2973 case RECIP_S: {
2974 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2975 float result = 1.0 / fs;
2976 set_fpu_register_float(fd_reg(), result);
2977 break;
2978 }
2979 case C_F_D:
2980 set_fcsr_bit(fcsr_cc, false);
2981 break;
2982 case C_UN_D:
2983 set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft));
2984 break;
2985 case C_EQ_D:
2986 set_fcsr_bit(fcsr_cc, (fs == ft));
2987 break;
2988 case C_UEQ_D:
2989 set_fcsr_bit(fcsr_cc, (fs == ft) || (std::isnan(fs) || std::isnan(ft)));
2990 break;
2991 case C_OLT_D:
2992 set_fcsr_bit(fcsr_cc, (fs < ft));
2993 break;
2994 case C_ULT_D:
2995 set_fcsr_bit(fcsr_cc, (fs < ft) || (std::isnan(fs) || std::isnan(ft)));
2996 break;
2997 case C_OLE_D:
2998 set_fcsr_bit(fcsr_cc, (fs <= ft));
2999 break;
3000 case C_ULE_D:
3001 set_fcsr_bit(fcsr_cc, (fs <= ft) || (std::isnan(fs) || std::isnan(ft)));
3002 break;
3003 case CVT_D_S:
3004 set_fpu_register_double(fd_reg(), static_cast<double>(fs));
3005 break;
3006 case SEL:
3007 DCHECK(IsMipsArchVariant(kMips32r6));
3008 set_fpu_register_float(fd_reg(), (fd_int & 0x1) == 0 ? fs : ft);
3009 break;
3010 case CLASS_S: { // Mips32r6 instruction
3011 // Convert float input to uint32_t for easier bit manipulation
3012 float fs = get_fpu_register_float(fs_reg());
3013 uint32_t classed = bit_cast<uint32_t>(fs);
3014
3015 // Extracting sign, exponent and mantissa from the input float
3016 uint32_t sign = (classed >> 31) & 1;
3017 uint32_t exponent = (classed >> 23) & 0x000000ff;
3018 uint32_t mantissa = classed & 0x007fffff;
3019 uint32_t result;
3020 float fResult;
3021
3022 // Setting flags if input float is negative infinity,
3023 // positive infinity, negative zero or positive zero
3024 bool negInf = (classed == 0xFF800000);
3025 bool posInf = (classed == 0x7F800000);
3026 bool negZero = (classed == 0x80000000);
3027 bool posZero = (classed == 0x00000000);
3028
3029 bool signalingNan;
3030 bool quietNan;
3031 bool negSubnorm;
3032 bool posSubnorm;
3033 bool negNorm;
3034 bool posNorm;
3035
3036 // Setting flags if float is NaN
3037 signalingNan = false;
3038 quietNan = false;
3039 if (!negInf && !posInf && (exponent == 0xff)) {
3040 quietNan = ((mantissa & 0x00200000) == 0) &&
3041 ((mantissa & (0x00200000 - 1)) == 0);
3042 signalingNan = !quietNan;
3043 }
3044
3045 // Setting flags if float is subnormal number
3046 posSubnorm = false;
3047 negSubnorm = false;
3048 if ((exponent == 0) && (mantissa != 0)) {
3049 DCHECK(sign == 0 || sign == 1);
3050 posSubnorm = (sign == 0);
3051 negSubnorm = (sign == 1);
3052 }
3053
3054 // Setting flags if float is normal number
3055 posNorm = false;
3056 negNorm = false;
3057 if (!posSubnorm && !negSubnorm && !posInf && !negInf && !signalingNan &&
3058 !quietNan && !negZero && !posZero) {
3059 DCHECK(sign == 0 || sign == 1);
3060 posNorm = (sign == 0);
3061 negNorm = (sign == 1);
3062 }
3063
3064 // Calculating result according to description of CLASS.S instruction
3065 result = (posZero << 9) | (posSubnorm << 8) | (posNorm << 7) |
3066 (posInf << 6) | (negZero << 5) | (negSubnorm << 4) |
3067 (negNorm << 3) | (negInf << 2) | (quietNan << 1) | signalingNan;
3068
3069 DCHECK(result != 0);
3070
3071 fResult = bit_cast<float>(result);
3072 set_fpu_register_float(fd_reg(), fResult);
3073
3074 break;
3075 }
3076 case SELEQZ_C:
3077 DCHECK(IsMipsArchVariant(kMips32r6));
3078 set_fpu_register_float(fd_reg(), (ft_int & 0x1) == 0
3079 ? get_fpu_register_float(fs_reg())
3080 : 0.0);
3081 break;
3082 case SELNEZ_C:
3083 DCHECK(IsMipsArchVariant(kMips32r6));
3084 set_fpu_register_float(fd_reg(), (ft_int & 0x1) != 0
3085 ? get_fpu_register_float(fs_reg())
3086 : 0.0);
3087 break;
3088 case MOVZ_C: {
3089 DCHECK(IsMipsArchVariant(kMips32r2));
3090 if (rt() == 0) {
3091 set_fpu_register_float(fd_reg(), fs);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003092 }
Andrei Popescu31002712010-02-23 13:46:05 +00003093 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003094 }
3095 case MOVN_C: {
3096 DCHECK(IsMipsArchVariant(kMips32r2));
3097 if (rt() != 0) {
3098 set_fpu_register_float(fd_reg(), fs);
3099 }
3100 break;
3101 }
3102 case MOVF: {
3103 // Same function field for MOVT.D and MOVF.D
3104 uint32_t ft_cc = (ft_reg() >> 2) & 0x7;
3105 ft_cc = get_fcsr_condition_bit(ft_cc);
3106
3107 if (get_instr()->Bit(16)) { // Read Tf bit.
3108 // MOVT.D
3109 if (test_fcsr_bit(ft_cc)) set_fpu_register_float(fd_reg(), fs);
3110 } else {
3111 // MOVF.D
3112 if (!test_fcsr_bit(ft_cc)) set_fpu_register_float(fd_reg(), fs);
3113 }
3114 break;
3115 }
3116 case TRUNC_W_S: { // Truncate single to word (round towards 0).
3117 float rounded = trunc(fs);
3118 int32_t result = static_cast<int32_t>(rounded);
3119 set_fpu_register_word(fd_reg(), result);
3120 if (set_fcsr_round_error(fs, rounded)) {
3121 set_fpu_register_word_invalid_result(fs, rounded);
3122 }
3123 } break;
3124 case TRUNC_L_S: { // Mips32r2 instruction.
3125 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
3126 float rounded = trunc(fs);
3127 int64_t i64 = static_cast<int64_t>(rounded);
3128 if (IsFp64Mode()) {
3129 set_fpu_register(fd_reg(), i64);
3130 if (set_fcsr_round64_error(fs, rounded)) {
3131 set_fpu_register_invalid_result64(fs, rounded);
Andrei Popescu31002712010-02-23 13:46:05 +00003132 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003133 } else {
3134 UNSUPPORTED();
3135 }
3136 break;
3137 }
3138 case FLOOR_W_S: // Round double to word towards negative infinity.
3139 {
3140 float rounded = std::floor(fs);
3141 int32_t result = static_cast<int32_t>(rounded);
3142 set_fpu_register_word(fd_reg(), result);
3143 if (set_fcsr_round_error(fs, rounded)) {
3144 set_fpu_register_word_invalid_result(fs, rounded);
3145 }
3146 } break;
3147 case FLOOR_L_S: { // Mips32r2 instruction.
3148 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
3149 float rounded = std::floor(fs);
3150 int64_t i64 = static_cast<int64_t>(rounded);
3151 if (IsFp64Mode()) {
3152 set_fpu_register(fd_reg(), i64);
3153 if (set_fcsr_round64_error(fs, rounded)) {
3154 set_fpu_register_invalid_result64(fs, rounded);
Andrei Popescu31002712010-02-23 13:46:05 +00003155 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003156 } else {
3157 UNSUPPORTED();
3158 }
3159 break;
3160 }
3161 case ROUND_W_S: {
3162 float rounded = std::floor(fs + 0.5);
3163 int32_t result = static_cast<int32_t>(rounded);
3164 if ((result & 1) != 0 && result - fs == 0.5) {
3165 // If the number is halfway between two integers,
3166 // round to the even one.
3167 result--;
3168 }
3169 set_fpu_register_word(fd_reg(), result);
3170 if (set_fcsr_round_error(fs, rounded)) {
3171 set_fpu_register_word_invalid_result(fs, rounded);
3172 }
3173 break;
3174 }
3175 case ROUND_L_S: { // Mips32r2 instruction.
3176 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
3177 float rounded = std::floor(fs + 0.5);
3178 int64_t result = static_cast<int64_t>(rounded);
3179 if ((result & 1) != 0 && result - fs == 0.5) {
3180 // If the number is halfway between two integers,
3181 // round to the even one.
3182 result--;
3183 }
3184 int64_t i64 = static_cast<int64_t>(result);
3185 if (IsFp64Mode()) {
3186 set_fpu_register(fd_reg(), i64);
3187 if (set_fcsr_round64_error(fs, rounded)) {
3188 set_fpu_register_invalid_result64(fs, rounded);
Steve Block44f0eee2011-05-26 01:26:41 +01003189 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003190 } else {
3191 UNSUPPORTED();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003192 }
Andrei Popescu31002712010-02-23 13:46:05 +00003193 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003194 }
3195 case CEIL_W_S: // Round double to word towards positive infinity.
3196 {
3197 float rounded = std::ceil(fs);
3198 int32_t result = static_cast<int32_t>(rounded);
3199 set_fpu_register_word(fd_reg(), result);
3200 if (set_fcsr_round_error(fs, rounded)) {
3201 set_fpu_register_word_invalid_result(fs, rounded);
3202 }
3203 } break;
3204 case CEIL_L_S: { // Mips32r2 instruction.
3205 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
3206 float rounded = std::ceil(fs);
3207 int64_t i64 = static_cast<int64_t>(rounded);
3208 if (IsFp64Mode()) {
3209 set_fpu_register(fd_reg(), i64);
3210 if (set_fcsr_round64_error(fs, rounded)) {
3211 set_fpu_register_invalid_result64(fs, rounded);
3212 }
3213 } else {
3214 UNSUPPORTED();
Steve Block44f0eee2011-05-26 01:26:41 +01003215 }
3216 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003217 }
3218 case MIN:
3219 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch097c5b22016-05-18 11:27:45 +01003220 set_fpu_register_float(fd_reg(), FPUMin(ft, fs));
Andrei Popescu31002712010-02-23 13:46:05 +00003221 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003222 case MAX:
3223 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch097c5b22016-05-18 11:27:45 +01003224 set_fpu_register_float(fd_reg(), FPUMax(ft, fs));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003225 break;
3226 case MINA:
3227 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch097c5b22016-05-18 11:27:45 +01003228 set_fpu_register_float(fd_reg(), FPUMinA(ft, fs));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003229 break;
3230 case MAXA:
3231 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch097c5b22016-05-18 11:27:45 +01003232 set_fpu_register_float(fd_reg(), FPUMaxA(ft, fs));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003233 break;
3234 case CVT_L_S: {
3235 if (IsFp64Mode()) {
3236 int64_t result;
3237 float rounded;
3238 round64_according_to_fcsr(fs, rounded, result, fs);
3239 set_fpu_register(fd_reg(), result);
3240 if (set_fcsr_round64_error(fs, rounded)) {
3241 set_fpu_register_invalid_result64(fs, rounded);
3242 }
3243 } else {
3244 UNSUPPORTED();
3245 }
3246 break;
3247 }
3248 case CVT_W_S: {
3249 float rounded;
3250 int32_t result;
3251 round_according_to_fcsr(fs, rounded, result, fs);
3252 set_fpu_register_word(fd_reg(), result);
3253 if (set_fcsr_round_error(fs, rounded)) {
3254 set_fpu_register_word_invalid_result(fs, rounded);
3255 }
3256 break;
3257 }
Andrei Popescu31002712010-02-23 13:46:05 +00003258 default:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003259 // CVT_W_S CVT_L_S ROUND_W_S ROUND_L_S FLOOR_W_S FLOOR_L_S
3260 // CEIL_W_S CEIL_L_S CVT_PS_S are unimplemented.
3261 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003262 }
Andrei Popescu31002712010-02-23 13:46:05 +00003263}
3264
Steve Block44f0eee2011-05-26 01:26:41 +01003265
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003266void Simulator::DecodeTypeRegisterLRsType() {
3267 double fs = get_fpu_register_double(fs_reg());
3268 double ft = get_fpu_register_double(ft_reg());
3269 switch (get_instr()->FunctionFieldRaw()) {
3270 case CVT_D_L: // Mips32r2 instruction.
3271 // Watch the signs here, we want 2 32-bit vals
3272 // to make a sign-64.
3273 int64_t i64;
3274 if (IsFp64Mode()) {
3275 i64 = get_fpu_register(fs_reg());
3276 } else {
3277 i64 = static_cast<uint32_t>(get_fpu_register_word(fs_reg()));
3278 i64 |= static_cast<int64_t>(get_fpu_register_word(fs_reg() + 1)) << 32;
3279 }
3280 set_fpu_register_double(fd_reg(), static_cast<double>(i64));
3281 break;
3282 case CVT_S_L:
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_float(fd_reg(), static_cast<float>(i64));
3290 break;
3291 case CMP_AF: // Mips64r6 CMP.D instructions.
3292 set_fpu_register(fd_reg(), 0);
3293 break;
3294 case CMP_UN:
3295 if (std::isnan(fs) || std::isnan(ft)) {
3296 set_fpu_register(fd_reg(), -1);
3297 } else {
3298 set_fpu_register(fd_reg(), 0);
3299 }
3300 break;
3301 case CMP_EQ:
3302 if (fs == ft) {
3303 set_fpu_register(fd_reg(), -1);
3304 } else {
3305 set_fpu_register(fd_reg(), 0);
3306 }
3307 break;
3308 case CMP_UEQ:
3309 if ((fs == ft) || (std::isnan(fs) || std::isnan(ft))) {
3310 set_fpu_register(fd_reg(), -1);
3311 } else {
3312 set_fpu_register(fd_reg(), 0);
3313 }
3314 break;
3315 case CMP_LT:
3316 if (fs < ft) {
3317 set_fpu_register(fd_reg(), -1);
3318 } else {
3319 set_fpu_register(fd_reg(), 0);
3320 }
3321 break;
3322 case CMP_ULT:
3323 if ((fs < ft) || (std::isnan(fs) || std::isnan(ft))) {
3324 set_fpu_register(fd_reg(), -1);
3325 } else {
3326 set_fpu_register(fd_reg(), 0);
3327 }
3328 break;
3329 case CMP_LE:
3330 if (fs <= ft) {
3331 set_fpu_register(fd_reg(), -1);
3332 } else {
3333 set_fpu_register(fd_reg(), 0);
3334 }
3335 break;
3336 case CMP_ULE:
3337 if ((fs <= ft) || (std::isnan(fs) || std::isnan(ft))) {
3338 set_fpu_register(fd_reg(), -1);
3339 } else {
3340 set_fpu_register(fd_reg(), 0);
3341 }
3342 break;
3343 case CMP_OR:
3344 if (!std::isnan(fs) && !std::isnan(ft)) {
3345 set_fpu_register(fd_reg(), -1);
3346 } else {
3347 set_fpu_register(fd_reg(), 0);
3348 }
3349 break;
3350 case CMP_UNE:
3351 if ((fs != ft) || (std::isnan(fs) || std::isnan(ft))) {
3352 set_fpu_register(fd_reg(), -1);
3353 } else {
3354 set_fpu_register(fd_reg(), 0);
3355 }
3356 break;
3357 case CMP_NE:
3358 if (fs != ft && (!std::isnan(fs) && !std::isnan(ft))) {
3359 set_fpu_register(fd_reg(), -1);
3360 } else {
3361 set_fpu_register(fd_reg(), 0);
3362 }
3363 break;
3364 default:
3365 UNREACHABLE();
3366 }
3367}
3368
3369
3370void Simulator::DecodeTypeRegisterCOP1() {
3371 switch (get_instr()->RsFieldRaw()) {
3372 case CFC1:
3373 // At the moment only FCSR is supported.
3374 DCHECK(fs_reg() == kFCSRRegister);
3375 set_register(rt_reg(), FCSR_);
3376 break;
3377 case MFC1:
3378 set_register(rt_reg(), get_fpu_register_word(fs_reg()));
3379 break;
3380 case MFHC1:
Ben Murdoch097c5b22016-05-18 11:27:45 +01003381 if (IsFp64Mode()) {
3382 set_register(rt_reg(), get_fpu_register_hi_word(fs_reg()));
3383 } else {
3384 set_register(rt_reg(), get_fpu_register_word(fs_reg() + 1));
3385 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003386 break;
3387 case CTC1: {
3388 // At the moment only FCSR is supported.
3389 DCHECK(fs_reg() == kFCSRRegister);
3390 int32_t reg = registers_[rt_reg()];
3391 if (IsMipsArchVariant(kMips32r6)) {
3392 FCSR_ = reg | kFCSRNaN2008FlagMask;
3393 } else {
3394 DCHECK(IsMipsArchVariant(kMips32r1) || IsMipsArchVariant(kMips32r2));
3395 FCSR_ = reg & ~kFCSRNaN2008FlagMask;
3396 }
3397 break;
3398 }
3399 case MTC1:
3400 // Hardware writes upper 32-bits to zero on mtc1.
3401 set_fpu_register_hi_word(fs_reg(), 0);
3402 set_fpu_register_word(fs_reg(), registers_[rt_reg()]);
3403 break;
3404 case MTHC1:
Ben Murdoch097c5b22016-05-18 11:27:45 +01003405 if (IsFp64Mode()) {
3406 set_fpu_register_hi_word(fs_reg(), registers_[rt_reg()]);
3407 } else {
3408 set_fpu_register_word(fs_reg() + 1, registers_[rt_reg()]);
3409 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003410 break;
3411 case S: {
3412 DecodeTypeRegisterSRsType();
3413 break;
3414 }
3415 case D:
3416 DecodeTypeRegisterDRsType();
3417 break;
3418 case W:
3419 DecodeTypeRegisterWRsType();
3420 break;
3421 case L:
3422 DecodeTypeRegisterLRsType();
3423 break;
3424 case PS:
3425 // Not implemented.
3426 UNREACHABLE();
3427 default:
3428 UNREACHABLE();
3429 }
3430}
3431
3432
3433void Simulator::DecodeTypeRegisterCOP1X() {
3434 switch (get_instr()->FunctionFieldRaw()) {
3435 case MADD_D:
3436 double fr, ft, fs;
3437 fr = get_fpu_register_double(fr_reg());
3438 fs = get_fpu_register_double(fs_reg());
3439 ft = get_fpu_register_double(ft_reg());
3440 set_fpu_register_double(fd_reg(), fs * ft + fr);
3441 break;
3442 default:
3443 UNREACHABLE();
3444 }
3445}
3446
3447
3448void Simulator::DecodeTypeRegisterSPECIAL() {
3449 int64_t alu_out = 0x12345678;
3450 int64_t i64hilo = 0;
3451 uint64_t u64hilo = 0;
3452 bool do_interrupt = false;
3453
3454 switch (get_instr()->FunctionFieldRaw()) {
3455 case SELEQZ_S:
3456 DCHECK(IsMipsArchVariant(kMips32r6));
3457 set_register(rd_reg(), rt() == 0 ? rs() : 0);
3458 break;
3459 case SELNEZ_S:
3460 DCHECK(IsMipsArchVariant(kMips32r6));
3461 set_register(rd_reg(), rt() != 0 ? rs() : 0);
3462 break;
3463 case JR: {
3464 int32_t next_pc = rs();
3465 int32_t current_pc = get_pc();
3466 Instruction* branch_delay_instr =
3467 reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize);
3468 BranchDelayInstructionDecode(branch_delay_instr);
3469 set_pc(next_pc);
3470 pc_modified_ = true;
3471 break;
3472 }
3473 case JALR: {
3474 int32_t next_pc = rs();
3475 int32_t return_addr_reg = rd_reg();
3476 int32_t current_pc = get_pc();
3477 Instruction* branch_delay_instr =
3478 reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize);
3479 BranchDelayInstructionDecode(branch_delay_instr);
3480 set_register(return_addr_reg, current_pc + 2 * Instruction::kInstrSize);
3481 set_pc(next_pc);
3482 pc_modified_ = true;
3483 break;
3484 }
3485 case SLL:
3486 alu_out = rt() << sa();
3487 SetResult(rd_reg(), static_cast<int32_t>(alu_out));
3488 break;
3489 case SRL:
3490 if (rs_reg() == 0) {
3491 // Regular logical right shift of a word by a fixed number of
3492 // bits instruction. RS field is always equal to 0.
3493 alu_out = rt_u() >> sa();
3494 } else {
3495 // Logical right-rotate of a word by a fixed number of bits. This
3496 // is special case of SRL instruction, added in MIPS32 Release 2.
3497 // RS field is equal to 00001.
3498 alu_out = base::bits::RotateRight32(rt_u(), sa());
3499 }
3500 SetResult(rd_reg(), static_cast<int32_t>(alu_out));
3501 break;
3502 case SRA:
3503 alu_out = rt() >> sa();
3504 SetResult(rd_reg(), static_cast<int32_t>(alu_out));
3505 break;
3506 case SLLV:
3507 alu_out = rt() << rs();
3508 SetResult(rd_reg(), static_cast<int32_t>(alu_out));
3509 break;
3510 case SRLV:
3511 if (sa() == 0) {
3512 // Regular logical right-shift of a word by a variable number of
3513 // bits instruction. SA field is always equal to 0.
3514 alu_out = rt_u() >> rs();
3515 } else {
3516 // Logical right-rotate of a word by a variable number of bits.
3517 // This is special case od SRLV instruction, added in MIPS32
3518 // Release 2. SA field is equal to 00001.
3519 alu_out = base::bits::RotateRight32(rt_u(), rs_u());
3520 }
3521 SetResult(rd_reg(), static_cast<int32_t>(alu_out));
3522 break;
3523 case SRAV:
3524 SetResult(rd_reg(), rt() >> rs());
3525 break;
3526 case LSA: {
3527 DCHECK(IsMipsArchVariant(kMips32r6));
3528 int8_t sa = lsa_sa() + 1;
3529 int32_t _rt = rt();
3530 int32_t _rs = rs();
3531 int32_t res = _rs << sa;
3532 res += _rt;
3533 DCHECK_EQ(res, (rs() << (lsa_sa() + 1)) + rt());
3534 SetResult(rd_reg(), (rs() << (lsa_sa() + 1)) + rt());
3535 break;
3536 }
3537 case MFHI: // MFHI == CLZ on R6.
3538 if (!IsMipsArchVariant(kMips32r6)) {
3539 DCHECK(sa() == 0);
3540 alu_out = get_register(HI);
3541 } else {
3542 // MIPS spec: If no bits were set in GPR rs, the result written to
3543 // GPR rd is 32.
3544 DCHECK(sa() == 1);
3545 alu_out = base::bits::CountLeadingZeros32(rs_u());
3546 }
3547 SetResult(rd_reg(), static_cast<int32_t>(alu_out));
3548 break;
3549 case MFLO:
3550 alu_out = get_register(LO);
3551 SetResult(rd_reg(), static_cast<int32_t>(alu_out));
3552 break;
3553 // Instructions using HI and LO registers.
3554 case MULT:
3555 i64hilo = static_cast<int64_t>(rs()) * static_cast<int64_t>(rt());
3556 if (!IsMipsArchVariant(kMips32r6)) {
3557 set_register(LO, static_cast<int32_t>(i64hilo & 0xffffffff));
3558 set_register(HI, static_cast<int32_t>(i64hilo >> 32));
3559 } else {
3560 switch (sa()) {
3561 case MUL_OP:
3562 set_register(rd_reg(), static_cast<int32_t>(i64hilo & 0xffffffff));
3563 break;
3564 case MUH_OP:
3565 set_register(rd_reg(), static_cast<int32_t>(i64hilo >> 32));
3566 break;
3567 default:
3568 UNIMPLEMENTED_MIPS();
3569 break;
3570 }
3571 }
3572 break;
3573 case MULTU:
3574 u64hilo = static_cast<uint64_t>(rs_u()) * static_cast<uint64_t>(rt_u());
3575 if (!IsMipsArchVariant(kMips32r6)) {
3576 set_register(LO, static_cast<int32_t>(u64hilo & 0xffffffff));
3577 set_register(HI, static_cast<int32_t>(u64hilo >> 32));
3578 } else {
3579 switch (sa()) {
3580 case MUL_OP:
3581 set_register(rd_reg(), static_cast<int32_t>(u64hilo & 0xffffffff));
3582 break;
3583 case MUH_OP:
3584 set_register(rd_reg(), static_cast<int32_t>(u64hilo >> 32));
3585 break;
3586 default:
3587 UNIMPLEMENTED_MIPS();
3588 break;
3589 }
3590 }
3591 break;
3592 case DIV:
3593 if (IsMipsArchVariant(kMips32r6)) {
3594 switch (get_instr()->SaValue()) {
3595 case DIV_OP:
3596 if (rs() == INT_MIN && rt() == -1) {
3597 set_register(rd_reg(), INT_MIN);
3598 } else if (rt() != 0) {
3599 set_register(rd_reg(), rs() / rt());
3600 }
3601 break;
3602 case MOD_OP:
3603 if (rs() == INT_MIN && rt() == -1) {
3604 set_register(rd_reg(), 0);
3605 } else if (rt() != 0) {
3606 set_register(rd_reg(), rs() % rt());
3607 }
3608 break;
3609 default:
3610 UNIMPLEMENTED_MIPS();
3611 break;
3612 }
3613 } else {
3614 // Divide by zero and overflow was not checked in the
3615 // configuration step - div and divu do not raise exceptions. On
3616 // division by 0 the result will be UNPREDICTABLE. On overflow
3617 // (INT_MIN/-1), return INT_MIN which is what the hardware does.
3618 if (rs() == INT_MIN && rt() == -1) {
3619 set_register(LO, INT_MIN);
3620 set_register(HI, 0);
3621 } else if (rt() != 0) {
3622 set_register(LO, rs() / rt());
3623 set_register(HI, rs() % rt());
3624 }
3625 }
3626 break;
3627 case DIVU:
3628 if (IsMipsArchVariant(kMips32r6)) {
3629 switch (get_instr()->SaValue()) {
3630 case DIV_OP:
3631 if (rt_u() != 0) {
3632 set_register(rd_reg(), rs_u() / rt_u());
3633 }
3634 break;
3635 case MOD_OP:
3636 if (rt_u() != 0) {
3637 set_register(rd_reg(), rs_u() % rt_u());
3638 }
3639 break;
3640 default:
3641 UNIMPLEMENTED_MIPS();
3642 break;
3643 }
3644 } else {
3645 if (rt_u() != 0) {
3646 set_register(LO, rs_u() / rt_u());
3647 set_register(HI, rs_u() % rt_u());
3648 }
3649 }
3650 break;
3651 case ADD:
3652 if (HaveSameSign(rs(), rt())) {
3653 if (rs() > 0) {
3654 if (rs() <= (Registers::kMaxValue - rt())) {
3655 SignalException(kIntegerOverflow);
3656 }
3657 } else if (rs() < 0) {
3658 if (rs() >= (Registers::kMinValue - rt())) {
3659 SignalException(kIntegerUnderflow);
3660 }
3661 }
3662 }
3663 SetResult(rd_reg(), rs() + rt());
3664 break;
3665 case ADDU:
3666 SetResult(rd_reg(), rs() + rt());
3667 break;
3668 case SUB:
3669 if (!HaveSameSign(rs(), rt())) {
3670 if (rs() > 0) {
3671 if (rs() <= (Registers::kMaxValue + rt())) {
3672 SignalException(kIntegerOverflow);
3673 }
3674 } else if (rs() < 0) {
3675 if (rs() >= (Registers::kMinValue + rt())) {
3676 SignalException(kIntegerUnderflow);
3677 }
3678 }
3679 }
3680 SetResult(rd_reg(), rs() - rt());
3681 break;
3682 case SUBU:
3683 SetResult(rd_reg(), rs() - rt());
3684 break;
3685 case AND:
3686 SetResult(rd_reg(), rs() & rt());
3687 break;
3688 case OR:
3689 SetResult(rd_reg(), rs() | rt());
3690 break;
3691 case XOR:
3692 SetResult(rd_reg(), rs() ^ rt());
3693 break;
3694 case NOR:
3695 SetResult(rd_reg(), ~(rs() | rt()));
3696 break;
3697 case SLT:
3698 SetResult(rd_reg(), rs() < rt() ? 1 : 0);
3699 break;
3700 case SLTU:
3701 SetResult(rd_reg(), rs_u() < rt_u() ? 1 : 0);
3702 break;
3703 // Break and trap instructions.
3704 case BREAK:
3705 do_interrupt = true;
3706 break;
3707 case TGE:
3708 do_interrupt = rs() >= rt();
3709 break;
3710 case TGEU:
3711 do_interrupt = rs_u() >= rt_u();
3712 break;
3713 case TLT:
3714 do_interrupt = rs() < rt();
3715 break;
3716 case TLTU:
3717 do_interrupt = rs_u() < rt_u();
3718 break;
3719 case TEQ:
3720 do_interrupt = rs() == rt();
3721 break;
3722 case TNE:
3723 do_interrupt = rs() != rt();
3724 break;
Ben Murdochc5610432016-08-08 18:44:38 +01003725 case SYNC:
3726 // TODO(palfia): Ignore sync instruction for now.
3727 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003728 // Conditional moves.
3729 case MOVN:
3730 if (rt()) {
3731 set_register(rd_reg(), rs());
3732 TraceRegWr(rs());
3733 }
3734 break;
3735 case MOVCI: {
3736 uint32_t cc = get_instr()->FBccValue();
3737 uint32_t fcsr_cc = get_fcsr_condition_bit(cc);
3738 if (get_instr()->Bit(16)) { // Read Tf bit.
3739 if (test_fcsr_bit(fcsr_cc)) set_register(rd_reg(), rs());
3740 } else {
3741 if (!test_fcsr_bit(fcsr_cc)) set_register(rd_reg(), rs());
3742 }
3743 break;
3744 }
3745 case MOVZ:
3746 if (!rt()) {
3747 set_register(rd_reg(), rs());
3748 TraceRegWr(rs());
3749 }
3750 break;
3751 default:
3752 UNREACHABLE();
3753 }
3754 if (do_interrupt) {
3755 SoftwareInterrupt(get_instr());
3756 }
3757}
3758
3759
3760void Simulator::DecodeTypeRegisterSPECIAL2() {
3761 int32_t alu_out;
3762 switch (get_instr()->FunctionFieldRaw()) {
3763 case MUL:
3764 // Only the lower 32 bits are kept.
3765 alu_out = rs_u() * rt_u();
3766 // HI and LO are UNPREDICTABLE after the operation.
3767 set_register(LO, Unpredictable);
3768 set_register(HI, Unpredictable);
3769 break;
3770 case CLZ:
3771 // MIPS32 spec: If no bits were set in GPR rs, the result written to
3772 // GPR rd is 32.
3773 alu_out = base::bits::CountLeadingZeros32(rs_u());
3774 break;
3775 default:
3776 alu_out = 0x12345678;
3777 UNREACHABLE();
3778 }
3779 SetResult(rd_reg(), alu_out);
3780}
3781
3782
3783void Simulator::DecodeTypeRegisterSPECIAL3() {
3784 int32_t alu_out;
3785 switch (get_instr()->FunctionFieldRaw()) {
3786 case INS: { // Mips32r2 instruction.
3787 // Interpret rd field as 5-bit msb of insert.
3788 uint16_t msb = rd_reg();
3789 // Interpret sa field as 5-bit lsb of insert.
3790 uint16_t lsb = sa();
3791 uint16_t size = msb - lsb + 1;
3792 uint32_t mask = (1 << size) - 1;
3793 alu_out = (rt_u() & ~(mask << lsb)) | ((rs_u() & mask) << lsb);
3794 // Ins instr leaves result in Rt, rather than Rd.
3795 SetResult(rt_reg(), alu_out);
3796 break;
3797 }
3798 case EXT: { // Mips32r2 instruction.
3799 // Interpret rd field as 5-bit msb of extract.
3800 uint16_t msb = rd_reg();
3801 // Interpret sa field as 5-bit lsb of extract.
3802 uint16_t lsb = sa();
3803 uint16_t size = msb + 1;
3804 uint32_t mask = (1 << size) - 1;
3805 alu_out = (rs_u() & (mask << lsb)) >> lsb;
3806 SetResult(rt_reg(), alu_out);
3807 break;
3808 }
3809 case BSHFL: {
3810 int sa = get_instr()->SaFieldRaw() >> kSaShift;
3811 switch (sa) {
3812 case BITSWAP: {
3813 uint32_t input = static_cast<uint32_t>(rt());
3814 uint32_t output = 0;
3815 uint8_t i_byte, o_byte;
3816
3817 // Reverse the bit in byte for each individual byte
3818 for (int i = 0; i < 4; i++) {
3819 output = output >> 8;
3820 i_byte = input & 0xff;
3821
3822 // Fast way to reverse bits in byte
3823 // Devised by Sean Anderson, July 13, 2001
3824 o_byte = static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) |
3825 (i_byte * 0x8020LU & 0x88440LU)) *
3826 0x10101LU >>
3827 16);
3828
3829 output = output | (static_cast<uint32_t>(o_byte << 24));
3830 input = input >> 8;
3831 }
3832
3833 alu_out = static_cast<int32_t>(output);
3834 break;
3835 }
Ben Murdoch61f157c2016-09-16 13:49:30 +01003836 case SEB: {
3837 uint8_t input = static_cast<uint8_t>(rt());
3838 uint32_t output = input;
3839 uint32_t mask = 0x00000080;
3840
3841 // Extending sign
3842 if (mask & input) {
3843 output |= 0xFFFFFF00;
3844 }
3845
3846 alu_out = static_cast<int32_t>(output);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003847 break;
Ben Murdoch61f157c2016-09-16 13:49:30 +01003848 }
3849 case SEH: {
3850 uint16_t input = static_cast<uint16_t>(rt());
3851 uint32_t output = input;
3852 uint32_t mask = 0x00008000;
3853
3854 // Extending sign
3855 if (mask & input) {
3856 output |= 0xFFFF0000;
3857 }
3858
3859 alu_out = static_cast<int32_t>(output);
3860 break;
3861 }
3862 case WSBH: {
3863 uint32_t input = static_cast<uint32_t>(rt());
3864 uint32_t output = 0;
3865
3866 uint32_t mask = 0xFF000000;
3867 for (int i = 0; i < 4; i++) {
3868 uint32_t tmp = mask & input;
3869 if (i % 2 == 0) {
3870 tmp = tmp >> 8;
3871 } else {
3872 tmp = tmp << 8;
3873 }
3874 output = output | tmp;
3875 mask = mask >> 8;
3876 }
3877
3878 alu_out = static_cast<int32_t>(output);
3879 break;
3880 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003881 default: {
3882 const uint8_t bp = get_instr()->Bp2Value();
3883 sa >>= kBp2Bits;
3884 switch (sa) {
3885 case ALIGN: {
3886 if (bp == 0) {
3887 alu_out = static_cast<int32_t>(rt());
3888 } else {
3889 uint32_t rt_hi = rt() << (8 * bp);
3890 uint32_t rs_lo = rs() >> (8 * (4 - bp));
3891 alu_out = static_cast<int32_t>(rt_hi | rs_lo);
3892 }
3893 break;
3894 }
3895 default:
3896 alu_out = 0x12345678;
3897 UNREACHABLE();
3898 break;
3899 }
3900 }
3901 }
3902 SetResult(rd_reg(), alu_out);
3903 break;
3904 }
3905 default:
3906 UNREACHABLE();
3907 }
3908}
3909
3910
3911void Simulator::DecodeTypeRegister(Instruction* instr) {
3912 const Opcode op = instr->OpcodeFieldRaw();
3913
3914 // Set up the variables if needed before executing the instruction.
3915 // ConfigureTypeRegister(instr);
3916 set_instr(instr);
3917
3918 // ---------- Execution.
3919 switch (op) {
3920 case COP1:
3921 DecodeTypeRegisterCOP1();
3922 break;
3923 case COP1X:
3924 DecodeTypeRegisterCOP1X();
3925 break;
3926 case SPECIAL:
3927 DecodeTypeRegisterSPECIAL();
3928 break;
3929 case SPECIAL2:
3930 DecodeTypeRegisterSPECIAL2();
3931 break;
3932 case SPECIAL3:
3933 DecodeTypeRegisterSPECIAL3();
3934 break;
3935 default:
3936 UNREACHABLE();
3937 }
3938}
3939
3940
3941// Type 2: instructions using a 16, 21 or 26 bits immediate. (e.g. beq, beqc).
Andrei Popescu31002712010-02-23 13:46:05 +00003942void Simulator::DecodeTypeImmediate(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +01003943 // Instruction fields.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003944 Opcode op = instr->OpcodeFieldRaw();
3945 int32_t rs_reg = instr->RsValue();
3946 int32_t rs = get_register(instr->RsValue());
3947 uint32_t rs_u = static_cast<uint32_t>(rs);
3948 int32_t rt_reg = instr->RtValue(); // Destination register.
3949 int32_t rt = get_register(rt_reg);
3950 int16_t imm16 = instr->Imm16Value();
Andrei Popescu31002712010-02-23 13:46:05 +00003951
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003952 int32_t ft_reg = instr->FtValue(); // Destination register.
Andrei Popescu31002712010-02-23 13:46:05 +00003953
Steve Block44f0eee2011-05-26 01:26:41 +01003954 // Zero extended immediate.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003955 uint32_t oe_imm16 = 0xffff & imm16;
Steve Block44f0eee2011-05-26 01:26:41 +01003956 // Sign extended immediate.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003957 int32_t se_imm16 = imm16;
Andrei Popescu31002712010-02-23 13:46:05 +00003958
Andrei Popescu31002712010-02-23 13:46:05 +00003959 // Next pc.
3960 int32_t next_pc = bad_ra;
3961
Steve Block44f0eee2011-05-26 01:26:41 +01003962 // Used for conditional branch instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00003963 bool execute_branch_delay_instruction = false;
3964
Steve Block44f0eee2011-05-26 01:26:41 +01003965 // Used for arithmetic instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00003966 int32_t alu_out = 0;
Andrei Popescu31002712010-02-23 13:46:05 +00003967
Steve Block44f0eee2011-05-26 01:26:41 +01003968 // Used for memory instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00003969 int32_t addr = 0x0;
3970
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003971 // Branch instructions common part.
3972 auto BranchAndLinkHelper = [this, instr, &next_pc,
3973 &execute_branch_delay_instruction](
3974 bool do_branch) {
3975 execute_branch_delay_instruction = true;
3976 int32_t current_pc = get_pc();
3977 if (do_branch) {
3978 int16_t imm16 = instr->Imm16Value();
3979 next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
3980 set_register(31, current_pc + 2 * Instruction::kInstrSize);
3981 } else {
3982 next_pc = current_pc + 2 * Instruction::kInstrSize;
3983 }
3984 };
3985
3986 auto BranchHelper = [this, instr, &next_pc,
3987 &execute_branch_delay_instruction](bool do_branch) {
3988 execute_branch_delay_instruction = true;
3989 int32_t current_pc = get_pc();
3990 if (do_branch) {
3991 int16_t imm16 = instr->Imm16Value();
3992 next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
3993 } else {
3994 next_pc = current_pc + 2 * Instruction::kInstrSize;
3995 }
3996 };
3997
3998 auto BranchAndLinkCompactHelper = [this, instr, &next_pc](bool do_branch,
3999 int bits) {
4000 int32_t current_pc = get_pc();
4001 CheckForbiddenSlot(current_pc);
4002 if (do_branch) {
4003 int32_t imm = instr->ImmValue(bits);
4004 imm <<= 32 - bits;
4005 imm >>= 32 - bits;
4006 next_pc = current_pc + (imm << 2) + Instruction::kInstrSize;
4007 set_register(31, current_pc + Instruction::kInstrSize);
4008 }
4009 };
4010
4011 auto BranchCompactHelper = [&next_pc, this, instr](bool do_branch, int bits) {
4012 int32_t current_pc = get_pc();
4013 CheckForbiddenSlot(current_pc);
4014 if (do_branch) {
4015 int32_t imm = instr->ImmValue(bits);
4016 imm <<= 32 - bits;
4017 imm >>= 32 - bits;
4018 next_pc = get_pc() + (imm << 2) + Instruction::kInstrSize;
4019 }
4020 };
4021
4022
Andrei Popescu31002712010-02-23 13:46:05 +00004023 switch (op) {
Steve Block44f0eee2011-05-26 01:26:41 +01004024 // ------------- COP1. Coprocessor instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00004025 case COP1:
4026 switch (instr->RsFieldRaw()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004027 case BC1: { // Branch on coprocessor condition.
4028 // Floating point.
4029 uint32_t cc = instr->FBccValue();
4030 uint32_t fcsr_cc = get_fcsr_condition_bit(cc);
4031 uint32_t cc_value = test_fcsr_bit(fcsr_cc);
4032 bool do_branch = (instr->FBtrueValue()) ? cc_value : !cc_value;
4033 BranchHelper(do_branch);
Andrei Popescu31002712010-02-23 13:46:05 +00004034 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004035 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004036 case BC1EQZ:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004037 BranchHelper(!(get_fpu_register(ft_reg) & 0x1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004038 break;
4039 case BC1NEZ:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004040 BranchHelper(get_fpu_register(ft_reg) & 0x1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004041 break;
Andrei Popescu31002712010-02-23 13:46:05 +00004042 default:
4043 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004044 }
Andrei Popescu31002712010-02-23 13:46:05 +00004045 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00004046 // ------------- REGIMM class.
Andrei Popescu31002712010-02-23 13:46:05 +00004047 case REGIMM:
4048 switch (instr->RtFieldRaw()) {
4049 case BLTZ:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004050 BranchHelper(rs < 0);
Andrei Popescu31002712010-02-23 13:46:05 +00004051 break;
4052 case BGEZ:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004053 BranchHelper(rs >= 0);
4054 break;
4055 case BLTZAL:
4056 BranchAndLinkHelper(rs < 0);
Andrei Popescu31002712010-02-23 13:46:05 +00004057 break;
4058 case BGEZAL:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004059 BranchAndLinkHelper(rs >= 0);
Andrei Popescu31002712010-02-23 13:46:05 +00004060 break;
4061 default:
4062 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004063 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004064 break; // case REGIMM.
Ben Murdoch257744e2011-11-30 15:57:28 +00004065 // ------------- Branch instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00004066 // When comparing to zero, the encoding of rt field is always 0, so we don't
4067 // need to replace rt with zero.
4068 case BEQ:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004069 BranchHelper(rs == rt);
Andrei Popescu31002712010-02-23 13:46:05 +00004070 break;
4071 case BNE:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004072 BranchHelper(rs != rt);
Andrei Popescu31002712010-02-23 13:46:05 +00004073 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004074 case POP06: // BLEZALC, BGEZALC, BGEUC, BLEZ (pre-r6)
4075 if (IsMipsArchVariant(kMips32r6)) {
4076 if (rt_reg != 0) {
4077 if (rs_reg == 0) { // BLEZALC
4078 BranchAndLinkCompactHelper(rt <= 0, 16);
4079 } else {
4080 if (rs_reg == rt_reg) { // BGEZALC
4081 BranchAndLinkCompactHelper(rt >= 0, 16);
4082 } else { // BGEUC
4083 BranchCompactHelper(
4084 static_cast<uint32_t>(rs) >= static_cast<uint32_t>(rt), 16);
4085 }
4086 }
4087 } else { // BLEZ
4088 BranchHelper(rs <= 0);
4089 }
4090 } else { // BLEZ
4091 BranchHelper(rs <= 0);
4092 }
Andrei Popescu31002712010-02-23 13:46:05 +00004093 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004094 case POP07: // BGTZALC, BLTZALC, BLTUC, BGTZ (pre-r6)
4095 if (IsMipsArchVariant(kMips32r6)) {
4096 if (rt_reg != 0) {
4097 if (rs_reg == 0) { // BGTZALC
4098 BranchAndLinkCompactHelper(rt > 0, 16);
4099 } else {
4100 if (rt_reg == rs_reg) { // BLTZALC
4101 BranchAndLinkCompactHelper(rt < 0, 16);
4102 } else { // BLTUC
4103 BranchCompactHelper(
4104 static_cast<uint32_t>(rs) < static_cast<uint32_t>(rt), 16);
4105 }
4106 }
4107 } else { // BGTZ
4108 BranchHelper(rs > 0);
4109 }
4110 } else { // BGTZ
4111 BranchHelper(rs > 0);
4112 }
Andrei Popescu31002712010-02-23 13:46:05 +00004113 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004114 case POP26: // BLEZC, BGEZC, BGEC/BLEC / BLEZL (pre-r6)
4115 if (IsMipsArchVariant(kMips32r6)) {
4116 if (rt_reg != 0) {
4117 if (rs_reg == 0) { // BLEZC
4118 BranchCompactHelper(rt <= 0, 16);
4119 } else {
4120 if (rs_reg == rt_reg) { // BGEZC
4121 BranchCompactHelper(rt >= 0, 16);
4122 } else { // BGEC/BLEC
4123 BranchCompactHelper(rs >= rt, 16);
4124 }
4125 }
4126 }
4127 } else { // BLEZL
4128 BranchAndLinkHelper(rs <= 0);
4129 }
4130 break;
4131 case POP27: // BGTZC, BLTZC, BLTC/BGTC / BGTZL (pre-r6)
4132 if (IsMipsArchVariant(kMips32r6)) {
4133 if (rt_reg != 0) {
4134 if (rs_reg == 0) { // BGTZC
4135 BranchCompactHelper(rt > 0, 16);
4136 } else {
4137 if (rs_reg == rt_reg) { // BLTZC
4138 BranchCompactHelper(rt < 0, 16);
4139 } else { // BLTC/BGTC
4140 BranchCompactHelper(rs < rt, 16);
4141 }
4142 }
4143 }
4144 } else { // BGTZL
4145 BranchAndLinkHelper(rs > 0);
4146 }
4147 break;
4148 case POP66: // BEQZC, JIC
4149 if (rs_reg != 0) { // BEQZC
4150 BranchCompactHelper(rs == 0, 21);
4151 } else { // JIC
4152 next_pc = rt + imm16;
4153 }
4154 break;
4155 case POP76: // BNEZC, JIALC
4156 if (rs_reg != 0) { // BNEZC
4157 BranchCompactHelper(rs != 0, 21);
4158 } else { // JIALC
4159 set_register(31, get_pc() + Instruction::kInstrSize);
4160 next_pc = rt + imm16;
4161 }
4162 break;
4163 case BC:
4164 BranchCompactHelper(true, 26);
4165 break;
4166 case BALC:
4167 BranchAndLinkCompactHelper(true, 26);
4168 break;
4169 case POP10: // BOVC, BEQZALC, BEQC / ADDI (pre-r6)
4170 if (IsMipsArchVariant(kMips32r6)) {
4171 if (rs_reg >= rt_reg) { // BOVC
4172 if (HaveSameSign(rs, rt)) {
4173 if (rs > 0) {
4174 BranchCompactHelper(rs > Registers::kMaxValue - rt, 16);
4175 } else if (rs < 0) {
4176 BranchCompactHelper(rs < Registers::kMinValue - rt, 16);
4177 }
4178 }
4179 } else {
4180 if (rs_reg == 0) { // BEQZALC
4181 BranchAndLinkCompactHelper(rt == 0, 16);
4182 } else { // BEQC
4183 BranchCompactHelper(rt == rs, 16);
4184 }
4185 }
4186 } else { // ADDI
4187 if (HaveSameSign(rs, se_imm16)) {
4188 if (rs > 0) {
4189 if (rs <= Registers::kMaxValue - se_imm16) {
4190 SignalException(kIntegerOverflow);
4191 }
4192 } else if (rs < 0) {
4193 if (rs >= Registers::kMinValue - se_imm16) {
4194 SignalException(kIntegerUnderflow);
4195 }
4196 }
4197 }
4198 SetResult(rt_reg, rs + se_imm16);
4199 }
4200 break;
4201 case POP30: // BNVC, BNEZALC, BNEC / DADDI (pre-r6)
4202 if (IsMipsArchVariant(kMips32r6)) {
4203 if (rs_reg >= rt_reg) { // BNVC
4204 if (!HaveSameSign(rs, rt) || rs == 0 || rt == 0) {
4205 BranchCompactHelper(true, 16);
4206 } else {
4207 if (rs > 0) {
4208 BranchCompactHelper(rs <= Registers::kMaxValue - rt, 16);
4209 } else if (rs < 0) {
4210 BranchCompactHelper(rs >= Registers::kMinValue - rt, 16);
4211 }
4212 }
4213 } else {
4214 if (rs_reg == 0) { // BNEZALC
4215 BranchAndLinkCompactHelper(rt != 0, 16);
4216 } else { // BNEC
4217 BranchCompactHelper(rt != rs, 16);
4218 }
Andrei Popescu31002712010-02-23 13:46:05 +00004219 }
4220 }
Andrei Popescu31002712010-02-23 13:46:05 +00004221 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004222 // ------------- Arithmetic instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00004223 case ADDIU:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004224 SetResult(rt_reg, rs + se_imm16);
Andrei Popescu31002712010-02-23 13:46:05 +00004225 break;
4226 case SLTI:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004227 SetResult(rt_reg, rs < se_imm16 ? 1 : 0);
Andrei Popescu31002712010-02-23 13:46:05 +00004228 break;
4229 case SLTIU:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004230 SetResult(rt_reg, rs_u < static_cast<uint32_t>(se_imm16) ? 1 : 0);
Andrei Popescu31002712010-02-23 13:46:05 +00004231 break;
4232 case ANDI:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004233 SetResult(rt_reg, rs & oe_imm16);
Andrei Popescu31002712010-02-23 13:46:05 +00004234 break;
4235 case ORI:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004236 SetResult(rt_reg, rs | oe_imm16);
Andrei Popescu31002712010-02-23 13:46:05 +00004237 break;
4238 case XORI:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004239 SetResult(rt_reg, rs ^ oe_imm16);
Andrei Popescu31002712010-02-23 13:46:05 +00004240 break;
4241 case LUI:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004242 if (rs_reg != 0) {
4243 // AUI
4244 DCHECK(IsMipsArchVariant(kMips32r6));
4245 SetResult(rt_reg, rs + (se_imm16 << 16));
4246 } else {
4247 // LUI
4248 SetResult(rt_reg, oe_imm16 << 16);
4249 }
Andrei Popescu31002712010-02-23 13:46:05 +00004250 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00004251 // ------------- Memory instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00004252 case LB:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004253 set_register(rt_reg, ReadB(rs + se_imm16));
Andrei Popescu31002712010-02-23 13:46:05 +00004254 break;
Steve Block44f0eee2011-05-26 01:26:41 +01004255 case LH:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004256 set_register(rt_reg, ReadH(rs + se_imm16, instr));
Steve Block44f0eee2011-05-26 01:26:41 +01004257 break;
4258 case LWL: {
Ben Murdoch257744e2011-11-30 15:57:28 +00004259 // al_offset is offset of the effective address within an aligned word.
Steve Block44f0eee2011-05-26 01:26:41 +01004260 uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
4261 uint8_t byte_shift = kPointerAlignmentMask - al_offset;
4262 uint32_t mask = (1 << byte_shift * 8) - 1;
4263 addr = rs + se_imm16 - al_offset;
4264 alu_out = ReadW(addr, instr);
4265 alu_out <<= byte_shift * 8;
4266 alu_out |= rt & mask;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004267 set_register(rt_reg, alu_out);
Steve Block44f0eee2011-05-26 01:26:41 +01004268 break;
4269 }
Andrei Popescu31002712010-02-23 13:46:05 +00004270 case LW:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004271 set_register(rt_reg, ReadW(rs + se_imm16, instr));
Andrei Popescu31002712010-02-23 13:46:05 +00004272 break;
4273 case LBU:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004274 set_register(rt_reg, ReadBU(rs + se_imm16));
Andrei Popescu31002712010-02-23 13:46:05 +00004275 break;
Steve Block44f0eee2011-05-26 01:26:41 +01004276 case LHU:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004277 set_register(rt_reg, ReadHU(rs + se_imm16, instr));
Steve Block44f0eee2011-05-26 01:26:41 +01004278 break;
4279 case LWR: {
Ben Murdoch257744e2011-11-30 15:57:28 +00004280 // al_offset is offset of the effective address within an aligned word.
Steve Block44f0eee2011-05-26 01:26:41 +01004281 uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
4282 uint8_t byte_shift = kPointerAlignmentMask - al_offset;
4283 uint32_t mask = al_offset ? (~0 << (byte_shift + 1) * 8) : 0;
4284 addr = rs + se_imm16 - al_offset;
4285 alu_out = ReadW(addr, instr);
4286 alu_out = static_cast<uint32_t> (alu_out) >> al_offset * 8;
4287 alu_out |= rt & mask;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004288 set_register(rt_reg, alu_out);
Steve Block44f0eee2011-05-26 01:26:41 +01004289 break;
4290 }
Andrei Popescu31002712010-02-23 13:46:05 +00004291 case SB:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004292 WriteB(rs + se_imm16, static_cast<int8_t>(rt));
Andrei Popescu31002712010-02-23 13:46:05 +00004293 break;
Steve Block44f0eee2011-05-26 01:26:41 +01004294 case SH:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004295 WriteH(rs + se_imm16, static_cast<uint16_t>(rt), instr);
Steve Block44f0eee2011-05-26 01:26:41 +01004296 break;
4297 case SWL: {
4298 uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
4299 uint8_t byte_shift = kPointerAlignmentMask - al_offset;
4300 uint32_t mask = byte_shift ? (~0 << (al_offset + 1) * 8) : 0;
4301 addr = rs + se_imm16 - al_offset;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004302 // Value to be written in memory.
4303 uint32_t mem_value = ReadW(addr, instr) & mask;
Steve Block44f0eee2011-05-26 01:26:41 +01004304 mem_value |= static_cast<uint32_t>(rt) >> byte_shift * 8;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004305 WriteW(addr, mem_value, instr);
Steve Block44f0eee2011-05-26 01:26:41 +01004306 break;
4307 }
Andrei Popescu31002712010-02-23 13:46:05 +00004308 case SW:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004309 WriteW(rs + se_imm16, rt, instr);
Andrei Popescu31002712010-02-23 13:46:05 +00004310 break;
Steve Block44f0eee2011-05-26 01:26:41 +01004311 case SWR: {
4312 uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
4313 uint32_t mask = (1 << al_offset * 8) - 1;
4314 addr = rs + se_imm16 - al_offset;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004315 uint32_t mem_value = ReadW(addr, instr);
Steve Block44f0eee2011-05-26 01:26:41 +01004316 mem_value = (rt << al_offset * 8) | (mem_value & mask);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004317 WriteW(addr, mem_value, instr);
Steve Block44f0eee2011-05-26 01:26:41 +01004318 break;
4319 }
Andrei Popescu31002712010-02-23 13:46:05 +00004320 case LWC1:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004321 set_fpu_register_hi_word(ft_reg, 0);
4322 set_fpu_register_word(ft_reg, ReadW(rs + se_imm16, instr));
Andrei Popescu31002712010-02-23 13:46:05 +00004323 break;
4324 case LDC1:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004325 set_fpu_register_double(ft_reg, ReadD(rs + se_imm16, instr));
Andrei Popescu31002712010-02-23 13:46:05 +00004326 break;
4327 case SWC1:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004328 WriteW(rs + se_imm16, get_fpu_register_word(ft_reg), instr);
Andrei Popescu31002712010-02-23 13:46:05 +00004329 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004330 case SDC1:
4331 WriteD(rs + se_imm16, get_fpu_register_double(ft_reg), instr);
4332 break;
4333 // ------------- PC-Relative instructions.
4334 case PCREL: {
4335 // rt field: checking 5-bits.
4336 int32_t imm21 = instr->Imm21Value();
4337 int32_t current_pc = get_pc();
4338 uint8_t rt = (imm21 >> kImm16Bits);
4339 switch (rt) {
4340 case ALUIPC:
4341 addr = current_pc + (se_imm16 << 16);
4342 alu_out = static_cast<int64_t>(~0x0FFFF) & addr;
4343 break;
4344 case AUIPC:
4345 alu_out = current_pc + (se_imm16 << 16);
4346 break;
4347 default: {
4348 int32_t imm19 = instr->Imm19Value();
4349 // rt field: checking the most significant 2-bits.
4350 rt = (imm21 >> kImm19Bits);
4351 switch (rt) {
4352 case LWPC: {
4353 // Set sign.
4354 imm19 <<= (kOpcodeBits + kRsBits + 2);
4355 imm19 >>= (kOpcodeBits + kRsBits + 2);
4356 addr = current_pc + (imm19 << 2);
4357 uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
4358 alu_out = *ptr;
4359 break;
4360 }
4361 case ADDIUPC: {
4362 int32_t se_imm19 = imm19 | ((imm19 & 0x40000) ? 0xfff80000 : 0);
4363 alu_out = current_pc + (se_imm19 << 2);
4364 break;
4365 }
4366 default:
4367 UNREACHABLE();
4368 break;
4369 }
4370 }
4371 }
4372 set_register(rs_reg, alu_out);
4373 break;
4374 }
Andrei Popescu31002712010-02-23 13:46:05 +00004375 default:
4376 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004377 }
Andrei Popescu31002712010-02-23 13:46:05 +00004378
Andrei Popescu31002712010-02-23 13:46:05 +00004379 if (execute_branch_delay_instruction) {
4380 // Execute branch delay slot
4381 // We don't check for end_sim_pc. First it should not be met as the current
4382 // pc is valid. Secondly a jump should always execute its branch delay slot.
4383 Instruction* branch_delay_instr =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004384 reinterpret_cast<Instruction*>(get_pc() + Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +00004385 BranchDelayInstructionDecode(branch_delay_instr);
4386 }
4387
4388 // If needed update pc after the branch delay execution.
4389 if (next_pc != bad_ra) {
4390 set_pc(next_pc);
4391 }
4392}
4393
Steve Block44f0eee2011-05-26 01:26:41 +01004394
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004395// Type 3: instructions using a 26 bytes immediate. (e.g. j, jal).
Andrei Popescu31002712010-02-23 13:46:05 +00004396void Simulator::DecodeTypeJump(Instruction* instr) {
4397 // Get current pc.
4398 int32_t current_pc = get_pc();
4399 // Get unchanged bits of pc.
4400 int32_t pc_high_bits = current_pc & 0xf0000000;
Ben Murdoch257744e2011-11-30 15:57:28 +00004401 // Next pc.
Steve Block44f0eee2011-05-26 01:26:41 +01004402 int32_t next_pc = pc_high_bits | (instr->Imm26Value() << 2);
Andrei Popescu31002712010-02-23 13:46:05 +00004403
Ben Murdoch257744e2011-11-30 15:57:28 +00004404 // Execute branch delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00004405 // We don't check for end_sim_pc. First it should not be met as the current pc
4406 // is valid. Secondly a jump should always execute its branch delay slot.
4407 Instruction* branch_delay_instr =
Ben Murdoch257744e2011-11-30 15:57:28 +00004408 reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +00004409 BranchDelayInstructionDecode(branch_delay_instr);
4410
4411 // Update pc and ra if necessary.
4412 // Do this after the branch delay execution.
4413 if (instr->IsLinkingInstruction()) {
Ben Murdoch257744e2011-11-30 15:57:28 +00004414 set_register(31, current_pc + 2 * Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +00004415 }
4416 set_pc(next_pc);
4417 pc_modified_ = true;
4418}
4419
Steve Block44f0eee2011-05-26 01:26:41 +01004420
Andrei Popescu31002712010-02-23 13:46:05 +00004421// Executes the current instruction.
4422void Simulator::InstructionDecode(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +01004423 if (v8::internal::FLAG_check_icache) {
4424 CheckICache(isolate_->simulator_i_cache(), instr);
4425 }
Andrei Popescu31002712010-02-23 13:46:05 +00004426 pc_modified_ = false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004427 v8::internal::EmbeddedVector<char, 256> buffer;
Andrei Popescu31002712010-02-23 13:46:05 +00004428 if (::v8::internal::FLAG_trace_sim) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004429 SNPrintF(trace_buf_, "%s", "");
Andrei Popescu31002712010-02-23 13:46:05 +00004430 disasm::NameConverter converter;
4431 disasm::Disassembler dasm(converter);
Ben Murdoch257744e2011-11-30 15:57:28 +00004432 dasm.InstructionDecode(buffer, reinterpret_cast<byte*>(instr));
Andrei Popescu31002712010-02-23 13:46:05 +00004433 }
4434
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004435 switch (instr->InstructionType(Instruction::TypeChecks::EXTRA)) {
Andrei Popescu31002712010-02-23 13:46:05 +00004436 case Instruction::kRegisterType:
4437 DecodeTypeRegister(instr);
4438 break;
4439 case Instruction::kImmediateType:
4440 DecodeTypeImmediate(instr);
4441 break;
4442 case Instruction::kJumpType:
4443 DecodeTypeJump(instr);
4444 break;
4445 default:
4446 UNSUPPORTED();
4447 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004448 if (::v8::internal::FLAG_trace_sim) {
Ben Murdochc5610432016-08-08 18:44:38 +01004449 PrintF(" 0x%08" PRIxPTR " %-44s %s\n",
4450 reinterpret_cast<intptr_t>(instr), buffer.start(),
4451 trace_buf_.start());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004452 }
Andrei Popescu31002712010-02-23 13:46:05 +00004453 if (!pc_modified_) {
4454 set_register(pc, reinterpret_cast<int32_t>(instr) +
Steve Block44f0eee2011-05-26 01:26:41 +01004455 Instruction::kInstrSize);
Andrei Popescu31002712010-02-23 13:46:05 +00004456 }
4457}
4458
4459
4460
4461void Simulator::Execute() {
4462 // Get the PC to simulate. Cannot use the accessor here as we need the
4463 // raw PC value and not the one used as input to arithmetic instructions.
4464 int program_counter = get_pc();
4465 if (::v8::internal::FLAG_stop_sim_at == 0) {
4466 // Fast version of the dispatch loop without checking whether the simulator
4467 // should be stopping at a particular executed instruction.
4468 while (program_counter != end_sim_pc) {
4469 Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
4470 icount_++;
4471 InstructionDecode(instr);
4472 program_counter = get_pc();
4473 }
4474 } else {
4475 // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when
4476 // we reach the particular instuction count.
4477 while (program_counter != end_sim_pc) {
4478 Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
4479 icount_++;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004480 if (icount_ == static_cast<uint64_t>(::v8::internal::FLAG_stop_sim_at)) {
Steve Block44f0eee2011-05-26 01:26:41 +01004481 MipsDebugger dbg(this);
Andrei Popescu31002712010-02-23 13:46:05 +00004482 dbg.Debug();
4483 } else {
4484 InstructionDecode(instr);
4485 }
4486 program_counter = get_pc();
4487 }
4488 }
4489}
4490
4491
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004492void Simulator::CallInternal(byte* entry) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004493 // Adjust JS-based stack limit to C-based stack limit.
4494 isolate_->stack_guard()->AdjustStackLimitForSimulator();
4495
Ben Murdoch257744e2011-11-30 15:57:28 +00004496 // Prepare to execute the code at entry.
Andrei Popescu31002712010-02-23 13:46:05 +00004497 set_register(pc, reinterpret_cast<int32_t>(entry));
4498 // Put down marker for end of simulation. The simulator will stop simulation
4499 // when the PC reaches this value. By saving the "end simulation" value into
4500 // the LR the simulation stops when returning to this call point.
4501 set_register(ra, end_sim_pc);
4502
4503 // Remember the values of callee-saved registers.
4504 // The code below assumes that r9 is not used as sb (static base) in
4505 // simulator code and therefore is regarded as a callee-saved register.
4506 int32_t s0_val = get_register(s0);
4507 int32_t s1_val = get_register(s1);
4508 int32_t s2_val = get_register(s2);
4509 int32_t s3_val = get_register(s3);
4510 int32_t s4_val = get_register(s4);
4511 int32_t s5_val = get_register(s5);
4512 int32_t s6_val = get_register(s6);
4513 int32_t s7_val = get_register(s7);
4514 int32_t gp_val = get_register(gp);
4515 int32_t sp_val = get_register(sp);
4516 int32_t fp_val = get_register(fp);
4517
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004518 // Set up the callee-saved registers with a known value. To be able to check
Andrei Popescu31002712010-02-23 13:46:05 +00004519 // that they are preserved properly across JS execution.
Ben Murdochda12d292016-06-02 14:46:10 +01004520 int32_t callee_saved_value = static_cast<int32_t>(icount_);
Andrei Popescu31002712010-02-23 13:46:05 +00004521 set_register(s0, callee_saved_value);
4522 set_register(s1, callee_saved_value);
4523 set_register(s2, callee_saved_value);
4524 set_register(s3, callee_saved_value);
4525 set_register(s4, callee_saved_value);
4526 set_register(s5, callee_saved_value);
4527 set_register(s6, callee_saved_value);
4528 set_register(s7, callee_saved_value);
4529 set_register(gp, callee_saved_value);
4530 set_register(fp, callee_saved_value);
4531
Ben Murdoch257744e2011-11-30 15:57:28 +00004532 // Start the simulation.
Andrei Popescu31002712010-02-23 13:46:05 +00004533 Execute();
4534
4535 // Check that the callee-saved registers have been preserved.
4536 CHECK_EQ(callee_saved_value, get_register(s0));
4537 CHECK_EQ(callee_saved_value, get_register(s1));
4538 CHECK_EQ(callee_saved_value, get_register(s2));
4539 CHECK_EQ(callee_saved_value, get_register(s3));
4540 CHECK_EQ(callee_saved_value, get_register(s4));
4541 CHECK_EQ(callee_saved_value, get_register(s5));
4542 CHECK_EQ(callee_saved_value, get_register(s6));
4543 CHECK_EQ(callee_saved_value, get_register(s7));
4544 CHECK_EQ(callee_saved_value, get_register(gp));
4545 CHECK_EQ(callee_saved_value, get_register(fp));
4546
4547 // Restore callee-saved registers with the original value.
4548 set_register(s0, s0_val);
4549 set_register(s1, s1_val);
4550 set_register(s2, s2_val);
4551 set_register(s3, s3_val);
4552 set_register(s4, s4_val);
4553 set_register(s5, s5_val);
4554 set_register(s6, s6_val);
4555 set_register(s7, s7_val);
4556 set_register(gp, gp_val);
4557 set_register(sp, sp_val);
4558 set_register(fp, fp_val);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004559}
4560
4561
4562int32_t Simulator::Call(byte* entry, int argument_count, ...) {
4563 va_list parameters;
4564 va_start(parameters, argument_count);
4565 // Set up arguments.
4566
4567 // First four arguments passed in registers.
4568 DCHECK(argument_count >= 4);
4569 set_register(a0, va_arg(parameters, int32_t));
4570 set_register(a1, va_arg(parameters, int32_t));
4571 set_register(a2, va_arg(parameters, int32_t));
4572 set_register(a3, va_arg(parameters, int32_t));
4573
4574 // Remaining arguments passed on stack.
4575 int original_stack = get_register(sp);
4576 // Compute position of stack on entry to generated code.
4577 int entry_stack = (original_stack - (argument_count - 4) * sizeof(int32_t)
4578 - kCArgsSlotsSize);
4579 if (base::OS::ActivationFrameAlignment() != 0) {
4580 entry_stack &= -base::OS::ActivationFrameAlignment();
4581 }
4582 // Store remaining arguments on stack, from low to high memory.
4583 intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
4584 for (int i = 4; i < argument_count; i++) {
4585 stack_argument[i - 4 + kCArgSlotCount] = va_arg(parameters, int32_t);
4586 }
4587 va_end(parameters);
4588 set_register(sp, entry_stack);
4589
4590 CallInternal(entry);
Andrei Popescu31002712010-02-23 13:46:05 +00004591
4592 // Pop stack passed arguments.
4593 CHECK_EQ(entry_stack, get_register(sp));
4594 set_register(sp, original_stack);
4595
4596 int32_t result = get_register(v0);
4597 return result;
4598}
4599
4600
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004601double Simulator::CallFP(byte* entry, double d0, double d1) {
4602 if (!IsMipsSoftFloatABI) {
4603 set_fpu_register_double(f12, d0);
4604 set_fpu_register_double(f14, d1);
4605 } else {
4606 int buffer[2];
4607 DCHECK(sizeof(buffer[0]) * 2 == sizeof(d0));
4608 memcpy(buffer, &d0, sizeof(d0));
4609 set_dw_register(a0, buffer);
4610 memcpy(buffer, &d1, sizeof(d1));
4611 set_dw_register(a2, buffer);
4612 }
4613 CallInternal(entry);
4614 if (!IsMipsSoftFloatABI) {
4615 return get_fpu_register_double(f0);
4616 } else {
4617 return get_double_from_register_pair(v0);
4618 }
4619}
4620
4621
Andrei Popescu31002712010-02-23 13:46:05 +00004622uintptr_t Simulator::PushAddress(uintptr_t address) {
4623 int new_sp = get_register(sp) - sizeof(uintptr_t);
4624 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp);
4625 *stack_slot = address;
4626 set_register(sp, new_sp);
4627 return new_sp;
4628}
4629
4630
4631uintptr_t Simulator::PopAddress() {
4632 int current_sp = get_register(sp);
4633 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp);
4634 uintptr_t address = *stack_slot;
4635 set_register(sp, current_sp + sizeof(uintptr_t));
4636 return address;
4637}
4638
4639
4640#undef UNSUPPORTED
4641
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004642} // namespace internal
4643} // namespace v8
Andrei Popescu31002712010-02-23 13:46:05 +00004644
Steve Block44f0eee2011-05-26 01:26:41 +01004645#endif // USE_SIMULATOR
Andrei Popescu31002712010-02-23 13:46:05 +00004646
Leon Clarkef7060e22010-06-03 12:02:55 +01004647#endif // V8_TARGET_ARCH_MIPS