public StackVirtualMachine(Action <string> errorCallback = null) { _memory = new uint[0xFFFF]; _flag = 0; _sp = 0x0000; _ip = 0x1000; _errorCallback = errorCallback; State = SVMSStates.Active; }
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; } } }