📄 run.c
字号:
case Y_C_ULE_S_OP: case Y_C_SF_S_OP: case Y_C_NGLE_S_OP: case Y_C_SEQ_S_OP: case Y_C_NGL_S_OP: case Y_C_LT_S_OP: case Y_C_NGE_S_OP: case Y_C_LE_S_OP: case Y_C_NGT_S_OP: { float v1 = FPR_S (FS (inst)), v2 = FPR_S (FT (inst)); double dv1 = v1, dv2 = v2; int cond = COND (inst); int cc = FD (inst); if (NaN (dv1) || NaN (dv2)) { if (cond & COND_IN) { RAISE_EXCEPTION (ExcCode_FPE, break); } set_fpu_cc (cond, cc, 0, 0, 1); } else { set_fpu_cc (cond, cc, v1 < v2, v1 == v2, 0); } } break; case Y_C_F_D_OP: case Y_C_UN_D_OP: case Y_C_EQ_D_OP: case Y_C_UEQ_D_OP: case Y_C_OLT_D_OP: case Y_C_OLE_D_OP: case Y_C_ULT_D_OP: case Y_C_ULE_D_OP: case Y_C_SF_D_OP: case Y_C_NGLE_D_OP: case Y_C_SEQ_D_OP: case Y_C_NGL_D_OP: case Y_C_LT_D_OP: case Y_C_NGE_D_OP: case Y_C_LE_D_OP: case Y_C_NGT_D_OP: { double v1 = FPR_D (FS (inst)), v2 = FPR_D (FT (inst)); int cond = COND (inst); int cc = FD (inst); if (NaN (v1) || NaN (v2)) { if (cond & COND_IN) { RAISE_EXCEPTION (ExcCode_FPE, break); } set_fpu_cc (cond, cc, 0, 0, 1); } else { set_fpu_cc (cond, cc, v1 < v2, v1 == v2, 0); } } break; case Y_CFC1_OP: R[RT (inst)] = FCR[FS (inst)]; break; case Y_CTC1_OP: FCR[FS (inst)] = R[RT (inst)]; if (FIR_REG == FS (inst)) { /* Read only register */ FIR = FIR_MASK; } else if (FCCR_REG == FS (inst)) { /* FCC bits in FCSR and FCCR linked */ FCSR = (FCSR & ~0xfe400000) | ((FCCR & 0xfe) << 24) | ((FCCR & 0x1) << 23); FCCR &= FCCR_MASK; } else if (FCSR_REG == FS (inst)) { /* FCC bits in FCSR and FCCR linked */ FCCR = ((FCSR >> 24) & 0xfe) | ((FCSR >> 23) & 0x1); FCSR &= FCSR_MASK; if ((R[RT (inst)] & ~FCSR_MASK) != 0) /* Trying to set unsupported mode */ RAISE_EXCEPTION (ExcCode_FPE, {}); } break; case Y_CEIL_W_D_OP: { double val = FPR_D (FS (inst)); SET_FPR_W (FD (inst), (int32)ceil (val)); break; } case Y_CEIL_W_S_OP: { double val = (double)FPR_S (FS (inst)); SET_FPR_W (FD (inst), (int32)ceil (val)); break; } case Y_CVT_D_S_OP: { double val = FPR_S (FS (inst)); SET_FPR_D (FD (inst), val); break; } case Y_CVT_D_W_OP: { double val = (double)FPR_W (FS (inst)); SET_FPR_D (FD (inst), val); break; } case Y_CVT_S_D_OP: { float val = (float)FPR_D (FS (inst)); SET_FPR_S (FD (inst), val); break; } case Y_CVT_S_W_OP: { float val = (float)FPR_W (FS (inst)); SET_FPR_S (FD (inst), val); break; } case Y_CVT_W_D_OP: { int val = (int32)FPR_D (FS (inst)); SET_FPR_W (FD (inst), val); break; } case Y_CVT_W_S_OP: { int val = (int32)FPR_S (FS (inst)); SET_FPR_W (FD (inst), val); break; } case Y_DIV_S_OP: SET_FPR_S (FD (inst), FPR_S (FS (inst)) / FPR_S (FT (inst))); break; case Y_DIV_D_OP: SET_FPR_D (FD (inst), FPR_D (FS (inst)) / FPR_D (FT (inst))); break; case Y_FLOOR_W_D_OP: { double val = FPR_D (FS (inst)); SET_FPR_W (FD (inst), (int32)floor (val)); break; } case Y_FLOOR_W_S_OP: { double val = (double)FPR_S (FS (inst)); SET_FPR_W (FD (inst), (int32)floor (val)); break; } case Y_LDC1_OP: { mem_addr addr = R[BASE (inst)] + IOFFSET (inst); if ((addr & 0x3) != 0) RAISE_EXCEPTION (ExcCode_AdEL, CP0_BadVAddr = addr); LOAD_INST ((reg_word *) &FPR_S(FT (inst)), read_mem_word (addr), 0xffffffff); LOAD_INST ((reg_word *) &FPR_S(FT (inst) + 1), read_mem_word (addr + sizeof(mem_word)), 0xffffffff); break; } case Y_LWC1_OP: LOAD_INST ((reg_word *) &FPR_S(FT (inst)), read_mem_word (R[BASE (inst)] + IOFFSET (inst)), 0xffffffff); break; case Y_MFC1_OP: { float val = FPR_S(FS (inst)); reg_word *vp = (reg_word *) &val; R[RT (inst)] = *vp; /* Fool coercion */ break; } case Y_MOV_S_OP: SET_FPR_S (FD (inst), FPR_S (FS (inst))); break; case Y_MOV_D_OP: SET_FPR_D (FD (inst), FPR_D (FS (inst))); break; case Y_MOVF_OP: { int cc = CC (inst); if ((FCCR & (1 << cc)) == 0) R[RD (inst)] = R[RS (inst)]; break; } case Y_MOVF_D_OP: { int cc = CC (inst); if ((FCCR & (1 << cc)) == 0) SET_FPR_D (FD (inst), FPR_D (FS (inst))); break; } case Y_MOVF_S_OP: { int cc = CC (inst); if ((FCCR & (1 << cc)) == 0) SET_FPR_S (FD (inst), FPR_S (FS (inst))); break; } case Y_MOVN_D_OP: { if (R[RT (inst)] != 0) SET_FPR_D (FD (inst), FPR_D (FS (inst))); break; } case Y_MOVN_S_OP: { if (R[RT (inst)] != 0) SET_FPR_S (FD (inst), FPR_S (FS (inst))); break; } case Y_MOVT_OP: { int cc = CC (inst); if ((FCCR & (1 << cc)) != 0) R[RD (inst)] = R[RS (inst)]; break; } case Y_MOVT_D_OP: { int cc = CC (inst); if ((FCCR & (1 << cc)) != 0) SET_FPR_D (FD (inst), FPR_D (FS (inst))); break; } case Y_MOVT_S_OP: { int cc = CC (inst); if ((FCCR & (1 << cc)) != 0) SET_FPR_S (FD (inst), FPR_S (FS (inst))); break; } case Y_MOVZ_D_OP: { if (R[RT (inst)] == 0) SET_FPR_D (FD (inst), FPR_D (FS (inst))); break; } case Y_MOVZ_S_OP: { if (R[RT (inst)] == 0) SET_FPR_S (FD (inst), FPR_S (FS (inst))); break; } case Y_MTC1_OP: { reg_word word = R[RT (inst)]; float *wp = (float *) &word; SET_FPR_S(FS (inst), *wp); /* fool coercion */ break; } case Y_MUL_S_OP: SET_FPR_S (FD (inst), FPR_S (FS (inst)) * FPR_S (FT (inst))); break; case Y_MUL_D_OP: SET_FPR_D (FD (inst), FPR_D (FS (inst)) * FPR_D (FT (inst))); break; case Y_NEG_S_OP: SET_FPR_S (FD (inst), -FPR_S (FS (inst))); break; case Y_NEG_D_OP: SET_FPR_D (FD (inst), -FPR_D (FS (inst))); break; case Y_ROUND_W_D_OP: { double val = FPR_D (FS (inst)); SET_FPR_W (FD (inst), (int32)(val + 0.5)); /* Casting truncates */ break; } case Y_ROUND_W_S_OP: { double val = (double)FPR_S (FS (inst)); SET_FPR_W (FD (inst), (int32)(val + 0.5)); /* Casting truncates */ break; } case Y_SDC1_OP: { double val = FPR_D (RT (inst)); reg_word *vp = (reg_word *) &val; mem_addr addr = R[BASE (inst)] + IOFFSET (inst); if ((addr & 0x3) != 0) RAISE_EXCEPTION (ExcCode_AdEL, CP0_BadVAddr = addr); set_mem_word (addr, *vp); set_mem_word (addr + sizeof(mem_word), *(vp + 1)); break; } case Y_SQRT_D_OP: SET_FPR_D (FD (inst), sqrt (FPR_D (FS (inst)))); break; case Y_SQRT_S_OP: SET_FPR_S (FD (inst), sqrt (FPR_S (FS (inst)))); break; case Y_SUB_S_OP: SET_FPR_S (FD (inst), FPR_S (FS (inst)) - FPR_S (FT (inst))); break; case Y_SUB_D_OP: SET_FPR_D (FD (inst), FPR_D (FS (inst)) - FPR_D (FT (inst))); break; case Y_SWC1_OP: { float val = FPR_S(RT (inst)); reg_word *vp = (reg_word *) &val; set_mem_word (R[BASE (inst)] + IOFFSET (inst), *vp); break; } case Y_TRUNC_W_D_OP: { double val = FPR_D (FS (inst)); SET_FPR_W (FD (inst), (int32)val); /* Casting truncates */ break; } case Y_TRUNC_W_S_OP: { double val = (double)FPR_S (FS (inst)); SET_FPR_W (FD (inst), (int32)val); /* Casting truncates */ break; } default: fatal_error ("Unknown instruction type: %d\n", OPCODE (inst)); break; } /* After instruction executes: */ PC += BYTES_PER_WORD; if (exception_occurred) { handle_exception (); } } /* End: for (step = 0; ... */ } /* End: for ( ; steps_to_run > 0 ... */ /* Executed enought steps, return, but are able to continue. */ return (1);}#ifdef WIN32static void CALLBACKtimer_completion_routine(LPVOID lpArgToCompletionRoutine, DWORD dwTimerLowValue, DWORD dwTimerHighValue){ bump_CP0_timer ();}#endif/* Increment CP0 Count register and test if it matches the Compare register. If so, cause an interrupt. */static voidbump_CP0_timer (){ CP0_Count += 1; if (CP0_Count == CP0_Compare) { RAISE_INTERRUPT (7); }}static voidstart_CP0_timer (){#ifdef WIN32 HANDLE timer = CreateWaitableTimer(NULL, TRUE, "SPIMTimer"); if (NULL == timer) { error ("CreateWaitableTimer failed"); } else { LARGE_INTEGER interval; interval.QuadPart = -10000 * TIMER_TICK_MS; /* Unit is 100 nsec */ if (!SetWaitableTimer (timer, &interval, 1, timer_completion_routine, 0, FALSE)) { error ("SetWaitableTimer failed"); } }#else /* Should use ITIMER_VIRTUAL delivering SIGVTALRM, but that does not seem to work under Cygwin, so we'll adopt the lowest common denominator. We ignore these signals, however, and read the timer with getitimer, since signals interrupt I/O calls, such as read, and make user interaction with SPIM work very poorly. Since speed isn't an important aspect of SPIM, polling isn't a big deal. */ if (-1 == (int)signal (SIGALRM, SIG_IGN)) { perror ("signal failed"); } else { /* Start a non-periodic timer for TIMER_TICK_MS microseconds. */ struct itimerval time; time.it_interval.tv_sec = 0; time.it_interval.tv_usec = 0; time.it_value.tv_sec = 0; time.it_value.tv_usec = TIMER_TICK_MS * 1000; if (-1 == setitimer (ITIMER_REAL, &time, NULL)) { perror ("setitmer failed"); } }#endif}/* Multiply two 32-bit numbers, V1 and V2, to produce a 64 bit result in the HI/LO registers. The algorithm is high-school math: A B x C D ------ AD || BD AC || CB || 0 where A and B are the high and low short words of V1, C and D are the short words of V2, AD is the product of A and D, and X || Y is (X << 16) + Y. Since the algorithm is programmed in C, we need to be careful not to overflow. */static voidunsigned_multiply (reg_word v1, reg_word v2){ u_reg_word a, b, c, d; u_reg_word bd, ad, cb, ac; u_reg_word mid, mid2, carry_mid = 0; a = (v1 >> 16) & 0xffff; b = v1 & 0xffff; c = (v2 >> 16) & 0xffff; d = v2 & 0xffff; bd = b * d; ad = a * d; cb = c * b; ac = a * c; mid = ad + cb; if (mid < ad || mid < cb) /* Arithmetic overflow or carry-out */ carry_mid = 1; mid2 = mid + ((bd >> 16) & 0xffff); if (mid2 < mid || mid2 < ((bd >> 16) & 0xffff)) /* Arithmetic overflow or carry-out */ carry_mid += 1; LO = (bd & 0xffff) | ((mid2 & 0xffff) << 16); HI = ac + (carry_mid << 16) + ((mid2 >> 16) & 0xffff);}static voidsigned_multiply (reg_word v1, reg_word v2){ int neg_sign = 0; if (v1 < 0) v1 = - v1, neg_sign = 1; if (v2 < 0) v2 = - v2, neg_sign = ! neg_sign; unsigned_multiply (v1, v2); if (neg_sign) { LO = ~ LO; HI = ~ HI; LO += 1; if (LO == 0) HI += 1; }}static voidset_fpu_cc (int cond, int cc, int less, int equal, int unordered){ int result; int fcsr_bit; result = 0; if (cond & COND_LT) result |= less; if (cond & COND_EQ) result |= equal; if (cond & COND_UN) result |= unordered; FCCR = (FCCR & ~(1 << cc)) | (result << cc); if (0 == cc) { fcsr_bit = 23; } else { fcsr_bit = 24 + cc; } FCSR = (FCSR & ~(1 << fcsr_bit)) | (result << fcsr_bit);}voidraise_exception (int excode){ if (ExcCode_Int != excode || ((CP0_Status & CP0_Status_IE) /* Allow interrupt if IE and !EXL */ && !(CP0_Status & CP0_Status_EXL))) { /* Ignore interrupt exception when interrupts disabled. */ exception_occurred = 1; if (running_in_delay_slot) { /* In delay slot */ if ((CP0_Status & CP0_Status_EXL) == 0) { /* Branch's addr */ CP0_EPC = ROUND_DOWN (PC - BYTES_PER_WORD, BYTES_PER_WORD); /* Set BD bit to record that instruction is in delay slot */ CP0_Cause |= CP0_Cause_BD; } } else { /* Not in delay slot */ if ((CP0_Status & CP0_Status_EXL) == 0) { /* Faulting instruction's address */ CP0_EPC = ROUND_DOWN (PC, BYTES_PER_WORD); } } /* ToDo: set CE field of Cause register to coprocessor causing exception */ /* Record cause of exception */ CP0_Cause = (CP0_Cause & ~CP0_Cause_ExcCode) | (excode << 2); /* Turn on EXL bit to prevent subsequent interrupts from affecting EPC */ CP0_Status |= CP0_Status_EXL;#ifdef MIPS1 CP0_Status = (CP0_Status & 0xffffffc0) | ((CP0_Status & 0xf) << 2);#endif }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -