summary refs log tree commit diff
diff options
context:
space:
mode:
authorAshelyn Rose <git@ashen.earth>2024-12-21 17:23:24 -0700
committerAshelyn Rose <git@ashen.earth>2024-12-21 17:23:24 -0700
commit9a2c2bc2d9ff45b9bd96c570b8c5fc0b03067ccc (patch)
tree12f65bfca6e285911713c6699b4d2a534df88cd4
parentfbbeed8c10dc9c9bdb34f946d5b844b537ebad7a (diff)
Implement setiosys
-rw-r--r--opcode_proc/src/lib.rs32
-rw-r--r--src/glk.rs1
-rw-r--r--src/instructions.rs431
-rw-r--r--src/interpreter.rs425
-rw-r--r--src/main.rs1
-rw-r--r--src/opcodes.rs780
6 files changed, 890 insertions, 780 deletions
diff --git a/opcode_proc/src/lib.rs b/opcode_proc/src/lib.rs
index d777214..7c84f9a 100644
--- a/opcode_proc/src/lib.rs
+++ b/opcode_proc/src/lib.rs
@@ -19,7 +19,7 @@ pub fn generate_opcodes(item: TokenStream) -> TokenStream {
         let code = &field.byte_code;
         let variant = &field.name;
         quote! {
-            #code => Self::#variant,
+            #code => Some(Self::#variant),
         }
     }).collect::<Vec<_>>();
 
@@ -39,6 +39,14 @@ pub fn generate_opcodes(item: TokenStream) -> TokenStream {
         }
     });
 
