Example #1
0
        public StackVirtualMachine(Action <string> errorCallback = null)
        {
            _memory        = new uint[0xFFFF];
            _flag          = 0;
            _sp            = 0x0000;
            _ip            = 0x1000;
            _errorCallback = errorCallback;

            State = SVMSStates.Active;
        }
Example #2
0
        public void Start()
        {
            try
            {
                var instruction = OpCodes.NoOperation;
                do
                {
                    if (State == SVMSStates.Active || State == SVMSStates.Step)
                    {
                        if (State == SVMSStates.Step)
                        {
                            State = SVMSStates.Idle;
                        }

                        #region Tick

                        uint operand1;
                        uint operand2;
                        uint result;
                        instruction = _memory[_ip];
                        switch (instruction)
                        {
                        case OpCodes.Halt:
                        case OpCodes.NoOperation:
                            /*
                             * No operation
                             */
                            break;

                        case OpCodes.Push:
                            /*
                             * Push value onto the stack
                             */
                            Push(GetVal());
                            break;

                        case OpCodes.Add:
                            /*
                             * Take top 2 operands from the stack, add them, and push the result
                             * In the event of overflow, set the carry flag
                             */
                            operand1 = Pop();
                            operand2 = Pop();
                            result   = operand1 + operand2;

                            if (result < operand1)
                            {
                                _flag |= Flags.Carry;
                            }

                            CheckForZeroResult(result);
                            Push(result);
                            break;

                        case OpCodes.Subtract:
                            /*
                             * Take top 2 operands from the stack, subtract them, and push the result
                             * In the event of overflow, set the carry flag
                             */
                            operand1 = Pop();
                            operand2 = Pop();
                            result   = operand1 - operand2;

                            if (result > operand1)
                            {
                                _flag |= Flags.Carry;
                            }

                            CheckForZeroResult(result);
                            Push(result);
                            break;

                        case OpCodes.Store:
                            /*
                             * Stores operand 2 at address specified by operand 1
                             */
                            _memory[GetVal()] = GetVal();
                            break;

                        case OpCodes.JumpToSubroutine:
                            /*
                             * Push the instruction pointer onto the stack and jump to address specified by operand 1
                             */
                            operand1 = GetVal();
                            Push(_ip);
                            _ip = operand1;
                            continue;

                        case OpCodes.Return:
                            /*
                             * Returns
                             */
                            _ip = Pop();
                            break;

                        case OpCodes.Swap:
                            /*
                             * Swaps the top 2 items on the stack
                             */
                            var tmp1 = Pop();
                            var tmp2 = Pop();
                            Push(tmp1);
                            Push(tmp2);
                            break;

                        case OpCodes.Compare:
                            /*
                             *  Compares operand 1 with operand 2, if they are equal, set the Equal flag
                             *  Under the hood it performs a subtraction, and sets the Z flag if it's zero
                             */
                            operand1 = GetVal();
                            operand2 = GetVal();
                            result   = operand1 - operand2;
                            CheckForZeroResult(result);
                            break;

                        case OpCodes.JumpIfEqual:
                            /*
                             *  Jump if the Equal flag is set
                             */
                            operand1 = GetVal();
                            if ((_flag & Flags.Zero) != 0)
                            {
                                Push(_ip);
                                _ip = operand1;
                                continue;
                            }
                            break;

                        case OpCodes.JumpIfNotEqual:
                            /*
                             *  Jump if the Equal flag is not set
                             */
                            operand1 = GetVal();
                            if ((_flag & Flags.Zero) == 0)
                            {
                                Push(_ip);
                                _ip = operand1;
                                continue;
                            }
                            break;

                        case OpCodes.ClearFlags:
                            /*
                             * Clear the flags
                             */
                            _flag = 0;
                            break;

                        case OpCodes.Increment:
                            /*
                             * Increment the top item on the stack
                             */
                            result = Pop();
                            ++result;
                            CheckForZeroResult(result);
                            Push(result);
                            break;

                        case OpCodes.Decrement:
                            /*
                             * Decrement the top item on the stack
                             */
                            operand1 = Pop();
                            result   = operand1 - 1;

                            if (result > operand1)
                            {       // Decremented from zero
                                result = 1;
                                _flag |= Flags.Sign;
                            }
                            else
                            {
                                CheckForZeroResult(result);
                            }

                            Push(result);
                            break;

                        case OpCodes.Jump:
                            /*
                             * jump to address specified by operand 1
                             */
                            operand1 = GetVal();
                            _ip      = operand1;
                            continue;

                        default:
                            throw new InvalidInstructionException($"{instruction.ToString("X")} is not a valid instruction");
                        }

                        #endregion

                        _ip++;
                    }
                } while (instruction != OpCodes.Halt);
            }
            catch (Exception ex)
            {
                if (_errorCallback != null)
                {
                    _errorCallback(GetDebugInfo(ex));
                }
                else
                {
                    throw ex;
                }
            }
        }