読者です 読者をやめる 読者になる 読者になる

FPGA開発日記

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

The RISC-V メモリコンシステンシモデル

RISC-Vウェブサイトに出ていたこの記事。

Vengineerさんにも言及いただいた。

riscv.org

5th RISC-V Workshopにも出ていた、RISC-Vのメモリコンシステンシモデルについてツールを用いてチェックしたというPrinceton大学の研究チームの記事だ。

発表資料はこちら。

https://content.riscv.org/wp-content/uploads/2016/12/Tue1200-web-RISC-V-Mem-Consistency-Trippel-Princeton.pdf

(結構Google翻訳にも頼ってしまったが、)要約すると、

  • RISC-Vのメモリコンシステンシモデルでは、C++11に必要なメモリアクセスオーダリングに違反する動作を行う可能性がある。
  • Rocketコアのようなシンプルなものでは影響を受けない。
  • RISC-V ISAの仕様を強化し、このエラーを回避する。新しいRISC-V仕様を2017年中に完成させる。

資料を読んでいたのだが、Store Atomicityとして、以下の3つが存在し、

Multiple-copy atomic: - All cores see store simultaneously - Read-Own-Write-Early-multiple-copy atomic: - Storing core can read its own store before other cores - Stores made visible to all remote cores simultaneously - Non-multiple-copy atomic: - Storing core can read its own store before other cores - Store is made visible to some remote cores before others

このうちNon-multiple-copy Atomicに問題があるということなのかな?メモリコンシステンシモデルについてまだ詳しくないので、良く分かっていない。

f:id:msyksphinz:20170425011331p:plain

スレッドT0とT1のストアが、スレッドT2とT3に到着する場合に異なる順序で到達する場合に発生するということか。 この例だとまだ良く分からないが、T0とT2がコア0、T1とT3がコア1に割り当てられており、それぞれL1キャッシュを共有している。

コア0(つまりT0とT2)はコア1のキャッシュの変更が見えるまでに時間がかかっており、ld xの結果はr0=0と読めているがld yの結果はr1=0と読めていない。 一方、コア1(つまりT1とT3)はコア0のキャッシュの変更が見えるまでに時間がかかっており、ld yの結果はr2=1と読めているが、ld xの結果はr3=0と読めていない。

RISC-V LLVM を用いたベンチマークビルドの方法(Compressed ISAを生成させない方法)

f:id:msyksphinz:20170325154038p:plain

前回のRISC-V LLVM 32ビット版命令生成には一つ問題があり、そのままパッチを当ててしまうとCompressed ISA(16ビット版 RISC-V ISA)を生成してしまう点にある。

現状自作CPUも自作ISSもCompressed ISAには対応していないので、32bit版命令しか生成しないように変更する。

msyksphinz.hatenablog.com

riscv-clangのリポジトリを変更する。

diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 156ee24..1fede05 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -1552,6 +1552,11 @@ static void getRISCVTargetCPU(const ArgList &Args,
     CmdArgs.push_back("-target-feature");
     CmdArgs.push_back("+rv64");
     parseRISCVExtensions(MArch.drop_front(4), CmdArgs);
+  }else if(Triple.getArch() == llvm::Triple::riscv) {
+    CmdArgs.push_back("-target-feature");
+    CmdArgs.push_back("+rv32");
+    CmdArgs.push_back("-target-feature");
+    CmdArgs.push_back("-rv64");
   }else{
     //default to RV64I
     CmdArgs.push_back("-target-feature");
@@ -9184,6 +9189,15 @@ void gnutools::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
     CmdArgs.push_back(Args.MakeArgString("-march=" + CPUName));
     break;
   }
+  case llvm::Triple::riscv: {
+       // for riscv-tools in sifive freedom-e-sdk
+       CmdArgs.push_back("-march=rv32ima");
+       CmdArgs.push_back("-mabi=ilp32");
+       // for riscv-tools in sifive freedom/rocket-chip/riscv-tools
+       //CmdArgs.push_back("-m32");
+       //CmdArgs.push_back("-msoft-float");
+     break;
+  }
   }

   Args.AddAllArgs(CmdArgs, options::OPT_I);

