From f26f6475ccd44ed14094075fb03e90c6aa640523 Mon Sep 17 00:00:00 2001 From: Ashelyn Rose Date: Fri, 6 Dec 2024 20:07:17 -0700 Subject: Minimum opcodes to run to completion --- src/instructions.rs | 7 - src/interpreter.rs | 471 +++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 451 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/instructions.rs b/src/instructions.rs index 8fa409c..59efd47 100644 --- a/src/instructions.rs +++ b/src/instructions.rs @@ -34,14 +34,10 @@ impl Instruction { let operation = OpCode::from_bytes(instruction_bytes); let operand_count = operation.get_operand_count(); - println!("Parsing {operand_count} operands for {operation:?}"); let operand_bytes = (operand_count + 1) / 2; let skip_last_half = operand_bytes != operand_count / 2; - println!("Reading {operand_bytes} bytes for operands and {}", if skip_last_half {"ignoring the last 4 bits"} else {"keeping the last 4 bits"}); let operand_bytes = (0..operand_bytes).into_iter().map(|_n| *bytes.next().unwrap().1); - println!("- check: byte array is {} long", operand_bytes.len()); let halfbytes : Vec<_> = operand_bytes.flat_map(|byte| vec![(byte, Nybble::Low), (byte, Nybble::High)]).collect(); - println!("- check: halfbyte array is {} long", halfbytes.len()); // Just ensure other borrows to the byte array have closed by rebinding it // This verifies we're at the operand data position @@ -96,7 +92,6 @@ impl OpCode { 0b11 => 4, _ => unreachable!() }; - println!("Opcode first byte: {first_byte:02x}, instruction length: {length} bytes"); return length } @@ -107,10 +102,8 @@ impl OpCode { 4 => ([bytes[0],bytes[1],bytes[2],bytes[3]], 0xC0000000), _ => panic!("Invalid opcode byte array") }; - println!("Read {} bytes: {bytes:?}", bytes.len()); let instruction = u32::from_be_bytes(padded_bytes) & !mask; - println!("Transmuting opcode 0x{instruction:03x}"); return unsafe { std::mem::transmute(instruction) } } diff --git a/src/interpreter.rs b/src/interpreter.rs index 39a33a8..800ebf0 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -1,6 +1,6 @@ use core::panic; -use crate::{glk::Glk, instructions::Instruction}; +use crate::{glk::Glk, instructions::{Instruction, Operand}}; pub type MemAddress = u32; pub type StackAddress = u32; @@ -92,20 +92,397 @@ impl Interpreter { let (instruction, bytes_read) = Instruction::read(&mut instruction_slice); self.reg_program += bytes_read; - println!("Parsed instruction {instruction:?}"); + 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::>(); + 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]); + 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!(), + } } } - fn create_return_stub(&mut self, dest_type: StubDestType, dest_addr: u32, program_counter: MemAddress, frame_pointer: StackAddress) { + fn call_function(&mut self, func_addr: FunctionPointer, args: Vec, 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); + + let new_program_counter = self.create_stack_frame(func_addr, args); + self.reg_program = new_program_counter; + } + fn create_return_stub(&mut self, dest_type: StubDestType, dest_addr: u32, program_counter: MemAddress, frame_pointer: StackAddress) { + self.push_stack(dest_type as u32); + self.push_stack(dest_addr); + self.push_stack(program_counter); + self.push_stack(frame_pointer); } // 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); @@ -132,7 +509,7 @@ impl Interpreter { format_of_locals.push(format); }; - let opcode_start = local_pointer + 2; + let opcode_start = local_pointer; // Writing stack frame self.reg_frame = self.reg_stack; @@ -140,13 +517,11 @@ impl Interpreter { 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; @@ -163,8 +538,6 @@ impl Interpreter { 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), @@ -178,7 +551,6 @@ impl Interpreter { // 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; @@ -191,15 +563,26 @@ impl Interpreter { } } - println!("Ending frame ptr: {}", self.reg_frame); - println!("Ending stack ptr: {}", self.reg_stack); + return opcode_start; + } - 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])); - } + fn return_from_function(&mut self, value: u32) { + todo!("Return not implemented"); + } - return opcode_start; + fn jump_with_offset(&mut self, offset: u32) { + if offset == 1 || offset == 0 { + return self.return_from_function(offset); + } + + let offset = offset as i32; + let destination = if offset < 0 { + self.reg_program - -offset as u32 + } else { + self.reg_program + offset as u32 + }; + + self.reg_program = destination; } fn push_stack(&mut self, value: u32) { @@ -212,6 +595,54 @@ impl Interpreter { self.get_word(self.reg_stack, ReadWriteDest::Stack) } + fn eval_source_operand(&mut self, operand: &Operand) -> u32 { + match operand { + Operand::Constant(value) => *value as u32, + Operand::PopStack => self.pop_stack(), + Operand::FrameIndirect(offset) => { + let start_of_locals = self.get_word(self.reg_frame, ReadWriteDest::Stack); + assert!(start_of_locals + offset < self.reg_stack, "Frame offset out of frame"); + self.get_word(start_of_locals + offset, ReadWriteDest::Stack) + }, + Operand::MemIndirect(address) => { + // TODO: Handle heap + assert!(*address < self.memory.len() as u32 - 4, "Memory offset out of memory"); + self.get_word(*address, ReadWriteDest::Memory) + }, + Operand::MemRamIndirect(offset) => { + let address = self.mem_writeable + offset; + // TODO: Handle heap + assert!(address < self.memory.len() as u32 - 4, "Memory offset out of memory"); + self.get_word(address, ReadWriteDest::Memory) + }, + } + } + + fn store_dest_operand(&mut self, operand: &Operand, value: u32) { + match operand { + Operand::Constant(0) => (), + Operand::Constant(constant_dst) => panic!("Cannot store to constant operand {constant_dst}"), + Operand::PopStack => self.push_stack(value), + Operand::FrameIndirect(offset) => { + let start_of_locals = self.get_word(self.reg_frame, ReadWriteDest::Stack); + assert!(start_of_locals + offset < self.reg_stack, "Frame offset out of frame"); + self.write_word(start_of_locals + offset, ReadWriteDest::Stack, value) + }, + Operand::MemIndirect(address) => { + assert!(*address >= self.mem_writeable, "Cannot write to ROM"); + // TODO: Handle heap + assert!(*address < self.memory.len() as u32 - 4, "Memory offset out of memory"); + self.write_word(*address, ReadWriteDest::Memory, value) + }, + Operand::MemRamIndirect(offset) => { + let address = self.mem_writeable + offset; + // TODO: Handle heap + assert!(address < self.memory.len() as u32 - 4, "Memory offset out of memory"); + self.write_word(address, ReadWriteDest::Memory, value) + }, + } + } + fn get_byte(&self, addr: u32, src: ReadWriteDest) -> u8 { let addr = addr as usize; let buffer = match src { -- cgit 1.4.1