summary refs log tree commit diff
path: root/src/interpreter.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/interpreter.rs')
-rw-r--r--src/interpreter.rs425
1 files changed, 37 insertions, 388 deletions
diff --git a/src/interpreter.rs b/src/interpreter.rs
index b93b05f..9f226ae 100644
--- a/src/interpreter.rs
+++ b/src/interpreter.rs
@@ -1,6 +1,6 @@
 use core::panic;
 
-use crate::{glk::Glk, instructions::{Instruction, Operand}};
+use crate::{glk::Glk, instructions::{Instruction, Operand}, opcodes::OpCode};
 
 pub type MemAddress = u32;
 pub type StackAddress = u32;
@@ -33,7 +33,7 @@ pub struct HeapChunk {
 pub enum Output {
     Null,
     Filter(FunctionPointer),
-    Glk(Glk),
+    Glk(Glk, u32),
 }
 
 pub struct Interpreter {
@@ -49,6 +49,7 @@ pub struct Interpreter {
     pub reg_strdec: MemAddress,
 
     pub output_mode: Output,
+    tmp_dest_oper: Option<Operand>,
 }
 
 impl Interpreter {
@@ -81,6 +82,7 @@ impl Interpreter {
             reg_strdec: str_decode,
 
             output_mode: Output::Null,
+            tmp_dest_oper: None,
         }
     }
 
@@ -90,406 +92,53 @@ impl Interpreter {
         loop {
             let pc = self.reg_program as usize;
             let mut instruction_slice = &self.memory[pc..pc+100];
-            let (instruction, bytes_read) = Instruction::read(&mut instruction_slice);
+            let instruction_read = Instruction::read(&mut instruction_slice);
+            if let Err(unknown_opcode) = instruction_read {
+                panic!("Unknown opcode 0x{unknown_opcode:03x} at 0x{pc:08x}")
+            }
+            let (instruction, bytes_read) = instruction_read.unwrap();
             self.reg_program += bytes_read;
 
             println!("Executing instruction {instruction:?}");
 
-            match instruction.operation {
-                crate::instructions::OpCode::Nop => (),
-                crate::instructions::OpCode::Add => {
-                    let op1 = self.eval_source_operand(&instruction.operands[0]);
-                    let op2 = self.eval_source_operand(&instruction.operands[1]);
-
-                    self.store_dest_operand(&instruction.operands[2], op1 + op2);
-                },
-                crate::instructions::OpCode::Sub => {
-                    let op1 = self.eval_source_operand(&instruction.operands[0]);
-                    let op2 = self.eval_source_operand(&instruction.operands[1]);
-
-                    self.store_dest_operand(&instruction.operands[2], op1 - op2);
-                },
-                crate::instructions::OpCode::Mul => {
-                    let op1 = self.eval_source_operand(&instruction.operands[0]);
-                    let op2 = self.eval_source_operand(&instruction.operands[1]);
-
-                    self.store_dest_operand(&instruction.operands[2], op1 * op2);
-                },
-                crate::instructions::OpCode::Div => {
-                    let op1 = self.eval_source_operand(&instruction.operands[0]) as i32;
-                    let op2 = self.eval_source_operand(&instruction.operands[1]) as i32;
-                    let result = (op1 / op2) as u32;
-
-                    self.store_dest_operand(&instruction.operands[2], result);
-                },
-                crate::instructions::OpCode::Mod => {
-                    let op1 = self.eval_source_operand(&instruction.operands[0]) as i32;
-                    let op2 = self.eval_source_operand(&instruction.operands[1]) as i32;
-                    let result = (op1 % op2) as u32;
-
-                    self.store_dest_operand(&instruction.operands[2], result);
-                },
-                crate::instructions::OpCode::Neg => {
-                    let op1 = self.eval_source_operand(&instruction.operands[0]) as i32;
-                    let result = (-op1) as u32;
-
-                    self.store_dest_operand(&instruction.operands[1], result);
-                },
-                crate::instructions::OpCode::Bitand => {
-                    let op1 = self.eval_source_operand(&instruction.operands[0]);
-                    let op2 = self.eval_source_operand(&instruction.operands[1]);
-
-                    self.store_dest_operand(&instruction.operands[2], op1 & op2);
-                },
-                crate::instructions::OpCode::Bitor => {
-                    let op1 = self.eval_source_operand(&instruction.operands[0]);
-                    let op2 = self.eval_source_operand(&instruction.operands[1]);
-
-                    self.store_dest_operand(&instruction.operands[2], op1 | op2);
-                },
-                crate::instructions::OpCode::Bitxor => {
-                    let op1 = self.eval_source_operand(&instruction.operands[0]);
-                    let op2 = self.eval_source_operand(&instruction.operands[1]);
-
-                    self.store_dest_operand(&instruction.operands[2], op1 ^ op2);
-                },
-                crate::instructions::OpCode::Bitnot => {
-                    let op1 = self.eval_source_operand(&instruction.operands[0]);
-
-                    self.store_dest_operand(&instruction.operands[1], !op1);
-                },
-                crate::instructions::OpCode::Shiftl => {
-                    let op1 = self.eval_source_operand(&instruction.operands[0]);
-                    let op2 = self.eval_source_operand(&instruction.operands[1]);
-
-                    self.store_dest_operand(&instruction.operands[2], op1 << op2);
-                },
-                crate::instructions::OpCode::Sshiftr => {
-                    let op1 = self.eval_source_operand(&instruction.operands[0]);
-                    let op2 = self.eval_source_operand(&instruction.operands[1]);
-
-                    self.store_dest_operand(&instruction.operands[2], op1 >> op2);
-                },
-                crate::instructions::OpCode::Ushiftr => {
-                    let op1 = self.eval_source_operand(&instruction.operands[0]);
-                    let op2 = self.eval_source_operand(&instruction.operands[1]);
-
-                    self.store_dest_operand(&instruction.operands[2], op1 >> op2);
-                },
-                crate::instructions::OpCode::Jump => {
-                    let op1 = self.eval_source_operand(&instruction.operands[0]);
-                    self.jump_with_offset(op1);
-                },
-                crate::instructions::OpCode::Jz => {
-                    let check = self.eval_source_operand(&instruction.operands[0]);
-                    let destination = self.eval_source_operand(&instruction.operands[1]);
-                    if check == 0 {
-                        self.jump_with_offset(destination);
-                    }
-                },
-                crate::instructions::OpCode::Jnz => {
-                    let check = self.eval_source_operand(&instruction.operands[0]);
-                    let destination = self.eval_source_operand(&instruction.operands[1]);
-                    if check != 0 {
-                        self.jump_with_offset(destination);
-                    }
-                },
-                crate::instructions::OpCode::Jeq => {
-                    let op1 = self.eval_source_operand(&instruction.operands[0]);
-                    let op2 = self.eval_source_operand(&instruction.operands[1]);
-                    let destination = self.eval_source_operand(&instruction.operands[2]);
-                    if op1 == op2 {
-                        self.jump_with_offset(destination);
-                    }
-                },
-                crate::instructions::OpCode::Jne => {
-                    let op1 = self.eval_source_operand(&instruction.operands[0]) as i32;
-                    let op2 = self.eval_source_operand(&instruction.operands[1]) as i32;
-                    let destination = self.eval_source_operand(&instruction.operands[2]);
-                    if op1 != op2 {
-                        self.jump_with_offset(destination);
-                    }
-                },
-                crate::instructions::OpCode::Jlt => {
-                    let op1 = self.eval_source_operand(&instruction.operands[0]) as i32;
-                    let op2 = self.eval_source_operand(&instruction.operands[1]) as i32;
-                    let destination = self.eval_source_operand(&instruction.operands[2]);
-                    if op1 < op2 {
-                        self.jump_with_offset(destination);
-                    }
-                },
-                crate::instructions::OpCode::Jge => {
-                    let op1 = self.eval_source_operand(&instruction.operands[0]) as i32;
-                    let op2 = self.eval_source_operand(&instruction.operands[1]) as i32;
-                    let destination = self.eval_source_operand(&instruction.operands[2]);
-                    if op1 >= op2 {
-                        self.jump_with_offset(destination);
-                    }
-                },
-                crate::instructions::OpCode::Jgt => {
-                    let op1 = self.eval_source_operand(&instruction.operands[0]) as i32;
-                    let op2 = self.eval_source_operand(&instruction.operands[1]) as i32;
-                    let destination = self.eval_source_operand(&instruction.operands[2]);
-                    if op1 > op2 {
-                        self.jump_with_offset(destination);
-                    }
-                },
-                crate::instructions::OpCode::Jle => {
-                    let op1 = self.eval_source_operand(&instruction.operands[0]);
-                    let op2 = self.eval_source_operand(&instruction.operands[1]);
-                    let destination = self.eval_source_operand(&instruction.operands[2]);
-                    if op1 <= op2 {
-                        self.jump_with_offset(destination);
-                    }
-                },
-                crate::instructions::OpCode::Jltu => {
-                    let op1 = self.eval_source_operand(&instruction.operands[0]);
-                    let op2 = self.eval_source_operand(&instruction.operands[1]);
-                    let destination = self.eval_source_operand(&instruction.operands[2]);
-                    if op1 < op2 {
-                        self.jump_with_offset(destination);
-                    }
-                },
-                crate::instructions::OpCode::Jgeu => {
-                    let op1 = self.eval_source_operand(&instruction.operands[0]);
-                    let op2 = self.eval_source_operand(&instruction.operands[1]);
-                    let destination = self.eval_source_operand(&instruction.operands[2]);
-                    if op1 >= op2 {
-                        self.jump_with_offset(destination);
-                    }
-                },
-                crate::instructions::OpCode::Jgtu => {
-                    let op1 = self.eval_source_operand(&instruction.operands[0]);
-                    let op2 = self.eval_source_operand(&instruction.operands[1]);
-                    let destination = self.eval_source_operand(&instruction.operands[2]);
-                    if op1 > op2 {
-                        self.jump_with_offset(destination);
-                    }
-                },
-                crate::instructions::OpCode::Jleu => {
-                    let op1 = self.eval_source_operand(&instruction.operands[0]);
-                    let op2 = self.eval_source_operand(&instruction.operands[1]);
-                    let destination = self.eval_source_operand(&instruction.operands[2]);
-                    if op1 <= op2 {
-                        self.jump_with_offset(destination);
-                    }
-                },
-                crate::instructions::OpCode::Jumpabs => {
-                    let destination = self.eval_source_operand(&instruction.operands[0]);
-                    self.reg_program = destination;
-                },
-                crate::instructions::OpCode::Copy => {
-                    let source = self.eval_source_operand(&instruction.operands[0]);
-                    self.store_dest_operand(&instruction.operands[1], source);
-                },
-                crate::instructions::OpCode::Copys => todo!(),
-                crate::instructions::OpCode::Copyb => todo!(),
-                crate::instructions::OpCode::Sexs => {
-                    let source = self.eval_source_operand(&instruction.operands[0]);
-                    let result = source as i16 as i32 as u32;
-                    self.store_dest_operand(&instruction.operands[1], result);
-                },
-                crate::instructions::OpCode::Sexb => {
-                    let source = self.eval_source_operand(&instruction.operands[0]);
-                    let result = source as i8 as i32 as u32;
-                    self.store_dest_operand(&instruction.operands[1], result);
-                },
-                crate::instructions::OpCode::Aload => {
-                    let l1 = self.eval_source_operand(&instruction.operands[0]);
-                    let l2 = self.eval_source_operand(&instruction.operands[1]);
-                    let value = self.get_word(l1.wrapping_add(4 * l2), ReadWriteDest::Memory);
-                    self.store_dest_operand(&instruction.operands[2], value);
-                },
-                crate::instructions::OpCode::Aloads => {
-                    let l1 = self.eval_source_operand(&instruction.operands[0]);
-                    let l2 = self.eval_source_operand(&instruction.operands[1]);
-                    let value = self.get_twobyte(l1.wrapping_add(2 * l2), ReadWriteDest::Memory);
-                    self.store_dest_operand(&instruction.operands[2], value as u32);
-                },
-                crate::instructions::OpCode::Aloadb => {
-                    let l1 = self.eval_source_operand(&instruction.operands[0]);
-                    let l2 = self.eval_source_operand(&instruction.operands[1]);
-                    let value = self.get_twobyte(l1.wrapping_add(l2), ReadWriteDest::Memory);
-                    self.store_dest_operand(&instruction.operands[2], value as u32);
-                },
-                crate::instructions::OpCode::Astore => {
-                    let l1 = self.eval_source_operand(&instruction.operands[0]);
-                    let l2 = self.eval_source_operand(&instruction.operands[1]);
-                    let l3 = self.eval_source_operand(&instruction.operands[2]);
-                    self.write_word(l1.wrapping_add(4 * l2), ReadWriteDest::Memory, l3);
-                },
-                crate::instructions::OpCode::Astores => {
-                    let l1 = self.eval_source_operand(&instruction.operands[0]);
-                    let l2 = self.eval_source_operand(&instruction.operands[1]);
-                    let l3 = self.eval_source_operand(&instruction.operands[2]);
-                    self.write_twobyte(l1.wrapping_add(2 * l2), ReadWriteDest::Memory, l3 as u16);
-                },
-                crate::instructions::OpCode::Astoreb => {
-                    let l1 = self.eval_source_operand(&instruction.operands[0]);
-                    let l2 = self.eval_source_operand(&instruction.operands[1]);
-                    let l3 = self.eval_source_operand(&instruction.operands[2]);
-                    self.write_byte(l1.wrapping_add(l2), ReadWriteDest::Memory, l3 as u8);
-                },
-                crate::instructions::OpCode::Aloadbit => todo!(),
-                crate::instructions::OpCode::Astorebit => todo!(),
-                crate::instructions::OpCode::Stkcount => todo!(),
-                crate::instructions::OpCode::Stkpeek => todo!(),
-                crate::instructions::OpCode::Stkswap => todo!(),
-                crate::instructions::OpCode::Stkroll => todo!(),
-                crate::instructions::OpCode::Stkcopy => todo!(),
-                crate::instructions::OpCode::Call => {
-                    let func_addr = self.eval_source_operand(&instruction.operands[0]);
-                    let arg_count = self.eval_source_operand(&instruction.operands[1]);
-                    let args = (0..arg_count).map(|_| self.pop_stack()).collect::<Vec<_>>();
-                    self.call_function(func_addr, args, &instruction.operands[2]);
-                },
-                crate::instructions::OpCode::Callf => {
-                    let func_addr = self.eval_source_operand(&instruction.operands[0]);
-                    self.call_function(func_addr, Vec::new(), &instruction.operands[1]);
-                },
-                crate::instructions::OpCode::Callfi => todo!(),
-                crate::instructions::OpCode::Callfii => todo!(),
-                crate::instructions::OpCode::Callfiii => todo!(),
-                crate::instructions::OpCode::Return => todo!(),
-                crate::instructions::OpCode::Catch => todo!(),
-                crate::instructions::OpCode::Throw => todo!(),
-                crate::instructions::OpCode::Tailcall => todo!(),
-                crate::instructions::OpCode::Streamchar => todo!(),
-                crate::instructions::OpCode::Streamnum => todo!(),
-                crate::instructions::OpCode::Streamstr => todo!(),
-                crate::instructions::OpCode::Streamunichar => todo!(),
-                crate::instructions::OpCode::Gestalt => {
-                    let gestalt_num = self.eval_source_operand(&instruction.operands[0]);
-                    let extra_arg   = self.eval_source_operand(&instruction.operands[1]);
-
-                    if gestalt_num == 4 && extra_arg == 2 {
-                        self.store_dest_operand(&instruction.operands[2], 1);
-                    } else {
-                        self.store_dest_operand(&instruction.operands[2], 0);
-                    }
-                },
-                crate::instructions::OpCode::Debugtrap => todo!(),
-                crate::instructions::OpCode::Getmemsize => todo!(),
-                crate::instructions::OpCode::Setmemsize => todo!(),
-                crate::instructions::OpCode::Random => todo!(),
-                crate::instructions::OpCode::Setrandom => todo!(),
-                crate::instructions::OpCode::Quit => {
-                    println!("Quit called");
-                    return;
-                },
-                crate::instructions::OpCode::Verify => todo!(),
-                crate::instructions::OpCode::Restart => todo!(),
-                crate::instructions::OpCode::Save => todo!(),
-                crate::instructions::OpCode::Restore => todo!(),
-                crate::instructions::OpCode::Saveundo => todo!(),
-                crate::instructions::OpCode::Restoreundo => todo!(),
-                crate::instructions::OpCode::Protect => todo!(),
-                crate::instructions::OpCode::Hasundo => todo!(),
-                crate::instructions::OpCode::Discardundo => todo!(),
-                crate::instructions::OpCode::Glk => todo!(),
-                crate::instructions::OpCode::Getstringtbl => todo!(),
-                crate::instructions::OpCode::Setstringtbl => todo!(),
-                crate::instructions::OpCode::Getiosys => todo!(),
-                crate::instructions::OpCode::Setiosys => todo!(),
-                crate::instructions::OpCode::Linearsearch => todo!(),
-                crate::instructions::OpCode::Binarysearch => todo!(),
-                crate::instructions::OpCode::Linkedsearch => todo!(),
-                crate::instructions::OpCode::Mzero => todo!(),
-                crate::instructions::OpCode::Mcopy => todo!(),
-                crate::instructions::OpCode::Malloc => todo!(),
-                crate::instructions::OpCode::Mfree => todo!(),
-                crate::instructions::OpCode::Accelfunc => todo!(),
-                crate::instructions::OpCode::Accelparam => todo!(),
-                crate::instructions::OpCode::Numtof => todo!(),
-                crate::instructions::OpCode::Ftonumz => todo!(),
-                crate::instructions::OpCode::Ftonumn => todo!(),
-                crate::instructions::OpCode::Ceil => todo!(),
-                crate::instructions::OpCode::Floor => todo!(),
-                crate::instructions::OpCode::Fadd => todo!(),
-                crate::instructions::OpCode::Fsub => todo!(),
-                crate::instructions::OpCode::Fmul => todo!(),
-                crate::instructions::OpCode::Fdiv => todo!(),
-                crate::instructions::OpCode::Fmod => todo!(),
-                crate::instructions::OpCode::Sqrt => todo!(),
-                crate::instructions::OpCode::Exp => todo!(),
-                crate::instructions::OpCode::Log => todo!(),
-                crate::instructions::OpCode::Pow => todo!(),
-                crate::instructions::OpCode::Sin => todo!(),
-                crate::instructions::OpCode::Cos => todo!(),
-                crate::instructions::OpCode::Tan => todo!(),
-                crate::instructions::OpCode::Asin => todo!(),
-                crate::instructions::OpCode::Acos => todo!(),
-                crate::instructions::OpCode::Atan => todo!(),
-                crate::instructions::OpCode::Atan2 => todo!(),
-                crate::instructions::OpCode::Jfeq => todo!(),
-                crate::instructions::OpCode::Jfne => todo!(),
-                crate::instructions::OpCode::Jflt => todo!(),
-                crate::instructions::OpCode::Jfle => todo!(),
-                crate::instructions::OpCode::Jfgt => todo!(),
-                crate::instructions::OpCode::Jfge => todo!(),
-                crate::instructions::OpCode::Jisnan => todo!(),
-                crate::instructions::OpCode::Jisinf => todo!(),
-                crate::instructions::OpCode::Numtod => todo!(),
-                crate::instructions::OpCode::Dtonumz => todo!(),
-                crate::instructions::OpCode::Dtonumn => todo!(),
-                crate::instructions::OpCode::Ftod => todo!(),
-                crate::instructions::OpCode::Dtof => todo!(),
-                crate::instructions::OpCode::Dceil => todo!(),
-                crate::instructions::OpCode::Dfloor => todo!(),
-                crate::instructions::OpCode::Dadd => todo!(),
-                crate::instructions::OpCode::Dsub => todo!(),
-                crate::instructions::OpCode::Dmul => todo!(),
-                crate::instructions::OpCode::Ddiv => todo!(),
-                crate::instructions::OpCode::Dmodr => todo!(),
-                crate::instructions::OpCode::Dmodq => todo!(),
-                crate::instructions::OpCode::Dsqrt => todo!(),
-                crate::instructions::OpCode::Dexp => todo!(),
-                crate::instructions::OpCode::Dlog => todo!(),
-                crate::instructions::OpCode::Dpow => todo!(),
-                crate::instructions::OpCode::Dsin => todo!(),
-                crate::instructions::OpCode::Dcos => todo!(),
-                crate::instructions::OpCode::Dtan => todo!(),
-                crate::instructions::OpCode::Dasin => todo!(),
-                crate::instructions::OpCode::Dacos => todo!(),
-                crate::instructions::OpCode::Datan => todo!(),
-                crate::instructions::OpCode::Datan2 => todo!(),
-                crate::instructions::OpCode::Jdeq => todo!(),
-                crate::instructions::OpCode::Jdne => todo!(),
-                crate::instructions::OpCode::Jdlt => todo!(),
-                crate::instructions::OpCode::Jdle => todo!(),
-                crate::instructions::OpCode::Jdgt => todo!(),
-                crate::instructions::OpCode::Jdge => todo!(),
-                crate::instructions::OpCode::Jdisnan => todo!(),
-                crate::instructions::OpCode::Jdisinf => todo!(),
+            let in_operands = instruction.in_operands.iter().map(|op| self.eval_source_operand(&op)).collect();
+            let no_store = OpCode::should_gen_return_stub(instruction.opcode.clone());
+            self.tmp_dest_oper = instruction.out_operands.get(0).cloned();
+
+            let result_values = OpCode::call_opcode(self, instruction.opcode, in_operands);
+
+            if !no_store {
+                instruction.out_operands.iter().enumerate().for_each(|(index, op)| self.store_dest_operand(&op, result_values[index]));
             }
         }
     }
 
-    fn call_function(&mut self, func_addr: FunctionPointer, args: Vec<u32>, dest_oper: &Operand) {
-        let (dest_type, dest_addr) = match dest_oper {
-            Operand::Constant(_) => (StubDestType::DoNotStore, 0),
-            Operand::PopStack => (StubDestType::PushOnStack, 0),
-            Operand::FrameIndirect(offset) => (StubDestType::LocalVariable, *offset),
-            Operand::MemIndirect(offset) => (StubDestType::MainMemory, *offset),
-            Operand::MemRamIndirect(offset) => (StubDestType::MainMemory, self.mem_writeable + *offset),
-        };
-
-        self.create_return_stub(dest_type, dest_addr, self.reg_program, self.reg_frame);
-
+    pub fn call_function(&mut self, func_addr: FunctionPointer, args: Vec<u32>) {
         let new_program_counter = self.create_stack_frame(func_addr, args);
         println!("Jumping to function at 0x{new_program_counter:04x}");
         self.reg_program = new_program_counter;
     }
 
-    fn create_return_stub(&mut self, dest_type: StubDestType, dest_addr: u32, program_counter: MemAddress, frame_pointer: StackAddress) {
+    pub fn create_return_stub(&mut self) {
+        let dest_oper = self.tmp_dest_oper.clone();
+        
+        let (dest_type, dest_addr) = match dest_oper {
+            None => (StubDestType::DoNotStore, 0),
+            Some(Operand::Constant(_)) => (StubDestType::DoNotStore, 0),
+            Some(Operand::PopStack) => (StubDestType::PushOnStack, 0),
+            Some(Operand::FrameIndirect(offset)) => (StubDestType::LocalVariable, offset),
+            Some(Operand::MemIndirect(offset)) => (StubDestType::MainMemory, offset),
+            Some(Operand::MemRamIndirect(offset)) => (StubDestType::MainMemory, self.mem_writeable + offset),
+        };
+
         self.push_stack(dest_type as u32);
         self.push_stack(dest_addr);
-        self.push_stack(program_counter);
-        self.push_stack(frame_pointer);
+        self.push_stack(self.reg_program);
+        self.push_stack(self.reg_frame);
     }
 
     // Returns program counter after parsing all the args
-    fn create_stack_frame(&mut self, func: FunctionPointer, mut args: Vec<u32>) -> MemAddress {
+    pub fn create_stack_frame(&mut self, func: FunctionPointer, mut args: Vec<u32>) -> MemAddress {
 
         // Reading function signature
         let func_type = self.get_byte(func, ReadWriteDest::Memory);
@@ -572,7 +221,7 @@ impl Interpreter {
         return opcode_start;
     }
 
-    fn return_from_function(&mut self, value: u32) {
+    pub fn return_from_function(&mut self, value: u32) {
         // Discard frame
         self.reg_stack = self.reg_frame - 4;
 
@@ -600,7 +249,7 @@ impl Interpreter {
         }
     }
 
-    fn jump_with_offset(&mut self, offset: u32) {
+    pub fn jump_with_offset(&mut self, offset: u32) {
         if offset == 1 || offset == 0 {
             return self.return_from_function(offset);
         }
@@ -616,12 +265,12 @@ impl Interpreter {
         self.reg_program = destination;
     }
 
-    fn push_stack(&mut self, value: u32) {
+    pub fn push_stack(&mut self, value: u32) {
         self.write_word(self.reg_stack, ReadWriteDest::Stack, value);
         self.reg_stack += 4;
     }
 
-    fn pop_stack(&mut self) -> u32 {
+    pub fn pop_stack(&mut self) -> u32 {
         self.reg_stack -= 4;
         self.get_word(self.reg_stack, ReadWriteDest::Stack)
     }