つまり、"-march=rv32imac" だったのが、"-march=rv32ima"に変更するので、Compressed ISAが生成されなくなる。 これでCoremarkをビルドしているのだが、シミュレーションを実行しても最後まで通過しない。ここは解析が必要だ。

Vivado 2017.1 AXI VIP packageの情報

Vivado 2017.1 AXI VIP Packageについていくつか情報が出ている。

japan.xilinx.com

XILINX_AXI_VIP_2017_1.zipをダウンロードすると、いくつかVIPパッケージ内の機能について記述されている。

f:id:msyksphinz:20170422032915p:plain

また、VivadoインストールディレクトリにはAXI VIPパッケージのようなものが入っている。

./Vivado/2017.1/data/ip/xilinx/axi_vip_v1_0
./Vivado/2017.1/data/ip/xilinx/axi_vip_v1_0/hdl/axi_vip_v1_0_vlsyn_rfs.sv
./Vivado/2017.1/data/ip/xilinx/axi_vip_v1_0/hdl/axi_vip_v1_0_vl_rfs.sv
./Vivado/2017.1/data/ip/xilinx/axi_vip_v1_0/hdl/axi_vip_v1_0_1_axi4pc.sv
./Vivado/2017.1/data/ip/xilinx/axi_vip_v1_0/xgui/axi_vip_v1_0.tcl
./Vivado/2017.1/data/ip/xilinx/axi_vip_v1_0/doc/axi_vip_v1_0_changelog.txt

ただ、疑問なのはこれ2016.4にも入ってるんだよなあ。

2016.4はシレッと入れておいて、2017.1で正式リリースということにしたいのかなあ。

RISC-V LLVM を用いたベンチマークビルドの方法

f:id:msyksphinz:20170325154038p:plain

前回、RISC-V LLVMをビルドしたが、実際にベンチマークプログラムをビルドするためにはどのようにすればよいのだろう。

まず、チュートリアルにのっとってみるのがよいだろう。Freedomプラットフォームの32bit RISC-Vプロセッサ向けにclangを用意する。

いろいろ調査したのだが、32bit対応のRISC-V clangをビルドするためには、現状のリポジトリに対してパッチを当てる必要がある。

RISC-V 32bit 対応Clangのビルド方法

github.com

RISC-V 32bit対応のClangはビルド方法としてはパッチを当てる必要がある。まずは普通通りriscv-llvmをチェックアウトする。

git clone https://github.com/msyksphinz/riscv-llvm.git riscv-llvm32
cd riscv-llvm32/
git submodule update --init

まずはclang向けのパッチをダウンロードしよう。

cd riscv-clang
wget https://github.com/riscv/riscv-llvm/files/893658/riscv-clang.patch.txt
patch -p1 < riscv-clang.patch.txt

次に、llvm向けのパッチをダウンロードする。

cd ../
wget https://github.com/riscv/riscv-llvm/files/893657/riscv-llvm.patch.txt
patch -p1 < riscv-llvm.patch.txt

ビルドを開始する。

cmake -DCMAKE_INSTALL_PREFIX=/opt/riscv32 -DLLVM_TARGETS_TO_BUILD="RISCV" ../
make && sudo make install

最後に、実際に使用するためにsysrootを設定しよう。以下のようにriscv32-unknown-elf-clangをリンクし、--sysrootとして設定するディレクトリを作成する。 RISCV環境は/home/msyksphinz/riscv32/に設定されているものとする。

export RISCV=/home/msyksphinz/riscv32/
cd ${RISCV}/bin/
ln -s /opt/riscv32/bin/clang riscv32-unknown-elf-clang
cd ${RISCV}
mkdir r32 && cd r32
ln -s ../riscv32-unknown-elf usr

これで、clangを利用する際に--sysroot=${RISCV}/r32と指定することでライブラリ等使用できるようになる。

次に、これを使ってベンチマークをビルドしてみよう。

FreedomプラットフォームのベンチマークプログラムにLLVM-Clangビルドを適用する

Freedomプラットフォームは、ベンチマークプログラムなどのビルドのためにテンプレートを持っている。

github.com

まずは、Dhrystoneのビルドからやってみよう。

freedom-e-sdkリポジトリのdhrystoneのディレクトリで、以下のように入力する。

make CC="riscv32-unknown-elf-clang --sysroot=/home/msyksphinz/riscv32/r32" dhry_1.o dhry_2.o dhry_printf.o dhry_stubs.o OPT=-O3
make

