わかりやすくQEMUを説明してみる(第3回):ペリフェラル
はじめに
前回(第2回)ではQEMUでのマシン語変換について、Tiny Code Generator(TCG)やTranslation Block(TB)について説明しました。
今回(第3回)ではQEMUにおけるペリフェラル回路のモデルについて説明します。
念のため:ペリフェラル回路とは?
これまでの連載において「ペリフェラル」という単語を頻繁につかってきました。念のため「ペリフェラル」とは何かについて確認しておきたいと思います。図1にARM Cortex-M3というCPUを使ったマイコンチップであるLM3S811のブロック図を示します。
図1の赤部分がARM Cortex-M3というCPUです。一方、黒枠内にあるバスにぶら下がる各回路、例えばUART、Watchdog Timer、I2Cなどは「ペリフェラル」と呼ばれています。「ペリフェラル」とは「周辺」という意味です。「ペリフェラル」は「ペリフェラル回路」や「周辺回路」とも呼ばれます。また上図にはありませんが、バスに接続されるユーザ独自の回路、例えば画像処理回路やAI処理回路なども「ペリフェラル」の一種としてとらえることができます。
MMIO(Memory-Mapped I/O)
一般的にペリフェラルはMMIO(Memory-Mapped I/O)と呼ばれます。QEMUでもMMIOという用語が使用されています。MMIOと呼ばれる理由は、CPUから見たメモリ空間上にペリフェラルにはアドレスが割り振られているためです。CPUからは通常のメモリアクセスと同じ命令(例:loadやstore)を使用してペリフェラルを操作します。
またIOはInputOutputの略でCPUが外部デバイスとやり取りするための手段を指します。以下のようなものが含まれます。
- Input: CPUがデバイスから情報を受け取る(例: キーボード入力やセンサー値の読み取り)
- Output: CPUがデバイスに情報を送る(例: ディスプレイ出力やモーター制御信号の送信)
ペリフェラルモデルもC言語の関数
QEMUではペリフェラル回路の動作もC言語の関数として記述されます。このペリフェラルのCプログラムがやるべきことは以下の通りです。
- CPUがペリフェラル内部の起動レジスタに値を書き込むと、所定の動作を実行
- 所定の動作が完了したらCPUに割り込みを通知
- 外部からの非同期イベントを受信し、所定の動作を実行
- 例:UARTが外部端末からのイベントを受信
なお上記で「非同期イベント」という単語を使いましたが、これは「いつ来るかわからないイベント」という程度の理解でいいかと思います。
実機ではCPUと各ペリフェラルは並列に(同時に)動作しています。しかしQEMUはC言語で書かれたプログラムであり、この並列性を表現することはできません。それではどうしているかというと変換後のマシン語の実行を定期的に中断して、ペリフェラルモデルの処理を行います。
QEMUにおいてペリフェラル回路がCPUから起動される様子について図2を使って説明します。
図2では変換後のマシン語が実行されたとき、その命令がstore命令の場合は、QEMUのMMU(Memory Management Unit)にておいてIOアクセスかどうかを判定します。なお、QEMUのMMUについては別の回で説明する予定です。ここでいうIOとはペリフェラルのことです。store命令であってもDRAMへのstore(書き込み)の場合もあり、その場合はペリフェラルモデルは起動されません。store命令においてデータ書き込み先アドレスがペリフェラルの場合は、該当するペリフェラルモデルの中で定義されているwrite()関数が呼ばれます。write()関数内では書き込み先のアドレスが起動レジスタの場合にペリフェラルの動作(処理)を開始します。
ペリフェラルの処理が終わると(関数の実行が終わると)、次のTB(Translation Block)内の命令(変換後の命令)を実行します。その後CPUからペリフェラルにアクセスする機会がないとに二度とペリフェラルの処理は実施されません。例えばUARTの場合、いつ来るかわからない外部端末からのイベントを受信しなければなりません。
それでは困るのでQEMUでは1msおきに、事前に登録されている各種コールバック関数を実行します。1msという時間はホスト側のタイマーを使って計測します。また、各種コールバック関数の本体は各ペリフェラルモデルの中で定義されています。この定期的に呼ばれる処理を完了したら再びTB(Translation Block)内の次の命令(変換後の命令)を実行します。
ペリフェラルのCモデルが無い場合は?
使用したいペリフェラルに対してQEMU用のCモデルが無い場合は以下のような対応策があります。
- 独自にC言語を使ってCモデルを記述する。
- QEMUでの作法に従って記述する必要あり
- QEMUに組み込まれている既存のペリフェラルモデルを参考にしてがんばれば、できる可能性あり
- SystemCと呼ばれるC++ライブラリを使って独自に記述する
- QEMUにてSystemCモデルを使えるようにするにはそれなりの知識が必要(弊社ではSystemCモデリングも可能)
- SystemCでは、欲しいペリフェラルのモデルが存在するかもしれない
- 弊社にご相談頂く
- 弊社のQEMUモデリングサービスに関しては以下をご参照ください
次回
今回(第3回)はQEMUにおけるペリフェラルの扱いについて説明しました。
次回(第4回)はQEMUにおけるアドレス変換について説明します。ARM CPUでのアドレス空間とx86 CPUでのアドレス空間をどのように対応づけしているかについて詳しく解説します。