Index: src/mips64/simulator-mips64.cc |
diff --git a/src/mips64/simulator-mips64.cc b/src/mips64/simulator-mips64.cc |
index 9a0d8fdce8bd359b8701ac56c45396e100eecdc0..00db0c82d2f2c3769e01e9cf05f2325902cd7f89 100644 |
--- a/src/mips64/simulator-mips64.cc |
+++ b/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; |
} |
@@ -2175,495 +2172,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 +2223,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 +2288,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 +2351,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 +2359,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 +2369,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 +2400,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 +2415,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 +2434,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 +2475,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 +2496,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 +2577,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 +2621,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 +2629,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 +2684,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 +2705,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 +2793,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 +2808,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 +2862,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 +2956,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 +2970,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 +3062,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 +3153,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 +3210,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 +3225,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 +3251,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 +3262,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 +3381,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 +3409,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 +3454,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 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 BSHFL: |
- case DBSHFL: |
- set_register(rd_reg, alu_out); |
- TraceRegWr(alu_out); |
+ } |
+ 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 +3772,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 +3819,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 +3889,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 +3902,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 +3929,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 +3991,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 +4048,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 +4075,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 +4150,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 +4164,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 +4197,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 +4219,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 +4266,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; |