これは、まずはC言語で記述されているベンチマーク部分はclangでコンパイルする。次に、ライブラリ等のラッパーは単なるmakeを使ってgccでビルドする、最後にldを使ってclangで生成したobjectとリンクするという訳だ。

同じように、Coremarkのディレクトリでもビルドすることができる。

make CC="riscv32-unknown-elf-clang --sysroot=/home/msyksphinz/riscv32/r32" core_list_join.o core_main.o core_matrix.o core_portme.o core_state.o core_util.o OPT=-O3
make

RISC-V LLVMのビルドとインストール手順

RISC-VはLLVMにも対応しており、リポジトリgithubに公開されている。

github.com

ブランチがいくつか存在するが、 riscv-trunk を選択すること。これは最新のLLVMを追いかけているブランチだ。

リポジトリのチェックアウトとビルド

ビルドまでは非常に簡単だ。ただしLLVMのビルドは時間がかかるので注意すること。手元のVirtualBox(at CPUx4)でビルドしても1時間程度かかった。

git clone -b RISCV https://github.com/riscv/riscv-llvm.git
git checkout riscv-trunk
git submodule update --init
mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX=/opt/riscv -DLLVM_TARGETS_TO_BUILD="RISCV" ../ $ make $ make install

上記でビルド完了だ。/opt/riscv/binにバイナリが配置されている。

追記。RISC-V LLVMを使ったベンチマークビルド方法

msyksphinz.hatenablog.com

Vivado 2017.1がリリースされていました

Vivado 2017.1がリリースされていた。

japan.xilinx.com

一応リリース情報を見てみよう。結構内容が盛りだくさんだ。

• Vivado IDE のユーザーインターフェイスを刷新。

まじで?

こんな感じだった。

f:id:msyksphinz:20170420231605p:plain

AXI Verification IP を導入
- SystemVerilog ベース、ライセンス不要
- AXI3、 AXI4、 および AXI4-Lite をサポー ト
Zynq-7000 VIP を導入 (上記の AXI VIP に基づ く )
- ライセンス不要、 SystemVerilog ベース

これ面白そうね。試してみたい。

消費電力で最適化された大型RAM用の新しい属性。
- 2のべき乗でないアドレスのRTLRAM用に使用するブロックRAMを最小限にすることが可能。
- ブロックRAM推論の改善点
- SDPモードのブロックRAMセルのカスケード接続をサポート
- 非対称ポート幅ブロックRAMのバイトライトイネーブルをサポート。

これも面白そう。

RISC-Vコア BOOM向けのCoremarkリポジトリの準備

BOOMコアの解析の続き。やはり途中で割り込みに飛んでしまう動作が気に食わないので、riscv-testsのリポジトリをForkしてCoremarkを追加してみようと思った。

まず、Coremarkのriscv-testsのディレクトリを解析してみよう。riscv-testsのbenchmarkディレクトリは以下のようになっている。

.
├── Makefile
├── common
│   ├── crt.S
│   ├── syscalls.c
│   ├── test.ld
│   └── util.h
...
├── mt-vvadd
│   ├── bmark.mk
│   ├── dataset.h
│   ├── mt-vvadd.c
│   ├── vvadd.c
│   └── vvadd_gendata.pl
├── multiply
│   ├── bmark.mk
│   ├── dataset1.h
│   ├── multiply.c
│   ├── multiply.h
│   ├── multiply_gendata.pl
│   └── multiply_main.c
├── qsort
...

つまり、中央のMakefileに共通の設定を記述して、個々のbmark.mkに個別の設定を追加するわけだ。早速Coremarkを追加してみよう。

github.com

coremarkのディレクトリを追加した。また、コンパイルオプションに最適化オプションを追加した。

├── coremark
│   ├── bmark.mk
│   ├── bmark.mk~
│   ├── core_list_join.c
│   ├── core_main.c
│   ├── core_matrix.c
│   ├── core_portme.c
│   ├── core_portme.h
│   ├── core_state.c
│   ├── core_util.c
│   ├── coremark.h
│   ├── ee_printf.c
│   ├── encoding.h
│   ├── syscalls.c
│   └── util.h
  • coremark/bmark.mk
