Interface 2018年2月号のRISCV記事を試したメモ（更新中）

ubuntu 16.04LTS 上で試しています。
記事ではFPGAボードとしてMAX10-FBを使っていますが、手持ちの Arty-7 への実装を試みます。

いつも環境構築で挫折する私ですが、一念発起してRISCVの開発環境を作ってみることにします。

### リスト１ RISC-V用GNUツールチェーンの準備
まずは riscv-gnu-toolchain を clone します。githubで riscv toolchain で検索した結果ヒットしたリポジトリをクローンして、続いて ./configure を実行したのですが、早速うまく行きません。記事だと ./configure のオプションが ?prefix=/opt/riscv となっているけれど、これは --prefix の間違いかなーと思い、念の為[./configure --help](http://www.itmedia.co.jp/help/tips/linux/l0371.html) で確認したところ、--prpefix で良さそう。改めて`./congifure --prefix=/opt/riscv` を実行したら、いくつか今度は no という表示が出ました。どうやらライブラリをインストールし忘れていたようです。

- mpfr
- gmp
- mpc

とか。なので、`apt-cache search mpfr` としてみたところ、たくさんのパッケージが見つかりました。ライブラリ単体と開発用 (-dev が後ろにつく) の２種類があるらしいので（そこからかよ）、`apt-cache search mpfr.*dev` として改めて検索すると、8個ほどのパッケージが見つかりました。mpfr という文字列が入っていないのも引っかかるのが謎ですが、記事を見直すと、libmpfr-dev が必要らしいので、これが漏れていたのでしょう。`sudo apt-get install libmpfr-dev` して、再度 `make -j$(nproc)`　でもう少し進みました。

次の問題は、

> checking size of unsigned long... 8
> checking size of unsigned __int128... 16
> checking for library containing dlopen... (cached) -ldl
> checking whether to use expat... yes
> checking for libexpat... no
> configure: error: expat is missing or unusable
> Makefile:10389: ターゲット 'configure-gdb' のレシピで失敗しました

というログ。libexpat が必要そうなので、探してみる（`apt-cache search libexpat`）と、libexpat-dev なるパッケージが見つかったので、 `sudo apt-get install libexpat-dev` してから再度 `make -j $(nproc)`.

これで無事、ツールチェーンのmake ができました。

### リスト２　OpenOCD の準備
つづいて、OpenOCD のビルドに移ります。`./configure ...` まで実行すると、以下のようなエラーが。

> configure: error: libusb-1.x is required for the MPSSE mode of FTDI based devices

`apt-cache search libusb-1\..*-dev` とすると、libusb-1.0-0-dev というのが見つかったので、これをインストールします。
`sudo apt-get install libusb-1.0-0-dev`

で、もう一回 `./configure --enable-maintainer-mode --disable-werror --enable-ftdi` とすると、今度は最後まで進んで以下のようなログが出ました。

> OpenOCD configuration summary
--------------------------------------------------
MPSSE mode of FTDI based devices        yes
ST-Link JTAG Programmer                 yes (auto)
TI ICDI JTAG Programmer                 yes (auto)
Keil ULINK JTAG Programmer              yes (auto)
Altera USB-Blaster II Compatible        yes (auto)
Versaloon-Link JTAG Programmer          yes (auto)
OSBDM (JTAG only) Programmer            yes (auto)
eStick/opendous JTAG Programmer         yes (auto)
Andes JTAG Programmer                   yes (auto)
USBProg JTAG Programmer                 yes (auto)
Raisonance RLink JTAG Programmer        yes (auto)
Olimex ARM-JTAG-EW Programmer           yes (auto)
CMSIS-DAP Compliant Debugger            no
Cypress KitProg Programmer              no
Altera USB-Blaster Compatible           no
ASIX Presto Adapter                     no
OpenJTAG Adapter                        no
SEGGER J-Link Programmer                yes (auto)

よさげなので、つづきの作業へ。

### リスト３　Eclipseの準備
`java --version` を実行したところ、以下のようなメッセージが出ました。

>
プログラム 'java' は以下のパッケージで見つかりました:
 * default-jre
 * gcj-4.9-jre-headless
 * gcj-5-jre-headless
 * openjdk-8-jre-headless
 * gcj-4.8-jre-headless
 * openjdk-9-jre-headless
次の操作を試してください: sudo apt install <選択したパッケージ>

headless というのは [GUIのためのコンポーネントを含んでいないという意味](https://ubuntuforums.org/showthread.php?t=1506461)らしいのですが、Eclipse を使うのにGUIはないと困るので、default-jre を選択することにします。

つづいて Eclipse 本体をダウンロードして、記事の手順どおりインストールしたのですが、図３の作業をしようとすると、RISC-Vが見つかりません。どうやら[GNU MCU Eclipse Plug-in](https://gnu-mcu-eclipse.github.io/plugins/install/) をインストールしなければいけないようです。Market Place から検索してインストールを試みましたが、失敗しました。[手動でURLを指定するとうまくいくらしい](https://github.com/gnu-mcu-eclipse/eclipse-plugins/issues/228)ので、Install New Software の work with に https://gnu-mcu-eclipse.github.io/plugins/install/ をいれてみたところ、成功しました。Eclipseを再起動して、無事完了。

### リスト４　SCR1コア本体とMAX10-FB基板用のリソースを用意する

ここは特に問題なく進みました。

### リスト５　インテルHEXフォーマットのバイナリ・ファイルを Verilog HDL の $readmemh で読み込める形式に変換

ここも特に問題なし。

### リスト６　回路シミュレータModelSim の起動と論理シミュレーションの実行

Xilinx の FPGAを使おうとしているので、このあたりから怪しくなって来ます。SCR1_AMX10FB/ の下に
`mkdir xilinx` としてディレクトリを作り、その中で作業をすることにします。

PLLだけは決定的に違うので、新たに作らないといけないのですが、よくわかからないので中身のないセルでごまかします。入出力のピン名だけは、元のpll.vに合わせました。

```verilog:pll.v
module pll(
  input wire inclk0
, output wire c0
);
assign c0 = inclk0;
endmodule
```

あとは、tb_top.v を実行するために必要な RTLを順に追加していくと、走るようになります。
ただし、PROJ_MAX10FB.memh の読み込みパスだけは相対パスでうまく指定ができず、フルパスで指定しています。
読み込めているかどうかは、シミュレーションを走らせて hex という reg が X でないことで確認しました。読み込みの段階でエラーを出してくれれば良いのですが、やり方がわかりません。

program counter を見れば良いのではないかとかんがえて、pipe と付いているRTL を眺めていくと、curr_pc という信号がそれらしい。シミュレーションでモニタしてみると、ずっと0のままになっているようです。readmemh は読み込めているようで、TB の hex には入っています。ただし、0でない値が入っているのは8143 番目以降で、0番めから順に読み込んでいては0が帰り続けるのは当然です。
scr1_arch_description.svh で、`parameter bit [`SCR1_XLEN-1:0] SCR1_ARCH_RST_VECTOR = `SCR1_XLEN'h7F40;` とすると（もともとは h200）一応 imem で値が読み込まれているようです。でもGPIOはZのままなので、なにかおかしい・・・・・・

### elf を逆アセンブルして見てみる
[大熱血！アセンブラ入門](http://kozos.jp/books/asm/)（以下、大熱血）を思い出し、実行ファイルを逆アセンブルしてみようと考えました。逆アセンブラの名前がわからないので、gnu 逆アセンブラ で google先生に聞いてみると、 objdump というのがそれらしい。 /opt/riscv/bin/ を覗くと、riscv64-unknown-objdump というのがあったので、多分これだろうとおもって実行してみました。
`riscv64-unknown-objdump -d PROJ_MAX10FB.efl > PROJ_MAX10FB.d` 
できたファイルを見てみと、main は ffffd0f6 にありました。というわけで、
```verilog:scr1_arch_description.svh
// CSR parameters:
parameter bit [`SCR1_XLEN-1:0]                              SCR1_ARCH_RST_VECTOR                = `SCR1_XLEN'hffffd0f6;
```
としてRTLシミュレーションを実行すると、機械語を順に読み込んでくれました。ただし、gpio_init ではGPIOの下位3bitを出力に設定するだけで出力値の設定はないので、シミュレーション上は0xXX -> 0xXX というあまりおもしろくない結果です。

念の為、Cコードのソースに `gpio_wr(0x0007);` を追加してみたのですが、これをやるとmainのアドレスがずれるので、 scr1_arch_description.svh を書きなおさなければならなくなりました。そんな面倒なわけはないので、main は必ずきまったアドレスに来るようにするとか、なにか方法があるはずなのですが、力尽きたのでとりあえずここまで。

（追記 2018/02/08）

気をとりなおして続き。

### リンカスクリプトを追ってみる。
[KEEPは参照されていなくてもシンボルを残す指定](https://stackoverflow.com/questions/9827157/what-does-keep-mean-in-a-linker-script)らしいです。volatile みたいなもんか。
で、link.ld を読んでいくと ENTRY(_start) という記述があるのですが、C言語のソースにはこのような名前の関数はありません。

> riscv-unknown-objdump -d PROJ_MAX10FB.elf

として逆アセンブルしてみても見つかりませんでした。でも

> riscv-unknown-nm PROJ_MAX10FB.elf

とやると、0xffffff00 に _start が存在することになっています。これがどこから来たのか悩んだ挙句、苦し紛れにリンカスクリプトを一部コメントアウトしてビルドしてみたところ、eclipse のコンソールのエラーメッセージから startup.S に飛べました。この中に、`_start:` というラベルがあったので、どうやらここのようです。
（余談ですが、startup.S ではラベルとして `1:` や `3:` などが使われていて数値と見分けづらいのですが、アセンブラはこういうものなのでしょうか？）

### _start のアドレスを特定する
main.c を一部コメントアウトしたりして、.text セクションのサイズを変えて riscv-unknown-nm を繰り返してみましたが、_start は常に 0xffffff00 にいるようです。というわけで、scr1_arch_description.svh の SCR1_ARCH_RST_VECTOR のところは、デフォルトでは 0x200 となっているので、なぜこんなに違うのかはわかりませんでいたが、とりあえず

> parameter bit [`SCR1_XLEN-1:0] SCR1_ARCH_RST_VECTOR = `SCR1_XLEN'hffffff00;

と書きなおしてRTLシミュレーションをかけ直すと、一応読み込んでくれました。

（続く）