Restructure the processor definition
This commit is contained in:
112
src/cpu/mod.rs
Normal file
112
src/cpu/mod.rs
Normal file
@@ -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<RefCell<Bus>>,
|
||||
// extensions:
|
||||
}
|
||||
|
||||
impl CPU {
|
||||
pub fn new(bus: Rc<RefCell<Bus>>) -> 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!("");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,2 @@
|
||||
|
||||
|
||||
lkkll
|
||||
|
||||
|
||||
1
src/ext/mod.rs
Normal file
1
src/ext/mod.rs
Normal file
@@ -0,0 +1 @@
|
||||
use crate::
|
||||
120
src/main.rs
120
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<RefCell<bus::Bus>>,
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
ADDI x2, x0, 1
|
||||
|
||||
loop:
|
||||
SUB x1, x1, x2
|
||||
SW x1, 4(x0)
|
||||
BLT x0, x1, loop
|
||||
@@ -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)
|
||||
|
||||
BIN
test/test.bin
BIN
test/test.bin
Binary file not shown.
@@ -1,4 +0,0 @@
|
||||
int main() {
|
||||
int x = 1 + 2;
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user