Skip to content
41 changes: 29 additions & 12 deletions vm/src/vm/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::{

use crate::vm::instructions::{ArithOp, Comparison, Instruction, LoadStoreWidth};

pub fn run_program(instruction_map: BTreeMap<u32, u32>, entrypoint: u32) -> (u32, u32) {
pub fn run_program(instruction_map: BTreeMap<u32, u32>, entrypoint: u32) -> (i32, i32) {
let mut memory = Memory::default();
load_program(instruction_map, &mut memory);
run_from_entrypoint(&mut memory, entrypoint)
Expand All @@ -17,16 +17,17 @@ fn load_program(instruction_map: BTreeMap<u32, u32>, 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 {}", &registers);
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
}
Expand All @@ -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
Expand Down Expand Up @@ -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,
Expand All @@ -101,15 +116,17 @@ 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,
offset,
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!(),
Expand Down
26 changes: 18 additions & 8 deletions vm/src/vm/instructions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand All @@ -132,7 +131,7 @@ pub enum Instruction {
},
Load {
dst: u32,
offset: u32,
offset: i32,
base: u32,
width: LoadStoreWidth,
},
Expand All @@ -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 {
Expand Down Expand Up @@ -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 => {
Expand Down Expand Up @@ -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 {
Expand Down