Beispiel #1
0
        /// <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);
        }
Beispiel #2
0
        /// <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);
        }
Beispiel #3
0
        /// <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);
        }
Beispiel #4
0
        /// <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);
        }
Beispiel #5
0
        /// <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);
        }
Beispiel #6
0
        /// <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);
        }
Beispiel #7
0
        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);
        }
Beispiel #8
0
        /// <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);
        }
Beispiel #9
0
        /// <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);
        }
Beispiel #11
0
        /// <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);
        }
Beispiel #12
0
        /// <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);
        }
Beispiel #13
0
        /// <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);
        }