1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
6 // Declares a Simulator for MIPS instructions if we are not generating a native
7 // MIPS binary. This Simulator allows us to run and debug MIPS code generation
8 // on regular desktop machines.
9 // V8 calls into generated code by "calling" the CALL_GENERATED_CODE macro,
10 // which will start execution in the Simulator or forwards to the real entry
11 // on a MIPS HW platform.
13 #ifndef V8_MIPS_SIMULATOR_MIPS_H_
14 #define V8_MIPS_SIMULATOR_MIPS_H_
16 #include "src/allocation.h"
17 #include "src/mips/constants-mips.h"
19 #if !defined(USE_SIMULATOR)
20 // Running without a simulator on a native mips platform.
25 // When running without a simulator we call the entry directly.
26 #define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
27 entry(p0, p1, p2, p3, p4)
29 typedef int (*mips_regexp_matcher)(String*, int, const byte*, const byte*,
30 void*, int*, int, Address, int, Isolate*);
33 // Call the generated regexp code directly. The code at the entry address
34 // should act as a function matching the type arm_regexp_matcher.
35 // The fifth argument is a dummy that reserves the space used for
36 // the return address added by the ExitFrame in native calls.
37 #define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7, p8) \
38 (FUNCTION_CAST<mips_regexp_matcher>(entry)( \
39 p0, p1, p2, p3, NULL, p4, p5, p6, p7, p8))
41 // The stack limit beyond which we will throw stack overflow errors in
42 // generated code. Because generated code on mips uses the C stack, we
43 // just use the C stack limit.
44 class SimulatorStack : public v8::internal::AllStatic {
46 static inline uintptr_t JsLimitFromCLimit(Isolate* isolate,
51 static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) {
52 return try_catch_address;
55 static inline void UnregisterCTryCatch() { }
58 } // namespace internal
61 // Calculated the stack limit beyond which we will throw stack overflow errors.
62 // This macro must be called from a C++ method. It relies on being able to take
63 // the address of "this" to get a value on the current execution stack and then
64 // calculates the stack limit based on that value.
65 // NOTE: The check for overflow is not safe as there is no guarantee that the
66 // running thread has its stack in all memory up to address 0x00000000.
67 #define GENERATED_CODE_STACK_LIMIT(limit) \
68 (reinterpret_cast<uintptr_t>(this) >= limit ? \
69 reinterpret_cast<uintptr_t>(this) - limit : 0)
71 #else // !defined(USE_SIMULATOR)
72 // Running with a simulator.
74 #include "src/assembler.h"
75 #include "src/hashmap.h"
80 // -----------------------------------------------------------------------------
85 static const int LINE_VALID = 0;
86 static const int LINE_INVALID = 1;
88 static const int kPageShift = 12;
89 static const int kPageSize = 1 << kPageShift;
90 static const int kPageMask = kPageSize - 1;
91 static const int kLineShift = 2; // The cache line is only 4 bytes right now.
92 static const int kLineLength = 1 << kLineShift;
93 static const int kLineMask = kLineLength - 1;
96 memset(&validity_map_, LINE_INVALID, sizeof(validity_map_));
99 char* ValidityByte(int offset) {
100 return &validity_map_[offset >> kLineShift];
103 char* CachedData(int offset) {
104 return &data_[offset];
108 char data_[kPageSize]; // The cached data.
109 static const int kValidityMapSize = kPageSize >> kLineShift;
110 char validity_map_[kValidityMapSize]; // One byte per line.
115 friend class MipsDebugger;
117 // Registers are declared in order. See SMRL chapter 2.
124 t0, t1, t2, t3, t4, t5, t6, t7,
125 s0, s1, s2, s3, s4, s5, s6, s7,
135 pc, // pc must be the last register.
141 // Coprocessor registers.
142 // Generated code will always use doubles. So we will only use even registers.
144 f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11,
145 f12, f13, f14, f15, // f12 and f14 are arguments FPURegisters.
146 f16, f17, f18, f19, f20, f21, f22, f23, f24, f25,
147 f26, f27, f28, f29, f30, f31,
151 explicit Simulator(Isolate* isolate);
154 // The currently executing Simulator instance. Potentially there can be one
155 // for each native thread.
156 static Simulator* current(v8::internal::Isolate* isolate);
158 // Accessors for register state. Reading the pc value adheres to the MIPS
159 // architecture specification and is off by a 8 from the currently executing
161 void set_register(int reg, int32_t value);
162 void set_dw_register(int dreg, const int* dbl);
163 int32_t get_register(int reg) const;
164 double get_double_from_register_pair(int reg);
165 // Same for FPURegisters.
166 void set_fpu_register(int fpureg, int64_t value);
167 void set_fpu_register_word(int fpureg, int32_t value);
168 void set_fpu_register_hi_word(int fpureg, int32_t value);
169 void set_fpu_register_float(int fpureg, float value);
170 void set_fpu_register_double(int fpureg, double value);
171 int64_t get_fpu_register(int fpureg) const;
172 int32_t get_fpu_register_word(int fpureg) const;
173 int32_t get_fpu_register_signed_word(int fpureg) const;
174 int32_t get_fpu_register_hi_word(int fpureg) const;
175 float get_fpu_register_float(int fpureg) const;
176 double get_fpu_register_double(int fpureg) const;
177 void set_fcsr_bit(uint32_t cc, bool value);
178 bool test_fcsr_bit(uint32_t cc);
179 void set_fcsr_rounding_mode(FPURoundingMode mode);
180 unsigned int get_fcsr_rounding_mode();
181 bool set_fcsr_round_error(double original, double rounded);
182 bool set_fcsr_round_error(float original, float rounded);
183 bool set_fcsr_round64_error(double original, double rounded);
184 bool set_fcsr_round64_error(float original, float rounded);
185 void round_according_to_fcsr(double toRound, double& rounded,
186 int32_t& rounded_int, double fs);
187 void round_according_to_fcsr(float toRound, float& rounded,
188 int32_t& rounded_int, float fs);
189 void round64_according_to_fcsr(double toRound, double& rounded,
190 int64_t& rounded_int, double fs);
191 void round64_according_to_fcsr(float toRound, float& rounded,
192 int64_t& rounded_int, float fs);
193 // Special case of set_register and get_register to access the raw PC value.
194 void set_pc(int32_t value);
195 int32_t get_pc() const;
197 Address get_sp() const {
198 return reinterpret_cast<Address>(static_cast<intptr_t>(get_register(sp)));
201 // Accessor to the internal simulator stack area.
202 uintptr_t StackLimit(uintptr_t c_limit) const;
204 // Executes MIPS instructions until the PC reaches end_sim_pc.
207 // Call on program start.
208 static void Initialize(Isolate* isolate);
210 static void TearDown(HashMap* i_cache, Redirection* first);
212 // V8 generally calls into generated JS code with 5 parameters and into
213 // generated RegExp code with 7 parameters. This is a convenience function,
214 // which sets up the simulator state and grabs the result on return.
215 int32_t Call(byte* entry, int argument_count, ...);
216 // Alternative: call a 2-argument double function.
217 double CallFP(byte* entry, double d0, double d1);
219 // Push an address onto the JS stack.
220 uintptr_t PushAddress(uintptr_t address);
222 // Pop an address from the JS stack.
223 uintptr_t PopAddress();
226 void set_last_debugger_input(char* input);
227 char* last_debugger_input() { return last_debugger_input_; }
230 static void FlushICache(v8::internal::HashMap* i_cache, void* start,
233 // Returns true if pc register contains one of the 'special_values' defined
234 // below (bad_ra, end_sim_pc).
235 bool has_bad_pc() const;
238 enum special_values {
239 // Known bad pc value to ensure that the simulator does not execute
240 // without being properly setup.
242 // A pc value used to signal the simulator to stop execution. Generally
243 // the ra is set to this value on transition from native C code to
244 // simulated execution, so that the simulator can "return" to the native
247 // Unpredictable value.
248 Unpredictable = 0xbadbeaf
251 // Unsupported instructions use Format to print an error and stop execution.
252 void Format(Instruction* instr, const char* format);
254 // Read and write memory.
255 inline uint32_t ReadBU(int32_t addr);
256 inline int32_t ReadB(int32_t addr);
257 inline void WriteB(int32_t addr, uint8_t value);
258 inline void WriteB(int32_t addr, int8_t value);
260 inline uint16_t ReadHU(int32_t addr, Instruction* instr);
261 inline int16_t ReadH(int32_t addr, Instruction* instr);
262 // Note: Overloaded on the sign of the value.
263 inline void WriteH(int32_t addr, uint16_t value, Instruction* instr);
264 inline void WriteH(int32_t addr, int16_t value, Instruction* instr);
266 inline int ReadW(int32_t addr, Instruction* instr);
267 inline void WriteW(int32_t addr, int value, Instruction* instr);
269 inline double ReadD(int32_t addr, Instruction* instr);
270 inline void WriteD(int32_t addr, double value, Instruction* instr);
272 // Helpers for data value tracing.
278 // DFLOAT - Floats may have printing issues due to paired lwc1's
281 void TraceRegWr(int32_t value);
282 void TraceMemWr(int32_t addr, int32_t value, TraceType t);
283 void TraceMemRd(int32_t addr, int32_t value);
284 EmbeddedVector<char, 128> trace_buf_;
286 // Operations depending on endianness.
287 // Get Double Higher / Lower word.
288 inline int32_t GetDoubleHIW(double* addr);
289 inline int32_t GetDoubleLOW(double* addr);
290 // Set Double Higher / Lower word.
291 inline int32_t SetDoubleHIW(double* addr);
292 inline int32_t SetDoubleLOW(double* addr);
294 // Executing is handled based on the instruction type.
295 void DecodeTypeRegister(Instruction* instr);
297 // Functions called from DecodeTypeRegister.
298 void DecodeTypeRegisterCOP1();
300 void DecodeTypeRegisterCOP1X();
302 void DecodeTypeRegisterSPECIAL();
304 void DecodeTypeRegisterSPECIAL2();
306 void DecodeTypeRegisterSPECIAL3();
308 // Called from DecodeTypeRegisterCOP1.
309 void DecodeTypeRegisterSRsType();
311 void DecodeTypeRegisterDRsType();
313 void DecodeTypeRegisterWRsType();
315 void DecodeTypeRegisterLRsType();
317 Instruction* currentInstr_;
318 inline Instruction* get_instr() const { return currentInstr_; }
319 inline void set_instr(Instruction* instr) { currentInstr_ = instr; }
321 inline int32_t rs_reg() const { return currentInstr_->RsValue(); }
322 inline int32_t rs() const { return get_register(rs_reg()); }
323 inline uint32_t rs_u() const {
324 return static_cast<uint32_t>(get_register(rs_reg()));
326 inline int32_t rt_reg() const { return currentInstr_->RtValue(); }
327 inline int32_t rt() const { return get_register(rt_reg()); }
328 inline uint32_t rt_u() const {
329 return static_cast<uint32_t>(get_register(rt_reg()));
331 inline int32_t rd_reg() const { return currentInstr_->RdValue(); }
332 inline int32_t fr_reg() const { return currentInstr_->FrValue(); }
333 inline int32_t fs_reg() const { return currentInstr_->FsValue(); }
334 inline int32_t ft_reg() const { return currentInstr_->FtValue(); }
335 inline int32_t fd_reg() const { return currentInstr_->FdValue(); }
336 inline int32_t sa() const { return currentInstr_->SaValue(); }
338 inline void SetResult(int32_t rd_reg, int32_t alu_out) {
339 set_register(rd_reg, alu_out);
343 void DecodeTypeImmediate(Instruction* instr);
344 void DecodeTypeJump(Instruction* instr);
346 // Used for breakpoints and traps.
347 void SoftwareInterrupt(Instruction* instr);
349 // Stop helper functions.
350 bool IsWatchpoint(uint32_t code);
351 void PrintWatchpoint(uint32_t code);
352 void HandleStop(uint32_t code, Instruction* instr);
353 bool IsStopInstruction(Instruction* instr);
354 bool IsEnabledStop(uint32_t code);
355 void EnableStop(uint32_t code);
356 void DisableStop(uint32_t code);
357 void IncreaseStopCounter(uint32_t code);
358 void PrintStopInfo(uint32_t code);
361 // Executes one instruction.
362 void InstructionDecode(Instruction* instr);
363 // Execute one instruction placed in a branch delay slot.
364 void BranchDelayInstructionDecode(Instruction* instr) {
365 if (instr->InstructionBits() == nopInstr) {
366 // Short-cut generic nop instructions. They are always valid and they
367 // never change the simulator state.
371 if (instr->IsForbiddenInBranchDelay()) {
372 V8_Fatal(__FILE__, __LINE__,
373 "Eror:Unexpected %i opcode in a branch delay slot.",
374 instr->OpcodeValue());
376 InstructionDecode(instr);
377 SNPrintF(trace_buf_, " ");
381 static void CheckICache(v8::internal::HashMap* i_cache, Instruction* instr);
382 static void FlushOnePage(v8::internal::HashMap* i_cache, intptr_t start,
384 static CachePage* GetCachePage(v8::internal::HashMap* i_cache, void* page);
395 void SignalException(Exception e);
397 // Runtime call support.
398 static void* RedirectExternalReference(void* external_function,
399 ExternalReference::Type type);
401 // Handle arguments and return value for runtime FP functions.
402 void GetFpArgs(double* x, double* y, int32_t* z);
403 void SetFpResult(const double& result);
405 void CallInternal(byte* entry);
407 // Architecture state.
409 int32_t registers_[kNumSimuRegisters];
410 // Coprocessor Registers.
411 // Note: FP32 mode uses only the lower 32-bit part of each element,
412 // the upper 32-bit is unpredictable.
413 int64_t FPUregisters_[kNumFPURegisters];
414 // FPU control register.
417 // Simulator support.
418 // Allocate 1MB for stack.
419 static const size_t stack_size_ = 1 * 1024*1024;
426 char* last_debugger_input_;
428 // Icache simulation.
429 v8::internal::HashMap* i_cache_;
431 v8::internal::Isolate* isolate_;
433 // Registered breakpoints.
434 Instruction* break_pc_;
437 // Stop is disabled if bit 31 is set.
438 static const uint32_t kStopDisabledBit = 1 << 31;
440 // A stop is enabled, meaning the simulator will stop when meeting the
441 // instruction, if bit 31 of watched_stops_[code].count is unset.
442 // The value watched_stops_[code].count & ~(1 << 31) indicates how many times
443 // the breakpoint was hit or gone through.
444 struct StopCountAndDesc {
448 StopCountAndDesc watched_stops_[kMaxStopCode + 1];
452 // When running with the simulator transition into simulated execution at this
454 #define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
455 reinterpret_cast<Object*>(Simulator::current(Isolate::Current())->Call( \
456 FUNCTION_ADDR(entry), 5, p0, p1, p2, p3, p4))
458 #define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7, p8) \
459 Simulator::current(Isolate::Current())->Call( \
460 entry, 10, p0, p1, p2, p3, NULL, p4, p5, p6, p7, p8)
463 // The simulator has its own stack. Thus it has a different stack limit from
464 // the C-based native code. The JS-based limit normally points near the end of
465 // the simulator stack. When the C-based limit is exhausted we reflect that by
466 // lowering the JS-based limit as well, to make stack checks trigger.
467 class SimulatorStack : public v8::internal::AllStatic {
469 static inline uintptr_t JsLimitFromCLimit(Isolate* isolate,
471 return Simulator::current(isolate)->StackLimit(c_limit);
474 static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) {
475 Simulator* sim = Simulator::current(Isolate::Current());
476 return sim->PushAddress(try_catch_address);
479 static inline void UnregisterCTryCatch() {
480 Simulator::current(Isolate::Current())->PopAddress();
484 } // namespace internal
487 #endif // !defined(USE_SIMULATOR)
488 #endif // V8_MIPS_SIMULATOR_MIPS_H_