FLAGS_STR = "$(PORT_CFLAGS) $(XCFLAGS) $(XLFLAGS) $(LFLAGS_END)"
RISCV_GCC_OPTS += -O3 -funroll-loops -fno-builtin $(PORT_CFLAGS) -I$(PORT_DIR) -I. -DFLAGS_STR=\"$(FLAGS_STR)\" -DITERATIONS=1
RISCV_LINK_OPTS += -O3 -funroll-loops -fno-builtin

これでCoremarkをコンパイルできるようになったが、他のベンチマークは落ちるようになってしまった。これは後で解析しなければならない。

make

riscv64-unknown-elf-gcc -T ./common/test.ld -I./../env -I./common -I./median -I./qsort -I./rsort -I./towers -I./vvadd -I./multiply -I./mm -I./dhrystone -I./spmv -I./mt-vvadd -I./mt-matmul -I./coremark  mm_main.o  mm.o  syscalls.o  crt.o -o mm.riscv -nostdlib -nostartfiles -ffast-math -lgcc -O3 -funroll-loops -fno-builtin
mm_main.o: 関数 `.L18' 内:
mm_main.c:(.text+0x3b0): `fabs' に対する定義されていない参照です
mm_main.c:(.text+0x3c4): `fabs' に対する定義されていない参照です
mm.o: 関数 `.L8' 内:
mm.c:(.text+0xe4): `fma' に対する定義されていない参照です
mm.c:(.text+0x104): `fma' に対する定義されていない参照です
mm.c:(.text+0x128): `fma' に対する定義されていない参照です
mm.c:(.text+0x144): `fma' に対する定義されていない参照です
mm.c:(.text+0x168): `fma' に対する定義されていない参照です
mm.o:mm.c:(.text+0x180): `fma' に対する定義されていない参照がさらに続いています
collect2: error: ld returned 1 exit status
mm/bmark.mk:28: ターゲット 'mm.riscv' のレシピで失敗しました
make: *** [mm.riscv] エラー 1

仕方がないのでCoremarkだけコンパイルする。

make coremark.riscv
...
riscv64-unknown-elf-gcc -T ./common/test.ld -I./../env -I./common -I./median -I./qsort -I./rsort -I./towers -I./vvadd -I./multiply -I./mm -I./dhrystone -I./spmv -I./mt-vvadd -I./mt-matmul -I./coremark  core_list_join.o  core_main.o  core_matrix.o  core_portme.o  core_state.o  core_util.o  ee_printf.o  syscalls.o  crt.o \
    -o coremark.riscv -nostdlib -nostartfiles -ffast-math -lgcc -O3 -funroll-loops -fno-builtin

無事にコンパイルできたので、BOOMに読み込ませて実行してみよう。まずはboomのディレクトリで、coremark.riscvにリンクを張る。

msyksphinz@msyksphinz-VirtualBox:~/work/rocket-chip/emulator$ pwd
/home/msyksphinz/work/rocket-chip/emulator
msyksphinz@msyksphinz-VirtualBox:~/work/rocket-chip/emulator$ ls -ltr output/coremark.riscv
lrwxrwxrwx 1 msyksphinz msyksphinz 83  4月 18 01:10 output/coremark.riscv -> /home/msyksphinz/work/rocket-chip/riscv-tools/riscv-tests/benchmarks/coremark.riscv

これでシミュレーションを実行すると、私のマシンでは約10分くらいでシミュレーションが完了した。いつも通り編集してパイプライントレースを生成してみる。

make CONFIG=BOOMConfig output/coremark.riscv.out
sed -ei '1d' output/coremark.riscv.out 
../boom/util/pipeview-helper.py -f output/coremark.riscv.out > coremark.trace.out
~/work/gem5/util/o3-pipeview.py -o coremark.pipe.out --color coremark.trace.out

それでもやはりいくつかは割り込みによるジャンプが入っていた。ただし、そこまでの量ではない。これ、いったい何なんだろうな?

f:id:msyksphinz:20170419011131p:plain

そして気になるCoremarkスコアは、start_time()=1162240000, stop_time()=1571200000となり、408960サイクル、CMK/MHzは2.44となった。そこまで高くないなあ?

やはりコンパイラGCCを使っているのがダメなんだろうか?Clangとか使ってみようかなあ。