From f0e4d42cd049ae2b427a26ee57c25ad5a32e1b01 Mon Sep 17 00:00:00 2001
From: MarvelousAnything <marvelousanything@gmail.com>
Date: Mon, 31 Oct 2022 21:01:19 -0400
Subject: [PATCH] Started Implementation
---
src/callable.rs | 27 +++
src/frame.rs | 18 ++
src/function.rs | 10 +
src/heap.rs | 65 ++++++
src/instruction.rs | 44 +++++
src/main.rs | 16 +-
src/native.rs | 6 +
src/program.rs | 0
src/stack.rs | 103 ++++++++++
src/state.rs | 64 ++++++
src/tvm.rs | 50 +++++
tvm.js | 478 +++++++++++++++++++++++++++++++++++++++++++++
12 files changed, 880 insertions(+), 1 deletion(-)
create mode 100644 src/callable.rs
create mode 100644 src/frame.rs
create mode 100644 src/function.rs
create mode 100644 src/heap.rs
create mode 100644 src/instruction.rs
create mode 100644 src/native.rs
create mode 100644 src/program.rs
create mode 100644 src/stack.rs
create mode 100644 src/state.rs
create mode 100644 src/tvm.rs
create mode 100644 tvm.js
diff --git a/src/callable.rs b/src/callable.rs
new file mode 100644
index 0000000..083d7eb
--- /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 0000000..686f8f2
--- /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 0000000..1b31fba
--- /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 0000000..3881f37
--- /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 0000000..f343b05
--- /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 e7a11a9..8c18c67 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 0000000..2a3aea5
--- /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 0000000..e69de29
diff --git a/src/stack.rs b/src/stack.rs
new file mode 100644
index 0000000..e3217f0
--- /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 0000000..fded70a
--- /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 0000000..8f1e08e
--- /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 0000000..7f511f5
--- /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
--
GitLab