Restructure the processor definition

This commit is contained in:
Benjamin Kyd
2023-06-14 01:58:00 +01:00
parent 59dcf80fbe
commit 00920b2ecc
10 changed files with 140 additions and 122 deletions

112
src/cpu/mod.rs Normal file
View 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!("");
}
}
}

View File

@@ -1,3 +1,2 @@
lkkll

1
src/ext/mod.rs Normal file
View File

@@ -0,0 +1 @@
use crate::

View File

@@ -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();
}

View File

@@ -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:

View File

@@ -1,6 +0,0 @@
ADDI x2, x0, 1
loop:
SUB x1, x1, x2
SW x1, 4(x0)
BLT x0, x1, loop

BIN
test/test

Binary file not shown.

View File

@@ -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)

Binary file not shown.

View File

@@ -1,4 +0,0 @@
int main() {
int x = 1 + 2;
return 0;
}