summary refs log tree commit diff
path: root/src/interpreter.rs
diff options
context:
space:
mode:
authorAshelyn Rose <git@ashen.earth>2024-12-06 11:27:34 -0700
committerAshelyn Rose <git@ashen.earth>2024-12-06 11:27:34 -0700
commitb902c11b89edc2d4e91d4bd1582792c9303bf874 (patch)
treeb04b8dcac49af4cd0ebb71c70872b35da9d5baba /src/interpreter.rs
Initial loading code
Diffstat (limited to 'src/interpreter.rs')
-rw-r--r--src/interpreter.rs302
1 files changed, 302 insertions, 0 deletions
diff --git a/src/interpreter.rs b/src/interpreter.rs
new file mode 100644
index 0000000..bc51754
--- /dev/null
+++ b/src/interpreter.rs
@@ -0,0 +1,302 @@
+use core::panic;
+
+use crate::glk::Glk;
+
+pub type MemAddress = u32;
+pub type StackAddress = u32;
+pub type FunctionPointer = MemAddress;
+
+enum StubDestType {
+    DoNotStore = 0,
+    MainMemory = 1,
+    LocalVariable = 2,
+    PushOnStack = 3,
+    ResumeCompressedString = 10,
+    ResumeFunctionFromString = 11,
+    ResumeInteger = 12,
+    ResumeCString = 13,
+    ResumeUnicodeString = 14,
+}
+
+enum Nybble {
+    High,
+    Low,
+}
+
+enum Operand {
+    Constant(i32),
+    PopStack,
+    FrameIndirect(StackAddress),
+    MemIndirect(MemAddress),
+    MemRamIndirect(MemAddress),
+}
+
+enum ReadWriteDest {
+    Stack,
+    Memory,
+}
+
+pub struct HeapChunk {
+    pub start_address: MemAddress,
+    pub length: u32,
+    pub contents: Option<Vec<u32>>
+}
+
+pub enum Output {
+    Null,
+    Filter(FunctionPointer),
+    Glk(Glk),
+}
+
+pub struct Interpreter {
+    memory: Vec<u8>,
+    stack: Vec<u8>,
+    mem_writeable: MemAddress,
+    mem_min: MemAddress,
+    heap: Vec<HeapChunk>,
+
+    reg_program: MemAddress,
+    reg_stack: StackAddress,
+    reg_frame: StackAddress,
+    reg_strdec: MemAddress,
+
+    output_mode: Output,
+}
+
+impl Interpreter {
+    pub fn init(
+        mut source_file: Vec<u8>,
+        ram_start: u32,
+        ext_start: u32,
+        ram_end: u32,
+        stack_size: u32,
+        str_decode: u32,
+    ) -> Self {
+        // Trick to ensure everything after ext_start is cleared
+        // even if the original file was longer
+        source_file.resize(ext_start as usize, 0);
+        source_file.resize(ext_start as usize, 0);
+
+        let mut stack = Vec::new();
+        stack.resize(stack_size as usize, 0);
+        
+        Self {
+            memory: source_file,
+            stack,
+            mem_writeable: ram_start,
+            mem_min: ram_end,
+            heap: Vec::new(),
+
+            reg_program: 0,
+            reg_stack: 0,
+            reg_frame: 0,
+            reg_strdec: str_decode,
+
+            output_mode: Output::Null,
+        }
+    }
+
+    pub fn run(&mut self, entry_func: MemAddress) {
+        self.reg_program = self.create_stack_frame(entry_func, Vec::new());
+
+        loop {
+            let instruction = self.load_program_instruction();
+
+            match instruction {
+                _ => todo!("Haven't done any of the instruction loading yet")
+            }
+        }
+    }
+
+    fn create_return_stub(&mut self, dest_type: StubDestType, dest_addr: u32, program_counter: MemAddress, frame_pointer: StackAddress) {
+
+    }
+
+    // Returns program counter after parsing all the args
+    fn create_stack_frame(&mut self, func: FunctionPointer, mut args: Vec<u32>) -> MemAddress {
+        println!("create_stack_frame: Loading function from {func:x}");
+
+        println!("Initial frame ptr: {}", self.reg_frame);
+        println!("Initial stack ptr: {}", self.reg_stack);
+
+        // Reading function signature
+        let func_type = self.get_byte(func, ReadWriteDest::Memory);
+        let args_in_locals = match func_type {
+            0xC0 => false,
+            0xC1 => true,
+            _ => panic!("Tried to call object that is not a function: {}", func_type),
+        };
+
+        let mut local_pointer = func + 1;
+        let mut format_of_locals = Vec::<(u8, u8)>::new();
+        loop {
+            let format = (
+                self.get_byte(local_pointer, ReadWriteDest::Memory),
+                self.get_byte(local_pointer + 1, ReadWriteDest::Memory),
+            );
+
+            local_pointer += 2;
+
+            if format == (0,0) {
+                break
+            }
+
+            format_of_locals.push(format);
+        };
+
+        let opcode_start = local_pointer + 1;
+
+        // Writing stack frame
+        self.reg_frame = self.reg_stack;
+        let mut header_len = 4 + 4 + format_of_locals.len() as StackAddress * 2;
+        Interpreter::align_ptr(&mut header_len, 16);
+
+        // Write locals pos
+        println!("Writing locals pos ({header_len}) to frame + 4 ({})", self.reg_frame + 4);
+        self.write_word(self.reg_frame + 4, ReadWriteDest::Stack, header_len);
+
+        // Write format of locals
+        let mut local_format_ptr = self.reg_frame + 8;
+        for (local_type, local_count) in format_of_locals.iter() {
+            println!("Writing local format ({}, {}) to {}", local_type, local_count, local_format_ptr);
+            self.write_byte(local_format_ptr, ReadWriteDest::Stack, *local_type);
+            self.write_byte(local_format_ptr + 1, ReadWriteDest::Stack, *local_count);
+            local_format_ptr += 2;
+        }
+
+        // Write locals
+        let mut local_pos = self.reg_frame+ header_len;
+        for (local_type, local_count) in format_of_locals {
+            Interpreter::align_ptr(&mut local_pos, local_type * 8);
+
+            for _count in 0..local_count {
+                let value = match args_in_locals {
+                    true => if args.len() > 0 {args.remove(0)} else {0}
+                    false => 0,
+                };
+
+                println!("Writing local variable ({}, {} bytes) to {}", value, local_type, local_pos);
+
+                match local_type {
+                    1 => self.write_byte(local_pos, ReadWriteDest::Stack, value as u8),
+                    2 => self.write_twobyte(local_pos, ReadWriteDest::Stack, value as u16),
+                    4 => self.write_word(local_pos, ReadWriteDest::Stack, value),
+                    _ => panic!("Invalid local type {local_type}")
+                }
+
+                local_pos += local_type as u32;
+            }
+        }
+        
+        // Write frame len
+        Interpreter::align_ptr(&mut local_pos, 32);
+        println!("Writing frame len ({}) to frame ptr ({})", local_pos - self.reg_frame, self.reg_frame);
+        self.write_word(self.reg_frame, ReadWriteDest::Stack, local_pos - self.reg_frame);
+        self.reg_stack = local_pos;
+
+        // Handle stack args
+        if !args_in_locals {
+            args.reverse();
+            for arg in args {
+                println!("Adding value to stack {arg}");
+                self.push_stack(arg);
+            }
+        }
+
+        println!("Ending frame ptr: {}", self.reg_frame);
+        println!("Ending stack ptr: {}", self.reg_stack);
+
+        for [a, b, c, d] in self.stack[self.reg_frame as usize..self.reg_stack as usize].iter()
+            .array_chunks::<4>() {
+                println!("{a:02x} {b:02x} {c:02x} {d:02x} ({})", u32::from_be_bytes([*a,*b,*c,*d]));
+            }
+
+        return opcode_start;
+    }
+
+    fn load_program_instruction(&mut self) {
+
+    }
+
+    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 {
+        self.reg_stack -= 4;
+        self.get_word(self.reg_stack, ReadWriteDest::Stack)
+    }
+
+    fn get_byte(&self, addr: u32, src: ReadWriteDest) -> u8 {
+        let addr = addr as usize;
+        let buffer = match src {
+            ReadWriteDest::Stack => &self.stack,
+            ReadWriteDest::Memory => &self.memory,
+        };
+
+        buffer[addr]
+    }
+
+    fn get_twobyte(&self, addr: u32, src: ReadWriteDest) -> u16 {
+        let addr = addr as usize;
+        let buffer = match src {
+            ReadWriteDest::Stack => &self.stack,
+            ReadWriteDest::Memory => &self.memory,
+        };
+
+        u16::from_be_bytes(buffer[addr..addr+2].try_into().unwrap())
+    }
+
+    fn get_word(&self, addr: u32, src: ReadWriteDest) -> u32 {
+        let addr = addr as usize;
+        let buffer = match src {
+            ReadWriteDest::Stack => &self.stack,
+            ReadWriteDest::Memory => &self.memory,
+        };
+
+        u32::from_be_bytes(buffer[addr..addr+4].try_into().unwrap())
+    }
+
+    fn write_byte(&mut self, addr: u32, dst: ReadWriteDest, value: u8) {
+        let addr = addr as usize;
+        let buffer = match dst {
+            ReadWriteDest::Stack => &mut self.stack,
+            ReadWriteDest::Memory => &mut self.memory,
+        };
+
+        buffer[addr] = value;
+    }
+
+    fn write_twobyte(&mut self, addr: u32, dst: ReadWriteDest, value: u16) {
+        let addr = addr as usize;
+        let buffer = match dst {
+            ReadWriteDest::Stack => &mut self.stack,
+            ReadWriteDest::Memory => &mut self.memory,
+        };
+
+        buffer[addr..addr+2].copy_from_slice(&value.to_be_bytes());
+    }
+
+    fn write_word(&mut self, addr: u32, dst: ReadWriteDest, value: u32) {
+        let addr = addr as usize;
+        let buffer = match dst {
+            ReadWriteDest::Stack => &mut self.stack,
+            ReadWriteDest::Memory => &mut self.memory,
+        };
+
+        buffer[addr..addr+4].copy_from_slice(&value.to_be_bytes());
+    }
+
+    fn align_ptr(ptr: &mut u32, align_size: u8) {
+        let modulo = match align_size {
+            8 => 1,
+            16 => 2,
+            32 => 4,
+            _ => panic!("Invalid alignment: {align_size}"),
+        };
+
+        let bytes_off = *ptr % modulo;
+        *ptr += bytes_off;
+    }
+}