RISC-V on Rust 从零开始(7) - 实作指令基本框架

使用Spike执行RISC-V gnu toolchain编译出来的ELF档,就可以得到完整执行此EFL档需要用到哪些指令。利用script统计後可以得到如下结果:

指令 执行次数 指令 执行次数 指令 执行次数 指令 执行次数
c.addi 22 c.bnez 6 c.sub 3 jalr 1
c.swsp 22 c.add 6 srai 3 c.andi 1
c.lwsp 21 c.sw 6 bgeu 2 bltu 1
addi 14 c.lw 6 andi 2 blt 1
c.li 14 c.lui 6 slli 2 bltz 1
sb 13 c.j 5 sw 2 c.slli 1
lw 11 auipc 4 sub 2 sll 1
c.mv 10 beqz 4 c.addi4spn 2 c.and 1
ret 10 c.jalr 4 c.addi16sp 2 lbu 1
c.beqz 9 li 4 beq 2 ecall 1
c.jal 6 bne 4

以上表格是根据执行次数的多寡来排序,这次就先处理第一个指令c.addi。

首先在RVCore中新增inst_c_addi成员函式:

impl RVCore {
     fn inst_c_addi(&mut self, inst: &inst_type::InstType) {
         if inst.get_rd() != 0 {
            self.regs[inst.get_rd()] = self.regs[inst.get_rd()] + inst.get_imm_ci();
         }
     }
 }

其中的get_rd(), get_imm_ci()等函式可以参考c.addi的spec:
https://ithelp.ithome.com.tw/upload/images/20210725/20122004C8PIk683w0.png

inst参数是指令经过decode之後得到的,InstType定义如下:

pub enum InstID {
    C_ADDI,
}

pub struct InstType {
    pub data: u32, // 从memory fetch到的指令
    pub len: u32, // 指令长度
    pub id: InstID, // 指令ID,由decoder填上
}

接下来实作c.addi的UT:

fn inst_c_addi_code(rd: u32, imm: u32) -> InstType {
    InstType {
        data: (((imm >> 5) & 1) << 12) | (rd << 7) | ((imm & 0x1f) << 2) | 0x1,
        len: 2,
        id: InstID::C_ADDI,
    }
}

#[test]
fn test_inst_c_addi() {
    let mut core: RVCore = Default::default();
    core.regs[2] = 0x1234;
    core.inst_c_addi(&inst_c_addi_code(2, 0x1));
    assert_eq!(0x1235, core.regs[2]);
}

如此就完成了c.addi指令的实作,其他指令也可以比照办理,完整程序码可以参考此连结


<<:  单元测试(Unit testing)

>>:  判断选取哪个radio button

【Day28】建立一个 LUIS Bot

今天我们要来将 Chatbot 与 Language Understanding Service (...

08 C++演算法自学指南

昨天主要描述在心理层面应该要注意的事情,今天则是从实际层面上细数在自学并准备 APCS 时会碰到什麽...

JavaScript学习日记 : Day28 - console实用技巧

开发过程中常常会需要使用console.log()来检视输出是否正确,所以能够妥善运用各种conso...

【DAY 11】SharePoint 後记- 为什麽要选择 SharePoint?

哈罗大家好~ 关於 SharePoint 的应用,到昨天告一段落,回顾一下你可能会觉得,文件库、清单...

5.MYSQL 建立资料库语法

这一篇要跟大家分享的是,直接在程序码的地方建立一个资料表,除了用之前的方法,还可以用下面这个方法 C...