眼鏡止水

FPGA、ネットワーク機器、料理、そしてメガネ女子。

【LiteX】WSL2上でLinuxの動くマルチコアRISC-V SoCをシミュレートする

概要

世は大マルチコア時代、身近なコンピュータシステムの多くがマルチコアのCPUを搭載しています。

本記事では、WSL2上でLinuxの動くマルチコアRISC-V SoCをシミュレートし、その動作を観察します。

作業

今回はLinux on LiteX-VexRiscvを使います。 まずはこれを使うにあたって必要な準備をします。 基本的に、READMEの内容に従います。

LiteXなどのインストール

Linux on LiteX-VexRiscvはLiteXのインフラを用います。 そのため、LiteXおよびその周辺環境をインストールする必要があります。 LiteXのREADME過去の記事を参考に、LiteX、meson、ninja、riscv-gnu-toolchainをインストールします。

blog.ojioji.ikeojihouse.com

Verilatorのインストール

Linux on LiteX-VexRiscvはシミュレータとしてVerilator (v4.2xx以降) を用います。 一方で、Ubuntuのaptでインストールされるものは記事執筆時点でv4.038のため、自前でビルドする必要があります。

Verilatorのドキュメント過去の記事を参考に、Verilatorの最新安定版をインストールします。

blog.ojioji.ikeojihouse.com

筆者の環境ではVerilator v5.026がインストールされました。

$ verilator --version
Verilator 5.026 2024-06-15 rev UNKNOWN.REV

SBTのインストール

Linux on LiteX-VexRiscvのREADMEには「標準的なVexRiscv-smpは生成済みだぜ。カスタムしたものを生成したい時だけSBTを使うぜ」と書いていますが、実際に作業を進めていると、どうやらシミュレーション用のCPUをSBTで生成するステップがあるようでした。 そのため、SBTをインストールします。

SBTのドキュメント過去の記事を参考に、SBTをインストールします。

blog.ojioji.ikeojihouse.com

筆者の環境ではSBT 1.10.1がインストールされました。

LinuX on Litex-VexRiscvのクローンとシミュレーション実行

初めに依存パッケージのインストールを行います。

sudo apt install -y build-essential device-tree-compiler wget git python3-setuptools

続いて、Linux on LiteX-VexRiscvをGitHubからクローンし、ディレクトリに移動します。

git clone https://github.com/litex-hub/linux-on-litex-vexriscv
cd linux-on-litex-vexriscv

次に、Issue #164からビルド済みのLinuxイメージおよびOpenSBIイメージをダウンロードし、適切な場所へ配置します。

cd images
wget https://github.com/litex-hub/linux-on-litex-vexriscv/files/8331338/linux_2022_03_23.zip
unzip -o linux_2022_03_23.zip
cd ..

そして、SoCを生成しシミュレーションを実行します。

./sim.py

おやおや、ライブラリが足りないと怒られました。 筆者の環境ではlibevent-devとlibjson-c-devを追加したところ動きました。

sudo apt install -y libevent-dev libjson-c-dev

再度sim.pyを実行したところ、LiteXのBIOSが起動し、OpenSBIが起動し、そしてLinux (buildroot) が起動しました。

LiteXのBIOSとOpenSBIが起動し、Linuxの起動が開始した様子。

シミュレーションのため、Linuxが起動してログインプロンプトが表示されるまでは数分程度かかりました。 ログインプロンプトにはユーザ名rootを入力することでログインできます。

マルチコアでLinuxを起動してみる

続いて、コア数を増やしてシミュレーションを行ってみます。 sim.pyを読むと、このファイルは引数をCPUであるVexRiscv-SMPのargs_fillメソッドに渡しそれを処理させていると分かります。

parser = argparse.ArgumentParser(description="Linux on LiteX-VexRiscv Simulation.")
    parser.add_argument("--with-sdram",       action="store_true",   help="Enable SDRAM support.")
    parser.add_argument("--sdram-module",     default="MT48LC16M16", help="Select SDRAM chip.")
    parser.add_argument("--sdram-data-width", default=32,            help="Set SDRAM chip data width.")
    parser.add_argument("--sdram-verbosity",  default=0,             help="Set SDRAM checker verbosity.")
    VexRiscvSMP.args_fill(parser)
    verilator_build_args(parser)
    args = parser.parse_args()

    VexRiscvSMP.args_read(args)

では、このVexRiscv-SMPのクラスはどこで定義されるかというと、それはLiteXのディレクトリにあるlitex/soc/cores/cpu/vexriscv_smp/core.pyの中です。 args_fillメソッドの定義を見るに引数--cpu-countでCPUコア数を指定できるようです。 それでは、--cpu-count=4としてシミュレーションを行ってみます。

初めにSBTが起動し、4コア版VexRiscv-SMPのVerilogファイルを生成します。 その後、1コア同様LiteX SoCやソフトウェアのビルドが走り、シミュレーションが開始します。 シミュレーションでは、やはりOpenSBIが起動し、Linuxカーネルが起動します。 注目すべき点は、セカンダリCPUたちの起動 (smp: Bringinc up secondary CPUs ...) の後に4つのCPUが認識されていることでしょう。

[    0.033890] smp: Bringing up secondary CPUs ...
[    0.061381] smp: Brought up 1 node, 4 CPUs

その後、しばらく (ほんとうにほんとうにしばらく) 待つとログインプロンプトが表示されます。 筆者の環境では、体感で20分以上かかりました。 筆者は筋トレ (大胸筋、肩、前腕) して時間をつぶしました。

rootでログインした様子。

さて、ログインプロンプトが表示されたら、先述のようにrootでログインします。 すると、Linux on LiteX-VexRiscvのAAが表示され、コマンドを入力できるようになります。 ただ、キーボードから文字を入力して反映されるまでも非常に時間がかかります。 「マルチコアなんだから速くなるのでは?」と思うかもしれませんが、今動いているものはあくまでシミュレーション、つまりソフトウェアです。 コアが増えた分シミュレーションモデルが大きくなり、ソフトウェアとして処理すべき事柄が増えたこと、そしておそらくシミュレーション自体はシングルスレッドで動いていること (htopとかでCPU使用率を見ると1スレッドが100%に張り付いているだけ。) から、現実の実行時間が大きくなっていると考えられます。

さて、念のためnprocを実行してみましょう。

root@buildroot:~# nproc
4

無事に4と表示されました。

まとめ

本記事ではLinux on LiteX-VexRiscvを用いて、WSL2上でLinuxの動くマルチコアRISC-V SoCをシミュレートしました。 その中で、Linux on LiteX-VexRiscvの処理の流れやLinux (buildroot) がRISC-V SoC上で起動する流れを確認しました。