blob: d26499bbc5db087fd8ac6c4597a2412a2173290c [file] [log] [blame]
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001// Copyright 2011 the V8 project authors. All rights reserved.
ager@chromium.org5c838252010-02-19 08:53:10 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
lrn@chromium.org7516f052011-03-30 08:52:27 +000028#include <limits.h>
machenbach@chromium.orge31286d2014-01-15 10:29:52 +000029#include <stdarg.h>
30#include <stdlib.h>
ulan@chromium.org77ca49a2013-04-22 09:43:56 +000031#include <cmath>
machenbach@chromium.orge31286d2014-01-15 10:29:52 +000032
ager@chromium.org5c838252010-02-19 08:53:10 +000033#include "v8.h"
34
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000035#if V8_TARGET_ARCH_MIPS
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000036
lrn@chromium.org34e60782011-09-15 07:25:40 +000037#include "cpu.h"
ager@chromium.org5c838252010-02-19 08:53:10 +000038#include "disasm.h"
39#include "assembler.h"
karlklose@chromium.org83a47282011-05-11 11:54:09 +000040#include "globals.h" // Need the BitCast.
ager@chromium.org5c838252010-02-19 08:53:10 +000041#include "mips/constants-mips.h"
42#include "mips/simulator-mips.h"
43
ager@chromium.org5c838252010-02-19 08:53:10 +000044
45// Only build the simulator if not compiling for real MIPS hardware.
lrn@chromium.org7516f052011-03-30 08:52:27 +000046#if defined(USE_SIMULATOR)
ager@chromium.org5c838252010-02-19 08:53:10 +000047
lrn@chromium.org7516f052011-03-30 08:52:27 +000048namespace v8 {
49namespace internal {
ager@chromium.org5c838252010-02-19 08:53:10 +000050
karlklose@chromium.org83a47282011-05-11 11:54:09 +000051// Utils functions.
ager@chromium.org5c838252010-02-19 08:53:10 +000052bool HaveSameSign(int32_t a, int32_t b) {
lrn@chromium.org7516f052011-03-30 08:52:27 +000053 return ((a ^ b) >= 0);
54}
55
56
57uint32_t get_fcsr_condition_bit(uint32_t cc) {
58 if (cc == 0) {
59 return 23;
60 } else {
61 return 24 + cc;
62 }
ager@chromium.org5c838252010-02-19 08:53:10 +000063}
64
65
66// This macro provides a platform independent use of sscanf. The reason for
67// SScanF not being implemented in a platform independent was through
68// ::v8::internal::OS in the same way as SNPrintF is that the Windows C Run-Time
69// Library does not provide vsscanf.
70#define SScanF sscanf // NOLINT
71
lrn@chromium.org7516f052011-03-30 08:52:27 +000072// The MipsDebugger class is used by the simulator while debugging simulated
ager@chromium.org5c838252010-02-19 08:53:10 +000073// code.
lrn@chromium.org7516f052011-03-30 08:52:27 +000074class MipsDebugger {
ager@chromium.org5c838252010-02-19 08:53:10 +000075 public:
danno@chromium.orgc612e022011-11-10 11:38:15 +000076 explicit MipsDebugger(Simulator* sim) : sim_(sim) { }
lrn@chromium.org7516f052011-03-30 08:52:27 +000077 ~MipsDebugger();
ager@chromium.org5c838252010-02-19 08:53:10 +000078
79 void Stop(Instruction* instr);
80 void Debug();
lrn@chromium.org7516f052011-03-30 08:52:27 +000081 // Print all registers with a nice formatting.
82 void PrintAllRegs();
83 void PrintAllRegsIncludingFPU();
ager@chromium.org5c838252010-02-19 08:53:10 +000084
85 private:
86 // We set the breakpoint code to 0xfffff to easily recognize it.
87 static const Instr kBreakpointInstr = SPECIAL | BREAK | 0xfffff << 6;
88 static const Instr kNopInstr = 0x0;
89
90 Simulator* sim_;
91
92 int32_t GetRegisterValue(int regnum);
lrn@chromium.org7516f052011-03-30 08:52:27 +000093 int32_t GetFPURegisterValueInt(int regnum);
94 int64_t GetFPURegisterValueLong(int regnum);
95 float GetFPURegisterValueFloat(int regnum);
96 double GetFPURegisterValueDouble(int regnum);
ager@chromium.org5c838252010-02-19 08:53:10 +000097 bool GetValue(const char* desc, int32_t* value);
98
99 // Set or delete a breakpoint. Returns true if successful.
100 bool SetBreakpoint(Instruction* breakpc);
101 bool DeleteBreakpoint(Instruction* breakpc);
102
103 // Undo and redo all breakpoints. This is needed to bracket disassembly and
104 // execution to skip past breakpoints when run from the debugger.
105 void UndoBreakpoints();
106 void RedoBreakpoints();
ager@chromium.org5c838252010-02-19 08:53:10 +0000107};
108
lrn@chromium.org7516f052011-03-30 08:52:27 +0000109
110MipsDebugger::~MipsDebugger() {
ager@chromium.org5c838252010-02-19 08:53:10 +0000111}
112
lrn@chromium.org7516f052011-03-30 08:52:27 +0000113
ager@chromium.org5c838252010-02-19 08:53:10 +0000114#ifdef GENERATED_CODE_COVERAGE
115static FILE* coverage_log = NULL;
116
117
118static void InitializeCoverage() {
119 char* file_name = getenv("V8_GENERATED_CODE_COVERAGE_LOG");
120 if (file_name != NULL) {
121 coverage_log = fopen(file_name, "aw+");
122 }
123}
124
125
lrn@chromium.org7516f052011-03-30 08:52:27 +0000126void MipsDebugger::Stop(Instruction* instr) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +0000127 // Get the stop code.
128 uint32_t code = instr->Bits(25, 6);
129 // Retrieve the encoded address, which comes just after this stop.
130 char** msg_address =
131 reinterpret_cast<char**>(sim_->get_pc() + Instr::kInstrSize);
132 char* msg = *msg_address;
133 ASSERT(msg != NULL);
134
135 // Update this stop description.
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000136 if (!watched_stops_[code].desc) {
137 watched_stops_[code].desc = msg;
ricow@chromium.orgc54d3652011-05-30 09:20:16 +0000138 }
139
140 if (strlen(msg) > 0) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000141 if (coverage_log != NULL) {
142 fprintf(coverage_log, "%s\n", str);
143 fflush(coverage_log);
144 }
ricow@chromium.orgc54d3652011-05-30 09:20:16 +0000145 // Overwrite the instruction and address with nops.
146 instr->SetInstructionBits(kNopInstr);
147 reinterpret_cast<Instr*>(msg_address)->SetInstructionBits(kNopInstr);
ager@chromium.org5c838252010-02-19 08:53:10 +0000148 }
ricow@chromium.orgc54d3652011-05-30 09:20:16 +0000149 sim_->set_pc(sim_->get_pc() + 2 * Instruction::kInstructionSize);
ager@chromium.org5c838252010-02-19 08:53:10 +0000150}
151
lrn@chromium.org7516f052011-03-30 08:52:27 +0000152
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000153#else // GENERATED_CODE_COVERAGE
ager@chromium.org5c838252010-02-19 08:53:10 +0000154
155#define UNSUPPORTED() printf("Unsupported instruction.\n");
156
157static void InitializeCoverage() {}
158
159
lrn@chromium.org7516f052011-03-30 08:52:27 +0000160void MipsDebugger::Stop(Instruction* instr) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +0000161 // Get the stop code.
162 uint32_t code = instr->Bits(25, 6);
163 // Retrieve the encoded address, which comes just after this stop.
164 char* msg = *reinterpret_cast<char**>(sim_->get_pc() +
165 Instruction::kInstrSize);
166 // Update this stop description.
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000167 if (!sim_->watched_stops_[code].desc) {
168 sim_->watched_stops_[code].desc = msg;
ricow@chromium.orgc54d3652011-05-30 09:20:16 +0000169 }
170 PrintF("Simulator hit %s (%u)\n", msg, code);
171 sim_->set_pc(sim_->get_pc() + 2 * Instruction::kInstrSize);
ager@chromium.org5c838252010-02-19 08:53:10 +0000172 Debug();
173}
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000174#endif // GENERATED_CODE_COVERAGE
ager@chromium.org5c838252010-02-19 08:53:10 +0000175
176
lrn@chromium.org7516f052011-03-30 08:52:27 +0000177int32_t MipsDebugger::GetRegisterValue(int regnum) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000178 if (regnum == kNumSimuRegisters) {
179 return sim_->get_pc();
180 } else {
181 return sim_->get_register(regnum);
182 }
183}
184
185
lrn@chromium.org7516f052011-03-30 08:52:27 +0000186int32_t MipsDebugger::GetFPURegisterValueInt(int regnum) {
187 if (regnum == kNumFPURegisters) {
188 return sim_->get_pc();
189 } else {
190 return sim_->get_fpu_register(regnum);
191 }
192}
193
194
195int64_t MipsDebugger::GetFPURegisterValueLong(int regnum) {
196 if (regnum == kNumFPURegisters) {
197 return sim_->get_pc();
198 } else {
199 return sim_->get_fpu_register_long(regnum);
200 }
201}
202
203
204float MipsDebugger::GetFPURegisterValueFloat(int regnum) {
205 if (regnum == kNumFPURegisters) {
206 return sim_->get_pc();
207 } else {
208 return sim_->get_fpu_register_float(regnum);
209 }
210}
211
212
213double MipsDebugger::GetFPURegisterValueDouble(int regnum) {
214 if (regnum == kNumFPURegisters) {
215 return sim_->get_pc();
216 } else {
217 return sim_->get_fpu_register_double(regnum);
218 }
219}
220
221
222bool MipsDebugger::GetValue(const char* desc, int32_t* value) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000223 int regnum = Registers::Number(desc);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000224 int fpuregnum = FPURegisters::Number(desc);
225
ager@chromium.org5c838252010-02-19 08:53:10 +0000226 if (regnum != kInvalidRegister) {
227 *value = GetRegisterValue(regnum);
228 return true;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000229 } else if (fpuregnum != kInvalidFPURegister) {
230 *value = GetFPURegisterValueInt(fpuregnum);
231 return true;
232 } else if (strncmp(desc, "0x", 2) == 0) {
233 return SScanF(desc, "%x", reinterpret_cast<uint32_t*>(value)) == 1;
ager@chromium.org5c838252010-02-19 08:53:10 +0000234 } else {
235 return SScanF(desc, "%i", value) == 1;
236 }
237 return false;
238}
239
240
lrn@chromium.org7516f052011-03-30 08:52:27 +0000241bool MipsDebugger::SetBreakpoint(Instruction* breakpc) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000242 // Check if a breakpoint can be set. If not return without any side-effects.
243 if (sim_->break_pc_ != NULL) {
244 return false;
245 }
246
247 // Set the breakpoint.
248 sim_->break_pc_ = breakpc;
249 sim_->break_instr_ = breakpc->InstructionBits();
250 // Not setting the breakpoint instruction in the code itself. It will be set
251 // when the debugger shell continues.
252 return true;
253}
254
255
lrn@chromium.org7516f052011-03-30 08:52:27 +0000256bool MipsDebugger::DeleteBreakpoint(Instruction* breakpc) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000257 if (sim_->break_pc_ != NULL) {
258 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
259 }
260
261 sim_->break_pc_ = NULL;
262 sim_->break_instr_ = 0;
263 return true;
264}
265
266
lrn@chromium.org7516f052011-03-30 08:52:27 +0000267void MipsDebugger::UndoBreakpoints() {
ager@chromium.org5c838252010-02-19 08:53:10 +0000268 if (sim_->break_pc_ != NULL) {
269 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
270 }
271}
272
273
lrn@chromium.org7516f052011-03-30 08:52:27 +0000274void MipsDebugger::RedoBreakpoints() {
ager@chromium.org5c838252010-02-19 08:53:10 +0000275 if (sim_->break_pc_ != NULL) {
276 sim_->break_pc_->SetInstructionBits(kBreakpointInstr);
277 }
278}
279
lrn@chromium.org7516f052011-03-30 08:52:27 +0000280
281void MipsDebugger::PrintAllRegs() {
ager@chromium.org5c838252010-02-19 08:53:10 +0000282#define REG_INFO(n) Registers::Name(n), GetRegisterValue(n), GetRegisterValue(n)
283
284 PrintF("\n");
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000285 // at, v0, a0.
ager@chromium.org5c838252010-02-19 08:53:10 +0000286 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
287 REG_INFO(1), REG_INFO(2), REG_INFO(4));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000288 // v1, a1.
ager@chromium.org5c838252010-02-19 08:53:10 +0000289 PrintF("%26s\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
290 "", REG_INFO(3), REG_INFO(5));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000291 // a2.
ager@chromium.org5c838252010-02-19 08:53:10 +0000292 PrintF("%26s\t%26s\t%3s: 0x%08x %10d\n", "", "", REG_INFO(6));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000293 // a3.
ager@chromium.org5c838252010-02-19 08:53:10 +0000294 PrintF("%26s\t%26s\t%3s: 0x%08x %10d\n", "", "", REG_INFO(7));
295 PrintF("\n");
296 // t0-t7, s0-s7
297 for (int i = 0; i < 8; i++) {
298 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
299 REG_INFO(8+i), REG_INFO(16+i));
300 }
301 PrintF("\n");
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000302 // t8, k0, LO.
ager@chromium.org5c838252010-02-19 08:53:10 +0000303 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
304 REG_INFO(24), REG_INFO(26), REG_INFO(32));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000305 // t9, k1, HI.
ager@chromium.org5c838252010-02-19 08:53:10 +0000306 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
307 REG_INFO(25), REG_INFO(27), REG_INFO(33));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000308 // sp, fp, gp.
ager@chromium.org5c838252010-02-19 08:53:10 +0000309 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
310 REG_INFO(29), REG_INFO(30), REG_INFO(28));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000311 // pc.
ager@chromium.org5c838252010-02-19 08:53:10 +0000312 PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
313 REG_INFO(31), REG_INFO(34));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000314
ager@chromium.org5c838252010-02-19 08:53:10 +0000315#undef REG_INFO
lrn@chromium.org7516f052011-03-30 08:52:27 +0000316#undef FPU_REG_INFO
ager@chromium.org5c838252010-02-19 08:53:10 +0000317}
318
lrn@chromium.org7516f052011-03-30 08:52:27 +0000319
320void MipsDebugger::PrintAllRegsIncludingFPU() {
321#define FPU_REG_INFO(n) FPURegisters::Name(n), FPURegisters::Name(n+1), \
322 GetFPURegisterValueInt(n+1), \
323 GetFPURegisterValueInt(n), \
324 GetFPURegisterValueDouble(n)
325
326 PrintAllRegs();
327
328 PrintF("\n\n");
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000329 // f0, f1, f2, ... f31.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000330 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(0) );
331 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(2) );
332 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(4) );
333 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(6) );
334 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(8) );
335 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(10));
336 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(12));
337 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(14));
338 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(16));
339 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(18));
340 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(20));
341 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(22));
342 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(24));
343 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(26));
344 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(28));
345 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(30));
346
347#undef REG_INFO
348#undef FPU_REG_INFO
349}
350
351
352void MipsDebugger::Debug() {
ager@chromium.org5c838252010-02-19 08:53:10 +0000353 intptr_t last_pc = -1;
354 bool done = false;
355
356#define COMMAND_SIZE 63
357#define ARG_SIZE 255
358
359#define STR(a) #a
360#define XSTR(a) STR(a)
361
362 char cmd[COMMAND_SIZE + 1];
363 char arg1[ARG_SIZE + 1];
364 char arg2[ARG_SIZE + 1];
lrn@chromium.org7516f052011-03-30 08:52:27 +0000365 char* argv[3] = { cmd, arg1, arg2 };
ager@chromium.org5c838252010-02-19 08:53:10 +0000366
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000367 // Make sure to have a proper terminating character if reaching the limit.
ager@chromium.org5c838252010-02-19 08:53:10 +0000368 cmd[COMMAND_SIZE] = 0;
369 arg1[ARG_SIZE] = 0;
370 arg2[ARG_SIZE] = 0;
371
372 // Undo all set breakpoints while running in the debugger shell. This will
373 // make them invisible to all commands.
374 UndoBreakpoints();
375
376 while (!done && (sim_->get_pc() != Simulator::end_sim_pc)) {
377 if (last_pc != sim_->get_pc()) {
378 disasm::NameConverter converter;
379 disasm::Disassembler dasm(converter);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000380 // Use a reasonably large buffer.
ager@chromium.org5c838252010-02-19 08:53:10 +0000381 v8::internal::EmbeddedVector<char, 256> buffer;
382 dasm.InstructionDecode(buffer,
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000383 reinterpret_cast<byte*>(sim_->get_pc()));
ager@chromium.org5c838252010-02-19 08:53:10 +0000384 PrintF(" 0x%08x %s\n", sim_->get_pc(), buffer.start());
385 last_pc = sim_->get_pc();
386 }
387 char* line = ReadLine("sim> ");
388 if (line == NULL) {
389 break;
390 } else {
danno@chromium.orgc612e022011-11-10 11:38:15 +0000391 char* last_input = sim_->last_debugger_input();
392 if (strcmp(line, "\n") == 0 && last_input != NULL) {
393 line = last_input;
394 } else {
395 // Ownership is transferred to sim_;
396 sim_->set_last_debugger_input(line);
397 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000398 // Use sscanf to parse the individual parts of the command line. At the
399 // moment no command expects more than two parameters.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000400 int argc = SScanF(line,
ager@chromium.org5c838252010-02-19 08:53:10 +0000401 "%" XSTR(COMMAND_SIZE) "s "
402 "%" XSTR(ARG_SIZE) "s "
403 "%" XSTR(ARG_SIZE) "s",
404 cmd, arg1, arg2);
405 if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000406 Instruction* instr = reinterpret_cast<Instruction*>(sim_->get_pc());
407 if (!(instr->IsTrap()) ||
408 instr->InstructionBits() == rtCallRedirInstr) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000409 sim_->InstructionDecode(
lrn@chromium.org7516f052011-03-30 08:52:27 +0000410 reinterpret_cast<Instruction*>(sim_->get_pc()));
ager@chromium.org5c838252010-02-19 08:53:10 +0000411 } else {
412 // Allow si to jump over generated breakpoints.
413 PrintF("/!\\ Jumping over generated breakpoint.\n");
lrn@chromium.org7516f052011-03-30 08:52:27 +0000414 sim_->set_pc(sim_->get_pc() + Instruction::kInstrSize);
ager@chromium.org5c838252010-02-19 08:53:10 +0000415 }
416 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) {
417 // Execute the one instruction we broke at with breakpoints disabled.
418 sim_->InstructionDecode(reinterpret_cast<Instruction*>(sim_->get_pc()));
419 // Leave the debugger shell.
420 done = true;
421 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000422 if (argc == 2) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000423 int32_t value;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000424 float fvalue;
ager@chromium.org5c838252010-02-19 08:53:10 +0000425 if (strcmp(arg1, "all") == 0) {
426 PrintAllRegs();
lrn@chromium.org7516f052011-03-30 08:52:27 +0000427 } else if (strcmp(arg1, "allf") == 0) {
428 PrintAllRegsIncludingFPU();
ager@chromium.org5c838252010-02-19 08:53:10 +0000429 } else {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000430 int regnum = Registers::Number(arg1);
431 int fpuregnum = FPURegisters::Number(arg1);
432
433 if (regnum != kInvalidRegister) {
434 value = GetRegisterValue(regnum);
ager@chromium.org5c838252010-02-19 08:53:10 +0000435 PrintF("%s: 0x%08x %d \n", arg1, value, value);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000436 } else if (fpuregnum != kInvalidFPURegister) {
437 if (fpuregnum % 2 == 1) {
438 value = GetFPURegisterValueInt(fpuregnum);
439 fvalue = GetFPURegisterValueFloat(fpuregnum);
440 PrintF("%s: 0x%08x %11.4e\n", arg1, value, fvalue);
441 } else {
442 double dfvalue;
443 int32_t lvalue1 = GetFPURegisterValueInt(fpuregnum);
444 int32_t lvalue2 = GetFPURegisterValueInt(fpuregnum + 1);
445 dfvalue = GetFPURegisterValueDouble(fpuregnum);
446 PrintF("%3s,%3s: 0x%08x%08x %16.4e\n",
447 FPURegisters::Name(fpuregnum+1),
448 FPURegisters::Name(fpuregnum),
449 lvalue1,
450 lvalue2,
451 dfvalue);
452 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000453 } else {
454 PrintF("%s unrecognized\n", arg1);
455 }
456 }
457 } else {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000458 if (argc == 3) {
459 if (strcmp(arg2, "single") == 0) {
460 int32_t value;
461 float fvalue;
462 int fpuregnum = FPURegisters::Number(arg1);
463
464 if (fpuregnum != kInvalidFPURegister) {
465 value = GetFPURegisterValueInt(fpuregnum);
466 fvalue = GetFPURegisterValueFloat(fpuregnum);
467 PrintF("%s: 0x%08x %11.4e\n", arg1, value, fvalue);
468 } else {
469 PrintF("%s unrecognized\n", arg1);
470 }
471 } else {
472 PrintF("print <fpu register> single\n");
473 }
474 } else {
475 PrintF("print <register> or print <fpu register> single\n");
476 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000477 }
478 } else if ((strcmp(cmd, "po") == 0)
479 || (strcmp(cmd, "printobject") == 0)) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000480 if (argc == 2) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000481 int32_t value;
482 if (GetValue(arg1, &value)) {
483 Object* obj = reinterpret_cast<Object*>(value);
484 PrintF("%s: \n", arg1);
485#ifdef DEBUG
486 obj->PrintLn();
487#else
488 obj->ShortPrint();
489 PrintF("\n");
490#endif
491 } else {
492 PrintF("%s unrecognized\n", arg1);
493 }
494 } else {
495 PrintF("printobject <value>\n");
496 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000497 } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0) {
498 int32_t* cur = NULL;
499 int32_t* end = NULL;
500 int next_arg = 1;
501
502 if (strcmp(cmd, "stack") == 0) {
503 cur = reinterpret_cast<int32_t*>(sim_->get_register(Simulator::sp));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000504 } else { // Command "mem".
lrn@chromium.org7516f052011-03-30 08:52:27 +0000505 int32_t value;
506 if (!GetValue(arg1, &value)) {
507 PrintF("%s unrecognized\n", arg1);
508 continue;
509 }
510 cur = reinterpret_cast<int32_t*>(value);
511 next_arg++;
512 }
513
514 int32_t words;
515 if (argc == next_arg) {
516 words = 10;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000517 } else {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000518 if (!GetValue(argv[next_arg], &words)) {
519 words = 10;
520 }
521 }
522 end = cur + words;
523
524 while (cur < end) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000525 PrintF(" 0x%08x: 0x%08x %10d",
lrn@chromium.org7516f052011-03-30 08:52:27 +0000526 reinterpret_cast<intptr_t>(cur), *cur, *cur);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000527 HeapObject* obj = reinterpret_cast<HeapObject*>(*cur);
528 int value = *cur;
529 Heap* current_heap = v8::internal::Isolate::Current()->heap();
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +0000530 if (((value & 1) == 0) || current_heap->Contains(obj)) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000531 PrintF(" (");
532 if ((value & 1) == 0) {
533 PrintF("smi %d", value / 2);
534 } else {
535 obj->ShortPrint();
536 }
537 PrintF(")");
538 }
539 PrintF("\n");
lrn@chromium.org7516f052011-03-30 08:52:27 +0000540 cur++;
541 }
542
danno@chromium.org40cb8782011-05-25 07:58:50 +0000543 } else if ((strcmp(cmd, "disasm") == 0) ||
544 (strcmp(cmd, "dpc") == 0) ||
545 (strcmp(cmd, "di") == 0)) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000546 disasm::NameConverter converter;
547 disasm::Disassembler dasm(converter);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000548 // Use a reasonably large buffer.
ager@chromium.org5c838252010-02-19 08:53:10 +0000549 v8::internal::EmbeddedVector<char, 256> buffer;
550
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000551 byte* cur = NULL;
552 byte* end = NULL;
ager@chromium.org5c838252010-02-19 08:53:10 +0000553
lrn@chromium.org7516f052011-03-30 08:52:27 +0000554 if (argc == 1) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000555 cur = reinterpret_cast<byte*>(sim_->get_pc());
lrn@chromium.org7516f052011-03-30 08:52:27 +0000556 end = cur + (10 * Instruction::kInstrSize);
557 } else if (argc == 2) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000558 int regnum = Registers::Number(arg1);
559 if (regnum != kInvalidRegister || strncmp(arg1, "0x", 2) == 0) {
560 // The argument is an address or a register name.
561 int32_t value;
562 if (GetValue(arg1, &value)) {
563 cur = reinterpret_cast<byte*>(value);
564 // Disassemble 10 instructions at <arg1>.
565 end = cur + (10 * Instruction::kInstrSize);
566 }
567 } else {
568 // The argument is the number of instructions.
569 int32_t value;
570 if (GetValue(arg1, &value)) {
571 cur = reinterpret_cast<byte*>(sim_->get_pc());
572 // Disassemble <arg1> instructions.
573 end = cur + (value * Instruction::kInstrSize);
574 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000575 }
576 } else {
577 int32_t value1;
578 int32_t value2;
579 if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000580 cur = reinterpret_cast<byte*>(value1);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000581 end = cur + (value2 * Instruction::kInstrSize);
ager@chromium.org5c838252010-02-19 08:53:10 +0000582 }
583 }
584
585 while (cur < end) {
586 dasm.InstructionDecode(buffer, cur);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000587 PrintF(" 0x%08x %s\n",
588 reinterpret_cast<intptr_t>(cur), buffer.start());
589 cur += Instruction::kInstrSize;
ager@chromium.org5c838252010-02-19 08:53:10 +0000590 }
591 } else if (strcmp(cmd, "gdb") == 0) {
592 PrintF("relinquishing control to gdb\n");
593 v8::internal::OS::DebugBreak();
594 PrintF("regaining control from gdb\n");
595 } else if (strcmp(cmd, "break") == 0) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000596 if (argc == 2) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000597 int32_t value;
598 if (GetValue(arg1, &value)) {
599 if (!SetBreakpoint(reinterpret_cast<Instruction*>(value))) {
600 PrintF("setting breakpoint failed\n");
601 }
602 } else {
603 PrintF("%s unrecognized\n", arg1);
604 }
605 } else {
606 PrintF("break <address>\n");
607 }
608 } else if (strcmp(cmd, "del") == 0) {
609 if (!DeleteBreakpoint(NULL)) {
610 PrintF("deleting breakpoint failed\n");
611 }
612 } else if (strcmp(cmd, "flags") == 0) {
613 PrintF("No flags on MIPS !\n");
ricow@chromium.orgc54d3652011-05-30 09:20:16 +0000614 } else if (strcmp(cmd, "stop") == 0) {
615 int32_t value;
616 intptr_t stop_pc = sim_->get_pc() -
617 2 * Instruction::kInstrSize;
618 Instruction* stop_instr = reinterpret_cast<Instruction*>(stop_pc);
619 Instruction* msg_address =
620 reinterpret_cast<Instruction*>(stop_pc +
621 Instruction::kInstrSize);
622 if ((argc == 2) && (strcmp(arg1, "unstop") == 0)) {
623 // Remove the current stop.
624 if (sim_->IsStopInstruction(stop_instr)) {
625 stop_instr->SetInstructionBits(kNopInstr);
626 msg_address->SetInstructionBits(kNopInstr);
627 } else {
628 PrintF("Not at debugger stop.\n");
629 }
630 } else if (argc == 3) {
631 // Print information about all/the specified breakpoint(s).
632 if (strcmp(arg1, "info") == 0) {
633 if (strcmp(arg2, "all") == 0) {
634 PrintF("Stop information:\n");
635 for (uint32_t i = kMaxWatchpointCode + 1;
636 i <= kMaxStopCode;
637 i++) {
638 sim_->PrintStopInfo(i);
639 }
640 } else if (GetValue(arg2, &value)) {
641 sim_->PrintStopInfo(value);
642 } else {
643 PrintF("Unrecognized argument.\n");
644 }
645 } else if (strcmp(arg1, "enable") == 0) {
646 // Enable all/the specified breakpoint(s).
647 if (strcmp(arg2, "all") == 0) {
648 for (uint32_t i = kMaxWatchpointCode + 1;
649 i <= kMaxStopCode;
650 i++) {
651 sim_->EnableStop(i);
652 }
653 } else if (GetValue(arg2, &value)) {
654 sim_->EnableStop(value);
655 } else {
656 PrintF("Unrecognized argument.\n");
657 }
658 } else if (strcmp(arg1, "disable") == 0) {
659 // Disable all/the specified breakpoint(s).
660 if (strcmp(arg2, "all") == 0) {
661 for (uint32_t i = kMaxWatchpointCode + 1;
662 i <= kMaxStopCode;
663 i++) {
664 sim_->DisableStop(i);
665 }
666 } else if (GetValue(arg2, &value)) {
667 sim_->DisableStop(value);
668 } else {
669 PrintF("Unrecognized argument.\n");
670 }
671 }
672 } else {
673 PrintF("Wrong usage. Use help command for more information.\n");
674 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000675 } else if ((strcmp(cmd, "stat") == 0) || (strcmp(cmd, "st") == 0)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000676 // Print registers and disassemble.
ager@chromium.org5c838252010-02-19 08:53:10 +0000677 PrintAllRegs();
678 PrintF("\n");
679
680 disasm::NameConverter converter;
681 disasm::Disassembler dasm(converter);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000682 // Use a reasonably large buffer.
ager@chromium.org5c838252010-02-19 08:53:10 +0000683 v8::internal::EmbeddedVector<char, 256> buffer;
684
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000685 byte* cur = NULL;
686 byte* end = NULL;
ager@chromium.org5c838252010-02-19 08:53:10 +0000687
lrn@chromium.org7516f052011-03-30 08:52:27 +0000688 if (argc == 1) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000689 cur = reinterpret_cast<byte*>(sim_->get_pc());
lrn@chromium.org7516f052011-03-30 08:52:27 +0000690 end = cur + (10 * Instruction::kInstrSize);
691 } else if (argc == 2) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000692 int32_t value;
693 if (GetValue(arg1, &value)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000694 cur = reinterpret_cast<byte*>(value);
ager@chromium.org5c838252010-02-19 08:53:10 +0000695 // no length parameter passed, assume 10 instructions
lrn@chromium.org7516f052011-03-30 08:52:27 +0000696 end = cur + (10 * Instruction::kInstrSize);
ager@chromium.org5c838252010-02-19 08:53:10 +0000697 }
698 } else {
699 int32_t value1;
700 int32_t value2;
701 if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000702 cur = reinterpret_cast<byte*>(value1);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000703 end = cur + (value2 * Instruction::kInstrSize);
ager@chromium.org5c838252010-02-19 08:53:10 +0000704 }
705 }
706
707 while (cur < end) {
708 dasm.InstructionDecode(buffer, cur);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000709 PrintF(" 0x%08x %s\n",
710 reinterpret_cast<intptr_t>(cur), buffer.start());
711 cur += Instruction::kInstrSize;
ager@chromium.org5c838252010-02-19 08:53:10 +0000712 }
713 } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
714 PrintF("cont\n");
715 PrintF(" continue execution (alias 'c')\n");
716 PrintF("stepi\n");
717 PrintF(" step one instruction (alias 'si')\n");
718 PrintF("print <register>\n");
719 PrintF(" print register content (alias 'p')\n");
720 PrintF(" use register name 'all' to print all registers\n");
721 PrintF("printobject <register>\n");
722 PrintF(" print an object from a register (alias 'po')\n");
lrn@chromium.org7516f052011-03-30 08:52:27 +0000723 PrintF("stack [<words>]\n");
724 PrintF(" dump stack content, default dump 10 words)\n");
725 PrintF("mem <address> [<words>]\n");
726 PrintF(" dump memory content, default dump 10 words)\n");
ager@chromium.org5c838252010-02-19 08:53:10 +0000727 PrintF("flags\n");
728 PrintF(" print flags\n");
729 PrintF("disasm [<instructions>]\n");
danno@chromium.org40cb8782011-05-25 07:58:50 +0000730 PrintF("disasm [<address/register>]\n");
731 PrintF("disasm [[<address/register>] <instructions>]\n");
732 PrintF(" disassemble code, default is 10 instructions\n");
733 PrintF(" from pc (alias 'di')\n");
ager@chromium.org5c838252010-02-19 08:53:10 +0000734 PrintF("gdb\n");
735 PrintF(" enter gdb\n");
736 PrintF("break <address>\n");
737 PrintF(" set a break point on the address\n");
738 PrintF("del\n");
739 PrintF(" delete the breakpoint\n");
ricow@chromium.orgc54d3652011-05-30 09:20:16 +0000740 PrintF("stop feature:\n");
741 PrintF(" Description:\n");
742 PrintF(" Stops are debug instructions inserted by\n");
743 PrintF(" the Assembler::stop() function.\n");
744 PrintF(" When hitting a stop, the Simulator will\n");
745 PrintF(" stop and and give control to the Debugger.\n");
746 PrintF(" All stop codes are watched:\n");
747 PrintF(" - They can be enabled / disabled: the Simulator\n");
748 PrintF(" will / won't stop when hitting them.\n");
749 PrintF(" - The Simulator keeps track of how many times they \n");
750 PrintF(" are met. (See the info command.) Going over a\n");
751 PrintF(" disabled stop still increases its counter. \n");
752 PrintF(" Commands:\n");
753 PrintF(" stop info all/<code> : print infos about number <code>\n");
754 PrintF(" or all stop(s).\n");
755 PrintF(" stop enable/disable all/<code> : enables / disables\n");
756 PrintF(" all or number <code> stop(s)\n");
757 PrintF(" stop unstop\n");
758 PrintF(" ignore the stop instruction at the current location\n");
759 PrintF(" from now on\n");
ager@chromium.org5c838252010-02-19 08:53:10 +0000760 } else {
761 PrintF("Unknown command: %s\n", cmd);
762 }
763 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000764 }
765
766 // Add all the breakpoints back to stop execution and enter the debugger
767 // shell when hit.
768 RedoBreakpoints();
769
770#undef COMMAND_SIZE
771#undef ARG_SIZE
772
773#undef STR
774#undef XSTR
775}
776
777
lrn@chromium.org7516f052011-03-30 08:52:27 +0000778static bool ICacheMatch(void* one, void* two) {
779 ASSERT((reinterpret_cast<intptr_t>(one) & CachePage::kPageMask) == 0);
780 ASSERT((reinterpret_cast<intptr_t>(two) & CachePage::kPageMask) == 0);
781 return one == two;
782}
ager@chromium.org5c838252010-02-19 08:53:10 +0000783
784
lrn@chromium.org7516f052011-03-30 08:52:27 +0000785static uint32_t ICacheHash(void* key) {
786 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)) >> 2;
787}
788
789
790static bool AllOnOnePage(uintptr_t start, int size) {
791 intptr_t start_page = (start & ~CachePage::kPageMask);
792 intptr_t end_page = ((start + size) & ~CachePage::kPageMask);
793 return start_page == end_page;
794}
795
796
danno@chromium.orgc612e022011-11-10 11:38:15 +0000797void Simulator::set_last_debugger_input(char* input) {
798 DeleteArray(last_debugger_input_);
799 last_debugger_input_ = input;
800}
801
802
lrn@chromium.org7516f052011-03-30 08:52:27 +0000803void Simulator::FlushICache(v8::internal::HashMap* i_cache,
804 void* start_addr,
805 size_t size) {
806 intptr_t start = reinterpret_cast<intptr_t>(start_addr);
807 int intra_line = (start & CachePage::kLineMask);
808 start -= intra_line;
809 size += intra_line;
810 size = ((size - 1) | CachePage::kLineMask) + 1;
811 int offset = (start & CachePage::kPageMask);
812 while (!AllOnOnePage(start, size - 1)) {
813 int bytes_to_flush = CachePage::kPageSize - offset;
814 FlushOnePage(i_cache, start, bytes_to_flush);
815 start += bytes_to_flush;
816 size -= bytes_to_flush;
817 ASSERT_EQ(0, start & CachePage::kPageMask);
818 offset = 0;
819 }
820 if (size != 0) {
821 FlushOnePage(i_cache, start, size);
822 }
823}
824
825
826CachePage* Simulator::GetCachePage(v8::internal::HashMap* i_cache, void* page) {
827 v8::internal::HashMap::Entry* entry = i_cache->Lookup(page,
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000828 ICacheHash(page),
829 true);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000830 if (entry->value == NULL) {
831 CachePage* new_page = new CachePage();
832 entry->value = new_page;
833 }
834 return reinterpret_cast<CachePage*>(entry->value);
835}
836
837
838// Flush from start up to and not including start + size.
839void Simulator::FlushOnePage(v8::internal::HashMap* i_cache,
840 intptr_t start,
841 int size) {
842 ASSERT(size <= CachePage::kPageSize);
843 ASSERT(AllOnOnePage(start, size - 1));
844 ASSERT((start & CachePage::kLineMask) == 0);
845 ASSERT((size & CachePage::kLineMask) == 0);
846 void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask));
847 int offset = (start & CachePage::kPageMask);
848 CachePage* cache_page = GetCachePage(i_cache, page);
849 char* valid_bytemap = cache_page->ValidityByte(offset);
850 memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift);
851}
852
853
854void Simulator::CheckICache(v8::internal::HashMap* i_cache,
855 Instruction* instr) {
856 intptr_t address = reinterpret_cast<intptr_t>(instr);
857 void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
858 void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask));
859 int offset = (address & CachePage::kPageMask);
860 CachePage* cache_page = GetCachePage(i_cache, page);
861 char* cache_valid_byte = cache_page->ValidityByte(offset);
862 bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID);
863 char* cached_line = cache_page->CachedData(offset & ~CachePage::kLineMask);
864 if (cache_hit) {
865 // Check that the data in memory matches the contents of the I-cache.
866 CHECK(memcmp(reinterpret_cast<void*>(instr),
867 cache_page->CachedData(offset),
868 Instruction::kInstrSize) == 0);
869 } else {
870 // Cache miss. Load memory into the cache.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000871 OS::MemCopy(cached_line, line, CachePage::kLineLength);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000872 *cache_valid_byte = CachePage::LINE_VALID;
873 }
874}
ager@chromium.org5c838252010-02-19 08:53:10 +0000875
876
lrn@chromium.org1c092762011-05-09 09:42:16 +0000877void Simulator::Initialize(Isolate* isolate) {
878 if (isolate->simulator_initialized()) return;
879 isolate->set_simulator_initialized(true);
880 ::v8::internal::ExternalReference::set_redirector(isolate,
881 &RedirectExternalReference);
ager@chromium.org5c838252010-02-19 08:53:10 +0000882}
883
884
lrn@chromium.org1c092762011-05-09 09:42:16 +0000885Simulator::Simulator(Isolate* isolate) : isolate_(isolate) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000886 i_cache_ = isolate_->simulator_i_cache();
887 if (i_cache_ == NULL) {
888 i_cache_ = new v8::internal::HashMap(&ICacheMatch);
889 isolate_->set_simulator_i_cache(i_cache_);
890 }
lrn@chromium.org1c092762011-05-09 09:42:16 +0000891 Initialize(isolate);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000892 // Set up simulator support first. Some of this information is needed to
ager@chromium.org5c838252010-02-19 08:53:10 +0000893 // setup the architecture state.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000894 stack_ = reinterpret_cast<char*>(malloc(stack_size_));
ager@chromium.org5c838252010-02-19 08:53:10 +0000895 pc_modified_ = false;
896 icount_ = 0;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000897 break_count_ = 0;
ager@chromium.org5c838252010-02-19 08:53:10 +0000898 break_pc_ = NULL;
899 break_instr_ = 0;
900
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000901 // Set up architecture state.
ager@chromium.org5c838252010-02-19 08:53:10 +0000902 // All registers are initialized to zero to start with.
903 for (int i = 0; i < kNumSimuRegisters; i++) {
904 registers_[i] = 0;
905 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000906 for (int i = 0; i < kNumFPURegisters; i++) {
907 FPUregisters_[i] = 0;
908 }
909 FCSR_ = 0;
ager@chromium.org5c838252010-02-19 08:53:10 +0000910
911 // The sp is initialized to point to the bottom (high address) of the
912 // allocated stack area. To be safe in potential stack underflows we leave
913 // some buffer below.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000914 registers_[sp] = reinterpret_cast<int32_t>(stack_) + stack_size_ - 64;
ager@chromium.org5c838252010-02-19 08:53:10 +0000915 // The ra and pc are initialized to a known bad value that will cause an
916 // access violation if the simulator ever tries to execute it.
917 registers_[pc] = bad_ra;
918 registers_[ra] = bad_ra;
919 InitializeCoverage();
lrn@chromium.org7516f052011-03-30 08:52:27 +0000920 for (int i = 0; i < kNumExceptions; i++) {
921 exceptions[i] = 0;
922 }
danno@chromium.orgc612e022011-11-10 11:38:15 +0000923
924 last_debugger_input_ = NULL;
ager@chromium.org5c838252010-02-19 08:53:10 +0000925}
926
927
titzer@chromium.orgf5a24542014-03-04 09:06:17 +0000928Simulator::~Simulator() {
929}
930
931
ager@chromium.org5c838252010-02-19 08:53:10 +0000932// When the generated code calls an external reference we need to catch that in
933// the simulator. The external reference will be a function compiled for the
934// host architecture. We need to call that function instead of trying to
935// execute it with the simulator. We do that by redirecting the external
936// reference to a swi (software-interrupt) instruction that is handled by
937// the simulator. We write the original destination of the jump just at a known
938// offset from the swi instruction so the simulator knows what to call.
939class Redirection {
940 public:
lrn@chromium.org7516f052011-03-30 08:52:27 +0000941 Redirection(void* external_function, ExternalReference::Type type)
ager@chromium.org5c838252010-02-19 08:53:10 +0000942 : external_function_(external_function),
943 swi_instruction_(rtCallRedirInstr),
lrn@chromium.org7516f052011-03-30 08:52:27 +0000944 type_(type),
945 next_(NULL) {
946 Isolate* isolate = Isolate::Current();
947 next_ = isolate->simulator_redirection();
948 Simulator::current(isolate)->
949 FlushICache(isolate->simulator_i_cache(),
950 reinterpret_cast<void*>(&swi_instruction_),
951 Instruction::kInstrSize);
952 isolate->set_simulator_redirection(this);
ager@chromium.org5c838252010-02-19 08:53:10 +0000953 }
954
955 void* address_of_swi_instruction() {
956 return reinterpret_cast<void*>(&swi_instruction_);
957 }
958
959 void* external_function() { return external_function_; }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000960 ExternalReference::Type type() { return type_; }
ager@chromium.org5c838252010-02-19 08:53:10 +0000961
lrn@chromium.org7516f052011-03-30 08:52:27 +0000962 static Redirection* Get(void* external_function,
963 ExternalReference::Type type) {
964 Isolate* isolate = Isolate::Current();
965 Redirection* current = isolate->simulator_redirection();
966 for (; current != NULL; current = current->next_) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000967 if (current->external_function_ == external_function) return current;
968 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000969 return new Redirection(external_function, type);
ager@chromium.org5c838252010-02-19 08:53:10 +0000970 }
971
972 static Redirection* FromSwiInstruction(Instruction* swi_instruction) {
973 char* addr_of_swi = reinterpret_cast<char*>(swi_instruction);
974 char* addr_of_redirection =
975 addr_of_swi - OFFSET_OF(Redirection, swi_instruction_);
976 return reinterpret_cast<Redirection*>(addr_of_redirection);
977 }
978
machenbach@chromium.org57a54ac2014-01-31 14:01:53 +0000979 static void* ReverseRedirection(int32_t reg) {
980 Redirection* redirection = FromSwiInstruction(
981 reinterpret_cast<Instruction*>(reinterpret_cast<void*>(reg)));
982 return redirection->external_function();
983 }
984
ager@chromium.org5c838252010-02-19 08:53:10 +0000985 private:
986 void* external_function_;
987 uint32_t swi_instruction_;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000988 ExternalReference::Type type_;
ager@chromium.org5c838252010-02-19 08:53:10 +0000989 Redirection* next_;
ager@chromium.org5c838252010-02-19 08:53:10 +0000990};
991
992
ager@chromium.org5c838252010-02-19 08:53:10 +0000993void* Simulator::RedirectExternalReference(void* external_function,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000994 ExternalReference::Type type) {
995 Redirection* redirection = Redirection::Get(external_function, type);
ager@chromium.org5c838252010-02-19 08:53:10 +0000996 return redirection->address_of_swi_instruction();
997}
998
999
1000// Get the active Simulator for the current thread.
lrn@chromium.org7516f052011-03-30 08:52:27 +00001001Simulator* Simulator::current(Isolate* isolate) {
1002 v8::internal::Isolate::PerIsolateThreadData* isolate_data =
lrn@chromium.org1c092762011-05-09 09:42:16 +00001003 isolate->FindOrAllocatePerThreadDataForThisThread();
1004 ASSERT(isolate_data != NULL);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001005 ASSERT(isolate_data != NULL);
1006
1007 Simulator* sim = isolate_data->simulator();
ager@chromium.org5c838252010-02-19 08:53:10 +00001008 if (sim == NULL) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001009 // TODO(146): delete the simulator object when a thread/isolate goes away.
lrn@chromium.org1c092762011-05-09 09:42:16 +00001010 sim = new Simulator(isolate);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001011 isolate_data->set_simulator(sim);
ager@chromium.org5c838252010-02-19 08:53:10 +00001012 }
1013 return sim;
1014}
1015
1016
1017// Sets the register in the architecture state. It will also deal with updating
1018// Simulator internal state for special registers such as PC.
1019void Simulator::set_register(int reg, int32_t value) {
1020 ASSERT((reg >= 0) && (reg < kNumSimuRegisters));
1021 if (reg == pc) {
1022 pc_modified_ = true;
1023 }
1024
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001025 // Zero register always holds 0.
ager@chromium.org5c838252010-02-19 08:53:10 +00001026 registers_[reg] = (reg == 0) ? 0 : value;
1027}
1028
lrn@chromium.org7516f052011-03-30 08:52:27 +00001029
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001030void Simulator::set_dw_register(int reg, const int* dbl) {
1031 ASSERT((reg >= 0) && (reg < kNumSimuRegisters));
1032 registers_[reg] = dbl[0];
1033 registers_[reg + 1] = dbl[1];
1034}
1035
1036
ager@chromium.org5c838252010-02-19 08:53:10 +00001037void Simulator::set_fpu_register(int fpureg, int32_t value) {
1038 ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters));
1039 FPUregisters_[fpureg] = value;
1040}
1041
lrn@chromium.org7516f052011-03-30 08:52:27 +00001042
1043void Simulator::set_fpu_register_float(int fpureg, float value) {
1044 ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters));
1045 *BitCast<float*>(&FPUregisters_[fpureg]) = value;
1046}
1047
1048
ager@chromium.org5c838252010-02-19 08:53:10 +00001049void Simulator::set_fpu_register_double(int fpureg, double value) {
1050 ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
lrn@chromium.org7516f052011-03-30 08:52:27 +00001051 *BitCast<double*>(&FPUregisters_[fpureg]) = value;
ager@chromium.org5c838252010-02-19 08:53:10 +00001052}
1053
1054
1055// Get the register from the architecture state. This function does handle
1056// the special case of accessing the PC register.
1057int32_t Simulator::get_register(int reg) const {
1058 ASSERT((reg >= 0) && (reg < kNumSimuRegisters));
1059 if (reg == 0)
1060 return 0;
1061 else
1062 return registers_[reg] + ((reg == pc) ? Instruction::kPCReadOffset : 0);
1063}
1064
lrn@chromium.org7516f052011-03-30 08:52:27 +00001065
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001066double Simulator::get_double_from_register_pair(int reg) {
1067 ASSERT((reg >= 0) && (reg < kNumSimuRegisters) && ((reg % 2) == 0));
1068
1069 double dm_val = 0.0;
1070 // Read the bits from the unsigned integer register_[] array
1071 // into the double precision floating point value and return it.
1072 char buffer[2 * sizeof(registers_[0])];
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001073 OS::MemCopy(buffer, &registers_[reg], 2 * sizeof(registers_[0]));
1074 OS::MemCopy(&dm_val, buffer, 2 * sizeof(registers_[0]));
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001075 return(dm_val);
1076}
1077
1078
ager@chromium.org5c838252010-02-19 08:53:10 +00001079int32_t Simulator::get_fpu_register(int fpureg) const {
1080 ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters));
1081 return FPUregisters_[fpureg];
1082}
1083
lrn@chromium.org7516f052011-03-30 08:52:27 +00001084
1085int64_t Simulator::get_fpu_register_long(int fpureg) const {
1086 ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
1087 return *BitCast<int64_t*>(
1088 const_cast<int32_t*>(&FPUregisters_[fpureg]));
1089}
1090
1091
1092float Simulator::get_fpu_register_float(int fpureg) const {
1093 ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters));
1094 return *BitCast<float*>(
1095 const_cast<int32_t*>(&FPUregisters_[fpureg]));
1096}
1097
1098
ager@chromium.org5c838252010-02-19 08:53:10 +00001099double Simulator::get_fpu_register_double(int fpureg) const {
1100 ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
lrn@chromium.org7516f052011-03-30 08:52:27 +00001101 return *BitCast<double*>(const_cast<int32_t*>(&FPUregisters_[fpureg]));
ager@chromium.org5c838252010-02-19 08:53:10 +00001102}
1103
lrn@chromium.org7516f052011-03-30 08:52:27 +00001104
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001105// Runtime FP routines take up to two double arguments and zero
1106// or one integer arguments. All are constructed here,
danno@chromium.org40cb8782011-05-25 07:58:50 +00001107// from a0-a3 or f12 and f14.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001108void Simulator::GetFpArgs(double* x, double* y, int32_t* z) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00001109 if (!IsMipsSoftFloatABI) {
1110 *x = get_fpu_register_double(12);
1111 *y = get_fpu_register_double(14);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001112 *z = get_register(a2);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001113 } else {
1114 // We use a char buffer to get around the strict-aliasing rules which
1115 // otherwise allow the compiler to optimize away the copy.
1116 char buffer[sizeof(*x)];
1117 int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
1118
1119 // Registers a0 and a1 -> x.
1120 reg_buffer[0] = get_register(a0);
1121 reg_buffer[1] = get_register(a1);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001122 OS::MemCopy(x, buffer, sizeof(buffer));
danno@chromium.org40cb8782011-05-25 07:58:50 +00001123 // Registers a2 and a3 -> y.
1124 reg_buffer[0] = get_register(a2);
1125 reg_buffer[1] = get_register(a3);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001126 OS::MemCopy(y, buffer, sizeof(buffer));
1127 // Register 2 -> z.
danno@chromium.org40cb8782011-05-25 07:58:50 +00001128 reg_buffer[0] = get_register(a2);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001129 OS::MemCopy(z, buffer, sizeof(*z));
danno@chromium.org40cb8782011-05-25 07:58:50 +00001130 }
1131}
1132
1133
1134// The return value is either in v0/v1 or f0.
1135void Simulator::SetFpResult(const double& result) {
1136 if (!IsMipsSoftFloatABI) {
1137 set_fpu_register_double(0, result);
1138 } else {
1139 char buffer[2 * sizeof(registers_[0])];
1140 int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001141 OS::MemCopy(buffer, &result, sizeof(buffer));
danno@chromium.org40cb8782011-05-25 07:58:50 +00001142 // Copy result to v0 and v1.
1143 set_register(v0, reg_buffer[0]);
1144 set_register(v1, reg_buffer[1]);
1145 }
1146}
1147
1148
lrn@chromium.org7516f052011-03-30 08:52:27 +00001149// Helper functions for setting and testing the FCSR register's bits.
1150void Simulator::set_fcsr_bit(uint32_t cc, bool value) {
1151 if (value) {
1152 FCSR_ |= (1 << cc);
1153 } else {
1154 FCSR_ &= ~(1 << cc);
1155 }
1156}
1157
1158
1159bool Simulator::test_fcsr_bit(uint32_t cc) {
1160 return FCSR_ & (1 << cc);
1161}
1162
1163
1164// Sets the rounding error codes in FCSR based on the result of the rounding.
1165// Returns true if the operation was invalid.
1166bool Simulator::set_fcsr_round_error(double original, double rounded) {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001167 bool ret = false;
1168
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00001169 if (!std::isfinite(original) || !std::isfinite(rounded)) {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001170 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1171 ret = true;
lrn@chromium.org7516f052011-03-30 08:52:27 +00001172 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001173
1174 if (original != rounded) {
1175 set_fcsr_bit(kFCSRInexactFlagBit, true);
1176 }
1177
1178 if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) {
1179 set_fcsr_bit(kFCSRUnderflowFlagBit, true);
1180 ret = true;
1181 }
1182
1183 if (rounded > INT_MAX || rounded < INT_MIN) {
1184 set_fcsr_bit(kFCSROverflowFlagBit, true);
1185 // The reference is not really clear but it seems this is required:
1186 set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1187 ret = true;
1188 }
1189
1190 return ret;
lrn@chromium.org7516f052011-03-30 08:52:27 +00001191}
1192
1193
ager@chromium.org5c838252010-02-19 08:53:10 +00001194// Raw access to the PC register.
1195void Simulator::set_pc(int32_t value) {
1196 pc_modified_ = true;
1197 registers_[pc] = value;
1198}
1199
lrn@chromium.org7516f052011-03-30 08:52:27 +00001200
1201bool Simulator::has_bad_pc() const {
1202 return ((registers_[pc] == bad_ra) || (registers_[pc] == end_sim_pc));
1203}
1204
1205
ager@chromium.org5c838252010-02-19 08:53:10 +00001206// Raw access to the PC register without the special adjustment when reading.
1207int32_t Simulator::get_pc() const {
1208 return registers_[pc];
1209}
1210
1211
1212// The MIPS cannot do unaligned reads and writes. On some MIPS platforms an
1213// interrupt is caused. On others it does a funky rotation thing. For now we
1214// simply disallow unaligned reads, but at some point we may want to move to
1215// emulating the rotate behaviour. Note that simulator runs have the runtime
1216// system running directly on the host system and only generated code is
1217// executed in the simulator. Since the host is typically IA32 we will not
1218// get the correct MIPS-like behaviour on unaligned accesses.
1219
1220int Simulator::ReadW(int32_t addr, Instruction* instr) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001221 if (addr >=0 && addr < 0x400) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001222 // This has to be a NULL-dereference, drop into debugger.
lrn@chromium.org34e60782011-09-15 07:25:40 +00001223 PrintF("Memory read from bad address: 0x%08x, pc=0x%08x\n",
1224 addr, reinterpret_cast<intptr_t>(instr));
lrn@chromium.org7516f052011-03-30 08:52:27 +00001225 MipsDebugger dbg(this);
1226 dbg.Debug();
1227 }
1228 if ((addr & kPointerAlignmentMask) == 0) {
ager@chromium.org5c838252010-02-19 08:53:10 +00001229 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
1230 return *ptr;
1231 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001232 PrintF("Unaligned read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1233 addr,
1234 reinterpret_cast<intptr_t>(instr));
lrn@chromium.org7516f052011-03-30 08:52:27 +00001235 MipsDebugger dbg(this);
1236 dbg.Debug();
ager@chromium.org5c838252010-02-19 08:53:10 +00001237 return 0;
1238}
1239
1240
1241void Simulator::WriteW(int32_t addr, int value, Instruction* instr) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001242 if (addr >= 0 && addr < 0x400) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001243 // This has to be a NULL-dereference, drop into debugger.
lrn@chromium.org34e60782011-09-15 07:25:40 +00001244 PrintF("Memory write to bad address: 0x%08x, pc=0x%08x\n",
1245 addr, reinterpret_cast<intptr_t>(instr));
lrn@chromium.org7516f052011-03-30 08:52:27 +00001246 MipsDebugger dbg(this);
1247 dbg.Debug();
1248 }
1249 if ((addr & kPointerAlignmentMask) == 0) {
ager@chromium.org5c838252010-02-19 08:53:10 +00001250 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
1251 *ptr = value;
1252 return;
1253 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001254 PrintF("Unaligned write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1255 addr,
1256 reinterpret_cast<intptr_t>(instr));
lrn@chromium.org7516f052011-03-30 08:52:27 +00001257 MipsDebugger dbg(this);
1258 dbg.Debug();
ager@chromium.org5c838252010-02-19 08:53:10 +00001259}
1260
1261
1262double Simulator::ReadD(int32_t addr, Instruction* instr) {
1263 if ((addr & kDoubleAlignmentMask) == 0) {
1264 double* ptr = reinterpret_cast<double*>(addr);
1265 return *ptr;
1266 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001267 PrintF("Unaligned (double) read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1268 addr,
1269 reinterpret_cast<intptr_t>(instr));
ager@chromium.org5c838252010-02-19 08:53:10 +00001270 OS::Abort();
1271 return 0;
1272}
1273
1274
1275void Simulator::WriteD(int32_t addr, double value, Instruction* instr) {
1276 if ((addr & kDoubleAlignmentMask) == 0) {
1277 double* ptr = reinterpret_cast<double*>(addr);
1278 *ptr = value;
1279 return;
1280 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001281 PrintF("Unaligned (double) write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1282 addr,
1283 reinterpret_cast<intptr_t>(instr));
ager@chromium.org5c838252010-02-19 08:53:10 +00001284 OS::Abort();
1285}
1286
1287
1288uint16_t Simulator::ReadHU(int32_t addr, Instruction* instr) {
1289 if ((addr & 1) == 0) {
1290 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1291 return *ptr;
1292 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001293 PrintF("Unaligned unsigned halfword read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1294 addr,
1295 reinterpret_cast<intptr_t>(instr));
ager@chromium.org5c838252010-02-19 08:53:10 +00001296 OS::Abort();
1297 return 0;
1298}
1299
1300
1301int16_t Simulator::ReadH(int32_t addr, Instruction* instr) {
1302 if ((addr & 1) == 0) {
1303 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
1304 return *ptr;
1305 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001306 PrintF("Unaligned signed halfword read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1307 addr,
1308 reinterpret_cast<intptr_t>(instr));
ager@chromium.org5c838252010-02-19 08:53:10 +00001309 OS::Abort();
1310 return 0;
1311}
1312
1313
1314void Simulator::WriteH(int32_t addr, uint16_t value, Instruction* instr) {
1315 if ((addr & 1) == 0) {
1316 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1317 *ptr = value;
1318 return;
1319 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001320 PrintF("Unaligned unsigned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1321 addr,
1322 reinterpret_cast<intptr_t>(instr));
ager@chromium.org5c838252010-02-19 08:53:10 +00001323 OS::Abort();
1324}
1325
1326
1327void Simulator::WriteH(int32_t addr, int16_t value, Instruction* instr) {
1328 if ((addr & 1) == 0) {
1329 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
1330 *ptr = value;
1331 return;
1332 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001333 PrintF("Unaligned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
1334 addr,
1335 reinterpret_cast<intptr_t>(instr));
ager@chromium.org5c838252010-02-19 08:53:10 +00001336 OS::Abort();
1337}
1338
1339
1340uint32_t Simulator::ReadBU(int32_t addr) {
1341 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1342 return *ptr & 0xff;
1343}
1344
1345
1346int32_t Simulator::ReadB(int32_t addr) {
1347 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001348 return *ptr;
ager@chromium.org5c838252010-02-19 08:53:10 +00001349}
1350
1351
1352void Simulator::WriteB(int32_t addr, uint8_t value) {
1353 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1354 *ptr = value;
1355}
1356
1357
1358void Simulator::WriteB(int32_t addr, int8_t value) {
1359 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
1360 *ptr = value;
1361}
1362
1363
1364// Returns the limit of the stack area to enable checking for stack overflows.
1365uintptr_t Simulator::StackLimit() const {
yangguo@chromium.org56454712012-02-16 15:33:53 +00001366 // Leave a safety margin of 1024 bytes to prevent overrunning the stack when
ager@chromium.org5c838252010-02-19 08:53:10 +00001367 // pushing values.
yangguo@chromium.org56454712012-02-16 15:33:53 +00001368 return reinterpret_cast<uintptr_t>(stack_) + 1024;
ager@chromium.org5c838252010-02-19 08:53:10 +00001369}
1370
1371
1372// Unsupported instructions use Format to print an error and stop execution.
1373void Simulator::Format(Instruction* instr, const char* format) {
1374 PrintF("Simulator found unsupported instruction:\n 0x%08x: %s\n",
lrn@chromium.org7516f052011-03-30 08:52:27 +00001375 reinterpret_cast<intptr_t>(instr), format);
ager@chromium.org5c838252010-02-19 08:53:10 +00001376 UNIMPLEMENTED_MIPS();
1377}
1378
1379
1380// Calls into the V8 runtime are based on this very simple interface.
1381// Note: To be able to return two values from some calls the code in runtime.cc
1382// uses the ObjectPair which is essentially two 32-bit values stuffed into a
1383// 64-bit value. With the code below we assume that all runtime calls return
lrn@chromium.org7516f052011-03-30 08:52:27 +00001384// 64 bits of result. If they don't, the v1 result register contains a bogus
ager@chromium.org5c838252010-02-19 08:53:10 +00001385// value, which is fine because it is caller-saved.
1386typedef int64_t (*SimulatorRuntimeCall)(int32_t arg0,
1387 int32_t arg1,
1388 int32_t arg2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001389 int32_t arg3,
1390 int32_t arg4,
1391 int32_t arg5);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001392
1393// These prototypes handle the four types of FP calls.
1394typedef int64_t (*SimulatorRuntimeCompareCall)(double darg0, double darg1);
1395typedef double (*SimulatorRuntimeFPFPCall)(double darg0, double darg1);
1396typedef double (*SimulatorRuntimeFPCall)(double darg0);
1397typedef double (*SimulatorRuntimeFPIntCall)(double darg0, int32_t arg0);
ager@chromium.org5c838252010-02-19 08:53:10 +00001398
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001399// This signature supports direct call in to API function native callback
1400// (refer to InvocationCallback in v8.h).
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001401typedef void (*SimulatorRuntimeDirectApiCall)(int32_t arg0);
machenbach@chromium.org57a54ac2014-01-31 14:01:53 +00001402typedef void (*SimulatorRuntimeProfilingApiCall)(int32_t arg0, void* arg1);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001403
1404// This signature supports direct call to accessor getter callback.
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001405typedef void (*SimulatorRuntimeDirectGetterCall)(int32_t arg0, int32_t arg1);
1406typedef void (*SimulatorRuntimeProfilingGetterCall)(
machenbach@chromium.org57a54ac2014-01-31 14:01:53 +00001407 int32_t arg0, int32_t arg1, void* arg2);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001408
ager@chromium.org5c838252010-02-19 08:53:10 +00001409// Software interrupt instructions are used by the simulator to call into the
lrn@chromium.org7516f052011-03-30 08:52:27 +00001410// C-based V8 runtime. They are also used for debugging with simulator.
ager@chromium.org5c838252010-02-19 08:53:10 +00001411void Simulator::SoftwareInterrupt(Instruction* instr) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001412 // There are several instructions that could get us here,
1413 // the break_ instruction, or several variants of traps. All
1414 // Are "SPECIAL" class opcode, and are distinuished by function.
1415 int32_t func = instr->FunctionFieldRaw();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00001416 uint32_t code = (func == BREAK) ? instr->Bits(25, 6) : -1;
lrn@chromium.org7516f052011-03-30 08:52:27 +00001417
ager@chromium.org5c838252010-02-19 08:53:10 +00001418 // We first check if we met a call_rt_redirected.
1419 if (instr->InstructionBits() == rtCallRedirInstr) {
1420 Redirection* redirection = Redirection::FromSwiInstruction(instr);
1421 int32_t arg0 = get_register(a0);
1422 int32_t arg1 = get_register(a1);
1423 int32_t arg2 = get_register(a2);
1424 int32_t arg3 = get_register(a3);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001425
lrn@chromium.org7516f052011-03-30 08:52:27 +00001426 int32_t* stack_pointer = reinterpret_cast<int32_t*>(get_register(sp));
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001427 // Args 4 and 5 are on the stack after the reserved space for args 0..3.
1428 int32_t arg4 = stack_pointer[4];
1429 int32_t arg5 = stack_pointer[5];
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001430
1431 bool fp_call =
1432 (redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) ||
1433 (redirection->type() == ExternalReference::BUILTIN_COMPARE_CALL) ||
1434 (redirection->type() == ExternalReference::BUILTIN_FP_CALL) ||
1435 (redirection->type() == ExternalReference::BUILTIN_FP_INT_CALL);
1436
danno@chromium.org40cb8782011-05-25 07:58:50 +00001437 if (!IsMipsSoftFloatABI) {
1438 // With the hard floating point calling convention, double
1439 // arguments are passed in FPU registers. Fetch the arguments
1440 // from there and call the builtin using soft floating point
1441 // convention.
1442 switch (redirection->type()) {
1443 case ExternalReference::BUILTIN_FP_FP_CALL:
1444 case ExternalReference::BUILTIN_COMPARE_CALL:
1445 arg0 = get_fpu_register(f12);
1446 arg1 = get_fpu_register(f13);
1447 arg2 = get_fpu_register(f14);
1448 arg3 = get_fpu_register(f15);
1449 break;
1450 case ExternalReference::BUILTIN_FP_CALL:
1451 arg0 = get_fpu_register(f12);
1452 arg1 = get_fpu_register(f13);
1453 break;
1454 case ExternalReference::BUILTIN_FP_INT_CALL:
1455 arg0 = get_fpu_register(f12);
1456 arg1 = get_fpu_register(f13);
1457 arg2 = get_register(a2);
1458 break;
1459 default:
1460 break;
1461 }
1462 }
1463
ager@chromium.org5c838252010-02-19 08:53:10 +00001464 // This is dodgy but it works because the C entry stubs are never moved.
1465 // See comment in codegen-arm.cc and bug 1242173.
1466 int32_t saved_ra = get_register(ra);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001467
1468 intptr_t external =
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001469 reinterpret_cast<intptr_t>(redirection->external_function());
lrn@chromium.org7516f052011-03-30 08:52:27 +00001470
1471 // Based on CpuFeatures::IsSupported(FPU), Mips will use either hardware
1472 // FPU, or gcc soft-float routines. Hardware FPU is simulated in this
1473 // simulator. Soft-float has additional abstraction of ExternalReference,
danno@chromium.org40cb8782011-05-25 07:58:50 +00001474 // to support serialization.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001475 if (fp_call) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001476 double dval0, dval1; // one or two double parameters
1477 int32_t ival; // zero or one integer parameters
1478 int64_t iresult = 0; // integer return value
1479 double dresult = 0; // double return value
1480 GetFpArgs(&dval0, &dval1, &ival);
1481 SimulatorRuntimeCall generic_target =
1482 reinterpret_cast<SimulatorRuntimeCall>(external);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001483 if (::v8::internal::FLAG_trace_sim) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00001484 switch (redirection->type()) {
1485 case ExternalReference::BUILTIN_FP_FP_CALL:
1486 case ExternalReference::BUILTIN_COMPARE_CALL:
danno@chromium.org40cb8782011-05-25 07:58:50 +00001487 PrintF("Call to host function at %p with args %f, %f",
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001488 FUNCTION_ADDR(generic_target), dval0, dval1);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001489 break;
1490 case ExternalReference::BUILTIN_FP_CALL:
danno@chromium.org40cb8782011-05-25 07:58:50 +00001491 PrintF("Call to host function at %p with arg %f",
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001492 FUNCTION_ADDR(generic_target), dval0);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001493 break;
1494 case ExternalReference::BUILTIN_FP_INT_CALL:
danno@chromium.org40cb8782011-05-25 07:58:50 +00001495 PrintF("Call to host function at %p with args %f, %d",
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001496 FUNCTION_ADDR(generic_target), dval0, ival);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001497 break;
1498 default:
1499 UNREACHABLE();
1500 break;
1501 }
1502 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001503 switch (redirection->type()) {
1504 case ExternalReference::BUILTIN_COMPARE_CALL: {
1505 SimulatorRuntimeCompareCall target =
1506 reinterpret_cast<SimulatorRuntimeCompareCall>(external);
1507 iresult = target(dval0, dval1);
1508 set_register(v0, static_cast<int32_t>(iresult));
1509 set_register(v1, static_cast<int32_t>(iresult >> 32));
1510 break;
1511 }
1512 case ExternalReference::BUILTIN_FP_FP_CALL: {
1513 SimulatorRuntimeFPFPCall target =
1514 reinterpret_cast<SimulatorRuntimeFPFPCall>(external);
1515 dresult = target(dval0, dval1);
1516 SetFpResult(dresult);
1517 break;
1518 }
1519 case ExternalReference::BUILTIN_FP_CALL: {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00001520 SimulatorRuntimeFPCall target =
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001521 reinterpret_cast<SimulatorRuntimeFPCall>(external);
1522 dresult = target(dval0);
1523 SetFpResult(dresult);
1524 break;
1525 }
1526 case ExternalReference::BUILTIN_FP_INT_CALL: {
1527 SimulatorRuntimeFPIntCall target =
1528 reinterpret_cast<SimulatorRuntimeFPIntCall>(external);
1529 dresult = target(dval0, ival);
1530 SetFpResult(dresult);
1531 break;
1532 }
1533 default:
1534 UNREACHABLE();
1535 break;
1536 }
1537 if (::v8::internal::FLAG_trace_sim) {
1538 switch (redirection->type()) {
1539 case ExternalReference::BUILTIN_COMPARE_CALL:
1540 PrintF("Returned %08x\n", static_cast<int32_t>(iresult));
1541 break;
1542 case ExternalReference::BUILTIN_FP_FP_CALL:
1543 case ExternalReference::BUILTIN_FP_CALL:
1544 case ExternalReference::BUILTIN_FP_INT_CALL:
1545 PrintF("Returned %f\n", dresult);
1546 break;
1547 default:
1548 UNREACHABLE();
1549 break;
1550 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00001551 }
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001552 } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) {
1553 if (::v8::internal::FLAG_trace_sim) {
1554 PrintF("Call to host function at %p args %08x\n",
1555 reinterpret_cast<void*>(external), arg0);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001556 }
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001557 SimulatorRuntimeDirectApiCall target =
1558 reinterpret_cast<SimulatorRuntimeDirectApiCall>(external);
1559 target(arg0);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001560 } else if (
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001561 redirection->type() == ExternalReference::PROFILING_API_CALL) {
1562 if (::v8::internal::FLAG_trace_sim) {
1563 PrintF("Call to host function at %p args %08x %08x\n",
1564 reinterpret_cast<void*>(external), arg0, arg1);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001565 }
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001566 SimulatorRuntimeProfilingApiCall target =
1567 reinterpret_cast<SimulatorRuntimeProfilingApiCall>(external);
machenbach@chromium.org57a54ac2014-01-31 14:01:53 +00001568 target(arg0, Redirection::ReverseRedirection(arg1));
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001569 } else if (
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001570 redirection->type() == ExternalReference::DIRECT_GETTER_CALL) {
1571 if (::v8::internal::FLAG_trace_sim) {
1572 PrintF("Call to host function at %p args %08x %08x\n",
1573 reinterpret_cast<void*>(external), arg0, arg1);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001574 }
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001575 SimulatorRuntimeDirectGetterCall target =
1576 reinterpret_cast<SimulatorRuntimeDirectGetterCall>(external);
1577 target(arg0, arg1);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001578 } else if (
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001579 redirection->type() == ExternalReference::PROFILING_GETTER_CALL) {
1580 if (::v8::internal::FLAG_trace_sim) {
1581 PrintF("Call to host function at %p args %08x %08x %08x\n",
1582 reinterpret_cast<void*>(external), arg0, arg1, arg2);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001583 }
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001584 SimulatorRuntimeProfilingGetterCall target =
1585 reinterpret_cast<SimulatorRuntimeProfilingGetterCall>(external);
machenbach@chromium.org57a54ac2014-01-31 14:01:53 +00001586 target(arg0, arg1, Redirection::ReverseRedirection(arg2));
ager@chromium.org5c838252010-02-19 08:53:10 +00001587 } else {
ager@chromium.org5c838252010-02-19 08:53:10 +00001588 SimulatorRuntimeCall target =
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001589 reinterpret_cast<SimulatorRuntimeCall>(external);
1590 if (::v8::internal::FLAG_trace_sim) {
ager@chromium.org5c838252010-02-19 08:53:10 +00001591 PrintF(
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001592 "Call to host function at %p "
1593 "args %08x, %08x, %08x, %08x, %08x, %08x\n",
ager@chromium.org5c838252010-02-19 08:53:10 +00001594 FUNCTION_ADDR(target),
1595 arg0,
1596 arg1,
1597 arg2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001598 arg3,
1599 arg4,
1600 arg5);
ager@chromium.org5c838252010-02-19 08:53:10 +00001601 }
lrn@chromium.org7516f052011-03-30 08:52:27 +00001602 int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5);
1603 set_register(v0, static_cast<int32_t>(result));
1604 set_register(v1, static_cast<int32_t>(result >> 32));
1605 }
1606 if (::v8::internal::FLAG_trace_sim) {
1607 PrintF("Returned %08x : %08x\n", get_register(v1), get_register(v0));
ager@chromium.org5c838252010-02-19 08:53:10 +00001608 }
1609 set_register(ra, saved_ra);
1610 set_pc(get_register(ra));
lrn@chromium.org7516f052011-03-30 08:52:27 +00001611
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00001612 } else if (func == BREAK && code <= kMaxStopCode) {
1613 if (IsWatchpoint(code)) {
1614 PrintWatchpoint(code);
1615 } else {
1616 IncreaseStopCounter(code);
1617 HandleStop(code, instr);
1618 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001619 } else {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001620 // All remaining break_ codes, and all traps are handled here.
1621 MipsDebugger dbg(this);
ager@chromium.org5c838252010-02-19 08:53:10 +00001622 dbg.Debug();
1623 }
1624}
1625
lrn@chromium.org7516f052011-03-30 08:52:27 +00001626
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00001627// Stop helper functions.
1628bool Simulator::IsWatchpoint(uint32_t code) {
1629 return (code <= kMaxWatchpointCode);
1630}
1631
1632
1633void Simulator::PrintWatchpoint(uint32_t code) {
1634 MipsDebugger dbg(this);
1635 ++break_count_;
1636 PrintF("\n---- break %d marker: %3d (instr count: %8d) ----------"
1637 "----------------------------------",
1638 code, break_count_, icount_);
1639 dbg.PrintAllRegs(); // Print registers and continue running.
1640}
1641
1642
1643void Simulator::HandleStop(uint32_t code, Instruction* instr) {
1644 // Stop if it is enabled, otherwise go on jumping over the stop
1645 // and the message address.
1646 if (IsEnabledStop(code)) {
1647 MipsDebugger dbg(this);
1648 dbg.Stop(instr);
1649 } else {
1650 set_pc(get_pc() + 2 * Instruction::kInstrSize);
1651 }
1652}
1653
1654
1655bool Simulator::IsStopInstruction(Instruction* instr) {
1656 int32_t func = instr->FunctionFieldRaw();
1657 uint32_t code = static_cast<uint32_t>(instr->Bits(25, 6));
1658 return (func == BREAK) && code > kMaxWatchpointCode && code <= kMaxStopCode;
1659}
1660
1661
1662bool Simulator::IsEnabledStop(uint32_t code) {
1663 ASSERT(code <= kMaxStopCode);
1664 ASSERT(code > kMaxWatchpointCode);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001665 return !(watched_stops_[code].count & kStopDisabledBit);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00001666}
1667
1668
1669void Simulator::EnableStop(uint32_t code) {
1670 if (!IsEnabledStop(code)) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001671 watched_stops_[code].count &= ~kStopDisabledBit;
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00001672 }
1673}
1674
1675
1676void Simulator::DisableStop(uint32_t code) {
1677 if (IsEnabledStop(code)) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001678 watched_stops_[code].count |= kStopDisabledBit;
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00001679 }
1680}
1681
1682
1683void Simulator::IncreaseStopCounter(uint32_t code) {
1684 ASSERT(code <= kMaxStopCode);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001685 if ((watched_stops_[code].count & ~(1 << 31)) == 0x7fffffff) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00001686 PrintF("Stop counter for code %i has overflowed.\n"
1687 "Enabling this code and reseting the counter to 0.\n", code);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001688 watched_stops_[code].count = 0;
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00001689 EnableStop(code);
1690 } else {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001691 watched_stops_[code].count++;
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00001692 }
1693}
1694
1695
1696// Print a stop status.
1697void Simulator::PrintStopInfo(uint32_t code) {
1698 if (code <= kMaxWatchpointCode) {
1699 PrintF("That is a watchpoint, not a stop.\n");
1700 return;
1701 } else if (code > kMaxStopCode) {
1702 PrintF("Code too large, only %u stops can be used\n", kMaxStopCode + 1);
1703 return;
1704 }
1705 const char* state = IsEnabledStop(code) ? "Enabled" : "Disabled";
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001706 int32_t count = watched_stops_[code].count & ~kStopDisabledBit;
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00001707 // Don't print the state of unused breakpoints.
1708 if (count != 0) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001709 if (watched_stops_[code].desc) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00001710 PrintF("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n",
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001711 code, code, state, count, watched_stops_[code].desc);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00001712 } else {
1713 PrintF("stop %i - 0x%x: \t%s, \tcounter = %i\n",
1714 code, code, state, count);
1715 }
1716 }
1717}
1718
1719
ager@chromium.org5c838252010-02-19 08:53:10 +00001720void Simulator::SignalExceptions() {
1721 for (int i = 1; i < kNumExceptions; i++) {
1722 if (exceptions[i] != 0) {
1723 V8_Fatal(__FILE__, __LINE__, "Error: Exception %i raised.", i);
1724 }
1725 }
1726}
1727
lrn@chromium.org7516f052011-03-30 08:52:27 +00001728
ager@chromium.org5c838252010-02-19 08:53:10 +00001729// Handle execution based on instruction types.
ager@chromium.org5c838252010-02-19 08:53:10 +00001730
lrn@chromium.org7516f052011-03-30 08:52:27 +00001731void Simulator::ConfigureTypeRegister(Instruction* instr,
1732 int32_t& alu_out,
1733 int64_t& i64hilo,
1734 uint64_t& u64hilo,
1735 int32_t& next_pc,
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00001736 int32_t& return_addr_reg,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001737 bool& do_interrupt) {
1738 // Every local variable declared here needs to be const.
1739 // This is to make sure that changed values are sent back to
1740 // DecodeTypeRegister correctly.
ager@chromium.org5c838252010-02-19 08:53:10 +00001741
lrn@chromium.org7516f052011-03-30 08:52:27 +00001742 // Instruction fields.
1743 const Opcode op = instr->OpcodeFieldRaw();
1744 const int32_t rs_reg = instr->RsValue();
1745 const int32_t rs = get_register(rs_reg);
1746 const uint32_t rs_u = static_cast<uint32_t>(rs);
1747 const int32_t rt_reg = instr->RtValue();
1748 const int32_t rt = get_register(rt_reg);
1749 const uint32_t rt_u = static_cast<uint32_t>(rt);
1750 const int32_t rd_reg = instr->RdValue();
1751 const uint32_t sa = instr->SaValue();
ager@chromium.org5c838252010-02-19 08:53:10 +00001752
lrn@chromium.org7516f052011-03-30 08:52:27 +00001753 const int32_t fs_reg = instr->FsValue();
ager@chromium.org5c838252010-02-19 08:53:10 +00001754
ager@chromium.org5c838252010-02-19 08:53:10 +00001755
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001756 // ---------- Configuration.
ager@chromium.org5c838252010-02-19 08:53:10 +00001757 switch (op) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001758 case COP1: // Coprocessor instructions.
ager@chromium.org5c838252010-02-19 08:53:10 +00001759 switch (instr->RsFieldRaw()) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001760 case BC1: // Handled in DecodeTypeImmed, should never come here.
ager@chromium.org5c838252010-02-19 08:53:10 +00001761 UNREACHABLE();
1762 break;
lrn@chromium.org7516f052011-03-30 08:52:27 +00001763 case CFC1:
1764 // At the moment only FCSR is supported.
1765 ASSERT(fs_reg == kFCSRRegister);
1766 alu_out = FCSR_;
1767 break;
ager@chromium.org5c838252010-02-19 08:53:10 +00001768 case MFC1:
1769 alu_out = get_fpu_register(fs_reg);
1770 break;
1771 case MFHC1:
lrn@chromium.org7516f052011-03-30 08:52:27 +00001772 UNIMPLEMENTED_MIPS();
ager@chromium.org5c838252010-02-19 08:53:10 +00001773 break;
lrn@chromium.org7516f052011-03-30 08:52:27 +00001774 case CTC1:
ager@chromium.org5c838252010-02-19 08:53:10 +00001775 case MTC1:
1776 case MTHC1:
1777 // Do the store in the execution step.
1778 break;
1779 case S:
1780 case D:
1781 case W:
1782 case L:
1783 case PS:
1784 // Do everything in the execution step.
1785 break;
1786 default:
1787 UNIMPLEMENTED_MIPS();
1788 };
1789 break;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001790 case COP1X:
1791 break;
ager@chromium.org5c838252010-02-19 08:53:10 +00001792 case SPECIAL:
1793 switch (instr->FunctionFieldRaw()) {
1794 case JR:
1795 case JALR:
lrn@chromium.org7516f052011-03-30 08:52:27 +00001796 next_pc = get_register(instr->RsValue());
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00001797 return_addr_reg = instr->RdValue();
ager@chromium.org5c838252010-02-19 08:53:10 +00001798 break;
1799 case SLL:
1800 alu_out = rt << sa;
1801 break;
1802 case SRL:
lrn@chromium.org7516f052011-03-30 08:52:27 +00001803 if (rs_reg == 0) {
1804 // Regular logical right shift of a word by a fixed number of
1805 // bits instruction. RS field is always equal to 0.
1806 alu_out = rt_u >> sa;
1807 } else {
1808 // Logical right-rotate of a word by a fixed number of bits. This
1809 // is special case of SRL instruction, added in MIPS32 Release 2.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001810 // RS field is equal to 00001.
lrn@chromium.org7516f052011-03-30 08:52:27 +00001811 alu_out = (rt_u >> sa) | (rt_u << (32 - sa));
1812 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001813 break;
1814 case SRA:
1815 alu_out = rt >> sa;
1816 break;
1817 case SLLV:
1818 alu_out = rt << rs;
1819 break;
1820 case SRLV:
lrn@chromium.org7516f052011-03-30 08:52:27 +00001821 if (sa == 0) {
1822 // Regular logical right-shift of a word by a variable number of
1823 // bits instruction. SA field is always equal to 0.
1824 alu_out = rt_u >> rs;
1825 } else {
1826 // Logical right-rotate of a word by a variable number of bits.
1827 // This is special case od SRLV instruction, added in MIPS32
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001828 // Release 2. SA field is equal to 00001.
lrn@chromium.org7516f052011-03-30 08:52:27 +00001829 alu_out = (rt_u >> rs_u) | (rt_u << (32 - rs_u));
1830 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001831 break;
1832 case SRAV:
1833 alu_out = rt >> rs;
1834 break;
1835 case MFHI:
1836 alu_out = get_register(HI);
1837 break;
1838 case MFLO:
1839 alu_out = get_register(LO);
1840 break;
1841 case MULT:
lrn@chromium.org7516f052011-03-30 08:52:27 +00001842 i64hilo = static_cast<int64_t>(rs) * static_cast<int64_t>(rt);
ager@chromium.org5c838252010-02-19 08:53:10 +00001843 break;
1844 case MULTU:
lrn@chromium.org7516f052011-03-30 08:52:27 +00001845 u64hilo = static_cast<uint64_t>(rs_u) * static_cast<uint64_t>(rt_u);
ager@chromium.org5c838252010-02-19 08:53:10 +00001846 break;
ager@chromium.org5c838252010-02-19 08:53:10 +00001847 case ADD:
1848 if (HaveSameSign(rs, rt)) {
1849 if (rs > 0) {
1850 exceptions[kIntegerOverflow] = rs > (Registers::kMaxValue - rt);
1851 } else if (rs < 0) {
1852 exceptions[kIntegerUnderflow] = rs < (Registers::kMinValue - rt);
1853 }
1854 }
1855 alu_out = rs + rt;
1856 break;
1857 case ADDU:
1858 alu_out = rs + rt;
1859 break;
1860 case SUB:
1861 if (!HaveSameSign(rs, rt)) {
1862 if (rs > 0) {
1863 exceptions[kIntegerOverflow] = rs > (Registers::kMaxValue + rt);
1864 } else if (rs < 0) {
1865 exceptions[kIntegerUnderflow] = rs < (Registers::kMinValue + rt);
1866 }
1867 }
1868 alu_out = rs - rt;
1869 break;
1870 case SUBU:
1871 alu_out = rs - rt;
1872 break;
1873 case AND:
1874 alu_out = rs & rt;
1875 break;
1876 case OR:
1877 alu_out = rs | rt;
1878 break;
1879 case XOR:
1880 alu_out = rs ^ rt;
1881 break;
1882 case NOR:
1883 alu_out = ~(rs | rt);
1884 break;
1885 case SLT:
1886 alu_out = rs < rt ? 1 : 0;
1887 break;
1888 case SLTU:
1889 alu_out = rs_u < rt_u ? 1 : 0;
1890 break;
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001891 // Break and trap instructions.
ager@chromium.org5c838252010-02-19 08:53:10 +00001892 case BREAK:
lrn@chromium.org7516f052011-03-30 08:52:27 +00001893
ager@chromium.org5c838252010-02-19 08:53:10 +00001894 do_interrupt = true;
1895 break;
1896 case TGE:
1897 do_interrupt = rs >= rt;
1898 break;
1899 case TGEU:
1900 do_interrupt = rs_u >= rt_u;
1901 break;
1902 case TLT:
1903 do_interrupt = rs < rt;
1904 break;
1905 case TLTU:
1906 do_interrupt = rs_u < rt_u;
1907 break;
1908 case TEQ:
1909 do_interrupt = rs == rt;
1910 break;
1911 case TNE:
1912 do_interrupt = rs != rt;
1913 break;
lrn@chromium.org7516f052011-03-30 08:52:27 +00001914 case MOVN:
1915 case MOVZ:
1916 case MOVCI:
1917 // No action taken on decode.
1918 break;
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001919 case DIV:
1920 case DIVU:
1921 // div and divu never raise exceptions.
1922 break;
ager@chromium.org5c838252010-02-19 08:53:10 +00001923 default:
1924 UNREACHABLE();
1925 };
1926 break;
1927 case SPECIAL2:
1928 switch (instr->FunctionFieldRaw()) {
1929 case MUL:
1930 alu_out = rs_u * rt_u; // Only the lower 32 bits are kept.
1931 break;
lrn@chromium.org7516f052011-03-30 08:52:27 +00001932 case CLZ:
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00001933 // MIPS32 spec: If no bits were set in GPR rs, the result written to
1934 // GPR rd is 32.
1935 // GCC __builtin_clz: If input is 0, the result is undefined.
1936 alu_out =
1937 rs_u == 0 ? 32 : CompilerIntrinsics::CountLeadingZeros(rs_u);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001938 break;
ager@chromium.org5c838252010-02-19 08:53:10 +00001939 default:
1940 UNREACHABLE();
lrn@chromium.org7516f052011-03-30 08:52:27 +00001941 };
1942 break;
1943 case SPECIAL3:
1944 switch (instr->FunctionFieldRaw()) {
1945 case INS: { // Mips32r2 instruction.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001946 // Interpret rd field as 5-bit msb of insert.
lrn@chromium.org7516f052011-03-30 08:52:27 +00001947 uint16_t msb = rd_reg;
1948 // Interpret sa field as 5-bit lsb of insert.
1949 uint16_t lsb = sa;
1950 uint16_t size = msb - lsb + 1;
1951 uint32_t mask = (1 << size) - 1;
1952 alu_out = (rt_u & ~(mask << lsb)) | ((rs_u & mask) << lsb);
1953 break;
1954 }
1955 case EXT: { // Mips32r2 instruction.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001956 // Interpret rd field as 5-bit msb of extract.
lrn@chromium.org7516f052011-03-30 08:52:27 +00001957 uint16_t msb = rd_reg;
1958 // Interpret sa field as 5-bit lsb of extract.
1959 uint16_t lsb = sa;
1960 uint16_t size = msb + 1;
1961 uint32_t mask = (1 << size) - 1;
1962 alu_out = (rs_u & (mask << lsb)) >> lsb;
1963 break;
1964 }
1965 default:
1966 UNREACHABLE();
1967 };
ager@chromium.org5c838252010-02-19 08:53:10 +00001968 break;
1969 default:
1970 UNREACHABLE();
1971 };
lrn@chromium.org7516f052011-03-30 08:52:27 +00001972}
1973
1974
1975void Simulator::DecodeTypeRegister(Instruction* instr) {
1976 // Instruction fields.
1977 const Opcode op = instr->OpcodeFieldRaw();
1978 const int32_t rs_reg = instr->RsValue();
1979 const int32_t rs = get_register(rs_reg);
1980 const uint32_t rs_u = static_cast<uint32_t>(rs);
1981 const int32_t rt_reg = instr->RtValue();
1982 const int32_t rt = get_register(rt_reg);
1983 const uint32_t rt_u = static_cast<uint32_t>(rt);
1984 const int32_t rd_reg = instr->RdValue();
1985
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001986 const int32_t fr_reg = instr->FrValue();
lrn@chromium.org7516f052011-03-30 08:52:27 +00001987 const int32_t fs_reg = instr->FsValue();
1988 const int32_t ft_reg = instr->FtValue();
1989 const int32_t fd_reg = instr->FdValue();
1990 int64_t i64hilo = 0;
1991 uint64_t u64hilo = 0;
1992
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001993 // ALU output.
lrn@chromium.org7516f052011-03-30 08:52:27 +00001994 // It should not be used as is. Instructions using it should always
1995 // initialize it first.
1996 int32_t alu_out = 0x12345678;
1997
1998 // For break and trap instructions.
1999 bool do_interrupt = false;
2000
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002001 // For jr and jalr.
lrn@chromium.org7516f052011-03-30 08:52:27 +00002002 // Get current pc.
2003 int32_t current_pc = get_pc();
2004 // Next pc
2005 int32_t next_pc = 0;
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00002006 int32_t return_addr_reg = 31;
lrn@chromium.org7516f052011-03-30 08:52:27 +00002007
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002008 // Set up the variables if needed before executing the instruction.
lrn@chromium.org7516f052011-03-30 08:52:27 +00002009 ConfigureTypeRegister(instr,
2010 alu_out,
2011 i64hilo,
2012 u64hilo,
2013 next_pc,
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00002014 return_addr_reg,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002015 do_interrupt);
ager@chromium.org5c838252010-02-19 08:53:10 +00002016
2017 // ---------- Raise exceptions triggered.
2018 SignalExceptions();
2019
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002020 // ---------- Execution.
ager@chromium.org5c838252010-02-19 08:53:10 +00002021 switch (op) {
2022 case COP1:
2023 switch (instr->RsFieldRaw()) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002024 case BC1: // Branch on coprocessor condition.
ager@chromium.org5c838252010-02-19 08:53:10 +00002025 UNREACHABLE();
2026 break;
lrn@chromium.org7516f052011-03-30 08:52:27 +00002027 case CFC1:
2028 set_register(rt_reg, alu_out);
ager@chromium.org5c838252010-02-19 08:53:10 +00002029 case MFC1:
ager@chromium.org5c838252010-02-19 08:53:10 +00002030 set_register(rt_reg, alu_out);
2031 break;
lrn@chromium.org7516f052011-03-30 08:52:27 +00002032 case MFHC1:
2033 UNIMPLEMENTED_MIPS();
2034 break;
2035 case CTC1:
2036 // At the moment only FCSR is supported.
2037 ASSERT(fs_reg == kFCSRRegister);
2038 FCSR_ = registers_[rt_reg];
2039 break;
ager@chromium.org5c838252010-02-19 08:53:10 +00002040 case MTC1:
ager@chromium.org5c838252010-02-19 08:53:10 +00002041 FPUregisters_[fs_reg] = registers_[rt_reg];
ager@chromium.org5c838252010-02-19 08:53:10 +00002042 break;
2043 case MTHC1:
lrn@chromium.org7516f052011-03-30 08:52:27 +00002044 UNIMPLEMENTED_MIPS();
ager@chromium.org5c838252010-02-19 08:53:10 +00002045 break;
2046 case S:
lrn@chromium.org7516f052011-03-30 08:52:27 +00002047 float f;
ager@chromium.org5c838252010-02-19 08:53:10 +00002048 switch (instr->FunctionFieldRaw()) {
2049 case CVT_D_S:
lrn@chromium.org7516f052011-03-30 08:52:27 +00002050 f = get_fpu_register_float(fs_reg);
2051 set_fpu_register_double(fd_reg, static_cast<double>(f));
2052 break;
ager@chromium.org5c838252010-02-19 08:53:10 +00002053 case CVT_W_S:
2054 case CVT_L_S:
lrn@chromium.org7516f052011-03-30 08:52:27 +00002055 case TRUNC_W_S:
2056 case TRUNC_L_S:
2057 case ROUND_W_S:
2058 case ROUND_L_S:
2059 case FLOOR_W_S:
2060 case FLOOR_L_S:
2061 case CEIL_W_S:
2062 case CEIL_L_S:
ager@chromium.org5c838252010-02-19 08:53:10 +00002063 case CVT_PS_S:
2064 UNIMPLEMENTED_MIPS();
2065 break;
2066 default:
2067 UNREACHABLE();
2068 }
2069 break;
2070 case D:
lrn@chromium.org7516f052011-03-30 08:52:27 +00002071 double ft, fs;
2072 uint32_t cc, fcsr_cc;
2073 int64_t i64;
2074 fs = get_fpu_register_double(fs_reg);
2075 ft = get_fpu_register_double(ft_reg);
2076 cc = instr->FCccValue();
2077 fcsr_cc = get_fcsr_condition_bit(cc);
ager@chromium.org5c838252010-02-19 08:53:10 +00002078 switch (instr->FunctionFieldRaw()) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002079 case ADD_D:
2080 set_fpu_register_double(fd_reg, fs + ft);
2081 break;
2082 case SUB_D:
2083 set_fpu_register_double(fd_reg, fs - ft);
2084 break;
2085 case MUL_D:
2086 set_fpu_register_double(fd_reg, fs * ft);
2087 break;
2088 case DIV_D:
2089 set_fpu_register_double(fd_reg, fs / ft);
2090 break;
2091 case ABS_D:
ulan@chromium.org837a67e2013-06-11 15:39:48 +00002092 set_fpu_register_double(fd_reg, fabs(fs));
lrn@chromium.org7516f052011-03-30 08:52:27 +00002093 break;
2094 case MOV_D:
2095 set_fpu_register_double(fd_reg, fs);
2096 break;
2097 case NEG_D:
2098 set_fpu_register_double(fd_reg, -fs);
2099 break;
2100 case SQRT_D:
2101 set_fpu_register_double(fd_reg, sqrt(fs));
2102 break;
2103 case C_UN_D:
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00002104 set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft));
lrn@chromium.org7516f052011-03-30 08:52:27 +00002105 break;
2106 case C_EQ_D:
2107 set_fcsr_bit(fcsr_cc, (fs == ft));
2108 break;
2109 case C_UEQ_D:
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00002110 set_fcsr_bit(fcsr_cc,
2111 (fs == ft) || (std::isnan(fs) || std::isnan(ft)));
lrn@chromium.org7516f052011-03-30 08:52:27 +00002112 break;
2113 case C_OLT_D:
2114 set_fcsr_bit(fcsr_cc, (fs < ft));
2115 break;
2116 case C_ULT_D:
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00002117 set_fcsr_bit(fcsr_cc,
2118 (fs < ft) || (std::isnan(fs) || std::isnan(ft)));
lrn@chromium.org7516f052011-03-30 08:52:27 +00002119 break;
2120 case C_OLE_D:
2121 set_fcsr_bit(fcsr_cc, (fs <= ft));
2122 break;
2123 case C_ULE_D:
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00002124 set_fcsr_bit(fcsr_cc,
2125 (fs <= ft) || (std::isnan(fs) || std::isnan(ft)));
lrn@chromium.org7516f052011-03-30 08:52:27 +00002126 break;
2127 case CVT_W_D: // Convert double to word.
2128 // Rounding modes are not yet supported.
2129 ASSERT((FCSR_ & 3) == 0);
2130 // In rounding mode 0 it should behave like ROUND.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002131 case ROUND_W_D: // Round double to word (round half to even).
lrn@chromium.org7516f052011-03-30 08:52:27 +00002132 {
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00002133 double rounded = std::floor(fs + 0.5);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002134 int32_t result = static_cast<int32_t>(rounded);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002135 if ((result & 1) != 0 && result - fs == 0.5) {
2136 // If the number is halfway between two integers,
2137 // round to the even one.
2138 result--;
2139 }
lrn@chromium.org7516f052011-03-30 08:52:27 +00002140 set_fpu_register(fd_reg, result);
2141 if (set_fcsr_round_error(fs, rounded)) {
2142 set_fpu_register(fd_reg, kFPUInvalidResult);
2143 }
2144 }
2145 break;
2146 case TRUNC_W_D: // Truncate double to word (round towards 0).
2147 {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002148 double rounded = trunc(fs);
2149 int32_t result = static_cast<int32_t>(rounded);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002150 set_fpu_register(fd_reg, result);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002151 if (set_fcsr_round_error(fs, rounded)) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002152 set_fpu_register(fd_reg, kFPUInvalidResult);
2153 }
2154 }
2155 break;
2156 case FLOOR_W_D: // Round double to word towards negative infinity.
2157 {
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00002158 double rounded = std::floor(fs);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002159 int32_t result = static_cast<int32_t>(rounded);
2160 set_fpu_register(fd_reg, result);
2161 if (set_fcsr_round_error(fs, rounded)) {
2162 set_fpu_register(fd_reg, kFPUInvalidResult);
2163 }
2164 }
2165 break;
2166 case CEIL_W_D: // Round double to word towards positive infinity.
2167 {
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00002168 double rounded = std::ceil(fs);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002169 int32_t result = static_cast<int32_t>(rounded);
2170 set_fpu_register(fd_reg, result);
2171 if (set_fcsr_round_error(fs, rounded)) {
2172 set_fpu_register(fd_reg, kFPUInvalidResult);
2173 }
2174 }
2175 break;
2176 case CVT_S_D: // Convert double to float (single).
2177 set_fpu_register_float(fd_reg, static_cast<float>(fs));
2178 break;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002179 case CVT_L_D: { // Mips32r2: Truncate double to 64-bit long-word.
2180 double rounded = trunc(fs);
2181 i64 = static_cast<int64_t>(rounded);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002182 set_fpu_register(fd_reg, i64 & 0xffffffff);
2183 set_fpu_register(fd_reg + 1, i64 >> 32);
2184 break;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002185 }
2186 case TRUNC_L_D: { // Mips32r2 instruction.
2187 double rounded = trunc(fs);
2188 i64 = static_cast<int64_t>(rounded);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002189 set_fpu_register(fd_reg, i64 & 0xffffffff);
2190 set_fpu_register(fd_reg + 1, i64 >> 32);
2191 break;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002192 }
lrn@chromium.org7516f052011-03-30 08:52:27 +00002193 case ROUND_L_D: { // Mips32r2 instruction.
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00002194 double rounded =
2195 fs > 0 ? std::floor(fs + 0.5) : std::ceil(fs - 0.5);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002196 i64 = static_cast<int64_t>(rounded);
2197 set_fpu_register(fd_reg, i64 & 0xffffffff);
2198 set_fpu_register(fd_reg + 1, i64 >> 32);
2199 break;
2200 }
2201 case FLOOR_L_D: // Mips32r2 instruction.
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00002202 i64 = static_cast<int64_t>(std::floor(fs));
lrn@chromium.org7516f052011-03-30 08:52:27 +00002203 set_fpu_register(fd_reg, i64 & 0xffffffff);
2204 set_fpu_register(fd_reg + 1, i64 >> 32);
2205 break;
2206 case CEIL_L_D: // Mips32r2 instruction.
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00002207 i64 = static_cast<int64_t>(std::ceil(fs));
lrn@chromium.org7516f052011-03-30 08:52:27 +00002208 set_fpu_register(fd_reg, i64 & 0xffffffff);
2209 set_fpu_register(fd_reg + 1, i64 >> 32);
2210 break;
2211 case C_F_D:
ager@chromium.org5c838252010-02-19 08:53:10 +00002212 UNIMPLEMENTED_MIPS();
2213 break;
2214 default:
2215 UNREACHABLE();
2216 }
2217 break;
2218 case W:
2219 switch (instr->FunctionFieldRaw()) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002220 case CVT_S_W: // Convert word to float (single).
2221 alu_out = get_fpu_register(fs_reg);
2222 set_fpu_register_float(fd_reg, static_cast<float>(alu_out));
ager@chromium.org5c838252010-02-19 08:53:10 +00002223 break;
2224 case CVT_D_W: // Convert word to double.
lrn@chromium.org7516f052011-03-30 08:52:27 +00002225 alu_out = get_fpu_register(fs_reg);
2226 set_fpu_register_double(fd_reg, static_cast<double>(alu_out));
ager@chromium.org5c838252010-02-19 08:53:10 +00002227 break;
2228 default:
2229 UNREACHABLE();
2230 };
2231 break;
2232 case L:
2233 switch (instr->FunctionFieldRaw()) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002234 case CVT_D_L: // Mips32r2 instruction.
2235 // Watch the signs here, we want 2 32-bit vals
2236 // to make a sign-64.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002237 i64 = static_cast<uint32_t>(get_fpu_register(fs_reg));
2238 i64 |= static_cast<int64_t>(get_fpu_register(fs_reg + 1)) << 32;
lrn@chromium.org7516f052011-03-30 08:52:27 +00002239 set_fpu_register_double(fd_reg, static_cast<double>(i64));
2240 break;
ager@chromium.org5c838252010-02-19 08:53:10 +00002241 case CVT_S_L:
ager@chromium.org5c838252010-02-19 08:53:10 +00002242 UNIMPLEMENTED_MIPS();
2243 break;
2244 default:
2245 UNREACHABLE();
2246 }
2247 break;
2248 case PS:
2249 break;
2250 default:
2251 UNREACHABLE();
2252 };
2253 break;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002254 case COP1X:
2255 switch (instr->FunctionFieldRaw()) {
2256 case MADD_D:
2257 double fr, ft, fs;
2258 fr = get_fpu_register_double(fr_reg);
2259 fs = get_fpu_register_double(fs_reg);
2260 ft = get_fpu_register_double(ft_reg);
2261 set_fpu_register_double(fd_reg, fs * ft + fr);
2262 break;
2263 default:
2264 UNREACHABLE();
2265 };
2266 break;
ager@chromium.org5c838252010-02-19 08:53:10 +00002267 case SPECIAL:
2268 switch (instr->FunctionFieldRaw()) {
2269 case JR: {
2270 Instruction* branch_delay_instr = reinterpret_cast<Instruction*>(
lrn@chromium.org7516f052011-03-30 08:52:27 +00002271 current_pc+Instruction::kInstrSize);
ager@chromium.org5c838252010-02-19 08:53:10 +00002272 BranchDelayInstructionDecode(branch_delay_instr);
2273 set_pc(next_pc);
2274 pc_modified_ = true;
2275 break;
2276 }
2277 case JALR: {
2278 Instruction* branch_delay_instr = reinterpret_cast<Instruction*>(
lrn@chromium.org7516f052011-03-30 08:52:27 +00002279 current_pc+Instruction::kInstrSize);
ager@chromium.org5c838252010-02-19 08:53:10 +00002280 BranchDelayInstructionDecode(branch_delay_instr);
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00002281 set_register(return_addr_reg,
2282 current_pc + 2 * Instruction::kInstrSize);
ager@chromium.org5c838252010-02-19 08:53:10 +00002283 set_pc(next_pc);
2284 pc_modified_ = true;
2285 break;
2286 }
2287 // Instructions using HI and LO registers.
2288 case MULT:
lrn@chromium.org7516f052011-03-30 08:52:27 +00002289 set_register(LO, static_cast<int32_t>(i64hilo & 0xffffffff));
2290 set_register(HI, static_cast<int32_t>(i64hilo >> 32));
2291 break;
ager@chromium.org5c838252010-02-19 08:53:10 +00002292 case MULTU:
lrn@chromium.org7516f052011-03-30 08:52:27 +00002293 set_register(LO, static_cast<int32_t>(u64hilo & 0xffffffff));
2294 set_register(HI, static_cast<int32_t>(u64hilo >> 32));
ager@chromium.org5c838252010-02-19 08:53:10 +00002295 break;
2296 case DIV:
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00002297 // Divide by zero and overflow was not checked in the configuration
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00002298 // step - div and divu do not raise exceptions. On division by 0
2299 // the result will be UNPREDICTABLE. On overflow (INT_MIN/-1),
2300 // return INT_MIN which is what the hardware does.
2301 if (rs == INT_MIN && rt == -1) {
2302 set_register(LO, INT_MIN);
2303 set_register(HI, 0);
2304 } else if (rt != 0) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002305 set_register(LO, rs / rt);
2306 set_register(HI, rs % rt);
2307 }
ager@chromium.org5c838252010-02-19 08:53:10 +00002308 break;
2309 case DIVU:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002310 if (rt_u != 0) {
2311 set_register(LO, rs_u / rt_u);
2312 set_register(HI, rs_u % rt_u);
2313 }
ager@chromium.org5c838252010-02-19 08:53:10 +00002314 break;
lrn@chromium.org7516f052011-03-30 08:52:27 +00002315 // Break and trap instructions.
ager@chromium.org5c838252010-02-19 08:53:10 +00002316 case BREAK:
2317 case TGE:
2318 case TGEU:
2319 case TLT:
2320 case TLTU:
2321 case TEQ:
2322 case TNE:
2323 if (do_interrupt) {
2324 SoftwareInterrupt(instr);
2325 }
2326 break;
lrn@chromium.org7516f052011-03-30 08:52:27 +00002327 // Conditional moves.
2328 case MOVN:
2329 if (rt) set_register(rd_reg, rs);
2330 break;
2331 case MOVCI: {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002332 uint32_t cc = instr->FBccValue();
lrn@chromium.org7516f052011-03-30 08:52:27 +00002333 uint32_t fcsr_cc = get_fcsr_condition_bit(cc);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002334 if (instr->Bit(16)) { // Read Tf bit.
lrn@chromium.org7516f052011-03-30 08:52:27 +00002335 if (test_fcsr_bit(fcsr_cc)) set_register(rd_reg, rs);
2336 } else {
2337 if (!test_fcsr_bit(fcsr_cc)) set_register(rd_reg, rs);
2338 }
2339 break;
2340 }
2341 case MOVZ:
2342 if (!rt) set_register(rd_reg, rs);
2343 break;
ager@chromium.org5c838252010-02-19 08:53:10 +00002344 default: // For other special opcodes we do the default operation.
2345 set_register(rd_reg, alu_out);
2346 };
2347 break;
2348 case SPECIAL2:
2349 switch (instr->FunctionFieldRaw()) {
2350 case MUL:
2351 set_register(rd_reg, alu_out);
2352 // HI and LO are UNPREDICTABLE after the operation.
2353 set_register(LO, Unpredictable);
2354 set_register(HI, Unpredictable);
2355 break;
lrn@chromium.org7516f052011-03-30 08:52:27 +00002356 default: // For other special2 opcodes we do the default operation.
2357 set_register(rd_reg, alu_out);
2358 }
2359 break;
2360 case SPECIAL3:
2361 switch (instr->FunctionFieldRaw()) {
2362 case INS:
2363 // Ins instr leaves result in Rt, rather than Rd.
2364 set_register(rt_reg, alu_out);
2365 break;
2366 case EXT:
2367 // Ext instr leaves result in Rt, rather than Rd.
2368 set_register(rt_reg, alu_out);
2369 break;
ager@chromium.org5c838252010-02-19 08:53:10 +00002370 default:
2371 UNREACHABLE();
lrn@chromium.org7516f052011-03-30 08:52:27 +00002372 };
ager@chromium.org5c838252010-02-19 08:53:10 +00002373 break;
2374 // Unimplemented opcodes raised an error in the configuration step before,
2375 // so we can use the default here to set the destination register in common
2376 // cases.
2377 default:
2378 set_register(rd_reg, alu_out);
2379 };
2380}
2381
lrn@chromium.org7516f052011-03-30 08:52:27 +00002382
ulan@chromium.org2efb9002012-01-19 15:36:35 +00002383// Type 2: instructions using a 16 bytes immediate. (e.g. addi, beq).
ager@chromium.org5c838252010-02-19 08:53:10 +00002384void Simulator::DecodeTypeImmediate(Instruction* instr) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002385 // Instruction fields.
ager@chromium.org5c838252010-02-19 08:53:10 +00002386 Opcode op = instr->OpcodeFieldRaw();
lrn@chromium.org7516f052011-03-30 08:52:27 +00002387 int32_t rs = get_register(instr->RsValue());
ager@chromium.org5c838252010-02-19 08:53:10 +00002388 uint32_t rs_u = static_cast<uint32_t>(rs);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002389 int32_t rt_reg = instr->RtValue(); // Destination register.
ager@chromium.org5c838252010-02-19 08:53:10 +00002390 int32_t rt = get_register(rt_reg);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002391 int16_t imm16 = instr->Imm16Value();
ager@chromium.org5c838252010-02-19 08:53:10 +00002392
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002393 int32_t ft_reg = instr->FtValue(); // Destination register.
ager@chromium.org5c838252010-02-19 08:53:10 +00002394
lrn@chromium.org7516f052011-03-30 08:52:27 +00002395 // Zero extended immediate.
ager@chromium.org5c838252010-02-19 08:53:10 +00002396 uint32_t oe_imm16 = 0xffff & imm16;
lrn@chromium.org7516f052011-03-30 08:52:27 +00002397 // Sign extended immediate.
ager@chromium.org5c838252010-02-19 08:53:10 +00002398 int32_t se_imm16 = imm16;
2399
2400 // Get current pc.
2401 int32_t current_pc = get_pc();
2402 // Next pc.
2403 int32_t next_pc = bad_ra;
2404
lrn@chromium.org7516f052011-03-30 08:52:27 +00002405 // Used for conditional branch instructions.
ager@chromium.org5c838252010-02-19 08:53:10 +00002406 bool do_branch = false;
2407 bool execute_branch_delay_instruction = false;
2408
lrn@chromium.org7516f052011-03-30 08:52:27 +00002409 // Used for arithmetic instructions.
ager@chromium.org5c838252010-02-19 08:53:10 +00002410 int32_t alu_out = 0;
lrn@chromium.org7516f052011-03-30 08:52:27 +00002411 // Floating point.
ager@chromium.org5c838252010-02-19 08:53:10 +00002412 double fp_out = 0.0;
lrn@chromium.org7516f052011-03-30 08:52:27 +00002413 uint32_t cc, cc_value, fcsr_cc;
ager@chromium.org5c838252010-02-19 08:53:10 +00002414
lrn@chromium.org7516f052011-03-30 08:52:27 +00002415 // Used for memory instructions.
ager@chromium.org5c838252010-02-19 08:53:10 +00002416 int32_t addr = 0x0;
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002417 // Value to be written in memory.
lrn@chromium.org7516f052011-03-30 08:52:27 +00002418 uint32_t mem_value = 0x0;
ager@chromium.org5c838252010-02-19 08:53:10 +00002419
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002420 // ---------- Configuration (and execution for REGIMM).
ager@chromium.org5c838252010-02-19 08:53:10 +00002421 switch (op) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002422 // ------------- COP1. Coprocessor instructions.
ager@chromium.org5c838252010-02-19 08:53:10 +00002423 case COP1:
2424 switch (instr->RsFieldRaw()) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002425 case BC1: // Branch on coprocessor condition.
2426 cc = instr->FBccValue();
2427 fcsr_cc = get_fcsr_condition_bit(cc);
2428 cc_value = test_fcsr_bit(fcsr_cc);
2429 do_branch = (instr->FBtrueValue()) ? cc_value : !cc_value;
2430 execute_branch_delay_instruction = true;
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002431 // Set next_pc.
lrn@chromium.org7516f052011-03-30 08:52:27 +00002432 if (do_branch) {
2433 next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
2434 } else {
2435 next_pc = current_pc + kBranchReturnOffset;
2436 }
ager@chromium.org5c838252010-02-19 08:53:10 +00002437 break;
2438 default:
2439 UNREACHABLE();
2440 };
2441 break;
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002442 // ------------- REGIMM class.
ager@chromium.org5c838252010-02-19 08:53:10 +00002443 case REGIMM:
2444 switch (instr->RtFieldRaw()) {
2445 case BLTZ:
2446 do_branch = (rs < 0);
2447 break;
2448 case BLTZAL:
2449 do_branch = rs < 0;
2450 break;
2451 case BGEZ:
2452 do_branch = rs >= 0;
2453 break;
2454 case BGEZAL:
2455 do_branch = rs >= 0;
2456 break;
2457 default:
2458 UNREACHABLE();
2459 };
2460 switch (instr->RtFieldRaw()) {
2461 case BLTZ:
2462 case BLTZAL:
2463 case BGEZ:
2464 case BGEZAL:
2465 // Branch instructions common part.
2466 execute_branch_delay_instruction = true;
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002467 // Set next_pc.
ager@chromium.org5c838252010-02-19 08:53:10 +00002468 if (do_branch) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002469 next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
ager@chromium.org5c838252010-02-19 08:53:10 +00002470 if (instr->IsLinkingInstruction()) {
2471 set_register(31, current_pc + kBranchReturnOffset);
2472 }
2473 } else {
2474 next_pc = current_pc + kBranchReturnOffset;
2475 }
2476 default:
2477 break;
2478 };
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002479 break; // case REGIMM.
2480 // ------------- Branch instructions.
ager@chromium.org5c838252010-02-19 08:53:10 +00002481 // When comparing to zero, the encoding of rt field is always 0, so we don't
2482 // need to replace rt with zero.
2483 case BEQ:
2484 do_branch = (rs == rt);
2485 break;
2486 case BNE:
2487 do_branch = rs != rt;
2488 break;
2489 case BLEZ:
2490 do_branch = rs <= 0;
2491 break;
2492 case BGTZ:
2493 do_branch = rs > 0;
2494 break;
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002495 // ------------- Arithmetic instructions.
ager@chromium.org5c838252010-02-19 08:53:10 +00002496 case ADDI:
2497 if (HaveSameSign(rs, se_imm16)) {
2498 if (rs > 0) {
2499 exceptions[kIntegerOverflow] = rs > (Registers::kMaxValue - se_imm16);
2500 } else if (rs < 0) {
2501 exceptions[kIntegerUnderflow] =
2502 rs < (Registers::kMinValue - se_imm16);
2503 }
2504 }
2505 alu_out = rs + se_imm16;
2506 break;
2507 case ADDIU:
2508 alu_out = rs + se_imm16;
2509 break;
2510 case SLTI:
2511 alu_out = (rs < se_imm16) ? 1 : 0;
2512 break;
2513 case SLTIU:
2514 alu_out = (rs_u < static_cast<uint32_t>(se_imm16)) ? 1 : 0;
2515 break;
2516 case ANDI:
2517 alu_out = rs & oe_imm16;
2518 break;
2519 case ORI:
2520 alu_out = rs | oe_imm16;
2521 break;
2522 case XORI:
2523 alu_out = rs ^ oe_imm16;
2524 break;
2525 case LUI:
2526 alu_out = (oe_imm16 << 16);
2527 break;
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002528 // ------------- Memory instructions.
ager@chromium.org5c838252010-02-19 08:53:10 +00002529 case LB:
2530 addr = rs + se_imm16;
2531 alu_out = ReadB(addr);
2532 break;
lrn@chromium.org7516f052011-03-30 08:52:27 +00002533 case LH:
2534 addr = rs + se_imm16;
2535 alu_out = ReadH(addr, instr);
2536 break;
2537 case LWL: {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002538 // al_offset is offset of the effective address within an aligned word.
lrn@chromium.org7516f052011-03-30 08:52:27 +00002539 uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
2540 uint8_t byte_shift = kPointerAlignmentMask - al_offset;
2541 uint32_t mask = (1 << byte_shift * 8) - 1;
2542 addr = rs + se_imm16 - al_offset;
2543 alu_out = ReadW(addr, instr);
2544 alu_out <<= byte_shift * 8;
2545 alu_out |= rt & mask;
2546 break;
2547 }
ager@chromium.org5c838252010-02-19 08:53:10 +00002548 case LW:
2549 addr = rs + se_imm16;
2550 alu_out = ReadW(addr, instr);
2551 break;
2552 case LBU:
2553 addr = rs + se_imm16;
2554 alu_out = ReadBU(addr);
2555 break;
lrn@chromium.org7516f052011-03-30 08:52:27 +00002556 case LHU:
2557 addr = rs + se_imm16;
2558 alu_out = ReadHU(addr, instr);
2559 break;
2560 case LWR: {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002561 // al_offset is offset of the effective address within an aligned word.
lrn@chromium.org7516f052011-03-30 08:52:27 +00002562 uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
2563 uint8_t byte_shift = kPointerAlignmentMask - al_offset;
2564 uint32_t mask = al_offset ? (~0 << (byte_shift + 1) * 8) : 0;
2565 addr = rs + se_imm16 - al_offset;
2566 alu_out = ReadW(addr, instr);
2567 alu_out = static_cast<uint32_t> (alu_out) >> al_offset * 8;
2568 alu_out |= rt & mask;
2569 break;
2570 }
ager@chromium.org5c838252010-02-19 08:53:10 +00002571 case SB:
2572 addr = rs + se_imm16;
2573 break;
lrn@chromium.org7516f052011-03-30 08:52:27 +00002574 case SH:
2575 addr = rs + se_imm16;
2576 break;
2577 case SWL: {
2578 uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
2579 uint8_t byte_shift = kPointerAlignmentMask - al_offset;
2580 uint32_t mask = byte_shift ? (~0 << (al_offset + 1) * 8) : 0;
2581 addr = rs + se_imm16 - al_offset;
2582 mem_value = ReadW(addr, instr) & mask;
2583 mem_value |= static_cast<uint32_t>(rt) >> byte_shift * 8;
2584 break;
2585 }
ager@chromium.org5c838252010-02-19 08:53:10 +00002586 case SW:
2587 addr = rs + se_imm16;
2588 break;
lrn@chromium.org7516f052011-03-30 08:52:27 +00002589 case SWR: {
2590 uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
2591 uint32_t mask = (1 << al_offset * 8) - 1;
2592 addr = rs + se_imm16 - al_offset;
2593 mem_value = ReadW(addr, instr);
2594 mem_value = (rt << al_offset * 8) | (mem_value & mask);
2595 break;
2596 }
ager@chromium.org5c838252010-02-19 08:53:10 +00002597 case LWC1:
2598 addr = rs + se_imm16;
2599 alu_out = ReadW(addr, instr);
2600 break;
2601 case LDC1:
2602 addr = rs + se_imm16;
2603 fp_out = ReadD(addr, instr);
2604 break;
2605 case SWC1:
2606 case SDC1:
2607 addr = rs + se_imm16;
2608 break;
2609 default:
2610 UNREACHABLE();
2611 };
2612
2613 // ---------- Raise exceptions triggered.
2614 SignalExceptions();
2615
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002616 // ---------- Execution.
ager@chromium.org5c838252010-02-19 08:53:10 +00002617 switch (op) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002618 // ------------- Branch instructions.
ager@chromium.org5c838252010-02-19 08:53:10 +00002619 case BEQ:
2620 case BNE:
2621 case BLEZ:
2622 case BGTZ:
2623 // Branch instructions common part.
2624 execute_branch_delay_instruction = true;
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002625 // Set next_pc.
ager@chromium.org5c838252010-02-19 08:53:10 +00002626 if (do_branch) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002627 next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
ager@chromium.org5c838252010-02-19 08:53:10 +00002628 if (instr->IsLinkingInstruction()) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002629 set_register(31, current_pc + 2* Instruction::kInstrSize);
ager@chromium.org5c838252010-02-19 08:53:10 +00002630 }
2631 } else {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002632 next_pc = current_pc + 2 * Instruction::kInstrSize;
ager@chromium.org5c838252010-02-19 08:53:10 +00002633 }
2634 break;
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002635 // ------------- Arithmetic instructions.
ager@chromium.org5c838252010-02-19 08:53:10 +00002636 case ADDI:
2637 case ADDIU:
2638 case SLTI:
2639 case SLTIU:
2640 case ANDI:
2641 case ORI:
2642 case XORI:
2643 case LUI:
2644 set_register(rt_reg, alu_out);
2645 break;
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002646 // ------------- Memory instructions.
ager@chromium.org5c838252010-02-19 08:53:10 +00002647 case LB:
lrn@chromium.org7516f052011-03-30 08:52:27 +00002648 case LH:
2649 case LWL:
ager@chromium.org5c838252010-02-19 08:53:10 +00002650 case LW:
2651 case LBU:
lrn@chromium.org7516f052011-03-30 08:52:27 +00002652 case LHU:
2653 case LWR:
ager@chromium.org5c838252010-02-19 08:53:10 +00002654 set_register(rt_reg, alu_out);
2655 break;
2656 case SB:
2657 WriteB(addr, static_cast<int8_t>(rt));
2658 break;
lrn@chromium.org7516f052011-03-30 08:52:27 +00002659 case SH:
2660 WriteH(addr, static_cast<uint16_t>(rt), instr);
2661 break;
2662 case SWL:
2663 WriteW(addr, mem_value, instr);
2664 break;
ager@chromium.org5c838252010-02-19 08:53:10 +00002665 case SW:
2666 WriteW(addr, rt, instr);
2667 break;
lrn@chromium.org7516f052011-03-30 08:52:27 +00002668 case SWR:
2669 WriteW(addr, mem_value, instr);
2670 break;
ager@chromium.org5c838252010-02-19 08:53:10 +00002671 case LWC1:
2672 set_fpu_register(ft_reg, alu_out);
2673 break;
2674 case LDC1:
2675 set_fpu_register_double(ft_reg, fp_out);
2676 break;
2677 case SWC1:
2678 addr = rs + se_imm16;
2679 WriteW(addr, get_fpu_register(ft_reg), instr);
2680 break;
2681 case SDC1:
2682 addr = rs + se_imm16;
lrn@chromium.org7516f052011-03-30 08:52:27 +00002683 WriteD(addr, get_fpu_register_double(ft_reg), instr);
ager@chromium.org5c838252010-02-19 08:53:10 +00002684 break;
2685 default:
2686 break;
2687 };
2688
2689
2690 if (execute_branch_delay_instruction) {
2691 // Execute branch delay slot
2692 // We don't check for end_sim_pc. First it should not be met as the current
2693 // pc is valid. Secondly a jump should always execute its branch delay slot.
2694 Instruction* branch_delay_instr =
lrn@chromium.org7516f052011-03-30 08:52:27 +00002695 reinterpret_cast<Instruction*>(current_pc+Instruction::kInstrSize);
ager@chromium.org5c838252010-02-19 08:53:10 +00002696 BranchDelayInstructionDecode(branch_delay_instr);
2697 }
2698
2699 // If needed update pc after the branch delay execution.
2700 if (next_pc != bad_ra) {
2701 set_pc(next_pc);
2702 }
2703}
2704
lrn@chromium.org7516f052011-03-30 08:52:27 +00002705
ulan@chromium.org2efb9002012-01-19 15:36:35 +00002706// Type 3: instructions using a 26 bytes immediate. (e.g. j, jal).
ager@chromium.org5c838252010-02-19 08:53:10 +00002707void Simulator::DecodeTypeJump(Instruction* instr) {
2708 // Get current pc.
2709 int32_t current_pc = get_pc();
2710 // Get unchanged bits of pc.
2711 int32_t pc_high_bits = current_pc & 0xf0000000;
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002712 // Next pc.
lrn@chromium.org7516f052011-03-30 08:52:27 +00002713 int32_t next_pc = pc_high_bits | (instr->Imm26Value() << 2);
ager@chromium.org5c838252010-02-19 08:53:10 +00002714
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002715 // Execute branch delay slot.
ager@chromium.org5c838252010-02-19 08:53:10 +00002716 // We don't check for end_sim_pc. First it should not be met as the current pc
2717 // is valid. Secondly a jump should always execute its branch delay slot.
2718 Instruction* branch_delay_instr =
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002719 reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize);
ager@chromium.org5c838252010-02-19 08:53:10 +00002720 BranchDelayInstructionDecode(branch_delay_instr);
2721
2722 // Update pc and ra if necessary.
2723 // Do this after the branch delay execution.
2724 if (instr->IsLinkingInstruction()) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002725 set_register(31, current_pc + 2 * Instruction::kInstrSize);
ager@chromium.org5c838252010-02-19 08:53:10 +00002726 }
2727 set_pc(next_pc);
2728 pc_modified_ = true;
2729}
2730
lrn@chromium.org7516f052011-03-30 08:52:27 +00002731
ager@chromium.org5c838252010-02-19 08:53:10 +00002732// Executes the current instruction.
2733void Simulator::InstructionDecode(Instruction* instr) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002734 if (v8::internal::FLAG_check_icache) {
2735 CheckICache(isolate_->simulator_i_cache(), instr);
2736 }
ager@chromium.org5c838252010-02-19 08:53:10 +00002737 pc_modified_ = false;
2738 if (::v8::internal::FLAG_trace_sim) {
2739 disasm::NameConverter converter;
2740 disasm::Disassembler dasm(converter);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002741 // Use a reasonably large buffer.
ager@chromium.org5c838252010-02-19 08:53:10 +00002742 v8::internal::EmbeddedVector<char, 256> buffer;
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002743 dasm.InstructionDecode(buffer, reinterpret_cast<byte*>(instr));
lrn@chromium.org7516f052011-03-30 08:52:27 +00002744 PrintF(" 0x%08x %s\n", reinterpret_cast<intptr_t>(instr),
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002745 buffer.start());
ager@chromium.org5c838252010-02-19 08:53:10 +00002746 }
2747
2748 switch (instr->InstructionType()) {
2749 case Instruction::kRegisterType:
2750 DecodeTypeRegister(instr);
2751 break;
2752 case Instruction::kImmediateType:
2753 DecodeTypeImmediate(instr);
2754 break;
2755 case Instruction::kJumpType:
2756 DecodeTypeJump(instr);
2757 break;
2758 default:
2759 UNSUPPORTED();
2760 }
2761 if (!pc_modified_) {
2762 set_register(pc, reinterpret_cast<int32_t>(instr) +
lrn@chromium.org7516f052011-03-30 08:52:27 +00002763 Instruction::kInstrSize);
ager@chromium.org5c838252010-02-19 08:53:10 +00002764 }
2765}
2766
2767
2768
2769void Simulator::Execute() {
2770 // Get the PC to simulate. Cannot use the accessor here as we need the
2771 // raw PC value and not the one used as input to arithmetic instructions.
2772 int program_counter = get_pc();
2773 if (::v8::internal::FLAG_stop_sim_at == 0) {
2774 // Fast version of the dispatch loop without checking whether the simulator
2775 // should be stopping at a particular executed instruction.
2776 while (program_counter != end_sim_pc) {
2777 Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
2778 icount_++;
2779 InstructionDecode(instr);
2780 program_counter = get_pc();
2781 }
2782 } else {
2783 // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when
2784 // we reach the particular instuction count.
2785 while (program_counter != end_sim_pc) {
2786 Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
2787 icount_++;
2788 if (icount_ == ::v8::internal::FLAG_stop_sim_at) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002789 MipsDebugger dbg(this);
ager@chromium.org5c838252010-02-19 08:53:10 +00002790 dbg.Debug();
2791 } else {
2792 InstructionDecode(instr);
2793 }
2794 program_counter = get_pc();
2795 }
2796 }
2797}
2798
2799
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00002800void Simulator::CallInternal(byte* entry) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002801 // Prepare to execute the code at entry.
ager@chromium.org5c838252010-02-19 08:53:10 +00002802 set_register(pc, reinterpret_cast<int32_t>(entry));
2803 // Put down marker for end of simulation. The simulator will stop simulation
2804 // when the PC reaches this value. By saving the "end simulation" value into
2805 // the LR the simulation stops when returning to this call point.
2806 set_register(ra, end_sim_pc);
2807
2808 // Remember the values of callee-saved registers.
2809 // The code below assumes that r9 is not used as sb (static base) in
2810 // simulator code and therefore is regarded as a callee-saved register.
2811 int32_t s0_val = get_register(s0);
2812 int32_t s1_val = get_register(s1);
2813 int32_t s2_val = get_register(s2);
2814 int32_t s3_val = get_register(s3);
2815 int32_t s4_val = get_register(s4);
2816 int32_t s5_val = get_register(s5);
2817 int32_t s6_val = get_register(s6);
2818 int32_t s7_val = get_register(s7);
2819 int32_t gp_val = get_register(gp);
2820 int32_t sp_val = get_register(sp);
2821 int32_t fp_val = get_register(fp);
2822
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002823 // Set up the callee-saved registers with a known value. To be able to check
ager@chromium.org5c838252010-02-19 08:53:10 +00002824 // that they are preserved properly across JS execution.
2825 int32_t callee_saved_value = icount_;
2826 set_register(s0, callee_saved_value);
2827 set_register(s1, callee_saved_value);
2828 set_register(s2, callee_saved_value);
2829 set_register(s3, callee_saved_value);
2830 set_register(s4, callee_saved_value);
2831 set_register(s5, callee_saved_value);
2832 set_register(s6, callee_saved_value);
2833 set_register(s7, callee_saved_value);
2834 set_register(gp, callee_saved_value);
2835 set_register(fp, callee_saved_value);
2836
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002837 // Start the simulation.
ager@chromium.org5c838252010-02-19 08:53:10 +00002838 Execute();
2839
2840 // Check that the callee-saved registers have been preserved.
2841 CHECK_EQ(callee_saved_value, get_register(s0));
2842 CHECK_EQ(callee_saved_value, get_register(s1));
2843 CHECK_EQ(callee_saved_value, get_register(s2));
2844 CHECK_EQ(callee_saved_value, get_register(s3));
2845 CHECK_EQ(callee_saved_value, get_register(s4));
2846 CHECK_EQ(callee_saved_value, get_register(s5));
2847 CHECK_EQ(callee_saved_value, get_register(s6));
2848 CHECK_EQ(callee_saved_value, get_register(s7));
2849 CHECK_EQ(callee_saved_value, get_register(gp));
2850 CHECK_EQ(callee_saved_value, get_register(fp));
2851
2852 // Restore callee-saved registers with the original value.
2853 set_register(s0, s0_val);
2854 set_register(s1, s1_val);
2855 set_register(s2, s2_val);
2856 set_register(s3, s3_val);
2857 set_register(s4, s4_val);
2858 set_register(s5, s5_val);
2859 set_register(s6, s6_val);
2860 set_register(s7, s7_val);
2861 set_register(gp, gp_val);
2862 set_register(sp, sp_val);
2863 set_register(fp, fp_val);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00002864}
2865
2866
2867int32_t Simulator::Call(byte* entry, int argument_count, ...) {
2868 va_list parameters;
2869 va_start(parameters, argument_count);
2870 // Set up arguments.
2871
2872 // First four arguments passed in registers.
2873 ASSERT(argument_count >= 4);
2874 set_register(a0, va_arg(parameters, int32_t));
2875 set_register(a1, va_arg(parameters, int32_t));
2876 set_register(a2, va_arg(parameters, int32_t));
2877 set_register(a3, va_arg(parameters, int32_t));
2878
2879 // Remaining arguments passed on stack.
2880 int original_stack = get_register(sp);
2881 // Compute position of stack on entry to generated code.
2882 int entry_stack = (original_stack - (argument_count - 4) * sizeof(int32_t)
2883 - kCArgsSlotsSize);
2884 if (OS::ActivationFrameAlignment() != 0) {
2885 entry_stack &= -OS::ActivationFrameAlignment();
2886 }
2887 // Store remaining arguments on stack, from low to high memory.
2888 intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
2889 for (int i = 4; i < argument_count; i++) {
2890 stack_argument[i - 4 + kCArgSlotCount] = va_arg(parameters, int32_t);
2891 }
2892 va_end(parameters);
2893 set_register(sp, entry_stack);
2894
2895 CallInternal(entry);
ager@chromium.org5c838252010-02-19 08:53:10 +00002896
2897 // Pop stack passed arguments.
2898 CHECK_EQ(entry_stack, get_register(sp));
2899 set_register(sp, original_stack);
2900
2901 int32_t result = get_register(v0);
2902 return result;
2903}
2904
2905
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00002906double Simulator::CallFP(byte* entry, double d0, double d1) {
2907 if (!IsMipsSoftFloatABI) {
2908 set_fpu_register_double(f12, d0);
2909 set_fpu_register_double(f14, d1);
2910 } else {
2911 int buffer[2];
2912 ASSERT(sizeof(buffer[0]) * 2 == sizeof(d0));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002913 OS::MemCopy(buffer, &d0, sizeof(d0));
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00002914 set_dw_register(a0, buffer);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002915 OS::MemCopy(buffer, &d1, sizeof(d1));
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00002916 set_dw_register(a2, buffer);
2917 }
2918 CallInternal(entry);
2919 if (!IsMipsSoftFloatABI) {
2920 return get_fpu_register_double(f0);
2921 } else {
2922 return get_double_from_register_pair(v0);
2923 }
2924}
2925
2926
ager@chromium.org5c838252010-02-19 08:53:10 +00002927uintptr_t Simulator::PushAddress(uintptr_t address) {
2928 int new_sp = get_register(sp) - sizeof(uintptr_t);
2929 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp);
2930 *stack_slot = address;
2931 set_register(sp, new_sp);
2932 return new_sp;
2933}
2934
2935
2936uintptr_t Simulator::PopAddress() {
2937 int current_sp = get_register(sp);
2938 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp);
2939 uintptr_t address = *stack_slot;
2940 set_register(sp, current_sp + sizeof(uintptr_t));
2941 return address;
2942}
2943
2944
2945#undef UNSUPPORTED
2946
lrn@chromium.org7516f052011-03-30 08:52:27 +00002947} } // namespace v8::internal
ager@chromium.org5c838252010-02-19 08:53:10 +00002948
lrn@chromium.org7516f052011-03-30 08:52:27 +00002949#endif // USE_SIMULATOR
ager@chromium.org5c838252010-02-19 08:53:10 +00002950
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002951#endif // V8_TARGET_ARCH_MIPS