diff --git a/src/cpu/mod.rs b/src/cpu/mod.rs new file mode 100644 index 0000000..5c2e9e1 --- /dev/null +++ b/src/cpu/mod.rs @@ -0,0 +1,112 @@ +use std::{cell::RefCell, rc::Rc}; +use crate::bus::*; +use crate::ram; +use crate::inst; +use crate::rv32; + +// Register ABI Description Saver +// x0 zero Zero Immutable +// 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 +pub struct CPU { + x: [rv32::Word; 32], + pc: rv32::Word, + bus: Rc>, + // extensions: +} + +impl CPU { + pub fn new(bus: Rc>) -> CPU { + CPU { + x: [0; 32], + pc: 0, + bus, + } + } + + pub fn init(&mut self) { + println!("VM RISC-V 32I CPU"); + println!("-----------------"); + println!("VM > Initializing CPU"); + + self.pc = DRAM_BASE as rv32::Word; + self.x[0] = 0x00000000; // x0 is tied to ground + self.x[2] = ram::DRAM_SIZE as u32; // x2 the addressable + } + + pub fn get_pc(&mut self) -> rv32::Word { + return self.pc; + } + + fn fetch(&mut self) -> inst::Instruction { + inst::Instruction { + inst: self.bus.borrow_mut().load_32(self.pc), + } + } + + pub fn exec(&mut self) { + while self.pc - DRAM_BASE < 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; + 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(); + } + } + + 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!(""); + } + } +} diff --git a/src/ext/i/mod.rs b/src/ext/i/mod.rs index b28b04f..bdc9623 100644 --- a/src/ext/i/mod.rs +++ b/src/ext/i/mod.rs @@ -1,3 +1,2 @@ - - +lkkll diff --git a/src/ext/mod.rs b/src/ext/mod.rs new file mode 100644 index 0000000..c730e33 --- /dev/null +++ b/src/ext/mod.rs @@ -0,0 +1 @@ +use crate:: diff --git a/src/main.rs b/src/main.rs index 8f922ed..11780ee 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,41 +1,29 @@ +use std::{cell::RefCell, rc::Rc}; use std::fs::File; use std::io::BufReader; use std::io::Read; mod bus; +mod cpu; mod inst; mod ram; mod rv32; use crate::bus::*; +use crate::cpu::*; + -// Register ABI Description Saver -// x0 zero Zero Immutable -// 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 { - bus: bus::Bus, - x: [rv32::Word; 32], - pc: rv32::Word, + bus: Rc>, + cpu: cpu::CPU, } impl VMRV32I { fn new() -> VMRV32I { - VMRV32I { - bus: Bus::new(), - x: [0; 32], - pc: 0, - } + let bus = Rc::new(RefCell::new(Bus::new())); + let mut cpu = CPU::new(Rc::clone(&bus)); + cpu.init(); + VMRV32I { cpu, bus } } fn load_prog(&mut self, file: &str) { @@ -50,10 +38,10 @@ impl VMRV32I { // put program at the base of DRAM for i in 0..buffer.len() { - self.bus.store_8(i as u32 + bus::DRAM_BASE, buffer[i]); + self.bus.borrow_mut().store_8(i as u32 + bus::DRAM_BASE, buffer[i]); } - println!("VM > Program loaded to 0x{:08x}", self.pc); + println!("VM > Program loaded to 0x{:08x}", self.cpu.get_pc()); } fn dump_prog(&mut self) { @@ -62,91 +50,21 @@ impl VMRV32I { println!( "VM > 0x{:08x}: 0x{:02x}", i, - self.bus.load_8(i + bus::DRAM_BASE) + self.bus.borrow_mut().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!(""); - } - } - - fn init_cpu(&mut self) { - println!("VM RISC-V 32I CPU"); - println!("-----------------"); - println!("VM > Initializing CPU"); - - self.bus = Bus::new(); - self.pc = DRAM_BASE as rv32::Word; - self.x[0] = 0x00000000; // x0 is tied to ground - self.x[2] = ram::DRAM_SIZE as u32; // x2 the addressable - } - - fn fetch(&mut self) -> inst::Instruction { - inst::Instruction { - inst: self.bus.load_32(self.pc), - } - } - - fn exec(&mut self) { - while self.pc - bus::DRAM_BASE < 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; - 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(); - } + fn dispatch(&mut self) { + self.cpu.exec(); } } fn main() { println!("VM Starting Up"); - let mut cpu = VMRV32I::new(); - cpu.init_cpu(); - cpu.load_prog("./test/add.bin"); - cpu.dump_prog(); - cpu.exec(); + let mut vm = VMRV32I::new(); + vm.load_prog("./test/add.bin"); + vm.dump_prog(); + vm.dispatch(); } diff --git a/test/Makefile b/test/Makefile index b683d27..ecfd0d3 100644 --- a/test/Makefile +++ b/test/Makefile @@ -1,16 +1,15 @@ GCC_COMPILER=riscv32-unknown-elf-gcc GCC_OBJCOPY=riscv32-unknown-elf-objcopy -all: - assemble - build - @echo "Done" +all: build assemble: $(GCC_COMPILER) -S test.c build: $(GCC_COMPILER) -Wl,-Ttext=0x0 -nostdlib -march=rv64i -mabi=lp64 -o test test.S + +bin: $(GCC_OBJCOPY) -O binary test test.bin clean: diff --git a/test/basic.S b/test/basic.S deleted file mode 100644 index 9d1b64f..0000000 --- a/test/basic.S +++ /dev/null @@ -1,6 +0,0 @@ -ADDI x2, x0, 1 - -loop: - SUB x1, x1, x2 - SW x1, 4(x0) - BLT x0, x1, loop diff --git a/test/test b/test/test deleted file mode 100755 index 46c25ad..0000000 Binary files a/test/test and /dev/null differ diff --git a/test/test.S b/test/test.S index 9d1b64f..ff33658 100644 --- a/test/test.S +++ b/test/test.S @@ -1,6 +1,5 @@ -ADDI x2, x0, 1 +jal x0, main -loop: - SUB x1, x1, x2 - SW x1, 4(x0) - BLT x0, x1, loop +main: + addi t0, x0, 100 + sb t0, 8(sp) diff --git a/test/test.bin b/test/test.bin deleted file mode 100755 index 469e604..0000000 Binary files a/test/test.bin and /dev/null differ diff --git a/test/test.c b/test/test.c deleted file mode 100644 index 3d13523..0000000 --- a/test/test.c +++ /dev/null @@ -1,4 +0,0 @@ -int main() { - int x = 1 + 2; - return 0; -}