Index: src/mips64/simulator-mips64.cc |
diff --git a/src/mips/simulator-mips.cc b/src/mips64/simulator-mips64.cc |
similarity index 73% |
copy from src/mips/simulator-mips.cc |
copy to src/mips64/simulator-mips64.cc |
index 052eaed8272f7224d1fc7830dc92c48770cb108f..86e8b91464eacbd74a54294a7a14fee232673782 100644 |
--- a/src/mips/simulator-mips.cc |
+++ b/src/mips64/simulator-mips64.cc |
@@ -9,13 +9,13 @@ |
#include "src/v8.h" |
-#if V8_TARGET_ARCH_MIPS |
+#if V8_TARGET_ARCH_MIPS64 |
#include "src/assembler.h" |
#include "src/disasm.h" |
#include "src/globals.h" // Need the BitCast. |
-#include "src/mips/constants-mips.h" |
-#include "src/mips/simulator-mips.h" |
+#include "src/mips64/constants-mips64.h" |
+#include "src/mips64/simulator-mips64.h" |
// Only build the simulator if not compiling for real MIPS hardware. |
@@ -25,7 +25,7 @@ namespace v8 { |
namespace internal { |
// Utils functions. |
-bool HaveSameSign(int32_t a, int32_t b) { |
+bool HaveSameSign(int64_t a, int64_t b) { |
return ((a ^ b) >= 0); |
} |
@@ -39,6 +39,25 @@ uint32_t get_fcsr_condition_bit(uint32_t cc) { |
} |
+static int64_t MultiplyHighSigned(int64_t u, int64_t v) { |
+ uint64_t u0, v0, w0; |
+ int64_t u1, v1, w1, w2, t; |
+ |
+ u0 = u & 0xffffffffL; |
+ u1 = u >> 32; |
+ v0 = v & 0xffffffffL; |
+ v1 = v >> 32; |
+ |
+ w0 = u0 * v0; |
+ t = u1 * v0 + (w0 >> 32); |
+ w1 = t & 0xffffffffL; |
+ w2 = t >> 32; |
+ w1 = u0 * v1 + w1; |
+ |
+ return u1 * v1 + w2 + (w1 >> 32); |
+} |
+ |
+ |
// This macro provides a platform independent use of sscanf. The reason for |
// SScanF not being implemented in a platform independent was through |
// ::v8::internal::OS in the same way as SNPrintF is that the Windows C Run-Time |
@@ -65,12 +84,11 @@ class MipsDebugger { |
Simulator* sim_; |
- int32_t GetRegisterValue(int regnum); |
- int32_t GetFPURegisterValueInt(int regnum); |
- int64_t GetFPURegisterValueLong(int regnum); |
+ int64_t GetRegisterValue(int regnum); |
+ int64_t GetFPURegisterValue(int regnum); |
float GetFPURegisterValueFloat(int regnum); |
double GetFPURegisterValueDouble(int regnum); |
- bool GetValue(const char* desc, int32_t* value); |
+ bool GetValue(const char* desc, int64_t* value); |
// Set or delete a breakpoint. Returns true if successful. |
bool SetBreakpoint(Instruction* breakpc); |
@@ -122,7 +140,8 @@ void MipsDebugger::Stop(Instruction* instr) { |
instr->SetInstructionBits(kNopInstr); |
reinterpret_cast<Instr*>(msg_address)->SetInstructionBits(kNopInstr); |
} |
- sim_->set_pc(sim_->get_pc() + 2 * Instruction::kInstructionSize); |
+ // TODO(yuyin): 2 -> 3? |
+ sim_->set_pc(sim_->get_pc() + 3 * Instruction::kInstructionSize); |
} |
@@ -144,13 +163,14 @@ void MipsDebugger::Stop(Instruction* instr) { |
sim_->watched_stops_[code].desc = msg; |
} |
PrintF("Simulator hit %s (%u)\n", msg, code); |
- sim_->set_pc(sim_->get_pc() + 2 * Instruction::kInstrSize); |
+ // TODO(yuyin): 2 -> 3? |
+ sim_->set_pc(sim_->get_pc() + 3 * Instruction::kInstrSize); |
Debug(); |
} |
#endif // GENERATED_CODE_COVERAGE |
-int32_t MipsDebugger::GetRegisterValue(int regnum) { |
+int64_t MipsDebugger::GetRegisterValue(int regnum) { |
if (regnum == kNumSimuRegisters) { |
return sim_->get_pc(); |
} else { |
@@ -159,7 +179,7 @@ int32_t MipsDebugger::GetRegisterValue(int regnum) { |
} |
-int32_t MipsDebugger::GetFPURegisterValueInt(int regnum) { |
+int64_t MipsDebugger::GetFPURegisterValue(int regnum) { |
if (regnum == kNumFPURegisters) { |
return sim_->get_pc(); |
} else { |
@@ -168,15 +188,6 @@ int32_t MipsDebugger::GetFPURegisterValueInt(int regnum) { |
} |
-int64_t MipsDebugger::GetFPURegisterValueLong(int regnum) { |
- if (regnum == kNumFPURegisters) { |
- return sim_->get_pc(); |
- } else { |
- return sim_->get_fpu_register_long(regnum); |
- } |
-} |
- |
- |
float MipsDebugger::GetFPURegisterValueFloat(int regnum) { |
if (regnum == kNumFPURegisters) { |
return sim_->get_pc(); |
@@ -195,7 +206,7 @@ double MipsDebugger::GetFPURegisterValueDouble(int regnum) { |
} |
-bool MipsDebugger::GetValue(const char* desc, int32_t* value) { |
+bool MipsDebugger::GetValue(const char* desc, int64_t* value) { |
int regnum = Registers::Number(desc); |
int fpuregnum = FPURegisters::Number(desc); |
@@ -203,12 +214,13 @@ bool MipsDebugger::GetValue(const char* desc, int32_t* value) { |
*value = GetRegisterValue(regnum); |
return true; |
} else if (fpuregnum != kInvalidFPURegister) { |
- *value = GetFPURegisterValueInt(fpuregnum); |
+ *value = GetFPURegisterValue(fpuregnum); |
return true; |
} else if (strncmp(desc, "0x", 2) == 0) { |
- return SScanF(desc, "%x", reinterpret_cast<uint32_t*>(value)) == 1; |
+ return SScanF(desc + 2, "%" SCNx64, |
+ reinterpret_cast<uint64_t*>(value)) == 1; |
} else { |
- return SScanF(desc, "%i", value) == 1; |
+ return SScanF(desc, "%" SCNu64, reinterpret_cast<uint64_t*>(value)) == 1; |
} |
return false; |
} |
@@ -259,33 +271,33 @@ void MipsDebugger::PrintAllRegs() { |
PrintF("\n"); |
// at, v0, a0. |
- PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n", |
+ PrintF("%3s: 0x%016lx %14ld\t%3s: 0x%016lx %14ld\t%3s: 0x%016lx %14ld\n", |
REG_INFO(1), REG_INFO(2), REG_INFO(4)); |
// v1, a1. |
- PrintF("%26s\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n", |
+ PrintF("%34s\t%3s: 0x%016lx %14ld\t%3s: 0x%016lx %14ld\n", |
"", REG_INFO(3), REG_INFO(5)); |
// a2. |
- PrintF("%26s\t%26s\t%3s: 0x%08x %10d\n", "", "", REG_INFO(6)); |
+ PrintF("%34s\t%34s\t%3s: 0x%016lx %14ld\n", "", "", REG_INFO(6)); |
// a3. |
- PrintF("%26s\t%26s\t%3s: 0x%08x %10d\n", "", "", REG_INFO(7)); |
+ PrintF("%34s\t%34s\t%3s: 0x%016lx %14ld\n", "", "", REG_INFO(7)); |
PrintF("\n"); |
- // t0-t7, s0-s7 |
+ // a4-t3, s0-s7 |
for (int i = 0; i < 8; i++) { |
- PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n", |
+ PrintF("%3s: 0x%016lx %14ld\t%3s: 0x%016lx %14ld\n", |
REG_INFO(8+i), REG_INFO(16+i)); |
} |
PrintF("\n"); |
// t8, k0, LO. |
- PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n", |
+ PrintF("%3s: 0x%016lx %14ld\t%3s: 0x%016lx %14ld\t%3s: 0x%016lx %14ld\n", |
REG_INFO(24), REG_INFO(26), REG_INFO(32)); |
// t9, k1, HI. |
- PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n", |
+ PrintF("%3s: 0x%016lx %14ld\t%3s: 0x%016lx %14ld\t%3s: 0x%016lx %14ld\n", |
REG_INFO(25), REG_INFO(27), REG_INFO(33)); |
// sp, fp, gp. |
- PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n", |
+ PrintF("%3s: 0x%016lx %14ld\t%3s: 0x%016lx %14ld\t%3s: 0x%016lx %14ld\n", |
REG_INFO(29), REG_INFO(30), REG_INFO(28)); |
// pc. |
- PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n", |
+ PrintF("%3s: 0x%016lx %14ld\t%3s: 0x%016lx %14ld\n", |
REG_INFO(31), REG_INFO(34)); |
#undef REG_INFO |
@@ -294,31 +306,47 @@ void MipsDebugger::PrintAllRegs() { |
void MipsDebugger::PrintAllRegsIncludingFPU() { |
-#define FPU_REG_INFO(n) FPURegisters::Name(n), FPURegisters::Name(n+1), \ |
- GetFPURegisterValueInt(n+1), \ |
- GetFPURegisterValueInt(n), \ |
- GetFPURegisterValueDouble(n) |
+#define FPU_REG_INFO(n) FPURegisters::Name(n), \ |
+ GetFPURegisterValue(n), \ |
+ GetFPURegisterValueDouble(n) |
PrintAllRegs(); |
PrintF("\n\n"); |
// f0, f1, f2, ... f31. |
- PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(0) ); |
- PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(2) ); |
- PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(4) ); |
- PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(6) ); |
- PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(8) ); |
- PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(10)); |
- PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(12)); |
- PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(14)); |
- PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(16)); |
- PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(18)); |
- PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(20)); |
- PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(22)); |
- PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(24)); |
- PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(26)); |
- PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(28)); |
- PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(30)); |
+ // TODO(plind): consider printing 2 columns for space efficiency. |
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(0) ); |
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(1) ); |
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(2) ); |
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(3) ); |
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(4) ); |
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(5) ); |
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(6) ); |
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(7) ); |
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(8) ); |
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(9) ); |
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(10)); |
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(11)); |
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(12)); |
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(13)); |
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(14)); |
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(15)); |
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(16)); |
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(17)); |
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(18)); |
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(19)); |
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(20)); |
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(21)); |
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(22)); |
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(23)); |
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(24)); |
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(25)); |
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(26)); |
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(27)); |
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(28)); |
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(29)); |
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(30)); |
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(31)); |
#undef REG_INFO |
#undef FPU_REG_INFO |
@@ -357,7 +385,7 @@ void MipsDebugger::Debug() { |
v8::internal::EmbeddedVector<char, 256> buffer; |
dasm.InstructionDecode(buffer, |
reinterpret_cast<byte*>(sim_->get_pc())); |
- PrintF(" 0x%08x %s\n", sim_->get_pc(), buffer.start()); |
+ PrintF(" 0x%016lx %s\n", sim_->get_pc(), buffer.start()); |
last_pc = sim_->get_pc(); |
} |
char* line = ReadLine("sim> "); |
@@ -396,8 +424,8 @@ void MipsDebugger::Debug() { |
done = true; |
} else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) { |
if (argc == 2) { |
- int32_t value; |
- float fvalue; |
+ int64_t value; |
+ double dvalue; |
if (strcmp(arg1, "all") == 0) { |
PrintAllRegs(); |
} else if (strcmp(arg1, "allf") == 0) { |
@@ -408,24 +436,12 @@ void MipsDebugger::Debug() { |
if (regnum != kInvalidRegister) { |
value = GetRegisterValue(regnum); |
- PrintF("%s: 0x%08x %d \n", arg1, value, value); |
+ PrintF("%s: 0x%08lx %ld \n", arg1, value, value); |
} else if (fpuregnum != kInvalidFPURegister) { |
- if (fpuregnum % 2 == 1) { |
- value = GetFPURegisterValueInt(fpuregnum); |
- fvalue = GetFPURegisterValueFloat(fpuregnum); |
- PrintF("%s: 0x%08x %11.4e\n", arg1, value, fvalue); |
- } else { |
- double dfvalue; |
- int32_t lvalue1 = GetFPURegisterValueInt(fpuregnum); |
- int32_t lvalue2 = GetFPURegisterValueInt(fpuregnum + 1); |
- dfvalue = GetFPURegisterValueDouble(fpuregnum); |
- PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", |
- FPURegisters::Name(fpuregnum+1), |
- FPURegisters::Name(fpuregnum), |
- lvalue1, |
- lvalue2, |
- dfvalue); |
- } |
+ value = GetFPURegisterValue(fpuregnum); |
+ dvalue = GetFPURegisterValueDouble(fpuregnum); |
+ PrintF("%3s: 0x%016lx %16.4e\n", |
+ FPURegisters::Name(fpuregnum), value, dvalue); |
} else { |
PrintF("%s unrecognized\n", arg1); |
} |
@@ -433,14 +449,15 @@ void MipsDebugger::Debug() { |
} else { |
if (argc == 3) { |
if (strcmp(arg2, "single") == 0) { |
- int32_t value; |
+ int64_t value; |
float fvalue; |
int fpuregnum = FPURegisters::Number(arg1); |
if (fpuregnum != kInvalidFPURegister) { |
- value = GetFPURegisterValueInt(fpuregnum); |
+ value = GetFPURegisterValue(fpuregnum); |
+ value &= 0xffffffffUL; |
fvalue = GetFPURegisterValueFloat(fpuregnum); |
- PrintF("%s: 0x%08x %11.4e\n", arg1, value, fvalue); |
+ PrintF("%s: 0x%08lx %11.4e\n", arg1, value, fvalue); |
} else { |
PrintF("%s unrecognized\n", arg1); |
} |
@@ -454,7 +471,7 @@ void MipsDebugger::Debug() { |
} else if ((strcmp(cmd, "po") == 0) |
|| (strcmp(cmd, "printobject") == 0)) { |
if (argc == 2) { |
- int32_t value; |
+ int64_t value; |
OFStream os(stdout); |
if (GetValue(arg1, &value)) { |
Object* obj = reinterpret_cast<Object*>(value); |
@@ -472,23 +489,23 @@ void MipsDebugger::Debug() { |
PrintF("printobject <value>\n"); |
} |
} else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0) { |
- int32_t* cur = NULL; |
- int32_t* end = NULL; |
+ int64_t* cur = NULL; |
+ int64_t* end = NULL; |
int next_arg = 1; |
if (strcmp(cmd, "stack") == 0) { |
- cur = reinterpret_cast<int32_t*>(sim_->get_register(Simulator::sp)); |
+ cur = reinterpret_cast<int64_t*>(sim_->get_register(Simulator::sp)); |
} else { // Command "mem". |
- int32_t value; |
+ int64_t value; |
if (!GetValue(arg1, &value)) { |
PrintF("%s unrecognized\n", arg1); |
continue; |
} |
- cur = reinterpret_cast<int32_t*>(value); |
+ cur = reinterpret_cast<int64_t*>(value); |
next_arg++; |
} |
- int32_t words; |
+ int64_t words; |
if (argc == next_arg) { |
words = 10; |
} else { |
@@ -499,15 +516,15 @@ void MipsDebugger::Debug() { |
end = cur + words; |
while (cur < end) { |
- PrintF(" 0x%08x: 0x%08x %10d", |
+ PrintF(" 0x%012lx: 0x%016lx %14ld", |
reinterpret_cast<intptr_t>(cur), *cur, *cur); |
HeapObject* obj = reinterpret_cast<HeapObject*>(*cur); |
- int value = *cur; |
+ int64_t value = *cur; |
Heap* current_heap = v8::internal::Isolate::Current()->heap(); |
if (((value & 1) == 0) || current_heap->Contains(obj)) { |
PrintF(" ("); |
if ((value & 1) == 0) { |
- PrintF("smi %d", value / 2); |
+ PrintF("smi %d", static_cast<int>(value >> 32)); |
} else { |
obj->ShortPrint(); |
} |
@@ -535,7 +552,7 @@ void MipsDebugger::Debug() { |
int regnum = Registers::Number(arg1); |
if (regnum != kInvalidRegister || strncmp(arg1, "0x", 2) == 0) { |
// The argument is an address or a register name. |
- int32_t value; |
+ int64_t value; |
if (GetValue(arg1, &value)) { |
cur = reinterpret_cast<byte*>(value); |
// Disassemble 10 instructions at <arg1>. |
@@ -543,7 +560,7 @@ void MipsDebugger::Debug() { |
} |
} else { |
// The argument is the number of instructions. |
- int32_t value; |
+ int64_t value; |
if (GetValue(arg1, &value)) { |
cur = reinterpret_cast<byte*>(sim_->get_pc()); |
// Disassemble <arg1> instructions. |
@@ -551,8 +568,8 @@ void MipsDebugger::Debug() { |
} |
} |
} else { |
- int32_t value1; |
- int32_t value2; |
+ int64_t value1; |
+ int64_t value2; |
if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) { |
cur = reinterpret_cast<byte*>(value1); |
end = cur + (value2 * Instruction::kInstrSize); |
@@ -561,7 +578,7 @@ void MipsDebugger::Debug() { |
while (cur < end) { |
dasm.InstructionDecode(buffer, cur); |
- PrintF(" 0x%08x %s\n", |
+ PrintF(" 0x%08lx %s\n", |
reinterpret_cast<intptr_t>(cur), buffer.start()); |
cur += Instruction::kInstrSize; |
} |
@@ -571,7 +588,7 @@ void MipsDebugger::Debug() { |
PrintF("regaining control from gdb\n"); |
} else if (strcmp(cmd, "break") == 0) { |
if (argc == 2) { |
- int32_t value; |
+ int64_t value; |
if (GetValue(arg1, &value)) { |
if (!SetBreakpoint(reinterpret_cast<Instruction*>(value))) { |
PrintF("setting breakpoint failed\n"); |
@@ -589,7 +606,7 @@ void MipsDebugger::Debug() { |
} else if (strcmp(cmd, "flags") == 0) { |
PrintF("No flags on MIPS !\n"); |
} else if (strcmp(cmd, "stop") == 0) { |
- int32_t value; |
+ int64_t value; |
intptr_t stop_pc = sim_->get_pc() - |
2 * Instruction::kInstrSize; |
Instruction* stop_instr = reinterpret_cast<Instruction*>(stop_pc); |
@@ -666,15 +683,15 @@ void MipsDebugger::Debug() { |
cur = reinterpret_cast<byte*>(sim_->get_pc()); |
end = cur + (10 * Instruction::kInstrSize); |
} else if (argc == 2) { |
- int32_t value; |
+ int64_t value; |
if (GetValue(arg1, &value)) { |
cur = reinterpret_cast<byte*>(value); |
// no length parameter passed, assume 10 instructions |
end = cur + (10 * Instruction::kInstrSize); |
} |
} else { |
- int32_t value1; |
- int32_t value2; |
+ int64_t value1; |
+ int64_t value2; |
if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) { |
cur = reinterpret_cast<byte*>(value1); |
end = cur + (value2 * Instruction::kInstrSize); |
@@ -683,7 +700,7 @@ void MipsDebugger::Debug() { |
while (cur < end) { |
dasm.InstructionDecode(buffer, cur); |
- PrintF(" 0x%08x %s\n", |
+ PrintF(" 0x%08lx %s\n", |
reinterpret_cast<intptr_t>(cur), buffer.start()); |
cur += Instruction::kInstrSize; |
} |
@@ -780,8 +797,8 @@ void Simulator::set_last_debugger_input(char* input) { |
void Simulator::FlushICache(v8::internal::HashMap* i_cache, |
void* start_addr, |
size_t size) { |
- intptr_t start = reinterpret_cast<intptr_t>(start_addr); |
- int intra_line = (start & CachePage::kLineMask); |
+ int64_t start = reinterpret_cast<int64_t>(start_addr); |
+ int64_t intra_line = (start & CachePage::kLineMask); |
start -= intra_line; |
size += intra_line; |
size = ((size - 1) | CachePage::kLineMask) + 1; |
@@ -791,7 +808,7 @@ void Simulator::FlushICache(v8::internal::HashMap* i_cache, |
FlushOnePage(i_cache, start, bytes_to_flush); |
start += bytes_to_flush; |
size -= bytes_to_flush; |
- ASSERT_EQ(0, start & CachePage::kPageMask); |
+ ASSERT_EQ((uint64_t)0, start & CachePage::kPageMask); |
offset = 0; |
} |
if (size != 0) { |
@@ -830,7 +847,7 @@ void Simulator::FlushOnePage(v8::internal::HashMap* i_cache, |
void Simulator::CheckICache(v8::internal::HashMap* i_cache, |
Instruction* instr) { |
- intptr_t address = reinterpret_cast<intptr_t>(instr); |
+ int64_t address = reinterpret_cast<int64_t>(instr); |
void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask)); |
void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask)); |
int offset = (address & CachePage::kPageMask); |
@@ -868,6 +885,7 @@ Simulator::Simulator(Isolate* isolate) : isolate_(isolate) { |
Initialize(isolate); |
// Set up simulator support first. Some of this information is needed to |
// setup the architecture state. |
+ stack_size_ = FLAG_sim_stack_size * KB; |
stack_ = reinterpret_cast<char*>(malloc(stack_size_)); |
pc_modified_ = false; |
icount_ = 0; |
@@ -888,7 +906,7 @@ Simulator::Simulator(Isolate* isolate) : isolate_(isolate) { |
// The sp is initialized to point to the bottom (high address) of the |
// allocated stack area. To be safe in potential stack underflows we leave |
// some buffer below. |
- registers_[sp] = reinterpret_cast<int32_t>(stack_) + stack_size_ - 64; |
+ registers_[sp] = reinterpret_cast<int64_t>(stack_) + stack_size_ - 64; |
// The ra and pc are initialized to a known bad value that will cause an |
// access violation if the simulator ever tries to execute it. |
registers_[pc] = bad_ra; |
@@ -953,7 +971,7 @@ class Redirection { |
return reinterpret_cast<Redirection*>(addr_of_redirection); |
} |
- static void* ReverseRedirection(int32_t reg) { |
+ static void* ReverseRedirection(int64_t reg) { |
Redirection* redirection = FromSwiInstruction( |
reinterpret_cast<Instruction*>(reinterpret_cast<void*>(reg))); |
return redirection->external_function(); |
@@ -993,7 +1011,7 @@ Simulator* Simulator::current(Isolate* isolate) { |
// Sets the register in the architecture state. It will also deal with updating |
// Simulator internal state for special registers such as PC. |
-void Simulator::set_register(int reg, int32_t value) { |
+void Simulator::set_register(int reg, int64_t value) { |
ASSERT((reg >= 0) && (reg < kNumSimuRegisters)); |
if (reg == pc) { |
pc_modified_ = true; |
@@ -1006,17 +1024,36 @@ void Simulator::set_register(int reg, int32_t value) { |
void Simulator::set_dw_register(int reg, const int* dbl) { |
ASSERT((reg >= 0) && (reg < kNumSimuRegisters)); |
- registers_[reg] = dbl[0]; |
- registers_[reg + 1] = dbl[1]; |
+ registers_[reg] = dbl[1]; |
+ registers_[reg] = registers_[reg] << 32; |
+ registers_[reg] += dbl[0]; |
} |
-void Simulator::set_fpu_register(int fpureg, int32_t value) { |
+void Simulator::set_fpu_register(int fpureg, int64_t value) { |
ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters)); |
FPUregisters_[fpureg] = value; |
} |
+void Simulator::set_fpu_register_word(int fpureg, int32_t value) { |
+ // Set ONLY lower 32-bits, leaving upper bits untouched. |
+ // TODO(plind): big endian issue. |
+ ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters)); |
+ int32_t *pword = reinterpret_cast<int32_t*>(&FPUregisters_[fpureg]); |
+ *pword = value; |
+} |
+ |
+ |
+void Simulator::set_fpu_register_hi_word(int fpureg, int32_t value) { |
+ // Set ONLY upper 32-bits, leaving lower bits untouched. |
+ // TODO(plind): big endian issue. |
+ ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters)); |
+ int32_t *phiword = (reinterpret_cast<int32_t*>(&FPUregisters_[fpureg])) + 1; |
+ *phiword = value; |
+} |
+ |
+ |
void Simulator::set_fpu_register_float(int fpureg, float value) { |
ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters)); |
*BitCast<float*>(&FPUregisters_[fpureg]) = value; |
@@ -1024,14 +1061,14 @@ void Simulator::set_fpu_register_float(int fpureg, float value) { |
void Simulator::set_fpu_register_double(int fpureg, double value) { |
- ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0)); |
+ ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters)); |
*BitCast<double*>(&FPUregisters_[fpureg]) = value; |
} |
// Get the register from the architecture state. This function does handle |
// the special case of accessing the PC register. |
-int32_t Simulator::get_register(int reg) const { |
+int64_t Simulator::get_register(int reg) const { |
ASSERT((reg >= 0) && (reg < kNumSimuRegisters)); |
if (reg == 0) |
return 0; |
@@ -1041,53 +1078,67 @@ int32_t Simulator::get_register(int reg) const { |
double Simulator::get_double_from_register_pair(int reg) { |
+ // TODO(plind): bad ABI stuff, refactor or remove. |
ASSERT((reg >= 0) && (reg < kNumSimuRegisters) && ((reg % 2) == 0)); |
double dm_val = 0.0; |
// Read the bits from the unsigned integer register_[] array |
// into the double precision floating point value and return it. |
- char buffer[2 * sizeof(registers_[0])]; |
- memcpy(buffer, ®isters_[reg], 2 * sizeof(registers_[0])); |
- memcpy(&dm_val, buffer, 2 * sizeof(registers_[0])); |
+ char buffer[sizeof(registers_[0])]; |
+ memcpy(buffer, ®isters_[reg], sizeof(registers_[0])); |
+ memcpy(&dm_val, buffer, sizeof(registers_[0])); |
return(dm_val); |
} |
-int32_t Simulator::get_fpu_register(int fpureg) const { |
+int64_t Simulator::get_fpu_register(int fpureg) const { |
ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters)); |
return FPUregisters_[fpureg]; |
} |
-int64_t Simulator::get_fpu_register_long(int fpureg) const { |
- ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0)); |
- return *BitCast<int64_t*>( |
- const_cast<int32_t*>(&FPUregisters_[fpureg])); |
+int32_t Simulator::get_fpu_register_word(int fpureg) const { |
+ ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters)); |
+ return static_cast<int32_t>(FPUregisters_[fpureg] & 0xffffffff); |
+} |
+ |
+ |
+int32_t Simulator::get_fpu_register_signed_word(int fpureg) const { |
+ ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters)); |
+ return static_cast<int32_t>(FPUregisters_[fpureg] & 0xffffffff); |
+} |
+ |
+ |
+uint32_t Simulator::get_fpu_register_hi_word(int fpureg) const { |
+ ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters)); |
+ return static_cast<uint32_t>((FPUregisters_[fpureg] >> 32) & 0xffffffff); |
} |
float Simulator::get_fpu_register_float(int fpureg) const { |
ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters)); |
return *BitCast<float*>( |
- const_cast<int32_t*>(&FPUregisters_[fpureg])); |
+ const_cast<int64_t*>(&FPUregisters_[fpureg])); |
} |
double Simulator::get_fpu_register_double(int fpureg) const { |
- ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0)); |
- return *BitCast<double*>(const_cast<int32_t*>(&FPUregisters_[fpureg])); |
+ ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters)); |
+ return *BitCast<double*>(&FPUregisters_[fpureg]); |
} |
// Runtime FP routines take up to two double arguments and zero |
// or one integer arguments. All are constructed here, |
-// from a0-a3 or f12 and f14. |
+// from a0-a3 or f12 and f13 (n64), or f14 (O32). |
void Simulator::GetFpArgs(double* x, double* y, int32_t* z) { |
if (!IsMipsSoftFloatABI) { |
+ const int fparg2 = (kMipsAbi == kN64) ? 13 : 14; |
*x = get_fpu_register_double(12); |
- *y = get_fpu_register_double(14); |
+ *y = get_fpu_register_double(fparg2); |
*z = get_register(a2); |
} else { |
+ // TODO(plind): bad ABI stuff, refactor or remove. |
// We use a char buffer to get around the strict-aliasing rules which |
// otherwise allow the compiler to optimize away the copy. |
char buffer[sizeof(*x)]; |
@@ -1114,7 +1165,7 @@ void Simulator::SetFpResult(const double& result) { |
set_fpu_register_double(0, result); |
} else { |
char buffer[2 * sizeof(registers_[0])]; |
- int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer); |
+ int64_t* reg_buffer = reinterpret_cast<int64_t*>(buffer); |
memcpy(buffer, &result, sizeof(buffer)); |
// Copy result to v0 and v1. |
set_register(v0, reg_buffer[0]); |
@@ -1142,6 +1193,40 @@ bool Simulator::test_fcsr_bit(uint32_t cc) { |
// Returns true if the operation was invalid. |
bool Simulator::set_fcsr_round_error(double original, double rounded) { |
bool ret = false; |
+ double max_int32 = std::numeric_limits<int32_t>::max(); |
+ double min_int32 = std::numeric_limits<int32_t>::min(); |
+ |
+ if (!std::isfinite(original) || !std::isfinite(rounded)) { |
+ set_fcsr_bit(kFCSRInvalidOpFlagBit, true); |
+ ret = true; |
+ } |
+ |
+ if (original != rounded) { |
+ set_fcsr_bit(kFCSRInexactFlagBit, true); |
+ } |
+ |
+ if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) { |
+ set_fcsr_bit(kFCSRUnderflowFlagBit, true); |
+ ret = true; |
+ } |
+ |
+ if (rounded > max_int32 || rounded < min_int32) { |
+ set_fcsr_bit(kFCSROverflowFlagBit, true); |
+ // The reference is not really clear but it seems this is required: |
+ set_fcsr_bit(kFCSRInvalidOpFlagBit, true); |
+ ret = true; |
+ } |
+ |
+ return ret; |
+} |
+ |
+ |
+// Sets the rounding error codes in FCSR based on the result of the rounding. |
+// Returns true if the operation was invalid. |
+bool Simulator::set_fcsr_round64_error(double original, double rounded) { |
+ bool ret = false; |
+ double max_int64 = std::numeric_limits<int64_t>::max(); |
+ double min_int64 = std::numeric_limits<int64_t>::min(); |
if (!std::isfinite(original) || !std::isfinite(rounded)) { |
set_fcsr_bit(kFCSRInvalidOpFlagBit, true); |
@@ -1157,7 +1242,7 @@ bool Simulator::set_fcsr_round_error(double original, double rounded) { |
ret = true; |
} |
- if (rounded > INT_MAX || rounded < INT_MIN) { |
+ if (rounded > max_int64 || rounded < min_int64) { |
set_fcsr_bit(kFCSROverflowFlagBit, true); |
// The reference is not really clear but it seems this is required: |
set_fcsr_bit(kFCSRInvalidOpFlagBit, true); |
@@ -1169,7 +1254,7 @@ bool Simulator::set_fcsr_round_error(double original, double rounded) { |
// Raw access to the PC register. |
-void Simulator::set_pc(int32_t value) { |
+void Simulator::set_pc(int64_t value) { |
pc_modified_ = true; |
registers_[pc] = value; |
} |
@@ -1181,7 +1266,7 @@ bool Simulator::has_bad_pc() const { |
// Raw access to the PC register without the special adjustment when reading. |
-int32_t Simulator::get_pc() const { |
+int64_t Simulator::get_pc() const { |
return registers_[pc]; |
} |
@@ -1194,54 +1279,165 @@ int32_t Simulator::get_pc() const { |
// executed in the simulator. Since the host is typically IA32 we will not |
// get the correct MIPS-like behaviour on unaligned accesses. |
-int Simulator::ReadW(int32_t addr, Instruction* instr) { |
+// TODO(plind): refactor this messy debug code when we do unaligned access. |
+void Simulator::DieOrDebug() { |
+ if (1) { // Flag for this was removed. |
+ MipsDebugger dbg(this); |
+ dbg.Debug(); |
+ } else { |
+ base::OS::Abort(); |
+ } |
+} |
+ |
+ |
+void Simulator::TraceRegWr(int64_t value) { |
+ if (::v8::internal::FLAG_trace_sim) { |
+ SNPrintF(trace_buf_, "%016lx", value); |
+ } |
+} |
+ |
+ |
+// TODO(plind): consider making icount_ printing a flag option. |
+void Simulator::TraceMemRd(int64_t addr, int64_t value) { |
+ if (::v8::internal::FLAG_trace_sim) { |
+ SNPrintF(trace_buf_, "%016lx <-- [%016lx] (%ld)", |
+ value, addr, icount_); |
+ } |
+} |
+ |
+ |
+void Simulator::TraceMemWr(int64_t addr, int64_t value, TraceType t) { |
+ if (::v8::internal::FLAG_trace_sim) { |
+ switch (t) { |
+ case BYTE: |
+ SNPrintF(trace_buf_, " %02x --> [%016lx]", |
+ static_cast<int8_t>(value), addr); |
+ break; |
+ case HALF: |
+ SNPrintF(trace_buf_, " %04x --> [%016lx]", |
+ static_cast<int16_t>(value), addr); |
+ break; |
+ case WORD: |
+ SNPrintF(trace_buf_, " %08x --> [%016lx]", |
+ static_cast<int32_t>(value), addr); |
+ break; |
+ case DWORD: |
+ SNPrintF(trace_buf_, "%016lx --> [%016lx] (%ld)", |
+ value, addr, icount_); |
+ break; |
+ } |
+ } |
+} |
+ |
+ |
+// TODO(plind): sign-extend and zero-extend not implmented properly |
+// on all the ReadXX functions, I don't think re-interpret cast does it. |
+int32_t Simulator::ReadW(int64_t addr, Instruction* instr) { |
if (addr >=0 && addr < 0x400) { |
// This has to be a NULL-dereference, drop into debugger. |
- PrintF("Memory read from bad address: 0x%08x, pc=0x%08x\n", |
+ PrintF("Memory read from bad address: 0x%08lx, pc=0x%08lx\n", |
addr, reinterpret_cast<intptr_t>(instr)); |
- MipsDebugger dbg(this); |
- dbg.Debug(); |
+ DieOrDebug(); |
+ } |
+ if ((addr & 0x3) == 0) { |
+ int32_t* ptr = reinterpret_cast<int32_t*>(addr); |
+ TraceMemRd(addr, static_cast<int64_t>(*ptr)); |
+ return *ptr; |
+ } |
+ PrintF("Unaligned read at 0x%08lx, pc=0x%08" V8PRIxPTR "\n", |
+ addr, |
+ reinterpret_cast<intptr_t>(instr)); |
+ DieOrDebug(); |
+ return 0; |
+} |
+ |
+ |
+uint32_t Simulator::ReadWU(int64_t addr, Instruction* instr) { |
+ if (addr >=0 && addr < 0x400) { |
+ // This has to be a NULL-dereference, drop into debugger. |
+ PrintF("Memory read from bad address: 0x%08lx, pc=0x%08lx\n", |
+ addr, reinterpret_cast<intptr_t>(instr)); |
+ DieOrDebug(); |
+ } |
+ if ((addr & 0x3) == 0) { |
+ uint32_t* ptr = reinterpret_cast<uint32_t*>(addr); |
+ TraceMemRd(addr, static_cast<int64_t>(*ptr)); |
+ return *ptr; |
+ } |
+ PrintF("Unaligned read at 0x%08lx, pc=0x%08" V8PRIxPTR "\n", |
+ addr, |
+ reinterpret_cast<intptr_t>(instr)); |
+ DieOrDebug(); |
+ return 0; |
+} |
+ |
+ |
+void Simulator::WriteW(int64_t addr, int value, Instruction* instr) { |
+ if (addr >= 0 && addr < 0x400) { |
+ // This has to be a NULL-dereference, drop into debugger. |
+ PrintF("Memory write to bad address: 0x%08lx, pc=0x%08lx\n", |
+ addr, reinterpret_cast<intptr_t>(instr)); |
+ DieOrDebug(); |
+ } |
+ if ((addr & 0x3) == 0) { |
+ TraceMemWr(addr, value, WORD); |
+ int* ptr = reinterpret_cast<int*>(addr); |
+ *ptr = value; |
+ return; |
+ } |
+ PrintF("Unaligned write at 0x%08lx, pc=0x%08" V8PRIxPTR "\n", |
+ addr, |
+ reinterpret_cast<intptr_t>(instr)); |
+ DieOrDebug(); |
+} |
+ |
+ |
+int64_t Simulator::Read2W(int64_t addr, Instruction* instr) { |
+ if (addr >=0 && addr < 0x400) { |
+ // This has to be a NULL-dereference, drop into debugger. |
+ PrintF("Memory read from bad address: 0x%08lx, pc=0x%08lx\n", |
+ addr, reinterpret_cast<intptr_t>(instr)); |
+ DieOrDebug(); |
} |
if ((addr & kPointerAlignmentMask) == 0) { |
- intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); |
+ int64_t* ptr = reinterpret_cast<int64_t*>(addr); |
+ TraceMemRd(addr, *ptr); |
return *ptr; |
} |
- PrintF("Unaligned read at 0x%08x, pc=0x%08" V8PRIxPTR "\n", |
+ PrintF("Unaligned read at 0x%08lx, pc=0x%08" V8PRIxPTR "\n", |
addr, |
reinterpret_cast<intptr_t>(instr)); |
- MipsDebugger dbg(this); |
- dbg.Debug(); |
+ DieOrDebug(); |
return 0; |
} |
-void Simulator::WriteW(int32_t addr, int value, Instruction* instr) { |
+void Simulator::Write2W(int64_t addr, int64_t value, Instruction* instr) { |
if (addr >= 0 && addr < 0x400) { |
// This has to be a NULL-dereference, drop into debugger. |
- PrintF("Memory write to bad address: 0x%08x, pc=0x%08x\n", |
+ PrintF("Memory write to bad address: 0x%08lx, pc=0x%08lx\n", |
addr, reinterpret_cast<intptr_t>(instr)); |
- MipsDebugger dbg(this); |
- dbg.Debug(); |
+ DieOrDebug(); |
} |
if ((addr & kPointerAlignmentMask) == 0) { |
- intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); |
+ TraceMemWr(addr, value, DWORD); |
+ int64_t* ptr = reinterpret_cast<int64_t*>(addr); |
*ptr = value; |
return; |
} |
- PrintF("Unaligned write at 0x%08x, pc=0x%08" V8PRIxPTR "\n", |
+ PrintF("Unaligned write at 0x%08lx, pc=0x%08" V8PRIxPTR "\n", |
addr, |
reinterpret_cast<intptr_t>(instr)); |
- MipsDebugger dbg(this); |
- dbg.Debug(); |
+ DieOrDebug(); |
} |
-double Simulator::ReadD(int32_t addr, Instruction* instr) { |
+double Simulator::ReadD(int64_t addr, Instruction* instr) { |
if ((addr & kDoubleAlignmentMask) == 0) { |
double* ptr = reinterpret_cast<double*>(addr); |
return *ptr; |
} |
- PrintF("Unaligned (double) read at 0x%08x, pc=0x%08" V8PRIxPTR "\n", |
+ PrintF("Unaligned (double) read at 0x%08lx, pc=0x%08" V8PRIxPTR "\n", |
addr, |
reinterpret_cast<intptr_t>(instr)); |
base::OS::Abort(); |
@@ -1249,90 +1445,99 @@ double Simulator::ReadD(int32_t addr, Instruction* instr) { |
} |
-void Simulator::WriteD(int32_t addr, double value, Instruction* instr) { |
+void Simulator::WriteD(int64_t addr, double value, Instruction* instr) { |
if ((addr & kDoubleAlignmentMask) == 0) { |
double* ptr = reinterpret_cast<double*>(addr); |
*ptr = value; |
return; |
} |
- PrintF("Unaligned (double) write at 0x%08x, pc=0x%08" V8PRIxPTR "\n", |
+ PrintF("Unaligned (double) write at 0x%08lx, pc=0x%08" V8PRIxPTR "\n", |
addr, |
reinterpret_cast<intptr_t>(instr)); |
- base::OS::Abort(); |
+ DieOrDebug(); |
} |
-uint16_t Simulator::ReadHU(int32_t addr, Instruction* instr) { |
+uint16_t Simulator::ReadHU(int64_t addr, Instruction* instr) { |
if ((addr & 1) == 0) { |
uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); |
+ TraceMemRd(addr, static_cast<int64_t>(*ptr)); |
return *ptr; |
} |
- PrintF("Unaligned unsigned halfword read at 0x%08x, pc=0x%08" V8PRIxPTR "\n", |
+ PrintF("Unaligned unsigned halfword read at 0x%08lx, pc=0x%08" V8PRIxPTR "\n", |
addr, |
reinterpret_cast<intptr_t>(instr)); |
- base::OS::Abort(); |
+ DieOrDebug(); |
return 0; |
} |
-int16_t Simulator::ReadH(int32_t addr, Instruction* instr) { |
+int16_t Simulator::ReadH(int64_t addr, Instruction* instr) { |
if ((addr & 1) == 0) { |
int16_t* ptr = reinterpret_cast<int16_t*>(addr); |
+ TraceMemRd(addr, static_cast<int64_t>(*ptr)); |
return *ptr; |
} |
- PrintF("Unaligned signed halfword read at 0x%08x, pc=0x%08" V8PRIxPTR "\n", |
+ PrintF("Unaligned signed halfword read at 0x%08lx, pc=0x%08" V8PRIxPTR "\n", |
addr, |
reinterpret_cast<intptr_t>(instr)); |
- base::OS::Abort(); |
+ DieOrDebug(); |
return 0; |
} |
-void Simulator::WriteH(int32_t addr, uint16_t value, Instruction* instr) { |
+void Simulator::WriteH(int64_t addr, uint16_t value, Instruction* instr) { |
if ((addr & 1) == 0) { |
+ TraceMemWr(addr, value, HALF); |
uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); |
*ptr = value; |
return; |
} |
- PrintF("Unaligned unsigned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n", |
- addr, |
- reinterpret_cast<intptr_t>(instr)); |
- base::OS::Abort(); |
+ PrintF( |
+ "Unaligned unsigned halfword write at 0x%08lx, pc=0x%08" V8PRIxPTR "\n", |
+ addr, |
+ reinterpret_cast<intptr_t>(instr)); |
+ DieOrDebug(); |
} |
-void Simulator::WriteH(int32_t addr, int16_t value, Instruction* instr) { |
+void Simulator::WriteH(int64_t addr, int16_t value, Instruction* instr) { |
if ((addr & 1) == 0) { |
+ TraceMemWr(addr, value, HALF); |
int16_t* ptr = reinterpret_cast<int16_t*>(addr); |
*ptr = value; |
return; |
} |
- PrintF("Unaligned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n", |
+ PrintF("Unaligned halfword write at 0x%08lx, pc=0x%08" V8PRIxPTR "\n", |
addr, |
reinterpret_cast<intptr_t>(instr)); |
- base::OS::Abort(); |
+ DieOrDebug(); |
} |
-uint32_t Simulator::ReadBU(int32_t addr) { |
+uint32_t Simulator::ReadBU(int64_t addr) { |
uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); |
+ TraceMemRd(addr, static_cast<int64_t>(*ptr)); |
return *ptr & 0xff; |
} |
-int32_t Simulator::ReadB(int32_t addr) { |
+int32_t Simulator::ReadB(int64_t addr) { |
int8_t* ptr = reinterpret_cast<int8_t*>(addr); |
+ TraceMemRd(addr, static_cast<int64_t>(*ptr)); |
return *ptr; |
} |
-void Simulator::WriteB(int32_t addr, uint8_t value) { |
+void Simulator::WriteB(int64_t addr, uint8_t value) { |
+ TraceMemWr(addr, value, BYTE); |
uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); |
*ptr = value; |
} |
-void Simulator::WriteB(int32_t addr, int8_t value) { |
+void Simulator::WriteB(int64_t addr, int8_t value) { |
+ TraceMemWr(addr, value, BYTE); |
int8_t* ptr = reinterpret_cast<int8_t*>(addr); |
*ptr = value; |
} |
@@ -1348,7 +1553,7 @@ uintptr_t Simulator::StackLimit() const { |
// Unsupported instructions use Format to print an error and stop execution. |
void Simulator::Format(Instruction* instr, const char* format) { |
- PrintF("Simulator found unsupported instruction:\n 0x%08x: %s\n", |
+ PrintF("Simulator found unsupported instruction:\n 0x%08lx: %s\n", |
reinterpret_cast<intptr_t>(instr), format); |
UNIMPLEMENTED_MIPS(); |
} |
@@ -1360,12 +1565,19 @@ void Simulator::Format(Instruction* instr, const char* format) { |
// 64-bit value. With the code below we assume that all runtime calls return |
// 64 bits of result. If they don't, the v1 result register contains a bogus |
// value, which is fine because it is caller-saved. |
-typedef int64_t (*SimulatorRuntimeCall)(int32_t arg0, |
- int32_t arg1, |
- int32_t arg2, |
- int32_t arg3, |
- int32_t arg4, |
- int32_t arg5); |
+ |
+struct ObjectPair { |
+ Object* x; |
+ Object* y; |
+}; |
+ |
+typedef ObjectPair (*SimulatorRuntimeCall)(int64_t arg0, |
+ int64_t arg1, |
+ int64_t arg2, |
+ int64_t arg3, |
+ int64_t arg4, |
+ int64_t arg5); |
+ |
// These prototypes handle the four types of FP calls. |
typedef int64_t (*SimulatorRuntimeCompareCall)(double darg0, double darg1); |
@@ -1375,13 +1587,13 @@ typedef double (*SimulatorRuntimeFPIntCall)(double darg0, int32_t arg0); |
// This signature supports direct call in to API function native callback |
// (refer to InvocationCallback in v8.h). |
-typedef void (*SimulatorRuntimeDirectApiCall)(int32_t arg0); |
-typedef void (*SimulatorRuntimeProfilingApiCall)(int32_t arg0, void* arg1); |
+typedef void (*SimulatorRuntimeDirectApiCall)(int64_t arg0); |
+typedef void (*SimulatorRuntimeProfilingApiCall)(int64_t arg0, void* arg1); |
// This signature supports direct call to accessor getter callback. |
-typedef void (*SimulatorRuntimeDirectGetterCall)(int32_t arg0, int32_t arg1); |
+typedef void (*SimulatorRuntimeDirectGetterCall)(int64_t arg0, int64_t arg1); |
typedef void (*SimulatorRuntimeProfilingGetterCall)( |
- int32_t arg0, int32_t arg1, void* arg2); |
+ int64_t arg0, int64_t arg1, void* arg2); |
// Software interrupt instructions are used by the simulator to call into the |
// C-based V8 runtime. They are also used for debugging with simulator. |
@@ -1391,20 +1603,24 @@ void Simulator::SoftwareInterrupt(Instruction* instr) { |
// Are "SPECIAL" class opcode, and are distinuished by function. |
int32_t func = instr->FunctionFieldRaw(); |
uint32_t code = (func == BREAK) ? instr->Bits(25, 6) : -1; |
- |
// We first check if we met a call_rt_redirected. |
if (instr->InstructionBits() == rtCallRedirInstr) { |
Redirection* redirection = Redirection::FromSwiInstruction(instr); |
- int32_t arg0 = get_register(a0); |
- int32_t arg1 = get_register(a1); |
- int32_t arg2 = get_register(a2); |
- int32_t arg3 = get_register(a3); |
- |
- int32_t* stack_pointer = reinterpret_cast<int32_t*>(get_register(sp)); |
- // Args 4 and 5 are on the stack after the reserved space for args 0..3. |
- int32_t arg4 = stack_pointer[4]; |
- int32_t arg5 = stack_pointer[5]; |
- |
+ int64_t arg0 = get_register(a0); |
+ int64_t arg1 = get_register(a1); |
+ int64_t arg2 = get_register(a2); |
+ int64_t arg3 = get_register(a3); |
+ int64_t arg4, arg5; |
+ |
+ if (kMipsAbi == kN64) { |
+ arg4 = get_register(a4); // Abi n64 register a4. |
+ arg5 = get_register(a5); // Abi n64 register a5. |
+ } else { // Abi O32. |
+ int64_t* stack_pointer = reinterpret_cast<int64_t*>(get_register(sp)); |
+ // Args 4 and 5 are on the stack after the reserved space for args 0..3. |
+ arg4 = stack_pointer[4]; |
+ arg5 = stack_pointer[5]; |
+ } |
bool fp_call = |
(redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) || |
(redirection->type() == ExternalReference::BUILTIN_COMPARE_CALL) || |
@@ -1440,7 +1656,7 @@ void Simulator::SoftwareInterrupt(Instruction* instr) { |
// This is dodgy but it works because the C entry stubs are never moved. |
// See comment in codegen-arm.cc and bug 1242173. |
- int32_t saved_ra = get_register(ra); |
+ int64_t saved_ra = get_register(ra); |
intptr_t external = |
reinterpret_cast<intptr_t>(redirection->external_function()); |
@@ -1482,8 +1698,8 @@ void Simulator::SoftwareInterrupt(Instruction* instr) { |
SimulatorRuntimeCompareCall target = |
reinterpret_cast<SimulatorRuntimeCompareCall>(external); |
iresult = target(dval0, dval1); |
- set_register(v0, static_cast<int32_t>(iresult)); |
- set_register(v1, static_cast<int32_t>(iresult >> 32)); |
+ set_register(v0, static_cast<int64_t>(iresult)); |
+ // set_register(v1, static_cast<int64_t>(iresult >> 32)); |
break; |
} |
case ExternalReference::BUILTIN_FP_FP_CALL: { |
@@ -1528,7 +1744,7 @@ void Simulator::SoftwareInterrupt(Instruction* instr) { |
} |
} else if (redirection->type() == ExternalReference::DIRECT_API_CALL) { |
if (::v8::internal::FLAG_trace_sim) { |
- PrintF("Call to host function at %p args %08x\n", |
+ PrintF("Call to host function at %p args %08lx\n", |
reinterpret_cast<void*>(external), arg0); |
} |
SimulatorRuntimeDirectApiCall target = |
@@ -1537,7 +1753,7 @@ void Simulator::SoftwareInterrupt(Instruction* instr) { |
} else if ( |
redirection->type() == ExternalReference::PROFILING_API_CALL) { |
if (::v8::internal::FLAG_trace_sim) { |
- PrintF("Call to host function at %p args %08x %08x\n", |
+ PrintF("Call to host function at %p args %08lx %08lx\n", |
reinterpret_cast<void*>(external), arg0, arg1); |
} |
SimulatorRuntimeProfilingApiCall target = |
@@ -1546,7 +1762,7 @@ void Simulator::SoftwareInterrupt(Instruction* instr) { |
} else if ( |
redirection->type() == ExternalReference::DIRECT_GETTER_CALL) { |
if (::v8::internal::FLAG_trace_sim) { |
- PrintF("Call to host function at %p args %08x %08x\n", |
+ PrintF("Call to host function at %p args %08lx %08lx\n", |
reinterpret_cast<void*>(external), arg0, arg1); |
} |
SimulatorRuntimeDirectGetterCall target = |
@@ -1555,7 +1771,7 @@ void Simulator::SoftwareInterrupt(Instruction* instr) { |
} else if ( |
redirection->type() == ExternalReference::PROFILING_GETTER_CALL) { |
if (::v8::internal::FLAG_trace_sim) { |
- PrintF("Call to host function at %p args %08x %08x %08x\n", |
+ PrintF("Call to host function at %p args %08lx %08lx %08lx\n", |
reinterpret_cast<void*>(external), arg0, arg1, arg2); |
} |
SimulatorRuntimeProfilingGetterCall target = |
@@ -1567,7 +1783,7 @@ void Simulator::SoftwareInterrupt(Instruction* instr) { |
if (::v8::internal::FLAG_trace_sim) { |
PrintF( |
"Call to host function at %p " |
- "args %08x, %08x, %08x, %08x, %08x, %08x\n", |
+ "args %08lx, %08lx, %08lx, %08lx, %08lx, %08lx\n", |
FUNCTION_ADDR(target), |
arg0, |
arg1, |
@@ -1576,12 +1792,15 @@ void Simulator::SoftwareInterrupt(Instruction* instr) { |
arg4, |
arg5); |
} |
- int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5); |
- set_register(v0, static_cast<int32_t>(result)); |
- set_register(v1, static_cast<int32_t>(result >> 32)); |
+ // int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5); |
+ // set_register(v0, static_cast<int32_t>(result)); |
+ // set_register(v1, static_cast<int32_t>(result >> 32)); |
+ ObjectPair result = target(arg0, arg1, arg2, arg3, arg4, arg5); |
+ set_register(v0, (int64_t)(result.x)); |
+ set_register(v1, (int64_t)(result.y)); |
} |
- if (::v8::internal::FLAG_trace_sim) { |
- PrintF("Returned %08x : %08x\n", get_register(v1), get_register(v0)); |
+ if (::v8::internal::FLAG_trace_sim) { |
+ PrintF("Returned %08lx : %08lx\n", get_register(v1), get_register(v0)); |
} |
set_register(ra, saved_ra); |
set_pc(get_register(ra)); |
@@ -1602,22 +1821,22 @@ void Simulator::SoftwareInterrupt(Instruction* instr) { |
// Stop helper functions. |
-bool Simulator::IsWatchpoint(uint32_t code) { |
+bool Simulator::IsWatchpoint(uint64_t code) { |
return (code <= kMaxWatchpointCode); |
} |
-void Simulator::PrintWatchpoint(uint32_t code) { |
+void Simulator::PrintWatchpoint(uint64_t code) { |
MipsDebugger dbg(this); |
++break_count_; |
- PrintF("\n---- break %d marker: %3d (instr count: %8d) ----------" |
+ PrintF("\n---- break %ld marker: %3d (instr count: %8ld) ----------" |
"----------------------------------", |
code, break_count_, icount_); |
dbg.PrintAllRegs(); // Print registers and continue running. |
} |
-void Simulator::HandleStop(uint32_t code, Instruction* instr) { |
+void Simulator::HandleStop(uint64_t code, Instruction* instr) { |
// Stop if it is enabled, otherwise go on jumping over the stop |
// and the message address. |
if (IsEnabledStop(code)) { |
@@ -1636,31 +1855,31 @@ bool Simulator::IsStopInstruction(Instruction* instr) { |
} |
-bool Simulator::IsEnabledStop(uint32_t code) { |
+bool Simulator::IsEnabledStop(uint64_t code) { |
ASSERT(code <= kMaxStopCode); |
ASSERT(code > kMaxWatchpointCode); |
return !(watched_stops_[code].count & kStopDisabledBit); |
} |
-void Simulator::EnableStop(uint32_t code) { |
+void Simulator::EnableStop(uint64_t code) { |
if (!IsEnabledStop(code)) { |
watched_stops_[code].count &= ~kStopDisabledBit; |
} |
} |
-void Simulator::DisableStop(uint32_t code) { |
+void Simulator::DisableStop(uint64_t code) { |
if (IsEnabledStop(code)) { |
watched_stops_[code].count |= kStopDisabledBit; |
} |
} |
-void Simulator::IncreaseStopCounter(uint32_t code) { |
+void Simulator::IncreaseStopCounter(uint64_t code) { |
ASSERT(code <= kMaxStopCode); |
if ((watched_stops_[code].count & ~(1 << 31)) == 0x7fffffff) { |
- PrintF("Stop counter for code %i has overflowed.\n" |
+ PrintF("Stop counter for code %ld has overflowed.\n" |
"Enabling this code and reseting the counter to 0.\n", code); |
watched_stops_[code].count = 0; |
EnableStop(code); |
@@ -1671,7 +1890,7 @@ void Simulator::IncreaseStopCounter(uint32_t code) { |
// Print a stop status. |
-void Simulator::PrintStopInfo(uint32_t code) { |
+void Simulator::PrintStopInfo(uint64_t code) { |
if (code <= kMaxWatchpointCode) { |
PrintF("That is a watchpoint, not a stop.\n"); |
return; |
@@ -1684,10 +1903,10 @@ void Simulator::PrintStopInfo(uint32_t code) { |
// Don't print the state of unused breakpoints. |
if (count != 0) { |
if (watched_stops_[code].desc) { |
- PrintF("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n", |
+ PrintF("stop %ld - 0x%lx: \t%s, \tcounter = %i, \t%s\n", |
code, code, state, count, watched_stops_[code].desc); |
} else { |
- PrintF("stop %i - 0x%x: \t%s, \tcounter = %i\n", |
+ PrintF("stop %ld - 0x%lx: \t%s, \tcounter = %i\n", |
code, code, state, count); |
} |
} |
@@ -1706,26 +1925,28 @@ void Simulator::SignalExceptions() { |
// Handle execution based on instruction types. |
void Simulator::ConfigureTypeRegister(Instruction* instr, |
- int32_t* alu_out, |
+ int64_t* alu_out, |
int64_t* i64hilo, |
uint64_t* u64hilo, |
- int32_t* next_pc, |
- int32_t* return_addr_reg, |
- bool* do_interrupt) { |
+ int64_t* next_pc, |
+ int64_t* return_addr_reg, |
+ bool* do_interrupt, |
+ int64_t* i128resultH, |
+ int64_t* i128resultL) { |
// Every local variable declared here needs to be const. |
// This is to make sure that changed values are sent back to |
// DecodeTypeRegister correctly. |
// Instruction fields. |
const Opcode op = instr->OpcodeFieldRaw(); |
- const int32_t rs_reg = instr->RsValue(); |
- const int32_t rs = get_register(rs_reg); |
- const uint32_t rs_u = static_cast<uint32_t>(rs); |
- const int32_t rt_reg = instr->RtValue(); |
- const int32_t rt = get_register(rt_reg); |
- const uint32_t rt_u = static_cast<uint32_t>(rt); |
- const int32_t rd_reg = instr->RdValue(); |
- const uint32_t sa = instr->SaValue(); |
+ const int64_t rs_reg = instr->RsValue(); |
+ const int64_t rs = get_register(rs_reg); |
+ const uint64_t rs_u = static_cast<uint64_t>(rs); |
+ const int64_t rt_reg = instr->RtValue(); |
+ const int64_t rt = get_register(rt_reg); |
+ const uint64_t rt_u = static_cast<uint64_t>(rt); |
+ const int64_t rd_reg = instr->RdValue(); |
+ const uint64_t sa = instr->SaValue(); |
const int32_t fs_reg = instr->FsValue(); |
@@ -1743,13 +1964,17 @@ void Simulator::ConfigureTypeRegister(Instruction* instr, |
*alu_out = FCSR_; |
break; |
case MFC1: |
+ *alu_out = static_cast<int64_t>(get_fpu_register_word(fs_reg)); |
+ break; |
+ case DMFC1: |
*alu_out = get_fpu_register(fs_reg); |
break; |
case MFHC1: |
- UNIMPLEMENTED_MIPS(); |
+ *alu_out = get_fpu_register_hi_word(fs_reg); |
break; |
case CTC1: |
case MTC1: |
+ case DMTC1: |
case MTHC1: |
// Do the store in the execution step. |
break; |
@@ -1774,30 +1999,64 @@ void Simulator::ConfigureTypeRegister(Instruction* instr, |
*return_addr_reg = instr->RdValue(); |
break; |
case SLL: |
+ *alu_out = (int32_t)rt << sa; |
+ break; |
+ case DSLL: |
*alu_out = rt << sa; |
break; |
+ case DSLL32: |
+ *alu_out = rt << sa << 32; |
+ break; |
case SRL: |
if (rs_reg == 0) { |
// Regular logical right shift of a word by a fixed number of |
// bits instruction. RS field is always equal to 0. |
- *alu_out = rt_u >> sa; |
+ *alu_out = (uint32_t)rt_u >> sa; |
} else { |
// Logical right-rotate of a word by a fixed number of bits. This |
// is special case of SRL instruction, added in MIPS32 Release 2. |
// RS field is equal to 00001. |
- *alu_out = (rt_u >> sa) | (rt_u << (32 - sa)); |
+ *alu_out = ((uint32_t)rt_u >> sa) | ((uint32_t)rt_u << (32 - sa)); |
} |
break; |
+ case DSRL: |
+ *alu_out = rt_u >> sa; |
+ break; |
+ case DSRL32: |
+ *alu_out = rt_u >> sa >> 32; |
+ break; |
case SRA: |
+ *alu_out = (int32_t)rt >> sa; |
+ break; |
+ case DSRA: |
*alu_out = rt >> sa; |
break; |
+ case DSRA32: |
+ *alu_out = rt >> sa >> 32; |
+ break; |
case SLLV: |
+ *alu_out = (int32_t)rt << rs; |
+ break; |
+ case DSLLV: |
*alu_out = rt << rs; |
break; |
case SRLV: |
if (sa == 0) { |
// Regular logical right-shift of a word by a variable number of |
// bits instruction. SA field is always equal to 0. |
+ *alu_out = (uint32_t)rt_u >> rs; |
+ } else { |
+ // Logical right-rotate of a word by a variable number of bits. |
+ // This is special case od SRLV instruction, added in MIPS32 |
+ // Release 2. SA field is equal to 00001. |
+ *alu_out = |
+ ((uint32_t)rt_u >> rs_u) | ((uint32_t)rt_u << (32 - rs_u)); |
+ } |
+ break; |
+ case DSRLV: |
+ if (sa == 0) { |
+ // Regular logical right-shift of a word by a variable number of |
+ // bits instruction. SA field is always equal to 0. |
*alu_out = rt_u >> rs; |
} else { |
// Logical right-rotate of a word by a variable number of bits. |
@@ -1807,6 +2066,9 @@ void Simulator::ConfigureTypeRegister(Instruction* instr, |
} |
break; |
case SRAV: |
+ *alu_out = (int32_t)rt >> rs; |
+ break; |
+ case DSRAV: |
*alu_out = rt >> rs; |
break; |
case MFHI: |
@@ -1816,12 +2078,25 @@ void Simulator::ConfigureTypeRegister(Instruction* instr, |
*alu_out = get_register(LO); |
break; |
case MULT: |
- *i64hilo = static_cast<int64_t>(rs) * static_cast<int64_t>(rt); |
+ // TODO(plind) - Unify MULT/DMULT with single set of 64-bit HI/Lo |
+ // regs. |
+ // TODO(plind) - make the 32-bit MULT ops conform to spec regarding |
+ // checking of 32-bit input values, and un-define operations of HW. |
+ *i64hilo = static_cast<int64_t>((int32_t)rs) * |
+ static_cast<int64_t>((int32_t)rt); |
break; |
case MULTU: |
*u64hilo = static_cast<uint64_t>(rs_u) * static_cast<uint64_t>(rt_u); |
break; |
+ case DMULT: |
+ *i128resultH = MultiplyHighSigned(rs, rt); |
+ *i128resultL = rs * rt; |
+ break; |
+ case DMULTU: |
+ UNIMPLEMENTED_MIPS(); |
+ break; |
case ADD: |
+ case DADD: |
if (HaveSameSign(rs, rt)) { |
if (rs > 0) { |
exceptions[kIntegerOverflow] = rs > (Registers::kMaxValue - rt); |
@@ -1831,10 +2106,17 @@ void Simulator::ConfigureTypeRegister(Instruction* instr, |
} |
*alu_out = rs + rt; |
break; |
- case ADDU: |
+ case ADDU: { |
+ int32_t alu32_out = rs + rt; |
+ // Sign-extend result of 32bit operation into 64bit register. |
+ *alu_out = static_cast<int64_t>(alu32_out); |
+ } |
+ break; |
+ case DADDU: |
*alu_out = rs + rt; |
break; |
case SUB: |
+ case DSUB: |
if (!HaveSameSign(rs, rt)) { |
if (rs > 0) { |
exceptions[kIntegerOverflow] = rs > (Registers::kMaxValue + rt); |
@@ -1844,7 +2126,13 @@ void Simulator::ConfigureTypeRegister(Instruction* instr, |
} |
*alu_out = rs - rt; |
break; |
- case SUBU: |
+ case SUBU: { |
+ int32_t alu32_out = rs - rt; |
+ // Sign-extend result of 32bit operation into 64bit register. |
+ *alu_out = static_cast<int64_t>(alu32_out); |
+ } |
+ break; |
+ case DSUBU: |
*alu_out = rs - rt; |
break; |
case AND: |
@@ -1867,6 +2155,7 @@ void Simulator::ConfigureTypeRegister(Instruction* instr, |
break; |
// Break and trap instructions. |
case BREAK: |
+ |
*do_interrupt = true; |
break; |
case TGE: |
@@ -1894,6 +2183,8 @@ void Simulator::ConfigureTypeRegister(Instruction* instr, |
break; |
case DIV: |
case DIVU: |
+ case DDIV: |
+ case DDIVU: |
// div and divu never raise exceptions. |
break; |
default: |
@@ -1903,7 +2194,8 @@ void Simulator::ConfigureTypeRegister(Instruction* instr, |
case SPECIAL2: |
switch (instr->FunctionFieldRaw()) { |
case MUL: |
- *alu_out = rs_u * rt_u; // Only the lower 32 bits are kept. |
+ // Only the lower 32 bits are kept. |
+ *alu_out = (int32_t)rs_u * (int32_t)rt_u; |
break; |
case CLZ: |
// MIPS32 spec: If no bits were set in GPR rs, the result written to |
@@ -1951,35 +2243,38 @@ void Simulator::ConfigureTypeRegister(Instruction* instr, |
void Simulator::DecodeTypeRegister(Instruction* instr) { |
// Instruction fields. |
const Opcode op = instr->OpcodeFieldRaw(); |
- const int32_t rs_reg = instr->RsValue(); |
- const int32_t rs = get_register(rs_reg); |
- const uint32_t rs_u = static_cast<uint32_t>(rs); |
- const int32_t rt_reg = instr->RtValue(); |
- const int32_t rt = get_register(rt_reg); |
- const uint32_t rt_u = static_cast<uint32_t>(rt); |
- const int32_t rd_reg = instr->RdValue(); |
+ const int64_t rs_reg = instr->RsValue(); |
+ const int64_t rs = get_register(rs_reg); |
+ const uint64_t rs_u = static_cast<uint32_t>(rs); |
+ const int64_t rt_reg = instr->RtValue(); |
+ const int64_t rt = get_register(rt_reg); |
+ const uint64_t rt_u = static_cast<uint32_t>(rt); |
+ const int64_t rd_reg = instr->RdValue(); |
const int32_t fr_reg = instr->FrValue(); |
const int32_t fs_reg = instr->FsValue(); |
const int32_t ft_reg = instr->FtValue(); |
- const int32_t fd_reg = instr->FdValue(); |
+ const int64_t fd_reg = instr->FdValue(); |
int64_t i64hilo = 0; |
uint64_t u64hilo = 0; |
// ALU output. |
// It should not be used as is. Instructions using it should always |
// initialize it first. |
- int32_t alu_out = 0x12345678; |
+ int64_t alu_out = 0x12345678; |
// For break and trap instructions. |
bool do_interrupt = false; |
// For jr and jalr. |
// Get current pc. |
- int32_t current_pc = get_pc(); |
+ int64_t current_pc = get_pc(); |
// Next pc |
- int32_t next_pc = 0; |
- int32_t return_addr_reg = 31; |
+ int64_t next_pc = 0; |
+ int64_t return_addr_reg = 31; |
+ |
+ int64_t i128resultH; |
+ int64_t i128resultL; |
// Set up the variables if needed before executing the instruction. |
ConfigureTypeRegister(instr, |
@@ -1988,7 +2283,9 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { |
&u64hilo, |
&next_pc, |
&return_addr_reg, |
- &do_interrupt); |
+ &do_interrupt, |
+ &i128resultH, |
+ &i128resultL); |
// ---------- Raise exceptions triggered. |
SignalExceptions(); |
@@ -2002,11 +2299,11 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { |
break; |
case CFC1: |
set_register(rt_reg, alu_out); |
- case MFC1: |
- set_register(rt_reg, alu_out); |
break; |
+ case MFC1: |
+ case DMFC1: |
case MFHC1: |
- UNIMPLEMENTED_MIPS(); |
+ set_register(rt_reg, alu_out); |
break; |
case CTC1: |
// At the moment only FCSR is supported. |
@@ -2014,10 +2311,15 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { |
FCSR_ = registers_[rt_reg]; |
break; |
case MTC1: |
- FPUregisters_[fs_reg] = registers_[rt_reg]; |
+ // Hardware writes upper 32-bits to zero on mtc1. |
+ set_fpu_register_hi_word(fs_reg, 0); |
+ set_fpu_register_word(fs_reg, registers_[rt_reg]); |
+ break; |
+ case DMTC1: |
+ set_fpu_register(fs_reg, registers_[rt_reg]); |
break; |
case MTHC1: |
- UNIMPLEMENTED_MIPS(); |
+ set_fpu_register_hi_word(fs_reg, registers_[rt_reg]); |
break; |
case S: |
float f; |
@@ -2104,6 +2406,7 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { |
// Rounding modes are not yet supported. |
ASSERT((FCSR_ & 3) == 0); |
// In rounding mode 0 it should behave like ROUND. |
+ // No break. |
case ROUND_W_D: // Round double to word (round half to even). |
{ |
double rounded = std::floor(fs + 0.5); |
@@ -2113,7 +2416,7 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { |
// round to the even one. |
result--; |
} |
- set_fpu_register(fd_reg, result); |
+ set_fpu_register_word(fd_reg, result); |
if (set_fcsr_round_error(fs, rounded)) { |
set_fpu_register(fd_reg, kFPUInvalidResult); |
} |
@@ -2123,7 +2426,7 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { |
{ |
double rounded = trunc(fs); |
int32_t result = static_cast<int32_t>(rounded); |
- set_fpu_register(fd_reg, result); |
+ set_fpu_register_word(fd_reg, result); |
if (set_fcsr_round_error(fs, rounded)) { |
set_fpu_register(fd_reg, kFPUInvalidResult); |
} |
@@ -2133,7 +2436,7 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { |
{ |
double rounded = std::floor(fs); |
int32_t result = static_cast<int32_t>(rounded); |
- set_fpu_register(fd_reg, result); |
+ set_fpu_register_word(fd_reg, result); |
if (set_fcsr_round_error(fs, rounded)) { |
set_fpu_register(fd_reg, kFPUInvalidResult); |
} |
@@ -2143,7 +2446,7 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { |
{ |
double rounded = std::ceil(fs); |
int32_t result = static_cast<int32_t>(rounded); |
- set_fpu_register(fd_reg, result); |
+ set_fpu_register_word(fd_reg, result); |
if (set_fcsr_round_error(fs, rounded)) { |
set_fpu_register(fd_reg, kFPUInvalidResult); |
} |
@@ -2152,38 +2455,48 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { |
case CVT_S_D: // Convert double to float (single). |
set_fpu_register_float(fd_reg, static_cast<float>(fs)); |
break; |
- case CVT_L_D: { // Mips32r2: Truncate double to 64-bit long-word. |
- double rounded = trunc(fs); |
- i64 = static_cast<int64_t>(rounded); |
- set_fpu_register(fd_reg, i64 & 0xffffffff); |
- set_fpu_register(fd_reg + 1, i64 >> 32); |
+ case CVT_L_D: // Mips64r2: Truncate double to 64-bit long-word. |
+ // Rounding modes are not yet supported. |
+ ASSERT((FCSR_ & 3) == 0); |
+ // In rounding mode 0 it should behave like ROUND. |
+ // No break. |
+ case ROUND_L_D: { // Mips64r2 instruction. |
+ // check error cases |
+ double rounded = fs > 0 ? floor(fs + 0.5) : ceil(fs - 0.5); |
+ int64_t result = static_cast<int64_t>(rounded); |
+ set_fpu_register(fd_reg, result); |
+ if (set_fcsr_round64_error(fs, rounded)) { |
+ set_fpu_register(fd_reg, kFPU64InvalidResult); |
+ } |
break; |
} |
- case TRUNC_L_D: { // Mips32r2 instruction. |
+ case TRUNC_L_D: { // Mips64r2 instruction. |
double rounded = trunc(fs); |
- i64 = static_cast<int64_t>(rounded); |
- set_fpu_register(fd_reg, i64 & 0xffffffff); |
- set_fpu_register(fd_reg + 1, i64 >> 32); |
+ int64_t result = static_cast<int64_t>(rounded); |
+ set_fpu_register(fd_reg, result); |
+ if (set_fcsr_round64_error(fs, rounded)) { |
+ set_fpu_register(fd_reg, kFPU64InvalidResult); |
+ } |
break; |
} |
- case ROUND_L_D: { // Mips32r2 instruction. |
- double rounded = |
- fs > 0 ? std::floor(fs + 0.5) : std::ceil(fs - 0.5); |
- i64 = static_cast<int64_t>(rounded); |
- set_fpu_register(fd_reg, i64 & 0xffffffff); |
- set_fpu_register(fd_reg + 1, i64 >> 32); |
+ case FLOOR_L_D: { // Mips64r2 instruction. |
+ double rounded = floor(fs); |
+ int64_t result = static_cast<int64_t>(rounded); |
+ set_fpu_register(fd_reg, result); |
+ if (set_fcsr_round64_error(fs, rounded)) { |
+ set_fpu_register(fd_reg, kFPU64InvalidResult); |
+ } |
break; |
} |
- case FLOOR_L_D: // Mips32r2 instruction. |
- i64 = static_cast<int64_t>(std::floor(fs)); |
- set_fpu_register(fd_reg, i64 & 0xffffffff); |
- set_fpu_register(fd_reg + 1, i64 >> 32); |
- break; |
- case CEIL_L_D: // Mips32r2 instruction. |
- i64 = static_cast<int64_t>(std::ceil(fs)); |
- set_fpu_register(fd_reg, i64 & 0xffffffff); |
- set_fpu_register(fd_reg + 1, i64 >> 32); |
+ case CEIL_L_D: { // Mips64r2 instruction. |
+ double rounded = ceil(fs); |
+ int64_t result = static_cast<int64_t>(rounded); |
+ set_fpu_register(fd_reg, result); |
+ if (set_fcsr_round64_error(fs, rounded)) { |
+ set_fpu_register(fd_reg, kFPU64InvalidResult); |
+ } |
break; |
+ } |
case C_F_D: |
UNIMPLEMENTED_MIPS(); |
break; |
@@ -2194,11 +2507,11 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { |
case W: |
switch (instr->FunctionFieldRaw()) { |
case CVT_S_W: // Convert word to float (single). |
- alu_out = get_fpu_register(fs_reg); |
+ alu_out = get_fpu_register_signed_word(fs_reg); |
set_fpu_register_float(fd_reg, static_cast<float>(alu_out)); |
break; |
case CVT_D_W: // Convert word to double. |
- alu_out = get_fpu_register(fs_reg); |
+ alu_out = get_fpu_register_signed_word(fs_reg); |
set_fpu_register_double(fd_reg, static_cast<double>(alu_out)); |
break; |
default: |
@@ -2208,10 +2521,7 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { |
case L: |
switch (instr->FunctionFieldRaw()) { |
case CVT_D_L: // Mips32r2 instruction. |
- // Watch the signs here, we want 2 32-bit vals |
- // to make a sign-64. |
- i64 = static_cast<uint32_t>(get_fpu_register(fs_reg)); |
- i64 |= static_cast<int64_t>(get_fpu_register(fs_reg + 1)) << 32; |
+ i64 = get_fpu_register(fs_reg); |
set_fpu_register_double(fd_reg, static_cast<double>(i64)); |
break; |
case CVT_S_L: |
@@ -2269,7 +2579,15 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { |
set_register(LO, static_cast<int32_t>(u64hilo & 0xffffffff)); |
set_register(HI, static_cast<int32_t>(u64hilo >> 32)); |
break; |
+ case DMULT: |
+ set_register(LO, static_cast<int64_t>(i128resultL)); |
+ set_register(HI, static_cast<int64_t>(i128resultH)); |
+ break; |
+ case DMULTU: |
+ UNIMPLEMENTED_MIPS(); |
+ break; |
case DIV: |
+ case DDIV: |
// Divide by zero and overflow was not checked in the configuration |
// step - div and divu do not raise exceptions. On division by 0 |
// the result will be UNPREDICTABLE. On overflow (INT_MIN/-1), |
@@ -2302,7 +2620,10 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { |
break; |
// Conditional moves. |
case MOVN: |
- if (rt) set_register(rd_reg, rs); |
+ if (rt) { |
+ set_register(rd_reg, rs); |
+ TraceRegWr(rs); |
+ } |
break; |
case MOVCI: { |
uint32_t cc = instr->FBccValue(); |
@@ -2315,16 +2636,21 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { |
break; |
} |
case MOVZ: |
- if (!rt) set_register(rd_reg, rs); |
+ if (!rt) { |
+ set_register(rd_reg, rs); |
+ TraceRegWr(rs); |
+ } |
break; |
default: // For other special opcodes we do the default operation. |
set_register(rd_reg, alu_out); |
+ TraceRegWr(alu_out); |
} |
break; |
case SPECIAL2: |
switch (instr->FunctionFieldRaw()) { |
case MUL: |
set_register(rd_reg, alu_out); |
+ TraceRegWr(alu_out); |
// HI and LO are UNPREDICTABLE after the operation. |
set_register(LO, Unpredictable); |
set_register(HI, Unpredictable); |
@@ -2338,10 +2664,12 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { |
case INS: |
// Ins instr leaves result in Rt, rather than Rd. |
set_register(rt_reg, alu_out); |
+ TraceRegWr(alu_out); |
break; |
case EXT: |
// Ext instr leaves result in Rt, rather than Rd. |
set_register(rt_reg, alu_out); |
+ TraceRegWr(alu_out); |
break; |
default: |
UNREACHABLE(); |
@@ -2352,6 +2680,7 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { |
// cases. |
default: |
set_register(rd_reg, alu_out); |
+ TraceRegWr(alu_out); |
} |
} |
@@ -2360,10 +2689,10 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { |
void Simulator::DecodeTypeImmediate(Instruction* instr) { |
// Instruction fields. |
Opcode op = instr->OpcodeFieldRaw(); |
- int32_t rs = get_register(instr->RsValue()); |
- uint32_t rs_u = static_cast<uint32_t>(rs); |
- int32_t rt_reg = instr->RtValue(); // Destination register. |
- int32_t rt = get_register(rt_reg); |
+ int64_t rs = get_register(instr->RsValue()); |
+ uint64_t rs_u = static_cast<uint64_t>(rs); |
+ int64_t rt_reg = instr->RtValue(); // Destination register. |
+ int64_t rt = get_register(rt_reg); |
int16_t imm16 = instr->Imm16Value(); |
int32_t ft_reg = instr->FtValue(); // Destination register. |
@@ -2374,24 +2703,26 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { |
int32_t se_imm16 = imm16; |
// Get current pc. |
- int32_t current_pc = get_pc(); |
+ int64_t current_pc = get_pc(); |
// Next pc. |
- int32_t next_pc = bad_ra; |
+ int64_t next_pc = bad_ra; |
// Used for conditional branch instructions. |
bool do_branch = false; |
bool execute_branch_delay_instruction = false; |
// Used for arithmetic instructions. |
- int32_t alu_out = 0; |
+ int64_t alu_out = 0; |
// Floating point. |
double fp_out = 0.0; |
uint32_t cc, cc_value, fcsr_cc; |
// Used for memory instructions. |
- int32_t addr = 0x0; |
+ int64_t addr = 0x0; |
// Value to be written in memory. |
- uint32_t mem_value = 0x0; |
+ uint64_t mem_value = 0x0; |
+ // Alignment for 32-bit integers used in LWL, LWR, etc. |
+ const int kInt32AlignmentMask = sizeof(uint32_t) - 1; |
// ---------- Configuration (and execution for REGIMM). |
switch (op) { |
@@ -2470,6 +2801,7 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { |
break; |
// ------------- Arithmetic instructions. |
case ADDI: |
+ case DADDI: |
if (HaveSameSign(rs, se_imm16)) { |
if (rs > 0) { |
exceptions[kIntegerOverflow] = rs > (Registers::kMaxValue - se_imm16); |
@@ -2480,7 +2812,13 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { |
} |
alu_out = rs + se_imm16; |
break; |
- case ADDIU: |
+ case ADDIU: { |
+ int32_t alu32_out = rs + se_imm16; |
+ // Sign-extend result of 32bit operation into 64bit register. |
+ alu_out = static_cast<int64_t>(alu32_out); |
+ } |
+ break; |
+ case DADDIU: |
alu_out = rs + se_imm16; |
break; |
case SLTI: |
@@ -2498,8 +2836,11 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { |
case XORI: |
alu_out = rs ^ oe_imm16; |
break; |
- case LUI: |
- alu_out = (oe_imm16 << 16); |
+ case LUI: { |
+ int32_t alu32_out = (oe_imm16 << 16); |
+ // Sign-extend result of 32bit operation into 64bit register. |
+ alu_out = static_cast<int64_t>(alu32_out); |
+ } |
break; |
// ------------- Memory instructions. |
case LB: |
@@ -2512,8 +2853,8 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { |
break; |
case LWL: { |
// al_offset is offset of the effective address within an aligned word. |
- uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask; |
- uint8_t byte_shift = kPointerAlignmentMask - al_offset; |
+ uint8_t al_offset = (rs + se_imm16) & kInt32AlignmentMask; |
+ uint8_t byte_shift = kInt32AlignmentMask - al_offset; |
uint32_t mask = (1 << byte_shift * 8) - 1; |
addr = rs + se_imm16 - al_offset; |
alu_out = ReadW(addr, instr); |
@@ -2525,6 +2866,14 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { |
addr = rs + se_imm16; |
alu_out = ReadW(addr, instr); |
break; |
+ case LWU: |
+ addr = rs + se_imm16; |
+ alu_out = ReadWU(addr, instr); |
+ break; |
+ case LD: |
+ addr = rs + se_imm16; |
+ alu_out = Read2W(addr, instr); |
+ break; |
case LBU: |
addr = rs + se_imm16; |
alu_out = ReadBU(addr); |
@@ -2535,8 +2884,8 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { |
break; |
case LWR: { |
// al_offset is offset of the effective address within an aligned word. |
- uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask; |
- uint8_t byte_shift = kPointerAlignmentMask - al_offset; |
+ uint8_t al_offset = (rs + se_imm16) & kInt32AlignmentMask; |
+ uint8_t byte_shift = kInt32AlignmentMask - al_offset; |
uint32_t mask = al_offset ? (~0 << (byte_shift + 1) * 8) : 0; |
addr = rs + se_imm16 - al_offset; |
alu_out = ReadW(addr, instr); |
@@ -2551,8 +2900,8 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { |
addr = rs + se_imm16; |
break; |
case SWL: { |
- uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask; |
- uint8_t byte_shift = kPointerAlignmentMask - al_offset; |
+ uint8_t al_offset = (rs + se_imm16) & kInt32AlignmentMask; |
+ uint8_t byte_shift = kInt32AlignmentMask - al_offset; |
uint32_t mask = byte_shift ? (~0 << (al_offset + 1) * 8) : 0; |
addr = rs + se_imm16 - al_offset; |
mem_value = ReadW(addr, instr) & mask; |
@@ -2560,10 +2909,11 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { |
break; |
} |
case SW: |
+ case SD: |
addr = rs + se_imm16; |
break; |
case SWR: { |
- uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask; |
+ uint8_t al_offset = (rs + se_imm16) & kInt32AlignmentMask; |
uint32_t mask = (1 << al_offset * 8) - 1; |
addr = rs + se_imm16 - al_offset; |
mem_value = ReadW(addr, instr); |
@@ -2610,7 +2960,9 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { |
break; |
// ------------- Arithmetic instructions. |
case ADDI: |
+ case DADDI: |
case ADDIU: |
+ case DADDIU: |
case SLTI: |
case SLTIU: |
case ANDI: |
@@ -2618,12 +2970,15 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { |
case XORI: |
case LUI: |
set_register(rt_reg, alu_out); |
+ TraceRegWr(alu_out); |
break; |
// ------------- Memory instructions. |
case LB: |
case LH: |
case LWL: |
case LW: |
+ case LWU: |
+ case LD: |
case LBU: |
case LHU: |
case LWR: |
@@ -2641,11 +2996,15 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { |
case SW: |
WriteW(addr, rt, instr); |
break; |
+ case SD: |
+ Write2W(addr, rt, instr); |
+ break; |
case SWR: |
WriteW(addr, mem_value, instr); |
break; |
case LWC1: |
- set_fpu_register(ft_reg, alu_out); |
+ set_fpu_register(ft_reg, kFPUInvalidResult); // Trash upper 32 bits. |
+ set_fpu_register_word(ft_reg, static_cast<int32_t>(alu_out)); |
break; |
case LDC1: |
set_fpu_register_double(ft_reg, fp_out); |
@@ -2711,14 +3070,15 @@ void Simulator::InstructionDecode(Instruction* instr) { |
CheckICache(isolate_->simulator_i_cache(), instr); |
} |
pc_modified_ = false; |
+ |
+ v8::internal::EmbeddedVector<char, 256> buffer; |
+ |
if (::v8::internal::FLAG_trace_sim) { |
+ SNPrintF(trace_buf_, " "); |
disasm::NameConverter converter; |
disasm::Disassembler dasm(converter); |
// Use a reasonably large buffer. |
- v8::internal::EmbeddedVector<char, 256> buffer; |
dasm.InstructionDecode(buffer, reinterpret_cast<byte*>(instr)); |
- PrintF(" 0x%08x %s\n", reinterpret_cast<intptr_t>(instr), |
- buffer.start()); |
} |
switch (instr->InstructionType()) { |
@@ -2734,8 +3094,14 @@ void Simulator::InstructionDecode(Instruction* instr) { |
default: |
UNSUPPORTED(); |
} |
+ |
+ if (::v8::internal::FLAG_trace_sim) { |
+ PrintF(" 0x%08lx %-44s %s\n", reinterpret_cast<intptr_t>(instr), |
+ buffer.start(), trace_buf_.start()); |
+ } |
+ |
if (!pc_modified_) { |
- set_register(pc, reinterpret_cast<int32_t>(instr) + |
+ set_register(pc, reinterpret_cast<int64_t>(instr) + |
Instruction::kInstrSize); |
} |
} |
@@ -2745,7 +3111,7 @@ void Simulator::InstructionDecode(Instruction* instr) { |
void Simulator::Execute() { |
// Get the PC to simulate. Cannot use the accessor here as we need the |
// raw PC value and not the one used as input to arithmetic instructions. |
- int program_counter = get_pc(); |
+ int64_t program_counter = get_pc(); |
if (::v8::internal::FLAG_stop_sim_at == 0) { |
// Fast version of the dispatch loop without checking whether the simulator |
// should be stopping at a particular executed instruction. |
@@ -2761,7 +3127,7 @@ void Simulator::Execute() { |
while (program_counter != end_sim_pc) { |
Instruction* instr = reinterpret_cast<Instruction*>(program_counter); |
icount_++; |
- if (icount_ == ::v8::internal::FLAG_stop_sim_at) { |
+ if (icount_ == static_cast<int64_t>(::v8::internal::FLAG_stop_sim_at)) { |
MipsDebugger dbg(this); |
dbg.Debug(); |
} else { |
@@ -2775,7 +3141,7 @@ void Simulator::Execute() { |
void Simulator::CallInternal(byte* entry) { |
// Prepare to execute the code at entry. |
- set_register(pc, reinterpret_cast<int32_t>(entry)); |
+ set_register(pc, reinterpret_cast<int64_t>(entry)); |
// Put down marker for end of simulation. The simulator will stop simulation |
// when the PC reaches this value. By saving the "end simulation" value into |
// the LR the simulation stops when returning to this call point. |
@@ -2784,21 +3150,21 @@ void Simulator::CallInternal(byte* entry) { |
// Remember the values of callee-saved registers. |
// The code below assumes that r9 is not used as sb (static base) in |
// simulator code and therefore is regarded as a callee-saved register. |
- int32_t s0_val = get_register(s0); |
- int32_t s1_val = get_register(s1); |
- int32_t s2_val = get_register(s2); |
- int32_t s3_val = get_register(s3); |
- int32_t s4_val = get_register(s4); |
- int32_t s5_val = get_register(s5); |
- int32_t s6_val = get_register(s6); |
- int32_t s7_val = get_register(s7); |
- int32_t gp_val = get_register(gp); |
- int32_t sp_val = get_register(sp); |
- int32_t fp_val = get_register(fp); |
+ int64_t s0_val = get_register(s0); |
+ int64_t s1_val = get_register(s1); |
+ int64_t s2_val = get_register(s2); |
+ int64_t s3_val = get_register(s3); |
+ int64_t s4_val = get_register(s4); |
+ int64_t s5_val = get_register(s5); |
+ int64_t s6_val = get_register(s6); |
+ int64_t s7_val = get_register(s7); |
+ int64_t gp_val = get_register(gp); |
+ int64_t sp_val = get_register(sp); |
+ int64_t fp_val = get_register(fp); |
// Set up the callee-saved registers with a known value. To be able to check |
// that they are preserved properly across JS execution. |
- int32_t callee_saved_value = icount_; |
+ int64_t callee_saved_value = icount_; |
set_register(s0, callee_saved_value); |
set_register(s1, callee_saved_value); |
set_register(s2, callee_saved_value); |
@@ -2840,30 +3206,44 @@ void Simulator::CallInternal(byte* entry) { |
} |
-int32_t Simulator::Call(byte* entry, int argument_count, ...) { |
+int64_t Simulator::Call(byte* entry, int argument_count, ...) { |
+ const int kRegisterPassedArguments = (kMipsAbi == kN64) ? 8 : 4; |
va_list parameters; |
va_start(parameters, argument_count); |
// Set up arguments. |
- // First four arguments passed in registers. |
+ // First four arguments passed in registers in both ABI's. |
ASSERT(argument_count >= 4); |
- set_register(a0, va_arg(parameters, int32_t)); |
- set_register(a1, va_arg(parameters, int32_t)); |
- set_register(a2, va_arg(parameters, int32_t)); |
- set_register(a3, va_arg(parameters, int32_t)); |
+ set_register(a0, va_arg(parameters, int64_t)); |
+ set_register(a1, va_arg(parameters, int64_t)); |
+ set_register(a2, va_arg(parameters, int64_t)); |
+ set_register(a3, va_arg(parameters, int64_t)); |
+ |
+ if (kMipsAbi == kN64) { |
+ // Up to eight arguments passed in registers in N64 ABI. |
+ // TODO(plind): N64 ABI calls these regs a4 - a7. Clarify this. |
+ if (argument_count >= 5) set_register(a4, va_arg(parameters, int64_t)); |
+ if (argument_count >= 6) set_register(a5, va_arg(parameters, int64_t)); |
+ if (argument_count >= 7) set_register(a6, va_arg(parameters, int64_t)); |
+ if (argument_count >= 8) set_register(a7, va_arg(parameters, int64_t)); |
+ } |
// Remaining arguments passed on stack. |
- int original_stack = get_register(sp); |
+ int64_t original_stack = get_register(sp); |
// Compute position of stack on entry to generated code. |
- int entry_stack = (original_stack - (argument_count - 4) * sizeof(int32_t) |
- - kCArgsSlotsSize); |
+ int stack_args_count = (argument_count > kRegisterPassedArguments) ? |
+ (argument_count - kRegisterPassedArguments) : 0; |
+ int stack_args_size = stack_args_count * sizeof(int64_t) + kCArgsSlotsSize; |
+ int64_t entry_stack = original_stack - stack_args_size; |
+ |
if (base::OS::ActivationFrameAlignment() != 0) { |
entry_stack &= -base::OS::ActivationFrameAlignment(); |
} |
// Store remaining arguments on stack, from low to high memory. |
intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack); |
- for (int i = 4; i < argument_count; i++) { |
- stack_argument[i - 4 + kCArgSlotCount] = va_arg(parameters, int32_t); |
+ for (int i = kRegisterPassedArguments; i < argument_count; i++) { |
+ int stack_index = i - kRegisterPassedArguments + kCArgSlotCount; |
+ stack_argument[stack_index] = va_arg(parameters, int64_t); |
} |
va_end(parameters); |
set_register(sp, entry_stack); |
@@ -2874,15 +3254,16 @@ int32_t Simulator::Call(byte* entry, int argument_count, ...) { |
CHECK_EQ(entry_stack, get_register(sp)); |
set_register(sp, original_stack); |
- int32_t result = get_register(v0); |
+ int64_t result = get_register(v0); |
return result; |
} |
double Simulator::CallFP(byte* entry, double d0, double d1) { |
if (!IsMipsSoftFloatABI) { |
+ const FPURegister fparg2 = (kMipsAbi == kN64) ? f13 : f14; |
set_fpu_register_double(f12, d0); |
- set_fpu_register_double(f14, d1); |
+ set_fpu_register_double(fparg2, d1); |
} else { |
int buffer[2]; |
ASSERT(sizeof(buffer[0]) * 2 == sizeof(d0)); |
@@ -2901,7 +3282,7 @@ double Simulator::CallFP(byte* entry, double d0, double d1) { |
uintptr_t Simulator::PushAddress(uintptr_t address) { |
- int new_sp = get_register(sp) - sizeof(uintptr_t); |
+ int64_t new_sp = get_register(sp) - sizeof(uintptr_t); |
uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp); |
*stack_slot = address; |
set_register(sp, new_sp); |
@@ -2910,7 +3291,7 @@ uintptr_t Simulator::PushAddress(uintptr_t address) { |
uintptr_t Simulator::PopAddress() { |
- int current_sp = get_register(sp); |
+ int64_t current_sp = get_register(sp); |
uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp); |
uintptr_t address = *stack_slot; |
set_register(sp, current_sp + sizeof(uintptr_t)); |
@@ -2924,4 +3305,4 @@ uintptr_t Simulator::PopAddress() { |
#endif // USE_SIMULATOR |
-#endif // V8_TARGET_ARCH_MIPS |
+#endif // V8_TARGET_ARCH_MIPS64 |