diff options
Diffstat (limited to 'src/interpreter.rs')
-rw-r--r-- | src/interpreter.rs | 302 |
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; + } +} |