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/mips64/constants-mips64.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)
30 // Call the generated regexp code directly. The code at the entry address
31 // should act as a function matching the type arm_regexp_matcher.
32 // The fifth (or ninth) argument is a dummy that reserves the space used for
33 // the return address added by the ExitFrame in native calls.
35 typedef int (*mips_regexp_matcher)(String* input,
37 const byte* input_start,
38 const byte* input_end,
46 #define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7, p8) \
47 (FUNCTION_CAST<mips_regexp_matcher>(entry)( \
48 p0, p1, p2, p3, p4, p5, p6, p7, NULL, p8))
52 typedef int (*mips_regexp_matcher)(String* input,
54 const byte* input_start,
55 const byte* input_end,
63 #define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7, p8) \
64 (FUNCTION_CAST<mips_regexp_matcher>(entry)( \
65 p0, p1, p2, p3, NULL, p4, p5, p6, p7, p8))
67 #endif // MIPS_ABI_N64
70 // The stack limit beyond which we will throw stack overflow errors in
71 // generated code. Because generated code on mips uses the C stack, we
72 // just use the C stack limit.
73 class SimulatorStack : public v8::internal::AllStatic {
75 static inline uintptr_t JsLimitFromCLimit(Isolate* isolate,
80 static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) {
81 return try_catch_address;
84 static inline void UnregisterCTryCatch() { }
87 } // namespace internal
90 // Calculated the stack limit beyond which we will throw stack overflow errors.
91 // This macro must be called from a C++ method. It relies on being able to take
92 // the address of "this" to get a value on the current execution stack and then
93 // calculates the stack limit based on that value.
94 // NOTE: The check for overflow is not safe as there is no guarantee that the
95 // running thread has its stack in all memory up to address 0x00000000.
96 #define GENERATED_CODE_STACK_LIMIT(limit) \
97 (reinterpret_cast<uintptr_t>(this) >= limit ? \
98 reinterpret_cast<uintptr_t>(this) - limit : 0)
100 #else // !defined(USE_SIMULATOR)
101 // Running with a simulator.
103 #include "src/assembler.h"
104 #include "src/hashmap.h"
109 // -----------------------------------------------------------------------------
114 static const int LINE_VALID = 0;
115 static const int LINE_INVALID = 1;
117 static const int kPageShift = 12;
118 static const int kPageSize = 1 << kPageShift;
119 static const int kPageMask = kPageSize - 1;
120 static const int kLineShift = 2; // The cache line is only 4 bytes right now.
121 static const int kLineLength = 1 << kLineShift;
122 static const int kLineMask = kLineLength - 1;
125 memset(&validity_map_, LINE_INVALID, sizeof(validity_map_));
128 char* ValidityByte(int offset) {
129 return &validity_map_[offset >> kLineShift];
132 char* CachedData(int offset) {
133 return &data_[offset];
137 char data_[kPageSize]; // The cached data.
138 static const int kValidityMapSize = kPageSize >> kLineShift;
139 char validity_map_[kValidityMapSize]; // One byte per line.
144 friend class MipsDebugger;
146 // Registers are declared in order. See SMRL chapter 2.
152 a0, a1, a2, a3, a4, a5, a6, a7,
154 s0, s1, s2, s3, s4, s5, s6, s7,
164 pc, // pc must be the last register.
170 // Coprocessor registers.
171 // Generated code will always use doubles. So we will only use even registers.
173 f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11,
174 f12, f13, f14, f15, // f12 and f14 are arguments FPURegisters.
175 f16, f17, f18, f19, f20, f21, f22, f23, f24, f25,
176 f26, f27, f28, f29, f30, f31,
180 explicit Simulator(Isolate* isolate);
183 // The currently executing Simulator instance. Potentially there can be one
184 // for each native thread.
185 static Simulator* current(v8::internal::Isolate* isolate);
187 // Accessors for register state. Reading the pc value adheres to the MIPS
188 // architecture specification and is off by a 8 from the currently executing
190 void set_register(int reg, int64_t value);
191 void set_register_word(int reg, int32_t value);
192 void set_dw_register(int dreg, const int* dbl);
193 int64_t get_register(int reg) const;
194 double get_double_from_register_pair(int reg);
195 // Same for FPURegisters.
196 void set_fpu_register(int fpureg, int64_t value);
197 void set_fpu_register_word(int fpureg, int32_t value);
198 void set_fpu_register_hi_word(int fpureg, int32_t value);
199 void set_fpu_register_float(int fpureg, float value);
200 void set_fpu_register_double(int fpureg, double value);
201 int64_t get_fpu_register(int fpureg) const;
202 int32_t get_fpu_register_word(int fpureg) const;
203 int32_t get_fpu_register_signed_word(int fpureg) const;
204 int32_t get_fpu_register_hi_word(int fpureg) const;
205 float get_fpu_register_float(int fpureg) const;
206 double get_fpu_register_double(int fpureg) const;
207 void set_fcsr_bit(uint32_t cc, bool value);
208 bool test_fcsr_bit(uint32_t cc);
209 bool set_fcsr_round_error(double original, double rounded);
210 bool set_fcsr_round64_error(double original, double rounded);
211 bool set_fcsr_round_error(float original, float rounded);
212 bool set_fcsr_round64_error(float original, float rounded);
213 void round_according_to_fcsr(double toRound, double& rounded,
214 int32_t& rounded_int, double fs);
215 void round64_according_to_fcsr(double toRound, double& rounded,
216 int64_t& rounded_int, double fs);
217 void round_according_to_fcsr(float toRound, float& rounded,
218 int32_t& rounded_int, float fs);
219 void round64_according_to_fcsr(float toRound, float& rounded,
220 int64_t& rounded_int, float fs);
221 void set_fcsr_rounding_mode(FPURoundingMode mode);
222 unsigned int get_fcsr_rounding_mode();
223 // Special case of set_register and get_register to access the raw PC value.
224 void set_pc(int64_t value);
225 int64_t get_pc() const;
227 Address get_sp() const {
228 return reinterpret_cast<Address>(static_cast<intptr_t>(get_register(sp)));
231 // Accessor to the internal simulator stack area.
232 uintptr_t StackLimit(uintptr_t c_limit) const;
234 // Executes MIPS instructions until the PC reaches end_sim_pc.
237 // Call on program start.
238 static void Initialize(Isolate* isolate);
240 static void TearDown(HashMap* i_cache, Redirection* first);
242 // V8 generally calls into generated JS code with 5 parameters and into
243 // generated RegExp code with 7 parameters. This is a convenience function,
244 // which sets up the simulator state and grabs the result on return.
245 int64_t Call(byte* entry, int argument_count, ...);
246 // Alternative: call a 2-argument double function.
247 double CallFP(byte* entry, double d0, double d1);
249 // Push an address onto the JS stack.
250 uintptr_t PushAddress(uintptr_t address);
252 // Pop an address from the JS stack.
253 uintptr_t PopAddress();
256 void set_last_debugger_input(char* input);
257 char* last_debugger_input() { return last_debugger_input_; }
260 static void FlushICache(v8::internal::HashMap* i_cache, void* start,
263 // Returns true if pc register contains one of the 'special_values' defined
264 // below (bad_ra, end_sim_pc).
265 bool has_bad_pc() const;
268 enum special_values {
269 // Known bad pc value to ensure that the simulator does not execute
270 // without being properly setup.
272 // A pc value used to signal the simulator to stop execution. Generally
273 // the ra is set to this value on transition from native C code to
274 // simulated execution, so that the simulator can "return" to the native
277 // Unpredictable value.
278 Unpredictable = 0xbadbeaf
281 // Unsupported instructions use Format to print an error and stop execution.
282 void Format(Instruction* instr, const char* format);
284 // Read and write memory.
285 inline uint32_t ReadBU(int64_t addr);
286 inline int32_t ReadB(int64_t addr);
287 inline void WriteB(int64_t addr, uint8_t value);
288 inline void WriteB(int64_t addr, int8_t value);
290 inline uint16_t ReadHU(int64_t addr, Instruction* instr);
291 inline int16_t ReadH(int64_t addr, Instruction* instr);
292 // Note: Overloaded on the sign of the value.
293 inline void WriteH(int64_t addr, uint16_t value, Instruction* instr);
294 inline void WriteH(int64_t addr, int16_t value, Instruction* instr);
296 inline uint32_t ReadWU(int64_t addr, Instruction* instr);
297 inline int32_t ReadW(int64_t addr, Instruction* instr);
298 inline void WriteW(int64_t addr, int32_t value, Instruction* instr);
299 inline int64_t Read2W(int64_t addr, Instruction* instr);
300 inline void Write2W(int64_t addr, int64_t value, Instruction* instr);
302 inline double ReadD(int64_t addr, Instruction* instr);
303 inline void WriteD(int64_t addr, double value, Instruction* instr);
305 // Helper for debugging memory access.
306 inline void DieOrDebug();
308 // Helpers for data value tracing.
314 // DFLOAT - Floats may have printing issues due to paired lwc1's
317 void TraceRegWr(int64_t value);
318 void TraceMemWr(int64_t addr, int64_t value, TraceType t);
319 void TraceMemRd(int64_t addr, int64_t value);
321 // Operations depending on endianness.
322 // Get Double Higher / Lower word.
323 inline int32_t GetDoubleHIW(double* addr);
324 inline int32_t GetDoubleLOW(double* addr);
325 // Set Double Higher / Lower word.
326 inline int32_t SetDoubleHIW(double* addr);
327 inline int32_t SetDoubleLOW(double* addr);
329 // functions called from DecodeTypeRegister.
330 void DecodeTypeRegisterCOP1();
332 void DecodeTypeRegisterCOP1X();
334 void DecodeTypeRegisterSPECIAL();
337 void DecodeTypeRegisterSPECIAL2();
339 void DecodeTypeRegisterSPECIAL3();
341 void DecodeTypeRegisterSRsType();
343 void DecodeTypeRegisterDRsType();
345 void DecodeTypeRegisterWRsType();
347 void DecodeTypeRegisterLRsType();
349 // Executing is handled based on the instruction type.
350 void DecodeTypeRegister(Instruction* instr);
352 Instruction* currentInstr_;
353 inline Instruction* get_instr() const { return currentInstr_; }
354 inline void set_instr(Instruction* instr) { currentInstr_ = instr; }
356 inline int32_t rs_reg() const { return currentInstr_->RsValue(); }
357 inline int64_t rs() const { return get_register(rs_reg()); }
358 inline uint64_t rs_u() const {
359 return static_cast<uint64_t>(get_register(rs_reg()));
361 inline int32_t rt_reg() const { return currentInstr_->RtValue(); }
362 inline int64_t rt() const { return get_register(rt_reg()); }
363 inline uint64_t rt_u() const {
364 return static_cast<uint64_t>(get_register(rt_reg()));
366 inline int32_t rd_reg() const { return currentInstr_->RdValue(); }
367 inline int32_t fr_reg() const { return currentInstr_->FrValue(); }
368 inline int32_t fs_reg() const { return currentInstr_->FsValue(); }
369 inline int32_t ft_reg() const { return currentInstr_->FtValue(); }
370 inline int32_t fd_reg() const { return currentInstr_->FdValue(); }
371 inline int32_t sa() const { return currentInstr_->SaValue(); }
373 inline void SetResult(const int32_t rd_reg, const int64_t alu_out) {
374 set_register(rd_reg, alu_out);
378 void DecodeTypeImmediate(Instruction* instr);
379 void DecodeTypeJump(Instruction* instr);
381 // Used for breakpoints and traps.
382 void SoftwareInterrupt(Instruction* instr);
384 // Stop helper functions.
385 bool IsWatchpoint(uint64_t code);
386 void PrintWatchpoint(uint64_t code);
387 void HandleStop(uint64_t code, Instruction* instr);
388 bool IsStopInstruction(Instruction* instr);
389 bool IsEnabledStop(uint64_t code);
390 void EnableStop(uint64_t code);
391 void DisableStop(uint64_t code);
392 void IncreaseStopCounter(uint64_t code);
393 void PrintStopInfo(uint64_t code);
396 // Executes one instruction.
397 void InstructionDecode(Instruction* instr);
398 // Execute one instruction placed in a branch delay slot.
399 void BranchDelayInstructionDecode(Instruction* instr) {
400 if (instr->InstructionBits() == nopInstr) {
401 // Short-cut generic nop instructions. They are always valid and they
402 // never change the simulator state.
406 if (instr->IsForbiddenInBranchDelay()) {
407 V8_Fatal(__FILE__, __LINE__,
408 "Eror:Unexpected %i opcode in a branch delay slot.",
409 instr->OpcodeValue());
411 InstructionDecode(instr);
412 SNPrintF(trace_buf_, " ");
416 static void CheckICache(v8::internal::HashMap* i_cache, Instruction* instr);
417 static void FlushOnePage(v8::internal::HashMap* i_cache, intptr_t start,
419 static CachePage* GetCachePage(v8::internal::HashMap* i_cache, void* page);
430 void SignalException(Exception e);
432 // Runtime call support.
433 static void* RedirectExternalReference(void* external_function,
434 ExternalReference::Type type);
436 // Handle arguments and return value for runtime FP functions.
437 void GetFpArgs(double* x, double* y, int32_t* z);
438 void SetFpResult(const double& result);
440 void CallInternal(byte* entry);
442 // Architecture state.
444 int64_t registers_[kNumSimuRegisters];
445 // Coprocessor Registers.
446 int64_t FPUregisters_[kNumFPURegisters];
447 // FPU control register.
450 // Simulator support.
451 // Allocate 1MB for stack.
457 EmbeddedVector<char, 128> trace_buf_;
460 char* last_debugger_input_;
462 // Icache simulation.
463 v8::internal::HashMap* i_cache_;
465 v8::internal::Isolate* isolate_;
467 // Registered breakpoints.
468 Instruction* break_pc_;
471 // Stop is disabled if bit 31 is set.
472 static const uint32_t kStopDisabledBit = 1 << 31;
474 // A stop is enabled, meaning the simulator will stop when meeting the
475 // instruction, if bit 31 of watched_stops_[code].count is unset.
476 // The value watched_stops_[code].count & ~(1 << 31) indicates how many times
477 // the breakpoint was hit or gone through.
478 struct StopCountAndDesc {
482 StopCountAndDesc watched_stops_[kMaxStopCode + 1];
486 // When running with the simulator transition into simulated execution at this
488 #define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
489 reinterpret_cast<Object*>(Simulator::current(Isolate::Current())->Call( \
490 FUNCTION_ADDR(entry), 5, reinterpret_cast<int64_t*>(p0), \
491 reinterpret_cast<int64_t*>(p1), reinterpret_cast<int64_t*>(p2), \
492 reinterpret_cast<int64_t*>(p3), reinterpret_cast<int64_t*>(p4)))
496 #define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7, p8) \
497 static_cast<int>(Simulator::current(Isolate::Current()) \
498 ->Call(entry, 10, p0, p1, p2, p3, p4, \
499 reinterpret_cast<int64_t*>(p5), p6, p7, NULL, \
501 #else // Must be O32 Abi.
502 #define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7, p8) \
504 Simulator::current(Isolate::Current()) \
505 ->Call(entry, 10, p0, p1, p2, p3, NULL, p4, p5, p6, p7, p8))
506 #endif // MIPS_ABI_N64
509 // The simulator has its own stack. Thus it has a different stack limit from
510 // the C-based native code. The JS-based limit normally points near the end of
511 // the simulator stack. When the C-based limit is exhausted we reflect that by
512 // lowering the JS-based limit as well, to make stack checks trigger.
513 class SimulatorStack : public v8::internal::AllStatic {
515 static inline uintptr_t JsLimitFromCLimit(Isolate* isolate,
517 return Simulator::current(isolate)->StackLimit(c_limit);
520 static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) {
521 Simulator* sim = Simulator::current(Isolate::Current());
522 return sim->PushAddress(try_catch_address);
525 static inline void UnregisterCTryCatch() {
526 Simulator::current(Isolate::Current())->PopAddress();
530 } // namespace internal
533 #endif // !defined(USE_SIMULATOR)
534 #endif // V8_MIPS_SIMULATOR_MIPS_H_