iT邦幫忙

0

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指令的實作,其他指令也可以比照辦理,完整程式碼可以參考此連結


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言