diff --git a/src/bus.rs b/src/bus.rs index e7eda55..4cc8be6 100644 --- a/src/bus.rs +++ b/src/bus.rs @@ -4,7 +4,7 @@ use crate::rv32; use crate::ram; pub struct Bus { - pub memory: ram::RAM, + memory: ram::RAM, } impl Bus { @@ -59,4 +59,42 @@ impl Bus { }, } } + + pub fn store_8(&mut self, address: rv32::XLen, data: rv32::Byte) { + match address { + DRAM_BASE.. => { + self.memory.write_8(address, data) + }, + _ => { + println!("VM > BUS > Peripheral at 0x{:08x} does not exist", address); + }, + } + } + + + pub fn store_16(&mut self, address: rv32::XLen, data: rv32::HalfWord) { + match address { + _ => { + println!("VM > BUS > Peripheral at 0x{:08x} does not exist", address); + }, + } + } + + + pub fn store_32(&mut self, address: rv32::XLen, data: rv32::Word) { + match address { + _ => { + println!("VM > BUS > Peripheral at 0x{:08x} does not exist", address); + }, + } + } + + + pub fn store_64(&mut self, address: rv32::XLen, data: rv32::DoubleWord) { + match address { + _ => { + println!("VM > BUS > Peripheral at 0x{:08x} does not exist", address); + }, + } + } } diff --git a/src/inst.rs b/src/inst.rs index cc038b1..22238b8 100644 --- a/src/inst.rs +++ b/src/inst.rs @@ -2,78 +2,110 @@ use modular_bitfield::prelude::*; use crate::rv32; +pub const R_TYPE: u8 = 0b00110011; +pub const I_TYPE: u8 = 0b00010011; +pub const S_TYPE: u8 = 0b00100011; +pub const B_TYPE: u8 = 0b01100011; +pub const U_TYPE: u8 = 0b00110111; +pub const J_TYPE: u8 = 0b01110011; + +// Null undecided type +#[bitfield] +#[derive(Debug)] +pub struct NullType { + pub opcode: B7, + pub _undefined: B25, +} + // Arithmetic logic #[bitfield] +#[derive(Debug)] pub struct RType { - opcode: B7, - rd: B5, - funct3: B3, - rs1: B5, - rs2: B5, - funct7: B7, + pub opcode: B7, + pub rd: B5, + pub funct3: B3, + pub rs1: B5, + pub rs2: B5, + pub funct7: B7, } // Loads & immeiate arithmetic #[bitfield] +#[derive(Debug)] pub struct IType { - opcode: B7, - rd: B5, - funct3: B3, - rs1: B5, - imm: B12, + pub opcode: B7, + pub rd: B5, + pub funct3: B3, + pub rs1: B5, + pub imm: B12, } // Stores #[bitfield] +#[derive(Debug)] pub struct SType { - opcode: B7, - imm_l: B5, - funct3: B3, - rs1: B5, - rs2: B5, - imm_h: B7, + pub opcode: B7, + pub imm_l: B5, + pub funct3: B3, + pub rs1: B5, + pub rs2: B5, + pub imm_h: B7, } // Conditional jump #[bitfield] +#[derive(Debug)] pub struct BType { - opcode: B7, - imm_11: B1, - imm_4_1: B4, - funct3: B3, - rs1: B5, - rs2: B5, - imm_10_5: B6, - imm_12: B1, + pub opcode: B7, + pub imm_11: B1, + pub imm_4_1: B4, + pub funct3: B3, + pub rs1: B5, + pub rs2: B5, + pub imm_10_5: B6, + pub imm_12: B1, } // Upper immediate #[bitfield] +#[derive(Debug)] pub struct UType { - opcode: B7, - rd: B5, - imm: B20, + pub opcode: B7, + pub rd: B5, + pub imm: B20, } - // Unconditional jump #[bitfield] +#[derive(Debug)] pub struct JType { - opcode: B7, - rd: B5, - imm_19_12: B8, - imm_11: B1, - imm_10_1: B10, - imm_20: B1, + pub opcode: B7, + pub rd: B5, + pub imm_19_12: B8, + pub imm_11: B1, + pub imm_10_1: B10, + pub imm_20: B1, } +/* #[derive(Debug)] +pub enum Decode { + null(std::mem::ManuallyDrop), + R(std::mem::ManuallyDrop), + I(std::mem::ManuallyDrop), + S(std::mem::ManuallyDrop), + B(std::mem::ManuallyDrop), + U(std::mem::ManuallyDrop), + J(std::mem::ManuallyDrop), +} */ + #[repr(align(8))] pub union Instruction { pub inst: rv32::Word, - pub r: std::mem::ManuallyDrop, - pub i: std::mem::ManuallyDrop, - pub s: std::mem::ManuallyDrop, - pub b: std::mem::ManuallyDrop, - pub u: std::mem::ManuallyDrop, - pub j: std::mem::ManuallyDrop, + pub null: std::mem::ManuallyDrop, + pub R: std::mem::ManuallyDrop, + pub I: std::mem::ManuallyDrop, + pub S: std::mem::ManuallyDrop, + pub B: std::mem::ManuallyDrop, + pub U: std::mem::ManuallyDrop, + pub J: std::mem::ManuallyDrop, } diff --git a/src/main.rs b/src/main.rs index b9dead8..dd98ec1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,6 +10,20 @@ mod rv32; use crate::bus::*; +// Register ABI Description Saver +// x0 zero Zero constant — +// x1 ra Return address Callee +// x2 sp Stack pointer Callee +// x3 gp Global pointer — +// x4 tp Thread pointer — +// x5 t0 Temporary link Caller +// x6-x7 t1-t2 Temporaries Caller +// x8 s0 / fp Saved / frame pointer Callee +// x9 s1 Saved register Callee +// x10-x11 a0-a1 Fn args/return values Caller +// x12-x17 a2-a7 Fn args Caller +// x18-x27 s2-s11 Saved registers Callee +// x28-x31 t3-t6 Temporaries Caller struct VMRV32I { // 32 bi bus bus: bus::Bus, @@ -40,7 +54,7 @@ impl VMRV32I { // put program at the base of DRAM for i in 0..buffer.len() { - self.bus.memory.0[i] = buffer[i]; + self.bus.store_8(i as u32 + bus::DRAM_BASE, buffer[i]); } println!("VM > Program loaded to 0x{:08x}", self.pc); @@ -49,7 +63,23 @@ impl VMRV32I { fn dump_prog(&mut self) { println!("VM > Dumping program (virtual addresses)"); for i in 0..12 { - println!("VM > 0x{:08x}: 0x{:02x}", i, self.bus.memory.0[i]); + println!( + "VM > 0x{:08x}: 0x{:02x}", + i, + self.bus.load_8(i + bus::DRAM_BASE) + ); + } + } + + fn dump_reg(&mut self) { + println!("VM > Dumping registers"); + println!("PC : 0x{:08x}", self.pc); + for i in 0..4 { + for j in 0..8 { + let coord = (i * 8) + j; + print!("x{0: <2}: {1: <4}", coord, self.x[coord]); + } + println!(""); } } @@ -61,7 +91,7 @@ impl VMRV32I { self.bus = Bus::new(); self.pc = DRAM_BASE as rv32::Word; self.x[0] = 0x00000000; // x0 is tied to ground - self.x[2] = self.bus.memory.len() as u32; // x2 the addressable space + self.x[2] = ram::DRAM_SIZE as u32; // x2 the addressable } fn fetch(&mut self) -> inst::Instruction { @@ -71,19 +101,46 @@ impl VMRV32I { } fn exec(&mut self) { - while self.pc > self.bus.memory.len() as u32 { + while self.pc > ram::DRAM_SIZE as u32 { // fetch let inst = self.fetch(); println!("VM > Fetched 0x{:08x}: 0x{:08x}", self.pc, unsafe { inst.inst }); self.pc = self.pc + rv32::WORD as u32; - - //decode - - // exec - self.x[0] = 0x00000000; + + // decode and execute + // we can use nulltype to extract the opcode + let opcode = unsafe { inst.null.opcode() }; + // then we can match the opcode to extract the op type + match opcode { + inst::I_TYPE => { + let inst = unsafe { inst.I }; + println!("VM > Decoded I Type instruction {:?}", inst); + match inst.funct3() { + 0x0 => { + self.x[inst.rd() as usize] = + self.x[inst.rs1() as usize].wrapping_add(inst.imm() as u32); + } + _ => println!("VM > INST {:03b} not implemented", inst.funct3()), + }; + } + inst::R_TYPE => { + let inst = unsafe { inst.R }; + println!("VM > Decoded R Type instruction {:?}", inst); + match inst.funct3() { + 0x0 => { + self.x[inst.rd() as usize] = self.x[inst.rs1() as usize] + .wrapping_add(self.x[inst.rs2() as usize]); + } + _ => println!("VM > INST {:03b} not implemented", inst.funct3()), + } + } + _ => println!("VM > OPCODE {:08b} not implemented", opcode), + }; + + self.dump_reg(); } } } diff --git a/src/ram.rs b/src/ram.rs index f6cec79..d9440af 100644 --- a/src/ram.rs +++ b/src/ram.rs @@ -3,7 +3,7 @@ use crate::rv32; //pub const DRAM_SIZE: u32 = 1 * 1024 * 1024 * 1024; // 1GB //pub const DRAM_SIZE: u32 = 1 * 1024; // 1KB -pub const DRAM_SIZE: u32 = 16; +pub const DRAM_SIZE: u32 = 12; pub struct RAM(pub Vec); @@ -54,30 +54,9 @@ impl RAM { ret } - //pub fn read(&mut self, address: rv32::XLen) -> T - //where - //T: num::Num - //+ num::ToPrimitive - //+ Default - //+ std::fmt::LowerHex - //+ std::ops::Shl - //+ std::ops::BitOr - //+ num::cast::NumCast, - //{ - //let address: usize = (address - bus::DRAM_BASE) as usize; - //let memory = &self.0; - - //(address..) - //.take(core::mem::size_of::()) - //.enumerate() - //.fold(T::default(), |mut acc, (i, x)| { - //println!("VM > Reading from 0x{:08x} to 0x{:08x}", x, acc); - //println!("VM > Memory: 0x{:02x}", memory[x]); - //println!("VM > Now Shift: {}", i * 8); - - //acc << u32::from(i as u32 * 8) | memory[x].from() - //}) - //} - - //pub fn write(&mut self, address: rv32::XLen, data: T) {} + pub fn write_8(&mut self, address: rv32::XLen, data: rv32::Byte) { + let memory = &mut self.0; + let address = (address - bus::DRAM_BASE) as usize; + memory[address] = data; + } }