daisukeの技術ブログ

AI、機械学習、最適化、Pythonなどについて、技術調査、技術書の理解した内容、ソフトウェア/ツール作成について書いていきます

QEMUに似たRenodeというOSSの組込みデバイスエミュレータを試す

今回から、Renode というオープンソースの組込みデバイスのエミュレータを試していきます。

簡単に言うと、QEMU と同じ位置付けの OSS です。QEMU よりも、組込みデバイスのサポートが充実しているようです。

それでは、やっていきます。

はじめに

「QEMUを動かす」の記事一覧です。良かったら参考にしてください。

QEMUを動かすの記事一覧

まず、Renode の公式サイトは以下です。

https://renode.io/

Renode の公式のドキュメントは以下です。

https://renode.readthedocs.io/en/latest/

また、GitHub は以下です。

https://github.com/renode/renode

今回は、Renode のインストールと、サンプルソースの動作確認をやっていきます。

Renodeのインストール

インストール手順は、公式の GitHub に書かれているので、それに従います。

と言っても、Renode 自体は、portable を選べば、解凍するだけです。

依存しているパッケージとして、mono-complete パッケージを先にインストールする必要があります。

それではやっていきます。

mono-completeのインストール

以下の公式サイトの手順に従います。

今回は、VirtualBox の Ubuntu 22.04 にインストールしますが、Ubuntu 20.04 の手順までしか書かれてないですね。Ubuntu 20.04 の手順に従います。

Download - Stable | Mono

$ sudo apt install ca-certificates gnupg
ca-certificates はすでに最新バージョン (20230311ubuntu0.22.04.1) です。
gnupg はすでに最新バージョン (2.2.27-3ubuntu2.1) です。
$ sudo gpg --homedir /tmp --no-default-keyring --keyring /usr/share/keyrings/mono-official-archive-keyring.gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
gpg: keybox'/usr/share/keyrings/mono-official-archive-keyring.gpg'が作成されました
gpg: /tmp/trustdb.gpg: 信用データベースができました
gpg: 鍵A6A19B38D3D831EF: 公開鍵"Xamarin Public Jenkins (auto-signing) <releng@xamarin.com>"をインポートしました
gpg: 処理数の合計: 1
gpg:               インポート: 1
$ echo "deb [signed-by=/usr/share/keyrings/mono-official-archive-keyring.gpg] https://download.mono-project.com/repo/ubuntu stable-focal main" | sudo tee /etc/apt/sources.list.d/mono-official-stable.list
deb [signed-by=/usr/share/keyrings/mono-official-archive-keyring.gpg] https://download.mono-project.com/repo/ubuntu stable-focal main
$ sudo apt update
$ sudo apt install mono-devel

結構多きかったですね。

$ mono -V
Mono JIT compiler version 6.12.0.200 (tarball Tue Jul 11 21:37:50 UTC 2023)
Copyright (C) 2002-2014 Novell, Inc, Xamarin Inc and Contributors. www.mono-project.com
        TLS:           __thread
        SIGSEGV:       altstack
        Notifications: epoll
        Architecture:  amd64
        Disabled:      none
        Misc:          softdebug
        Interpreter:   yes
        LLVM:          yes(610)
        Suspend:       hybrid
        GC:            sgen (concurrent by default)

バージョン 6.12 がインストールされました。Renode には、バージョン 5.2 以上が必要という条件でした。

依存関係のパッケージインストール

続いて、他の依存関係のパッケージをインストールします。

$ sudo apt-get install policykit-1 libgtk2.0-0 screen uml-utilities gtk-sharp2 libc6-dev gcc python3 python3-pip

Renodeのダウンロードとインストール

Renode 用に専用の作業ディレクトリを作って、そこに Renode をダウンロードします。

$ mkdir renode
$ cd renode
$ wget https://github.com/renode/renode/releases/download/v1.15.0/renode-1.15.0.linux-portable.tar.gz

公式の手順では、解凍に -C--strip-components=1 を使っていますが、同じことを実現するのに、別の手順を使うのは、効率が良くないと思います。

ということで、普通のやり方にします。

$ tar zxvf renode-1.15.0.linux-portable.tar.gz
$ renode_1.15.0_portable/renode -v
Renode v1.15.0.27975
  build: 9111b18e-202403181532
  build type: Release
  runtime: Mono 4.0.30319.42000

