diff --git a/vm/src/vm/execution.rs b/vm/src/vm/execution.rs index aaa5d8f4c..822dff66c 100644 --- a/vm/src/vm/execution.rs +++ b/vm/src/vm/execution.rs @@ -5,7 +5,7 @@ use std::{ use crate::vm::instructions::{ArithOp, Comparison, Instruction, LoadStoreWidth}; -pub fn run_program(instruction_map: BTreeMap, entrypoint: u32) -> (u32, u32) { +pub fn run_program(instruction_map: BTreeMap, entrypoint: u32) -> (i32, i32) { let mut memory = Memory::default(); load_program(instruction_map, &mut memory); run_from_entrypoint(&mut memory, entrypoint) @@ -17,16 +17,17 @@ fn load_program(instruction_map: BTreeMap, memory: &mut Memory) { } } -fn run_from_entrypoint(memory: &mut Memory, entrypoint: u32) -> (u32, u32) { +fn run_from_entrypoint(memory: &mut Memory, entrypoint: u32) -> (i32, i32) { let mut pc = entrypoint; let mut registers = Registers::default(); + registers.0[2] = 0xFFFFFFFF; // 4GB while pc != registers.0[1] { let next_instruction = memory.0[&pc]; let instruction = Instruction::parse(next_instruction); run_instruction(&instruction, &mut registers, &mut pc, memory); } println!("Final Register Values:\n {}", ®isters); - let return_values = (registers.0[10], registers.0[11]); + let return_values = (registers.0[10] as i32, registers.0[11] as i32); println!("Return Values: {return_values:?}"); return_values } @@ -45,6 +46,7 @@ struct Registers([u32; 32]); impl Display for Registers { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { writeln!(f, "Registers:")?; + writeln!(f, "Zero(zero): {}", self.0[0])?; writeln!(f, "ReturnAddress(ra): {}", self.0[1])?; writeln!(f, "StackPointer(sp): {}", self.0[2])?; // Not used for now @@ -74,20 +76,33 @@ fn run_instruction( *pc += 4; match inst { Instruction::ArithImm { dst, src, imm, op } => { - let (a, b) = (registers.0[*src as usize], imm); + let (a, b) = (registers.0[*src as usize] as i32, *imm); let res = match op { ArithOp::Add => a + b, - _ => unimplemented!(), + ArithOp::Sub => panic!("SubImm not supported"), + ArithOp::Xor => a ^ b, + ArithOp::Or => a | b, + ArithOp::And => a & b, + ArithOp::ShiftLeftLogical => a << b, + ArithOp::ShiftRightLogical => a >> b, + ArithOp::ShiftRightArith => a >> b, + ArithOp::SetLessThan => (a < b) as i32, + ArithOp::SetLessThanU => ((a as u32) < (b as u32)) as i32, }; - registers.0[*dst as usize] = res; + registers.0[*dst as usize] = res as u32; } Instruction::JumpAndLinkRegister { dst, base, offset } => { - registers.0[*dst as usize] = *pc; - *pc = registers.0[*base as usize] + offset; + if *dst != 0 { + registers.0[*dst as usize] = *pc; + } + *pc = (registers.0[*base as usize] as i32 + offset) as u32; } Instruction::JumpAndLink { dst, offset } => { - registers.0[*dst as usize] = *pc; - *pc += offset; + if *dst != 0 { + registers.0[*dst as usize] = *pc; + } + *pc -= 4; + *pc = (*pc as i32 + offset) as u32; } Instruction::Store { src, @@ -101,7 +116,9 @@ fn run_instruction( LoadStoreWidth::Half => todo!(), LoadStoreWidth::Word => value, }; - memory.0.insert(*base + *offset, value); + memory + .0 + .insert(registers.0[*base as usize] + *offset, value); } Instruction::Load { dst, @@ -109,7 +126,7 @@ fn run_instruction( base, width, } => { - let value = memory.0[&(*base + *offset)]; + let value = memory.0[&((registers.0[*base as usize] as i32 + *offset) as u32)]; let value = match width { LoadStoreWidth::Byte => todo!(), LoadStoreWidth::Half => todo!(), diff --git a/vm/src/vm/instructions.rs b/vm/src/vm/instructions.rs index e6822e5d6..2370dce1d 100644 --- a/vm/src/vm/instructions.rs +++ b/vm/src/vm/instructions.rs @@ -7,7 +7,6 @@ const BRANCH_OPCODE: u32 = 0b1100011; const JUMP_AND_LINK_REGISTER_OPCCODE: u32 = 0b1100111; const JUMP_AND_LINK_OPCCODE: u32 = 0b1101111; -// TODO: consider using num_enum dep to replace TyFrom/ using the constants here enum Opcode { Arith, ArithImm, @@ -112,17 +111,17 @@ pub enum Instruction { ArithImm { dst: u32, src: u32, - imm: u32, + imm: i32, op: ArithOp, }, JumpAndLink { dst: u32, - offset: u32, + offset: i32, }, JumpAndLinkRegister { base: u32, dst: u32, - offset: u32, + offset: i32, }, Store { src: u32, @@ -132,7 +131,7 @@ pub enum Instruction { }, Load { dst: u32, - offset: u32, + offset: i32, base: u32, width: LoadStoreWidth, }, @@ -150,6 +149,8 @@ const FUNC3_MASK: u32 = 0x00007000; const RS1_MASK: u32 = 0x000f8000; const RS2_MASK: u32 = 0x01f00000; const RD_MASK: u32 = 0x00000f80; +const SIGN_MASK: u32 = 0x80000000; +const I_TYPE_IMM_MASK: u32 = 0x7ff; impl Instruction { pub fn parse(instruction: u32) -> Instruction { @@ -231,11 +232,15 @@ const SLTU_FUNC_IDENTIFIER: u32 = 0x3; // | imm | rs1 |funct3| rd |opcode| // |31..20|19..15|14..12|11..7| 6..0 | fn parse_i_instruction(instruction: u32, opcode: Opcode) -> Instruction { - let func7 = (instruction & FUNC7_MASK) >> 25; let func3 = (instruction & FUNC3_MASK) >> 12; - let rs2 = (instruction & RS2_MASK) >> 20; let rs1 = (instruction & RS1_MASK) >> 15; - let mut imm = func7 | rs2; + let imm = ((instruction >> 20) & I_TYPE_IMM_MASK) as i32; + let mut imm: i32 = if (instruction & SIGN_MASK) != 0 { + imm - (1 << 11) + } else { + imm + }; + let rd = (instruction & RD_MASK) >> 7; match opcode { Opcode::ArithImm => { @@ -353,6 +358,11 @@ fn parse_b_instruction(instruction: u32, opcode: Opcode) -> Instruction { fn parse_j_instruction(instruction: u32, opcode: Opcode) -> Instruction { let imm = instruction & 0xff000 | ((instruction & 0x100000) >> 9) | ((instruction >> 20) & 0x7fe); + let imm: i32 = if (instruction & SIGN_MASK) != 0 { + imm as i32 - (1 << 20) + } else { + imm as i32 + }; let rd = (instruction & RD_MASK) >> 7; match opcode { Opcode::JumpAndLink => Instruction::JumpAndLink {