Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(541)

Unified Diff: src/mips/simulator-mips.cc

Issue 1320006: Updates and fixes for MIPS support. (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 10 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/mips/simulator-mips.cc
===================================================================
--- src/mips/simulator-mips.cc (revision 4259)
+++ src/mips/simulator-mips.cc (working copy)
@@ -51,7 +51,7 @@
// Utils functions
bool HaveSameSign(int32_t a, int32_t b) {
- return ((a ^ b) > 0);
+ return ((a ^ b) >= 0);
}
@@ -284,9 +284,11 @@
"%" XSTR(ARG_SIZE) "s",
cmd, arg1, arg2);
if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
- if (!(reinterpret_cast<Instruction*>(sim_->get_pc())->IsTrap())) {
+ Instruction* instr = reinterpret_cast<Instruction*>(sim_->get_pc());
+ if (!(instr->IsTrap()) ||
+ instr->InstructionBits() == rtCallRedirInstr) {
sim_->InstructionDecode(
- reinterpret_cast<Instruction*>(sim_->get_pc()));
+ reinterpret_cast<Instruction*>(sim_->get_pc()));
} else {
// Allow si to jump over generated breakpoints.
PrintF("/!\\ Jumping over generated breakpoint.\n");
@@ -500,6 +502,10 @@
for (int i = 0; i < kNumSimuRegisters; i++) {
registers_[i] = 0;
}
+ for (int i = 0; i < kNumFPURegisters; i++) {
+ FPUregisters_[i] = 0;
+ }
+ FPUccr_ = 0;
// 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
@@ -629,6 +635,22 @@
const_cast<int32_t*>(&FPUregisters_[fpureg]));
}
+// Helper functions for setting and testing the FPU condition code bits.
+void Simulator::set_fpu_ccr_bit(uint32_t cc, bool value) {
+ ASSERT(is_uint3(cc));
+ if (value) {
+ FPUccr_ |= (1 << cc);
+ } else {
+ FPUccr_ &= ~(1 << cc);
+ }
+}
+
+bool Simulator::test_fpu_ccr_bit(uint32_t cc) {
+ ASSERT(is_uint3(cc));
+ return FPUccr_ & (1 << cc);
+}
+
+
// Raw access to the PC register.
void Simulator::set_pc(int32_t value) {
pc_modified_ = true;
@@ -676,7 +698,7 @@
double* ptr = reinterpret_cast<double*>(addr);
return *ptr;
}
- PrintF("Unaligned read at 0x%08x, pc=%p\n", addr, instr);
+ PrintF("Unaligned (double) read at 0x%08x, pc=%p\n", addr, instr);
OS::Abort();
return 0;
}
@@ -688,7 +710,7 @@
*ptr = value;
return;
}
- PrintF("Unaligned write at 0x%08x, pc=%p\n", addr, instr);
+ PrintF("Unaligned (double) write at 0x%08x, pc=%p\n", addr, instr);
OS::Abort();
}
@@ -745,7 +767,7 @@
int32_t Simulator::ReadB(int32_t addr) {
int8_t* ptr = reinterpret_cast<int8_t*>(addr);
- return ((*ptr << 24) >> 24) & 0xff;
+ return *ptr;
}
@@ -781,16 +803,17 @@
// Note: To be able to return two values from some calls the code in runtime.cc
// uses the ObjectPair which is essentially two 32-bit values stuffed into a
// 64-bit value. With the code below we assume that all runtime calls return
-// 64 bits of result. If they don't, the r1 result register contains a bogus
+// 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);
-typedef double (*SimulatorRuntimeFPCall)(double fparg0,
- double fparg1);
+typedef double (*SimulatorRuntimeFPCall)(int32_t arg0,
+ int32_t arg1,
+ int32_t arg2,
+ int32_t arg3);
-
// Software interrupt instructions are used by the simulator to call into the
// C-based V8 runtime.
void Simulator::SoftwareInterrupt(Instruction* instr) {
@@ -801,47 +824,54 @@
int32_t arg1 = get_register(a1);
int32_t arg2 = get_register(a2);
int32_t arg3 = get_register(a3);
- // fp args are (not always) in f12 and f14.
- // See MIPS conventions for more details.
- double fparg0 = get_fpu_register_double(f12);
- double fparg1 = get_fpu_register_double(f14);
+ int32_t result_l, result_h;
// 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);
+
+ intptr_t external =
+ reinterpret_cast<int32_t>(redirection->external_function());
+ SimulatorRuntimeCall target =
+ reinterpret_cast<SimulatorRuntimeCall>(external);
+
+ if (::v8::internal::FLAG_trace_sim) {
+ PrintF(
+ "Call to host function at %p with args %08x, %08x, %08x, %08x\n",
+ FUNCTION_ADDR(target),
+ arg0,
+ arg1,
+ arg2,
+ arg3);
+ }
+
+ // Based on CpuFeatures::IsSupported(FPU), Mips will use either hardware
+ // FPU, or gcc soft-float routines. Hardware FPU is simulated in this
+ // simulator. Soft-float has additional abstraction of ExternalReference,
+ // to support serialization. Finally, when simulated on x86 host, the
+ // x86 softfloat routines are used, and this Redirection infrastructure
+ // lets simulated-mips make calls into x86 C code.
+ // When doing that, the 'double' return type must be handled differently
+ // than the usual int64_t return. The data is returned in different
+ // registers and cannot be cast from one type to the other. However, the
+ // calling arguments are passed the same way in both cases.
if (redirection->fp_return()) {
- intptr_t external =
- reinterpret_cast<intptr_t>(redirection->external_function());
SimulatorRuntimeFPCall target =
reinterpret_cast<SimulatorRuntimeFPCall>(external);
- if (::v8::internal::FLAG_trace_sim) {
- PrintF("Call to host function at %p with args %f, %f\n",
- FUNCTION_ADDR(target), fparg0, fparg1);
- }
- double result = target(fparg0, fparg1);
- set_fpu_register_double(f0, result);
+ double result = target(arg0, arg1, arg2, arg3);
+ uint64_t u64;
+ u64 = *v8i::BitCast<uint64_t*, double*>(const_cast<double*>(&result));
+ result_h = static_cast<uint32_t>(u64 >> 32);
+ result_l = static_cast<uint32_t>(u64 & 0xffffffff);
} else {
- intptr_t external =
- reinterpret_cast<int32_t>(redirection->external_function());
- SimulatorRuntimeCall target =
- reinterpret_cast<SimulatorRuntimeCall>(external);
- if (::v8::internal::FLAG_trace_sim) {
- PrintF(
- "Call to host function at %p with args %08x, %08x, %08x, %08x\n",
- FUNCTION_ADDR(target),
- arg0,
- arg1,
- arg2,
- arg3);
- }
int64_t result = target(arg0, arg1, arg2, arg3);
- int32_t lo_res = static_cast<int32_t>(result);
- int32_t hi_res = static_cast<int32_t>(result >> 32);
- if (::v8::internal::FLAG_trace_sim) {
- PrintF("Returned %08x\n", lo_res);
- }
- set_register(v0, lo_res);
- set_register(v1, hi_res);
+ result_l = static_cast<int32_t>(result);
+ result_h = static_cast<int32_t>(result >> 32);
}
+ set_register(v0, result_l);
+ set_register(v1, result_h);
+ if (::v8::internal::FLAG_trace_sim) {
+ PrintF("Returned %08x : %08x\n", result_h, result_l);
+ }
set_register(ra, saved_ra);
set_pc(get_register(ra));
} else {
@@ -860,7 +890,7 @@
// Handle execution based on instruction types.
void Simulator::DecodeTypeRegister(Instruction* instr) {
- // Instruction fields
+ // Instruction fields.
Opcode op = instr->OpcodeFieldRaw();
int32_t rs_reg = instr->RsField();
int32_t rs = get_register(rs_reg);
@@ -871,14 +901,16 @@
int32_t rd_reg = instr->RdField();
uint32_t sa = instr->SaField();
- int32_t fs_reg= instr->FsField();
+ int32_t fs_reg = instr->FsField();
+ int32_t ft_reg = instr->FtField();
+ int32_t fd_reg = instr->FdField();
+ 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.
+ // It should not be used as is. Instructions using it should always
+ // initialize it first.
int32_t alu_out = 0x12345678;
- // Output or temporary for floating point.
- double fp_out = 0.0;
// For break and trap instructions.
bool do_interrupt = false;
@@ -893,15 +925,14 @@
switch (op) {
case COP1: // Coprocessor instructions
switch (instr->RsFieldRaw()) {
- case BC1: // branch on coprocessor condition
+ case BC1: // Handled in DecodeTypeImmed, should never come here.
UNREACHABLE();
break;
case MFC1:
alu_out = get_fpu_register(fs_reg);
break;
case MFHC1:
- fp_out = get_fpu_register_double(fs_reg);
- alu_out = *v8i::BitCast<int32_t*, double*>(&fp_out);
+ UNIMPLEMENTED_MIPS();
break;
case MTC1:
case MTHC1:
@@ -949,10 +980,10 @@
alu_out = get_register(LO);
break;
case MULT:
- UNIMPLEMENTED_MIPS();
+ i64hilo = static_cast<int64_t>(rs) * static_cast<int64_t>(rt);
break;
case MULTU:
- UNIMPLEMENTED_MIPS();
+ u64hilo = static_cast<uint64_t>(rs_u) * static_cast<uint64_t>(rt_u);
break;
case DIV:
case DIVU:
@@ -1024,6 +1055,10 @@
case TNE:
do_interrupt = rs != rt;
break;
+ case MOVN:
+ case MOVZ:
+ // No action taken on decode.
+ break;
default:
UNREACHABLE();
};
@@ -1033,10 +1068,39 @@
case MUL:
alu_out = rs_u * rt_u; // Only the lower 32 bits are kept.
break;
+ case CLZ:
+ alu_out = __builtin_clz(rs_u);
+ break;
default:
UNREACHABLE();
- }
+ };
break;
+ case SPECIAL3:
+ switch (instr->FunctionFieldRaw()) {
+ case INS: { // mips32r2 instruction.
+ // Interpret Rd field as 5-bit msb of insert.
+ uint16_t msb = rd_reg;
+ // Interpret sa field as 5-bit lsb of insert.
+ uint16_t lsb = sa;
+ uint16_t size = msb - lsb + 1;
+ uint16_t mask = (1 << size) - 1;
+ alu_out = (rt_u & ~(mask << lsb)) | ((rs_u & mask) << lsb);
+ }
+ break;
+ case EXT: { // mips32r2 instruction.
+ // Interpret Rd field as 5-bit msb of extract.
+ uint16_t msb = rd_reg;
+ // Interpret sa field as 5-bit lsb of extract.
+ uint16_t lsb = sa;
+ uint16_t size = msb - lsb + 1;
+ uint16_t mask = (1 << size) - 1;
+ alu_out = (rs_u & (mask << lsb)) >> lsb;
+ }
+ break;
+ default:
+ UNREACHABLE();
+ };
+ break;
default:
UNREACHABLE();
};
@@ -1052,18 +1116,16 @@
UNREACHABLE();
break;
case MFC1:
- case MFHC1:
set_register(rt_reg, alu_out);
break;
+ case MFHC1:
+ UNIMPLEMENTED_MIPS();
+ break;
case MTC1:
- // We don't need to set the higher bits to 0, because MIPS ISA says
- // they are in an unpredictable state after executing MTC1.
FPUregisters_[fs_reg] = registers_[rt_reg];
- FPUregisters_[fs_reg+1] = Unpredictable;
break;
case MTHC1:
- // Here we need to keep the lower bits unchanged.
- FPUregisters_[fs_reg+1] = registers_[rt_reg];
+ UNIMPLEMENTED_MIPS();
break;
case S:
switch (instr->FunctionFieldRaw()) {
@@ -1078,9 +1140,59 @@
}
break;
case D:
+ double ft, fs;
+ uint32_t cc;
+ fs = get_fpu_register_double(fs_reg);
+ ft = get_fpu_register_double(ft_reg);
+ cc = instr->FCccField();
switch (instr->FunctionFieldRaw()) {
+ case ADD_D:
+ set_fpu_register_double(fd_reg, fs + ft);
+ break;
+ case SUB_D:
+ set_fpu_register_double(fd_reg, fs - ft);
+ break;
+ case MUL_D:
+ set_fpu_register_double(fd_reg, fs * ft);
+ break;
+ case DIV_D:
+ set_fpu_register_double(fd_reg, fs / ft);
+ break;
+ case ABS_D:
+ set_fpu_register_double(fd_reg, fs < 0 ? -fs : fs);
+ break;
+ case MOV_D:
+ set_fpu_register_double(fd_reg, fs);
+ break;
+ case NEG_D:
+ set_fpu_register_double(fd_reg, -fs);
+ break;
+ case CVT_W_D: // Convert double to word
+ set_fpu_register(fd_reg, static_cast<int32_t>(fs));
+ break;
+ case C_UN_D:
+ set_fpu_ccr_bit(cc, isnan(fs) || isnan(ft));
+ break;
+ case C_EQ_D:
+ set_fpu_ccr_bit(cc, (fs == ft));
+ break;
+ case C_UEQ_D:
+ set_fpu_ccr_bit(cc, (fs == ft) || (isnan(fs) || isnan(ft)));
+ break;
+ case C_OLT_D:
+ set_fpu_ccr_bit(cc, (fs < ft));
+ break;
+ case C_ULT_D:
+ set_fpu_ccr_bit(cc, (fs < ft) || (isnan(fs) || isnan(ft)));
+ break;
+ case C_OLE_D:
+ set_fpu_ccr_bit(cc, (fs <= ft));
+ break;
+ case C_ULE_D:
+ set_fpu_ccr_bit(cc, (fs <= ft) || (isnan(fs) || isnan(ft)));
+ break;
+ case C_F_D:
case CVT_S_D:
- case CVT_W_D:
case CVT_L_D:
UNIMPLEMENTED_MIPS();
break;
@@ -1094,7 +1206,8 @@
UNIMPLEMENTED_MIPS();
break;
case CVT_D_W: // Convert word to double.
- set_fpu_register(rd_reg, static_cast<double>(rs));
+ alu_out = get_fpu_register(fs_reg);
+ set_fpu_register_double(fd_reg, static_cast<double>(alu_out));
break;
default:
UNREACHABLE();
@@ -1137,7 +1250,12 @@
}
// Instructions using HI and LO registers.
case MULT:
+ set_register(LO, static_cast<int32_t>(i64hilo & 0xffffffff));
+ set_register(HI, static_cast<int32_t>(i64hilo >> 32));
+ break;
case MULTU:
+ set_register(LO, static_cast<int32_t>(u64hilo & 0xffffffff));
+ set_register(HI, static_cast<int32_t>(u64hilo >> 32));
break;
case DIV:
// Divide by zero was checked in the configuration step.
@@ -1148,7 +1266,7 @@
set_register(LO, rs_u / rt_u);
set_register(HI, rs_u % rt_u);
break;
- // Break and trap instructions
+ // Break and trap instructions.
case BREAK:
case TGE:
case TGEU:
@@ -1160,6 +1278,13 @@
SoftwareInterrupt(instr);
}
break;
+ // Conditional moves.
+ case MOVN:
+ if (rt) set_register(rd_reg, rs);
+ break;
+ case MOVZ:
+ if (!rt) set_register(rd_reg, rs);
+ break;
default: // For other special opcodes we do the default operation.
set_register(rd_reg, alu_out);
};
@@ -1172,9 +1297,23 @@
set_register(LO, Unpredictable);
set_register(HI, Unpredictable);
break;
+ default: // For other special2 opcodes we do the default operation.
+ set_register(rd_reg, alu_out);
+ }
+ break;
+ case SPECIAL3:
+ switch (instr->FunctionFieldRaw()) {
+ case INS:
+ // Ins instr leaves result in Rt, rather than Rd.
+ set_register(rt_reg, alu_out);
+ break;
+ case EXT:
+ // Ext instr leaves result in Rt, rather than Rd.
+ set_register(rt_reg, alu_out);
+ break;
default:
UNREACHABLE();
- }
+ };
break;
// Unimplemented opcodes raised an error in the configuration step before,
// so we can use the default here to set the destination register in common
@@ -1186,7 +1325,7 @@
// Type 2: instructions using a 16 bytes immediate. (eg: addi, beq)
void Simulator::DecodeTypeImmediate(Instruction* instr) {
- // Instruction fields
+ // Instruction fields.
Opcode op = instr->OpcodeFieldRaw();
int32_t rs = get_register(instr->RsField());
uint32_t rs_u = static_cast<uint32_t>(rs);
@@ -1195,11 +1334,10 @@
int16_t imm16 = instr->Imm16Field();
int32_t ft_reg = instr->FtField(); // destination register
- int32_t ft = get_register(ft_reg);
- // zero extended immediate
+ // Zero extended immediate.
uint32_t oe_imm16 = 0xffff & imm16;
- // sign extended immediate
+ // Sign extended immediate.
int32_t se_imm16 = imm16;
// Get current pc.
@@ -1207,25 +1345,35 @@
// Next pc.
int32_t next_pc = bad_ra;
- // Used for conditional branch instructions
+ // Used for conditional branch instructions.
bool do_branch = false;
bool execute_branch_delay_instruction = false;
- // Used for arithmetic instructions
+ // Used for arithmetic instructions.
int32_t alu_out = 0;
- // Floating point
+ // Floating point.
double fp_out = 0.0;
+ uint32_t cc, cc_value;
- // Used for memory instructions
+ // Used for memory instructions.
int32_t addr = 0x0;
// ---------- Configuration (and execution for REGIMM)
switch (op) {
- // ------------- COP1. Coprocessor instructions
+ // ------------- COP1. Coprocessor instructions.
case COP1:
switch (instr->RsFieldRaw()) {
- case BC1: // branch on coprocessor condition
- UNIMPLEMENTED_MIPS();
+ case BC1: // Branch on coprocessor condition.
+ cc = instr->FBccField();
+ cc_value = test_fpu_ccr_bit(cc);
+ do_branch = (instr->FBtrueField()) ? cc_value : !cc_value;
+ execute_branch_delay_instruction = true;
+ // Set next_pc
+ if (do_branch) {
+ next_pc = current_pc + (imm16 << 2) + Instruction::kInstructionSize;
+ } else {
+ next_pc = current_pc + kBranchReturnOffset;
+ }
break;
default:
UNREACHABLE();
@@ -1322,6 +1470,10 @@
addr = rs + se_imm16;
alu_out = ReadB(addr);
break;
+ case LH:
+ addr = rs + se_imm16;
+ alu_out = ReadH(addr, instr);
+ break;
case LW:
addr = rs + se_imm16;
alu_out = ReadW(addr, instr);
@@ -1330,9 +1482,16 @@
addr = rs + se_imm16;
alu_out = ReadBU(addr);
break;
+ case LHU:
+ addr = rs + se_imm16;
+ alu_out = ReadHU(addr, instr);
+ break;
case SB:
addr = rs + se_imm16;
break;
+ case SH:
+ addr = rs + se_imm16;
+ break;
case SW:
addr = rs + se_imm16;
break;
@@ -1387,13 +1546,18 @@
break;
// ------------- Memory instructions
case LB:
+ case LH:
case LW:
case LBU:
+ case LHU:
set_register(rt_reg, alu_out);
break;
case SB:
WriteB(addr, static_cast<int8_t>(rt));
break;
+ case SH:
+ WriteH(addr, static_cast<uint16_t>(rt), instr);
+ break;
case SW:
WriteW(addr, rt, instr);
break;
@@ -1409,7 +1573,7 @@
break;
case SDC1:
addr = rs + se_imm16;
- WriteD(addr, ft, instr);
+ WriteD(addr, get_fpu_register_double(ft_reg), instr);
break;
default:
break;
@@ -1537,7 +1701,7 @@
int 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)
- - kArgsSlotsSize);
+ - kCArgsSlotsSize);
if (OS::ActivationFrameAlignment() != 0) {
entry_stack &= -OS::ActivationFrameAlignment();
}

Powered by Google App Engine
This is Rietveld 408576698