+    let gen_stub_arms = ops_def.codes.iter().map(|field| {
+        let variant = &field.name;
+        let value = &field.no_store;
+        quote! {
+            #enum_name::#variant => #value,
+        }
+    });
+
     let closure_match_arms = ops_def.codes.iter().map(|field| {
         let variant = &field.name;
         let closure_expr = &field.func_block;
@@ -87,15 +95,16 @@ pub fn generate_opcodes(item: TokenStream) -> TokenStream {
     });
 
     let tokens = quote! {
+        #[derive(Debug, Clone)]
         pub enum #enum_name {
             #(#field_names),*
         }
 
         impl #enum_name {
-            pub fn get_from_code(code: u32) -> Self {
+            pub fn get_from_code(code: u32) -> Option<Self> {
                 match code {
                     #(#getcode_match_arms)*
-                    _ => panic!("Unknown opcode 0x{code:03x}")
+                    _ => None
                 }
             }
 
@@ -111,6 +120,12 @@ pub fn generate_opcodes(item: TokenStream) -> TokenStream {
                 }
             }
 
+            pub fn should_gen_return_stub(opcode: Self) -> bool {
+                match opcode {
+                    #(#gen_stub_arms)*
+                }
+            }
+
             pub fn call_opcode(interpreter: &mut crate::Interpreter, opcode: Self, input_params: Vec<u32>) -> Vec<u32> {
                 match opcode {
                     #(#closure_match_arms)*
@@ -148,6 +163,15 @@ impl Parse for SingleOpcodeDefinition {
         parenthesized!(code in attr);
         let byte_code = code.parse::<LitInt>()?;
 
+        let mut no_store = false;
+        if attr.peek(Token![,]) {
+            attr.parse::<Token![,]>()?;
+            let extra_attr = attr.parse::<Ident>()?;
+            if extra_attr == "no_store" {
+                no_store = true;
+            }
+        }
+
         input.parse::<Token![fn]>()?;
         let name = input.parse::<Ident>()?;
 
@@ -186,6 +210,7 @@ impl Parse for SingleOpcodeDefinition {
 
         Ok(SingleOpcodeDefinition {
             byte_code,
+            no_store,
             name,
             input_params,
             interpreter_ident,
@@ -204,6 +229,7 @@ struct OpcodeBlock {
 
 struct SingleOpcodeDefinition {
     pub byte_code: LitInt,
+    pub no_store: bool,
     pub name: Ident,
     pub interpreter_ident: Option<Ident>,
     pub input_params: Vec<PatType>,
diff --git a/src/glk.rs b/src/glk.rs
index 3efb095..ed308f9 100644
--- a/src/glk.rs
+++ b/src/glk.rs
@@ -1,3 +1,2 @@
 pub struct Glk {
-
 }
diff --git a/src/instructions.rs b/src/instructions.rs
index 59efd47..55bc5b9 100644
--- a/src/instructions.rs
+++ b/src/instructions.rs
@@ -1,11 +1,13 @@
 use core::panic;
 
 use crate::interpreter::{MemAddress, StackAddress};
+use crate::opcodes::OpCode;
 
 #[derive(Debug)]
 pub struct Instruction {
-    pub operation: OpCode,
-    pub operands: Vec<Operand>
+    pub opcode: OpCode,
+    pub in_operands: Vec<Operand>,
+    pub out_operands: Vec<Operand>,
 }
 
 enum Nybble {
@@ -13,7 +15,7 @@ enum Nybble {
     Low,
 }
 
-#[derive(PartialEq, Debug)]
+#[derive(PartialEq, Debug, Clone)]
 pub enum Operand {
     Constant(i32),
     PopStack,
@@ -23,17 +25,44 @@ pub enum Operand {
 }
 
 impl Instruction {
-    pub fn read<'a, I>(bytes: &mut I) -> (Instruction, u32)
+    pub fn read<'a, I>(bytes: &mut I) -> Result<(Instruction, u32), u32>
     where
         I: IntoIterator<Item = &'a u8> + Copy
     {
         let mut bytes = bytes.into_iter().enumerate().peekable();
-        let instruction_length = OpCode::get_length(*bytes.peek().unwrap().1);
-        let mut bytes = bytes.into_iter();
-        let instruction_bytes = (0..instruction_length).into_iter().map(|_n| *bytes.next().unwrap().1).collect();
-        let operation = OpCode::from_bytes(instruction_bytes);
 
-        let operand_count = operation.get_operand_count();
+        let instruction_length = {
+            let first_byte = *bytes.peek().unwrap().1;
+            match first_byte >> 6 {
+                0b00 | 0b01 => 1,
+                0b10 => 2,
+                0b11 => 4,
+                _ => unreachable!()
+            }
+        };
+
+        let mask = match instruction_length {
+            1 => 0,
+            2 => 0x8000,
+            4 => 0xC0000000,
+            _ => panic!("Invalid opcode byte array"),
+        };
+
+        let instruction_bytes = (0..4-instruction_length).into_iter().map(|_n| 0).chain(
+                (0..instruction_length).into_iter().map(|_n| *bytes.next().unwrap().1)
+            ).collect::<Vec<_>>();
+
+        let opcode_num = u32::from_be_bytes(instruction_bytes.clone().try_into().unwrap()) & !mask;
+        println!("instruction length: {instruction_length}, number: 0x{opcode_num:x}, bytes: {instruction_bytes:?}");
+        let opcode = OpCode::get_from_code(opcode_num);
+        if let None = opcode {
+            return Err(opcode_num);
+        }
+        let opcode = opcode.unwrap();
+        let input_operand_count = OpCode::get_input_arg_count(opcode.clone());
+        let output_operand_count = OpCode::get_output_arg_count(opcode.clone());
+
+        let operand_count = input_operand_count + output_operand_count;
         let operand_bytes = (operand_count + 1) / 2;
         let skip_last_half = operand_bytes != operand_count / 2;
         let operand_bytes = (0..operand_bytes).into_iter().map(|_n| *bytes.next().unwrap().1);
@@ -76,382 +105,14 @@ impl Instruction {
             operands.remove(operands.len() - 1);
         }
 
-        // Return instruction along with the number of bytes we've read
-        (Instruction {
-            operation,
-            operands,
-        }, data_bytes.peek().unwrap().0 as u32)
-    }
-}
-
-impl OpCode {
-    fn get_length(first_byte: u8) -> usize {
-        let length = match first_byte >> 6 {
-            0b00 | 0b01 => 1,
-            0b10 => 2,
-            0b11 => 4,
-            _ => unreachable!()
-        };
-        return length
-    }
-
-    fn from_bytes(bytes: Vec<u8>) -> Self {
-        let (padded_bytes, mask) = match bytes.len() {
-            1 => ([0,0,0,bytes[0]], 0),
-            2 => ([0,0,bytes[0],bytes[1]], 0x8000),
-            4 => ([bytes[0],bytes[1],bytes[2],bytes[3]], 0xC0000000),
-            _ => panic!("Invalid opcode byte array")
-        };
-
-        let instruction = u32::from_be_bytes(padded_bytes) & !mask;
-        return unsafe { std::mem::transmute(instruction) }
-    }
-
-    fn get_operand_count(&self) -> usize {
-        match *self {
-            // Misc
-            OpCode::Nop => 0,
-            OpCode::Gestalt => 3,
-            OpCode::Debugtrap => 1,
-            OpCode::Glk => 3,
-
-            // Integer math
-            OpCode::Add => 3,
-            OpCode::Sub => 3,
-            OpCode::Mul => 3,
-            OpCode::Div => 3,
-            OpCode::Mod => 3,
-            OpCode::Neg => 2,
-            OpCode::Bitand => 3,
-            OpCode::Bitor => 3,
-            OpCode::Bitxor => 3,
-            OpCode::Bitnot => 3,
-            OpCode::Shiftl => 3,
-            OpCode::Sshiftr => 3,
-            OpCode::Ushiftr => 3,
-
-            // Branches
-            OpCode::Jump => 1,
-            OpCode::Jz => 2,
-            OpCode::Jnz => 2,
-            OpCode::Jeq => 3,
-            OpCode::Jne => 3,
-            OpCode::Jlt => 3,
-            OpCode::Jge => 3,
-            OpCode::Jgt => 3,
-            OpCode::Jle => 3,
-            OpCode::Jltu => 3,
-            OpCode::Jgeu => 3,
-            OpCode::Jgtu => 3,
-            OpCode::Jleu => 3,
-            OpCode::Jumpabs => 1,
+        let in_operands = operands[0..input_operand_count].try_into().unwrap();
+        let out_operands = operands[input_operand_count..].try_into().unwrap();
 
-            // Moving data
-            OpCode::Copy => 2,
-            OpCode::Copys => 2,
-            OpCode::Copyb => 2,
-            OpCode::Sexs => 2,
-            OpCode::Sexb => 2,
-
-            // Array data
-            OpCode::Aload => 3,
-            OpCode::Aloads => 3,
-            OpCode::Aloadb => 3,
-            OpCode::Aloadbit => 3,
-            OpCode::Astore => 3,
-            OpCode::Astores => 3,
-            OpCode::Astoreb => 3,
-            OpCode::Astorebit => 3,
-
-            // Stack operations
-            OpCode::Stkcount => 1,
-            OpCode::Stkpeek => 2,
-            OpCode::Stkswap => 0,
-            OpCode::Stkroll => 2,
-            OpCode::Stkcopy => 1,
-
-            // Functions
-            OpCode::Call => 3,
-            OpCode::Callf => 2,
-            OpCode::Callfi => 3,
-            OpCode::Callfii => 4,
-            OpCode::Callfiii => 5,
-            OpCode::Return => 1,
-            OpCode::Tailcall => 2,
-
-            // Continuations
-            OpCode::Catch => 2,
-            OpCode::Throw => 2,
-
-            // Memory
-            OpCode::Getmemsize => 1,
-            OpCode::Setmemsize => 2,
-            OpCode::Malloc => 2,
-            OpCode::Mfree => 1,
-
-            // Game state
-            OpCode::Quit => 0,
-            OpCode::Restart => 0,
-            OpCode::Save => 2,
-            OpCode::Restore => 2,
-            OpCode::Saveundo => 1,
-            OpCode::Restoreundo => 1,
-            OpCode::Hasundo => 1,
-            OpCode::Discardundo => 0,
-            OpCode::Protect => 2,
-            OpCode::Verify => 1,
-
-            // Output
-            OpCode::Getiosys => 2,
-            OpCode::Setiosys => 2,
-            OpCode::Streamchar => 1,
-            OpCode::Streamunichar => 1,
-            OpCode::Streamnum => 1,
-            OpCode::Streamstr => 1,
-            OpCode::Getstringtbl => 1,
-            OpCode::Setstringtbl => 1,
-
-            // Floating point math
-            OpCode::Numtof => 2,
-            OpCode::Ftonumz => 2,
-            OpCode::Ftonumn => 2,
-            OpCode::Fadd => 3,
-            OpCode::Fsub => 3,
-            OpCode::Fmul => 3,
-            OpCode::Fdiv => 3,
-            OpCode::Fmod => 4,
-            OpCode::Ceil => 2,
-            OpCode::Floor => 2,
-            OpCode::Sqrt => 2,
-            OpCode::Exp => 2,
-            OpCode::Log => 2,
-            OpCode::Pow => 3,
-            OpCode::Sin => 2,
-            OpCode::Cos => 2,
-            OpCode::Tan => 2,
-            OpCode::Asin => 2,
-            OpCode::Acos => 2,
-            OpCode::Atan => 2,
-            OpCode::Atan2 => 3,
-
-            // Double precision math
-            OpCode::Numtod => 3,
-            OpCode::Dtonumz => 3,
-            OpCode::Dtonumn => 3,
-            OpCode::Ftod => 3,
-            OpCode::Dtof => 3,
-            OpCode::Dadd => 6,
-            OpCode::Dsub => 6,
-            OpCode::Dmul => 6,
-            OpCode::Ddiv => 6,
-            OpCode::Dmodr => 6,
-            OpCode::Dmodq => 6,
-            OpCode::Dceil => 4,
-            OpCode::Dfloor => 4,
-            OpCode::Dsqrt => 4,
-            OpCode::Dexp => 4,
-            OpCode::Dlog => 4,
-            OpCode::Dpow => 6,
-            OpCode::Dsin => 4,
-            OpCode::Dcos => 4,
-            OpCode::Dtan => 4,
-            OpCode::Dasin => 4,
-            OpCode::Dacos => 4,
-            OpCode::Datan => 4,
-            OpCode::Datan2 => 4,
-
-            // Floating point comparisons
-            OpCode::Jisnan => 2,
-            OpCode::Jisinf => 2,
-            OpCode::Jfeq => 4,
-            OpCode::Jfne => 4,
-            OpCode::Jflt => 3,
-            OpCode::Jfle => 3,
-            OpCode::Jfgt => 3,
-            OpCode::Jfge => 3,
-
-            // Double precision comparisons
-            OpCode::Jdisnan => 3,
-            OpCode::Jdisinf => 3,
-            OpCode::Jdeq => 7,
-            OpCode::Jdne => 7,
-            OpCode::Jdlt => 5,
-            OpCode::Jdle => 5,
-            OpCode::Jdgt => 5,
-            OpCode::Jdge => 5,
-
-            // RNG
-            OpCode::Random => 2,
-            OpCode::Setrandom => 1,
-
-            // Block copy and clear
-            OpCode::Mzero => 2,
-            OpCode::Mcopy => 3,
-
-            // Searching
-            OpCode::Linearsearch => 8,
-            OpCode::Binarysearch => 8,
-            OpCode::Linkedsearch => 7,
-
-            // Accelerated functions
-            OpCode::Accelfunc => 2,
-            OpCode::Accelparam => 2,
-        }
+        // Return instruction along with the number of bytes we've read
+        Ok((Instruction {
+            opcode,
+            in_operands,
+            out_operands,
+        }, data_bytes.peek().unwrap().0 as u32))
     }
 }
-
-
-#[repr(u32)]
-#[derive(Debug)]
-pub enum OpCode {
-    Nop = 0x00,
-    Add = 0x10,
-    Sub = 0x11,
-    Mul = 0x12,
-    Div = 0x13,
-    Mod = 0x14,
-    Neg = 0x15,
-    Bitand = 0x18,
-    Bitor = 0x19,
-    Bitxor = 0x1A,
-    Bitnot = 0x1B,
-    Shiftl = 0x1C,
-    Sshiftr = 0x1D,
-    Ushiftr = 0x1E,
-    Jump = 0x20,
-    Jz = 0x22,
-    Jnz = 0x23,
-    Jeq = 0x24,
-    Jne = 0x25,
-    Jlt = 0x26,
-    Jge = 0x27,
-    Jgt = 0x28,
-    Jle = 0x29,
-    Jltu = 0x2A,
-    Jgeu = 0x2B,
-    Jgtu = 0x2C,
-    Jleu = 0x2D,
-    Call = 0x30,
-    Return = 0x31,
-    Catch = 0x32,
-    Throw = 0x33,
-    Tailcall = 0x34,
-    Copy = 0x40,
-    Copys = 0x41,
-    Copyb = 0x42,
-    Sexs = 0x44,
-    Sexb = 0x45,
-    Aload = 0x48,
-    Aloads = 0x49,
-    Aloadb = 0x4A,
-    Aloadbit = 0x4B,
-    Astore = 0x4C,
-    Astores = 0x4D,
-    Astoreb = 0x4E,
-    Astorebit = 0x4F,
-    Stkcount = 0x50,
-    Stkpeek = 0x51,
-    Stkswap = 0x52,
-    Stkroll = 0x53,
-    Stkcopy = 0x54,
-    Streamchar = 0x70,
-    Streamnum = 0x71,
-    Streamstr = 0x72,
-    Streamunichar = 0x73,
-    Gestalt = 0x100,
-    Debugtrap = 0x101,
-    Getmemsize = 0x102,
-    Setmemsize = 0x103,
-    Jumpabs = 0x104,
-    Random = 0x110,
-    Setrandom = 0x111,
-    Quit = 0x120,
-    Verify = 0x121,
-    Restart = 0x122,
-    Save = 0x123,
-    Restore = 0x124,
-    Saveundo = 0x125,
-    Restoreundo = 0x126,
-    Protect = 0x127,
-    Hasundo = 0x128,
-    Discardundo = 0x129,
-    Glk = 0x130,
-    Getstringtbl = 0x140,
-    Setstringtbl = 0x141,
-    Getiosys = 0x148,
-    Setiosys = 0x149,
-    Linearsearch = 0x150,
-    Binarysearch = 0x151,
-    Linkedsearch = 0x152,
-    Callf = 0x160,
-    Callfi = 0x161,
-    Callfii = 0x162,
-    Callfiii = 0x163,
-    Mzero = 0x170,
-    Mcopy = 0x171,
-    Malloc = 0x178,
-    Mfree = 0x179,
-    Accelfunc = 0x180,
-    Accelparam = 0x181,
-    Numtof = 0x190,
-    Ftonumz = 0x191,
-    Ftonumn = 0x192,
-    Ceil = 0x198,
-    Floor = 0x199,
-    Fadd = 0x1A0,
-    Fsub = 0x1A1,
-    Fmul = 0x1A2,
-    Fdiv = 0x1A3,
-    Fmod = 0x1A4,
-    Sqrt = 0x1A8,
-    Exp = 0x1A9,
-    Log = 0x1AA,
-    Pow = 0x1AB,
-    Sin = 0x1B0,
-    Cos = 0x1B1,
-    Tan = 0x1B2,
-    Asin = 0x1B3,
-    Acos = 0x1B4,
-    Atan = 0x1B5,
-    Atan2 = 0x1B6,
-    Jfeq = 0x1C0,
-    Jfne = 0x1C1,
-    Jflt = 0x1C2,
-    Jfle = 0x1C3,
-    Jfgt = 0x1C4,
-    Jfge = 0x1C5,
-    Jisnan = 0x1C8,
-    Jisinf = 0x1C9,
-    Numtod = 0x200,
-    Dtonumz = 0x201,
-    Dtonumn = 0x202,
-    Ftod = 0x203,
-    Dtof = 0x204,
-    Dceil = 0x208,
-    Dfloor = 0x209,
-    Dadd = 0x210,
-    Dsub = 0x211,
-    Dmul = 0x212,
-    Ddiv = 0x213,
-    Dmodr = 0x214,
-    Dmodq = 0x215,
-    Dsqrt = 0x218,
-    Dexp = 0x219,
-    Dlog = 0x21A,
-    Dpow = 0x21B,
-    Dsin = 0x220,
-    Dcos = 0x221,
-    Dtan = 0x222,
-    Dasin = 0x223,
-    Dacos = 0x224,
-    Datan = 0x225,
-    Datan2 = 0x226,
-    Jdeq = 0x230,
-    Jdne = 0x231,
-    Jdlt = 0x232,
-    Jdle = 0x233,
-    Jdgt = 0x234,
-    Jdge = 0x235,
-    Jdisnan = 0x238,
-    Jdisinf = 0x239,
-}
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)
     }
diff --git a/src/main.rs b/src/main.rs
index 4e97cd4..3aeb2e7 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -3,7 +3,6 @@ mod interpreter;
 mod glk;
 mod instructions;
 mod opcodes;
-use opcodes::OpCodes;
 
 use interpreter::Interpreter;
 use std::{env, fs, process::exit};
diff --git a/src/opcodes.rs b/src/opcodes.rs
index e8ef7fe..1fbc80f 100644
--- a/src/opcodes.rs
+++ b/src/opcodes.rs
@@ -1,7 +1,9 @@
 use opcode_proc::generate_opcodes;
 
+use crate::{glk::Glk, interpreter::Output};
+
 generate_opcodes!(
-    pub enum OpCodes {
+    pub enum OpCode {
         #[code(0x00)]
         fn Nop() {
             
@@ -17,11 +19,785 @@ generate_opcodes!(
             a - b
         },
 
+        #[code(0x12)]
+        fn Mul(a: u32, b: u32) -> u32 {
+            a * b
+        },
+
+        #[code(0x13)]
+        fn Div(a: u32, b: u32) -> u32 {
+            a / b
+        },
+
+        #[code(0x14)]
+        fn Mod(a: u32, b: u32) -> u32 {
+            a % b
+        },
+
+        #[code(0x15)]
+        fn Neg(a: u32) -> u32 {
+            -(a as i32) as u32
+        },
+
+        #[code(0x18)]
+        fn Bitand(a: u32, b: u32) -> u32 {
+            a & b
+        },
+
+        #[code(0x19)]
+        fn Bitor(a: u32, b: u32) -> u32 {
+            a | b
+        },
+
+        #[code(0x1A)]
+        fn Bitxor(a: u32, b: u32) -> u32 {
+            a ^ b
+        },
+
+        #[code(0x1B)]
+        fn Bitnot(a: u32) -> u32 {
+            !a
+        },
+
+        #[code(0x1C)]
+        fn Shiftl() {
+            todo!()
+        },
+
+        #[code(0x1D)]
+        fn Sshiftr() {
+            todo!()
+        },
+
+        #[code(0x1E)]
+        fn Ushiftr() {
+            todo!()
+        },
+
+        #[code(0x20)]
+        fn Jump() {
+            todo!()
+        },
+
+        #[code(0x22)]
+        fn Jz() {
+            todo!()
+        },
+
         #[code(0x23)]
         fn Jnz(&mut interpreter, comparison: u32, offset: u32) {
             if comparison != 0 {
-                interpreter.reg_program += offset;
+                interpreter.reg_program = interpreter.reg_program + offset - 2;
+            }
+        },
+
+        #[code(0x24)]
+        fn Jeq() {
+            todo!();
+        },
+
+        #[code(0x25)]
+        fn Jne() {
+            todo!();
+        },
+
+        #[code(0x26)]
+        fn Jlt() {
+            todo!();
+        },
+
+        #[code(0x27)]
+        fn Jge() {
+            todo!();
+        },
+
+        #[code(0x28)]
+        fn Jgt() {
+            todo!();
+        },
+
+        #[code(0x29)]
+        fn Jle() {
+            todo!();
+        },
+
+        #[code(0x2A)]
+        fn Jltu() {
+            todo!();
+        },
+
+        #[code(0x2B)]
+        fn Jgeu() {
+            todo!();
+        },
+
+        #[code(0x2C)]
+        fn Jgtu() {
+            todo!();
+        },
+
+        #[code(0x2D)]
+        fn Jleu() {
+            todo!();
+        },
+
+        #[code(0x30), no_store]
+        fn Call(&mut interpreter, func_addr: u32, arg_count: u32) -> u32 {
+            let args = (0..arg_count).map(|_| interpreter.pop_stack()).collect::<Vec<_>>();
+
+            interpreter.create_return_stub();
+            interpreter.call_function(func_addr, args);
+
+            // This gets ignored because of gen_return_stub but it's here for type reasons
+            return 0;
+        },
+
+        #[code(0x31)]
+        fn Return() {
+            todo!();
+        },
+
+        #[code(0x32)]
+        fn Catch() {
+            todo!();
+        },
+
+        #[code(0x33)]
+        fn Throw() {
+            todo!();
+        },
+
+        #[code(0x34)]
+        fn Tailcall() {
+            todo!();
+        },
+
+        #[code(0x40)]
+        fn Copy(param: u32) -> u32 {
+            return param
+        },
+
+        #[code(0x41)]
+        fn Copys() {
+            todo!();
+        },
+
+        #[code(0x42)]
+        fn Copyb() {
+            todo!();
+        },
+
+        #[code(0x44)]
+        fn Sexs() {
+            todo!();
+        },
+
+        #[code(0x45)]
+        fn Sexb() {
+            todo!();
+        },
+
+        #[code(0x48)]
+        fn Aload() {
+            todo!();
+        },
+
+        #[code(0x49)]
+        fn Aloads() {
+            todo!();
+        },
+
+        #[code(0x4A)]
+        fn Aloadb() {
+            todo!();
+        },
+
+        #[code(0x4B)]
+        fn Aloadbit() {
+            todo!();
+        },
+
+        #[code(0x4C)]
+        fn Astore() {
+            todo!();
+        },
+
+        #[code(0x4D)]
+        fn Astores() {
+            todo!();
+        },
+
+        #[code(0x4E)]
+        fn Astoreb() {
+            todo!();
+        },
+
+        #[code(0x4F)]
+        fn Astorebit() {
+            todo!();
+        },
+
+        #[code(0x50)]
+        fn Stkcount() {
+            todo!();
+        },
+
+        #[code(0x51)]
+        fn Stkpeek() {
+            todo!();
+        },
+
+        #[code(0x52)]
+        fn Stkswap() {
+            todo!();
+        },
+
+        #[code(0x53)]
+        fn Stkroll() {
+            todo!();
+        },
+
+        #[code(0x54)]
+        fn Stkcopy() {
+            todo!();
+        },
+
+        #[code(0x70)]
+        fn Streamchar() {
+            todo!();
+        },
+
+        #[code(0x71)]
+        fn Streamnum() {
+            todo!();
+        },
+
+        #[code(0x72)]
+        fn Streamstr() {
+            todo!();
+        },
+
+        #[code(0x73)]
+        fn Streamunichar() {
+            todo!();
+        },
+
+        #[code(0x100)]
+        fn Gestalt(gestalt_selector: u32, extra_arg: u32) -> u32 {
+            match gestalt_selector {
+                // IO System
+                4 => {
+                    return match extra_arg {
+                        // Null
+                        0 => 1,
+                        1 => 0,
+                        2 => 1,
+                        20 => 0,
+                        _ => 0,
+                    }
+                }
+
+                _ => {
+                    println!("WARN: Unknown gestalt {gestalt_selector}");
+                    return 0
+                }
+            }
+        },
+
+        #[code(0x101)]
+        fn Debugtrap() {
+            todo!();
+        },
+
+        #[code(0x102)]
+        fn Getmemsize() {
+            todo!();
+        },
+
+        #[code(0x103)]
+        fn Setmemsize() {
+            todo!();
+        },
+
+        #[code(0x104)]
+        fn Jumpabs() {
+            todo!();
+        },
+
+        #[code(0x110)]
+        fn Random() {
+            todo!();
+        },
+
+        #[code(0x111)]
+        fn Setrandom() {
+            todo!();
+        },
+
+        #[code(0x120)]
+        fn Quit() {
+            println!("Story exited");
+            std::process::exit(0);
+        },
+
+        #[code(0x121)]
+        fn Verify() {
+            todo!();
+        },
+
+        #[code(0x122)]
+        fn Restart() {
+            todo!();
+        },
+
+        #[code(0x123)]
+        fn Save() {
+            todo!();
+        },
+
+        #[code(0x124)]
+        fn Restore() {
+            todo!();
+        },
+
+        #[code(0x125)]
+        fn Saveundo() {
+            todo!();
+        },
+
+        #[code(0x126)]
+        fn Restoreundo() {
+            todo!();
+        },
+
+        #[code(0x127)]
+        fn Protect() {
+            todo!();
+        },
+
+        #[code(0x128)]
+        fn Hasundo() {
+            todo!();
+        },
+
+        #[code(0x129)]
+        fn Discardundo() {
+            todo!();
+        },
+
+        #[code(0x130)]
+        fn Glk() {
+            todo!();
+        },
+
+        #[code(0x140)]
+        fn Getstringtbl() {
+            todo!();
+        },
+
+        #[code(0x141)]
+        fn Setstringtbl() {
+            todo!();
+        },
+
+        #[code(0x148)]
+        fn Getiosys() {
+            todo!();
+        },
+
+        #[code(0x149)]
+        fn Setiosys(&mut interpreter, mode: u32, rock: u32) {
+            match mode {
+                0 => {
+                    interpreter.output_mode = Output::Null;
+                },
+                1 => {
+                    interpreter.output_mode = Output::Filter(rock);
+                },
+                2 => {
+                    interpreter.output_mode = Output::Glk(Glk {}, rock);
+                },
+                20 => {
+                    panic!("This interpreter does not support FyreVM");
+                },
+                _ => {
+                    panic!("Unknown iosys mode {mode}");
+                }
             }
+        },
+
+        #[code(0x150)]
+        fn Linearsearch() {
+            todo!();
+        },
+
+        #[code(0x151)]
+        fn Binarysearch() {
+            todo!();
+        },
+
+        #[code(0x152)]
+        fn Linkedsearch() {
+            todo!();
+        },
+
+        #[code(0x160), no_store]
+        fn Callf(&mut interpreter, func_addr: u32) -> u32 {
+            interpreter.create_return_stub();
+            interpreter.call_function(func_addr, Vec::new());
+
+            // This gets ignored because of gen_return_stub but it's here for type reasons
+            return 0;
+        },
+
+        #[code(0x161)]
+        fn Callfi() {
+            todo!();
+        },
+
+        #[code(0x162)]
+        fn Callfii() {
+            todo!();
+        },
+
+        #[code(0x163)]
+        fn Callfiii() {
+            todo!();
+        },
+
+        #[code(0x170)]
+        fn Mzero() {
+            todo!();
+        },
+
+        #[code(0x171)]
+        fn Mcopy() {
+            todo!();
+        },
+
+        #[code(0x178)]
+        fn Malloc() {
+            todo!();
+        },
+
+        #[code(0x179)]
+        fn Mfree() {
+            todo!();
+        },
+
+        #[code(0x180)]
+        fn Accelfunc() {
+            todo!();
+        },
+
+        #[code(0x181)]
+        fn Accelparam() {
+            todo!();
+        },
+
+        #[code(0x190)]
+        fn Numtof() {
+            todo!();
+        },
+
+        #[code(0x191)]
+        fn Ftonumz() {
+            todo!();
+        },
+
+        #[code(0x192)]
+        fn Ftonumn() {
+            todo!();
+        },
+
+        #[code(0x198)]
+        fn Ceil() {
+            todo!();
+        },
+
+        #[code(0x199)]
+        fn Floor() {
+            todo!();
+        },
+
+        #[code(0x1A0)]
+        fn Fadd() {
+            todo!();
+        },
+
+        #[code(0x1A1)]
+        fn Fsub() {
+            todo!();
+        },
+
+        #[code(0x1A2)]
+        fn Fmul() {
+            todo!();
+        },
+
+        #[code(0x1A3)]
+        fn Fdiv() {
+            todo!();
+        },
+
+        #[code(0x1A4)]
+        fn Fmod() {
+            todo!();
+        },
+
+        #[code(0x1A8)]
+        fn Sqrt() {
+            todo!();
+        },
+
+        #[code(0x1A9)]
+        fn Exp() {
+            todo!();
+        },
+
+        #[code(0x1AA)]
+        fn Log() {
+            todo!();
+        },
+
+        #[code(0x1AB)]
+        fn Pow() {
+            todo!();
+        },
+
+        #[code(0x1B0)]
+        fn Sin() {
+            todo!();
+        },
+
+        #[code(0x1B1)]
+        fn Cos() {
+            todo!();
+        },
+
+        #[code(0x1B2)]
+        fn Tan() {
+            todo!();
+        },
+
+        #[code(0x1B3)]
+        fn Asin() {
+            todo!();
+        },
+
+        #[code(0x1B4)]
+        fn Acos() {
+            todo!();
+        },
+
+        #[code(0x1B5)]
+        fn Atan() {
+            todo!();
+        },
+
+        #[code(0x1B6)]
+        fn Atan2() {
+            todo!();
+        },
+
+        #[code(0x1C0)]
+        fn Jfeq() {
+            todo!();
+        },
+
+        #[code(0x1C1)]
+        fn Jfne() {
+            todo!();
+        },
+
+        #[code(0x1C2)]
+        fn Jflt() {
+            todo!();
+        },
+
+        #[code(0x1C3)]
+        fn Jfle() {
+            todo!();
+        },
+
+        #[code(0x1C4)]
+        fn Jfgt() {
+            todo!();
+        },
+
+        #[code(0x1C5)]
+        fn Jfge() {
+            todo!();
+        },
+
+        #[code(0x1C8)]
+        fn Jisnan() {
+            todo!();
+        },
+
+        #[code(0x1C9)]
+        fn Jisinf() {
+            todo!();
+        },
+
+        #[code(0x200)]
+        fn Numtod() {
+            todo!();
+        },
+
+        #[code(0x201)]
+        fn Dtonumz() {
+            todo!();
+        },
+
+        #[code(0x202)]
+        fn Dtonumn() {
+            todo!();
+        },
+
+        #[code(0x203)]
+        fn Ftod() {
+            todo!();
+        },
+
+        #[code(0x204)]
+        fn Dtof() {
+            todo!();
+        },
+
+        #[code(0x208)]
+        fn Dceil() {
+            todo!();
+        },
+
+        #[code(0x209)]
+        fn Dfloor() {
+            todo!();
+        },
+
+        #[code(0x210)]
+        fn Dadd() {
+            todo!();
+        },
+
+        #[code(0x211)]
+        fn Dsub() {
+            todo!();
+        },
+
+        #[code(0x212)]
+        fn Dmul() {
+            todo!();
+        },
+
+        #[code(0x213)]
+        fn Ddiv() {
+            todo!();
+        },
+
+        #[code(0x214)]
+        fn Dmodr() {
+            todo!();
+        },
+
+        #[code(0x215)]
+        fn Dmodq() {
+            todo!();
+        },
+
+        #[code(0x218)]
+        fn Dsqrt() {
+            todo!();
+        },
+
+        #[code(0x219)]
+        fn Dexp() {
+            todo!();
+        },
+
+        #[code(0x21A)]
+        fn Dlog() {
+            todo!();
+        },
+
+        #[code(0x21B)]
+        fn Dpow() {
+            todo!();
+        },
+
+        #[code(0x220)]
+        fn Dsin() {
+            todo!();
+        },
+
+        #[code(0x221)]
+        fn Dcos() {
+            todo!();
+        },
+
+        #[code(0x222)]
+        fn Dtan() {
+            todo!();
+        },
+
+        #[code(0x223)]
+        fn Dasin() {
+            todo!();
+        },
+
+        #[code(0x224)]
+        fn Dacos() {
+            todo!();
+        },
+
+        #[code(0x225)]
+        fn Datan() {
+            todo!();
+        },
+
+        #[code(0x226)]
+        fn Datan2() {
+            todo!();
+        },
+
+        #[code(0x230)]
+        fn Jdeq() {
+            todo!();
+        },
+
+        #[code(0x231)]
+        fn Jdne() {
+            todo!();
+        },
+
+        #[code(0x232)]
+        fn Jdlt() {
+            todo!();
+        },
+
+        #[code(0x233)]
+        fn Jdle() {
+            todo!();
+        },
+
+        #[code(0x234)]
+        fn Jdgt() {
+            todo!();
+        },
+
+        #[code(0x235)]
+        fn Jdge() {
+            todo!();
+        },
+
+        #[code(0x238)]
+        fn Jdisnan() {
+            todo!();
+        },
+
+        #[code(0x239)]
+        fn Jdisinf() {
+            todo!();
         }
     }
 );