这次要实作的是 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 = 0PC = 4, inst = 0PC = 8, inst = 0PC = 12, inst = 0PC = 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);}