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