Cmod A7ボード(FPGA)を使って開発しているオリジナル16ビットCPUコアMoscoviumのメモリですが、命令コードを格納するためのROMと、演算や処理に使aうデータを記憶するRAMから構成されています。
今回のテーマは、命令コード格納用のROMに関する課題の克服です。
先般、Moscoviumの開発環境にBlocklyを使用可能な様に整備したところ、コードサイズが思った以上に大きくなっていました。
「#31-6 Moscoviumの開発環境(カスカス)」
「#31-7 Moscoviumの開発環境(モジモジ)」
コードサイズ比較: Blockly版÷アセンブラ版≒2.7倍
これで済むならまだ良いですが、アセンブラと言う抽象度の低いプログラミング言語から、Blocklyという抽象度の高い開発環境となることで、より複雑かつ、より大規模なプログラム開発が容易になるという特徴があります。
同じ動作のプログラムでコードサイズ×2.7倍な所に、更に大規模なプログラムを作り始めたら、ROM容量が足りなくなるのではないか?これが今回のテーマのモチベーションです。
現在のバスステートコントローラBUSC2040では、最大ROM容量16Kバイトと最大RAM容量40Kバイトを16ビットアドレス空間に配置してあります(下図)。
※上図は、この後の議論を既に反映した新メモリマップであることに留意。旧メモリマップの解説としては、ROM(16KB)/RAM(40KB)と、なっている部分に注目。
Moscoviumのプログラムカウンタpcは16ビット長なので、最大64Kバイト空間しかアクセスできない所へ、RAM領域とI/Oレジスタ領域を配置する必要があるため、今までのメモリマップでは、ROM容量を拡張する余地がありませんでした。
と、言うのは正確ではなくて、ROM容量を大きくする場合、代わりにRAM容量を減らすしか手が無い、と言った方が正しいです。
そこで、適切なROM/RAM容量比率を決定するため、手持ちのマイコンボードで使われているMCU(Micro Controller Unit)のメモリ容量について調査してみた結果が下表です。
型名 |
Flash 容量[KB] |
RAM 容量[KB] |
Flash/RAM 容量比 |
備考 |
ATtiny2313A | 2 | 0.125 | 16 | |
ATtiny85 | 8 | 0.5 | 16 | |
ATmega16U2 | 16 | 0.5 | 32 | UNO, USB⇔UART変換 |
ATmega32U4 | 32 | 2.5 | 13 | Arduino Micro |
ATmega328P | 32 | 2 | 16 | Arduino UNO |
STM32F103C8T6 | 64 | 20 | 3 | STM32ボード |
ATmega2560 | 256 | 8 | 32 | Arduino MEGA |
SAM3X8E | 512 | 96 | 5 | Arduino DUE |
考察:
そうか、ぼんやりと思い出しましたよ。Moscoviumの仕様を策定するに当たっては、PCやスマホのMPU(Micro Processing Unit)を意識してしまったのだ、と……。
PCやスマホの場合、所謂メインメモリはRAM(もっと限定すると、SDRAM)で構成されています。
通常は、補助ストレージ(NAND型Flashメモリが多い)からプログラムコードを読み込み、メインメモリ(RAM)に展開したら、RAMからプログラムをフェッチしながら実行します。
従って、PCやスマホ(MPU)に要求されるメモリ機能は以下の通りです。
補助ストレージは別として、メインメモリ(RAM)内にプログラムコードと演算データの両方を保持する必要があるので、大容量のRAMが必要、かつ、大事だと解ります。
一方、マイコン(MCU)の場合、要求されるメモリ機能は以下の様になります。
なので、MPUと異なりMCUでは実は、RAMよりROMの方が大量に必要だったのですね。
全然明後日の方向を眺めながら、Moscoviumの仕様を策定していたんじゃないのかい?これでは破綻するはずです。
そうと解れば、サクッと頭を切り替えて、相応にROM容量を拡大すれば良いのです(1^−^)d。
Moscovium マイコン |
ROM 容量[KB] |
RAM 容量[KB] |
ROM/RAM 容量比 |
備考 |
現状 | 16 | 40 | 0.4 | 逆転 |
案1) | 32 | 24 | 1.3 | ROM容量×2倍 |
案2) | 40 | 16 | 2.5 | STM32ボード(STM32F103C8T6)級 |
案3) | 48 | 8 | 6.0 | Arduino DUE(SAM3X8E)級 |
考察:
同じマイコン(MCU)である、STM32ボードやDUEのROM/RAM容量比に倣って、最大48KバイトROM、8KバイトRAMまでROM容量を拡大する事とします。
新メモリマップは、下図を参照してください。
本当に大容量のRAMが必要なアプリケーションがあれば、24ビット拡張アドレス空間に配置した、E-RAM領域(最大128KB)やSRAM領域(512Kバイト)を使うことができます。従って、16ビットアドレス空間の方は、目いっぱいまで命令ROMを配置しました。
現に、これまで、何10KバイトもRAMが必要となるアプリケーションを組む機会が無かったので、ほとんどのケースでは8Kバイトもあれば十分だと思われます。
Moscoviumマイコンを設定するコンパイルオプションとして、以下のマクロを追加します。
命令フェッチ可能なI-RAMですが、「命令コードを配置しない」と決めれば、何ら遜色なく、普通にRAMとして使用可能です(ただし、シングルコア版に限る)。すなわち、RAM(8Kバイト)+I-RAM(4Kバイト)で合計12KバイトのRAMとしても使用可能と言う事ですので、うまく応用すれば、「RAMが足りないよ〜」等という困ったケースには遭遇👽しないはずです。
コンパイルオプションの具体的な設定方法については、nsoc113by8808.vh等を参考にしてください。
VivadoのRAMマクロでは、2冪サイズのRAMマクロが消費されます。
何とかならなかったのか?と言わざるを得ないショボい仕様ですが、Vivadoの仕様みたいなので致し方ありません。
無駄を避けるためには、例えば、48Kバイト=32Kバイト+16Kバイトの様に、2冪サイズに分割して作成しなくてはなりません。しかし、何しろROMなので、ROMに記憶するデータをVerilog MEMファイルで指定する必要があります。
無駄を避けようとROMを分割してしまうと、MEMファイルも分割して作成しなければならず、それはそれで、プログラム開発時の手間を増やし、嬉しくありません。
64Kバイト消費するRAMマクロの内、48KバイトまではROMとして活用されるため、本当に無駄になるのは16Kバイト分です。MEMファイルの分割など、後々の不都合を考えれば高々16Kバイトの無駄は許容して良いと判断しました。
今回、論理検証用として、48KバイトROMと命令RAM(I-RAM)を搭載したNSOC113BY8808を作成しました。型名規則は、こちらのリンクを参照ください。
Blockly開発環境でのプログラム開発を前提としているため、スーパスケイラ版Nihonium-SS+単精度浮動小数演算ユニットS-FPUを搭載した、CPU周りの最大強化版です。贅沢(1^^;)。
Cmod A7ボード用Moscoviumマイコンの設計データ(Vivadoプロジェクト)は、GitHubにて配布しております。以下バナーよりアクセスしてください。
Cmod A7ボード(FPGA)への書き込み手順は、こちらのリンクを参照してください。
48KバイトROMを搭載した、NSOC113BY8808をコンパイル(論理合成・配置配線)してみました。結果は以下の通りです。
コンパイル結果:
スーパスケイラ版のNihonium-SS+S-FPUと言う事で、タイミングクリティカルな回路規模が大きいです。このためか、タイミング解析(STA)はギリギリでメットしている感じですね。ほとんど余裕度(Setup Slack)がありません。どの程度の余地があるのかは判りませんが、メットしているのでOKでは、あります。
今のところ、32Kバイトや48Kバイトもの大きなプログラムは手元に有りません。従って、FPGAに書き込んで動作確認するまでも無く、シミュレーションで動作確認して終了とします。
Cmod A7ボード(FPGA)を使ったMoscoviumマイコンのシミュレーション手順は、こちらのリンクをご参照ください。
シミュレーション専用の、48KバイトROM動作検証用プログラムを以下にリンクしておきます。
検証用プログラム:mcoc_rom_48k.asm
Moscoviumマイコンのマクロアセンブラでは、デフォルトで4Kバイトの命令ROM容量を前提としたオブジェクトファイル(Verilog MEMファイル)を生成する様になっています。4Kバイト以外の命令ROMを使用する場合、以下の疑似命令を使って、ROM容量値を指定する必要があります。
romsiz 48*1024 // 48Kバイトの命令ROM容量を指定
Blocklyの場合、こちらの変換オプションから、「@rom_siz=48*1024@」を設定してください。
Moscoviumマイコンは、ROM容量が判ると、RAMの最上位アドレスが判るメモリマップに、なっています。ランタイムライブラリが"@rom_siz=<size>@"変換オプションの設定値を使ってRAMの先頭アドレスを確定し、変数領域を割り当てているため、正しく正確にROM容量を設定してください。
こちらのプログラムと、NSOC113BY8808のデザインを使ってシミュレーションを実行し、ログを確認してみましょう。
実験サンプル:シミュレーションログ
113a
0224
5dc0
4259
0000
c000
d000
2000
message #1 at top of ROM
message #2 at bottom of ROM
Bmessage #2 at bottom of ROM
Bmessage #1 at top of ROM
Test Pass
CPI: 785/ 532( 40)= 1475/1000
finish: 51240 ns
最初に出力された8個の16ビット16進数値は、IDREGユニットのI/Oレジスタ8個を読み出した結果です。
辺りが、特徴的な読み出し値です。IDREGユニットを使うと、搭載されているROM容量やRAM容量、先頭アドレスなどを知ることができる仕組みです。48KバイトROM選択時のメモリマップはこちらを参照してください。
その後、「message #1」と「message #2」がログに出力されました。「message #1」はROMの先頭(上位アドレス)付近、「message #2」は48Kバイトに拡張したROMの最下位アドレス付近にdats疑似命令で確保した文字列データを出力した物です。
「message」と、「Bmessage」が表示されていますが、「message」を表示させるサブルーチンはROMの上位アドレス側、「Bmessage」を表示させるサブルーチンはROMの下位アドレス側に配置しました。
つまり、上のログにて、以下のROM動作を確認できたことになります。
詳細な動作内容については、こちらのプログラムでご確認ください。
サンプルプログラムとしては、以上としておきますが、他にも、ROM領域が48Kバイトに拡張したことで変化する、以下の事象についても確認してあります。
ここまで来て漸く、ROM/RAM容量比率が間違っている、と認識したのですが、全く、何を考えて仕様策定していたんだ?って事ですね……。「間違い」に気が付ける事、「間違い」に気が付いたら臨機応変に修正できる事、そう言う事も大切、と思う今日この頃でした。