FPGA開発日記

FPGAというより、コンピュータアーキテクチャかもね! カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages/

RISC-Vのテストパタンセット riscv-tests

最近はほとんどテストベンチのメンテナンスを行っていなかったのだが、Privileged Instructions v1.9.1に対応させるために、久し振りにriscv-testsを使ったISSのリグレッションを実行してみた。

しばらくずっと触っていなかったのだけれども、昔メンテナンスして殆どのパタンをISSで通すようにしていたのだけれども、最近やってみると殆ど落ちるようになってしまっていた。

mtohost, mfromhost、各種システムレジスタの廃止

そもそも最初全てのパタンが解析できないようになっていたのだが、どうやらmtohost/mfromhostは廃止されてしまったらしい。 そして、時間計測系のシステムレジスタ(mtime系)のレジスタも廃止されており、csr系命令のアドレスマップも変わっており、相当の変更が必要だ。

テストパタンの終了方式

では、mtohostが廃止されたことにより、riscv-testsはどのようにして計測を終了させるのだろう?

パタンの説明では、どうやら0x8000_1000への書き込みでもってパタンの終了を判定しなければならないらしい。

80000040 <write_tohost>:
80000040:       00001f17                auipc   t5,0x1
80000044:       fdcf2023                sw      t3,-64(t5) # 80001000 <tohost>
80000048:       ff9ff06f                j       80000040 <write_tohost>

これにより0x8000_1000に書き込まれた値でもってテストパタンの成功失敗を判定しなければならないらしい。

RISC-V ISSの変更 (テストパタンの終了判定)

テストパタンの終了判定条件の追加

そこで、ISSを変更して、RISC-Vのテストパタン終了判定のための機構を取り入れることにした。

具体的には、0x8000_1000にアクセスした場合にそこで終了し、テストパタンの結果を返すことにする。このままだと他のベンチマークプログラムに影響してしまうが、それは後で修正する。

新規命令の追加 (mret/sret/hret/uret)命令の追加

これまでは一つのsret命令だけだったのだが、Privileged Instruction v.1.9.1ではそれぞれ別々の命令として定義されている。

f:id:msyksphinz:20161224005958p:plain

それぞれの命令を追加した。

github.com

リグレッション結果

いつの間にかめっちゃ落ちるようになってるなあ。。。

12% tests passed, 350 tests failed out of 398

Total Test time (real) = 315.32 sec

The following tests FAILED:
          1 - rv32mi-p-breakpoint (Failed)
          2 - rv32mi-p-csr (Failed)
          3 - rv32mi-p-illegal (Failed)
          4 - rv32mi-p-ma_addr (Failed)
...

12%しかPASSしてない!

2018/06/09追記。テストパタンの終了条件は、テストバイナリ中のtohostにアクセスすればシミュレーション終了とできる。 現在テストパタンによってはこの場所が異なっているので注意。 バイナリをロードして、tohostの位置をチェックしてテストの終了条件を変える。

$riscv64-unknown-elf-objdump -D /home/msyksphinz/riscv64/riscv64-unknown-elf/share/riscv-tests/isa/rv64ud-p-move

セクション .tohost の逆アセンブル:

0000000080002000 <tohost>:
        ...

0000000080002040 <fromhost>:
  • riscv_pe_thread.cpp
MemResult RiscvPeThread::StoreToBus (Addr_t addr, Size_t size, Byte_t *data)
{
  Addr_t paddr, internal_paddr;

  MemResult mem_result = ConvertVirtualAddress (&paddr, addr, MemAccType::WriteMemType);
  if (mem_result != MemResult::MemNoExcept) {
    return mem_result;
  }

  Addr_t mtohost_addr;
  if (FindGVarAddr (&mtohost_addr, "tohost") == true) {  // ここでチェック。速度的に問題ありだな。毎回チェックする必要はないが...
    if (paddr == mtohost_addr) {
      SetStopSim (true); // if MTOHOST is hit, ready to stop simulation
      Word_t result;
      memcpy (&result, data, 4);
      SetResult (result);
    }
  }

これでテストがかなりパスするようになった。401本中Passは379本となった。

$ grep Fail result.txt
rv64si-p-dirty                 Fail
rv32si-p-sbreak                Fail
rv64uc-v-rvc                   Fail
rv32ua-v-lrsc                  Fail
rv64um-p-divu                  Fail
rv64ua-p-lrsc                  Fail
rv32mi-p-breakpoint            Fail
rv64si-p-wfi                   Fail
rv32mi-p-mcsr                  Fail
rv32ua-p-lrsc                  Fail
rv32si-p-wfi                   Fail
rv32si-p-dirty                 Fail
rv64ua-v-lrsc                  Fail
rv64mi-p-ma_addr               Fail
rv64um-v-divu                  Fail
rv32mi-p-sbreak                Fail
rv32mi-p-ma_addr               Fail
rv32uc-v-rvc                   Fail
rv32mi-p-shamt                 Fail
rv64mi-p-breakpoint            Fail
rv64mi-p-illegal               Fail
rv32mi-p-illegal               Fail