/// <summary> /// Method for performing MUL instruction /// </summary> public static bool Multiply(ModuleBase module, MixInstruction.Instance instance) { var indexedAddress = InstructionHelpers.GetValidIndexedAddress(module, instance.AddressValue, instance.Index); if (indexedAddress == int.MinValue) { return(false); } Register rA = module.Registers.RA; Register rX = module.Registers.RX; long rAValue = rA.LongValue; long memoryWordValue = WordField.LoadFromFullWord(instance.FieldSpec, module.Memory[indexedAddress]).LongValue; var result = decimal.Multiply(rAValue, memoryWordValue); rA.Sign = rX.Sign = result.GetSign(); result = result.GetMagnitude(); var rXResultValue = (long)(result % ((long)1 << rX.BitCount)); var rAResultValue = (long)decimal.Truncate(result / ((long)1 << rX.BitCount)); rA.MagnitudeLongValue = rAResultValue; rX.MagnitudeLongValue = rXResultValue; return(true); }
/// <summary> /// Method for performing the OUT instruction /// </summary> public static bool Output(ModuleBase module, MixInstruction.Instance instance) { if (module.Devices == null) { module.ReportRuntimeError("Module does not provide devices"); return(false); } var mValue = InstructionHelpers.GetValidIndexedAddress(module, instance.AddressValue, instance.Index); if (mValue == int.MinValue) { return(false); } int deviceIndex = instance.FieldSpec.MixByteValue.ByteValue; MixDevice device = module.Devices[deviceIndex]; if (!device.SupportsOutput) { module.ReportRuntimeError("Device " + deviceIndex + " doesn't support output"); return(false); } if (device.Busy) { return(false); } var field = WordField.LoadFromRegister(new FieldSpec(4, 5), module.Registers.RX); device.StartOutput(module.Memory, mValue, (int)field.LongValue, module is Mix && ((Mix)module).Mode == ModuleBase.RunMode.Control ? new InterruptQueueCallback(((Mix)module).QueueInterrupt) : null); return(true); }
/// <summary> /// Method for performing the JRED instruction /// </summary> public static bool JumpIfReady(ModuleBase module, MixInstruction.Instance instance) { if (module.Devices == null) { module.ReportRuntimeError("Module does not provide devices"); return(false); } var indexedAddress = InstructionHelpers.GetValidIndexedAddress(module, instance.AddressValue, instance.Index); if (indexedAddress == int.MinValue) { return(false); } int deviceIndex = instance.FieldSpec.MixByteValue.ByteValue; MixDevice device = module.Devices[deviceIndex]; if (!device.Busy) { JumpInstructions.Jump(module, indexedAddress); return(false); } return(true); }
/// <summary> /// Method for performing the STZ instruction /// </summary> public static bool StoreZero(ModuleBase module, MixInstruction.Instance instance) { var indexedAddress = InstructionHelpers.GetValidIndexedAddress(module, instance.AddressValue, instance.Index); if (indexedAddress != int.MinValue) { var word = new FullWord(); WordField.LoadFromFullWord(instance.FieldSpec, word).ApplyToFullWord(module.Memory[indexedAddress]); } return(true); }
/// <summary> /// Method for performing CMPx instructions /// </summary> public static bool Compare(ModuleBase module, MixInstruction.Instance instance) { var indexedAddress = InstructionHelpers.GetValidIndexedAddress(module, instance.AddressValue, instance.Index); if (indexedAddress == int.MinValue) { return(false); } int registerIndex = instance.MixInstruction.Opcode - opcodeBase; Register register = module.Registers[registerIndex]; module.Registers.CompareIndicator = WordField.LoadFromFullWord(instance.FieldSpec, register.FullWordValue).CompareTo(module.Memory[indexedAddress]).ToCompValue(); return(true); }
/// <summary> /// Method for performing DIV instruction /// </summary> public static bool Divide(ModuleBase module, MixInstruction.Instance instance) { var indexedAddress = InstructionHelpers.GetValidIndexedAddress(module, instance.AddressValue, instance.Index); if (indexedAddress == int.MinValue) { return(false); } long memoryWordValue = WordField.LoadFromFullWord(instance.FieldSpec, module.Memory[indexedAddress]).LongValue; if (memoryWordValue == 0L) { module.ReportOverflow(); return(true); } Register rA = module.Registers.RA; Register rX = module.Registers.RX; long rAValue = rA.LongValue; long rXValue = rX.LongValue; decimal rAXValue = (decimal)rAValue * ((long)1 << rX.BitCount) + rXValue; decimal divider = rAXValue / memoryWordValue; rX.Sign = rA.Sign; rA.Sign = divider.GetSign(); divider = divider.GetMagnitude(); if (divider > rA.MaxMagnitude) { module.ReportOverflow(); return(true); } decimal remainder = rAXValue % memoryWordValue; rA.MagnitudeLongValue = (long)divider; rX.MagnitudeLongValue = (long)remainder; return(true); }
static bool DoLoad(ModuleBase module, MixInstruction.Instance instance, int registerIndex, bool negateSign) { var indexedAddress = InstructionHelpers.GetValidIndexedAddress(module, instance.AddressValue, instance.Index); if (indexedAddress == int.MinValue) { return(false); } var memoryField = WordField.LoadFromFullWord(instance.FieldSpec, module.Memory[indexedAddress]); if (negateSign) { memoryField.InvertSign(); } memoryField.ApplyToRegister(module.Registers[registerIndex]); return(true); }
/// <summary> /// Method for performing STx instructions /// </summary> public static bool StoreRegister(ModuleBase module, MixInstruction.Instance instance) { var indexedAddress = InstructionHelpers.GetValidIndexedAddress(module, instance.AddressValue, instance.Index); if (indexedAddress != int.MinValue) { Register sourceRegister; if (instance.MixInstruction.Opcode == storeJOpcode) { sourceRegister = module.Registers.RJ; } else { sourceRegister = module.Registers[instance.MixInstruction.Opcode - storeOpcodeBase]; } WordField.LoadFromRegister(instance.FieldSpec, sourceRegister).ApplyToFullWord(module.Memory[indexedAddress]); } return(true); }
/// <summary> /// Method for performing ADD and SUB instructions /// </summary> public static bool AddSubstract(ModuleBase module, MixInstruction.Instance instance) { var indexedAddress = InstructionHelpers.GetValidIndexedAddress(module, instance.AddressValue, instance.Index); if (indexedAddress == int.MinValue) { return(false); } Register rA = module.Registers.RA; long rALongValue = rA.LongValue; long memoryWordValue = WordField.LoadFromFullWord(instance.FieldSpec, module.Memory[indexedAddress]).LongValue; if (instance.MixInstruction.Opcode == substractOpcode) { memoryWordValue = -memoryWordValue; } long sumValue = rALongValue + memoryWordValue; if (sumValue != 0L) { rA.Sign = sumValue.GetSign(); sumValue = sumValue.GetMagnitude(); } if (sumValue > rA.MaxMagnitude) { module.ReportOverflow(); sumValue &= rA.MaxMagnitude; } rA.MagnitudeLongValue = sumValue; return(true); }
public static bool DoFloatingPoint(ModuleBase module, MixInstruction.Instance instance) { if (!(module is Mix)) { module.ReportRuntimeError(string.Format("Floating point instruction {0} is only available within Mix", instance.Instruction.Mnemonic)); return(false); } var mix = (Mix)module; FloatingPointModule floatingPointModule = mix.FloatingPointModule; if (floatingPointModule == null) { module.ReportRuntimeError(string.Format("Instruction {0} requires floating point module to be enabled", instance.Instruction.Mnemonic)); return(false); } if (mExecutionStatus != null && mExecutionStatus.ProgramCounter != module.ProgramCounter) { mExecutionStatus = null; } if (mExecutionStatus == null) { mExecutionStatus = new ExecutionStatus(module.Mode, module.ProgramCounter, instance.Instruction.Mnemonic); } if (mExecutionStatus.CurrentStep == ExecutionStatus.Step.Initialize) { mExecutionStatus.RAValue = module.Registers.RA.FullWordValue; bool prenormInstruction = Array.IndexOf(mPrenormOpcodes, instance.MixInstruction.Opcode) != -1; bool fcmpInstruction = !prenormInstruction && instance.MixInstruction.Opcode == fcmpOpcode; if (prenormInstruction || fcmpInstruction) { var indexedAddress = InstructionHelpers.GetValidIndexedAddress(module, instance.AddressValue, instance.Index); if (indexedAddress == int.MinValue) { mExecutionStatus = null; return(false); } mExecutionStatus.ParameterValue = module.Memory[indexedAddress]; } module.Registers.SaveToMemory(floatingPointModule.FullMemory, ModuleSettings.FloatingPointMemoryWordCount, 0); if (!floatingPointModule.ValidateCall(mExecutionStatus.Mnemonic)) { module.ReportRuntimeError("Unable to initialize floating point module"); mExecutionStatus = null; return(false); } module.Mode = ModuleBase.RunMode.Module; if (prenormInstruction) { mExecutionStatus.CurrentStep = ExecutionStatus.Step.PrenormRA; if (floatingPointModule.PreparePrenorm(mExecutionStatus.RAValue)) { module.ReportBreakpointReached(); return(false); } } else { mExecutionStatus.CurrentStep = ExecutionStatus.Step.ExecuteInstruction; if (fcmpInstruction ? floatingPointModule.PrepareCall(mExecutionStatus.Mnemonic, mExecutionStatus.RAValue, mExecutionStatus.ParameterValue) : floatingPointModule.PrepareCall(mExecutionStatus.Mnemonic, mExecutionStatus.RAValue)) { module.ReportBreakpointReached(); return(false); } } } mExecutionStatus.OverflowDetected |= floatingPointModule.Tick(); switch (floatingPointModule.Status) { case ModuleBase.RunStatus.Idle: switch (mExecutionStatus.CurrentStep) { case ExecutionStatus.Step.PrenormRA: mExecutionStatus.RAValue = floatingPointModule.Registers.RA.FullWordValue; mExecutionStatus.CurrentStep = ExecutionStatus.Step.PrenormParameter; if (floatingPointModule.PreparePrenorm(mExecutionStatus.ParameterValue)) { module.ReportBreakpointReached(); return(false); } break; case ExecutionStatus.Step.PrenormParameter: mExecutionStatus.ParameterValue = floatingPointModule.Registers.RA.FullWordValue; mExecutionStatus.CurrentStep = ExecutionStatus.Step.ExecuteInstruction; if (floatingPointModule.PrepareCall(mExecutionStatus.Mnemonic, mExecutionStatus.RAValue, mExecutionStatus.ParameterValue)) { module.ReportBreakpointReached(); return(false); } break; case ExecutionStatus.Step.ExecuteInstruction: mExecutionStatus.RAValue = floatingPointModule.Registers.RA.FullWordValue; Registers.CompValues comparatorValue = floatingPointModule.Registers.CompareIndicator; module.Registers.LoadFromMemory(floatingPointModule.FullMemory, ModuleSettings.FloatingPointMemoryWordCount); module.Registers.OverflowIndicator = mExecutionStatus.OverflowDetected; if (mExecutionStatus.Mnemonic == FcmpMnemonic) { module.Registers.CompareIndicator = comparatorValue; } else { module.Registers.RA.Magnitude = mExecutionStatus.RAValue.Magnitude; module.Registers.RA.Sign = mExecutionStatus.RAValue.Sign; } module.Mode = ModuleBase.RunMode.Normal; mExecutionStatus = null; return(true); } break; case ModuleBase.RunStatus.BreakpointReached: module.ReportBreakpointReached(); break; case ModuleBase.RunStatus.InvalidInstruction: case ModuleBase.RunStatus.RuntimeError: module.ReportRuntimeError(string.Format("Floating point module failed to execute instruction {0}", mExecutionStatus.Mnemonic)); module.Mode = mExecutionStatus.Mode; mExecutionStatus = null; break; } return(false); }
/// <summary> /// Method for performing JMP, JSJ, JOV, JNOV, JL, JE, JG, JGE, JNE and JLE instructions /// </summary> public static bool NonRegJump(ModuleBase module, MixInstruction.Instance instance) { var indexedAddress = InstructionHelpers.GetValidIndexedAddress(module, instance.AddressValue, instance.Index); if (indexedAddress == int.MinValue) { return(false); } switch (instance.MixInstruction.FieldSpec.MixByteValue.ByteValue) { case jmpField: Jump(module, indexedAddress); return(false); case jsjField: DoJump(module, indexedAddress, true); return(false); case jovField: if (!module.Registers.OverflowIndicator) { module.Registers.OverflowIndicator = false; break; } Jump(module, indexedAddress); return(false); case jnovField: if (module.Registers.OverflowIndicator) { module.Registers.OverflowIndicator = false; break; } Jump(module, indexedAddress); return(false); case jlField: if (module.Registers.CompareIndicator != Registers.CompValues.Less) { break; } Jump(module, indexedAddress); return(false); case jeField: if (module.Registers.CompareIndicator != Registers.CompValues.Equal) { break; } Jump(module, indexedAddress); return(false); case jgField: if (module.Registers.CompareIndicator != Registers.CompValues.Greater) { break; } Jump(module, indexedAddress); return(false); case jgeField: if (module.Registers.CompareIndicator != Registers.CompValues.Greater && module.Registers.CompareIndicator != Registers.CompValues.Equal) { break; } Jump(module, indexedAddress); return(false); case jneField: if (module.Registers.CompareIndicator == Registers.CompValues.Equal) { break; } Jump(module, indexedAddress); return(false); case jleField: if (module.Registers.CompareIndicator != Registers.CompValues.Less && module.Registers.CompareIndicator != Registers.CompValues.Equal) { break; } Jump(module, indexedAddress); return(false); } return(true); }
/// <summary> /// Method for performing JxN, JxZ, JxP, JxNN, JxNZ, JxNP, JxE and JxO instructions /// </summary> public static bool RegJump(ModuleBase module, MixInstruction.Instance instance) { var indexedAddress = InstructionHelpers.GetValidIndexedAddress(module, instance.AddressValue, instance.Index); if (indexedAddress == int.MinValue) { return(false); } int registerIndex = instance.MixInstruction.Opcode - regJumpOpcodeBase; long longValue = module.Registers[registerIndex].LongValue; switch (instance.MixInstruction.FieldSpec.MixByteValue.ByteValue) { case regJumpNegField: if (longValue >= 0L) { break; } Jump(module, indexedAddress); return(false); case regJumpZeroField: if (longValue != 0L) { break; } Jump(module, indexedAddress); return(false); case regJumpPosField: if (longValue <= 0L) { break; } Jump(module, indexedAddress); return(false); case regJumpNonNegField: if (longValue < 0L) { break; } Jump(module, indexedAddress); return(false); case regJumpNonZeroField: if (longValue == 0L) { break; } Jump(module, indexedAddress); return(false); case regJumpNonPosField: if (longValue > 0L) { break; } Jump(module, indexedAddress); return(false); case regJumpEvenField: if (longValue % 2 != 0) { break; } Jump(module, indexedAddress); return(false); case regJumpOddField: if (longValue % 2 == 0) { break; } Jump(module, indexedAddress); return(false); } return(true); }
/// <summary> /// Method for performing the MOVE instruction /// </summary> public static bool Move(ModuleBase module, MixInstruction.Instance instance) { mMoveStatuses.TryGetValue(module.ModuleName, out moveStatus status); // if we have a move status, check if it applies to this instruction if (status != null && status.ProgramCounter != module.ProgramCounter) { status = null; mMoveStatuses.Remove(module.ModuleName); } if (status == null) { var fromAddress = InstructionHelpers.GetValidIndexedAddress(module, instance.AddressValue, instance.Index); if (fromAddress == int.MinValue) { return(false); } var toAddress = InstructionHelpers.GetValidIndexedAddress(module, 0, 1); if (toAddress == int.MinValue) { return(false); } status = new moveStatus(module.ProgramCounter, fromAddress, toAddress, instance.FieldSpec.MixByteValue.ByteValue); mMoveStatuses[module.ModuleName] = status; return(false); } // the MOVE instruction takes two ticks per moved word... switch (status.CurrentWordState) { // ... during one of those, the actual move is performed... case moveStatus.WordStates.BeforeMove: case moveStatus.WordStates.RegisterIncreased: IMemory memory = module.Memory; int currentFromAddress = status.FromAddress + status.CurrentWord; int currentToAddress = status.ToAddress + status.CurrentWord; if (currentFromAddress > memory.MaxWordIndex || currentToAddress > memory.MaxWordIndex) { module.ReportRuntimeError("Source or target address overflow"); status = null; mMoveStatuses.Remove(module.ModuleName); return(false); } memory[currentToAddress] = memory[currentFromAddress]; status.CurrentWordState = moveStatus.WordStates.Moved; break; // ... during the other, the value of rI1 is increased case moveStatus.WordStates.Moved: Register rI1 = module.Registers.RI1; rI1.LongValue++; status.NextWord(); if (status.CurrentWord >= status.WordCount) { status = null; mMoveStatuses.Remove(module.ModuleName); return(true); } status.CurrentWordState = moveStatus.WordStates.RegisterIncreased; break; } // return false to prevent the PC from increasing return(false); }