Cmod A7ボード(FPGA)を使って、オリジナル16ビットCPUコアMoscoviumの開発を進めています。
今回は、Moscoviumの減量👙がテーマです。
Moscoviumシリーズで小さなCPUコアとしては、オリジナル8ビットCPUコアTennessineがあります。Tennessineは確かに、論理規模が小さいという点では正解なのですが、少し使い難いことが短所です。
Moscoviumシリーズは、8ビット〜32ビットまでスケーラブルに、同じ命令コードを使うCPUシリーズです。
Nihoniumは32ビットでありながら16ビットモードで起動するため、Moscoviumのオブジェクトコードを実行することができます。つまり、オブジェクトコード互換なのです。ビット幅が違うのに!
更に、Nihoniumでは必要に応じて、状態レジスタsrのNHビット=1に設定することで、シームレスに32ビットモードへ移行することができ、演算・処理性能を向上することができます。Moscoviumと互換動作可能な事に加えて、32ビットモードへの移行が可能なので、死角なしです。
さて、Tennessineの使い難さに戻ると、Tennessineは8ビットCPUなので、汎用レジスタや演算器がすべて8ビットサイズです。よって、以下の様なオブジェクトコードは、Moscovium/Tennessine共に、正常に実行可能です。
ldbiu r0,12
ldbiu r1,3
mulu r0,r1
上の例では、Moscovium/Tennessine共、r0=r0×r1=12×3=36が代入されます。ここまでは、オブジェクトコード互換です。
ところが、以下コードに変わっただけで、MoscoviumとTennessineの動作は異なってしまいます。
ldbiu r0,12
ldbiu r1,34 // 3 → 34に変更
mulu r0,r1
CPUコア毎に実行結果を見てみると:
乗算結果408(=0x0198)が8ビットを超えたことで、Tennessineには下位8ビットに相当する演算結果152(=0x98)だけが残りました。動作仕様としては、Moscovium/Tennessine共、正しいです。上手い表現が見つかりませんが、オブジェクトコード互換では、あるのです。しかし、演算結果が8ビット幅を超えたことで、動作が互換では無くなってしまいました。
同様なプログラムミスは、16ビットCPUのMoscoviumでも起きます。演算結果が16ビット幅を超えてしまう事で、意図した動作と異なってしまうのは、16ビットCPUの「あるある」ですよね?
例えば、Arduino UNO(AVR8)の例ですが、BMP180の変換コードなどを挙げることができます(以下記事等)。
「#31-1 気圧の測定」
Tennessineの場合、8ビットCPUであるが故、「16ビット幅を超える」が、「8ビット幅を超える」ケースで、正常動作しなくなってしまうのです。
ちょっとしたプログラムを組むと、大抵のケースでは扱う数値が8ビットを超えるため、Moscovium用に作成したプログラムは、そのままではTennessineでは動作しません。Moscovium ⇔ Tennessine間の移行では、毎回、プログラムの「移植」作業が発生するため、とても使い難いのです。
※始めから、Tennessineを使うつもりでプログラムするのであれば「移植」作業は発生しないので、使い用は有ります。ただ、途中で切り替えることが困難なので、最初からTennessineを選ぶのは勇気が要ります。
Blockly for Moscovium開発環境(以下単に、Blocklyと記載する)の導入によって、開発効率は格段に高くなりました。何より、ブロックを使ったプログラミングは、楽しくて癖になりますo(1^−^)o。
Blocklyは、MoscoviumとNihoniumには対応したのですが、Tennessineで動作させるには、ランタイムライブラリを含めて大改造が必要なため費用対効果が合わず、対応を断念しました。
対応CPUコアであるMoscoviumであっても、全ての機能に対応した状態ではありません。Blocklyが対応していない機能の中で論理規模を増大させる機能があれば、その論理を削減することでMoscoviumを減量して、スリム化する事が可能なはずです。
勿論、未対応機能を減量するだけなので、Blockly開発環境の対象から外れる事は、ありません。
Blockly開発環境対応のスリム版として、新たに、Moscovium-BSコア(Blockly Slim edition)をラインアップに加えます。以下、減量可能な機能について考察して行きます。
汎用レジスタバンクは、SrレジスタのBK[1:0]フィールドを設定することで、汎用レジスタ8本をごっそりと切り替える機能です。
Moscoviumには、4組の汎用レジスタバンクがあります。合計32本(汎用レジスタ8本×4バンク)もの16ビット汎用レジスタが存在します。論理的には、レジスタを構成するフリップフロップFFの数もさることながら、汎用レジスタ値をCPUの内部バスに出力する際の選択回路(マルチプレクサ)の論理規模が大きいと推定できます。
汎用レジスタバンクを廃止、またはバンク数を削減できれば、減量可能です。
基本的に、Blockly自体は汎用レジスタバンクには非対応です。
ただし、Blocklyで割り込みを実装する時、割り込みサービスルーチン(ISR)内で、汎用レジスタの退避・回復をするのに汎用レジスタバンクを使うのであれば、便利で高速です。この機能実現のため、Blocklyの変換オプション(@isr_bank@)にて、ISR内での汎用レジスタバンク使用を指定可能です。
その他、ユーザがインラインアセンブラなどでSrレジスタのBK[1:0]フィールドを設定して使用する事は可能です。ただ、自分で設計しておいて何ですか、個人的には、バンク切り替えによって全レジスタが一斉に切り替わってしまう、汎用レジスタバンクは使い難いです。
「Blockly使用時には、汎用レジスタバンクの使用禁止」という制限が付いても、大きな欠点とは、ならないと考えました。
Blocklyが対応しているISR内での使用機能(@isr_bank@)は残したいため、汎用レジスタバンク自体の廃止は、しません。しかし、BlocklyのISR内使用に限定すれば、汎用レジスタバンクは2組で十分です。よって、汎用レジスタバンクを4組から2組へ減量しようと思います。
Moscoviumには、除算命令が存在しますが、CPU自体は除算器を搭載しておらず、外部の除算コプロセッサDIVC32で除算を実行します。DIVC32は、その名の通り、16ビットCPUのMoscoviumにて、32÷32ビット除算を実行可能なコプロセッサです。
高速に演算するため、フラッシュ除算方式とステップ除算方式を組み合わせたハイブリッド方式であり、論理規模が大きいです。
Blocklyでは、16÷16ビット除算の実行にもDIVC32を使用しますが、32÷32ビット除算には非対応なため、32ビット除算命令については減量することができます。
廃止: divlu/divls/divlq/divlr/divlqr/divlrr命令
Moscoviumの命令デコーダが小さくなるはずです。廃止した命令コードは、nop命令と同じ動作と、なります。
除算命令の中で、16ビット除算命令は残します。Blocklyが使うので、残す必要があります。
残留: divu/divs/divur/divsr命令
Blocklyでは、四則演算をCPU命令で実行するため、除算コプロセッサ自体は必要です。しかし、DIVC32は余計な32ビット除算に対応したことで、論理規模が肥大化しています。CPU命令だけではなく、除算コプロセッサ自体も減量が必要であろうと思われます。この課題は次回解決したいと思っています。
あと、細かい所では、SrレジスタのMLビットとDRビットは廃止します。ML/DRビットが廃止可能な事に関しては、こちらの記事「#25-7 乗除算命令を強化する」を参照してください。以下をMoscovium-BS(スリム版)での仕様とします。
内部信号が固定されることで、論理合成の時にCPUの命令デコーダが最適化され、論理規模を減量できると期待できます。
なお、Moscovium(通常版)とMoscovium-BS(スリム版)の判定には、MLビットの挙動を利用することができます。
前節までの考察に基づき、Moscovium-BSコアのプログラマモデルは、下図右側の通りと、なります。
Moscoviumのプログラマモデル(上図左側)と比べてみると、一目瞭然、だいぶ論理規模が小さくなっています。
汎用レジスタバンクを2組に減らしたので、Moscovium-BSコア(上図右側)ではBK1ビットが削除されており、書き込みできません。読み出すと常に0が読み出されます。汎用レジスタバンクを使おうとした時に、BK1に書き込みできるかどうかでも、MoscoviumとMoscovium-BSの判定は可能です。
まずは、Moscovium本体の減量を実施しました。
通常版のMoscoviumとは異なるデザインと、なるため、Moscovium-BS(Blockly Slim edition)と呼称します。コンパイルオプションは、「`define MCOC_CORE_MCBS」です。
CPUコア単体で論理合成した結果を以下表に示します。
論理規模 | LUT数 | FF数 | 備考 |
Moscovium | 2,000 | 630 | 16ビットCPUコア、通常版。 |
Moscovium-BS | 1,600 | 360 | 16ビットCPUコア、Blocklyスリム版。 |
Tennessine | 1,000 | 240 | 8ビットCPUコア。 |
Moscovium-BSに着目してみると、Tennessineほどではありませんが、Moscoviumに比べて約400LUT(20%)の減量に成功しました。FF数も大幅に削減できています。何より、8ビットのTennessineと異なり、削減した一部機能を除くMoscovium用のオブジェクトコードを、そのまま実行可能なのです。Cool!
有りがちなのは、「互換性維持」のため、従来の仕様を変更できずに首を絞めるケースです。今回は、「Blocklyで使わない論理機能は削減の対象」と割り切ったことで互換性を捨て、思い切った減量が叶いました。しかもRTLの変更量は大変少なく、デグレイドなどバグの作り込み余地も、ほぼゼロに近いです。
ここで折り返しです。あと、除算コプロセッサの減量が残っています。次回完結編にご期待ください。