private void Inst_Add(MipsInstruction inst) { if (!MipsState.Operating64BitMode) { try { MipsState.WriteGPR32Signed(inst.Rd, MipsState.ReadGPR32Signed(inst.Rs) + MipsState.ReadGPR32Signed(inst.Rt)); } catch (OverflowException) { CauseException = ExceptionCode.OverFlow; } } else { if (MipsState.ReadGPRUnsigned(inst.Rs).IsSigned32() && MipsState.ReadGPRUnsigned(inst.Rt).IsSigned32()) { try { MipsState.WriteGPRSigned(inst.Rd, MipsState.ReadGPRSigned(inst.Rs) + MipsState.ReadGPRSigned(inst.Rt)); } catch (OverflowException) { CauseException = ExceptionCode.OverFlow; } } } }
private void Inst_Dmfc1(MipsInstruction inst) { if (!CheckCop1Usable()) { CauseException = ExceptionCode.CopUnstable; return; } if (!CheckEvenOddAllowed(inst.Fs)) { CauseFPUException(FPUExceptionType.Unimplemented); return; } UInt64 value = 0; if (MipsState.CP0Regs.StatusReg.AdditionalFPR) { value = MipsState.Fpr.ReadFPRUnsigned(inst.Fs); } else { value = MipsState.Fpr.ReadFPR32Unsigned(inst.Fs + 1) << 32; value |= MipsState.Fpr.ReadFPR32Unsigned(inst.Fs); } MipsState.WriteGPRUnsigned(inst.Rt, value); }
private void Inst_Addi(MipsInstruction inst) { if (!MipsState.Operating64BitMode) { try { MipsState.WriteGPR32Signed(inst.Rt, MipsState.ReadGPR32Signed(inst.Rs) + (Int32)(Int16)inst.Immediate); } catch (OverflowException) { CauseException = ExceptionCode.OverFlow; } } else { try { MipsState.WriteGPRSigned(inst.Rt, MipsState.ReadGPRSigned(inst.Rs) + (Int64)(Int16)inst.Immediate); } catch (OverflowException) { CauseException = ExceptionCode.OverFlow; } } }
private void Inst_Bgez(MipsInstruction inst) { if (!MipsState.Operating64BitMode) { DoBranch(MipsState.ReadGPR32Signed(inst.Rs) >= 0, inst); } else { DoBranch(MipsState.ReadGPRSigned(inst.Rs) >= 0, inst); } }
private void Inst_Beql(MipsInstruction inst) { if (!MipsState.Operating64BitMode) { DoBranchLikely(MipsState.ReadGPR32Unsigned(inst.Rs) == MipsState.ReadGPR32Unsigned(inst.Rt), inst); } else { DoBranchLikely(MipsState.ReadGPRUnsigned(inst.Rs) == MipsState.ReadGPRUnsigned(inst.Rt), inst); } }
private void Inst_Teq(MipsInstruction inst) { Boolean condition; if (!MipsState.Operating64BitMode) condition = MipsState.ReadGPR32Unsigned(inst.Rs) == MipsState.ReadGPR32Unsigned(inst.Rt); else condition = MipsState.ReadGPRUnsigned(inst.Rs) == MipsState.ReadGPRUnsigned(inst.Rt); if (condition) CauseException = ExceptionCode.Trap; }
private void Inst_Cfc1(MipsInstruction inst) { if (!CheckCop1Usable()) { CauseException = ExceptionCode.CopUnstable; return; } if (inst.Rd == 0) { MipsState.WriteGPRUnsigned(inst.Rd, MipsState.FCR0); } if (inst.Rd == 31) { MipsState.WriteGPRUnsigned(inst.Rd, MipsState.FCR31.RegisterValue); } }
private void Inst_Ctc1(MipsInstruction inst) { if (!CheckCop1Usable()) { CauseException = ExceptionCode.CopUnstable; return; } if (inst.Fs == 0) { MipsState.FCR0 = MipsState.ReadGPR32Unsigned(inst.Rt); } if (inst.Fs == 31) { MipsState.FCR31.RegisterValue = MipsState.ReadGPR32Unsigned(inst.Rt); } }
private void Inst_Eret(MipsInstruction inst) { if (MipsState.CP0Regs.StatusReg.CopUsable0) CauseException = ExceptionCode.CopUnstable; if (MipsState.CP0Regs.StatusReg.ExceptionLevel) { MipsState.PC = (Int64)MipsState.CP0Regs.ErrorEPC; MipsState.CP0Regs.StatusReg.ExceptionLevel = false; } else { MipsState.PC = (Int64)MipsState.CP0Regs.EPC; MipsState.CP0Regs.StatusReg.ExceptionLevel = false; } MipsState.LLBit = false; }
private void Inst_Sllv(MipsInstruction inst) { Int32 shiftAmount = MipsState.ReadGPR32Signed(inst.Rs) & 0x1F; if (!MipsState.Operating64BitMode) { MipsState.WriteGPR32Unsigned(inst.Rd, MipsState.ReadGPR32Unsigned(inst.Rt) << shiftAmount); } else { UInt64 result = MipsState.ReadGPRUnsigned(inst.Rt) << shiftAmount; /* Truncate */ if (shiftAmount == 0) { MipsState.WriteGPRSigned(inst.Rd, (Int32)(UInt32)result); } else { MipsState.WriteGPRUnsigned(inst.Rd, result); } } }
private void Inst_FpuRoundW(MipsInstruction inst) { unchecked { if (!CheckCop1Usable()) { CauseException = ExceptionCode.CopUnstable; return; } if (!CheckEvenOddAllowed(inst)) { return; } DataFormat format = inst.DecodeDataFormat(); if (format == DataFormat.Single || format == DataFormat.Double) { FPUHardware.SetRoundingMode(FPURoundMode.Near); FPUEntity value = new FPUEntity(format, MipsState); FPUEntity result = new FPUEntity(DataFormat.Word, MipsState); value.Load(inst.Fs); result.Value = (UInt32)Math.Round(value.Value, MidpointRounding.ToEven); result.Store(inst.Fd); if (FPUHardware.CheckFPUException()) { CauseFPUException(FPUHardware.GetFPUException()); } } else { CauseFPUException(FPUExceptionType.Unimplemented); } } }
private void Inst_FpuSqrt(MipsInstruction inst) { if (!CheckCop1Usable()) { CauseException = ExceptionCode.CopUnstable; return; } if (!CheckEvenOddAllowed(inst)) { return; } unchecked { DataFormat format = inst.DecodeDataFormat(); if (format == DataFormat.Single || format == DataFormat.Double) { FPUEntity value = new FPUEntity(format, MipsState); value.Load(inst.Fs); FPUHardware.SetRoundingMode(MipsState.FCR31.RM); value.Value = Math.Sqrt(value.Value); value.Store(inst.Fd); if (FPUHardware.CheckFPUException()) { CauseFPUException(FPUHardware.GetFPUException()); } } else { CauseFPUException(FPUExceptionType.Unimplemented); } } }
private void Inst_Mfc0(MipsInstruction inst) { if (MipsState.CP0Regs.StatusReg.CopUsable0) { if (!MipsState.Operating64BitMode) { MipsState.WriteGPR32Unsigned(inst.Rt, (UInt32)MipsState.CP0Regs[inst.Rd]); /* Count register */ if (inst.Rt == 9) { MupenHelper.UpdateCount(); } } else { MipsState.WriteGPRUnsigned(inst.Rt, MipsState.CP0Regs[inst.Rd]); } } else { CauseException = ExceptionCode.CopUnstable; } }
private void Inst_FpuConvertW(MipsInstruction inst) { unchecked { if (!CheckCop1Usable()) { CauseException = ExceptionCode.CopUnstable; return; } if (!CheckEvenOddAllowed(inst)) { return; } DataFormat format = inst.DecodeDataFormat(); if (format != DataFormat.Reserved || format != DataFormat.Word) { FPUEntity value = new FPUEntity(format, MipsState); FPUEntity result = new FPUEntity(DataFormat.Word, MipsState); value.Load(inst.Fs); result.Value = Convert.ToUInt32(value.Value); value.Store(inst.Fd); if (FPUHardware.CheckFPUException()) { CauseFPUException(FPUHardware.GetFPUException()); } } else { CauseFPUException(FPUExceptionType.Unimplemented); } } }
private void Inst_Lbu(MipsInstruction inst) { try { if (!MipsState.Operating64BitMode) { MipsState.WriteGPR32Signed(inst.Rt, DataManipulator.LoadByteUnsigned(ComputeAddress32(inst))); } else { MipsState.WriteGPRSigned(inst.Rt, DataManipulator.LoadByteUnsigned(ComputeAddress64(inst))); } } catch (TLBException tlbe) { switch (tlbe.ExceptionType) { case TLBExceptionType.Invalid: CauseException = ExceptionCode.Invalid; break; case TLBExceptionType.Mod: CauseException = ExceptionCode.TlbMod; break; case TLBExceptionType.Refill: CauseException = ExceptionCode.TlbStore; break; default: break; } } }
private void Inst_Syscall(MipsInstruction inst) { CauseException = ExceptionCode.Syscall; }
private void Inst_Mtlo(MipsInstruction inst) { MipsState.Lo = MipsState.ReadGPRUnsigned(inst.Rs); }
protected void DoBranchLikely(Boolean condition, MipsInstruction inst) { MipsState.NullifyEnabled = !condition; DoBranch(condition, inst); }
private void Inst_Break(MipsInstruction inst) { CauseException = ExceptionCode.Breakpoint; }
protected Int64 ComputeAddress64(MipsInstruction inst) { return (((Int64)(Int16)inst.Immediate) + MipsState.ReadGPRSigned(inst.Rs)); }
private void Inst_tlbr(MipsInstruction inst) { /* Read Indexed TLB Entry: TLB Entry[index] => TLB Registers */ ParentMips.Tlb.Read(); }
private void Inst_Jalr(MipsInstruction inst) { DoJump(MipsState.ReadGPRSigned(inst.Rs)); MipsState.WriteGPRSigned(inst.Rd, inst.Address + 8); }
private void Inst_J(MipsInstruction inst) { DoJump(JumpComputeTargetAddress(inst)); }
private void Inst_Jal(MipsInstruction inst) { MipsState.WriteGPRSigned(31, inst.Address + 8); DoJump(JumpComputeTargetAddress(inst)); }
private void Inst_tlbp(MipsInstruction inst) { /* Probe the TLB */ ParentMips.Tlb.Probe(); }
private void Inst_tlbwr(MipsInstruction inst) { /* Write Random TLB Entry: TLB Registers => TLB Entry[random_index] */ ParentMips.Tlb.WriteRandom(); }
private void Inst_tlbwi(MipsInstruction inst) { /* Write Indexed TLB Entry: TLB Registers => TLB Entry[index] */ ParentMips.Tlb.Write(); }
private void Inst_Teqi(MipsInstruction inst) { Boolean condition; if (!MipsState.Operating64BitMode) condition = MipsState.ReadGPR32Signed(inst.Rs) == (Int32)(Int16)inst.Immediate; else condition = MipsState.ReadGPRSigned(inst.Rs) == (Int64)(Int16)inst.Immediate; if (condition) CauseException = ExceptionCode.Trap; }
private void OpCall(MipsOp[] callTable, Int32 index, MipsInstruction inst) { /* NOP */ if (inst.Instruction == 0) return; MipsOp call = callTable[index]; if (call != null) { call(inst); } else { throw new InvalidOperationException("Unsupport Instruction: " + inst.ToString()); } }
public static Int64 BranchComputeTargetAddress(MipsInstruction inst) { return((inst.Address + 4) + (((Int64)(Int16)inst.Immediate) << 2)); }
protected Int64 ComputeAddress(MipsInstruction inst) { return(((Int64)(Int16)inst.Immediate) + MipsState.ReadGPRSigned(inst.Rs)); }
private Boolean CheckEvenOddAllowed(MipsInstruction inst) { if (MipsState.CP0Regs.StatusReg.AdditionalFPR) { return true; } else { return (inst.Fd % 2 == 0) && (inst.Fs % 2 == 0) && (inst.Ft % 2 == 0); } }
public static Int64 JumpComputeTargetAddress(MipsInstruction inst) { return((inst.Target << 2) | ((inst.Address + 4) & 0xFFFF0000)); }
protected void CallInstruction(MipsInstruction inst) { OpCall(m_OpsTableMain, inst.Opcode, inst); }
protected void DoBranch(Boolean condition, MipsInstruction inst) { MipsState.BranchEnabled = true; MipsState.BranchDelaySlot = MipsState.PC + 4; MipsState.BranchTarget = condition ? BranchComputeTargetAddress(inst.Address, inst.Immediate): MipsState.PC + 8; }
private void Inst_Cache(MipsInstruction inst) { logger.Debug("Cache instruction ignored"); }
private void Inst_Mflo(MipsInstruction inst) { MipsState.WriteGPRUnsigned(inst.Rd, MipsState.Lo); }
protected void DoBranch(Boolean condition, MipsInstruction inst) { MipsState.BranchEnabled = true; MipsState.BranchDelaySlot = MipsState.PC + 4; MipsState.BranchTarget = condition ? MapAddress(BranchComputeTargetAddress(inst)) : MipsState.PC + 8; }
private void Inst_Sync(MipsInstruction inst) { /* LOL Just ignore this, we know loads and stores always finish before SYNC opcode */ return; }
private void Inst_Scd(MipsInstruction inst) { /* This is used in atomic operations, for now let it always pass */ MipsState.WriteGPRUnsigned(inst.Rt, 1); Inst_Sd(inst); }
private void Inst_Sb(MipsInstruction inst) { Int64 address = ComputeAddress(inst); DataManipulator.Store(address, MipsState.ReadGPRUnsigned(inst.Rt) & 0xFF); }
private void Inst_Bc1tl(MipsInstruction inst) { DoBranchLikely(MipsState.FCR31.Condition, inst); }
private void Inst_Bc1f(MipsInstruction inst) { DoBranch(MipsState.FCR31.Condition, inst); }
private void Inst_Addiu(MipsInstruction inst) { unchecked { if (!MipsState.Operating64BitMode) { MipsState.WriteGPR32Unsigned(inst.Rt, MipsState.ReadGPR32Unsigned(inst.Rs) + (UInt32)(Int32)(Int16)inst.Immediate); } else { if (MipsState.ReadGPRUnsigned(inst.Rs).IsSigned32()) { MipsState.WriteGPRUnsigned(inst.Rt, MipsState.ReadGPRUnsigned(inst.Rs) + (UInt64)(Int64)(Int16)inst.Immediate); } } } }
protected void TraceOp(Int64 pc, MipsInstruction inst) { if (logger.IsDebugEnabled) logger.Debug("{0:X8} {1:X4} {2:X4} {3}", pc, inst.Instruction >> 16, inst.Instruction & 0xFFFF, inst.ToString()); }
private void Inst_Jr(MipsInstruction inst) { DoJump(MipsState.ReadGPRSigned(inst.Rs)); }
private void Inst_Nor(MipsInstruction inst) { MipsState.WriteGPRUnsigned(inst.Rd, ~(MipsState.ReadGPRUnsigned(inst.Rs) | MipsState.ReadGPRUnsigned(inst.Rt))); }
private void Inst_Xori(MipsInstruction inst) { if (!MipsState.Operating64BitMode) { MipsState.WriteGPR32Signed(inst.Rt, MipsState.ReadGPR32Signed(inst.Rs) ^ (Int32)(Int16)inst.Immediate); } else { MipsState.WriteGPRSigned(inst.Rt, MipsState.ReadGPRSigned(inst.Rs) ^ (Int64)(Int16)inst.Immediate); } }