FPGA開発日記

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

C++で記述された軽量CNN実装 mojo-cnn 試行 (3. RISC-V on FPGAで動かしてみる)

f:id:msyksphinz:20170925003926p:plain

前回はmojo-cnnをRISC-V向けに移植したので、今度は実機で動くかどうか試してみよう。

mojo-cnnはモデルデータをファイルとして保持しており、真面目に動かすならば1つのバイナリにすべきなのかもしれないが、とりあえずRocket-ChipにあるProxy Kernelがホスト上にあるファイルを読み込む役割を持っていると想定して、バイナリファイルのそばにデータを置いておく。

久しぶりにZedBoardを起動して、RISC-Vターゲットにコンパイルしたmojo-cnnのバイナリとCIFAR-10データセットをコピーしてきて、起動した。

root@zynq:~# ./fesvr-zynq  ~/mojo-cnn-msyksphinz/examples/test

とりあえずしばらく流しているけれども、全然動く気配がない。もう少し真面目にデバッグしないとダメかな。。。

f:id:msyksphinz:20180516005220p:plain
図. ZedBoard 上でRISC-V Mojo-CNNを動かしてみるが、どうも動かない。。。動作周波数が単純に低い?

C++で記述された軽量CNN実装 mojo-cnn 試行 (2. RISC-V 向けにリコンパイルとシミュレーション)

f:id:msyksphinz:20180515001039j:plain
※ 画像はイメージです。

前回はmojo-cnnをx86上で動作させてみたのだが、最終的にはRISC-Vプロセッサ上で動作させてみたいので、RISC-V向けにリコンパイルしてみよう。

やることはMakefileのg++の部分を書き換えるだけだ。

diff --git a/examples/makefile b/examples/makefile
index 75ca26c..d8485f5 100644
--- a/examples/makefile
+++ b/examples/makefile
@@ -1,4 +1,4 @@
-CC=g++
+CC=riscv64-unknown-elf-g++
 # CFLAGS_OMP= -I../mojo/ -std=c++11 -fopenmp -O3 -DMOJO_OPM -DMOJO_AVX -msse4 -mavx

さらに、usleepが定義されていないのでその部分はとりあえず削除した。

