private static void HandleGeneral(VR4300 cpu, SystemControlUnit.CauseRegister.ExceptionCode excCode, byte?ce = null) { cpu.CP0.Cause.ExcCode = excCode; if (ce.HasValue) { cpu.CP0.Cause.CE = ce.Value; } cpu.CP0.Registers[(int)SystemControlUnit.RegisterIndex.BadVAddr] = cpu.PC; if (!cpu.CP0.Status.EXL) { if ((cpu.CP0.Cause.BD = cpu.branchDelay)) { cpu.CP0.Registers[(int)SystemControlUnit.RegisterIndex.EPC] = cpu.PC - Instruction.Size; } else { cpu.CP0.Registers[(int)SystemControlUnit.RegisterIndex.EPC] = cpu.PC; } } cpu.CP0.Status.EXL = true; cpu.PC = (cpu.CP0.Status.DS.BEV ? GeneralVectorBEV : GeneralVector) + GeneralVectorOffset; }
public SystemControlUnit(VR4300 cpu) { this.cpu = cpu; Config = new ConfigRegister(this); Status = new StatusRegister(this); Cause = new CauseRegister(this); operations = new Dictionary <Instruction, Action <Instruction> > { [From(OpCode.MT)] = i => { var destination = i.RD; var data = cpu.GPR[i.RT]; switch ((RegisterIndex)destination) { case RegisterIndex.Cause: Registers[destination] &= ~CauseRegister.WriteMask; Registers[destination] |= data & CauseRegister.WriteMask; return; case RegisterIndex.Compare: var ip = Cause.IP; ip.TimerInterrupt = false; Cause.IP = ip; break; } Registers[destination] = data; }, [From(OpCode.MF)] = i => cpu.GPR[i.RT] = (ulong)(int)Registers[i.RD], [From(FunctOpCode.TLBWI)] = i => { /* TODO. */ }, [From(FunctOpCode.ERET)] = i => { if (Status.ERL) { cpu.PC = Registers[(int)RegisterIndex.ErrorEPC]; Status.ERL = false; } else { cpu.PC = Registers[(int)RegisterIndex.EPC]; Status.EXL = false; } cpu.LLBit = false; cpu.DelaySlot = null; } }; }
public FloatingPointUnit(VR4300 cpu) { this.cpu = cpu; ImplementationRevision = new ImplementationRevisionRegister(this); ControlStatus = new ControlStatusRegister(this); operations = new Dictionary <OpCode, Action <Instruction> > { [OpCode.CF] = i => { switch (i.RD) { case 0: cpu.GPR[i.RT] = (ulong)(int)cpu.FCR0; break; case 31: cpu.GPR[i.RT] = (ulong)(int)cpu.FCR31; break; default: ExceptionProcessing.ReservedInstruction(cpu, i); return; } }, [OpCode.CT] = i => { switch (i.RD) { case 0: return; // Read-only register. case 31: cpu.FCR31 = (uint)cpu.GPR[i.RT]; if ((ControlStatus.Cause & (ControlStatus.Enables | ControlStatusRegister.ExceptionFlags.E)) != 0) { ExceptionProcessing.FloatingPoint(cpu); return; } break; default: ExceptionProcessing.ReservedInstruction(cpu, i); return; } } }; }
public static void ColdReset(VR4300 cpu) { var ds = cpu.CP0.Status.DS; ds.TS = ds.SR = cpu.CP0.Status.RP = false; cpu.CP0.Config.EP = 0; cpu.CP0.Status.ERL = ds.BEV = true; cpu.CP0.Config.BE = (SystemControlUnit.ConfigRegister.Endianness) 1; cpu.CP0.Registers[(int)SystemControlUnit.RegisterIndex.Random] = 31; cpu.CP0.Config.EC = cpu.DivMode; cpu.CP0.Status.DS = ds; HandleReset(cpu); }
public static void FloatingPoint(VR4300 cpu) => HandleGeneral(cpu, SystemControlUnit.CauseRegister.ExceptionCode.FPE);
public static void CoprocessorUnusable(VR4300 cpu, byte unit) => HandleGeneral(cpu, SystemControlUnit.CauseRegister.ExceptionCode.CpU, unit);
public static void ReservedInstruction(VR4300 cpu, Instruction instruction) { HandleGeneral(cpu, SystemControlUnit.CauseRegister.ExceptionCode.RI); throw new UnimplementedOperationException(instruction); // TODO: Remove this and the parameter once every instruction gets implemented. }
public static void Interrupt(VR4300 cpu) => HandleGeneral(cpu, SystemControlUnit.CauseRegister.ExceptionCode.Int);
private static void HandleReset(VR4300 cpu) { cpu.CP0.Registers[(int)SystemControlUnit.RegisterIndex.ErrorEPC] = cpu.PC; cpu.PC = ResetVector; }