Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(94)

Unified Diff: src/mips/simulator-mips.cc

Issue 1046873004: MIPS: Refactor simulator and add selection instructions for r6. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/mips/simulator-mips.cc
diff --git a/src/mips/simulator-mips.cc b/src/mips/simulator-mips.cc
index 7ea38419358a600f8c6202f2f30bcdd5c6e350bb..2e4921c71059eb799228c38bfa7bf5886b192d6b 100644
--- a/src/mips/simulator-mips.cc
+++ b/src/mips/simulator-mips.cc
@@ -2079,6 +2079,8 @@ void Simulator::ConfigureTypeRegister(Instruction* instr,
case DIV:
case DIVU:
// div and divu never raise exceptions.
+ case SELEQZ_S:
+ case SELNEZ_S:
break;
default:
UNREACHABLE();
@@ -2130,366 +2132,393 @@ void Simulator::ConfigureTypeRegister(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();
+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) {
+ double ft, fs;
+ uint32_t cc, fcsr_cc;
+ int64_t i64;
+ fs = get_fpu_register_double(fs_reg);
+ ft = get_fpu_register_double(ft_reg);
+ int64_t ft_int = static_cast<int64_t>(ft);
+ cc = instr->FCccValue();
+ fcsr_cc = get_fcsr_condition_bit(cc);
+ switch (instr->FunctionFieldRaw()) {
+ case SELEQZ_C:
+ DCHECK(IsMipsArchVariant(kMips32r6));
+ 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);
+ break;
+ case ADD_D:
+ set_fpu_register_double(fd_reg, fs + ft);
+ break;
+ case SUB_D:
+ set_fpu_register_double(fd_reg, fs - ft);
+ break;
+ case MUL_D:
+ set_fpu_register_double(fd_reg, fs * ft);
+ break;
+ case DIV_D:
+ set_fpu_register_double(fd_reg, fs / ft);
+ break;
+ case ABS_D:
+ set_fpu_register_double(fd_reg, fabs(fs));
+ break;
+ case MOV_D:
+ set_fpu_register_double(fd_reg, fs);
+ break;
+ case NEG_D:
+ set_fpu_register_double(fd_reg, -fs);
+ break;
+ case SQRT_D:
+ set_fpu_register_double(fd_reg, fast_sqrt(fs));
+ break;
+ case C_UN_D:
+ set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft));
+ break;
+ case C_EQ_D:
+ set_fcsr_bit(fcsr_cc, (fs == ft));
+ break;
+ case C_UEQ_D:
+ set_fcsr_bit(fcsr_cc, (fs == ft) || (std::isnan(fs) || std::isnan(ft)));
+ break;
+ case C_OLT_D:
+ set_fcsr_bit(fcsr_cc, (fs < ft));
+ break;
+ case C_ULT_D:
+ set_fcsr_bit(fcsr_cc, (fs < ft) || (std::isnan(fs) || std::isnan(ft)));
+ break;
+ case C_OLE_D:
+ set_fcsr_bit(fcsr_cc, (fs <= ft));
+ break;
+ case C_ULE_D:
+ set_fcsr_bit(fcsr_cc, (fs <= ft) || (std::isnan(fs) || std::isnan(ft)));
+ break;
+ case CVT_W_D: // Convert double to word.
+ // Rounding modes are not yet supported.
+ DCHECK((FCSR_ & 3) == 0);
+ // In rounding mode 0 it should behave like ROUND.
+ case ROUND_W_D: // Round double to word (round half to even).
+ {
+ double rounded = std::floor(fs + 0.5);
+ int32_t result = static_cast<int32_t>(rounded);
+ if ((result & 1) != 0 && result - fs == 0.5) {
+ // If the number is halfway between two integers,
+ // round to the even one.
+ result--;
+ }
+ set_fpu_register_word(fd_reg, result);
+ if (set_fcsr_round_error(fs, rounded)) {
+ 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);
+ if (set_fcsr_round_error(fs, rounded)) {
+ 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);
+ if (set_fcsr_round_error(fs, rounded)) {
+ 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);
+ if (set_fcsr_round_error(fs, rounded)) {
+ 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));
+ break;
+ case CVT_L_D: { // Mips32r2: Truncate double to 64-bit long-word.
+ double rounded = trunc(fs);
+ i64 = static_cast<int64_t>(rounded);
+ if (IsFp64Mode()) {
+ set_fpu_register(fd_reg, i64);
+ } else {
+ set_fpu_register_word(fd_reg, i64 & 0xffffffff);
+ set_fpu_register_word(fd_reg + 1, i64 >> 32);
+ }
+ break;
+ }
+ case TRUNC_L_D: { // Mips32r2 instruction.
paul.l... 2015/03/31 04:02:01 This comment (and many other like it need to be ch
+ double rounded = trunc(fs);
+ i64 = static_cast<int64_t>(rounded);
+ if (IsFp64Mode()) {
+ set_fpu_register(fd_reg, i64);
+ } else {
+ set_fpu_register_word(fd_reg, i64 & 0xffffffff);
+ set_fpu_register_word(fd_reg + 1, i64 >> 32);
+ }
+ break;
+ }
+ case ROUND_L_D: { // Mips32r2 instruction.
+ double rounded = fs > 0 ? std::floor(fs + 0.5) : std::ceil(fs - 0.5);
+ i64 = static_cast<int64_t>(rounded);
+ if (IsFp64Mode()) {
+ set_fpu_register(fd_reg, i64);
+ } else {
+ set_fpu_register_word(fd_reg, i64 & 0xffffffff);
+ set_fpu_register_word(fd_reg + 1, i64 >> 32);
+ }
+ break;
+ }
+ case FLOOR_L_D: // Mips32r2 instruction.
+ i64 = static_cast<int64_t>(std::floor(fs));
+ if (IsFp64Mode()) {
+ set_fpu_register(fd_reg, i64);
+ } else {
+ set_fpu_register_word(fd_reg, i64 & 0xffffffff);
+ set_fpu_register_word(fd_reg + 1, i64 >> 32);
+ }
+ break;
+ case CEIL_L_D: // Mips32r2 instruction.
+ i64 = static_cast<int64_t>(std::ceil(fs));
+ if (IsFp64Mode()) {
+ set_fpu_register(fd_reg, i64);
+ } else {
+ set_fpu_register_word(fd_reg, i64 & 0xffffffff);
+ set_fpu_register_word(fd_reg + 1, i64 >> 32);
+ }
+ break;
+ case C_F_D:
+ UNIMPLEMENTED_MIPS();
+ break;
+ default:
+ UNREACHABLE();
+ }
+}
- 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;
+void Simulator::DecodeTypeRegisterWRsType(Instruction* instr, int32_t& alu_out,
+ const int32_t& fd_reg,
+ const int32_t& fs_reg) {
+ switch (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));
+ 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));
+ break;
+ default: // Mips64r6 CMP.S instructions unimplemented.
+ UNREACHABLE();
+ }
+}
- // 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);
+void Simulator::DecodeTypeRegisterSRsType(Instruction* instr,
+ const int32_t& ft_reg,
+ const int32_t& fs_reg,
+ const int32_t& fd_reg) {
+ float f;
+ double ft = get_fpu_register_double(ft_reg);
+ int64_t ft_int = static_cast<int64_t>(ft);
+ switch (instr->FunctionFieldRaw()) {
+ case CVT_D_S:
+ f = get_fpu_register_float(fs_reg);
+ set_fpu_register_double(fd_reg, static_cast<double>(f));
+ break;
+ case SELEQZ_C:
+ DCHECK(IsMipsArchVariant(kMips32r6));
+ set_fpu_register_double(
+ fd_reg, (ft_int & 0x1) == 0 ? get_fpu_register_double(fs_reg) : 0.0);
+ break;
+ case SELNEZ_C:
+ DCHECK(IsMipsArchVariant(kMips32r6));
+ set_fpu_register_double(
+ fd_reg, (ft_int & 0x1) != 0 ? get_fpu_register_double(fs_reg) : 0.0);
+ break;
+ default:
+ // CVT_W_S CVT_L_S TRUNC_W_S ROUND_W_S ROUND_L_S FLOOR_W_S FLOOR_L_S
+ // CEIL_W_S CEIL_L_S CVT_PS_S are unimplemented.
+ UNREACHABLE();
+ }
+}
- // ---------- Raise exceptions triggered.
- SignalExceptions();
- // ---------- Execution.
- switch (op) {
- case COP1:
- switch (instr->RsFieldRaw()) {
- case CFC1:
- set_register(rt_reg, alu_out);
- break;
- case MFC1:
- set_register(rt_reg, alu_out);
- break;
- case MFHC1:
- set_register(rt_reg, alu_out);
- break;
- case CTC1:
- // At the moment only FCSR is supported.
- 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]);
- break;
- case MTHC1:
- set_fpu_register_hi_word(fs_reg, registers_[rt_reg]);
- break;
- case S:
- float f;
- switch (instr->FunctionFieldRaw()) {
- case CVT_D_S:
- f = get_fpu_register_float(fs_reg);
- set_fpu_register_double(fd_reg, static_cast<double>(f));
- break;
- default:
- // CVT_W_S CVT_L_S TRUNC_W_S ROUND_W_S ROUND_L_S FLOOR_W_S FLOOR_L_S
- // CEIL_W_S CEIL_L_S CVT_PS_S are unimplemented.
- UNREACHABLE();
- }
- break;
- case D:
- double ft, fs;
- uint32_t cc, fcsr_cc;
- int64_t i64;
- fs = get_fpu_register_double(fs_reg);
- ft = get_fpu_register_double(ft_reg);
- cc = instr->FCccValue();
- fcsr_cc = get_fcsr_condition_bit(cc);
- switch (instr->FunctionFieldRaw()) {
- case ADD_D:
- set_fpu_register_double(fd_reg, fs + ft);
- break;
- case SUB_D:
- set_fpu_register_double(fd_reg, fs - ft);
- break;
- case MUL_D:
- set_fpu_register_double(fd_reg, fs * ft);
- break;
- case DIV_D:
- set_fpu_register_double(fd_reg, fs / ft);
- break;
- case ABS_D:
- set_fpu_register_double(fd_reg, fabs(fs));
- break;
- case MOV_D:
- set_fpu_register_double(fd_reg, fs);
- break;
- case NEG_D:
- set_fpu_register_double(fd_reg, -fs);
- break;
- case SQRT_D:
- set_fpu_register_double(fd_reg, fast_sqrt(fs));
- break;
- case C_UN_D:
- set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft));
- break;
- case C_EQ_D:
- set_fcsr_bit(fcsr_cc, (fs == ft));
- break;
- case C_UEQ_D:
- set_fcsr_bit(fcsr_cc,
- (fs == ft) || (std::isnan(fs) || std::isnan(ft)));
- break;
- case C_OLT_D:
- set_fcsr_bit(fcsr_cc, (fs < ft));
- break;
- case C_ULT_D:
- set_fcsr_bit(fcsr_cc,
- (fs < ft) || (std::isnan(fs) || std::isnan(ft)));
- break;
- case C_OLE_D:
- set_fcsr_bit(fcsr_cc, (fs <= ft));
- break;
- case C_ULE_D:
- set_fcsr_bit(fcsr_cc,
- (fs <= ft) || (std::isnan(fs) || std::isnan(ft)));
- break;
- case CVT_W_D: // Convert double to word.
- // Rounding modes are not yet supported.
- DCHECK((FCSR_ & 3) == 0);
- // In rounding mode 0 it should behave like ROUND.
- case ROUND_W_D: // Round double to word (round half to even).
- {
- double rounded = std::floor(fs + 0.5);
- int32_t result = static_cast<int32_t>(rounded);
- if ((result & 1) != 0 && result - fs == 0.5) {
- // If the number is halfway between two integers,
- // round to the even one.
- result--;
- }
- set_fpu_register_word(fd_reg, result);
- if (set_fcsr_round_error(fs, rounded)) {
- 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);
- if (set_fcsr_round_error(fs, rounded)) {
- 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);
- if (set_fcsr_round_error(fs, rounded)) {
- 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);
- if (set_fcsr_round_error(fs, rounded)) {
- 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));
- break;
- case CVT_L_D: { // Mips32r2: Truncate double to 64-bit long-word.
- double rounded = trunc(fs);
- i64 = static_cast<int64_t>(rounded);
- if (IsFp64Mode()) {
- set_fpu_register(fd_reg, i64);
- } else {
- set_fpu_register_word(fd_reg, i64 & 0xffffffff);
- set_fpu_register_word(fd_reg + 1, i64 >> 32);
- }
- break;
- }
- case TRUNC_L_D: { // Mips32r2 instruction.
- double rounded = trunc(fs);
- i64 = static_cast<int64_t>(rounded);
- if (IsFp64Mode()) {
- set_fpu_register(fd_reg, i64);
- } else {
- set_fpu_register_word(fd_reg, i64 & 0xffffffff);
- set_fpu_register_word(fd_reg + 1, i64 >> 32);
- }
- break;
- }
- case ROUND_L_D: { // Mips32r2 instruction.
- double rounded =
- fs > 0 ? std::floor(fs + 0.5) : std::ceil(fs - 0.5);
- i64 = static_cast<int64_t>(rounded);
- if (IsFp64Mode()) {
- set_fpu_register(fd_reg, i64);
- } else {
- set_fpu_register_word(fd_reg, i64 & 0xffffffff);
- set_fpu_register_word(fd_reg + 1, i64 >> 32);
- }
- break;
- }
- case FLOOR_L_D: // Mips32r2 instruction.
- i64 = static_cast<int64_t>(std::floor(fs));
- if (IsFp64Mode()) {
- set_fpu_register(fd_reg, i64);
- } else {
- set_fpu_register_word(fd_reg, i64 & 0xffffffff);
- set_fpu_register_word(fd_reg + 1, i64 >> 32);
- }
- break;
- case CEIL_L_D: // Mips32r2 instruction.
- i64 = static_cast<int64_t>(std::ceil(fs));
- if (IsFp64Mode()) {
- set_fpu_register(fd_reg, i64);
- } else {
- set_fpu_register_word(fd_reg, i64 & 0xffffffff);
- set_fpu_register_word(fd_reg + 1, i64 >> 32);
- }
- break;
- case C_F_D:
- UNIMPLEMENTED_MIPS();
- break;
- default:
- UNREACHABLE();
- }
- break;
- case W:
- switch (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));
- 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));
- break;
- default: // Mips64r6 CMP.S instructions unimplemented.
- UNREACHABLE();
- }
- break;
- case L:
- fs = get_fpu_register_double(fs_reg);
- ft = get_fpu_register_double(ft_reg);
- switch (instr->FunctionFieldRaw()) {
- case CVT_D_L: // Mips32r2 instruction.
- // Watch the signs here, we want 2 32-bit vals
- // to make a sign-64.
- if (IsFp64Mode()) {
- 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;
- }
- set_fpu_register_double(fd_reg, static_cast<double>(i64));
- break;
- case CVT_S_L:
- UNIMPLEMENTED_MIPS();
- break;
- case CMP_AF: // Mips64r6 CMP.D instructions.
- UNIMPLEMENTED_MIPS();
- break;
- case CMP_UN:
- if (std::isnan(fs) || std::isnan(ft)) {
- set_fpu_register(fd_reg, -1);
- } else {
- set_fpu_register(fd_reg, 0);
- }
- break;
- case CMP_EQ:
- if (fs == ft) {
- set_fpu_register(fd_reg, -1);
- } else {
- 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);
- } else {
- set_fpu_register(fd_reg, 0);
- }
- break;
- case CMP_LT:
- if (fs < ft) {
- set_fpu_register(fd_reg, -1);
- } else {
- 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);
- } else {
- set_fpu_register(fd_reg, 0);
- }
- break;
- case CMP_LE:
- if (fs <= ft) {
- set_fpu_register(fd_reg, -1);
- } else {
- 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);
- } else {
- set_fpu_register(fd_reg, 0);
- }
- break;
- default: // CMP_OR CMP_UNE CMP_NE UNIMPLEMENTED.
- UNREACHABLE();
- }
- break;
- default:
- UNREACHABLE();
+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()) {
+ 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);
+ } 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;
}
+ set_fpu_register_double(fd_reg, static_cast<double>(i64));
break;
- case COP1X:
- switch (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);
- break;
- default:
- UNREACHABLE();
+ case CVT_S_L:
+ UNIMPLEMENTED_MIPS();
+ break;
+ case CMP_AF: // Mips64r6 CMP.D instructions.
+ UNIMPLEMENTED_MIPS();
+ break;
+ case CMP_UN:
+ if (std::isnan(fs) || std::isnan(ft)) {
+ set_fpu_register(fd_reg, -1);
+ } else {
+ set_fpu_register(fd_reg, 0);
}
break;
- case SPECIAL:
- switch (instr->FunctionFieldRaw()) {
+ case CMP_EQ:
+ if (fs == ft) {
+ set_fpu_register(fd_reg, -1);
+ } else {
+ 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);
+ } else {
+ set_fpu_register(fd_reg, 0);
+ }
+ break;
+ case CMP_LT:
+ if (fs < ft) {
+ set_fpu_register(fd_reg, -1);
+ } else {
+ 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);
+ } else {
+ set_fpu_register(fd_reg, 0);
+ }
+ break;
+ case CMP_LE:
+ if (fs <= ft) {
+ set_fpu_register(fd_reg, -1);
+ } else {
+ 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);
+ } else {
+ set_fpu_register(fd_reg, 0);
+ }
+ break;
+ default: // CMP_OR CMP_UNE CMP_NE UNIMPLEMENTED.
+ UNREACHABLE();
+ }
+}
+
+
+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()) {
+ case CFC1:
+ set_register(rt_reg, alu_out);
+ break;
+ case MFC1:
+ set_register(rt_reg, alu_out);
+ break;
+ case MFHC1:
+ set_register(rt_reg, alu_out);
+ break;
+ case CTC1:
+ // At the moment only FCSR is supported.
+ 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]);
+ break;
+ case MTHC1:
+ set_fpu_register_hi_word(fs_reg, registers_[rt_reg]);
+ break;
+ case S: {
+ DecodeTypeRegisterSRsType(instr, ft_reg, fs_reg, fd_reg);
+ break;
+ }
+ case D:
+ DecodeTypeRegisterDRsType(instr, fr_reg, fs_reg, ft_reg, fd_reg);
+ break;
+ case W:
+ DecodeTypeRegisterWRsType(instr, alu_out, fd_reg, fs_reg);
+ break;
+ case L:
+ DecodeTypeRegisterLRsType(instr, ft_reg, fs_reg, fd_reg);
+ break;
+ 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()) {
+ 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);
+ break;
+ default:
+ UNREACHABLE();
+ }
+}
+
+
+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()) {
+ case SELEQZ_S:
+ DCHECK(IsMipsArchVariant(kMips32r6));
+ 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);
@@ -2638,32 +2667,105 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
default: // For other special opcodes we do the default operation.
set_register(rd_reg, alu_out);
}
+}
+
+
+void Simulator::DecodeTypeRegisterSPECIAL2(Instruction* instr,
+ const int32_t& rd_reg,
+ int32_t& alu_out) {
+ switch (instr->FunctionFieldRaw()) {
+ case MUL:
+ set_register(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);
+ }
+}
+
+
+void Simulator::DecodeTypeRegisterSPECIAL3(Instruction* instr,
+ const int32_t& rt_reg,
+ int32_t& alu_out) {
+ switch (instr->FunctionFieldRaw()) {
+ case INS:
+ // Ins instr leaves result in Rt, rather than Rd.
+ set_register(rt_reg, alu_out);
+ break;
+ case EXT:
+ // Ext instr leaves result in Rt, rather than Rd.
+ set_register(rt_reg, alu_out);
+ break;
+ default:
+ UNREACHABLE();
+ }
+}
+
+
+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();
+
+ // ---------- 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);
+ break;
+ case COP1X:
+ DecodeTypeRegisterCOP1X(instr, fr_reg, fs_reg, ft_reg, fd_reg);
+ 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);
break;
case SPECIAL2:
- switch (instr->FunctionFieldRaw()) {
- case MUL:
- set_register(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);
- }
+ DecodeTypeRegisterSPECIAL2(instr, rd_reg, alu_out);
break;
case SPECIAL3:
- switch (instr->FunctionFieldRaw()) {
- case INS:
- // Ins instr leaves result in Rt, rather than Rd.
- set_register(rt_reg, alu_out);
- break;
- case EXT:
- // Ext instr leaves result in Rt, rather than Rd.
- set_register(rt_reg, alu_out);
- break;
- default:
- UNREACHABLE();
- }
+ DecodeTypeRegisterSPECIAL3(instr, rt_reg, alu_out);
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

Powered by Google App Engine
This is Rietveld 408576698