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 v8::internal
60 // Calculated the stack limit beyond which we will throw stack overflow errors.
61 // This macro must be called from a C++ method. It relies on being able to take
62 // the address of "this" to get a value on the current execution stack and then
63 // calculates the stack limit based on that value.
64 // NOTE: The check for overflow is not safe as there is no guarantee that the
65 // running thread has its stack in all memory up to address 0x00000000.
66 #define GENERATED_CODE_STACK_LIMIT(limit) \
67 (reinterpret_cast<uintptr_t>(this) >= limit ? \
68 reinterpret_cast<uintptr_t>(this) - limit : 0)
70 #else // !defined(USE_SIMULATOR)
71 // Running with a simulator.
73 #include "src/assembler.h"
74 #include "src/hashmap.h"
79 // -----------------------------------------------------------------------------
84 static const int LINE_VALID = 0;
85 static const int LINE_INVALID = 1;
87 static const int kPageShift = 12;
88 static const int kPageSize = 1 << kPageShift;
89 static const int kPageMask = kPageSize - 1;
90 static const int kLineShift = 2; // The cache line is only 4 bytes right now.
91 static const int kLineLength = 1 << kLineShift;
92 static const int kLineMask = kLineLength - 1;
95 memset(&validity_map_, LINE_INVALID, sizeof(validity_map_));
98 char* ValidityByte(int offset) {
99 return &validity_map_[offset >> kLineShift];
102 char* CachedData(int offset) {
103 return &data_[offset];
107 char data_[kPageSize]; // The cached data.
108 static const int kValidityMapSize = kPageSize >> kLineShift;
109 char validity_map_[kValidityMapSize]; // One byte per line.
114 friend class MipsDebugger;
116 // Registers are declared in order. See SMRL chapter 2.
123 t0, t1, t2, t3, t4, t5, t6, t7,
124 s0, s1, s2, s3, s4, s5, s6, s7,
134 pc, // pc must be the last register.
140 // Coprocessor registers.
141 // Generated code will always use doubles. So we will only use even registers.
143 f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11,
144 f12, f13, f14, f15, // f12 and f14 are arguments FPURegisters.
145 f16, f17, f18, f19, f20, f21, f22, f23, f24, f25,
146 f26, f27, f28, f29, f30, f31,
150 explicit Simulator(Isolate* isolate);
153 // The currently executing Simulator instance. Potentially there can be one
154 // for each native thread.
155 static Simulator* current(v8::internal::Isolate* isolate);
157 // Accessors for register state. Reading the pc value adheres to the MIPS
158 // architecture specification and is off by a 8 from the currently executing
160 void set_register(int reg, int32_t value);
161 void set_dw_register(int dreg, const int* dbl);
162 int32_t get_register(int reg) const;
163 double get_double_from_register_pair(int reg);
164 // Same for FPURegisters.
165 void set_fpu_register(int fpureg, int64_t value);
166 void set_fpu_register_word(int fpureg, int32_t value);
167 void set_fpu_register_hi_word(int fpureg, int32_t value);
168 void set_fpu_register_float(int fpureg, float value);
169 void set_fpu_register_double(int fpureg, double value);
170 int64_t get_fpu_register(int fpureg) const;
171 int32_t get_fpu_register_word(int fpureg) const;
172 int32_t get_fpu_register_signed_word(int fpureg) const;
173 int32_t get_fpu_register_hi_word(int fpureg) const;
174 float get_fpu_register_float(int fpureg) const;
175 double get_fpu_register_double(int fpureg) const;
176 void set_fcsr_bit(uint32_t cc, bool value);
177 bool test_fcsr_bit(uint32_t cc);
178 void set_fcsr_rounding_mode(FPURoundingMode mode);
179 unsigned int get_fcsr_rounding_mode();
180 bool set_fcsr_round_error(double original, double rounded);
181 bool set_fcsr_round_error(float original, float rounded);
182 bool set_fcsr_round64_error(double original, double rounded);
183 bool set_fcsr_round64_error(float original, float rounded);
184 void round_according_to_fcsr(double toRound, double& rounded,
185 int32_t& rounded_int, double fs);
186 void round_according_to_fcsr(float toRound, float& rounded,
187 int32_t& rounded_int, float fs);
188 void round64_according_to_fcsr(double toRound, double& rounded,
189 int64_t& rounded_int, double fs);
190 void round64_according_to_fcsr(float toRound, float& rounded,
191 int64_t& rounded_int, float fs);
192 // Special case of set_register and get_register to access the raw PC value.
193 void set_pc(int32_t value);
194 int32_t get_pc() const;
196 Address get_sp() const {
197 return reinterpret_cast<Address>(static_cast<intptr_t>(get_register(sp)));
200 // Accessor to the internal simulator stack area.
201 uintptr_t StackLimit(uintptr_t c_limit) const;
203 // Executes MIPS instructions until the PC reaches end_sim_pc.
206 // Call on program start.
207 static void Initialize(Isolate* isolate);
209 static void TearDown(HashMap* i_cache, Redirection* first);
211 // V8 generally calls into generated JS code with 5 parameters and into
212 // generated RegExp code with 7 parameters. This is a convenience function,
213 // which sets up the simulator state and grabs the result on return.
214 int32_t Call(byte* entry, int argument_count, ...);
215 // Alternative: call a 2-argument double function.
216 double CallFP(byte* entry, double d0, double d1);
218 // Push an address onto the JS stack.
219 uintptr_t PushAddress(uintptr_t address);
221 // Pop an address from the JS stack.
222 uintptr_t PopAddress();
225 void set_last_debugger_input(char* input);
226 char* last_debugger_input() { return last_debugger_input_; }
229 static void FlushICache(v8::internal::HashMap* i_cache, void* start,
232 // Returns true if pc register contains one of the 'special_values' defined
233 // below (bad_ra, end_sim_pc).
234 bool has_bad_pc() const;
237 enum special_values {
238 // Known bad pc value to ensure that the simulator does not execute
239 // without being properly setup.
241 // A pc value used to signal the simulator to stop execution. Generally
242 // the ra is set to this value on transition from native C code to
243 // simulated execution, so that the simulator can "return" to the native
246 // Unpredictable value.
247 Unpredictable = 0xbadbeaf
250 // Unsupported instructions use Format to print an error and stop execution.
251 void Format(Instruction* instr, const char* format);
253 // Read and write memory.
254 inline uint32_t ReadBU(int32_t addr);
255 inline int32_t ReadB(int32_t addr);
256 inline void WriteB(int32_t addr, uint8_t value);
257 inline void WriteB(int32_t addr, int8_t value);
259 inline uint16_t ReadHU(int32_t addr, Instruction* instr);
260 inline int16_t ReadH(int32_t addr, Instruction* instr);
261 // Note: Overloaded on the sign of the value.
262 inline void WriteH(int32_t addr, uint16_t value, Instruction* instr);
263 inline void WriteH(int32_t addr, int16_t value, Instruction* instr);
265 inline int ReadW(int32_t addr, Instruction* instr);
266 inline void WriteW(int32_t addr, int value, Instruction* instr);
268 inline double ReadD(int32_t addr, Instruction* instr);
269 inline void WriteD(int32_t addr, double value, Instruction* instr);
271 // Helpers for data value tracing.
277 // DFLOAT - Floats may have printing issues due to paired lwc1's
280 void TraceRegWr(int32_t value);
281 void TraceMemWr(int32_t addr, int32_t value, TraceType t);
282 void TraceMemRd(int32_t addr, int32_t value);
283 EmbeddedVector<char, 128> trace_buf_;
285 // Operations depending on endianness.
286 // Get Double Higher / Lower word.
287 inline int32_t GetDoubleHIW(double* addr);
288 inline int32_t GetDoubleLOW(double* addr);
289 // Set Double Higher / Lower word.
290 inline int32_t SetDoubleHIW(double* addr);
291 inline int32_t SetDoubleLOW(double* addr);
293 // Executing is handled based on the instruction type.
294 void DecodeTypeRegister(Instruction* instr);
296 // Functions called from DecodeTypeRegister.
297 void DecodeTypeRegisterCOP1();
299 void DecodeTypeRegisterCOP1X();
301 void DecodeTypeRegisterSPECIAL();
303 void DecodeTypeRegisterSPECIAL2();
305 void DecodeTypeRegisterSPECIAL3();
307 // Called from DecodeTypeRegisterCOP1.
308 void DecodeTypeRegisterSRsType();
310 void DecodeTypeRegisterDRsType();
312 void DecodeTypeRegisterWRsType();
314 void DecodeTypeRegisterLRsType();
316 Instruction* currentInstr_;
317 inline Instruction* get_instr() const { return currentInstr_; }
318 inline void set_instr(Instruction* instr) { currentInstr_ = instr; }
320 inline int32_t rs_reg() const { return currentInstr_->RsValue(); }
321 inline int32_t rs() const { return get_register(rs_reg()); }
322 inline uint32_t rs_u() const {
323 return static_cast<uint32_t>(get_register(rs_reg()));
325 inline int32_t rt_reg() const { return currentInstr_->RtValue(); }
326 inline int32_t rt() const { return get_register(rt_reg()); }
327 inline uint32_t rt_u() const {
328 return static_cast<uint32_t>(get_register(rt_reg()));
330 inline int32_t rd_reg() const { return currentInstr_->RdValue(); }
331 inline int32_t fr_reg() const { return currentInstr_->FrValue(); }
332 inline int32_t fs_reg() const { return currentInstr_->FsValue(); }
333 inline int32_t ft_reg() const { return currentInstr_->FtValue(); }
334 inline int32_t fd_reg() const { return currentInstr_->FdValue(); }
335 inline int32_t sa() const { return currentInstr_->SaValue(); }
337 inline void SetResult(int32_t rd_reg, int32_t alu_out) {
338 set_register(rd_reg, alu_out);
342 void DecodeTypeImmediate(Instruction* instr);
343 void DecodeTypeJump(Instruction* instr);
345 // Used for breakpoints and traps.
346 void SoftwareInterrupt(Instruction* instr);
348 // Stop helper functions.
349 bool IsWatchpoint(uint32_t code);
350 void PrintWatchpoint(uint32_t code);
351 void HandleStop(uint32_t code, Instruction* instr);
352 bool IsStopInstruction(Instruction* instr);
353 bool IsEnabledStop(uint32_t code);
354 void EnableStop(uint32_t code);
355 void DisableStop(uint32_t code);
356 void IncreaseStopCounter(uint32_t code);
357 void PrintStopInfo(uint32_t code);
360 // Executes one instruction.
361 void InstructionDecode(Instruction* instr);
362 // Execute one instruction placed in a branch delay slot.
363 void BranchDelayInstructionDecode(Instruction* instr) {
364 if (instr->InstructionBits() == nopInstr) {
365 // Short-cut generic nop instructions. They are always valid and they
366 // never change the simulator state.
370 if (instr->IsForbiddenInBranchDelay()) {
371 V8_Fatal(__FILE__, __LINE__,
372 "Eror:Unexpected %i opcode in a branch delay slot.",
373 instr->OpcodeValue());
375 InstructionDecode(instr);
376 SNPrintF(trace_buf_, " ");
380 static void CheckICache(v8::internal::HashMap* i_cache, Instruction* instr);
381 static void FlushOnePage(v8::internal::HashMap* i_cache, intptr_t start,
383 static CachePage* GetCachePage(v8::internal::HashMap* i_cache, void* page);
394 void SignalException(Exception e);
396 // Runtime call support.
397 static void* RedirectExternalReference(void* external_function,
398 ExternalReference::Type type);
400 // Handle arguments and return value for runtime FP functions.
401 void GetFpArgs(double* x, double* y, int32_t* z);
402 void SetFpResult(const double& result);
404 void CallInternal(byte* entry);
406 // Architecture state.
408 int32_t registers_[kNumSimuRegisters];
409 // Coprocessor Registers.
410 // Note: FP32 mode uses only the lower 32-bit part of each element,
411 // the upper 32-bit is unpredictable.
412 int64_t FPUregisters_[kNumFPURegisters];
413 // FPU control register.
416 // Simulator support.
417 // Allocate 1MB for stack.
418 static const size_t stack_size_ = 1 * 1024*1024;
425 char* last_debugger_input_;
427 // Icache simulation.
428 v8::internal::HashMap* i_cache_;
430 v8::internal::Isolate* isolate_;
432 // Registered breakpoints.
433 Instruction* break_pc_;
436 // Stop is disabled if bit 31 is set.
437 static const uint32_t kStopDisabledBit = 1 << 31;
439 // A stop is enabled, meaning the simulator will stop when meeting the
440 // instruction, if bit 31 of watched_stops_[code].count is unset.
441 // The value watched_stops_[code].count & ~(1 << 31) indicates how many times
442 // the breakpoint was hit or gone through.
443 struct StopCountAndDesc {
447 StopCountAndDesc watched_stops_[kMaxStopCode + 1];
451 // When running with the simulator transition into simulated execution at this
453 #define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
454 reinterpret_cast<Object*>(Simulator::current(Isolate::Current())->Call( \
455 FUNCTION_ADDR(entry), 5, p0, p1, p2, p3, p4))
457 #define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7, p8) \
458 Simulator::current(Isolate::Current())->Call( \
459 entry, 10, p0, p1, p2, p3, NULL, p4, p5, p6, p7, p8)
462 // The simulator has its own stack. Thus it has a different stack limit from
463 // the C-based native code. The JS-based limit normally points near the end of
464 // the simulator stack. When the C-based limit is exhausted we reflect that by
465 // lowering the JS-based limit as well, to make stack checks trigger.
466 class SimulatorStack : public v8::internal::AllStatic {
468 static inline uintptr_t JsLimitFromCLimit(Isolate* isolate,
470 return Simulator::current(isolate)->StackLimit(c_limit);
473 static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) {
474 Simulator* sim = Simulator::current(Isolate::Current());
475 return sim->PushAddress(try_catch_address);
478 static inline void UnregisterCTryCatch() {
479 Simulator::current(Isolate::Current())->PopAddress();
483 } } // namespace v8::internal
485 #endif // !defined(USE_SIMULATOR)
486 #endif // V8_MIPS_SIMULATOR_MIPS_H_