FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

RustでRISC-V命令セットシミュレータを作ろう (12. RV32機能の実装)

f:id:msyksphinz:20190224185310p:plain:w400

Rustで自作命令セットシミュレータを作っているが、RV64のテストパタンはある程度Passできるようになっている。

RV32についてだが、これまではRV32とRV64を別のクラスとして実装していた。しかしどうもこれでは冗長なコードがあってたまらないので、統一してRV64のクラスのみでRV32もサポートすることにした。

RV32をサポートするために、まずはRV64のRISC-Vコアを管理しているstructにXLENのパラメータを追加する。

  • swimmer_rust/src/riscv_core.rs
pub struct Riscv64Env {
    pub m_xlen: i32,
...
    pub fn new(xlen: i32) -> Riscv64Env {
        Riscv64Env {
            m_xlen: xlen,
            m_pc: DRAM_BASE as Addr64T,
...

これに応じて、各命令の実装を変えていく。例えば、ADD命令やSUB命令ならば演算の最後に符号によるXLENビット長への丸め込みを行っておく。

  • swimmer_rust/src/riscv_insts.rs
            RiscvInstId::ADD => {
                let rs1_data = self.read_reg(rs1);
                let rs2_data = self.read_reg(rs2);
                let reg_data: Xlen64T = self.sext_xlen(rs1_data.wrapping_add(rs2_data));
                self.write_reg(rd, reg_data);
            }
            RiscvInstId::SUB => {
                let rs1_data = self.read_reg(rs1);
                let rs2_data = self.read_reg(rs2);
                let reg_data: Xlen64T = self.sext_xlen(rs1_data.wrapping_sub(rs2_data));
                self.write_reg(rd, reg_data);
            }
...

このsext_xlen()だが、Spikeの実装をかなりパクってしまった。

  • swimmer_rust/src/riscv_core.rs
    pub fn sext_xlen(&mut self, hex: Xlen64T) -> Xlen64T {
        return (hex << (64-self.m_xlen)) >> (64-self.m_xlen)
    }

    pub fn uext_xlen(&mut self, hex: Xlen64T) -> UXlen64T {
        return ((hex as UXlen64T) << (64-self.m_xlen)) >> (64-self.m_xlen)
    }

とりあえずテストを動かしてみる。まずはPhysical Addressモードの場合でテストを行う。

cargo run -- --arch rv32 riscv-tests/isa/rv32ui-p-add.bin | tee rv32ui-p-add.log
       466:M:Bare:ffffffff8000000c:03ff0a63:beq        x30,x31,0x34        :x30=>000000000000000b x31=>0000000000000008
       467:M:Bare:ffffffff80000010:00900f93:addi       x31,x00,0x009      :x00=>0000000000000000 x31<=0000000000000009
       468:M:Bare:ffffffff80000014:03ff0663:beq        x30,x31,0x2c        :x30=>000000000000000b x31=>0000000000000009
       469:M:Bare:ffffffff80000018:00b00f93:addi       x31,x00,0x00b      :x00=>0000000000000000 x31<=000000000000000b
       470:M:Bare:ffffffff8000001c:03ff0263:beq        x30,x31,0x24        :x30=>000000000000000b x31=>000000000000000b
       471:M:Bare:ffffffff80000040:00001f17:auipc      x30,0x00001        :x30<=ffffffff80001040
       472:M:Bare:ffffffff80000044:fc3f2023:sw         x03,0x0000fc0(x30) :x03=>0000000000000001 x30=>ffffffff80001040 (ffffffff80001000)<=00000001
PASS : riscv-tests/isa/rv32ui-p-add.bin

動作自体は問題ないようだ。あとはリグレッションテストで確認していく。