Intel Agilex で Nios V をたくさん実装してみた

## もくじ

- [はじめに](#はじめに)
- [環境](#環境)
- [構成（HW）](#構成hw)
- [構成（SW）](#構成sw)
- [たくさん実装してみた](#たくさん実装してみた)
- [マルチコアデバッグ](#マルチコアデバッグ)
- [おわりに](#おわりに)

<a id="anchor1"></a>
## はじめに
RISC-V の注目度は年々増加しており、多くのメーカーで RISC-V をベースとした開発が進んでいる印象です。
今回私が使用する Nios V も RISC-V ベースのプロセッサーの一つであり、こちらはインテルにより開発されたソフトコア・プロセッサーです。
この記事は、RISC-V を使用して何か面白ことができないかと考えた結果、インテル FPGA の Agilex で Nios V を限界まで実装してみた、実験系の記事となっております。 
<a id="anchor2"></a>
## 環境
今回はインテルの FPGA を使用するということと Nios V を使用するということから。。

HW 側の開発は
- [**Intel Quartus Prime Pro Edition Design Software Version 22.2 for Windows (以後 Quartus Prime)**](https://www.intel.com/content/www/us/en/products/details/fpga/development-tools/quartus-prime.html)

SW 側の開発は
- [**RiscFree IDE for Intel FPGAs (以後 RiscFree)**](https://www.intel.com/content/www/us/en/products/details/fpga/nios-processor/v.html?wapkw=nios&amp;elq_cid=8531801_ts1671086268746&amp;erpm_id=11078939_ts1671086268746)

上記を使用します。

また、FPGA (Agilex) については下記を使用します。
- [**インテル Agilex F シリーズ FPGA 開発キット**](https://www.intel.com/content/www/us/en/products/details/fpga/development-kits/agilex/f-series/dev-agf014.html)
<a id="anchor3"></a>
## 構成（HW）
今回は Nios V をたくさん実装するということで、Nios V が入ったサブモジュールを作成し、そのモジュールをトップ階層にインスタンスしていく構成にしています。
まず、サブモジュールの構成としては。
- **Nios V/m**
- **On Chip RAM**
- **JTAG-UART**

動作確認するうえで最低限必要なこの 3 つです。

トップ階層には。
- **CLK**
- **Reset**
- **サブモジュール (Nios V)**
- **ISSP 用 Reset**

を使用します。
ISSP については見慣れないかと思いますが、今回使用する開発 Kit に FPGA Reset 用のボタンがないため、ISSP により HW ロジックを使用して、Reset を toggle できるようにしていると理解していただければ大丈夫です。
ではこの構成をブロック図にするとこのような感じです。
（オレンジ色は Birdge、紫色は IP で色分けしています。）
![block.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2950832/f42d8c53-f15c-b675-1cf5-06f885cdbcc2.png)


今回の構成では、Nios V 用の実行メモリの On chip RAM は 128kByte で生成しています。
詳細については[『たくさん実装してみた』](#たくさん実装してみた)にて Platofomr Deisgner のキャプチャを紹介していますのでそちらも併せてご参照ください。

また、今回はスタンドアロンでの動作確認はしないため、各 Nios V の Reset Vector や、Boot 方法など細かい設定は特に意識せずデバッガ で elf ファイルを RAM に流して動作させるためだけの構成です。

<a id="anchor4"></a>
## 構成（SW）
SW は JTAG コンソールに出力するだけの簡易的なプログラムにしており、
複数実装するため、それぞれのコンソールでどの Nios V が動いているか確認できるよう差分を作っています。
以下今回実装する SW です。
```c:hello.c
#include "system.h"
#include <stdio.h>
#include <unistd.h>

int main() {

    for (int i = 0; i < 10000; ++i) {
    	usleep(500000);
    	printf("Hello world　count %d, Nios V/m cpu0 \n",i);
    	usleep(500000);
    }
    printf("Bye world!\n");
    return 0;
}
```
<a id="anchor5"></a>
## たくさん実装してみた。
今回の構成は Platform Designer にて作成しております。トップ階層にはサブモジュールをインスタンスすればいいため、それぞれの IP を一つ一つ実装する手間はなく、幸いトップ階層は綺麗に保てています。出来なかった場合大変だなと考えていたためこの点に関しては安心しました。（ Generate に時間はかかりましたが。。）
まず Nios V 一つだけで確認してみましょう。
先程説明した通りサブモジュール化した Nios V を 1 つだけ Platform Designer システムに実装しているように見えています。
下図が トップ階層システム。（赤枠が Sub module）
![Niosv_x1_top.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2950832/2b2688fc-8064-b870-06fe-5423421f5622.png)

こちらが Sub Module （赤枠が Nios V/m）
![Niosv_submod.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2950832/e5afbe3e-3204-c06b-7574-d3997c7ee581.png)

コンパイル結果は下図です。
![Niosv_x1_report.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2950832/c5949152-a798-047d-e19b-c2878a261b46.png)
128kB Onchip RAM に使用しておりますが、まだ 1% と余裕ですね。

では次は 10 個で試してみます。
こちらも後々楽をするために Sub module を 10 個実装した Sub module を作成し、トップ階層にインスタンスしています。
下図がコンパイル結果です。
![Niosv_x10_report.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2950832/58093b6a-2669-39d9-bb87-890d20bf8445.png)


おおよそ、RAM Block については Sub Module 一つにつき 1 % といったところでしょうか？
では、思い切って 100 個実装してみましょう。
![Niosv_x100_report.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2950832/827f78ba-4d25-12e9-a662-e2888d752275.png)



ギリギリ実装できました!
100 個実装しても大丈夫です!!

もう少し実装できるかとは思いますが、RAM リソースが 9 割以上となったため、今回は 100 個で一区切りとしたいと思います。。
<a id="anchor6"></a>
## マルチコアデバッグ
実際に複数実装した際のデバッグについても最後に書きたいと思います。
まず Nios V の開発環境ですが 2 章でも紹介した RiscFree を使用します。こちらは　Quartus Prime のダウンロード時にインストーラーを同時にダウンロードできるため、併せてインストールしています。
ではマルチコアデバッグの手順ですが RiscFree の起動や、プロジェクトのインポート等の手順はこの記事では割愛しています。
（Build までの手順は下記記事を参考にしました。）
[Ashling* RiscFree* IDE を使用した Nios®V プロジェクト開発手順](https://malt.zendesk.com/hc/ja/articles/9280647796761-Ashling-RiscFree-IDE-%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%9F-Nios-V-%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E9%96%8B%E7%99%BA%E6%89%8B%E9%A0%86 "Ashling* RiscFree* IDE を使用した Nios®V プロジェクト開発手順")
 
下図はプロジェクトをインポートし Build が完了した状態です。
（画面サイズの都合上。今回は 5 つ同時デバッグにしています。）
![Niosv_buld_comp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2950832/f1337e93-c6b1-cac6-6c42-4fe66c34db68.png)
この状態から手順の紹介をします。
まず CPU それぞれの Debug configuration を作成します。
どの CPU に対して作成するかは、下図のように Deugger タブ内の Core selection から選択できます。
![Debug.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2950832/e3c51420-8043-b4e8-2a9d-ecb184872171.png)
設定後 Apply によるそれぞれの Debug configuration を作成後、Launch Group により作成した Debug configuration を Group 化し同時実行できるようにします。
![Niosv_Lunch_group.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2950832/740de34f-b724-4ade-8a03-dae569528305.png)
これで、Debug configuration は完成です。
次に、コンソール出力先を準備します。
今回は画面表示の都合上、Nios V command shell にそれぞれの出力を表示させます。
Nios V command shell を実行する CPU の数だけ起動し、下記コマンドを実行します。
```shell:入力コマンド
#juart-terminal -c <CPU 毎に変更> -d <デバイス番号> -i <インスタンス番号>
juart-terminal -c 1 -d 0 -i 0
```
このコマンドにより、それぞれの Command shell が JTAG コンソールと紐づきます。
（ Core selection より設定した CPU の末番と -i の引数が対応しています）
![juart.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2950832/3b340b53-48b5-2df3-97e2-8b17d07c2b09.png)
それでは、先程作成した Group を選択し Debug を押下しましょう。
デフォルトで main の最初で Break するようになっているので、ユーザー側で それぞれのソースに対して Break point を増やしたり、レジスタや変数の値を確認しながらデバッグすることができます。
今回の実行結果は下図です。
JTAG コンソールが同時に動作している状況をキャプチャしています。
![Animation.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2950832/4d076f18-7687-17c8-2d2e-747a6d726664.gif)

<a id="anchor7"></a>
## おわりに
今回は面白そうという理由だけで Nios V をたくさん実装してみましたが、コンパイル時間、Platform Designer の階層設計など時間がかかる作業が多く、軽い気持ちで始めた記事でしたがなかなか大変でした。ただ、この構成を実際にされる方は少ないかと思いますので、マルチコアデバッグのところを参考にしていただければと思います。。