OLD | NEW |
| (Empty) |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 // Declares a Simulator for MIPS instructions if we are not generating a native | |
6 // MIPS binary. This Simulator allows us to run and debug MIPS code generation | |
7 // on regular desktop machines. | |
8 // Dart calls into generated code by "calling" the InvokeDartCode stub, | |
9 // which will start execution in the Simulator or forwards to the real entry | |
10 // on a MIPS HW platform. | |
11 | |
12 #ifndef RUNTIME_VM_SIMULATOR_MIPS_H_ | |
13 #define RUNTIME_VM_SIMULATOR_MIPS_H_ | |
14 | |
15 #ifndef RUNTIME_VM_SIMULATOR_H_ | |
16 #error Do not include simulator_mips.h directly; use simulator.h. | |
17 #endif | |
18 | |
19 #include "vm/constants_mips.h" | |
20 | |
21 namespace dart { | |
22 | |
23 class Isolate; | |
24 class Mutex; | |
25 class RawObject; | |
26 class SimulatorSetjmpBuffer; | |
27 class Thread; | |
28 | |
29 class Simulator { | |
30 public: | |
31 static const uword kSimulatorStackUnderflowSize = 64; | |
32 | |
33 Simulator(); | |
34 ~Simulator(); | |
35 | |
36 // The currently executing Simulator instance, which is associated to the | |
37 // current isolate | |
38 static Simulator* Current(); | |
39 | |
40 // Accessors for register state. | |
41 void set_register(Register reg, int32_t value); | |
42 int32_t get_register(Register reg) const; | |
43 | |
44 // Accessors for floating point register state. | |
45 void set_fregister(FRegister freg, int32_t value); | |
46 void set_fregister_float(FRegister freg, float value); | |
47 void set_fregister_double(FRegister freg, double value); | |
48 void set_fregister_long(FRegister freg, int64_t value); | |
49 | |
50 int32_t get_fregister(FRegister freg) const; | |
51 float get_fregister_float(FRegister freg) const; | |
52 double get_fregister_double(FRegister freg) const; | |
53 int64_t get_fregister_long(FRegister freg) const; | |
54 | |
55 void set_dregister_bits(DRegister freg, int64_t value); | |
56 void set_dregister(DRegister freg, double value); | |
57 | |
58 int64_t get_dregister_bits(DRegister freg) const; | |
59 double get_dregister(DRegister freg) const; | |
60 | |
61 int32_t get_sp() const { return get_register(SPREG); } | |
62 | |
63 // Accessor for the pc. | |
64 void set_pc(int32_t value) { pc_ = value; } | |
65 int32_t get_pc() const { return pc_; } | |
66 | |
67 // Accessors for hi, lo registers. | |
68 void set_hi_register(int32_t value) { hi_reg_ = value; } | |
69 void set_lo_register(int32_t value) { lo_reg_ = value; } | |
70 int32_t get_hi_register() const { return hi_reg_; } | |
71 int32_t get_lo_register() const { return lo_reg_; } | |
72 | |
73 int32_t get_fcsr_condition_bit(int32_t cc) const { | |
74 if (cc == 0) { | |
75 return 23; | |
76 } else { | |
77 return 24 + cc; | |
78 } | |
79 } | |
80 | |
81 void set_fcsr_bit(uint32_t cc, bool value) { | |
82 if (value) { | |
83 fcsr_ |= (1 << cc); | |
84 } else { | |
85 fcsr_ &= ~(1 << cc); | |
86 } | |
87 } | |
88 | |
89 bool test_fcsr_bit(uint32_t cc) { return fcsr_ & (1 << cc); } | |
90 | |
91 // Accessors to the internal simulator stack base and top. | |
92 uword StackBase() const { return reinterpret_cast<uword>(stack_); } | |
93 uword StackTop() const; | |
94 | |
95 // Accessor to the instruction counter. | |
96 uint64_t get_icount() const { return icount_; } | |
97 | |
98 // The thread's top_exit_frame_info refers to a Dart frame in the simulator | |
99 // stack. The simulator's top_exit_frame_info refers to a C++ frame in the | |
100 // native stack. | |
101 uword top_exit_frame_info() const { return top_exit_frame_info_; } | |
102 void set_top_exit_frame_info(uword value) { top_exit_frame_info_ = value; } | |
103 | |
104 // Call on program start. | |
105 static void InitOnce(); | |
106 | |
107 // Dart generally calls into generated code with 4 parameters. This is a | |
108 // convenience function, which sets up the simulator state and grabs the | |
109 // result on return. When fp_return is true the return value is the D0 | |
110 // floating point register. Otherwise, the return value is V1:V0. | |
111 int64_t Call(int32_t entry, | |
112 int32_t parameter0, | |
113 int32_t parameter1, | |
114 int32_t parameter2, | |
115 int32_t parameter3, | |
116 bool fp_return = false, | |
117 bool fp_args = false); | |
118 | |
119 // Implementation of atomic compare and exchange in the same synchronization | |
120 // domain as other synchronization primitive instructions (e.g. ldrex, strex). | |
121 static uword CompareExchange(uword* address, | |
122 uword compare_value, | |
123 uword new_value); | |
124 static uint32_t CompareExchangeUint32(uint32_t* address, | |
125 uint32_t compare_value, | |
126 uint32_t new_value); | |
127 | |
128 // Runtime and native call support. | |
129 enum CallKind { | |
130 kRuntimeCall, | |
131 kLeafRuntimeCall, | |
132 kLeafFloatRuntimeCall, | |
133 kBootstrapNativeCall, | |
134 kNativeCall | |
135 }; | |
136 static uword RedirectExternalReference(uword function, | |
137 CallKind call_kind, | |
138 int argument_count); | |
139 | |
140 static uword FunctionForRedirect(uword redirect); | |
141 | |
142 void JumpToFrame(uword pc, uword sp, uword fp, Thread* thread); | |
143 | |
144 private: | |
145 // A pc value used to signal the simulator to stop execution. Generally | |
146 // the ra is set to this value on transition from native C code to | |
147 // simulated execution, so that the simulator can "return" to the native | |
148 // C code. | |
149 static const uword kEndSimulatingPC = -1; | |
150 | |
151 // Special registers for the results of div, divu. | |
152 int32_t hi_reg_; | |
153 int32_t lo_reg_; | |
154 | |
155 int32_t registers_[kNumberOfCpuRegisters]; | |
156 int32_t fregisters_[kNumberOfFRegisters]; | |
157 int32_t fcsr_; | |
158 uword pc_; | |
159 | |
160 // Simulator support. | |
161 char* stack_; | |
162 uint64_t icount_; | |
163 bool delay_slot_; | |
164 SimulatorSetjmpBuffer* last_setjmp_buffer_; | |
165 uword top_exit_frame_info_; | |
166 | |
167 // Registered breakpoints. | |
168 Instr* break_pc_; | |
169 int32_t break_instr_; | |
170 | |
171 // Illegal memory access support. | |
172 static bool IsIllegalAddress(uword addr) { return addr < 64 * 1024; } | |
173 void HandleIllegalAccess(uword addr, Instr* instr); | |
174 | |
175 // Read and write memory. | |
176 void UnalignedAccess(const char* msg, uword addr, Instr* instr); | |
177 | |
178 // Handles a legal instruction that the simulator does not implement. | |
179 void UnimplementedInstruction(Instr* instr); | |
180 | |
181 void set_pc(uword value) { pc_ = value; } | |
182 | |
183 void Format(Instr* instr, const char* format); | |
184 | |
185 inline int8_t ReadB(uword addr); | |
186 inline uint8_t ReadBU(uword addr); | |
187 inline int16_t ReadH(uword addr, Instr* instr); | |
188 inline uint16_t ReadHU(uword addr, Instr* instr); | |
189 inline intptr_t ReadW(uword addr, Instr* instr); | |
190 | |
191 inline void WriteB(uword addr, uint8_t value); | |
192 inline void WriteH(uword addr, uint16_t value, Instr* isntr); | |
193 inline void WriteW(uword addr, intptr_t value, Instr* instr); | |
194 | |
195 inline double ReadD(uword addr, Instr* instr); | |
196 inline void WriteD(uword addr, double value, Instr* instr); | |
197 | |
198 // We keep track of 16 exclusive access address tags across all threads. | |
199 // Since we cannot simulate a native context switch, which clears | |
200 // the exclusive access state of the local monitor, we associate the thread | |
201 // requesting exclusive access to the address tag. | |
202 // Multiple threads requesting exclusive access (using the LL instruction) | |
203 // to the same address will result in multiple address tags being created for | |
204 // the same address, one per thread. | |
205 // At any given time, each thread is associated to at most one address tag. | |
206 static Mutex* exclusive_access_lock_; | |
207 static const int kNumAddressTags = 16; | |
208 static struct AddressTag { | |
209 Thread* thread; | |
210 uword addr; | |
211 } exclusive_access_state_[kNumAddressTags]; | |
212 static int next_address_tag_; | |
213 | |
214 // Synchronization primitives support. | |
215 void ClearExclusive(); | |
216 intptr_t ReadExclusiveW(uword addr, Instr* instr); | |
217 intptr_t WriteExclusiveW(uword addr, intptr_t value, Instr* instr); | |
218 | |
219 // Set access to given address to 'exclusive state' for current thread. | |
220 static void SetExclusiveAccess(uword addr); | |
221 | |
222 // Returns true if the current thread has exclusive access to given address, | |
223 // returns false otherwise. In either case, set access to given address to | |
224 // 'open state' for all threads. | |
225 // If given addr is NULL, set access to 'open state' for current | |
226 // thread (CLREX). | |
227 static bool HasExclusiveAccessAndOpen(uword addr); | |
228 | |
229 void DoBranch(Instr* instr, bool taken, bool likely); | |
230 void DoBreak(Instr* instr); | |
231 | |
232 void DecodeSpecial(Instr* instr); | |
233 void DecodeSpecial2(Instr* instr); | |
234 void DecodeRegImm(Instr* instr); | |
235 void DecodeCop1(Instr* instr); | |
236 void InstructionDecode(Instr* instr); | |
237 | |
238 void Execute(); | |
239 void ExecuteDelaySlot(); | |
240 | |
241 // Returns true if tracing of executed instructions is enabled. | |
242 bool IsTracingExecution() const; | |
243 | |
244 // Longjmp support for exceptions. | |
245 SimulatorSetjmpBuffer* last_setjmp_buffer() { return last_setjmp_buffer_; } | |
246 void set_last_setjmp_buffer(SimulatorSetjmpBuffer* buffer) { | |
247 last_setjmp_buffer_ = buffer; | |
248 } | |
249 | |
250 friend class SimulatorDebugger; | |
251 friend class SimulatorSetjmpBuffer; | |
252 DISALLOW_COPY_AND_ASSIGN(Simulator); | |
253 }; | |
254 | |
255 } // namespace dart | |
256 | |
257 #endif // RUNTIME_VM_SIMULATOR_MIPS_H_ | |
OLD | NEW |