From 7889b2b2865134d5e067740b42de22a1693f2f0e Mon Sep 17 00:00:00 2001
From: MarvelousAnything <marvelousanything@gmail.com>
Date: Tue, 1 Nov 2022 15:23:05 -0400
Subject: [PATCH] Did some work. I am committing to push to github.

---
 src/callable.rs    |  44 +++++++-
 src/frame.rs       |  82 ++++++++++++++-
 src/function.rs    |  19 ++++
 src/instruction.rs | 251 ++++++++++++++++++++++++++++++++++++++++++++-
 src/main.rs        |  15 ++-
 src/native.rs      |  97 +++++++++++++++++-
 src/stack.rs       |   2 +
 src/state.rs       |  66 +++++++++---
 src/tvm.rs         |  43 +++++++-
 9 files changed, 586 insertions(+), 33 deletions(-)

diff --git a/src/callable.rs b/src/callable.rs
index 083d7eb..f66b0cf 100644
--- a/src/callable.rs
+++ b/src/callable.rs
@@ -1,26 +1,60 @@
 use std::fmt::Debug;
 use crate::function::Function;
 use crate::native::NativeFunction;
+use crate::stack::StackHolder;
 use crate::tvm::Tvm;
 
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub enum Callable {
     Function(Function),
-    NativeFunction(NativeFunction),
+    Native(NativeFunction),
+}
+
+impl Callable {
+    pub fn get_callable(id: i32) -> Self {
+        match id {
+            n if n < -111 => panic!("Invalid callable id: {}", n),
+            n @ -111..=-101 => Callable::Native(NativeFunction::get_native(n)),
+            n if n >= 0 => Callable::Function(Function::get_function(n as usize)),
+            _ => unreachable!(),
+        }
+    }
+
+    pub fn get_id(&self) -> i32 {
+        match self {
+            Callable::Function(function) => function.id as i32,
+            Callable::Native(native) => native.get_id(),
+        }
+    }
 }
 
 pub trait Caller: Debug + Clone {
-    fn call(callable: Callable);
+    fn do_call(&mut self, callable: Callable);
 }
 
 impl Caller for Tvm {
-    fn call(callable: Callable) {
+    fn do_call(&mut self, callable: Callable) {
         match callable {
             Callable::Function(function) => {
                 println!("Calling function: {:?}", function);
+                self.push(0);
             },
-            Callable::NativeFunction(native_function) => {
-                println!("Calling native function: {:?}", native_function);
+            Callable::Native(native_function) => {
+
+                match native_function {
+                    NativeFunction::IPrint { .. } => {
+                        let value = self.pop();
+                        println!("stdout: {}", value);
+                        self.push(0);
+                    },
+                    NativeFunction::Alloc { .. } => {
+                        let size = self.pop();
+                        self.push(self.heap_size as i32);
+                        self.heap_size += size as usize;
+                        println!("Allocating {} bytes", size);
+                    },
+                    _ => println!("Calling native function: {:?}", native_function),
+                }
             },
         }
     }
diff --git a/src/frame.rs b/src/frame.rs
index e35e0ac..7dc701b 100644
--- a/src/frame.rs
+++ b/src/frame.rs
@@ -1,5 +1,7 @@
 use crate::callable::Callable;
 use crate::instruction::Instruction;
+use crate::state::{Stateful, StateResult};
+use crate::state::StateResult::Continue;
 use crate::tvm::Tvm;
 
 #[derive(Debug, Clone, PartialEq, Eq)]
@@ -8,6 +10,14 @@ pub struct Frame {
     pub name: String,
     pub data: Vec<FrameData>,
     pub pc: usize,
+    pub previous_frame: Option<Box<Frame>>,
+    pub result: Option<StateResult>,
+}
+
+impl Frame {
+    pub fn builder() -> FrameBuilder {
+        FrameBuilder::new()
+    }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq)]
@@ -18,12 +28,80 @@ pub enum FrameData {
     Primitive(i32),
 }
 
+impl FrameData {
+    pub fn get_id(&self) -> i32 {
+        match self {
+            FrameData::Frame(frame) => frame.id as i32,
+            FrameData::Callable(callable, _) => callable.get_id(),
+            FrameData::Instruction(instruction, _) => instruction.get_op() as i32,
+            FrameData::Primitive(value) => *value,
+        }
+    }
+}
+
 pub trait FrameEvaluator {
-    fn eval_frame(&mut self, frame: Frame);
+    fn do_frame_eval(&mut self, frame: &Frame);
 }
 
 impl FrameEvaluator for Tvm {
-    fn eval_frame(&mut self, frame: Frame) {
+    fn do_frame_eval(&mut self, frame: &Frame) {
         println!("Evaluating frame: {:?}", frame);
+        if self.should_continue() {
+            self.eval(frame.clone());
+        }
+    }
+}
+
+#[derive(Default)]
+pub struct FrameBuilder {
+    id: usize,
+    name: String,
+    data: Vec<FrameData>,
+}
+
+impl FrameBuilder {
+    pub fn new() -> Self {
+        Self::default()
+    }
+
+    pub fn id(mut self, id: usize) -> Self {
+        self.id = id;
+        self
+    }
+
+    pub fn name(mut self, name: String) -> Self {
+        self.name = name;
+        self
+    }
+
+    pub fn frame(mut self, frame: Frame) -> Self {
+        self.data.push(FrameData::Frame(frame));
+        self
+    }
+
+    pub fn callable(mut self, callable: i32, args: Vec<i32>) -> Self {
+        self.data.push(FrameData::Callable(Callable::get_callable(callable), args));
+        self
+    }
+
+    pub fn instruction(mut self, instruction: Instruction, args: Vec<i32>) -> Self {
+        self.data.push(FrameData::Instruction(instruction, args));
+        self
+    }
+
+    pub fn primitive(mut self, primitive: i32) -> Self {
+        self.data.push(FrameData::Primitive(primitive));
+        self
+    }
+
+    pub fn build(self) -> Frame {
+        Frame {
+            id: self.id,
+            name: self.name,
+            data: self.data,
+            pc: 0,
+            previous_frame: None,
+            result: None
+        }
     }
 }
\ No newline at end of file
diff --git a/src/function.rs b/src/function.rs
index 1b31fba..b5eca56 100644
--- a/src/function.rs
+++ b/src/function.rs
@@ -7,4 +7,23 @@ pub struct Function {
     pub args: usize,
     pub locals: usize,
     pub frame: Frame,
+}
+
+impl Function {
+    pub(crate) fn get_function(id: usize) -> Function {
+        Function {
+            id,
+            name: "test-function".to_string(),
+            args: 0,
+            locals: 0,
+            frame: Frame {
+                id: 0,
+                name: "test-frame".to_string(),
+                data: vec![],
+                pc: 0,
+                previous_frame: None,
+                result: None,
+            }
+        }
+    }
 }
\ No newline at end of file
diff --git a/src/instruction.rs b/src/instruction.rs
index f343b05..305e98b 100644
--- a/src/instruction.rs
+++ b/src/instruction.rs
@@ -1,4 +1,11 @@
+use std::cell::RefCell;
 use std::fmt::Debug;
+use std::rc::Rc;
+use crate::callable::Callable;
+use crate::frame::{Frame, FrameData};
+use crate::stack::StackHolder;
+use crate::state::{Stateful, StateResult};
+use crate::state::StateResult::Exit;
 use crate::tvm::Tvm;
 
 #[derive(Debug, Clone, PartialEq, Eq)]
@@ -33,12 +40,250 @@ pub enum Instruction {
     Unknown(u32),
 }
 
+impl Instruction {
+    pub fn get_instruction(op_code: u32) -> Instruction {
+        match op_code {
+            1 => Instruction::Push {
+                op: 1,
+                name: "push".to_string(),
+                num_operands: 0
+            },
+            2 => Instruction::Fetch {
+                op: 2,
+                name: "fetch".to_string(),
+                num_operands: 0
+            },
+            3 => Instruction::Store {
+                op: 3,
+                name: "store".to_string(),
+                num_operands: 0
+            },
+            4 => Instruction::IF {
+                op: 4,
+                name: "if".to_string(),
+                num_operands: 0
+            },
+            5 => Instruction::Loop {
+                op: 5,
+                name: "loop".to_string(),
+                num_operands: 0
+            },
+            6 => Instruction::Break {
+                op: 6,
+                name: "break".to_string(),
+                num_operands: 0
+            },
+            7 => Instruction::Return {
+                op: 7,
+                name: "return".to_string(),
+                num_operands: 0
+            },
+            8 => Instruction::Call {
+                op: 8,
+                name: "call".to_string(),
+                num_operands: 0
+            },
+            9 => Instruction::FPPlus {
+                op: 9,
+                name: "fp+".to_string(),
+                num_operands: 0
+            },
+            10 => Instruction::Add {
+                op: 10,
+                name: "+".to_string(),
+                num_operands: 0
+            },
+            11 => Instruction::Sub {
+                op: 11,
+                name: "-".to_string(),
+                num_operands: 0
+            },
+            12 => Instruction::Mul {
+                op: 12,
+                name: "*".to_string(),
+                num_operands: 0
+            },
+            13 => Instruction::Div {
+                op: 13,
+                name: "/".to_string(),
+                num_operands: 0
+            },
+            14 => Instruction::Mod {
+                op: 14,
+                name: "%".to_string(),
+                num_operands: 0
+            },
+            15 => Instruction::Not {
+                op: 15,
+                name: "!".to_string(),
+                num_operands: 0
+            },
+            16 => Instruction::And {
+                op: 16,
+                name: "&".to_string(),
+                num_operands: 0
+            },
+            17 => Instruction::OR {
+                op: 17,
+                name: "|".to_string(),
+                num_operands: 0
+            },
+            18 => Instruction::Xor {
+                op: 18,
+                name: "^".to_string(),
+                num_operands: 0
+            },
+            19 => Instruction::EQ {
+                op: 19,
+                name: "==".to_string(),
+                num_operands: 0
+            },
+            20 => Instruction::Neq {
+                op: 20,
+                name: "!=".to_string(),
+                num_operands: 0
+            },
+            21 => Instruction::LT {
+                op: 21,
+                name: "<".to_string(),
+                num_operands: 0
+            },
+            22 => Instruction::Leq {
+                op: 22,
+                name: "<=".to_string(),
+                num_operands: 0
+            },
+            23 => Instruction::GT {
+                op: 23,
+                name: ">".to_string(),
+                num_operands: 0
+            },
+            24 => Instruction::Geq {
+                op: 24,
+                name: ">=".to_string(),
+                num_operands: 0
+            },
+            25 => Instruction::Pop {
+                op: 25,
+                name: "pop".to_string(),
+                num_operands: 0
+            },
+            26 => Instruction::LShift {
+                op: 26,
+                name: "<<".to_string(),
+                num_operands: 0
+            },
+            27 => Instruction::RShift {
+                op: 27,
+                name: ">>".to_string(),
+                num_operands: 0
+            },
+            _ => Instruction::Unknown(op_code),
+        }
+    }
+
+    pub fn get_op(&self) -> u32 {
+        match self {
+            Instruction::Push { op, .. } => *op,
+            Instruction::Fetch { op, .. } => *op,
+            Instruction::Store { op, .. } => *op,
+            Instruction::IF { op, .. } => *op,
+            Instruction::Loop { op, .. } => *op,
+            Instruction::Break { op, .. } => *op,
+            Instruction::Return { op, .. } => *op,
+            Instruction::Call { op, .. } => *op,
+            Instruction::FPPlus { op, .. } => *op,
+            Instruction::Add { op, .. } => *op,
+            Instruction::Sub { op, .. } => *op,
+            Instruction::Mul { op, .. } => *op,
+            Instruction::Div { op, .. } => *op,
+            Instruction::Mod { op, .. } => *op,
+            Instruction::Not { op, .. } => *op,
+            Instruction::And { op, .. } => *op,
+            Instruction::OR { op, .. } => *op,
+            Instruction::Xor { op, .. } => *op,
+            Instruction::EQ { op, .. } => *op,
+            Instruction::Neq { op, .. } => *op,
+            Instruction::LT { op, .. } => *op,
+            Instruction::Leq { op, .. } => *op,
+            Instruction::GT { op, .. } => *op,
+            Instruction::Geq { op, .. } => *op,
+            Instruction::Pop { op, .. } => *op,
+            Instruction::LShift { op, .. } => *op,
+            Instruction::RShift { op, .. } => *op,
+            Instruction::Unknown(op) => *op,
+        }
+    }
+}
+
 pub trait Evaluator: Debug + Clone {
-    fn eval(&mut self, instruction: Instruction);
+    fn do_eval(&mut self, frame: &mut Frame);
 }
 
 impl Evaluator for Tvm {
-    fn eval(&mut self, instruction: Instruction) {
-        println!("Evaluating instruction: {:?}", instruction);
+    fn do_eval(&mut self, frame: &mut Frame) {
+        if frame.pc >= frame.data.len() {
+            self.last_result = Some(Exit);
+            return;
+        }
+        let data = &frame.data.get(frame.pc).unwrap();
+        frame.pc += 1;
+        match data {
+            FrameData::Frame(frame) => {
+                self.frame_eval(frame.clone())
+            },
+            FrameData::Instruction(instruction, ..) => {
+                println!("Evaluating instruction: {:?}", instruction);
+                match instruction {
+                    Instruction::Push { .. } => {
+                        let x = &frame.data[frame.pc].get_id();
+                        self.push(*x);
+                        frame.pc += 1;
+                    }
+                    Instruction::Fetch { .. } => {
+                        let index = self.pop();
+                        self.push(self.memory[index as usize]);
+                    }
+                    Instruction::Store { .. } => {}
+                    Instruction::IF { .. } => {}
+                    Instruction::Loop { .. } => {}
+                    Instruction::Break { .. } => {}
+                    Instruction::Return { .. } => {}
+                    Instruction::Call { .. } => {
+                        let id = &frame.data[frame.pc].get_id();
+                        let callable = Callable::get_callable(*id);
+                        self.call(callable);
+                        frame.pc += 1;
+                    }
+                    Instruction::FPPlus { .. } => {}
+                    Instruction::Add { .. } => {}
+                    Instruction::Sub { .. } => {}
+                    Instruction::Mul { .. } => {}
+                    Instruction::Div { .. } => {}
+                    Instruction::Mod { .. } => {}
+                    Instruction::Not { .. } => {}
+                    Instruction::And { .. } => {}
+                    Instruction::OR { .. } => {}
+                    Instruction::Xor { .. } => {}
+                    Instruction::EQ { .. } => {}
+                    Instruction::Neq { .. } => {}
+                    Instruction::LT { .. } => {}
+                    Instruction::Leq { .. } => {}
+                    Instruction::GT { .. } => {}
+                    Instruction::Geq { .. } => {}
+                    Instruction::Pop { .. } => {}
+                    Instruction::LShift { .. } => {}
+                    Instruction::RShift { .. } => {}
+                    Instruction::Unknown(_) => {}
+                }
+            },
+            FrameData::Callable(callable, ..) => {
+                println!("Evaluating callable: {:?}", callable);
+                self.call(callable.clone())
+            },
+            FrameData::Primitive(primitive) => {
+                println!("Primitive: {:?}", primitive);
+            }
+        }
     }
 }
\ No newline at end of file
diff --git a/src/main.rs b/src/main.rs
index 8c18c67..04c7410 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,3 +1,4 @@
+use crate::state::Stateful;
 use crate::tvm::Tvm;
 
 mod tvm;
@@ -12,6 +13,16 @@ mod function;
 mod instruction;
 
 fn main() {
-    let tvm = Tvm::default();
-    println!("{:?}", tvm);
+    use std::io::{ stdin ,stdout, Write};
+    let mut s = String::new();
+    let _ = stdout().flush();
+    let mut tvm = Tvm::default();
+    tvm.start();
+    loop {
+        stdin().read_line(&mut s).expect("Did not enter a correct string");
+        if !s.is_empty() {
+            print!("Tick {}:\t\t", tvm.ticks);
+            tvm.tick();
+        }
+    }
 }
diff --git a/src/native.rs b/src/native.rs
index 2a3aea5..2b0cdb5 100644
--- a/src/native.rs
+++ b/src/native.rs
@@ -1,6 +1,95 @@
 #[derive(Debug, Clone, PartialEq, Eq)]
-pub struct NativeFunction {
-    pub id: i32,
-    pub name: String,
-    pub args: usize,
+pub enum  NativeFunction {
+    IPrint { id: i32, name: String, args: u32 },
+    SPrint { id: i32, name: String, args: u32 },
+    IRead { id: i32, name: String, args: u32 },
+    SRead { id: i32, name: String, args: u32 },
+    NL { id: i32, name: String, args: u32 },
+    Random { id: i32, name: String, args: u32 },
+    Timer { id: i32, name: String, args: u32 },
+    StopTimer { id: i32, name: String, args: u32 },
+    Alloc { id: i32, name: String, args: u32 },
+    Free { id: i32, name: String, args: u32 },
+    I2S { id: i32, name: String, args: u32 },
+    Unknown(i32),
+}
+
+impl NativeFunction {
+    pub fn get_native(id: i32) -> Self {
+        match id {
+            -101 => NativeFunction::IPrint {
+                id,
+                name: "iprint".to_string(),
+                args: 1,
+            },
+            -102 => NativeFunction::SPrint {
+                id,
+                name: "sprint".to_string(),
+                args: 1,
+            },
+            -103 => NativeFunction::IRead {
+                id,
+                name: "iread".to_string(),
+                args: 1,
+            },
+            -104 => NativeFunction::SRead {
+                id,
+                name: "sread".to_string(),
+                args: 2,
+            },
+            -105 => NativeFunction::NL {
+                id,
+                name: "nl".to_string(),
+                args: 0,
+            },
+            -106 => NativeFunction::Random {
+                id,
+                name: "random".to_string(),
+                args: 1,
+            },
+            -107 => NativeFunction::Timer {
+                id,
+                name: "timer".to_string(),
+                args: 2,
+            },
+            -108 => NativeFunction::StopTimer {
+                id,
+                name: "stoptimer".to_string(),
+                args: 1,
+            },
+            -109 => NativeFunction::Alloc {
+                id,
+                name: "alloc".to_string(),
+                args: 1,
+            },
+            -110 => NativeFunction::Free {
+                id,
+                name: "free".to_string(),
+                args: 1,
+            },
+            -111 => NativeFunction::I2S {
+                id,
+                name: "i2s".to_string(),
+                args: 1,
+            },
+            n => NativeFunction::Unknown(n),
+        }
+    }
+    
+    pub fn get_id(&self) -> i32 {
+        match self {
+            NativeFunction::IPrint { id, .. } => *id,
+            NativeFunction::SPrint { id, .. } => *id,
+            NativeFunction::IRead { id, .. } => *id,
+            NativeFunction::SRead { id, .. } => *id,
+            NativeFunction::NL { id, .. } => *id,
+            NativeFunction::Random { id, .. } => *id,
+            NativeFunction::Timer { id, .. } => *id,
+            NativeFunction::StopTimer { id, .. } => *id,
+            NativeFunction::Alloc { id, .. } => *id,
+            NativeFunction::Free { id, .. } => *id,
+            NativeFunction::I2S { id, .. } => *id,
+            NativeFunction::Unknown(n) => *n,
+        }
+    }
 }
\ No newline at end of file
diff --git a/src/stack.rs b/src/stack.rs
index e3217f0..684c256 100644
--- a/src/stack.rs
+++ b/src/stack.rs
@@ -23,11 +23,13 @@ impl StackHolder for Tvm {
     }
 
     fn pop(&mut self) -> i32 {
+        println!("Popping from stack");
         self.stack_pointer += 1;
         self.memory[self.stack_pointer]
     }
 
     fn push(&mut self, value: i32) {
+        println!("Pushing {} to stack", value);
         self.memory[self.stack_pointer] = value;
         self.stack_pointer -= 1;
     }
diff --git a/src/state.rs b/src/state.rs
index 5bd6d54..5e07364 100644
--- a/src/state.rs
+++ b/src/state.rs
@@ -1,4 +1,5 @@
 use std::fmt::Debug;
+use std::rc::Rc;
 use crate::callable::Callable;
 use crate::frame::Frame;
 use crate::tvm::Tvm;
@@ -12,6 +13,7 @@ pub enum StateResult {
     Return(i32),
     Break,
     Continue,
+    Exit,
 }
 
 #[derive(Debug, Clone, PartialEq, Eq)]
@@ -19,7 +21,7 @@ pub enum TvmState {
     Waiting,
     Paused,
     Call(Callable),
-    Eval(Frame, usize),
+    Eval(Frame),
     FrameEval(Frame),
     Halted,
 }
@@ -30,7 +32,7 @@ impl TvmState {
             TvmState::Waiting => Box::new(states::Waiting),
             TvmState::Paused => Box::new(states::Paused),
             TvmState::Call(callable) => Box::new(states::Call { callable: callable.clone() }),
-            TvmState::Eval(frame, pc) => Box::new(states::Eval { frame: frame.clone(), pc: *pc }),
+            TvmState::Eval(frame) => Box::new(states::Eval { frame: frame.clone(), pc: 0 }),
             TvmState::FrameEval(frame) => Box::new(states::FrameEval { frame: frame.clone() }),
             TvmState::Halted => Box::new(states::Halted),
         }
@@ -49,7 +51,7 @@ impl TvmState {
     }
 
     pub fn is_eval(&self) -> bool {
-        matches!(self, TvmState::Eval(_, _))
+        matches!(self, TvmState::Eval(_))
     }
 
     pub fn is_frame_eval(&self) -> bool {
@@ -73,6 +75,25 @@ pub trait Stateful : Debug {
     fn get_last_result(&self) -> Option<StateResult>;
     fn is_paused(&self) -> bool;
     fn handle_result(&mut self, result: StateResult);
+
+    fn call(&mut self, callable: Callable) {
+        self.set_state(TvmState::Call(callable));
+    }
+
+    fn eval(&mut self, frame: Frame) {
+        self.set_state(TvmState::Eval(frame));
+    }
+
+    fn frame_eval(&mut self, frame: Frame) {
+        self.set_state(TvmState::FrameEval(frame));
+    }
+
+    fn should_continue(&self) -> bool {
+        !self.get_state().is_halted()
+            || matches!(self.get_last_result(), Some(StateResult::Exit))
+            || matches!(self.get_last_result(), Some(StateResult::Break))
+            || matches!(self.get_last_result(), Some(StateResult::Return(_)))
+    }
 }
 
 impl Stateful for Tvm {
@@ -81,6 +102,7 @@ impl Stateful for Tvm {
     }
 
     fn set_state(&mut self, state: TvmState) {
+        println!("Setting state to: {:?}", state);
         self.previous_state = Some(self.state.clone());
         self.state = state;
     }
@@ -110,15 +132,23 @@ impl Stateful for Tvm {
     }
 
     fn tick(&mut self) {
+        // Do nothing if the tvm is paused
+        if !self.is_paused() {
+            self.increment_ticks();
+            self.state.to_state().tick(self);
+            let result = self.get_last_result();
+            self.handle_result(result.unwrap());
+        }
 
+        println!("Tvm state: {:?}", self.state);
     }
 
     fn get_last_result(&self) -> Option<StateResult> {
-        todo!()
+        self.last_result.clone()
     }
 
     fn is_paused(&self) -> bool {
-        self.state == TvmState::Paused
+        matches!(self.state, TvmState::Paused)
     }
 
     fn handle_result(&mut self, result: StateResult) {
@@ -127,6 +157,10 @@ impl Stateful for Tvm {
 }
 
 pub mod states {
+    use crate::callable::Caller;
+    use crate::frame::FrameEvaluator;
+    use crate::instruction::Evaluator;
+    use crate::state::StateResult::{Continue, Exit};
     use super::*;
 
     #[derive(Debug, Clone)]
@@ -152,40 +186,46 @@ pub mod states {
     impl State for Waiting {
         // Tick should do nothing.
         fn tick(&mut self, tvm: &mut Tvm) -> StateResult {
-            StateResult::Continue
+            Continue
         }
     }
 
     impl State for Paused {
         // Tick should do nothing.
         fn tick(&mut self, tvm: &mut Tvm) -> StateResult {
-            StateResult::Continue
+            Continue
         }
     }
 
     impl State for Call {
         fn tick(&mut self, tvm: &mut Tvm) -> StateResult {
-            unimplemented!()
+            tvm.do_call(self.callable.clone());
+            Continue
         }
     }
 
     impl State for Eval {
         fn tick(&mut self, tvm: &mut Tvm) -> StateResult {
-            unimplemented!()
+            if tvm.should_continue() {
+                tvm.do_eval(&mut self.frame);
+                self.pc = self.frame.pc;
+            }
+            Exit
         }
     }
 
     impl State for FrameEval {
-
         fn tick(&mut self, tvm: &mut Tvm) -> StateResult {
-            unimplemented!()
+            if tvm.should_continue() {
+                tvm.do_frame_eval(&self.frame);
+            }
+            Exit
         }
     }
 
     impl State for Halted {
-
         fn tick(&mut self, tvm: &mut Tvm) -> StateResult {
-            unimplemented!()
+            Continue
         }
     }
 }
diff --git a/src/tvm.rs b/src/tvm.rs
index e670e38..e025a81 100644
--- a/src/tvm.rs
+++ b/src/tvm.rs
@@ -1,5 +1,7 @@
 use crate::frame::Frame;
-use crate::state::{StateResult, TvmState};
+use crate::instruction::Instruction;
+use crate::state::{Stateful, StateResult, TvmState};
+use crate::state::StateResult::Continue;
 
 #[derive(Debug, Clone)]
 pub struct Tvm {
@@ -23,19 +25,33 @@ impl Default for Tvm {
             state: TvmState::Waiting,
             ticks: 0,
             previous_state: None,
-            last_result: None,
+            last_result: Some(Continue),
         }
     }
 }
 
 impl Tvm {
-    pub fn frame_eval(&mut self, frame: Frame) {
-        self.state = TvmState::FrameEval(frame);
+
+    pub fn start(&mut self) {
+        let builder = Frame::builder();
+        let frame = builder
+            .id(0)
+            .name("main".to_string())
+            .instruction(Instruction::get_instruction(1), vec![])
+            .primitive(0)
+            .callable(-101, vec![])
+            .instruction(Instruction::get_instruction(8), vec![])
+            .primitive(-109)
+            .primitive(10)
+            .build();
+
+        self.frame_eval(frame);
     }
 }
 
 #[cfg(test)]
 mod test {
+    use crate::state::Stateful;
     use super::*;
 
     #[test]
@@ -49,4 +65,23 @@ mod test {
         assert_eq!(tvm.ticks, 0);
         assert_eq!(tvm.previous_state, None);
     }
+
+    #[test]
+    fn test_tick_count() {
+        let mut tvm = Tvm::default();
+        tvm.tick();
+        tvm.tick();
+        tvm.tick();
+        tvm.tick();
+        tvm.tick();
+        tvm.tick();
+        tvm.tick();
+        tvm.tick();
+        tvm.tick();
+        tvm.tick();
+        tvm.tick();
+        tvm.tick();
+
+        assert_eq!(tvm.ticks, 12);
+    }
 }
\ No newline at end of file
-- 
GitLab