第4章:外部メモリ ― SPI Flash/RAM で「非力さ」を脱する
第3章までで、自作の周辺(GPIO・タイマ・PWM)をWishboneに足しました。本章からは、いよいよ外部の他人のIP(既製IP)を調達して組み込む段に入ります。最初の題材は外部メモリ。序章の先輩比較表で見たとおり、CH32V003はRAM 2KB/Flash 16KBと、メモリが大きな弱点でした。本章では、外部のSPI FlashとRAMを実装し、この「非力さ」を正面から脱します。そしてこれは、後のMicroPython移植(第11章)の土台にもなります。
4.1 なぜ外部メモリが要るのか
マイコンの「窮屈さ」は、たいていメモリの少なさから来ます。プログラムが大きくなればFlash(不揮発の置き場)が足りなくなり、扱うデータが増えればRAM(作業場)が足りなくなります。FPGA内蔵のメモリ(BRAM)だけでは、すぐ頭打ちです。そこで、チップの外に大きなメモリを置いて、バス越しに使うのが定石です。
外部SPI Flash(プログラムの置き場)
不揮発(電源を切っても消えない)で、安価にMB級の容量。プログラム本体を置きます。CH32V003の16KBに対し、外部Flashなら桁違いの大きさを確保できます。
外部RAM(広い作業場)
揮発するが高速で、大きなデータ・ヒープを扱えます。MicroPythonのような「実行時にメモリを多く使う」ソフトを載せるには、ここが効いてきます。
★鍵となる仕組み「XIP(その場実行)」: 外部Flashの嬉しい使い方が XIP(eXecute In Place)です。これは、Flashの中身をCPUのメモリ空間に直接マップし、Flashから命令を読みながらそのまま実行する仕組み。いちいちRAMへコピーしなくても、大きなプログラムを外部Flashに置いたまま動かせます。先輩マイコンが「大きなプログラムを動かせる」のは、この仕組みのおかげです。本章で調達するIPは、まさにこれを実現します。
4.2 【IP調達・実演】SPI Flashコントローラを調達する
では、序章の7ステップで外部SPI Flashコントローラを調達します。今回は「他人が書いた既製IP」を相手にする初めての回。現物確認(ステップ4)の重みが、ぐっと増します。
IP調達ワークフロー:SPI Flashコントローラ
───────────────────────────────────────────────────────────────
1. 要求を言語化 ・外部SPI FlashからXIP(その場実行)できる
・PicoRV32エコシステムと相性が良い
・実績がある(枯れている)/組み込み可能なライセンス
・できればQSPI(高速)にも対応
2. 探索先 PicoRV32公式に付属する PicoSoC(公式の参照SoC), GitHub
3. 候補を絞る PicoSoC同梱の spimemio を第一候補(公式・同作者・実績)
4. 現物を確認 公式リポジトリの picosoc/spimemio.v を開いて確認(次項4.3で詳述)
5. 採否を判断 採用。ただし「接続の方言」に統合上の課題あり(後述)
6. 統合 我々のWishboneに載せる工夫が要る(4.4)
7. 検証 付属の spiflash.v(シミュ用Flashモデル)でTB → FPGAで実機確認
4.3 【現物確認】spimemio を開いて分かったこと
ステップ4で現物を確認したところ、採用に値する長所と、見過ごせない統合上の注意点の両方が見えました。正直に両方記します。
長所(採用の理由)
PicoRV32と同じ作者(Claire Xenia Wolf)・同じISCライセンス。公式の参照SoCに組み込まれた実績あるコントローラで、外部FlashからのXIPに対応し、高速なQSPIモードも持ちます。Flashをメモリ空間にマップして直接実行できます。
注意点(統合の課題)
★ spimemio は、PicoSoCの中でPicoRV32の「素のメモリI/F」に直結する前提で書かれています。Wishboneのスレーブとしては書かれていません。我々はWishbone主バスを選んだので、ここに「方言の違い」が生じます。
※これこそ「現物を開く」価値です(実験ログ): 「PicoRV32用のSPI Flashコントローラがある」という情報だけなら、AIや記事からも得られます。しかし実際にファイルを開かなければ、「それが素のI/F前提で、Wishboneではない」という肝心の事実は分かりません。もし現物を見ずに「Wishboneに挿すだけ」と思い込んで設計を進めたら、後で大きな手戻りになっていたはずです。釣った魚は、料理の前に必ず捌いて中を確かめる――7ステップのステップ4が要である理由が、ここにはっきり表れています。
※同じことが simpleuart にも言えます(先回りのメモ): 現物を見るついでに、PicoSoCのUART(simpleuart)も確認しました。こちらも同様に素のI/F前提でした。つまり「PicoSoCの周辺を我々のWishbone SoCに迎えるときは、方言の橋渡しが要る」という共通のパターンが見えてきます。これは第5章(UART調達)でも効いてくる、重要な気づきです。
4.4 統合の設計判断 ― 方言の橋をどう架けるか
採用は決めました。残るは「素のI/F方言で書かれた spimemio を、Wishbone主バスのSoCにどう載せるか」という設計判断です。ここは勝手に決めず、選択肢を並べて、考え方を示します。
案A:Wishboneスレーブで包む
spimemio を、第3章で作ったWishboneスレーブの型でラップし、バスに1つの部品として挿す。SoC全体がWishboneで統一され、見通しが良い。橋(ラッパ)を1枚書く手間がかかる。
案B:メモリ経路だけ素I/Fにする
命令フェッチの経路(Flash+RAM)はPicoSoC流に素のI/Fで組み、その他の周辺だけWishboneにするハイブリッド。XIPの性能は出しやすいが、SoCに2つの作法が混在し、複雑になる。
※本章の推奨と、確認のお願い(設計判断): 本講座は「Wishboneで統一して見通しよく学ぶ」ことを重んじてきました。その方針に沿うなら案A(Wishboneスレーブで包む)が素直です。XIPの最高速を狙う本格用途では案Bも有力ですが、まずは学びやすさ優先で案Aを推します。ただしこれは性能にも関わる設計判断なので、案A/案Bのどちらで進めるかは、著者の確認をいただいてから確定します(勝手に決めません)。決まり次第、ラッパの完全コードは検証込みの専用工程で用意します。
4.5 メモリマップを更新する
外部メモリが加わるので、第2章で作ったメモリマップを更新します。プログラムは外部Flashに置き、作業用の小さなRAM(FPGA内蔵BRAM)を速い領域として用意する――これはPicoSoCでも使われている、理にかなった構成です。
メモリマップ(外部Flash統合後・上位ニブル adr[31:28] で住み分け) ─────────────────────────────────────────────────────────────── 0x0000_0000 〜 RAM(BRAM・小さな高速作業場:スタック/データ専用) 0x1000_0000 〜 LED(第3章) 0x2000_0000 〜 GPIO(第3章。+0 出力 / +4 入力) 0x3000_0000 〜 タイマ(第3章。+0 リロード / +4 ステータス) 0x4000_0000 〜 PWM(第3章。+0 デューティ) 0x5000_0000 〜 外部SPI Flash(XIP・本章で調達)★リセットベクタ PROGADDR_RESET=0x5000_0000 0x6000_0000 〜 UART(第5章で調達) ← 以降は後章で席を予約 0x7000_0000 〜 SPI (第5章で調達) 0x8000_0000 〜 UART2(第6章・無線モジュール用) ─────────────────────────────────────────────────────────────── ※ 上記は専用ビルド工程でシミュ検証済みの割り当て。実機での最終確認は[改訂マーカー]。
※リセットベクタの設計(シミュ検証済/実機確認は改訂マーカー): PicoSoCでは、リセット直後にCPUが最初に実行する番地(リセットベクタ)をFlash内のある位置に置いていました。第1章で見たパラメータ PROGADDR_RESET を、この位置に合わせます。専用ビルド工程では、外部Flash領域の先頭 0x5000_0000 をリセットベクタとして XIP 起動することをシミュレーションで確認済みです(実機での最終確認は[改訂マーカー])。
4.6 外部RAM ― 広い作業場をどう持つか
大きなデータや、将来のMicroPythonのために、外部RAMも視野に入れます。ただしここは正直に線を引きます。Basys 3 には、すぐ使える大容量の外部RAMは載っていません(あるのはFPGA内蔵のBRAMです)。大きな外部RAMが欲しい場合は、Pmod経由でPSRAM等を増設するか、最終的な基板化(第14章)で実装する、という段取りになります。
※外部RAMコントローラのIPは、必要になった段で7ステップで(誇張を避ける): 外部RAM(PSRAM/HyperRAM等)を制御するIPにも、オープンソースの選択肢があります。ただし具体的にどれを使うかは、現物確認(実在・対応バス・ライセンス・成熟度)を経て決めるべきで、いま固有名を断定はしません。本講座では、まず内蔵BRAMの小さなRAM+外部Flashのプログラムで土台を作り、より大きな外部RAMはMicroPythonを本格的に載せる段(第11章)や基板化(第14章)で、改めて7ステップで調達します。「RAMが要る」と「このIPを使う」の間には、必ず現物確認を挟みます。
4.7 【確認】外部Flashから、プログラムを直接実行する
本章のゴールは、「外部SPI Flashに置いたプログラムが、XIPでそのまま動く」ことの確認です。検証は、序章の段階どおりに進めます。幸い、調達した spimemio にはシミュレーション用のFlashモデル(spiflash.v)が付属しているので、実物のFlashが手元になくても波形で確かめられます。
- 統合: 4.4で確定した方式(案A/案B)で、
spimemioをSoCに組み込む。 - シミュレーション: 付属の
spiflash.vをFlashの代役に使い、CPUが外部Flashから命令を読み出して実行する様子を波形で確認(第12章で本格化)。 - FPGA(Basys 3): Pmod経由で実物のSPI Flashをつなぎ、プログラムを書き込んで、XIPで動くことを実機確認。
- 記録: 「先輩の16KBを、外部Flashで桁違いに超えた」――その到達を実験ログに残す。
4.8 この章のまとめ
- 先輩の弱点に正面から向き合った: メモリの非力さを、外部Flash(プログラム)+外部RAM(データ)で脱する方針を立てた。
- XIPを理解した: 外部Flashをメモリ空間にマップし、その場で実行する仕組みを学んだ。
- 既製IPを調達した: 公式PicoSoCの
spimemio(同作者・ISC・実績・QSPI)を、7ステップで調達した。 - 現物確認で統合課題を発見した:
spimemio(とsimpleuart)は素のI/F前提でWishboneではない、という肝心の事実を、ファイルを開いて掴んだ。橋の架け方(案A/案B)を設計判断として提示した。 - メモリマップを更新した: Flash・RAM・周辺の住み分けを設計し、リセットベクタの考え方を押さえた。
外部メモリで「窮屈さ」を脱する道筋ができました。次の第5章では、いよいよ通信に踏み込みます。本章で見えた「PicoSoCの周辺は素I/F方言」という気づきを携えて、UART・SPI・I2C、そしてEthernetを調達し、Wishboneへ橋渡しします。Webhook/MQTTといった、ネット越しのAI連携につながる入口も見渡します。