diff options
Diffstat (limited to 'deps/v8/src/mips64/simulator-mips64.cc')
-rw-r--r-- | deps/v8/src/mips64/simulator-mips64.cc | 1859 |
1 files changed, 783 insertions, 1076 deletions
diff --git a/deps/v8/src/mips64/simulator-mips64.cc b/deps/v8/src/mips64/simulator-mips64.cc index 9a0d8fdce8..b82b2d9b3c 100644 --- a/deps/v8/src/mips64/simulator-mips64.cc +++ b/deps/v8/src/mips64/simulator-mips64.cc @@ -909,9 +909,6 @@ Simulator::Simulator(Isolate* isolate) : isolate_(isolate) { registers_[pc] = bad_ra; registers_[ra] = bad_ra; InitializeCoverage(); - for (int i = 0; i < kNumExceptions; i++) { - exceptions[i] = 0; - } last_debugger_input_ = NULL; } @@ -1055,18 +1052,26 @@ void Simulator::set_fpu_register(int fpureg, int64_t value) { void Simulator::set_fpu_register_word(int fpureg, int32_t value) { // Set ONLY lower 32-bits, leaving upper bits untouched. - // TODO(plind): big endian issue. DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters)); - int32_t *pword = reinterpret_cast<int32_t*>(&FPUregisters_[fpureg]); + int32_t* pword; + if (kArchEndian == kLittle) { + pword = reinterpret_cast<int32_t*>(&FPUregisters_[fpureg]); + } else { + pword = reinterpret_cast<int32_t*>(&FPUregisters_[fpureg]) + 1; + } *pword = value; } void Simulator::set_fpu_register_hi_word(int fpureg, int32_t value) { // Set ONLY upper 32-bits, leaving lower bits untouched. - // TODO(plind): big endian issue. DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters)); - int32_t *phiword = (reinterpret_cast<int32_t*>(&FPUregisters_[fpureg])) + 1; + int32_t* phiword; + if (kArchEndian == kLittle) { + phiword = (reinterpret_cast<int32_t*>(&FPUregisters_[fpureg])) + 1; + } else { + phiword = reinterpret_cast<int32_t*>(&FPUregisters_[fpureg]); + } *phiword = value; } @@ -2175,495 +2180,25 @@ void Simulator::PrintStopInfo(uint64_t code) { } -void Simulator::SignalExceptions() { - for (int i = 1; i < kNumExceptions; i++) { - if (exceptions[i] != 0) { - V8_Fatal(__FILE__, __LINE__, "Error: Exception %i raised.", i); - } - } +void Simulator::SignalException(Exception e) { + V8_Fatal(__FILE__, __LINE__, "Error: Exception %i raised.", + static_cast<int>(e)); } // Handle execution based on instruction types. -void Simulator::ConfigureTypeRegister(Instruction* instr, int64_t* alu_out, - int64_t* i64hilo, uint64_t* u64hilo, - int64_t* next_pc, int* return_addr_reg, - bool* do_interrupt, int64_t* i128resultH, - int64_t* i128resultL) { - // Every local variable declared here needs to be const. - // This is to make sure that changed values are sent back to - // DecodeTypeRegister correctly. - - // Instruction fields. - const Opcode op = instr->OpcodeFieldRaw(); - const int32_t rs_reg = instr->RsValue(); - const int64_t rs = get_register(rs_reg); - const uint64_t rs_u = static_cast<uint64_t>(rs); - const int32_t rt_reg = instr->RtValue(); - const int64_t rt = get_register(rt_reg); - const uint64_t rt_u = static_cast<uint64_t>(rt); - const int32_t rd_reg = instr->RdValue(); - const uint64_t sa = instr->SaValue(); - const uint8_t bp2 = instr->Bp2Value(); - const uint8_t bp3 = instr->Bp3Value(); - - const int32_t fs_reg = instr->FsValue(); - - - // ---------- Configuration. - switch (op) { - case COP1: // Coprocessor instructions. - switch (instr->RsFieldRaw()) { - case CFC1: - // At the moment only FCSR is supported. - DCHECK(fs_reg == kFCSRRegister); - *alu_out = FCSR_; - break; - case MFC1: - *alu_out = static_cast<int64_t>(get_fpu_register_word(fs_reg)); - break; - case DMFC1: - *alu_out = get_fpu_register(fs_reg); - break; - case MFHC1: - *alu_out = get_fpu_register_hi_word(fs_reg); - break; - case CTC1: - case MTC1: - case DMTC1: - case MTHC1: - case S: - case D: - case W: - case L: - case PS: - // Do everything in the execution step. - break; - default: - // BC1 BC1EQZ BC1NEZ handled in DecodeTypeImmed, should never come here. - UNREACHABLE(); - } - break; - case COP1X: - break; - case SPECIAL: - switch (instr->FunctionFieldRaw()) { - case JR: - case JALR: - *next_pc = get_register(instr->RsValue()); - *return_addr_reg = instr->RdValue(); - break; - case SLL: - *alu_out = static_cast<int32_t>(rt) << sa; - break; - case DSLL: - *alu_out = rt << sa; - break; - case DSLL32: - *alu_out = rt << sa << 32; - break; - case SRL: - if (rs_reg == 0) { - // Regular logical right shift of a word by a fixed number of - // bits instruction. RS field is always equal to 0. - // Sign-extend the 32-bit result. - *alu_out = static_cast<int32_t>(static_cast<uint32_t>(rt_u) >> sa); - } else { - // Logical right-rotate of a word by a fixed number of bits. This - // is special case of SRL instruction, added in MIPS32 Release 2. - // RS field is equal to 00001. - *alu_out = static_cast<int32_t>( - base::bits::RotateRight32(static_cast<const uint32_t>(rt_u), - static_cast<const uint32_t>(sa))); - } - break; - case DSRL: - *alu_out = rt_u >> sa; - break; - case DSRL32: - *alu_out = rt_u >> sa >> 32; - break; - case SRA: - *alu_out = (int32_t)rt >> sa; - break; - case DSRA: - *alu_out = rt >> sa; - break; - case DSRA32: - *alu_out = rt >> sa >> 32; - break; - case SLLV: - *alu_out = (int32_t)rt << rs; - break; - case DSLLV: - *alu_out = rt << rs; - break; - case SRLV: - if (sa == 0) { - // Regular logical right-shift of a word by a variable number of - // bits instruction. SA field is always equal to 0. - *alu_out = static_cast<int32_t>((uint32_t)rt_u >> rs); - } else { - // Logical right-rotate of a word by a variable number of bits. - // This is special case od SRLV instruction, added in MIPS32 - // Release 2. SA field is equal to 00001. - *alu_out = static_cast<int32_t>( - base::bits::RotateRight32(static_cast<const uint32_t>(rt_u), - static_cast<const uint32_t>(rs_u))); - } - break; - case DSRLV: - if (sa == 0) { - // Regular logical right-shift of a word by a variable number of - // bits instruction. SA field is always equal to 0. - *alu_out = rt_u >> rs; - } else { - // Logical right-rotate of a word by a variable number of bits. - // This is special case od SRLV instruction, added in MIPS32 - // Release 2. SA field is equal to 00001. - *alu_out = - base::bits::RotateRight32(static_cast<const uint32_t>(rt_u), - static_cast<const uint32_t>(rs_u)); - } - break; - case SRAV: - *alu_out = (int32_t)rt >> rs; - break; - case DSRAV: - *alu_out = rt >> rs; - break; - case MFHI: // MFHI == CLZ on R6. - if (kArchVariant != kMips64r6) { - DCHECK(instr->SaValue() == 0); - *alu_out = get_register(HI); - } else { - // MIPS spec: If no bits were set in GPR rs, the result written to - // GPR rd is 32. - DCHECK(instr->SaValue() == 1); - *alu_out = - base::bits::CountLeadingZeros32(static_cast<int32_t>(rs_u)); - } - break; - case MFLO: - *alu_out = get_register(LO); - break; - case MULT: { // MULT == D_MUL_MUH. - int32_t rs_lo = static_cast<int32_t>(rs); - int32_t rt_lo = static_cast<int32_t>(rt); - *i64hilo = static_cast<int64_t>(rs_lo) * static_cast<int64_t>(rt_lo); - break; - } - case MULTU: - *u64hilo = static_cast<uint64_t>(rs_u & 0xffffffff) * - static_cast<uint64_t>(rt_u & 0xffffffff); - break; - case DMULT: // DMULT == D_MUL_MUH. - if (kArchVariant != kMips64r6) { - *i128resultH = MultiplyHighSigned(rs, rt); - *i128resultL = rs * rt; - } else { - switch (instr->SaValue()) { - case MUL_OP: - *i128resultL = rs * rt; - break; - case MUH_OP: - *i128resultH = MultiplyHighSigned(rs, rt); - break; - default: - UNIMPLEMENTED_MIPS(); - break; - } - } - break; - case DMULTU: - UNIMPLEMENTED_MIPS(); - break; - case ADD: - case DADD: - if (HaveSameSign(rs, rt)) { - if (rs > 0) { - exceptions[kIntegerOverflow] = rs > (Registers::kMaxValue - rt); - } else if (rs < 0) { - exceptions[kIntegerUnderflow] = rs < (Registers::kMinValue - rt); - } - } - *alu_out = rs + rt; - break; - case ADDU: { - int32_t alu32_out = static_cast<int32_t>(rs + rt); - // Sign-extend result of 32bit operation into 64bit register. - *alu_out = static_cast<int64_t>(alu32_out); - break; - } - case DADDU: - *alu_out = rs + rt; - break; - case SUB: - case DSUB: - if (!HaveSameSign(rs, rt)) { - if (rs > 0) { - exceptions[kIntegerOverflow] = rs > (Registers::kMaxValue + rt); - } else if (rs < 0) { - exceptions[kIntegerUnderflow] = rs < (Registers::kMinValue + rt); - } - } - *alu_out = rs - rt; - break; - case SUBU: { - int32_t alu32_out = static_cast<int32_t>(rs - rt); - // Sign-extend result of 32bit operation into 64bit register. - *alu_out = static_cast<int64_t>(alu32_out); - break; - } - case DSUBU: - *alu_out = rs - rt; - break; - case AND: - *alu_out = rs & rt; - break; - case OR: - *alu_out = rs | rt; - break; - case XOR: - *alu_out = rs ^ rt; - break; - case NOR: - *alu_out = ~(rs | rt); - break; - case SLT: - *alu_out = rs < rt ? 1 : 0; - break; - case SLTU: - *alu_out = rs_u < rt_u ? 1 : 0; - break; - // Break and trap instructions. - case BREAK: - - *do_interrupt = true; - break; - case TGE: - *do_interrupt = rs >= rt; - break; - case TGEU: - *do_interrupt = rs_u >= rt_u; - break; - case TLT: - *do_interrupt = rs < rt; - break; - case TLTU: - *do_interrupt = rs_u < rt_u; - break; - case TEQ: - *do_interrupt = rs == rt; - break; - case TNE: - *do_interrupt = rs != rt; - break; - case MOVN: - case MOVZ: - case MOVCI: - // No action taken on decode. - break; - case DIV: - case DIVU: - case DDIV: - case DDIVU: - // div and divu never raise exceptions. - break; - case SELEQZ_S: - case SELNEZ_S: - break; - default: - UNREACHABLE(); - } - break; - case SPECIAL2: - switch (instr->FunctionFieldRaw()) { - case MUL: - // Only the lower 32 bits are kept. - *alu_out = (int32_t)rs_u * (int32_t)rt_u; - break; - case CLZ: - // MIPS32 spec: If no bits were set in GPR rs, the result written to - // GPR rd is 32. - *alu_out = - base::bits::CountLeadingZeros32(static_cast<uint32_t>(rs_u)); - break; - default: - UNREACHABLE(); - } - break; - case SPECIAL3: - switch (instr->FunctionFieldRaw()) { - case INS: { // Mips32r2 instruction. - // Interpret rd field as 5-bit msb of insert. - uint16_t msb = rd_reg; - // Interpret sa field as 5-bit lsb of insert. - uint16_t lsb = sa; - uint16_t size = msb - lsb + 1; - uint64_t mask = (1ULL << size) - 1; - *alu_out = (rt_u & ~(mask << lsb)) | ((rs_u & mask) << lsb); - break; - } - case EXT: { // Mips32r2 instruction. - // Interpret rd field as 5-bit msb of extract. - uint16_t msb = rd_reg; - // Interpret sa field as 5-bit lsb of extract. - uint16_t lsb = sa; - uint16_t size = msb + 1; - uint64_t mask = (1ULL << size) - 1; - *alu_out = static_cast<int32_t>((rs_u & (mask << lsb)) >> lsb); - break; - } - case DEXT: { // Mips32r2 instruction. - // Interpret rd field as 5-bit msb of extract. - uint16_t msb = rd_reg; - // Interpret sa field as 5-bit lsb of extract. - uint16_t lsb = sa; - uint16_t size = msb + 1; - uint64_t mask = (1ULL << size) - 1; - *alu_out = static_cast<int64_t>((rs_u & (mask << lsb)) >> lsb); - break; - } - case BSHFL: { - int sa = instr->SaFieldRaw() >> kSaShift; - switch (sa) { - case BITSWAP: { - uint32_t input = static_cast<uint32_t>(rt); - uint32_t output = 0; - uint8_t i_byte, o_byte; - - // Reverse the bit in byte for each individual byte - for (int i = 0; i < 4; i++) { - output = output >> 8; - i_byte = input & 0xff; - - // Fast way to reverse bits in byte - // Devised by Sean Anderson, July 13, 2001 - o_byte = - static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) | - (i_byte * 0x8020LU & 0x88440LU)) * - 0x10101LU >> - 16); - - output = output | (static_cast<uint32_t>(o_byte << 24)); - input = input >> 8; - } - - *alu_out = static_cast<int64_t>(static_cast<int32_t>(output)); - break; - } - case SEB: - case SEH: - case WSBH: - UNREACHABLE(); - break; - default: { - sa >>= kBp2Bits; - switch (sa) { - case ALIGN: { - if (bp2 == 0) { - *alu_out = static_cast<int32_t>(rt); - } else { - uint64_t rt_hi = rt << (8 * bp2); - uint64_t rs_lo = rs >> (8 * (4 - bp2)); - *alu_out = static_cast<int32_t>(rt_hi | rs_lo); - } - break; - } - default: - UNREACHABLE(); - break; - } - break; - } - } - break; - } - case DBSHFL: { - int sa = instr->SaFieldRaw() >> kSaShift; - switch (sa) { - case DBITSWAP: { - switch (instr->SaFieldRaw() >> kSaShift) { - case DBITSWAP_SA: { // Mips64r6 - uint64_t input = static_cast<uint64_t>(rt); - uint64_t output = 0; - uint8_t i_byte, o_byte; - - // Reverse the bit in byte for each individual byte - for (int i = 0; i < 8; i++) { - output = output >> 8; - i_byte = input & 0xff; - - // Fast way to reverse bits in byte - // Devised by Sean Anderson, July 13, 2001 - o_byte = - static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) | - (i_byte * 0x8020LU & 0x88440LU)) * - 0x10101LU >> - 16); - - output = output | ((static_cast<uint64_t>(o_byte) << 56)); - input = input >> 8; - } - - *alu_out = static_cast<int64_t>(output); - break; - } - } - break; - } - case DSBH: - case DSHD: - UNREACHABLE(); - break; - default: { - sa >>= kBp3Bits; - switch (sa) { - case DALIGN: { - if (bp3 == 0) { - *alu_out = static_cast<int64_t>(rt); - } else { - uint64_t rt_hi = rt << (8 * bp3); - uint64_t rs_lo = rs >> (8 * (8 - bp3)); - *alu_out = static_cast<int64_t>(rt_hi | rs_lo); - } - break; - } - default: - UNREACHABLE(); - break; - } - break; - } - } - break; - } - default: - UNREACHABLE(); - } - break; - default: - UNREACHABLE(); - } -} - - -void Simulator::DecodeTypeRegisterSRsType(Instruction* instr, - const int32_t fs_reg, - const int32_t ft_reg, - const int32_t fd_reg) { +void Simulator::DecodeTypeRegisterSRsType() { float fs, ft, fd; - fs = get_fpu_register_float(fs_reg); - ft = get_fpu_register_float(ft_reg); - fd = get_fpu_register_float(fd_reg); + fs = get_fpu_register_float(fs_reg()); + ft = get_fpu_register_float(ft_reg()); + fd = get_fpu_register_float(fd_reg()); int32_t ft_int = bit_cast<int32_t>(ft); int32_t fd_int = bit_cast<int32_t>(fd); uint32_t cc, fcsr_cc; - cc = instr->FCccValue(); + cc = get_instr()->FCccValue(); fcsr_cc = get_fcsr_condition_bit(cc); - switch (instr->FunctionFieldRaw()) { + switch (get_instr()->FunctionFieldRaw()) { case RINT: { DCHECK(kArchVariant == kMips64r6); float result, temp_result; @@ -2696,44 +2231,44 @@ void Simulator::DecodeTypeRegisterSRsType(Instruction* instr, result = lower; break; } - set_fpu_register_float(fd_reg, result); + set_fpu_register_float(fd_reg(), result); if (result != fs) { set_fcsr_bit(kFCSRInexactFlagBit, true); } break; } case ADD_S: - set_fpu_register_float(fd_reg, fs + ft); + set_fpu_register_float(fd_reg(), fs + ft); break; case SUB_S: - set_fpu_register_float(fd_reg, fs - ft); + set_fpu_register_float(fd_reg(), fs - ft); break; case MUL_S: - set_fpu_register_float(fd_reg, fs * ft); + set_fpu_register_float(fd_reg(), fs * ft); break; case DIV_S: - set_fpu_register_float(fd_reg, fs / ft); + set_fpu_register_float(fd_reg(), fs / ft); break; case ABS_S: - set_fpu_register_float(fd_reg, fabs(fs)); + set_fpu_register_float(fd_reg(), fabs(fs)); break; case MOV_S: - set_fpu_register_float(fd_reg, fs); + set_fpu_register_float(fd_reg(), fs); break; case NEG_S: - set_fpu_register_float(fd_reg, -fs); + set_fpu_register_float(fd_reg(), -fs); break; case SQRT_S: - set_fpu_register_float(fd_reg, fast_sqrt(fs)); + set_fpu_register_float(fd_reg(), fast_sqrt(fs)); break; case RSQRT_S: { float result = 1.0 / fast_sqrt(fs); - set_fpu_register_float(fd_reg, result); + set_fpu_register_float(fd_reg(), result); break; } case RECIP_S: { float result = 1.0 / fs; - set_fpu_register_float(fd_reg, result); + set_fpu_register_float(fd_reg(), result); break; } case C_F_D: @@ -2761,7 +2296,7 @@ void Simulator::DecodeTypeRegisterSRsType(Instruction* instr, set_fcsr_bit(fcsr_cc, (fs <= ft) || (std::isnan(fs) || std::isnan(ft))); break; case CVT_D_S: - set_fpu_register_double(fd_reg, static_cast<double>(fs)); + set_fpu_register_double(fd_reg(), static_cast<double>(fs)); break; case CLASS_S: { // Mips64r6 instruction // Convert float input to uint32_t for easier bit manipulation @@ -2824,7 +2359,7 @@ void Simulator::DecodeTypeRegisterSRsType(Instruction* instr, DCHECK(result != 0); fResult = bit_cast<float>(result); - set_fpu_register_float(fd_reg, fResult); + set_fpu_register_float(fd_reg(), fResult); break; } @@ -2832,9 +2367,9 @@ void Simulator::DecodeTypeRegisterSRsType(Instruction* instr, float rounded; int64_t result; round64_according_to_fcsr(fs, rounded, result, fs); - set_fpu_register(fd_reg, result); + set_fpu_register(fd_reg(), result); if (set_fcsr_round64_error(fs, rounded)) { - set_fpu_register(fd_reg, kFPU64InvalidResult); + set_fpu_register(fd_reg(), kFPU64InvalidResult); } break; } @@ -2842,26 +2377,26 @@ void Simulator::DecodeTypeRegisterSRsType(Instruction* instr, float rounded; int32_t result; round_according_to_fcsr(fs, rounded, result, fs); - set_fpu_register_word(fd_reg, result); + set_fpu_register_word(fd_reg(), result); if (set_fcsr_round_error(fs, rounded)) { - set_fpu_register_word(fd_reg, kFPUInvalidResult); + set_fpu_register_word(fd_reg(), kFPUInvalidResult); } break; } case TRUNC_W_S: { // Truncate single to word (round towards 0). float rounded = trunc(fs); int32_t result = static_cast<int32_t>(rounded); - set_fpu_register_word(fd_reg, result); + set_fpu_register_word(fd_reg(), result); if (set_fcsr_round_error(fs, rounded)) { - set_fpu_register_word(fd_reg, kFPUInvalidResult); + set_fpu_register_word(fd_reg(), kFPUInvalidResult); } } break; case TRUNC_L_S: { // Mips64r2 instruction. float rounded = trunc(fs); int64_t result = static_cast<int64_t>(rounded); - set_fpu_register(fd_reg, result); + set_fpu_register(fd_reg(), result); if (set_fcsr_round64_error(fs, rounded)) { - set_fpu_register(fd_reg, kFPU64InvalidResult); + set_fpu_register(fd_reg(), kFPU64InvalidResult); } break; } @@ -2873,9 +2408,9 @@ void Simulator::DecodeTypeRegisterSRsType(Instruction* instr, // round to the even one. result--; } - set_fpu_register_word(fd_reg, result); + set_fpu_register_word(fd_reg(), result); if (set_fcsr_round_error(fs, rounded)) { - set_fpu_register_word(fd_reg, kFPUInvalidResult); + set_fpu_register_word(fd_reg(), kFPUInvalidResult); } break; } @@ -2888,18 +2423,18 @@ void Simulator::DecodeTypeRegisterSRsType(Instruction* instr, result--; } int64_t i64 = static_cast<int64_t>(result); - set_fpu_register(fd_reg, i64); + set_fpu_register(fd_reg(), i64); if (set_fcsr_round64_error(fs, rounded)) { - set_fpu_register(fd_reg, kFPU64InvalidResult); + set_fpu_register(fd_reg(), kFPU64InvalidResult); } break; } case FLOOR_L_S: { // Mips64r2 instruction. float rounded = floor(fs); int64_t result = static_cast<int64_t>(rounded); - set_fpu_register(fd_reg, result); + set_fpu_register(fd_reg(), result); if (set_fcsr_round64_error(fs, rounded)) { - set_fpu_register(fd_reg, kFPU64InvalidResult); + set_fpu_register(fd_reg(), kFPU64InvalidResult); } break; } @@ -2907,38 +2442,38 @@ void Simulator::DecodeTypeRegisterSRsType(Instruction* instr, { float rounded = std::floor(fs); int32_t result = static_cast<int32_t>(rounded); - set_fpu_register_word(fd_reg, result); + set_fpu_register_word(fd_reg(), result); if (set_fcsr_round_error(fs, rounded)) { - set_fpu_register_word(fd_reg, kFPUInvalidResult); + set_fpu_register_word(fd_reg(), kFPUInvalidResult); } } break; case CEIL_W_S: // Round double to word towards positive infinity. { float rounded = std::ceil(fs); int32_t result = static_cast<int32_t>(rounded); - set_fpu_register_word(fd_reg, result); + set_fpu_register_word(fd_reg(), result); if (set_fcsr_round_error(fs, rounded)) { - set_fpu_register(fd_reg, kFPUInvalidResult); + set_fpu_register(fd_reg(), kFPUInvalidResult); } } break; case CEIL_L_S: { // Mips64r2 instruction. float rounded = ceil(fs); int64_t result = static_cast<int64_t>(rounded); - set_fpu_register(fd_reg, result); + set_fpu_register(fd_reg(), result); if (set_fcsr_round64_error(fs, rounded)) { - set_fpu_register(fd_reg, kFPU64InvalidResult); + set_fpu_register(fd_reg(), kFPU64InvalidResult); } break; } case MINA: DCHECK(kArchVariant == kMips64r6); - fs = get_fpu_register_float(fs_reg); + fs = get_fpu_register_float(fs_reg()); if (std::isnan(fs) && std::isnan(ft)) { - set_fpu_register_float(fd_reg, fs); + set_fpu_register_float(fd_reg(), fs); } else if (std::isnan(fs) && !std::isnan(ft)) { - set_fpu_register_float(fd_reg, ft); + set_fpu_register_float(fd_reg(), ft); } else if (!std::isnan(fs) && std::isnan(ft)) { - set_fpu_register_float(fd_reg, fs); + set_fpu_register_float(fd_reg(), fs); } else { float result; if (fabs(fs) > fabs(ft)) { @@ -2948,18 +2483,18 @@ void Simulator::DecodeTypeRegisterSRsType(Instruction* instr, } else { result = (fs > ft ? fs : ft); } - set_fpu_register_float(fd_reg, result); + set_fpu_register_float(fd_reg(), result); } break; case MAXA: DCHECK(kArchVariant == kMips64r6); - fs = get_fpu_register_float(fs_reg); + fs = get_fpu_register_float(fs_reg()); if (std::isnan(fs) && std::isnan(ft)) { - set_fpu_register_float(fd_reg, fs); + set_fpu_register_float(fd_reg(), fs); } else if (std::isnan(fs) && !std::isnan(ft)) { - set_fpu_register_float(fd_reg, ft); + set_fpu_register_float(fd_reg(), ft); } else if (!std::isnan(fs) && std::isnan(ft)) { - set_fpu_register_float(fd_reg, fs); + set_fpu_register_float(fd_reg(), fs); } else { float result; if (fabs(fs) < fabs(ft)) { @@ -2969,78 +2504,76 @@ void Simulator::DecodeTypeRegisterSRsType(Instruction* instr, } else { result = (fs > ft ? fs : ft); } - set_fpu_register_float(fd_reg, result); + set_fpu_register_float(fd_reg(), result); } break; case MIN: DCHECK(kArchVariant == kMips64r6); - fs = get_fpu_register_float(fs_reg); + fs = get_fpu_register_float(fs_reg()); if (std::isnan(fs) && std::isnan(ft)) { - set_fpu_register_float(fd_reg, fs); + set_fpu_register_float(fd_reg(), fs); } else if (std::isnan(fs) && !std::isnan(ft)) { - set_fpu_register_float(fd_reg, ft); + set_fpu_register_float(fd_reg(), ft); } else if (!std::isnan(fs) && std::isnan(ft)) { - set_fpu_register_float(fd_reg, fs); + set_fpu_register_float(fd_reg(), fs); } else { - set_fpu_register_float(fd_reg, (fs >= ft) ? ft : fs); + set_fpu_register_float(fd_reg(), (fs >= ft) ? ft : fs); } break; case MAX: DCHECK(kArchVariant == kMips64r6); - fs = get_fpu_register_float(fs_reg); + fs = get_fpu_register_float(fs_reg()); if (std::isnan(fs) && std::isnan(ft)) { - set_fpu_register_float(fd_reg, fs); + set_fpu_register_float(fd_reg(), fs); } else if (std::isnan(fs) && !std::isnan(ft)) { - set_fpu_register_float(fd_reg, ft); + set_fpu_register_float(fd_reg(), ft); } else if (!std::isnan(fs) && std::isnan(ft)) { - set_fpu_register_float(fd_reg, fs); + set_fpu_register_float(fd_reg(), fs); } else { - set_fpu_register_float(fd_reg, (fs <= ft) ? ft : fs); + set_fpu_register_float(fd_reg(), (fs <= ft) ? ft : fs); } break; case SEL: DCHECK(kArchVariant == kMips64r6); - set_fpu_register_float(fd_reg, (fd_int & 0x1) == 0 ? fs : ft); + set_fpu_register_float(fd_reg(), (fd_int & 0x1) == 0 ? fs : ft); break; case SELEQZ_C: DCHECK(kArchVariant == kMips64r6); - set_fpu_register_float( - fd_reg, (ft_int & 0x1) == 0 ? get_fpu_register_float(fs_reg) : 0.0); + set_fpu_register_float(fd_reg(), (ft_int & 0x1) == 0 + ? get_fpu_register_float(fs_reg()) + : 0.0); break; case SELNEZ_C: DCHECK(kArchVariant == kMips64r6); - set_fpu_register_float( - fd_reg, (ft_int & 0x1) != 0 ? get_fpu_register_float(fs_reg) : 0.0); + set_fpu_register_float(fd_reg(), (ft_int & 0x1) != 0 + ? get_fpu_register_float(fs_reg()) + : 0.0); break; case MOVZ_C: { DCHECK(kArchVariant == kMips64r2); - int32_t rt_reg = instr->RtValue(); - int64_t rt = get_register(rt_reg); - if (rt == 0) { - set_fpu_register_float(fd_reg, fs); + if (rt() == 0) { + set_fpu_register_float(fd_reg(), fs); } break; } case MOVN_C: { DCHECK(kArchVariant == kMips64r2); - int32_t rt_reg = instr->RtValue(); - int64_t rt = get_register(rt_reg); - if (rt != 0) { - set_fpu_register_float(fd_reg, fs); + if (rt() != 0) { + set_fpu_register_float(fd_reg(), fs); } break; } case MOVF: { // Same function field for MOVT.D and MOVF.D - uint32_t ft_cc = (ft_reg >> 2) & 0x7; + uint32_t ft_cc = (ft_reg() >> 2) & 0x7; ft_cc = get_fcsr_condition_bit(ft_cc); - if (instr->Bit(16)) { // Read Tf bit. + if (get_instr()->Bit(16)) { // Read Tf bit. // MOVT.D - if (test_fcsr_bit(ft_cc)) set_fpu_register_float(fd_reg, fs); + if (test_fcsr_bit(ft_cc)) set_fpu_register_float(fd_reg(), fs); } else { // MOVF.D - if (!test_fcsr_bit(ft_cc)) set_fpu_register_float(fd_reg, fs); + if (!test_fcsr_bit(ft_cc)) set_fpu_register_float(fd_reg(), fs); } break; } @@ -3052,21 +2585,19 @@ void Simulator::DecodeTypeRegisterSRsType(Instruction* instr, } -void Simulator::DecodeTypeRegisterDRsType(Instruction* instr, - const int32_t fs_reg, - const int32_t ft_reg, - const int32_t fd_reg) { +void Simulator::DecodeTypeRegisterDRsType() { double ft, fs, fd; uint32_t cc, fcsr_cc; - fs = get_fpu_register_double(fs_reg); - ft = (instr->FunctionFieldRaw() != MOVF) ? get_fpu_register_double(ft_reg) - : 0.0; - fd = get_fpu_register_double(fd_reg); - cc = instr->FCccValue(); + fs = get_fpu_register_double(fs_reg()); + ft = (get_instr()->FunctionFieldRaw() != MOVF) + ? get_fpu_register_double(ft_reg()) + : 0.0; + fd = get_fpu_register_double(fd_reg()); + cc = get_instr()->FCccValue(); fcsr_cc = get_fcsr_condition_bit(cc); int64_t ft_int = bit_cast<int64_t>(ft); int64_t fd_int = bit_cast<int64_t>(fd); - switch (instr->FunctionFieldRaw()) { + switch (get_instr()->FunctionFieldRaw()) { case RINT: { DCHECK(kArchVariant == kMips64r6); double result, temp, temp_result; @@ -3098,7 +2629,7 @@ void Simulator::DecodeTypeRegisterDRsType(Instruction* instr, result = lower; break; } - set_fpu_register_double(fd_reg, result); + set_fpu_register_double(fd_reg(), result); if (result != fs) { set_fcsr_bit(kFCSRInexactFlagBit, true); } @@ -3106,56 +2637,52 @@ void Simulator::DecodeTypeRegisterDRsType(Instruction* instr, } case SEL: DCHECK(kArchVariant == kMips64r6); - set_fpu_register_double(fd_reg, (fd_int & 0x1) == 0 ? fs : ft); + set_fpu_register_double(fd_reg(), (fd_int & 0x1) == 0 ? fs : ft); break; case SELEQZ_C: DCHECK(kArchVariant == kMips64r6); - set_fpu_register_double(fd_reg, (ft_int & 0x1) == 0 ? fs : 0.0); + set_fpu_register_double(fd_reg(), (ft_int & 0x1) == 0 ? fs : 0.0); break; case SELNEZ_C: DCHECK(kArchVariant == kMips64r6); - set_fpu_register_double(fd_reg, (ft_int & 0x1) != 0 ? fs : 0.0); + set_fpu_register_double(fd_reg(), (ft_int & 0x1) != 0 ? fs : 0.0); break; case MOVZ_C: { DCHECK(kArchVariant == kMips64r2); - int32_t rt_reg = instr->RtValue(); - int64_t rt = get_register(rt_reg); - if (rt == 0) { - set_fpu_register_double(fd_reg, fs); + if (rt() == 0) { + set_fpu_register_double(fd_reg(), fs); } break; } case MOVN_C: { DCHECK(kArchVariant == kMips64r2); - int32_t rt_reg = instr->RtValue(); - int64_t rt = get_register(rt_reg); - if (rt != 0) { - set_fpu_register_double(fd_reg, fs); + if (rt() != 0) { + set_fpu_register_double(fd_reg(), fs); } break; } case MOVF: { // Same function field for MOVT.D and MOVF.D - uint32_t ft_cc = (ft_reg >> 2) & 0x7; + uint32_t ft_cc = (ft_reg() >> 2) & 0x7; ft_cc = get_fcsr_condition_bit(ft_cc); - if (instr->Bit(16)) { // Read Tf bit. + if (get_instr()->Bit(16)) { // Read Tf bit. // MOVT.D - if (test_fcsr_bit(ft_cc)) set_fpu_register_double(fd_reg, fs); + if (test_fcsr_bit(ft_cc)) set_fpu_register_double(fd_reg(), fs); } else { // MOVF.D - if (!test_fcsr_bit(ft_cc)) set_fpu_register_double(fd_reg, fs); + if (!test_fcsr_bit(ft_cc)) set_fpu_register_double(fd_reg(), fs); } break; } case MINA: DCHECK(kArchVariant == kMips64r6); - fs = get_fpu_register_double(fs_reg); + fs = get_fpu_register_double(fs_reg()); if (std::isnan(fs) && std::isnan(ft)) { - set_fpu_register_double(fd_reg, fs); + set_fpu_register_double(fd_reg(), fs); } else if (std::isnan(fs) && !std::isnan(ft)) { - set_fpu_register_double(fd_reg, ft); + set_fpu_register_double(fd_reg(), ft); } else if (!std::isnan(fs) && std::isnan(ft)) { - set_fpu_register_double(fd_reg, fs); + set_fpu_register_double(fd_reg(), fs); } else { double result; if (fabs(fs) > fabs(ft)) { @@ -3165,18 +2692,18 @@ void Simulator::DecodeTypeRegisterDRsType(Instruction* instr, } else { result = (fs > ft ? fs : ft); } - set_fpu_register_double(fd_reg, result); + set_fpu_register_double(fd_reg(), result); } break; case MAXA: DCHECK(kArchVariant == kMips64r6); - fs = get_fpu_register_double(fs_reg); + fs = get_fpu_register_double(fs_reg()); if (std::isnan(fs) && std::isnan(ft)) { - set_fpu_register_double(fd_reg, fs); + set_fpu_register_double(fd_reg(), fs); } else if (std::isnan(fs) && !std::isnan(ft)) { - set_fpu_register_double(fd_reg, ft); + set_fpu_register_double(fd_reg(), ft); } else if (!std::isnan(fs) && std::isnan(ft)) { - set_fpu_register_double(fd_reg, fs); + set_fpu_register_double(fd_reg(), fs); } else { double result; if (fabs(fs) < fabs(ft)) { @@ -3186,67 +2713,67 @@ void Simulator::DecodeTypeRegisterDRsType(Instruction* instr, } else { result = (fs > ft ? fs : ft); } - set_fpu_register_double(fd_reg, result); + set_fpu_register_double(fd_reg(), result); } break; case MIN: DCHECK(kArchVariant == kMips64r6); - fs = get_fpu_register_double(fs_reg); + fs = get_fpu_register_double(fs_reg()); if (std::isnan(fs) && std::isnan(ft)) { - set_fpu_register_double(fd_reg, fs); + set_fpu_register_double(fd_reg(), fs); } else if (std::isnan(fs) && !std::isnan(ft)) { - set_fpu_register_double(fd_reg, ft); + set_fpu_register_double(fd_reg(), ft); } else if (!std::isnan(fs) && std::isnan(ft)) { - set_fpu_register_double(fd_reg, fs); + set_fpu_register_double(fd_reg(), fs); } else { - set_fpu_register_double(fd_reg, (fs >= ft) ? ft : fs); + set_fpu_register_double(fd_reg(), (fs >= ft) ? ft : fs); } break; case MAX: DCHECK(kArchVariant == kMips64r6); - fs = get_fpu_register_double(fs_reg); + fs = get_fpu_register_double(fs_reg()); if (std::isnan(fs) && std::isnan(ft)) { - set_fpu_register_double(fd_reg, fs); + set_fpu_register_double(fd_reg(), fs); } else if (std::isnan(fs) && !std::isnan(ft)) { - set_fpu_register_double(fd_reg, ft); + set_fpu_register_double(fd_reg(), ft); } else if (!std::isnan(fs) && std::isnan(ft)) { - set_fpu_register_double(fd_reg, fs); + set_fpu_register_double(fd_reg(), fs); } else { - set_fpu_register_double(fd_reg, (fs <= ft) ? ft : fs); + set_fpu_register_double(fd_reg(), (fs <= ft) ? ft : fs); } break; case ADD_D: - set_fpu_register_double(fd_reg, fs + ft); + set_fpu_register_double(fd_reg(), fs + ft); break; case SUB_D: - set_fpu_register_double(fd_reg, fs - ft); + set_fpu_register_double(fd_reg(), fs - ft); break; case MUL_D: - set_fpu_register_double(fd_reg, fs * ft); + set_fpu_register_double(fd_reg(), fs * ft); break; case DIV_D: - set_fpu_register_double(fd_reg, fs / ft); + set_fpu_register_double(fd_reg(), fs / ft); break; case ABS_D: - set_fpu_register_double(fd_reg, fabs(fs)); + set_fpu_register_double(fd_reg(), fabs(fs)); break; case MOV_D: - set_fpu_register_double(fd_reg, fs); + set_fpu_register_double(fd_reg(), fs); break; case NEG_D: - set_fpu_register_double(fd_reg, -fs); + set_fpu_register_double(fd_reg(), -fs); break; case SQRT_D: - set_fpu_register_double(fd_reg, fast_sqrt(fs)); + set_fpu_register_double(fd_reg(), fast_sqrt(fs)); break; case RSQRT_D: { double result = 1.0 / fast_sqrt(fs); - set_fpu_register_double(fd_reg, result); + set_fpu_register_double(fd_reg(), result); break; } case RECIP_D: { double result = 1.0 / fs; - set_fpu_register_double(fd_reg, result); + set_fpu_register_double(fd_reg(), result); break; } case C_UN_D: @@ -3274,9 +2801,9 @@ void Simulator::DecodeTypeRegisterDRsType(Instruction* instr, double rounded; int32_t result; round_according_to_fcsr(fs, rounded, result, fs); - set_fpu_register_word(fd_reg, result); + set_fpu_register_word(fd_reg(), result); if (set_fcsr_round_error(fs, rounded)) { - set_fpu_register_word(fd_reg, kFPUInvalidResult); + set_fpu_register_word(fd_reg(), kFPUInvalidResult); } break; } @@ -3289,48 +2816,48 @@ void Simulator::DecodeTypeRegisterDRsType(Instruction* instr, // round to the even one. result--; } - set_fpu_register_word(fd_reg, result); + set_fpu_register_word(fd_reg(), result); if (set_fcsr_round_error(fs, rounded)) { - set_fpu_register(fd_reg, kFPUInvalidResult); + set_fpu_register(fd_reg(), kFPUInvalidResult); } } break; case TRUNC_W_D: // Truncate double to word (round towards 0). { double rounded = trunc(fs); int32_t result = static_cast<int32_t>(rounded); - set_fpu_register_word(fd_reg, result); + set_fpu_register_word(fd_reg(), result); if (set_fcsr_round_error(fs, rounded)) { - set_fpu_register(fd_reg, kFPUInvalidResult); + set_fpu_register(fd_reg(), kFPUInvalidResult); } } break; case FLOOR_W_D: // Round double to word towards negative infinity. { double rounded = std::floor(fs); int32_t result = static_cast<int32_t>(rounded); - set_fpu_register_word(fd_reg, result); + set_fpu_register_word(fd_reg(), result); if (set_fcsr_round_error(fs, rounded)) { - set_fpu_register(fd_reg, kFPUInvalidResult); + set_fpu_register(fd_reg(), kFPUInvalidResult); } } break; case CEIL_W_D: // Round double to word towards positive infinity. { double rounded = std::ceil(fs); int32_t result = static_cast<int32_t>(rounded); - set_fpu_register_word(fd_reg, result); + set_fpu_register_word(fd_reg(), result); if (set_fcsr_round_error(fs, rounded)) { - set_fpu_register(fd_reg, kFPUInvalidResult); + set_fpu_register(fd_reg(), kFPUInvalidResult); } } break; case CVT_S_D: // Convert double to float (single). - set_fpu_register_float(fd_reg, static_cast<float>(fs)); + set_fpu_register_float(fd_reg(), static_cast<float>(fs)); break; case CVT_L_D: { // Mips64r2: Truncate double to 64-bit long-word. double rounded; int64_t result; round64_according_to_fcsr(fs, rounded, result, fs); - set_fpu_register(fd_reg, result); + set_fpu_register(fd_reg(), result); if (set_fcsr_round64_error(fs, rounded)) { - set_fpu_register(fd_reg, kFPU64InvalidResult); + set_fpu_register(fd_reg(), kFPU64InvalidResult); } break; } @@ -3343,36 +2870,36 @@ void Simulator::DecodeTypeRegisterDRsType(Instruction* instr, result--; } int64_t i64 = static_cast<int64_t>(result); - set_fpu_register(fd_reg, i64); + set_fpu_register(fd_reg(), i64); if (set_fcsr_round64_error(fs, rounded)) { - set_fpu_register(fd_reg, kFPU64InvalidResult); + set_fpu_register(fd_reg(), kFPU64InvalidResult); } break; } case TRUNC_L_D: { // Mips64r2 instruction. double rounded = trunc(fs); int64_t result = static_cast<int64_t>(rounded); - set_fpu_register(fd_reg, result); + set_fpu_register(fd_reg(), result); if (set_fcsr_round64_error(fs, rounded)) { - set_fpu_register(fd_reg, kFPU64InvalidResult); + set_fpu_register(fd_reg(), kFPU64InvalidResult); } break; } case FLOOR_L_D: { // Mips64r2 instruction. double rounded = floor(fs); int64_t result = static_cast<int64_t>(rounded); - set_fpu_register(fd_reg, result); + set_fpu_register(fd_reg(), result); if (set_fcsr_round64_error(fs, rounded)) { - set_fpu_register(fd_reg, kFPU64InvalidResult); + set_fpu_register(fd_reg(), kFPU64InvalidResult); } break; } case CEIL_L_D: { // Mips64r2 instruction. double rounded = ceil(fs); int64_t result = static_cast<int64_t>(rounded); - set_fpu_register(fd_reg, result); + set_fpu_register(fd_reg(), result); if (set_fcsr_round64_error(fs, rounded)) { - set_fpu_register(fd_reg, kFPU64InvalidResult); + set_fpu_register(fd_reg(), kFPU64InvalidResult); } break; } @@ -3437,7 +2964,7 @@ void Simulator::DecodeTypeRegisterDRsType(Instruction* instr, DCHECK(result != 0); dResult = bit_cast<double>(result); - set_fpu_register_double(fd_reg, dResult); + set_fpu_register_double(fd_reg(), dResult); break; } @@ -3451,93 +2978,90 @@ void Simulator::DecodeTypeRegisterDRsType(Instruction* instr, } -void Simulator::DecodeTypeRegisterWRsType(Instruction* instr, - const int32_t fs_reg, - const int32_t fd_reg, - const int32_t ft_reg, - int64_t& alu_out) { - float fs = get_fpu_register_float(fs_reg); - float ft = get_fpu_register_float(ft_reg); - switch (instr->FunctionFieldRaw()) { +void Simulator::DecodeTypeRegisterWRsType() { + float fs = get_fpu_register_float(fs_reg()); + float ft = get_fpu_register_float(ft_reg()); + int64_t alu_out = 0x12345678; + switch (get_instr()->FunctionFieldRaw()) { case CVT_S_W: // Convert word to float (single). - alu_out = get_fpu_register_signed_word(fs_reg); - set_fpu_register_float(fd_reg, static_cast<float>(alu_out)); + alu_out = get_fpu_register_signed_word(fs_reg()); + set_fpu_register_float(fd_reg(), static_cast<float>(alu_out)); break; case CVT_D_W: // Convert word to double. - alu_out = get_fpu_register_signed_word(fs_reg); - set_fpu_register_double(fd_reg, static_cast<double>(alu_out)); + alu_out = get_fpu_register_signed_word(fs_reg()); + set_fpu_register_double(fd_reg(), static_cast<double>(alu_out)); break; case CMP_AF: - set_fpu_register_word(fd_reg, 0); + set_fpu_register_word(fd_reg(), 0); break; case CMP_UN: if (std::isnan(fs) || std::isnan(ft)) { - set_fpu_register_word(fd_reg, -1); + set_fpu_register_word(fd_reg(), -1); } else { - set_fpu_register_word(fd_reg, 0); + set_fpu_register_word(fd_reg(), 0); } break; case CMP_EQ: if (fs == ft) { - set_fpu_register_word(fd_reg, -1); + set_fpu_register_word(fd_reg(), -1); } else { - set_fpu_register_word(fd_reg, 0); + set_fpu_register_word(fd_reg(), 0); } break; case CMP_UEQ: if ((fs == ft) || (std::isnan(fs) || std::isnan(ft))) { - set_fpu_register_word(fd_reg, -1); + set_fpu_register_word(fd_reg(), -1); } else { - set_fpu_register_word(fd_reg, 0); + set_fpu_register_word(fd_reg(), 0); } break; case CMP_LT: if (fs < ft) { - set_fpu_register_word(fd_reg, -1); + set_fpu_register_word(fd_reg(), -1); } else { - set_fpu_register_word(fd_reg, 0); + set_fpu_register_word(fd_reg(), 0); } break; case CMP_ULT: if ((fs < ft) || (std::isnan(fs) || std::isnan(ft))) { - set_fpu_register_word(fd_reg, -1); + set_fpu_register_word(fd_reg(), -1); } else { - set_fpu_register_word(fd_reg, 0); + set_fpu_register_word(fd_reg(), 0); } break; case CMP_LE: if (fs <= ft) { - set_fpu_register_word(fd_reg, -1); + set_fpu_register_word(fd_reg(), -1); } else { - set_fpu_register_word(fd_reg, 0); + set_fpu_register_word(fd_reg(), 0); } break; case CMP_ULE: if ((fs <= ft) || (std::isnan(fs) || std::isnan(ft))) { - set_fpu_register_word(fd_reg, -1); + set_fpu_register_word(fd_reg(), -1); } else { - set_fpu_register_word(fd_reg, 0); + set_fpu_register_word(fd_reg(), 0); } break; case CMP_OR: if (!std::isnan(fs) && !std::isnan(ft)) { - set_fpu_register_word(fd_reg, -1); + set_fpu_register_word(fd_reg(), -1); } else { - set_fpu_register_word(fd_reg, 0); + set_fpu_register_word(fd_reg(), 0); } break; case CMP_UNE: if ((fs != ft) || (std::isnan(fs) || std::isnan(ft))) { - set_fpu_register_word(fd_reg, -1); + set_fpu_register_word(fd_reg(), -1); } else { - set_fpu_register_word(fd_reg, 0); + set_fpu_register_word(fd_reg(), 0); } break; case CMP_NE: if (fs != ft) { - set_fpu_register_word(fd_reg, -1); + set_fpu_register_word(fd_reg(), -1); } else { - set_fpu_register_word(fd_reg, 0); + set_fpu_register_word(fd_reg(), 0); } break; default: @@ -3546,93 +3070,90 @@ void Simulator::DecodeTypeRegisterWRsType(Instruction* instr, } -void Simulator::DecodeTypeRegisterLRsType(Instruction* instr, - const int32_t fs_reg, - const int32_t fd_reg, - const int32_t ft_reg) { - double fs = get_fpu_register_double(fs_reg); - double ft = get_fpu_register_double(ft_reg); +void Simulator::DecodeTypeRegisterLRsType() { + double fs = get_fpu_register_double(fs_reg()); + double ft = get_fpu_register_double(ft_reg()); int64_t i64; - switch (instr->FunctionFieldRaw()) { + switch (get_instr()->FunctionFieldRaw()) { case CVT_D_L: // Mips32r2 instruction. - i64 = get_fpu_register(fs_reg); - set_fpu_register_double(fd_reg, static_cast<double>(i64)); + i64 = get_fpu_register(fs_reg()); + set_fpu_register_double(fd_reg(), static_cast<double>(i64)); break; case CVT_S_L: - i64 = get_fpu_register(fs_reg); - set_fpu_register_float(fd_reg, static_cast<float>(i64)); + i64 = get_fpu_register(fs_reg()); + set_fpu_register_float(fd_reg(), static_cast<float>(i64)); break; case CMP_AF: - set_fpu_register(fd_reg, 0); + set_fpu_register(fd_reg(), 0); break; case CMP_UN: if (std::isnan(fs) || std::isnan(ft)) { - set_fpu_register(fd_reg, -1); + set_fpu_register(fd_reg(), -1); } else { - set_fpu_register(fd_reg, 0); + set_fpu_register(fd_reg(), 0); } break; case CMP_EQ: if (fs == ft) { - set_fpu_register(fd_reg, -1); + set_fpu_register(fd_reg(), -1); } else { - set_fpu_register(fd_reg, 0); + set_fpu_register(fd_reg(), 0); } break; case CMP_UEQ: if ((fs == ft) || (std::isnan(fs) || std::isnan(ft))) { - set_fpu_register(fd_reg, -1); + set_fpu_register(fd_reg(), -1); } else { - set_fpu_register(fd_reg, 0); + set_fpu_register(fd_reg(), 0); } break; case CMP_LT: if (fs < ft) { - set_fpu_register(fd_reg, -1); + set_fpu_register(fd_reg(), -1); } else { - set_fpu_register(fd_reg, 0); + set_fpu_register(fd_reg(), 0); } break; case CMP_ULT: if ((fs < ft) || (std::isnan(fs) || std::isnan(ft))) { - set_fpu_register(fd_reg, -1); + set_fpu_register(fd_reg(), -1); } else { - set_fpu_register(fd_reg, 0); + set_fpu_register(fd_reg(), 0); } break; case CMP_LE: if (fs <= ft) { - set_fpu_register(fd_reg, -1); + set_fpu_register(fd_reg(), -1); } else { - set_fpu_register(fd_reg, 0); + set_fpu_register(fd_reg(), 0); } break; case CMP_ULE: if ((fs <= ft) || (std::isnan(fs) || std::isnan(ft))) { - set_fpu_register(fd_reg, -1); + set_fpu_register(fd_reg(), -1); } else { - set_fpu_register(fd_reg, 0); + set_fpu_register(fd_reg(), 0); } break; case CMP_OR: if (!std::isnan(fs) && !std::isnan(ft)) { - set_fpu_register(fd_reg, -1); + set_fpu_register(fd_reg(), -1); } else { - set_fpu_register(fd_reg, 0); + set_fpu_register(fd_reg(), 0); } break; case CMP_UNE: if ((fs != ft) || (std::isnan(fs) || std::isnan(ft))) { - set_fpu_register(fd_reg, -1); + set_fpu_register(fd_reg(), -1); } else { - set_fpu_register(fd_reg, 0); + set_fpu_register(fd_reg(), 0); } break; case CMP_NE: if (fs != ft && (!std::isnan(fs) && !std::isnan(ft))) { - set_fpu_register(fd_reg, -1); + set_fpu_register(fd_reg(), -1); } else { - set_fpu_register(fd_reg, 0); + set_fpu_register(fd_reg(), 0); } break; default: @@ -3640,54 +3161,56 @@ void Simulator::DecodeTypeRegisterLRsType(Instruction* instr, } } -void Simulator::DecodeTypeRegisterCOP1( - Instruction* instr, const int32_t rs_reg, const int64_t rs, - const uint64_t rs_u, const int32_t rt_reg, const int64_t rt, - const uint64_t rt_u, const int32_t rd_reg, const int32_t fr_reg, - const int32_t fs_reg, const int32_t ft_reg, const int32_t fd_reg, - int64_t& alu_out) { - switch (instr->RsFieldRaw()) { + +void Simulator::DecodeTypeRegisterCOP1() { + switch (get_instr()->RsFieldRaw()) { case BC1: // Branch on coprocessor condition. case BC1EQZ: case BC1NEZ: UNREACHABLE(); break; case CFC1: - set_register(rt_reg, alu_out); + // At the moment only FCSR is supported. + DCHECK(fs_reg() == kFCSRRegister); + set_register(rt_reg(), FCSR_); break; case MFC1: + set_register(rt_reg(), + static_cast<int64_t>(get_fpu_register_word(fs_reg()))); + break; case DMFC1: + set_register(rt_reg(), get_fpu_register(fs_reg())); + break; case MFHC1: - set_register(rt_reg, alu_out); + set_register(rt_reg(), get_fpu_register_hi_word(fs_reg())); break; case CTC1: // At the moment only FCSR is supported. - DCHECK(fs_reg == kFCSRRegister); - FCSR_ = static_cast<uint32_t>(registers_[rt_reg]); + DCHECK(fs_reg() == kFCSRRegister); + FCSR_ = static_cast<uint32_t>(rt()); break; case MTC1: // Hardware writes upper 32-bits to zero on mtc1. - set_fpu_register_hi_word(fs_reg, 0); - set_fpu_register_word(fs_reg, static_cast<int32_t>(registers_[rt_reg])); + set_fpu_register_hi_word(fs_reg(), 0); + set_fpu_register_word(fs_reg(), static_cast<int32_t>(rt())); break; case DMTC1: - set_fpu_register(fs_reg, registers_[rt_reg]); + set_fpu_register(fs_reg(), rt()); break; case MTHC1: - set_fpu_register_hi_word(fs_reg, - static_cast<int32_t>(registers_[rt_reg])); + set_fpu_register_hi_word(fs_reg(), static_cast<int32_t>(rt())); break; case S: - DecodeTypeRegisterSRsType(instr, fs_reg, ft_reg, fd_reg); + DecodeTypeRegisterSRsType(); break; case D: - DecodeTypeRegisterDRsType(instr, fs_reg, ft_reg, fd_reg); + DecodeTypeRegisterDRsType(); break; case W: - DecodeTypeRegisterWRsType(instr, fs_reg, fd_reg, ft_reg, alu_out); + DecodeTypeRegisterWRsType(); break; case L: - DecodeTypeRegisterLRsType(instr, fs_reg, fd_reg, ft_reg); + DecodeTypeRegisterLRsType(); break; default: UNREACHABLE(); @@ -3695,18 +3218,14 @@ void Simulator::DecodeTypeRegisterCOP1( } -void Simulator::DecodeTypeRegisterCOP1X(Instruction* instr, - const int32_t fr_reg, - const int32_t fs_reg, - const int32_t ft_reg, - const int32_t fd_reg) { - switch (instr->FunctionFieldRaw()) { +void Simulator::DecodeTypeRegisterCOP1X() { + switch (get_instr()->FunctionFieldRaw()) { case MADD_D: double fr, ft, fs; - fr = get_fpu_register_double(fr_reg); - fs = get_fpu_register_double(fs_reg); - ft = get_fpu_register_double(ft_reg); - set_fpu_register_double(fd_reg, fs * ft + fr); + fr = get_fpu_register_double(fr_reg()); + fs = get_fpu_register_double(fs_reg()); + ft = get_fpu_register_double(ft_reg()); + set_fpu_register_double(fd_reg(), fs * ft + fr); break; default: UNREACHABLE(); @@ -3714,25 +3233,24 @@ void Simulator::DecodeTypeRegisterCOP1X(Instruction* instr, } -void Simulator::DecodeTypeRegisterSPECIAL( - Instruction* instr, const int32_t rs_reg, const int64_t rs, - const uint64_t rs_u, const int32_t rt_reg, const int64_t rt, - const uint64_t rt_u, const int32_t rd_reg, const int32_t fr_reg, - const int32_t fs_reg, const int32_t ft_reg, const int32_t fd_reg, - const int64_t i64hilo, const uint64_t u64hilo, const int64_t alu_out, - const bool do_interrupt, const int64_t current_pc, const int64_t next_pc, - const int32_t return_addr_reg, const int64_t i128resultH, - const int64_t i128resultL) { - switch (instr->FunctionFieldRaw()) { +void Simulator::DecodeTypeRegisterSPECIAL() { + int64_t i64hilo; + uint64_t u64hilo; + int64_t alu_out; + bool do_interrupt = false; + + switch (get_instr()->FunctionFieldRaw()) { case SELEQZ_S: DCHECK(kArchVariant == kMips64r6); - set_register(rd_reg, rt == 0 ? rs : 0); + set_register(rd_reg(), rt() == 0 ? rs() : 0); break; case SELNEZ_S: DCHECK(kArchVariant == kMips64r6); - set_register(rd_reg, rt != 0 ? rs : 0); + set_register(rd_reg(), rt() != 0 ? rs() : 0); break; case JR: { + int64_t next_pc = rs(); + int64_t current_pc = get_pc(); Instruction* branch_delay_instr = reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize); BranchDelayInstructionDecode(branch_delay_instr); @@ -3741,6 +3259,9 @@ void Simulator::DecodeTypeRegisterSPECIAL( break; } case JALR: { + int64_t next_pc = rs(); + int64_t current_pc = get_pc(); + int32_t return_addr_reg = rd_reg(); Instruction* branch_delay_instr = reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize); BranchDelayInstructionDecode(branch_delay_instr); @@ -3749,18 +3270,118 @@ void Simulator::DecodeTypeRegisterSPECIAL( pc_modified_ = true; break; } + case SLL: + SetResult(rd_reg(), static_cast<int32_t>(rt()) << sa()); + break; + case DSLL: + SetResult(rd_reg(), rt() << sa()); + break; + case DSLL32: + SetResult(rd_reg(), rt() << sa() << 32); + break; + case SRL: + if (rs_reg() == 0) { + // Regular logical right shift of a word by a fixed number of + // bits instruction. RS field is always equal to 0. + // Sign-extend the 32-bit result. + alu_out = static_cast<int32_t>(static_cast<uint32_t>(rt_u()) >> sa()); + } else { + // Logical right-rotate of a word by a fixed number of bits. This + // is special case of SRL instruction, added in MIPS32 Release 2. + // RS field is equal to 00001. + alu_out = static_cast<int32_t>( + base::bits::RotateRight32(static_cast<const uint32_t>(rt_u()), + static_cast<const uint32_t>(sa()))); + } + SetResult(rd_reg(), alu_out); + break; + case DSRL: + SetResult(rd_reg(), rt_u() >> sa()); + break; + case DSRL32: + SetResult(rd_reg(), rt_u() >> sa() >> 32); + break; + case SRA: + SetResult(rd_reg(), (int32_t)rt() >> sa()); + break; + case DSRA: + SetResult(rd_reg(), rt() >> sa()); + break; + case DSRA32: + SetResult(rd_reg(), rt() >> sa() >> 32); + break; + case SLLV: + SetResult(rd_reg(), (int32_t)rt() << rs()); + break; + case DSLLV: + SetResult(rd_reg(), rt() << rs()); + break; + case SRLV: + if (sa() == 0) { + // Regular logical right-shift of a word by a variable number of + // bits instruction. SA field is always equal to 0. + alu_out = static_cast<int32_t>((uint32_t)rt_u() >> rs()); + } else { + // Logical right-rotate of a word by a variable number of bits. + // This is special case od SRLV instruction, added in MIPS32 + // Release 2. SA field is equal to 00001. + alu_out = static_cast<int32_t>( + base::bits::RotateRight32(static_cast<const uint32_t>(rt_u()), + static_cast<const uint32_t>(rs_u()))); + } + SetResult(rd_reg(), alu_out); + break; + case DSRLV: + if (sa() == 0) { + // Regular logical right-shift of a word by a variable number of + // bits instruction. SA field is always equal to 0. + alu_out = rt_u() >> rs(); + } else { + // Logical right-rotate of a word by a variable number of bits. + // This is special case od SRLV instruction, added in MIPS32 + // Release 2. SA field is equal to 00001. + alu_out = + base::bits::RotateRight32(static_cast<const uint32_t>(rt_u()), + static_cast<const uint32_t>(rs_u())); + } + SetResult(rd_reg(), alu_out); + break; + case SRAV: + SetResult(rd_reg(), (int32_t)rt() >> rs()); + break; + case DSRAV: + SetResult(rd_reg(), rt() >> rs()); + break; + case MFHI: // MFHI == CLZ on R6. + if (kArchVariant != kMips64r6) { + DCHECK(sa() == 0); + alu_out = get_register(HI); + } else { + // MIPS spec: If no bits were set in GPR rs(), the result written to + // GPR rd() is 32. + DCHECK(sa() == 1); + alu_out = base::bits::CountLeadingZeros32(static_cast<int32_t>(rs_u())); + } + SetResult(rd_reg(), alu_out); + break; + case MFLO: + SetResult(rd_reg(), get_register(LO)); + break; // Instructions using HI and LO registers. - case MULT: + case MULT: { // MULT == D_MUL_MUH. + int32_t rs_lo = static_cast<int32_t>(rs()); + int32_t rt_lo = static_cast<int32_t>(rt()); + i64hilo = static_cast<int64_t>(rs_lo) * static_cast<int64_t>(rt_lo); if (kArchVariant != kMips64r6) { set_register(LO, static_cast<int32_t>(i64hilo & 0xffffffff)); set_register(HI, static_cast<int32_t>(i64hilo >> 32)); } else { - switch (instr->SaValue()) { + switch (sa()) { case MUL_OP: - set_register(rd_reg, static_cast<int32_t>(i64hilo & 0xffffffff)); + set_register(rd_reg(), static_cast<int32_t>(i64hilo & 0xffffffff)); break; case MUH_OP: - set_register(rd_reg, static_cast<int32_t>(i64hilo >> 32)); + set_register(rd_reg(), static_cast<int32_t>(i64hilo >> 32)); break; default: UNIMPLEMENTED_MIPS(); @@ -3768,21 +3389,24 @@ void Simulator::DecodeTypeRegisterSPECIAL( } } break; + } case MULTU: + u64hilo = static_cast<uint64_t>(rs_u() & 0xffffffff) * + static_cast<uint64_t>(rt_u() & 0xffffffff); set_register(LO, static_cast<int32_t>(u64hilo & 0xffffffff)); set_register(HI, static_cast<int32_t>(u64hilo >> 32)); break; case DMULT: // DMULT == D_MUL_MUH. if (kArchVariant != kMips64r6) { - set_register(LO, static_cast<int64_t>(i128resultL)); - set_register(HI, static_cast<int64_t>(i128resultH)); + set_register(LO, rs() * rt()); + set_register(HI, MultiplyHighSigned(rs(), rt())); } else { - switch (instr->SaValue()) { + switch (sa()) { case MUL_OP: - set_register(rd_reg, static_cast<int64_t>(i128resultL)); + set_register(rd_reg(), rs() * rt()); break; case MUH_OP: - set_register(rd_reg, static_cast<int64_t>(i128resultH)); + set_register(rd_reg(), MultiplyHighSigned(rs(), rt())); break; default: UNIMPLEMENTED_MIPS(); @@ -3793,42 +3417,38 @@ void Simulator::DecodeTypeRegisterSPECIAL( case DMULTU: UNIMPLEMENTED_MIPS(); break; - case DSLL: - set_register(rd_reg, alu_out); - TraceRegWr(alu_out); - break; case DIV: case DDIV: { const int64_t int_min_value = - instr->FunctionFieldRaw() == DIV ? INT_MIN : LONG_MIN; + get_instr()->FunctionFieldRaw() == DIV ? INT_MIN : LONG_MIN; switch (kArchVariant) { case kMips64r2: // Divide by zero and overflow was not checked in the // configuration step - div and divu do not raise exceptions. On // division by 0 the result will be UNPREDICTABLE. On overflow // (INT_MIN/-1), return INT_MIN which is what the hardware does. - if (rs == int_min_value && rt == -1) { + if (rs() == int_min_value && rt() == -1) { set_register(LO, int_min_value); set_register(HI, 0); - } else if (rt != 0) { - set_register(LO, rs / rt); - set_register(HI, rs % rt); + } else if (rt() != 0) { + set_register(LO, rs() / rt()); + set_register(HI, rs() % rt()); } break; case kMips64r6: - switch (instr->SaValue()) { + switch (sa()) { case DIV_OP: - if (rs == int_min_value && rt == -1) { - set_register(rd_reg, int_min_value); - } else if (rt != 0) { - set_register(rd_reg, rs / rt); + if (rs() == int_min_value && rt() == -1) { + set_register(rd_reg(), int_min_value); + } else if (rt() != 0) { + set_register(rd_reg(), rs() / rt()); } break; case MOD_OP: - if (rs == int_min_value && rt == -1) { - set_register(rd_reg, 0); - } else if (rt != 0) { - set_register(rd_reg, rs % rt); + if (rs() == int_min_value && rt() == -1) { + set_register(rd_reg(), 0); + } else if (rt() != 0) { + set_register(rd_reg(), rs() % rt()); } break; default: @@ -3842,91 +3462,317 @@ void Simulator::DecodeTypeRegisterSPECIAL( break; } case DIVU: - if (rt_u != 0) { - set_register(LO, rs_u / rt_u); - set_register(HI, rs_u % rt_u); + if (rt_u() != 0) { + uint32_t rt_u_32 = static_cast<uint32_t>(rt_u()); + uint32_t rs_u_32 = static_cast<uint32_t>(rs_u()); + set_register(LO, rs_u_32 / rt_u_32); + set_register(HI, rs_u_32 % rt_u_32); + } + break; + case DDIVU: + if (rt_u() != 0) { + set_register(LO, rs_u() / rt_u()); + set_register(HI, rs_u() % rt_u()); } break; + case ADD: + case DADD: + if (HaveSameSign(rs(), rt())) { + if (rs() > 0) { + if (rs() > (Registers::kMaxValue - rt())) { + SignalException(kIntegerOverflow); + } + } else if (rs() < 0) { + if (rs() < (Registers::kMinValue - rt())) { + SignalException(kIntegerUnderflow); + } + } + } + SetResult(rd_reg(), rs() + rt()); + break; + case ADDU: { + int32_t alu32_out = static_cast<int32_t>(rs() + rt()); + // Sign-extend result of 32bit operation into 64bit register. + SetResult(rd_reg(), static_cast<int64_t>(alu32_out)); + break; + } + case DADDU: + SetResult(rd_reg(), rs() + rt()); + break; + case SUB: + case DSUB: + if (!HaveSameSign(rs(), rt())) { + if (rs() > 0) { + if (rs() > (Registers::kMaxValue + rt())) { + SignalException(kIntegerOverflow); + } + } else if (rs() < 0) { + if (rs() < (Registers::kMinValue + rt())) { + SignalException(kIntegerUnderflow); + } + } + } + SetResult(rd_reg(), rs() - rt()); + break; + case SUBU: { + int32_t alu32_out = static_cast<int32_t>(rs() - rt()); + // Sign-extend result of 32bit operation into 64bit register. + SetResult(rd_reg(), static_cast<int64_t>(alu32_out)); + break; + } + case DSUBU: + SetResult(rd_reg(), rs() - rt()); + break; + case AND: + SetResult(rd_reg(), rs() & rt()); + break; + case OR: + SetResult(rd_reg(), rs() | rt()); + break; + case XOR: + SetResult(rd_reg(), rs() ^ rt()); + break; + case NOR: + SetResult(rd_reg(), ~(rs() | rt())); + break; + case SLT: + SetResult(rd_reg(), rs() < rt() ? 1 : 0); + break; + case SLTU: + SetResult(rd_reg(), rs_u() < rt_u() ? 1 : 0); + break; // Break and trap instructions. case BREAK: + do_interrupt = true; + break; case TGE: + do_interrupt = rs() >= rt(); + break; case TGEU: + do_interrupt = rs_u() >= rt_u(); + break; case TLT: + do_interrupt = rs() < rt(); + break; case TLTU: + do_interrupt = rs_u() < rt_u(); + break; case TEQ: + do_interrupt = rs() == rt(); + break; case TNE: - if (do_interrupt) { - SoftwareInterrupt(instr); - } + do_interrupt = rs() != rt(); break; // Conditional moves. case MOVN: - if (rt) { - set_register(rd_reg, rs); - TraceRegWr(rs); + if (rt()) { + SetResult(rd_reg(), rs()); } break; case MOVCI: { - uint32_t cc = instr->FBccValue(); + uint32_t cc = get_instr()->FBccValue(); uint32_t fcsr_cc = get_fcsr_condition_bit(cc); - if (instr->Bit(16)) { // Read Tf bit. - if (test_fcsr_bit(fcsr_cc)) set_register(rd_reg, rs); + if (get_instr()->Bit(16)) { // Read Tf bit. + if (test_fcsr_bit(fcsr_cc)) set_register(rd_reg(), rs()); } else { - if (!test_fcsr_bit(fcsr_cc)) set_register(rd_reg, rs); + if (!test_fcsr_bit(fcsr_cc)) set_register(rd_reg(), rs()); } break; } case MOVZ: - if (!rt) { - set_register(rd_reg, rs); - TraceRegWr(rs); + if (!rt()) { + SetResult(rd_reg(), rs()); } break; - default: // For other special opcodes we do the default operation. - set_register(rd_reg, alu_out); - TraceRegWr(alu_out); + default: + UNREACHABLE(); + } + if (do_interrupt) { + SoftwareInterrupt(get_instr()); } } -void Simulator::DecodeTypeRegisterSPECIAL2(Instruction* instr, - const int32_t rd_reg, - int64_t alu_out) { - switch (instr->FunctionFieldRaw()) { +void Simulator::DecodeTypeRegisterSPECIAL2() { + int64_t alu_out; + switch (get_instr()->FunctionFieldRaw()) { case MUL: - set_register(rd_reg, alu_out); - TraceRegWr(alu_out); + alu_out = static_cast<int32_t>(rs_u()) * static_cast<int32_t>(rt_u()); + SetResult(rd_reg(), alu_out); // HI and LO are UNPREDICTABLE after the operation. set_register(LO, Unpredictable); set_register(HI, Unpredictable); break; - default: // For other special2 opcodes we do the default operation. - set_register(rd_reg, alu_out); + case CLZ: + // MIPS32 spec: If no bits were set in GPR rs(), the result written to + // GPR rd is 32. + alu_out = base::bits::CountLeadingZeros32(static_cast<uint32_t>(rs_u())); + set_register(rd_reg(), alu_out); + break; + default: + alu_out = 0x12345678; + UNREACHABLE(); } } -void Simulator::DecodeTypeRegisterSPECIAL3(Instruction* instr, - const int32_t rt_reg, - const int32_t rd_reg, - const int64_t alu_out) { - switch (instr->FunctionFieldRaw()) { - case INS: - // Ins instr leaves result in Rt, rather than Rd. - set_register(rt_reg, alu_out); - TraceRegWr(alu_out); +void Simulator::DecodeTypeRegisterSPECIAL3() { + int64_t alu_out; + switch (get_instr()->FunctionFieldRaw()) { + case INS: { // Mips32r2 instruction. + // Interpret rd field as 5-bit msb of insert. + uint16_t msb = rd_reg(); + // Interpret sa field as 5-bit lsb of insert. + uint16_t lsb = sa(); + uint16_t size = msb - lsb + 1; + uint64_t mask = (1ULL << size) - 1; + alu_out = (rt_u() & ~(mask << lsb)) | ((rs_u() & mask) << lsb); + SetResult(rt_reg(), alu_out); break; - case EXT: - case DEXT: - // Dext/Ext instr leaves result in Rt, rather than Rd. - set_register(rt_reg, alu_out); - TraceRegWr(alu_out); + } + case EXT: { // Mips32r2 instruction. + // Interpret rd field as 5-bit msb of extract. + uint16_t msb = rd_reg(); + // Interpret sa field as 5-bit lsb of extract. + uint16_t lsb = sa(); + uint16_t size = msb + 1; + uint64_t mask = (1ULL << size) - 1; + alu_out = static_cast<int32_t>((rs_u() & (mask << lsb)) >> lsb); + SetResult(rt_reg(), alu_out); break; - case BSHFL: - case DBSHFL: - set_register(rd_reg, alu_out); - TraceRegWr(alu_out); + } + case DEXT: { // Mips32r2 instruction. + // Interpret rd field as 5-bit msb of extract. + uint16_t msb = rd_reg(); + // Interpret sa field as 5-bit lsb of extract. + uint16_t lsb = sa(); + uint16_t size = msb + 1; + uint64_t mask = (1ULL << size) - 1; + alu_out = static_cast<int64_t>((rs_u() & (mask << lsb)) >> lsb); + SetResult(rt_reg(), alu_out); break; + } + case BSHFL: { + int32_t sa = get_instr()->SaFieldRaw() >> kSaShift; + switch (sa) { + case BITSWAP: { + uint32_t input = static_cast<uint32_t>(rt()); + uint32_t output = 0; + uint8_t i_byte, o_byte; + + // Reverse the bit in byte for each individual byte + for (int i = 0; i < 4; i++) { + output = output >> 8; + i_byte = input & 0xff; + + // Fast way to reverse bits in byte + // Devised by Sean Anderson, July 13, 2001 + o_byte = static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) | + (i_byte * 0x8020LU & 0x88440LU)) * + 0x10101LU >> + 16); + + output = output | (static_cast<uint32_t>(o_byte << 24)); + input = input >> 8; + } + + alu_out = static_cast<int64_t>(static_cast<int32_t>(output)); + break; + } + case SEB: + case SEH: + case WSBH: + alu_out = 0x12345678; + UNREACHABLE(); + break; + default: { + const uint8_t bp2 = get_instr()->Bp2Value(); + sa >>= kBp2Bits; + switch (sa) { + case ALIGN: { + if (bp2 == 0) { + alu_out = static_cast<int32_t>(rt()); + } else { + uint64_t rt_hi = rt() << (8 * bp2); + uint64_t rs_lo = rs() >> (8 * (4 - bp2)); + alu_out = static_cast<int32_t>(rt_hi | rs_lo); + } + break; + } + default: + alu_out = 0x12345678; + UNREACHABLE(); + break; + } + break; + } + } + SetResult(rd_reg(), alu_out); + break; + } + case DBSHFL: { + int32_t sa = get_instr()->SaFieldRaw() >> kSaShift; + switch (sa) { + case DBITSWAP: { + switch (sa) { + case DBITSWAP_SA: { // Mips64r6 + uint64_t input = static_cast<uint64_t>(rt()); + uint64_t output = 0; + uint8_t i_byte, o_byte; + + // Reverse the bit in byte for each individual byte + for (int i = 0; i < 8; i++) { + output = output >> 8; + i_byte = input & 0xff; + + // Fast way to reverse bits in byte + // Devised by Sean Anderson, July 13, 2001 + o_byte = + static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) | + (i_byte * 0x8020LU & 0x88440LU)) * + 0x10101LU >> + 16); + + output = output | ((static_cast<uint64_t>(o_byte) << 56)); + input = input >> 8; + } + + alu_out = static_cast<int64_t>(output); + break; + } + } + break; + } + case DSBH: + case DSHD: + alu_out = 0x12345678; + UNREACHABLE(); + break; + default: { + const uint8_t bp3 = get_instr()->Bp3Value(); + sa >>= kBp3Bits; + switch (sa) { + case DALIGN: { + if (bp3 == 0) { + alu_out = static_cast<int64_t>(rt()); + } else { + uint64_t rt_hi = rt() << (8 * bp3); + uint64_t rs_lo = rs() >> (8 * (8 - bp3)); + alu_out = static_cast<int64_t>(rt_hi | rs_lo); + } + break; + } + default: + alu_out = 0x12345678; + UNREACHABLE(); + break; + } + break; + } + } + SetResult(rd_reg(), alu_out); + break; + } default: UNREACHABLE(); } @@ -3934,97 +3780,46 @@ void Simulator::DecodeTypeRegisterSPECIAL3(Instruction* instr, void Simulator::DecodeTypeRegister(Instruction* instr) { - // Instruction fields. - const Opcode op = instr->OpcodeFieldRaw(); - const int32_t rs_reg = instr->RsValue(); - const int64_t rs = get_register(rs_reg); - const uint64_t rs_u = static_cast<uint32_t>(rs); - const int32_t rt_reg = instr->RtValue(); - const int64_t rt = get_register(rt_reg); - const uint64_t rt_u = static_cast<uint32_t>(rt); - const int32_t rd_reg = instr->RdValue(); - - const int32_t fr_reg = instr->FrValue(); - const int32_t fs_reg = instr->FsValue(); - const int32_t ft_reg = instr->FtValue(); - const int32_t fd_reg = instr->FdValue(); - int64_t i64hilo = 0; - uint64_t u64hilo = 0; - - // ALU output. - // It should not be used as is. Instructions using it should always - // initialize it first. - int64_t alu_out = 0x12345678; - - // For break and trap instructions. - bool do_interrupt = false; - - // For jr and jalr. - // Get current pc. - int64_t current_pc = get_pc(); - // Next pc - int64_t next_pc = 0; - int32_t return_addr_reg = 31; - - int64_t i128resultH; - int64_t i128resultL; - - // Set up the variables if needed before executing the instruction. - ConfigureTypeRegister(instr, - &alu_out, - &i64hilo, - &u64hilo, - &next_pc, - &return_addr_reg, - &do_interrupt, - &i128resultH, - &i128resultL); - - // ---------- Raise exceptions triggered. - SignalExceptions(); + set_instr(instr); // ---------- Execution. - switch (op) { + switch (instr->OpcodeFieldRaw()) { case COP1: - DecodeTypeRegisterCOP1(instr, rs_reg, rs, rs_u, rt_reg, rt, rt_u, rd_reg, - fr_reg, fs_reg, ft_reg, fd_reg, alu_out); + DecodeTypeRegisterCOP1(); break; case COP1X: - DecodeTypeRegisterCOP1X(instr, fr_reg, fs_reg, ft_reg, fd_reg); + DecodeTypeRegisterCOP1X(); break; case SPECIAL: - DecodeTypeRegisterSPECIAL( - instr, rs_reg, rs, rs_u, rt_reg, rt, rt_u, rd_reg, fr_reg, fs_reg, - ft_reg, fd_reg, i64hilo, u64hilo, alu_out, do_interrupt, current_pc, - next_pc, return_addr_reg, i128resultH, i128resultL); + DecodeTypeRegisterSPECIAL(); break; case SPECIAL2: - DecodeTypeRegisterSPECIAL2(instr, rd_reg, alu_out); + DecodeTypeRegisterSPECIAL2(); break; case SPECIAL3: switch (instr->FunctionFieldRaw()) { case BSHFL: { - int sa = instr->SaValue(); - sa >>= kBp2Bits; - switch (sa) { + int32_t saVal = sa(); + saVal >>= kBp2Bits; + switch (saVal) { case ALIGN: { - DecodeTypeRegisterSPECIAL3(instr, rt_reg, rd_reg, alu_out); + DecodeTypeRegisterSPECIAL3(); break; } } } case DBSHFL: { - int sa = instr->SaValue(); - sa >>= kBp3Bits; - switch (sa) { + int32_t saVal = sa(); + saVal >>= kBp2Bits; + switch (saVal) { case DALIGN: { - DecodeTypeRegisterSPECIAL3(instr, rt_reg, rd_reg, alu_out); + DecodeTypeRegisterSPECIAL3(); break; } } } default: - DecodeTypeRegisterSPECIAL3(instr, rt_reg, rd_reg, alu_out); + DecodeTypeRegisterSPECIAL3(); break; } break; @@ -4032,60 +3827,68 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { // so we can use the default here to set the destination register in common // cases. default: - set_register(rd_reg, alu_out); - TraceRegWr(alu_out); + UNREACHABLE(); } } +// Branch instructions common part. +#define BranchAndLinkHelper(do_branch) \ + execute_branch_delay_instruction = true; \ + if (do_branch) { \ + next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize; \ + set_register(31, current_pc + kBranchReturnOffset); \ + } else { \ + next_pc = current_pc + kBranchReturnOffset; \ + } + + +#define BranchHelper(do_branch) \ + execute_branch_delay_instruction = true; \ + if (do_branch) { \ + next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize; \ + } else { \ + next_pc = current_pc + kBranchReturnOffset; \ + } + + // Type 2: instructions using a 16 bytes immediate. (e.g. addi, beq). void Simulator::DecodeTypeImmediate(Instruction* instr) { // Instruction fields. - Opcode op = instr->OpcodeFieldRaw(); + Opcode op = instr->OpcodeFieldRaw(); int32_t rs_reg = instr->RsValue(); - int64_t rs = get_register(instr->RsValue()); - uint64_t rs_u = static_cast<uint64_t>(rs); - int32_t rt_reg = instr->RtValue(); // Destination register. - int64_t rt = get_register(rt_reg); - int16_t imm16 = instr->Imm16Value(); + int64_t rs = get_register(instr->RsValue()); + uint64_t rs_u = static_cast<uint64_t>(rs); + int32_t rt_reg = instr->RtValue(); // Destination register. + int64_t rt = get_register(rt_reg); + int16_t imm16 = instr->Imm16Value(); int32_t imm18 = instr->Imm18Value(); - int32_t imm19 = instr->Imm19Value(); int32_t imm21 = instr->Imm21Value(); int32_t imm26 = instr->Imm26Value(); - int32_t ft_reg = instr->FtValue(); // Destination register. - int64_t ft = get_fpu_register(ft_reg); + int32_t ft_reg = instr->FtValue(); // Destination register. + int64_t ft = get_fpu_register(ft_reg); // Zero extended immediate. uint64_t oe_imm16 = 0xffff & imm16; // Sign extended immediate. int64_t se_imm16 = imm16; int64_t se_imm18 = imm18 | ((imm18 & 0x20000) ? 0xfffffffffffc0000 : 0); - int64_t se_imm19 = imm19 | ((imm19 & 0x40000) ? 0xfffffffffff80000 : 0); int64_t se_imm26 = imm26 | ((imm26 & 0x2000000) ? 0xfffffffffc000000 : 0); - // Get current pc. int64_t current_pc = get_pc(); // Next pc. int64_t next_pc = bad_ra; - // pc increment - int16_t pc_increment; // Used for conditional branch instructions. - bool do_branch = false; bool execute_branch_delay_instruction = false; // Used for arithmetic instructions. int64_t alu_out = 0; - // Floating point. - double fp_out = 0.0; - uint32_t cc, cc_value, fcsr_cc; // Used for memory instructions. int64_t addr = 0x0; - // Value to be written in memory. - uint64_t mem_value = 0x0; // Alignment for 32-bit integers used in LWL, LWR, etc. const int kInt32AlignmentMask = sizeof(uint32_t) - 1; @@ -4094,11 +3897,11 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { // ------------- COP1. Coprocessor instructions. case COP1: switch (instr->RsFieldRaw()) { - case BC1: // Branch on coprocessor condition. - cc = instr->FBccValue(); - fcsr_cc = get_fcsr_condition_bit(cc); - cc_value = test_fcsr_bit(fcsr_cc); - do_branch = (instr->FBtrueValue()) ? cc_value : !cc_value; + case BC1: { // Branch on coprocessor condition. + uint32_t cc = instr->FBccValue(); + uint32_t fcsr_cc = get_fcsr_condition_bit(cc); + uint32_t cc_value = test_fcsr_bit(fcsr_cc); + bool do_branch = (instr->FBtrueValue()) ? cc_value : !cc_value; execute_branch_delay_instruction = true; // Set next_pc. if (do_branch) { @@ -4107,21 +3910,20 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { next_pc = current_pc + kBranchReturnOffset; } break; + } case BC1EQZ: - do_branch = (ft & 0x1) ? false : true; execute_branch_delay_instruction = true; // Set next_pc. - if (do_branch) { + if (!(ft & 0x1)) { next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize; } else { next_pc = current_pc + kBranchReturnOffset; } break; case BC1NEZ: - do_branch = (ft & 0x1) ? true : false; execute_branch_delay_instruction = true; // Set next_pc. - if (do_branch) { + if (ft & 0x1) { next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize; } else { next_pc = current_pc + kBranchReturnOffset; @@ -4135,54 +3937,35 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { case REGIMM: switch (instr->RtFieldRaw()) { case BLTZ: - do_branch = (rs < 0); - break; - case BLTZAL: - do_branch = rs < 0; + BranchHelper(rs < 0); break; case BGEZ: - do_branch = rs >= 0; + BranchHelper(rs >= 0); + break; + case BLTZAL: + BranchAndLinkHelper(rs < 0); break; case BGEZAL: - do_branch = rs >= 0; + BranchAndLinkHelper(rs >= 0); break; default: UNREACHABLE(); } - switch (instr->RtFieldRaw()) { - case BLTZ: - case BLTZAL: - case BGEZ: - case BGEZAL: - // Branch instructions common part. - execute_branch_delay_instruction = true; - // Set next_pc. - if (do_branch) { - next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize; - if (instr->IsLinkingInstruction()) { - set_register(31, current_pc + kBranchReturnOffset); - } - } else { - next_pc = current_pc + kBranchReturnOffset; - } - default: - break; - } - break; // case REGIMM. + break; // case REGIMM. // ------------- Branch instructions. // When comparing to zero, the encoding of rt field is always 0, so we don't // need to replace rt with zero. case BEQ: - do_branch = (rs == rt); + BranchHelper(rs == rt); break; case BNE: - do_branch = rs != rt; + BranchHelper(rs != rt); break; case BLEZ: - do_branch = rs <= 0; + BranchHelper(rs <= 0); break; case BGTZ: - do_branch = rs > 0; + BranchHelper(rs > 0); break; case POP66: { if (rs_reg) { // BEQZC @@ -4216,52 +3999,53 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { case DADDI: if (HaveSameSign(rs, se_imm16)) { if (rs > 0) { - exceptions[kIntegerOverflow] = rs > (Registers::kMaxValue - se_imm16); + if (rs > Registers::kMaxValue - se_imm16) { + SignalException(kIntegerOverflow); + } } else if (rs < 0) { - exceptions[kIntegerUnderflow] = - rs < (Registers::kMinValue - se_imm16); + if (rs < Registers::kMinValue - se_imm16) { + SignalException(kIntegerUnderflow); + } } } - alu_out = rs + se_imm16; + SetResult(rt_reg, rs + se_imm16); break; case ADDIU: { int32_t alu32_out = static_cast<int32_t>(rs + se_imm16); // Sign-extend result of 32bit operation into 64bit register. - alu_out = static_cast<int64_t>(alu32_out); + SetResult(rt_reg, static_cast<int64_t>(alu32_out)); break; } case DADDIU: - alu_out = rs + se_imm16; + SetResult(rt_reg, rs + se_imm16); break; case SLTI: - alu_out = (rs < se_imm16) ? 1 : 0; + SetResult(rt_reg, rs < se_imm16 ? 1 : 0); break; case SLTIU: - alu_out = (rs_u < static_cast<uint64_t>(se_imm16)) ? 1 : 0; + SetResult(rt_reg, rs_u < static_cast<uint64_t>(se_imm16) ? 1 : 0); break; case ANDI: - alu_out = rs & oe_imm16; + SetResult(rt_reg, rs & oe_imm16); break; case ORI: - alu_out = rs | oe_imm16; + SetResult(rt_reg, rs | oe_imm16); break; case XORI: - alu_out = rs ^ oe_imm16; + SetResult(rt_reg, rs ^ oe_imm16); break; case LUI: { int32_t alu32_out = static_cast<int32_t>(oe_imm16 << 16); // Sign-extend result of 32bit operation into 64bit register. - alu_out = static_cast<int64_t>(alu32_out); + SetResult(rt_reg, static_cast<int64_t>(alu32_out)); break; } // ------------- Memory instructions. case LB: - addr = rs + se_imm16; - alu_out = ReadB(addr); + set_register(rt_reg, ReadB(rs + se_imm16)); break; case LH: - addr = rs + se_imm16; - alu_out = ReadH(addr, instr); + set_register(rt_reg, ReadH(rs + se_imm16, instr)); break; case LWL: { // al_offset is offset of the effective address within an aligned word. @@ -4272,27 +4056,23 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { alu_out = ReadW(addr, instr); alu_out <<= byte_shift * 8; alu_out |= rt & mask; + set_register(rt_reg, alu_out); break; } case LW: - addr = rs + se_imm16; - alu_out = ReadW(addr, instr); + set_register(rt_reg, ReadW(rs + se_imm16, instr)); break; case LWU: - addr = rs + se_imm16; - alu_out = ReadWU(addr, instr); + set_register(rt_reg, ReadWU(rs + se_imm16, instr)); break; case LD: - addr = rs + se_imm16; - alu_out = Read2W(addr, instr); + set_register(rt_reg, Read2W(rs + se_imm16, instr)); break; case LBU: - addr = rs + se_imm16; - alu_out = ReadBU(addr); + set_register(rt_reg, ReadBU(rs + se_imm16)); break; case LHU: - addr = rs + se_imm16; - alu_out = ReadHU(addr, instr); + set_register(rt_reg, ReadHU(rs + se_imm16, instr)); break; case LWR: { // al_offset is offset of the effective address within an aligned word. @@ -4303,59 +4083,68 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { alu_out = ReadW(addr, instr); alu_out = static_cast<uint32_t> (alu_out) >> al_offset * 8; alu_out |= rt & mask; + set_register(rt_reg, alu_out); break; } case SB: - addr = rs + se_imm16; + WriteB(rs + se_imm16, static_cast<int8_t>(rt)); break; case SH: - addr = rs + se_imm16; + WriteH(rs + se_imm16, static_cast<uint16_t>(rt), instr); break; case SWL: { uint8_t al_offset = (rs + se_imm16) & kInt32AlignmentMask; uint8_t byte_shift = kInt32AlignmentMask - al_offset; uint32_t mask = byte_shift ? (~0 << (al_offset + 1) * 8) : 0; addr = rs + se_imm16 - al_offset; - mem_value = ReadW(addr, instr) & mask; + uint64_t mem_value = ReadW(addr, instr) & mask; mem_value |= static_cast<uint32_t>(rt) >> byte_shift * 8; + WriteW(addr, static_cast<int32_t>(mem_value), instr); break; } case SW: + WriteW(rs + se_imm16, static_cast<int32_t>(rt), instr); + break; case SD: - addr = rs + se_imm16; + Write2W(rs + se_imm16, rt, instr); break; case SWR: { uint8_t al_offset = (rs + se_imm16) & kInt32AlignmentMask; uint32_t mask = (1 << al_offset * 8) - 1; addr = rs + se_imm16 - al_offset; - mem_value = ReadW(addr, instr); + uint64_t mem_value = ReadW(addr, instr); mem_value = (rt << al_offset * 8) | (mem_value & mask); + WriteW(addr, static_cast<int32_t>(mem_value), instr); break; } case LWC1: - addr = rs + se_imm16; - alu_out = ReadW(addr, instr); + set_fpu_register(ft_reg, kFPUInvalidResult); // Trash upper 32 bits. + set_fpu_register_word(ft_reg, ReadW(rs + se_imm16, instr)); break; case LDC1: - addr = rs + se_imm16; - fp_out = ReadD(addr, instr); + set_fpu_register_double(ft_reg, ReadD(rs + se_imm16, instr)); break; - case SWC1: + case SWC1: { + int32_t alu_out_32 = static_cast<int32_t>(get_fpu_register(ft_reg)); + WriteW(rs + se_imm16, alu_out_32, instr); + break; + } case SDC1: - addr = rs + se_imm16; + WriteD(rs + se_imm16, get_fpu_register_double(ft_reg), instr); break; // ------------- JIALC and BNEZC instructions. - case POP76: + case POP76: { // Next pc. next_pc = rt + se_imm16; // The instruction after the jump is NOT executed. - pc_increment = Instruction::kInstrSize; + uint16_t pc_increment = Instruction::kInstrSize; if (instr->IsLinkingInstruction()) { set_register(31, current_pc + pc_increment); } set_pc(next_pc); pc_modified_ = true; break; + } // ------------- PC-Relative instructions. case PCREL: { // rt field: checking 5-bits. @@ -4369,6 +4158,7 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { alu_out = current_pc + (se_imm16 << 16); break; default: { + int32_t imm19 = instr->Imm19Value(); // rt field: checking the most significant 3-bits. rt = (imm21 >> kImm18Bits); switch (rt) { @@ -4382,28 +4172,29 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { rt = (imm21 >> kImm19Bits); switch (rt) { case LWUPC: { - int32_t offset = imm19; // Set sign. - offset <<= (kOpcodeBits + kRsBits + 2); - offset >>= (kOpcodeBits + kRsBits + 2); - addr = current_pc + (offset << 2); + imm19 <<= (kOpcodeBits + kRsBits + 2); + imm19 >>= (kOpcodeBits + kRsBits + 2); + addr = current_pc + (imm19 << 2); uint32_t* ptr = reinterpret_cast<uint32_t*>(addr); alu_out = *ptr; break; } case LWPC: { - int32_t offset = imm19; // Set sign. - offset <<= (kOpcodeBits + kRsBits + 2); - offset >>= (kOpcodeBits + kRsBits + 2); - addr = current_pc + (offset << 2); + imm19 <<= (kOpcodeBits + kRsBits + 2); + imm19 >>= (kOpcodeBits + kRsBits + 2); + addr = current_pc + (imm19 << 2); int32_t* ptr = reinterpret_cast<int32_t*>(addr); alu_out = *ptr; break; } - case ADDIUPC: + case ADDIUPC: { + int64_t se_imm19 = + imm19 | ((imm19 & 0x40000) ? 0xfffffffffff80000 : 0); alu_out = current_pc + (se_imm19 << 2); break; + } default: UNREACHABLE(); break; @@ -4414,100 +4205,13 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { break; } } + set_register(rs_reg, alu_out); break; } default: UNREACHABLE(); } - // ---------- Raise exceptions triggered. - SignalExceptions(); - - // ---------- Execution. - switch (op) { - // ------------- Branch instructions. - case BEQ: - case BNE: - case BLEZ: - case BGTZ: - // Branch instructions common part. - execute_branch_delay_instruction = true; - // Set next_pc. - if (do_branch) { - next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize; - if (instr->IsLinkingInstruction()) { - set_register(31, current_pc + 2* Instruction::kInstrSize); - } - } else { - next_pc = current_pc + 2 * Instruction::kInstrSize; - } - break; - // ------------- Arithmetic instructions. - case ADDI: - case DADDI: - case ADDIU: - case DADDIU: - case SLTI: - case SLTIU: - case ANDI: - case ORI: - case XORI: - case LUI: - set_register(rt_reg, alu_out); - TraceRegWr(alu_out); - break; - // ------------- Memory instructions. - case LB: - case LH: - case LWL: - case LW: - case LWU: - case LD: - case LBU: - case LHU: - case LWR: - set_register(rt_reg, alu_out); - break; - case SB: - WriteB(addr, static_cast<int8_t>(rt)); - break; - case SH: - WriteH(addr, static_cast<uint16_t>(rt), instr); - break; - case SWL: - WriteW(addr, static_cast<int32_t>(mem_value), instr); - break; - case SW: - WriteW(addr, static_cast<int32_t>(rt), instr); - break; - case SD: - Write2W(addr, rt, instr); - break; - case SWR: - WriteW(addr, static_cast<int32_t>(mem_value), instr); - break; - case LWC1: - set_fpu_register(ft_reg, kFPUInvalidResult); // Trash upper 32 bits. - set_fpu_register_word(ft_reg, static_cast<int32_t>(alu_out)); - break; - case LDC1: - set_fpu_register_double(ft_reg, fp_out); - break; - case SWC1: - addr = rs + se_imm16; - WriteW(addr, static_cast<int32_t>(get_fpu_register(ft_reg)), instr); - break; - case SDC1: - addr = rs + se_imm16; - WriteD(addr, get_fpu_register_double(ft_reg), instr); - break; - case PCREL: - set_register(rs_reg, alu_out); - default: - break; - } - - if (execute_branch_delay_instruction) { // Execute branch delay slot // We don't check for end_sim_pc. First it should not be met as the current @@ -4523,6 +4227,9 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { } } +#undef BranchHelper +#undef BranchAndLinkHelper + // Type 3: instructions using a 26 bytes immediate. (e.g. j, jal). void Simulator::DecodeTypeJump(Instruction* instr) { @@ -4567,7 +4274,7 @@ void Simulator::InstructionDecode(Instruction* instr) { dasm.InstructionDecode(buffer, reinterpret_cast<byte*>(instr)); } - switch (instr->InstructionType()) { + switch (instr->InstructionType(Instruction::TypeChecks::EXTRA)) { case Instruction::kRegisterType: DecodeTypeRegister(instr); break; |