diff --git a/src/callable.rs b/src/callable.rs
new file mode 100644
index 0000000000000000000000000000000000000000..083d7eb550179b684fd49ae4c89f1d63fc9d86a1
--- /dev/null
+++ b/src/callable.rs
@@ -0,0 +1,27 @@
+use std::fmt::Debug;
+use crate::function::Function;
+use crate::native::NativeFunction;
+use crate::tvm::Tvm;
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum Callable {
+    Function(Function),
+    NativeFunction(NativeFunction),
+}
+
+pub trait Caller: Debug + Clone {
+    fn call(callable: Callable);
+}
+
+impl Caller for Tvm {
+    fn call(callable: Callable) {
+        match callable {
+            Callable::Function(function) => {
+                println!("Calling function: {:?}", function);
+            },
+            Callable::NativeFunction(native_function) => {
+                println!("Calling native function: {:?}", native_function);
+            },
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/frame.rs b/src/frame.rs
new file mode 100644
index 0000000000000000000000000000000000000000..686f8f2adcb112caf85b0dc2728e2f537f5acb8d
--- /dev/null
+++ b/src/frame.rs
@@ -0,0 +1,18 @@
+use crate::callable::Callable;
+use crate::instruction::Instruction;
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct Frame {
+    pub id: usize,
+    pub name: String,
+    pub data: Vec<FrameData>,
+    pub pc: usize,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum FrameData {
+    Frame(Frame),
+    Callable(Callable, Vec<i32>), // TODO: Maybe this should be a reference to the callable id?
+    Instruction(Instruction, Vec<i32>),
+    Primitive(i32),
+}
\ No newline at end of file
diff --git a/src/function.rs b/src/function.rs
new file mode 100644
index 0000000000000000000000000000000000000000..1b31fbadba209d501193d5563e631e0f8a478c86
--- /dev/null
+++ b/src/function.rs
@@ -0,0 +1,10 @@
+use crate::frame::Frame;
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct Function {
+    pub id: usize,
+    pub name: String,
+    pub args: usize,
+    pub locals: usize,
+    pub frame: Frame,
+}
\ No newline at end of file
diff --git a/src/heap.rs b/src/heap.rs
new file mode 100644
index 0000000000000000000000000000000000000000..3881f37c92fbd86996a8827ef5a33a552d89063f
--- /dev/null
+++ b/src/heap.rs
@@ -0,0 +1,65 @@
+use crate::tvm::Tvm;
+
+trait HeapHolder {
+    fn get_heap(&self) -> &[i32];
+    fn get_heap_size(&self) -> usize;
+    fn allocate(&mut self, size: usize) -> usize;
+    fn deallocate(&mut self, address: usize);
+}
+
+impl HeapHolder for Tvm {
+    fn get_heap(&self) -> &[i32] {
+        &self.memory[..self.heap_size]
+    }
+
+    fn get_heap_size(&self) -> usize {
+        self.heap_size
+    }
+
+    fn allocate(&mut self, size: usize) -> usize {
+        let address = self.heap_size;
+        self.heap_size += size;
+        address
+    }
+
+    fn deallocate(&mut self, address: usize) {
+        self.heap_size = address;
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+
+    #[test]
+    fn test_get_heap() {
+        let mut tvm = Tvm::default();
+        tvm.allocate(3);
+        assert_eq!(tvm.get_heap(), &[0, 0, 0]);
+    }
+
+    #[test]
+    fn test_get_heap_size() {
+        let mut tvm = Tvm::default();
+        tvm.allocate(3);
+        assert_eq!(tvm.get_heap_size(), 3);
+    }
+
+    #[test]
+    fn test_allocate() {
+        let mut tvm = Tvm::default();
+        let address = tvm.allocate(3);
+        assert_eq!(address, 0);
+        assert_eq!(tvm.get_heap(), &[0, 0, 0]);
+    }
+
+    #[test]
+    fn test_deallocate() {
+        let mut tvm = Tvm::default();
+        let address = tvm.allocate(3);
+        assert_eq!(address, 0);
+        assert_eq!(tvm.get_heap(), &[0, 0, 0]);
+        tvm.deallocate(address);
+        assert_eq!(tvm.get_heap(), &[]);
+    }
+}
\ No newline at end of file
diff --git a/src/instruction.rs b/src/instruction.rs
new file mode 100644
index 0000000000000000000000000000000000000000..f343b05086c9f64e7af90bdcc453003f8ad12be9
--- /dev/null
+++ b/src/instruction.rs
@@ -0,0 +1,44 @@
+use std::fmt::Debug;
+use crate::tvm::Tvm;
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum Instruction {
+    Push { op: u32, name: String, num_operands: u32 },
+    Fetch { op: u32, name: String, num_operands: u32 },
+    Store { op: u32, name: String, num_operands: u32 },
+    IF { op: u32, name: String, num_operands: u32 },
+    Loop { op: u32, name: String, num_operands: u32 },
+    Break { op: u32, name: String, num_operands: u32 },
+    Return { op: u32, name: String, num_operands: u32 },
+    Call { op: u32, name: String, num_operands: u32 },
+    FPPlus { op: u32, name: String, num_operands: u32 },
+    Add { op: u32, name: String, num_operands: u32 },
+    Sub { op: u32, name: String, num_operands: u32 },
+    Mul { op: u32, name: String, num_operands: u32 },
+    Div { op: u32, name: String, num_operands: u32 },
+    Mod { op: u32, name: String, num_operands: u32 },
+    Not { op: u32, name: String, num_operands: u32 },
+    And { op: u32, name: String, num_operands: u32 },
+    OR { op: u32, name: String, num_operands: u32 },
+    Xor { op: u32, name: String, num_operands: u32 },
+    EQ { op: u32, name: String, num_operands: u32 },
+    Neq { op: u32, name: String, num_operands: u32 },
+    LT { op: u32, name: String, num_operands: u32 },
+    Leq { op: u32, name: String, num_operands: u32 },
+    GT { op: u32, name: String, num_operands: u32 },
+    Geq { op: u32, name: String, num_operands: u32 },
+    Pop { op: u32, name: String, num_operands: u32 },
+    LShift { op: u32, name: String, num_operands: u32 },
+    RShift { op: u32, name: String, num_operands: u32 },
+    Unknown(u32),
+}
+
+pub trait Evaluator: Debug + Clone {
+    fn eval(&mut self, instruction: Instruction);
+}
+
+impl Evaluator for Tvm {
+    fn eval(&mut self, instruction: Instruction) {
+        println!("Evaluating instruction: {:?}", instruction);
+    }
+}
\ No newline at end of file
diff --git a/src/main.rs b/src/main.rs
index e7a11a969c037e00a796aafeff6258501ec15e9a..8c18c67bc18ad499efae52db7d0946eeee3994c4 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,3 +1,17 @@
+use crate::tvm::Tvm;
+
+mod tvm;
+mod state;
+mod stack;
+mod program;
+mod heap;
+mod callable;
+mod frame;
+mod native;
+mod function;
+mod instruction;
+
 fn main() {
-    println!("Hello, world!");
+    let tvm = Tvm::default();
+    println!("{:?}", tvm);
 }
diff --git a/src/native.rs b/src/native.rs
new file mode 100644
index 0000000000000000000000000000000000000000..2a3aea551df2cf7ab5d158abffd77d94c0506ff7
--- /dev/null
+++ b/src/native.rs
@@ -0,0 +1,6 @@
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct NativeFunction {
+    pub id: i32,
+    pub name: String,
+    pub args: usize,
+}
\ No newline at end of file
diff --git a/src/program.rs b/src/program.rs
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/stack.rs b/src/stack.rs
new file mode 100644
index 0000000000000000000000000000000000000000..e3217f09a3179d8414fc65936ce0063fe02161bf
--- /dev/null
+++ b/src/stack.rs
@@ -0,0 +1,103 @@
+use crate::tvm::Tvm;
+
+pub trait StackHolder {
+    fn get_stack(&self) -> &[i32];
+    fn get_stack_size(&self) -> usize;
+    fn get_stack_pointer(&self) -> usize;
+    fn pop(&mut self) -> i32;
+    fn push(&mut self, value: i32);
+    fn peek(&self) -> i32;
+}
+
+impl StackHolder for Tvm {
+    fn get_stack(&self) -> &[i32] {
+        &self.memory[self.stack_pointer..][1..]
+    }
+
+    fn get_stack_size(&self) -> usize {
+        self.memory.len() - (self.stack_pointer + 1)
+    }
+
+    fn get_stack_pointer(&self) -> usize {
+        self.stack_pointer
+    }
+
+    fn pop(&mut self) -> i32 {
+        self.stack_pointer += 1;
+        self.memory[self.stack_pointer]
+    }
+
+    fn push(&mut self, value: i32) {
+        self.memory[self.stack_pointer] = value;
+        self.stack_pointer -= 1;
+    }
+
+    fn peek(&self) -> i32 {
+        self.memory[self.stack_pointer + 1]
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+
+    #[test]
+    fn test_get_stack() {
+        let mut tvm = Tvm::default();
+        tvm.push(1);
+        tvm.push(2);
+        tvm.push(3);
+        assert_eq!(tvm.get_stack(), &[3, 2, 1]);
+    }
+
+    #[test]
+    fn test_get_stack_size() {
+        let mut tvm = Tvm::default();
+        tvm.push(1);
+        tvm.push(2);
+        tvm.push(3);
+        assert_eq!(tvm.get_stack_size(), 3);
+    }
+
+    #[test]
+    fn test_get_stack_pointer() {
+        let mut tvm = Tvm::default();
+        tvm.push(1);
+        tvm.push(2);
+        tvm.push(3);
+        // 65535 - 3 = 65532
+        assert_eq!(tvm.get_stack_pointer(), 65532);
+    }
+
+    #[test]
+    fn test_pop() {
+        let mut tvm = Tvm::default();
+        tvm.push(1);
+        tvm.push(2);
+        tvm.push(3);
+        assert_eq!(tvm.pop(), 3);
+        assert_eq!(tvm.pop(), 2);
+        assert_eq!(tvm.pop(), 1);
+    }
+
+    #[test]
+    fn test_push() {
+        let mut tvm = Tvm::default();
+        tvm.push(1);
+        tvm.push(2);
+        tvm.push(3);
+        assert_eq!(tvm.get_stack(), &[3, 2, 1]);
+    }
+
+    #[test]
+    fn test_peek() {
+        let mut tvm = Tvm::default();
+        tvm.push(1);
+        tvm.push(2);
+        tvm.push(3);
+        let sp = tvm.get_stack_pointer();
+        assert_eq!(tvm.peek(), 3, "peek() should return the top of the stack");
+        assert_eq!(tvm.peek(), tvm.peek(), "peek() should be equal to itself");
+        assert_eq!(tvm.get_stack_pointer(), sp, "stack pointer should not change"); // stack pointer should not change
+    }
+}
\ No newline at end of file
diff --git a/src/state.rs b/src/state.rs
new file mode 100644
index 0000000000000000000000000000000000000000..fded70a6901a76ed8a4237dcf25a1d276b1afb2a
--- /dev/null
+++ b/src/state.rs
@@ -0,0 +1,64 @@
+use std::fmt::Debug;
+use crate::callable::Callable;
+use crate::frame::Frame;
+use crate::tvm::Tvm;
+
+pub trait State : Debug + Clone {
+    fn pause(&mut self);
+    fn resume(&mut self);
+    fn tick(&mut self) -> StateResult;
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum StateResult {
+    Return(i32),
+    Break,
+    Continue,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum TvmState {
+    Waiting,
+    Paused,
+    Call(Callable),
+    Eval(Frame, usize),
+    FrameEval(Frame),
+    Halted,
+}
+
+pub trait Stateful : Debug {
+    fn get_state(&self) -> TvmState;
+    fn set_state(&mut self, state: TvmState);
+    fn get_ticks(&self) -> usize;
+    fn increment_ticks(&mut self);
+    fn previous_state(&self) -> Option<TvmState>;
+    fn is_paused(&self) -> bool;
+}
+
+impl Stateful for Tvm {
+    fn get_state(&self) -> TvmState {
+        self.state.clone()
+    }
+
+    fn set_state(&mut self, state: TvmState) {
+        self.previous_state = Some(self.state.clone());
+        self.state = state;
+    }
+
+    fn get_ticks(&self) -> usize {
+        self.ticks
+    }
+
+    fn increment_ticks(&mut self) {
+        self.ticks += 1;
+    }
+
+    fn previous_state(&self) -> Option<TvmState> {
+        self.previous_state.clone()
+    }
+
+    fn is_paused(&self) -> bool {
+        self.state == TvmState::Paused
+    }
+}
+
diff --git a/src/tvm.rs b/src/tvm.rs
new file mode 100644
index 0000000000000000000000000000000000000000..8f1e08e2184bd8d420109b98d64bfe7d0cea2899
--- /dev/null
+++ b/src/tvm.rs
@@ -0,0 +1,50 @@
+use crate::frame::Frame;
+use crate::state::{TvmState};
+
+#[derive(Debug, Clone)]
+pub struct Tvm {
+    pub memory: [i32; 65536],
+    pub stack_pointer: usize,
+    pub frame_pointer: usize,
+    pub heap_size: usize,
+    pub state: TvmState,
+    pub ticks: usize,
+    pub previous_state: Option<TvmState>,
+}
+
+impl Default for Tvm {
+    fn default() -> Self {
+        Tvm {
+            memory: [0; 65536],
+            stack_pointer: 65535,
+            frame_pointer: 65535,
+            heap_size: 0,
+            state: TvmState::Waiting,
+            ticks: 0,
+            previous_state: None,
+        }
+    }
+}
+
+impl Tvm {
+    pub fn frame_eval(&mut self, frame: Frame) {
+        self.state = TvmState::FrameEval(frame);
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+
+    #[test]
+    fn test_default() {
+        let tvm = Tvm::default();
+        assert_eq!(tvm.memory.len(), 65536);
+        assert_eq!(tvm.stack_pointer, 65535);
+        assert_eq!(tvm.frame_pointer, 65535);
+        assert_eq!(tvm.heap_size, 0);
+        assert_eq!(tvm.state, TvmState::Waiting);
+        assert_eq!(tvm.ticks, 0);
+        assert_eq!(tvm.previous_state, None);
+    }
+}
\ No newline at end of file
diff --git a/tvm.js b/tvm.js
new file mode 100644
index 0000000000000000000000000000000000000000..7f511f5c327ace29655dd181e86a5e374a7219c2
--- /dev/null
+++ b/tvm.js
@@ -0,0 +1,478 @@
+var mem=[]
+mem.length = 65536
+var sp
+var fp
+var hwin
+var imgnum, butnum, labnum, tabnum
+var edata
+
+startvm()
+
+function push(x) {
+    mem[sp] = x
+    sp--
+}
+
+function pop(x) {
+    sp++
+    return mem[sp]
+}
+
+function a2s(x) {
+    s = ""
+    while(mem[x] != 0) {
+        s += String.fromCharCode(mem[x])
+        x++
+    }
+    return s
+}
+
+function leval(l) {
+    pc = 0
+    while(pc >= 0) {
+        pc = eval(l, pc)
+    }
+    return pc
+}
+
+function call(n) {
+    // Convert the old numbering to the new
+    if(n > -100) {
+        switch(n) {
+            case -1: n = -101; break;
+            case -2: n = -102; break;
+            // case -3: n = -103: break;
+            // case -4: n = -104; break;
+            case -5: n = -105; break;
+            case -10: n = -106; break;
+            case -11: n = -107; break;
+            case -12: n = -108; break;
+            case -13: n = -201; break;
+            case -14: n = -202; break;
+            case -15: n = -203; break;
+            case -16: n = -204; break;
+            case -17: n = -205; break;
+            case -18: n = -206; break;
+            case -19: n = -109; break;
+            case -20: n = -110; break;
+            case -21: n = -111; break;
+            case -22: n = -207; break;
+            case -23: n = -208; break;
+            case -24: n = -209; break;
+            case -25: n = -103; break;
+            case -26: n = -104; break;
+            case -27: n = -210; break;
+        }
+    }
+    if(n < -200 && hwin == null) {
+        hwin = window.open()
+    }
+    switch(n) {
+        case -101:	/* iprint */
+            x = pop()
+            stdout.value += x
+            push(0)
+            break
+        case -102:	/* sprint */
+            x = pop()
+            s = a2s(x)
+            stdout.value += s
+            push(0)
+            break
+        case -103:	/* iread */
+            p = pop()
+            if(p == 0-1) {
+                x = window.prompt("Integer input:")
+            }
+            else {
+                s = a2s(p)
+                x = window.prompt(s)
+            }
+            push(parseInt(x, 10))
+            break
+        case -104:	/* sread */
+            a = pop()
+            p = pop()
+            if(p == -1) {
+                x = window.prompt("String input:")
+            }
+            else {
+                s = a2s(p)
+                x = window.prompt(s)
+            }
+            for(i = 0; i < x.length; i++)
+                mem[a+i] = x.charCodeAt(i)
+            mem[a+i] = 0
+            push(0)
+            break
+        case -105:	/* nl */
+            stdout.value += "\n"
+            push(0)
+            break
+        case -106:	/* random */
+            n = pop()
+            n = Math.floor(Math.random() * n)
+            push(n)
+            break
+        case -107:	/* timer */
+            var f
+            to = pop()
+            f = pop()
+            n = setTimeout(function(){call(f); pop();}, to)
+            push(n)
+            break
+        case -108:	/* stoptimer */
+            n = pop()
+            clearTimeout(n)
+            push(0)
+            break
+        case -201:	/* makeimg */
+            hwin.document.write('<img id=img' + imgnum + ' />\n')
+            push(imgnum)
+            imgnum++
+            break
+        case -202:	/* setimg */
+            n = pop()
+            src = pop()
+            s = a2s(src)
+            i = hwin.document.getElementById('img'+n)
+            i.src = s
+            push(0)
+            break
+        case -203:	/* button */
+            butname = pop()
+            n = pop()
+            s = a2s(butname)
+            t1 = '<button id=but' + butnum + ' onclick="window.opener.call(' + n + ');window.opener.pop()">'
+            hwin.document.write(t1 + s + '</button>\n')
+            push(butnum)
+            butnum++
+            break
+        case -204:	/* html */
+            x = pop()
+            s = a2s(x)
+            hwin.document.write(s)
+            push(0)
+            break
+        case -205: /* makelabel */
+            labtxt = pop()
+            s = a2s(labtxt)
+            hwin.document.write('<label id=lab' + labnum + '>' + s + '</label>\n')
+            push(labnum)
+            labnum++
+            break
+        case -206:	/* setlabel */
+            n = pop()
+            label = pop()
+            s = a2s(label)
+            l = hwin.document.getElementById('lab'+n)
+            l.innerHTML = s
+            push(0)
+            break
+        case -109:	/* alloc */
+            n = pop()
+            push(edata)
+            edata += n
+            break
+        case -110:	/* free */
+            a = pop()
+            push(0)
+            break
+        case -111:	/* i2s */
+            s = pop()
+            n = pop()
+            istr = n.toString(10)
+            for(i = 0; i < istr.length; i++)
+                mem[s + i] = istr.charCodeAt(i)
+            mem[s+i] = 0
+            push(istr.length)
+            break
+        case -207:	/* maketable */
+            r = pop()
+            c = pop()
+            f = pop()
+            hwin.document.write('<table id=tab' + tabnum + '>\n')
+            for(i = 0; i < r; i++) {
+                hwin.document.write('<tr>\n')
+                for(j = 0; j < c; j++) {
+                    hwin.document.write('<td onclick="window.opener.cellclick(' + tabnum + ',' + i + ',' + j + ',' + f + ')"></td>\n')
+                }
+                hwin.document.write('</tr>\n')
+            }
+            hwin.document.write('</table>\n')
+            push(tabnum)
+            tabnum++
+            break
+        case -208:	/* setcell */
+            tnum = pop()
+            r = pop()
+            c = pop()
+            cval = pop()
+            s = a2s(cval)
+            t = hwin.document.getElementById('tab' + tnum)
+            t.rows[r].cells[c].innerHTML = s
+            push(0)
+            break
+        case -209:	/* setcellcolor */
+            tnum = pop()
+            r = pop()
+            c = pop()
+            cval = pop()
+            s = a2s(cval)
+            t = hwin.document.getElementById('tab' + tnum)
+            t.rows[r].cells[c].style = "background-color:" + s
+            push(0)
+            break
+        case -210:	/* buttonlabel */
+            bnum = pop()
+            nlab = pop()
+            s = a2s(nlab)
+            b = hwin.document.getElementById('but' + bnum)
+            b.innerHTML=s
+            push(0)
+            break
+        case -3:	/* old iread */
+            x = window.prompt("Integer input:")
+            push(parseInt(x, 10))
+            break
+        case -4:	/* old sread */
+            a = pop()
+            x = window.prompt("String input:")
+            for(i = 0; i < x.length; i++)
+                mem[a+i] = x.charCodeAt(i)
+            mem[a+i] = 0
+            push(0)
+            break
+        default:
+            if(n < 0) {
+                console.log("Invalid function call", n)
+                return
+            }
+            for(i = 0; i < m[n+2][3]; i++)
+                push(0)
+            mem[sp] = fp
+            fp = sp
+            sp--
+            leval(m[n+2][4])
+            r = pop()
+            sp = fp
+            fp = mem[sp]
+            sp += m[n+2][2] + m[n+2][3]
+            push(r)
+            break
+    }
+}
+
+function cellclick(t, r, c, f) {
+    push(c)
+    push(r)
+    for(i = 0; i < m[f+2][3]; i++)
+        push(0)
+    mem[sp] = fp
+    fp = sp
+    sp--
+    leval(m[f+2][4])
+    r = pop()
+    sp = fp
+    fp = mem[sp]
+    sp += m[f+2][2] + m[f+2][3]
+//	push(r)
+}
+
+function eval(l, pc) {
+    if(pc >= l.length) {
+        return -1
+    }
+    ir = l[pc]
+    pc++
+    switch(ir) {
+        case 1:	/* push */
+            push(l[pc])
+            pc++
+            break
+        case 2:	/* fetch */
+            a = pop()
+            push(mem[a])
+            break
+        case 3:	/* store */
+            v = pop()
+            a = pop()
+            mem[a] = v
+            break
+        case 4:	/* if */
+            x = pop()
+            if(x != 0) {
+                r = leval(l[pc])
+                pc += 2
+            }
+            else {
+                pc++
+                r = leval(l[pc])
+                pc++
+            }
+            if(r <= -2)
+                return r
+            break
+        case 5:	/* loop */
+            while(1) {
+                r = leval(l[pc])
+                if(r == -2)
+                    break // does not exit the 
+                else if(r == -3)
+                    return -3
+            }
+            pc++
+            break
+        case 6:	/* break */
+            x = pop()
+            if(x != 0)
+                return -2
+            break
+        case 7:	/* return */
+            return -3
+            break
+        case 8:	/* call */
+            call(l[pc])
+            pc++
+            break
+        case 9:	/* fpplus */
+            a = pop()
+            a += fp
+            push(a)
+            break
+        case 10:	/* add */
+            y = pop()
+            x = pop()
+            push(x+y)
+            break
+        case 11:	/* sub */
+            y = pop()
+            x = pop()
+            push(x-y)
+            break
+        case 12:	/* mul */
+            y = pop()
+            x = pop()
+            push(x*y)
+            break
+        case 13:	/* div */
+            y = pop()
+            x = pop()
+            push(Math.floor(x/y))
+            break
+        case 14:	/* mod */
+            y = pop()
+            x = pop()
+            push(x%y)
+            break
+        case 15:	/* not */
+            x = pop()
+            push(~x)
+            break
+        case 16:	/* and */
+            y = pop()
+            x = pop()
+            push(x&y)
+            break
+        case 17:	/* or */
+            y = pop()
+            x = pop()
+            push(x|y)
+            break
+        case 18:	/* xor */
+            y = pop()
+            x = pop()
+            push(x^y)
+            break
+        case 19:	/* eq */
+            y = pop()
+            x = pop()
+            if(x == y)
+                push(1)
+            else
+                push(0)
+            break
+        case 20:	/* neq */
+            y = pop()
+            x = pop()
+            if(x != y)
+                push(1)
+            else
+                push(0)
+            break
+        case 21:	/* lt */
+            y = pop()
+            x = pop()
+            if(x < y)
+                push(1)
+            else
+                push(0)
+            break
+        case 22:	/* leq */
+            y = pop()
+            x = pop()
+            if(x <= y)
+                push(1)
+            else
+                push(0)
+            break
+        case 23:	/* gt */
+            y = pop()
+            x = pop()
+            if(x > y)
+                push(1)
+            else
+                push(0)
+            break
+        case 24:	/* geq */
+            y = pop()
+            x = pop()
+            if(x >= y)
+                push(1)
+            else
+                push(0)
+            break
+        case 25:	/* pop */
+            pop()
+            break
+        case 26:	/* lshift */
+            s = pop()
+            x = pop()
+            push(x << s)
+            break
+        case 27:	/* rshift */
+            s = pop()
+            x = pop()
+            push(x >> s)
+            break
+        default:
+            console.log("unknown opcode ", ir)
+            break
+    }
+    return pc
+}
+
+function start() {
+    edata = m[0][1]
+    call(m[0][0])
+    console.log("halt")
+}
+
+function startvm() {
+    hwin = null
+    imgnum = 0
+    butnum = 0
+    labnum = 0
+    tabnum = 0
+    document.write("<html>\n<body>\n")
+    document.write('<button onclick="start();">Start</button><br>\n')
+    document.write("<label>Standard Output</label><br>\n")
+    document.write('<textarea id="stdout" cols="80" rows="20"></textarea><br>\n')
+    document.write("</body>\n</html>\n")
+    m = JSON.parse(tape)
+    sp = 65535
+    fp = 65535
+    for(n = 0; n < m[1].length; n++) {
+        mem[m[1][n][0]] = m[1][n][1]
+    }
+}
\ No newline at end of file