Chromium Code Reviews| 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 |