Renode のインストールは以上です。

STM32で動作確認

公式のドキュメントには、STM32 のチュートリアルは見当たりませんでした。代わりに以下のページを見つけました。

interrupt.memfault.com

少し古いですが、このページのチュートリアルをやっていきます。

サンプルソースのビルド

起動方法が現在のものとは異なっていたり、エミュレーション開始時の挙動が少し異なります。

$ git clone https://github.com/memfault/interrupt.git
$ cd interrupt/example/renode/
$ make
git clone https://github.com/libopencm3/libopencm3.git libopencm3
Cloning into 'libopencm3'...
remote: Enumerating objects: 30727, done.
remote: Counting objects: 100% (149/149), done.
remote: Compressing objects: 100% (104/104), done.
remote: Total 30727 (delta 83), reused 75 (delta 45), pack-reused 30578
Receiving objects: 100% (30727/30727), 7.04 MiB | 25.76 MiB/s, done.
Resolving deltas: 100% (20039/20039), done.
Initializing OPENCM3 Lib
git -C libopencm3 checkout 89074d6a13ed7febba04d3c421ce7bf2b7972156
Note: switching to '89074d6a13ed7febba04d3c421ce7bf2b7972156'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:

  git switch -c <new-branch-name>

Or undo this operation with:

  git switch -

Turn off this advice by setting config variable advice.detachedHead to false

HEAD is now at 89074d6a stm32h7: fix inverted VOS settings for Vcore.
make -C libopencm3
make[1]: ディレクトリ '/home/daisuke/svn_/renode/interrupt/example/renode/libopencm3' に入ります
  GENHDR  include/libopencm3/stm32/f0/irq.json
/usr/bin/env: `python': そのようなファイルやディレクトリはありません
make[1]: *** [Makefile:59: include/libopencm3/stm32/f0/irq.json.genhdr] エラー 127
make[1]: ディレクトリ '/home/daisuke/svn_/renode/interrupt/example/renode/libopencm3' から出ます
make: *** [Makefile:17: libopencm3/89074d6a13ed7febba04d3c421ce7bf2b7972156] エラー 2

エラーが出ました。Git でエラーが出てるようです?ので、対処します。

$ cd libopencm3/
$ git switch -
$ cd ..
$ make
Initializing OPENCM3 Lib
git -C libopencm3 checkout 89074d6a13ed7febba04d3c421ce7bf2b7972156
HEAD is now at 89074d6a stm32h7: fix inverted VOS settings for Vcore.
make -C libopencm3
make[1]: ディレクトリ '/home/daisuke/svn_/renode/interrupt/example/renode/libopencm3' に入ります
  GENHDR  include/libopencm3/stm32/f0/irq.json
/usr/bin/env: `python': そのようなファイルやディレクトリはありません
make[1]: *** [Makefile:59: include/libopencm3/stm32/f0/irq.json.genhdr] エラー 127
make[1]: ディレクトリ '/home/daisuke/svn_/renode/interrupt/example/renode/libopencm3' から出ます
make: *** [Makefile:17: libopencm3/89074d6a13ed7febba04d3c421ce7bf2b7972156] エラー 2

Git は原因ではなかったかもしれません。python が無いと言われてます。python3 はあるので、シンボリックリンクを作って対応します。

$ which python3
/usr/bin/python3
$ cd /usr/bin/
$ sudo ln -s python3 python
$ cd -
$ make
Initializing OPENCM3 Lib
git -C libopencm3 checkout 89074d6a13ed7febba04d3c421ce7bf2b7972156
HEAD is now at 89074d6a stm32h7: fix inverted VOS settings for Vcore.
make -C libopencm3
make[1]: ディレクトリ '/home/daisuke/svn_/renode/interrupt/example/renode/libopencm3' に入ります
  GENHDR  include/libopencm3/stm32/f0/irq.json
  GENHDR  include/libopencm3/stm32/f1/irq.json
  GENHDR  include/libopencm3/stm32/f2/irq.json
(長いので省略)
  CC      sync.c
  CC      dwt.c
  AR      libopencm3_pac55xx.a
