Index: runtime/vm/simulator_mips.cc |
=================================================================== |
--- runtime/vm/simulator_mips.cc (revision 19556) |
+++ runtime/vm/simulator_mips.cc (working copy) |
@@ -16,6 +16,12 @@ |
namespace dart { |
+DEFINE_FLAG(int, stop_sim_at, 0, "Address to stop simulator at."); |
+ |
+void Simulator::InitOnce() { |
+} |
+ |
+ |
Simulator::Simulator() { |
// Setup simulator support first. Some of this information is needed to |
// setup the architecture state. |
@@ -26,6 +32,18 @@ |
stack_ = new char[(Isolate::GetSpecifiedStackSize() + |
Isolate::kStackSizeBuffer + |
kSimulatorStackUnderflowSize)]; |
+ icount_ = 0; |
+ delay_slot_ = false; |
+ |
+ // Setup architecture state. |
+ // All registers are initialized to zero to start with. |
+ for (int i = 0; i < kNumberOfCpuRegisters; i++) { |
+ registers_[i] = 0; |
+ } |
+ pc_ = 0; |
+ // The sp is initialized to point to the bottom (high address) of the |
+ // allocated stack area. |
+ registers_[SP] = StackTop(); |
} |
@@ -51,15 +69,19 @@ |
// 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(Register reg, int32_t value) { |
- UNIMPLEMENTED(); |
+ if (reg != R0) { |
+ registers_[reg] = 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(Register reg) const { |
- UNIMPLEMENTED(); |
- return 0; |
+ if (reg == R0) { |
+ return 0; |
+ } |
+ return registers_[reg]; |
} |
@@ -73,18 +95,182 @@ |
} |
-void Simulator::InitOnce() { |
+void Simulator::Format(Instr* instr, const char* format) { |
+ OS::PrintErr("Simulator - unknown instruction: %s\n", format); |
+ UNIMPLEMENTED(); |
} |
+void Simulator::DecodeSpecial(Instr* instr) { |
+ switch (instr->FunctionField()) { |
+ case SLL: { |
+ if ((instr->RdField() == R0) && |
+ (instr->RtField() == R0) && |
+ (instr->SaField() == 0)) { |
+ // Format(instr, "nop"); |
+ // Nothing to be done for NOP. |
+ } else { |
+ Format(instr, "sll 'rd, 'rt, 'sa"); |
+ } |
+ break; |
+ } |
+ case JR: { |
+ ASSERT(instr->RtField() == R0); |
+ ASSERT(instr->RdField() == R0); |
+ ASSERT(!delay_slot_); |
+ // Format(instr, "jr'hint 'rs"); |
+ uword next_pc = get_register(instr->RsField()); |
+ ExecuteDelaySlot(); |
+ pc_ = next_pc - Instr::kInstrSize; // Account for regular PC increment. |
+ break; |
+ } |
+ default: { |
+ OS::PrintErr("DecodeSpecial: 0x%x\n", instr->InstructionBits()); |
+ UNREACHABLE(); |
+ break; |
+ } |
+ } |
+} |
+ |
+void Simulator::InstructionDecode(Instr* instr) { |
+ switch (instr->OpcodeField()) { |
+ case SPECIAL: { |
+ DecodeSpecial(instr); |
+ break; |
+ } |
+ case ORI: { |
+ // Format(instr, "ori 'rt, 'rs, 'imm"); |
+ int32_t rs_val = get_register(instr->RsField()); |
+ set_register(instr->RtField(), rs_val | instr->ImmField()); |
regis
2013/03/06 21:18:42
The immediate field should be zero extended, i.e.
Ivan Posva
2013/03/07 11:03:22
The result of ImmField() is already unsigned.
|
+ break; |
+ } |
+ default: { |
+ OS::PrintErr("Undecoded instruction: 0x%x\n", instr->InstructionBits()); |
+ UNREACHABLE(); |
+ break; |
+ } |
+ } |
+ pc_ += Instr::kInstrSize; |
+} |
+ |
+ |
+void Simulator::ExecuteDelaySlot() { |
+ ASSERT(pc_ != kEndSimulatingPC); |
+ delay_slot_ = true; |
+ icount_++; |
+ if (icount_ == FLAG_stop_sim_at) { |
+ UNIMPLEMENTED(); |
+ } |
+ Instr* instr = Instr::At(pc_ + Instr::kInstrSize); |
+ InstructionDecode(instr); |
+ delay_slot_ = false; |
+} |
+ |
+ |
+void Simulator::Execute() { |
+ if (FLAG_stop_sim_at == 0) { |
+ // Fast version of the dispatch loop without checking whether the simulator |
+ // should be stopping at a particular executed instruction. |
+ while (pc_ != kEndSimulatingPC) { |
+ icount_++; |
+ Instr* instr = Instr::At(pc_); |
+ InstructionDecode(instr); |
+ } |
+ } else { |
+ // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when |
+ // we reach the particular instruction count. |
+ while (pc_ != kEndSimulatingPC) { |
+ icount_++; |
+ if (icount_ == FLAG_stop_sim_at) { |
+ UNIMPLEMENTED(); |
+ } else { |
+ Instr* instr = Instr::At(pc_); |
+ InstructionDecode(instr); |
+ } |
+ } |
+ } |
+} |
+ |
+ |
int64_t Simulator::Call(int32_t entry, |
int32_t parameter0, |
int32_t parameter1, |
int32_t parameter2, |
- int32_t parameter3, |
- int32_t parameter4) { |
- UNIMPLEMENTED(); |
- return 0LL; |
+ int32_t parameter3) { |
+ // Save the SP register before the call so we can restore it. |
+ int32_t sp_before_call = get_register(SP); |
+ |
+ // Setup parameters. |
+ set_register(A0, parameter0); |
+ set_register(A1, parameter1); |
+ set_register(A2, parameter2); |
+ set_register(A3, parameter3); |
+ |
+ // Make sure the activation frames are properly aligned. |
+ int32_t stack_pointer = sp_before_call; |
+ static const int kFrameAlignment = OS::ActivationFrameAlignment(); |
+ if (kFrameAlignment > 0) { |
+ stack_pointer = Utils::RoundDown(stack_pointer, kFrameAlignment); |
+ } |
+ set_register(SP, stack_pointer); |
+ |
+ // Prepare to execute the code at entry. |
+ set_pc(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 |
+ // RA the simulation stops when returning to this call point. |
+ set_register(RA, kEndSimulatingPC); |
+ |
+ // 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 r16_val = get_register(R16); |
+ int32_t r17_val = get_register(R17); |
+ int32_t r18_val = get_register(R18); |
+ int32_t r19_val = get_register(R19); |
+ int32_t r20_val = get_register(R20); |
+ int32_t r21_val = get_register(R21); |
+ int32_t r22_val = get_register(R22); |
+ int32_t r23_val = get_register(R23); |
+ |
+ // Setup the callee-saved registers with a known value. To be able to check |
+ // that they are preserved properly across dart execution. |
+ int32_t callee_saved_value = icount_; |
+ set_register(R16, callee_saved_value); |
+ set_register(R17, callee_saved_value); |
+ set_register(R18, callee_saved_value); |
+ set_register(R19, callee_saved_value); |
+ set_register(R20, callee_saved_value); |
+ set_register(R21, callee_saved_value); |
+ set_register(R22, callee_saved_value); |
+ set_register(R23, callee_saved_value); |
+ |
+ // Start the simulation |
+ Execute(); |
+ |
+ // Check that the callee-saved registers have been preserved. |
+ ASSERT(callee_saved_value == get_register(R16)); |
+ ASSERT(callee_saved_value == get_register(R17)); |
+ ASSERT(callee_saved_value == get_register(R18)); |
+ ASSERT(callee_saved_value == get_register(R19)); |
+ ASSERT(callee_saved_value == get_register(R20)); |
+ ASSERT(callee_saved_value == get_register(R21)); |
+ ASSERT(callee_saved_value == get_register(R22)); |
+ ASSERT(callee_saved_value == get_register(R23)); |
+ |
+ // Restore callee-saved registers with the original value. |
+ set_register(R16, r16_val); |
+ set_register(R17, r17_val); |
+ set_register(R18, r18_val); |
+ set_register(R19, r19_val); |
+ set_register(R20, r20_val); |
+ set_register(R21, r21_val); |
+ set_register(R22, r22_val); |
+ set_register(R23, r23_val); |
+ |
+ // Restore the SP register and return R1:R0. |
+ set_register(SP, sp_before_call); |
+ return Utils::LowHighTo64Bits(get_register(V0), get_register(V1)); |
} |
} // namespace dart |