Index: src/mips/simulator-mips.cc |
diff --git a/src/mips/simulator-mips.cc b/src/mips/simulator-mips.cc |
index 6dea3f09a3969f339af0733c75a5642e5bb4bf3c..4ef61abe3db140721365325748679b91852271fd 100644 |
--- a/src/mips/simulator-mips.cc |
+++ b/src/mips/simulator-mips.cc |
@@ -979,10 +979,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; |
} |
@@ -1628,7 +1624,8 @@ void Simulator::TraceRegWr(int32_t value) { |
// TODO(plind): consider making icount_ printing a flag option. |
void Simulator::TraceMemRd(int32_t addr, int32_t value) { |
if (::v8::internal::FLAG_trace_sim) { |
- SNPrintF(trace_buf_, "%08x <-- [%08x] (%d)", value, addr, icount_); |
+ SNPrintF(trace_buf_, "%08x <-- [%08x] (%" PRIu64 ")", value, addr, |
+ icount_); |
} |
} |
@@ -2101,7 +2098,8 @@ bool Simulator::IsWatchpoint(uint32_t code) { |
void Simulator::PrintWatchpoint(uint32_t code) { |
MipsDebugger dbg(this); |
++break_count_; |
- PrintF("\n---- break %d marker: %3d (instr count: %8d) ----------" |
+ PrintF("\n---- break %d marker: %3d (instr count: %" PRIu64 |
+ ") ----------" |
"----------------------------------", |
code, break_count_, icount_); |
dbg.PrintAllRegs(); // Print registers and continue running. |
@@ -2185,362 +2183,26 @@ void Simulator::PrintStopInfo(uint32_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, |
- int32_t* alu_out, |
- int64_t* i64hilo, |
- uint64_t* u64hilo, |
- int32_t* next_pc, |
- int32_t* return_addr_reg, |
- bool* do_interrupt) { |
- // 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 int32_t rs = get_register(rs_reg); |
- const uint32_t rs_u = static_cast<uint32_t>(rs); |
- const int32_t rt_reg = instr->RtValue(); |
- const int32_t rt = get_register(rt_reg); |
- const uint32_t rt_u = static_cast<uint32_t>(rt); |
- const int32_t rd_reg = instr->RdValue(); |
- const uint32_t sa = instr->SaValue(); |
- const uint8_t bp = instr->Bp2Value(); |
- |
- 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 = get_fpu_register_word(fs_reg); |
- break; |
- case MFHC1: |
- *alu_out = get_fpu_register_hi_word(fs_reg); |
- break; |
- case CTC1: |
- case MTC1: |
- 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 = rt << sa; |
- 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. |
- *alu_out = 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 = base::bits::RotateRight32(rt_u, sa); |
- } |
- break; |
- case SRA: |
- *alu_out = rt >> sa; |
- break; |
- case SLLV: |
- *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 = 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(rt_u, rs_u); |
- } |
- break; |
- case SRAV: |
- *alu_out = rt >> rs; |
- break; |
- case MFHI: // MFHI == CLZ on R6. |
- if (!IsMipsArchVariant(kMips32r6)) { |
- 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(rs_u); |
- } |
- break; |
- case MFLO: |
- *alu_out = get_register(LO); |
- break; |
- case MULT: // MULT == MUL_MUH. |
- if (!IsMipsArchVariant(kMips32r6)) { |
- *i64hilo = static_cast<int64_t>(rs) * static_cast<int64_t>(rt); |
- } else { |
- switch (instr->SaValue()) { |
- case MUL_OP: |
- case MUH_OP: |
- *i64hilo = static_cast<int64_t>(rs) * static_cast<int64_t>(rt); |
- break; |
- default: |
- UNIMPLEMENTED_MIPS(); |
- break; |
- } |
- } |
- break; |
- case MULTU: // MULTU == MUL_MUH_U. |
- if (!IsMipsArchVariant(kMips32r6)) { |
- *u64hilo = static_cast<uint64_t>(rs_u) * |
- static_cast<uint64_t>(rt_u); |
- } else { |
- switch (instr->SaValue()) { |
- case MUL_OP: |
- case MUH_OP: |
- *u64hilo = static_cast<uint64_t>(rs_u) * |
- static_cast<uint64_t>(rt_u); |
- break; |
- default: |
- UNIMPLEMENTED_MIPS(); |
- break; |
- } |
- } |
- break; |
- case ADD: |
- 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: |
- *alu_out = rs + rt; |
- break; |
- case SUB: |
- 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: |
- *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: |
- // div and divu never raise exceptions. |
- case SELEQZ_S: |
- case SELNEZ_S: |
- break; |
- default: |
- UNREACHABLE(); |
- } |
- break; |
- case SPECIAL2: |
- switch (instr->FunctionFieldRaw()) { |
- case MUL: |
- *alu_out = rs_u * rt_u; // Only the lower 32 bits are kept. |
- 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(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; |
- uint32_t mask = (1 << 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; |
- uint32_t mask = (1 << size) - 1; |
- *alu_out = (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<int32_t>(output); |
- break; |
- } |
- case SEB: |
- case SEH: |
- case WSBH: |
- UNREACHABLE(); |
- break; |
- default: { |
- sa >>= kBp2Bits; |
- switch (sa) { |
- case ALIGN: { |
- if (bp == 0) { |
- *alu_out = static_cast<int32_t>(rt); |
- } else { |
- uint32_t rt_hi = rt << (8 * bp); |
- uint32_t rs_lo = rs >> (8 * (4 - bp)); |
- *alu_out = static_cast<int32_t>(rt_hi | rs_lo); |
- } |
- break; |
- } |
- default: |
- UNREACHABLE(); |
- break; |
- } |
- } |
- } |
- break; |
- } |
- default: |
- UNREACHABLE(); |
- } |
- break; |
- default: |
- UNREACHABLE(); |
- } |
-} |
- |
- |
-void Simulator::DecodeTypeRegisterDRsType(Instruction* instr, |
- const int32_t& fr_reg, |
- 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; |
int64_t i64; |
- 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); |
+ 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()); |
int64_t ft_int = bit_cast<int64_t>(ft); |
int64_t fd_int = bit_cast<int64_t>(fd); |
- cc = instr->FCccValue(); |
+ cc = get_instr()->FCccValue(); |
fcsr_cc = get_fcsr_condition_bit(cc); |
- switch (instr->FunctionFieldRaw()) { |
+ switch (get_instr()->FunctionFieldRaw()) { |
case RINT: { |
DCHECK(IsMipsArchVariant(kMips32r6)); |
double result, temp, temp_result; |
@@ -2572,7 +2234,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); |
} |
@@ -2580,69 +2242,67 @@ void Simulator::DecodeTypeRegisterDRsType(Instruction* instr, |
} |
case SEL: |
DCHECK(IsMipsArchVariant(kMips32r6)); |
- 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(IsMipsArchVariant(kMips32r6)); |
- 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(IsMipsArchVariant(kMips32r6)); |
- 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(IsMipsArchVariant(kMips32r2)); |
- int32_t rt_reg = instr->RtValue(); |
- int32_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(IsMipsArchVariant(kMips32r2)); |
- int32_t rt_reg = instr->RtValue(); |
+ int32_t rt_reg = get_instr()->RtValue(); |
int32_t rt = get_register(rt_reg); |
if (rt != 0) { |
- set_fpu_register_double(fd_reg, fs); |
+ 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 MIN: |
DCHECK(IsMipsArchVariant(kMips32r6)); |
- 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 MINA: |
DCHECK(IsMipsArchVariant(kMips32r6)); |
- 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)) { |
@@ -2652,18 +2312,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(IsMipsArchVariant(kMips32r6)); |
- 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)) { |
@@ -2673,57 +2333,57 @@ 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 MAX: |
DCHECK(IsMipsArchVariant(kMips32r6)); |
- 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; |
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: { |
DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)); |
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: { |
DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)); |
double result = 1.0 / fs; |
- set_fpu_register_double(fd_reg, result); |
+ set_fpu_register_double(fd_reg(), result); |
break; |
} |
case C_UN_D: |
@@ -2751,9 +2411,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; |
case ROUND_W_D: // Round double to word (round half to even). |
@@ -2765,49 +2425,49 @@ 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_word(fd_reg, kFPUInvalidResult); |
+ set_fpu_register_word(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_word(fd_reg, kFPUInvalidResult); |
+ set_fpu_register_word(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_word(fd_reg, kFPUInvalidResult); |
+ set_fpu_register_word(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_word(fd_reg, kFPUInvalidResult); |
+ set_fpu_register_word(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: { // Mips32r2: Truncate double to 64-bit long-word. |
if (IsFp64Mode()) { |
int64_t result; |
double rounded; |
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); |
} |
} else { |
UNSUPPORTED(); |
@@ -2820,9 +2480,9 @@ void Simulator::DecodeTypeRegisterDRsType(Instruction* instr, |
double rounded = trunc(fs); |
i64 = static_cast<int64_t>(rounded); |
if (IsFp64Mode()) { |
- 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); |
} |
} else { |
UNSUPPORTED(); |
@@ -2840,9 +2500,9 @@ void Simulator::DecodeTypeRegisterDRsType(Instruction* instr, |
} |
int64_t i64 = static_cast<int64_t>(result); |
if (IsFp64Mode()) { |
- 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); |
} |
} else { |
UNSUPPORTED(); |
@@ -2854,9 +2514,9 @@ void Simulator::DecodeTypeRegisterDRsType(Instruction* instr, |
double rounded = std::floor(fs); |
int64_t i64 = static_cast<int64_t>(rounded); |
if (IsFp64Mode()) { |
- 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); |
} |
} else { |
UNSUPPORTED(); |
@@ -2868,9 +2528,9 @@ void Simulator::DecodeTypeRegisterDRsType(Instruction* instr, |
double rounded = std::ceil(fs); |
int64_t i64 = static_cast<int64_t>(rounded); |
if (IsFp64Mode()) { |
- 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); |
} |
} else { |
UNSUPPORTED(); |
@@ -2938,7 +2598,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; |
} |
@@ -2952,92 +2612,90 @@ void Simulator::DecodeTypeRegisterDRsType(Instruction* instr, |
} |
-void Simulator::DecodeTypeRegisterWRsType(Instruction* instr, int32_t& alu_out, |
- const int32_t& fd_reg, |
- const int32_t& fs_reg, |
- const int32_t& ft_reg) { |
- 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()); |
+ int32_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: |
@@ -3046,20 +2704,17 @@ void Simulator::DecodeTypeRegisterWRsType(Instruction* instr, int32_t& alu_out, |
} |
-void Simulator::DecodeTypeRegisterSRsType(Instruction* instr, |
- const int32_t& ft_reg, |
- const int32_t& fs_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(IsMipsArchVariant(kMips32r6)); |
float result, temp_result; |
@@ -3092,46 +2747,46 @@ 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: { |
DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)); |
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: { |
DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)); |
float result = 1.0 / fs; |
- set_fpu_register_float(fd_reg, result); |
+ set_fpu_register_float(fd_reg(), result); |
break; |
} |
case C_F_D: |
@@ -3159,15 +2814,15 @@ 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 SEL: |
DCHECK(IsMipsArchVariant(kMips32r6)); |
- 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 CLASS_S: { // Mips32r6 instruction |
// Convert float input to uint32_t for easier bit manipulation |
- float fs = get_fpu_register_float(fs_reg); |
+ float fs = get_fpu_register_float(fs_reg()); |
uint32_t classed = bit_cast<uint32_t>(fs); |
// Extracting sign, exponent and mantissa from the input float |
@@ -3227,58 +2882,56 @@ 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; |
} |
case SELEQZ_C: |
DCHECK(IsMipsArchVariant(kMips32r6)); |
- 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(IsMipsArchVariant(kMips32r6)); |
- 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(IsMipsArchVariant(kMips32r2)); |
- int32_t rt_reg = instr->RtValue(); |
- int32_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(IsMipsArchVariant(kMips32r2)); |
- int32_t rt_reg = instr->RtValue(); |
- int32_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; |
} |
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: { // Mips32r2 instruction. |
@@ -3286,9 +2939,9 @@ void Simulator::DecodeTypeRegisterSRsType(Instruction* instr, |
float rounded = trunc(fs); |
int64_t i64 = static_cast<int64_t>(rounded); |
if (IsFp64Mode()) { |
- 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); |
} |
} else { |
UNSUPPORTED(); |
@@ -3299,9 +2952,9 @@ 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 FLOOR_L_S: { // Mips32r2 instruction. |
@@ -3309,9 +2962,9 @@ void Simulator::DecodeTypeRegisterSRsType(Instruction* instr, |
float rounded = std::floor(fs); |
int64_t i64 = static_cast<int64_t>(rounded); |
if (IsFp64Mode()) { |
- 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); |
} |
} else { |
UNSUPPORTED(); |
@@ -3326,9 +2979,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; |
} |
@@ -3343,9 +2996,9 @@ void Simulator::DecodeTypeRegisterSRsType(Instruction* instr, |
} |
int64_t i64 = static_cast<int64_t>(result); |
if (IsFp64Mode()) { |
- 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); |
} |
} else { |
UNSUPPORTED(); |
@@ -3356,9 +3009,9 @@ void Simulator::DecodeTypeRegisterSRsType(Instruction* instr, |
{ |
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_word(fd_reg, kFPUInvalidResult); |
+ set_fpu_register_word(fd_reg(), kFPUInvalidResult); |
} |
} break; |
case CEIL_L_S: { // Mips32r2 instruction. |
@@ -3366,9 +3019,9 @@ void Simulator::DecodeTypeRegisterSRsType(Instruction* instr, |
float rounded = std::ceil(fs); |
int64_t i64 = static_cast<int64_t>(rounded); |
if (IsFp64Mode()) { |
- 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); |
} |
} else { |
UNSUPPORTED(); |
@@ -3377,39 +3030,39 @@ void Simulator::DecodeTypeRegisterSRsType(Instruction* instr, |
} |
case MIN: |
DCHECK(IsMipsArchVariant(kMips32r6)); |
- 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(IsMipsArchVariant(kMips32r6)); |
- 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 MINA: |
DCHECK(IsMipsArchVariant(kMips32r6)); |
- 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)) { |
@@ -3419,18 +3072,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(IsMipsArchVariant(kMips32r6)); |
- 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)) { |
@@ -3440,7 +3093,7 @@ 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 CVT_L_S: { |
@@ -3448,9 +3101,9 @@ void Simulator::DecodeTypeRegisterSRsType(Instruction* instr, |
int64_t result; |
float rounded; |
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); |
} |
} else { |
UNSUPPORTED(); |
@@ -3461,9 +3114,9 @@ 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; |
} |
@@ -3475,105 +3128,102 @@ void Simulator::DecodeTypeRegisterSRsType(Instruction* instr, |
} |
-void Simulator::DecodeTypeRegisterLRsType(Instruction* instr, |
- const int32_t& ft_reg, |
- const int32_t& fs_reg, |
- const int32_t& fd_reg) { |
- double fs = get_fpu_register_double(fs_reg); |
- double ft = get_fpu_register_double(ft_reg); |
- switch (instr->FunctionFieldRaw()) { |
+void Simulator::DecodeTypeRegisterLRsType() { |
+ double fs = get_fpu_register_double(fs_reg()); |
+ double ft = get_fpu_register_double(ft_reg()); |
+ switch (get_instr()->FunctionFieldRaw()) { |
case CVT_D_L: // Mips32r2 instruction. |
// Watch the signs here, we want 2 32-bit vals |
// to make a sign-64. |
int64_t i64; |
if (IsFp64Mode()) { |
- i64 = get_fpu_register(fs_reg); |
+ i64 = get_fpu_register(fs_reg()); |
} else { |
- i64 = static_cast<uint32_t>(get_fpu_register_word(fs_reg)); |
- i64 |= static_cast<int64_t>(get_fpu_register_word(fs_reg + 1)) << 32; |
+ i64 = static_cast<uint32_t>(get_fpu_register_word(fs_reg())); |
+ i64 |= static_cast<int64_t>(get_fpu_register_word(fs_reg() + 1)) << 32; |
} |
- set_fpu_register_double(fd_reg, static_cast<double>(i64)); |
+ set_fpu_register_double(fd_reg(), static_cast<double>(i64)); |
break; |
case CVT_S_L: |
if (IsFp64Mode()) { |
- i64 = get_fpu_register(fs_reg); |
+ i64 = get_fpu_register(fs_reg()); |
} else { |
- i64 = static_cast<uint32_t>(get_fpu_register_word(fs_reg)); |
- i64 |= static_cast<int64_t>(get_fpu_register_word(fs_reg + 1)) << 32; |
+ i64 = static_cast<uint32_t>(get_fpu_register_word(fs_reg())); |
+ i64 |= static_cast<int64_t>(get_fpu_register_word(fs_reg() + 1)) << 32; |
} |
- set_fpu_register_float(fd_reg, static_cast<float>(i64)); |
+ set_fpu_register_float(fd_reg(), static_cast<float>(i64)); |
break; |
case CMP_AF: // Mips64r6 CMP.D instructions. |
- 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: |
@@ -3582,67 +3232,62 @@ void Simulator::DecodeTypeRegisterLRsType(Instruction* instr, |
} |
-void Simulator::DecodeTypeRegisterCOP1( |
- Instruction* instr, const int32_t& rs_reg, const int32_t& rs, |
- const uint32_t& rs_u, const int32_t& rt_reg, const int32_t& rt, |
- const uint32_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& i64hilo, uint64_t& u64hilo, int32_t& alu_out, bool& do_interrupt, |
- int32_t& current_pc, int32_t& next_pc, int32_t& return_addr_reg) { |
- switch (instr->RsFieldRaw()) { |
+void Simulator::DecodeTypeRegisterCOP1() { |
+ switch (get_instr()->RsFieldRaw()) { |
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, alu_out); |
+ set_register(rt_reg(), get_fpu_register_word(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_ = registers_[rt_reg]; |
+ DCHECK(fs_reg() == kFCSRRegister); |
+ FCSR_ = registers_[rt_reg()]; |
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, registers_[rt_reg]); |
+ set_fpu_register_hi_word(fs_reg(), 0); |
+ set_fpu_register_word(fs_reg(), registers_[rt_reg()]); |
break; |
case MTHC1: |
- set_fpu_register_hi_word(fs_reg, registers_[rt_reg]); |
+ set_fpu_register_hi_word(fs_reg(), registers_[rt_reg()]); |
break; |
case S: { |
- DecodeTypeRegisterSRsType(instr, ft_reg, fs_reg, fd_reg); |
+ DecodeTypeRegisterSRsType(); |
break; |
} |
case D: |
- DecodeTypeRegisterDRsType(instr, fr_reg, fs_reg, ft_reg, fd_reg); |
+ DecodeTypeRegisterDRsType(); |
break; |
case W: |
- DecodeTypeRegisterWRsType(instr, alu_out, fd_reg, fs_reg, ft_reg); |
+ DecodeTypeRegisterWRsType(); |
break; |
case L: |
- DecodeTypeRegisterLRsType(instr, ft_reg, fs_reg, fd_reg); |
+ DecodeTypeRegisterLRsType(); |
break; |
+ case PS: |
+ // Not implemented. |
+ UNREACHABLE(); |
default: |
UNREACHABLE(); |
} |
} |
-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(); |
@@ -3650,216 +3295,411 @@ void Simulator::DecodeTypeRegisterCOP1X(Instruction* instr, |
} |
-void Simulator::DecodeTypeRegisterSPECIAL( |
- Instruction* instr, const int32_t& rs_reg, const int32_t& rs, |
- const uint32_t& rs_u, const int32_t& rt_reg, const int32_t& rt, |
- const uint32_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& i64hilo, uint64_t& u64hilo, int32_t& alu_out, bool& do_interrupt, |
- int32_t& current_pc, int32_t& next_pc, int32_t& return_addr_reg) { |
- switch (instr->FunctionFieldRaw()) { |
+void Simulator::DecodeTypeRegisterSPECIAL() { |
+ int64_t alu_out = 0x12345678; |
+ int64_t i64hilo = 0; |
+ uint64_t u64hilo = 0; |
+ bool do_interrupt = false; |
+ |
+ switch (get_instr()->FunctionFieldRaw()) { |
case SELEQZ_S: |
DCHECK(IsMipsArchVariant(kMips32r6)); |
- set_register(rd_reg, rt == 0 ? rs : 0); |
+ set_register(rd_reg(), rt() == 0 ? rs() : 0); |
break; |
case SELNEZ_S: |
DCHECK(IsMipsArchVariant(kMips32r6)); |
- set_register(rd_reg, rt != 0 ? rs : 0); |
- break; |
- case JR: { |
- Instruction* branch_delay_instr = reinterpret_cast<Instruction*>( |
- current_pc+Instruction::kInstrSize); |
- BranchDelayInstructionDecode(branch_delay_instr); |
- set_pc(next_pc); |
- pc_modified_ = true; |
- break; |
+ set_register(rd_reg(), rt() != 0 ? rs() : 0); |
+ break; |
+ case JR: { |
+ int32_t next_pc = rs(); |
+ int32_t current_pc = get_pc(); |
+ Instruction* branch_delay_instr = |
+ reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize); |
+ BranchDelayInstructionDecode(branch_delay_instr); |
+ set_pc(next_pc); |
+ pc_modified_ = true; |
+ break; |
+ } |
+ case JALR: { |
+ int32_t next_pc = rs(); |
+ int32_t return_addr_reg = rd_reg(); |
+ int32_t current_pc = get_pc(); |
+ Instruction* branch_delay_instr = |
+ reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize); |
+ BranchDelayInstructionDecode(branch_delay_instr); |
+ set_register(return_addr_reg, current_pc + 2 * Instruction::kInstrSize); |
+ set_pc(next_pc); |
+ pc_modified_ = true; |
+ break; |
+ } |
+ case SLL: |
+ alu_out = rt() << sa(); |
+ SetResult(rd_reg(), static_cast<int32_t>(alu_out)); |
+ 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. |
+ alu_out = 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 = base::bits::RotateRight32(rt_u(), sa()); |
+ } |
+ SetResult(rd_reg(), static_cast<int32_t>(alu_out)); |
+ break; |
+ case SRA: |
+ alu_out = rt() >> sa(); |
+ SetResult(rd_reg(), static_cast<int32_t>(alu_out)); |
+ break; |
+ case SLLV: |
+ alu_out = rt() << rs(); |
+ SetResult(rd_reg(), static_cast<int32_t>(alu_out)); |
+ 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 = 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(rt_u(), rs_u()); |
+ } |
+ SetResult(rd_reg(), static_cast<int32_t>(alu_out)); |
+ break; |
+ case SRAV: |
+ alu_out = rt() >> rs(); |
+ SetResult(rd_reg(), static_cast<int32_t>(alu_out)); |
+ break; |
+ case MFHI: // MFHI == CLZ on R6. |
+ if (!IsMipsArchVariant(kMips32r6)) { |
+ 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(rs_u()); |
+ } |
+ SetResult(rd_reg(), static_cast<int32_t>(alu_out)); |
+ break; |
+ case MFLO: |
+ alu_out = get_register(LO); |
+ SetResult(rd_reg(), static_cast<int32_t>(alu_out)); |
+ break; |
+ // Instructions using HI and LO registers. |
+ case MULT: |
+ i64hilo = static_cast<int64_t>(rs()) * static_cast<int64_t>(rt()); |
+ if (!IsMipsArchVariant(kMips32r6)) { |
+ set_register(LO, static_cast<int32_t>(i64hilo & 0xffffffff)); |
+ set_register(HI, static_cast<int32_t>(i64hilo >> 32)); |
+ } else { |
+ switch (sa()) { |
+ case MUL_OP: |
+ set_register(rd_reg(), static_cast<int32_t>(i64hilo & 0xffffffff)); |
+ break; |
+ case MUH_OP: |
+ set_register(rd_reg(), static_cast<int32_t>(i64hilo >> 32)); |
+ break; |
+ default: |
+ UNIMPLEMENTED_MIPS(); |
+ break; |
} |
- case JALR: { |
- Instruction* branch_delay_instr = reinterpret_cast<Instruction*>( |
- current_pc+Instruction::kInstrSize); |
- BranchDelayInstructionDecode(branch_delay_instr); |
- set_register(return_addr_reg, |
- current_pc + 2 * Instruction::kInstrSize); |
- set_pc(next_pc); |
- pc_modified_ = true; |
- break; |
+ } |
+ break; |
+ case MULTU: |
+ u64hilo = static_cast<uint64_t>(rs_u()) * static_cast<uint64_t>(rt_u()); |
+ if (!IsMipsArchVariant(kMips32r6)) { |
+ set_register(LO, static_cast<int32_t>(u64hilo & 0xffffffff)); |
+ set_register(HI, static_cast<int32_t>(u64hilo >> 32)); |
+ } else { |
+ switch (sa()) { |
+ case MUL_OP: |
+ set_register(rd_reg(), static_cast<int32_t>(u64hilo & 0xffffffff)); |
+ break; |
+ case MUH_OP: |
+ set_register(rd_reg(), static_cast<int32_t>(u64hilo >> 32)); |
+ break; |
+ default: |
+ UNIMPLEMENTED_MIPS(); |
+ break; |
} |
- // Instructions using HI and LO registers. |
- case MULT: |
- if (!IsMipsArchVariant(kMips32r6)) { |
- set_register(LO, static_cast<int32_t>(i64hilo & 0xffffffff)); |
- set_register(HI, static_cast<int32_t>(i64hilo >> 32)); |
- } else { |
- switch (instr->SaValue()) { |
- case MUL_OP: |
- set_register(rd_reg, |
- static_cast<int32_t>(i64hilo & 0xffffffff)); |
- break; |
- case MUH_OP: |
- set_register(rd_reg, static_cast<int32_t>(i64hilo >> 32)); |
- break; |
- default: |
- UNIMPLEMENTED_MIPS(); |
- break; |
- } |
- } |
- break; |
- case MULTU: |
- if (!IsMipsArchVariant(kMips32r6)) { |
- set_register(LO, static_cast<int32_t>(u64hilo & 0xffffffff)); |
- set_register(HI, static_cast<int32_t>(u64hilo >> 32)); |
- } else { |
- switch (instr->SaValue()) { |
- case MUL_OP: |
- set_register(rd_reg, |
- static_cast<int32_t>(u64hilo & 0xffffffff)); |
- break; |
- case MUH_OP: |
- set_register(rd_reg, static_cast<int32_t>(u64hilo >> 32)); |
- break; |
- default: |
- UNIMPLEMENTED_MIPS(); |
- break; |
+ } |
+ break; |
+ case DIV: |
+ if (IsMipsArchVariant(kMips32r6)) { |
+ switch (get_instr()->SaValue()) { |
+ case DIV_OP: |
+ if (rs() == INT_MIN && rt() == -1) { |
+ set_register(rd_reg(), INT_MIN); |
+ } else if (rt() != 0) { |
+ set_register(rd_reg(), rs() / rt()); |
} |
- } |
- break; |
- case DIV: |
- if (IsMipsArchVariant(kMips32r6)) { |
- switch (instr->SaValue()) { |
- case DIV_OP: |
- if (rs == INT_MIN && rt == -1) { |
- set_register(rd_reg, INT_MIN); |
- } else if (rt != 0) { |
- set_register(rd_reg, rs / rt); |
- } |
- break; |
- case MOD_OP: |
- if (rs == INT_MIN && rt == -1) { |
- set_register(rd_reg, 0); |
- } else if (rt != 0) { |
- set_register(rd_reg, rs % rt); |
- } |
- break; |
- default: |
- UNIMPLEMENTED_MIPS(); |
- break; |
+ break; |
+ case MOD_OP: |
+ if (rs() == INT_MIN && rt() == -1) { |
+ set_register(rd_reg(), 0); |
+ } else if (rt() != 0) { |
+ set_register(rd_reg(), rs() % rt()); |
} |
- } else { |
- // 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 && rt == -1) { |
- set_register(LO, INT_MIN); |
- set_register(HI, 0); |
- } else if (rt != 0) { |
- set_register(LO, rs / rt); |
- set_register(HI, rs % rt); |
+ break; |
+ default: |
+ UNIMPLEMENTED_MIPS(); |
+ break; |
+ } |
+ } else { |
+ // 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 && rt() == -1) { |
+ set_register(LO, INT_MIN); |
+ set_register(HI, 0); |
+ } else if (rt() != 0) { |
+ set_register(LO, rs() / rt()); |
+ set_register(HI, rs() % rt()); |
+ } |
+ } |
+ break; |
+ case DIVU: |
+ if (IsMipsArchVariant(kMips32r6)) { |
+ switch (get_instr()->SaValue()) { |
+ case DIV_OP: |
+ if (rt_u() != 0) { |
+ set_register(rd_reg(), rs_u() / rt_u()); |
} |
- } |
- break; |
- case DIVU: |
- if (IsMipsArchVariant(kMips32r6)) { |
- switch (instr->SaValue()) { |
- case DIV_OP: |
- if (rt_u != 0) { |
- set_register(rd_reg, rs_u / rt_u); |
- } |
- break; |
- case MOD_OP: |
- if (rt_u != 0) { |
- set_register(rd_reg, rs_u % rt_u); |
- } |
- break; |
- default: |
- UNIMPLEMENTED_MIPS(); |
- break; |
- } |
- } else { |
- if (rt_u != 0) { |
- set_register(LO, rs_u / rt_u); |
- set_register(HI, rs_u % rt_u); |
+ break; |
+ case MOD_OP: |
+ if (rt_u() != 0) { |
+ set_register(rd_reg(), rs_u() % rt_u()); |
} |
+ break; |
+ default: |
+ UNIMPLEMENTED_MIPS(); |
+ break; |
+ } |
+ } else { |
+ if (rt_u() != 0) { |
+ set_register(LO, rs_u() / rt_u()); |
+ set_register(HI, rs_u() % rt_u()); |
+ } |
+ } |
+ break; |
+ case ADD: |
+ if (HaveSameSign(rs(), rt())) { |
+ if (rs() > 0) { |
+ if (rs() <= (Registers::kMaxValue - rt())) { |
+ SignalException(kIntegerOverflow); |
} |
- break; |
- // Break and trap instructions. |
- case BREAK: |
- case TGE: |
- case TGEU: |
- case TLT: |
- case TLTU: |
- case TEQ: |
- case TNE: |
- if (do_interrupt) { |
- SoftwareInterrupt(instr); |
+ } else if (rs() < 0) { |
+ if (rs() >= (Registers::kMinValue - rt())) { |
+ SignalException(kIntegerUnderflow); |
} |
- break; |
- // Conditional moves. |
- case MOVN: |
- if (rt) { |
- set_register(rd_reg, rs); |
- TraceRegWr(rs); |
+ } |
+ } |
+ SetResult(rd_reg(), rs() + rt()); |
+ break; |
+ case ADDU: |
+ SetResult(rd_reg(), rs() + rt()); |
+ break; |
+ case SUB: |
+ if (!HaveSameSign(rs(), rt())) { |
+ if (rs() > 0) { |
+ if (rs() <= (Registers::kMaxValue + rt())) { |
+ SignalException(kIntegerOverflow); |
} |
- break; |
- case MOVCI: { |
- uint32_t cc = 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); |
- } else { |
- if (!test_fcsr_bit(fcsr_cc)) set_register(rd_reg, rs); |
+ } else if (rs() < 0) { |
+ if (rs() >= (Registers::kMinValue + rt())) { |
+ SignalException(kIntegerUnderflow); |
} |
- break; |
} |
- case MOVZ: |
- if (!rt) { |
- set_register(rd_reg, rs); |
- TraceRegWr(rs); |
- } |
- break; |
- default: // For other special opcodes we do the default operation. |
- set_register(rd_reg, alu_out); |
- TraceRegWr(alu_out); |
} |
+ SetResult(rd_reg(), rs() - rt()); |
+ break; |
+ case SUBU: |
+ 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: |
+ do_interrupt = rs() != rt(); |
+ break; |
+ // Conditional moves. |
+ case MOVN: |
+ if (rt()) { |
+ set_register(rd_reg(), rs()); |
+ TraceRegWr(rs()); |
+ } |
+ break; |
+ case MOVCI: { |
+ uint32_t cc = get_instr()->FBccValue(); |
+ uint32_t fcsr_cc = get_fcsr_condition_bit(cc); |
+ 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()); |
+ } |
+ break; |
+ } |
+ case MOVZ: |
+ if (!rt()) { |
+ set_register(rd_reg(), rs()); |
+ TraceRegWr(rs()); |
+ } |
+ break; |
+ default: |
+ UNREACHABLE(); |
+ } |
+ if (do_interrupt) { |
+ SoftwareInterrupt(get_instr()); |
+ } |
} |
-void Simulator::DecodeTypeRegisterSPECIAL2(Instruction* instr, |
- const int32_t& rd_reg, |
- int32_t& alu_out) { |
- switch (instr->FunctionFieldRaw()) { |
+void Simulator::DecodeTypeRegisterSPECIAL2() { |
+ int32_t alu_out; |
+ switch (get_instr()->FunctionFieldRaw()) { |
case MUL: |
- set_register(rd_reg, alu_out); |
- TraceRegWr(alu_out); |
+ // Only the lower 32 bits are kept. |
+ alu_out = rs_u() * rt_u(); |
// 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); |
- TraceRegWr(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(rs_u()); |
+ break; |
+ default: |
+ alu_out = 0x12345678; |
+ UNREACHABLE(); |
} |
+ SetResult(rd_reg(), alu_out); |
} |
-void Simulator::DecodeTypeRegisterSPECIAL3(Instruction* instr, |
- const int32_t& rt_reg, |
- const int32_t& rd_reg, |
- int32_t& alu_out) { |
- switch (instr->FunctionFieldRaw()) { |
- case INS: |
+void Simulator::DecodeTypeRegisterSPECIAL3() { |
+ int32_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; |
+ uint32_t mask = (1 << size) - 1; |
+ alu_out = (rt_u() & ~(mask << lsb)) | ((rs_u() & mask) << lsb); |
// Ins instr leaves result in Rt, rather than Rd. |
- set_register(rt_reg, alu_out); |
- TraceRegWr(alu_out); |
+ SetResult(rt_reg(), alu_out); |
break; |
- case EXT: |
- 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; |
+ uint32_t mask = (1 << size) - 1; |
+ alu_out = (rs_u() & (mask << lsb)) >> lsb; |
+ SetResult(rt_reg(), alu_out); |
break; |
- case BSHFL: |
- set_register(rd_reg, alu_out); |
- TraceRegWr(alu_out); |
+ } |
+ case BSHFL: { |
+ int 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<int32_t>(output); |
+ break; |
+ } |
+ case SEB: |
+ case SEH: |
+ case WSBH: |
+ alu_out = 0x12345678; |
+ UNREACHABLE(); |
+ break; |
+ default: { |
+ const uint8_t bp = get_instr()->Bp2Value(); |
+ sa >>= kBp2Bits; |
+ switch (sa) { |
+ case ALIGN: { |
+ if (bp == 0) { |
+ alu_out = static_cast<int32_t>(rt()); |
+ } else { |
+ uint32_t rt_hi = rt() << (8 * bp); |
+ uint32_t rs_lo = rs() >> (8 * (4 - bp)); |
+ alu_out = static_cast<int32_t>(rt_hi | rs_lo); |
+ } |
+ break; |
+ } |
+ default: |
+ alu_out = 0x12345678; |
+ UNREACHABLE(); |
+ break; |
+ } |
+ } |
+ } |
+ SetResult(rd_reg(), alu_out); |
break; |
+ } |
default: |
UNREACHABLE(); |
} |
@@ -3867,134 +3707,101 @@ 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 int32_t rs = get_register(rs_reg); |
- const uint32_t rs_u = static_cast<uint32_t>(rs); |
- const int32_t rt_reg = instr->RtValue(); |
- const int32_t rt = get_register(rt_reg); |
- const uint32_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. |
- int32_t alu_out = 0x12345678; |
- |
- // For break and trap instructions. |
- bool do_interrupt = false; |
- |
- // For jr and jalr. |
- // Get current pc. |
- int32_t current_pc = get_pc(); |
- // Next pc |
- int32_t next_pc = 0; |
- int32_t return_addr_reg = 31; |
// Set up the variables if needed before executing the instruction. |
- ConfigureTypeRegister(instr, &alu_out, &i64hilo, &u64hilo, &next_pc, |
- &return_addr_reg, &do_interrupt); |
- |
- // ---------- Raise exceptions triggered. |
- SignalExceptions(); |
+ // ConfigureTypeRegister(instr); |
+ set_instr(instr); |
// ---------- Execution. |
switch (op) { |
case COP1: |
- DecodeTypeRegisterCOP1(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); |
+ 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); |
+ DecodeTypeRegisterSPECIAL(); |
break; |
case SPECIAL2: |
- DecodeTypeRegisterSPECIAL2(instr, rd_reg, alu_out); |
+ DecodeTypeRegisterSPECIAL2(); |
break; |
case SPECIAL3: |
- DecodeTypeRegisterSPECIAL3(instr, rt_reg, rd_reg, alu_out); |
+ DecodeTypeRegisterSPECIAL3(); |
break; |
- // Unimplemented opcodes raised an error in the configuration step before, |
- // so we can use the default here to set the destination register in common |
- // cases. |
default: |
- set_register(rd_reg, 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 + 2 * Instruction::kInstrSize); \ |
+ } else { \ |
+ next_pc = current_pc + 2 * Instruction::kInstrSize; \ |
+ } |
+ |
+#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 + 2 * Instruction::kInstrSize; \ |
+ } |
+ |
+ |
// 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(); |
- int32_t rs = get_register(instr->RsValue()); |
- uint32_t rs_u = static_cast<uint32_t>(rs); |
- int32_t rt_reg = instr->RtValue(); // Destination register. |
- int32_t rt = get_register(rt_reg); |
- int16_t imm16 = instr->Imm16Value(); |
- int32_t imm19 = instr->Imm19Value(); |
+ int32_t rs = get_register(instr->RsValue()); |
+ uint32_t rs_u = static_cast<uint32_t>(rs); |
+ int32_t rt_reg = instr->RtValue(); // Destination register. |
+ int32_t rt = get_register(rt_reg); |
+ int16_t imm16 = instr->Imm16Value(); |
int32_t imm21 = instr->Imm21Value(); |
int32_t imm26 = instr->Imm26Value(); |
- int32_t ft_reg = instr->FtValue(); // Destination register. |
- int64_t ft; |
+ int32_t ft_reg = instr->FtValue(); // Destination register. |
+ int64_t ft; |
// Zero extended immediate. |
- uint32_t oe_imm16 = 0xffff & imm16; |
+ uint32_t oe_imm16 = 0xffff & imm16; |
// Sign extended immediate. |
int32_t se_imm16 = imm16; |
- int32_t se_imm19 = imm19 | ((imm19 & 0x40000) ? 0xfff80000 : 0); |
int32_t se_imm26 = imm26 | ((imm26 & 0x2000000) ? 0xfc000000 : 0); |
- |
// Get current pc. |
int32_t current_pc = get_pc(); |
// Next pc. |
int32_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. |
int32_t alu_out = 0; |
- // Floating point. |
- double fp_out = 0.0; |
- uint32_t cc, cc_value, fcsr_cc; |
// Used for memory instructions. |
int32_t addr = 0x0; |
- // Value to be written in memory. |
- uint32_t mem_value = 0x0; |
// ---------- Configuration (and execution for REGIMM). |
switch (op) { |
// ------------- 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. |
+ // Floating point. |
+ 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) { |
@@ -4003,12 +3810,12 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { |
next_pc = current_pc + kBranchReturnOffset; |
} |
break; |
+ } |
case BC1EQZ: |
ft = get_fpu_register(ft_reg); |
- 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; |
@@ -4016,10 +3823,9 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { |
break; |
case BC1NEZ: |
ft = get_fpu_register(ft_reg); |
- 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; |
@@ -4033,54 +3839,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 |
@@ -4113,43 +3900,44 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { |
case ADDI: |
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: |
- 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<uint32_t>(se_imm16)) ? 1 : 0; |
+ SetResult(rt_reg, rs_u < static_cast<uint32_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: |
- alu_out = (oe_imm16 << 16); |
+ SetResult(rt_reg, oe_imm16 << 16); |
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. |
@@ -4160,19 +3948,17 @@ 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 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. |
@@ -4183,58 +3969,64 @@ 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) & kPointerAlignmentMask; |
uint8_t byte_shift = kPointerAlignmentMask - 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; |
+ // Value to be written in memory. |
+ uint32_t mem_value = ReadW(addr, instr) & mask; |
mem_value |= static_cast<uint32_t>(rt) >> byte_shift * 8; |
+ WriteW(addr, mem_value, instr); |
break; |
} |
case SW: |
- addr = rs + se_imm16; |
+ WriteW(rs + se_imm16, rt, instr); |
break; |
case SWR: { |
uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask; |
uint32_t mask = (1 << al_offset * 8) - 1; |
addr = rs + se_imm16 - al_offset; |
- mem_value = ReadW(addr, instr); |
+ uint32_t mem_value = ReadW(addr, instr); |
mem_value = (rt << al_offset * 8) | (mem_value & mask); |
+ WriteW(addr, mem_value, instr); |
break; |
} |
case LWC1: |
- addr = rs + se_imm16; |
- alu_out = ReadW(addr, instr); |
+ set_fpu_register_hi_word(ft_reg, 0); |
+ 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: |
+ WriteW(rs + se_imm16, get_fpu_register_word(ft_reg), 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; |
+ int16_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. |
@@ -4248,115 +4040,37 @@ 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 2-bits. |
rt = (imm21 >> kImm19Bits); |
switch (rt) { |
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); |
uint32_t* ptr = reinterpret_cast<uint32_t*>(addr); |
alu_out = *ptr; |
break; |
} |
- case ADDIUPC: |
+ case ADDIUPC: { |
+ int32_t se_imm19 = imm19 | ((imm19 & 0x40000) ? 0xfff80000 : 0); |
alu_out = current_pc + (se_imm19 << 2); |
break; |
+ } |
default: |
UNREACHABLE(); |
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 ADDIU: |
- 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 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, mem_value, instr); |
- break; |
- case SW: |
- WriteW(addr, rt, instr); |
- break; |
- case SWR: |
- WriteW(addr, mem_value, instr); |
- break; |
- case LWC1: |
- set_fpu_register_hi_word(ft_reg, 0); |
- set_fpu_register_word(ft_reg, alu_out); |
- break; |
- case LDC1: |
- set_fpu_register_double(ft_reg, fp_out); |
- break; |
- case SWC1: |
- addr = rs + se_imm16; |
- WriteW(addr, get_fpu_register_word(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 |
@@ -4372,6 +4086,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) { |
@@ -4413,7 +4130,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; |