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> } pub enum Output { Null, Filter(FunctionPointer), Glk(Glk), } pub struct Interpreter { memory: Vec, stack: Vec, mem_writeable: MemAddress, mem_min: MemAddress, heap: Vec, reg_program: MemAddress, reg_stack: StackAddress, reg_frame: StackAddress, reg_strdec: MemAddress, output_mode: Output, } impl Interpreter { pub fn init( mut source_file: Vec, 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) -> 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; } }