diff --git a/mojo/network.h b/mojo/network.h
index 413400a..481a282 100644
--- a/mojo/network.h
+++ b/mojo/network.h
@@ -94,8 +94,9 @@ mojo::matrix transform(const mojo::matrix in, const int x_center, const int y_ce
 #include <windows.h>
        void mojo_sleep(unsigned milliseconds) { Sleep(milliseconds); }
 #else
-#include <unistd.h>
-       void mojo_sleep(unsigned milliseconds) { usleep(milliseconds * 1000); }
+//#include <unistd.h>
+//     void mojo_sleep(unsigned milliseconds) { usleep(milliseconds * 1000); }
+       void mojo_sleep(unsigned milliseconds) { return; }
 #endif

 #ifdef MOJO_PROFILE_LAYERS

これでリコンパイルした。

$ make
riscv64-unknown-elf-g++ -I../mojo/ -std=c++11 test.cpp -o test
riscv64-unknown-elf-g++ -I../mojo/ -std=c++11 train_mnist.cpp -o train_mnist
riscv64-unknown-elf-g++ -I../mojo/ -std=c++11 train_cifar.cpp -o train_cifar

まずはspikeを使って実行してみよう。QEMUを使えばもっと早いのかもしれないが使い方がまだよく分かっていない。

$ spike pk test
Mojo CNN Configuration:
  0 : I1 : input 32 32 3 identity
  1 : Lc1 : convolution 3 50 1 elu
  2 : Lp1 : max_pool 2 2
  3 : Lc2 : deepcnet 100 elu
  4 : Lc3 : deepcnet 150 elu
  5 : R3 : concatenate 7 zero
  6 : Lc4 : deepcnet 200 elu
  7 : Lc5 : deepcnet 250 elu
  8 : FC1 : fully_connected 10 tanh

  I1-Lc1, Lc1-Lp1, Lp1-Lc2
  Lc2-Lc3, Lc3-R3, R3-Lc4
  Lc4-Lc5, Lc5-FC1

Testing CIFAR-10:
  testing : 10% (2035sec remaining)

とりあえず最後まで完走した!(キャプチャ取り忘れた...)とりあえず最後まで動くRISC-Vバイナリが作れたようだ。

Zynq FPGAで動かしてみようかな。

C++で記述された軽量CNN実装 mojo-cnn 試行 (1. x86上での動作試行)

f:id:msyksphinz:20180515001039j:plain
※ 画像はイメージです。

ディープラーニングと言えばTensorFlowだのKerasだのChainerだの、高級なインタフェースを持ったツールを使うケースが多いが、例えばマイコンや組み込みプロセッサなどでディープラーニングを動かしたいときは、そこまで高級な機能はいらず、C++などで簡単に記述されたCNNの実装のほうが実行しやすかったりする。

というわけで、RISC-V上で(というかFPGA上などで動いている非力なプロセッサ)でCNNを動かすことができれば面白そうだ。 「ゼロから作るディープラーニング」を見ながら位置からC++で実装してもよいけど大変そうなので、とりあえず簡単なフレームワークは無いかと探して、mojo-cnnというC++のCNN実装を見つけた。

github.com

mojo-cnn を使ってCIFAR-10を動かしたい

さっそくgit cloneして動作させてみる。環境はUbuntu 18.04 LTS上にダウンロードして試行した。 MNISTはもう飽きてしまったのでCIFAR-10を使ってみたい。ちょうとmojo-cnnにもCIFAR-10を動かすための環境がある。

単純にcloneしてビルドすると以下のようにエラーが出る。

$ git clone https://github.com/gnawice/mojo-cnn.git
$ cd mojo-cnn/example
$ make
g++ -I../mojo/ -std=c++11 -fopenmp -O3 -DMOJO_OPM -DMOJO_AVX -msse4 -mavx test.cpp -o test
In file included from test.cpp:44:0:
../mojo/mojo.h:31:0: warning: "MOJO_AVX" redefined
 #define MOJO_AVX // turn on AVX / SSE3 / SIMD optimizations

<command-line>:0:0: note: this is the location of the previous definition
In file included from ../mojo/network.h:38:0,
                 from ../mojo/mojo.h:78,
                 from test.cpp:44:
../mojo/layer.h:41:10: fatal error: windows.h: No such file or directory
 #include <windows.h>
          ^~~~~~~~~~~
compilation terminated.
makefile:7: recipe for target 'test' failed
make: *** [test] Error 1

#include <windows.h> を除去しても以下のようなエラーで進まない。

diff --git a/mojo/layer.h b/mojo/layer.h
index 4abef77..1e2e773 100644
--- a/mojo/layer.h
+++ b/mojo/layer.h
@@ -38,7 +38,7 @@
 namespace mojo
 {

-#include <windows.h>
+// #include <windows.h>
        /*
        double PCFreq = 0.0;
        __int64 CounterStart = 0;
g++ -I../mojo/ -std=c++11 -fopenmp -O3 -DMOJO_OPM -DMOJO_AVX -msse4 -mavx test.cpp -o test
In file included from test.cpp:44:0:
../mojo/mojo.h:31:0: warning: "MOJO_AVX" redefined
 #define MOJO_AVX // turn on AVX / SSE3 / SIMD optimizations

<command-line>:0:0: note: this is the location of the previous definition
In file included from ../mojo/mojo.h:76:0,
                 from test.cpp:44:
../mojo/core_math.h: In function ‘void mojo::dotsum_unwrapped_2x2(const float*, const float*, float*, int)’:
../mojo/core_math.h:178:2: error: ‘_mm256_zeroupper’ was not declared in this scope
  _mm256_zeroupper();
  ^~~~~~~~~~~~~~~~
../mojo/core_math.h:178:2: note: suggested alternative: ‘_mm_setzero_pd’
  _mm256_zeroupper();
...

どうもLinux環境だとAVXのIntrinsicが使えないようなので、これを使わないようにしよう。

  • AVX / SSE を使うオプションを削除する。またVGGはOpenCVを使うので除去した。
diff --git a/examples/makefile b/examples/makefile
index ee79729..70267b4 100644
--- a/examples/makefile
+++ b/examples/makefile
@@ -1,7 +1,7 @@
 CC=g++
-CFLAGS_OMP= -I../mojo/ -std=c++11 -fopenmp -O3 -DMOJO_OPM -DMOJO_AVX -msse4 -mavx
+CFLAGS_OMP= -I../mojo/ -std=c++11 -O3

-all: test train_mnist train_cifar vgg
+all: test train_mnist train_cifar

 test: test.cpp
        $(CC) $(CFLAGS_OMP) test.cpp -o test
  • MOJO_AVX / MOJO_OMP をundefinedにする。
--- a/mojo/mojo.h
+++ b/mojo/mojo.h
@@ -28,8 +28,8 @@

 #pragma once

-#define MOJO_AVX       // turn on AVX / SSE3 / SIMD optimizations
-#define MOJO_OMP       // allow multi-threading through openmp
+// #define MOJO_AVX    // turn on AVX / SSE3 / SIMD optimizations
+// #define MOJO_OMP    // allow multi-threading through openmp
 //#define MOJO_LUTS    // use look up tables, uses more memory
 //#define MOJO_CV3     // use OpenCV 3.x utilities
 //#define MOJO_CV2     // use OpenCV 2.x utilities

これでコンパイルできるようになったのでだが、次にトレーニングデータとしてCIFAR-10のデータセットをダウンロードしてこなければならない。

$ cd ../data/
$ curl -L http://www.cs.toronto.edu/~kriz/cifar-10-binary.tar.gz | tar xvz

これでシミュレーションを開始しよう。

$ ./train_cifar
==  Network Configuration  ====================================================
  0 : I1 : input 32 32 3 identity
  1 : C1 : convolution 3 16 1 elu
  2 : P1 : semi_stochastic_pool 3 3
  3 : C2 : convolution 3 64 1 elu
  4 : P2 : semi_stochastic_pool 4 4
  5 : FC2 : fully_connected 10 softmax

  I1-C1, C1-P1, P1-C2
  C2-P2, P2-FC2
==  CIFAR-10  Epoch  1  =============================================== 0:00:00
  mini batch:           16
  training time:        236.644 seconds on 1 threads
  model updates:        1805 (37% of records)
  estimated accuracy:   43.39%
  testing:              20% (13sec remaining)

...

==  CIFAR-10  Epoch  129  ============================================= 7:00:58
  mini batch:           16
  training time:        175.415 seconds on 1 threads
  model updates:        1061 (26% of records)
  estimated accuracy:   68.424%
  test accuracy:        67.69% (32.31% error)
  saved model:          ../models/snapshots/tmp_129.txt

==  CIFAR-10  Epoch  130  ============================================= 7:04:10
  mini batch:           16
  training time:        175.767 seconds on 1 threads
  model updates:        1061 (26% of records)
  estimated accuracy:   68.426%
  test accuracy:        67.69% (32.31% error)
  saved model:          ../models/snapshots/tmp_130.txt

==  CIFAR-10  Epoch  131  ============================================= 7:07:23
  mini batch:           16
  training time:        175.754 seconds on 1 threads
  model updates:        1062 (26% of records)
  estimated accuracy:   68.436%
  test accuracy:        67.66% (32.34% error)
  saved model:          ../models/snapshots/tmp_131.txt

Elvis just left the building. No further improvement in training found.
Stopping..

EPOCH 131までかかってる... しかも7時間も。さすがにAVXもなし、GPUもなしというのでかなりきつい。

でもとりあえず純粋C++で動いているので、RISC-Vとかほかのプラットフォームに移植しやすそうだし改造も簡単そうだ。

AWS EC2 F1インスタンスを使ったハードウェア開発の勉強 (7. cl_dram_dmaプロジェクトの解析)

AWS F1インスタンス HDK の勉強を続けている。 前回ModelSimを使ってcl_dram_dma の波形パタンを取得しようとしたが、動作が非常に遅くなってしまい失敗した。

どうにかして波形以外の情報を取得するためには、アサーションのようなものを組み込んでテキストファイルとしてログを取得するしかない。

という訳で、cl_dram_dmaのAXIバスの位置にロガーを挿入して動作を確認してみた。 GitHubに変更箇所をアップロードしてある。

f:id:msyksphinz:20180512230652p:plain
図. cl_dram_dma のデザインでアサーションを挿入した場所

github.com

ちなみに、テストパタンはTBで記述されている。ソフトウェアで書いてあるのかと思ったら違うのね。

  • aws-fpga/hdk/cl/examples/cl_dram_dma/verif/tests/test_dram_dma.sv

  • 0x0000_0000_0002 から 128byte ほど 0xAA を転送する。

      //Queue data to be transfered to CL DDR
      tb.que_buffer_to_cl(.chan(0), .src_addr(host_memory_buffer_address), .cl_addr(64'h0000_0000_0002), .len(len0) ); // move buffer to DDR 0

      // Put test pattern in host memory
      for (int i = 0 ; i < len0 ; i++) begin
         tb.hm_put_byte(.addr(host_memory_buffer_address), .d(8'hAA));
         host_memory_buffer_address++;
      end
  1. 0x0004_0000_0000 から 128byte ほど 0xBB を転送する。
      tb.que_buffer_to_cl(.chan(1), .src_addr(host_memory_buffer_address), .cl_addr(64'h0004_0000_0000), .len(len1) ); // move buffer to DDR 1

      for (int i = 0 ; i < len1 ; i++) begin
         tb.hm_put_byte(.addr(host_memory_buffer_address), .d(8'hBB));
         host_memory_buffer_address++;
      end
  1. 0x0008_0000_0005 から 6000byte ほど 0xCC を転送する。
      tb.que_buffer_to_cl(.chan(2), .src_addr(host_memory_buffer_address), .cl_addr(64'h0008_0000_0005), .len(len2) ); // move buffer to DDR 2

      for (int i = 0 ; i < len2 ; i++) begin
         tb.hm_put_byte(.addr(host_memory_buffer_address), .d(8'hCC));
         host_memory_buffer_address++;
      end
  1. 0x000C_0000_0000 から 300byte ほど 0xDD を転送する。
      tb.que_buffer_to_cl(.chan(3), .src_addr(host_memory_buffer_address), .cl_addr(64'h000C_0000_0000), .len(len3) ); // move buffer to DDR 3

      for (int i = 0 ; i < len3 ; i++) begin
         tb.hm_put_byte(.addr(host_memory_buffer_address), .d(8'hDD));
         host_memory_buffer_address++;
      end

一応、正しくログが取れているようだ。

tb.card.u_ddr4_rdimm_D.rcd_enabled.genblk1.u_ddr4_dimm.rank_instances[0].even_ranks.u_ddr4_rank.Micron_model.instance_of_sdram_devices[15].micron_mem_model.u_ddr4_model.always_diff_ck.if_diff_ck:Initialization complete @27185552
tb.card.u_ddr4_rdimm_D.rcd_enabled.genblk1.u_ddr4_dimm.rank_instances[0].even_ranks.u_ddr4_rank.Micron_model.instance_of_sdram_devices[16].micron_mem_model.u_ddr4_model.always_diff_ck.if_diff_ck:Initialization complete @27185552
tb.card.u_ddr4_rdimm_D.rcd_enabled.genblk1.u_ddr4_dimm.rank_instances[0].even_ranks.u_ddr4_rank.Micron_model.instance_of_sdram_devices[17].micron_mem_model.u_ddr4_model.always_diff_ck.if_diff_ck:Initialization complete @27185552
[            33462000] : Initializing buffers
[            33462000] : starting H2C DMA channels
            33474000 : [sh_cl_dma AW] LEN=  0 SIZE=6 ADDR=0000000000000002
            33474000 : [sh_cl_dma  W] STB=fffffffffffffffc DATA=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0000
            33482000 : [sh_cl_dma  W] STB=ffffffffffffffff DATA=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
            33490000 : [sh_cl_dma AW] LEN=  0 SIZE=6 ADDR=0000000000000040
            33494000 : [sh_cl_dma  W] STB=0000000000000003 DATA=0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000aaaa
            33506000 : [sh_cl_dma AW] LEN=  0 SIZE=6 ADDR=0000000000000080
            33510000 : [sh_cl_dma  W] STB=ffffffffffffffff DATA=bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
            33522000 : [sh_cl_dma AW] LEN=  1 SIZE=6 ADDR=0000000400000000
            33526000 : [sh_cl_dma  W] STB=ffffffffffffffff DATA=bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
            33642000 : [sh_cl_dma AW] LEN=  0 SIZE=6 ADDR=0000000800000005
            33646000 : [sh_cl_dma  W] STB=ffffffffffffffe0 DATA=cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc0000000000
            33650000 : [sh_cl_dma  W] STB=ffffffffffffffff DATA=cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
            33766000 : [sh_cl_dma AW] LEN= 62 SIZE=6 ADDR=0000000800000040
...

RISC-V仕様のFormal表現いろいろ

8th RISC-V Workshop in Barcelona で非常に気になったワーキンググループの一つ、RISC-V Formal Specification について調べた。

Formal Group は、 RISC-Vの仕様を、英語で書かれた仕様書としてだけでなく、マシンでもチェック可能なプログラムのような形で表現すること。 実際、RISC-Vの仕様書はすべての命令が英語の文章として記述されており、正式なDescriptionとして記述されてないので非常に気になっていた。

f:id:msyksphinz:20180512000426p:plain
MITによるFormal Semanticsの発表。発表資料は[リンク先](https://content.riscv.org/wp-content/uploads/2018/05/slidesThomasBourgeat.pdf)を参照。

今回の 8th RISC-V Workshop でのMITの発表は、このRISC-Vの仕様をHaskellとして表現する、ということ。

ちなみにこれ以外にもFormal表現はたくさんあるらしい (RISC-V Organizationは統一する気は無いのか...)

このriscv-semanticでいうと、さらに、CLASHというコンパイラを使うと、Haskellのコードを回路に変換することができる、らしい。

試しにソースコードを見てみる。 確かに、すべての命令がHaskellで記述されている。

  • src/ExecuteM.hs
execute (Mulh rd rs1 rs2) = do
  x <- getRegister rs1
  y <- getRegister rs2
  setRegister rd (highBits ((regToZ_signed x) * (regToZ_signed y)) :: t)

MMUの部分とかは結構分かりやすいのではないだろうか?

  • src/VirtualMemory.hs
calculateAddress :: (RiscvProgram p t) => AccessType -> MachineInt -> p MachineInt
calculateAddress accessType va = do
  mode <- fmap getMode (getCSRField Field.MODE)
  privMode <- getPrivMode
  mprv <- getCSRField Field.MPRV
  mpp <- getCSRField Field.MPP
  let effectPriv = if mprv == 1 then decodePrivMode mpp else privMode
  if mode == None || (privMode == Machine && accessType == Instruction) || (effectPriv == Machine)
    then return va
    else -- First the translation may be in a cache, possibly stalled, cacheAccess use the typeclass defined "TLB"
      cacheAccess va $
       do
    ppn <- getCSRField Field.PPN
    maybePTE <- findLeafEntry (mode, accessType, va, (shift ppn 12)) (pageTableLevels mode - 1)
    case maybePTE of
      Nothing -> pageFault accessType va
      Just (level, pte, addr) -> do
        let r = testBit pte 1
        let w = testBit pte 2
        let x = testBit pte 3
        let u = testBit pte 4

RISC-V Formal Semantics を使えるようにする

まずは、Haskellコンパイラ環境であるStackをインストールする。

curl -sSL https://get.haskellstack.org/ | sh
git clone https://github.com/mit-plv/riscv-semantics.git
cd riscv-semantics
./install.sh  # これで何かしら大量にインストールされる

で、make を実行してみるのだが、なんか失敗するじゃないか。

$ make
riscv-none-embed-gcc -march=rv32im -mabi=ilp32 -static -nostdlib -nostartfiles -mcmodel=medany -c init.S -o init32.o
make[1]: riscv-none-embed-gcc: コマンドが見つかりませんでした
Makefile:25: ターゲット 'init32.o' のレシピで失敗しました

そもそも riscv-none-embed-gcc が必要とは書いていないのでこれはおかしいのでは?Makefileを書き直してriscv32-unknown-elf-gcc で書き直してみる。

diff --git a/Makefile b/Makefile
index 4878218..689bf7d 100644
--- a/Makefile
+++ b/Makefile
@@ -9,7 +9,9 @@ test:
        $(MAKE) -C test

 riscv-tests:
-       RISCV_PREFIX=riscv-none-embed- $(MAKE) -C riscv-tests/isa rv64mi rv64si rv64ui
+       $(MAKE) -C riscv-tests/isa rv64mi rv64si rv64ui
+
+#      RISCV_PREFIX=riscv-none-embed- $(MAKE) -C riscv-tests/isa rv64mi rv64si rv64ui

 clean:
        rm -rf .stack-work/
diff --git a/test/Makefile b/test/Makefile
index e325f2f..289857a 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -12,8 +12,8 @@ HEX32=$(addsuffix .hex,$(ELF32))
 HEX64=$(addsuffix .hex,$(ELF64))
 ELF2HEX=../elf2hex

-RISCVCC64=riscv-none-embed-gcc -march=rv64im -mabi=lp64 -static -nostdlib -nostartfiles -mcmodel=medany
-RISCVCC32=riscv-none-embed-gcc -march=rv32im -mabi=ilp32 -static -nostdlib -nostartfiles -mcmodel=medany
+RISCVCC64=riscv32-unknown-elf-gcc -march=rv64im -mabi=lp64 -static -nostdlib -nostartfiles -mcmodel=medany
+RISCVCC32=riscv32-unknown-elf-gcc -march=rv32im -mabi=ilp32 -static -nostdlib -nostartfiles -mcmodel=medany

 all: $(HEX32) $(HEX64)

これで通るようになった。makeを実行するとテストパタンセットがすべてコンパイルされた?

ただし、ここから先のHaskellの実行がうまく行かない。Haskellについてはあまりに無知なのだが、何か間違っているのだろうか?

stack exec riscv-semantics test/build/thuemorse32.hex
Executable named riscv-semantics not found on path: ["/home/msyksphinz/work/formal/riscv-semantics/.stack-work/install/x86_64-linux/nightly-2017-10-26/8.2.1/bin","/home/msyksphinz/.stack/snapshots/x86_64-linux/nightly-2017-10-26/8.2.1/bin","/home/msyksphinz/.stack/compiler-tools/x86_64-linux/ghc-8.2.1/bin","/home/msyksphinz/.stack/programs/x86_64-linux/ghc-8.2.1/bin"...

AWS EC2 F1インスタンスを使ったハードウェア開発の勉強 (6. cl_dram_dmaの波形取得の試行)

AWS F1インスタンス HDK の勉強を続けている。なかなか時間が取れなくて遅々として進まないが...

何か一つF1インスタンス向けに一つデザインを作って動かしてみたい。そのためには、DRAMのメモリアクセスを理解して実装できるようにならなければならない。

そのために、cl_dram_dmaデザインサンプルの波形を取得したいのだが、、うまく行かない。

まず、これまでのようにVivadoシミュレータを使ったシミュレーションで、GUIを立ち上げて波形を取得しようとしたのだが、Vivado Simulatorが異常終了してしまった。

git diff Makefile.vivado waves.tcl
diff --git a/hdk/cl/examples/cl_dram_dma/verif/scripts/Makefile.vivado b/hdk/cl/examples/cl_dram_dma/verif/scripts/Makefile.vivado
index 972820f..2e50fb7 100644
--- a/hdk/cl/examples/cl_dram_dma/verif/scripts/Makefile.vivado
+++ b/hdk/cl/examples/cl_dram_dma/verif/scripts/Makefile.vivado
@@ -29,5 +29,5 @@ run:
 ifeq ($(TEST),test_null)
        cd $(SIM_DIR) && xsim -R -log $(C_TEST).log -tclbatch $(SCRIPTS_DIR)/waves.tcl tb
 else
-       cd $(SIM_DIR) && xsim -R -log $(TEST).log -tclbatch $(SCRIPTS_DIR)/waves.tcl tb
+       cd $(SIM_DIR) && xsim -R -log $(TEST).log -g -tclbatch $(SCRIPTS_DIR)/waves.tcl tb
 endif
diff --git a/hdk/cl/examples/cl_dram_dma/verif/scripts/waves.tcl b/hdk/cl/examples/cl_dram_dma/verif/scripts/waves.tcl
index 4b14d0d..706639e 100644
--- a/hdk/cl/examples/cl_dram_dma/verif/scripts/waves.tcl
+++ b/hdk/cl/examples/cl_dram_dma/verif/scripts/waves.tcl
@@ -24,4 +24,4 @@ if { [string length $curr_wave] == 0 } {
 }

 run 200 us
-quit
+# quit
make TEST=test_dram_dma
f:id:msyksphinz:20180511003343p:plain
図. Vivado Simulator で波形を表示させようとすると落ちる。

しかし諦めることはない。aws-fpgaリポジトリはそれ以外のシミュレータも対応している。 例えば、VCS / QuestaSim / IES に対応している。 私はVCSやIESは持っていないが、Quaestaならば Intel FPGA Starter Editionが無料で使えるではないか!どうにかこれで代用できないだろうか?

www.altera.co.jp

というわけ、Xilinxの環境にも関わらず、QuestaSim Intel FPGA Starter Editionをダウンロードしてインストールした。

インストール自体は普通に完了した。ただしいくつか正常に動作させるために足りていないといわれるパッケージをインストールしたり、QuestaSimのディレクトリでリンクを追加したりした。

$ cd ${HOME}/intelFPGA_lite/18.0/modelsim_ase
$ ln -s linuxaloem linuxpe
$ ln -s linuxaloem linux_x86_64pe

さらに、QuestaSimを動作させるために Makefile を以下のように変更した。 これでシミュレーションを実行する。

diff --git a/hdk/cl/examples/cl_dram_dma/verif/scripts/Makefile.questa b/hdk/cl/examples/cl_dram_dma/verif/scripts/Makefile.questa
index 994d639..3480a42 100644
--- a/hdk/cl/examples/cl_dram_dma/verif/scripts/Makefile.questa
+++ b/hdk/cl/examples/cl_dram_dma/verif/scripts/Makefile.questa
@@ -26,13 +26,13 @@ compile: $(COMPLIB_DIR)
        mkdir -p $(SIM_DIR)
        cd ${SIM_DIR} && ln -s -f ../questa_complib/modelsim.ini
        cd $(SIM_DIR) && vlog $(C_FILES) -ccflags "-I$(C_SDK_USR_INC_DIR)" -ccflags "-I$(C_SDK_USR_UTILS_DIR)" -ccflags "-I$(C_COMMON_DIR)" -ccflags "-DSV_TEST" -ccflags "-DSCOPE" -ccflags "-I$(C_INC_DIR)"
-       cd $(SIM_DIR) && vlog -mfcu -sv -64 -timescale 1ps/1ps -93 -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/secureip -f $(SCRIPTS_DIR)/top.$(SIMULATOR).f
+       cd $(SIM_DIR) && vlog -mfcu -sv -timescale 1ps/1ps -93 -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/secureip -f $(SCRIPTS_DIR)/top.$(SIMULATOR).f

 run:
 ifeq ($(TEST),test_null)
-       cd $(SIM_DIR) &&  vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_12 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_13 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_11 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_11 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -l $(C_TEST).log -do "run -all; quit -f" tb glbl $(TEST)
+       cd $(SIM_DIR) &&  vsim -c -voptargs="+acc" -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_12 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_13 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_11 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_11 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -l $(C_TEST).log -do "run -all; quit -f" tb glbl $(TEST)
 else
-       cd $(SIM_DIR) &&  vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_12 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_13 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_11 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_11 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -l $(TEST).log -do "run -all; quit -f" tb glbl $(TEST)
+       cd $(SIM_DIR) &&  vsim -c -voptargs="+acc" -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_12 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_13 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_11 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_11 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -l $(TEST).log -do "add log -r sim:/tb/card/fpga/CL/*; run -all" tb glbl $(TEST)
 endif

 $(COMPLIB_DIR):

シミュレーションを実行すると、以下で固まってしまった。Vivado Simulator (のGUIなし)だと、ちゃんと進むのに...

make TEST=test_dram_dma QUESTA=1
# Info: [Unisim HPIO_VREF-1] Fabric Tune Value changed to 0011101. Instance: tb.card.fpga.CL.SH_DDR.<protected>.<protected>.<protected>.inst.u_ddr4_mem_intfc.u_mig_ddr4_phy.inst.u_ddr_iob.genByte[8].u_ddr_iob_byte.genblk1.genVref.u_hpio_vref
# Info: [Unisim HPIO_VREF-1] Fabric Tune Value changed to 0011101. Instance: tb.card.fpga.CL.SH_DDR.<protected>.<protected>.<protected>.inst.u_ddr4_mem_intfc.u_mig_ddr4_phy.inst.u_ddr_iob.genByte[7].u_ddr_iob_byte.genblk1.genVref.u_hpio_vref
# Info: [Unisim HPIO_VREF-1] Fabric Tune Value changed to 0011101. Instance: tb.card.fpga.CL.SH_DDR.<protected>.<protected>.<protected>.inst.u_ddr4_mem_intfc.u_mig_ddr4_phy.inst.u_ddr_iob.genByte[6].u_ddr_iob_byte.genblk1.genVref.u_hpio_vref
# Info: [Unisim HPIO_VREF-1] Fabric Tune Value changed to 0011101. Instance: tb.card.fpga.CL.SH_DDR.<protected>.<protected>.<protected>.inst.u_ddr4_mem_intfc.u_mig_ddr4_phy.inst.u_ddr_iob.genByte[5].u_ddr_iob_byte.genblk1.genVref.u_hpio_vref
# Info: [Unisim HPIO_VREF-1] Fabric Tune Value changed to 0011101. Instance: tb.card.fpga.CL.SH_DDR.<protected>.<protected>.<protected>.inst.u_ddr4_mem_intfc.u_mig_ddr4_phy.inst.u_ddr_iob.genByte[4].u_ddr_iob_byte.genblk1.genVref.u_hpio_vref
# Info: [Unisim HPIO_VREF-1] Fabric Tune Value changed to 0011101. Instance: tb.card.fpga.CL.SH_DDR.<protected>.<protected>.<protected>.inst.u_ddr4_mem_intfc.u_mig_ddr4_phy.inst.u_ddr_iob.genByte[3].u_ddr_iob_byte.genblk1.genVref.u_hpio_vref

GUIを立ち上げてみた。とりあえずシミュレーションは進んでいるようだが、まったく終わらない... 一応波形は取れているようだが、Vivado Simulationに比べて非常に遅い。何故だ?

f:id:msyksphinz:20180511010814p:plain
図. test_dram_dma の波形を取得する。なんとなく波形がとれているが...

「30日でできる!OS自作入門」を読み始めた (26日目 ウィンドウの高速化と複数コンソール起動のサポート)

30日でできる! OS自作入門

30日でできる! OS自作入門

26日目はウィンドウを完了する。前半はウィンドウの表示の高速化と、後半はコンソールを複数表示できるようにするための手法だ。

前半のウィンドウの高速化は、これまでは8ビット単位で行っていたビット情報の代入を、32bit単位で行うことによってウィンドウの高速化を行う。 その分、タイルの表示位置位置を4ピクセル単位に変更して、処理を高速化することに成功している。

後半はウィンドウを複数表示できるようにし、コンソールを何度も作成できるようにした。 徐々にアプリケーションを起動するのが楽しくなってきた。これでメニューバーとか表示出来たらすごく楽しそうだ。

f:id:msyksphinz:20180513173116p:plain