make[1]: ディレクトリ '/home/daisuke/svn_/renode/interrupt/example/renode/libopencm3' から出ます
touch libopencm3/89074d6a13ed7febba04d3c421ce7bf2b7972156
Building renode example app
make -f Makefile_renode_example.mk
make[1]: ディレクトリ '/home/daisuke/svn_/renode/interrupt/example/renode' に入ります
  CC    renode-example.c
  GENLNK  stm32f407vgt6
  LD    renode-example.elf
  OBJCOPY       renode-example.bin
make[1]: ディレクトリ '/home/daisuke/svn_/renode/interrupt/example/renode' から出ます

ビルドは成功したようです。

実行してみる

Renode は解凍したディレクトリ以下のパスを、@xxx という形で、相対パスで指定できるようです。生成された ELFファイルのシンボリックリンクを Renode のディレクトリに作ることにします。

$ cd renode_1.15.0_portable/
$ ln -s ../interrupt/example/renode/renode-example.elf

それでは、Renode を起動していきます。

$ ./renode

Renode を起動すると、Renode モニターと呼ばれる、Renode 用のコンソールが自動的に立ち上がります(下図の右側のウィンドウ)。

Renodeを起動したところ
Renodeを起動したところ

この Renode モニターで、以下のように、環境の構築、評価ボードの指定、ELF ファイルのロード、UART 用のモニターの起動、GDB の設定などを行い、最後に start でエミュレーションを開始します。

(monitor) mach create
(machine-0) machine LoadPlatformDescription @platforms/boards/stm32f4_discovery-kit
.repl
(machine-0) sysbus LoadELF @renode-example.elf
(machine-0) showAnalyzer sysbus.usart2
(machine-0) machine StartGdbServer 3333
(machine-0) start

しかし、チュートリアルにもあるように、今回の評価ボードの設定が、CCM メモリに対応していないため、以下のような大量の警告が出ます。

18:04:50.1427 [WARNING] sysbus: [cpu: 0x8000D94] WriteDoubleWord to non existing peripheral at 0x1004CC3C, value 0x0.

チュートリアルの方で、CCM の設定を作ってくれているので、それを使います。拡張子が repl のファイルは、REnode PLatform という Renode の設定ファイルです。

$ cp ../interrupt/example/renode/add-ccm.repl ./
$ cat add-ccm.repl
ccm: Memory.MappedMemory @ sysbus 0x10000000
    size: 0x10000

ついでに、シェルスクリプトのように、自動的に設定などを実行するファイルもコピーしておきます。この拡張子が resc のファイルも Renode で使うファイルで、REnode SCripts から来ているようです。

先ほど、手動で実行した内容が、書かれています。

$ cp ../interrupt/example/renode/renode-config.resc ./
cat renode-config.resc
:name: STM32F4 Discovery Printf
:description: This script runs the usart_printf example on stm32f4 discovery

$name?="STM32F4_Discovery"
$bin?=@renode-example.elf

# Create Machine & Load config
mach create $name
machine LoadPlatformDescription @platforms/boards/stm32f4_discovery-kit.repl
machine LoadPlatformDescription @add-ccm.repl

# Create a terminal window showing the output of UART2
showAnalyzer sysbus.usart2

# Enable GDB
machine StartGdbServer 3333

macro reset
"""
    sysbus LoadELF $bin
"""

runMacro $reset

では、今度は、rescファイルを使って実行します。Renode の起動に引数として、rescファイルを指定することが出来ます。

$ ./renode renode-config.resc

起動した Renodeモニターに、「start」を入力します。

hello worldが出た
hello worldが出た

USART で警告が出てるのが気になりますが、とりあえず、動作したようです。

おわりに

今回は、QEMU に似た、Renode というエミュレータを動かしてみました。

少し使ってみた印象としては、QEMU より扱いやすく、UI(ユーザインタフェース)が洗練されている感じです。QEMU は、CCMデータRAM に対応していませんでしたが、Renode は、設定を追加するだけで対応できました。

また、QEMU は、Eclipse で使えましたが、Renode は、VSCode のデバッグに公式のドキュメントとして対応しています(QEMU も VSCode で動かせると思います)。

次回は、Renode で GDB を使ってデバッグをしてみたいと思います。

この記事が誰かの役に立てば嬉しいです。

最後になりましたが、エンジニアグループのランキングに参加中です。

気楽にポチッとよろしくお願いいたします🙇

今回は以上です!

最後までお読みいただき、ありがとうございました。