OLD | NEW |
---|---|
1 // Copyright 2011 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <limits.h> | 5 #include <limits.h> |
6 #include <stdarg.h> | 6 #include <stdarg.h> |
7 #include <stdlib.h> | 7 #include <stdlib.h> |
8 #include <cmath> | 8 #include <cmath> |
9 | 9 |
10 #include "src/v8.h" | 10 #include "src/v8.h" |
(...skipping 2061 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2072 *do_interrupt = rs != rt; | 2072 *do_interrupt = rs != rt; |
2073 break; | 2073 break; |
2074 case MOVN: | 2074 case MOVN: |
2075 case MOVZ: | 2075 case MOVZ: |
2076 case MOVCI: | 2076 case MOVCI: |
2077 // No action taken on decode. | 2077 // No action taken on decode. |
2078 break; | 2078 break; |
2079 case DIV: | 2079 case DIV: |
2080 case DIVU: | 2080 case DIVU: |
2081 // div and divu never raise exceptions. | 2081 // div and divu never raise exceptions. |
2082 case SELEQZ_S: | |
2083 case SELNEZ_S: | |
2082 break; | 2084 break; |
2083 default: | 2085 default: |
2084 UNREACHABLE(); | 2086 UNREACHABLE(); |
2085 } | 2087 } |
2086 break; | 2088 break; |
2087 case SPECIAL2: | 2089 case SPECIAL2: |
2088 switch (instr->FunctionFieldRaw()) { | 2090 switch (instr->FunctionFieldRaw()) { |
2089 case MUL: | 2091 case MUL: |
2090 *alu_out = rs_u * rt_u; // Only the lower 32 bits are kept. | 2092 *alu_out = rs_u * rt_u; // Only the lower 32 bits are kept. |
2091 break; | 2093 break; |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2123 default: | 2125 default: |
2124 UNREACHABLE(); | 2126 UNREACHABLE(); |
2125 } | 2127 } |
2126 break; | 2128 break; |
2127 default: | 2129 default: |
2128 UNREACHABLE(); | 2130 UNREACHABLE(); |
2129 } | 2131 } |
2130 } | 2132 } |
2131 | 2133 |
2132 | 2134 |
2133 void Simulator::DecodeTypeRegister(Instruction* instr) { | 2135 void Simulator::DecodeTypeRegisterDRsType(Instruction* instr, |
2134 // Instruction fields. | 2136 const int32_t& fr_reg, |
2135 const Opcode op = instr->OpcodeFieldRaw(); | 2137 const int32_t& fs_reg, |
2136 const int32_t rs_reg = instr->RsValue(); | 2138 const int32_t& ft_reg, |
2137 const int32_t rs = get_register(rs_reg); | 2139 const int32_t& fd_reg) { |
2138 const uint32_t rs_u = static_cast<uint32_t>(rs); | 2140 double ft, fs; |
2139 const int32_t rt_reg = instr->RtValue(); | 2141 uint32_t cc, fcsr_cc; |
2140 const int32_t rt = get_register(rt_reg); | 2142 int64_t i64; |
2141 const uint32_t rt_u = static_cast<uint32_t>(rt); | 2143 fs = get_fpu_register_double(fs_reg); |
2142 const int32_t rd_reg = instr->RdValue(); | 2144 ft = get_fpu_register_double(ft_reg); |
2143 | 2145 int64_t ft_int = static_cast<int64_t>(ft); |
2144 const int32_t fr_reg = instr->FrValue(); | 2146 cc = instr->FCccValue(); |
2145 const int32_t fs_reg = instr->FsValue(); | 2147 fcsr_cc = get_fcsr_condition_bit(cc); |
2146 const int32_t ft_reg = instr->FtValue(); | 2148 switch (instr->FunctionFieldRaw()) { |
2147 const int32_t fd_reg = instr->FdValue(); | 2149 case SELEQZ_C: |
2148 int64_t i64hilo = 0; | 2150 DCHECK(IsMipsArchVariant(kMips32r6)); |
2149 uint64_t u64hilo = 0; | 2151 set_fpu_register_double(fd_reg, (ft_int & 0x1) == 0 ? fs : 0.0); |
2150 | 2152 break; |
2151 // ALU output. | 2153 case SELNEZ_C: |
2152 // It should not be used as is. Instructions using it should always | 2154 DCHECK(IsMipsArchVariant(kMips32r6)); |
2153 // initialize it first. | 2155 set_fpu_register_double(fd_reg, (ft_int & 0x1) != 0 ? fs : 0.0); |
2154 int32_t alu_out = 0x12345678; | 2156 break; |
2155 | 2157 case ADD_D: |
2156 // For break and trap instructions. | 2158 set_fpu_register_double(fd_reg, fs + ft); |
2157 bool do_interrupt = false; | 2159 break; |
2158 | 2160 case SUB_D: |
2159 // For jr and jalr. | 2161 set_fpu_register_double(fd_reg, fs - ft); |
2160 // Get current pc. | 2162 break; |
2161 int32_t current_pc = get_pc(); | 2163 case MUL_D: |
2162 // Next pc | 2164 set_fpu_register_double(fd_reg, fs * ft); |
2163 int32_t next_pc = 0; | 2165 break; |
2164 int32_t return_addr_reg = 31; | 2166 case DIV_D: |
2165 | 2167 set_fpu_register_double(fd_reg, fs / ft); |
2166 // Set up the variables if needed before executing the instruction. | 2168 break; |
2167 ConfigureTypeRegister(instr, | 2169 case ABS_D: |
2168 &alu_out, | 2170 set_fpu_register_double(fd_reg, fabs(fs)); |
2169 &i64hilo, | 2171 break; |
2170 &u64hilo, | 2172 case MOV_D: |
2171 &next_pc, | 2173 set_fpu_register_double(fd_reg, fs); |
2172 &return_addr_reg, | 2174 break; |
2173 &do_interrupt); | 2175 case NEG_D: |
2174 | 2176 set_fpu_register_double(fd_reg, -fs); |
2175 // ---------- Raise exceptions triggered. | 2177 break; |
2176 SignalExceptions(); | 2178 case SQRT_D: |
2177 | 2179 set_fpu_register_double(fd_reg, fast_sqrt(fs)); |
2178 // ---------- Execution. | 2180 break; |
2179 switch (op) { | 2181 case C_UN_D: |
2180 case COP1: | 2182 set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft)); |
2181 switch (instr->RsFieldRaw()) { | 2183 break; |
2182 case CFC1: | 2184 case C_EQ_D: |
2183 set_register(rt_reg, alu_out); | 2185 set_fcsr_bit(fcsr_cc, (fs == ft)); |
2184 break; | 2186 break; |
2185 case MFC1: | 2187 case C_UEQ_D: |
2186 set_register(rt_reg, alu_out); | 2188 set_fcsr_bit(fcsr_cc, (fs == ft) || (std::isnan(fs) || std::isnan(ft))); |
2187 break; | 2189 break; |
2188 case MFHC1: | 2190 case C_OLT_D: |
2189 set_register(rt_reg, alu_out); | 2191 set_fcsr_bit(fcsr_cc, (fs < ft)); |
2190 break; | 2192 break; |
2191 case CTC1: | 2193 case C_ULT_D: |
2192 // At the moment only FCSR is supported. | 2194 set_fcsr_bit(fcsr_cc, (fs < ft) || (std::isnan(fs) || std::isnan(ft))); |
2193 DCHECK(fs_reg == kFCSRRegister); | 2195 break; |
2194 FCSR_ = registers_[rt_reg]; | 2196 case C_OLE_D: |
2195 break; | 2197 set_fcsr_bit(fcsr_cc, (fs <= ft)); |
2196 case MTC1: | 2198 break; |
2197 // Hardware writes upper 32-bits to zero on mtc1. | 2199 case C_ULE_D: |
2198 set_fpu_register_hi_word(fs_reg, 0); | 2200 set_fcsr_bit(fcsr_cc, (fs <= ft) || (std::isnan(fs) || std::isnan(ft))); |
2199 set_fpu_register_word(fs_reg, registers_[rt_reg]); | 2201 break; |
2200 break; | 2202 case CVT_W_D: // Convert double to word. |
2201 case MTHC1: | 2203 // Rounding modes are not yet supported. |
2202 set_fpu_register_hi_word(fs_reg, registers_[rt_reg]); | 2204 DCHECK((FCSR_ & 3) == 0); |
2203 break; | 2205 // In rounding mode 0 it should behave like ROUND. |
2204 case S: | 2206 case ROUND_W_D: // Round double to word (round half to even). |
2205 float f; | 2207 { |
2206 switch (instr->FunctionFieldRaw()) { | 2208 double rounded = std::floor(fs + 0.5); |
2207 case CVT_D_S: | 2209 int32_t result = static_cast<int32_t>(rounded); |
2208 f = get_fpu_register_float(fs_reg); | 2210 if ((result & 1) != 0 && result - fs == 0.5) { |
2209 set_fpu_register_double(fd_reg, static_cast<double>(f)); | 2211 // If the number is halfway between two integers, |
2210 break; | 2212 // round to the even one. |
2211 default: | 2213 result--; |
2212 // CVT_W_S CVT_L_S TRUNC_W_S ROUND_W_S ROUND_L_S FLOOR_W_S FLOOR_L_S | 2214 } |
2213 // CEIL_W_S CEIL_L_S CVT_PS_S are unimplemented. | 2215 set_fpu_register_word(fd_reg, result); |
2214 UNREACHABLE(); | 2216 if (set_fcsr_round_error(fs, rounded)) { |
2215 } | 2217 set_fpu_register_word(fd_reg, kFPUInvalidResult); |
2216 break; | 2218 } |
2217 case D: | 2219 } break; |
2218 double ft, fs; | 2220 case TRUNC_W_D: // Truncate double to word (round towards 0). |
2219 uint32_t cc, fcsr_cc; | 2221 { |
2220 int64_t i64; | 2222 double rounded = trunc(fs); |
2221 fs = get_fpu_register_double(fs_reg); | 2223 int32_t result = static_cast<int32_t>(rounded); |
2222 ft = get_fpu_register_double(ft_reg); | 2224 set_fpu_register_word(fd_reg, result); |
2223 cc = instr->FCccValue(); | 2225 if (set_fcsr_round_error(fs, rounded)) { |
2224 fcsr_cc = get_fcsr_condition_bit(cc); | 2226 set_fpu_register_word(fd_reg, kFPUInvalidResult); |
2225 switch (instr->FunctionFieldRaw()) { | 2227 } |
2226 case ADD_D: | 2228 } break; |
2227 set_fpu_register_double(fd_reg, fs + ft); | 2229 case FLOOR_W_D: // Round double to word towards negative infinity. |
2228 break; | 2230 { |
2229 case SUB_D: | 2231 double rounded = std::floor(fs); |
2230 set_fpu_register_double(fd_reg, fs - ft); | 2232 int32_t result = static_cast<int32_t>(rounded); |
2231 break; | 2233 set_fpu_register_word(fd_reg, result); |
2232 case MUL_D: | 2234 if (set_fcsr_round_error(fs, rounded)) { |
2233 set_fpu_register_double(fd_reg, fs * ft); | 2235 set_fpu_register_word(fd_reg, kFPUInvalidResult); |
2234 break; | 2236 } |
2235 case DIV_D: | 2237 } break; |
2236 set_fpu_register_double(fd_reg, fs / ft); | 2238 case CEIL_W_D: // Round double to word towards positive infinity. |
2237 break; | 2239 { |
2238 case ABS_D: | 2240 double rounded = std::ceil(fs); |
2239 set_fpu_register_double(fd_reg, fabs(fs)); | 2241 int32_t result = static_cast<int32_t>(rounded); |
2240 break; | 2242 set_fpu_register_word(fd_reg, result); |
2241 case MOV_D: | 2243 if (set_fcsr_round_error(fs, rounded)) { |
2242 set_fpu_register_double(fd_reg, fs); | 2244 set_fpu_register_word(fd_reg, kFPUInvalidResult); |
2243 break; | 2245 } |
2244 case NEG_D: | 2246 } break; |
2245 set_fpu_register_double(fd_reg, -fs); | 2247 case CVT_S_D: // Convert double to float (single). |
2246 break; | 2248 set_fpu_register_float(fd_reg, static_cast<float>(fs)); |
2247 case SQRT_D: | 2249 break; |
2248 set_fpu_register_double(fd_reg, fast_sqrt(fs)); | 2250 case CVT_L_D: { // Mips32r2: Truncate double to 64-bit long-word. |
2249 break; | 2251 double rounded = trunc(fs); |
2250 case C_UN_D: | 2252 i64 = static_cast<int64_t>(rounded); |
2251 set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft)); | 2253 if (IsFp64Mode()) { |
2252 break; | 2254 set_fpu_register(fd_reg, i64); |
2253 case C_EQ_D: | 2255 } else { |
2254 set_fcsr_bit(fcsr_cc, (fs == ft)); | 2256 set_fpu_register_word(fd_reg, i64 & 0xffffffff); |
2255 break; | 2257 set_fpu_register_word(fd_reg + 1, i64 >> 32); |
2256 case C_UEQ_D: | 2258 } |
2257 set_fcsr_bit(fcsr_cc, | 2259 break; |
2258 (fs == ft) || (std::isnan(fs) || std::isnan(ft))); | 2260 } |
2259 break; | 2261 case TRUNC_L_D: { // Mips32r2 instruction. |
paul.l...
2015/03/31 04:02:01
This comment (and many other like it need to be ch
| |
2260 case C_OLT_D: | 2262 double rounded = trunc(fs); |
2261 set_fcsr_bit(fcsr_cc, (fs < ft)); | 2263 i64 = static_cast<int64_t>(rounded); |
2262 break; | 2264 if (IsFp64Mode()) { |
2263 case C_ULT_D: | 2265 set_fpu_register(fd_reg, i64); |
2264 set_fcsr_bit(fcsr_cc, | 2266 } else { |
2265 (fs < ft) || (std::isnan(fs) || std::isnan(ft))); | 2267 set_fpu_register_word(fd_reg, i64 & 0xffffffff); |
2266 break; | 2268 set_fpu_register_word(fd_reg + 1, i64 >> 32); |
2267 case C_OLE_D: | 2269 } |
2268 set_fcsr_bit(fcsr_cc, (fs <= ft)); | 2270 break; |
2269 break; | 2271 } |
2270 case C_ULE_D: | 2272 case ROUND_L_D: { // Mips32r2 instruction. |
2271 set_fcsr_bit(fcsr_cc, | 2273 double rounded = fs > 0 ? std::floor(fs + 0.5) : std::ceil(fs - 0.5); |
2272 (fs <= ft) || (std::isnan(fs) || std::isnan(ft))); | 2274 i64 = static_cast<int64_t>(rounded); |
2273 break; | 2275 if (IsFp64Mode()) { |
2274 case CVT_W_D: // Convert double to word. | 2276 set_fpu_register(fd_reg, i64); |
2275 // Rounding modes are not yet supported. | 2277 } else { |
2276 DCHECK((FCSR_ & 3) == 0); | 2278 set_fpu_register_word(fd_reg, i64 & 0xffffffff); |
2277 // In rounding mode 0 it should behave like ROUND. | 2279 set_fpu_register_word(fd_reg + 1, i64 >> 32); |
2278 case ROUND_W_D: // Round double to word (round half to even). | 2280 } |
2279 { | 2281 break; |
2280 double rounded = std::floor(fs + 0.5); | 2282 } |
2281 int32_t result = static_cast<int32_t>(rounded); | 2283 case FLOOR_L_D: // Mips32r2 instruction. |
2282 if ((result & 1) != 0 && result - fs == 0.5) { | 2284 i64 = static_cast<int64_t>(std::floor(fs)); |
2283 // If the number is halfway between two integers, | 2285 if (IsFp64Mode()) { |
2284 // round to the even one. | 2286 set_fpu_register(fd_reg, i64); |
2285 result--; | 2287 } else { |
2286 } | 2288 set_fpu_register_word(fd_reg, i64 & 0xffffffff); |
2287 set_fpu_register_word(fd_reg, result); | 2289 set_fpu_register_word(fd_reg + 1, i64 >> 32); |
2288 if (set_fcsr_round_error(fs, rounded)) { | 2290 } |
2289 set_fpu_register_word(fd_reg, kFPUInvalidResult); | 2291 break; |
2290 } | 2292 case CEIL_L_D: // Mips32r2 instruction. |
2291 } | 2293 i64 = static_cast<int64_t>(std::ceil(fs)); |
2292 break; | 2294 if (IsFp64Mode()) { |
2293 case TRUNC_W_D: // Truncate double to word (round towards 0). | 2295 set_fpu_register(fd_reg, i64); |
2294 { | 2296 } else { |
2295 double rounded = trunc(fs); | 2297 set_fpu_register_word(fd_reg, i64 & 0xffffffff); |
2296 int32_t result = static_cast<int32_t>(rounded); | 2298 set_fpu_register_word(fd_reg + 1, i64 >> 32); |
2297 set_fpu_register_word(fd_reg, result); | 2299 } |
2298 if (set_fcsr_round_error(fs, rounded)) { | 2300 break; |
2299 set_fpu_register_word(fd_reg, kFPUInvalidResult); | 2301 case C_F_D: |
2300 } | 2302 UNIMPLEMENTED_MIPS(); |
2301 } | 2303 break; |
2302 break; | 2304 default: |
2303 case FLOOR_W_D: // Round double to word towards negative infinity. | 2305 UNREACHABLE(); |
2304 { | 2306 } |
2305 double rounded = std::floor(fs); | 2307 } |
2306 int32_t result = static_cast<int32_t>(rounded); | 2308 |
2307 set_fpu_register_word(fd_reg, result); | 2309 |
2308 if (set_fcsr_round_error(fs, rounded)) { | 2310 void Simulator::DecodeTypeRegisterWRsType(Instruction* instr, int32_t& alu_out, |
2309 set_fpu_register_word(fd_reg, kFPUInvalidResult); | 2311 const int32_t& fd_reg, |
2310 } | 2312 const int32_t& fs_reg) { |
2311 } | 2313 switch (instr->FunctionFieldRaw()) { |
2312 break; | 2314 case CVT_S_W: // Convert word to float (single). |
2313 case CEIL_W_D: // Round double to word towards positive infinity. | 2315 alu_out = get_fpu_register_signed_word(fs_reg); |
2314 { | 2316 set_fpu_register_float(fd_reg, static_cast<float>(alu_out)); |
2315 double rounded = std::ceil(fs); | 2317 break; |
2316 int32_t result = static_cast<int32_t>(rounded); | 2318 case CVT_D_W: // Convert word to double. |
2317 set_fpu_register_word(fd_reg, result); | 2319 alu_out = get_fpu_register_signed_word(fs_reg); |
2318 if (set_fcsr_round_error(fs, rounded)) { | 2320 set_fpu_register_double(fd_reg, static_cast<double>(alu_out)); |
2319 set_fpu_register_word(fd_reg, kFPUInvalidResult); | 2321 break; |
2320 } | 2322 default: // Mips64r6 CMP.S instructions unimplemented. |
2321 } | 2323 UNREACHABLE(); |
2322 break; | 2324 } |
2323 case CVT_S_D: // Convert double to float (single). | 2325 } |
2324 set_fpu_register_float(fd_reg, static_cast<float>(fs)); | 2326 |
2325 break; | 2327 |
2326 case CVT_L_D: { // Mips32r2: Truncate double to 64-bit long-word. | 2328 void Simulator::DecodeTypeRegisterSRsType(Instruction* instr, |
2327 double rounded = trunc(fs); | 2329 const int32_t& ft_reg, |
2328 i64 = static_cast<int64_t>(rounded); | 2330 const int32_t& fs_reg, |
2329 if (IsFp64Mode()) { | 2331 const int32_t& fd_reg) { |
2330 set_fpu_register(fd_reg, i64); | 2332 float f; |
2331 } else { | 2333 double ft = get_fpu_register_double(ft_reg); |
2332 set_fpu_register_word(fd_reg, i64 & 0xffffffff); | 2334 int64_t ft_int = static_cast<int64_t>(ft); |
2333 set_fpu_register_word(fd_reg + 1, i64 >> 32); | 2335 switch (instr->FunctionFieldRaw()) { |
2334 } | 2336 case CVT_D_S: |
2335 break; | 2337 f = get_fpu_register_float(fs_reg); |
2336 } | 2338 set_fpu_register_double(fd_reg, static_cast<double>(f)); |
2337 case TRUNC_L_D: { // Mips32r2 instruction. | 2339 break; |
2338 double rounded = trunc(fs); | 2340 case SELEQZ_C: |
2339 i64 = static_cast<int64_t>(rounded); | 2341 DCHECK(IsMipsArchVariant(kMips32r6)); |
2340 if (IsFp64Mode()) { | 2342 set_fpu_register_double( |
2341 set_fpu_register(fd_reg, i64); | 2343 fd_reg, (ft_int & 0x1) == 0 ? get_fpu_register_double(fs_reg) : 0.0); |
2342 } else { | 2344 break; |
2343 set_fpu_register_word(fd_reg, i64 & 0xffffffff); | 2345 case SELNEZ_C: |
2344 set_fpu_register_word(fd_reg + 1, i64 >> 32); | 2346 DCHECK(IsMipsArchVariant(kMips32r6)); |
2345 } | 2347 set_fpu_register_double( |
2346 break; | 2348 fd_reg, (ft_int & 0x1) != 0 ? get_fpu_register_double(fs_reg) : 0.0); |
2347 } | 2349 break; |
2348 case ROUND_L_D: { // Mips32r2 instruction. | 2350 default: |
2349 double rounded = | 2351 // CVT_W_S CVT_L_S TRUNC_W_S ROUND_W_S ROUND_L_S FLOOR_W_S FLOOR_L_S |
2350 fs > 0 ? std::floor(fs + 0.5) : std::ceil(fs - 0.5); | 2352 // CEIL_W_S CEIL_L_S CVT_PS_S are unimplemented. |
2351 i64 = static_cast<int64_t>(rounded); | 2353 UNREACHABLE(); |
2352 if (IsFp64Mode()) { | 2354 } |
2353 set_fpu_register(fd_reg, i64); | 2355 } |
2354 } else { | 2356 |
2355 set_fpu_register_word(fd_reg, i64 & 0xffffffff); | 2357 |
2356 set_fpu_register_word(fd_reg + 1, i64 >> 32); | 2358 void Simulator::DecodeTypeRegisterLRsType(Instruction* instr, |
2357 } | 2359 const int32_t& ft_reg, |
2358 break; | 2360 const int32_t& fs_reg, |
2359 } | 2361 const int32_t& fd_reg) { |
2360 case FLOOR_L_D: // Mips32r2 instruction. | 2362 double fs = get_fpu_register_double(fs_reg); |
2361 i64 = static_cast<int64_t>(std::floor(fs)); | 2363 double ft = get_fpu_register_double(ft_reg); |
2362 if (IsFp64Mode()) { | 2364 switch (instr->FunctionFieldRaw()) { |
2363 set_fpu_register(fd_reg, i64); | 2365 case CVT_D_L: // Mips32r2 instruction. |
2364 } else { | 2366 // Watch the signs here, we want 2 32-bit vals |
2365 set_fpu_register_word(fd_reg, i64 & 0xffffffff); | 2367 // to make a sign-64. |
2366 set_fpu_register_word(fd_reg + 1, i64 >> 32); | 2368 int64_t i64; |
2367 } | 2369 if (IsFp64Mode()) { |
2368 break; | 2370 i64 = get_fpu_register(fs_reg); |
2369 case CEIL_L_D: // Mips32r2 instruction. | 2371 } else { |
2370 i64 = static_cast<int64_t>(std::ceil(fs)); | 2372 i64 = static_cast<uint32_t>(get_fpu_register_word(fs_reg)); |
2371 if (IsFp64Mode()) { | 2373 i64 |= static_cast<int64_t>(get_fpu_register_word(fs_reg + 1)) << 32; |
2372 set_fpu_register(fd_reg, i64); | 2374 } |
2373 } else { | 2375 set_fpu_register_double(fd_reg, static_cast<double>(i64)); |
2374 set_fpu_register_word(fd_reg, i64 & 0xffffffff); | 2376 break; |
2375 set_fpu_register_word(fd_reg + 1, i64 >> 32); | 2377 case CVT_S_L: |
2376 } | 2378 UNIMPLEMENTED_MIPS(); |
2377 break; | 2379 break; |
2378 case C_F_D: | 2380 case CMP_AF: // Mips64r6 CMP.D instructions. |
2379 UNIMPLEMENTED_MIPS(); | 2381 UNIMPLEMENTED_MIPS(); |
2380 break; | 2382 break; |
2381 default: | 2383 case CMP_UN: |
2382 UNREACHABLE(); | 2384 if (std::isnan(fs) || std::isnan(ft)) { |
2383 } | 2385 set_fpu_register(fd_reg, -1); |
2384 break; | 2386 } else { |
2385 case W: | 2387 set_fpu_register(fd_reg, 0); |
2386 switch (instr->FunctionFieldRaw()) { | 2388 } |
2387 case CVT_S_W: // Convert word to float (single). | 2389 break; |
2388 alu_out = get_fpu_register_signed_word(fs_reg); | 2390 case CMP_EQ: |
2389 set_fpu_register_float(fd_reg, static_cast<float>(alu_out)); | 2391 if (fs == ft) { |
2390 break; | 2392 set_fpu_register(fd_reg, -1); |
2391 case CVT_D_W: // Convert word to double. | 2393 } else { |
2392 alu_out = get_fpu_register_signed_word(fs_reg); | 2394 set_fpu_register(fd_reg, 0); |
2393 set_fpu_register_double(fd_reg, static_cast<double>(alu_out)); | 2395 } |
2394 break; | 2396 break; |
2395 default: // Mips64r6 CMP.S instructions unimplemented. | 2397 case CMP_UEQ: |
2396 UNREACHABLE(); | 2398 if ((fs == ft) || (std::isnan(fs) || std::isnan(ft))) { |
2397 } | 2399 set_fpu_register(fd_reg, -1); |
2398 break; | 2400 } else { |
2399 case L: | 2401 set_fpu_register(fd_reg, 0); |
2400 fs = get_fpu_register_double(fs_reg); | 2402 } |
2401 ft = get_fpu_register_double(ft_reg); | 2403 break; |
2402 switch (instr->FunctionFieldRaw()) { | 2404 case CMP_LT: |
2403 case CVT_D_L: // Mips32r2 instruction. | 2405 if (fs < ft) { |
2404 // Watch the signs here, we want 2 32-bit vals | 2406 set_fpu_register(fd_reg, -1); |
2405 // to make a sign-64. | 2407 } else { |
2406 if (IsFp64Mode()) { | 2408 set_fpu_register(fd_reg, 0); |
2407 i64 = get_fpu_register(fs_reg); | 2409 } |
2408 } else { | 2410 break; |
2409 i64 = static_cast<uint32_t>(get_fpu_register_word(fs_reg)); | 2411 case CMP_ULT: |
2410 i64 |= static_cast<int64_t>( | 2412 if ((fs < ft) || (std::isnan(fs) || std::isnan(ft))) { |
2411 get_fpu_register_word(fs_reg + 1)) << 32; | 2413 set_fpu_register(fd_reg, -1); |
2412 } | 2414 } else { |
2413 set_fpu_register_double(fd_reg, static_cast<double>(i64)); | 2415 set_fpu_register(fd_reg, 0); |
2414 break; | 2416 } |
2415 case CVT_S_L: | 2417 break; |
2416 UNIMPLEMENTED_MIPS(); | 2418 case CMP_LE: |
2417 break; | 2419 if (fs <= ft) { |
2418 case CMP_AF: // Mips64r6 CMP.D instructions. | 2420 set_fpu_register(fd_reg, -1); |
2419 UNIMPLEMENTED_MIPS(); | 2421 } else { |
2420 break; | 2422 set_fpu_register(fd_reg, 0); |
2421 case CMP_UN: | 2423 } |
2422 if (std::isnan(fs) || std::isnan(ft)) { | 2424 break; |
2423 set_fpu_register(fd_reg, -1); | 2425 case CMP_ULE: |
2424 } else { | 2426 if ((fs <= ft) || (std::isnan(fs) || std::isnan(ft))) { |
2425 set_fpu_register(fd_reg, 0); | 2427 set_fpu_register(fd_reg, -1); |
2426 } | 2428 } else { |
2427 break; | 2429 set_fpu_register(fd_reg, 0); |
2428 case CMP_EQ: | 2430 } |
2429 if (fs == ft) { | 2431 break; |
2430 set_fpu_register(fd_reg, -1); | 2432 default: // CMP_OR CMP_UNE CMP_NE UNIMPLEMENTED. |
2431 } else { | 2433 UNREACHABLE(); |
2432 set_fpu_register(fd_reg, 0); | 2434 } |
2433 } | 2435 } |
2434 break; | 2436 |
2435 case CMP_UEQ: | 2437 |
2436 if ((fs == ft) || (std::isnan(fs) || std::isnan(ft))) { | 2438 void Simulator::DecodeTypeRegisterCOP1( |
2437 set_fpu_register(fd_reg, -1); | 2439 Instruction* instr, const int32_t& rs_reg, const int32_t& rs, |
2438 } else { | 2440 const uint32_t& rs_u, const int32_t& rt_reg, const int32_t& rt, |
2439 set_fpu_register(fd_reg, 0); | 2441 const uint32_t& rt_u, const int32_t& rd_reg, const int32_t& fr_reg, |
2440 } | 2442 const int32_t& fs_reg, const int32_t& ft_reg, const int32_t& fd_reg, |
2441 break; | 2443 int64_t& i64hilo, uint64_t& u64hilo, int32_t& alu_out, bool& do_interrupt, |
2442 case CMP_LT: | 2444 int32_t& current_pc, int32_t& next_pc, int32_t& return_addr_reg) { |
2443 if (fs < ft) { | 2445 switch (instr->RsFieldRaw()) { |
2444 set_fpu_register(fd_reg, -1); | 2446 case CFC1: |
2445 } else { | 2447 set_register(rt_reg, alu_out); |
2446 set_fpu_register(fd_reg, 0); | 2448 break; |
2447 } | 2449 case MFC1: |
2448 break; | 2450 set_register(rt_reg, alu_out); |
2449 case CMP_ULT: | 2451 break; |
2450 if ((fs < ft) || (std::isnan(fs) || std::isnan(ft))) { | 2452 case MFHC1: |
2451 set_fpu_register(fd_reg, -1); | 2453 set_register(rt_reg, alu_out); |
2452 } else { | 2454 break; |
2453 set_fpu_register(fd_reg, 0); | 2455 case CTC1: |
2454 } | 2456 // At the moment only FCSR is supported. |
2455 break; | 2457 DCHECK(fs_reg == kFCSRRegister); |
2456 case CMP_LE: | 2458 FCSR_ = registers_[rt_reg]; |
2457 if (fs <= ft) { | 2459 break; |
2458 set_fpu_register(fd_reg, -1); | 2460 case MTC1: |
2459 } else { | 2461 // Hardware writes upper 32-bits to zero on mtc1. |
2460 set_fpu_register(fd_reg, 0); | 2462 set_fpu_register_hi_word(fs_reg, 0); |
2461 } | 2463 set_fpu_register_word(fs_reg, registers_[rt_reg]); |
2462 break; | 2464 break; |
2463 case CMP_ULE: | 2465 case MTHC1: |
2464 if ((fs <= ft) || (std::isnan(fs) || std::isnan(ft))) { | 2466 set_fpu_register_hi_word(fs_reg, registers_[rt_reg]); |
2465 set_fpu_register(fd_reg, -1); | 2467 break; |
2466 } else { | 2468 case S: { |
2467 set_fpu_register(fd_reg, 0); | 2469 DecodeTypeRegisterSRsType(instr, ft_reg, fs_reg, fd_reg); |
2468 } | 2470 break; |
2469 break; | 2471 } |
2470 default: // CMP_OR CMP_UNE CMP_NE UNIMPLEMENTED. | 2472 case D: |
2471 UNREACHABLE(); | 2473 DecodeTypeRegisterDRsType(instr, fr_reg, fs_reg, ft_reg, fd_reg); |
2472 } | 2474 break; |
2473 break; | 2475 case W: |
2474 default: | 2476 DecodeTypeRegisterWRsType(instr, alu_out, fd_reg, fs_reg); |
2475 UNREACHABLE(); | 2477 break; |
2476 } | 2478 case L: |
2477 break; | 2479 DecodeTypeRegisterLRsType(instr, ft_reg, fs_reg, fd_reg); |
2478 case COP1X: | 2480 break; |
2479 switch (instr->FunctionFieldRaw()) { | 2481 default: |
2480 case MADD_D: | 2482 UNREACHABLE(); |
2481 double fr, ft, fs; | 2483 } |
2482 fr = get_fpu_register_double(fr_reg); | 2484 } |
2483 fs = get_fpu_register_double(fs_reg); | 2485 |
2484 ft = get_fpu_register_double(ft_reg); | 2486 |
2485 set_fpu_register_double(fd_reg, fs * ft + fr); | 2487 void Simulator::DecodeTypeRegisterCOP1X(Instruction* instr, |
2486 break; | 2488 const int32_t& fr_reg, |
2487 default: | 2489 const int32_t& fs_reg, |
2488 UNREACHABLE(); | 2490 const int32_t& ft_reg, |
2489 } | 2491 const int32_t& fd_reg) { |
2490 break; | 2492 switch (instr->FunctionFieldRaw()) { |
2491 case SPECIAL: | 2493 case MADD_D: |
2492 switch (instr->FunctionFieldRaw()) { | 2494 double fr, ft, fs; |
2495 fr = get_fpu_register_double(fr_reg); | |
2496 fs = get_fpu_register_double(fs_reg); | |
2497 ft = get_fpu_register_double(ft_reg); | |
2498 set_fpu_register_double(fd_reg, fs * ft + fr); | |
2499 break; | |
2500 default: | |
2501 UNREACHABLE(); | |
2502 } | |
2503 } | |
2504 | |
2505 | |
2506 void Simulator::DecodeTypeRegisterSPECIAL( | |
2507 Instruction* instr, const int32_t& rs_reg, const int32_t& rs, | |
2508 const uint32_t& rs_u, const int32_t& rt_reg, const int32_t& rt, | |
2509 const uint32_t& rt_u, const int32_t& rd_reg, const int32_t& fr_reg, | |
2510 const int32_t& fs_reg, const int32_t& ft_reg, const int32_t& fd_reg, | |
2511 int64_t& i64hilo, uint64_t& u64hilo, int32_t& alu_out, bool& do_interrupt, | |
2512 int32_t& current_pc, int32_t& next_pc, int32_t& return_addr_reg) { | |
2513 switch (instr->FunctionFieldRaw()) { | |
2514 case SELEQZ_S: | |
2515 DCHECK(IsMipsArchVariant(kMips32r6)); | |
2516 set_register(rd_reg, rt == 0 ? rs : 0); | |
2517 break; | |
2518 case SELNEZ_S: | |
2519 DCHECK(IsMipsArchVariant(kMips32r6)); | |
2520 set_register(rd_reg, rt != 0 ? rs : 0); | |
2521 break; | |
2493 case JR: { | 2522 case JR: { |
2494 Instruction* branch_delay_instr = reinterpret_cast<Instruction*>( | 2523 Instruction* branch_delay_instr = reinterpret_cast<Instruction*>( |
2495 current_pc+Instruction::kInstrSize); | 2524 current_pc+Instruction::kInstrSize); |
2496 BranchDelayInstructionDecode(branch_delay_instr); | 2525 BranchDelayInstructionDecode(branch_delay_instr); |
2497 set_pc(next_pc); | 2526 set_pc(next_pc); |
2498 pc_modified_ = true; | 2527 pc_modified_ = true; |
2499 break; | 2528 break; |
2500 } | 2529 } |
2501 case JALR: { | 2530 case JALR: { |
2502 Instruction* branch_delay_instr = reinterpret_cast<Instruction*>( | 2531 Instruction* branch_delay_instr = reinterpret_cast<Instruction*>( |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2631 if (!test_fcsr_bit(fcsr_cc)) set_register(rd_reg, rs); | 2660 if (!test_fcsr_bit(fcsr_cc)) set_register(rd_reg, rs); |
2632 } | 2661 } |
2633 break; | 2662 break; |
2634 } | 2663 } |
2635 case MOVZ: | 2664 case MOVZ: |
2636 if (!rt) set_register(rd_reg, rs); | 2665 if (!rt) set_register(rd_reg, rs); |
2637 break; | 2666 break; |
2638 default: // For other special opcodes we do the default operation. | 2667 default: // For other special opcodes we do the default operation. |
2639 set_register(rd_reg, alu_out); | 2668 set_register(rd_reg, alu_out); |
2640 } | 2669 } |
2670 } | |
2671 | |
2672 | |
2673 void Simulator::DecodeTypeRegisterSPECIAL2(Instruction* instr, | |
2674 const int32_t& rd_reg, | |
2675 int32_t& alu_out) { | |
2676 switch (instr->FunctionFieldRaw()) { | |
2677 case MUL: | |
2678 set_register(rd_reg, alu_out); | |
2679 // HI and LO are UNPREDICTABLE after the operation. | |
2680 set_register(LO, Unpredictable); | |
2681 set_register(HI, Unpredictable); | |
2682 break; | |
2683 default: // For other special2 opcodes we do the default operation. | |
2684 set_register(rd_reg, alu_out); | |
2685 } | |
2686 } | |
2687 | |
2688 | |
2689 void Simulator::DecodeTypeRegisterSPECIAL3(Instruction* instr, | |
2690 const int32_t& rt_reg, | |
2691 int32_t& alu_out) { | |
2692 switch (instr->FunctionFieldRaw()) { | |
2693 case INS: | |
2694 // Ins instr leaves result in Rt, rather than Rd. | |
2695 set_register(rt_reg, alu_out); | |
2696 break; | |
2697 case EXT: | |
2698 // Ext instr leaves result in Rt, rather than Rd. | |
2699 set_register(rt_reg, alu_out); | |
2700 break; | |
2701 default: | |
2702 UNREACHABLE(); | |
2703 } | |
2704 } | |
2705 | |
2706 | |
2707 void Simulator::DecodeTypeRegister(Instruction* instr) { | |
2708 // Instruction fields. | |
2709 const Opcode op = instr->OpcodeFieldRaw(); | |
2710 const int32_t rs_reg = instr->RsValue(); | |
2711 const int32_t rs = get_register(rs_reg); | |
2712 const uint32_t rs_u = static_cast<uint32_t>(rs); | |
2713 const int32_t rt_reg = instr->RtValue(); | |
2714 const int32_t rt = get_register(rt_reg); | |
2715 const uint32_t rt_u = static_cast<uint32_t>(rt); | |
2716 const int32_t rd_reg = instr->RdValue(); | |
2717 | |
2718 const int32_t fr_reg = instr->FrValue(); | |
2719 const int32_t fs_reg = instr->FsValue(); | |
2720 const int32_t ft_reg = instr->FtValue(); | |
2721 const int32_t fd_reg = instr->FdValue(); | |
2722 int64_t i64hilo = 0; | |
2723 uint64_t u64hilo = 0; | |
2724 | |
2725 // ALU output. | |
2726 // It should not be used as is. Instructions using it should always | |
2727 // initialize it first. | |
2728 int32_t alu_out = 0x12345678; | |
2729 | |
2730 // For break and trap instructions. | |
2731 bool do_interrupt = false; | |
2732 | |
2733 // For jr and jalr. | |
2734 // Get current pc. | |
2735 int32_t current_pc = get_pc(); | |
2736 // Next pc | |
2737 int32_t next_pc = 0; | |
2738 int32_t return_addr_reg = 31; | |
2739 | |
2740 // Set up the variables if needed before executing the instruction. | |
2741 ConfigureTypeRegister(instr, &alu_out, &i64hilo, &u64hilo, &next_pc, | |
2742 &return_addr_reg, &do_interrupt); | |
2743 | |
2744 // ---------- Raise exceptions triggered. | |
2745 SignalExceptions(); | |
2746 | |
2747 // ---------- Execution. | |
2748 switch (op) { | |
2749 case COP1: | |
2750 DecodeTypeRegisterCOP1(instr, rs_reg, rs, rs_u, rt_reg, rt, rt_u, rd_reg, | |
2751 fr_reg, fs_reg, ft_reg, fd_reg, i64hilo, u64hilo, | |
2752 alu_out, do_interrupt, current_pc, next_pc, | |
2753 return_addr_reg); | |
2754 break; | |
2755 case COP1X: | |
2756 DecodeTypeRegisterCOP1X(instr, fr_reg, fs_reg, ft_reg, fd_reg); | |
2757 break; | |
2758 case SPECIAL: | |
2759 DecodeTypeRegisterSPECIAL(instr, rs_reg, rs, rs_u, rt_reg, rt, rt_u, | |
2760 rd_reg, fr_reg, fs_reg, ft_reg, fd_reg, i64hilo, | |
2761 u64hilo, alu_out, do_interrupt, current_pc, | |
2762 next_pc, return_addr_reg); | |
2641 break; | 2763 break; |
2642 case SPECIAL2: | 2764 case SPECIAL2: |
2643 switch (instr->FunctionFieldRaw()) { | 2765 DecodeTypeRegisterSPECIAL2(instr, rd_reg, alu_out); |
2644 case MUL: | |
2645 set_register(rd_reg, alu_out); | |
2646 // HI and LO are UNPREDICTABLE after the operation. | |
2647 set_register(LO, Unpredictable); | |
2648 set_register(HI, Unpredictable); | |
2649 break; | |
2650 default: // For other special2 opcodes we do the default operation. | |
2651 set_register(rd_reg, alu_out); | |
2652 } | |
2653 break; | 2766 break; |
2654 case SPECIAL3: | 2767 case SPECIAL3: |
2655 switch (instr->FunctionFieldRaw()) { | 2768 DecodeTypeRegisterSPECIAL3(instr, rt_reg, alu_out); |
2656 case INS: | |
2657 // Ins instr leaves result in Rt, rather than Rd. | |
2658 set_register(rt_reg, alu_out); | |
2659 break; | |
2660 case EXT: | |
2661 // Ext instr leaves result in Rt, rather than Rd. | |
2662 set_register(rt_reg, alu_out); | |
2663 break; | |
2664 default: | |
2665 UNREACHABLE(); | |
2666 } | |
2667 break; | 2769 break; |
2668 // Unimplemented opcodes raised an error in the configuration step before, | 2770 // Unimplemented opcodes raised an error in the configuration step before, |
2669 // so we can use the default here to set the destination register in common | 2771 // so we can use the default here to set the destination register in common |
2670 // cases. | 2772 // cases. |
2671 default: | 2773 default: |
2672 set_register(rd_reg, alu_out); | 2774 set_register(rd_reg, alu_out); |
2673 } | 2775 } |
2674 } | 2776 } |
2675 | 2777 |
2676 | 2778 |
(...skipping 583 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3260 } | 3362 } |
3261 | 3363 |
3262 | 3364 |
3263 #undef UNSUPPORTED | 3365 #undef UNSUPPORTED |
3264 | 3366 |
3265 } } // namespace v8::internal | 3367 } } // namespace v8::internal |
3266 | 3368 |
3267 #endif // USE_SIMULATOR | 3369 #endif // USE_SIMULATOR |
3268 | 3370 |
3269 #endif // V8_TARGET_ARCH_MIPS | 3371 #endif // V8_TARGET_ARCH_MIPS |
OLD | NEW |