RA2A1 シミュレーターを作っている話 — 設計・実装・検査のフローと現在地
なぜシミュレーターを自作するのか
マイコン開発の地味な苦しみのひとつが、「コードを書いてはボードに焼いて、動作を確認して、また書く」というサイクルの遅さです。
書き込み自体は数秒で終わっても、ロジックのデバッグのためだけにボードに手を伸ばし、シリアルターミナルを開き、ケーブルが抜けていないか確認する……その繰り返しに、じわじわとコストが積み上がります。
というわけで、RENESAS RA2A1 グループのマイコン用ハードウェアシミュレーターをC++で自作しています。
✏️ dencat添削: 「自作」というか、正確には AIエージェント(AntigravityとClaude code)との二人三脚 で構築を進めています。実は私、コードを一行も書いていません……!全体の方針立てとレビューが主な役割です。
目標はシンプルです。
「実機(e2 studio)のCコードを1文字も変えずに、PC上で動かしてデバッグできる環境を作る。」
シミュレーターの設計方針
実機コードをそのまま使う
e2 studio プロジェクト内の Cソースコードを「読み込み専用」で直接参照し、PC(x86_64)向けにクロスコンパイルします。FSP(Renesas Flexible Software Package)が提供するAPI(R_SCI_Open や R_ADC_ScanStart など)はPC用のモックに差し替えることで、ファームウェアのコードを一切書き換えずに動かせます。
OOPによるペリフェラル分離
GPIO、ADC、UART(SCI)などの周辺回路は、それぞれ ISimulatedPeripheral を継承した独立したクラスとして実装しています。新しいペリフェラルを追加するときも、既存モジュールに触れる必要がありません。
環境を汚さないローカルビルド
OpenGLやX11などの開発ライブラリは、Micromamba(軽量版Conda)を使ってプロジェクト内の ./env にのみインストールします。ホストの /usr は一切変更しません。
開発・検査サイクル
各ペリフェラルの追加は、以下のサイクルに従って進めています。
要求仕様の設計・合意
↓
インターフェース先行設計(ISimulatedPeripheral)
↓
レジスタ・時間シミュレーション実装
↓
自動テストコードの作成(Unit / Integration Test)
↓
実機ファームウェアとの統合実行
↓
GUIおよびロジックアナライザによる動作確認
↓(パスすれば)
リリース & ロードマップ更新
「動いた気がする」ではなく、自動テストで100%通過することを定義の完了(DoD) としています。
全体ロードマップ(4フェーズ)
フェーズ I:シミュレータ検証基盤の確立 ← 今ここ
✏️ dencat添削: 想像より進んでます!すでに ハードウェアマニュアル26章ぶんを実装完了、各種ペリフェラルをどんどん実装中というフェーズです。
まず土台を固めています。
- テストランナー導入: CMakeにGoogle Testを統合し、GPIO・ADC・SCI・DACの各レジスタ読み書きと時間進行を自動テストでカバー
- FSPモックの構築: 実機ファームウェアのヘッダーをPC用に差し替えてネイティブコンパイル可能にする
- ICU(割り込みコントローラー)の独立化: 暫定実装だった
MockNvicをIcuPeripheralとして正式に切り出し、割り込みイベントリンクレジスタ(IELSRn)と接続する - ELC(イベントリンクコントローラー): タイマーからADCへのような非同期イベント伝播バスを実装する
フェーズIのDoD(Definition of Done):
- 既存の GPIO / SCI / ADC / DAC の自動テストが100%通過すること
- 実機ファームウェアのコードがエラーなくx86_64向けにビルドできること
- ELCによるイベント連鎖がテストコード上で正確に動作すること
フェーズ II:ファームウェアループ & ライフサイクル制御
while(1) のメインループを安全に走らせながら、GUIがフリーズしない実行モデルを確立。WDT(ウォッチドッグ)のリセットや、スタンバイ・スヌーズといった低消費電力モードも実装する予定です。
フェーズ III:通信 & データフローの高度化
I2C、SPI、CANなどのバス通信の精密模擬と、DTC(データトランスファコントローラー)によるCPU非介入の自動転送、MPU(メモリ保護ユニット)違反検出などを実装します。
フェーズ IV:アナログ極限 & 実機挙動一致検証
オペアンプ、コンパレータ、24ビットΣΔ ADCなどのアナログ回路の物理シミュレーションと、RFP(Renesas Flash Programmer)による仮想フラッシュ書き込みシーケンスの再現を目標にしています。
今できていること
すでに動いているもの:
- GPIO: ポートレジスタへの読み書きとGUI上でのピン状態表示
- SCI / UART: 物理ピンレベルのUARTシミュレーション。
PCLK分周とBRR(ビットレートレジスタ)の値から正確なビットタイミングを逆算し、ボーレート不一致による「文字化け」まで再現できます - ADC: スキャンシーケンスの基本動作
- DAC: デジタル-アナログ変換の基本
UARTの文字化け再現が特にお気に入りです。GUIのBRRレジスタを変更すると、minicomやTeraTermに接続したターミナルがリアルタイムで文字化けし始めます。「実機でなぜか文字化けした」という問題をシミュレーター上で再現・調査できるのが強みです。
✏️ dencat添削: ここに挙げたのは一部分。実際には GDBデバッグで
Reset_Handler〜hal_entryのブレークポイント到達も確認済み で、思っていたよりずっと進んでいました!
規模感
| 項目 | 執筆時点の見積もり | ✏️ dencat添削(実数) |
|---|---|---|
| 言語 | C++(シミュレーター本体) | (変更なし) |
| ビルドシステム | CMake + Micromamba(隔離環境) | (変更なし) |
| テストフレームワーク | Google Test | (変更なし) |
| GUIフレームワーク | OpenGL + ImGui | (変更なし) |
| 対象MCU | RENESAS RA2A1グループ(ARM Cortex-M23) | (変更なし) |
| ペリフェラル実装済み | GPIO / SCI / ADC / DAC | ハードウェアマニュアル26章ぶん実装済み |
仕様書(*-spec.md) |
(未記載) | 約7,000行 |
| ソースコード | (未記載) | 約30,000行(見積もり) |
| プロジェクト容量 | (未記載) | 約1GB |
| フェーズ | I / IV(基盤確立中) | 各種ペリフェラルを並行実装中 |
おわりに
フェーズI完了まではまだ作業があります。特に FSPモックの範囲をどこまで広げるかがポイントで、ここが土台になるのでじっくり進めているところです。
✏️ dencat添削: 「土台はもうほぼ固まっていて、各種ペリフェラルの実装ラッシュ中」という方が正確です。次は
iodefineの検証(レジスタのヌケモレチェック)と、EK-RA2A1サンプルプロジェクトを通せるかの確認に向かいます。
進捗はこのブログで随時報告していく予定です。マイコン開発をしている方や、「シミュレーター自作おもしろそう」と思ってくれた方、フィードバックがあればぜひ。
この記事は、Yuki-System のエージェントであるユキ(Claude code)によって、管理者との対話を通じて執筆されました。
dencat's note
クォーター制限ぐぬぬ
というわけで、2週間ぶりくらいにブログを書きますが、何がおきていたかと言うと、、、
AntigravityをRA2A1シミュづくりの為に酷使して、週間クォーター制限を先週も、今週も食らっておりました。。。
あまりにもエージェントAIを使えない日々が続いたフラストレーションで、Claude code APIを25ドル消費してしまい、「そんなことならPro版使ったほうが安いじゃん」、と思い、Pro版を用意しました。
というわけで、AntigravityとClaude codeの二刀流でRA2A1シミュレーターの構築を進めています。
なぜRA2A1?
お仕事でたっぷり擦りまくっているからですね。
これからもお世話になりますし、ルネサスのRAシリーズはこれからもガンガンお世話になりそうですから。
どんな進め方をした?
- 要件定義。とりあえず「おもちゃ」を用意してみる
- まずは、GUIを用意。
- LEDに見立てた丸ポチをLチカさせたり
- UARTでボーレートが合わないために文字化けが発生させたり
- 最終的に求めるのは、
- 簡易な「レジスタ」シミュレートと、
- 高精度重視の「クロック」シミュレート。
- 本当にできるの?って僕自身でも謎ですけど。レジスタくらいならできるでしょうね。。。多分。
- まずは、GUIを用意。
- 全体の進行方向定義
- ハードウェアマニュアルの解析。
- 章毎の実装。
- 実装結果の妥当性チェック。
- EK-RA2A1サンプルコードをシミュレートできるか。
- ハードウェアマニュアルの解析
- 約1500ページを章毎のPDFに分解。
*-spec.mdに1章ずつ構築。
- ハードウェアマニュアル解析結果のレビュー
- Antigravityに用意してもらった
*-spec.mdを、Claude codeにレビューしてAntigravityに突き返し
- Antigravityに用意してもらった
- 基本機能を実装。
- 基本的なところまで作れたところで、GDBサーバーとのやり取りデバッグ
Reset_Handler〜hal_entryにつけたブレークポイントへ到達
- 各種ペリフェラルをどんどん実装中。。。
どんな規模になっている?
現在、26章まで実装したところで、RA2A1シミュレーションプロジェクトは、1GBくらいの容量になりました。
*-spec.md はすべてで7000行の規模となり、ソースコードは3万行くらいと見積もって作業を勧めています。
コードは書いている?
一行も書いておらず。私がやっていることは、、、
- 全体の進め方の方針立て
- DTCのバックグラウンドで何がおきているか知りたいとか、
- GDBデバッグ通らない、ぐぬぬとか。
- 進め方の補正とか。
- e2studioで動作確認用の.elfの作成とか。
以前作成したagentic-aiスキルがキチンと働いていますね。
今後の予定
- 実装の続き
- 作られた
iodefineの検証(レジスタのヌケモレチェック) - EK-RA2A1サンプルプロジェクトを全部通せるかの動作確認
でんねこ