FPGA開発日記

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

RISC-VのオープンソースプロセッサBOOMv3(SonicBOOM)を試す(2. Coremark値の測定)

RISC-VのオープンソースプロセッサBOOMv3(SonicBOOM)が公開されているが、シミュレーションを行うためにはChipyardの環境を用意するのが原則になっているようだ。

SonicBOOMv3のリポジトリ事態にCoremarkは入っていないようなので自分でバイナリを構築する必要があるらしい。が、CoremarkのRISC-V向けビルド環境があるらしい。

github.com

pk向けのバイナリとBaremetalのバイナリの両方が作れるらしい。これをダウンロードしてビルドしておけばよいのか。

git clone https://github.com/riscv-boom/riscv-coremark.git
cd riscv-coremark
git submodule update --init --recursive
./build-coremark.sh

一応ログを出したいので、BOOMをログ付きでビルドしておく。

  • src/main/scala/common/parameters.scala
diff --git a/src/main/scala/common/parameters.scala b/src/main/scala/common/parameters.scala
index 1a0c25fd..8d7c910c 100644
--- a/src/main/scala/common/parameters.scala
+++ b/src/main/scala/common/parameters.scala
@@ -92,7 +92,7 @@ case class BoomCoreParams(
   clockGate: Boolean = false,

   /* debug stuff */
-  enableCommitLogPrintf: Boolean = false,
+  enableCommitLogPrintf: Boolean = true,
   enableBranchPrintf: Boolean = false,
   enableMemtracePrintf: Boolean = false

で、そのままVerilatorのバイナリに流して実行する。CMK値は 3.83CMK/MHz となった。

cd sims/verilator/
make CONFIG=MediumBoomConfig
./simulator-chipyard-MediumBoomConfig +verbose ../../riscv-coremark/coremark.bare.riscv >& coremark.medium.riscv.log

全部ログがcoremark.medium.riscv.logに出てきてしまうので、grepして抽出する。

grep -v ^3 coremark.bare.riscv.log
using random seed 1592581205
This emulator compiled with JTAG Remote Bitbang client. To enable, use +jtag_rbb_enable=1.
Listening on port 55449
2K performance run parameters for coremark.
CoreMark Size    : 666
Total ticks      : 2608224
Total time (secs): %f
Iterations/Sec   : %f
ERROR! Must execute for at least 10 secs for a valid result!
Iterations       : 10
Compiler version : GCC9.2.0
Compiler flags   : -O2 -mcmodel=medany -static -std=gnu99 -fno-c3 0x00000000800025b4 (0xdf7d)
ommon -nostdlib -nostartfiles -lm -lgcc -T ../riscv64-baremetal/3 0x00000000800025b4 (0xdf7d)
link.ld
Memory location  : Please put data memory location here
                        (e.g. code in flash, data on heap etc)
seedcrc          : 0xe9f5
[0]crclist       : 0xe714
[0]crcmatrix     : 0x1fd7
[0]crcstate      : 0x8e3a
[0]crcfinal      : 0xfcaf
Errors detected
*** PASSED *** Completed after 2659834 cycles
[UART] UART0 is here (stdin/stdout).

ついでにMegaBoomConfigも試してみる(最大構成)。CMK値は 5.33 CMK/MHz となった。

./simulator-chipyard-MegaBoomConfig +verbose ../../riscv-coremark/coremark.bare.riscv >& coremark.mega.riscv.log
using random seed 1592619488
This emulator compiled with JTAG Remote Bitbang client. To enable, use +jtag_rbb_enable=1.
Listening on port 59775
2K performance run parameters for coremark.
CoreMark Size    : 666
Total ticks      : 1873606
Total time (secs): %f
Iterations/Sec   : %f
ERROR! Must execute for at least 10 secs for a valid result!
Iterations       : 10
Compiler version : GCC9.2.0
Compiler flags   : -O2 -mcmodel=medany -static -std=gnu99 -fno-c3 0x00000000800025b2 (0x6298) x14 0x0000000000000000
ommon -nostdlib -nostartfiles -lm -lgcc -T ../riscv64-baremetal/3 0x00000000800025b4 (0xdf7d)
link.ld
Memory location  : Please put data memory location here
                        (e.g. code in flash, data on heap etc)
seedcrc          : 0xe9f5
[0]crclist       : 0xe714
[0]crcmatrix     : 0x1fd7
[0]crcstate      : 0x8e3a
[0]crcfinal      : 0xfcaf
Errors detected
*** PASSED *** Completed after 1917263 cycles
[UART] UART0 is here (stdin/stdout).

ベンチマークをすべて流してみても、全体的にMegaBoomConfigはMediumBoomConfigよりも高速だ。1.5倍くらいのサイクル性能向上かな。

f:id:msyksphinz:20200620104041p:plain

RISC-VのオープンソースプロセッサBOOMv3を試す

RISC-VのオープンソースプロセッサBOOMv3(SonicBOOM)が公開されているが、シミュレーションを行うためにはChipyardの環境を用意するのが原則になっているようだ。

Chipyardの環境はかなり巨大なので用意するのが面倒なのだが、構築方法を忘れそうなので一応メモしておく。

基本的には以下のチュートリアルに則る。環境はWSLのUbuntu 18.04だ。

chipyard.readthedocs.io

リビジョンはTAG 1.3.0を使用している。

git clone https://github.com/ucb-bar/chipyard.git
cd chipyard
./scripts/init-submodules-no-riscv-tools.sh

riscv-toolsはChipyardのものを使っておくのが安心な気がする。

MAKEFLAGS="-j$(nproc) ./scripts/build-toolchains.sh riscv-tools

BOOMv3のビルドにはMediumBoomConfigを使用する。MegaBoomConfigを試行したがメモリが足りなさ過ぎて動作しなかった。っていうか無理やりヒープ領域を増やしたらWindowsごと落ちてしまった。

diff --git a/variables.mk b/variables.mk
index 4d49d5f..0e8c983 100644
--- a/variables.mk
+++ b/variables.mk
@@ -117,7 +117,7 @@ sim_common_files       ?= $(build_dir)/sim_files.common.f
 #########################################################################################
 # java arguments used in sbt
 #########################################################################################
-JAVA_HEAP_SIZE ?= 8G
+JAVA_HEAP_SIZE ?= 100G
 JAVA_ARGS ?= -Xmx$(JAVA_HEAP_SIZE) -Xss8M -XX:MaxPermSize=256M

 #########################################################################################
cd sims/verilator/
make CONFIG=MediumBoomConfig

シミュレーションの実行にはrun-bmark-testsを使用する。これでベンチマーク一式が測れる。

make CONFIG=MediumBoomConfig run-bmark-tests
  [ PASSED ] /home/msyksphinz/work/riscv/chipyard/chipyard/sims/verilator/output/chipyard.TestHarness.MediumBoomConfig/median.riscv.out          Completed after 30841 cycles
  [ PASSED ] /home/msyksphinz/work/riscv/chipyard/chipyard/sims/verilator/output/chipyard.TestHarness.MediumBoomConfig/multiply.riscv.out        Completed after 53063 cycles
  [ PASSED ] /home/msyksphinz/work/riscv/chipyard/chipyard/sims/verilator/output/chipyard.TestHarness.MediumBoomConfig/qsort.riscv.out   Completed after 329075 cycles
  [ PASSED ] /home/msyksphinz/work/riscv/chipyard/chipyard/sims/verilator/output/chipyard.TestHarness.MediumBoomConfig/towers.riscv.out          Completed after 19261 cycles
  [ PASSED ] /home/msyksphinz/work/riscv/chipyard/chipyard/sims/verilator/output/chipyard.TestHarness.MediumBoomConfig/vvadd.riscv.out   Completed after 20004 cycles
  [ PASSED ] /home/msyksphinz/work/riscv/chipyard/chipyard/sims/verilator/output/chipyard.TestHarness.MediumBoomConfig/dhrystone.riscv.out       Completed after 151856 cycles
  [ PASSED ] /home/msyksphinz/work/riscv/chipyard/chipyard/sims/verilator/output/chipyard.TestHarness.MediumBoomConfig/mt-matmul.riscv.out       Completed after 34710 cycles
  [ PASSED ] /home/msyksphinz/work/riscv/chipyard/chipyard/sims/verilator/output/chipyard.TestHarness.MediumBoomConfig/mm.riscv.out      Completed after 276499 cycles
  [ PASSED ] /home/msyksphinz/work/riscv/chipyard/chipyard/sims/verilator/output/chipyard.TestHarness.MediumBoomConfig/spmv.riscv.out    Completed after 137791 cycles
  [ PASSED ] /home/msyksphinz/work/riscv/chipyard/chipyard/sims/verilator/output/chipyard.TestHarness.MediumBoomConfig/mt-vvadd.riscv.out        Completed after 104985 cycles

ログをベースにしてこれまでの測定結果からベンチマークのサイクル結果を比較しなおしてみた。

    BOOMv1 BOOMv2 BOOMv3(MediumBoomConfig)
  Insts Cycle Cycle Insts Cycle
dhrystone.riscv 200153 137573 147995 196029 115112
median.riscv 4259 7805 9400 4156 6685
mm.riscv 25287 17295 17079 24688 16568
mt-matmul - 15992 16298 - 14065
mt-vvadd.riscv - 9073 6870 - 10128
mt-vvadd.riscv - 7438 6084 - 7131
multiply.riscv 21003 18243 20110 24101 20335
qsort.riscv 124233 206542 252488 127368 223280
rsort.riscv 171284 112013 100222 -  
spmv.riscv 32535 27714 28843 34851 29401
towers.riscv 6623 4605 5395 6170 4017
vvadd.riscv 2519 1981 2014 2417 1350
f:id:msyksphinz:20200619225203p:plain

だいたい10%程度のサイクル性能向上かな。

RISC-VのアウトオブオーダプロセッサSonicBOOM (BOOMv3)の論文を読む

SonicBOOMというのはBOOM(Berkeley Out-of-Order Machine)の第3世代で、なぜSonicという名前を付けたのか謎だが、IPCを向上させるための技術が詰め込まれている。

carrv.github.io

  • SonicBOOM: The 3rd Generation Berkeley Out-of-Order Machine

https://carrv.github.io/2020/papers/CARRV2020_paper_15_Zhao.pdf

アーキテクチャの改良が行われており、

  • 実行パスの改善
  • 命令フェッチユニットの再実装(TAGE分岐ユニットの増強)
  • 1サイクル当たり複数のロードストア命令を発行できるように改良

これにより、SPEC CPUベンチマークにより過去のBOOMと比較して2倍のIPCを達成し、Coremarkスコアは6.2を達成することができた。

概要

SonicBOOMの構成を以下に示す。4命令フェッチ・8命令発行が可能な構成となっている。

f:id:msyksphinz:20200606113104p:plain
SonicBOOMのパイプライン。図は論文より抜粋。

パイプラインの構成。BOOMv1/BOOMv2/BOOMv3のパイプラインの進化。

まず、フロントエンドに分岐予測器が増強されている。TAGE・RASを追加しているところを見ると、Maxionの実装をフィードバックさせているようにも見える。バックエンドのパイプラインが増強されているように見えるのは、RoCCが付いているから。ただしRoCCはあまり使わないので大勢に影響はない。

f:id:msyksphinz:20200606113146p:plain
BOOMv1-v3のパイプラインの歴史。図は本論文より抜粋。

簡単にBOOMの歴史について纏められているので紹介すると、

  • BOOM v1:単純なアウトオブオーダプロセッサ。シンプルなパイプラインで当時はRVC命令が使用できなかった。IPC重視でMIPS R10kの構成に非常に似ている。
  • BOOM v2:BOOM v2はv1に比べて物理デザインのフローを改良すべく、クリティカルパスの削減を行っている。この中でレジスタの構成方法を改良し、レジスタアクセスのクリティカルパスを削減している。
  • BOOM v3:マイクロアーキテクチャの改良が行われている。

SonicBOOMの改良点についてより詳細に見ていくことにする。

命令フェッチ

  • C拡張命令(つまり2バイト命令)のサポート。これはRocketでもすでに行われていることなので驚くにあたらない。むしろ遅いくらい。
  • 分岐予測器の実装。フェッチユニット内の分岐予測器を実装し直し、分岐予測器はICacheにマッチするようにバンク化されている。さらにTAGEを実装することで分岐予測の精度を向上させている。さらにRASを実装することで関数から復帰する際の分岐予測ミスを削減している。
  • 分岐予測解決メカニズムの改善。BOOMv2では1サイクルに1つの分岐命令しか解決することができていなかったが、複数の分岐解決ユニットを持つことで改善を行っている。

実行ユニット

実行ユニットではRoCC(Rocket Custom Coprocessor)のサポートが行われ散る。さらにSFB(Short Forward Branch)に対する最適化が実装されている。

SFBというのはShort Forward Branchというらしいのだが、データに依存して基本ブロックをジャンプするような短い分岐シーケンスのことを言うらしい。RISC-VではConditional Moveが存在しないのでいちいち比較してはジャンプするしか対処方法が無いのだが、ここでは"set-flag"と"conditional-execute"のマイクロ命令を用意したとしている。

もう少し読み進めると、分岐命令を"set-flag"命令に置き換え、比較の結果によってリネームするレジスタファイルを置き換えるらしい。そして"conditional-execute"によりその命令を実行するか、単純にオリジナルの物理レジスタから書き込み先のレジスタに置き換えるだけの動作にするかを決定する。例が載っている。

f:id:msyksphinz:20200606113230p:plain
Short Forward Branchの適用例。図は本論文から抜粋。

ループを使って最大値とそのインデックスを見つけだすルーチンだが、アセンブリに変換すると単純に中央のアセンブリコードのようなシーケンスになる。条件が成立しない(最大値を見つけた)と値の更新のためのmv命令が実行され、そうでなければskipまでジャンプして次の命令シーケンスの実行が行われる。

これを分解し、bge命令をset.ge命令に置き換えることで仮想的にフラグを設定する。フラグが有効である場合はp.mv命令を実行し、そうでないp.mv命令は実行されない。しかしこれの条件判定はどのようにするんだろう?たとえばどこからどこまでがp.の適用対象範囲なのだ?

ロードストアユニット

f:id:msyksphinz:20200606113305p:plain
SonicBOOMのロードストアユニットの概要。本論文より抜粋。

これまでのRocketのL1キャッシュは1リクエストしか受け付けることができなかったので制約があった。そこで複数リクエストを受け付けることができるように改良を行ったというのが今回のBOOMv3だ。

  • L1データキャッシュのデュアルポート化

L1データキャッシュをデュアルポート化し、2つのバンクを用意した。各バンクは1R1WのSRAMで構成されている。2R1Wの実装も考えたが物理的な実装に問題がありシンプルな方を選んだらしい。ロードストアユニットをデュアル発行できるようにするため、ロードアドレスとストアアドレスのCAMを複製してTLBをデュアルポートにした。

  • L1の性能向上

SonicBOOMではL1データキャッシュのミスが発生すると即座にL2にリフィルのリクエストを発行する。リフィルデータはラインフィルバッファに送られるため、キャッシュのeviction(既存のキャッシュの書き出し)と同時にキャッシュのリフィルが行われている。SonicBOOMのノンブロッキングL1データキャッシュには複数のステートマシンが実装されており、キャッシュフィルとevictionが同時に動くようになっている。

性能

性能評価については以下の構成で行っている。

  • FinFETのプロセスを使い1GHzで合成している。また、AWS F1インスタンスを用いてシミュレーションを行い性能を測定している。
  • SPECの性能。全体的に引けを取らないが、全体的にSkylakeと比較して劣る。Amazon Gravitonとは良い勝負かな?
f:id:msyksphinz:20200606113340p:plain
SonicBOOMとSkylake、GravitonでのSPEC性能比較。図は本論文より抜粋。
  • Coremarkの性能。かなり高い性能を達成できたとしている。XuanTie 910の方が上か。。。
f:id:msyksphinz:20200606113406p:plain
SonicBOOMと他社CPUコアでのCoremark/MHz値の比較。図は本論文より抜粋。

今後の課題

  • ベクトル命令の実装
  • 命令・データプリフェッチの実装

RISC-Vのトレースフォーマット仕様書が公開されたので読んでみる(7. リファレンスアルゴリズム)

RISC-V トレースフォーマットの勉強。続き。

github.com

github.com

1章ずつ、翻訳ではなく日本語でサマライズしていく形式で進めていく。


6. リファレンスアルゴリズム

以下のようなエンコーダの実装を考える。

  • Qualified? : 命令がフィルタリングのクライテリアを満たしているか?そうであればトレースされるべきか?
  • Branch? : 命令が分岐命令か?
  • e_ccd : 例外を受け取っているか、もしくはコンテキストが変わり推論不可能なPCの変更が発生しているか?
  • te_inst : エンコーダによって送信されるパケットのタイプ。
  • ppch : 特権が変更されたか、もしくはコンテキストが変更され通知する必要があるか?
  • updiscon : 推論できないPCのジャンプが発生した。命令により、ソースコードだけでは推論できないプログラムカウンタの変更が発生した。
  • resync_br : resyncカウンタが最大値に到達し、分岐マップに出力されていないエントリが存在する。
  • er_ccdn : 命令のリタイアとともに例外が通知され、コンテキストが変更されて推論できないPCのジャンプが発生する。
  • exc_only : 同時の命令リタイアが無く、例外のみ発生した。
  • rpt_br : 分岐マップがフルになったが、分岐予測ミスが発生した。
  • cci : コンテキストの変更が非同期に通知された。
f:id:msyksphinz:20200327000256p:plain

RISC-Vのトレースフォーマット仕様書が公開されたので読んでみる(6. パケットフォーマット2)

RISC-V トレースフォーマットの勉強。続き。

github.com

github.com

1章ずつ、翻訳ではなく日本語でサマライズしていく形式で進めていく。


5. トレースエンコーダの出力パケット

5.7 Format 1 パケット

このパケットには分岐命令の情報が含まれている。また、分岐命令の情報を通知しなければならないときにもこのパケットが使用される(例えば分岐マップがfullである場合など)。

5.7.1 Format 1 updiscon フィールド

5.7.2 Format 1 branch__map field

分岐マップがフルになったことが通知されても、ほとんど場合にはアドレスを通知する必要がない。これはbranchesを0に設定することを意味する。この場合の例外は、最後の分岐が推論不可能なジャンプを行った場合である。この場合はbranchesは31が設定される。

パケット Format 1 : アドレス・分岐マップ

  • format
    • ビット幅:2
    • 01(diff-delta) 分岐情報とアドレスの差分が含まれる。
  • branches
    • ビット幅:2
    • branch__mapの有効なビット数を示す。
  • branch__map
    • ビット幅:branchesフィールで決定される。
    • 分岐がTaken・Not Takenであることを示す。各ビットにつき:
      • 0 : 分岐がTaken
      • 1 : 分岐がNot Taken
  • address
    • ビット幅:iaddress_width_p - iaddress_lsb_p
    • 命令アドレスの差分
  • notify
    • ビット幅:1
  • updiscon
    • ビット幅:1
  • irreport
    • ビット幅:1
  • irdepth
    • ビット幅:return_stack_size_p + (re turn_stack_size_p > 0 ? 1 : 0) + call_counter_size_p

パケット Format 1 : アドレスなし・分岐マップ

  • format

    • ビット幅:2
    • 01(diff-delta) 分岐情報とアドレスの差分が含まれる。
  • branches

    • ビット幅:2
    • branch__mapの有効なビット数を示す。
  • branch__map

    • ビット幅:branchesフィールで決定される。
    • 分岐がTaken・Not Takenであることを示す。各ビットにつき:
      • 0 : 分岐がTaken
      • 1 : 分岐がNot Taken

5.8 Format 0 パケット

効率的にパケットを拡張するためのフォーマット。

  • 正しく予測できた分岐の数を通知するための拡張。
  • キャッシュインデックスのジャンプターゲットを通知するための拡張。

分岐予測がサポートされ有効である場合、2つの選択肢があり得る:

  • フル分岐マップを出力する(フォーマット1を使用する)
  • 正しく予測できた分岐の数を通知する。

パケットフォーマット0、サブフォーマット0、アドレスなし、分岐数

  • format
    • ビット幅:2
    • 00 (opt-ext): 効率的な拡張のためのオプションフォーマット。
  • subformat
    • ビット幅:xxx
    • 0:正しく分岐予測できた回数
  • branch_count
    • ビット幅:32
    • 正しく予測できた分岐の数-31
  • branch_fmt
    • ビット幅:2
    • 00(アドレスなし):パケットにはアドレス情報が含まれず、最後に正しく予測した分岐の、次の分岐命令は失敗している。

RISC-Vのトレースフォーマット仕様書が公開されたので読んでみる(5. パケットフォーマット)

RISC-V トレースフォーマットの勉強。続き。

github.com

github.com

1章ずつ、翻訳ではなく日本語でサマライズしていく形式で進めていく。


5. トレースエンコーダの出力パケット

トレースエンコーダでは、以下の情報を含まなければならない。

  • パケットタイプ
  • パケットのバイト長
  • パケットのペイロード

UltraSoCのメッセージインフラストラクチャとArmのトレースバスについて例を示す。図5.1はUltraSoCのインフラストラクチャである。

  • ヘッダバイトには5ビットのフィールドでペイロードのバイト長を示している。次の2ビットは「フロー」(宛先ルーティングID)、そして1ビットでオプションの16bitタイムスタンプが付加されているかを示している。
  • インデックスフィールドはパケットのソースを示している。ビット幅はシステム依存であり、トレースエンコーダによって出力される初期値はゼロである。
  • オプションの2バイトのタイムスタンプが含まれる。
  • パケットのペイロードが含まれる。

trace_packet_format

Arm Trace Bus(ATB)ではパケットのソースはATIDバスフィールドによって表現され、「フロー」に相当するものは存在しない。

  • 5ビットのフィールドでペイロードのバイト数を表現する。
  • 1ビットのフィールドで16bitタイムスタンプが付加されているかどうかを示す。
  • オプションの2バイトのタイムスタンプ
  • パケットのペイロード

5.1 Format 3 パケット

Format 3パケットは同期操作に使用される。コンテキストとサポート情報を通知するために使用される。4つのサブフォーマットが含まれる。

5.2 Format 3 サブフォーマット0:同期

命令を識別するためのすべての情報が入っている。最初にトレースされる命令のために送られる。再同期タイマにより再同期がスケジュールされる場合にも送信される。

フィールド名 ビット幅 説明
format 2 11(sync) : 同期
subformat 2 00(start) : トレース開始、もしくは再同期
branch 1 分岐命令を示しており、分岐が成立した場合には場合は0を設定する。分岐命令ではないか、分岐が成立しなかった場合には1を設定する。
privilege privilece_width_p 命令のPrivilegeレベルを示す
context context_width_pもしくはif_context_pが1の場合は0 命令コンテキスト
address iaddress_width_p - iaddress_lsb_p 完全な命令アドレス。アドレスのアライメントはiaddress_lsb_pによって決定される。

5.2.1 Format 3 Branchフィールド

分岐命令の場合、BranchフィールドビットはTaken/Not Takenを示す。このビットを削除することで効率は若干向上し、分岐の状態は「キャリーオーバー」され次のte_instパケットに引き継がれる。しかしこのような方針を取った場合には問題が発生することがある。最初のトレース命令がジャンプ命令で、その直後に例外が発生したものとする。Format 3パケットは2つの連続した命令で生成される。2番目のパケットには分岐のマップが含まれておらず、従って最初の分岐命令の結果を通知する方法がない。

  • 同じサイクルに2つのパケットを生成する必要があり、エンコーダの複雑性が上がってしまう。
  • トレースを生成するためのアルゴリズムが複雑化してしまう。

5.3 Format 3 サブフォーマット1 : 例外

このパケットにも命令を完全に識別するための情報が含まれている。このパケットは例外後に通知され、例外ハンドラ亜土れうを通知と同様に、例外要因や例外発生元の命令情報についても含まれる。

暗黙的例外モードが有効である場合、アドレスは除外される。

フィールド名 ビット幅 説明
format 2 11(sync) : 同期
subformat 2 01(例外) : 例外要因及びトラップハンドラアドレス
branch 1 分岐命令を示しており、分岐が成立した場合には場合は0を設定する。分岐命令ではないか、分岐が成立しなかった場合には1を設定する。
privilege privilece_width_p 命令のPrivilegeレベルを示す
context context_width_pもしくはif_context_pが1の場合は0 命令コンテキスト
ecause ecause_width_p 例外要因
interrupt 1 割り込み
address iaddress_width_p - iaddress_lsb_p 完全な命令アドレス。アドレスのアライメントはiaddress_lsb_pによって決定される。
tvalepc iaddress_width_p ecauseが2かつinterruptが0(不定命令例外)の場合は例外アドレス、それ以外の場合はトラップ値

5.3.1 Format 3 tvalepcフィールド

このフィールドは不定命令例外のアドレスもしくはそれ以外の時はトラップ値が格納される。これは実行に失敗した命令のアドレスはすべての場合において通知されることを示す。トラップ値はハードウェアブレークポイントにおいてもトリガされたアドレスが格納される。またはページフォルトおよび命令フェッチ・ロード・ストアミスアラインについても同様であるが、不定命令例外についてはオペコードが格納される。

5.4 Format 3 サブフォーマット2 : コンテキスト

このパケットにはコンテキストの情報のみが含まれる。このパケットはコンテキストの切り替えが発生した場合に通知される。

フィールド名 ビット幅 説明
format 2 11(sync) : 同期
subformat 2 10(例外) : コンテキスト変更
privilege privilece_width_p 命令のPrivilegeレベルを示す
context context_width_p 命令コンテキスト

5.5 Format 3 サブフォーマット : サポート

このパケットではデコーダをサポートするための情報が含まれている。

  • トレースの有効無効
  • オペレーティングモードの変更
  • 1つ以上のパケットが送信できなかった(例えば、パケット転送インフラストラクチャによるバックプレッシャによる)

5.5.1 Format 3 サブフォーマット3 qual_status field

トレースが終了すると、エンコーダは最後にトレースされた命令のアドレスを報告し、これにFormat 3 サブフォーマット3(サポート情報)パケットが続く。トレースが終了したことを示すために、ended_repends_updの2つのコードが提供されている。これは、セクション5.6.2で詳細に説明されているものとまったく同じ曖昧なケースに関連しており、原則として、そのセクションで説明されているメカニズムを使用して、最後にトレースされた命令がlooplabelにあるときを明確にすることができる。

  • ended__rep トレースが終了しない場合、前のパケットが送信されていないことを示す。これは最初のループイタレーションのループラベルを実行した後トレーシングがストップしたことを示す。

  • ended__upd 推論不可能なPCジャンプにより、とりあえず前のパケットが発行されたことを示す。これは2番目のループイタレーションの後にトレースがストップしたことを示す。

フィールド名 ビット幅 説明
format 2 11(sync) : 同期
subformat 2 11(例外) : デコーダのサポートパケット
enable 1 エンコーダが有効の場合1が設定される。
encoder__mode N トレースアルゴリズムを指定する。詳細とビット数は依存している。下剤では分岐トレースモードのみが定義されており、値は0である。
qual__status 2 資格情報を示す。
00(no__change) : フィルタの資格は変更なし。
01(ended__rep) : 資格が終了する。これまでのte__instが明示的に転送され最後の資格命令であることを示す。
10(trace__lost) : 1つ以上のパケットをロストした。
11(ended__upd) : 資格が終了する。過去のte__instはとりあえず送信される。
options N ランタイムのコンフィグレーションビットの値である。ビット数は実装に依存する。
- シーケンシャルな予測可能ジャンプ:シーケンシャルな予測化のうなジャンプのターゲットをレポートしない
- 暗黙的なリターン:リターンアドレスを通知しない
- 暗黙的な例外:format 3のアドレスを通知しない、トラップベクタをecauseから決定できる場合に、サブフォーマット1のte__instパケットを送信しない。

5.6 Format 2 パケット

このパケットには命令アドレスしか含まれず、命令のアドレスを通知しなければならないときだけ使用される。

フィールド名 ビット幅 説明
format 2 10(addr-only) : アドレス差分および分岐命令の情報は含まれない。
address iaddress_width_p - iaddress_lsb_p 命令アドレス差分
notify 1
updiscon 1
irreport 1
irdepth return_stack_size_p + (return_stack_size_p > 0 ? 1 : 0) + call_counter_size

5.6.1 Format 2 notifyフィールド

このフィールドは殆どの場合はaddressフィールドのMSBと同じ値が設定される。trigger[2]入力が1に設定されたことにより通知リクエストが行われた結果をカバーするためのビットである。

5.6.2 Format 2 notify と updisconフィールdお

このビットは殆ど圧縮されて効率に影響はない。notifyは殆ど場合addressフィールドのMSBと同一であり、updisconは通常はnotifyの同じである。このビットはデコーダソフトウェアが曖昧性によりプログラムを再構成することができなかった場合に使用される。以下のようなコードを考える。

looplabel - 4: opcode A
looplabel : opcode B
looplabel + 4: opcode C
:
looplabel + N: JALR # Jump to looplabel

これは、次の反復への間接的なジャンプバックを伴うループです。これは推測不可能な不連続であり、フォーマット 1 または 2 のパケットで報告されます。しかし、ループへの最初のエントリは、looplabel 4 の命令からのフォールスルーであり、明示的には報告されないことに注意してください。これは、プログラムの実行パスを再構築する際に、ループラベルのアドレスが2回発生することを意味します。一見すると、デコーダは、1 回目にループラベルに到達したときに、これが実行の終わりではないと判断できるように見えますが、それは前の命令が不連続を引き起こすような命令ではなかったからです。したがって、JALRに到達するまで実行パスの再構築を続けることができ、そこからlooplabelでのオペコードBが最後のリタイア命令であることを推論することができます。しかし、このアプローチがうまくいかない状況もあります。例えば、looplabel + 4 に例外がある場合を考えてみましょう。この場合、デコーダは、エンコーダからの追加情報がないと、これが 1 回目と 2 回目のループの繰り返しで発生したかどうかを判断できません。これが updiscon フィールドの目的です。詳細はこちらを参照してください。

  1. コードは1回目のループの繰り返しの最後まで実行され、エンコーダはJALRに続いてフォーマット1/2でlooplabelを報告し、2回目のループを実行し続けます。 この場合、 updiscon == notify となります。次のパケットはフォーマット1/2になります。
  2. コードは 1 回目のループの反復の最後まで実行され、looplabel にジャンプしますが、2 回目の反復で looplabel + 4 で例外、特権の変更、または再同期が発生します。この場合、エンコーダはJALRに続いてフォーマット1/2でlooplabelを報告し、updateiscon == !notifyで次のパケットはフォーマット3になります。
  3. looplabelの1回目の実行直後に例外が発生します。この場合、エンコーダはフォーマット 0/1/1/2 を使用して、updiscon == notify でループラベルを報告し、次のパケットはフォーマット 3 となります。
  4. Hartは、エンコーダにlooplabelでの命令の破棄を通知するように要求します。この場合、エンコーダはlooplabelの1回目の実行をnotify == !address[MSB]で報告し、それ以降の実行をnotify == address[MSB]で報告します(JALRの結果、いずれにしても報告されていたでしょうから)。

RISC-Vのトレースフォーマット仕様書が公開されたので読んでみる(4. フィルタリング)

RISC-V トレースフォーマットの勉強。続き。

github.com

github.com

1章ずつ、翻訳ではなく日本語でサマライズしていく形式で進めていく。


4. フィルタリング

エンコーダがトレースを生成するためのメカニズムを示している。例えば、以下の条件ではトレースは生成されるべきである。

  • 命令アドレスが特定の範囲内に存在する。
  • 1つの命令のアドレスから始まり、2番目の命令アドレスまで続く。
  • 1つ以上の特定の特権モード。
  • 特定のコンテキストもしくはコンテキストの範囲内。
  • 特定の要因の例外しくは割り込みハンドラ。もしくは特定のtvalの値。
  • impldefもしくはtrigger信号に基づく値
  • 特定の固定時間

このような実装をどのようにして実装するかについては、以下のような実装方法が考えられる。

  • 特定の演算に基づくコンパレータ(<, >, =, !=,など)。iaddress, contextおよびtvalに適用される。
  • privおよびcauseの選択
  • interruptおよびimpdef入力に対するマスク付きマッチング
  • trigger[0]がアサートされた場合のトレース有効化機能、trigger[0]がアサートされた場合のトレース継続機能