/// <summary> /// Method for performing the NUM instruction /// </summary> public static bool ConvertToNumeric(ModuleBase module, MixInstruction.Instance instance) { decimal num = 0M; Register rA = module.Registers.RA; for (int i = 0; i < rA.ByteCount; i++) { num *= 10M; num += rA[i] % 10; } Register rX = module.Registers.RX; for (int j = 0; j < rX.ByteCount; j++) { num *= 10M; num += rX[j] % 10; } if (num > rA.MaxMagnitude) { module.ReportOverflow(); num = num % rA.MaxMagnitude; } rA.MagnitudeLongValue = (long)num; return(true); }
public static InstanceValidationError[] InstanceValid(MixInstruction.Instance instance) { int index = 0; InstanceValidationError[] errorArray = new InstanceValidationError[2]; if (instance.Index > 6) { errorArray[index] = new InstanceValidationError(InstanceValidationError.Sources.Index, 0, 6); index++; } if (instance.FieldSpec.MixByteValue.ByteValue >= Devices.DeviceCount) { errorArray[index] = new InstanceValidationError(InstanceValidationError.Sources.FieldSpec, 0, 20); index++; } if (index == 1) { return new InstanceValidationError[] { errorArray[0] } } ; if (index == 2) { return(errorArray); } return(null); }
/// <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 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 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); }
public static InstanceValidationError[] ValidateIndex(MixInstruction.Instance instance) => instance.Index > 6 ? new InstanceValidationError[] { new InstanceValidationError(InstanceValidationError.Sources.Index, 0, 6) } : null;
static bool DoIncrease(ModuleBase module, MixInstruction.Instance instance, int registerIndex, bool negateSign) { var indexedAddress = module.Registers.GetIndexedAddress(instance.AddressValue, instance.Index); Register register = module.Registers[registerIndex]; long longValue = register.LongValue; if (negateSign) { indexedAddress = -indexedAddress; } longValue += indexedAddress; if (longValue != 0L) { register.Sign = longValue.GetSign(); longValue = longValue.GetMagnitude(); } if (longValue > register.MaxMagnitude) { if (register is IndexRegister) { module.ReportRuntimeError("Index register overflow"); return(false); } module.ReportOverflow(); longValue &= register.MaxMagnitude; } register.MagnitudeLongValue = longValue; return(true); }
public static InstanceValidationError[] ValidateIndexAndFieldSpec(MixInstruction.Instance instance) { int index = 0; InstanceValidationError[] errorArray = new InstanceValidationError[2]; if (instance.Index > 6) { errorArray[index] = new InstanceValidationError(InstanceValidationError.Sources.Index, 0, 6); index++; } if (!instance.FieldSpec.IsValid) { errorArray[index] = new InstanceValidationError(InstanceValidationError.Sources.FieldSpec, "valid fieldspec required"); index++; } if (index == 1) { return new InstanceValidationError[] { errorArray[0] } } ; if (index == 2) { return(errorArray); } return(null); } }
public RuntimeValidationError(int programCounter, MixInstruction.Instance instance, string message, int validLowerBound, int validUpperBound, int actualValue) : base(message, validLowerBound, validUpperBound) { Instance = instance; ProgramCounter = programCounter; ActualValue = actualValue; }
/// <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); }
public static bool ForceInterrupt(ModuleBase module, MixInstruction.Instance instance) { if (!(module is Mix)) { module.ReportRuntimeError(string.Format("The {0} instruction is only available in Mix", instance.Instruction.Mnemonic)); return(false); } InterruptHandler.HandleInterrupt((Mix)module, new Interrupt(Interrupt.Types.Forced)); return(false); }
/// <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); }
static bool DoEnter(ModuleBase module, MixInstruction.Instance instance, int registerIndex, bool negateSign) { var indexedAddress = module.Registers.GetIndexedAddress(instance.AddressValue, instance.Index); Register register = module.Registers[registerIndex]; if (negateSign) { indexedAddress = -indexedAddress; } register.LongValue = indexedAddress; if (indexedAddress == 0) { register.Sign = instance.Sign; } 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); }
/// <summary> /// Method for performing SLB and SRB instructions /// </summary> public static bool ShiftAXBinary(ModuleBase module, MixInstruction.Instance instance) { var indexedAddress = module.Registers.GetIndexedAddress(instance.AddressValue, instance.Index); if (indexedAddress < 0) { module.ReportRuntimeError("Indexed value must be nonnegative: " + indexedAddress); return(false); } Register rA = module.Registers.RA; Register rX = module.Registers.RX; int registerBitCount = FullWordRegister.RegisterByteCount * MixByte.BitCount; int shiftCount = indexedAddress % (registerBitCount * 2); if (shiftCount == 0) { return(true); } long rAlongValue = rA.MagnitudeLongValue; long rXlongValue = rX.MagnitudeLongValue; switch (instance.MixInstruction.FieldSpec.MixByteValue.ByteValue) { case slbField: rA.MagnitudeLongValue = ((rAlongValue << shiftCount) & rA.MaxMagnitude) | (rXlongValue >> (rX.BitCount - shiftCount)); rX.MagnitudeLongValue = (rXlongValue << shiftCount) & rX.MaxMagnitude; break; case srbField: rA.MagnitudeLongValue = rAlongValue >> shiftCount; rX.MagnitudeLongValue = (rXlongValue >> shiftCount) | (rAlongValue << (rX.BitCount - shiftCount)); break; } 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 the CHAR instruction /// </summary> public static bool ConvertToChar(ModuleBase module, MixInstruction.Instance instance) { Register rA = module.Registers.RA; long magnitudeLongValue = rA.MagnitudeLongValue; Register rX = module.Registers.RX; for (int i = rX.ByteCount - 1; i >= 0; i--) { rX[i] = zeroCharValue + ((byte)(magnitudeLongValue % 10L)); magnitudeLongValue /= 10L; } for (int i = rA.ByteCount - 1; i >= 0; i--) { rA[i] = zeroCharValue + ((byte)(magnitudeLongValue % 10L)); magnitudeLongValue /= 10L; } return(true); }
/// <summary> /// Method for performing SLA and SRA instructions /// </summary> public static bool ShiftA(ModuleBase module, MixInstruction.Instance instance) { var indexedAddress = module.Registers.GetIndexedAddress(instance.AddressValue, instance.Index); if (indexedAddress < 0) { module.ReportRuntimeError("Indexed value must be nonnegative: " + indexedAddress); return(false); } Register rA = module.Registers.RA; int shiftCount = indexedAddress % rA.ByteCount; if (shiftCount != 0) { switch (instance.MixInstruction.FieldSpec.MixByteValue.ByteValue) { case slaField: ShiftWordLeft(rA, shiftCount); for (int i = rA.ByteCount - shiftCount; i < rA.ByteCount; i++) { rA[i] = 0; } break; case sraField: ShiftWordRight(rA, shiftCount); for (int j = shiftCount - 1; j >= 0; j--) { rA[j] = 0; } break; } } 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 the IOC instruction /// </summary> public static bool IOControl(ModuleBase module, MixInstruction.Instance instance) { if (module.Devices == null) { module.ReportRuntimeError("Module does not provide devices"); return(false); } var indexedAddress = module.Registers.GetIndexedAddress(instance.AddressValue, instance.Index); int deviceIndex = instance.FieldSpec.MixByteValue.ByteValue; MixDevice device = module.Devices[deviceIndex]; if (device.Busy) { return(false); } var field = WordField.LoadFromRegister(new FieldSpec(4, 5), module.Registers.RX); device.StartIoc(indexedAddress, (int)field.LongValue, module is Mix && ((Mix)module).Mode == ModuleBase.RunMode.Control ? new InterruptQueueCallback(((Mix)module).QueueInterrupt) : null); 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 RuntimeValidationError(int programCounter, MixInstruction.Instance instance, int validLowerBound, int validUpperBound, int actualValue) : this(programCounter, instance, null, validLowerBound, validUpperBound, actualValue) { }
public RuntimeValidationError(int programCounter, MixInstruction.Instance instance, string message) : this(programCounter, instance, message, int.MinValue, int.MinValue, int.MinValue) { }
public InstructionText(MixInstruction.Instance instance) { mInstance = instance; }
/// <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 INCx instructions /// </summary> public static bool Increase(ModuleBase module, MixInstruction.Instance instance) => DoIncrease(module, instance, instance.MixInstruction.Opcode - opcodeBase, false);
/// <summary> /// Method for performing ENNx instructions /// </summary> public static bool EnterNegative(ModuleBase module, MixInstruction.Instance instance) => DoEnter(module, instance, instance.MixInstruction.Opcode - opcodeBase, true);
/// <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); }
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 LDxN instructions /// </summary> public static bool LoadNegative(ModuleBase module, MixInstruction.Instance instance) { int registerIndex = instance.MixInstruction.Opcode - loadNegOpcodeBase; return(DoLoad(module, instance, registerIndex, true)); }