這次要實作的是 RISC-V 的核心基本架構。RISC-V提供了32個integer register用作基本的算術邏輯運算,如下圖:
以 Rust 的struct實作如下,目前先支援32位元的架構:
#[derive(Default)]
struct RVCore {
pc: u32,
regs: [u32; 32],
}
與C++最大的不同在於陣列的宣告,regs: [u32; 32]
代表這邊宣告regs是一個長度為32的陣列,且每個元素為usigned 32-bit integer。繼承Default class目的是為了讓RVCore能夠自動初始化,往後使用RVCore就不用手動初始化每一個欄位。
光有data沒有太大用處,還必須有用來操作的method:
impl RVCore {
fn step(&mut self, inst: u32) {
println!("PC = {}, inst = {}", self.pc, inst);
self.pc += 4;
}
fn run(&mut self, num_steps: i32) {
let mut step_count = 0;
while step_count < num_steps {
self.step(0);
step_count += 1;
}
}
}
Rust的語法相當有趣,data與method必須分成不同的block定義,好處是不會像C++那樣,data與method混在一起,提升了可讀性。這裡定義了step(),每次會傳入一條指令,執行並印出目前的PC,並且把PC加4。run() 則是可以指定要跑幾個step,目前每次都是傳0給step(),先看看能不能正常運作。
接下來在main裡面測試RVCore是否能正常運作:
fn main() {
let mut core: RVCore = Default::default();
core.run(5);
}
在命令列輸入cargo run
可以看到以下輸出:
PC = 0, inst = 0
PC = 4, inst = 0
PC = 8, inst = 0
PC = 12, inst = 0
PC = 16, inst = 0
沒錯,這就是我們所預期的,可以想像這是一個最基本的RISC-V核心,可以讓他跑任意條指令,每條指令都只會把PC加4,這樣一個最基本的核心架構就完成了。完整的程式碼如下:
#[derive(Default)]
struct RVCore {
pc: u32,
regs: [u32; 32],
}
impl RVCore {
fn step(&mut self, inst: u32) {
println!("PC = {}, inst = {}", self.pc, inst);
self.pc += 4;
}
fn run(&mut self, num_steps: i32) {
let mut step_count = 0;
while step_count < num_steps {
self.step(0);
step_count += 1;
}
}
}
fn main() {
let mut core: RVCore = Default::default();
core.run(5);
}