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 v8::internal
89 // Calculated the stack limit beyond which we will throw stack overflow errors.
90 // This macro must be called from a C++ method. It relies on being able to take
91 // the address of "this" to get a value on the current execution stack and then
92 // calculates the stack limit based on that value.
93 // NOTE: The check for overflow is not safe as there is no guarantee that the
94 // running thread has its stack in all memory up to address 0x00000000.
95 #define GENERATED_CODE_STACK_LIMIT(limit) \
96 (reinterpret_cast<uintptr_t>(this) >= limit ? \
97 reinterpret_cast<uintptr_t>(this) - limit : 0)
99 #else // !defined(USE_SIMULATOR)
100 // Running with a simulator.
102 #include "src/assembler.h"
103 #include "src/hashmap.h"
108 // -----------------------------------------------------------------------------
113 static const int LINE_VALID = 0;
114 static const int LINE_INVALID = 1;
116 static const int kPageShift = 12;
117 static const int kPageSize = 1 << kPageShift;
118 static const int kPageMask = kPageSize - 1;
119 static const int kLineShift = 2; // The cache line is only 4 bytes right now.
120 static const int kLineLength = 1 << kLineShift;
121 static const int kLineMask = kLineLength - 1;
124 memset(&validity_map_, LINE_INVALID, sizeof(validity_map_));
127 char* ValidityByte(int offset) {
128 return &validity_map_[offset >> kLineShift];
131 char* CachedData(int offset) {
132 return &data_[offset];
136 char data_[kPageSize]; // The cached data.
137 static const int kValidityMapSize = kPageSize >> kLineShift;
138 char validity_map_[kValidityMapSize]; // One byte per line.
143 friend class MipsDebugger;
145 // Registers are declared in order. See SMRL chapter 2.
151 a0, a1, a2, a3, a4, a5, a6, a7,
153 s0, s1, s2, s3, s4, s5, s6, s7,
163 pc, // pc must be the last register.
169 // Coprocessor registers.
170 // Generated code will always use doubles. So we will only use even registers.
172 f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11,
173 f12, f13, f14, f15, // f12 and f14 are arguments FPURegisters.
174 f16, f17, f18, f19, f20, f21, f22, f23, f24, f25,
175 f26, f27, f28, f29, f30, f31,
179 explicit Simulator(Isolate* isolate);
182 // The currently executing Simulator instance. Potentially there can be one
183 // for each native thread.
184 static Simulator* current(v8::internal::Isolate* isolate);
186 // Accessors for register state. Reading the pc value adheres to the MIPS
187 // architecture specification and is off by a 8 from the currently executing
189 void set_register(int reg, int64_t value);
190 void set_register_word(int reg, int32_t value);
191 void set_dw_register(int dreg, const int* dbl);
192 int64_t get_register(int reg) const;
193 double get_double_from_register_pair(int reg);
194 // Same for FPURegisters.
195 void set_fpu_register(int fpureg, int64_t value);
196 void set_fpu_register_word(int fpureg, int32_t value);
197 void set_fpu_register_hi_word(int fpureg, int32_t value);
198 void set_fpu_register_float(int fpureg, float value);
199 void set_fpu_register_double(int fpureg, double value);
200 int64_t get_fpu_register(int fpureg) const;
201 int32_t get_fpu_register_word(int fpureg) const;
202 int32_t get_fpu_register_signed_word(int fpureg) const;
203 int32_t get_fpu_register_hi_word(int fpureg) const;
204 float get_fpu_register_float(int fpureg) const;
205 double get_fpu_register_double(int fpureg) const;
206 void set_fcsr_bit(uint32_t cc, bool value);
207 bool test_fcsr_bit(uint32_t cc);
208 bool set_fcsr_round_error(double original, double rounded);
209 bool set_fcsr_round64_error(double original, double rounded);
210 bool set_fcsr_round_error(float original, float rounded);
211 bool set_fcsr_round64_error(float original, float rounded);
212 void round_according_to_fcsr(double toRound, double& rounded,
213 int32_t& rounded_int, double fs);
214 void round64_according_to_fcsr(double toRound, double& rounded,
215 int64_t& rounded_int, double fs);
216 void round_according_to_fcsr(float toRound, float& rounded,
217 int32_t& rounded_int, float fs);
218 void round64_according_to_fcsr(float toRound, float& rounded,
219 int64_t& rounded_int, float fs);
220 void set_fcsr_rounding_mode(FPURoundingMode mode);
221 unsigned int get_fcsr_rounding_mode();
222 // Special case of set_register and get_register to access the raw PC value.
223 void set_pc(int64_t value);
224 int64_t get_pc() const;
227 return reinterpret_cast<Address>(static_cast<intptr_t>(get_register(sp)));
230 // Accessor to the internal simulator stack area.
231 uintptr_t StackLimit() const;
233 // Executes MIPS instructions until the PC reaches end_sim_pc.
236 // Call on program start.
237 static void Initialize(Isolate* isolate);
239 static void TearDown(HashMap* i_cache, Redirection* first);
241 // V8 generally calls into generated JS code with 5 parameters and into
242 // generated RegExp code with 7 parameters. This is a convenience function,
243 // which sets up the simulator state and grabs the result on return.
244 int64_t Call(byte* entry, int argument_count, ...);
245 // Alternative: call a 2-argument double function.
246 double CallFP(byte* entry, double d0, double d1);
248 // Push an address onto the JS stack.
249 uintptr_t PushAddress(uintptr_t address);
251 // Pop an address from the JS stack.
252 uintptr_t PopAddress();
255 void set_last_debugger_input(char* input);
256 char* last_debugger_input() { return last_debugger_input_; }
259 static void FlushICache(v8::internal::HashMap* i_cache, void* start,
262 // Returns true if pc register contains one of the 'special_values' defined
263 // below (bad_ra, end_sim_pc).
264 bool has_bad_pc() const;
267 enum special_values {
268 // Known bad pc value to ensure that the simulator does not execute
269 // without being properly setup.
271 // A pc value used to signal the simulator to stop execution. Generally
272 // the ra is set to this value on transition from native C code to
273 // simulated execution, so that the simulator can "return" to the native
276 // Unpredictable value.
277 Unpredictable = 0xbadbeaf
280 // Unsupported instructions use Format to print an error and stop execution.
281 void Format(Instruction* instr, const char* format);
283 // Read and write memory.
284 inline uint32_t ReadBU(int64_t addr);
285 inline int32_t ReadB(int64_t addr);
286 inline void WriteB(int64_t addr, uint8_t value);
287 inline void WriteB(int64_t addr, int8_t value);
289 inline uint16_t ReadHU(int64_t addr, Instruction* instr);
290 inline int16_t ReadH(int64_t addr, Instruction* instr);
291 // Note: Overloaded on the sign of the value.
292 inline void WriteH(int64_t addr, uint16_t value, Instruction* instr);
293 inline void WriteH(int64_t addr, int16_t value, Instruction* instr);
295 inline uint32_t ReadWU(int64_t addr, Instruction* instr);
296 inline int32_t ReadW(int64_t addr, Instruction* instr);
297 inline void WriteW(int64_t addr, int32_t value, Instruction* instr);
298 inline int64_t Read2W(int64_t addr, Instruction* instr);
299 inline void Write2W(int64_t addr, int64_t value, Instruction* instr);
301 inline double ReadD(int64_t addr, Instruction* instr);
302 inline void WriteD(int64_t addr, double value, Instruction* instr);
304 // Helper for debugging memory access.
305 inline void DieOrDebug();
307 // Helpers for data value tracing.
313 // DFLOAT - Floats may have printing issues due to paired lwc1's
316 void TraceRegWr(int64_t value);
317 void TraceMemWr(int64_t addr, int64_t value, TraceType t);
318 void TraceMemRd(int64_t addr, int64_t value);
320 // Operations depending on endianness.
321 // Get Double Higher / Lower word.
322 inline int32_t GetDoubleHIW(double* addr);
323 inline int32_t GetDoubleLOW(double* addr);
324 // Set Double Higher / Lower word.
325 inline int32_t SetDoubleHIW(double* addr);
326 inline int32_t SetDoubleLOW(double* addr);
328 // functions called from DecodeTypeRegister
329 void DecodeTypeRegisterCOP1(Instruction* instr, const int32_t rs_reg,
330 const int64_t rs, const uint64_t rs_u,
331 const int32_t rt_reg, const int64_t rt,
332 const uint64_t rt_u, const int32_t rd_reg,
333 const int32_t fr_reg, const int32_t fs_reg,
334 const int32_t ft_reg, const int32_t fd_reg,
337 void DecodeTypeRegisterCOP1X(Instruction* instr, const int32_t fr_reg,
338 const int32_t fs_reg, const int32_t ft_reg,
339 const int32_t fd_reg);
341 void DecodeTypeRegisterSPECIAL(
342 Instruction* instr, const int32_t rs_reg, const int64_t rs,
343 const uint64_t rs_u, const int32_t rt_reg, const int64_t rt,
344 const uint64_t rt_u, const int32_t rd_reg, const int32_t fr_reg,
345 const int32_t fs_reg, const int32_t ft_reg, const int32_t fd_reg,
346 const int64_t i64hilo, const uint64_t u64hilo, const int64_t alu_out,
347 const bool do_interrupt, const int64_t current_pc, const int64_t next_pc,
348 const int32_t return_addr_reg, const int64_t i128resultH,
349 const int64_t i128resultL);
352 void DecodeTypeRegisterSPECIAL2(Instruction* instr, const int32_t rd_reg,
353 const int64_t alu_out);
355 void DecodeTypeRegisterSPECIAL3(Instruction* instr, const int32_t rt_reg,
356 const int32_t rd_reg, const int64_t alu_out);
358 void DecodeTypeRegisterSRsType(Instruction* instr, const int32_t fs_reg,
359 const int32_t ft_reg, const int32_t fd_reg);
361 void DecodeTypeRegisterDRsType(Instruction* instr, const int32_t fs_reg,
362 const int32_t ft_reg, const int32_t fd_reg);
364 void DecodeTypeRegisterWRsType(Instruction* instr, const int32_t fs_reg,
365 const int32_t ft_reg, const int32_t fd_reg,
368 void DecodeTypeRegisterLRsType(Instruction* instr, const int32_t fs_reg,
369 const int32_t fd_reg, const int32_t ft_reg);
370 // Executing is handled based on the instruction type.
371 void DecodeTypeRegister(Instruction* instr);
373 // Helper function for DecodeTypeRegister.
374 void ConfigureTypeRegister(Instruction* instr, int64_t* alu_out,
375 int64_t* i64hilo, uint64_t* u64hilo,
376 int64_t* next_pc, int* return_addr_reg,
377 bool* do_interrupt, int64_t* result128H,
378 int64_t* result128L);
380 void DecodeTypeImmediate(Instruction* instr);
381 void DecodeTypeJump(Instruction* instr);
383 // Used for breakpoints and traps.
384 void SoftwareInterrupt(Instruction* instr);
386 // Stop helper functions.
387 bool IsWatchpoint(uint64_t code);
388 void PrintWatchpoint(uint64_t code);
389 void HandleStop(uint64_t code, Instruction* instr);
390 bool IsStopInstruction(Instruction* instr);
391 bool IsEnabledStop(uint64_t code);
392 void EnableStop(uint64_t code);
393 void DisableStop(uint64_t code);
394 void IncreaseStopCounter(uint64_t code);
395 void PrintStopInfo(uint64_t code);
398 // Executes one instruction.
399 void InstructionDecode(Instruction* instr);
400 // Execute one instruction placed in a branch delay slot.
401 void BranchDelayInstructionDecode(Instruction* instr) {
402 if (instr->InstructionBits() == nopInstr) {
403 // Short-cut generic nop instructions. They are always valid and they
404 // never change the simulator state.
408 if (instr->IsForbiddenInBranchDelay()) {
409 V8_Fatal(__FILE__, __LINE__,
410 "Eror:Unexpected %i opcode in a branch delay slot.",
411 instr->OpcodeValue());
413 InstructionDecode(instr);
414 SNPrintF(trace_buf_, " ");
418 static void CheckICache(v8::internal::HashMap* i_cache, Instruction* instr);
419 static void FlushOnePage(v8::internal::HashMap* i_cache, intptr_t start,
421 static CachePage* GetCachePage(v8::internal::HashMap* i_cache, void* page);
430 int16_t exceptions[kNumExceptions];
433 void SignalExceptions();
435 // Runtime call support.
436 static void* RedirectExternalReference(void* external_function,
437 ExternalReference::Type type);
439 // Handle arguments and return value for runtime FP functions.
440 void GetFpArgs(double* x, double* y, int32_t* z);
441 void SetFpResult(const double& result);
443 void CallInternal(byte* entry);
445 // Architecture state.
447 int64_t registers_[kNumSimuRegisters];
448 // Coprocessor Registers.
449 int64_t FPUregisters_[kNumFPURegisters];
450 // FPU control register.
453 // Simulator support.
454 // Allocate 1MB for stack.
460 EmbeddedVector<char, 128> trace_buf_;
463 char* last_debugger_input_;
465 // Icache simulation.
466 v8::internal::HashMap* i_cache_;
468 v8::internal::Isolate* isolate_;
470 // Registered breakpoints.
471 Instruction* break_pc_;
474 // Stop is disabled if bit 31 is set.
475 static const uint32_t kStopDisabledBit = 1 << 31;
477 // A stop is enabled, meaning the simulator will stop when meeting the
478 // instruction, if bit 31 of watched_stops_[code].count is unset.
479 // The value watched_stops_[code].count & ~(1 << 31) indicates how many times
480 // the breakpoint was hit or gone through.
481 struct StopCountAndDesc {
485 StopCountAndDesc watched_stops_[kMaxStopCode + 1];
489 // When running with the simulator transition into simulated execution at this
491 #define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
492 reinterpret_cast<Object*>(Simulator::current(Isolate::Current())->Call( \
493 FUNCTION_ADDR(entry), 5, reinterpret_cast<int64_t*>(p0), \
494 reinterpret_cast<int64_t*>(p1), reinterpret_cast<int64_t*>(p2), \
495 reinterpret_cast<int64_t*>(p3), reinterpret_cast<int64_t*>(p4)))
499 #define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7, p8) \
501 Simulator::current(Isolate::Current()) \
502 ->Call(entry, 10, p0, p1, p2, p3, p4, p5, p6, p7, NULL, p8))
503 #else // Must be O32 Abi.
504 #define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7, p8) \
506 Simulator::current(Isolate::Current()) \
507 ->Call(entry, 10, p0, p1, p2, p3, NULL, p4, p5, p6, p7, p8))
508 #endif // MIPS_ABI_N64
511 // The simulator has its own stack. Thus it has a different stack limit from
512 // the C-based native code. Setting the c_limit to indicate a very small
513 // stack cause stack overflow errors, since the simulator ignores the input.
514 // This is unlikely to be an issue in practice, though it might cause testing
515 // trouble down the line.
516 class SimulatorStack : public v8::internal::AllStatic {
518 static inline uintptr_t JsLimitFromCLimit(Isolate* isolate,
520 return Simulator::current(isolate)->StackLimit();
523 static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) {
524 Simulator* sim = Simulator::current(Isolate::Current());
525 return sim->PushAddress(try_catch_address);
528 static inline void UnregisterCTryCatch() {
529 Simulator::current(Isolate::Current())->PopAddress();
533 } } // namespace v8::internal
535 #endif // !defined(USE_SIMULATOR)
536 #endif // V8_MIPS_SIMULATOR_MIPS_H_