FPGAボード(Sipeed Lichee Tang Primer)を使って設計したオリジナル16ビットCPUコアMoscoviumのパフォーマンスがちょっと気になった件。
問題と感じたのは、SDRAMにキャッシュメモリを適用して実行したマーチングテストの話です。
「#20-2 キャッシュメモリコントローラの設計(下)」
上記事中の実験では、キャッシュヒット率が85%を超えていたにもかかわらず、マーチングテストは10%程しか高速化できていませんでした。
原因は、SDRAMアクセスに要していた時間よりも、Moscoviumの32ビットデータ処理の方が支配的だったため、でした。何という事でしょう!キャッシュメモリの速さを実感する前に、Moscoviumの遅さが目立ってしまうとは。
なんとかせねば、と思ったのです。
前回、NihoniumをMoscoviumのオブジェクトコードレベル後方互換とすること、演算器(ALU)内に乗除算器を内蔵すること、32ビット即値ロード命令を多ワード長命令とすることを決めました。更に詳細設計を進め、オリジナル32ビットCPUコアNihoniumを完成させたいと思います。
状態レジスタsrのNHビットによって、汎用レジスタや演算命令のビット幅を16/32ビットに変化させる仕様とすることを決めました。
一方、メモリアクセス命令はアクセスサイズが指定されています。例えば、ldb命令はメモリから1バイト(b)データを読み出すし、stw命令はメモリに1ワード(w)データを書き込みます。
汎用レジスタを32ビットに拡張するので、ldl命令やstl命令など、ロングワード(l)アクセスする命令を追加する必要があります。
※「ワード」と言う単位を、C言語のintみたいに処理系依存で語る人も居ますが、Moscovium/Nihoniumでは、ワード=16ビット、ロングワード=32ビットと定義します。
以下表に、新規追加命令を含むメモリアクセス命令の一覧を示して解説を続けます。
用途 | アクセスサイズ | 命令 | 別名 | 備考 | |
メモリ操作 | レジスタ間接 | バイト |
ldb stb |
Moscovium互換。 | |
レジスタ間接 | ワード |
ldw stw |
Moscovium互換。 | ||
スタックポインタ相対 |
ldwsp stwsp |
ldsp stsp |
Moscovium互換。 従来の命令は別名で残す。 |
||
レジスタ間接 | ロングワード |
ldl stl |
Nihoniumへ追加。 | ||
スタックポインタ相対 |
ldlsp stlsp |
Nihoniumへ追加。 | |||
スタック操作 | 汎用レジスタ | ワード |
pushw popw |
push pop |
Moscovium互換。 従来の命令は別名で残す。 |
ロングワード |
pushl popl |
Nihoniumへ追加。 | |||
制御レジスタ | ワード |
pushc popc |
Moscovium互換。 |
Nihoniumでは、通常のldw命令/stw命令等で32ビットアドレスアクセスが可能となったため、Moscoviumで追加したTrレジスタを上位16ビットアドレスとする拡張アドレスアクセス命令(ldwx命令/stwx命令)の存在意義は無くなりました。これらの命令は、Moscoviumとの後方互換性維持のために残しますが、Nihonium (NH=1モード)ではldw命令/stw命令の使用を推奨します。
汎用レジスタの32ビット化に伴って、ロングワードアクセス命令を追加しました(前節)。ただし、CPU外部メモリバスのビット幅は16ビットのままとします。
今まで作って来たI/Oユニットは全て16ビットバスだし、バスステートコントローラやROM/RAMなどもすべて16ビットバスなので、全部、そのまま使いたいからです。さもないと、メモリバスの32ビット拡張や、RAMやSDRAMの32ビット化等の変更が派生して、大仕事になります。
よってNihoniumは、内部32ビット/外部16ビットのCPUとなります。昔のMC68000みたいな感じです。
追加したロングワードアクセス命令でロングワードアクセスする時は、ワードアクセス×2回に分割されるので、メモリアクセスのパフォーマンスは向上しません(下図)。
※パイプラインについてはこちらを参照してください。
アクセス速度を犠牲にした分、利点もあります。ロングワードアクセスする時、アドレスはロングワード(32ビット)境界である必要は無く、ワード(16ビット)境界に乗っていれば良いため、小回りが利きます。スタック🏭も、ワードサイズ/ロングワードサイズのデータを混在して出し入れすることができます。
以下図にメモリアクセスMEMブロックのブロック図を示します。
上のブロック図で、A,B,Cバスは32ビットに拡張してあります。一方、CPUの外部バスである、メモリバスの書き込みデータbdatw、読み出しデータbdatrは、16ビットのままです。アドレスbadrは、既にMoscoviumで32ビットに拡張してありました。
メモリバスに対する書き込みデータbdatwへの出力(上図のbwbfブロック)は、32ビットBバスの上位16ビットまたは下位16ビットを適宜切り替えて出力します。
読み出しデータbdatrは、上位16ビットおよび下位16ビットの2回に分けて読み出したデータを一旦brbfブロック内でラッチしておいて、32ビットデータが揃った時点で、一気に32ビットCバスへ出力するような回路となります(下図)。
MEMブロック内で32ビットデータを揃えてからCバスへ載せることによって、Cバスを受ける汎用レジスタ側で、「上位16ビットの取り込み」、「下位16ビットの取り込み」の様に無駄な制御を追加する必要がなくなります。MEMブロックの論理追加は1か所ですが、汎用レジスタ側の論理追加は汎用レジスタの数だけN倍化されてしまうので、チマチマと論理縮小の悪あがきとなります。
32ビット化したNihoniumの動作を実行するために、いくつか命令を追加する必要が生じました。
16ビット固定長命令を採用したのは良いけれど、16ビット→65,536個しかコード数がありません。この中に8ビット即値や11ビットディスプレースメント値(分岐命令)も含まれているため、命令コードの空き領域が少なくなっています。命令コードを捻出しておきましょう。
以下、捻出後のNihonium命令コード割り当て表です。
ビット | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
NO命令群 | 0 | 0 | 0 | 0 | 0 | OPC_NO | ||||||||||
BR命令群 | 0 | OPC_BR | dsp11 | |||||||||||||
RR命令群 | 0 | 1 | 1 | 1 | 0/1 | OPC_RR | Rd | Rs | ||||||||
R命令群 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0/1 | 0/1 | OPC_R | Rn | ||||
RI命令群 | 1 | OPC_RI | Rd | imm8 |
Moscoviumの命令コード割り当て表と見比べてみると、変更したのは、R命令群に第7ビットを割り当て拡張したことです。これによって、R命令群に+16個命令を追加することができます。もし将来、更にR命令群の命令を追加する必要が生じた場合、第8ビットをR命令群へ割り当て拡張すると、+32個追加することができるので、まだ少しの余裕があります。
RR命令群には、少し空きコードが残っていたので、こちらはそのままとしましたが、将来さらに命令を追加する必要に迫られた場合には、RR命令群の第12ビットを割り当て拡張すると、一気に+64個の命令を追加することができます。
今回追加する命令は以下の通りです。
空きコードが少ないことは確かなので、最低限必要な命令に絞って追加したつもりです。
多ワード長命令を許容したので、実行速度とコード効率が気にならない命令であれば、NO命令群のコード+2ワード目以降の命令コードを使って、無限に拡張することもできるので、狭い16ビット命令コードもそれほどの欠点にはならないでしょう。
今回のNihoniumは、我ながら中々興味深い取り組みとなりました。Nihoniumは面白い可能性を秘めています。
以上で、オリジナル32ビットCPUコアNihoniumの詳細設計を終了します。あとは淡々とコーディングするだけですので、詳細は省略します。
Nihoniumの命令セットマニュアルを以下にリンクしておきます。
オリジナル16ビットCPUコアMoscovium命令セットマニュアル
オリジナル32ビットCPUコアNihonium命令セットマニュアル
Moscoviumをスクラッチから起こした時は、まだまだここから大変でした。周辺回路を作って、I/Oユニットを少しづつ揃えて行く必要があったのです。
今回は、ベースとなるマイコンMCOC115がそのまま使えるよう、CPUのI/F信号に関しては、ほぼMoscoviumと同じにしてあるので、そのままCPUを置き換えたら完成します。
こちらの表に、型名の解釈を追加しておきました。
共通RTL(mcoc_comn.v)や、共通インクルードファイル(mcoc115.incl)、アセンブラ(asm_mcvm.olv)等のファイル名は、維持します。Nihonium用に名前を変えたところで、中身はほとんど同じ物となって、単なるN倍化となるだけですので。
Moscovium/Nihoniumはオブジェクトコードレベルで互換なので、アセンブラ(asm_mcvm.olv)は共通して使用可能です。
※アセンブラ(asm_mcvm.olv)はOlive+のスクリプトですので、実行するためには、WindowsにOlive+のインストールが必要となります。
Moscovium専用命令(divlu、divls、等)、Nihonium専用命令(ldl、stl、等)問わず、全ての命令がエラー無くアセンブルされます。現在実行中のCPUをソフトウェアで判定して、実行コードを切り替えるようなプログラムのアセンブルが可能と言う事です。
asm疑似命令のオプションに"moscovium"または"nihonium"を使うことで、指定したCPUで使用できない命令をアセンブルした時、警告メッセージを出力することができるようになっています。
※なお、Moscovium/Nihoniumでは、未定義命令はnop命令と同じ動作となります。Moscovium/Nihoniumの専用命令を、他方の非対応CPUで実行した場合も、nop命令と同じ動作です。
※ただし、ldli命令等の多ワード長命令には注意してください。例えば、ldli命令は3ワード命令で、2,3ワード目に即値データが格納されています。この命令を未定義のMoscoviumで実行すると、1ワード目の命令コードに関してはnop命令と同じですが、2,3ワード目の即値データも「命令コード」だと思って実行してしまいます。
以下リンクより、オリジナル32ビットCPUコアNihoniumを搭載したマイコンNHOC113SC0408のデザインをダウンロードできます。FPGAボード(Sipeed Lichee Tang Primer)への書き込み手順はこちらを参照してください。
SDRAMコントローラSDRAMC8Mユニットおよび、キャッシュメモリコントローラCACHE2W4Kユニットを備えています。
以下に、コンパイル(論理合成・配置配線)結果をまとめておきます。
CPUが32ビットNihoniumとなったことで、Moscovium版MCOC115SC0408と比べて、24MHzドメインのクリティカルパスが強化されているはずですが、最大動作周波数(Max Freq)を見比べてみると、以下の様な値でした。
Moscovium版MCOC115SC0408: Max Freq=31.161MHz
Nihonium版NHOC113SC0408: Max Freq=29.199MHz
多少の最大動作周波数低下は見られるものの、ターゲット24MHzに対してはまだ余裕があって、問題ありません。
CPU単体でコンパイルしてみたところ、その論理規模は以下表の様になりました。
CPUコア | LUT | 乗算器 | |
Moscovium (16ビット) | 3,000 | 1 | |
CPUコア単体 | 2,100 | − | |
乗算コプロセッサMULC16 | 100 | 1 | |
除算コプロセッサDIVC32 | 800 | − | |
Nihonium (32ビット) | 4,700 | 4 |
Nihoniumは、Moscoviumに対して乗除算コプロセッサをALUに内蔵した構成のため、Moscoviumの乗除算コプロセッサ追加版との比較を実施しています。
Moscovium+乗除算コプロセッサで約3,000LUTのところ、Nihoniumは約4,700LUTなので、約5割の増加でした。演算器(ALU)の32ビット化による論理規模の増加分として、想定の範囲内です。ただ、マイコンNHOC113SC0408全体で約9,200LUTのところ、Nihoniumコアだけで約4,700LUTを占めているので、決して小さくはないCPUコアかと思われます。
なお、今までずっとTD IDEのver.4.6.4と言うのを使って来たのですが、今回TD IDEをver.5.0.4にアップデートいたしました。
TD IDEのver.5.0.4は、FPGAボード(Sipeed Lichee Tang Primer)の販売元HPのリンクをたどって入手できます。TD IDEのインストールについてはこちらを参照してください。
TD IDE ver.4.6.4とver.5.0.4のプロジェクトには互換性が無い為、古いver.4.6.4に戻ることはできないのですが、多少なりともバグが改定されたver.5.0.4を使った方が、精神安定上宜しいでしょう。RTLなどのファイルは従来のまま使用可能です。
デザインデータページに載せたプロジェクトファイルも、ver.5.0.4用にアップデートしてあります。
オリジナル32ビットCPUコアNihoniumを完成させました。コンパイル(論理合成・配置配線)結果は問題なく、論理規模の増加量は、オリジナル16ビットCPUコアMoscoviumに比べて約50%増と判りました。次回、実物(FPGAボード)で動作確認して、どの程度高速化できたのか検証してみたいと思います。