| 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
|
|
|